From fbd610b8a9573bc6ed360ec599a4196c84a109eb Mon Sep 17 00:00:00 2001
From: Steve Plimpton <sjplimp@sandia.gov>
Date: Wed, 10 Oct 2018 13:39:44 -0600
Subject: [PATCH] global/local hyperdynamics src and doc files

---
 doc/fix_hyper_global.txt         |  146 +++
 doc/fix_hyper_local.txt          |  200 ++++
 doc/hyper.txt                    |  117 +++
 src/REPLICA/fix_event_hyper.cpp  |   95 ++
 src/REPLICA/fix_event_hyper.h    |   60 ++
 src/REPLICA/fix_hyper.cpp        |   35 +
 src/REPLICA/fix_hyper.h          |   43 +
 src/REPLICA/fix_hyper_global.cpp |  497 +++++++++
 src/REPLICA/fix_hyper_global.h   |  110 ++
 src/REPLICA/fix_hyper_local.cpp  | 1610 ++++++++++++++++++++++++++++++
 src/REPLICA/fix_hyper_local.h    |  175 ++++
 src/REPLICA/hyper.cpp            |  548 ++++++++++
 src/REPLICA/hyper.h              |   65 ++
 13 files changed, 3701 insertions(+)
 create mode 100644 doc/fix_hyper_global.txt
 create mode 100644 doc/fix_hyper_local.txt
 create mode 100644 doc/hyper.txt
 create mode 100644 src/REPLICA/fix_event_hyper.cpp
 create mode 100644 src/REPLICA/fix_event_hyper.h
 create mode 100644 src/REPLICA/fix_hyper.cpp
 create mode 100644 src/REPLICA/fix_hyper.h
 create mode 100644 src/REPLICA/fix_hyper_global.cpp
 create mode 100644 src/REPLICA/fix_hyper_global.h
 create mode 100644 src/REPLICA/fix_hyper_local.cpp
 create mode 100644 src/REPLICA/fix_hyper_local.h
 create mode 100644 src/REPLICA/hyper.cpp
 create mode 100644 src/REPLICA/hyper.h

