diff --git a/src/fix_heat.cpp b/src/fix_heat.cpp
index 46934f96e..af173115e 100644
--- a/src/fix_heat.cpp
+++ b/src/fix_heat.cpp
@@ -1,194 +1,259 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 /* ----------------------------------------------------------------------
    Contributing author: Paul Crozier (SNL)
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "stdlib.h"
 #include "string.h"
 #include "fix_heat.h"
 #include "atom.h"
 #include "domain.h"
 #include "region.h"
 #include "group.h"
 #include "force.h"
 #include "update.h"
 #include "modify.h"
 #include "input.h"
 #include "variable.h"
+#include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 using namespace FixConst;
 
-enum{CONSTANT,EQUAL};
+enum{CONSTANT,EQUAL,ATOM};
 
 /* ---------------------------------------------------------------------- */
 
 FixHeat::FixHeat(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
 {
   if (narg < 4) error->all(FLERR,"Illegal fix heat command");
 
   scalar_flag = 1;
   global_freq = 1;
   extscalar = 0;
 
   nevery = atoi(arg[3]);
   if (nevery <= 0) error->all(FLERR,"Illegal fix heat command");
 
   hstr = NULL;
 
   if (strstr(arg[4],"v_") == arg[4]) {
     int n = strlen(&arg[4][2]) + 1;
     hstr = new char[n];
     strcpy(hstr,&arg[4][2]);
-    hstyle = EQUAL;
   } else {
     heat_input = atof(arg[4]);
     hstyle = CONSTANT;
   }
 
   // optional args
 
   iregion = -1;
   idregion = NULL;
 
   int iarg = 5;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"region") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal fix heat command");
       iregion = domain->find_region(arg[iarg+1]);
       if (iregion == -1)
         error->all(FLERR,"Region ID for fix heat does not exist");
       int n = strlen(arg[iarg+1]) + 1;
       idregion = new char[n];
       strcpy(idregion,arg[iarg+1]);
       iarg += 2;
     } else error->all(FLERR,"Illegal fix heat command");
   }
 
   scale = 1.0;