diff --git a/doc/fix_hyper_global.txt b/doc/fix_hyper_global.txt
new file mode 100644
index 0000000000..c841f0b891
--- /dev/null
+++ b/doc/fix_hyper_global.txt
@@ -0,0 +1,146 @@
+"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+fix hyper/global command :h3
+
+[Syntax:]
+
+fix ID group-ID hyper/global cutbond qfactor Vmax Tequil :pre
+
+ID, group-ID are documented in "fix"_fix.html command
+hyper/global = style name of this fix command
+cutbond = max distance at which a pair of atoms is considered bonded (distance units)
+qfactor = max strain at which bias potential goes to 0.0 (unitless)
+Vmax = height of bias potential (energy units)
+Tequil = equilibration temperature (temperature units) :ul
+
+[Examples:]
+
+fix 1 all hyper/global 1.0 0.3 0.8 300.0 :pre
+
+[Description:]
+
+This fix is meant to be used with the "hyper"_hyper.html command to
+perform a bond-boost hyperdynamics simulation.  The role of this fix
+is a select a single pair of atoms within the system at each timestep
+to add a global bias potential to, which will alter their dynamics.
+This is in contrast to the "fix hyper/local"_fix_hyper_local.html
+command, which can add a local bias potential to multiple pairs of
+atoms at each timestep.
+
+For a system that undergoes rare transition events, where one or more
+atoms move across an energy barrier to a new potential energy basin,
+the effect of the bias potential is to induce more rapid transitions.
+This can lead to a dramatic speed-up in the rate at which events
+occurs, without altering their relative frequencies, thus leading to
+an overall dramatic speed-up in the effective elapsed time of the
+simulation.
+
+Cite various papers.
+
+The current strain of a bond IJ is defined as
+
+Eij = (Rij - R0ij) / R0ij :pre
+
+Emax = is the max of the absolute value of Eij for all IJ bonds.
+
+dVij = Vmax * (1 - (Eij/q)^2) for abs(Eij) < q
+     = 0  otherwise :pre
+
+Delta Vbias = minimum of dVij for all IJ bonds :pre
+
+The boost factor B = exp(beta * Delta Vbias)
+for a single timestep.
+
+Thus the accumulated hypertime is simply
+
+t_hyper = Sum (i = 1 to Nsteps) Bi * dt :pre
+
+The {cutbond} argument is the cutoff distance for defining bonds
+between pairs of nearby atoms.  A pair of atoms in their equilibrium,
+minimum-energy config, which are a distance Rij < cutbond, are
+defined as a bonded pair.
+
+The {qfactor} argument is the limiting strain at which
+the Vbias (the bias potential) goes to 0.0.
+
+If {qfactor} is too big, then transitions are affected b/c
+the bias energy is non-zero at the transitions.  If it is
+too small than not must boost is achieved for a large system
+with many bonds (some bonds Eij always exceeds qfactor).
+
+The {Vmax} argument is the prefactor on the bias potential.
+
+The {Tequil} argument is part of the beta term in the
+exponential factor that determines how much boost is
+achieved as a function of the bias potential.
+
+[Restart, fix_modify, output, run start/stop, minimize info:]
+
+No information about this fix is written to "binary restart
+files"_restart.html.
+
+The "fix_modify"_fix_modify.html {energy} option is supported by this
+fix to add the energy of the bias potential to the the system's
+potential energy as part of "thermodynamic output"_thermo_style.html.
+
+This fix computes a global scalar and global vector of length 10,
+which can be accessed by various "output
+commands"_Section_howto.html#howto_15.  The scalar is the magnitude of
+the bias potential (energy units) applied on the current timestep.
+The vector stores the following quantities:
+
+1 = boost factor on this step (unitless)
+2 = max strain of any bond on this step (unitless)
+3 = ID of first atom in the max-strain bond
+4 = ID of second atom in the max-strain bond
+5 = average # of bonds/atom on this step :ul
+
+6 = fraction of step with no bias during this run
+7 = max drift distance of any atom during this run (distance units)
+8 = max bond length during this run (distance units) :ul
+
+9 = cummulative hyper time since fix created (time units)
+10 = cummulative count of event timesteps since fix created
+11 = cummulative count of atoms in events since fix created :ul
+
+The first 5 quantities are for the current timestep.  The quantities
+6-8 are for the current run.  The quantities 9-11 are cummulative
+across multiple runs (since the fix was defined in the input script).
+
+For value 10, events are checked for by the "hyper"_hyper.html command
+once every {Nevent} timesteps.  This value is the count of the number
+of timesteps on which one (or more) events was detected.  It is NOT
+the number of distinct events, since more than one physical event may
+occur in the same {Nevent} time window.
+
+For value 11, each time the "hyper"_hyper.html command checks for an
+event, the event compute it uses will flag zero or more atoms as
+participating in an event.  E.g. atoms that have displaced more than
+some distance from the previous quench state.  This value is the count
+of the number of atoms participating in any of the events that were
+found.
+
+The scalar and vector values calculated by this fix are all
+"intensive".
+
+No parameter of this fix can be used with the {start/stop} keywords of
+the "run"_run.html command.  This fix is not invoked during "energy
+minimization"_minimize.html.
+
+[Restrictions:]
+
+This fix is part of the REPLICA package.  It is only enabled if LAMMPS
+was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_3 section for more info.
+
+[Related commands:]
+
+"fix hyper/local"_fix_hyper_local.html
+
+[Default:] None
diff --git a/doc/fix_hyper_local.txt b/doc/fix_hyper_local.txt
new file mode 100644
index 0000000000..ef98637fa5
--- /dev/null
+++ b/doc/fix_hyper_local.txt
@@ -0,0 +1,200 @@
+"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+fix hyper/local command :h3
+
+[Syntax:]
+
+fix ID group-ID hyper/local cutbond qfactor Vmax Tequil Dcut alpha boost :pre
+
+ID, group-ID are documented in "fix"_fix.html command :ulb,l
+hyper/local = style name of this fix command :l
+cutbond = max distance at which a pair of atoms is considered bonded (distance units) :l
+qfactor = max strain at which bias potential goes to 0.0 (unitless) :l
+Vmax = estimated height of bias potential (energy units) :l
+Tequil = equilibration temperature (temperature units) :l
+Dcut = min distance between boosted bonds (distance units) :l
+alpha = boostostat relaxation time (time units) :l
+boost = desired time boost factor (unitless) :l
+zero or more keyword/value pairs may be appended :l
+keyword = {histo} or {lost} or {check/bias} or {check/coeff}
+  {histo} values = Nevery Nbin delta Nout
+    Nevery = histogram bond bias coefficients every this many timesteps
+    Nbin = # of histogram bins
+    delta = width of each histogram bin
+    Nout = output histogram counts every this many timesteps
+  {lostbond} value = error/warn/ignore
+  {check/bias} values = Nevery error/warn/ignore
+  {check/coeff} values = Nevery error/warn/ignore :pre
+:ule
+
+[Examples:]
+
+fix 1 all hyper/local 1.0 0.3 0.8 300.0 :pre
+
+[Description:]
+
+This fix is meant to be used with the "hyper"_hyper.html command to
+perform a bond-boost hyperdynamics simulation.  The role of this fix
+is a select a multiple pairs of atoms within the system at each
+timestep to add a local bias potential to, which will alter their
+dynamics.  This is in contrast to the "fix
+hyper/global"_fix_hyper_global.html command, which adds a global bias
+potential to a single pair of atoms at each timestep.
+
+For a system that undergoes rare transition events, where one or more
+atoms move across an energy barrier to a new potential energy basin,
+the effect of the bias potential is to induce more rapid transitions.
+This can lead to a dramatic speed-up in the rate at which events
+occurs, without altering their relative frequencies, thus leading to
+an overall dramatic speed-up in the effective wall-clock time of the
+simulation.
+
+Cite various papers.
+
+The current strain of a bond IJ is defined as
+
+Eij = (Rij - R0ij) / R0ij
+
+Emax = is the max of the absolute value of Eij for all IJ bonds.
+
+dVij = Vmax * (1 - (Eij/q)^2) for abs(Eij) < q
+     = 0  otherwise
+
+Delta Vbias = minimum of dVij for all IJ bonds
+
+The boost factor B = exp(beta * Delta Vbias)
+for a single timestep.
+
+Thus the accumulated hypertime is simply
+
+t_hyper = Sum (i = 1 to Nsteps) Bi * dt
+
+NOTE: Add eqs for boostostat and boost coeff.
+Explain how many bonds are boosted simultaneously
+and how to choose boost factor and initial Vmax.
+
+The {cutbond} argument is the cutoff distance for defining bonds
+between pairs of nearby atoms.  A pair of atoms in their equilibrium,
+minimum-energy config, which are a distance Rij < cutbond, are
+defined as a bonded pair.
+
+The {qfactor} argument is the limiting strain at which
+the Vbias (the bias potential) goes to 0.0.
+
+If qfactor is too big, then transitions are affected b/c
+the bias energy is non-zero at the transitions.  If it is
+too small than not must boost is achieved for a large system
+with many bonds (some bonds Eij always exceeds qfactor).
+
+The {Vmax} argument is the initial prefactor on the bias potential.
+Should be chosen as estimate of final.  Will be adjusted by
+boost cooeficient
+
+The {Tequil} argument is part of the beta term in the
+exponential factor that determines how much boost is
+achieved as a function of the bias potential.
+
+The {Dcut} argument is the distance required between two bonds for
+them to be selected as both being boosted.  The distance is between
+the center points of each bond.  Actually between any pair of atoms in
+either bond.
+
+The {alpha} argument is a pre-factor on the update equation
+for each atom's boostostat:
+
+NOTE: give equation above
+
+Note that the units for {alpha} are in time units, similar
+to other thermostat or barostat damping parameters
+
+The {boost} argument is the desired boost factor (e.g. 100x)
+that all the atoms in the system will experience.  
+
+NOTE: explain how to choose good value for this.  If this parameter is
+chosen to be too large, then the bias potential applied to pairs of
+bonded atoms may become unphysically large, leading to bad dynamics.
+If chosen too small, the hyperdynamics run may be inefficient in the
+sense that events take a long time to occur.
+
+[Restart, fix_modify, output, run start/stop, minimize info:]
+
+No information about this fix is written to "binary restart
+files"_restart.html.
+
+The "fix_modify"_fix_modify.html {energy} option is supported by this
+fix to add the energy of the bias potential to the the system's
+potential energy as part of "thermodynamic output"_thermo_style.html.
+
+This fix computes a global scalar and global vector of length 23,
+which can be accessed by various "output
+commands"_Section_howto.html#howto_15.  The scalar is the magnitude of
+the bias potential (energy units) applied on the current timestep,
+summed over all biased bonds.  The vector stores the following
+quantities:
+
+1 = # of boosted bonds on this step
+2 = max strain of any bond on this step (unitless)
+3 = average bias potential for all bonds on this step (energy units)
+4 = average bonds/atom on this step
+5 = average neighbor bonds/bond on this step :ul
+
+6 = fraction of steps and bonds with no bias during this run
+7 = max drift distance of any atom during this run (distance units)
+8 = max bond length during this run (distance units)
+9 = average # of boosted bonds/step during this run
+10 = average bias potential for all bonds during this run (energy units)
+11 = max bias potential for any bond during this run (energy units)
+12 = min bias potential for any bond during this run (energy units)
+13 = max distance from my box of any ghost atom with maxstrain < qfactor during th
+is run (distance units)
+14 = max distance outside my box of any ghost atom with any maxstrain during this run (distance units)
+15 = count of ghost neighbor atoms not found on reneighbor steps during this run
+16 = count of lost bond partners during this run
+17 = average bias coeff for lost bond partners during this run
+18 = count of bias overlaps found during this run
+19 = count of non-matching bias coefficients found during this run :ul
+
+20 = cummulative hyper time since fix created (time units)
+21 = cummulative count of event timesteps since fix created
+22 = cummulative count of atoms in events since fix created
+23 = cummulative # of new bonds since fix created :ul
+
+The first quantities (1-5) are for the current timestep.  The
+quantities 6-19 are for the current hyper run.  They are reset each
+time a new hyper run is performed.  The quantities 20-23 are
+cummulative across multiple hyper runs,  They are only set to initial
+values once, when this fix is defined in the input script.
+
+For value 6, the numerator is a count of all biased bonds on every
+timestep whose bias value = 0.0.  The denominator is the count of all
+biased bonds on all timesteps.
+
+For values 13 and 14, the maxstrain of a ghost atom is the maxstrain
+of any bond it is part of, and it is checked for ghost atoms within
+the bond neighbor cutoff.
+
+The scalar and vector values calculated by this fix are all
+"intensive".
+
+No parameter of this fix can be used with the {start/stop} keywords of
+the "run"_run.html command.  This fix is not invoked during "energy
+minimization"_minimize.html.
+
+[Restrictions:]
+
+This fix is part of the REPLICA package.  It is only enabled if LAMMPS
+was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_3 section for more info.
+
+[Related commands:]
+
+"hyper"_hyper.html, "fix hyper/global"_fix_hyper_global.html
+
+[Default:] None
+
diff --git a/doc/hyper.txt b/doc/hyper.txt
new file mode 100644
index 0000000000..966d33a30f
--- /dev/null
+++ b/doc/hyper.txt
@@ -0,0 +1,117 @@
+"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+hyper command :h3
+
+[Syntax:]
+
+hyper N Nevent fixID computeID keyword values ... :pre
+
+N = # of timesteps to run :ulb,l
+Nevent = check for events every this many steps :l
+fixID = ID of a fix that applies a global or local bias potential :l
+computeID = ID of a compute that identifies when an event has occurred :l
+zero or more keyword/value pairs may be appended :l
+keyword = {min} or {time} :l
+  {min} values = etol ftol maxiter maxeval
+    etol = stopping tolerance for energy, used in quenching
+    ftol = stopping tolerance for force, used in quenching
+    maxiter = max iterations of minimize, used in quenching
+    maxeval = max number of force/energy evaluations, used in quenching
+  {time} value = {steps} or {clock}
+    {steps} = simulation runs for N timesteps (default)
+    {clock} = simulation runs until hyper time exceeds N timesteps :pre
+:ule
+
+[Examples:]
+
+hyper 5000 100 global event :pre
+
+[Description:]
+
+Run a bond-boost hyperdynamics (HD) simulation where time is
+accelerated by application of a bias potential to a one or more pairs
+of atoms in the system.  This command can be used to run both global
+and local hyperdyamics.  In global HD a single bond (nearby pair of
+atoms) within the system is biased on a given timestep.  In local HD
+multiple bonds (separated by a sufficient distance) can be biased
+simultaneously at each timestep.
+
+Make next paragraph more HD-specific.
+
+Both global and local HD are described in "this paper"_#Voter2013 by
+Art Voter and collaborators.  They are methods for performing
+accelerated dynamics that is suitable for infrequent-event systems
+that obey first-order kinetics.  A good overview of accelerated
+dynamics methods for such systems in given in "this review
+paper"_#Voter2002prd from the same group.  To quote from the paper:
+"The dynamical evolution is characterized by vibrational excursions
+within a potential basin, punctuated by occasional transitions between
+basins."  The transition probability is characterized by p(t) =
+k*exp(-kt) where k is the rate constant.  Running multiple replicas
+gives an effective enhancement in the timescale spanned by the
+multiple simulations, while waiting for an event to occur.
+
+How different than PRD.
+
+An HD run has several stages, which are repeated each time an "event"
+occurs, as defined below.  The logic for a HD run is as follows:
+
+quench
+reset list of bonds :pre
+
+while (time remains):
+  run dynamics for Nevery steps
+  quench
+  check for an event
+  if event occurred: reset list of bonds
+  restore pre-quench state :pre
+
+Explain each of the steps above.  Explain what list of bonds is and
+how event is detected.
+
+Explain the specified fix and compute.
+
+Statistics about the number of events, the number of bonds that a bias
+potential is applied to, the accumulated hyper time, etc are stored by
+the fix and can be output with thermodynamic output.
+
+:line
+
+[Restrictions:]
+
+This command can only be used if LAMMPS was built with the REPLICA
+package.  See the "Making LAMMPS"_Section_start.html#start_3 section
+for more info on packages.
+
+NOTE: is this true?
+This command cannot be used when any fixes are defined that keep track
+of elapsed time to perform time-dependent operations.  Examples
+include the "ave" fixes such as "fix ave/chunk"_fix_ave_chunk.html.
+Also "fix dt/reset"_fix_dt_reset.html and "fix
+deposit"_fix_deposit.html.
+
+[Related commands:]
+
+"fix hyper/global"_fix_hyper_global.html, "fix
+hyper/local"_fix_hyper_local.html, "compute
+event/displace"_compute_event_displace.html
+
+[Default:]
+
+The option defaults are min = 0.1 0.1 40 50 and time = steps.
+
+:line
+
+:link(Voter2013)
+[(Voter2013)] S. Y. Kim, D. Perez, A. F. Voter, J Chem Phys, 139,
+144110 (2013).
+
+:link(Voter2002prd)
+[(Voter2002)] Voter, Montalenti, Germann, Annual Review of Materials
+Research 32, 321 (2002).
diff --git a/src/REPLICA/fix_event_hyper.cpp b/src/REPLICA/fix_event_hyper.cpp
new file mode 100644
index 0000000000..7dd306c735
--- /dev/null
+++ b/src/REPLICA/fix_event_hyper.cpp
@@ -0,0 +1,95 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include "fix_event_hyper.h"
+#include "atom.h"
+#include "update.h"
+#include "domain.h"
+#include "neighbor.h"
+#include "comm.h"
+#include "universe.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+using namespace FixConst;
+
+/* ---------------------------------------------------------------------- */
+
+FixEventHyper::FixEventHyper(LAMMPS *lmp, int narg, char **arg) :
+  FixEvent(lmp, narg, arg)
+{
+  if (narg != 3) error->all(FLERR,"Illegal fix event command");
+
+  restart_global = 1;
+
+  event_number = 0;
+  event_timestep = update->ntimestep;
+  clock = 0;
+}
+
+/* ----------------------------------------------------------------------
+   save current atom coords as an event (via call to base class)
+   called when an event occurs in some replica
+   set event_timestep = when event occurred in a particular replica
+   update clock = elapsed time since last event, across all replicas
+------------------------------------------------------------------------- */
+
+void FixEventHyper::store_event_hyper(bigint ntimestep, int delta_clock)
+{
+  store_event();
+  event_timestep = ntimestep;
+  clock += delta_clock;
+  event_number++;
+}
+
+/* ----------------------------------------------------------------------
+   pack entire state of Fix into one write
+------------------------------------------------------------------------- */
+
+void FixEventHyper::write_restart(FILE *fp)
+{
+  int n = 0;
+  double list[6];
+  list[n++] = event_number;
+  list[n++] = event_timestep;
+  list[n++] = clock;
+  list[n++] = replica_number;
+  list[n++] = correlated_event;
+  list[n++] = ncoincident;
+
+  if (comm->me == 0) {
+    int size = n * sizeof(double);
+    fwrite(&size,sizeof(int),1,fp);
+    fwrite(list,sizeof(double),n,fp);
+  }
+}
+
+/* ----------------------------------------------------------------------
+   use state info from restart file to restart the Fix
+------------------------------------------------------------------------- */
+
+void FixEventHyper::restart(char *buf)
+{
+  int n = 0;
+  double *list = (double *) buf;
+
+  event_number = static_cast<int> (list[n++]);
+  event_timestep = static_cast<bigint> (list[n++]);
+  clock = static_cast<bigint> (list[n++]);
+  replica_number = static_cast<int> (list[n++]);
+  correlated_event = static_cast<int> (list[n++]);
+  ncoincident = static_cast<int> (list[n++]);
+}
diff --git a/src/REPLICA/fix_event_hyper.h b/src/REPLICA/fix_event_hyper.h
new file mode 100644
index 0000000000..4c5d4a93ee
--- /dev/null
+++ b/src/REPLICA/fix_event_hyper.h
@@ -0,0 +1,60 @@
+/* -*- c++ -*- ----------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifdef FIX_CLASS
+
+FixStyle(EVENT/HYPER,FixEventHyper)
+
+#else
+
+#ifndef LMP_FIX_EVENT_HYPER_H
+#define LMP_FIX_EVENT_HYPER_H
+
+#include "fix_event.h"
+
+namespace LAMMPS_NS {
+
+class FixEventHyper : public FixEvent {
+ public:
+  int event_number;      // event counter
+  bigint event_timestep; // timestep of last event on any replica
+  bigint clock;          // total elapsed timesteps across all replicas
+  int replica_number;    // replica where last event occured
+  int correlated_event;  // 1 if last event was correlated, 0 otherwise
+  int ncoincident;       // # of simultaneous events on different replicas
+
+  FixEventHyper(class LAMMPS *, int, char **);
+  ~FixEventHyper() {}
+
+  void write_restart(FILE *);
+  void restart(char *);
+
+  // methods specific to FixEventHyper, invoked by hyper
+
+  void store_event_hyper(bigint, int);
+};
+
+}
+
+#endif
+#endif
+
+/* ERROR/WARNING messages:
+
+E: Illegal ... command
+
+Self-explanatory.  Check the input script syntax and compare to the
+documentation for the command.  You can use -echo screen as a
+command-line option when running LAMMPS to see the offending line.
+
+*/
diff --git a/src/REPLICA/fix_hyper.cpp b/src/REPLICA/fix_hyper.cpp
new file mode 100644
index 0000000000..9f01d9542c
--- /dev/null
+++ b/src/REPLICA/fix_hyper.cpp
@@ -0,0 +1,35 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include <string.h>
+#include "fix_hyper.h"
+
+using namespace LAMMPS_NS;
+
+/* ---------------------------------------------------------------------- */
+
+FixHyper::FixHyper(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) {}
+
+/* ----------------------------------------------------------------------
+   extract hyper flag setting for all Fixes that perform hyperdynamics
+------------------------------------------------------------------------- */
+
+void *FixHyper::extract(const char *str, int &dim)
+{
+  dim = 0;
+  if (strcmp(str,"hyperflag") == 0) {
+    return &hyperflag;
+  }
+  return NULL;
+}
+
diff --git a/src/REPLICA/fix_hyper.h b/src/REPLICA/fix_hyper.h
new file mode 100644
index 0000000000..7cb6cadf8f
--- /dev/null
+++ b/src/REPLICA/fix_hyper.h
@@ -0,0 +1,43 @@
+/* -*- c++ -*- ----------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifndef LMP_FIX_HYPER_H
+#define LMP_FIX_HYPER_H
+
+#include "fix.h"
+
+namespace LAMMPS_NS {
+
+class FixHyper : public Fix {
+ public:
+  FixHyper(class LAMMPS *, int, char **);
+  virtual ~FixHyper() {}
+  void *extract(const char *, int &);
+
+  // must be provided by child class
+
+  virtual void init_hyper() = 0;
+  virtual void build_bond_list(int) = 0;
+  virtual double query(int) = 0;
+
+ protected:
+  int hyperflag;
+};
+
+}
+
+#endif
+
+/* ERROR/WARNING messages:
+
+*/
diff --git a/src/REPLICA/fix_hyper_global.cpp b/src/REPLICA/fix_hyper_global.cpp
new file mode 100644
index 0000000000..ba45e47407
--- /dev/null
+++ b/src/REPLICA/fix_hyper_global.cpp
@@ -0,0 +1,497 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include <mpi.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include "fix_hyper_global.h"
+#include "atom.h"
+#include "update.h"
+#include "force.h"
+#include "domain.h"
+#include "comm.h"
+#include "neighbor.h"
+#include "neigh_request.h"
+#include "neigh_list.h"
+#include "modify.h"
+#include "math_extra.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+using namespace FixConst;
+
+#define DELTA 16384
+#define VECLEN 5
+
+/* ---------------------------------------------------------------------- */
+
+FixHyperGlobal::FixHyperGlobal(LAMMPS *lmp, int narg, char **arg) :
+  FixHyper(lmp, narg, arg)
+{
+  // NOTE: add NULL declarations
+  // NOTE: count/output # of timesteps on which bias is non-zero
+  // NOTE: require newton on?
+
+  if (atom->map_style == 0) 
+    error->all(FLERR,"Fix hyper/global command requires atom map");
+
+  if (narg != 7) error->all(FLERR,"Illegal fix hyper/global command");
+
+  hyperflag = 1;
+  scalar_flag = 1;
+  vector_flag = 1;
+  size_vector = 11;
+  global_freq = 1;
+  extscalar = 0;
+  extvector = 0;
+
+  cutbond = force->numeric(FLERR,arg[3]);
+  qfactor = force->numeric(FLERR,arg[4]);
+  vmax = force->numeric(FLERR,arg[5]);
+  tequil = force->numeric(FLERR,arg[6]);
+
+  if (cutbond < 0.0 || qfactor <= 0.0 || vmax < 0.0 || tequil <= 0.0)
+    error->all(FLERR,"Illegal fix hyper/global command");
+
+  invqfactorsq = 1.0 / (qfactor*qfactor);
+  cutbondsq = cutbond*cutbond;
+  beta = 1.0 / (force->boltz * tequil);
+
+  maxbond = 0;
+  nblocal = 0;
+  blist = NULL;
+
+  maxold = 0;
+  xold = NULL;
+  tagold = NULL;
+
+  me = comm->me;
+  firstflag = 1;
+  bcastflag = 0;
+  for (int i = 0; i < VECLEN; i++) outvec[i] = 0.0;
+
+  nevent = 0;
+  nevent_atom = 0;
+  t_hyper = 0.0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+FixHyperGlobal::~FixHyperGlobal()
+{
+  memory->sfree(blist);
+  memory->destroy(xold);
+  memory->destroy(tagold);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixHyperGlobal::setmask()
+{
+  int mask = 0;
+  mask |= PRE_NEIGHBOR;
+  mask |= PRE_FORCE;
+  mask |= PRE_REVERSE;
+  mask |= THERMO_ENERGY;
+  return mask;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperGlobal::init_hyper()
+{
+  maxdriftsq = 0.0;
+  maxbondlen = 0.0;
+  nobias = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperGlobal::init()
+{
+  dt = update->dt;
+
+  // need an occasional half neighbor list
+
+  int irequest = neighbor->request(this,instance_me);
+  neighbor->requests[irequest]->pair = 0;
+  neighbor->requests[irequest]->fix = 1;
+  neighbor->requests[irequest]->occasional = 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperGlobal::init_list(int id, NeighList *ptr)
+{
+  list = ptr;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperGlobal::setup_pre_neighbor()
+{
+  pre_neighbor();
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperGlobal::setup_pre_reverse(int eflag, int vflag)
+{
+  // no increment in nobias or hyper time when pre-run forces are calculated
+
+  int nobias_hold = nobias;
+  double t_hyper_hold = t_hyper;
+
+  pre_reverse(eflag,vflag);
+
+  nobias = nobias_hold;
+  t_hyper = t_hyper_hold;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperGlobal::pre_neighbor()
+{
+  int i,m,jnum,iold,jold,ilocal,jlocal;
+  double distsq;
+
+  // reset local IDs for owned bond atoms, since atoms have migrated
+  // uses xold and tagold from when bonds were created
+  // must be done after ghost atoms are setup via comm->borders()
+
+  double **x = atom->x;
+
+  int flag = 0;
+
+  for (m = 0; m < nblocal; m++) {
+    iold = blist[m].iold;
+    jold = blist[m].jold;
+    ilocal = atom->map(tagold[iold]);
+    jlocal = atom->map(tagold[jold]);
+    ilocal = domain->closest_image(xold[iold],ilocal);
+    jlocal = domain->closest_image(xold[iold],jlocal);
+    blist[m].i = ilocal;
+    blist[m].j = jlocal;
+
+    if (ilocal < 0 || jlocal < 0) flag++;
+    else {
+      distsq = MathExtra::distsq3(x[ilocal],xold[iold]);
+      maxdriftsq = MAX(distsq,maxdriftsq);
+    }
+  }
+
+  if (flag) error->one(FLERR,"Fix hyper/global bond atom not found");
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperGlobal::pre_reverse(int eflag, int vflag)
+{
+  int i,j,m,imax,jmax;
+  double xtmp,ytmp,ztmp,delx,dely,delz;
+  double r,r0,estrain,rmax,r0max,emax,dt_boost;
+  double vbias,fbias,fbiasr;
+
+  // compute current strain of each owned bond
+  // emax = maximum strain of any bond I own
+  // imax,jmax = local indices of my 2 atoms in that bond
+
+  double **x = atom->x;
+  emax = 0.0;
+
+  for (m = 0; m < nblocal; m++) {
+    i = blist[m].i;
+    j = blist[m].j;
+    delx = x[i][0] - x[j][0];
+    dely = x[i][1] - x[j][1];
+    delz = x[i][2] - x[j][2];
+    r = sqrt(delx*delx + dely*dely + delz*delz);
+    maxbondlen = MAX(r,maxbondlen);
+    r0 = blist[m].r0;
+    estrain = fabs(r-r0) / r0;
+
+    if (estrain > emax) {
+      emax = estrain;
+      rmax = r;
+      r0max = r0;
+      imax = i;
+      jmax = j;
+    }
+  }
+
+  // perform Allreduce() on pairme = double/int pair
+  // finds max strain and what proc owns it
+  // owner = proc that owns that bond
+
+  pairme.value = emax;
+  pairme.proc = me;
+  MPI_Allreduce(&pairme,&pairall,1,MPI_DOUBLE_INT,MPI_MAXLOC,world);
+  owner = pairall.proc;
+
+  bcastflag = 1;
+
+  // all procs acquire t_hyper from owner proc
+  // MPI_Bcast call by owner proc is below
+
+  for (int i = 0; i < VECLEN; i++) outvec[i] = 0.0;
+
+  if (owner != me) {
+    MPI_Bcast(&t_hyper,1,MPI_DOUBLE,owner,world);
+    return;
+  }
+
+  // I own the bond with max strain
+  // compute Vbias and apply force to atoms imax,jmax
+  // NOTE: logic would need to be different for newton off
+
+  double **f = atom->f;
+
+  vbias = fbias = 0.0;
+  dt_boost = 1.0;
+
+  if (emax < qfactor) {
+    vbias = vmax * (1.0 - emax*emax*invqfactorsq);
+    fbias = 2.0 * vmax * emax / (qfactor*qfactor * r0max);
+    dt_boost = exp(beta*vbias);
+
+    delx = x[imax][0] - x[jmax][0];
+    dely = x[imax][1] - x[jmax][1];
+    delz = x[imax][2] - x[jmax][2];
+
+    fbiasr = fbias / rmax;
+    f[imax][0] += delx*fbiasr;
+    f[imax][1] += dely*fbiasr;
+    f[imax][2] += delz*fbiasr;
+
+    f[jmax][0] -= delx*fbiasr;
+    f[jmax][1] -= dely*fbiasr;
+    f[jmax][2] -= delz*fbiasr;
+  } else nobias++;
+
+  // NOTE: should there be a virial contribution from boosted bond?
+
+  // output quantities
+
+  outvec[0] = vbias;
+  outvec[1] = dt_boost;
+  outvec[2] = emax;
+  outvec[3] = atom->tag[imax];
+  outvec[4] = atom->tag[jmax];
+
+  t_hyper += dt_boost*dt;
+  MPI_Bcast(&t_hyper,1,MPI_DOUBLE,owner,world);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperGlobal::build_bond_list(int natom)
+{
+  int i,j,n,ii,jj,inum,jnum;
+  double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+  tagint *bptr;
+  double *rptr;
+
+  if (natom) {
+    nevent++;
+    nevent_atom += natom;
+  }
+
+  // trigger neighbor list build
+
+  neighbor->build_one(list);
+
+  // identify bonds assigned to each owned atom
+  // do not create a bond between two non-group atoms
+
+  double **x = atom->x;
+  int *mask = atom->mask;
+
+  inum = list->inum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  nblocal = 0;
+
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+
+      // skip if neither atom I or J are in fix group
+
+      if (!(mask[i] & groupbit) && !(mask[j] & groupbit)) continue;
+
+      delx = xtmp - x[j][0];
+      dely = ytmp - x[j][1];
+      delz = ztmp - x[j][2];
+      rsq = delx*delx + dely*dely + delz*delz;
+
+      if (rsq < cutbondsq) {
+        if (nblocal == maxbond) grow_bond();
+        blist[nblocal].i = i;
+        blist[nblocal].j = j;
+        blist[nblocal].iold = i;
+        blist[nblocal].jold = j;
+        blist[nblocal].r0 = sqrt(rsq);
+        nblocal++;
+      }
+    }
+  }
+
+  // store IDs and coords for owned+ghost atoms at time of bond creation
+  // realloc xold and tagold as needed
+
+  if (atom->nmax > maxold) {
+    memory->destroy(xold);
+    memory->destroy(tagold);
+    maxold = atom->nmax;
+    memory->create(xold,maxold,3,"hyper/global:xold");
+    memory->create(tagold,maxold,"hyper/global:tagold");
+  }
+
+  tagint *tag = atom->tag;
+  int nall = atom->nlocal + atom->nghost;
+
+  for (i = 0; i < nall; i++) {
+    xold[i][0] = x[i][0];
+    xold[i][1] = x[i][1];
+    xold[i][2] = x[i][2];
+    tagold[i] = tag[i];
+  }
+}
+
+/* ----------------------------------------------------------------------
+   grow bond list by a chunk
+------------------------------------------------------------------------- */
+
+void FixHyperGlobal::grow_bond()
+{
+  // NOTE: could add int arg to do initial large alloc:
+  // maxbond = maxbond/DELTA * DELTA; maxbond += DELTA;
+
+  maxbond += DELTA;
+  if (maxbond < 0 || maxbond > MAXSMALLINT)
+    error->one(FLERR,"Fix hyper/local per-processor bond count is too big");
+  blist = (OneBond *) 
+    memory->srealloc(blist,maxbond*sizeof(OneBond),"hyper/local:blist");
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixHyperGlobal::compute_scalar()
+{
+  if (bcastflag) {
+    MPI_Bcast(outvec,VECLEN,MPI_DOUBLE,owner,world);
+    bcastflag = 0;
+  }
+  return outvec[0];
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixHyperGlobal::compute_vector(int i)
+{
+  if (bcastflag) {
+    MPI_Bcast(outvec,VECLEN,MPI_DOUBLE,owner,world);
+    bcastflag = 0;
+  }
+
+  // 11 vector outputs returned for i = 0-10
+
+  // i = 0 = boost factor on this step
+  // i = 1 = max strain of any bond on this step
+  // i = 2 = ID of atom I in max-strain bond on this step
+  // i = 3 = ID of atom J in max-strain bond on this step
+  // i = 4 = ave bonds/atom on this step
+
+  // i = 5 = fraction of steps with no bias during this run
+  // i = 6 = max drift of any atom during this run
+  // i = 7 = max bond length during this run
+
+  // i = 8 = cummulative hyper time since fix created
+  // i = 9 = cummulative # of event timesteps since fix created 
+  // i = 10 = cummulative # of atoms in events since fix created
+
+  if (i == 0) return outvec[1];
+  if (i == 1) return outvec[2];
+  if (i == 2) return outvec[3];
+  if (i == 3) return outvec[4];
+
+  if (i == 4) {
+    int allbonds;     // NOTE: bigint?
+    MPI_Allreduce(&nblocal,&allbonds,1,MPI_INT,MPI_SUM,world);
+    return 2.0*allbonds/atom->natoms;
+  }
+
+  if (i == 5) {
+    if (update->ntimestep == update->firststep) return 0.0;
+    int allnobias;
+    MPI_Allreduce(&nobias,&allnobias,1,MPI_INT,MPI_SUM,world);
+    return 1.0*allnobias / (update->ntimestep - update->firststep);
+  }
+
+  if (i == 6) {
+    double alldriftsq;
+    MPI_Allreduce(&maxdriftsq,&alldriftsq,1,MPI_DOUBLE,MPI_MAX,world);
+    return sqrt(alldriftsq);
+  }
+
+  if (i == 7) {
+    double allbondlen;
+    MPI_Allreduce(&maxbondlen,&allbondlen,1,MPI_DOUBLE,MPI_MAX,world);
+    return allbondlen;
+  }
+
+  if (i == 8) return t_hyper;
+  if (i == 9) return (double) nevent;
+  if (i == 10) return (double) nevent_atom;
+}
+
+/* ----------------------------------------------------------------------
+   wrapper on compute_vector()
+   used by hyper.cpp to call FixHyper
+------------------------------------------------------------------------- */
+
+double FixHyperGlobal::query(int i)
+{
+  if (i == 1) return compute_vector(8);  // cummulative hyper time
+  if (i == 2) return compute_vector(9);  // nevent
+  if (i == 3) return compute_vector(10); // nevent_atom 
+  if (i == 4) return compute_vector(4);  // ave bonds/atom
+  if (i == 5) return compute_vector(6);  // maxdrift
+  if (i == 6) return compute_vector(7);  // maxbondlen
+  if (i == 7) return compute_vector(5);  // fraction with zero bias
+
+  error->all(FLERR,"Invalid query to fix hyper/global");
+}
+
+/* ----------------------------------------------------------------------
+   memory usage of local atom-based arrays
+------------------------------------------------------------------------- */
+
+double FixHyperGlobal::memory_usage()
+{
+  double bytes = maxbond * sizeof(OneBond);    // blist
+  return bytes;
+}
diff --git a/src/REPLICA/fix_hyper_global.h b/src/REPLICA/fix_hyper_global.h
new file mode 100644
index 0000000000..d8b1cef425
--- /dev/null
+++ b/src/REPLICA/fix_hyper_global.h
@@ -0,0 +1,110 @@
+/* -*- c++ -*- ----------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifdef FIX_CLASS
+
+FixStyle(hyper/global,FixHyperGlobal)
+
+#else
+
+#ifndef LMP_FIX_HYPER_GLOBAL_H
+#define LMP_FIX_HYPER_GLOBAL_H
+
+#include "fix_hyper.h"
+
+namespace LAMMPS_NS {
+
+class FixHyperGlobal : public FixHyper {
+ public:
+  FixHyperGlobal(class LAMMPS *, int, char **);
+  ~FixHyperGlobal();
+  int setmask();
+  void init();
+  void init_list(int, class NeighList *);
+  void setup_pre_neighbor();
+  void setup_pre_reverse(int, int);
+  void pre_neighbor();
+  void pre_reverse(int, int);
+  double compute_scalar();
+  double compute_vector(int);
+  double query(int);
+
+  double memory_usage();
+
+  // extra methods visible to callers
+
+  void init_hyper();
+  void build_bond_list(int);
+
+ private:
+  int me;
+  double cutbond,qfactor,vmax,tequil;
+
+  int firstflag,bcastflag,owner,nevent,nevent_atom;
+  double cutbondsq,beta,dt,t_hyper,invqfactorsq;
+  double outvec[5];        // same as VECLEN in *.cpp
+  double maxbondlen;       // max length of any bond
+  double maxdriftsq;       // max distance any atom drifts from original pos
+  int nobias;              // # of steps when bias = 0, b/c bond too long
+
+  class NeighList *list;
+
+  // list of my owned bonds
+  // persists on a proc from one event until the next
+
+  int maxbond;                 // allocated size of blist
+
+  struct OneBond {             // single IJ bond, atom I is owner
+    int i,j;                   // current local indices of 2 bond atoms
+    int iold,jold;             // local indices when bonds were formed
+    double r0;                 // relaxed bond length
+  };
+
+  struct OneBond *blist;        // list of owned bonds
+  int nblocal;                  // # of owned bonds
+
+  // coords and IDs of owned+ghost atoms when bonds were formed
+  // persists on a proc from one event until the next
+
+  int maxold;                   // allocated size of old atoms
+
+  double **xold;                // coords of atoms when bonds were formed
+  tagint *tagold;               // IDs of atoms when bonds were formed
+
+  // MPI data struct for finding bond with max strain via Allreduce
+
+  struct Two {
+    double value;
+    int proc;
+  };
+  Two pairme,pairall;
+
+  // internal methods
+
+  void grow_bond();
+};
+
+}
+
+#endif
+#endif
+
+/* ERROR/WARNING messages:
+
+E: Illegal ... command
+
+Self-explanatory.  Check the input script syntax and compare to the
+documentation for the command.  You can use -echo screen as a
+command-line option when running LAMMPS to see the offending line.
+
+*/
diff --git a/src/REPLICA/fix_hyper_local.cpp b/src/REPLICA/fix_hyper_local.cpp
new file mode 100644
index 0000000000..b60ba7339f
--- /dev/null
+++ b/src/REPLICA/fix_hyper_local.cpp
@@ -0,0 +1,1610 @@
+/* ----------------------------------------------------------------------
+   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 Gene<ral Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include <mpi.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include "fix_hyper_local.h"
+#include "atom.h"
+#include "update.h"
+#include "force.h"
+#include "pair.h"
+#include "domain.h"
+#include "comm.h"
+#include "neighbor.h"
+#include "neigh_request.h"
+#include "neigh_list.h"
+#include "modify.h"
+#include "math_extra.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+using namespace FixConst;
+
+#define DELTABOOST 16
+#define BOOSTINIT 1.0
+#define COEFFMAX 1.2
+#define BIG 1.0e20
+
+enum{STRAIN,STRAINREGION,BIASFLAG};
+enum{IGNORE,WARN,ERROR};
+
+/* ---------------------------------------------------------------------- */
+
+FixHyperLocal::FixHyperLocal(LAMMPS *lmp, int narg, char **arg) :
+  FixHyper(lmp, narg, arg)
+{
+  // NOTE: add NULL declarations
+
+  // error checks
+  // solution for tagint != int is to worry about storing
+  //   local index vs global ID in same variable
+  //   maybe need to declare them all tagint, not int
+
+  if (atom->map_style == 0) 
+    error->all(FLERR,"Fix hyper/local command requires atom map");
+
+  if (sizeof(tagint) != sizeof(int))
+     error->all(FLERR,"Fix hyper/local requires tagint = int");
+
+  // parse args
+
+  if (narg < 10) error->all(FLERR,"Illegal fix hyper/local command");
+
+  hyperflag = 2;
+  scalar_flag = 1;
+  vector_flag = 1;
+  size_vector = 23;
+
+  global_freq = 1;
+  extscalar = 0;
+  extvector = 0;
+
+  cutbond = force->numeric(FLERR,arg[3]);
+  qfactor = force->numeric(FLERR,arg[4]);
+  vmax = force->numeric(FLERR,arg[5]);
+  tequil = force->numeric(FLERR,arg[6]);
+  dcut = force->numeric(FLERR,arg[7]);
+  alpha_user = force->numeric(FLERR,arg[8]);
+  boosttarget = force->numeric(FLERR,arg[9]);
+
+  if (cutbond < 0.0 || qfactor < 0.0 || vmax < 0.0 || 
+      tequil <= 0.0 || dcut <= 0.0 || alpha_user <= 0.0 || boosttarget < 1.0)
+    error->all(FLERR,"Illegal fix hyper/local command");
+
+  invqfactorsq = 1.0 / (qfactor*qfactor);
+  cutbondsq = cutbond*cutbond;
+  dcutsq = dcut*dcut;
+  beta = 1.0 / (force->boltz * tequil);
+
+  // optional args
+
+  histoflag = 0;
+  lostbond = IGNORE;
+  checkbias = 0;
+  checkcoeff = 0;
+
+  int iarg = 10;
+  while (iarg < narg) {
+    if (strcmp(arg[iarg],"histo") == 0) {
+      if (iarg+5 > narg) error->all(FLERR,"Illegal fix hyper/local command");
+      histoflag = 1;
+      histo_every = force->inumeric(FLERR,arg[iarg+1]);
+      histo_count = force->inumeric(FLERR,arg[iarg+2]);
+      histo_delta = force->numeric(FLERR,arg[iarg+3]);
+      histo_print = force->inumeric(FLERR,arg[iarg+4]);
+      if (histo_every <= 0 || histo_count % 2 || 
+          histo_delta <= 0.0 || histo_print <= 0)
+        error->all(FLERR,"Illegal fix hyper/local command");
+      iarg += 5;
+
+    } else if (strcmp(arg[iarg],"lostbond") == 0) {
+      if (iarg+2 > narg) error->all(FLERR,"Illegal fix hyper/local command");
+      if (strcmp(arg[iarg+1],"error") == 0) lostbond = ERROR;
+      else if (strcmp(arg[iarg+1],"warn") == 0) lostbond = WARN;
+      else if (strcmp(arg[iarg+1],"ignore") == 0) lostbond = IGNORE;
+      else error->all(FLERR,"Illegal fix hyper/local command");
+      iarg += 2;
+
+    } else if (strcmp(arg[iarg],"check/bias") == 0) {
+      if (iarg+3 > narg) error->all(FLERR,"Illegal fix hyper/local command");
+      checkbias = 1;
+      checkbias_every = force->inumeric(FLERR,arg[iarg+1]);
+      if (strcmp(arg[iarg+2],"error") == 0) checkbias_flag = ERROR;
+      else if (strcmp(arg[iarg+2],"warn") == 0) checkbias_flag = WARN;
+      else if (strcmp(arg[iarg+2],"ignore") == 0) checkbias_flag = IGNORE;
+      else error->all(FLERR,"Illegal fix hyper/local command");
+      iarg += 3;
+
+    } else if (strcmp(arg[iarg],"check/coeff") == 0) {
+      if (iarg+3 > narg) error->all(FLERR,"Illegal fix hyper/local command");
+      checkcoeff = 1;
+      checkcoeff_every = force->inumeric(FLERR,arg[iarg+1]);
+      if (strcmp(arg[iarg+2],"error") == 0) checkcoeff_flag = ERROR;
+      else if (strcmp(arg[iarg+2],"warn") == 0) checkcoeff_flag = WARN;
+      else if (strcmp(arg[iarg+2],"ignore") == 0) checkcoeff_flag = IGNORE;
+      else error->all(FLERR,"Illegal fix hyper/local command");
+      iarg += 3;
+
+    } else error->all(FLERR,"Illegal fix hyper/local command");
+  }
+
+  // per-atom data structs
+
+  maxbond = 0;
+  bonds = NULL;
+  numbond = NULL;
+  maxstrain = NULL;
+  maxstrain_region = NULL;
+  maxstrain_bondindex = NULL;
+  biasflag = NULL;
+
+  maxold = old_nall = 0;
+  old2now = NULL;
+  xold = NULL;      // NOTE: don't really need except to monitor drift
+  tagold = NULL;
+
+  nboost = maxboost = 0;
+  boost = NULL;
+
+  // maxbondperatom = max # of bonds any atom is part of
+  // will be reset in bond_build()
+  // set comm size needed by this fix
+
+  maxbondperatom = 1;
+  comm_forward = 1;
+  comm_reverse = 1;
+
+  // perform initial allocation of atom-based arrays
+  // register with Atom class
+
+  grow_arrays(atom->nmax);
+  atom->add_callback(0);
+
+  me = comm->me;
+  firstflag = 1;
+
+  allbonds = 0;
+  allboost = 0.0;
+
+  starttime = update->ntimestep;
+  nostrainyet = 1;
+  nnewbond = 0;
+  nevent = 0;
+  nevent_atom = 0;
+  mybias = 0.0;
+
+  histo = allhisto = NULL;
+  if (histoflag) {
+    invhisto_delta = 1.0 / histo_delta;
+    histo_lo = 1.0 - (histo_count/2 * histo_delta);
+    histo = new bigint[histo_count+2];
+    allhisto = new bigint[histo_count+2];
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+FixHyperLocal::~FixHyperLocal()
+{
+  memory->destroy(bonds);
+  memory->destroy(numbond);
+
+  memory->destroy(maxstrain);
+  memory->destroy(maxstrain_region);
+  memory->destroy(maxstrain_bondindex);
+  memory->destroy(biasflag);
+
+  memory->destroy(old2now);
+  memory->destroy(xold);
+  memory->destroy(tagold);
+  memory->destroy(boost);
+  delete [] histo;
+  delete [] allhisto;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixHyperLocal::setmask()
+{
+  int mask = 0;
+  mask |= PRE_NEIGHBOR;
+  mask |= PRE_REVERSE;
+  mask |= MIN_PRE_NEIGHBOR;
+  mask |= THERMO_ENERGY;
+  return mask;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::init_hyper()
+{
+  ghost_toofar = 0;
+  lostbond_partner = 0;
+  lostbond_coeff = 0.0;
+  checkbias_count = 0;
+  checkcoeff_count = 0;
+  maxdriftsq = 0.0;
+  maxbondlen = 0.0;
+  maxboostcoeff = 0.0;
+  minboostcoeff = BIG;
+  sumboostcoeff = 0.0;
+  nboost_running = 0;
+  nobias_running = 0;
+  rmaxever = 0.0;
+  rmaxeverbig = 0.0;
+
+  nbondbuild = 0;
+  time_bondbuild = 0.0;
+
+  if (histoflag) histo_steps = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::init()
+{
+  alpha = update->dt / alpha_user;
+
+  // cutghost = communication cutoff as calculated by Neighbor and Comm
+  // error if cutghost is smaller than Dcut
+  // warn if no drift distance added to cutghost
+
+  if (firstflag) {
+    double cutghost;            
+    if (force->pair) 
+      cutghost = MAX(force->pair->cutforce+neighbor->skin,comm->cutghostuser);
+    else 
+      cutghost = comm->cutghostuser;
+    
+    if (cutghost < dcut) 
+      error->all(FLERR,"Fix hyper/local bond cutoff exceeds ghost atom range - "
+                 "use comm_modify cutoff command");
+    if (cutghost < dcut+cutbond && me == 0) 
+      error->warning(FLERR,"Fix hyper/local ghost atom range "
+                     "may not allow for atom drift between events");
+  }
+
+  // NOTE: error if not newton,
+  //       since bond force bias will not be applied correctly to straddle bonds?
+
+  // NOTE: if exclusions are enabled, some near-neighbors won't appear
+  //       will be missed in bonds - WARN if molecular system?
+
+  // need an occasional full neighbor list with cutoff = Dcut
+  // do not need to include neigh skin in cutoff,
+  //   b/c this list will be built every time bond_build() is called
+  // NOTE: what if pair style list cutoff > Dcut
+  //   or what if neigh skin is huge?
+
+  int irequest = neighbor->request(this,instance_me);
+  neighbor->requests[irequest]->pair = 0;
+  neighbor->requests[irequest]->fix = 1;
+  neighbor->requests[irequest]->half = 0;
+  neighbor->requests[irequest]->full = 1;
+  neighbor->requests[irequest]->cut = 1;
+  neighbor->requests[irequest]->cutoff = dcut;
+  neighbor->requests[irequest]->occasional = 1;
+
+  // DEBUG timing output
+
+  timefirst = timesecond = timethird = timefourth = timefifth =
+    timesixth = timeseventh = timetotal = 0.0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::init_list(int id, NeighList *ptr)
+{
+  list = ptr;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::setup_pre_neighbor()
+{
+  // called for dynamics and minimization   NOTE: check if min is needed?
+
+  pre_neighbor();
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::setup_pre_reverse(int eflag, int vflag)
+{
+  // only called for dynamics, not minimization
+  // setupflag prevents boostostat update of boost coeffs in setup
+  // also prevents increments of nboost_running, nbias_running, sumboostcoeff
+
+  setupflag = 1;
+  pre_reverse(eflag,vflag);
+  setupflag = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::pre_neighbor()
+{
+  int i,m,n,ilocal,jlocal;
+
+  // convert global ID bond partners back to local indices
+  // need to use closest_image() so can calculate bond lengths
+  // error flag should not happen for a well-behaved system
+  // b/c are only looking up bond partners inside or near my sub-domain
+
+  double **x = atom->x;
+  int nlocal = atom->nlocal;
+
+  int missing = 0;
+  double missing_coeff = 0.0;
+
+  for (i = 0; i < nlocal; i++) {
+    n = numbond[i];
+    for (m = 0; m < n; m++) {
+      jlocal = atom->map(bonds[i][m].jtag);
+      if (jlocal >= 0) bonds[i][m].j = domain->closest_image(i,jlocal);
+      else {
+        bonds[i][m].j = -1;
+        missing++;
+        missing_coeff += bonds[i][m].boostcoeff;
+        if (lostbond != IGNORE) {
+          char str[128];
+          sprintf(str,"Fix hyper/local bond info missing for bond " 
+                  TAGINT_FORMAT "," TAGINT_FORMAT 
+                  " with coeff %g at step " BIGINT_FORMAT,
+                  atom->tag[i],bonds[i][m].jtag,bonds[i][m].boostcoeff,
+                  update->ntimestep);
+          if (lostbond == ERROR) error->one(FLERR,str);
+          if (lostbond == WARN) error->warning(FLERR,str);
+        }
+      }
+    }
+  }
+
+  lostbond_partner += missing;
+  lostbond_coeff += missing_coeff;
+
+  // set old2now to point to current local atom indices
+  // only necessary for tagold entries > 0
+  //   because if tagold = 0, atom is not active in Dcut neighbor list
+  // must be done after atoms migrate and ghost atoms setup via comm->borders()
+  // does not matter if there are multiple ghost copies of a global ID
+  //   since only need the ghost atom strain, not its coordinates
+  // NOTE: maybe need not use closest image, b/c old2now only used to access
+  //   maxstrain values, which will be same for any copy of ghost atom ??
+  //   also need it to compute maxdriftsq correctly when a proc spans a PBC
+
+  double distsq;
+
+  for (i = 0; i < old_nall; i++) {
+    if (tagold[i] == 0) continue;
+    ilocal = atom->map(tagold[i]);
+    ilocal = domain->closest_image(xold[i],ilocal);
+    old2now[i] = ilocal;
+
+    if (ilocal >= 0) {
+      distsq = MathExtra::distsq3(x[ilocal],xold[i]);
+      maxdriftsq = MAX(distsq,maxdriftsq);
+    } else ghost_toofar++;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::pre_reverse(int eflag, int vflag)
+{
+  int i,j,m,ii,jj,inum,jnum,iold,jold,nbond,bondindex;
+  tagint itag,jtag;
+  double xtmp,ytmp,ztmp,delx,dely,delz;
+  double r,r0,estrain,emax,vbias,fbias,fbiasr,boostcoeff;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+
+  //double time1,time2,time3,time4,time5,time6,time7,time8;
+  //time1 = MPI_Wtime();
+
+  // compute current maxstrain and maxstrain_bond for each owned atom
+  // use per-atom full bond list
+  // this is double-calculating for IJ and JI bonds
+  //   could compute once, but would have to find/store index of JI bond
+  // order two I,J atoms consistently for IJ and JI calcs
+  //   to insure no round-off issue when comparing maxstrain values of I,J
+
+  double **x = atom->x;
+  tagint *tag = atom->tag;
+  int nlocal = atom->nlocal;
+
+  int mybonds = 0;
+  nostrainyet = 0;
+
+  for (i = 0; i < nlocal; i++) {
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    itag = tag[i];
+    emax = 0.0;
+    bondindex = -1;
+    jtag = 0;
+
+    nbond = numbond[i];
+    mybonds += nbond;
+    for (m = 0; m < nbond; m++) {
+      j = bonds[i][m].j;
+      if (j < 0) continue;
+      jtag = bonds[i][m].jtag;
+      r0 = bonds[i][m].r0;
+      if (itag < jtag) {
+        delx = xtmp - x[j][0];
+        dely = ytmp - x[j][1];
+        delz = ztmp - x[j][2];
+      } else {
+        delx = x[j][0] - xtmp;
+        dely = x[j][1] - ytmp;
+        delz = x[j][2] - ztmp;;
+      }
+      r = sqrt(delx*delx + dely*dely + delz*delz);
+      maxbondlen = MAX(r,maxbondlen);
+      estrain = fabs(r-r0) / r0;
+      if (estrain > emax) {
+        emax = estrain;
+        bondindex = m;
+      }
+    }
+    maxstrain[i] = emax;
+    maxstrain_bondindex[i] = bondindex;
+  }
+
+  //time2 = MPI_Wtime();
+
+  // forward comm to acquire maxstrain of all ghost atoms
+
+  commflag = STRAIN;
+  comm->forward_comm_fix(this);
+
+  //time3 = MPI_Wtime();
+
+  // use original Dcut neighbor list to check maxstrain of all neighbor atoms
+  // set maxstrain_region of I atoms = maxstrain of I and all J neighs
+  // neighbor list has old indices for IJ b/c reneighboring may have occurred
+  //   use old2now[] to convert to current indices
+  // if neighbor is not currently known (too far away),
+  //   then assume it was part of an event and its strain = qfactor
+  // this double loop sets maxstrain_region of mostly owned atoms
+  //   but possibly some ghost atoms as well
+
+  int nall = nlocal + atom->nghost;
+  for (i = 0; i < nall; i++) maxstrain_region[i] = 0.0;
+
+  inum = list->inum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  // find largest distance from subbox that a ghost atom is with strain < qfactor
+
+  double rmax = rmaxever;
+  double rmaxbig = rmaxeverbig;
+  double *sublo = domain->sublo;
+  double *subhi = domain->subhi;
+
+  for (ii = 0; ii < inum; ii++) {
+    iold = ilist[ii];
+    jlist = firstneigh[iold];
+    jnum = numneigh[iold];
+
+    // I and J may be ghost atoms
+    // will always know I b/c atoms do not drift that far
+    // but may no longer know J if hops outside cutghost
+    // in that case, assume it performed an event, its strain = qfactor
+
+    i = old2now[iold];
+    emax = maxstrain[i];
+    
+    for (jj = 0; jj < jnum; jj++) {
+      jold = jlist[jj];
+      j = old2now[jold];
+      if (j >= 0) emax = MAX(emax,maxstrain[j]);
+      else {
+        emax = MAX(emax,qfactor);
+        continue;
+      }
+
+      // DEBUG - only good for 2 dims x,y
+
+      if (j >= nlocal) {
+        if (x[j][0] < sublo[0]) rmaxbig = MAX(rmaxbig,sublo[0]-x[j][0]);
+        if (x[j][1] < sublo[1]) rmaxbig = MAX(rmaxbig,sublo[1]-x[j][1]);
+        if (x[j][0] > subhi[0]) rmaxbig = MAX(rmaxbig,x[j][0]-subhi[0]);
+        if (x[j][1] > subhi[1]) rmaxbig = MAX(rmaxbig,x[j][1]-subhi[1]);
+        if (maxstrain[j] < qfactor) {
+          if (x[j][0] < sublo[0]) rmax = MAX(rmax,sublo[0]-x[j][0]);
+          if (x[j][1] < sublo[1]) rmax = MAX(rmax,sublo[1]-x[j][1]);
+          if (x[j][0] > subhi[0]) rmax = MAX(rmax,x[j][0]-subhi[0]);
+          if (x[j][1] > subhi[1]) rmax = MAX(rmax,x[j][1]-subhi[1]);
+        }
+      }
+    }
+
+    maxstrain_region[i] = emax;
+  }
+
+  double rmax2[2],rmax2all[2];
+  rmax2[0] = rmax;
+  rmax2[1] = rmaxbig;
+  MPI_Allreduce(&rmax2,&rmax2all,2,MPI_DOUBLE,MPI_MAX,world);
+  rmaxever = rmax2all[0];
+  rmaxeverbig = rmax2all[1];
+
+  MPI_Allreduce(&mybonds,&allbonds,1,MPI_INT,MPI_SUM,world);
+
+  //time4 = MPI_Wtime();
+
+  // reverse comm to acquire maxstrain_region from ghost atoms
+  // needed b/c neighbor list referred to old owned atoms,
+  //   so above loop may set maxstrain_region of ghost atoms
+  // forward comm to acquire maxstrain_region of all ghost atoms
+
+  commflag = STRAINREGION;
+  comm->reverse_comm_fix(this);
+  comm->forward_comm_fix(this);
+
+  //time5 = MPI_Wtime();
+
+  // identify biased bonds and add to boost list
+  // for each max-strain bond IJ of atom I:
+  //   bias this bond only if all these conditions hold:
+  //     itag < jtag, so bond is only biased once
+  //     maxstrain[i] = maxstrain_region[i]
+  //     maxstrain[j] = maxstrain_region[j]
+  // NOTE: also need to check that maxstrain[i] = maxstrain[j] ??
+  //       don't think so, b/c maxstrain_region[i] includes maxstrain[i]
+
+  nboost = 0;
+
+  for (i = 0; i < nlocal; i++) {
+    if (numbond[i] == 0) continue;
+    itag = tag[i];
+    j = bonds[i][maxstrain_bondindex[i]].j;
+    jtag = tag[j];
+    if (itag > jtag) continue;
+
+    if (maxstrain[i] != maxstrain_region[i]) continue;
+    if (maxstrain[j] != maxstrain_region[j]) continue;
+
+    if (nboost == maxboost) {
+      maxboost += DELTABOOST;
+      memory->grow(boost,maxboost,"hyper/local:boost");
+    }
+    boost[nboost++] = i;
+  }
+
+  //time6 = MPI_Wtime();
+
+  // apply boost force to bonds with locally max strain
+
+  double **f = atom->f;
+
+  int nobias = 0;
+  mybias = 0.0;
+
+  for (int iboost = 0; iboost < nboost; iboost++) {
+    i = boost[iboost];
+    emax = maxstrain[i];
+    if (emax >= qfactor) {
+      nobias++;
+      continue;
+    }
+
+    m = maxstrain_bondindex[i];
+    j = bonds[i][m].j;
+    r0 = bonds[i][m].r0;
+    boostcoeff = bonds[i][m].boostcoeff;
+
+    vbias = boostcoeff * vmax * (1.0 - emax*emax*invqfactorsq);
+    fbias = boostcoeff * 2.0 * vmax * emax / (qfactor*qfactor * r0);
+
+    delx = x[i][0] - x[j][0];
+    dely = x[i][1] - x[j][1];
+    delz = x[i][2] - x[j][2];
+    r = sqrt(delx*delx + dely*dely + delz*delz);
+    fbiasr = fbias / r;
+
+    f[i][0] += delx*fbiasr;
+    f[i][1] += dely*fbiasr;
+    f[i][2] += delz*fbiasr;
+
+    f[j][0] -= delx*fbiasr;
+    f[j][1] -= dely*fbiasr;
+    f[j][2] -= delz*fbiasr;
+
+    mybias += vbias;
+  }
+
+  //time7 = MPI_Wtime();
+
+  // no boostostat update of boost coeffs when pre_reverse called from setup()
+  // nboost_running, nobias_running, sumboostcoeff only incremented on run steps
+  // NOTE: maybe should also not bias any bonds on firststep of this fix
+
+  if (setupflag) return;
+  nboost_running += nboost;
+  nobias_running += nobias;
+
+  // apply boostostat to boost coefficients of all bonds of all owned atoms
+  // use per-atom full bond list
+  // this is double-calculating for IJ and JI bonds
+  //   should be identical for both, b/c emax is the same
+  //   could compute once, but would have to find/store index of JI bond
+  // delta in boost coeff is function of maxboost_region vs target boost
+  // maxboost_region is function of two maxstrain_regions for I,J
+  // NOTE: if J is lost to I but not vice versa, then biascoeff IJ != JI
+
+
+
+
+  // DEBUG info for Max and Min bias coeffs every step
+
+  //  if (update->ntimestep >= 300000) {
+  if (update->ntimestep >= 0) {
+
+    double emaxi,emaxj,maxboost_region;
+    double mincoeff = 1.0e20;
+    double maxcoeff = -1.0e20;
+    double delta;
+    double maxcoeffprev,deltamax,eimax,ejmax,emaximax,emaxjmax,mbrmax;
+    double mincoeffprev,deltamin,eimin,ejmin,emaximin,emaxjmin,mbrmin;
+    int itagmax,jtagmax,jtagmax2;
+    int itagmin,jtagmin,jtagmin2;
+
+    for (i = 0; i < nlocal; i++) {
+      emaxi = maxstrain_region[i];
+      nbond = numbond[i];
+      for (m = 0; m < nbond; m++) {
+        j = bonds[i][m].j;
+        if (j < 0) continue;
+        emaxj = maxstrain_region[j];
+        emax = MAX(emaxi,emaxj);
+        if (emax < qfactor) vbias = vmax * (1.0 - emax*emax*invqfactorsq);
+        else vbias = 0.0;
+        boostcoeff = bonds[i][m].boostcoeff;
+        maxboost_region = exp(beta * boostcoeff*vbias);
+        delta = -alpha * (maxboost_region-boosttarget) / boosttarget;
+        boostcoeff += delta;
+
+        if (boostcoeff > maxcoeff) {
+          maxcoeffprev = boostcoeff - delta;
+          maxcoeff = boostcoeff;
+          itagmax = tag[i];
+          jtagmax = tag[j];
+          jtagmax2 = bonds[i][m].jtag;
+          deltamax = delta;
+          eimax = maxstrain[i];
+          ejmax = maxstrain[j];
+          emaximax = emaxi;
+          emaxjmax = emaxj;
+          mbrmax = maxboost_region;
+        }
+
+        if (boostcoeff < mincoeff) {
+          mincoeffprev = boostcoeff - delta;
+          mincoeff = boostcoeff;
+          itagmin = tag[i];
+          jtagmin = tag[j];
+          jtagmin2 = bonds[i][m].jtag;
+          deltamin = delta;
+          eimin = maxstrain[i];
+          ejmin = maxstrain[j];
+          emaximin = emaxi;
+          emaxjmin = emaxj;
+          mbrmin = maxboost_region;
+        }
+      }
+    }
+
+    // min/max owner = procs that own the Min and Max bias coeffs
+
+    pairme.value = mincoeff;
+    pairme.proc = me;
+    MPI_Allreduce(&pairme,&pairall,1,MPI_DOUBLE_INT,MPI_MINLOC,world);
+    int minowner = pairall.proc;
+    
+    pairme.value = maxcoeff;
+    pairme.proc = me;
+    MPI_Allreduce(&pairme,&pairall,1,MPI_DOUBLE_INT,MPI_MAXLOC,world);
+    int maxowner = pairall.proc;
+  
+    // get info about which atom and bond influenced Max coeff
+    // querystrain = strain of bond that is influencing the max Cij
+    // inbondi,inbondj = ID of I,J atoms in the influence bond
+    // incoeff = bias coeff of influence bond
+    // inbias = 1/0 if inflence bond is biased or not on this step
+    // instraddle = 1/0 if influence bond straddles proc boundary or not
+
+    double querystrain;
+    if (maxowner == me) querystrain = MAX(emaximax,emaxjmax);
+    MPI_Bcast(&querystrain,1,MPI_DOUBLE,maxowner,world);
+
+    int count = 0;
+    for (i = 0; i < nlocal; i++) {
+      m = maxstrain_bondindex[i];
+      if (tag[i] > bonds[i][m].jtag) continue;
+      if (querystrain == maxstrain[i]) count++;
+    }
+
+    int countall;
+    MPI_Allreduce(&count,&countall,1,MPI_INT,MPI_SUM,world);
+
+    int inbias = 0;
+    int instraddle = countall;     // output in rare case countall != 1
+    tagint inbondi = 0;
+    tagint inbondj = 0;
+    double incoeff = 0.0;
+    
+    if (countall == 1) {
+      int procowner;
+      int proc = 0;
+      for (i = 0; i < nlocal; i++) {
+        m = maxstrain_bondindex[i];
+        if (tag[i] > bonds[i][m].jtag) continue;
+        if (querystrain == maxstrain[i]) {
+          proc = me;
+          inbondi = tag[i];
+          inbondj = bonds[i][m].jtag;
+          incoeff = bonds[i][m].boostcoeff;
+          instraddle = 0;
+          if (bonds[i][m].j >= nlocal) instraddle = 1;
+          inbias = 0;
+          for (int iboost = 0; iboost < nboost; iboost++)
+            if (boost[iboost] == i) inbias = 1;
+        }
+      }
+      
+      MPI_Allreduce(&proc,&procowner,1,MPI_INT,MPI_MAX,world);
+      MPI_Bcast(&inbondi,1,MPI_LMP_TAGINT,procowner,world);
+      MPI_Bcast(&inbondj,1,MPI_LMP_TAGINT,procowner,world);
+      MPI_Bcast(&incoeff,1,MPI_DOUBLE,procowner,world);
+      MPI_Bcast(&instraddle,1,MPI_INT,procowner,world);
+      MPI_Bcast(&inbias,1,MPI_INT,procowner,world);
+    }
+
+    // output by procs that own the Min and Max bias coeffs
+    
+    if (minowner == me) {
+      printf("MinCoeff %ld %d : %d %d %d : prev/delta/new %g %g %g : "
+             "Eij %g %g %g %g : BR %g\n",
+             update->ntimestep,comm->me,itagmin,jtagmin,jtagmin2,
+             mincoeffprev,deltamin,mincoeff,eimin,ejmin,emaximin,emaxjmin,mbrmin);
+    }
+    if (maxowner == me) {
+      printf("MaxCoeff %ld %d : %d %d %d : prev/delta/new %g %g %g : "
+             "Eij %g %g %g %g : Bond %d %d %g %d %d : BR %g\n",
+             update->ntimestep,comm->me,itagmax,jtagmax,jtagmax2,
+             maxcoeffprev,deltamax,maxcoeff,
+             eimax,ejmax,emaximax,emaxjmax,
+             inbondi,inbondj,incoeff,inbias,instraddle,mbrmax);
+    }
+  }
+
+  // end of DEBUG
+
+
+
+
+
+  double myboost = 0.0;
+  double emaxi,emaxj,maxboost_region;
+
+  for (i = 0; i < nlocal; i++) {
+    emaxi = maxstrain_region[i];
+    nbond = numbond[i];
+    for (m = 0; m < nbond; m++) {
+      j = bonds[i][m].j;
+      if (j < 0) continue;
+      emaxj = maxstrain_region[j];
+      emax = MAX(emaxi,emaxj);
+      if (emax < qfactor) vbias = vmax * (1.0 - emax*emax*invqfactorsq);
+      else vbias = 0.0;
+      boostcoeff = bonds[i][m].boostcoeff;
+      maxboost_region = exp(beta * boostcoeff*vbias);
+      boostcoeff -= alpha * (maxboost_region-boosttarget) / boosttarget;
+      // COMMENT OUT for now
+      //boostcoeff = MIN(boostcoeff,COEFFMAX);
+      myboost += boostcoeff;
+      maxboostcoeff = MAX(maxboostcoeff,boostcoeff);
+      minboostcoeff = MIN(minboostcoeff,boostcoeff);
+      bonds[i][m].boostcoeff = boostcoeff;
+    }
+  }
+
+  // running stats
+
+  MPI_Allreduce(&myboost,&allboost,1,MPI_DOUBLE,MPI_SUM,world);
+  if (allbonds) sumboostcoeff += allboost/allbonds;
+
+  // histogram the bond coeffs and output as requested
+  // do not double count each bond
+
+  if (histoflag && update->ntimestep % histo_every == 0) {
+    if (histo_steps == 0)
+      for (i = 0; i < histo_count+2; i++) histo[i] = 0;
+    histo_steps++;
+
+    int ihisto;
+    for (i = 0; i < nlocal; i++) {
+      nbond = numbond[i];
+      for (m = 0; m < nbond; m++) {
+        if (tag[i] > bonds[i][m].jtag) continue;
+        boostcoeff = bonds[i][m].boostcoeff;
+        if (boostcoeff < histo_lo) ihisto = -1;
+        else ihisto = static_cast<int> ((boostcoeff-histo_lo) * invhisto_delta);
+        if (ihisto >= histo_count) ihisto = histo_count;
+        histo[ihisto+1]++;
+      }
+    }
+
+    if (update->ntimestep % histo_print == 0) {
+      MPI_Allreduce(histo,allhisto,histo_count+2,MPI_LMP_BIGINT,MPI_SUM,world);
+
+      bigint total;
+      for (i = 0; i < histo_count+2; i++) total += allhisto[i];
+
+      if (me == 0) {
+        if (screen) {
+          fprintf(screen,"Histogram of bias coeffs:\n");
+          for (i = 0; i < histo_count+2; i++) 
+            fprintf(screen,"  %g",1.0*allhisto[i]/total);
+          fprintf(screen,"\n");
+        }
+        if (logfile) {
+          fprintf(logfile,"Histogram of bias coeffs:\n");
+          for (i = 0; i < histo_count+2; i++) 
+            fprintf(logfile,"  %g",1.0*allhisto[i]/total);
+          fprintf(logfile,"\n");
+        }
+      }
+    }
+  }
+
+  // check for any biased bonds that are too close to each other
+  // keep a running count for output
+
+  if (checkbias && update->ntimestep % checkbias_every == 0) {
+
+    // mark each atom in a biased bond with ID of partner
+    // nboost loop will mark some ghost atoms
+
+    for (i = 0; i < nall; i++) biasflag[i] = 0;
+
+    for (int iboost = 0; iboost < nboost; iboost++) {
+      i = boost[iboost];
+      m = maxstrain_bondindex[i];
+      j = bonds[i][m].j;
+      biasflag[i] = tag[j];
+      biasflag[j] = tag[i];
+    }
+
+    // reverse comm to acquire biasflag from ghost atoms
+    // needed b/c above loop may set biasflag of ghost atoms
+    // forward comm to acquire biasflag of all ghost atoms
+
+    commflag = BIASFLAG;
+    comm->reverse_comm_fix(this);
+    comm->forward_comm_fix(this);
+
+    // I and J may be ghost atoms
+    // only continue if I is a biased atom
+    // if J is unknonw (drifted ghost) just ignore
+    // if J is biased and is not bonded to I, then flag as too close
+
+    for (ii = 0; ii < inum; ii++) {
+      iold = ilist[ii];
+      i = old2now[iold];
+      if (biasflag[i] == 0) continue;
+
+      jlist = firstneigh[iold];
+      jnum = numneigh[iold];
+
+      for (jj = 0; jj < jnum; jj++) {
+        jold = jlist[jj];
+        j = old2now[jold];
+        if (j < 0) continue;
+        if (biasflag[j] && biasflag[j] != tag[i]) checkbias_count++;
+      }
+    }
+  }
+
+  // check for any bond bias coeffcients that do not match
+  // cannot check unless both atoms IJ are owned by this proc
+  // keep a running count for output
+
+  if (checkcoeff && update->ntimestep % checkcoeff_every == 0) {
+    int jb,jbonds;
+    double ibias,jbias;
+    
+    for (i = 0; i < nlocal; i++) {
+      nbond = numbond[i];
+      for (m = 0; m < nbond; m++) {
+        if (tag[i] > bonds[i][m].jtag) continue;
+        j = bonds[i][m].j;
+        if (j < 0) continue;
+        if (j >= nlocal) continue;
+        itag = tag[i];
+        jbonds = numbond[j];
+        for (jb = 0; jb < jbonds; jb++)
+          if (bonds[j][jb].jtag == itag) break;
+        if (jb == jbonds) 
+          error->one(FLERR,"Fix hyper/local could not find duplicate bond");
+        if (bonds[i][m].boostcoeff != bonds[j][jb].boostcoeff) 
+          checkcoeff_count++;
+      }
+    }
+  }
+
+  // DEBUG timing output
+  // examine these timings for new hyper/local before delete this code
+  // verify that boost cooefs stay in sync for 2 copies of each bond
+  //   before delete this code
+
+  /*
+  time8 = MPI_Wtime();
+
+  timefirst += time2-time1;
+  timesecond += time3-time2;
+  timethird += time4-time3;
+  timefourth += time5-time4;
+  timefifth += time6-time5;
+  timesixth += time7-time6;
+  timeseventh += time8-time7;
+  timetotal += time8-time1;
+
+  double bpera = compute_vector(6);
+  double nbperb = compute_vector(7);
+
+  if (update->ntimestep == 10000 && me == 0) {
+    printf("TIME First %g\n",timefirst);
+    printf("TIME Second %g\n",timesecond);
+    printf("TIME Third %g\n",timethird);
+    printf("TIME Fourth %g\n",timefourth);
+    printf("TIME Fifth %g\n",timefifth);
+    printf("TIME Sixth %g\n",timesixth);
+    printf("TIME Seventh %g\n",timeseventh);
+    printf("TIME Total %g\n",timetotal);
+    printf("Bonds/atom, neigh-bonds/bond %g %g\n",bpera,nbperb);
+    also print nbondbuild and tbondbuild
+  }
+  */
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::min_pre_neighbor()
+{
+  pre_neighbor();
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::build_bond_list(int natom)
+{
+  int i,j,ii,jj,m,n,inum,jnum,nbond;
+  tagint itag,jtag;
+  double xtmp,ytmp,ztmp,delx,dely,delz,rsq,oldcoeff;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+
+  double time1,time2;
+  time1 = MPI_Wtime();
+
+  if (natom) {
+    nevent++;
+    nevent_atom += natom;
+  }
+
+  // trigger Dcut neighbor list build
+  // NOTE: turn off special bonds in this Dcut neigh list?
+
+  neighbor->build_one(list);
+
+  // make copy of old bonds to preserve boostcoeffs for bonds that persist
+  // allocate new numbond
+
+  OneBond **old_bonds = bonds;
+  int *old_numbond = numbond;
+
+  int nmax = atom->nmax;
+  memory->create(numbond,nmax,"hyper/local:numbond");
+
+  // old_nall = value of nall at time bonds are built
+  // reallocate new xold and tagold if necessary
+  // initialize xold to current coords
+  // initialize tagold to zero, so atoms not in neighbor list will remain zero
+
+  old_nall = atom->nlocal + atom->nghost;
+
+  if (old_nall > maxold) {
+    memory->destroy(xold);
+    memory->destroy(tagold);
+    memory->destroy(old2now);
+    maxold = atom->nmax;
+    memory->create(xold,maxold,3,"hyper/local:xold");
+    memory->create(tagold,maxold,"hyper/local:tagold");
+    memory->create(old2now,maxold,"hyper/local:old2now");
+  }
+
+  double **x = atom->x;
+
+  memcpy(&xold[0][0],&x[0][0],3*old_nall*sizeof(double));
+  for (i = 0; i < old_nall; i++) tagold[i] = 0;
+
+  // create and populate new bonds data struct
+  // while loop allows maxbondperatom to increase once if necessary
+  //   don't know new maxbondperatom value until end of loop
+  // in practice maxbondperatom will hardly ever increase
+  //   since there is a physical max value
+
+  tagint *tag = atom->tag;
+  int *mask = atom->mask;
+  int nlocal = atom->nlocal;
+
+  inum = list->inum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+  
+  while (1) {
+    bonds = (OneBond **) memory->create(bonds,nmax,maxbondperatom,
+                                        "hyper/local:bonds");
+    if (bonds) memset(bonds[0],0,nmax*sizeof(OneBond));
+    for (i = 0; i < nlocal; i++) numbond[i] = 0;
+
+    // identify bonds assigned to each owned atom
+    // do not create a bond between two non-group atoms
+    // set tagold = global ID for all I,J atoms used in neighbor list
+    //   tagold remains 0 for unused atoms, skipped in pre_neighbor
+
+    int nbondmax = 0;
+
+    for (ii = 0; ii < inum; ii++) {
+      i = ilist[ii];
+      xtmp = x[i][0];
+      ytmp = x[i][1];
+      ztmp = x[i][2];
+      itag = tag[i];
+      tagold[i] = tag[i];
+      jlist = firstneigh[i];
+      jnum = numneigh[i];
+      nbond = 0;
+
+      for (jj = 0; jj < jnum; jj++) {
+        j = jlist[jj];
+        j &= NEIGHMASK;
+        jtag = tag[j];
+        tagold[j] = jtag;
+
+        // skip if neither atom I or J are in fix group
+        // order IJ to insure IJ and JI bonds are stored consistently
+
+        if (!(mask[i] & groupbit) && !(mask[j] & groupbit)) continue;
+
+        if (itag < jtag) {
+          delx = xtmp - x[j][0];
+          dely = ytmp - x[j][1];
+          delz = ztmp - x[j][2];
+        } else {
+          delx = x[j][0] - xtmp;
+          dely = x[j][1] - ytmp;
+          delz = x[j][2] - ztmp;
+        }
+
+        rsq = delx*delx + dely*dely + delz*delz;
+
+        // NOTE: could create two bonds for IJ both owned from one calc?
+        //       have to skip one of 2 bonds in that case
+
+        if (rsq < cutbondsq) {
+          if (nbond >= maxbondperatom) {
+            nbond++;
+            continue;
+          }
+          
+          bonds[i][nbond].r0 = sqrt(rsq);
+          bonds[i][nbond].jtag = tag[j];
+          bonds[i][nbond].j = j;
+
+          if (firstflag) oldcoeff = 0.0;
+          else {
+            oldcoeff = 0.0;
+            jtag = tag[j];
+            n = old_numbond[i];
+            for (m = 0; m < n; m++) {
+              if (old_bonds[i][m].jtag == jtag) {
+                oldcoeff = old_bonds[i][m].boostcoeff;
+                break;
+              }
+            }
+          }
+
+          if (oldcoeff > 0.0) bonds[i][nbond].boostcoeff = oldcoeff;
+          else {
+            bonds[i][nbond].boostcoeff = BOOSTINIT;
+            nnewbond++;
+          }
+          nbond++;
+        }
+      }
+      numbond[i] = nbond;
+      nbondmax = MAX(nbondmax,nbond);
+    }
+
+    // maxbondperatom must increase uniformly on all procs
+    // since bonds are comunicated when atoms migrate
+
+    int allnbondmax;
+    MPI_Allreduce(&nbondmax,&allnbondmax,1,MPI_INT,MPI_MAX,world);
+    if (allnbondmax <= maxbondperatom) break;
+
+    maxbondperatom = allnbondmax;
+    memory->destroy(bonds);
+  }
+
+  // deallocate old_bonds and old_numbond
+
+  memory->destroy(old_bonds);
+  memory->destroy(old_numbond);
+
+  time2 = MPI_Wtime();
+  if (firstflag) nnewbond = 0;
+  else {
+    time_bondbuild += time2-time1;
+    nbondbuild++;
+  }
+  firstflag = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixHyperLocal::pack_forward_comm(int n, int *list, double *buf, 
+                                     int pbc_flag, int *pbc)
+{
+  int i,j,k,m,ibond,nbond,start;
+
+  m = 0;
+
+  // STRAIN
+  // pack maxstrain vector
+
+  if (commflag == STRAIN) {
+    for (i = 0; i < n; i++) {
+      j = list[i];
+      buf[m++] = maxstrain[j];
+    }
+
+  // STRAINREGION
+  // pack maxstrain_region vector
+
+  } else if (commflag == STRAINREGION) {
+    for (i = 0; i < n; i++) {
+      j = list[i];
+      buf[m++] = maxstrain_region[j];
+    }
+
+  // BIASFLAG
+  // pack biasflag vector
+
+  } else if (commflag == BIASFLAG) {
+    for (i = 0; i < n; i++) {
+      j = list[i];
+      buf[m++] = ubuf(biasflag[j]).d;
+    }
+  }
+
+  return m;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::unpack_forward_comm(int n, int first, double *buf)
+{
+  int i,j,k,m,last,ibond,nbond,jlocal,flag;
+
+  m = 0;
+  last = first + n;
+
+  // STRAIN
+  // unpack maxstrain vector
+
+  if (commflag == STRAIN) {
+    for (i = first; i < last; i++) {
+      maxstrain[i] = buf[m++];
+    }
+
+  // STRAINREGION
+  // unpack maxstrain_region vector
+
+  } else if (commflag == STRAINREGION) {
+    for (i = first; i < last; i++) {
+      maxstrain_region[i] = buf[m++];
+    }
+
+  // BIASFLAG
+  // unpack biasflag vector
+
+  } else if (commflag == BIASFLAG) {
+    for (i = first; i < last; i++) {
+      biasflag[i] = (tagint) ubuf(buf[m++]).i;
+    }
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixHyperLocal::pack_reverse_comm(int n, int first, double *buf)
+{
+  int i,m,last;
+
+  m = 0;
+  last = first + n;
+
+  // STRAINREGION
+  // pack maxstrain_region vector
+
+  if (commflag == STRAINREGION) {
+    for (i = first; i < last; i++) {
+      buf[m++] = maxstrain_region[i];
+    }
+
+  // BIASFLAG
+  // pack biasflag vector
+
+  } else if (commflag == BIASFLAG) {
+    for (i = first; i < last; i++) {
+      buf[m++] = ubuf(biasflag[i]).d;
+    }
+  }
+
+  return m;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixHyperLocal::unpack_reverse_comm(int n, int *list, double *buf)
+{
+  int i,j,m;
+
+  m = 0;
+
+  // STRAINREGION
+  // unpack maxstrain_region vector
+
+  if (commflag == STRAINREGION) {
+    for (i = 0; i < n; i++) {
+      j = list[i];
+      maxstrain_region[j] += buf[m++];
+    }
+
+  // BIASFLAG
+  // unpack biasflag vector
+
+  } else if (commflag == BIASFLAG) {
+    for (i = 0; i < n; i++) {
+      j = list[i];
+      biasflag[j] = (tagint) ubuf(buf[m++]).i;
+    }
+  }
+}
+
+/* ----------------------------------------------------------------------
+   allocate atom-based arrays
+------------------------------------------------------------------------- */
+
+void FixHyperLocal::grow_arrays(int nmax)
+{
+  // NOTE: not all of these need to be Nmax in length, could allocate elsewhere
+
+  memory->grow(maxstrain,nmax,"hyper/local:maxstrain");
+  memory->grow(maxstrain_bondindex,nmax,"hyper/local:maxstrain_bondindex");
+  memory->grow(maxstrain_region,nmax,"hyper/local:maxstrain_region");
+  if (checkbias) memory->grow(biasflag,nmax,"hyper/local:biasflag");
+
+  memory->grow(numbond,nmax,"hyper/local:numbond");
+  memory->grow(bonds,nmax,maxbondperatom,"hyper/local:bonds");
+
+  // zero so valgrind does not complain about memcpy() in copy()
+  // also so loops in pre_neighbor() are OK before
+  //   bonds are setup for the first time
+
+  if (bonds) {
+    memset(bonds[maxbond],0,(nmax-maxbond)*maxbondperatom*sizeof(OneBond));
+    memset(&numbond[maxbond],0,(nmax-maxbond)*sizeof(int));
+    maxbond = nmax;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   copy values within local atom-based arrays
+------------------------------------------------------------------------- */
+
+void FixHyperLocal::copy_arrays(int i, int j, int delflag)
+{
+  // avoid valgrind copy-to-self warning
+
+  if (i != j) memcpy(bonds[j],bonds[i],numbond[i]*sizeof(OneBond));
+  numbond[j] = numbond[i];
+}
+
+/* ----------------------------------------------------------------------
+   pack values in local atom-based array for exchange with another proc
+------------------------------------------------------------------------- */
+
+int FixHyperLocal::pack_exchange(int i, double *buf)
+{
+  int m = 1;
+  int n = numbond[i];
+  buf[m++] = ubuf(n).d;
+  for (int j = 0; j < n; j++) {
+    buf[m++] = bonds[i][j].r0;
+    buf[m++] = bonds[i][j].boostcoeff;
+    buf[m++] = ubuf(bonds[i][j].jtag).d;
+    buf[m++] = ubuf(bonds[i][j].j).d;
+  }
+
+  buf[0] = m;
+  return m;
+}
+
+/* ----------------------------------------------------------------------
+   unpack values in local atom-based array from exchange with another proc
+------------------------------------------------------------------------- */
+
+int FixHyperLocal::unpack_exchange(int nlocal, double *buf)
+{
+  int m = 1;
+  int n = numbond[nlocal] = (int) ubuf(buf[m++]).i;
+  for (int j = 0; j < n; j++) {
+    bonds[nlocal][j].r0 = buf[m++];
+    bonds[nlocal][j].boostcoeff = buf[m++];
+    bonds[nlocal][j].jtag = (tagint) ubuf(buf[m++]).i;
+    bonds[nlocal][j].j = (int) ubuf(buf[m++]).i;
+  }
+
+  return m;
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixHyperLocal::compute_scalar()
+{
+  double allbias;
+  MPI_Allreduce(&mybias,&allbias,1,MPI_DOUBLE,MPI_SUM,world);
+  return allbias;
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixHyperLocal::compute_vector(int i)
+{
+  // 23 vector outputs returned for i = 0-22
+
+  // i = 0 = # of boosted bonds on this step
+  // i = 1 = max strain of any bond on this step
+  // i = 2 = average bias potential for all bonds on this step
+  // i = 3 = ave bonds/atom on this step
+  // i = 4 = ave neighbor bonds/bond on this step
+
+  // i = 5 = fraction of steps and bonds with no bias during this run
+  // i = 6 = max drift distance of any atom during this run
+  // i = 7 = max bond length during this run
+  // i = 8 = average # of boosted bonds/step during this run
+  // i = 9 = average bias potential for all bonds during this run
+  // i = 10 = max bias potential for any bond during this run
+  // i = 11 = min bias potential for any bond during this run
+  // i = 12 = max dist from my box of any ghost atom with 
+  //          maxstain < qfactor during this run
+  // i = 13 = max dist from my box of any ghost atom with
+  //          any maxstrain during this run
+  // i = 14 = count of ghost atoms that could not be found
+  //          by any proc at any reneighbor step during this run
+  // i = 15 = count of lost bond partners during this run
+  // i = 16 = average bias coeff for lost bond partners during this run
+  // i = 17 = count of bias overlaps found during this run
+  // i = 18 = count of non-matching bias coefficients found during this run
+
+  // i = 19 = cummulative hyper time
+  // i = 20 = cummulative # of event timesteps since fix created 
+  // i = 21 = cummulative # of atoms in events since fix created
+  // i = 22 = cummulative # of new bonds formed since fix created
+
+  if (i == 0) {
+    int nboostall;
+    MPI_Allreduce(&nboost,&nboostall,1,MPI_INT,MPI_SUM,world);
+    return (double) nboostall;
+  }
+
+  if (i == 1) {
+    if (nostrainyet) return 0.0;
+    int nlocal = atom->nlocal;
+    double emax = 0.0;
+    for (int j = 0; j < nlocal; j++)
+      emax = MAX(emax,maxstrain[j]);
+    double eall;
+    MPI_Allreduce(&emax,&eall,1,MPI_DOUBLE,MPI_MAX,world);
+    return eall;
+  }
+
+  if (i == 2) {
+    if (allboost && allbonds) return allboost/allbonds * vmax;
+    return 1.0;
+  }
+
+  if (i == 3) return 1.0*allbonds/atom->natoms;
+
+  if (i == 4) {
+    int nlocal = atom->nlocal;
+    int nbonds = 0;   // BIGINT?
+    for (int j = 0; j < nlocal; j++)
+      nbonds += numbond[j];
+    int allbonds;
+    MPI_Allreduce(&nbonds,&allbonds,1,MPI_INT,MPI_SUM,world);
+    int allneigh;   // BIGINT?
+    MPI_Allreduce(&list->ipage->ndatum,&allneigh,1,MPI_INT,MPI_SUM,world);
+    double neighsperatom = allneigh/atom->natoms; 
+    double bondsperatom = 0.5*allbonds/atom->natoms;
+    return neighsperatom * bondsperatom;
+  }
+
+  if (i == 5) {
+    int allboost_running,allnobias_running;
+    MPI_Allreduce(&nboost_running,&allboost_running,1,MPI_INT,MPI_SUM,world);
+    MPI_Allreduce(&nobias_running,&allnobias_running,1,MPI_INT,MPI_SUM,world);
+    if (allboost_running) return 1.0*allnobias_running / allboost_running;
+    return 0.0;
+  }
+
+  if (i == 6) {
+    double alldriftsq;
+    MPI_Allreduce(&maxdriftsq,&alldriftsq,1,MPI_DOUBLE,MPI_MAX,world);
+    return (double) sqrt(alldriftsq);
+  }
+
+  if (i == 7) {
+    double allbondlen;
+    MPI_Allreduce(&maxbondlen,&allbondlen,1,MPI_DOUBLE,MPI_MAX,world);
+    return allbondlen;
+  }
+
+  if (i == 8) {
+    if (update->ntimestep == update->firststep) return 0.0;
+    int allboost_running;
+    MPI_Allreduce(&nboost_running,&allboost_running,1,MPI_INT,MPI_SUM,world);
+    return 1.0*allboost_running / (update->ntimestep - update->firststep);
+  }
+
+  if (i == 9) {
+    if (update->ntimestep == update->firststep) return 0.0;
+    return sumboostcoeff * vmax / (update->ntimestep - update->firststep);
+  }
+
+  if (i == 10) {
+    double allboostcoeff;
+    MPI_Allreduce(&maxboostcoeff,&allboostcoeff,1,MPI_DOUBLE,MPI_MAX,world);
+    return allboostcoeff * vmax;
+  }
+
+  if (i == 11) {
+    double allboostcoeff;
+    MPI_Allreduce(&minboostcoeff,&allboostcoeff,1,MPI_DOUBLE,MPI_MAX,world);
+    return allboostcoeff * vmax;
+  }
+
+  if (i == 12) return rmaxever;
+  if (i == 13) return rmaxeverbig;
+
+  if (i == 14) {
+    int allghost_toofar;
+    MPI_Allreduce(&ghost_toofar,&allghost_toofar,1,MPI_INT,MPI_SUM,world);
+    return 1.0*allghost_toofar;
+  }
+
+  if (i == 15) {
+    int alllost;
+    MPI_Allreduce(&lostbond_partner,&alllost,1,MPI_INT,MPI_SUM,world);
+    return 1.0*alllost;
+  }
+
+  if (i == 16) {
+    int alllost;
+    MPI_Allreduce(&lostbond_partner,&alllost,1,MPI_INT,MPI_SUM,world);
+    double allcoeff;
+    MPI_Allreduce(&lostbond_coeff,&allcoeff,1,MPI_DOUBLE,MPI_SUM,world);
+    if (alllost == 0) return 0;
+    return allcoeff/alllost;
+  }
+
+  if (i == 17) {
+    int allclose;
+    MPI_Allreduce(&checkbias_count,&allclose,1,MPI_INT,MPI_SUM,world);
+    return 1.0*allclose;
+  }
+
+  if (i == 18) {
+    int allcoeff;
+    MPI_Allreduce(&checkcoeff_count,&allcoeff,1,MPI_INT,MPI_SUM,world);
+    return 1.0*allcoeff;
+  }
+
+  if (i == 19) {
+    return boosttarget * update->dt * (update->ntimestep - starttime);
+  }
+
+  if (i == 20) return (double) nevent;
+  if (i == 21) return (double) nevent_atom;
+
+  if (i == 22) {
+    int allnew;
+    MPI_Allreduce(&nnewbond,&allnew,1,MPI_INT,MPI_SUM,world);
+    return (double) 0.5*allnew;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   wrapper on compute_vector()
+   used by hyper.cpp to call FixHyper
+------------------------------------------------------------------------- */
+
+double FixHyperLocal::query(int i)
+{
+  if (i == 1) return compute_vector(19);  // cummulative hyper time
+  if (i == 2) return compute_vector(20);  // nevent
+  if (i == 3) return compute_vector(21);  // nevent_atom 
+  if (i == 4) return compute_vector(3);   // ave bonds/atom
+  if (i == 5) return compute_vector(6);   // maxdrift
+  if (i == 6) return compute_vector(7);   // maxbondlen
+  if (i == 7) return compute_vector(5);   // fraction with zero bias
+
+  // unique to local hyper
+
+  if (i == 8) return compute_vector(22);   // number of new bonds
+  if (i == 9) return 1.0*maxbondperatom;   // max bonds/atom
+  if (i == 10) return compute_vector(8);   // ave # of boosted bonds/step
+  if (i == 11) return compute_vector(9);   // ave boost coeff over all bonds
+  if (i == 12) return compute_vector(10);  // max boost cooef for any bond
+  if (i == 13) return compute_vector(11);  // max boost cooef for any bond
+  if (i == 14) return compute_vector(4);   // neighbor bonds/bond
+  if (i == 15) return compute_vector(2);   // ave boost cooef now
+  if (i == 16) return time_bondbuild;      // CPU time for bond_build calls
+  if (i == 17) return rmaxever;            // ghost atom distance for < maxstrain
+  if (i == 18) return rmaxeverbig;         // ghost atom distance for any strain
+  if (i == 19) return compute_vector(14);  // count of ghost atoms not found
+  if (i == 20) return compute_vector(15);  // count of lost bond partners
+  if (i == 21) return compute_vector(16);  // ave bias coeff of long bonds
+  if (i == 22) return compute_vector(17);  // count of bias overlaps
+  if (i == 23) return compute_vector(18);  // count of non-matching bias coeffs
+
+  error->all(FLERR,"Invalid query to fix hyper/local");
+}
+
+/* ----------------------------------------------------------------------
+   memory usage of per-atom and per-bond arrays
+------------------------------------------------------------------------- */
+
+double FixHyperLocal::memory_usage()
+{
+  int nmax = atom->nmax;
+  double bytes = 2*nmax * sizeof(int);     // numbond, maxstrain_bondindex
+  bytes = 2*nmax * sizeof(double);         // maxstrain, maxstrain_region
+  bytes += maxbondperatom*nmax * sizeof(OneBond);      // bonds
+  bytes += 3*maxold * sizeof(double);      // xold
+  bytes += maxold * sizeof(tagint);        // tagold
+  bytes += maxold * sizeof(int);           // old2now
+  return bytes;
+}
diff --git a/src/REPLICA/fix_hyper_local.h b/src/REPLICA/fix_hyper_local.h
new file mode 100644
index 0000000000..5150386929
--- /dev/null
+++ b/src/REPLICA/fix_hyper_local.h
@@ -0,0 +1,175 @@
+/* -*- c++ -*- ----------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifdef FIX_CLASS
+
+FixStyle(hyper/local,FixHyperLocal)
+
+#else
+
+#ifndef LMP_FIX_HYPER_LOCAL_H
+#define LMP_FIX_HYPER_LOCAL_H
+
+#include "fix_hyper.h"
+
+namespace LAMMPS_NS {
+
+class FixHyperLocal : public FixHyper {
+ public:
+  FixHyperLocal(class LAMMPS *, int, char **);
+  ~FixHyperLocal();
+  int setmask();
+  void init();
+  void init_list(int, class NeighList *);
+  void setup_pre_neighbor();
+  void setup_pre_reverse(int, int);
+  void pre_neighbor();
+  void pre_reverse(int, int);
+  void min_pre_neighbor();
+  double compute_scalar();
+  double compute_vector(int);
+  double query(int);
+
+  int pack_forward_comm(int, int *, double *, int, int *);
+  void unpack_forward_comm(int, int, double *);
+  int pack_reverse_comm(int, int, double *);
+  void unpack_reverse_comm(int, int *, double *);
+
+  void grow_arrays(int);
+  void copy_arrays(int, int, int);
+  int pack_exchange(int, double *);
+  int unpack_exchange(int, double *);
+
+  double memory_usage();
+
+  // extra methods visible to callers
+
+  void init_hyper();
+  void build_bond_list(int);
+
+ private:
+  int me;
+  double cutbond,qfactor,vmax,tequil,dcut;
+  double alpha_user;         // timescale to apply boostostat (time units)
+  double alpha;              // unitless dt/alpha_user
+  double boosttarget;        // target value of boost
+  int histoflag;
+  int lostbond,lostbond_partner;
+  double lostbond_coeff;
+  int checkbias,checkbias_every,checkbias_flag,checkbias_count;
+  int checkcoeff,checkcoeff_every,checkcoeff_flag,checkcoeff_count;
+
+  int setupflag;             // 1 during setup, 0 during run
+  int firstflag;             // set for first time bond_build takes place
+  int nostrainyet;           // 1 until maxstrain is first computed
+
+  int nboost_running,nobias_running;
+  int nbondbuild;
+  double time_bondbuild;
+  bigint starttime;
+  double sumboostcoeff;  // sum of aveboost at every timestep
+  int allbonds;          // sum of bond count on this step
+  double allboost;       // sum of boostcoeff on all bonds on this step
+
+  int nnewbond;              // running tally of number of new bonds created
+  int maxbondperatom;        // max # of bonds any atom ever has        
+  int commflag;              // flag for communication mode
+  int nevent;                // # of events that trigger bond rebuild
+  int nevent_atom;           // # of atoms that experienced an event
+  double cutbondsq,dcutsq;
+  double beta,t_hyper,invqfactorsq;
+  double mybias;
+  double maxbondlen;         // cummulative max length of any bond
+  double maxdriftsq;         // max distance any atom drifts from original pos
+  double maxboostcoeff;      // cummulative max boost coeff for any bond
+  double minboostcoeff;      // cummulative min boost coeff for any bond
+  double rmaxever,rmaxeverbig;
+  int ghost_toofar;
+
+  double timefirst,timesecond,timethird,timefourth;
+  double timefifth,timesixth,timeseventh,timetotal;
+
+  // data structs for per-atom and per-bond info
+  // all of these are for current owned and ghost atoms
+  // except list and old2now are for atom indices at time of last bond build
+
+  class NeighList *list;       // full neigh list up to Dcut distance
+                               // created only when bonds are rebuilt
+
+  int *old2now;                // o2n[i] = current local index of old atom i
+                               //   stored for old owned and ghost atoms
+                               //   I = old index when bonds were last created
+                               //   old indices are stored in old neighbor list
+
+  double **xold;               // coords of owned+ghost atoms when bonds created
+  tagint *tagold;              // global IDs of owned+ghost atoms when b created
+             
+  int maxold;                  // allocated size of old2now
+  int maxbond;                 // allocated size of bonds
+  int old_nall;                // nlocal+nghost when old2now was last setup
+
+  struct OneBond {             // single IJ bond, atom I is owner
+    double r0;                 // original relaxed bond length
+    double boostcoeff;         // boost coefficient
+    tagint jtag;               // global index of J atom in bond IJ
+    int j;                     // local index of J atom in bond IJ
+  };
+
+  struct OneBond **bonds;      // 2d array of bonds for owned atoms
+  int *numbond;                // number of bonds for each owned atom
+
+  double *maxstrain;           // max-strain of any bond atom I is part of
+                               //   for owned and ghost atoms
+  double *maxstrain_region;    // max-strain of any neighbor atom J of atom I
+                               //   for owned and ghost atoms
+  int *maxstrain_bondindex;    // index of max-strain bond of each atom I
+                               //   just for owned atoms
+  tagint *biasflag;            // atoms in biased bonds marked with bond partner
+                               //   for owned and ghost atoms
+
+  // list of boosted bonds that this proc will bias
+
+  int maxboost;                // allocated size of boost list
+  int nboost;                  // # of boosted bonds I own
+  int *boost;                  // index of atom I in each boosted bond
+
+  // histogramming of bond boost cooeficients
+
+  int histo_flag,histo_every,histo_count,histo_print,histo_steps;
+  double histo_delta,invhisto_delta,histo_lo;
+  bigint *histo,*allhisto;
+
+  // DEBUG: MPI data struct for finding min/max bias coeffs via Allreduce
+
+  struct Two {
+    double value;
+    int proc;
+  };
+  Two pairme,pairall;
+
+};
+
+}
+
+#endif
+#endif
+
+/* ERROR/WARNING messages:
+
+E: Illegal ... command
+
+Self-explanatory.  Check the input script syntax and compare to the
+documentation for the command.  You can use -echo screen as a
+command-line option when running LAMMPS to see the offending line.
+
+*/
diff --git a/src/REPLICA/hyper.cpp b/src/REPLICA/hyper.cpp
new file mode 100644
index 0000000000..0449943215
--- /dev/null
+++ b/src/REPLICA/hyper.cpp
@@ -0,0 +1,548 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "hyper.h"
+#include "update.h"
+#include "atom.h"
+#include "domain.h"
+#include "region.h"
+#include "integrate.h"
+#include "min.h"
+#include "force.h"
+#include "neighbor.h"
+#include "modify.h"
+#include "compute_event_displace.h"
+#include "fix_hyper.h"
+#include "fix_event_hyper.h"
+#include "output.h"
+#include "dump.h"
+#include "finish.h"
+#include "timer.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+enum{NOHYPER,GLOBAL,LOCAL};
+
+/* ---------------------------------------------------------------------- */
+
+Hyper::Hyper(LAMMPS *lmp) : Pointers(lmp) {}
+
+/* ----------------------------------------------------------------------
+   perform hyperdynamics simulation
+------------------------------------------------------------------------- */
+
+void Hyper::command(int narg, char **arg)
+{
+  MPI_Comm_rank(world,&me);
+  MPI_Comm_size(world,&nprocs);
+
+  // error checks
+
+  if (domain->box_exist == 0)
+    error->all(FLERR,"Hyper command before simulation box is defined");
+
+  if (narg < 4) error->all(FLERR,"Illegal hyper command");
+
+  int nsteps = force->inumeric(FLERR,arg[0]);
+  t_event = force->inumeric(FLERR,arg[1]);
+
+  char *id_fix = new char[strlen(arg[2])+1];
+  strcpy(id_fix,arg[2]);
+
+  char *id_compute = new char[strlen(arg[3])+1];
+  strcpy(id_compute,arg[3]);
+
+  options(narg-4,&arg[4]);
+
+  // total # of timesteps must be multiple of t_event
+
+  if (t_event <= 0) 
+    error->all(FLERR,"Invalid t_event in hyper command");
+  if (nsteps % t_event)
+    error->all(FLERR,"Hyper nsteps must be multiple of t_event");
+  if (rebond < 0)
+    error->all(FLERR,"Invalid rebond in hyper command");
+  if (rebond && rebond % t_event)
+    error->all(FLERR,"Hyper rebond must be multiple of t_event");
+
+  // FixHyper class performs global or local hyperdynamics
+
+  int hyperenable,hyperstyle;
+
+  if (strcmp(id_fix,"NULL") == 0) {
+    hyperenable = 0;
+    hyperstyle = NOHYPER;
+  } else {
+    int ifix = modify->find_fix(id_fix);
+    if (ifix < 0) error->all(FLERR,"Could not find fix ID for hyper");
+    fix_hyper = (FixHyper *) modify->fix[ifix];
+    int dim;
+    int *hyperflag = (int *) fix_hyper->extract("hyperflag",dim);
+    if (hyperflag == NULL || *hyperflag == 0)
+      error->all(FLERR,"Hyper fix is not a valid hyperdynamics fix");
+    if (*hyperflag == 1) hyperstyle = GLOBAL;
+    if (*hyperflag == 2) hyperstyle = LOCAL;
+    hyperenable = 1;
+  }
+
+  // create FixEventHyper class to store event and pre-quench states
+
+  char **args = new char*[3];
+  args[0] = (char *) "hyper_event";
+  args[1] = (char *) "all";
+  args[2] = (char *) "EVENT/HYPER";
+  modify->add_fix(3,args);
+  fix_event = (FixEventHyper *) modify->fix[modify->nfix-1];
+  delete [] args;
+
+  // create Finish for timing output
+
+  finish = new Finish(lmp);
+
+  // assign FixEventHyper 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 hyper");
+  compute_event = (ComputeEventDisplace *) modify->compute[icompute];
+  compute_event->reset_extra_compute_fix("hyper_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 hyper");
+  }
+
+  neighbor->every = 1;
+  neighbor->delay = 0;
+  neighbor->dist_check = 1;
+
+  // initialize hyper 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;
+  if (update->laststep < 0)
+    error->all(FLERR,"Too many timesteps");
+
+  lmp->init();
+
+  // init minimizer settings and minimizer itself
+
+  update->etol = etol;
+  update->ftol = ftol;
+  update->max_eval = maxeval;
+
+  // cannot use hyper with a changing box
+  // removing this restriction would require saving/restoring box params
+
+  if (domain->box_change)
+    error->all(FLERR,"Cannot use hyper with a changing box");
+
+  // cannot use hyper with time-dependent fixes or regions
+
+  for (int i = 0; i < modify->nfix; i++)
+    if (modify->fix[i]->time_depend)
+      error->all(FLERR,"Cannot use hyper 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 hyper with a time-dependent region defined");
+
+  // perform hyperdynamics simulation
+
+  timer->init();
+  timer->barrier_start();
+  time_start = timer->get_wall(Timer::TOTAL);
+
+  nbuild = ndanger = 0;
+  time_dynamics = time_quench = 0.0;
+  double clock = 0.0;
+
+  if (hyperenable) fix_hyper->init_hyper();
+
+  timer->barrier_start();
+  time_start = timer->get_wall(Timer::TOTAL);
+
+  // perform initial minimization and bond list creation
+
+  int nevent = 0;
+  int nevent_atoms = 0;
+
+  fix_event->store_state_quench();
+  quench(1);
+  if (dumpflag)
+    for (int idump = 0; idump < ndump; idump++)
+      output->dump[dumplist[idump]]->write();
+  fix_event->store_event();
+  if (hyperenable) fix_hyper->build_bond_list(0);
+  fix_event->restore_state_quench();
+
+  // main loop: dynamics, store state, quench, check event, restore state
+
+  int ecount;
+  int istep = 0;
+
+  while (istep < nsteps) {
+    dynamics(t_event,time_dynamics);
+    fix_event->store_state_quench();
+    quench(0);
+    
+    ecount = compute_event->all_events();
+
+    if (ecount) {
+      nevent++;
+      nevent_atoms += ecount;
+
+      if (dumpflag)
+        for (int idump = 0; idump < ndump; idump++)
+          output->dump[dumplist[idump]]->write();
+      fix_event->store_event();
+      if (hyperenable) fix_hyper->build_bond_list(ecount);
+
+    } else if (rebond && update->ntimestep % rebond == 0) {
+      fix_event->store_event();
+      if (hyperenable) fix_hyper->build_bond_list(ecount);
+    }
+    
+    fix_event->restore_state_quench();
+
+    // NOTE: replace clock with hypertime
+    //clock = clock + t_event*universe->nworlds;
+    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::DYNAMICS,time_dynamics);
+  timer->set_wall(Timer::QUENCH,time_quench);
+
+  neighbor->ncalls = nbuild;
+  neighbor->ndanger = ndanger;
+
+  update->nsteps = nsteps;
+
+  if (me == 0) {
+    if (screen) fprintf(screen,"Final hyper stats ...\n\n");
+    if (logfile) fprintf(logfile,"Final hyper stats ...\n\n");
+  }
+
+  // subset of quantities also available in fix hyper output
+
+  int nevent_running = 0;
+  int nevent_atoms_running = 0;
+  double t_hyper = 0.0;
+  double avebonds = 0.0;
+  double maxdrift = 0.0;
+  double maxbondlen = 0.0;
+  double fraczero = 1.0;
+
+  double nnewbond,avenboost,aveboostcoeff,maxboostcoeff,minboostcoeff;
+  double maxbondperatom,neighbondperbond,aveboostnow;
+  double tbondbuild,rmaxever,rmaxeverbig,allghost_toofar;
+  double lostbond,lostbondcoeff,biasoverlap,nonmatchbiascoeff;
+
+  if (hyperenable) {
+    t_hyper = fix_hyper->query(1);
+    nevent_running = fix_hyper->query(2);
+    nevent_atoms_running = fix_hyper->query(3);
+    avebonds = fix_hyper->query(4);
+    maxdrift = fix_hyper->query(5);
+    maxbondlen = fix_hyper->query(6);
+    fraczero = fix_hyper->query(7);
+
+    if (hyperstyle == LOCAL) {
+      nnewbond = fix_hyper->query(8);
+      maxbondperatom = fix_hyper->query(9);
+      avenboost = fix_hyper->query(10);
+      aveboostcoeff = fix_hyper->query(11);
+      maxboostcoeff = fix_hyper->query(12);
+      minboostcoeff = fix_hyper->query(13);
+      neighbondperbond = fix_hyper->query(14);
+      aveboostnow = fix_hyper->query(15);
+      tbondbuild = fix_hyper->query(16);
+      rmaxever = fix_hyper->query(17);
+      rmaxeverbig = fix_hyper->query(18);
+      allghost_toofar = fix_hyper->query(19);
+      lostbond = fix_hyper->query(20);
+      lostbondcoeff = fix_hyper->query(21);
+      biasoverlap = fix_hyper->query(22);
+      nonmatchbiascoeff = fix_hyper->query(23);
+    }
+  }
+
+  if (me == 0) {
+    if (screen) {
+      fprintf(screen,"Cummulative quantities for fix hyper:\n");
+      fprintf(screen,"  hyper time = %g\n",t_hyper);
+      fprintf(screen,"  event timesteps = %d\n",nevent_running);
+      fprintf(screen,"  # of atoms in events = %d\n",nevent_atoms_running);
+      fprintf(screen,"Quantities for this hyper run:\n");
+      fprintf(screen,"  event timesteps = %d\n",nevent);
+      fprintf(screen,"  # of atoms in events = %d\n",nevent_atoms);
+      fprintf(screen,"  max length of any bond = %g\n",maxbondlen);
+      fprintf(screen,"  max drift distance of any atom = %g\n",maxdrift);
+      fprintf(screen,"  fraction of steps & bonds with zero bias = %g\n",
+              fraczero);
+      fprintf(screen,"Current quantities:\n");
+      fprintf(screen,"  ave bonds/atom = %g\n",avebonds);
+
+      if (hyperstyle == LOCAL) {
+        fprintf(screen,"Cummulative quantities specific to fix hyper/local:\n");
+        fprintf(screen,"  # of new bonds formed = %g\n",nnewbond);
+        fprintf(screen,"  max bonds/atom = %g\n",maxbondperatom);
+        fprintf(screen,"Quantities for this hyper run specific to "
+                "fix hyper/local:\n");
+        fprintf(screen,"  ave boosted bonds/step = %g\n",avenboost);
+        fprintf(screen,"  ave boost coeff of all bonds = %g\n",aveboostcoeff);
+        fprintf(screen,"  max boost coeff of any bond = %g\n",maxboostcoeff);
+        fprintf(screen,"  min boost coeff of any bond = %g\n",minboostcoeff);
+        fprintf(screen,"  max dist from my box of any "
+                "non-maxstrain bond ghost atom = %g\n",rmaxever);
+        fprintf(screen,"  max dist from my box of any bond ghost atom = %g\n",
+                rmaxeverbig);
+        fprintf(screen,"  count of bond ghost neighbors "
+                "not found on reneighbor steps = %g\n",allghost_toofar);
+        fprintf(screen,"  lost bond partners = %g\n",lostbond);
+        fprintf(screen,"  ave bias coeff for lost bond partners = %g\n",
+                lostbondcoeff);
+        fprintf(screen,"  bias overlaps = %g\n",biasoverlap);
+        fprintf(screen,"  non-matching bias coeffs = %g\n",nonmatchbiascoeff);
+        fprintf(screen,"  CPU time for bond builds = %g\n",tbondbuild);
+        fprintf(screen,"Current quantities specific to fix hyper/local:\n");
+        fprintf(screen,"  neighbor bonds/bond = %g\n",neighbondperbond);
+        fprintf(screen,"  ave boost coeff for all bonds = %g\n",aveboostnow);
+      }
+      fprintf(screen,"\n");
+    }
+
+    if (logfile) {
+      fprintf(logfile,"Cummulative quantities for fix hyper:\n");
+      fprintf(logfile,"  hyper time = %g\n",t_hyper);
+      fprintf(logfile,"  event timesteps = %d\n",nevent_running);
+      fprintf(logfile,"  # of atoms in events = %d\n",nevent_atoms_running);
+      fprintf(logfile,"Quantities for this hyper run:\n");
+      fprintf(logfile,"  event timesteps = %d\n",nevent);
+      fprintf(logfile,"  # of atoms in events = %d\n",nevent_atoms);
+      fprintf(logfile,"  max length of any bond = %g\n",maxbondlen);
+      fprintf(logfile,"  max drift distance of any atom = %g\n",maxdrift);
+      fprintf(logfile,"  fraction of steps & bonds with zero bias = %g\n",
+              fraczero);
+      fprintf(logfile,"Current quantities:\n");
+      fprintf(logfile,"  ave bonds/atom = %g\n",avebonds);
+
+      if (hyperstyle == LOCAL) {
+        fprintf(logfile,"Cummulative quantities specific tofix hyper/local:\n");
+        fprintf(logfile,"  # of new bonds formed = %g\n",nnewbond);
+        fprintf(logfile,"  max bonds/atom = %g\n",maxbondperatom);
+        fprintf(logfile,"Quantities for this hyper run specific to "
+                "fix hyper/local:\n");
+        fprintf(logfile,"  ave boosted bonds/step = %g\n",avenboost);
+        fprintf(logfile,"  ave boost coeff of all bonds = %g\n",aveboostcoeff);
+        fprintf(logfile,"  max boost coeff of any bond = %g\n",maxboostcoeff);
+        fprintf(logfile,"  min boost coeff of any bond = %g\n",minboostcoeff);
+        fprintf(logfile,"  max dist from my box of any "
+                "non-maxstrain bond ghost atom = %g\n",rmaxever);
+        fprintf(logfile,"  max dist from my box of any bond ghost atom = %g\n",
+                rmaxeverbig);
+        fprintf(logfile,"  count of ghost bond neighbors "
+                "not found on reneighbor steps = %g\n",allghost_toofar);
+        fprintf(logfile,"  lost bond partners = %g\n",lostbond);
+        fprintf(logfile,"  ave bias coeff for lost bond partners = %g\n",
+                lostbondcoeff);
+        fprintf(logfile,"  bias overlaps = %g\n",biasoverlap);
+        fprintf(logfile,"  non-matching bias coeffs = %g\n",nonmatchbiascoeff);
+        fprintf(logfile,"  CPU time for bond builds = %g\n",tbondbuild);
+        fprintf(logfile,"Current quantities specific to fix hyper/local:\n");
+        fprintf(logfile,"  neighbor bonds/bond = %g\n",neighbondperbond);
+        fprintf(logfile,"  ave boost coeff for all bonds = %g\n",aveboostnow);
+      }
+      fprintf(logfile,"\n");
+    }
+  }
+
+  // timing stats
+
+  finish->end(4);
+
+  update->whichflag = 0;
+  update->firststep = update->laststep = 0;
+  update->beginstep = update->endstep = 0;
+
+  // reset reneighboring criteria
+
+  neighbor->every = neigh_every;
+  neighbor->delay = neigh_delay;
+  neighbor->dist_check = neigh_dist_check;
+
+  delete [] id_fix;
+  delete [] id_compute;
+  memory->destroy(dumplist);
+  delete finish;
+  modify->delete_fix("hyper_event");
+
+  compute_event->reset_extra_compute_fix(NULL);
+}
+
+/* ----------------------------------------------------------------------
+   short dynamics run
+------------------------------------------------------------------------- */
+
+void Hyper::dynamics(int nsteps, double &time_category)
+{
+  update->whichflag = 1;
+  update->nsteps = nsteps;
+
+  // full init works
+  // need to try partial init or setup
+
+  lmp->init();
+  update->integrate->setup(0);
+  // 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_dynamics += timer->get_wall(Timer::TOTAL);
+
+  nbuild += neighbor->ncalls - ncalls;
+  ndanger += neighbor->ndanger;
+
+  update->integrate->cleanup();
+  finish->end(0);
+}
+
+/* ----------------------------------------------------------------------
+   quench minimization
+   flag = 1 to trigger output of memory in setup() call
+------------------------------------------------------------------------- */
+
+void Hyper::quench(int flag)
+{
+  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)
+    error->all(FLERR,"Too many iterations");
+  update->restrict_output = 1;
+
+  // full init works
+
+  lmp->init();
+  update->minimize->setup(flag);
+
+  // partial init does not work
+
+  //modify->addstep_compute_all(update->ntimestep);
+  //update->minimize->setup_minimal(1);
+
+  // NOTE: what doing with ncalls?
+  int ncalls = neighbor->ncalls;
+
+  timer->barrier_start();
+  update->minimize->run(maxiter);
+  timer->barrier_stop();
+  time_quench += timer->get_wall(Timer::TOTAL);
+
+  update->minimize->cleanup();
+  finish->end(0);
+
+  // reset timestep as if quench did not occur
+  // clear timestep storage from computes, since now invalid
+
+  update->restrict_output = 0;
+  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();
+}
+
+/* ----------------------------------------------------------------------
+   parse optional parameters at end of hyper input line
+------------------------------------------------------------------------- */
+
+void Hyper::options(int narg, char **arg)
+{
+  // set defaults
+
+  etol = 1.0e-4;
+  ftol = 1.0e-4;
+  maxiter = 40;
+  maxeval = 50;
+  stepmode = 0;
+  dumpflag = 0;
+  ndump = 0;
+  dumplist = NULL;
+  rebond = 0;
+
+  int iarg = 0;
+  while (iarg < narg) {
+    if (strcmp(arg[iarg],"min") == 0) {
+      if (iarg+5 > narg) error->all(FLERR,"Illegal hyper 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 hyper command");
+      iarg += 5;
+
+    } else if (strcmp(arg[iarg],"time") == 0) {
+      if (iarg+2 > narg) error->all(FLERR,"Illegal hyper 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 hyper command");
+      iarg += 2;
+
+    } else if (strcmp(arg[iarg],"dump") == 0) {
+      if (iarg+2 > narg) error->all(FLERR,"Illegal hyper command");
+      dumpflag = 1;
+      int idump = output->find_dump(arg[iarg+1]);
+      if (idump < 0) 
+        error->all(FLERR,"Dump ID in hyper command does not exist");
+      memory->grow(dumplist,ndump+1,"hyper:dumplist");
+      dumplist[ndump++] = idump;
+      iarg += 2;
+
+    } else if (strcmp(arg[iarg],"rebond") == 0) {
+      if (iarg+2 > narg) error->all(FLERR,"Illegal hyper command");
+      rebond = force->inumeric(FLERR,arg[iarg+1]);
+      iarg += 2;
+
+    } else error->all(FLERR,"Illegal hyper command");
+  }
+}
diff --git a/src/REPLICA/hyper.h b/src/REPLICA/hyper.h
new file mode 100644
index 0000000000..1b05172bcf
--- /dev/null
+++ b/src/REPLICA/hyper.h
@@ -0,0 +1,65 @@
+/* -*- c++ -*- ----------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifdef COMMAND_CLASS
+
+CommandStyle(hyper,Hyper)
+
+#else
+
+#ifndef LMP_HYPER_H
+#define LMP_HYPER_H
+
+#include "pointers.h"
+
+namespace LAMMPS_NS {
+
+class Hyper : protected Pointers {
+ public:
+  Hyper(class LAMMPS *);
+  ~Hyper() {}
+  void command(int, char **);
+
+ private:
+  int me,nprocs;
+  int t_event;
+  double etol,ftol;
+  int maxiter,maxeval;
+  int stepmode,dumpflag,ndump,rebond;
+  int *dumplist;
+
+  int neigh_every,neigh_delay,neigh_dist_check;
+  int quench_reneighbor;
+  bigint nbuild,ndanger;
+
+  double time_dynamics,time_quench;
+  double time_start;
+
+  class FixHyper *fix_hyper;
+  class FixEventHyper *fix_event;
+  class ComputeEventDisplace *compute_event;
+  class Finish *finish;
+
+  void dynamics(int, double &);
+  void quench(int flag);
+  void options(int, char **);
+};
+
+}
+
+#endif
+#endif
+
+/* ERROR/WARNING messages:
+
+*/
-- 
GitLab