+
+  maxatom = 0;
+  vheat = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 FixHeat::~FixHeat()
 {
   delete [] hstr;
   delete [] idregion;
+  memory->destroy(vheat);
 }
 
 /* ---------------------------------------------------------------------- */
 
 int FixHeat::setmask()
 {
   int mask = 0;
   mask |= END_OF_STEP;
   return mask;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void FixHeat::init()
 {
   // set index and check validity of region
 
   if (iregion >= 0) {
     iregion = domain->find_region(idregion);
     if (iregion == -1)
       error->all(FLERR,"Region ID for fix heat does not exist");
   }
 
   // check variable
 
   if (hstr) {
     hvar = input->variable->find(hstr);
     if (hvar < 0) 
       error->all(FLERR,"Variable name for fix heat does not exist");
-    if (!input->variable->equalstyle(hvar))
-      error->all(FLERR,"Variable for fix heat is invalid style");
+    if (input->variable->equalstyle(hvar)) hstyle = EQUAL;
+    else if (input->variable->equalstyle(hvar)) hstyle = ATOM;
+    else error->all(FLERR,"Variable for fix heat is invalid style");
   }
 
   // cannot have 0 atoms in group
 
   if (group->count(igroup) == 0)
     error->all(FLERR,"Fix heat group has no atoms");
   masstotal = group->mass(igroup);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void FixHeat::end_of_step()
 {
+  int i;
   double heat,ke;
   double vsub[3],vcm[3];
-  Region *region = NULL;
-  if (iregion >= 0) region = domain->regions[iregion];
+  Region *region;
+
+  double **x = atom->x;
+  double **v = atom->v;
+  int *mask = atom->mask;
+  int nlocal = atom->nlocal;
 
-  if (hstyle == EQUAL) {
+  // reallocate vheat array if necessary
+
+  if (hstyle == ATOM && atom->nlocal > maxatom) {
+    maxatom = atom->nmax;
+    memory->destroy(vheat);
+    memory->create(vheat,maxatom,"heat:vheat");
+  }
+
+  if (hstyle != CONSTANT) {
     modify->clearstep_compute();
-    heat_input = input->variable->compute_equal(hvar);
+
+    if (hstyle == EQUAL) heat_input = input->variable->compute_equal(hvar);
+    else {
+      input->variable->compute_atom(hvar,igroup,vheat,1,0);
+
+      double mine = 0.0;
+      if (iregion < 0) {
+        for (i = 0; i < nlocal; i++)
+          if (mask[i] & groupbit) mine += vheat[i];
+      } else {
+        region = domain->regions[iregion];
+        for (i = 0; i < nlocal; i++)
+          if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
+            mine += vheat[i];
+      }
+      MPI_Allreduce(&mine,&heat_input,1,MPI_DOUBLE,MPI_SUM,world);
+    }
+
     modify->addstep_compute(update->ntimestep + nevery);
   }
 
+  // vcm = center-of-mass velocity of scaled atoms
+  // scale = velocity scale factor to accomplish eflux change in energy
+  // vsub = ???  // NOTE: document this?
+
   if (iregion < 0) {
     heat = heat_input*nevery*update->dt*force->ftm2v;
     ke = group->ke(igroup)*force->ftm2v;
     group->vcm(igroup,masstotal,vcm);
   } else {
     masstotal = group->mass(igroup,iregion);
     if (masstotal == 0.0) error->all(FLERR,"Fix heat group has no atoms");
     heat = heat_input*nevery*update->dt*force->ftm2v;
     ke = group->ke(igroup,iregion)*force->ftm2v;
     group->vcm(igroup,masstotal,vcm,iregion);
   }
 
   double vcmsq = vcm[0]*vcm[0] + vcm[1]*vcm[1] + vcm[2]*vcm[2];
   double escale = (ke + heat - 0.5*vcmsq*masstotal)/(ke - 0.5*vcmsq*masstotal);
   if (escale < 0.0) error->all(FLERR,"Fix heat kinetic energy went negative");
   scale = sqrt(escale);
 
+  // NOTE: if hstyle = ATOM, do something different to compute vsub ??
+
   vsub[0] = (scale-1.0) * vcm[0];
   vsub[1] = (scale-1.0) * vcm[1];
   vsub[2] = (scale-1.0) * vcm[2];
 
-  double **x = atom->x;
-  double **v = atom->v;
-  int *mask = atom->mask;
-  int nlocal = atom->nlocal;
-
-  if (iregion < 0) {
-    for (int i = 0; i < nlocal; i++)
-      if (mask[i] & groupbit) {
-        v[i][0] = scale*v[i][0] - vsub[0];
-        v[i][1] = scale*v[i][1] - vsub[1];
-        v[i][2] = scale*v[i][2] - vsub[2];
-      }
+  // add heat via scale factor on velocities for CONSTANT and EQUAL cases
+
+  if (hstyle != ATOM) {
+    if (iregion < 0) {
+      for (i = 0; i < nlocal; i++)
+        if (mask[i] & groupbit) {
+          v[i][0] = scale*v[i][0] - vsub[0];
+          v[i][1] = scale*v[i][1] - vsub[1];
+          v[i][2] = scale*v[i][2] - vsub[2];
+        }
+    } else {
+      region = domain->regions[iregion];
+      for (int i = 0; i < nlocal; i++)
+        if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
+          v[i][0] = scale*v[i][0] - vsub[0];
+          v[i][1] = scale*v[i][1] - vsub[1];
+          v[i][2] = scale*v[i][2] - vsub[2];
+        }
+    }
+
+  // add heat via per-atom scale factor on velocities for ATOM case
+    
   } else {
-    for (int i = 0; i < nlocal; i++)
-      if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
-        v[i][0] = scale*v[i][0] - vsub[0];
-        v[i][1] = scale*v[i][1] - vsub[1];
-        v[i][2] = scale*v[i][2] - vsub[2];
-      }
+    if (iregion < 0) {
+      for (i = 0; i < nlocal; i++)
+        if (mask[i] & groupbit) {
+          scale = 0.0;   // NOTE: set to per-atom value
+          v[i][0] = scale*v[i][0] - vsub[0];
+          v[i][1] = scale*v[i][1] - vsub[1];
+          v[i][2] = scale*v[i][2] - vsub[2];
+        }
+    } else {
+      region = domain->regions[iregion];
+      for (int i = 0; i < nlocal; i++)
+        if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
+          scale = 0.0;   // NOTE: set to per-atom value
+          v[i][0] = scale*v[i][0] - vsub[0];
+          v[i][1] = scale*v[i][1] - vsub[1];
+          v[i][2] = scale*v[i][2] - vsub[2];
+        }
+    }
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 double FixHeat::compute_scalar()
 {
+  // NOTE: what should this be for per-atom case?
+
   return scale;
 }
diff --git a/src/fix_heat.h b/src/fix_heat.h
index 4562ac9a9..35884704f 100644
--- a/src/fix_heat.h
+++ b/src/fix_heat.h
@@ -1,72 +1,75 @@
 /* ----------------------------------------------------------------------
    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(heat,FixHeat)
 
 #else
 
 #ifndef LMP_FIX_HEAT_H
 #define LMP_FIX_HEAT_H
 
 #include "fix.h"
 
 namespace LAMMPS_NS {
 
 class FixHeat : public Fix {
  public:
   FixHeat(class LAMMPS *, int, char **);
   ~FixHeat();
   int setmask();
   void init();
   void end_of_step();
   double compute_scalar();
 
  private:
   int iregion;
   double heat_input;
   double masstotal;
   double scale;
   char *idregion;
   char *hstr;
   int hstyle,hvar;
+
+  int maxatom;
+  double *vheat;
 };
 
 }
 
 #endif
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 E: Region ID for fix heat does not exist
 
 Self-explanatory.
 
 E: Fix heat group has no atoms
 
 Self-explanatory.
 
 E: Fix heat kinetic energy went negative
 
 This will cause the velocity rescaling about to be performed by fix
 heat to be invalid.
 
 */