diff --git a/lib/atc/ATC_Coupling.cpp b/lib/atc/ATC_Coupling.cpp
index b60063883..b02158418 100644
--- a/lib/atc/ATC_Coupling.cpp
+++ b/lib/atc/ATC_Coupling.cpp
@@ -1,2160 +1,2358 @@
 // ATC headers
 #include "ATC_Coupling.h"
 #include "FE_Engine.h"
 #include "Array.h"
 #include "Array2D.h"
 #include "ATC_Error.h"
 #include "PrescribedDataManager.h"
 #include "AtomicRegulator.h"
 #include "TimeIntegrator.h"
 #include "PhysicsModel.h"
 #include "AtomToMoleculeTransfer.h"
 #include "MoleculeSet.h"
 #include "FieldManager.h"
 
 using std::string;
 using std::map;
 using std::pair;
 using std::set;
+using std::ifstream;
+using std::stringstream;
+using ATC_Utility::is_numeric;
+using ATC_Utility::to_string;
 
 namespace ATC {
   //--------------------------------------------------
   ATC_Coupling::ATC_Coupling(string groupName, double ** & perAtomArray, LAMMPS_NS::Fix * thisFix) :
     ATC_Method(groupName, perAtomArray, thisFix),
     consistentInitialization_(false),
     equilibriumStart_(false),
     useFeMdMassMatrix_(false),
     trackCharge_(false),
     temperatureDef_(NONE),
     prescribedDataMgr_(NULL),
     physicsModel_(NULL),
     extrinsicModelManager_(this),
     atomicRegulator_(NULL),
     atomQuadForInternal_(true),
     elementMask_(NULL),
     elementMaskMass_(NULL),
     elementMaskMassMd_(NULL),
     nodalAtomicMass_(NULL),
     nodalAtomicCount_(NULL),
     nodalAtomicHeatCapacity_(NULL),
     internalToMask_(NULL),
     internalElement_(NULL),
     ghostElement_(NULL),
     nodalGeometryType_(NULL),
     bndyIntType_(NO_QUADRATURE),
     bndyFaceSet_(NULL),
     atomicWeightsMask_(NULL),
     shpFcnMask_(NULL),
     shpFcnDerivsMask_(NULL),
     sourceIntegration_(FULL_DOMAIN)
   {
     // size the field mask
     fieldMask_.reset(NUM_FIELDS,NUM_FLUX); 
     fieldMask_ = false;
     // default: no consistent mass matrices
     useConsistentMassMatrix_.reset(NUM_FIELDS);
     useConsistentMassMatrix_ = false;
     mdMassNormalization_ = true;
     // check to see if lammps has any charges
     if (lammpsInterface_->atom_charge()) trackCharge_ = true;
     // default: perform velocity verlet
     integrateInternalAtoms_ = true;
   }
   //--------------------------------------------------
   ATC_Coupling::~ATC_Coupling()
   {
     interscaleManager_.clear(); 
     if (feEngine_) { delete feEngine_; feEngine_ = NULL; } 
     if (physicsModel_) delete physicsModel_;
     if (atomicRegulator_) delete atomicRegulator_;
     if (prescribedDataMgr_) delete prescribedDataMgr_;
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       delete _tiIt_->second;
     }
   }
   //--------------------------------------------------
   // Interactions with LAMMPS fix commands
   // parse input command and pass on to finite element engine 
   //   or physics specific transfers if necessary
   //   revert to physics-specific transfer if no command matches input
   // first keyword is unique to particular class
   // base class keyword matching must apply to ALL physics
   // order:  derived, base, owned objects
   //--------------------------------------------------
   bool ATC_Coupling::modify(int narg, char **arg)
   {
     FieldName thisField;
     int thisIndex;
     int argIdx=0;
 
     bool match = false; 
     
     // gateways to other modules e.g. extrinsic, control, mesh
     // pass off to extrinsic
     if (strcmp(arg[argIdx],"extrinsic")==0) {
       argIdx++;
       match = extrinsicModelManager_.modify(narg-argIdx,&arg[argIdx]);
     }
     // catch special case
     if ((strcmp(arg[argIdx],"control")==0)
       &&(strcmp(arg[argIdx+1],"charge")==0)) {
       match = extrinsicModelManager_.modify(narg-argIdx,&arg[argIdx]);
     }
     // parsing handled here
     else {
       /*! \page man_initial fix_modify AtC initial 
         \section syntax
         fix_modify AtC initial <field> <nodeset> <constant | function>
         - <field> = field name valid for type of physics, temperature | electron_temperature
         - <nodeset> = name of set of nodes to apply initial condition
         - <constant | function> = value or name of function followed by its
           parameters
         \section examples
         <TT> fix_modify atc initial temperature groupNAME 10. </TT>
         \section description
         Sets the initial values for the specified field at the specified nodes.
         \section restrictions
         keyword 'all' reserved in nodeset name
         \section default 
         none
       */
       // set initial conditions
       if (strcmp(arg[argIdx],"initial")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string nsetName(arg[argIdx++]);
         XT_Function * f = NULL;
         // parse constant
         if (narg == argIdx+1) {
           f = XT_Function_Mgr::instance()->constant_function(atof(arg[argIdx]));
         }
         // parse function
         else {
           f = XT_Function_Mgr::instance()->function(&(arg[argIdx]),narg-argIdx);
         }
         prescribedDataMgr_->fix_initial_field(nsetName,thisField,thisIndex,f);
         match = true;
       }
 
       /*! \page man_fix_nodes fix_modify AtC fix 
         \section syntax
-        fix_modify AtC fix <field> <nodeset> <constant | function>
+        fix_modify AtC fix <field> <nodeset> <constant | function | >
         - <field> = field name valid for type of physics
         - <nodeset> = name of set of nodes to apply boundary condition
-        - <constant | function> = value or name of function followed by its
-          parameters
+        - <constant | function | > = value or name of function followed by its
+          parameters or nothing to fix the field at its current state
         \section examples
         <TT> fix_modify AtC fix temperature groupNAME 10. </TT> \n
         <TT> fix_modify AtC fix temperature groupNAME 0 0 0 10.0 0 0 1.0 </TT> \n
         \section description
         Creates a constraint on the values of the specified field at specified nodes.
         \section restrictions
         keyword 'all' reserved in nodeset name
         \section related 
         see \ref man_unfix_nodes
         \section default 
         none
       */
       // fix and unfix nodes
       else if (strcmp(arg[argIdx],"fix")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string nsetName(arg[argIdx++]);
         XT_Function * f = NULL;
         // fix current value 
         if (narg == argIdx) {
           set<int> nodeSet = (feEngine_->fe_mesh())->nodeset(nsetName);
           set<int>::const_iterator iset;
           const DENS_MAT & field =(fields_.find(thisField)->second).quantity(); 
           for (iset = nodeSet.begin(); iset != nodeSet.end(); iset++) {
             int inode = *iset;
             double v = field(inode,thisIndex);
             f = XT_Function_Mgr::instance()->constant_function(v);
             set<int> one; one.insert(inode);
             prescribedDataMgr_->fix_field(one,thisField,thisIndex,f);
           }
          }
-        // parse constant
+        // parse constant or file
         else if (narg == argIdx+1) {
-          f = XT_Function_Mgr::instance()->constant_function(atof(arg[argIdx]));
-          prescribedDataMgr_->fix_field(nsetName,thisField,thisIndex,f);
+          string a(arg[argIdx]);
+          if (is_numeric(a)) { // constant
+            f = XT_Function_Mgr::instance()->constant_function(atof(arg[argIdx]));
+            prescribedDataMgr_->fix_field(nsetName,thisField,thisIndex,f);
+          } 
+          else {
+            ATC::LammpsInterface::instance()->print_msg("reading "+field_to_string(thisField)+" on nodeset "+nsetName+" from file "+a);
+            string s = ATC::LammpsInterface::instance()->read_file(a);
+            stringstream ss; ss << s; 
+            double v; 
+            set<int> nodeSet = (feEngine_->fe_mesh())->nodeset(nsetName);
+            set<int>::const_iterator iset;
+            for (iset = nodeSet.begin(); iset != nodeSet.end(); iset++) {
+              int inode = *iset;
+              int i;
+              ss >> i >>  v;
+              if (i != inode) ATC::LammpsInterface::instance()->print_msg_once("WARNING: node mismatch in file read");
+              f = XT_Function_Mgr::instance()->constant_function(v);
+              set<int> one; one.insert(inode);
+              prescribedDataMgr_->fix_field(one,thisField,thisIndex,f);
+            }
+          }
         }
         // parse function
         else {
           f = XT_Function_Mgr::instance()->function(&(arg[argIdx]),narg-argIdx);
           prescribedDataMgr_->fix_field(nsetName,thisField,thisIndex,f);
         }
         match = true;
       }
 
       /*! \page man_unfix_nodes fix_modify AtC unfix 
         \section syntax
         fix_modify AtC unfix <field> <nodeset> 
         - <field> = field name valid for type of physics
         - <nodeset> = name of set of nodes 
         \section examples
         <TT> fix_modify AtC unfix temperature groupNAME </TT>
         \section description
         Removes constraint on field values for specified nodes.
         \section restrictions
         keyword 'all' reserved in nodeset name
         \section related 
         see \ref man_fix_nodes
         \section default 
         none
       */
       else if (strcmp(arg[argIdx],"unfix")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string nsetName(arg[argIdx++]);
         prescribedDataMgr_->unfix_field(nsetName,thisField,thisIndex);
         match = true;
       }
 
     /*! \page man_source fix_modify AtC source
       \section syntax
        fix_modify AtC source <field> <element_set> <value | function>
         - <field> = field name valid for type of physics
         - <element_set> = name of set of elements 
       \section examples
       <TT> fix_modify atc source temperature middle temporal_ramp 10. 0. </TT>
       \section description
       Add domain sources to the mesh. The units are consistent with LAMMPS's 
       units for mass, length and time and are defined by the PDE being solved,
       e.g. for thermal transfer the balance equation is for energy and source
       is energy per time.
       \section restrictions 
       keyword 'all' reserved in element_set name
       \section related
       see \ref man_remove_source
       \section default
       none
     */
       else if (strcmp(arg[argIdx],"source")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string esetName(arg[argIdx++]);
         XT_Function * f = NULL;
         // parse constant
         if (narg == argIdx+1) {
-          f = XT_Function_Mgr::instance()->constant_function(atof(arg[argIdx]));
+          string a(arg[argIdx]);
+          if (is_numeric(a)) { // constant
+            f = XT_Function_Mgr::instance()->constant_function(atof(arg[argIdx]));
+            prescribedDataMgr_->fix_source(esetName,thisField,thisIndex,f);
+          } 
+          else {
+            ATC::LammpsInterface::instance()->print_msg("reading "+field_to_string(thisField)+" source on node set "+esetName+" from file "+a);
+            string s = ATC::LammpsInterface::instance()->read_file(arg[argIdx]);
+            stringstream ss; ss << s; 
+            double v; 
+            set<int> nset = (feEngine_->fe_mesh())->nodeset(esetName);
+            set< pair < int, double > > src; 
+            set<int>::const_iterator iset;
+            double sum = 0.;
+            for (iset = nset.begin(); iset != nset.end(); iset++) {
+              int inode = *iset;
+              int i;
+              ss >> i >> v;
+              if (i != inode) ATC::LammpsInterface::instance()->print_msg_once("WARNING: node mismatch in file read");
+              src.insert(pair<int,double> (inode,v));
+              sum += v;
+            }
+            if (ss.gcount()) ATC::LammpsInterface::instance()->print_msg_once("WARNING: not all of file read");
+            ATC::LammpsInterface::instance()->print_msg_once("total source: "+to_string(sum));
+            prescribedDataMgr_->fix_source(thisField,thisIndex,src);
+          }
         }
         // parse function
         else {
           f = XT_Function_Mgr::instance()->function(&(arg[argIdx]),narg-argIdx);
+          prescribedDataMgr_->fix_source(esetName,thisField,thisIndex,f);
         }
-        prescribedDataMgr_->fix_source(esetName,thisField,thisIndex,f);
         fieldMask_(thisField,PRESCRIBED_SOURCE) = true;
         match = true;
       }
 
     /*! \page man_remove_source fix_modify AtC remove_source
       \section syntax
       fix_modify AtC remove_source <field> <element_set>
         - <field> = field name valid for type of physics
         - <element_set> = name of set of elements 
       \section examples
       <TT> fix_modify atc remove_source temperature groupNAME </TT>
       \section description
       Remove a domain source.
       \section restrictions
       keyword 'all' reserved in element_set name
       \section related
       see \ref man_source
       \section default
     */
       else if (strcmp(arg[argIdx],"remove_source")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string esetName(arg[argIdx++]);
         prescribedDataMgr_->unfix_source(esetName,thisField,thisIndex);
         fieldMask_(thisField,PRESCRIBED_SOURCE) = false;
         match = true;
       }
+      else if (strcmp(arg[argIdx],"write_source")==0) {
+        argIdx++;
+        FieldName thisField;
+        int thisIndex;
+        parse_field(arg,argIdx,thisField,thisIndex);
+        string nsetName(arg[argIdx++]);
+        string filename(arg[argIdx++]);
+        set_sources();
+        FIELDS * s = & sources_; // PRESCRIBED_SOURCES
+        if (argIdx < narg && strcmp(arg[argIdx],"extrinsic")==0) s = & extrinsicSources_;
+//s = & extrinsicSources_;
+        stringstream  f;
+        set<int> nodeSet = (feEngine_->fe_mesh())->nodeset(nsetName);
+        set<int>::const_iterator iset;
+        const DENS_MAT & source =(s->find(thisField)->second).quantity();
+        for (iset = nodeSet.begin(); iset != nodeSet.end(); iset++) {
+          int inode = *iset;
+          double v = source(inode,thisIndex);
+          f << inode << " " << std::setprecision(17) << v << "\n";
+        }
+        LammpsInterface::instance()->write_file(filename,f.str());
+        match = true;
+      }
+
   
     /*! \page man_fix_flux fix_modify AtC fix_flux
       \section syntax
        fix_modify AtC fix_flux <field> <face_set> <value | function>
         - <field> = field name valid for type of physics, temperature | electron_temperature
         - <face_set> = name of set of element faces
       \section examples
        <TT> fix_modify atc fix_flux temperature faceSet 10.0 </TT> \n
        
       \section description
        Command for fixing normal fluxes e.g. heat_flux. 
        This command only prescribes the normal component of the physical flux, e.g. heat (energy) flux.
        The units are in AtC units, i.e. derived from the LAMMPS length, time, and mass scales.
       \section restrictions 
       Only normal fluxes (Neumann data) can be prescribed.
       \section related
       see \ref man_unfix_flux
       \section default
     */
       else if (strcmp(arg[argIdx],"fix_flux")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string fsetName(arg[argIdx++]);
         XT_Function * f = NULL;
         // parse constant
         if (narg == argIdx+1) {
           f = XT_Function_Mgr::instance()->constant_function(atof(arg[argIdx]));
         }
         // parse function
         else {
           f = XT_Function_Mgr::instance()->function(&(arg[argIdx]),narg-argIdx);
         }
         prescribedDataMgr_->fix_flux(fsetName,thisField,thisIndex,f);
         fieldMask_(thisField,PRESCRIBED_SOURCE) = true;
         match = true;
       }
 
     /*! \page man_unfix_flux fix_modify AtC unfix_flux
       \section syntax
       fix_modify AtC fix_flux <field> <face_set> <value | function>
         - <field> = field name valid for type of physics, temperature | electron_temperature
         - <face_set> = name of set of element faces
       \section examples
        <TT> fix_modify atc unfix_flux temperature faceSet  </TT> \n
        
       \section description
        Command for removing prescribed normal fluxes e.g. heat_flux, stress. 
       \section restrictions 
       \section related
       see \ref man_unfix_flux
       \section default
     */
       else if (strcmp(arg[argIdx],"unfix_flux")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string fsetName(arg[argIdx++]);
         prescribedDataMgr_->unfix_flux(fsetName,thisField,thisIndex);
         fieldMask_(thisField,PRESCRIBED_SOURCE) = false;
         match = true;
       }
 
       
     /*! \page man_fe_md_boundary fix_modify AtC fe_md_boundary 
       \section syntax
       fix_modify AtC fe_md_boundary <faceset | interpolate | no_boundary> [args]
       \section examples
        <TT> fix_modify atc fe_md_boundary interpolate </TT> \n
       \section description
       Specifies different methods for computing fluxes between between the MD and FE integration regions.  Faceset defines a faceset separating the MD and FE regions and uses finite element face quadrature to compute the flux.  Interpolate uses a reconstruction scheme to approximate the flux, which is more robust but less accurate if the MD/FE boundary does correspond to a faceset.  No boundary results in no fluxes between the systems being computed.
       \section restrictions 
       If faceset is used, all the AtC non-boundary atoms must lie within and completely fill the domain enclosed by the faceset.
       \section related
       see \man_boundary_faceset for how to specify the faceset name.
       \section default
       Interpolate.
     */
       else if (strcmp(arg[argIdx],"fe_md_boundary")==0) {
         bndyIntType_ = FE_INTERPOLATION;// default
         if(strcmp(arg[argIdx],"faceset")==0) {
           argIdx++;
           bndyIntType_ = FE_QUADRATURE;
           string name(arg[argIdx++]);
           bndyFaceSet_ = & ( (feEngine_->fe_mesh())->faceset(name));
         } 
         else if (strcmp(arg[argIdx],"interpolate")==0) {
           argIdx++;
           bndyIntType_ = FE_INTERPOLATION;
         }
         else if (strcmp(arg[argIdx],"no_boundary")==0) { 
           bndyIntType_ = NO_QUADRATURE; 
         }
         else {
           throw ATC_Error("Bad boundary integration type");
         }
       }
 
 
 
     /*! \page man_boundary_faceset fix_modify AtC boundary_faceset 
       \section syntax
       fix_modify AtC boundary_faceset <is | add> [args]
       \section examples
       fix_modify AtC boundary_faceset is obndy
       \section description
       This command species the faceset name when using a faceset to compute the MD/FE boundary fluxes.  The faceset must already exist.
       \section restrictions
       This is only valid when fe_md_boundary is set to faceset.
       \section related
       \man_fe_md_boundary
       \section default
     */
       else if (strcmp(arg[argIdx],"boundary_faceset")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"is")==0) { // replace existing faceset
           argIdx++;
           boundaryFaceNames_.clear();
           string name(arg[argIdx++]);
           boundaryFaceNames_.insert(name);
           match = true;
         }
         else if (strcmp(arg[argIdx],"add")==0) { // add this faceset to list
           argIdx++;
           string name(arg[argIdx]);
           boundaryFaceNames_.insert(name);
           match = true;
         }
       }
 
       /*! \page man_internal_quadrature fix_modify AtC internal_quadrature 
         \section syntax
         fix_modify atc internal_quadrature <on | off> [region]
         \section examples
         <TT> fix_modify atc internal_quadrature off </TT>
         \section description
         Command to use or not use atomic quadrature on internal elements
         fully filled with atoms. By turning the internal quadrature off
         these elements do not contribute to the governing PDE and the fields
         at the internal nodes follow the weighted averages of the atomic data.
         \section optional
         Optional region tag specifies which finite element nodes will be treated
         as being within the MD region.  This option is only valid with
         internal_quadrature off.
         \section restrictions
         \section related 
         \section default 
         on
       */
       else if (strcmp(arg[argIdx],"internal_quadrature")==0) {
         if (initialized_) {
           throw ATC_Error("Cannot change internal_quadrature method after first run");
         }
         argIdx++;
         if (strcmp(arg[argIdx],"on")==0) {
           argIdx++;
           atomQuadForInternal_ = true;
           match = true;
         }
         else if (strcmp(arg[argIdx],"off")==0) {
           argIdx++;
           if (argIdx == narg) {
             atomQuadForInternal_ = false;
             regionID_ = -1;
             match = true;
           }
           else {
             for (regionID_ = 0; regionID_ < lammpsInterface_->nregion(); regionID_++) 
               if (strcmp(arg[argIdx],lammpsInterface_->region_name(regionID_)) == 0) break;
             if (regionID_ < lammpsInterface_->nregion()) {
               atomQuadForInternal_ = false;
               match = true;
             }
             else {
               throw ATC_Error("Region " + string(arg[argIdx]) + " does not exist");
             }
           }
         }
         if (match) {
           needReset_ = true;
         }
       }
 
       else if (strcmp(arg[argIdx],"fix_robin")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string fsetName(arg[argIdx++]);
         UXT_Function * f = NULL;
         // parse linear
         if (narg == argIdx+2) {
           f = UXT_Function_Mgr::instance()->linear_function(atof(arg[argIdx]),atof(arg[argIdx+1]));
         }
         // parse function
         else {
           throw ATC_Error("unimplemented function");
         }
         prescribedDataMgr_->fix_robin(fsetName,thisField,thisIndex,f);
         fieldMask_(thisField,ROBIN_SOURCE) = true;
         match = true;
       }
       else if (strcmp(arg[argIdx],"unfix_robin")==0) {
         argIdx++;
         parse_field(arg,argIdx,thisField,thisIndex);
         string fsetName(arg[argIdx++]);
         prescribedDataMgr_->unfix_robin(fsetName,thisField,thisIndex);
         fieldMask_(thisField,ROBIN_SOURCE) = false;
         match = true;
       }
 
+      
+      else if (strcmp(arg[argIdx],"fix_open")==0) {
+        argIdx++;
+        parse_field(arg,argIdx,thisField);
+        string fsetName(arg[argIdx++]);
+        prescribedDataMgr_->fix_open(fsetName,thisField);
+        fieldMask_(thisField,OPEN_SOURCE) = true;
+        match = true;
+      }
+      else if (strcmp(arg[argIdx],"unfix_open")==0) {
+        argIdx++;
+        parse_field(arg,argIdx,thisField);
+        string fsetName(arg[argIdx++]);
+        prescribedDataMgr_->unfix_open(fsetName,thisField);
+        fieldMask_(thisField,OPEN_SOURCE) = false;
+        match = true;
+      }
+
       /*! \page man_atomic_charge fix_modify AtC atomic_charge
       \section syntax
       fix_modify AtC <include | omit> atomic_charge
         - <include | omit> = switch to activiate/deactiviate inclusion of intrinsic atomic charge in ATC
       \section examples
        <TT> fix_modify atc compute include atomic_charge </TT>
       \section description
        Determines whether AtC tracks the total charge as a finite element field
       \section restrictions
       Required for:  electrostatics
       \section related
       \section default
       if the atom charge is defined, default is on, otherwise default is off
     */
       else if (strcmp(arg[argIdx],"include")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"atomic_charge")==0) {
           trackCharge_ = true;
           match = true;
           needReset_ = true;
         }
       }
       else if (strcmp(arg[argIdx],"omit")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"atomic_charge")==0) {
           trackCharge_ = false;
           match = true;
           needReset_ = true;
         }
       }
 
       /*! \page man_source_integration fix_modify AtC source_integration
       \section syntax
       fix_modify AtC source_integration < fe | atom>
       \section examples
        <TT> fix_modify atc source_integration atom </TT>
       \section description
       \section restrictions
       \section related
       \section default
       Default is fe
     */
       else if (strcmp(arg[argIdx],"source_integration")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"fe")==0) {
           sourceIntegration_ = FULL_DOMAIN;
         }
+        else {
+          sourceIntegration_ = FULL_DOMAIN_ATOMIC_QUADRATURE_SOURCE;
+        }
         match = true;
       }
 
       /*! \page man_consistent_fe_initialization fix_modify AtC consistent_fe_initialization
       \section syntax
        fix_modify AtC consistent_fe_initialization <on | off>
         - <on|off> = switch to activiate/deactiviate the intial setting of FE intrinsic field to match the projected MD field
       \section examples
        <TT> fix_modify atc consistent_fe_initialization on </TT>
       \section description
       Determines whether AtC initializes FE intrinsic fields (e.g., temperature) to match the projected MD values.  This is particularly useful for fully overlapping simulations.
       \section restrictions
       Can be used with:  thermal, two_temperature.
       Cannot be used with time filtering on. Does not include boundary nodes.
       \section related
       \section default
       Default is off
     */
       else if (strcmp(arg[argIdx],"consistent_fe_initialization")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"on")==0) {
           if (timeFilterManager_.filter_dynamics())
             throw ATC_Error("Consistent FE initialization cannot be used with time filtering");
           consistentInitialization_ = true;
           match = true;
         }
         else if (strcmp(arg[argIdx],"off")==0) {
           consistentInitialization_ = false;
           match = true;
         }
       }
 
       // switch for equilibrium filtering start
       /*! \page man_equilibrium_start fix_modify AtC equilibrium_start
         \section syntax
         fix_modify AtC equilibrium_start <on|off>
         
         \section examples
         <TT> fix_modify atc equilibrium_start on </TT> \n
         
         \section description
         Starts filtered calculations assuming they start in equilibrium, i.e. perfect finite element force balance.
         
         \section restrictions
         only needed before filtering is begun
         
         \section related
         see \ref man_time_filter
         
         \section default
         on
       */
       else if (strcmp(arg[argIdx],"equilibrium_start")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"on")==0) {
           equilibriumStart_ = true;
           match = true;
         }
         else if (strcmp(arg[argIdx],"off")==0) {
           equilibriumStart_ = false;
           match = true;
         }
       }
 
       /*! \page man_mass_matrix fix_modify AtC mass_matrix
         \section syntax 
         fix_modify AtC mass_matrix <fe | md_fe>
         - <fe | md_fe> = activiate/deactiviate using the FE mass matrix in the MD region
         \section examples
         <TT> fix_modify atc mass_matrix fe </TT>
         \section description
         Determines whether AtC uses the FE mass matrix based on Gaussian quadrature or based on atomic quadrature in the MD region.  This is useful for fully overlapping simulations to improve efficiency.
         \section restrictions
         Should not be used unless the FE region is contained within the MD region, otherwise the method will be unstable and inaccurate
         \section related
         \section default
         Default is off
       */
 
       else if (strcmp(arg[argIdx],"mass_matrix")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"fe")==0) {
           useFeMdMassMatrix_ = true;
           match = true;
         }
         else {
           useFeMdMassMatrix_ = false;
           match = true;
         }
         if (match) {
           needReset_ = true;
         }
       }
 
     /*! \page man_material fix_modify AtC material
       \section syntax
       fix_modify AtC material [elementset_name] [material_id]  \n
       \section examples
       <TT> fix_modify AtC material gap_region 2</TT>
       \section description
       Sets the material model in elementset_name to be of type material_id.
       \section restrictions 
       The element set must already be created and the material must be specified in the material file given the the atc fix on construction
       \section related
       \section default
       All elements default to the first material in the material file.
     */
     else if (strcmp(arg[argIdx],"material")==0) {
       argIdx++;
       string elemsetName(arg[argIdx++]);
       int matId = physicsModel_->material_index(arg[argIdx++]);
       using std::set;
       set<int> elemSet = (feEngine_->fe_mesh())->elementset(elemsetName);
       if(elementToMaterialMap_.size() == 0) {
         throw ATC_Error("need mesh before material command");
       }
       // set elementToMaterialMap
       set<int>::const_iterator iset;
       for (iset = elemSet.begin(); iset != elemSet.end(); iset++) {
         int ielem = *iset;
         
         // and the tag a string
         elementToMaterialMap_(ielem) = matId;
       }
       match = true;
       needReset_ = true;
     }
 
     } // end else 
     // no match, call base class parser
     if (!match) {
       match = ATC_Method::modify(narg, arg);
     }
     return match; // return to FixATC
   }
 
   //--------------------------------------------------
    /** PDE type */
    WeakEquation::PDE_Type ATC_Coupling::pde_type(const FieldName fieldName) const
    {
      const WeakEquation * weakEq = physicsModel_->weak_equation(fieldName);
      if (weakEq == NULL) return WeakEquation::PROJECTION_PDE; 
      return weakEq->type();
    }
   //--------------------------------------------------
    /** is dynamic PDE */
    bool ATC_Coupling::is_dynamic(const FieldName fieldName) const
    {
      const WeakEquation * weakEq = physicsModel_->weak_equation(fieldName);
      if (weakEq == NULL) return false; 
      return (physicsModel_->weak_equation(fieldName)->type() == WeakEquation::DYNAMIC_PDE);
    }
 
 
   //--------------------------------------------------
   /** allow FE_Engine to construct data manager after mesh is constructed */
   void ATC_Coupling::construct_prescribed_data_manager (void) {
     prescribedDataMgr_ = new PrescribedDataManager(feEngine_,fieldSizes_);
   }
 
   //--------------------------------------------------
   // pack_fields
   //   bundle all allocated field matrices into a list
   //   for output needs
   //--------------------------------------------------
   void ATC_Coupling::pack_fields(RESTART_LIST & data)
   {
     ATC_Method::pack_fields(data);
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->pack_fields(data);
     }
   }
 
   //--------------------------------------------------------------
   // create_physics_model
   // - method to create physics model 
   //--------------------------------------------------------------
   void ATC_Coupling::create_physics_model(const PhysicsType & physicsType,
                                           string matFileName)
   {
     if (physicsModel_) {
       throw ATC_Error("Attempted to create PhysicsModel multiple times in ATC_Coupling");
     }
     // Create PhysicsModel based on physicsType
     switch (physicsType) {
     case NO_PHYSICS :
       break;
     case THERMAL :
       physicsModel_ = new PhysicsModelThermal(matFileName);
       break;
     case ELASTIC :
       physicsModel_ = new PhysicsModelElastic(matFileName);
       break;
     case SHEAR:
       physicsModel_ = new PhysicsModelShear(matFileName);
       break;
     case SPECIES :
       physicsModel_ = new PhysicsModelSpecies(matFileName);
       break;
     case THERMO_ELASTIC :
       physicsModel_ = new PhysicsModelThermoElastic(matFileName);
       break;
     default:
       throw ATC_Error("Unknown physics type in ATC_Coupling::create_physics_model");
     }
   }
 
   //--------------------------------------------------------
   //  construct_methods
   //    have managers instantiate requested algorithms
   //    and methods
   //--------------------------------------------------------
   void ATC_Coupling::construct_methods()
   {
     ATC_Method::construct_methods();
 
     // construct needed time filters for mass matrices
     if (timeFilterManager_.need_reset()) {
       init_filter();
       map<FieldName,int>::const_iterator field;
       for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
         FieldName thisField = field->first;
         // fill in mass matrix time filters if needed
         if (!massMatTimeFilters_[thisField])
           massMatTimeFilters_[thisField] = timeFilterManager_.construct(TimeFilterManager::INSTANTANEOUS);
       }
     }
 
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->construct_methods();
     }
     atomicRegulator_->construct_methods();
   }
   //-------------------------------------------------------------------
   void ATC_Coupling::init_filter()
   {
     if (timeFilterManager_.need_reset()) {
       map<FieldName,int>::const_iterator field;
       for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
         FieldName thisField = field->first;
         int thisSize = field->second;
         (nodalAtomicFieldsRoc_[thisField].set_quantity()).reset(nNodes_,thisSize);
       }
     }
   }
   //--------------------------------------------------------
   void ATC_Coupling::set_fixed_nodes()
   {
     // set fields
     prescribedDataMgr_->set_fixed_fields(time(),
       fields_,dot_fields_,ddot_fields_,dddot_fields_);
 
 
     // set related data
     map<FieldName,int>::const_iterator field;
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       int thisSize = field->second;
       DENS_MAT & rhs(rhs_[thisField].set_quantity());
       for (int inode = 0; inode < nNodes_ ; ++inode) {
         for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
           if (prescribedDataMgr_->is_fixed(inode,thisField,thisIndex)) {
             rhs(inode,thisIndex) = 0.;
           }
         }
       }
     }
   }
   //--------------------------------------------------------
   void ATC_Coupling::set_initial_conditions()
   {
     // set fields 
     prescribedDataMgr_->set_initial_conditions(time(),
       fields_,dot_fields_,ddot_fields_,dddot_fields_);
 
     // set (all) related data
     map<FieldName,int>::const_iterator field;
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       int thisSize = field->second;
       DENS_MAT & rhs(rhs_[thisField].set_quantity());
       for (int inode = 0; inode < nNodes_ ; ++inode) {
         for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
           rhs(inode,thisIndex) = 0.;
         }
       }
     }
   }
   //--------------------------------------------------------
   void ATC_Coupling::set_sources()
   {
-    // set fields
-    prescribedDataMgr_->set_sources(time(),sources_);
-
+    prescribedDataMgr_->set_sources(time(),sources_); // PRESCRIBED_SOURCE
+    extrinsicModelManager_.set_sources(fields_,extrinsicSources_); // EXTRINSIC_SOURCE
   }
   //-----------------------------------------------------------------
   // this is w_a source_a
   void ATC_Coupling::compute_sources_at_atoms(const RHS_MASK & rhsMask,
                                               const FIELDS & fields,
                                               const PhysicsModel * physicsModel,
                                               FIELD_MATS & atomicSources)
   {
     if (shpFcnMask_) {
       feEngine_->compute_source(rhsMask,
                                 fields,
                                 physicsModel,
                                 atomMaterialGroupsMask_,
                                 atomicWeightsMask_->quantity(),
                                 shpFcnMask_->quantity(),
                                 shpFcnDerivsMask_->quantity(),
                                 atomicSources);
     }
     else {
       for (FIELDS::const_iterator field = fields.begin(); 
            field != fields.end(); field++) {
         FieldName thisFieldName = field->first;
         FIELDS::const_iterator fieldItr = fields.find(thisFieldName);
         const DENS_MAT & f = (fieldItr->second).quantity();
         atomicSources[thisFieldName].reset(f.nRows(),f.nCols());
       }
     }
   }
   //-----------------------------------------------------------------
   
   void ATC_Coupling::compute_atomic_sources(const RHS_MASK & fieldMask,
                                             const FIELDS & fields,
                                             FIELDS & atomicSources)
   {
 
     for (FIELDS::const_iterator field = fields.begin();
          field != fields.end(); field++) {
       FieldName thisFieldName = field->first;
       if (is_intrinsic(thisFieldName)) {
         atomicSources[thisFieldName] = 0.;
         if (fieldMask(thisFieldName,FLUX)) {
           atomicSources[thisFieldName] = boundaryFlux_[thisFieldName];
         }
         if (fieldMask(thisFieldName,PRESCRIBED_SOURCE)) {
           atomicSources[thisFieldName] -= fluxMask_*(sources_[thisFieldName].quantity());
         } 
 
 
         // add in sources from extrinsic models
         if (fieldMask(thisFieldName,EXTRINSIC_SOURCE))
           atomicSources[thisFieldName] -= fluxMask_*(extrinsicSources_[thisFieldName].quantity());
 
       }
     }
   }
   //-----------------------------------------------------------------
   void ATC_Coupling::masked_atom_domain_rhs_tangent(
     const pair<FieldName,FieldName> row_col,
     const RHS_MASK & rhsMask,
     const FIELDS & fields, 
     SPAR_MAT & stiffness,
     const PhysicsModel * physicsModel)
   {
     if (shpFcnMask_) {
       feEngine_->compute_tangent_matrix(rhsMask, row_col,
                                         fields, physicsModel, atomMaterialGroupsMask_,
                                         atomicWeightsMask_->quantity(), shpFcnMask_->quantity(),
                                         shpFcnDerivsMask_->quantity(),stiffness);
     }
     else {
       stiffness.reset(nNodes_,nNodes_);
     }
   }
   //-----------------------------------------------------------------
   void ATC_Coupling::compute_rhs_tangent(
     const pair<FieldName,FieldName> row_col,
     const RHS_MASK & rhsMask,
     const FIELDS & fields, 
     SPAR_MAT & stiffness,
     const IntegrationDomainType integrationType,
     const PhysicsModel * physicsModel)
   {
 
+    if (integrationType  == FULL_DOMAIN_ATOMIC_QUADRATURE_SOURCE) {
+      RHS_MASK rhsMaskFE = rhsMask;
+      RHS_MASK rhsMaskMD = rhsMask; rhsMaskMD = false;
+      for (FIELDS::const_iterator field = fields.begin(); 
+           field != fields.end(); field++) {
+        FieldName thisFieldName = field->first;
+        if ( rhsMaskFE(thisFieldName,SOURCE) ) {
+          rhsMaskFE(thisFieldName,SOURCE) = false;
+          rhsMaskMD(thisFieldName,SOURCE) = true;
+        }
+      }
+      feEngine_->compute_tangent_matrix(rhsMaskFE, row_col,
+        fields , physicsModel, elementToMaterialMap_, stiffness);
+      masked_atom_domain_rhs_tangent(row_col,
+                                     rhsMaskMD,
+                                     fields,
+                                     stiffnessAtomDomain_,
+                                     physicsModel);
+      stiffness += stiffnessAtomDomain_; 
+
+    }
+    else {
       feEngine_->compute_tangent_matrix(rhsMask, row_col,
         fields , physicsModel, elementToMaterialMap_, stiffness);
+    }
     ROBIN_SURFACE_SOURCE & robinFcn = *(prescribedDataMgr_->robin_functions()); 
     feEngine_->add_robin_tangent(rhsMask, fields, time(), robinFcn, stiffness);
+    OPEN_SURFACE & openFaces = *(prescribedDataMgr_->open_faces());
+    feEngine_->add_open_tangent(rhsMask, fields, openFaces, stiffness);
+  }
+  //-----------------------------------------------------------------
+  void ATC_Coupling::tangent_matrix(
+    const pair<FieldName,FieldName> row_col,
+    const RHS_MASK & rhsMask,
+    const PhysicsModel * physicsModel,
+    SPAR_MAT & stiffness)
+  {
+    feEngine_->compute_tangent_matrix(rhsMask, row_col,
+      fields_ , physicsModel, elementToMaterialMap_, stiffness);
   }
   //-----------------------------------------------------------------
   void ATC_Coupling::compute_rhs_vector(const RHS_MASK & rhsMask,
                                         const FIELDS & fields, 
                                               FIELDS & rhs,
                                         const IntegrationDomainType domain,
                                         const PhysicsModel * physicsModel)
   {
     if (!physicsModel) physicsModel = physicsModel_;
     
-
     // compute FE contributions
     
     evaluate_rhs_integral(rhsMask,fields,rhs,domain,physicsModel);
 
     for (int n = 0; n < rhsMask.nRows(); n++) {
       FieldName thisFieldName = FieldName(n);
       if (rhsMask(thisFieldName,PRESCRIBED_SOURCE)) {
         if (is_intrinsic(thisFieldName)) {
           rhs[thisFieldName] += fluxMaskComplement_*(sources_[thisFieldName].quantity());
         } 
         else {
           rhs[thisFieldName] +=                     sources_[thisFieldName].quantity();
         }
       }
 
       // add in sources from extrinsic models
       if (rhsMask(thisFieldName,EXTRINSIC_SOURCE)) {
         if (is_intrinsic(thisFieldName)) {
           rhs[thisFieldName] += fluxMaskComplement_*(extrinsicSources_[thisFieldName].quantity());
         }
         else {
           rhs[thisFieldName] +=                     extrinsicSources_[thisFieldName].quantity();
         }
       }
       
     }
-    ROBIN_SURFACE_SOURCE & robinFcn = *(prescribedDataMgr_->robin_functions()); 
+    ROBIN_SURFACE_SOURCE & robinFcn = *(prescribedDataMgr_->robin_functions());
     feEngine_->add_robin_fluxes(rhsMask, fields, time(), robinFcn, rhs);
+    OPEN_SURFACE & openFaces = *(prescribedDataMgr_->open_faces());
+    feEngine_->add_open_fluxes(rhsMask, fields, openFaces, rhs);
   }
   //-----------------------------------------------------------------
   void ATC_Coupling::masked_atom_domain_rhs_integral(
     const Array2D<bool> & rhsMask,
     const FIELDS & fields, FIELDS & rhs,
     const PhysicsModel * physicsModel)
   {
     if (shpFcnMask_) {
       feEngine_->compute_rhs_vector(rhsMask,
                                     fields,
                                     physicsModel,
                                     atomMaterialGroupsMask_,
                                     atomicWeightsMask_->quantity(),
                                     shpFcnMask_->quantity(),
                                     shpFcnDerivsMask_->quantity(),
                                     rhs);
     }
     else {
       for (FIELDS::const_iterator field = fields.begin(); 
            field != fields.end(); field++) {
         FieldName thisFieldName = field->first;
         FIELDS::const_iterator fieldItr = fields.find(thisFieldName);
         const DENS_MAT & f = (fieldItr->second).quantity();
         (rhs[thisFieldName].set_quantity()).reset(f.nRows(),f.nCols());
       }
     }
   }
   //-----------------------------------------------------------------
   void ATC_Coupling::evaluate_rhs_integral(
     const Array2D<bool> & rhsMask,
     const FIELDS & fields, FIELDS & rhs,
     const IntegrationDomainType integrationType,
     const PhysicsModel * physicsModel)
   {
     
     if (!physicsModel) physicsModel = physicsModel_;
 
     
     if      (integrationType == FE_DOMAIN ) {
       feEngine_->compute_rhs_vector(rhsMask, 
                                     fields, 
                                     physicsModel,
                                     elementToMaterialMap_,
-                                    rhs, 
+                                    rhs, false,
                                     &(elementMask_->quantity()));
       masked_atom_domain_rhs_integral(rhsMask,
                                       fields,
                                       rhsAtomDomain_,
                                       physicsModel);
       for (FIELDS::const_iterator field = fields.begin(); 
            field != fields.end(); field++) {
         FieldName thisFieldName = field->first;
         rhs[thisFieldName] -= rhsAtomDomain_[thisFieldName].quantity();
       }
     }
     else if (integrationType == ATOM_DOMAIN) {
       
       masked_atom_domain_rhs_integral(rhsMask,
                                       fields,
                                       rhs,
                                       physicsModel);
     }
+    else if (integrationType  == FULL_DOMAIN_ATOMIC_QUADRATURE_SOURCE) {
+      RHS_MASK rhsMaskFE = rhsMask;
+      RHS_MASK rhsMaskMD = rhsMask; rhsMaskMD = false;
+      for (FIELDS::const_iterator field = fields.begin(); 
+           field != fields.end(); field++) {
+        FieldName thisFieldName = field->first;
+        if ( rhsMaskFE(thisFieldName,SOURCE) ) {
+          rhsMaskFE(thisFieldName,SOURCE) = false;
+          rhsMaskMD(thisFieldName,SOURCE) = true;
+        }
+      }
+      feEngine_->compute_rhs_vector(rhsMaskFE,
+                                    fields,
+                                    physicsModel,
+                                    elementToMaterialMap_,
+                                    rhs);
+      masked_atom_domain_rhs_integral(rhsMaskMD,
+                                      fields,
+                                      rhsAtomDomain_,
+                                      physicsModel);
+      for (FIELDS::const_iterator field = fields.begin(); 
+           field != fields.end(); field++) {
+        FieldName thisFieldName = field->first;
+
+        if ( ((rhs[thisFieldName].quantity()).size() > 0)
+         && ((rhsAtomDomain_[thisFieldName].quantity()).size() > 0) )
+          rhs[thisFieldName] += rhsAtomDomain_[thisFieldName].quantity();
+      }
+    }
+    else if (integrationType  == FULL_DOMAIN_FREE_ONLY) {
+      feEngine_->compute_rhs_vector(rhsMask,
+                                    fields,
+                                    physicsModel,
+                                    elementToMaterialMap_,
+                                    rhs, true);
+    }
     else { // domain == FULL_DOMAIN
       feEngine_->compute_rhs_vector(rhsMask,
                                     fields,
                                     physicsModel,
                                     elementToMaterialMap_,
                                     rhs);
     }
   }
   
   //--------------------------------------------------
   bool ATC_Coupling::reset_methods() const
   {
     bool resetMethods = ATC_Method::reset_methods() || atomicRegulator_->need_reset();
     for (_ctiIt_ = timeIntegrators_.begin(); _ctiIt_ != timeIntegrators_.end(); ++_ctiIt_) {
       resetMethods |= (_ctiIt_->second)->need_reset();
     }
     return resetMethods;
   }
   //--------------------------------------------------
   void ATC_Coupling::initialize()
   { 
     // initialize physics model
     if (physicsModel_) physicsModel_->initialize();
 
     ATC_Method::initialize();
     
     // initialized_ is set to true by derived class initialize()
     // STEP 6 - data initialization continued:  set initial conditions
     if (!initialized_) {
       // Apply integration masking and new ICs
       // initialize schedule derivatives
       try {
         set_initial_conditions();
       }
       catch (ATC::ATC_Error& atcError) {
         if (!useRestart_)
           throw;
       }
     }
    
     // initialize and fix computational geometry, this can be changed in the future for Eulerian calculations that fill and empty elements which is why it is outside a !initialized_ guard
     internalElement_->unfix_quantity();
     if (ghostElement_) ghostElement_->unfix_quantity();
     internalElement_->quantity();
     if (ghostElement_) ghostElement_->quantity();
     nodalGeometryType_->quantity();
     internalElement_->fix_quantity();
     if (ghostElement_) ghostElement_->fix_quantity();
     reset_flux_mask();
 
     // setup grouping of atoms by material
     reset_atom_materials();
 
     // reset time filters if needed
     if (timeFilterManager_.need_reset()) {
       if ((!initialized_) || (atomToElementMapType_ == EULERIAN)) {
         map<FieldName,int>::const_iterator field;
         for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
           FieldName thisField = field->first;
           if (is_intrinsic(thisField) && is_dynamic(thisField)) { 
             compute_mass_matrix(thisField);
             if (!useConsistentMassMatrix_(thisField) && !useFeMdMassMatrix_) {
               massMatsMd_[thisField] = massMatsMdInstantaneous_[thisField].quantity();
               massMatsAq_[thisField] = massMatsAqInstantaneous_[thisField].quantity();
               update_mass_matrix(thisField);
             }
           }
         }
       }
     }
     
     // prepare computes for first timestep
     lammpsInterface_->computes_addstep(lammpsInterface_->ntimestep()+1);
 
     // resetting precedence:
     // time integrator -> kinetostat/thermostat -> time filter
     // init_filter uses fieldRateNdFiltered which comes from the time integrator,
     // which is why the time integrator is initialized first
 
     // other initializations
     if (reset_methods()) {
       for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
         (_tiIt_->second)->initialize();
       }
       atomicRegulator_->initialize();
     }
     extrinsicModelManager_.initialize();
     if (timeFilterManager_.need_reset()) {// reset thermostat power
       init_filter();
     }
     // clears need for reset
     timeFilterManager_.initialize();
     ghostManager_.initialize();
 
     if (!initialized_) {
       // initialize sources based on initial FE temperature
       double dt = lammpsInterface_->dt();
       prescribedDataMgr_->set_sources(time()+0.5*dt,sources_);
       extrinsicModelManager_.set_sources(fields_,extrinsicSources_);
       atomicRegulator_->compute_boundary_flux(fields_);
       compute_atomic_sources(fieldMask_,fields_,atomicSources_);
 
       // read in field data if necessary
       if (useRestart_) {
         RESTART_LIST data;
         read_restart_data(restartFileName_,data);
         useRestart_ = false;
       }
 
       // set consistent initial conditions, if requested
       if (!timeFilterManager_.filter_dynamics() && consistentInitialization_) {
         
         const INT_ARRAY & nodeType(nodalGeometryType_->quantity());
 
         if (fieldSizes_.find(VELOCITY) != fieldSizes_.end()) {
           DENS_MAT & velocity(fields_[VELOCITY].set_quantity());
           DENS_MAN * nodalAtomicVelocity(interscaleManager_.dense_matrix("NodalAtomicVelocity"));
           const DENS_MAT & atomicVelocity(nodalAtomicVelocity->quantity());
           for (int i = 0; i<nNodes_; ++i) {
             
             if (nodeType(i,0)==MD_ONLY) {
               for (int j = 0; j < nsd_; j++) {
                 velocity(i,j) = atomicVelocity(i,j);
               }
             }
           }
         }
 
         if (fieldSizes_.find(TEMPERATURE) != fieldSizes_.end()) {
           DENS_MAT & temperature(fields_[TEMPERATURE].set_quantity());
           DENS_MAN * nodalAtomicTemperature(interscaleManager_.dense_matrix("NodalAtomicTemperature"));
           const DENS_MAT & atomicTemperature(nodalAtomicTemperature->quantity());
             
           for (int i = 0; i<nNodes_; ++i) {
             
             if (nodeType(i,0)==MD_ONLY) {
               temperature(i,0) = atomicTemperature(i,0);
             }
           }
         }
 
         if (fieldSizes_.find(DISPLACEMENT) != fieldSizes_.end()) {
           DENS_MAT & displacement(fields_[DISPLACEMENT].set_quantity());
           DENS_MAN * nodalAtomicDisplacement(interscaleManager_.dense_matrix("NodalAtomicDisplacement"));
           const DENS_MAT & atomicDisplacement(nodalAtomicDisplacement->quantity());
           for (int i = 0; i<nNodes_; ++i) {
             
             if (nodeType(i,0)==MD_ONLY) {
               for (int j = 0; j < nsd_; j++) {
                 displacement(i,j) = atomicDisplacement(i,j);
               }
             }
           }
         }
           
         //WIP_JAT update next two when full species time integrator is added
         if (fieldSizes_.find(MASS_DENSITY) != fieldSizes_.end()) {
           DENS_MAT & massDensity(fields_[MASS_DENSITY].set_quantity());
           const DENS_MAT & atomicMassDensity(atomicFields_[MASS_DENSITY]->quantity());
           for (int i = 0; i<nNodes_; ++i) {
             
             if (nodeType(i,0)==MD_ONLY) {
               massDensity(i,0) = atomicMassDensity(i,0);
             }
           }
         }
           
         if (fieldSizes_.find(SPECIES_CONCENTRATION) != fieldSizes_.end()) {
           DENS_MAT & speciesConcentration(fields_[SPECIES_CONCENTRATION].set_quantity());
           const DENS_MAT & atomicSpeciesConcentration(atomicFields_[SPECIES_CONCENTRATION]->quantity());
           for (int i = 0; i<nNodes_; ++i) {
             
             if (nodeType(i,0)==MD_ONLY) {
               for (int j = 0; j < atomicSpeciesConcentration.nCols(); ++j) {
                 speciesConcentration(i,j) = atomicSpeciesConcentration(i,j);
               }
             }
           }
         }
       }
       
       initialized_ = true;
     }
 
   }
   //-------------------------------------------------------------------
   void ATC_Coupling::construct_time_integration_data()
   {
     if (!initialized_) {
 
       map<FieldName,int>::const_iterator field;
       for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
         FieldName thisField = field->first;
         int thisSize = field->second;
         
         // Allocate fields, initialize to default values, set up initial schedule
         
         fields_[thisField].reset(nNodes_,thisSize);
         dot_fields_[thisField].reset(nNodes_,thisSize);
         ddot_fields_[thisField].reset(nNodes_,thisSize);
         dddot_fields_[thisField].reset(nNodes_,thisSize);
         
         // Allocate restricted fields
         if (is_intrinsic(thisField)) {
           nodalAtomicFields_[thisField].reset(nNodes_,thisSize);
           nodalAtomicFieldsRoc_[thisField].reset(nNodes_,thisSize);
         }
 
         // Dimension finite element rhs matrix
         rhs_[thisField].reset(nNodes_,thisSize);
         rhsAtomDomain_[thisField].reset(nNodes_,thisSize);
         
         sources_[thisField].reset(nNodes_,thisSize);
         extrinsicSources_[thisField].reset(nNodes_,thisSize);
         boundaryFlux_[thisField].reset(nNodes_,thisSize);
         
         if (is_intrinsic(thisField) && is_dynamic(thisField)) {
           massMats_[thisField].reset(nNodes_,nNodes_); // PARALLELIZE
           massMatsFE_[thisField].reset(nNodes_,nNodes_);
           massMatsAq_[thisField].reset(nNodes_,nNodes_);
           massMatsMd_[thisField].reset(nNodes_,nNodes_);
           massMatsMdInstantaneous_[thisField].reset(nNodes_,nNodes_);
           massMatsAqInstantaneous_[thisField].reset(nNodes_,nNodes_);
           massMatsInv_[thisField].reset(nNodes_,nNodes_);  // PARALLELIZE
           massMatsMdInv_[thisField].reset(nNodes_,nNodes_); // PARALLELIZE
         }
         else {
           // no MD mass matrices needed, regular matrices computed in extrinsic model
           if (useConsistentMassMatrix_(thisField)) {
             // compute FE mass matrix in full domain
             
             consistentMassMats_[thisField].reset(nNodes_,nNodes_); // PARALLELIZE
             consistentMassMatsInv_[thisField].reset(nNodes_,nNodes_); // PARALLELIZE
           }
           else {
             massMats_[thisField].reset(nNodes_,nNodes_); // PARALLELIZE
             massMatsInv_[thisField].reset(nNodes_,nNodes_); // PARALLELIZE
           }
         }
       }
     }
   }
   //--------------------------------------------------------
   //  create_full_element_mask
   //    constructs element mask which only masks out 
   //    null elements
   //--------------------------------------------------------
   MatrixDependencyManager<DenseMatrix, bool> * ATC_Coupling::create_full_element_mask()
   {
     MatrixDependencyManager<DenseMatrix, bool> * elementMaskMan = new MatrixDependencyManager<DenseMatrix, bool>(feEngine_->num_elements(),1);
     DenseMatrix<bool> & elementMask(elementMaskMan->set_quantity());
     elementMask = true;
       
     const set<int> & nullElements = feEngine_->null_elements();
     set<int>::const_iterator iset;
     for (iset = nullElements.begin(); iset != nullElements.end(); iset++) {
       int ielem = *iset;
       elementMask(ielem,0) = false;
     }
 
     return elementMaskMan;
   }
   //--------------------------------------------------------
   //  create_element_set_mask
   //    constructs element mask based on an element set,
   //    uses ints for MPI communication later
   //--------------------------------------------------------
   MatrixDependencyManager<DenseMatrix, int> * ATC_Coupling::create_element_set_mask(const string & elementSetName)
   {
     MatrixDependencyManager<DenseMatrix, int> * elementMaskMan = new MatrixDependencyManager<DenseMatrix, int>(feEngine_->num_elements(),1);
     DenseMatrix<int> & elementMask(elementMaskMan->set_quantity());
     elementMask = false;
 
     const set<int> & elementSet((feEngine_->fe_mesh())->elementset(elementSetName));
     set<int>::const_iterator iset;
     for (iset = elementSet.begin(); iset != elementSet.end(); ++iset) {
       int ielem = *iset;
       elementMask(ielem,0) = true;
     }
       
     const set<int> & nullElements = feEngine_->null_elements();
     for (iset = nullElements.begin(); iset != nullElements.end(); iset++) {
       int ielem = *iset;
       elementMask(ielem,0) = false;
     }
 
     return elementMaskMan;
   }
   //--------------------------------------------------------
   //  set_computational_geometry
   //    constructs needed transfer operators which define
   //    hybrid atom/FE computational geometry
   //--------------------------------------------------------
   void ATC_Coupling::set_computational_geometry()
   {
     ATC_Method::set_computational_geometry();
 
     // does element contain internal atoms
     if (internalElementSet_.size()) {
       // set up elements and maps based on prescribed element sets
       internalElement_ = create_element_set_mask(internalElementSet_);
     }
     else {
       internalElement_ = new AtomTypeElement(this,atomElement_);
     }
     interscaleManager_.add_dense_matrix_int(internalElement_,
                                             "ElementHasInternal");
 
     if (groupbitGhost_) {
       atomGhostElement_ = new AtomToElementMap(this,
                                                atomGhostCoarseGrainingPositions_,
                                                GHOST);
       interscaleManager_.add_per_atom_int_quantity(atomGhostElement_,
                                                    "AtomGhostElement");
       
       // does element contain ghost atoms
       ghostElement_ = new AtomTypeElement(this,atomGhostElement_);
       interscaleManager_.add_dense_matrix_int(ghostElement_,
                                               "ElementHasGhost");
     }
     
     // element masking for approximate right-hand side FE atomic quadrature
     if (atomQuadForInternal_) {
       elementMask_ = create_full_element_mask();
     }
     else {
       if (internalElementSet_.size()) {
         // when geometry is based on elements, there are no mixed elements
         elementMask_ = new MatrixDependencyManager<DenseMatrix, bool>;
-        (elementMask_->set_quantity()).reset(feEngine_->num_elements(),1,false);
+        (elementMask_->set_quantity()).reset(feEngine_->num_elements(),1);
       }
       else {
         elementMask_ = new ElementMask(this);
       }
       internalToMask_ = new AtomToElementset(this,elementMask_);
       interscaleManager_.add_per_atom_int_quantity(internalToMask_,
                                                    "InternalToMaskMap");
     }
     interscaleManager_.add_dense_matrix_bool(elementMask_,
                                              "ElementMask");
 
     if (useFeMdMassMatrix_) {
       if (atomQuadForInternal_) {
         elementMaskMass_ = elementMask_;
       }
       else {
         elementMaskMass_ = create_full_element_mask();
         interscaleManager_.add_dense_matrix_bool(elementMaskMass_,
                                                  "NonNullElementMask");
       }
 
       elementMaskMassMd_ = new AtomElementMask(this);
       interscaleManager_.add_dense_matrix_bool(elementMaskMassMd_,
                                                "InternalElementMask");
     }
 
     // assign element and node types for computational geometry
     if (internalElementSet_.size()) {
       nodalGeometryType_ = new NodalGeometryTypeElementSet(this);
     }
     else {
       nodalGeometryType_ = new NodalGeometryType(this);
     }
     interscaleManager_.add_dense_matrix_int(nodalGeometryType_,
                                             "NodalGeometryType");
   }
   //--------------------------------------------------------
   //  construct_interpolant
-  //    constructs: interpolatn, accumulant, weights, and spatial derivatives
+  //    constructs: interpolant, accumulant, weights, and spatial derivatives
   //--------------------------------------------------------
   void ATC_Coupling::construct_interpolant()
   {
     // finite element shape functions for interpolants
     PerAtomShapeFunction * atomShapeFunctions = new PerAtomShapeFunction(this);
     interscaleManager_.add_per_atom_sparse_matrix(atomShapeFunctions,"Interpolant");
     shpFcn_ = atomShapeFunctions;
 
     // use shape functions for accumulants if no kernel function is provided
     if (!kernelFunction_) {
       accumulant_ = shpFcn_;
     }
     else {
       if (kernelOnTheFly_) throw ATC_Error("ATC_Coupling::construct_transfers - on the fly kernel evaluations not supported");
       PerAtomKernelFunction * atomKernelFunctions = new PerAtomKernelFunction(this);
       interscaleManager_.add_per_atom_sparse_matrix(atomKernelFunctions,
                                                     "Accumulant");
       accumulant_ = atomKernelFunctions;
       accumulantWeights_ = new AccumulantWeights(accumulant_);
       mdMassNormalization_ = false;
     }
     
     this->create_atom_volume();
 
     // masked atom weights
     if (atomQuadForInternal_) {
       atomicWeightsMask_ = atomVolume_;
     }
     else {
       atomicWeightsMask_ = new MappedDiagonalMatrix(this,
                                                     atomVolume_,
                                                     internalToMask_);
       interscaleManager_.add_diagonal_matrix(atomicWeightsMask_,
                                              "AtomWeightsMask");
     }
     // nodal volumes for mass matrix, relies on atomVolumes constructed in base class construct_transfers
     nodalAtomicVolume_ = new AdmtfShapeFunctionRestriction(this,atomVolume_,shpFcn_);
     interscaleManager_.add_dense_matrix(nodalAtomicVolume_,"NodalAtomicVolume");
 
     // shape function derivatives, masked shape function and derivatives if needed for FE quadrature in atomic domain
     if (atomQuadForInternal_) {
       shpFcnDerivs_ = new PerAtomShapeFunctionGradient(this);
       interscaleManager_.add_vector_sparse_matrix(shpFcnDerivs_,
                                                   "InterpolantGradient");
 
       shpFcnMask_ = shpFcn_;
       shpFcnDerivsMask_ = shpFcnDerivs_;
     }
     else {
       bool hasMaskedElt = false;
       const DenseMatrix<bool> & elementMask(elementMask_->quantity());
       for (int i = 0; i < elementMask.size(); ++i) {
         if (elementMask(i,0)) {
           hasMaskedElt = true;
           break;
         }
       }
       if (hasMaskedElt) {
         shpFcnDerivs_ = new PerAtomShapeFunctionGradient(this);
         interscaleManager_.add_vector_sparse_matrix(shpFcnDerivs_,
                                                     "InterpolantGradient");
 
         shpFcnMask_ = new RowMappedSparseMatrix(this,
                                                 shpFcn_,
                                                 internalToMask_);
         interscaleManager_.add_sparse_matrix(shpFcnMask_,
                                              "ShapeFunctionMask");
         shpFcnDerivsMask_ = new RowMappedSparseMatrixVector(this,
                                                             shpFcnDerivs_,
                                                             internalToMask_);
         interscaleManager_.add_vector_sparse_matrix(shpFcnDerivsMask_,"ShapeFunctionGradientMask");
       }
     }
   }
   //--------------------------------------------------------
   //  construct_molecule_transfers
   //--------------------------------------------------------
   void ATC_Coupling::construct_molecule_transfers()
   {
     
     map<string,pair<MolSize,int> >::const_iterator molecule;
     PerAtomQuantity<double> * atomProcGhostCoarseGrainingPositions = interscaleManager_.per_atom_quantity("AtomicProcGhostCoarseGrainingPositions");
     FundamentalAtomQuantity * mass = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                                   PROC_GHOST);
     for (molecule = moleculeIds_.begin(); molecule != moleculeIds_.end(); molecule++) {
       const string moleculeName = molecule->first;
       int groupbit = (molecule->second).second;
       SmallMoleculeSet * smallMoleculeSet = new SmallMoleculeSet(this,groupbit);
       smallMoleculeSet->initialize();
       interscaleManager_.add_small_molecule_set(smallMoleculeSet,moleculeName);
       SmallMoleculeCentroid * moleculeCentroid = 
         new SmallMoleculeCentroid(this,mass,smallMoleculeSet,atomProcGhostCoarseGrainingPositions);
       interscaleManager_.add_dense_matrix(moleculeCentroid,"MoleculeCentroid"+moleculeName);
 
       // shape function at molecular coordinates
       PointToElementMap * elementMapMol = 
         new PointToElementMap(this,moleculeCentroid);
       interscaleManager_.add_dense_matrix_int(elementMapMol,
                                               "ElementMap"+moleculeName);
       InterpolantSmallMolecule * shpFcnMol = new InterpolantSmallMolecule(this,
         elementMapMol, moleculeCentroid, smallMoleculeSet);
       interscaleManager_.add_sparse_matrix(shpFcnMol,
                                            "ShapeFunction"+moleculeName);
     }
   }
   //--------------------------------------------------------
   //  construct_transfers
   //    constructs needed transfer operators
   //--------------------------------------------------------
   void ATC_Coupling::construct_transfers()
   {
     ATC_Method::construct_transfers();
 
     if (!useFeMdMassMatrix_) {
       // transfer for MD mass matrices based on requested intrinsic fields
       if (fieldSizes_.find(TEMPERATURE) != fieldSizes_.end()) {
         // classical thermodynamic heat capacity of the atoms
         HeatCapacity * heatCapacity = new HeatCapacity(this);
         interscaleManager_.add_per_atom_quantity(heatCapacity,
                                                  "AtomicHeatCapacity");
 
         // atomic thermal mass matrix
         nodalAtomicHeatCapacity_ = new AtfShapeFunctionRestriction(this,
                                                                    heatCapacity,
                                                                    shpFcn_);
         interscaleManager_.add_dense_matrix(nodalAtomicHeatCapacity_,
                                             "NodalAtomicHeatCapacity");
       }
       if ((fieldSizes_.find(VELOCITY) != fieldSizes_.end()) || (fieldSizes_.find(DISPLACEMENT) != fieldSizes_.end())) {
         // atomic momentum mass matrix
         FundamentalAtomQuantity * atomicMass = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_MASS);
         nodalAtomicMass_ = new AtfShapeFunctionRestriction(this,
                                                            atomicMass,
                                                            shpFcn_);
         interscaleManager_.add_dense_matrix(nodalAtomicMass_,
                                             "AtomicMomentumMassMat");
       }
       if (fieldSizes_.find(MASS_DENSITY) != fieldSizes_.end()) {
         // atomic dimensionless mass matrix
         ConstantQuantity<double> * atomicOnes = new ConstantQuantity<double>(this,1);
         interscaleManager_.add_per_atom_quantity(atomicOnes,"AtomicOnes");
         nodalAtomicCount_ = new AtfShapeFunctionRestriction(this,
                                                             atomicOnes,
                                                             shpFcn_);
         interscaleManager_.add_dense_matrix(nodalAtomicCount_,
                                             "AtomicDimensionlessMassMat");
       }
     }
 
     extrinsicModelManager_.construct_transfers();
   }
   //--------------------------------------------------
   void ATC_Coupling::delete_mass_mat_time_filter(FieldName thisField)
   {
   }
   //--------------------------------------------------
   void ATC_Coupling::set_mass_mat_time_filter(FieldName thisField,TimeFilterManager::FilterIntegrationType filterIntegrationType)
   {
     massMatTimeFilters_[thisField] = timeFilterManager_.construct(filterIntegrationType);
   }
   //--------------------------------------------------------------
   /** method to trigger construction of mesh data after mesh construction */
   //--------------------------------------------------------------
   void ATC_Coupling::initialize_mesh_data(void)
   {
     int nelts = feEngine_->fe_mesh()->num_elements();
     elementToMaterialMap_.reset(nelts);
     elementToMaterialMap_ = 0;
 
     construct_prescribed_data_manager();
     meshDataInitialized_ = true;
   }
   //--------------------------------------------------------
   
   void ATC_Coupling::reset_flux_mask(void)
   {
     int i;
     // this is exact only for uniform meshes and certain types of atomic weights
     // \int_{\Omega_MD} N_I dV = \sum_\alpha N_I\alpha V_\alpha
     fluxMask_.reset((invNodeVolumes_.quantity()) 
               * (nodalAtomicVolume_->quantity()));
 
     DIAG_MAT id(fluxMask_.nRows(),fluxMask_.nCols()); 
     id = 1.0;
     fluxMaskComplement_ = id + -1.0*fluxMask_;
 
     // set flux masks for nodes we can tell by geometry
     const INT_ARRAY & nodeType(nodalGeometryType_->quantity());
     for (i = 0; i < nNodes_; ++i) {
       if (nodeType(i,0)==MD_ONLY) {
         fluxMask_(i,i) = 1.;
         fluxMaskComplement_(i,i) = 0.;
       }
       else if (nodeType(i,0)==FE_ONLY) {
         fluxMask_(i,i) = 0.;
         fluxMaskComplement_(i,i) = 1.;
       }
     }
   }
 
   //--------------------------------------------------------
   void ATC_Coupling::compute_mass_matrix(FieldName thisField, PhysicsModel * physicsModel)
   {
 
     if (!physicsModel) physicsModel = physicsModel_;
     if (useConsistentMassMatrix_(thisField)) {
       // compute FE mass matrix in full domain
       
       Array<FieldName> massMask(1);
       massMask(0) = thisField; 
       
       feEngine_->compute_mass_matrix(massMask,fields_,physicsModel,
                                      elementToMaterialMap_,consistentMassMats_,
                                      &(elementMask_->quantity()));
       // brute force computation of inverse
       consistentMassMatsInv_[thisField] = inv((consistentMassMats_[thisField].quantity()).dense_copy());
     }
+    else if (! is_intrinsic(thisField)) {
+      Array<FieldName> massMask(1);
+      massMask(0) = thisField; 
+      
+      feEngine_->compute_lumped_mass_matrix(massMask,fields_,physicsModel,
+                                            elementToMaterialMap_,massMats_,
+                                            &(elementMask_->quantity()));
+      const DIAG_MAT & myMassMat(massMats_[thisField].quantity());
+      DIAG_MAT & myMassMatInv(massMatsInv_[thisField].set_quantity());
+      for (int iNode = 0; iNode < nNodes_; iNode++) {
+        
+        if (fabs(myMassMat(iNode,iNode))>0)
+          myMassMatInv(iNode,iNode) = 1./myMassMat(iNode,iNode);
+        else
+          myMassMatInv(iNode,iNode) = 0.;
+      }
+    }
     else { // lumped mass matrix
       // compute FE mass matrix in full domain
       Array<FieldName> massMask(1);
       massMask(0) = thisField;
 
       if (useFeMdMassMatrix_) {
         feEngine_->compute_lumped_mass_matrix(massMask,fields_,physicsModel,
                                               elementToMaterialMap_,massMats_,
                                               &(elementMaskMass_->quantity()));
         const DIAG_MAT & myMassMat(massMats_[thisField].quantity());
         DIAG_MAT & myMassMatInv(massMatsInv_[thisField].set_quantity());
         DIAG_MAT & myMassMatMdInv(massMatsMdInv_[thisField].set_quantity());
 
         feEngine_->compute_lumped_mass_matrix(massMask,fields_,physicsModel,
                                               elementToMaterialMap_,massMatsMd_,
                                               &(elementMaskMassMd_->quantity()));
         const DIAG_MAT & myMassMatMd(massMatsMd_[thisField].quantity());
         // compute inverse mass matrices since we're using lumped masses
         for (int iNode = 0; iNode < nNodes_; iNode++) {
           
           if (fabs(myMassMat(iNode,iNode))>0)
             myMassMatInv(iNode,iNode) = 1./myMassMat(iNode,iNode);
           else
             myMassMatInv(iNode,iNode) = 0.;
 
           if (fabs(myMassMatMd(iNode,iNode))>0)
             myMassMatMdInv(iNode,iNode) = 1./myMassMatMd(iNode,iNode);
           else
             myMassMatMdInv(iNode,iNode) = 0.;
         }
       }
       else {
         feEngine_->compute_lumped_mass_matrix(massMask,fields_,physicsModel,
                                               elementToMaterialMap_,massMatsFE_,
                                               &(elementMask_->quantity()));
         // fully remove contributions from internal nodes
         
         DIAG_MAT & myMassMatFE(massMatsFE_[thisField].set_quantity());
+        //myMassMatFE.print("MMFE");
         if (!atomQuadForInternal_) {
           const INT_ARRAY & nodeType(nodalGeometryType_->quantity());
           for (int iNode = 0; iNode < nNodes_; iNode++)
             if (nodeType(iNode,0)==MD_ONLY) {
               myMassMatFE(iNode,iNode) = 0.;
             }
         }
         
         // atomic quadrature for FE mass matrix in atomic domain
         if (shpFcnMask_) {
           feEngine_->compute_lumped_mass_matrix(massMask,fields_,physicsModel,atomMaterialGroupsMask_,
                                                 atomicWeightsMask_->quantity(),shpFcnMask_->quantity(),
                                                 massMatsAqInstantaneous_);
         }
         else {
           (massMatsAqInstantaneous_[thisField].set_quantity()).reset(nNodes_,nNodes_);
         }
         
         // set up mass MD matrices
         compute_md_mass_matrix(thisField,massMatsMdInstantaneous_[thisField].set_quantity());
       }
     }
   }
   //--------------------------------------------------------
   void ATC_Coupling::update_mass_matrix(FieldName thisField)
   {
     DIAG_MAT & myMassMat(massMats_[thisField].set_quantity());
     DIAG_MAT & myMassMatInv(massMatsInv_[thisField].set_quantity());
     DIAG_MAT & myMassMatMDInv(massMatsMdInv_[thisField].set_quantity());
     const DIAG_MAT & myMassMatMD(massMatsMd_[thisField].quantity());
 
     myMassMat = massMatsFE_[thisField].quantity();
     // remove contributions from overlap by approximate quadrature
     myMassMat -= massMatsAq_[thisField].quantity();
     // add contributions from atomic region
     myMassMat += myMassMatMD;
 
     // compute inverse mass matrices since we're using lumped masses
     for (int iNode = 0; iNode < nNodes_; iNode++) {
       
       if (fabs(myMassMatMD(iNode,iNode))>0) { 
         myMassMatMDInv(iNode,iNode) = 1./myMassMatMD(iNode,iNode);
       }
       else
         myMassMatMDInv(iNode,iNode) = 0.;
       
       if (fabs(myMassMat(iNode,iNode))>0) {
         myMassMatInv(iNode,iNode) = 1./myMassMat(iNode,iNode);
       }
       else
         myMassMatInv(iNode,iNode) = 0.;
     }
   }
 
   //---------------------------------------------------------
   //  compute_md_mass_matrix
   //    compute the mass matrix arising from only atomistic
   //    quadrature and contributions as a summation
   //---------------------------------------------------------
   void ATC_Coupling::compute_md_mass_matrix(FieldName thisField,
                                             DIAG_MAT & massMat)
   {
     
     if (thisField == TEMPERATURE) {
       massMat.shallowreset(nodalAtomicHeatCapacity_->quantity());
     }
     
     else if (thisField == DISPLACEMENT || thisField == VELOCITY) {
       massMat.shallowreset(nodalAtomicMass_->quantity());
     }
     else if (thisField == MASS_DENSITY || thisField == SPECIES_CONCENTRATION) {
       massMat.shallowreset(nodalAtomicVolume_->quantity());
     }
   }   
 
   //--------------------------------------------------
   // write_restart_file
   //   bundle matrices that need to be saved and call
   //   fe_engine to write the file
   //--------------------------------------------------
   void ATC_Coupling::write_restart_data(string fileName, RESTART_LIST & data)
   {
     atomicRegulator_->pack_fields(data);
     ATC_Method::write_restart_data(fileName,data);
   }
   
   //--------------------------------------------------
   // read_restart_file
   //   bundle matrices that need to be saved and call
   //   fe_engine to write the file
   //--------------------------------------------------
   void ATC_Coupling::read_restart_data(string fileName, RESTART_LIST & data)
   {
     atomicRegulator_->pack_fields(data);
     ATC_Method::read_restart_data(fileName,data);
   }
 
   //--------------------------------------------------
   void ATC_Coupling::reset_nlocal()
   {
     ATC_Method::reset_nlocal();
     atomicRegulator_->reset_nlocal();
   }
 
   //--------------------------------------------------------
   void ATC_Coupling::reset_atom_materials()
   {
     int nMaterials = physicsModel_->nMaterials();
     atomMaterialGroups_.reset(nMaterials);
     atomMaterialGroupsMask_.reset(nMaterials);
 
     for (int i = 0; i < nMaterials; i++) {
       atomMaterialGroups_(i).clear();
       atomMaterialGroupsMask_(i).clear();
     }
 
     const INT_ARRAY & atomToElementMap(atomElement_->quantity());
     for (int i = 0; i < nLocal_; i++) {
       atomMaterialGroups_(elementToMaterialMap_(atomToElementMap(i,0))).insert(i);
     }
     if (atomQuadForInternal_) {
       for (int i = 0; i < nLocal_; i++) {
         atomMaterialGroupsMask_(elementToMaterialMap_(atomToElementMap(i,0))).insert(i);
       }
     }
     else {
       const INT_ARRAY & map(internalToMask_->quantity());
       for (int i = 0; i < nLocal_; i++) {
         int idx = map(i,0);
         if (idx > -1) {
           atomMaterialGroupsMask_(elementToMaterialMap_(atomToElementMap(i,0))).insert(idx);
         }
       }
     }
 
     atomicRegulator_->reset_atom_materials(elementToMaterialMap_,
                                            atomElement_);
   }
 
   //--------------------------------------------------------
   //  pre_init_integrate
   //    time integration before the lammps atomic
   //    integration of the Verlet step 1
   //--------------------------------------------------------
   void ATC_Coupling::pre_init_integrate()
   {
     ATC_Method::pre_init_integrate();
     double dt = lammpsInterface_->dt();
 
     // Perform any initialization, no actual integration
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->pre_initial_integrate1(dt);
     }
 
     // Apply controllers to atom velocities, if needed
     atomicRegulator_->apply_pre_predictor(dt,lammpsInterface_->ntimestep());
 
     // predict nodal fields and time derivatives
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->pre_initial_integrate2(dt);
     }
     extrinsicModelManager_.pre_init_integrate();
   }
 
   //--------------------------------------------------------
   //  init_integrate
   //    time integration of lammps atomic quantities
   //--------------------------------------------------------
   void ATC_Coupling::init_integrate()
   {
     atomTimeIntegrator_->init_integrate_velocity(dt());
     ghostManager_.init_integrate_velocity(dt());
     // account for other fixes doing time integration
     interscaleManager_.fundamental_force_reset(LammpsInterface::ATOM_VELOCITY);
 
     // apply constraints to velocity
     atomicRegulator_->apply_mid_predictor(dt(),lammpsInterface_->ntimestep());
 
     atomTimeIntegrator_->init_integrate_position(dt());
     ghostManager_.init_integrate_position(dt());
     // account for other fixes doing time integration
     interscaleManager_.fundamental_force_reset(LammpsInterface::ATOM_POSITION);
   }
 
   ///--------------------------------------------------------
   //  post_init_integrate
   //    time integration after the lammps atomic updates of
   //    Verlet step 1
   //--------------------------------------------------------
   void ATC_Coupling::post_init_integrate()
   {
     double dt = lammpsInterface_->dt();
   
     // Compute nodal velocity at n+1
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->post_initial_integrate1(dt);
     }
 
     // Update kinetostat quantities if displacement is being regulated
     atomicRegulator_->apply_post_predictor(dt,lammpsInterface_->ntimestep());
 
     // Update extrisic model
     extrinsicModelManager_.post_init_integrate();
 
     // fixed values, non-group bcs handled through FE
     set_fixed_nodes();
       
     update_time(0.5);
 
     // ghost update, if needed
     ATC_Method::post_init_integrate();
 
     // Apply time filtering to mass matrices, if needed
     if ((atomToElementMapType_ == EULERIAN) && timeFilterManager_.filter_dynamics() && !useFeMdMassMatrix_) {
       map<FieldName,int>::const_iterator field;
       for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
         FieldName thisField = field->first;
         if (!useConsistentMassMatrix_(thisField) && is_intrinsic(thisField)) {
           massMatTimeFilters_[thisField]->apply_pre_step1(massMatsAq_[thisField].set_quantity(),
                                                           massMatsAqInstantaneous_[thisField].quantity(),dt);
           massMatTimeFilters_[thisField]->apply_pre_step1(massMatsMd_[thisField].set_quantity(),
                                                           massMatsMdInstantaneous_[thisField].quantity(),dt);
         }
       }
     }
   }
 
   
   //--------------------------------------------------------
   void ATC_Coupling::pre_neighbor()
   {
     ATC_Method::pre_neighbor();
     reset_atom_materials();
   }
 
   //--------------------------------------------------------
   void ATC_Coupling::pre_exchange()
   {
     ATC_Method::pre_exchange();
   }
 
   //--------------------------------------------------------
   //  pre_force
   //    prior to calculation of forces
   //--------------------------------------------------------
   void ATC_Coupling::pre_force()
   {
     ATC_Method::pre_force();
     atomicRegulator_->pre_force(); 
   }
 
   //--------------------------------------------------------
   void ATC_Coupling::post_force()
   {
     ATC_Method::post_force();
 
     if ( (atomToElementMapType_ == EULERIAN) && (step() % atomToElementMapFrequency_ == 0) ) {
       reset_atom_materials();
 
       if (!useFeMdMassMatrix_) {
         map<FieldName,int>::const_iterator field;
         for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
           FieldName thisField = field->first;
           if (is_intrinsic(thisField) && is_dynamic(thisField)) {
             compute_mass_matrix(thisField);  
           }
         }
       }
     }
 
     if (atomToElementMapType_ == EULERIAN && !useFeMdMassMatrix_) {
       if (timeFilterManager_.filter_dynamics() || (step() % atomToElementMapFrequency_ == 0)) {
         double dt = lammpsInterface_->dt();
         map<FieldName,int>::const_iterator field;
         for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
           FieldName thisField = field->first;
           if (is_intrinsic(thisField) && is_dynamic(thisField)) {
             massMatTimeFilters_[thisField]->apply_post_step1(massMatsAq_[thisField].set_quantity(),
                                                              massMatsAqInstantaneous_[thisField].quantity(),dt);
             massMatTimeFilters_[thisField]->apply_post_step1(massMatsMd_[thisField].set_quantity(),
                                                              massMatsMdInstantaneous_[thisField].quantity(),dt);
             update_mass_matrix(thisField); 
           }
         }
       }
     }
 
     // apply extrinsic model
     extrinsicModelManager_.post_force();
   }
 
   //--------------------------------------------------------
   //  post_final_integrate
   //    integration after the second stage lammps atomic 
   //    update of Verlet step 2
   //--------------------------------------------------------
   void ATC_Coupling::post_final_integrate()
   {
     double dt = lammpsInterface_->dt();
 
     // update of atomic contributions for fractional step methods
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->pre_final_integrate1(dt);
     }
 
     // Set sources
     prescribedDataMgr_->set_sources(time()+0.5*dt,sources_);
     extrinsicModelManager_.pre_final_integrate();
-    
+
     bool needsSources = false;
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       if ((_tiIt_->second)->has_final_predictor()) {
         needsSources = true;
         break;
       }
     }
     if (needsSources) {
       extrinsicModelManager_.set_sources(fields_,extrinsicSources_);
       atomicRegulator_->compute_boundary_flux(fields_);
       compute_atomic_sources(intrinsicMask_,fields_,atomicSources_);
     }
     atomicRegulator_->apply_pre_corrector(dt,lammpsInterface_->ntimestep());
-
+    
     // Compute atom-integrated rhs
     // parallel communication happens within FE_Engine
     compute_rhs_vector(intrinsicMask_,fields_,rhs_,FE_DOMAIN);
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->add_to_rhs();
     }
     atomicRegulator_->add_to_rhs(rhs_);
     
     // Compute and add atomic contributions to FE equations
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->post_final_integrate1(dt);
     }
-    
+
    // fix nodes, non-group bcs applied through FE
     set_fixed_nodes();
         
     // corrector step extrinsic model
     extrinsicModelManager_.post_final_integrate();
 
     // set state-based sources
     needsSources = false;
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       if ((_tiIt_->second)->has_final_corrector()) {
         needsSources = true;
         break;
       }
     }
     if (needsSources) {
       extrinsicModelManager_.set_sources(fields_,extrinsicSources_);
       atomicRegulator_->compute_boundary_flux(fields_);
       compute_atomic_sources(intrinsicMask_,fields_,atomicSources_);
     }
 
     // Finish update of FE velocity
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->post_final_integrate2(dt);
     }
     
     // apply corrector phase of thermostat
+    set_fixed_nodes();
     atomicRegulator_->apply_post_corrector(dt,lammpsInterface_->ntimestep());
 
     // final phase of time integration
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->post_final_integrate3(dt);
     }
 
     // Fix nodes, non-group bcs applied through FE
     set_fixed_nodes();
     
     update_time(0.5);
     
     output();
     lammpsInterface_->computes_addstep(lammpsInterface_->ntimestep()+1); // adds next step to computes
     //ATC_Method::post_final_integrate();
   }
 
   //=================================================================
   //
   //=================================================================
   void ATC_Coupling::finish()
   {
     ATC_Method::finish();
     // Time integrator
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->finish();
     }
     atomicRegulator_->finish();
   }
 
 
 
   //=================================================================
   //
   //=================================================================
   void ATC_Coupling::compute_boundary_flux(const Array2D<bool> & rhsMask,
                                            const FIELDS & fields, 
                                            FIELDS & rhs,
                                            const Array< set <int> > atomMaterialGroups,
                                            const VectorDependencyManager<SPAR_MAT * > * shpFcnDerivs,
                                            const SPAR_MAN * shpFcn,
                                            const DIAG_MAN * atomicWeights,
                                            
                                            const MatrixDependencyManager<DenseMatrix, bool> * elementMask,
-                                           const RegulatedNodes * nodeSet)
+                                           const SetDependencyManager<int> * nodeSet)
   {
     if (bndyIntType_ == FE_QUADRATURE) {
       feEngine_->compute_boundary_flux(rhsMask,
                                        fields,
                                        physicsModel_,
                                        elementToMaterialMap_,
                                        (* bndyFaceSet_),
                                        rhs);
     }
     else if (bndyIntType_ == FE_INTERPOLATION) {
       if (elementMask) {
         feEngine_->compute_boundary_flux(rhsMask,
                                          fields,
                                          physicsModel_,
                                          elementToMaterialMap_,
                                          atomMaterialGroups,
                                          atomicWeights->quantity(),
                                          shpFcn->quantity(),
                                          shpFcnDerivs->quantity(),
                                          fluxMask_,
                                          rhs,
                                          &elementMask->quantity(),
                                          &nodeSet->quantity());
       }
       else {
         feEngine_->compute_boundary_flux(rhsMask,
                                          fields,
                                          physicsModel_,
                                          elementToMaterialMap_,
                                          atomMaterialGroups_,
                                          atomVolume_->quantity(),
                                          shpFcn_->quantity(),
                                          shpFcnDerivs_->quantity(),
                                          fluxMask_,
                                          rhs);
       }
     }
     else if (bndyIntType_ == NO_QUADRATURE) {
       FIELDS::const_iterator field;
       for (field = fields.begin(); field != fields.end(); field++) {
         FieldName thisFieldName = field->first;
 
 if (thisFieldName >= rhsMask.nRows()) break;
         if (rhsMask(thisFieldName,FLUX)) {
           int nrows = (field->second).nRows();
           int ncols = (field->second).nCols();
           rhs[thisFieldName].reset(nrows,ncols);
         }
       }
     }
   }
 
   //-----------------------------------------------------------------
   void ATC_Coupling::compute_flux(const Array2D<bool> & rhsMask,
                                   const FIELDS & fields, 
                                   GRAD_FIELD_MATS & flux,
-                                  const PhysicsModel * physicsModel) 
+                                  const PhysicsModel * physicsModel,
+                                  bool project) 
   {
     if (! physicsModel) { physicsModel = physicsModel_; }
     feEngine_->compute_flux(rhsMask,
                             fields,
                             physicsModel,
                             elementToMaterialMap_,
                             flux);
+    if (project) {
+      for (FIELDS::const_iterator field = fields.begin(); 
+           field != fields.end(); field++) {
+        FieldName name = field->first;
+        if ( rhsMask(name,FLUX) ) {
+          for(int i=0; i < nsd_ ; ++i) {
+            DENS_MAT & f = flux[name][i];
+if (i==0) f.print("pre flux_"+field_to_string(name)+"_"+ATC_Utility::to_string(i));
+            apply_inverse_mass_matrix(f);
+if (i==0) f.print("flux_"+field_to_string(name)+"_"+ATC_Utility::to_string(i));
+          }
+        }
+      }
+    }
   }
 
-
   //--------------------------------------------------------
 
   void ATC_Coupling::nodal_projection(const FieldName & fieldName,
                                       const PhysicsModel * physicsModel,
                                       FIELD & field)
   {
     FIELDS rhs;
     rhs[fieldName].reset(nNodes_,field.nCols());
     Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
     rhsMask = false;
     rhsMask(fieldName,SOURCE) = true;
     compute_rhs_vector(rhsMask, fields_, rhs, sourceIntegration_, physicsModel);
     const DENS_MAT & B(rhs[fieldName].quantity());
 
     field = (invNodeVolumes_.quantity())*B;
   }
 
   // parse_boundary_integration
   //   parses the boundary integration to determine
   //   the type of boundary integration being used
   //--------------------------------------------------
   
   
   BoundaryIntegrationType ATC_Coupling::parse_boundary_integration(int narg,
                                                                    char **arg,
                                                                    const set< pair<int,int> > * boundaryFaceSet)
   {
     
     int argIndex = 0;
     BoundaryIntegrationType myBoundaryIntegrationType = FE_INTERPOLATION;// default
       if (narg > 0) {
         if(strcmp(arg[argIndex],"faceset")==0) {
           argIndex++;
           myBoundaryIntegrationType = FE_QUADRATURE;
           string name(arg[argIndex]);
           boundaryFaceSet = & ( (feEngine_->fe_mesh())->faceset(name));
           set_boundary_face_set(boundaryFaceSet);
         } 
         else if (strcmp(arg[argIndex],"interpolate")==0) {
           myBoundaryIntegrationType = FE_INTERPOLATION;
         }
         else if (strcmp(arg[argIndex],"no_boundary")==0) { 
           myBoundaryIntegrationType = NO_QUADRATURE; 
         }
         else {
           throw ATC_Error("Bad boundary integration type");
         }
       }
     set_boundary_integration_type(myBoundaryIntegrationType);
     return myBoundaryIntegrationType;
   }
 
 }; // namespace ATC
diff --git a/lib/atc/ATC_Coupling.h b/lib/atc/ATC_Coupling.h
index 7a51ba3b8..002041b53 100644
--- a/lib/atc/ATC_Coupling.h
+++ b/lib/atc/ATC_Coupling.h
@@ -1,456 +1,500 @@
 #ifndef ATC_COUPLING_H
 #define ATC_COUPLING_H
 
 #include <set>
 #include <map>
 #include <string>
 #include <utility>
 
 // ATC headers
 #include "ATC_Method.h"
 #include "ExtrinsicModel.h"
 
 namespace ATC {
 
   // Forward declarations
   class PrescribedDataManager;
   class AtomicRegulator;
   class TimeIntegrator;
   class ReferencePositions;
 
   /**
    *  @class  ATC_Coupling
    *  @brief  Base class for atom-continuum coupling 
    */
 
   class ATC_Coupling : public ATC_Method {
 
   public: /** methods */
     
     friend class ExtrinsicModel; // friend is not inherited
     friend class ExtrinsicModelTwoTemperature;
     friend class ExtrinsicModelDriftDiffusion; 
     friend class ExtrinsicModelDriftDiffusionConvection;
     friend class ExtrinsicModelElectrostatic;
     friend class ExtrinsicModelElectrostaticMomentum;
     friend class SchrodingerPoissonSolver;
     friend class SliceSchrodingerPoissonSolver;
+    friend class GlobalSliceSchrodingerPoissonSolver;
 
     /** constructor */
     ATC_Coupling(std::string groupName, double **& perAtomArray, LAMMPS_NS::Fix * thisFix);
 
     /** destructor */
     virtual ~ATC_Coupling();
 
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
 
     /** pre neighbor */
     virtual void pre_neighbor();
 
     /** pre exchange */
     virtual void pre_exchange();
     virtual void reset_atoms(){};
 
     /** pre force */
     virtual void pre_force();
 
     /** post force */
     virtual void post_force();
 
     /** pre integration run */
     virtual void initialize();
 
     /** flags whether a methods reset is required */
     virtual bool reset_methods() const;
 
     /** post integration run : called at end of run or simulation */
     virtual void finish();
 
     /** first time, before atomic integration */
     virtual void pre_init_integrate();
 
     /** Predictor phase, Verlet first step for velocity and position */
     virtual void init_integrate(); 
 
     /** Predictor phase, executed after Verlet */
     virtual void post_init_integrate();
 
     /** Corrector phase, executed after Verlet*/
     
     virtual void post_final_integrate();
 
     /** pre/post atomic force calculation in minimize */
     virtual void min_pre_force(){};
     virtual void min_post_force(){};
 
     // data access
     /** get map general atomic shape function matrix to overlap region */
     SPAR_MAT &get_atom_to_overlap_mat() {return atomToOverlapMat_.set_quantity();};
     /** get map general atomic shape function matrix to overlap region */
     SPAR_MAN &atom_to_overlap_mat() {return atomToOverlapMat_;};
     /** check if atomic quadrature is being used for MD_ONLY nodes */
     bool atom_quadrature_on(){return atomQuadForInternal_;};
     const std::set<std::string> & boundary_face_names() {return boundaryFaceNames_;};
     /** access to boundary integration method */
     int boundary_integration_type() {return bndyIntType_;};
     void set_boundary_integration_type(int boundaryIntegrationType) 
     {bndyIntType_ = boundaryIntegrationType;};
     void set_boundary_face_set(const std::set< std::pair<int,int> > * boundaryFaceSet) 
     {bndyFaceSet_ = boundaryFaceSet;};
     BoundaryIntegrationType parse_boundary_integration
       (int narg, char **arg, const std::set< std::pair<int,int> > * boundaryFaceSet);
     TemperatureDefType temperature_def() const {return temperatureDef_;};
     void set_temperature_def(TemperatureDefType tdef) {temperatureDef_ = tdef;};
 
 //--------------------------------------------------------
 
     /** access to all boundary fluxes */
     FIELDS &boundary_fluxes() {return boundaryFlux_;}; 
     /** wrapper for FE_Engine's compute_boundary_flux functions */
     void compute_boundary_flux(const Array2D<bool> & rhs_mask,
                                const FIELDS &fields, 
                                FIELDS &rhs,
                                const Array< std::set <int> > atomMaterialGroups,
                                const VectorDependencyManager<SPAR_MAT * > * shpFcnDerivs,
                                const SPAR_MAN * shpFcn = NULL,
                                const DIAG_MAN * atomicWeights = NULL,
                                const MatrixDependencyManager<DenseMatrix, bool> * elementMask = NULL,
-                               const RegulatedNodes * nodeSet = NULL);
+                               const SetDependencyManager<int> * nodeSet = NULL);
     /** access to full right hand side / forcing vector */
     FIELDS &rhs() {return rhs_;};
+    Array2D <bool> rhs_mask() const {
+      Array2D <bool> mask(NUM_FIELDS,NUM_FLUX);
+      mask = false;
+      return mask;
+    }
 
     DENS_MAN &field_rhs(FieldName thisField) { return rhs_[thisField]; };
     /** allow FE_Engine to construct ATC structures after mesh is constructed */
     virtual void initialize_mesh_data(void);  
 
 // public for FieldIntegrator
     bool source_atomic_quadrature(FieldName field)  
-      { return false; }
+      { return (sourceIntegration_ == FULL_DOMAIN_ATOMIC_QUADRATURE_SOURCE); }
     ATC::IntegrationDomainType source_integration() 
       { return sourceIntegration_; }
 
     /** wrapper for FE_Engine's compute_sources */
     void compute_sources_at_atoms(const RHS_MASK & rhsMask,
                                   const FIELDS & fields,
                                   const PhysicsModel * physicsModel,
                                   FIELD_MATS & atomicSources);
     /** computes tangent matrix using atomic quadrature near FE region */
    void masked_atom_domain_rhs_tangent(const std::pair<FieldName,FieldName> row_col,
                                        const RHS_MASK & rhsMask,      
                                        const FIELDS & fields,                  
                                        SPAR_MAT & stiffness,
                                        const PhysicsModel * physicsModel);
     /** wrapper for FE_Engine's compute_rhs_vector functions */
     void compute_rhs_vector(const RHS_MASK & rhs_mask,
                             const FIELDS &fields, 
                             FIELDS &rhs,
                             const IntegrationDomainType domain, // = FULL_DOMAIN
                             const PhysicsModel * physicsModel=NULL);
    /** wrapper for FE_Engine's compute_tangent_matrix */
    void compute_rhs_tangent(const std::pair<FieldName,FieldName> row_col,
                             const RHS_MASK & rhsMask,      
                             const FIELDS & fields,                  
                             SPAR_MAT & stiffness,
                             const IntegrationDomainType integrationType,
                             const PhysicsModel * physicsModel=NULL);
+   void tangent_matrix(const std::pair<FieldName,FieldName> row_col,
+                            const RHS_MASK & rhsMask,      
+                            const PhysicsModel * physicsModel,
+                            SPAR_MAT & stiffness);
 
    /** PDE type */
    WeakEquation::PDE_Type pde_type(const FieldName fieldName) const;
    /** is dynamic PDE */
    bool is_dynamic(const FieldName fieldName) const;
 
 // public for ImplicitSolveOperator
     /** return pointer to PrescribedDataManager */
     PrescribedDataManager * prescribed_data_manager() 
       { return prescribedDataMgr_; }
 // public for Kinetostat
+    // TODO rename to "mass_matrix"
     DIAG_MAT &get_mass_mat(FieldName thisField)
       { return massMats_[thisField].set_quantity();};
+    /** access to underlying mass matrices */
+    MATRIX * mass_matrix(FieldName thisField)
+    {
+      if (!useConsistentMassMatrix_(thisField)) {
+        return & massMats_[thisField].set_quantity();
+      }
+      else {
+        return & consistentMassMats_[thisField].set_quantity();
+      }
+    }
+    /** const access to underlying mass matrices */
+    const MATRIX * mass_matrix(FieldName thisField) const
+    {
+      if (!useConsistentMassMatrix_(thisField)) {
+        MASS_MATS::const_iterator it = massMats_.find(thisField);
+        if (it != massMats_.end()) {
+          return & (it->second).quantity();
+        }
+        else {
+          return NULL;
+        }
+      }
+      else {
+        CON_MASS_MATS::const_iterator it = consistentMassMats_.find(thisField);
+        if (it != consistentMassMats_.end()) {
+          return & (it->second).quantity();
+        }
+        else {
+          return NULL;
+        }
+      }
+    }
     /** */
     DENS_MAN &atomic_source(FieldName thisField){return atomicSources_[thisField];};
 
 
     //---------------------------------------------------------------
     /** \name materials  */
     //---------------------------------------------------------------
     /*@{*/
     /** access to element to material map */
     Array<int> &element_to_material_map(void){return elementToMaterialMap_;}
     /*@}*/
 
     /** check if method is tracking charge */
     bool track_charge() {return trackCharge_;};
 
     void set_mass_mat_time_filter(FieldName thisField,TimeFilterManager::FilterIntegrationType filterIntegrationType);
 
     /** return referece to ExtrinsicModelManager */
     ExtrinsicModelManager & extrinsic_model_manager() 
       { return extrinsicModelManager_; }
     /** access to time integrator */
     const TimeIntegrator * time_integrator(const FieldName & field) const {
       _ctiIt_ = timeIntegrators_.find(field);
       if (_ctiIt_ == timeIntegrators_.end()) return NULL;
       return _ctiIt_->second;
     };
 
     //---------------------------------------------------------------
     /** \name managers */
     //---------------------------------------------------------------
     /*@{*/
     /** allow FE_Engine to construct data manager after mesh is constructed */
     void construct_prescribed_data_manager (void); 
     /** method to create physics model */
     void create_physics_model(const PhysicsType & physicsType,
                               std::string matFileName);
     /** access to physics model */
     PhysicsModel * physics_model() {return physicsModel_; };
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name creation */
     //---------------------------------------------------------------
     /*@{*/
     /** set up atom to material identification */
     virtual void reset_atom_materials();
     /** */
     void reset_node_mask();
     /** */
     void reset_overlap_map();
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name output/restart */
     //---------------------------------------------------------------
     /*@{*/
     void pack_fields(RESTART_LIST & data);
     virtual void  read_restart_data(std::string fileName_, RESTART_LIST & data);
     virtual void write_restart_data(std::string fileName_, RESTART_LIST & data);
     void output() { ATC_Method::output(); }
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name initial & boundary conditions  */
     //---------------------------------------------------------------
     /*@{*/
     /** mask for computation of fluxes */
     void set_fixed_nodes();
     /** set initial conditions by changing fields */
     void set_initial_conditions();
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name sources  */
     //---------------------------------------------------------------
     /** calculate and set matrix of sources_ */
     void set_sources();
     /** assemble various contributions to the heat flux in the atomic region */
     void compute_atomic_sources(const Array2D<bool> & rhs_mask,
                                 const FIELDS &fields, 
                                 FIELDS &atomicSources);
 
     DENS_MAT &get_source(FieldName thisField){return sources_[thisField].set_quantity();};
     DENS_MAN &source(FieldName thisField){return sources_[thisField];};
     FIELDS & sources(){return sources_;};
     /** access to name atomic source terms */
     DENS_MAT &get_atomic_source(FieldName thisField){return atomicSources_[thisField].set_quantity();};
     /** access to name extrinsic source terms */
     DENS_MAT &get_extrinsic_source(FieldName thisField){return extrinsicSources_[thisField].set_quantity();};
     DENS_MAN &extrinsic_source(FieldName thisField){return extrinsicSources_[thisField];};
 
     /** nodal projection of a field through the physics model */
 
     void nodal_projection(const FieldName & fieldName,
                           const PhysicsModel * physicsModel,
                           FIELD & field);
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name fluxes  */
     //---------------------------------------------------------------
     /*@{*/
     /** access for field mask */
     Array2D<bool> &field_mask() {return fieldMask_;}; 
     /** create field mask */
     void reset_flux_mask();
     /** field mask for intrinsic integration */
     Array2D<bool> intrinsicMask_;
     /** wrapper for FE_Engine's compute_flux functions */
     void compute_flux(const Array2D<bool> & rhs_mask,
                       const FIELDS &fields, 
                       GRAD_FIELD_MATS &flux,
-                      const PhysicsModel * physicsModel=NULL);
+                      const PhysicsModel * physicsModel=NULL,
+                      const bool normalize = false);
     /** evaluate rhs on the atomic domain which is near the FE region */
     void masked_atom_domain_rhs_integral(const Array2D<bool> & rhs_mask,
                                          const FIELDS &fields, 
                                          FIELDS &rhs,
                                          const PhysicsModel * physicsModel);
     /** evaluate rhs on a specified domain defined by mask and physics model */
     void evaluate_rhs_integral(const Array2D<bool> & rhs_mask,
                            const FIELDS &fields, 
                            FIELDS &rhs,
                            const IntegrationDomainType domain,
                            const PhysicsModel * physicsModel=NULL);
     /** access to boundary fluxes */
     DENS_MAT &get_boundary_flux(FieldName thisField){return boundaryFlux_[thisField].set_quantity();};
     DENS_MAN &boundary_flux(FieldName thisField){return boundaryFlux_[thisField];};
     /** access to finite element right-hand side data */
     DENS_MAT &get_field_rhs(FieldName thisField)
       { return rhs_[thisField].set_quantity(); };
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name mass matrices  */
     //---------------------------------------------------------------
     /*@{*/
     // atomic field time derivative filtering
     virtual void init_filter(void);
     // mass matrix filtering
     void delete_mass_mat_time_filter(FieldName thisField);
     /** compute mass matrix for requested field */
     void compute_mass_matrix(FieldName thisField, PhysicsModel * physicsModel = NULL);
     /** updates filtering of MD contributions */
     void update_mass_matrix(FieldName thisField);
     /** compute the mass matrix components coming from MD integration */
     virtual void compute_md_mass_matrix(FieldName thisField,
                                         DIAG_MAT & massMats);
 
   private: /** methods */
     ATC_Coupling(); // do not define
 
   protected: /** data */
 
     //---------------------------------------------------------------
     /** initialization routines */
     //---------------------------------------------------------------
     /** sets up all data necessary to define the computational geometry */
     virtual void set_computational_geometry();
     /** constructs all data which is updated with time integration, i.e. fields */
     virtual void construct_time_integration_data();
     /** create methods, e.g. time integrators, filters */
     virtual void construct_methods();
     /** set up data which is dependency managed */
     virtual void construct_transfers();
     /** sets up mol transfers */
     virtual void construct_molecule_transfers();
     /** sets up accumulant & interpolant */
     virtual void construct_interpolant();
     /** reset number of local atoms */
     virtual void reset_nlocal();
 
     //---------------------------------------------------------------
     /** status */
     //---------------------------------------------------------------
     /*@{*/
     /** flag on if FE nodes in MD region should be initialized to projected MD values */
     bool consistentInitialization_;
     bool equilibriumStart_;
     bool useFeMdMassMatrix_;
     /** flag to determine if charge is tracked */
     bool trackCharge_;
     /** temperature definition model */
     TemperatureDefType temperatureDef_;
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name managers */
     //---------------------------------------------------------------
     /*@{*/
     /** prescribed data handler */
     PrescribedDataManager * prescribedDataMgr_;
     /** pointer to physics model */
     PhysicsModel * physicsModel_;
     /** manager for extrinsic models */
     ExtrinsicModelManager extrinsicModelManager_;
     /** manager for regulator */
     AtomicRegulator * atomicRegulator_;
     /** managers for time integrators per field */
     std::map<FieldName,TimeIntegrator * > timeIntegrators_;
     /** time integrator iterator */
     mutable std::map<FieldName,TimeIntegrator * >::iterator _tiIt_;
     /** time integrator const iterator */
     mutable std::map<FieldName,TimeIntegrator * >::const_iterator _ctiIt_;
     /*@}*/
 
     //---------------------------------------------------------------
     /** materials */
     //---------------------------------------------------------------
     /*@{*/
     Array<int> elementToMaterialMap_;  // ATOMIC_TAG * elementToMaterialMap_;
     /** atomic ATC material tag */
     
     
     Array< std::set <int> > atomMaterialGroups_;  // ATOMIC_TAG*atomMaterialGroups_;
     Array< std::set <int> > atomMaterialGroupsMask_;  // ATOMIC_TAG*atomMaterialGroupsMask_;
     /*@}*/
 
     //---------------------------------------------------------------
     /** computational geometry */
     //---------------------------------------------------------------
     /*@{*/
     bool atomQuadForInternal_;  
     MatrixDependencyManager<DenseMatrix, bool> * elementMask_;
     MatrixDependencyManager<DenseMatrix, bool> * elementMaskMass_;
     MatrixDependencyManager<DenseMatrix, bool> * elementMaskMassMd_;
     /** operator to compute the mass matrix for the momentum equation from MD integration */
     AtfShapeFunctionRestriction * nodalAtomicMass_;
     /** operator to compute the dimensionless mass matrix from MD integration */
     AtfShapeFunctionRestriction * nodalAtomicCount_;
     /** operator to compute mass matrix from MD */
     AtfShapeFunctionRestriction * nodalAtomicHeatCapacity_;
     MatrixDependencyManager<DenseMatrix, bool> * create_full_element_mask();
     MatrixDependencyManager<DenseMatrix, int> * create_element_set_mask(const std::string & elementSetName);
     LargeToSmallAtomMap * internalToMask_;
     MatrixDependencyManager<DenseMatrix, int> * internalElement_;
     MatrixDependencyManager<DenseMatrix, int> * ghostElement_;
     DenseMatrixTransfer<int> * nodalGeometryType_;
     /*@}*/
 
     /** \name boundary integration */
     /*@{*/
     /** boundary flux quadrature */
     int bndyIntType_;
     const std::set< std::pair<int,int> > * bndyFaceSet_;
     std::set<std::string> boundaryFaceNames_;
     /*@}*/
 
     //----------------------------------------------------------------
     /** \name shape function matrices */
     //----------------------------------------------------------------
     /*@{*/
     DIAG_MAN * atomicWeightsMask_;
     SPAR_MAN * shpFcnMask_;
     VectorDependencyManager<SPAR_MAT * > * shpFcnDerivsMask_;
     Array<bool> atomMask_;  
     SPAR_MAN atomToOverlapMat_;
     DIAG_MAN nodalMaskMat_;
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name PDE data */
     //---------------------------------------------------------------
     /*@{*/
     /** mask for computation of fluxes */
     Array2D<bool> fieldMask_; 
     DIAG_MAT fluxMask_;
     DIAG_MAT fluxMaskComplement_;
     /** sources */
     FIELDS sources_;
     FIELDS atomicSources_;
     FIELDS extrinsicSources_;
     ATC::IntegrationDomainType sourceIntegration_;
     SPAR_MAT stiffnessAtomDomain_;
     /** rhs/forcing terms */
     FIELDS rhs_;  // for pde
     FIELDS rhsAtomDomain_; // for thermostat
     FIELDS boundaryFlux_; // for thermostat & rhs pde
     // DATA structures for tracking individual species and molecules
     FIELD_POINTERS atomicFields_;
     /*@}*/
 
     // workspace variables
     mutable DENS_MAT _deltaQuantity_;
   };
 };
 
 #endif
diff --git a/lib/atc/ATC_CouplingEnergy.cpp b/lib/atc/ATC_CouplingEnergy.cpp
index 8ba10c4f8..033805490 100644
--- a/lib/atc/ATC_CouplingEnergy.cpp
+++ b/lib/atc/ATC_CouplingEnergy.cpp
@@ -1,412 +1,412 @@
 // ATC_Transfer headers
 #include "ATC_CouplingEnergy.h"
 #include "Thermostat.h"
 #include "ATC_Error.h"
 #include "PrescribedDataManager.h"
 #include "FieldManager.h"
 
 // Other Headers
 #include <vector>
 #include <set>
 #include <utility>
 #include <typeinfo>
 
 using std::string;
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ATC_CouplingEnergy
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ATC_CouplingEnergy::ATC_CouplingEnergy(string groupName,
                                          double ** & perAtomArray,
                                          LAMMPS_NS::Fix * thisFix,
                                          string matParamFile,
                                          ExtrinsicModelType extrinsicModel)
     : ATC_Coupling(groupName,perAtomArray,thisFix),
       nodalAtomicKineticTemperature_(NULL),
       nodalAtomicConfigurationalTemperature_(NULL)
   {
     // Allocate PhysicsModel 
     create_physics_model(THERMAL, matParamFile);
 
     // create extrinsic physics model
     if (extrinsicModel != NO_MODEL) {
       extrinsicModelManager_.create_model(extrinsicModel,matParamFile);  
     }
 
     // Defaults
     set_time();
     bndyIntType_ = FE_INTERPOLATION;
   
     // set up field data based on physicsModel
     physicsModel_->num_fields(fieldSizes_,fieldMask_);
 
     // set up atomic regulator
     atomicRegulator_ = new Thermostat(this);
 
     // set up physics specific time integrator and thermostat
     timeIntegrators_[TEMPERATURE] = new ThermalTimeIntegrator(this,TimeIntegrator::GEAR);
 
     // default physics
     temperatureDef_ = KINETIC;
 
     // output variable vector info:
     // output[1] = total coarse scale thermal energy
     // output[2] = average temperature
     vectorFlag_ = 1;
     sizeVector_ = 2;
     scalarVectorFreq_ = 1;
     extVector_ = 1;
     if (extrinsicModel != NO_MODEL)
       sizeVector_ += extrinsicModelManager_.size_vector(sizeVector_);
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ATC_CouplingEnergy::~ATC_CouplingEnergy()
   {
     // clear out all managed memory to avoid conflicts with dependencies on class member data
     interscaleManager_.clear();
   }
 
   //--------------------------------------------------------
   //  initialize
   //    sets up all the necessary data
   //--------------------------------------------------------
   void ATC_CouplingEnergy::initialize()
   {
     // Base class initalizations
     ATC_Coupling::initialize();
 
     // reset integration field mask
     intrinsicMask_.reset(NUM_FIELDS,NUM_FLUX);
     intrinsicMask_ = false;
     for (int i = 0; i < NUM_FLUX; i++)
       intrinsicMask_(TEMPERATURE,i) = fieldMask_(TEMPERATURE,i);
   }
 
   //--------------------------------------------------------
   //  construct_transfers
   //    constructs needed transfer operators
   //--------------------------------------------------------
   void ATC_CouplingEnergy::construct_transfers()
   {
     ATC_Coupling::construct_transfers();
 
     // always need kinetic energy
     AtomicEnergyForTemperature * atomicTwiceKineticEnergy = new TwiceKineticEnergy(this);
     AtomicEnergyForTemperature * atomEnergyForTemperature = NULL;
 
     // Appropriate per-atom quantity based on desired temperature definition
     if (temperatureDef_==KINETIC) {
       atomEnergyForTemperature = atomicTwiceKineticEnergy;
     }
     else if (temperatureDef_==TOTAL) {
       if (timeIntegrators_[TEMPERATURE]->time_integration_type() != TimeIntegrator::FRACTIONAL_STEP)
         throw ATC_Error("ATC_CouplingEnergy:construct_transfers()  on the fractional step time integrator can be used with non-kinetic defitions of the temperature");
 
       // kinetic energy
       interscaleManager_.add_per_atom_quantity(atomicTwiceKineticEnergy,
                                                "AtomicTwiceKineticEnergy");
 
       // atomic potential energy
       ComputedAtomQuantity * atomicPotentialEnergy = new ComputedAtomQuantity(this,
                                                                               lammpsInterface_->compute_pe_name(),
                                                                               1./(lammpsInterface_->mvv2e()));
       interscaleManager_.add_per_atom_quantity(atomicPotentialEnergy,
                                                "AtomicPotentialEnergy");
 
       // reference potential energy
       AtcAtomQuantity<double> * atomicReferencePotential;
       if (!initialized_) {
         atomicReferencePotential = new AtcAtomQuantity<double>(this);
         interscaleManager_.add_per_atom_quantity(atomicReferencePotential,
                                                  "AtomicReferencePotential");
         atomicReferencePotential->set_memory_type(PERSISTENT);
       }
       else {
         atomicReferencePotential = static_cast<AtcAtomQuantity<double> * >(interscaleManager_.per_atom_quantity("AtomicReferencePotential"));
       }
       nodalRefPotentialEnergy_ = new AtfShapeFunctionRestriction(this,
                                                                  atomicReferencePotential,
                                                                  shpFcn_);
       interscaleManager_.add_dense_matrix(nodalRefPotentialEnergy_,
                                           "NodalAtomicReferencePotential");
 
       // fluctuating potential energy
       AtomicEnergyForTemperature * atomicFluctuatingPotentialEnergy =
         new FluctuatingPotentialEnergy(this,
                                        atomicPotentialEnergy,
                                        atomicReferencePotential);
       interscaleManager_.add_per_atom_quantity(atomicFluctuatingPotentialEnergy,
          "AtomicFluctuatingPotentialEnergy");
 
       // atomic total energy
       atomEnergyForTemperature = new MixedKePeEnergy(this,1,1);
 
       // kinetic temperature measure for post-processing
       // nodal restriction of the atomic energy quantity for the temperature definition
       AtfShapeFunctionRestriction * nodalAtomicTwiceKineticEnergy = new AtfShapeFunctionRestriction(this,
-        atomicTwiceKineticEnergy,
-        shpFcn_);
+                                                                                                    atomicTwiceKineticEnergy,
+                                                                                                    shpFcn_);
       interscaleManager_.add_dense_matrix(nodalAtomicTwiceKineticEnergy,
-                                               "NodalAtomicTwiceKineticEnergy");
+                                          "NodalAtomicTwiceKineticEnergy");
       nodalAtomicKineticTemperature_ = new AtfShapeFunctionMdProjection(this,
         nodalAtomicTwiceKineticEnergy,
         TEMPERATURE);
       interscaleManager_.add_dense_matrix(nodalAtomicKineticTemperature_,
         "NodalAtomicKineticTemperature");
 
       // potential temperature measure for post-processing (must multiply by 2 for configurational temperature
       // nodal restriction of the atomic energy quantity for the temperature definition
       AtfShapeFunctionRestriction * nodalAtomicFluctuatingPotentialEnergy = new AtfShapeFunctionRestriction(this,
         atomicFluctuatingPotentialEnergy,
         shpFcn_);
       interscaleManager_.add_dense_matrix(nodalAtomicFluctuatingPotentialEnergy,
-        "NodalAtomicFluctuatingPotentialEnergy");
+                                          "NodalAtomicFluctuatingPotentialEnergy");
       nodalAtomicConfigurationalTemperature_ = new AtfShapeFunctionMdProjection(this,
         nodalAtomicFluctuatingPotentialEnergy,
         TEMPERATURE);
       interscaleManager_.add_dense_matrix(nodalAtomicConfigurationalTemperature_,
-        "NodalAtomicConfigurationalTemperature");
+                                          "NodalAtomicConfigurationalTemperature");
     }
 
     // register the per-atom quantity for the temperature definition
     interscaleManager_.add_per_atom_quantity(atomEnergyForTemperature,
                                              "AtomicEnergyForTemperature");
     
     // nodal restriction of the atomic energy quantity for the temperature definition
     AtfShapeFunctionRestriction * nodalAtomicEnergy = new AtfShapeFunctionRestriction(this,
-        atomEnergyForTemperature,
-        shpFcn_);
+                                                                                      atomEnergyForTemperature,
+                                                                                      shpFcn_);
     interscaleManager_.add_dense_matrix(nodalAtomicEnergy,
-                                             "NodalAtomicEnergy");
+                                        "NodalAtomicEnergy");
     
     // nodal atomic temperature field
     
     AtfShapeFunctionMdProjection * nodalAtomicTemperature = new AtfShapeFunctionMdProjection(this,
                                                                                              nodalAtomicEnergy,
                                                                                              TEMPERATURE);
     interscaleManager_.add_dense_matrix(nodalAtomicTemperature,
                                         "NodalAtomicTemperature");
 
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->construct_transfers();
     }
     atomicRegulator_->construct_transfers();
   }
 
   //---------------------------------------------------------
   //  init_filter
   //    sets up the time filtering operations in all objects
   //---------------------------------------------------------
   void ATC_CouplingEnergy::init_filter()
   {
     
     TimeIntegrator::TimeIntegrationType timeIntegrationType = timeIntegrators_[TEMPERATURE]->time_integration_type();
     
     
     
     
     if (timeFilterManager_.end_equilibrate()) { 
       if (timeIntegrationType==TimeIntegrator::GEAR) {
         if (equilibriumStart_) {
           
           
           
           if (atomicRegulator_->regulator_target()==AtomicRegulator::DYNAMICS) { // based on FE equation
             DENS_MAT vdotflamMat(-2.*(nodalAtomicFields_[TEMPERATURE].quantity())); // note 2 is for 1/2 vdotflam addition
             atomicRegulator_->reset_lambda_contribution(vdotflamMat);
           }
           else { // based on MD temperature equation
             DENS_MAT vdotflamMat(-1.*(nodalAtomicFields_[TEMPERATURE].quantity()));
             atomicRegulator_->reset_lambda_contribution(vdotflamMat);
           }
         }
       }
       else if (timeIntegrationType==TimeIntegrator::FRACTIONAL_STEP) {
         if (equilibriumStart_) {
           DENS_MAT powerMat(-1.*(nodalAtomicFields_[TEMPERATURE].quantity()));
           atomicRegulator_->reset_lambda_contribution(powerMat);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //  modify
   //    parses inputs and modifies state of the filter
   //--------------------------------------------------------
   bool ATC_CouplingEnergy::modify(int narg, char **arg)
   {
     bool foundMatch = false;
     int argIndx = 0;
     
     // check to see if input is a transfer class command
     // check derived class before base class
 
     // pass-through to thermostat
     if (strcmp(arg[argIndx],"control")==0) {
       argIndx++;
       foundMatch = atomicRegulator_->modify(narg-argIndx,&arg[argIndx]);
     }
 
     // pass-through to timeIntegrator class
     else if (strcmp(arg[argIndx],"time_integration")==0) {
       argIndx++;
       foundMatch = timeIntegrators_[TEMPERATURE]->modify(narg-argIndx,&arg[argIndx]);
     }
 
     // switch for the kind of temperature being used
     /*! \page man_temperature_definition fix_modify AtC temperature_definition
       \section syntax
       fix_modify AtC temperature_definition <kinetic|total>
 
       \section examples
       <TT> fix_modify atc temperature_definition kinetic </TT> \n
 
       \section description
       Change the definition for the atomic temperature used to create the finite element temperature.  The kinetic option is based only on the kinetic energy of the atoms while the total option uses the total energy (kinetic + potential) of an atom.
 
       \section restrictions
       This command is only valid when using thermal coupling.  Also, while not a formal restriction, the user should ensure that associating a potential energy with each atom makes physical sense for the total option to be meaningful.
 
         \section default
         kinetic
       */
     else if (strcmp(arg[argIndx],"temperature_definition")==0) {
       argIndx++;
       string_to_temperature_def(arg[argIndx],temperatureDef_);
       if (temperatureDef_ == TOTAL) {
         setRefPE_ = true;
       }
       foundMatch = true;
       needReset_ = true;
     }
 
     // no match, call base class parser
     if (!foundMatch) {
       foundMatch = ATC_Coupling::modify(narg, arg);
     }
 
     return foundMatch;
 
   }
 
   //--------------------------------------------------------------------
   //     compute_vector
   //--------------------------------------------------------------------
   // this is for direct output to lammps thermo
   double ATC_CouplingEnergy::compute_vector(int n)
   {
     // output[1] = total coarse scale thermal energy
     // output[2] = average temperature
 
     double mvv2e = lammpsInterface_->mvv2e(); // convert to lammps energy units
   
     if (n == 0) {
       Array<FieldName> mask(1);
       FIELD_MATS energy;
       mask(0) = TEMPERATURE;
       
       feEngine_->compute_energy(mask, 
                                 fields_,
                                 physicsModel_,
                                 elementToMaterialMap_,
                                 energy,
                                 &(elementMask_->quantity()));
       
       double phononEnergy = mvv2e * energy[TEMPERATURE].col_sum();
       return phononEnergy;
     }
     else if (n == 1) {
       double aveT = (fields_[TEMPERATURE].quantity()).col_sum()/nNodes_;
       return aveT;
     }
     else if (n > 1) {
       double extrinsicValue = extrinsicModelManager_.compute_vector(n);
       return extrinsicValue;
     }
 
     return 0.;
 
   }
 
   //--------------------------------------------------------------------
   //     output
   //--------------------------------------------------------------------
   void ATC_CouplingEnergy::output()
   {
     if (output_now()) {
       feEngine_->departition_mesh();
 
       // avoid possible mpi calls
       if (nodalAtomicKineticTemperature_)
         _keTemp_ = nodalAtomicKineticTemperature_->quantity();
       if (nodalAtomicConfigurationalTemperature_)
       _peTemp_ = nodalAtomicConfigurationalTemperature_->quantity();
       
       OUTPUT_LIST outputData;
         
       // base class output
       ATC_Method::output();
 
       // push atc fields time integrator modifies into output arrays
       for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
         (_tiIt_->second)->post_process();
       }
 
       // auxilliary data
       for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
         (_tiIt_->second)->output(outputData);
       }
       atomicRegulator_->output(outputData);
       extrinsicModelManager_.output(outputData);
       
       DENS_MAT & temperature(nodalAtomicFields_[TEMPERATURE].set_quantity());
       DENS_MAT & dotTemperature(dot_fields_[TEMPERATURE].set_quantity());
       DENS_MAT & ddotTemperature(ddot_fields_[TEMPERATURE].set_quantity());
       DENS_MAT & rocTemperature(nodalAtomicFieldsRoc_[TEMPERATURE].set_quantity());
       DENS_MAT & fePower(rhs_[TEMPERATURE].set_quantity());
       if (lammpsInterface_->rank_zero()) {
         // global data
         double T_mean   = (fields_[TEMPERATURE].quantity()).col_sum(0)/nNodes_;
         feEngine_->add_global("temperature_mean",  T_mean);
         double T_stddev   = (fields_[TEMPERATURE].quantity()).col_stdev(0);
         feEngine_->add_global("temperature_std_dev",  T_stddev);
         double Ta_mean =  (nodalAtomicFields_[TEMPERATURE].quantity()).col_sum(0)/nNodes_;
         feEngine_->add_global("atomic_temperature_mean",  Ta_mean);
         double Ta_stddev =  (nodalAtomicFields_[TEMPERATURE].quantity()).col_stdev(0); 
         feEngine_->add_global("atomic_temperature_std_dev",  Ta_stddev);
 
         // different temperature measures, if appropriate
         if (nodalAtomicKineticTemperature_)
           outputData["kinetic_temperature"] = & _keTemp_;
         
         if (nodalAtomicConfigurationalTemperature_) {
           _peTemp_ *= 2; // account for full temperature
           outputData["configurational_temperature"] = & _peTemp_;
         }
         
         // mesh data
         outputData["NodalAtomicTemperature"] = &temperature;
         outputData["dot_temperature"] = &dotTemperature;
         outputData["ddot_temperature"] = &ddotTemperature;
         outputData["NodalAtomicPower"] = &rocTemperature;
         outputData["fePower"] = &fePower;
 
         // write data
         feEngine_->write_data(output_index(), fields_, & outputData);
       }
       feEngine_->partition_mesh();
     }
   }
 };
diff --git a/lib/atc/ATC_CouplingMomentumEnergy.cpp b/lib/atc/ATC_CouplingMomentumEnergy.cpp
index 7c1de1bbc..a29603a61 100644
--- a/lib/atc/ATC_CouplingMomentumEnergy.cpp
+++ b/lib/atc/ATC_CouplingMomentumEnergy.cpp
@@ -1,508 +1,512 @@
 // ATC headers
 #include "ATC_CouplingMomentumEnergy.h"
 #include "KinetoThermostat.h"
 #include "ATC_Error.h"
 #include "PrescribedDataManager.h"
+#include "FieldManager.h"
 
 // Other Headers
 #include <vector>
 #include <map>
 #include <set>
 #include <utility>
 #include <typeinfo>
 #include <iostream>
 
 using std::string;
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ATC_CouplingMomentumEnergy
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ATC_CouplingMomentumEnergy::ATC_CouplingMomentumEnergy(string groupName,
                                                          double ** & perAtomArray,
                                                          LAMMPS_NS::Fix * thisFix,
                                                          string matParamFile,
                                                          ExtrinsicModelType extrinsicModel)
     : ATC_Coupling(groupName,perAtomArray,thisFix),
       nodalAtomicKineticTemperature_(NULL),
       nodalAtomicConfigurationalTemperature_(NULL),
       refPE_(0)
   {
     // Allocate PhysicsModel 
     create_physics_model(THERMO_ELASTIC, matParamFile);
 
     // create extrinsic physics model
     if (extrinsicModel != NO_MODEL) {
       extrinsicModelManager_.create_model(extrinsicModel,matParamFile);  
     }
 
     // set up field data based on physicsModel
     physicsModel_->num_fields(fieldSizes_,fieldMask_);
 
     // Defaults
     set_time();
     bndyIntType_ = FE_INTERPOLATION;
     trackCharge_ = false;
 
     // set up atomic regulator
     atomicRegulator_ = new KinetoThermostat(this);
 
     // set up physics specific time integrator and thermostat
     trackDisplacement_ = true;
     fieldSizes_[DISPLACEMENT] = fieldSizes_[VELOCITY];
     timeIntegrators_[VELOCITY] = new MomentumTimeIntegrator(this,TimeIntegrator::FRACTIONAL_STEP);
     timeIntegrators_[TEMPERATURE] = new ThermalTimeIntegrator(this,TimeIntegrator::FRACTIONAL_STEP);
     ghostManager_.set_boundary_dynamics(GhostManager::PRESCRIBED);
 
     // default physics
     temperatureDef_ = KINETIC;
 
     // output variable vector info:
     // output[1] = total coarse scale mechanical kinetic energy
     // output[2] = total coarse scale mechanical potential energy
     // output[3] = total coarse scale mechanical energy
     // output[1] = total coarse scale thermal energy
     // output[2] = average temperature
     scalarFlag_ = 1;
     vectorFlag_ = 1;
     sizeVector_ = 5;
     scalarVectorFreq_ = 1;
     extVector_ = 1;
     if (extrinsicModel != NO_MODEL)
       sizeVector_ += extrinsicModelManager_.size_vector(sizeVector_);
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ATC_CouplingMomentumEnergy::~ATC_CouplingMomentumEnergy()
   {
     // clear out all managed memory to avoid conflicts with dependencies on class member data
     interscaleManager_.clear();
   }
 
   //--------------------------------------------------------
   //  initialize
   //    sets up all the necessary data
   //--------------------------------------------------------
   void ATC_CouplingMomentumEnergy::initialize()
   {
     // clear displacement entries if requested
     if (!trackDisplacement_) {
       fieldSizes_.erase(DISPLACEMENT);
       for (int i = 0; i < NUM_FLUX; i++)
         fieldMask_(DISPLACEMENT,i) = false;
     }
 
     // Base class initalizations
     ATC_Coupling::initialize();
 
     // reset integration field mask
     intrinsicMask_.reset(NUM_FIELDS,NUM_FLUX);
     intrinsicMask_ = false;
     for (int i = 0; i < NUM_FLUX; i++)
       intrinsicMask_(VELOCITY,i) = fieldMask_(VELOCITY,i);
     for (int i = 0; i < NUM_FLUX; i++)
       intrinsicMask_(TEMPERATURE,i) = fieldMask_(TEMPERATURE,i);
 
     refPE_=0;
     refPE_=potential_energy();
   }
 
   //--------------------------------------------------------
   //  construct_transfers
   //    constructs needed transfer operators
   //--------------------------------------------------------
   void ATC_CouplingMomentumEnergy::construct_transfers()
   {
     ATC_Coupling::construct_transfers();
 
     // momentum of each atom
     AtomicMomentum * atomicMomentum = new AtomicMomentum(this);
     interscaleManager_.add_per_atom_quantity(atomicMomentum,
                                              "AtomicMomentum");
     
     // nodal momentum for RHS
     AtfShapeFunctionRestriction * nodalAtomicMomentum = new AtfShapeFunctionRestriction(this,
                                                                                         atomicMomentum,
                                                                                         shpFcn_);
     interscaleManager_.add_dense_matrix(nodalAtomicMomentum,
                                         "NodalAtomicMomentum");
     
     // nodal forces
     FundamentalAtomQuantity * atomicForce = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_FORCE);
     AtfShapeFunctionRestriction * nodalAtomicForce = new AtfShapeFunctionRestriction(this,
                                                                                      atomicForce,
                                                                                      shpFcn_);
     interscaleManager_.add_dense_matrix(nodalAtomicForce,
                                         "NodalAtomicForce");
     
     // nodal velocity derived only from atoms
     AtfShapeFunctionMdProjection * nodalAtomicVelocity = new AtfShapeFunctionMdProjection(this,
                                                                                           nodalAtomicMomentum,
                                                                                           VELOCITY);
     interscaleManager_.add_dense_matrix(nodalAtomicVelocity,
                                         "NodalAtomicVelocity");
     
     if (trackDisplacement_) {
       // mass-weighted (center-of-mass) displacement of each atom
       AtomicMassWeightedDisplacement * atomicMassWeightedDisplacement;
       if (needXrefProcessorGhosts_ || groupbitGhost_) { // explicit construction on internal group
         PerAtomQuantity<double> * atomReferencePositions = interscaleManager_.per_atom_quantity("AtomicInternalReferencePositions");
         atomicMassWeightedDisplacement = new AtomicMassWeightedDisplacement(this,atomPositions_,
                                                                             atomMasses_,
                                                                             atomReferencePositions,
                                                                             INTERNAL);
       }
       else
         atomicMassWeightedDisplacement = new AtomicMassWeightedDisplacement(this);
       interscaleManager_.add_per_atom_quantity(atomicMassWeightedDisplacement,
                                                "AtomicMassWeightedDisplacement");
       
       // nodal (RHS) mass-weighted displacement
       AtfShapeFunctionRestriction * nodalAtomicMassWeightedDisplacement = new AtfShapeFunctionRestriction(this,
                                                                                                           atomicMassWeightedDisplacement,
                                                                                                           shpFcn_);
       interscaleManager_.add_dense_matrix(nodalAtomicMassWeightedDisplacement,
                                           "NodalAtomicMassWeightedDisplacement");
       
       // nodal displacement derived only from atoms
       AtfShapeFunctionMdProjection * nodalAtomicDisplacement = new AtfShapeFunctionMdProjection(this,
                                                                                                 nodalAtomicMassWeightedDisplacement,
                                                                                                 VELOCITY);
       interscaleManager_.add_dense_matrix(nodalAtomicDisplacement,
                                           "NodalAtomicDisplacement");
     }
 
-    // always need kinetic energy
+    // always need fluctuating velocity and kinetic energy
+    
     FtaShapeFunctionProlongation * atomicMeanVelocity = new FtaShapeFunctionProlongation(this,&fields_[VELOCITY],shpFcn_);
     interscaleManager_.add_per_atom_quantity(atomicMeanVelocity,
-                                             "AtomicMeanVelocity");
-    AtomicEnergyForTemperature * atomicTwiceKineticEnergy = new TwiceFluctuatingKineticEnergy(this);
+                                             field_to_prolongation_name(VELOCITY));
+    FieldManager fieldManager(this);
+    PerAtomQuantity<double> * fluctuatingAtomicVelocity = fieldManager.per_atom_quantity("AtomicFluctuatingVelocity"); // also creates ProlongedVelocity
+    AtomicEnergyForTemperature * atomicTwiceKineticEnergy = new TwiceKineticEnergy(this,fluctuatingAtomicVelocity);
     AtomicEnergyForTemperature * atomEnergyForTemperature = NULL;
 
     // Appropriate per-atom quantity based on desired temperature definition
     if (temperatureDef_==KINETIC) {
       atomEnergyForTemperature = atomicTwiceKineticEnergy;
     }
     else if (temperatureDef_==TOTAL) {
       if (timeIntegrators_[TEMPERATURE]->time_integration_type() != TimeIntegrator::FRACTIONAL_STEP)
         throw ATC_Error("ATC_CouplingMomentumEnergy:construct_transfers()  on the fractional step time integrator can be used with non-kinetic defitions of the temperature");
 
       // kinetic energy
       interscaleManager_.add_per_atom_quantity(atomicTwiceKineticEnergy,
                                                "AtomicTwiceKineticEnergy");
 
       // atomic potential energy
       ComputedAtomQuantity * atomicPotentialEnergy = new ComputedAtomQuantity(this,lammpsInterface_->compute_pe_name(),
                                                                               1./(lammpsInterface_->mvv2e()));
       interscaleManager_.add_per_atom_quantity(atomicPotentialEnergy,
                                                "AtomicPotentialEnergy");
 
       // reference potential energy
       AtcAtomQuantity<double> * atomicReferencePotential;
       if (!initialized_) {
         atomicReferencePotential = new AtcAtomQuantity<double>(this);
         interscaleManager_.add_per_atom_quantity(atomicReferencePotential,
                                                  "AtomicReferencePotential");
         atomicReferencePotential->set_memory_type(PERSISTENT);
       }
       else {
         atomicReferencePotential = static_cast<AtcAtomQuantity<double> * >(interscaleManager_.per_atom_quantity("AtomicReferencePotential"));
       }
       nodalRefPotentialEnergy_ = new AtfShapeFunctionRestriction(this,
                                                                  atomicReferencePotential,
                                                                  shpFcn_);
       interscaleManager_.add_dense_matrix(nodalRefPotentialEnergy_,
                                           "NodalAtomicReferencePotential");
 
       // fluctuating potential energy
       AtomicEnergyForTemperature * atomicFluctuatingPotentialEnergy = new FluctuatingPotentialEnergy(this,
                                                                                                      atomicPotentialEnergy,
                                                                                                      atomicReferencePotential);
       interscaleManager_.add_per_atom_quantity(atomicFluctuatingPotentialEnergy,
                                                "AtomicFluctuatingPotentialEnergy");
 
       // atomic total energy
       atomEnergyForTemperature = new MixedKePeEnergy(this,1,1);
 
       // kinetic temperature measure for post-processing
       // nodal restriction of the atomic energy quantity for the temperature definition
       AtfShapeFunctionRestriction * nodalAtomicTwiceKineticEnergy = new AtfShapeFunctionRestriction(this,
                                                                                                     atomicTwiceKineticEnergy,
                                                                                                     shpFcn_);
       interscaleManager_.add_dense_matrix(nodalAtomicTwiceKineticEnergy,
                                           "NodalAtomicTwiceKineticEnergy");
       nodalAtomicKineticTemperature_ = new AtfShapeFunctionMdProjection(this,
                                                                         nodalAtomicTwiceKineticEnergy,
                                                                         TEMPERATURE);
       interscaleManager_.add_dense_matrix(nodalAtomicKineticTemperature_,
                                           "NodalAtomicKineticTemperature");
 
       // potential temperature measure for post-processing (must multiply by 2 for configurational temperature
       // nodal restriction of the atomic energy quantity for the temperature definition
       AtfShapeFunctionRestriction * nodalAtomicFluctuatingPotentialEnergy = new AtfShapeFunctionRestriction(this,
                                                                                                             atomicFluctuatingPotentialEnergy,
                                                                                                             shpFcn_);
       interscaleManager_.add_dense_matrix(nodalAtomicFluctuatingPotentialEnergy,
                                           "NodalAtomicFluctuatingPotentialEnergy");
       nodalAtomicConfigurationalTemperature_ = new AtfShapeFunctionMdProjection(this,
                                                                                 nodalAtomicFluctuatingPotentialEnergy,
                                                                                 TEMPERATURE);
       interscaleManager_.add_dense_matrix(nodalAtomicConfigurationalTemperature_,
                                           "NodalAtomicConfigurationalTemperature");
     }
 
     // register the per-atom quantity for the temperature definition
     interscaleManager_.add_per_atom_quantity(atomEnergyForTemperature,
                                              "AtomicEnergyForTemperature");
     
     // nodal restriction of the atomic energy quantity for the temperature definition
     AtfShapeFunctionRestriction * nodalAtomicEnergy = new AtfShapeFunctionRestriction(this,
                                                                                       atomEnergyForTemperature,
                                                                                       shpFcn_);
     interscaleManager_.add_dense_matrix(nodalAtomicEnergy,
                                         "NodalAtomicEnergy");
     
     // nodal atomic temperature field
     
     AtfShapeFunctionMdProjection * nodalAtomicTemperature = new AtfShapeFunctionMdProjection(this,
                                                                                              nodalAtomicEnergy,
                                                                                              TEMPERATURE);
     interscaleManager_.add_dense_matrix(nodalAtomicTemperature,
                                         "NodalAtomicTemperature");
 
     for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
       (_tiIt_->second)->construct_transfers();
     }
     atomicRegulator_->construct_transfers();
   }
 
   //---------------------------------------------------------
   //  init_filter
   //    sets up the time filtering operations in all objects
   //---------------------------------------------------------
   void ATC_CouplingMomentumEnergy::init_filter()
   {
     if (timeIntegrators_[TEMPERATURE]->time_integration_type() != TimeIntegrator::FRACTIONAL_STEP) {
       throw ATC_Error("ATC_CouplingMomentumEnergy::initialize - method only valid with fractional step time integration");
     }
 
     
     ATC_Coupling::init_filter();
     
     
     
     
     if (timeFilterManager_.end_equilibrate() && equilibriumStart_) {
       if (atomicRegulator_->coupling_mode(VELOCITY)==AtomicRegulator::FLUX || atomicRegulator_->coupling_mode(VELOCITY)==AtomicRegulator::GHOST_FLUX)
         // nothing needed in other cases since kinetostat force is balanced by boundary flux in FE equations
        atomicRegulator_->reset_lambda_contribution(nodalAtomicFieldsRoc_[VELOCITY].quantity(),VELOCITY);
  
       DENS_MAT powerMat(-1.*(nodalAtomicFields_[TEMPERATURE].quantity()));
       atomicRegulator_->reset_lambda_contribution(powerMat,TEMPERATURE);
     }
   }
 
   //--------------------------------------------------------
   //  modify
   //    parses inputs and modifies state of the filter
   //--------------------------------------------------------
   bool ATC_CouplingMomentumEnergy::modify(int narg, char **arg)
   {
     bool foundMatch = false;
     int argIndex = 0;
     return foundMatch;
   }
 
   //--------------------------------------------------------------------
   //     compute_scalar : added energy
   //--------------------------------------------------------------------
   double ATC_CouplingMomentumEnergy::compute_scalar(void)
   {
     double energy = 0.0;
     energy += extrinsicModelManager_.compute_scalar();
     return energy;
   }
 
     //--------------------------------------------------------------------
   //     total kinetic energy
   //--------------------------------------------------------------------
   double ATC_CouplingMomentumEnergy::kinetic_energy(void)
   {
     const MATRIX & M = massMats_[VELOCITY].quantity();
 
     const DENS_MAT & velocity(fields_[VELOCITY].quantity());
     double mvv2e = lammpsInterface_->mvv2e();
     double kineticEnergy = 0;
     DENS_VEC velocitySquared(nNodes_);
     for (int i = 0; i < nNodes_; i++)
       for (int j = 0; j < nsd_; j++)
         velocitySquared(i) += velocity(i,j)*velocity(i,j);
     kineticEnergy = (M*velocitySquared).sum();
     kineticEnergy *= mvv2e; // convert to LAMMPS units
     return kineticEnergy;
   }
   //--------------------------------------------------------------------
   //     total potential energy
   //--------------------------------------------------------------------
   double ATC_CouplingMomentumEnergy::potential_energy(void)
   {
     Array<FieldName> mask(1);
     mask(0) = VELOCITY;
     FIELD_MATS energy;
     feEngine_->compute_energy(mask, 
                                 fields_,
                                 physicsModel_,
                                 elementToMaterialMap_,
                                 energy,
                                 &(elementMask_->quantity()));
     double potentialEnergy = energy[VELOCITY].col_sum();
     double mvv2e = lammpsInterface_->mvv2e();
     potentialEnergy *= mvv2e; // convert to LAMMPS units
     return potentialEnergy-refPE_;
   }
   
   //--------------------------------------------------------------------
   //     compute_vector
   //--------------------------------------------------------------------
   // this is for direct output to lammps thermo
   double ATC_CouplingMomentumEnergy::compute_vector(int n)
   {
     // output[1] = total coarse scale kinetic energy
     // output[2] = total coarse scale potential energy
     // output[3] = total coarse scale energy
     // output[4] = total coarse scale thermal energy
     // output[5] = average temperature
 
     double mvv2e = lammpsInterface_->mvv2e(); // convert to lammps energy units
 
     if (n == 0) {
       return kinetic_energy();
     }
     else if (n == 1) {
       return potential_energy();
     }
     else if (n == 2) {
       return kinetic_energy()+potential_energy();
     }
     else if (n == 4) {
       Array<FieldName> mask(1);
       FIELD_MATS energy;
       mask(0) = TEMPERATURE;
       
       feEngine_->compute_energy(mask, 
                                 fields_,
                                 physicsModel_,
                                 elementToMaterialMap_,
                                 energy,
                                 &(elementMask_->quantity()));
       
       double phononEnergy = mvv2e * energy[TEMPERATURE].col_sum();
       return phononEnergy;
     }
     else if (n == 5) {
       double aveT = (fields_[TEMPERATURE].quantity()).col_sum()/nNodes_;
       return aveT;
     }
     else if (n > 5) {
       double extrinsicValue = extrinsicModelManager_.compute_vector(n);
       return extrinsicValue;
     }
 
     return 0.;
 
   }
 
   //--------------------------------------------------------------------
   //     output
   //--------------------------------------------------------------------
   void ATC_CouplingMomentumEnergy::output()
   {
     if (output_now()) {
       feEngine_->departition_mesh();
       // avoid possible mpi calls
       if (nodalAtomicKineticTemperature_)
         _keTemp_ = nodalAtomicKineticTemperature_->quantity();
       if (nodalAtomicConfigurationalTemperature_)
         _peTemp_ = nodalAtomicConfigurationalTemperature_->quantity();
       
       OUTPUT_LIST outputData;
       
       // base class output
       ATC_Method::output();
 
       // push atc fields time integrator modifies into output arrays
       for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
         (_tiIt_->second)->post_process();
       }
 
       // auxilliary data
       
       for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) {
         (_tiIt_->second)->output(outputData);
       }
       atomicRegulator_->output(outputData);
       extrinsicModelManager_.output(outputData);
         
       DENS_MAT & velocity(nodalAtomicFields_[VELOCITY].set_quantity());
       DENS_MAT & rhs(rhs_[VELOCITY].set_quantity());
       DENS_MAT & temperature(nodalAtomicFields_[TEMPERATURE].set_quantity());
       DENS_MAT & dotTemperature(dot_fields_[TEMPERATURE].set_quantity());
       DENS_MAT & ddotTemperature(ddot_fields_[TEMPERATURE].set_quantity());
       DENS_MAT & rocTemperature(nodalAtomicFieldsRoc_[TEMPERATURE].set_quantity());
       DENS_MAT & fePower(rhs_[TEMPERATURE].set_quantity());
       if (lammpsInterface_->rank_zero()) {
         // global data
         double T_mean   = (fields_[TEMPERATURE].quantity()).col_sum(0)/nNodes_;
         feEngine_->add_global("temperature_mean",  T_mean);
         double T_stddev   = (fields_[TEMPERATURE].quantity()).col_stdev(0);
         feEngine_->add_global("temperature_std_dev",  T_stddev);
         double Ta_mean =  (nodalAtomicFields_[TEMPERATURE].quantity()).col_sum(0)/nNodes_;
         feEngine_->add_global("atomic_temperature_mean",  Ta_mean);
         double Ta_stddev =  (nodalAtomicFields_[TEMPERATURE].quantity()).col_stdev(0); 
         feEngine_->add_global("atomic_temperature_std_dev",  Ta_stddev);
 
         // different temperature measures, if appropriate
         if (nodalAtomicKineticTemperature_)
           outputData["kinetic_temperature"] = & _keTemp_;
         
         if (nodalAtomicConfigurationalTemperature_) {
           _peTemp_ *= 2; // account for full temperature
           outputData["configurational_temperature"] = & _peTemp_;
         }
         
         // mesh data
         outputData["NodalAtomicVelocity"] = &velocity;
         outputData["FE_Force"] = &rhs;
         if (trackDisplacement_)
           outputData["NodalAtomicDisplacement"] = & nodalAtomicFields_[DISPLACEMENT].set_quantity();
         outputData["NodalAtomicTemperature"] = &temperature;
         outputData["dot_temperature"] = &dotTemperature;
         outputData["ddot_temperature"] = &ddotTemperature;
         outputData["NodalAtomicPower"] = &rocTemperature;
         outputData["fePower"] = &fePower;
       
         feEngine_->write_data(output_index(), fields_, & outputData);
       }
       
       //      hence propagation is performed on proc 0 but not others.
       //      The real fix is to have const data in the output list
       // force optional variables to reset to keep in sync
       if (trackDisplacement_) {
         nodalAtomicFields_[DISPLACEMENT].force_reset();
       }
       fields_[VELOCITY].propagate_reset();
 
       feEngine_->partition_mesh();
     }
   }
 
 };
diff --git a/lib/atc/ATC_Error.h b/lib/atc/ATC_Error.h
index 91d3b4dcf..fc356dbec 100644
--- a/lib/atc/ATC_Error.h
+++ b/lib/atc/ATC_Error.h
@@ -1,53 +1,52 @@
 // ATC_Error : a base class for atom-continuum errors
 
 #ifndef ATC_ERROR
 #define ATC_ERROR
 
 #include <string>
 
 // the following two convert __LINE__ to a string
 #define STRING2(x) #x
 #define STRING(x) STRING2(x)
 // prints file and line number for error messages
 #define ERROR(x) __FILE__":"STRING(__LINE__)" "x
 //#define FILELINE __FILE__+to_string(__LINE__)
 #define FILELINE __FILE__
 
 #define ERROR_FOR_BACKTRACE
 #define HACK(l,m)
 
 
-
 namespace ATC {
   /**
    *  @class  ATC_Error
    *  @brief  Base class for throwing run-time errors with descriptions
    */
 
 class ATC_Error {
 
  public:
   // constructor
   ATC_Error(std::string errorDescription)
   {
     errorDescription_ = "ERROR: " + errorDescription;
     ERROR_FOR_BACKTRACE
   };
 
   ATC_Error(std::string location, std::string errorDescription)
   {
     errorDescription_ = "ERROR: " + location + ": "+ errorDescription;
     ERROR_FOR_BACKTRACE
   };
 
   std::string error_description() {
     return errorDescription_;
   };
 
  private:
   // string describing the type of error
   std::string errorDescription_;
 };
 
 }
 #endif
diff --git a/lib/atc/ATC_Method.cpp b/lib/atc/ATC_Method.cpp
index 6acf25efd..b1f3fa254 100644
--- a/lib/atc/ATC_Method.cpp
+++ b/lib/atc/ATC_Method.cpp
@@ -1,2311 +1,2427 @@
 // ATC headers
 #include "ATC_Method.h"
 #include "LammpsInterface.h"
 #include "FE_Engine.h"
 #include "Array.h"
 #include "Array2D.h"
 #include "ATC_Error.h"
 #include "Function.h"
 #include "PrescribedDataManager.h"
 #include "TimeIntegrator.h"
 #include "PhysicsModel.h"
 #include "PerAtomQuantityLibrary.h"
 #include "TransferLibrary.h"
 #include "KernelFunction.h"
 #include "Utility.h"
 #include "FieldManager.h"
 
 #include <fstream>
 #include <sstream>
 #include <iostream>
 
 using ATC_Utility::sgn;
 using ATC_Utility::to_string;
 using ATC_Utility::is_dbl;
 
 using std::stringstream;
 using std::ifstream;
 using std::ofstream;
 using std::string;
 using std::map;
 using std::set;
 using std::vector;
 using std::pair;
 
 namespace ATC {
 
   ATC_Method::ATC_Method(string groupName, double ** & perAtomArray, LAMMPS_NS::Fix * thisFix) :
     nodalAtomicVolume_(NULL),
     needReset_(true),
     lammpsInterface_(LammpsInterface::instance()),
     interscaleManager_(this),
     timeFilterManager_(this),
     integrateInternalAtoms_(false),
     atomTimeIntegrator_(NULL),
     ghostManager_(this),
     feEngine_(NULL),
     initialized_(false),
     meshDataInitialized_(false),
     localStep_(0),
     sizeComm_(8), // 3 positions + 1 material id * 2 for output
     atomCoarseGrainingPositions_(NULL),
     atomGhostCoarseGrainingPositions_(NULL),
     atomProcGhostCoarseGrainingPositions_(NULL),
     atomReferencePositions_(NULL),
+    nNodes_(0),
     nsd_(lammpsInterface_->dimension()),
     xref_(NULL),
     readXref_(false),
     needXrefProcessorGhosts_(false),
     trackDisplacement_(false),
     needsAtomToElementMap_(true),
     atomElement_(NULL),
     atomGhostElement_(NULL),
     internalElementSet_(""),
     atomMasses_(NULL),
     atomPositions_(NULL),
     atomVelocities_(NULL),
     atomForces_(NULL),
     parallelConsistency_(true),
     outputNow_(false),
     outputTime_(true),
     outputFrequency_(0),
     sampleFrequency_(0),
     sampleCounter_(0),
     peScale_(1./(lammpsInterface_->mvv2e())),
     keScale_(1.),
     scalarFlag_(0),
     vectorFlag_(0),
     sizeVector_(0),
     scalarVectorFreq_(0),
     sizePerAtomCols_(4), 
     perAtomOutput_(NULL),
     perAtomArray_(perAtomArray),
     extScalar_(0),
     extVector_(0),
     extList_(NULL),
     thermoEnergyFlag_(0),
     atomVolume_(NULL),
     atomicWeightsWriteFlag_(false),
     atomicWeightsWriteFrequency_(0),
     atomWeightType_(LATTICE),
     domainDecomposition_(REPLICATED_MEMORY),
     groupbit_(0),
     groupbitGhost_(0),
     needProcGhost_(false),
     groupTag_(groupName),
     nLocal_(0),
     nLocalTotal_(0),
     nLocalGhost_(0),
     atomToElementMapType_(LAGRANGIAN),
     atomToElementMapFrequency_(0),
     regionID_(-1),
     mdMassNormalization_(false),
     kernelBased_(false),
     kernelOnTheFly_(false),
     kernelFunction_(NULL),
     bondOnTheFly_(false),
     accumulant_(NULL),
     accumulantMol_(NULL),
     accumulantMolGrad_(NULL),
     accumulantWeights_(NULL),
     accumulantInverseVolumes_(&invNodeVolumes_),
     accumulantBandwidth_(0),
     useRestart_(false),
     hasRefPE_(false),
     setRefPE_(false),
     setRefPEvalue_(false),
     refPEvalue_(0.),
     readRefPE_(false),
     nodalRefPotentialEnergy_(NULL),
     simTime_(0.0),
     stepCounter_(0)
   {
     lammpsInterface_->print_msg_once("version "+version());    
     lammpsInterface_->set_fix_pointer(thisFix);
     interscaleManager_.set_lammps_data_prefix();
     grow_arrays(lammpsInterface_->nmax());
     feEngine_ = new FE_Engine(lammpsInterface_->world());
 
     
     lammpsInterface_->create_compute_pe_peratom();
   }
 
   ATC_Method::~ATC_Method()
   {
     lammpsInterface_->destroy_2d_double_array(xref_);
     lammpsInterface_->destroy_2d_double_array(perAtomOutput_);
     if (atomTimeIntegrator_) delete atomTimeIntegrator_;
     if (feEngine_) delete feEngine_;
   }
 
   //--------------------------------------------------
   // pack_fields
   //   bundle all allocated field matrices into a list
   //   for output needs
   //--------------------------------------------------
   void ATC_Method::pack_fields(RESTART_LIST & data)
   {
     map<FieldName,int>::const_iterator field;
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       string fieldName = field_to_string(thisField);
       string matrixName;
       // copy all fields from ATC_Method.h
       matrixName = "fields_" + fieldName;
       data[matrixName] = & fields_[thisField].set_quantity();
       matrixName = "dot_fields_" + fieldName;
       data[matrixName] = & dot_fields_[thisField].set_quantity();
       matrixName = "ddot_fields_" + fieldName;
       data[matrixName] = & ddot_fields_[thisField].set_quantity();
       matrixName = "dddot_fields_" + fieldName;
       data[matrixName] = & dddot_fields_[thisField].set_quantity();
       matrixName = "NodalAtomicFieldsRoc_" + fieldName;
       data[matrixName] = & nodalAtomicFieldsRoc_[thisField].set_quantity();
     }
   }
   
   //--------------------------------------------------
   // write_restart_file
   //   bundle matrices that need to be saved and call
   //   fe_engine to write the file
   //--------------------------------------------------
   void ATC_Method::write_restart_data(string fileName, RESTART_LIST & data)
   {
     pack_fields(data); 
     feEngine_->write_restart_file(fileName,&data);
   }
 
   //--------------------------------------------------
   // read_restart_file
   //   bundle matrices that need to be saved and call
   //   fe_engine to write the file
   //--------------------------------------------------
   void ATC_Method::read_restart_data(string fileName, RESTART_LIST & data)
   {
     pack_fields(data); 
     feEngine_->read_restart_file(fileName,&data);
   }
 
   //--------------------------------------------------
   // Interactions with LAMMPS fix commands
   // parse input command and pass on to finite element engine 
   //   or physics specific transfers if necessary
   //   revert to physics-specific transfer if no command matches input
   // first keyword is unique to particular class
   // base class keyword matching must apply to ALL physics
   // order:  derived, base, owned objects
   //--------------------------------------------------
   bool ATC_Method::modify(int narg, char **arg)
   {
     int argIdx=0;
     bool match = false; 
     
     // gateways to other modules e.g. extrinsic, control, mesh
     // pass off to fe engine
     if (strcmp(arg[argIdx],"mesh")==0) {
       match = feEngine_->modify(narg, arg); 
       if (feEngine_->has_mesh()  && !meshDataInitialized_) 
         this->initialize_mesh_data();
     }
     // pass off to time filter
     else if (strcmp(arg[argIdx],"filter")==0) { 
       argIdx++;
       match = timeFilterManager_.modify(narg-argIdx,&arg[argIdx]);
 
         // consistentInitialization_ = false; 
     }
     // pass off to kernel function manager
     else if (strcmp(arg[argIdx],"kernel")==0) {
       argIdx++;
 
       if (kernelFunction_) {
         //delete kernelFunction_;
         //resetKernelFunction_ = true;
       }
       kernelFunction_ = KernelFunctionMgr::instance()->function(&arg[argIdx],narg-argIdx); 
       if (kernelFunction_) match = true;
       else ATC_Error("no matching kernel found");
       feEngine_->set_kernel(kernelFunction_);
       
       accumulantMol_=&kernelAccumulantMol_; // KKM add
       accumulantMolGrad_=&kernelAccumulantMolGrad_; // KKM add
     }
     // pass off to ghost manager
     else if (strcmp(arg[argIdx],"boundary_dynamics")==0) {
       argIdx++;
       match = ghostManager_.modify(narg-argIdx,&arg[argIdx]);
     }
 
     // parsing handled here
     else {
       if (strcmp(arg[argIdx],"parallel_consistency")==0) {
         argIdx++;
         //if (!kernelFunction_)          { throw ATC_Error("on_the_fly requires a kernel function"); }
         if (strcmp(arg[argIdx],"off")==0) parallelConsistency_ = false;
         else                              parallelConsistency_ = true;
         match = true;  
       }
      /*! \page man_hardy_on_the_fly fix_modify AtC on_the_fly 
         \section syntax
         fix_modify AtC on_the_fly <bond | kernel> <optional on | off> \n        - bond | kernel (keyword) = specifies on-the-fly calculation of bond or 
 kernel         matrix elements \n
         - on | off (keyword) =  activate or discontinue on-the-fly mode \n 
         \section examples
         <TT> fix_modify AtC on_the_fly bond on </TT> \n        <TT> fix_modify AtC on_the_fly kernel </TT> \n
         <TT> fix_modify AtC on_the_fly kernel off </TT> \n
         \section description
         Overrides normal mode of pre-calculating and storing bond pair-to-node a
 nd 
         kernel atom-to-node matrices. If activated, will calculate elements of t
 hese
         matrices during repeated calls of field computations (i.e. "on-the-fly") and not store them for
         future use.   \n        on flag is optional - if omitted, on_the_fly will be activated for the s
 pecified 
         matrix. Can be deactivated using off flag. \n 
         \section restrictions
         Must be used with the hardy/field type of AtC fix 
         ( see \ref man_fix_atc )
         \section related
         \section default
         By default, on-the-fly calculation is not active (i.e. off). However, code does a memory allocation check to determine if it can store all needed bond and kernel matrix ele ments. If this allocation fails, on-the-fly is activated. \n
       */
 
       else if (strcmp(arg[argIdx],"on_the_fly")==0) {
         argIdx++;
         //if (!kernelFunction_)          { throw ATC_Error("on_the_fly requires a kernel function"); }
         if (strcmp(arg[argIdx],"bond")==0) {
           argIdx++;
           bondOnTheFly_ = true;
           if (narg > argIdx && strcmp(arg[argIdx],"off")==0) bondOnTheFly_ = false;
         }
         else if (strcmp(arg[argIdx],"kernel")==0) {
           argIdx++;
           kernelOnTheFly_ = true;
           if (narg > argIdx && strcmp(arg[argIdx],"off")==0) kernelOnTheFly_ = false;
         }
         else { throw ATC_Error("unsupported on_the_fly type"); }
         match = true;
       }
 
       /*! \page man_output fix_modify AtC output
         \section syntax
         fix_modify AtC output <filename_prefix> <frequency>
         [text | full_text | binary | vector_components | tensor_components ]
         fix_modify AtC output index [step | time ]
         - filename_prefix (string) = prefix for data files 
         - frequency (integer) = frequency of output in time-steps 
         - options (keyword/s): \n
         text = creates text output of index, step and nodal variable values for unique nodes \n
         full_text = creates text output index, nodal id, step, nodal coordinates and nodal variable values for unique and image nodes \n
         binary = creates binary Ensight output \n
         vector_components = outputs vectors as scalar components \n
         tensor_components = outputs tensor as scalar components 
         (use this for Paraview)\n
          
         \section examples
         <TT> fix_modify AtC output heatFE 100 </TT> \n
         <TT> fix_modify AtC output hardyFE 1 text tensor_components </TT> \n
         <TT> fix_modify AtC output hardyFE 10 text binary tensor_components </TT> \n
         <TT> fix_modify AtC output index step </TT> \n
         \section description
         Creates text and/or binary (Ensight, "gold" format) output of nodal/mesh data 
         which is transfer/physics specific. Output indexed by step or time is possible.
         \section restrictions
         \section related 
         see \ref man_fix_atc
         \section default 
         no default format
         output indexed by time
       */
       else if (strcmp(arg[argIdx],"output")==0) {
         argIdx++;
       /*! \page man_output_nodeset fix_modify AtC output nodeset
         \section syntax
         fix_modify AtC output nodeset <nodeset_name> <operation>
         - nodeset_name (string) = name of nodeset to be operated on
         - operation (keyword/s): \n
         sum = creates nodal sum over nodes in specified nodeset \n
         \section examples
         <TT> fix_modify AtC output nodeset nset1 sum </TT> \n
         \section description
         Performs operation over the nodes belonging to specified nodeset
         and outputs resulting variable values to GLOBALS file.
         \section restrictions
         \section related 
         see \ref man_fix_atc
         \section default 
         none
       */
         if (strcmp(arg[argIdx],"nodeset")==0) {
           argIdx++;
           string nset = arg[argIdx++];
           if       (strcmp(arg[argIdx],"sum")==0) {
             argIdx++;
             string field = arg[argIdx];
             pair < string, FieldName >  id(nset,string_to_field(field));
             nsetData_[id] = NODESET_SUM;
             match = true;
           }
           else if (strcmp(arg[argIdx],"average")==0) {
             argIdx++;
             string field = arg[argIdx];
             pair < string, FieldName >  id(nset,string_to_field(field));
             nsetData_[id] = NODESET_AVERAGE;
             match = true;
           }
         }
 
-
       /*! \page man_boundary_integral fix_modify AtC output boundary_integral 
         \section syntax
         fix_modify AtC output boundary_integral [field] faceset [name]
         - field (string) : name of hardy field
         - name (string)  : name of faceset
         \section examples
         <TT> fix_modify AtC output boundary_integral stress faceset loop1 </TT> \n
         \section description
         Calculates a surface integral of the given field dotted with the
         outward normal of the faces and puts output in the "GLOBALS" file
         \section restrictions
         Must be used with the hardy/field type of AtC fix 
         ( see \ref man_fix_atc )
         \section related
         \section default
         none
       */
 
       /*! \page man_contour_integral fix_modify AtC output contour_integral
         \section syntax
         fix_modify AtC output contour_integral [field] faceset [name] <axis [x | y | z
 ]>
         - field (string) : name of hardy field
         - name (string)  : name of faceset
         - axis (string)  : x or y or z
         \section examples
         <TT> fix_modify AtC output contour_integral stress faceset loop1 </TT> \n
         \section description
         Calculates a surface integral of the given field dotted with the
         outward normal of the faces and puts output in the "GLOBALS" file
         \section restrictions
         Must be used with the hardy/field type of AtC fix 
         ( see \ref man_fix_atc )
         \section related
         \section default
         none
       */
 
         else if ( (strcmp(arg[argIdx],"boundary_integral")==0) 
                || (strcmp(arg[argIdx],"contour_integral")==0) ) {
           FacesetIntegralType type = BOUNDARY_INTEGRAL;
           if  (strcmp(arg[argIdx],"contour_integral")==0) 
                               type = CONTOUR_INTEGRAL;
           argIdx++;
           string field(arg[argIdx++]);
           if(strcmp(arg[argIdx],"faceset")==0) {
             argIdx++;
             string name(arg[argIdx++]);
             pair <string,string> pair_name(name,field);
             fsetData_[pair_name] = type;
             match = true;
           }
         } // end "boundary_integral" || "contour_integral"
 
       /*! \page man_output_elementset fix_modify AtC output elementset
         \section syntax
-        fix_modify AtC output volume_integral <eset_name> <field> {`
+        fix_modify AtC output volume_integral <eset_name> <field> 
         - set_name (string) = name of elementset to be integrated over
         - fieldname (string) = name of field to integrate
         csum = creates nodal sum over nodes in specified nodeset \n
         \section examples
         <TT> fix_modify AtC output eset1 mass_density </TT> \n
         \section description
         Performs volume integration of specified field over elementset
         and outputs resulting variable values to GLOBALS file.
         \section restrictions
         \section related 
         see \ref man_fix_atc
         \section default 
         none
       */
 
         else if ( (strcmp(arg[argIdx],"volume_integral")==0) ) {
           argIdx++;
           string name(arg[argIdx++]);
           string field(arg[argIdx++]);
           pair <string,FieldName> pair_name(name,string_to_field(field));
           if (++argIdx < narg) { // keyword average
             esetData_[pair_name] = ELEMENTSET_AVERAGE; 
           }
           else {
             esetData_[pair_name] = ELEMENTSET_TOTAL; 
           }
           match = true;
         }
 
         else if (strcmp(arg[argIdx],"now")==0) {
           argIdx++;
           double dt = 1.0;
           if (argIdx < narg) {
             dt = atof(arg[argIdx++]);
           }
           update_time(dt);
           update_step();
           outputNow_ = true;
           this->output();
           outputNow_ = false;
           match = true;
         }
         else 
           if (strcmp(arg[argIdx],"index")==0) {
             argIdx++;
             if (strcmp(arg[argIdx],"step")==0) { outputTime_ = false; }
             else                               { outputTime_ = true; }
           match = true;
         }
         else {
           outputPrefix_ = arg[argIdx++];
           outputFrequency_ = atoi(arg[argIdx++]);
           bool ensight_output = false, full_text_output = false;
           bool text_output = false, vect_comp = false, tensor_comp = false;
           int rank = lammpsInterface_->comm_rank();
           for (int i = argIdx; i<narg; ++i) {
             if      (strcmp(arg[i],"full_text")==0) full_text_output = true;
             else if (strcmp(arg[i],"text")==0)           text_output = true;
             else if (strcmp(arg[i],"binary")==0)      ensight_output = true;
             else if (strcmp(arg[i],"vector_components")==0) vect_comp = true;
             else if (strcmp(arg[i],"tensor_components")==0) tensor_comp = true;
             else { throw ATC_Error(" output: unknown keyword ");  }
           }
           if (outputFrequency_>0) {
             set<int> otypes;
             if (full_text_output || text_output) {
               lammpsInterface_->print_msg_once("Warning : text output can create _LARGE_ files");
             }
             if (full_text_output) otypes.insert(FULL_GNUPLOT);
             if (text_output)      otypes.insert(GNUPLOT);
             if (ensight_output)   otypes.insert(ENSIGHT);
             if (ntracked() > 0) {
                string fstem = field_to_string(SPECIES_CONCENTRATION);
                string istem = field_to_intrinsic_name(SPECIES_CONCENTRATION);
                vector<string> tnames = tracked_names();
                vector<string> fnames;
                vector<string> inames;
                for (unsigned int i = 0; i < tnames.size(); i++) {
                  fnames.push_back(fstem+tnames[i]);
                  inames.push_back(istem+tnames[i]);
                }
                feEngine_->add_field_names(fstem,fnames);
                feEngine_->add_field_names(istem,inames);
             }
             feEngine_->initialize_output(rank,outputPrefix_,otypes);
             if (vect_comp) 
               feEngine_->output_manager()
                 ->set_option(OUTPUT_VECTOR_COMPONENTS,true);
             if (tensor_comp) 
               feEngine_->output_manager()
                 ->set_option(OUTPUT_TENSOR_COMPONENTS,true);
           }
           match = true;
         }
       }
+    else if (strcmp(arg[argIdx],"write")==0) {
+      argIdx++;
+      FieldName thisField;
+      int thisIndex;
+      parse_field(arg,argIdx,thisField,thisIndex);
+      string nsetName(arg[argIdx++]);
+      string filename(arg[argIdx++]);
+      stringstream  f;
+      set<int> nodeSet = (feEngine_->fe_mesh())->nodeset(nsetName);
+      set<int>::const_iterator iset;
+      const DENS_MAT & field =(fields_.find(thisField)->second).quantity();
+      for (iset = nodeSet.begin(); iset != nodeSet.end(); iset++) {
+        int inode = *iset;
+        double v = field(inode,thisIndex);
+        f << inode << " " << std::setprecision(17) << v << "\n";
+      }
+      LammpsInterface::instance()->write_file(filename,f.str());
+      match = true;
+    }
     // add a species for tracking
     /*! \page man_add_species fix_modify AtC add_species
       \section syntax
       fix_modify_AtC add_species <TAG> <group|type> <ID> \n
       - <TAG> = tag for tracking a species \n
       - group|type = LAMMPS defined group or type of atoms \n
       - <ID> = name of group or type number \n
       \section examples
       <TT> fix_modify AtC add_species gold type 1 </TT> \n
       <TT> group GOLDGROUP type 1 </TT> \n
       <TT> fix_modify AtC add_species gold group GOLDGROUP </TT>
       \section description
       Associates a tag with all atoms of a specified type or within a specified group. \n 
       \section restrictions
       \section related
       \section default
       No defaults for this command. 
     */
     else if (strcmp(arg[argIdx],"add_species")==0) {
       argIdx++;
       string speciesTag = arg[argIdx];
       string tag = arg[argIdx];
       argIdx++;
       if (strcmp(arg[argIdx],"group")==0) {
         if (narg-argIdx == 2) {
           string name = arg[++argIdx];
           int id = lammpsInterface_->group_bit(name);
           groupList_.push_back(id); 
           groupNames_.push_back(tag); 
         } 
         else {
           while (++argIdx < narg) {
             string name = arg[argIdx];
             int id = lammpsInterface_->group_bit(name);
             string tag = speciesTag+"-"+name;
             groupList_.push_back(id); 
             groupNames_.push_back(tag); 
           }
         }
       }
       else if (strcmp(arg[argIdx],"type")==0) {
         if (narg-argIdx == 2) {
           int id = atoi(arg[++argIdx]);
           typeList_.push_back(id); 
           typeNames_.push_back(tag); 
         } 
         else {
           while (++argIdx < narg) {
             int id = atoi(arg[argIdx]);
             string tag = speciesTag+"_"+to_string(id);
             typeList_.push_back(id); 
             typeNames_.push_back(tag); 
           }
         }
       }
       else {
         throw ATC_Error("ATC_Method: add_species only handles groups or types"); }
       match = true;
     }
 
     // remove species from tracking
     
     /*! \page man_remove_species fix_modify AtC remove_species
       \section syntax
       fix_modify_AtC delete_species <TAG> \n
       
       - <TAG> = tag for tracking a species \n
       \section examples
       <TT> fix_modify AtC remove_species gold </TT> \n
       \section description
       Removes tag designated for tracking a specified species. \n 
       \section restrictions
       \section related
       \section default
       No defaults for this command. 
     */
     else if (strcmp(arg[argIdx],"delete_species")==0) {
       argIdx++;
       string tag = arg[argIdx++];
       if (strcmp(arg[argIdx],"group")==0) {
         for (unsigned int j = 0; j < groupList_.size(); j++) {
           if (tag == groupNames_[j]) {
             groupList_.erase(groupList_.begin()+j); 
             groupNames_.erase(groupNames_.begin()+j); 
             break;
           }
         }
       }
       else if (strcmp(arg[argIdx],"type")==0) {
         for (unsigned int j = 0; j < typeList_.size(); j++) {
           if (tag == typeNames_[j]) {
             typeList_.erase(typeList_.begin()+j); 
             typeNames_.erase(typeNames_.begin()+j); 
             break;
           }
         }
       }
       else {
         throw ATC_Error("ATC_Method: delete_species only handles groups or types"); }
       match = true;
       
     }
 
     // add a molecule for tracking
     /*! \page man_add_molecule fix_modify AtC add_molecule
       \section syntax
       fix_modify_AtC add_molecule <small|large> <TAG> <GROUP_NAME> \n
       
       - small|large = can be small if molecule size < cutoff radius, must be large otherwise \n
       - <TAG> = tag for tracking a species \n
       - <GROUP_NAME> = name of group that tracking will be applied to \n   
       \section examples
       <TT> group WATERGROUP type 1 2 </TT> \n
       <TT> fix_modify AtC add_molecule small water WATERGROUP </TT> \n
       \section description
       Associates a tag with all molecules corresponding to a specified group. \n 
       \section restrictions
       \section related
       \section default
       No defaults for this command. 
     */
     else if (strcmp(arg[argIdx],"add_molecule")==0) {
       argIdx++;
       MolSize size;
       if (strcmp(arg[argIdx],"small")==0) {
         size = MOL_SMALL;
         //needXrefProcessorGhosts_ = true;
         needProcGhost_ = true;
       }
       else
         throw ATC_Error("ATC_CouplingMass:  Bad molecule size in add_molecule");
       argIdx++;
       string moleculeTag = arg[argIdx];
       
       argIdx++;
       int groupBit = lammpsInterface_->group_bit(arg[argIdx]);
       moleculeIds_[moleculeTag] = pair<MolSize,int>(size,groupBit);
       match = true;
     }
 
     // remove molecule from tracking
     /*! \page man_remove_molecule fix_modify AtC remove_molecule
       \section syntax
       fix_modify_AtC remove_molecule <TAG> \n
       
       - <TAG> = tag for tracking a molecule type \n
       \section examples
       <TT> fix_modify AtC remove_molecule water </TT> \n
       \section description
       Removes tag designated for tracking a specified set of molecules. \n 
       \section restrictions
       \section related
       \section default
       No defaults for this command. 
     */
     else if (strcmp(arg[argIdx],"remove_molecule")==0) {
       argIdx++;
       string moleculeTag = arg[argIdx];
       moleculeIds_.erase(moleculeTag);
       
       taggedDensMan_.erase(moleculeTag);
     }
           
       /*! \page man_boundary fix_modify AtC boundary 
         \section syntax
         fix_modify AtC boundary type <atom-type-id>
         - <atom-type-id> = type id for atoms that represent a ficticious
         boundary internal to the FE mesh
         \section examples
         <TT> fix_modify AtC boundary type ghost_atoms </TT>
         \section description
         Command to define the atoms that represent the ficticious 
         boundary internal to the FE mesh. For fully overlapped MD/FE 
         domains with periodic boundary conditions no boundary atoms should
         be defined.
         \section restrictions
         \section default 
         none
       */
       else if (strcmp(arg[argIdx],"boundary")==0) {
         argIdx++;
         groupTagGhost_ = arg[argIdx++];
         match = true;
       }
 
       /*! \page man_internal_atom_integrate fix_modify AtC internal_atom_integrate
         \section syntax
         fix_modify AtC internal_atom_integrate <on | off>
         <TT> fix_modify AtC internal_atom_integrate on </TT>
         \section description
         Has AtC perform time integration for the atoms in the group on which it operates.  This does not include boundary atoms.
         \section restrictions
         AtC must be created before any fixes doing time integration.  It must be on for coupling methods which impose constraints on velocities during the first verlet step, e.g. control momentum glc_velocity.
         \section default
         on for coupling methods, off for post-processors
         off
        */
       else if (strcmp(arg[argIdx],"internal_atom_integrate")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"off")==0) {
           integrateInternalAtoms_ = false;
           match = true;
         }
         else {
           integrateInternalAtoms_ = true;
           match = true;
         }
       }
 
       /*! \page man_internal_element_set fix_modify AtC internal_element_set
         \section syntax
         fix_modify AtC internal_element_set <element-set-name>
         - <element-set-name> = name of element set defining internal region, or off
         \section examples
         <TT> fix_modify AtC internal_element_set myElementSet </TT>
         <TT> fix_modify AtC internal_element_set off </TT>
         \section description
         Enables AtC to base the region for internal atoms to be an element set.
         If no ghost atoms are used, all the AtC atoms must be constrained to remain
         in this element set by the user, e.g., with walls.  If boundary atoms are 
         used in conjunction with Eulerian atom maps
         AtC will partition all atoms of a boundary or internal type to be of type internal
         if they are in the internal region or to be of type boundary otherwise.
         \section restrictions
         If boundary atoms are used in conjunction with Eulerian atom maps, the Eulerian
         reset frequency must be an integer multiple of the Lammps reneighbor frequency
         \section related
         see \ref atom_element_map_type and \ref boundary
         \section default
         off
        */
       else if (strcmp(arg[argIdx],"internal_element_set")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"off")==0) {
           internalElementSet_ = "";
           match = true;
         }
         else {
           internalElementSet_ = string(arg[argIdx]);
           const set<int> & elementSet((feEngine_->fe_mesh())->elementset(internalElementSet_)); // check it exists and is not trivial
           if (elementSet.size()==0) throw ATC_Error("internal_element_set - element set " + internalElementSet_ + " has no elements");
           match = true;
         }
       }
 
     /*! \page man_atom_weight fix_modify AtC atom_weight 
       \section syntax
       fix_modify AtC atom_weight <method> <arguments>
         - <method> = \n
           value: atoms in specified group assigned constant value given \n 
           lattice: volume per atom for specified lattice type (e.g. fcc) and parameter \n
           element: element volume divided among atoms within element \n
           region: volume per atom determined based on the atom count in the MD regions and their volumes. Note: meaningful only if atoms completely fill all the regions. \n
           group: volume per atom determined based on the atom count in a group and its volume\n
           read_in: list of values for atoms are read-in from specified file \n
       \section examples
        <TT> fix_modify atc atom_weight constant myatoms 11.8 </TT> \n
        <TT> fix_modify atc atom_weight lattice </TT> \n
        <TT> fix_modify atc atom_weight read-in atm_wt_file.txt </TT> \n
       \section description
        Command for assigning the value of atomic weights used for atomic integration in
        atom-continuum coupled simulations. 
       \section restrictions 
       Use of lattice option requires a lattice type and parameter is already specified.
       \section related
       \section default
       lattice
     */
       else if (strcmp(arg[argIdx],"atom_weight")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"constant")==0) { 
           argIdx++;
           atomWeightType_ = USER;
           int groupbit = -1;
           if (strcmp(arg[argIdx],"all")==0) {
           }
           else {
             groupbit = lammpsInterface_->group_bit(arg[argIdx]);
           }
           argIdx++;
           double value = atof(arg[argIdx]);
           Valpha_[groupbit] = value;
           match = true;
         }
         else if (strcmp(arg[argIdx],"lattice")==0) {
           atomWeightType_ = LATTICE;
           match = true;
         }
         else if (strcmp(arg[argIdx],"element")==0) {
           atomWeightType_ = ELEMENT;
           match = true;
         }
         else if (strcmp(arg[argIdx],"region")==0) {
           atomWeightType_ = REGION;
           match = true;
         }
         else if (strcmp(arg[argIdx],"group")==0) {
           atomWeightType_ = GROUP;
           match = true;
         }
         else if (strcmp(arg[argIdx],"multiscale")==0) {
           atomWeightType_ = MULTISCALE;
           match = true;
         }
         else if (strcmp(arg[argIdx],"node")==0) {
           atomWeightType_ = NODE;
           match = true;
         }
         else if (strcmp(arg[argIdx],"node_element")==0) {
           atomWeightType_ = NODE_ELEMENT;
           match = true;
         }
         else if (strcmp(arg[argIdx],"read_in")==0) {
           atomWeightType_ = READ_IN;
           argIdx++;
           atomicWeightsFile_ = arg[argIdx];
           match = true;
         }
         if (match) {
           needReset_ = true;
         }
       }
 
     /*! \page man_decomposition fix_modify AtC decomposition 
       \section syntax
       fix_modify AtC decomposition <type> 
         - <type> = \n
           replicated_memory: nodal information replicated on each processor \n 
           distributed_memory: only owned nodal information on processor  \n
       \section examples
        <TT> fix_modify atc decomposition distributed_memory </TT> \n
       \section description
        Command for assigning the distribution of work and memory for parallel runs.
       \section restrictions 
       replicated_memory is appropriate for simulations were the number of nodes << number of atoms
       \section related
       \section default
       replicated_memory
     */
       else if (strcmp(arg[argIdx],"decomposition")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"replicated_memory")==0) { 
           domainDecomposition_ = REPLICATED_MEMORY;
           match = true;
         }
         else if (strcmp(arg[argIdx],"distributed_memory")==0) {
           domainDecomposition_ = DISTRIBUTED_MEMORY;
           match = true;
         }
       }
 
     /*! \page man_write_atom_weights fix_modify AtC write_atom_weights
       \section syntax
       fix_modify AtC write_atom_weights <filename> <frequency>
         - <filename> = name of file that atomic weights are written to \n
         - <frequency> = how often writes will occur \n
       \section examples
        <TT> fix_modify atc write_atom_weights atm_wt_file.txt 10 </TT> \n
       \section description
        Command for writing the values of atomic weights to a specified file.
       \section restrictions 
       \section related
       \section default
     */
       else if (strcmp(arg[argIdx],"write_atom_weights")==0) {
         argIdx++;
         atomicWeightsFile_ = arg[argIdx];
         argIdx++;
         atomicWeightsWriteFrequency_ = atoi(arg[argIdx]);
         atomicWeightsWriteFlag_ = true;
         match = true;
       }
 
 
       /*! \page man_reset_time fix_modify AtC reset_time 
       \section syntax
       fix_modify AtC reset_time <value> 
       \section examples
        <TT> fix_modify atc reset_time 0.0 </TT> \n
       \section description
       Resets the simulation time counter. 
       \section restrictions
       \section related
       \section default
       */
       else if (strcmp(arg[argIdx],"reset_time")==0) {
         argIdx++;
         set_time();
         if (narg > argIdx) {
           double time = atof(arg[argIdx]);
           set_time(time);
         }
         match = true;
       }
 
       /*! \page man_reset_time fix_modify AtC kernel_bandwidth
       \section syntax
       fix_modify AtC kernel_bandwidth <value> 
       \section examples
-       <TT> fix_modify atc reset_time 8 </TT> \n
+       <TT> fix_modify atc kernel_bandwidth 8 </TT> \n
       \section description
       Sets a maximum parallel bandwidth for the kernel functions during parallel communication.  If the command is not issued, the default will be to assume the bandwidth of the kernel matrix corresponds to the number of sampling locations.
       \section restrictions
       Only is used if kernel functions are being used.
       \section related
       \section default
       Number of sample locations.
       */
       else if (strcmp(arg[argIdx],"kernel_bandwidth")==0) {
         argIdx++;
         accumulantBandwidth_ = atoi(arg[argIdx]);
         match = true;
       }
 
       /*! \page man_reset_atomic_reference_positions fix_modify AtC reset_atomic_reference_positions 
       \section syntax
       fix_modify AtC reset_atomic_reference_positions
       \section examples
        <TT> fix_modify atc reset_atomic_reference_positions
       \section description
       Resets the atomic positions ATC uses to perform point to field operations.
       In can be used to use perfect lattice sites in ATC but a thermalized or
       deformed lattice in LAMMPS.
       \section restrictions
       \section related
       \section default
       Default is off
       */
       else if (strcmp(arg[argIdx],"reset_atomic_reference_positions")==0) {
         argIdx++;
         xRefFile_ = arg[argIdx];
         readXref_ = true;
         match = true;
       }
 
       /*! \page man_set fix_modify AtC set 
         \section syntax
         fix_modify AtC set reference_potential_energy <value_or_filename(optional)>
         - value (double) : optional user specified zero point for PE in native LAMMPS energy units \n
         - filename (string) : optional user specified string for file of nodal PE values to be read-in 
         \section examples
         <TT> fix_modify AtC set reference_potential_energy </TT> \n
         <TT> fix_modify AtC set reference_potential_energy -0.05 </TT> \n
         <TT> fix_modify AtC set reference_potential_energy myPEvalues </TT> \n
         \section description
         Used to set various quantities for the post-processing algorithms.
         It sets the zero point for the potential energy density using 
         the value provided for all nodes, or from the current 
         configuration of the lattice if no value is provided, or 
         values provided within the specified filename.
         \section restrictions
         Must be used with the hardy/field type of AtC fix 
         ( see \ref man_fix_atc )
         \section related
         \section default
         Defaults to lammps zero point i.e. isolated atoms
       */
       else if (strcmp(arg[argIdx],"set")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"reference_potential_energy")==0) {
           argIdx++;
           setRefPE_ = true;
           if (narg > argIdx) {
             string a(arg[argIdx]);
             if (is_dbl(a)) {
               double value = atof(arg[argIdx]);
               refPEvalue_ = value;
               setRefPEvalue_ = true;
             }
             else {
               nodalRefPEfile_ = arg[argIdx];
               readRefPE_ = true;
             }
           } 
           match = true;
         }
       } // end "set"
 
 
 
       /*! \page man_atom_element_map fix_modify AtC atom_element_map
       \section syntax
       fix_modify AtC atom_element_map  <eulerian|lagrangian> <frequency> \n
       - frequency (int) : frequency of updating atom-to-continuum maps based on the
       current configuration - only for eulerian 
       \section examples
       <TT> fix_modify atc atom_element_map eulerian 100 </TT>
       \section description
       Changes frame of reference from eulerian to lagrangian and sets the
       frequency for which the map from atoms to elements is reformed and 
       all the attendant data is recalculated.
       \section restrictions 
       Cannot change map type after initialization.
       \section related
       \section default
       lagrangian
       */
       else if (strcmp(arg[argIdx],"atom_element_map")==0) {
         argIdx++;
         if (strcmp(arg[argIdx],"eulerian")==0) {
           atomToElementMapType_ = EULERIAN;
           argIdx++;
           atomToElementMapFrequency_ = atoi(arg[argIdx]);
         } 
         else {
           atomToElementMapType_ = LAGRANGIAN;
           atomToElementMapFrequency_ = 0;
         } 
         match = true;
         needReset_ = true;
       }
 
       /*! \page man_read_restart fix_modify AtC read_restart
       \section syntax
       fix_modify AtC read_restart [file_name]  \n
       \section examples
       <TT> fix_modify AtC read_restart ATC_state </TT> \n
       \section description
       Reads the current state of the fields from a named text-based restart 
       file.
       \section restrictions 
       The restart file only contains fields and their time derivatives.
       The reference positions of the atoms and the commands that initialize
       the fix are not saved e.g. an identical mesh containing the same atoms 
       will have to be recreated. 
       \section related
       see write_restart \ref man_write_restart
       \section default
       none
       */
       else if (strcmp(arg[argIdx],"read_restart")==0) {
         argIdx++;
         restartFileName_  = arg[argIdx];
         useRestart_ = true;
         match = true;
       }
 
       /*! \page man_write_restart fix_modify AtC write_restart
       \section syntax
       fix_modify AtC write_restart [file_name]  \n
       \section examples
       <TT> fix_modify AtC write_restart restart.mydata </TT> \n
       \section description
       Dumps the current state of the fields to a named text-based restart file.
       This done when the command is invoked and not repeated, unlike the 
       similar lammps command.
       \section restrictions 
       The restart file only contains fields and their time derivatives.
       The reference positions of the atoms and the commands that initialize
       the fix are not saved e.g. an identical mesh containing the same atoms 
       will have to be recreated. 
       \section related
       see read_restart \ref man_read_restart
       \section default
       none
       */
       else if (strcmp(arg[argIdx],"write_restart")==0) {
         argIdx++;
         string restartFileName(arg[argIdx]);
         RESTART_LIST data;
         write_restart_data(restartFileName,data);
         match = true;
       }
 
     } // end else 
 
     return match; // return to FixATC
   
   }
 
+  //--------------------------------------------------
+  // helper function for parser
+  // handles : "displacement x"  and "temperature" by indexing argIdx
+  // for fluxes : only normal fluxes can be prescribed
+  //--------------------------------------------------
+  void ATC_Method::parse_field(/*const*/ char ** args, int & argIdx,
+                               FieldName & thisField)
+  {
+    string thisName = args[argIdx++];
+    thisField = string_to_field(thisName);
+    map<FieldName,int>::const_iterator iter = fieldSizes_.find(thisField);
+    if (iter == fieldSizes_.end()) {
+      throw ATC_Error("Bad field name: "+thisName);
+    }
+  }
+
   //--------------------------------------------------
   // helper function for parser
   // handles : "displacement x"  and "temperature" by indexing argIdx
   // for fluxes : only normal fluxes can be prescribed
   //--------------------------------------------------
   void ATC_Method::parse_field(/*const*/ char ** args, int & argIdx,
                            FieldName & thisField, int & thisIndex)
   {
     string thisName = args[argIdx++];
     if (args[argIdx] == NULL) {
       throw ATC_Error("Need to give field '"+thisName+"' more args");
     }
     thisField = string_to_field(thisName);
     map<FieldName,int>::const_iterator iter = fieldSizes_.find(thisField);
     if (iter == fieldSizes_.end()) {
       throw ATC_Error("Bad field name: "+thisName);
     }
     string thisDim = args[argIdx];
     thisIndex = 0;
     if (string_to_index(thisDim,thisIndex)) {
       if ( !( thisIndex < fieldSizes_[thisField]) ) {
         throw ATC_Error("Bad field dimension "+thisDim);
       }
       argIdx++;
     }
   }
 
   //-------------------------------------------------------------------
   // this sets the peratom output
   
   void ATC_Method::update_peratom_output()
   {
     perAtomArray_ = perAtomOutput_; 
     // copy values
     for (int i = 0; i < lammpsInterface_->nlocal(); i++) {
       for (int j = 0; j < nsd_; j++) {
         perAtomOutput_[i][j] = xref_[i][j];
       }
       for (int j = nsd_; j < sizePerAtomCols_; j++) {
         perAtomOutput_[i][j] = 0;
       }
     }
     int indx = nsd_;
     if (atomVolume_->nRows() > 0) { // kernel Hardy does not compute these
       const DIAG_MAT & myAtomicWeights(atomVolume_->quantity());
       for (int i = 0; i < nLocal_; i++) {
         double wg = myAtomicWeights(i,i);
         if (wg > 0) {
           int ii = internalToAtom_(i);
           perAtomOutput_[ii][indx] = 1./wg;
         }
       }
     }
   }
 
   void ATC_Method::adjust_xref_pbc()
   {
     
     int nlocal = lammpsInterface_->nlocal();
     int xperiodic = lammpsInterface_->xperiodic();
     int yperiodic = lammpsInterface_->yperiodic();
     int zperiodic = lammpsInterface_->zperiodic();
     double **x = lammpsInterface_->xatom();
     double boxxlo,boxxhi;
     double boxylo,boxyhi;
     double boxzlo,boxzhi;
 
     lammpsInterface_->box_bounds(boxxlo,boxxhi,
                                  boxylo,boxyhi,
                                  boxzlo,boxzhi);
 //  bool changed = false;
     for (int i = 0; i < nlocal; i++) {
       if (xperiodic) {
         if (x[i][0] < boxxlo) {
           xref_[i][0] += Xprd_;
 //        changed = true;
         }
         if (x[i][0] >= boxxhi) { 
           xref_[i][0] -= Xprd_;
 //        changed = true;
         } 
       } 
 
       if (yperiodic) {
         if (x[i][1] < boxylo) {
           xref_[i][1] += Yprd_;
 //        changed = true;
         }
         if (x[i][1] >= boxyhi) {
           xref_[i][1] -= Yprd_;
 //        changed = true;
         } 
       } 
 
       if (zperiodic) {
         if (x[i][2] < boxzlo) {
           xref_[i][2] += Zprd_;
 //        changed = true;
         }
         if (x[i][2] >= boxzhi) {
           xref_[i][2] -= Zprd_;
 //        changed = true;
         } 
       } 
     }
 
     // propagate reset if needed
     if (atomToElementMapType_ == LAGRANGIAN) {
       if (atomCoarseGrainingPositions_) {
         atomCoarseGrainingPositions_->force_reset();
       }
     }
     else if (atomReferencePositions_) {
       atomReferencePositions_->force_reset();
     }
 
   }
   //-------------------------------------------------------------------
   void ATC_Method::initialize()
   { 
     feEngine_->partition_mesh();
     // initialized_ is set to true by derived class initialize()
     // localStep_ is a counter within a run or minimize
     localStep_ = 0;
     // STEP 1)  get basic information data from Lammps/fix
     // 1a)  group ids for all internal atoms
     groupbit_ = lammpsInterface_->group_bit(groupTag_);
 
     // 1b) group ids for ghost atoms
     groupbitGhost_ = 0;
     if (!groupTagGhost_.empty()) {
       groupbitGhost_ = lammpsInterface_->group_bit(groupTagGhost_);
     }
 
     // 1c) periodicity and box bounds/lengths
     if (!initialized_) {
       
       lammpsInterface_->box_periodicity(periodicity[0],
                                             periodicity[1],
                                             periodicity[2]);
       lammpsInterface_->box_bounds(box_bounds[0][0],box_bounds[1][0],
                                        box_bounds[0][1],box_bounds[1][1],
                                        box_bounds[0][2],box_bounds[1][2]);
       for (int k = 0; k < nsd_; k++) {
         box_length[k] = box_bounds[1][k] - box_bounds[0][k]; 
       }
 
       lammpsInterface_->set_reference_box();
 
       // get periodicity data from lammps for parallel exchange to adjust for periodicity
       Xprd_ = lammpsInterface_->domain_xprd();
       Yprd_ = lammpsInterface_->domain_yprd();
       Zprd_ = lammpsInterface_->domain_zprd();
 //    box_length[0] = Xprd_;
 //    box_length[1] = Yprd_;
 //    box_length[2] = Zprd_;
       XY_ = lammpsInterface_->domain_xy();
       XZ_ = lammpsInterface_->domain_xz();
       YZ_ = lammpsInterface_->domain_yz();
     }
 
     // STEP 2 computational geometry
     // 2a) get basic information from continuum/FE
     this->set_continuum_data();
 
     // STEP 2b) set up data structures for computational geometry
     if (this->reset_methods()) {
       // clear memory manager
       interscaleManager_.clear_temporary_data();
       atomVolume_ = NULL;
 
       // reference positions and energy
       if (!initialized_) {
         double **x = lammpsInterface_->xatom();
         for (int i = 0; i < lammpsInterface_->nmax(); i++) {
           for (int j = 0; j < nsd_; j++) {
             xref_[i][j] = x[i][j];
           }
         }
         
         // re-write non-ghosts' xref with values from a file
         if (readXref_) {
           bool success = read_atomic_ref_positions(xRefFile_.c_str());
           if (!success)
             throw ATC_Error("Error reading atomic reference positions");
           readXref_ = false;
         }
 
+        // ensure initial configuration is consistent with element set
+        
+        if (internalElementSet_.size() && groupbitGhost_) {
+          int *mask = lammpsInterface_->atom_mask();
+          int nlocal = lammpsInterface_->nlocal();
+          const FE_Mesh * feMesh = feEngine_->fe_mesh();
+          const set<int> & elementSet(feMesh->elementset(internalElementSet_));
+          int element;
+          DENS_VEC coords(nsd_);
+          for (int i = 0; i < nlocal; ++i) {
+            if (mask[i] & groupbit_ || mask[i] & groupbitGhost_) {
+              for (int j = 0; j < nsd_; j++) {
+                coords(j) = xref_[i][j];
+              }
+              element = feMesh->map_to_element(coords);
+              if (elementSet.find(element) == elementSet.end()) {
+                mask[i] |= groupbitGhost_;
+                mask[i] &= ~groupbit_;
+              }
+              else {
+                mask[i] &= ~groupbitGhost_;
+                mask[i] |= groupbit_;
+              }
+            }
+          }
+        }
+
         // set up maps from lammps to atc indexing
         reset_nlocal();
       }
 
       this->set_computational_geometry();
     }
 
     // 2c) basic data regarding atomic system, e.g. atom coordinates
     if (atomToElementMapType_ == EULERIAN) {
       reset_coordinates();
     }
 
     // STEP 3) set up variables which will be integrated in time
     this->construct_time_integration_data();
 
     // STEP 4) instantiate all the various specific algorithms and methods
     this->construct_methods();
 
     // STEP 5) construct dependency-managed data
     // 5b) all other transfer operators
     // needs to be done before every run in case options have changed or the atoms have been changed by the user
     
     if (this->reset_methods()) {
       // construct all the needed data structures
       this->construct_transfers();
 
       // allocate all space needed for lammps arrays
       interscaleManager_.grow_arrays(lammpsInterface_->nmax());
     }
     // reset all computes invoked flags and lammps data
     interscaleManager_.lammps_force_reset();
  
     // STEP 6) initialize data
     // 6b) size quantities which use pack_comm
     interscaleManager_.size_comm_quantities();
 
     // 6c) set coarse-graining functions and atomic weights
     if (!initialized_) {
       // FE_Engine allocates all required memory
       // assume initial atomic position is the reference position for now
       
       // \int_\Omega N_I dV : static if the mesh is
       NodeVolumes_.reset(nNodes_,nNodes_);
       invNodeVolumes_.reset(nNodes_,nNodes_);
       feEngine_->compute_lumped_mass_matrix(NodeVolumes_);
       invNodeVolumes_.set_quantity() = NodeVolumes_.inv(); 
     }
     atomVolume_->set_reset();
 
     // 6d) reference values
     this->set_reference_potential_energy();
 
     // 6e) atomic output for 0th step
     update_peratom_output();
 
+    massMatInv_.reset(nNodes_,nNodes_);
+    feEngine_->compute_lumped_mass_matrix(massMatInv_);
+    for (int i = 0; i < nNodes_; ++i)  {
+      massMatInv_(i,i) = 1./massMatInv_(i,i);
+    }
+    
     // clear need for resets
     needReset_ = false;
 
   }
   //-------------------------------------------------------------------
   void ATC_Method::set_continuum_data()
   {
     // initialize finite element engine and get basic properties
     if (!initialized_) {
       feEngine_->initialize();
       if (nsd_!=feEngine_->nsd()) {
         throw ATC_Error("Spatial dimensions inconsistent between LAMMPS and ATC");
       }
       nNodes_ = feEngine_->num_nodes();
     }
   }
 
   //-------------------------------------------------------------------
   void ATC_Method::set_computational_geometry()
   {
     // set positions used for coarse-graining operators
     
     
     
     
     if (!initialized_) {
       if (atomToElementMapType_ == EULERIAN) {
         FundamentalAtomQuantity * atomPositionsAll = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_POSITION,ALL);
         ClonedAtomQuantity<double> * myAtomPositions =
           new ClonedAtomQuantity<double>(this,atomPositionsAll,INTERNAL);
         atomCoarseGrainingPositions_ = myAtomPositions;
         interscaleManager_.add_per_atom_quantity(myAtomPositions,
                                                  "AtomicCoarseGrainingPositions");
 
         if (trackDisplacement_) {
           XrefWrapper * myAtomReferencePositions = new XrefWrapper(this);
           atomReferencePositions_ = myAtomReferencePositions;
           interscaleManager_.add_per_atom_quantity(myAtomReferencePositions,
                                                    "AtomicReferencePositions");
           atomReferencePositions_->set_memory_type(PERSISTENT);
         }
 
         if (groupbitGhost_) {
           myAtomPositions = new ClonedAtomQuantity<double>(this,atomPositionsAll,GHOST);
           atomGhostCoarseGrainingPositions_ = myAtomPositions;
           interscaleManager_.add_per_atom_quantity(myAtomPositions,
                                                    "AtomicGhostCoarseGrainingPositions");
         }
         if(needProcGhost_){
           FundamentalAtomQuantity * atomPositionsAll = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_POSITION,PROC_GHOST);
           ClonedAtomQuantity<double> * myAtomPositions =
             new ClonedAtomQuantity<double>(this,atomPositionsAll,PROC_GHOST);
           atomProcGhostCoarseGrainingPositions_ = myAtomPositions;
           interscaleManager_.add_per_atom_quantity(myAtomPositions,
                                                    "AtomicProcGhostCoarseGrainingPositions");
         }  
       }
       else {
         XrefWrapper * myAtomPositions = new XrefWrapper(this);
         atomCoarseGrainingPositions_ = myAtomPositions;
         interscaleManager_.add_per_atom_quantity(myAtomPositions,
                                                  "AtomicCoarseGrainingPositions");
         atomReferencePositions_ = atomCoarseGrainingPositions_;
 
         if (groupbitGhost_) {
           myAtomPositions = new XrefWrapper(this,GHOST);
           atomGhostCoarseGrainingPositions_ = myAtomPositions;
           interscaleManager_.add_per_atom_quantity(myAtomPositions,
                                                    "AtomicGhostCoarseGrainingPositions");
         }
         if (needProcGhost_) {
           XrefWrapper * myAtomPositions = new XrefWrapper(this);
           atomProcGhostCoarseGrainingPositions_ = myAtomPositions;
           interscaleManager_.add_per_atom_quantity(myAtomPositions,
                                                    "AtomicProcGhostCoarseGrainingPositions");
         }
       }
       atomCoarseGrainingPositions_->set_memory_type(PERSISTENT);
       if (atomGhostCoarseGrainingPositions_) atomGhostCoarseGrainingPositions_->set_memory_type(PERSISTENT);
       if (atomProcGhostCoarseGrainingPositions_) atomProcGhostCoarseGrainingPositions_->set_memory_type(PERSISTENT);
     }
 
     // Add in atom to element map if using shape functions
     if (needsAtomToElementMap_) {
       atomElement_ = new AtomToElementMap(this);
       interscaleManager_.add_per_atom_int_quantity(atomElement_,"AtomElement");
     }
   }
 
   //-------------------------------------------------------------------
   void ATC_Method::construct_methods()
   {
     
     if (this->reset_methods()) {
       if (atomTimeIntegrator_) delete atomTimeIntegrator_;
       if (integrateInternalAtoms_) {
         atomTimeIntegrator_ = new AtomTimeIntegratorType(this,INTERNAL);
       }
       else {
         atomTimeIntegrator_ = new AtomTimeIntegrator();
       }
 
       // set up integration schemes for ghosts
       ghostManager_.construct_methods();
     }
   }
 
   //-------------------------------------------------------------------
   void ATC_Method::construct_transfers()
   {
     this->construct_interpolant();
 
     this->construct_molecule_transfers();
 
     atomTimeIntegrator_->construct_transfers();
     ghostManager_.construct_transfers();
 
 
 
   }
   //-------------------------------------------------------------------
   PerAtomDiagonalMatrix<double> * ATC_Method::create_atom_volume()
   {
     if (atomVolume_) {
       return atomVolume_;
     }
     else {
       // set variables to compute atomic weights
       DENS_MAN * nodalVolume(NULL);
       switch (atomWeightType_) {
       case USER:
         atomVolume_ = new AtomVolumeUser(this,Valpha_);
         break;
       case LATTICE:
         atomVolume_ = new AtomVolumeLattice(this);
         break;
       case ELEMENT:
         atomVolume_ = new AtomVolumeElement(this);
         break;
       case REGION:
         atomVolume_ = new AtomVolumeRegion(this);
         break;
       case GROUP:
         atomVolume_ = new AtomVolumeGroup(this,Valpha_);
         break;
       case MULTISCALE:
         if (!shpFcn_) {
           throw ATC_Error("ATC_Method::create_atom_volume - Multiscale algorithm requires an interpolant");
         }
         nodalVolume = new NodalAtomVolume(this,shpFcn_);
         interscaleManager_.add_dense_matrix(nodalVolume,"NodalAtomVolume");
         atomVolume_ = new FtaShapeFunctionProlongationDiagonalMatrix(this,nodalVolume,shpFcn_);
         break;
       case NODE:
         if (!shpFcn_) {
           throw ATC_Error("ATC_Method::create_atom_volume - Node algorithm requires an interpolant");
         }
         nodalVolume = new NodalVolume(this,shpFcn_);
         interscaleManager_.add_dense_matrix(nodalVolume,"NodalVolume");
         atomVolume_ = new FtaShapeFunctionProlongationDiagonalMatrix(this,nodalVolume,shpFcn_);
         break;
       case NODE_ELEMENT:
         if (!shpFcn_) {
           throw ATC_Error("ATC_Method::create_atom_volume - Node-Element algorithm requires an interpolant");
         }
         nodalVolume = new NodalAtomVolumeElement(this,shpFcn_);
         interscaleManager_.add_dense_matrix(nodalVolume,"NodalAtomVolumeElement");
         atomVolume_ = new FtaShapeFunctionProlongationDiagonalMatrix(this,nodalVolume,shpFcn_);
         break;
       case READ_IN:
         atomVolume_ = new AtomVolumeFile(this,atomicWeightsFile_);
         break;
       }
       if (atomVolume_) {
         interscaleManager_.add_per_atom_diagonal_matrix(atomVolume_,"AtomVolume");
       }
       else {
         throw ATC_Error("ATC_Method::create_atom_volume - bad option for atom volume algorithm");
       }
 
       return atomVolume_;
     }
   }
   //--------------------------------------------------------
   void ATC_Method::init_integrate()
   {
     atomTimeIntegrator_->init_integrate_velocity(dt());
     ghostManager_.init_integrate_velocity(dt());
     // account for other fixes doing time integration
     interscaleManager_.fundamental_force_reset(LammpsInterface::ATOM_VELOCITY);
 
     atomTimeIntegrator_->init_integrate_position(dt());
     ghostManager_.init_integrate_position(dt());
     // account for other fixes doing time integration
     interscaleManager_.fundamental_force_reset(LammpsInterface::ATOM_POSITION);
   }
   //-------------------------------------------------------------------
   void ATC_Method::post_init_integrate()
   {
     ghostManager_.post_init_integrate();
   }
   //-------------------------------------------------------------------
   void ATC_Method::pre_exchange()
   {
     adjust_xref_pbc();
     // call interscale manager to sync atc per-atom data with lammps array ahead of parallel communication
     interscaleManager_.prepare_exchange();
 
     // change types based on moving from internal region to ghost region
     if ((atomToElementMapType_ == EULERIAN) && (step() % atomToElementMapFrequency_ == 0)) {
       ghostManager_.pre_exchange();
     }
   }
   //-------------------------------------------------------------------
   void ATC_Method::setup_pre_exchange()
   {
     adjust_xref_pbc();
     // call interscale manager to sync atc per-atom data with lammps array ahead of parallel communication
     interscaleManager_.prepare_exchange();
   }
   //-------------------------------------------------------------------
   void ATC_Method::pre_neighbor()
   {
     // reset quantities arising from atom exchange
     reset_nlocal();
 
     interscaleManager_.post_exchange();
 
     // forward_comm should go here
   }
   //-------------------------------------------------------------------
   void ATC_Method::min_post_force()
   {
     post_force();
   }
   //-------------------------------------------------------------------
   void ATC_Method::post_force()
   {
     // this resets allow for the possibility of other fixes modifying positions and velocities, e.g. walls, but reduces efficiency
     interscaleManager_.lammps_force_reset();
   }
   //--------------------------------------------------------
   void ATC_Method::final_integrate()
   {
     atomTimeIntegrator_->final_integrate(dt());
     ghostManager_.final_integrate(dt());
     // account for other fixes doing time integration
     interscaleManager_.fundamental_force_reset(LammpsInterface::ATOM_VELOCITY);
   }
   //-------------------------------------------------------------------
   void ATC_Method::post_final_integrate()
   {
     if (atomicWeightsWriteFlag_ && (step() % atomicWeightsWriteFrequency_ == 0)) {
       write_atomic_weights(atomicWeightsFile_,atomVolume_->quantity());
     }
   }
   //-------------------------------------------------------------------
   void ATC_Method::end_of_step()
   {
     localStep_ += 1;
   }
   //--------------------------------------------------------------
   void ATC_Method::finish()
   {
     // FE Engine
     if (feEngine_) feEngine_->finish();
     feEngine_->departition_mesh();
   }
 
   //--------------------------------------------------------------
   /** method to add new fields to the included list */
   //--------------------------------------------------------------
   void ATC_Method::add_fields(map<FieldName,int> & newFieldSizes)
   {
     map<FieldName,int>::const_iterator field;
     for (field = newFieldSizes.begin(); field!=newFieldSizes.end(); field++) {
       FieldName thisField = field->first;
       int thisSize = field->second;
       if (fieldSizes_.find(thisField)==fieldSizes_.end()) {
           fieldSizes_[thisField] = thisSize;
       }
     }
   }
  
 //-------------------------------------------------------------------
   void ATC_Method::set_reference_potential_energy(void)
   {
     if (setRefPE_) {
       if (setRefPEvalue_) {
         nodalRefPotentialEnergy_->set_quantity() = refPEvalue_;
         setRefPEvalue_ = false;
       }
       else if (readRefPE_) {
         if (LammpsInterface::instance()->rank_zero()) {
           stringstream ss;
           ss << "reading reference potential energy from " << nodalRefPEfile_;
           LammpsInterface::instance()->print_msg(ss.str());
         }
         (nodalRefPotentialEnergy_->set_quantity()).from_file(nodalRefPEfile_);
         readRefPE_ = false;
       }
       else {
         hasRefPE_ = false;
         SPAR_MAN * referenceAccumulant = interscaleManager_.sparse_matrix("ReferenceAccumulant");
         if (referenceAccumulant) {
           referenceAccumulant->set_quantity() = accumulant_->quantity();
         }
         DIAG_MAN * referenceAccumulantInverseVolumes = interscaleManager_.diagonal_matrix("ReferenceAccumulantInverseVolumes");
         if (referenceAccumulantInverseVolumes) {
           referenceAccumulantInverseVolumes->set_quantity() = accumulantInverseVolumes_->quantity();
         }
         PAQ * atomicRefPe = interscaleManager_.per_atom_quantity("AtomicReferencePotential");
         if (!atomicRefPe) {
           throw ATC_Error("ATC_Method::set_reference_potential_energy - atomic reference PE object was not created during construct_transfers");
         }
         PAQ* pe = interscaleManager_.per_atom_quantity("AtomicPotentialEnergy");
         if (!pe) {
           throw ATC_Error("ATC_Method::set_reference_potential_energy - atomic PE object was not created during construct_transfers");
         }
         atomicRefPe->set_quantity() = pe->quantity();
         atomicRefPe->fix_quantity();
       }
       setRefPE_ = false;
       hasRefPE_ = true;
     }
   }
 //-------------------------------------------------------------------
  
 
   //=================================================================
   // memory management and processor information exchange
   //=================================================================
 
 
   //-----------------------------------------------------------------
   // number of doubles 
   //-----------------------------------------------------------------
   int ATC_Method::doubles_per_atom() const
   {
     
     int doubles = 4;
     doubles += interscaleManager_.memory_usage();
     return doubles;
   }
 
   //-----------------------------------------------------------------
   // memory usage of local atom-based arrays 
   //-----------------------------------------------------------------
   int ATC_Method::memory_usage()
   {
     int bytes = doubles_per_atom();
     bytes *= lammpsInterface_->nmax() * sizeof(double);
     return bytes;
   }
 
   //-----------------------------------------------------------------
   // allocate local atom-based arrays 
   //-----------------------------------------------------------------
   void ATC_Method::grow_arrays(int nmax)
   {
     xref_ =
       lammpsInterface_->grow_2d_double_array(xref_,nmax,3,"fix_atc:xref");
 
     perAtomOutput_ = 
       lammpsInterface_->grow_2d_double_array(perAtomOutput_,nmax,sizePerAtomCols_,"fix_atc:perAtomOutput");
     interscaleManager_.grow_arrays(nmax);
   }
 
   //-----------------------------------------------------------------
   // copy values within local atom-based arrays 
   //-----------------------------------------------------------------
   void ATC_Method::copy_arrays(int i, int j)
   {
     xref_[j][0] = xref_[i][0];
     xref_[j][1] = xref_[i][1];
     xref_[j][2] = xref_[i][2];
 
     for (int ii = 0 ; ii < sizePerAtomCols_ ; ii++ ) {
       perAtomOutput_[j][ii] = perAtomOutput_[i][ii];
     }
     interscaleManager_.copy_arrays(i,j);
   }
 
   //-----------------------------------------------------------------
   // pack values in local atom-based arrays for exchange with another proc 
   //-----------------------------------------------------------------
   int ATC_Method::pack_exchange(int i, double *buf)
   {
     buf[0] = xref_[i][0]; 
     buf[1] = xref_[i][1]; 
     buf[2] = xref_[i][2]; 
     
     int j = 4;
     for (int ii = 0 ; ii < sizePerAtomCols_ ; ii++ ) {
       buf[j++] = perAtomOutput_[i][ii];
     }
     int interscaleSizeComm = interscaleManager_.pack_exchange(i,&buf[j]);
     return sizeComm_ + interscaleSizeComm;
   }
 
   //-----------------------------------------------------------------
   // unpack values in local atom-based arrays from exchange with another proc 
   //-----------------------------------------------------------------
   int ATC_Method::unpack_exchange(int nlocal, double *buf)
   {
     xref_[nlocal][0] = buf[0];
     xref_[nlocal][1] = buf[1];
     xref_[nlocal][2] = buf[2];
 
     int j = 4;
     for (int ii = 0 ; ii < sizePerAtomCols_ ; ii++ ) {
       perAtomOutput_[nlocal][ii] = buf[j++];
     }
     int interscaleSizeComm = interscaleManager_.unpack_exchange(nlocal,&buf[j]);
     return sizeComm_ + interscaleSizeComm;
   }
 
   //-----------------------------------------------------------------
   // pack values in local atom-based arrays from exchange with another proc 
   //-----------------------------------------------------------------
   int ATC_Method::pack_comm(int n, int *list, double *buf, 
                             int pbc_flag, int *pbc)
   {
     int i,j,m;
     double dx = 0,dy = 0,dz = 0;
 
     int * num_bond = lammpsInterface_->num_bond();
     int ** bond_atom = lammpsInterface_->bond_atom();
   
     m = 0;
     if (pbc_flag == 0) {
       for (i = 0; i < n; i++) {
         j = list[i];
         buf[m++] = xref_[j][0];
         buf[m++] = xref_[j][1];
         buf[m++] = xref_[j][2];
         
         if (num_bond) {
           buf[m++] = num_bond[j];
           for (int ii = 0; ii < lammpsInterface_->bond_per_atom(); ii++) {
             buf[m++] = bond_atom[j][ii];
           }
         }
       }
     } 
     else {
       if (lammpsInterface_->domain_triclinic() == 0) {
         dx = pbc[0]*Xprd_;
         dy = pbc[1]*Yprd_;
         dz = pbc[2]*Zprd_;
       } 
       else {
         dx = pbc[0]*Xprd_ + pbc[5]*XY_ + pbc[4]*XZ_;
         dy = pbc[1]*Yprd_ + pbc[3]*YZ_;
         dz = pbc[2]*Zprd_;
       }
       for (i = 0; i < n; i++) {
         j = list[i];
         buf[m++] = xref_[j][0] + dx;
         buf[m++] = xref_[j][1] + dy;
         buf[m++] = xref_[j][2] + dz;
 
         if (num_bond) {
           buf[m++] = num_bond[j];
           for (int ii = 0; ii < lammpsInterface_->bond_per_atom(); ii++) {
             buf[m++] = bond_atom[j][ii];
           }
         }
 
       }
     }
-
-    return m;
-    //int mySize = 3;
-    //if (num_bond)
-    //  mySize += 1 + lammpsInterface_->bond_per_atom();
-    //return mySize;
+    return m;  // total amount of data sent
   }
 
   //-----------------------------------------------------------------
   // unpack values in local atom-based arrays from exchange with another proc 
   //-----------------------------------------------------------------
   void ATC_Method::unpack_comm(int n, int first, double *buf)
   {
     int i,m,last;
 
     int * num_bond = lammpsInterface_->num_bond();
     int ** bond_atom = lammpsInterface_->bond_atom();
 
     m = 0;
     last = first + n;
     for (i = first; i < last; i++) {
       xref_[i][0] = buf[m++];
       xref_[i][1] = buf[m++];
       xref_[i][2] = buf[m++];
       
       if (num_bond) {
         num_bond[i] = static_cast<int>(buf[m++]);
         for (int ii = 0; ii < lammpsInterface_->bond_per_atom(); ii++) {
           bond_atom[i][ii] = static_cast<int>(buf[m++]);
         }
       }
 
     }
   }
 
+  //-----------------------------------------------------------------
+  //
+  //-----------------------------------------------------------------
+  int ATC_Method::comm_forward()
+  {
+    int size = 3;
+    if (lammpsInterface_->num_bond()) 
+      { size += lammpsInterface_->bond_per_atom()+1; }
+    return size;
+  }
+
   //-----------------------------------------------------------------
   //
   //-----------------------------------------------------------------
   void ATC_Method::reset_nlocal()
   {
     nLocalTotal_ = lammpsInterface_->nlocal();
     const int * mask = lammpsInterface_->atom_mask();
     nLocal_ = 0;
     nLocalGhost_ = 0;   
 
     for (int i = 0; i < nLocalTotal_; ++i) {
       if (mask[i] & groupbit_) nLocal_++;
       if (mask[i] & groupbitGhost_) nLocalGhost_++;
     }
 
     // set up internal & ghost maps
     
     if (nLocal_>0) {
       // set map
       internalToAtom_.resize(nLocal_);
       int j = 0;
       // construct internalToAtom map 
       //  : internal index -> local lammps atom index
       for (int i = 0; i < nLocalTotal_; ++i) {
         if (mask[i] & groupbit_) internalToAtom_(j++) = i;
       }
 #ifdef EXTENDED_ERROR_CHECKING
       stringstream ss;
       ss << "Nlocal = " << nLocal_ << " but only found " << j << "atoms";
       if (j!=nLocal_) throw ATC_Error(ss.str());
 #endif
       // construct reverse map
       atomToInternal_.clear();
       for (int i = 0; i < nLocal_; ++i) {
         atomToInternal_[internalToAtom_(i)] = i;
       }
     }
     if (nLocalGhost_>0) {
       // set map
       ghostToAtom_.resize(nLocalGhost_);
       int j = 0;
       for (int i = 0; i < nLocalTotal_; ++i) {
         if (mask[i] & groupbitGhost_) ghostToAtom_(j++) = i;
       }
     }
 
     //WIP_JAT this should not be needed at all, but a memory problem with sparse matrices requires them to be reset (possibly related to note in SparseMatrix-inl.h::_delete())
     interscaleManager_.reset_nlocal();
 
   }
 
   //-------------------------------------------------------------------
   void ATC_Method::reset_coordinates()
   {
     // update coarse graining positions for internal and ghost atoms
     atomCoarseGrainingPositions_->unfix_quantity();
     atomCoarseGrainingPositions_->quantity();
     atomCoarseGrainingPositions_->fix_quantity();
     if (atomGhostCoarseGrainingPositions_) {
       atomGhostCoarseGrainingPositions_->unfix_quantity();
       atomGhostCoarseGrainingPositions_->quantity();
       atomGhostCoarseGrainingPositions_->fix_quantity();
     }
      if (atomProcGhostCoarseGrainingPositions_) {
       atomProcGhostCoarseGrainingPositions_->unfix_quantity();
       atomProcGhostCoarseGrainingPositions_->quantity();
       atomProcGhostCoarseGrainingPositions_->fix_quantity();
     } 
   }
 
   //-----------------------------------------------------------------
   //
   //-----------------------------------------------------------------
   void ATC_Method::write_atomic_weights(const string filename, const DIAG_MAT & atomicVolumeMatrix)
   {
     int nlocal = lammpsInterface_->nlocal();
     int nlocalmax;
     LammpsInterface::instance()->int_allmax(&nlocal,&nlocalmax);           
     int natoms = int(lammpsInterface_->natoms());
     ofstream out;
     const char* fname = &filename[0];
  
     // create tag to local id map for this processor
     map <int,int> id2tag;
     map <int,int>::const_iterator itr;
     int * atom_tag = lammpsInterface_->atom_tag();
     for (int i = 0; i < nlocal; ++i) {
       id2tag[i] = atom_tag[i];
     }
 
     int comm_rank = LammpsInterface::instance()->comm_rank();
     int nprocs;
     LammpsInterface::instance()->int_allmax(&comm_rank,&nprocs);
     nprocs += 1;
 
     if (comm_rank == 0) {
       out.open(fname);
       // print header lines
       out << "Atomic Weights for LAMMPS/atc analysis\n";
       out << " \n";
       out << natoms << " Atoms in system\n";
       out << " \n";
       // print atomic weights from proc 0
       for(int i = 0; i < nlocal; i++) {
         out << id2tag[i] << "  " << atomicVolumeMatrix(i,i) << "\n";
       }
     }
                 
     if (nprocs > 1) {
       int max_size,send_size;
       send_size = nlocal;
       LammpsInterface::instance()->int_allmax(&send_size,&max_size);
 
       if (comm_rank == 0) {
         int intbuf[max_size];
         double buf[max_size];
         for (int iproc = 1; iproc < nprocs; iproc++) {
           LammpsInterface::instance()->int_recv(intbuf,max_size,iproc);
           LammpsInterface::instance()->recv(buf,max_size,iproc);
           for (int i = 0; i < max_size; i++) {
             out << intbuf[i] << "  " << buf[i] << "\n";
           }  
         }
       } else {
         int intbuf[send_size];
         double buf[send_size];
         for (int i = 0; i < send_size; i++) {
           intbuf[i] = id2tag[i];
           buf[i] = atomicVolumeMatrix(i,i);
         }
         LammpsInterface::instance()->int_send(intbuf,send_size);
         LammpsInterface::instance()->send(buf,send_size);
       }
     }
                 
     if (comm_rank == 0) { 
       out.close();
     }           
   }
         
   //-----------------------------------------------------------------
   //
   //-----------------------------------------------------------------
   void ATC_Method::compute_consistent_md_mass_matrix(const SPAR_MAT & shapeFunctionMatrix,
                                                        SPAR_MAT & mdMassMatrix) const
   {
     
     int nCols = shapeFunctionMatrix.nCols();
     DENS_MAT massMatrixLocal(nCols,nCols);
     DENS_MAT denseMdMassMatrix(nCols,nCols);
     if (nLocal_>0)
       massMatrixLocal = shapeFunctionMatrix.transMat(shapeFunctionMatrix);
     
     lammpsInterface_->allsum(massMatrixLocal.ptr(),
                              denseMdMassMatrix.ptr(),
                              denseMdMassMatrix.size());
     mdMassMatrix.reset(denseMdMassMatrix,1.e-10);
   }
 
   //=================================================================
   // Interscale operators
   //=================================================================
   // in the spirit of the current design of ATC: atoms local, nodes global
   
   
   
   
   bool ATC_Method::nodal_influence(const int groupbit,
                               set<int> & nset, set<int> & aset, double tol)
   {
     int nghost = nodal_influence(groupbit,nset,aset,true,tol);
     int local_nghost = nghost;
     lammpsInterface_->int_allsum(&local_nghost,&nghost);
     if (nghost == 0) {
        nodal_influence(groupbit,nset,aset,false,tol);
     }
     return (nghost > 0);
   }
   int ATC_Method::nodal_influence(const int groupbit,
         set<int> & nset, set<int> & aset, bool ghost, double tol)
   {
     Array<int> & amap = (ghost) ? ghostToAtom_ : internalToAtom_;
     int natoms = (ghost) ? nLocalGhost_ : nLocal_;
     DENS_MAT influence(nNodes_,1);
     DENS_MAT atomInfluence(natoms,1);
     const int *mask = lammpsInterface_->atom_mask();
     for (int i = 0; i < natoms; i++) {  
       if (mask[amap(i)] & groupbit) {
          atomInfluence(i,0) = 1;
          aset.insert(i);
       }
     }
     // relies on shape functions
     if (ghost) {
       restrict_volumetric_quantity(atomInfluence,influence,(interscaleManager_.per_atom_sparse_matrix("InterpolantGhost"))->quantity());
     }
     else {
     restrict_volumetric_quantity(atomInfluence,influence); 
     }
 
     DENS_MAT localInfluence = influence;
     lammpsInterface_->allsum(localInfluence.ptr(),
                              influence.ptr(),
                              influence.size());
 
     for (int i = 0; i < nNodes_; i++) {  
       if (fabs(influence(i,0)) > tol)  { nset.insert(i);  }
     }
     return aset.size();
   }
 
 
   //--------------------------------------------------------
   void ATC_Method::restrict_volumetric_quantity(const MATRIX & atomData,
                                                 MATRIX & nodeData,
                                                 const SPAR_MAT & shpFcn)
   {
     // computes nodeData = N*DeltaVAtom*atomData where N are the shape functions
     DENS_MAT workNodeArray(nodeData.nRows(),nodeData.nCols()); 
     //DENS_MAT workNodeArray;
 
 
     if (atomData.nRows() > 0) { // or shpFcn_??? 
       workNodeArray = shpFcn.transMat(atomData);
     }
     int count = nodeData.nRows()*nodeData.nCols();
     lammpsInterface_->allsum(workNodeArray.ptr(),nodeData.ptr(),count);
     return;
   }
 
 
   //--------------------------------------------------------
   void ATC_Method::restrict_volumetric_quantity(const MATRIX & atomData,
                                                 MATRIX & nodeData)
   {
     restrict_volumetric_quantity(atomData,nodeData,shpFcn_->quantity());
     return;
   }
 
 
   //--------------------------------------------------------
   void ATC_Method::prolong(const MATRIX & nodeData,
                              MATRIX & atomData)
   {
     // computes the finite element interpolation at atoms atomData = N*nodeData
     if (nLocal_>0) {
       atomData = (shpFcn_->quantity())*nodeData;
     }
     return;
   }
 
   //========================================================
   // FE functions
   //========================================================
 
   //--------------------------------------------------------
   void ATC_Method::output()
   {
 //  if (lammpsInterface_->comm_rank() == 0) {
       compute_nodeset_output();
       compute_faceset_output();
       compute_elementset_output();
 //  }
   }
   //--------------------------------------------------------
   void ATC_Method::compute_nodeset_output(void) 
   {
     map< pair <string, FieldName>, NodesetOperationType >::const_iterator iter;
     for (iter = nsetData_.begin(); iter != nsetData_.end();iter++){
       pair <string, FieldName> id = iter->first;
       string nsetName = id.first;
       FieldName field = id.second;
       double sum = 0.0;
       const set<int> nset = feEngine_->fe_mesh()->nodeset(nsetName);
       const DENS_MAT & thisField = (fields_.find(field)->second).quantity();
       set< int >::const_iterator itr;
       for (itr = nset.begin(); itr != nset.end();itr++){
         int node = *itr;
         sum += thisField(node,0);
       }
       string name = nsetName + "_" + field_to_string(field);
       if (iter->second == NODESET_AVERAGE) {
         sum /= nset.size();
         name = "average_"+name;
       }
       feEngine_->add_global(name, sum);
     }
   }
   //--------------------------------------------------------
   void ATC_Method::compute_faceset_output(void)
   {
     map < pair<string,string>, FacesetIntegralType >::const_iterator iter;
     DENS_MAT values;
     for (iter = fsetData_.begin(); iter !=  fsetData_.end(); iter++) {
       string bndyName  = (iter->first).first;
       string fieldName = (iter->first).second;
       const set< PAIR > & faceSet = (feEngine_->fe_mesh())->faceset(bndyName);
       ATOMIC_DATA::iterator data_iter = filteredData_.find(fieldName);
       if (data_iter == filteredData_.end()) {
         string msg = "Specified fieldName "+fieldName+
           " not found in filteredData_ while attempting surface integration";
         throw ATC_Error(msg);
       }
       const DENS_MAT & data =  ((data_iter->second).quantity());
       string stem = bndyName + "_" + fieldName + "_";
       bool tf = false;
       if (iter->second == CONTOUR_INTEGRAL) {
         stem = "contour_"+stem;
         tf = true;
       }
       feEngine_->field_surface_flux(data,faceSet,values,tf);
       for (int i = 0; i < values.nRows() ; ++i ) {
         string name = stem + to_string(i+1);
         feEngine_->add_global(name, values(i,0));
       }
     }
   }
   //--------------------------------------------------------
   void ATC_Method::compute_elementset_output(void) 
   {
     map< pair <string, FieldName>, ElementsetOperationType >::const_iterator iter;
     for (iter = esetData_.begin(); iter != esetData_.end();iter++){
       pair <string, FieldName> id = iter->first;
       string esetName = id.first;
       FieldName field = id.second;
       const ESET eset = feEngine_->fe_mesh()->elementset(esetName);
       const DENS_MAT & thisField = (fields_.find(field)->second).quantity();
       DENS_VEC total = feEngine_->integrate(thisField,eset);
       string name = esetName + "_" + field_to_string(field);
       if (iter->second == ELEMENTSET_AVERAGE) {
         DENS_MAT ones(nNodes_,0); ones = 1;
         DENS_VEC V = feEngine_->integrate(ones,eset);
         total /= V[0];
         name = "average_"+name;
       }
       if (total.size() == 1) {
         feEngine_->add_global(name, total[0]);
       }
       else {
         for (int i = 0; i < total.size(); i++) {
           feEngine_->add_global(name+to_string(i), total[i]);
         }
       }
     }
   }
 
 
   //=================================================================
   // 
   //=================================================================
   //--------------------------------------------------------
   bool ATC_Method::read_atomic_ref_positions(const char * filename)
   {
     int nlocal = lammpsInterface_->nlocal();
     ifstream in;
     const int lineSize = 256;
     char line[lineSize];
 
     // create tag to local id map for this processor
     map <int,int> tag2id;
     map <int,int>::const_iterator itr;
     int * atom_tag = lammpsInterface_->atom_tag();
     for (int i = 0; i < nlocal; ++i) {
       tag2id[atom_tag[i]] = i;
     }
 
     // get number of atoms
     int natoms = 0;
+    int ncols = 0;
+    int style = LammpsInterface::CHARGE_STYLE;
     if (LammpsInterface::instance()->rank_zero()) {
       in.open(filename);
       string msg;
       string name = filename;
       msg = "no "+name+" reference file found";
       if (! in.good()) throw ATC_Error(msg);
       in.getline(line,lineSize); // header
       in.getline(line,lineSize); // blank line
       in >> natoms;
-      in.close();
       stringstream ss; 
-      ss << "found " << natoms << " atoms in reference file";
+      ss << "found " << natoms << " atoms in reference " << filename ;
+      while(in.good()) {
+        in.getline(line,lineSize);
+        string str(line);
+        int pos = str.find("Atoms");           
+        if (pos > -1) {
+          in.getline(line,lineSize); // blank line
+          break;
+        }
+      }
+      in.getline(line,lineSize);
+      std::vector<std::string> tokens;
+      ATC_Utility::command_strings(line, tokens);
+      ncols = tokens.size();
+      switch (ncols) {
+      // atomic: id type x y z
+      case 5:
+      case 8:
+         ss << " style:atomic";
+         style = LammpsInterface::ATOMIC_STYLE;
+         break;
+      // charge: id type q x y z 
+      // molecule : id molecule-ID type x y z
+      case 6:
+         ss << " style:charge";
+         style = LammpsInterface::CHARGE_STYLE;
+         break;
+      // full  : id molecule-ID type q x y z
+      case 7:
+         ss << " style:full";
+         style = LammpsInterface::FULL_STYLE;
+         break;
+      default: 
+         throw ATC_Error("cannot determine atom style, columns:"+to_string(ncols));
+         break;
+      }
       LammpsInterface::instance()->print_msg(ss.str());
+      in.close();
     }
     LammpsInterface::instance()->int_broadcast(&natoms);
 
     // read atoms and assign
     if (LammpsInterface::instance()->rank_zero()) {
       in.open(filename); 
       while(in.good()) {
         in.getline(line,lineSize);
         string str(line);
         int pos = str.find("Atoms");           
         if (pos > -1) {
           in.getline(line,lineSize); // blank line
           break;
         }
       }
     }
-    int nread = 0,type = -1, tag = -1, count = 0;
-    double x[3]={0,0,0};
+    int nread = 0,type = -1, tag = -1, count = 0, mId = -1;
+    double x[3]={0,0,0}, q =0;
     while (nread < natoms) {
       if (LammpsInterface::instance()->rank_zero()) {
          in.getline(line,lineSize);
          stringstream ss (line,stringstream::in | stringstream::out);
+         if      (style == LammpsInterface::CHARGE_STYLE) 
+         ss >> tag >> type >> q >> x[0] >> x[1] >> x[2]; 
+         else if (style == LammpsInterface::FULL_STYLE) 
+         ss >> tag >> mId >> type >> q >> x[0] >> x[1] >> x[2]; 
+         else
          ss >> tag >> type >> x[0] >> x[1] >> x[2]; 
          nread++;
       }
       LammpsInterface::instance()->int_broadcast(&nread);
       LammpsInterface::instance()->int_broadcast(&tag);
       LammpsInterface::instance()->broadcast(x,3);
       itr = tag2id.find(tag);
       if (itr != tag2id.end()) {
         int iatom = itr->second;
         xref_[iatom][0] = x[0];
         xref_[iatom][1] = x[1];
         xref_[iatom][2] = x[2];
         count++;
       }
     }
     if (LammpsInterface::instance()->rank_zero()) {
       in.close();
       stringstream ss; 
       ss << "read  " << natoms << " reference positions";
       LammpsInterface::instance()->print_msg(ss.str());
     }
     if (count != nlocal) 
        throw ATC_Error("reset "+to_string(count)+" atoms vs "+to_string(nlocal));
 
 
     return true;
   }  
 
 //--------------------------------------------------------
   void ATC_Method::remap_ghost_ref_positions(void)
   {
     
     int nlocal = lammpsInterface_->nlocal();
     int nghost = lammpsInterface_->nghost();
 
     double box_bounds[2][3];
     lammpsInterface_->box_bounds(box_bounds[0][0],box_bounds[1][0],
                                     box_bounds[0][1],box_bounds[1][1],
                                     box_bounds[0][2],box_bounds[1][2]);
     double xlo = box_bounds[0][0], xhi = box_bounds[1][0];
     double ylo = box_bounds[0][1], yhi = box_bounds[1][1];
     double zlo = box_bounds[0][2], zhi = box_bounds[1][2];
 
     double box_length[3];
     for (int k = 0; k < 3; k++) {
       box_length[k] = box_bounds[1][k] - box_bounds[0][k];
     }
     double Lx = box_length[0], Ly = box_length[1], Lz = box_length[2];
 
     // create tag to local id map for this processor
     map <int,int> tag2id;
     map <int,int>::const_iterator itr;
     int * atom_tag = lammpsInterface_->atom_tag();
     for (int i = 0; i < nlocal; ++i) {
       tag2id[atom_tag[i]] = i;
     }
     
     // loop over ghosts
     double ** x = lammpsInterface_->xatom();
     for (int j = nlocal; j < nlocal + nghost; j++) {
       int tag = atom_tag[j];
       int i = tag2id[tag];
       //itr = tag2id.find(tag);
       //if (itr != tag2id.end()) 
       double* xj = x[j];
       double* Xj = xref_[j];
       //double Xj[3];
       double* Xi = xref_[i];
       // the assumption is that xref_[j] has been shuffled 
       // so make an image of xref_[i] that is close to x[j]
       if (xj[0] <= xlo) Xj[0] = Xi[0] -Lx; 
       if (xj[0] >= xhi) Xj[0] = Xi[0] +Lx; 
       if (xj[1] <= ylo) Xj[1] = Xi[1] -Ly; 
       if (xj[1] >= yhi) Xj[1] = Xi[1] +Ly; 
       if (xj[2] <= zlo) Xj[2] = Xi[2] -Lz;
       if (xj[2] >= zhi) Xj[2] = Xi[2] +Lz; 
     }
   }
 };
diff --git a/lib/atc/ATC_Method.h b/lib/atc/ATC_Method.h
index d7708d298..aa8f23872 100644
--- a/lib/atc/ATC_Method.h
+++ b/lib/atc/ATC_Method.h
@@ -1,863 +1,870 @@
 #ifndef ATC_METHOD_H
 #define ATC_METHOD_H
 
 // ATC_Method headers
 #include "ATC_TypeDefs.h"
 #include "PhysicsModel.h"
 #include "MatrixLibrary.h"
 #include "Array.h"
 #include "Array2D.h"
 #include "OutputManager.h"
 #include "Function.h"
 #include "FE_Element.h"
 #include "TimeFilter.h"
 #include "LammpsInterface.h"
 #include "FE_Engine.h"
 #include "ExtrinsicModel.h"
 #include "InterscaleOperators.h"
 #include "TransferLibrary.h"
 #include "GhostManager.h"
 
 // Other headers
 #include <vector>
 #include <set>
 #include <utility>
 #include <string>
 #include <map>
 
 
 
 namespace ATC {
 
   // forward declarations
   class AtomTimeIntegrator;
 
   /**
    *  @class  ATC_Method
    *  @brief  Base class for atom-continuum coupling or transfer operators
    */
 
   class ATC_Method {
 
   public: /** methods */
 
     /** constructor */
     ATC_Method(std::string groupName, double **& perAtomArray, LAMMPS_NS::Fix * thisFix);
 
     /** destructor */
     virtual ~ATC_Method();
 
     std::string version() {return "2.0";}
 
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
+    void parse_field(/*const*/ char ** args, int &argIndex,
+                     FieldName &thisField);
     void parse_field(/*const*/ char ** args, int &argIndex,
                    FieldName &thisField, int &thisIndex);
 
     /** initialize any computes that will be needed prior to the first timestep */
     virtual void init_computes() {
       lammpsInterface_->computes_addstep(lammpsInterface_->ntimestep());
     };
 
     /** pre integration run */
     virtual void initialize();
 
     /** Predictor phase, executed before Verlet */
     virtual void pre_init_integrate() {
       feEngine_->partition_mesh(); 
       update_step();
     };
 
     /** Predictor phase, Verlet first step for velocity and position */
     virtual void init_integrate(); 
 
     /** Predictor phase, executed after Verlet */
     virtual void post_init_integrate();
 
     /** Corrector phase, executed before Verlet */
     virtual void pre_final_integrate(){};
 
     /** Corrector phase, Verlet second step for velocity */
     virtual void final_integrate();
 
     /** Corrector phase, executed after Verlet*/
     virtual void post_final_integrate();
 
     /** post integration run : called at end of run or simulation */
     virtual void finish();
 
     /** pre/post atomic force calculation */
     virtual void pre_force(){};
 
     /** pre/post atomic force calculation in minimize */
     virtual void min_pre_force(){};
     virtual void min_post_force();
 
     /** called at end of step for run or minimize */
     virtual void end_of_step();
 
     //---------------------------------------------------------------
     /** \name memory management and processor information exchange */
     //---------------------------------------------------------------
     /*@{*/
     /** pre_exchange  is our indicator that atoms have moved across processors */
     virtual void pre_exchange();
     void setup_pre_exchange();
     virtual void pre_neighbor();
     virtual void post_force();
     int doubles_per_atom() const;
     virtual int memory_usage();
     virtual void grow_arrays(int);
     void copy_arrays(int, int);
     int pack_exchange(int, double *);
     int unpack_exchange(int, double *);
-    int comm_forward(void) {return sizeComm_;}
+    int comm_forward(void);
     int pack_comm(int , int *, double *, int, int *);
     void unpack_comm(int, int, double *);
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name managers */
     //---------------------------------------------------------------
     /*@{*/
     /** access to FE engine */
     const FE_Engine * fe_engine() const {return feEngine_;};
     /** access to interscale manager */
     InterscaleManager & interscale_manager() {return interscaleManager_;};
     /** access to lammps interface */
     
     LammpsInterface const * lammps_interface() const {return lammpsInterface_;};
     /** access to time filter */
     TimeFilterManager * time_filter_manager() {return &timeFilterManager_;};
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name access methods for output computation data */
     //---------------------------------------------------------------
     /*@{*/
     /** compute scalar for output */
     virtual double compute_scalar() {return 0.;}
     /** compute vector for output */
     virtual double compute_vector(int n) {return 0.;}
     /** compute vector for output */
     virtual double compute_array(int irow, int icol) {return 0.;}; 
     int scalar_flag() const {return scalarFlag_;}
     int vector_flag() const {return vectorFlag_;}
     int size_vector() const {return sizeVector_;}
     int peratom_flag() const {return sizePerAtomCols_ > 0;}
     int size_peratom_cols() const {return sizePerAtomCols_;}
     int peratom_freq() const {return 1;}
     void set_peratom_pointer(double ** & ptr) { ptr = perAtomOutput_; }
     int global_freq() const {return scalarVectorFreq_;};
     int extscalar() const {return extScalar_;};
     int extvector() const {return extVector_;};
     int * extlist() {return extList_;};
     int thermo_energy_flag() const {return thermoEnergyFlag_;};
     bool parallel_consistency() const {return parallelConsistency_;};
 
     /** access to step number */
     int step() const {return stepCounter_;};
     double time() const {return simTime_;};
     double dt() const {return lammpsInterface_->dt();}
 
     /** time/step functions */
     bool sample_now(void) const
     { 
       int s = step();
       bool now =  ( (sampleFrequency_ > 0) && (s % sampleFrequency_ == 0));
       return now;
     }
     bool output_now(void) const
     { 
       int s = step();
 
       bool now = ( (outputFrequency_ > 0) && (s == 1 || s % outputFrequency_ == 0) ); 
       now = now || outputNow_;
       return now;
     }
     double output_index(void) const
     {
       if (outputTime_) return time();
       else             return step();
     }
 
     /** print tracked types and groups */
     int print_tracked() const
     {
       std::string msg = "species:\n";
       for(unsigned int i = 0; i < typeList_.size(); i++) {
         msg+=" type:"+ATC_Utility::to_string(typeList_[i])+" name: "+ typeNames_[i]+"\n";      }
       for(unsigned int i = 0; i < groupList_.size(); i++) {
         msg+=" group (bit):"+ATC_Utility::to_string(groupList_[i])+" name: "+ groupNames_[i]+"\n";
       }
       ATC::LammpsInterface::instance()->print_msg_once(msg);
       return typeList_.size()+groupList_.size();
     }
     std::vector<std::string>  tracked_names() const
     {
       std::vector<std::string> names(typeList_.size()+groupList_.size());
       int j = 0;
       for(unsigned int i = 0; i < typeList_.size(); i++) {
         names[j++] = typeNames_[i];
       }
       for(unsigned int i = 0; i < groupList_.size(); i++) {
         names[j++] = groupNames_[i];
       }
       return names;
     }
     int tag_to_type(std::string tag) const {
       for(unsigned int i = 0; i < typeList_.size(); i++) {
         if (tag == typeNames_[i]) return typeList_[i];
       }
       return -1;
     }
     int type_index(int t) const {
       for(unsigned int i = 0; i < typeList_.size(); i++) {
         if (t == typeList_[i]) return i;
       }
       return -1;
     }
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name Access methods for sizes */
     //---------------------------------------------------------------
     /*@{*/
     /** get number of unique FE nodes */
     int num_nodes() const {return nNodes_;};
     /** get number of spatial dimensions */
     int nsd() const {return nsd_;};
     /** get number of ATC internal atoms on this processor */
     int nlocal() const {return nLocal_;};
     /** get total number of LAMMPS atoms on this processor */
     int nlocal_total() const {return nLocalTotal_;};
     /** get number of ATC ghost atoms on this processor */
     int nlocal_ghost() const {return nLocalGhost_;};
     /** get the number of all LAMMPS real and parallel ghost atoms on this processor */
     int nproc_ghost() const {return nLocalTotal_ + lammpsInterface_->nghost();};
     /** match group bits */
     bool is_ghost_group(int grpbit) { return (grpbit == groupbitGhost_); }
     bool is_internal_group(int grpbit) { return (grpbit == groupbit_); }
     unsigned int ntracked() { return typeList_.size()+groupList_.size(); }
     bool has_tracked_species() { return typeList_.size()+groupList_.size() > 0; }
     /*@}*/
 
     virtual void initialize_mesh_data(void){meshDataInitialized_=true;}
 
     //---------------------------------------------------------------
     /** \name Access methods for data used by various methods */
     //---------------------------------------------------------------
     /*@{*/
 
 
 
     /** access to name FE fields */
     DENS_MAN &field(FieldName thisField){return fields_[thisField];};
     /** access to FE field time derivatives */
     DENS_MAT &get_dot_field(FieldName thisField){return dot_fields_[thisField].set_quantity();};
     DENS_MAN &dot_field(FieldName thisField){return dot_fields_[thisField];};
     /** access to nodal fields of atomic variables */
     DENS_MAT &get_atomic_field(FieldName thisField)
       { return nodalAtomicFields_[thisField].set_quantity(); };
     DENS_MAN &nodal_atomic_field(FieldName thisField)
       { return nodalAtomicFields_[thisField]; };
     /** access to all fields */
     FIELDS &fields() {return fields_;};
     /** access to all fields rates of change (roc) */
     FIELDS &fields_roc() {return dot_fields_;};
     /** add a new field */
     void add_fields(std::map<FieldName,int> & newFieldSizes);
     /** access FE rate of change */
     DENS_MAT &get_field_roc(FieldName thisField)
       { return dot_fields_[thisField].set_quantity(); };
     DENS_MAN &field_roc(FieldName thisField)
       { return dot_fields_[thisField]; };
     /** access atomic rate of change contributions to finite element equation */
 
     DENS_MAT &get_nodal_atomic_field_roc(FieldName thisField)
       { return nodalAtomicFieldsRoc_[thisField].set_quantity(); };
     DENS_MAN &nodal_atomic_field_roc(FieldName thisField)
       { return nodalAtomicFieldsRoc_[thisField]; };
     /** access to second time derivative (2roc) */
 
     DENS_MAT &get_field_2roc(FieldName thisField)
       { return ddot_fields_[thisField].set_quantity(); };
     DENS_MAN &field_2roc(FieldName thisField)
       { return ddot_fields_[thisField]; };
     /** access to third time derivative (3roc) */
     DENS_MAT &get_field_3roc(FieldName thisField)
       { return dddot_fields_[thisField].set_quantity(); };
     DENS_MAN &field_3roc(FieldName thisField)
       { return dddot_fields_[thisField]; };
     /** group bit */
     int groupbit() {return groupbit_;};
     /** group bit for ghosts */
     int groupbit_ghost() {return groupbitGhost_;};
     /** internal atom to global map */
     const Array<int> &internal_to_atom_map() {return internalToAtom_;};
     /** ghost atom to global map */
     const Array<int> &ghost_to_atom_map() {return ghostToAtom_;};
     const std::map<int,int> & atom_to_internal_map() {return atomToInternal_;};
     /** access to xref */
     double ** xref() {return xref_;};
     /** access to faceset names */
     const std::set<PAIR> &faceset(const std::string & name) const {return (feEngine_->fe_mesh())->faceset(name);};
     DENS_VEC copy_nodal_coordinates(int i) const { return feEngine_->fe_mesh()->nodal_coordinates(i); }
     /** access to set of DENS_MANs accessed by tagging */
 
     DENS_MAN & tagged_dens_man(const std::string & tag) {return taggedDensMan_[tag];};
     /** access to atom to element type map */
     AtomToElementMapType atom_to_element_map_type() {return atomToElementMapType_;};
     /** access to atom to element update frequency */
     int atom_to_element_map_frequency() {return atomToElementMapFrequency_;};
     /** flag on whether atc is initialized */
     bool is_initialized() const {return initialized_;};
     /** step number within a run or minimize */
     int local_step() const {return localStep_;};
     /** flags whether a methods reset is required */
     virtual bool reset_methods() const {return (!initialized_) || timeFilterManager_.need_reset() || timeFilterManager_.end_equilibrate() || ghostManager_.need_reset();};
     /** sizes of each field being considered */
     const std::map<FieldName,int> & field_sizes() {return fieldSizes_;};
     /*@}*/
    /** compute the consistent MD mass matrix */
    void compute_consistent_md_mass_matrix(const SPAR_MAT & shapeFunctionMatrix,
                                           SPAR_MAT & mdMassMatrix) const;
     /** access to molecule ids */
     const std::map<std::string,std::pair<MolSize,int> > & molecule_ids() const {return moleculeIds_;};
     /** access to internal element set */
     const std::string & internal_element_set() {return internalElementSet_;};
     
 
     //----------------------------------------------------------------
     /** \name mass matrix operations */
     //----------------------------------------------------------------
+    void apply_inverse_mass_matrix(MATRIX & data) {
+      data = massMatInv_*data;
+    }
     //      inverted using GMRES
     void apply_inverse_mass_matrix(MATRIX & data, FieldName thisField)
     {
       
       if (useConsistentMassMatrix_(thisField)) {
         //data = consistentMassInverse_*data;
         data = (consistentMassMatsInv_[thisField].quantity())*data;
         return;
       }
       data = (massMatsInv_[thisField].quantity())*data;
     };
     /** multiply inverse mass matrix times given data and return result */
     void apply_inverse_mass_matrix(const MATRIX & data_in, MATRIX & data_out,
                                    FieldName thisField)
     {
       if (useConsistentMassMatrix_(thisField)) { 
         //data_out = consistentMassInverse_*data_in;
         data_out = (consistentMassMatsInv_[thisField].quantity())*data_in;
         return;
       }
       data_out = (massMatsInv_[thisField].quantity())*data_in;
     };
     void apply_inverse_md_mass_matrix(const MATRIX & data_in, MATRIX & data_out,
                                    FieldName thisField)
     { data_out = (massMatsMdInv_[thisField].quantity())*data_in; };
 
 
     DIAG_MAN &mass_mat(FieldName thisField)
       { return massMats_[thisField];};
+    
 
     //---------------------------------------------------------------
     /** \name mass matrices  */
     //---------------------------------------------------------------
     /*@{*/
     /** access to  mass matrices */
     /** access to inverse mass matrices */
     DIAG_MAT &get_mass_mat_inv(FieldName thisField)
       { return massMatsInv_[thisField].set_quantity();};
     DIAG_MAN &mass_mat_inv(FieldName thisField)
       { return massMatsInv_[thisField];};
     /** nodal volumes associated with the atoms, used for the atomic mass matrix */
     AdmtfShapeFunctionRestriction * nodalAtomicVolume_;
 
     void register_mass_matrix_dependency(DependencyManager * dependent,
                                          FieldName thisField)
     {
       if (useConsistentMassMatrix_(thisField)) { 
         consistentMassMatsInv_[thisField].register_dependence(dependent);
         return;
       }
       massMatsInv_[thisField].register_dependence(dependent);
     };
     
     void apply_inverse_md_mass_matrix(MATRIX & data, FieldName thisField)
     { data = (massMatsMdInv_[thisField].quantity())*data; };
     void register_md_mass_matrix_dependency(DependencyManager * dependent,
                                             FieldName thisField)
     {massMatsMdInv_[thisField].register_dependence(dependent);}
 //    /** determine weighting method for atomic integration */
 //    void compute_consistent_md_mass_matrix(const SPAR_MAT & shapeFunctionMatrix,
  //                                          SPAR_MAT & mdMassMatrix);
     virtual void compute_md_mass_matrix(FieldName thisField,
                                         DIAG_MAT & massMat) {};
 /** access to md mass matrices */
 
     DIAG_MAN &mass_mat_md_inv(FieldName thisField)
       { return massMatsMdInv_[thisField];};
     DIAG_MAN &set_mass_mat_md(FieldName thisField)
      { return massMatsMd_[thisField]; };
     const DIAG_MAN &mass_mat_md(FieldName thisField) const
      {
        MASS_MATS::const_iterator man =  massMatsMd_.find(thisField);
        if (man == massMatsMd_.end() ) {
          std::string msg = " MD mass for " + field_to_string(thisField) +  " does not exist";
          throw ATC_Error(msg);
        }
        return man->second;
      };
     /*@}*/
                 
     //----------------------------------------------------------------
     /** \name Interscale operators */
     //----------------------------------------------------------------
     bool use_md_mass_normalization() const { return mdMassNormalization_;}  
     bool kernel_based() { return kernelBased_; }
     bool kernel_on_the_fly() const { return kernelOnTheFly_;}
     bool has_kernel_function() { return kernelFunction_ != NULL; }
     KernelFunction * kernel_function() { return kernelFunction_; }
     std::vector<int> & type_list() { return typeList_; }
     std::vector<int> & group_list() { return groupList_; }
     SPAR_MAN* interpolant() { return shpFcn_; }
     SPAR_MAN* accumulant() { return accumulant_; }
     DIAG_MAN* accumulant_weights() { return  accumulantWeights_;}
     DIAG_MAN* accumulant_inverse_volumes() { return accumulantInverseVolumes_; }
     int accumulant_bandwidth() const { if (accumulantBandwidth_) return accumulantBandwidth_; else return feEngine_->num_nodes(); };
 
     PerAtomQuantity<double> * atom_coarsegraining_positions() { return  atomCoarseGrainingPositions_; }
     PerAtomQuantity<double> * atom_reference_positions() { return  atomReferencePositions_; }
     PerAtomQuantity<int> * atom_to_element_map() { return atomElement_;}
 
     double ke_scale() { return keScale_; }
     double pe_scale() { return peScale_; }
     
     /** from a atom group, find the nodes that have non-zero shape function contributions */
 
     bool nodal_influence(const int groupbit, std::set<int>& nset, std::set<int>& aset, double tol =1.e-8);
     int nodal_influence(const int groupbit, std::set<int>& nset, std::set<int>& aset, 
       bool ghost,
       double tol =1.e-8);
     /*@{*/
 
     
 
  /** Restrict based on atomic volume integration for volumetric quantities : given w_\alpha, w_I = \sum_\alpha N_{I\alpha} w_\alpha */
     void restrict_volumetric_quantity(const MATRIX &atomData,
                                       MATRIX &nodeData); 
     void restrict_volumetric_quantity(const MATRIX &atomData,
                                       MATRIX &nodeData,
                                       const SPAR_MAT & shpFcn);
 
     /** Prolong : given w_I,  w_\alpha = \sum_I N_{I\alpha} w_I */
     void prolong(const MATRIX &nodeData, MATRIX &atomData);
 
     //---------------------------------------------------------------
     /** \name quadrature weights */
     //---------------------------------------------------------------
     PerAtomDiagonalMatrix<double> * create_atom_volume();
 
     //---------------------------------------------------------------
     /** \name access to potential energy reference */
     //---------------------------------------------------------------
     /*@{*/
     DENS_MAN * nodal_ref_potential_energy(void) { return nodalRefPotentialEnergy_; }
 
   protected: /** methods */
     /** time functions */
     void set_time(double t=0) {simTime_=t;};
     void update_time(double alpha = 1.0)  
     {
       double dt = lammpsInterface_->dt();
       simTime_ += alpha*dt;
       if (dt == 0.0) simTime_ = stepCounter_;
     }
     // note step counter different than lammps step e.g. min
     void update_step(void)  { ++stepCounter_; }
 
     //---------------------------------------------------------------
     /** initialization routines */
     //---------------------------------------------------------------
     /** gets baseline data from continuum model */
     virtual void set_continuum_data();
     /** sets up all data necessary to define the computational geometry */
     virtual void set_computational_geometry();
     /** constructs all data which is updated with time integration, i.e. fields */
     virtual void construct_time_integration_data() = 0;
     /** create methods, e.g. time integrators, filters */
     virtual void construct_methods();
     /** set up data which is dependency managed */
     virtual void construct_transfers();
     /** sets up accumulant & interpolant */
     virtual void construct_interpolant()=0;
     /** sets up mol transfers */
     virtual void construct_molecule_transfers()=0;
 
     /** update the peratom output pointers */
     void update_peratom_output(void);
 
     virtual void  read_restart_data(std::string fileName_, RESTART_LIST & data);
     virtual void write_restart_data(std::string fileName_, RESTART_LIST & data);
     void pack_fields(RESTART_LIST & data); 
 
    /** mass matrices */
+    DIAG_MAT  massMatInv_;
     MASS_MATS massMats_;
     MASS_MATS massMatsInv_;
     MASS_MATS massMatsMd_;
     MASS_MATS massMatsMdInstantaneous_;
     MASS_MATS massMatsMdInv_;
     MASS_MATS massMatsFE_;
     MASS_MATS massMatsAq_;
     MASS_MATS massMatsAqInstantaneous_;
     Array<bool> useConsistentMassMatrix_;
     std::map<FieldName,SPAR_MAN> consistentMassMats_;
     std::map<FieldName,DENS_MAN> consistentMassMatsInv_;
     std::map<FieldName,TimeFilter * > massMatTimeFilters_;
 
     //---------------------------------------------------------------
     /** \name quadrature weight function */
     //---------------------------------------------------------------
     /*@{*/
     void write_atomic_weights(const std::string filename,const DIAG_MAT & atomicVolumeMatrix);
 
     /** resets shape function matrices based on atoms on this processor */
     virtual void reset_nlocal();
     virtual void reset_coordinates();
     /*@}*/
 
     /** re-read reference positions */
     bool read_atomic_ref_positions(const char * filename);
     void remap_ghost_ref_positions(void);
     void adjust_xref_pbc();
 
     //---------------------------------------------------------------
     /** \name output functions */
     //---------------------------------------------------------------
     /*@{*/
     virtual void output();
     void compute_nodeset_output(void);
     void compute_faceset_output(void);
     void compute_elementset_output(void);
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name types, groups, and molecules */
     //---------------------------------------------------------------
     /*@{*/
     /** map from species string tag to LAMMPS type id or group bit */
     std::map<std::string,std::pair<MolSize,int> > moleculeIds_;
     /** a list of lammps types & groups ATC tracks */
     std::vector<std::string> typeNames_;
     std::vector<std::string> groupNames_;
     std::vector<int> typeList_;
     std::vector<int> groupList_;
     /*@}*/
 
     void reset_fields();
 
   private: /** methods */ 
     ATC_Method(); // do not define
 
   protected: /** data */
     
     /* parsed input requires changes */
     bool needReset_;
 
     // managers
     /** pointer to lammps interface class */
     LammpsInterface * lammpsInterface_;
 
     /** manager for atomic quantities and interscale operations */
     InterscaleManager interscaleManager_;
 
     TimeFilterManager timeFilterManager_;
 
     /** check to see if we are integrating the atoms */
     bool integrateInternalAtoms_;
     /** object which integrates atoms */
     AtomTimeIntegrator * atomTimeIntegrator_;
     /** objects which handles integration and modification of ghost atoms */
     GhostManager ghostManager_;
 
     /** finite element handler */
     FE_Engine * feEngine_;
 
     // status flags
     /** flag on if initialization has been performed */
     bool initialized_;
     bool meshDataInitialized_;
 
     /** counter for steps of a run or minimize */
     int localStep_;
 
     // sizes
     /** size of per atom communication */
     int sizeComm_;
 
     /** atomic coordinates for coarse graining */
     PerAtomQuantity<double> * atomCoarseGrainingPositions_;
     PerAtomQuantity<double> * atomGhostCoarseGrainingPositions_;
     PerAtomQuantity<double> * atomProcGhostCoarseGrainingPositions_;
     PerAtomQuantity<double> * atomReferencePositions_;
 
     
     /** number of unique FE nodes */
     int nNodes_;
 
     /** Number of Spatial Dimensions */
     int nsd_;
 
 #ifdef EXTENDED_ERROR_CHECKING
     /** data for handling atoms crossing processors */
     bool atomSwitch_;
 #endif
 
     /** reference position of the atoms */
     double ** xref_;
     bool readXref_;
     bool needXrefProcessorGhosts_;
     std::string xRefFile_;
 
     /** flag for tracking displacements or not, depending on physics */
     bool trackDisplacement_;
 
     /** map from reference positions to element id, pointer is to internal only */
     
     bool needsAtomToElementMap_;
     PerAtomQuantity<int> * atomElement_;
     PerAtomQuantity<int> * atomGhostElement_;
 
     /* use element sets to define internal and/or ghost regions */
     std::string internalElementSet_;
     
     /** atomic ATC material tag */
     
     
     double Xprd_,Yprd_,Zprd_; // lengths of periodic box in reference frame
     double XY_,YZ_,XZ_;
     double boxXlo_,boxXhi_; // lo/hi bounds of periodic box in reference frame
     double boxYlo_,boxYhi_; // lo/hi bounds of periodic box in reference frame
     double boxZlo_,boxZhi_; // lo/hi bounds of periodic box in reference frame
     // next data members are for consistency with existing ATC_Transfer, but are redundant and do not
     // conform to naming standards, and should be accessible through the mesh
     /** periodicity flags and lengths */
     int periodicity[3];
     double box_bounds[2][3];
     double box_length[3];
 
     /** pointers to needed atom quantities and transfers */
     FundamentalAtomQuantity * atomMasses_;
     FundamentalAtomQuantity * atomPositions_;
     FundamentalAtomQuantity * atomVelocities_;
     FundamentalAtomQuantity * atomForces_;
 
     //---------------------------------------------------------------
     /** \name output data */
     //---------------------------------------------------------------
     /*@{*/
 
   //private:
     bool parallelConsistency_;
 
     /** base name for output files */
     std::string outputPrefix_;
 
     /** output flag */ 
     
     bool outputNow_;
     /** output time or step (for lammps compatibility) */
     bool outputTime_;
   
     /** output frequency */
     int outputFrequency_;
   
     /** sample frequency */
     int sampleFrequency_;
   
     /** sample counter */
     int sampleCounter_;
 
     TAG_FIELDS filteredData_; 
 
     double peScale_,keScale_;
 
   //protected:
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name member data related to compute_scalar() and compute_vector() */
     //---------------------------------------------------------------
     /*@{*/
     int scalarFlag_;              // 0/1 if compute_scalar() function exists
     int vectorFlag_;              // 0/1 if compute_vector() function exists
     int sizeVector_;              // N = size of global vector
     int scalarVectorFreq_;        // frequency compute s/v data is available at
     int sizePerAtomCols_;         // N = size of per atom vector to dump
     
     double **perAtomOutput_;      // per atom data
     double **&perAtomArray_;      // per atom data
     int extScalar_;               // 0/1 if scalar is intensive/extensive
     int extVector_;               // 0/1/-1 if vector is all int/ext/extlist
     int *extList_;                // list of 0/1 int/ext for each vec component
     int thermoEnergyFlag_;        // 0/1 if fix adds to overall energy
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name fields and necessary data for FEM */
     //---------------------------------------------------------------
     /*@{*/
     std::map<FieldName,int> fieldSizes_;
     FIELDS fields_;
     /*@}*/
 
 
     //---------------------------------------------------------------
     /** \name time integration and filtering fields */
     //---------------------------------------------------------------
     /*@{*/
     
     FIELDS dot_fields_; 
     FIELDS ddot_fields_;
     FIELDS dddot_fields_;
 
     /** Restricted Fields */
 
     FIELDS nodalAtomicFields_;  // replaces fieldNdFiltered_
     FIELDS nodalAtomicFieldsRoc_; 
 
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name quadrature weights */
     //---------------------------------------------------------------
     /*@{*/
     
     DIAG_MAT NodeVolumes_; 
     DIAG_MAN invNodeVolumes_; 
     /** atomic quadrature integration weights (V_\alpha) */
     ProtectedAtomDiagonalMatrix<double> * atomVolume_;
     std::string atomicWeightsFile_;
     bool atomicWeightsWriteFlag_;
     int atomicWeightsWriteFrequency_;
     double atomicVolume_;  // global atomic volume for homogeneous set of atoms
     std::map<int,double> Valpha_;
     AtomicWeightType atomWeightType_;
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name domain decomposition */
     //---------------------------------------------------------------
     /*@{*/
     DomainDecompositionType domainDecomposition_;
     /*@}*/
 
     //---------------------------------------------------------------
     /** \name atom data  */
     //---------------------------------------------------------------
     /*@{*/
     /** bitwise comparisons for boundary (ghost) atoms */
     int groupbit_;
     int groupbitGhost_;
     bool needProcGhost_;
     std::string groupTag_;
     std::string groupTagGhost_;
   
     /** number of atoms of correct type,
         ghosts are atoms outside our domain of interest
         boundary are atoms contributing to boundary flux terms */
     /** Number of "internal" atoms on this processor */
     int nLocal_;
     /** Number of atoms on this processor */
     int nLocalTotal_;
     int nLocalGhost_;
     Array<int> internalToAtom_;
     std::map<int,int> atomToInternal_;
     Array<int> ghostToAtom_;
     /*@}*/
     //----------------------------------------------------------------
     /** \name  maps and masks */
     //----------------------------------------------------------------
     /*@{*/
 
     AtomToElementMapType atomToElementMapType_;
     int atomToElementMapFrequency_;
     int regionID_;
     /*@}*/
 
     //----------------------------------------------------------------
     /** \name shape function matrices */
     //----------------------------------------------------------------
     /*@{*/
     // sparse matrix where columns correspond to global node numbering
     SPAR_MAN * shpFcn_;
     VectorDependencyManager<SPAR_MAT * > * shpFcnDerivs_;
     /** map from species std::string tag to the species density */
     std::map<std::string,DENS_MAN> taggedDensMan_;
 
     /** weighted shape function matrices at overlap nodes
         for use with thermostats */
     SPAR_MAN NhatOverlap_;
     /*@}*/
 
     //----------------------------------------------------------------
     /** \name accumulant matrices */
     //----------------------------------------------------------------
     /*@{*/
     /** compute kernel shape functions on-the-fly w/o storing N_Ia */
     bool mdMassNormalization_;
     bool kernelBased_;
     bool kernelOnTheFly_;
     class KernelFunction * kernelFunction_;
     bool bondOnTheFly_;
     SPAR_MAN* accumulant_;
     SPAR_MAN* accumulantMol_; // KKM add
     SPAR_MAN* accumulantMolGrad_; // KKM add
     SPAR_MAN  kernelAccumulantMol_; // KKM add
     SPAR_MAN  kernelAccumulantMolGrad_; // KKM add
     DIAG_MAN* accumulantWeights_;
     DIAG_MAN* accumulantInverseVolumes_;  
     int accumulantBandwidth_;
     /*@}*/
 
 
     //---------------------------------------------------------------
     /** \name restart procedures */
     //---------------------------------------------------------------
     bool useRestart_;
     std::string restartFileName_;
 
     //---------------------------------------------------------------
     /** \name data specific to node/faceset for global output */
     //---------------------------------------------------------------
     /** group computes : type, group_id -> value */
     std::map< std::pair<std::string, FieldName > , NodesetOperationType> nsetData_;
     std::map< std::pair<std::string,std::string>, FacesetIntegralType  >       fsetData_;
     std::map< std::pair<std::string, FieldName>,ElementsetOperationType > esetData_;
 
 
     //---------------------------------------------------------------
     /** \name reference data */ 
     //---------------------------------------------------------------
     bool hasRefPE_;
     bool setRefPE_;
     bool setRefPEvalue_;
     double refPEvalue_;
     bool readRefPE_;
     std::string nodalRefPEfile_;
     DENS_MAN* nodalRefPotentialEnergy_;
     void set_reference_potential_energy(void);
 
   private: /** data */
     /** current time in simulation */
     double simTime_;
 
     /** step counter */
     int stepCounter_;
 
   };
 
 };
 
 #endif
diff --git a/lib/atc/ATC_TypeDefs.h b/lib/atc/ATC_TypeDefs.h
index 8906d5c63..5567af13c 100644
--- a/lib/atc/ATC_TypeDefs.h
+++ b/lib/atc/ATC_TypeDefs.h
@@ -1,625 +1,631 @@
 #ifndef ATC_TYPEDEFS_H
 #define ATC_TYPEDEFS_H
 
 #include <set>
 #include <vector>
 #include <map>
 #include <utility>
 #include <string>
 
 #ifdef NEW_LAMMPS
 #include "lmptype.h"
 #endif
 
 #include "Array.h"
 #include "Array2D.h"
 
 #include "MatrixLibrary.h"
 #include "DependencyManager.h"
 
 namespace ATC
 {
   /** physical constants */
   static const double kBeV_ = 8.617343e-5;// [eV/K]
 
   /** unsigned ints, when needed */
   typedef int INDEX; 
 
   /** elementset integral */
   enum ElementsetOperationType {
     ELEMENTSET_TOTAL=0,
     ELEMENTSET_AVERAGE
   };
   /** faceset integral */
   enum FacesetIntegralType {
     BOUNDARY_INTEGRAL=0,
     CONTOUR_INTEGRAL
   };
 
   /** nodeset operation */
   enum NodesetOperationType {
     NODESET_SUM=0,
     NODESET_AVERAGE
   };
 
   /** boundary integration */
   enum BoundaryIntegrationType {
     NO_QUADRATURE=0,
     FE_QUADRATURE,
     FE_INTERPOLATION
   };
   /** domain integration */
   enum IntegrationDomainType {
     FULL_DOMAIN=0,
     ATOM_DOMAIN,
-    FE_DOMAIN
+    FE_DOMAIN,
+    FULL_DOMAIN_ATOMIC_QUADRATURE_SOURCE, 
+    FULL_DOMAIN_FREE_ONLY
   };
   /** domain decomposition */
   enum DomainDecompositionType {
     REPLICATED_MEMORY=0,
     DISTRIBUTED_MEMORY 
   };
   /** atomic weight specification */
   enum AtomicWeightType {
     USER=0,
     LATTICE,
     ELEMENT,
     REGION,
     GROUP,
     MULTISCALE,
     NODE,
     NODE_ELEMENT,
     READ_IN
   };
   /** geometry location with respect to MD domain */
   enum GeometryType {
     FE_ONLY = 0,
     MD_ONLY,
     BOUNDARY
   };
   /** enumerated type for atomic reference frame */
   enum AtomToElementMapType {
     LAGRANGIAN=0,
     EULERIAN
   };
   /* enumerated type for coupling matrix structure */
   enum MatrixStructure {
     FULL=0,     // contributions from all nodes
     LOCALIZED,  // contributions only from nodes with sources
     LUMPED      // row-sum lumped version of full matrix
   };
   /* enumerated type for distinguishing ghost from internal atoms */
   enum AtomType {
     INTERNAL=0,
     GHOST,
     ALL,
     PROC_GHOST,
     NO_ATOMS,
     NUM_ATOM_TYPES
   };
   /** field types */
   enum FieldName { 
       TIME=-2,
       POSITION=-1,
       TEMPERATURE=0, // Intrinsic Fields
       DISPLACEMENT,
       VELOCITY,
       MASS_DENSITY,
       CHARGE_DENSITY,
       SPECIES_CONCENTRATION,
       ELECTRON_DENSITY, // Extrinsic Fields
       ELECTRON_VELOCITY,
       ELECTRON_TEMPERATURE,
       ELECTRIC_POTENTIAL,
       ELECTRON_WAVEFUNCTION,
       ELECTRON_WAVEFUNCTIONS, 
       ELECTRON_WAVEFUNCTION_ENERGIES, 
       FERMI_ENERGY, 
       MOMENTUM,
       PROJECTED_VELOCITY,
       KINETIC_TEMPERATURE,
       THERMAL_ENERGY,
       KINETIC_ENERGY,
       STRESS,
       KINETIC_STRESS,
       HEAT_FLUX,
       CHARGE_FLUX,
       SPECIES_FLUX,
       INTERNAL_ENERGY,
       REFERENCE_POTENTIAL_ENERGY,
       POTENTIAL_ENERGY,
       ENERGY,
       NUMBER_DENSITY,
       ESHELBY_STRESS,
       CAUCHY_BORN_STRESS,
       CAUCHY_BORN_ENERGY,
       CAUCHY_BORN_ESHELBY_STRESS,
       TRANSFORMED_STRESS,
       VACANCY_CONCENTRATION,
       ROTATION,
       STRETCH,
       DIPOLE_MOMENT,
       QUADRUPOLE_MOMENT,
       CAUCHY_BORN_ELASTIC_DEFORMATION_GRADIENT,
       DISLOCATION_DENSITY,
       NUM_TOTAL_FIELDS 
   };
   const int NUM_FIELDS = ELECTRON_WAVEFUNCTION+1; 
 
 #define NDIM 3
   static const int FieldSizes[NUM_TOTAL_FIELDS] = {
     1, // TEMPERATURE
     NDIM, // DISPLACEMENT
     NDIM, // VELOCITY
     1, // MASS_DENSITY
     1, // CHARGE_DENSITY
     0, // SPECIES_CONCENTRATION - VARIABLE
     1, // ELECTRON_DENSITY
     NDIM, // ELECTRON_VELOCITY
     1, // ELECTRON_TEMPERATURE
     1, // ELECTRIC_POTENTIAL
     1, // ELECTRON_WAVEFUNCTION ?
     0, // ELECTRON_WAVEFUNCTIONS - VARIABLE
     0, // ELECTRON_WAVEFUNCTION_ENERGIES - VARIABLE
     1, // FERMI_ENERGY
     NDIM, // MOMENTUM
     NDIM, // PROJECTED_VELOCITY
     1, // KINETIC_TEMPERATURE
     1, // THERMAL_ENERGY
     1, // KINETIC_ENERGY
     NDIM*NDIM, // STRESS
     NDIM*NDIM, // KINETIC_STRESS
     NDIM, // HEAT_FLUX
     NDIM, // CHARGE_FLUX
     0, // SPECIES_FLUX - VARIABLE
     1, // INTERNAL_ENERGY
     1, // REFERENCE_POTENTIAL_ENERGY
     1, // POTENTIAL_ENERGY
     1, // ENERGY
     1, // NUMBER_DENSITY
     NDIM*NDIM, // ESHELBY_STRESS
     NDIM*NDIM, // CAUCHY_BORN_STRESS,
     1, //  CAUCHY_BORN_ENERGY,
     NDIM*NDIM, //  CAUCHY_BORN_ESHELBY_STRESS,
     NDIM*NDIM, //  TRANSFORMED_STRESS,
     1, //  VACANCY_CONCENTRATION,
     NDIM*NDIM, //  ROTATION,
     NDIM*NDIM, //  STRETCH,
     NDIM, // DIPOLE_MOMENT,
     NDIM, // QUADRUPOLE_MOMENT,
     NDIM*NDIM, //  CAUCHY_BORN_ELASTIC_DEFORMATION_GRADIENT,
     NDIM*NDIM //  DISLOCATION_DENSITY
   };
 
   enum NodalAtomicFieldNormalization { 
     NO_NORMALIZATION=0,
     VOLUME_NORMALIZATION, NUMBER_NORMALIZATION, MASS_NORMALIZATION,
     MASS_MATRIX
   };
 
   inline FieldName use_mass_matrix(FieldName in) {
     if (in == TEMPERATURE) return in;
     else                   return MASS_DENSITY;
   }
 
   /** enums for FE Element and Interpolate classes */
   enum FeEltGeometry   {HEXA, TETRA};
   enum FeIntQuadrature {NODAL, GAUSS1, GAUSS2, GAUSS3, FACE};
 
   /** field name enum to string */
   inline FeIntQuadrature string_to_FIQ(const std::string &str) 
   {
     if (str == "nodal")
       return NODAL;
     else if (str == "gauss1")
       return GAUSS1;
     else if (str == "gauss2")
       return GAUSS2;
     else if (str == "gauss3")
       return GAUSS3;
     else if (str == "face")
       return FACE;
     else
       throw ATC_Error("Bad quadrature input" + str + ".");
   }
 
   /** field name enum to string */
   inline std::string field_to_string(const FieldName index) 
   {
     switch (index) {
     case TEMPERATURE:
       return "temperature";
     case DISPLACEMENT:
       return "displacement";
     case VELOCITY:
       return "velocity";
     case MASS_DENSITY:
       return "mass_density";
     case CHARGE_DENSITY:
       return "charge_density";
     case ELECTRON_DENSITY:
       return "electron_density";
     case ELECTRON_VELOCITY:
       return "electron_velocity";
     case ELECTRON_TEMPERATURE:
       return "electron_temperature";
     case ELECTRIC_POTENTIAL:
       return "electric_potential";
     case ELECTRON_WAVEFUNCTION:
       return "electron_wavefunction";
     case ELECTRON_WAVEFUNCTIONS:
       return "electron_wavefunctions";
     case ELECTRON_WAVEFUNCTION_ENERGIES:
       return "electron_wavefunction_energies";
     case FERMI_ENERGY:
       return "fermi_energy";
     case MOMENTUM:
       return "momentum";
     case PROJECTED_VELOCITY:
       return "projected_velocity";
     case KINETIC_TEMPERATURE:
       return "kinetic_temperature";
     case THERMAL_ENERGY:
       return "thermal_energy";
     case KINETIC_ENERGY:
       return "kinetic_energy";
     case STRESS:
       return "stress";
     case KINETIC_STRESS:
       return "kinetic_stress";
     case ESHELBY_STRESS:
       return "eshelby_stress";
     case CAUCHY_BORN_STRESS:
       return "cauchy_born_stress";
     case CAUCHY_BORN_ENERGY:
       return "cauchy_born_energy";
     case CAUCHY_BORN_ESHELBY_STRESS:
       return "cauchy_born_eshelby_stress";
     case HEAT_FLUX:
       return "heat_flux";
     case CHARGE_FLUX:
       return "charge_flux";
     case SPECIES_FLUX:
       return "species_flux";
     case INTERNAL_ENERGY:
       return "internal_energy";
     case POTENTIAL_ENERGY:
       return "potential_energy";
     case REFERENCE_POTENTIAL_ENERGY:
       return "reference_potential_energy";
     case ENERGY:
       return "energy";
     case NUMBER_DENSITY:
       return "number_density";
     case TRANSFORMED_STRESS:
       return "transformed_stress";
     case VACANCY_CONCENTRATION:
       return "vacancy_concentration";
     case SPECIES_CONCENTRATION:
       return "species_concentration";
     case ROTATION:
       return "rotation";
     case STRETCH:
       return "stretch";
     case DIPOLE_MOMENT:
       return "dipole_moment";
     case QUADRUPOLE_MOMENT:
       return "quadrupole_moment";
     default:
       throw ATC_Error("field not found in field_to_string");
     }
   };
 
   /** string to field enum */
   inline FieldName string_to_field(const std::string & name) 
   {
     if      (name=="temperature")
       return TEMPERATURE;
     else if (name=="displacement")
       return DISPLACEMENT;
     else if (name=="velocity")
       return VELOCITY;
     else if (name=="mass_density")
       return MASS_DENSITY;
     else if (name=="charge_density")
       return CHARGE_DENSITY;
     else if (name=="electron_density")
       return ELECTRON_DENSITY;
     else if (name=="electron_velocity")
       return ELECTRON_VELOCITY;
     else if (name=="electron_temperature")
       return ELECTRON_TEMPERATURE;
     else if (name=="electric_potential")
       return ELECTRIC_POTENTIAL;
     else if (name=="electron_wavefunction")
       return ELECTRON_WAVEFUNCTION;
     else if (name=="electron_wavefunctions")
       return ELECTRON_WAVEFUNCTIONS;
     else if (name=="electron_wavefunction_energies")
       return ELECTRON_WAVEFUNCTION_ENERGIES;
     else if (name=="fermi_energy")
       return FERMI_ENERGY;
     else if (name=="momentum")
       return MOMENTUM;
     else if (name=="projected_velocity")
       return PROJECTED_VELOCITY;
     else if (name=="kinetic_temperature")
       return KINETIC_TEMPERATURE; // temperature from total KE
     else if (name=="thermal_energy")
       return THERMAL_ENERGY;
     else if (name=="kinetic_energy")
       return KINETIC_ENERGY;
     else if (name=="stress")
       return STRESS;
     else if (name=="kinetic_stress")
       return KINETIC_STRESS;
     else if (name=="eshelby_stress")
       return ESHELBY_STRESS;
     else if (name=="cauchy_born_stress")
       return CAUCHY_BORN_STRESS;
     else if (name=="cauchy_born_energy")
       return CAUCHY_BORN_ENERGY;
     else if (name=="cauchy_born_eshelby_stress")
       return CAUCHY_BORN_ESHELBY_STRESS;
     else if (name=="heat_flux")
       return HEAT_FLUX;
     else if (name=="charge_flux")
       return CHARGE_FLUX;
     else if (name=="species_flux")
       return SPECIES_FLUX;
     else if (name=="internal_energy")
       return INTERNAL_ENERGY;
     else if (name=="reference_potential_energy")
       return REFERENCE_POTENTIAL_ENERGY;
     else if (name=="potential_energy")
       return POTENTIAL_ENERGY;
     else if (name=="energy")
       return ENERGY;
     else if (name=="number_density")
       return NUMBER_DENSITY;
     else if (name=="transformed_stress")
       return TRANSFORMED_STRESS;
     else if (name=="vacancy_concentration")
       return VACANCY_CONCENTRATION;
     else if (name=="species_concentration")
       return SPECIES_CONCENTRATION;
     else if (name=="rotation")
       return ROTATION;
     else if (name=="stretch")
       return STRETCH;
     else if (name=="dipole_moment")
       return DIPOLE_MOMENT;
     else if (name=="quadrupole_moment")
       return QUADRUPOLE_MOMENT;
     else
       throw ATC_Error(name + " is not a valid field");
   };
 
   inline bool is_intrinsic(const FieldName & field_enum) 
   {
     if  (field_enum==TEMPERATURE
       || field_enum==DISPLACEMENT
       || field_enum==VELOCITY
       || field_enum==MASS_DENSITY
       || field_enum==CHARGE_DENSITY
       || field_enum==SPECIES_CONCENTRATION
       || field_enum==KINETIC_TEMPERATURE
       || field_enum==POTENTIAL_ENERGY
       || field_enum==REFERENCE_POTENTIAL_ENERGY
      )   return true;
     else return false;
   };
 
   inline std::string field_to_intrinsic_name(const FieldName index) 
   {
     if (is_intrinsic(index)) {
       return "NodalAtomic"+ATC_Utility::to_cap(field_to_string(index));
     }
     else {
       throw ATC_Error("field "+field_to_string(index)+" is not an intrinsic field");
     }
   }
   inline std::string field_to_restriction_name(const FieldName index) 
   {
     if (is_intrinsic(index)) {
       return "Restricted"+ATC_Utility::to_cap(field_to_string(index));
     }
     else {
       throw ATC_Error("field "+field_to_string(index)+" is not an intrinsic field");
     }
   }
   inline std::string field_to_prolongation_name(const FieldName index) 
   {
     return "Prolonged"+ATC_Utility::to_cap(field_to_string(index));
   }
 
 
   /** types of temperature definitions */
   enum TemperatureDefType {
     NONE = 0,
     KINETIC,
     TOTAL
   };
 
   /** string to temperature definition enum */
   inline bool string_to_temperature_def(const std::string & name, TemperatureDefType & index) {
     if      (name=="none")
       index = NONE;
     else if (name=="kinetic")
       index = KINETIC;
     else if (name=="total")
       index = TOTAL;
     else {
       throw ATC_Error("temperature operator type "+name+" not valid");
       return false;
     }
 
     return true;
   };
 
   /** solver types */
   enum SolverType { DIRECT=0, ITERATIVE};
   enum DirichletType {DIRICHLET_PENALTY=0, DIRICHLET_CONDENSE};
 
   /** physics types */
   enum PhysicsType
   {
     NO_PHYSICS=0, // for post-processing only
     THERMAL,
     ELASTIC,
     SHEAR,
     THERMO_ELASTIC,
     SPECIES // aka Mass
   };
  
   /** rhs types */
   enum FluxType 
   {
     FLUX = 0,           // has a source weighted by gradient of shape function
     SOURCE,             // has a source term weighted by the shape function
     PRESCRIBED_SOURCE,  // has a prescribed source term
     ROBIN_SOURCE,       // has a Robin source term
+    OPEN_SOURCE,        // has a open boundary source term
     EXTRINSIC_SOURCE,   // has an extrinsic source term
     NUM_FLUX
   };
 
   /** stiffness/ derivative of rhs types */
   enum StiffnessType 
   {
     BB_STIFFNESS = 0,    
     NN_STIFFNESS,    
     BN_STIFFNESS,    
     NB_STIFFNESS,    
     NUM_STIFFNESS
   };
 
   /** LAMMPS atom type identifiers */
   enum IdType {
     ATOM_TYPE=0,
     ATOM_GROUP
   };
 
   /** molecule size identifiers */
   enum MolSize {
     MOL_SMALL=0,
     MOL_LARGE
   };
 
   /** basic */
   typedef std::pair<int, int> PAIR;
 
   /** typedefs for compact set of bc values */
   typedef std::set < std::pair < int, double> > BC_SET; // node, value
   typedef std::vector< BC_SET > BCS;  // dof (node, value)
   typedef std::set<int> NSET;  // nodeset
   typedef std::set<PAIR> FSET;  // faceset
   typedef std::set<int> ESET;  // elementset
 
   /** typedefs for N and B integrand functions */
   typedef std::set<FieldName> ARG_NAMES; 
   typedef std::map<FieldName, ATC_matrix::DenseMatrix<double> > ARGS; 
   typedef ATC::MatrixDependencyManager<ATC_matrix::DenseMatrix, double>  FIELD;
   typedef std::vector<ATC::MatrixDependencyManager<ATC_matrix::DenseMatrix, double> >  GRAD_FIELD;
   typedef std::map<FieldName, ATC::MatrixDependencyManager<ATC_matrix::DenseMatrix, double> > FIELDS;
   typedef std::map<FieldName, ATC::MatrixDependencyManager<ATC_matrix::DenseMatrix, double> * > FIELD_POINTERS;
   typedef std::map<FieldName, ATC_matrix::DenseMatrix<double> > FIELD_MATS;
   typedef std::map<std::string, ATC::MatrixDependencyManager<ATC_matrix::DenseMatrix, double> > TAG_FIELDS;
   typedef std::map<FieldName, std::vector<ATC::MatrixDependencyManager<ATC_matrix::DenseMatrix, double> > > GRAD_FIELDS;
   typedef std::map<FieldName, std::vector<ATC_matrix::DenseMatrix<double> > > GRAD_FIELD_MATS;
   typedef std::map<FieldName, ATC::MatrixDependencyManager<DiagonalMatrix, double> > MASS_MATS;
   typedef std::map<FieldName, ATC::MatrixDependencyManager<SparseMatrix, double> > CON_MASS_MATS;
   typedef ATC::MatrixDependencyManager<ATC_matrix::DenseMatrix, double> DENS_MAN;
   typedef ATC::MatrixDependencyManager<SparseMatrix, double> SPAR_MAN;
   typedef ATC::MatrixDependencyManager<ParSparseMatrix, double> PAR_SPAR_MAN;
   typedef ATC::MatrixDependencyManager<DiagonalMatrix, double> DIAG_MAN;
   typedef ATC::MatrixDependencyManager<ParDiagonalMatrix, double> PAR_DIAG_MAN;
 
   /** typedefs for WeakEquation evaluation */
   typedef Array2D<bool>  RHS_MASK;
 
   /** typedefs for input/output */
   typedef std::map<std::string, const ATC_matrix::Matrix<double>*> OUTPUT_LIST;
   typedef std::map<std::string, ATC_matrix::Matrix<double>*> RESTART_LIST;
 
   typedef  std::pair<int, int>  ID_PAIR;
   typedef std::vector< std::pair<int, int> > ID_LIST;
 
   /** misc typedefs */
   class XT_Function;
   class UXT_Function;
   typedef std::map<FieldName, std::map<PAIR, Array<XT_Function*> > > SURFACE_SOURCE;
   typedef std::map<FieldName, std::map<PAIR, Array<UXT_Function*> > > ROBIN_SURFACE_SOURCE;
+  typedef std::map<FieldName, std::set<PAIR> > OPEN_SURFACE;
   typedef std::map<FieldName, Array2D<XT_Function *> > VOLUME_SOURCE;
   typedef std::map<std::string, ATC::MatrixDependencyManager<ATC_matrix::DenseMatrix, double> > ATOMIC_DATA;
   
   /** typedefs for FE_Mesh */
   typedef std::map<std::string, std::set<int > > NODE_SET_MAP;
   typedef std::map<std::string, std::set<int > > ELEMENT_SET_MAP;
   typedef std::map<std::string, std::set<PAIR> > FACE_SET_MAP;
 
   /** string to index */
   // inline vs. static is used to avoid compiler warnings that the function isn't used
   // the compiler seems to just check if static functions are used in the file they're
   // declared in rather than all the files that include the header,
   // same for arrays (but not primitives, e.g. ints) hopefully this also speeds up the code
   inline bool string_to_index(const std::string & dim, int & index, int & sgn)
   {
     char dir;
     if (dim.empty()) return false;
     sgn = (dim[0] == '-') ? -1 : 1;
     dir = dim[dim.size()-1]; // dir is last character
     if      (dir == 'x') index = 0;
     else if (dir == 'y') index = 1;
     else if (dir == 'z') index = 2;
     else return false;
     return true;
   };
 
   /** string to index */
   inline std::string index_to_string(const int &index)
   {
     if      (index==0) return "x";
     else if (index==1) return "y";
     else if (index==2) return "z";
     return "unknown";
   };
 
   /** string to index */
   inline bool string_to_index(const std::string &dim, int &index)
   {
     if (dim=="x")
       index = 0;
     else if (dim=="y")
       index = 1;
     else if (dim=="z")
       index = 2;
     else
       return false;
 
     return true;
   };
 
   inline std::string print_mask(const Array2D<bool> & rhsMask) 
   {
     std::string msg;
     for (int i = 0; i < NUM_FIELDS; i++) {       
       FieldName field = (FieldName) i;
       std::string name = field_to_string(field);
       if (rhsMask(field,FLUX)
           || rhsMask(field,SOURCE)           
           || rhsMask(field,PRESCRIBED_SOURCE)
           || rhsMask(field,ROBIN_SOURCE)
+          || rhsMask(field,OPEN_SOURCE)
           || rhsMask(field,EXTRINSIC_SOURCE))  {
         msg = "RHS_MASK: " + name;
         if (rhsMask(field,FLUX))              msg += " flux";
         if (rhsMask(field,SOURCE))            msg += " source";
         if (rhsMask(field,PRESCRIBED_SOURCE)) msg += " prescribed_src";
         if (rhsMask(field,ROBIN_SOURCE))      msg += " robin_src";
+        if (rhsMask(field,OPEN_SOURCE))       msg += " open_src";
         if (rhsMask(field,EXTRINSIC_SOURCE))  msg += " extrinsic_src";
       }
     }
     return msg;
   }
 }
 
 #endif
diff --git a/lib/atc/AtomicRegulator.cpp b/lib/atc/AtomicRegulator.cpp
index ec04b8556..9d329852a 100644
--- a/lib/atc/AtomicRegulator.cpp
+++ b/lib/atc/AtomicRegulator.cpp
@@ -1,987 +1,990 @@
 // ATC Headers
 #include "AtomicRegulator.h"
 #include "ATC_Error.h"
 #include "ATC_Coupling.h"
 #include "PrescribedDataManager.h"
 #include "TimeIntegrator.h"
 #include "LinearSolver.h"
 
 using std::map;
 using std::string;
 using std::set;
 using std::pair;
 
 namespace ATC {
 
   
   // only one regulator method at time, i.e. fixed & flux, thermo & elastic
   // regulator manages lambda variables, creates new ones when requested with dimensions and zero ics (map of tag to lambda)
   // regulator keeps track of which lambda are being used, unused lambdas deleted (map of tag to bool), all tags set to unused on start of initialization
   // method requests needed lambda from regulator
   // method sets up all needed linear solvers, null linear solver does nothing
   // regulator adds nodes to fixed or fluxed lists it owns, based on localization and type
   // method gets lists of fixed nodes and fluxed nodes
   // method lumps fluxed lambdas and truncates fixed lambdas based on single localized bool in regulator
   // inherited methods should be fixed, fluxed, combined
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomicRegulator
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomicRegulator::AtomicRegulator(ATC_Coupling * atc,
                                    const string & regulatorPrefix) :
     atc_(atc),
     howOften_(1),
     needReset_(true),
     maxIterations_(myMaxIterations),
     tolerance_(myTolerance),
     regulatorTarget_(NONE),
     couplingMode_(UNCOUPLED),
     nNodes_(0),
     nsd_(atc_->nsd()),
     nLocal_(0),
     useLocalizedLambda_(false),
     useLumpedLambda_(false),
     timeFilter_(NULL),
     regulatorMethod_(NULL),
     boundaryIntegrationType_(NO_QUADRATURE),
     regulatorPrefix_(regulatorPrefix)
   {
     applyInDirection_.resize(atc_->nsd(),true);
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   AtomicRegulator::~AtomicRegulator()
   {
     delete_method();
     set_all_data_to_unused();
     delete_unused_data();
   }
 
   //--------------------------------------------------------
   //  delete_method:
   //    deletes the method
   //--------------------------------------------------------
   void AtomicRegulator::delete_method()
   {
     if (regulatorMethod_)
       delete regulatorMethod_;
   }
 
   //--------------------------------------------------------
   //  delete_unused_data:
   //    deletes all data that is currently not in use
   //--------------------------------------------------------
   void AtomicRegulator::delete_unused_data()
   {
     map<string, pair<bool,DENS_MAN * > >::iterator it;
     for (it = regulatorData_.begin(); it != regulatorData_.end(); it++) {
       if (((it->second).first)) {
         delete (it->second).second;
         regulatorData_.erase(it);
       }
     }
   }
 
   //--------------------------------------------------------
   //  get_regulator_data:
   //    gets a pointer to the requested data, is crated if
   //    if doesn't exist
   //--------------------------------------------------------
   DENS_MAN * AtomicRegulator::regulator_data(const string tag, int nCols)
   {
     DENS_MAN * data(NULL);
     map<string, pair<bool,DENS_MAN * > >::iterator it = regulatorData_.find(tag);
     if (it == regulatorData_.end()) {
       data = new DENS_MAN(nNodes_,nCols);
       regulatorData_.insert(pair<string, pair<bool,DENS_MAN * > >(tag,pair<bool,DENS_MAN * >(false,data)));
     }
     else {
       data = (it->second).second;
       if ((data->nRows() != nNodes_) || (data->nCols() != nCols)) {
         data->reset(nNodes_,nCols);
       }
       (it->second).first = false;
     }
     return data;
   }
 
   //--------------------------------------------------------
   //  get_regulator_data:
   //    gets a pointer to the requested data, or NULL if
   //    if doesn't exist
   //--------------------------------------------------------
   const DENS_MAN * AtomicRegulator::regulator_data(const string tag) const
   {
     map<string, pair<bool,DENS_MAN * > >::const_iterator it = regulatorData_.find(tag);
     if (it == regulatorData_.end()) {
       return NULL;
     }
     else {
       return const_cast<DENS_MAN * >((it->second).second);
     }
   }
 
   //--------------------------------------------------------
   //  set_all_data_to_unused:
   //    sets bool such that all data is unused
   //--------------------------------------------------------
   void AtomicRegulator::set_all_data_to_unused()
   {
     map<string, pair<bool,DENS_MAN * > >::iterator it;
     for (it = regulatorData_.begin(); it != regulatorData_.end(); it++) {
       (it->second).first = true;
     }
   }
 
   //--------------------------------------------------------
   //  set_all_data_to_used:
   //    sets bool such that all data is used
   //--------------------------------------------------------
   void AtomicRegulator::set_all_data_to_used()
   {
     map<string, pair<bool,DENS_MAN * > >::iterator it;
     for (it = regulatorData_.begin(); it != regulatorData_.end(); it++) {
       (it->second).first = false;
     }
   }
 
   //--------------------------------------------------------
   //  modify:
   //    parses and adjusts controller state based on
   //    user input, in the style of LAMMPS user input
   //--------------------------------------------------------
   bool AtomicRegulator::modify(int narg, char **arg)
   {
     bool foundMatch = false;
 
         // set parameters for numerical matrix solutions
     /*! \page man_control fix_modify AtC control
       \section syntax
       fix_modify AtC control <physics_type> <solution_parameter> <value>\n
         - physics_type (string) = thermal | momentum\n
         - solution_parameter (string) = max_iterations | tolerance\n
       
       fix_modify AtC transfer <physics_type> control max_iterations <max_iterations>\n
         - max_iterations (int) = maximum number of iterations that will be used by iterative matrix solvers\n
 
       fix_modify AtC transfer <physics_type> control tolerance <tolerance> \n
         - tolerance (float) = relative tolerance to which matrix equations will be solved\n
 
       \section examples
       <TT> fix_modify AtC control thermal max_iterations 10 </TT> \n
       <TT> fix_modify AtC control momentum tolerance 1.e-5 </TT> \n
       \section description
       Sets the numerical parameters for the matrix solvers used in the specified control algorithm.  Many solution approaches require iterative solvers, and these methods enable users to provide the maximum number of iterations and the relative tolerance.
       \section restrictions
       only for be used with specific controllers :
       thermal, momentum \n
       They are ignored if a lumped solution is requested
       \section related
       \section default
       max_iterations is the number of rows in the matrix\n
       tolerance is 1.e-10
     */
     int argIndex = 0;
     if (strcmp(arg[argIndex],"max_iterations")==0) {
       argIndex++;
       maxIterations_ = atoi(arg[argIndex]);
       if (maxIterations_ < 1) {
         throw ATC_Error("Bad maximum iteration count");
       }
       needReset_ = true;
       foundMatch = true;
     }
     else if (strcmp(arg[argIndex],"tolerance")==0) {
       argIndex++;
       tolerance_ = atof(arg[argIndex]);
       if (tolerance_ < 0.) {
         throw ATC_Error("Bad tolerance value");
       }
       needReset_ = true;
       foundMatch = true;
     }
 
     /*! \page man_localized_lambda fix_modify AtC control localized_lambda 
       \section syntax
       fix_modify AtC control localized_lambda <on|off> 
       \section examples
        <TT> fix_modify atc control localized_lambda on </TT> \n
       \section description
       Turns on localization algorithms for control algorithms to restrict the influence of FE coupling or boundary conditions to a region near the boundary of the MD region.  Control algorithms will not affect atoms in elements not possessing faces on the boundary of the region.  Flux-based control is localized via row-sum lumping while quantity control is done by solving a truncated matrix equation.
       \section restrictions 
       \section related
       \section default
       Default is off.
     */
     else if (strcmp(arg[argIndex],"localized_lambda")==0) {
       argIndex++;
       if (strcmp(arg[argIndex],"on")==0) {
         useLocalizedLambda_ = true;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"off")==0) {
         useLocalizedLambda_ = false;
         foundMatch = true;
       }
     }
 
     
     
     /*! \page man_lumped_lambda_solve fix_modify AtC control lumped_lambda_solve 
       \section syntax
       fix_modify AtC control lumped_lambda_solve <on|off> 
       \section examples
        <TT> fix_modify atc control lumped_lambda_solve on </TT> \n
       \section description
       Command to use or not use lumped matrix for lambda solve
       \section restrictions 
       \section related
       \section default
     */
     else if (strcmp(arg[argIndex],"lumped_lambda_solve")==0) {
       argIndex++;
       if (strcmp(arg[argIndex],"on")==0) {
         useLumpedLambda_ = true;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"off")==0) {
         useLumpedLambda_ = false;
         foundMatch = true;
       }
     }
 
     /*! \page man_mask_direction fix_modify AtC control mask_direction
       \section syntax
       fix_modify AtC control mask_direction <direction> <on|off> 
       \section examples
        <TT> fix_modify atc control mask_direction 0 on </TT> \n
       \section description
       Command to mask out certain dimensions from the atomic regulator
       \section restrictions 
       \section related
       \section default
     */
     else if (strcmp(arg[argIndex],"mask_direction")==0) {
       argIndex++;
       int dir = atoi(arg[argIndex]);
       argIndex++;
       if (strcmp(arg[argIndex],"on")==0) {
         applyInDirection_[dir] = false;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"off")==0) {
         applyInDirection_[dir] = true;
         foundMatch = true;
       }
     }
 
     return foundMatch;
   }
 
   //--------------------------------------------------------
   //  reset_nlocal:
   //    resizes lambda force if necessary
   //--------------------------------------------------------
   void AtomicRegulator::reset_nlocal()
   {
     nLocal_ = atc_->nlocal();
     if (regulatorMethod_)
       regulatorMethod_->reset_nlocal();
   }
   //--------------------------------------------------------
   //  reset_atom_materials:
   //    resets the localized atom to material map
   //--------------------------------------------------------
   void AtomicRegulator::reset_atom_materials(const Array<int> & elementToMaterialMap,
                                              const MatrixDependencyManager<DenseMatrix, int> * atomElement)
   {
     if (regulatorMethod_)
       regulatorMethod_->reset_atom_materials(elementToMaterialMap,
                                              atomElement);
   }
   //--------------------------------------------------------
   //  reset_method:
   //    sets up methods, if necessary
   //--------------------------------------------------------
   void AtomicRegulator::reset_method()
   {
     // set up defaults for anything that didn't get set
     if (!regulatorMethod_)
       regulatorMethod_ = new RegulatorMethod(this);
     if (!timeFilter_)
       timeFilter_ = (atc_->time_filter_manager())->construct();
   }
   //--------------------------------------------------------
   //  md_fixed_nodes:
   //    determines if any fixed nodes overlap the MD region
   //--------------------------------------------------------
   bool AtomicRegulator::md_fixed_nodes(FieldName fieldName) const
   {
     FixedNodes fixedNodes(atc_,fieldName);
     const set<int> & myNodes(fixedNodes.quantity());
     if (myNodes.size() == 0) {
       return false;
     }
     else {
       return true;
     }
   }
   //--------------------------------------------------------
   //  md_flux_nodes:
   //    determines if any nodes with fluxes overlap the MD region
   //--------------------------------------------------------
   bool AtomicRegulator::md_flux_nodes(FieldName fieldName) const
   {
     FluxNodes fluxNodes(atc_,fieldName);
     const set<int> & myNodes(fluxNodes.quantity());
     if (myNodes.size() == 0) {
       return false;
     }
     else {
       return true;
     }
   }
   //--------------------------------------------------------
   //  construct_methods:
   //    sets up methods before a run
   //--------------------------------------------------------
   void AtomicRegulator::construct_methods()
   {
     // get base-line data that was set in stages 1 & 2 of ATC_Method::initialize
     // computational geometry
     nNodes_ = atc_->num_nodes();
 
     // make sure consistent boundary integration is being used
     atc_->set_boundary_integration_type(boundaryIntegrationType_);
   }
 
   //--------------------------------------------------------
   //  construct_transfers:
   //    pass through to appropriate transfer constuctors
   //--------------------------------------------------------
   void AtomicRegulator::construct_transfers()
   {
     regulatorMethod_->construct_transfers();
   }
 
   //--------------------------------------------------------
   //  initialize:
   //    sets up methods before a run
   //--------------------------------------------------------
   void AtomicRegulator::initialize()
   {
     regulatorMethod_->initialize();
     needReset_ = false;
   }
 
   //--------------------------------------------------------
   //  output:
   //    pass through to appropriate output methods
   //--------------------------------------------------------
   void AtomicRegulator::output(OUTPUT_LIST & outputData) const
   {
     regulatorMethod_->output(outputData);
   }
 
   //--------------------------------------------------------
   //  finish:
   //    pass through to appropriate end-of-run methods
   //--------------------------------------------------------
   void AtomicRegulator::finish()
   {
     regulatorMethod_->finish();
     set_all_data_to_unused();
   }
 
   //--------------------------------------------------------
   //  apply_pre_predictor:
   //    applies the controller in the pre-predictor
   //    phase of the time integrator  
   //--------------------------------------------------------
   void AtomicRegulator::apply_pre_predictor(double dt, int timeStep)
   {
     if (timeStep % howOften_==0) // apply full integration scheme, including filter
       regulatorMethod_->apply_pre_predictor(dt);
   }
 
   //--------------------------------------------------------
   //  apply_mid_predictor:
   //    applies the controller in the mid-predictor
   //    phase of the time integrator  
   //--------------------------------------------------------
   void AtomicRegulator::apply_mid_predictor(double dt, int timeStep)
   {
     if (timeStep % howOften_==0) // apply full integration scheme, including filter
       regulatorMethod_->apply_mid_predictor(dt);
   }
 
   //--------------------------------------------------------
   //  apply_post_predictor:
   //    applies the controller in the post-predictor
   //    phase of the time integrator  
   //--------------------------------------------------------
   void AtomicRegulator::apply_post_predictor(double dt, int timeStep)
   {
     if (timeStep % howOften_==0) // apply full integration scheme, including filter
       regulatorMethod_->apply_post_predictor(dt);
   }
  
   //--------------------------------------------------------
   //  apply_pre_corrector:
   //    applies the controller in the pre-corrector phase
   //    of the time integrator
   //--------------------------------------------------------
   void AtomicRegulator::apply_pre_corrector(double dt, int timeStep)
   {
     if (timeStep % howOften_==0) // apply full integration scheme, including filter   
       regulatorMethod_->apply_pre_corrector(dt);
   }
 
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    applies the controller in the post-corrector phase
   //    of the time integrator
   //--------------------------------------------------------
   void AtomicRegulator::apply_post_corrector(double dt, int timeStep)
   {
     if (timeStep % howOften_==0) // apply full integration scheme, including filter
       regulatorMethod_->apply_post_corrector(dt);
   }
 
   //--------------------------------------------------------
   //  pre_exchange
   //--------------------------------------------------------
   void AtomicRegulator::pre_exchange()
   {
     regulatorMethod_->pre_exchange();
   }
 
   //--------------------------------------------------------
   //  pre_force
   //--------------------------------------------------------
   void AtomicRegulator::pre_force()
   {
     regulatorMethod_->post_exchange();
   }
 
   //--------------------------------------------------
   // pack_fields
   //   bundle all allocated field matrices into a list
   //   for output needs
   //--------------------------------------------------
   void AtomicRegulator::pack_fields(RESTART_LIST & data)
   {
     map<string, pair<bool,DENS_MAN * > >::iterator it;
     for (it = regulatorData_.begin(); it != regulatorData_.end(); it++) {
       data[(it->first)] = &(((it->second).second)->set_quantity());
     }
   }
 
   //--------------------------------------------------------
   //  compute_boundary_flux:
   //    computes the boundary flux to be consistent with
   //    the controller
   //--------------------------------------------------------
   void AtomicRegulator::compute_boundary_flux(FIELDS & fields)
   {
     regulatorMethod_->compute_boundary_flux(fields);
   }
 
   //--------------------------------------------------------
   //  add_to_rhs:
   //    adds any controller contributions to the FE rhs 
   //--------------------------------------------------------
   void AtomicRegulator::add_to_rhs(FIELDS & rhs)
   {
     regulatorMethod_->add_to_rhs(rhs);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class RegulatorMethod
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   RegulatorMethod::RegulatorMethod(AtomicRegulator * atomicRegulator,
                                    const string & regulatorPrefix) :
     atomicRegulator_(atomicRegulator),
     atc_(atomicRegulator_->atc_transfer()),
     boundaryFlux_(atc_->boundary_fluxes()),
     fieldMask_(NUM_FIELDS,NUM_FLUX),
     nNodes_(atomicRegulator_->num_nodes()),
     regulatorPrefix_(atomicRegulator->regulator_prefix()+regulatorPrefix),
     shpFcnDerivs_(NULL)
   {
     fieldMask_ = false;
   }
 
   //--------------------------------------------------------
   //  compute_boundary_flux
   //    default computation of boundary flux based on
   //    finite
   //--------------------------------------------------------
   void RegulatorMethod::compute_boundary_flux(FIELDS & fields)
   {
     atc_->compute_boundary_flux(fieldMask_,
                                 fields,
                                 boundaryFlux_,
                                 atomMaterialGroups_,
                                 shpFcnDerivs_);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class RegulatorShapeFunction
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   RegulatorShapeFunction::RegulatorShapeFunction(AtomicRegulator * atomicRegulator,
                                                  const string & regulatorPrefix) :
     RegulatorMethod(atomicRegulator,regulatorPrefix),
     lambda_(NULL),
     atomLambdas_(NULL),
     shapeFunctionMatrix_(NULL),
     linearSolverType_(AtomicRegulator::NO_SOLVE),
     maxIterations_(atomicRegulator->max_iterations()),
     tolerance_(atomicRegulator->tolerance()),
     matrixSolver_(NULL),
     regulatedNodes_(NULL),
     applicationNodes_(NULL),
     boundaryNodes_(NULL),
     shpFcn_(NULL),
     atomicWeights_(NULL),
     elementMask_(NULL),
     lambdaAtomMap_(NULL),
     weights_(NULL),
     nsd_(atomicRegulator_->nsd()),
     nLocal_(atomicRegulator_->nlocal())
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   RegulatorShapeFunction::~RegulatorShapeFunction()
   {
     if (matrixSolver_)
       delete matrixSolver_;
   }
 
   //--------------------------------------------------------
   //  create_node_maps
   //  - creates the node mappings between all nodes and the
   //    subset which are regulated
   //--------------------------------------------------------
   void RegulatorShapeFunction::create_node_maps()
   {
     this->construct_regulated_nodes();
 
     InterscaleManager & interscaleManager(atc_->interscale_manager());
-    nodeToOverlapMap_ = static_cast<NodeToSubset * >(interscaleManager.dense_matrix_int("NodeToOverlapMap"));
+    nodeToOverlapMap_ = static_cast<NodeToSubset * >(interscaleManager.dense_matrix_int(regulatorPrefix_+"NodeToOverlapMap"));
     if (!nodeToOverlapMap_) {
       nodeToOverlapMap_ = new NodeToSubset(atc_,regulatedNodes_);
       interscaleManager.add_dense_matrix_int(nodeToOverlapMap_,
-                                                  regulatorPrefix_+"NodeToOverlapMap");
+                                             regulatorPrefix_+"NodeToOverlapMap");
     }
-    overlapToNodeMap_ = static_cast<SubsetToNode * >(interscaleManager.dense_matrix_int("OverlapToNodeMap"));
+    overlapToNodeMap_ = static_cast<SubsetToNode * >(interscaleManager.dense_matrix_int(regulatorPrefix_+"OverlapToNodeMap"));
     if (!overlapToNodeMap_) {
       overlapToNodeMap_ = new SubsetToNode(nodeToOverlapMap_);
       interscaleManager.add_dense_matrix_int(overlapToNodeMap_,
-                                                  regulatorPrefix_+"OverlapToNodeMap");
+                                             regulatorPrefix_+"OverlapToNodeMap");
     }
     
   }
 
   //--------------------------------------------------------
   //  construct_transfers
   //  - create all the needed transfer operators, in this
   //    case weights for the lambda matrix
   //--------------------------------------------------------
   void RegulatorShapeFunction::construct_transfers()
   {
     this->set_weights(); // construct specific weighting matrix transfer
 
     // specialized quantities for boundary flux integration if the lambda atom map exists
     if (lambdaAtomMap_ && (atomicRegulator_->boundary_integration_type() == FE_INTERPOLATION)) {
       InterscaleManager & interscaleManager(atc_->interscale_manager());
 
       // atomic weights
       PerAtomDiagonalMatrix<double> * atomWeights(interscaleManager.per_atom_diagonal_matrix("AtomVolume"));
       atomicWeights_ = new MappedDiagonalMatrix(atc_,
                                                 atomWeights,
                                                 lambdaAtomMap_);
       interscaleManager.add_diagonal_matrix(atomicWeights_,
                                             regulatorPrefix_+"RegulatorAtomWeights");
 
       // shape function
       shpFcn_ = new RowMappedSparseMatrix(atc_,
                                           interscaleManager.per_atom_sparse_matrix("Interpolant"),
                                           lambdaAtomMap_);
       interscaleManager.add_sparse_matrix(shpFcn_,
                                           regulatorPrefix_+"RegulatorShapeFunction");
 
       // shape function derivatives
       VectorDependencyManager<SPAR_MAT * > * interpolantGradient = interscaleManager.vector_sparse_matrix("InterpolantGradient");
       if (!interpolantGradient) {
         interpolantGradient = new PerAtomShapeFunctionGradient(atc_);
         interscaleManager.add_vector_sparse_matrix(interpolantGradient,
                                                    "InterpolantGradient");
       }
       shpFcnDerivs_ = new RowMappedSparseMatrixVector(atc_,
                                                       interpolantGradient,
                                                       lambdaAtomMap_);
       interscaleManager.add_vector_sparse_matrix(shpFcnDerivs_,
                                                  regulatorPrefix_+"RegulatorShapeFunctionGradient");
     }
   }
 
   //--------------------------------------------------------
   //  initialize
   //  - pre-run work, in this cases constructs the linear
   //    solver
   //--------------------------------------------------------
   void RegulatorShapeFunction::initialize()
   {
     if (!shapeFunctionMatrix_) {
       throw ATC_Error("RegulatorShapeFunction::initialize - shapeFunctionMatrix_ must be created before the initialize phase");
     }
     if (matrixSolver_)
       delete matrixSolver_;
 
     if (linearSolverType_ == AtomicRegulator::RSL_SOLVE) {
       matrixSolver_ = new LambdaMatrixSolverLumped(matrixTemplate_,
                                                    shapeFunctionMatrix_,
                                                    maxIterations_,
                                                    tolerance_,
                                                    applicationNodes_,
                                                    nodeToOverlapMap_);
     }
     else if (linearSolverType_ == AtomicRegulator::CG_SOLVE) {
       matrixSolver_ = new LambdaMatrixSolverCg(matrixTemplate_,
                                                shapeFunctionMatrix_,
                                                maxIterations_,
                                                tolerance_);
     }
     else {
       throw ATC_Error("RegulatorShapeFunction::initialize - unsupported solver type");
     }
 
-    compute_sparsity();    
+    compute_sparsity();
   }
 
   //--------------------------------------------------------
   //  compute_sparsity
   //  - creates sparsity template
   //--------------------------------------------------------
   void RegulatorShapeFunction::compute_sparsity(void)
   {
     
     // first get local pattern from N N^T
     int nNodeOverlap = nodeToOverlapMap_->size();
     DENS_MAT tmpLocal(nNodeOverlap,nNodeOverlap);
     DENS_MAT tmp(nNodeOverlap,nNodeOverlap);
     const SPAR_MAT & myShapeFunctionMatrix(shapeFunctionMatrix_->quantity());
     if (myShapeFunctionMatrix.nRows() > 0) {
       tmpLocal = myShapeFunctionMatrix.transMat(myShapeFunctionMatrix);
     }
     
     // second accumulate total pattern across processors
     LammpsInterface::instance()->allsum(tmpLocal.ptr(), tmp.ptr(), tmp.size());
     // third extract non-zero entries & construct sparse template
     SPAR_MAT & myMatrixTemplate(matrixTemplate_.set_quantity());
     myMatrixTemplate.reset(nNodeOverlap,nNodeOverlap);
     for (int i = 0; i < nNodeOverlap; i++) {
       for (int j = 0; j < nNodeOverlap; j++) {
         if (abs(tmp(i,j))>0) {
           myMatrixTemplate.add(i,j,0.);
         }
       }
     }
     myMatrixTemplate.compress();
   }
 
   //--------------------------------------------------------
   //  solve_for_lambda
   //    solves matrix equation for lambda using given rhs
   //--------------------------------------------------------
   void RegulatorShapeFunction::solve_for_lambda(const DENS_MAT & rhs,
                                                 DENS_MAT & lambda)
   {
 
     // assemble N^T W N with appropriate weighting matrix
     
     DIAG_MAT weights;
     if (shapeFunctionMatrix_->nRows() > 0) {
       weights.reset(weights_->quantity());
     }
     matrixSolver_->assemble_matrix(weights);
     
     // solve on overlap nodes
     int nNodeOverlap = nodeToOverlapMap_->size();
     DENS_MAT rhsOverlap(nNodeOverlap,rhs.nCols());
     map_unique_to_overlap(rhs, rhsOverlap);
     DENS_MAT lambdaOverlap(nNodeOverlap,lambda.nCols());
 
     for (int i = 0; i < rhs.nCols(); i++) {
       CLON_VEC tempLambda(lambdaOverlap,CLONE_COL,i);
       if (atomicRegulator_->apply_in_direction(i)) {
         CLON_VEC tempRHS(rhsOverlap,CLONE_COL,i);
         matrixSolver_->execute(tempRHS,tempLambda);
       }
       else {
         tempLambda = 0.;
       }
     }
     
     // map solution back to all nodes
     map_overlap_to_unique(lambdaOverlap,lambda);
   }
 
   //--------------------------------------------------------
   //  reset_nlocal:
   //    resets data dependent on local atom count
   //--------------------------------------------------------
   void RegulatorShapeFunction::reset_nlocal()
   {
     RegulatorMethod::reset_nlocal();
     nLocal_ = atomicRegulator_->nlocal();
 
     
     
     //compute_sparsity();
   }
 
   //--------------------------------------------------------
   //  reset_atom_materials:
   //    resets the localized atom to material map
   //--------------------------------------------------------
   void RegulatorShapeFunction::reset_atom_materials(const Array<int> & elementToMaterialMap,
                                                     const MatrixDependencyManager<DenseMatrix, int> * atomElement)
   {
     // specialized quantities for boundary flux integration if the lambda atom map exists
     if (lambdaAtomMap_ && (atomicRegulator_->boundary_integration_type() == FE_INTERPOLATION)) {
       int nMaterials = (atc_->physics_model())->nMaterials();
       atomMaterialGroups_.reset(nMaterials);
       const INT_ARRAY & atomToElementMap(atomElement->quantity());
       const INT_ARRAY & map(lambdaAtomMap_->quantity());
       int idx;
       for (int i = 0; i < nLocal_; i++) {
         idx = map(i,0);
         if (idx > -1) {
           atomMaterialGroups_(elementToMaterialMap(atomToElementMap(i,0))).insert(idx);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //  map_unique_to_overlap:
   //    maps unique node data to overlap node data
   //--------------------------------------------------------
   void RegulatorShapeFunction::map_unique_to_overlap(const MATRIX & uniqueData,
                                                      MATRIX & overlapData)
   {
     const INT_ARRAY & nodeToOverlapMap(nodeToOverlapMap_->quantity());
     for (int i = 0; i < nNodes_; i++) {
       if (nodeToOverlapMap(i,0) > -1) {
         for (int j = 0; j < uniqueData.nCols(); j++) {
           overlapData(nodeToOverlapMap(i,0),j) = uniqueData(i,j);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //  map_overlap_to_unique:
   //    maps overlap node data to unique node data
   //--------------------------------------------------------
   void RegulatorShapeFunction::map_overlap_to_unique(const MATRIX & overlapData,
                                                      MATRIX & uniqueData)
   {
     const INT_ARRAY & overlapToNodeMap(overlapToNodeMap_->quantity());
     uniqueData.resize(nNodes_,overlapData.nCols());
     for (int i = 0; i < overlapToNodeMap.size(); i++) {
       for (int j = 0; j < overlapData.nCols(); j++) {
         uniqueData(overlapToNodeMap(i,0),j) = overlapData(i,j);
       }
     }
   }
   //--------------------------------------------------------
   //  construct_regulated_nodes:
   //    constructs the set of nodes being regulated
   //--------------------------------------------------------
   void RegulatorShapeFunction::construct_regulated_nodes()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
-    regulatedNodes_ = static_cast<RegulatedNodes *>(interscaleManager.set_int("RegulatedNodes"));
+    regulatedNodes_ = interscaleManager.set_int("RegulatedNodes");
 
     if (!regulatedNodes_) {
       if (!(atomicRegulator_->use_localized_lambda())) {
         regulatedNodes_ = new RegulatedNodes(atc_);
       }
       else {
         regulatedNodes_ = new AllRegulatedNodes(atc_);
       }
       interscaleManager.add_set_int(regulatedNodes_,
                                     regulatorPrefix_+"RegulatedNodes");
     }
 
     // application and regulated are same, unless specified
     applicationNodes_ = regulatedNodes_;
     // boundary and regulated nodes are same, unless specified
     boundaryNodes_ = regulatedNodes_;
 
     // special set of boundary elements
     if (atomicRegulator_->use_localized_lambda()) {
-      elementMask_ = new ElementMaskNodeSet(atc_,boundaryNodes_);
-      interscaleManager.add_dense_matrix_bool(elementMask_,
-                                                   regulatorPrefix_+"BoundaryElementMask");
+      elementMask_ = interscaleManager.dense_matrix_bool(regulatorPrefix_+"BoundaryElementMask");
+      if (!elementMask_) {
+        elementMask_ = new ElementMaskNodeSet(atc_,boundaryNodes_);
+        interscaleManager.add_dense_matrix_bool(elementMask_,
+                                                regulatorPrefix_+"BoundaryElementMask");
+      }
     }
   }
 
   //--------------------------------------------------------
   //  compute_boundary_flux
   //    default computation of boundary flux based on
   //    finite
   //--------------------------------------------------------
   void RegulatorShapeFunction::compute_boundary_flux(FIELDS & fields)
   {
     atc_->compute_boundary_flux(fieldMask_,
                                 fields,
                                 boundaryFlux_,
                                 atomMaterialGroups_,
                                 shpFcnDerivs_,
                                 shpFcn_,
                                 atomicWeights_,
                                 elementMask_,
                                 boundaryNodes_);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaMatrixSolver
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to necessary data
   //--------------------------------------------------------
   LambdaMatrixSolver::LambdaMatrixSolver(SPAR_MAN & matrixTemplate, SPAR_MAN * shapeFunctionMatrix, int maxIterations, double tolerance) :
     matrixTemplate_(matrixTemplate),
     shapeFunctionMatrix_(shapeFunctionMatrix),
     maxIterations_(maxIterations),
     tolerance_(tolerance)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  assemble_matrix
   //        Assemble the matrix using the shape function
   //        matrices and weights.  This improves efficiency
   //        when multiple solves or iterations are required.
   //--------------------------------------------------------
   void LambdaMatrixSolver::assemble_matrix(DIAG_MAT & weights)
   {
     // form matrix : sum_a N_Ia * W_a * N_Ja
     
     SPAR_MAT lambdaMatrixLocal(matrixTemplate_.quantity());
     if (weights.nRows()>0)
       lambdaMatrixLocal.weighted_least_squares(shapeFunctionMatrix_->quantity(),weights);
 
     // swap contributions
     lambdaMatrix_ = matrixTemplate_.quantity();
     LammpsInterface::instance()->allsum(lambdaMatrixLocal.ptr(),
                                         lambdaMatrix_.ptr(), lambdaMatrix_.size());
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaMatrixSolverLumped
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to necessary data
   //--------------------------------------------------------
-  LambdaMatrixSolverLumped::LambdaMatrixSolverLumped(SPAR_MAN & matrixTemplate, SPAR_MAN * shapeFunctionMatrix, int maxIterations, double tolerance, const RegulatedNodes * applicationNodes, const NodeToSubset * nodeToOverlapMap) :
+  LambdaMatrixSolverLumped::LambdaMatrixSolverLumped(SPAR_MAN & matrixTemplate, SPAR_MAN * shapeFunctionMatrix, int maxIterations, double tolerance, const SetDependencyManager<int> * applicationNodes, const NodeToSubset * nodeToOverlapMap) :
     LambdaMatrixSolver(matrixTemplate,shapeFunctionMatrix,maxIterations,tolerance),
     applicationNodes_(applicationNodes),
     nodeToOverlapMap_(nodeToOverlapMap)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  assemble_matrix
   //        Assemble the matrix using the shape function
   //        matrices and weights.  This improves efficiency
   //        when multiple solves or iterations are required.
   //--------------------------------------------------------
   void LambdaMatrixSolverLumped::assemble_matrix(DIAG_MAT & weights)
   {
     LambdaMatrixSolver::assemble_matrix(weights);
     
     lumpedMatrix_ = lambdaMatrix_.row_sum_lump();
   }
 
   void LambdaMatrixSolverLumped::execute(VECTOR & rhs, VECTOR & lambda) 
   {
     
     // solve lumped equation
     const set<int> & applicationNodes(applicationNodes_->quantity());
     const INT_ARRAY & nodeToOverlapMap(nodeToOverlapMap_->quantity());
     lambda = 0.;
     set<int>::const_iterator iset;
     for (iset = applicationNodes.begin(); iset != applicationNodes.end(); iset++) {
       int node = nodeToOverlapMap(*iset,0);
       lambda(node) = rhs(node)/lumpedMatrix_(node,node);
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaMatrixSolverCg
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to necessary data
   //--------------------------------------------------------
   LambdaMatrixSolverCg::LambdaMatrixSolverCg(SPAR_MAN & matrixTemplate, SPAR_MAN * shapeFunctionMatrix, int maxIterations, double tolerance) :
     LambdaMatrixSolver(matrixTemplate,shapeFunctionMatrix,maxIterations,tolerance)
   {
     // do nothing
   }
 
   void LambdaMatrixSolverCg::execute(VECTOR & rhs, VECTOR & lambda)
   {
     if (lambdaMatrix_.size()<1)
       throw ATC_Error("solver given zero size matrix in LambdaMatrixSolverCg::execute()");
 
 
     LinearSolver solver(lambdaMatrix_, ATC::LinearSolver::ITERATIVE_SOLVE_SYMMETRIC, true);
     int myMaxIt = maxIterations_ > 0 ? maxIterations_ : 2*lambdaMatrix_.nRows();
     solver.set_max_iterations(myMaxIt);
     solver.set_tolerance(tolerance_);
     solver.solve(lambda,rhs);
   }
 };
diff --git a/lib/atc/AtomicRegulator.h b/lib/atc/AtomicRegulator.h
index eadfce66d..5d1e59f60 100644
--- a/lib/atc/AtomicRegulator.h
+++ b/lib/atc/AtomicRegulator.h
@@ -1,625 +1,631 @@
 /** Atomic Regulator : a base class class for atom-continuum control */
 
 #ifndef ATOMICREGULATOR_H
 #define ATOMICREGULATOR_H
 
 #include "ATC_TypeDefs.h"
 #include <map>
 #include <set>
 #include <vector>
 #include <utility>
 #include <string>
 
 namespace ATC {
 
   static const int myMaxIterations = 0;
   static const double myTolerance = 1.e-10;
 
   // forward declarations
   class TimeFilter;
   class RegulatorMethod;
   class LambdaMatrixSolver;
   class ATC_Coupling;
   class NodeToSubset;
   class SubsetToNode;
   class RegulatedNodes;
   class ElementMaskNodeSet;
   class LargeToSmallAtomMap;
   template <typename T>
     class PerAtomQuantity;
   template <typename T>
     class ProtectedAtomQuantity;
   template <typename T>
     class PerAtomSparseMatrix;
 
   /**
    *  @class  AtomicRegulator
    *  @brief  Base class for atom-continuum control
    */
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomicRegulator
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   class AtomicRegulator {
   
   public:
 
     /** linear solver types */
     enum LinearSolverType {
       NO_SOLVE=0,
       CG_SOLVE, // conjugate gradient
       RSL_SOLVE   // row-sum lumping solution
     };
 
     /** regulator target variable */
     enum RegulatorTargetType {
       NONE=0,
       FIELD,
       DERIVATIVE,
       DYNAMICS
     };
 
     enum RegulatorCouplingType {
       UNCOUPLED=0,
       FLUX,
       GHOST_FLUX,
       FIXED
     };
   
     // constructor
     AtomicRegulator(ATC_Coupling * atc,
                     const std::string & regulatorPrefix = "");
         
     // destructor
     virtual ~AtomicRegulator();
         
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
 
     /** instantiate up the desired method(s) */
     virtual void construct_methods() = 0;
 
     /** method(s) create all necessary transfer operators */
     virtual void construct_transfers();
 
     /** initialization of method data */
     virtual void initialize();
         
     /** add output information */
     virtual void output(OUTPUT_LIST & outputData) const;
     virtual double compute_vector(int n) const {return 0;}
     
     /** final work at the end of a run */
     virtual void finish();
 
     /** reset number of local atoms, as well as atomic data */
     virtual void reset_nlocal();
 
     /** set up atom to material identification */
     virtual void reset_atom_materials(const Array<int> & elementToMaterialMap,
                                       const MatrixDependencyManager<DenseMatrix, int> * atomElement);
         
     // application steps
     /** apply the regulator in the pre-predictor phase */
     virtual void apply_pre_predictor(double dt, int timeStep);
     /** apply the regulator in the mid-predictor phase */
     virtual void apply_mid_predictor(double dt, int timeStep);
     /** apply the regulator in the post-predictor phase */
     virtual void apply_post_predictor(double dt, int timeStep);
     /** apply the regulator in the pre-correction phase */
     virtual void apply_pre_corrector(double dt, int timeStep);
     /** apply the regulator in the post-correction phase */
     virtual void apply_post_corrector(double dt, int timeStep);
 
     /** prior to exchanges */
     virtual void pre_force();
     /** prior to exchanges */
     virtual void pre_exchange();
 
     /** pack fields for restart */
     virtual void pack_fields(RESTART_LIST & data);
 
     /** thermo output */
     virtual int size_vector(int s) const {return 0;};
 
     // coupling to FE state
     /** FE state variable regulator is applied to */
     virtual RegulatorTargetType regulator_target() const {return regulatorTarget_;};
     /** type of boundary coupling */
     //TEMP_JAT field variable should be removed
     virtual RegulatorCouplingType coupling_mode(const FieldName field=NUM_TOTAL_FIELDS) const {return couplingMode_;};
     /** compute the thermal boundary flux, must be consistent with regulator */
     virtual void compute_boundary_flux(FIELDS & fields);
     /** add contributions (if any) to the finite element right-hand side */
     virtual void add_to_rhs(FIELDS & rhs);
         
     // data access, intended for method objects
     /** returns a pointer to the DENS_MAN associated with the tag, creates a new data member if necessary */
     DENS_MAN * regulator_data(const std::string tag, int nCols);
     /** can externally set regulator dynamic contributions */
     virtual void reset_lambda_contribution(const DENS_MAT & target, const FieldName field=NUM_TOTAL_FIELDS) {};
     /** returns a const pointer to the DENS_MAN associated with the tag, or NULL */
     const DENS_MAN * regulator_data(const std::string tag) const;
     /** return the maximum number of iterations */
     int max_iterations() {return maxIterations_;};
     /** return the solver tolerance */
     double tolerance() {return tolerance_;};
     /** access for ATC transfer */
     ATC_Coupling * atc_transfer() {return atc_;};
     /** access for time filter */
     TimeFilter * time_filter() {return timeFilter_;};
     /** access for number of nodes */
     int num_nodes() {return nNodes_;};
     /** access for number of spatial dimensions */
     int nsd() {return nsd_;};
     /** access for number of local atoms */
     int nlocal() {return nLocal_;}; 
     /** access for boundary integration methods */
     BoundaryIntegrationType boundary_integration_type()
       {return boundaryIntegrationType_;};
     /** access for boundary face sets */
     const std::set< std::pair<int,int> > * face_sets()
       { return boundaryFaceSet_;};
     /** access for needing a reset */
     bool need_reset() const {return needReset_;};
     /** force a reset to occur */
     void force_reset() {needReset_ = true;};
     /** check if lambda is localized */
     bool use_localized_lambda() const {return useLocalizedLambda_;};
     /** check if matrix should be lumpted for lambda solve */
     bool use_lumped_lambda_solve() const {return useLumpedLambda_;};
     /** check to see if this direction is being used */
     bool apply_in_direction(int i) const {return applyInDirection_[i];};
 
     
     /** checks if there are any fixed nodes in the MD region */
     bool md_fixed_nodes(FieldName fieldName = NUM_TOTAL_FIELDS) const;
 
     /** checks if there are any flux nodes in the MD region */
     bool md_flux_nodes(FieldName fieldName = NUM_TOTAL_FIELDS) const;
 
     /** returns prefix tag for regulator */
     const std::string & regulator_prefix() const {return regulatorPrefix_;};
         
   protected:
 
     // methods
     /** deletes the current regulator method */
     void delete_method();
 
     /** deletes all unused data */
     void delete_unused_data();
 
     /** sets all data to be unused */
     void set_all_data_to_unused();
 
     /** sets all data to be used */
     void set_all_data_to_used();
         
     // data
     /** point to atc_transfer object */
     ATC_Coupling * atc_;
         
     /** how often in number of time steps regulator is applied */
     int howOften_;
 
     // reset/reinitialize flags
     /** flag to reset data */
     bool needReset_;
     /** reinitialize method */
     void reset_method();
 
     // regulator data
     /** container for all data, string is tag, bool is false if currently in use */
     std::map<std::string, std::pair<bool,DENS_MAN * > > regulatorData_;
 
     /** maximum number of iterations used in solving for lambda */
     int maxIterations_;
     /** tolerance used in solving for lambda */
     double tolerance_;
 
     /** regulator target flag */
     RegulatorTargetType regulatorTarget_;
     /** regulator fe coupling type flag */
     RegulatorCouplingType couplingMode_;
                 
     /** number of nodes */
     int nNodes_;
     /** number of spatial dimensions */
     int nsd_;
     /** number of local atoms */
     int nLocal_;
 
     /** use of localization techniques */
     bool useLocalizedLambda_;
     bool useLumpedLambda_;
 
     /** restrict application in certain directions */
     std::vector<bool> applyInDirection_;
         
     // method pointers
     /** time filtering object */
     TimeFilter * timeFilter_;
     /** sets up and solves the regulator equations */
     RegulatorMethod * regulatorMethod_;
 
     // boundary flux information
     BoundaryIntegrationType boundaryIntegrationType_;
     const std::set< std::pair<int,int> > * boundaryFaceSet_;
 
     /** prefix string for registering data */
     const std::string regulatorPrefix_;
 
   private:
     
     // DO NOT define this
     AtomicRegulator();
         
   };
 
   /**
    *  @class  RegulatorMethod
    *  @brief  Base class for implementation of control algorithms
    */
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class RegulatorMethod
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class RegulatorMethod {
   
   public:
   
     RegulatorMethod(AtomicRegulator * atomicRegulator,
                     const std::string & regulatorPrefix = "");
         
     virtual ~RegulatorMethod(){};
 
     /** instantiate all needed data */
     virtual void construct_transfers(){};
 
     /** pre-"run" initialization */
     virtual void initialize(){};
 
     /** reset number of local atoms, as well as atomic data */
     virtual void reset_nlocal(){};
 
     /** set up atom to material identification */
     virtual void reset_atom_materials(const Array<int> & elementToMaterialMap,
                                       const MatrixDependencyManager<DenseMatrix, int> * atomElement){};
         
     /** applies regulator to atoms in the pre-predictor phase */
     virtual void apply_pre_predictor(double dt){};
 
     /** applies regulator to atoms in the mid-predictor phase */
     virtual void apply_mid_predictor(double dt){};
 
     /** applies regulator to atoms in the post-predictor phase */
     virtual void apply_post_predictor(double dt){};
 
     /** applies regulator to atoms in the pre-corrector phase */
     virtual void apply_pre_corrector(double dt){};
 
     /** applies regulator to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt){};
 
     /** applies regulator to atoms in the pre-corrector phase */
     virtual void apply_pre_force(double dt){};
 
     /** applies regulator to atoms in the post-corrector phase */
     virtual void apply_post_force(double dt){};
 
     /** applies regulator in pre-force phase */
     virtual void pre_force(){};
 
     /** applies regulator in pre-exchange phase */
     virtual void pre_exchange(){};
 
     /** applies regulator in post-exchange phase */
     virtual void post_exchange(){};
 
     /** compute boundary flux, requires regulator input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields);
 
     /** add contributions (if any) to the finite element right-hand side */
     virtual void add_to_rhs(FIELDS & rhs){};
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData){};
     virtual double compute_vector(int n) const {return 0;}
 
     /** final work at the end of a run */
     virtual void finish(){};
 
     /** pack fields for restart */
     virtual void pack_fields(RESTART_LIST & data){};
         
   protected:
 
     //data
     /** pointer to atomic regulator object for data */
     AtomicRegulator * atomicRegulator_;
 
     /** pointer to ATC_transfer object */
     ATC_Coupling * atc_;
 
     /** boundary flux */
     FIELDS & boundaryFlux_;
 
     /** field mask for specifying boundary flux */
     Array2D<bool> fieldMask_;
 
     /** number of nodes */
     int nNodes_;
 
     /** prefix string for registering data */
     const std::string regulatorPrefix_;
 
     /** mapping for atom materials for atomic FE quadrature */
     Array<std::set<int> > atomMaterialGroups_;
 
     /** shape function derivative matrices for boundary atoms */
     VectorDependencyManager<SPAR_MAT * > * shpFcnDerivs_;
 
   private:
 
     // DO NOT define this
     RegulatorMethod();
   
   };
 
   /**
    *  @class  RegulatorShapeFunction
    *  @brief  Base class for implementation of regulation algorithms using the shape function matrices
    */
   // DESIGN each regulator handles only one lambda, but solvers and data are added later
   //        add a new function to set the linear solver based on enum CG_SOLVE or RSL_SOLVE and shape function matrix
   //        followed by call to compute sparsity pattern
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class RegulatorShapeFunction
   //    base class for all regulators of general form
   //    of N^T w N lambda = rhs
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class RegulatorShapeFunction : public RegulatorMethod {
   
   public:
   
     RegulatorShapeFunction(AtomicRegulator * atomicRegulator,
                            const std::string & regulatorPrefix = "");
         
     virtual ~RegulatorShapeFunction();
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-"run" initialization */
     virtual void initialize();
 
+    /** sets lambda to an initial value */
+    virtual void set_lambda_to_value(double value) {*lambda_ = value;}
+
     /** reset number of local atoms, as well as atomic data */
     virtual void reset_nlocal();
 
     /** set up atom to material identification */
     virtual void reset_atom_materials(const Array<int> & elementToMaterialMap,
                                       const MatrixDependencyManager<DenseMatrix, int> * atomElement);
 
     /** compute boundary flux, requires regulator input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields);
 
+    /** access to nodes the thermostat is applied to */
+    const SetDependencyManager<int> * application_nodes() const {return applicationNodes_;};
+
     /** determine if local shape function matrices are needed */
     virtual bool use_local_shape_functions() const {return false;};
 
   protected:
 
     // methods
     /** compute sparsity for matrix */
     void compute_sparsity(void);
 
     /** solve matrix equation */
     void solve_for_lambda(const DENS_MAT & rhs,
                           DENS_MAT & lambda);
 
     /** set weighting factor for in matrix Nhat^T * weights * Nhat */
     virtual void set_weights() = 0;
 
     /** Mapping between unique nodes and nodes overlapping MD region */
     void map_unique_to_overlap(const MATRIX & uniqueData,
                                MATRIX & overlapData);
 
     /** Mapping between nodes overlapping MD region to unique nodes */
     void map_overlap_to_unique(const MATRIX & overlapData,
                                MATRIX & uniqueData);
 
     /** sets up the transfer which is the set of nodes being regulated */
     virtual void construct_regulated_nodes();
 
     /** creates data structure needed for all to regulated node maps */
     virtual void create_node_maps();
 
     // member data
     /** lambda coupling parameter */
     DENS_MAN * lambda_;
 
     /** lambda at atomic locations */
-    ProtectedAtomQuantity<double> * atomLambdas_;
+    PerAtomQuantity<double> * atomLambdas_;
 
     /** shape function matrix for use in GLC solve */
     PerAtomSparseMatrix<double> * shapeFunctionMatrix_;
 
     /** algorithm being used for the linear solver */
     AtomicRegulator::LinearSolverType linearSolverType_;
 
     /** pre-templated sparsity pattern for N^T * T * N */
     SPAR_MAN matrixTemplate_;
 
     /** maximum number of iterations used in solving for lambda */
     int maxIterations_;
 
     /** tolerance used in solving for lambda */
     double tolerance_;
 
     /** matrix solver object */
     LambdaMatrixSolver * matrixSolver_;
 
     /** set of nodes used to construct matrix */
-    RegulatedNodes * regulatedNodes_;
+    SetDependencyManager<int> * regulatedNodes_;
 
     /** set of nodes on which lambda is non-zero */
-    RegulatedNodes * applicationNodes_;
+    SetDependencyManager<int> * applicationNodes_;
 
     /** set of nodes needed for localized boundary quadrature */
-    RegulatedNodes * boundaryNodes_;
+    SetDependencyManager<int> * boundaryNodes_;
 
     /** mapping from all nodes to overlap nodes: -1 is no overlap, otherwise entry is overlap index */
     NodeToSubset * nodeToOverlapMap_;
 
     /** mapping from overlap nodes to unique nodes */
     SubsetToNode * overlapToNodeMap_;
 
     /** shape function matrix for boundary atoms */
     SPAR_MAN * shpFcn_;
 
     /** atomic weights for boundary atoms */
     DIAG_MAN * atomicWeights_;
 
     /** element mask for boundary elements corresponding to nodeToOverlapMap_ */
-    ElementMaskNodeSet * elementMask_;
+    MatrixDependencyManager<ATC_matrix::DenseMatrix, bool> * elementMask_;
 
     /** maps atoms from atc indexing to regulator indexing */
     LargeToSmallAtomMap * lambdaAtomMap_;
 
     /** weight per-atom transfer */
     PerAtomQuantity<double> * weights_;
 
     /** number of spatial dimensions */
     int nsd_;
 
     /** number of ATC internal atoms on this processor */
     int nLocal_;
 
   private:
 
     // DO NOT define this
     RegulatorShapeFunction();
 
   };
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaMatrixSolver
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class LambdaMatrixSolver {
   
   public:
         
     LambdaMatrixSolver(SPAR_MAN & matrixTemplate, SPAR_MAN * shapeFunctionMatrix, int maxIterations, double tolerance);
         
     virtual ~LambdaMatrixSolver(){};
 
     /** assemble the matrix */
     virtual void assemble_matrix(DIAG_MAT & weights);
         
     /** execute the solver */
     virtual void execute(VECTOR & rhs, VECTOR & lambda)=0;
 
   protected:
 
     /** sparse template for the matrix */
     SPAR_MAN & matrixTemplate_;
 
     /** non-symmetric part of the matrix */
     SPAR_MAN * shapeFunctionMatrix_;
 
     /** matrix used to solve for lambda */
     SPAR_MAT lambdaMatrix_;
         
     /** maximum number of iterations */
     int maxIterations_;
 
     /** relative tolerance to solve to */
     double tolerance_;
 
   private:
 
     // DO NOT define this
     LambdaMatrixSolver();
   
   };
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaMatrixSolverLumped
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class LambdaMatrixSolverLumped : public LambdaMatrixSolver {
   
   public:
         
-    LambdaMatrixSolverLumped(SPAR_MAN & matrixTemplate, SPAR_MAN * shapeFunctionMatrix, int maxIterations, double tolerance, const RegulatedNodes * applicationNodes, const NodeToSubset * nodeToOverlapMap);
+    LambdaMatrixSolverLumped(SPAR_MAN & matrixTemplate, SPAR_MAN * shapeFunctionMatrix, int maxIterations, double tolerance, const SetDependencyManager<int> * applicationNodes, const NodeToSubset * nodeToOverlapMap);
         
     virtual ~LambdaMatrixSolverLumped(){};
 
     /** assemble the matrix */
     virtual void assemble_matrix(DIAG_MAT & weights);
         
     /** execute the solver */
     virtual void execute(VECTOR & rhs, VECTOR & lambda); 
         
   protected:
 
     /** lumped version of the matrix governing lamda */
     DIAG_MAT lumpedMatrix_;
 
     /** set of regulated nodes */
-    const RegulatedNodes * applicationNodes_;
+    const SetDependencyManager<int> * applicationNodes_;
 
     /** mapping from all nodes to overlap nodes: -1 is no overlap, otherwise entry is overlap index */
     const NodeToSubset * nodeToOverlapMap_;
 
   private:
 
     // DO NOT define this
     LambdaMatrixSolverLumped();
   
   };
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaMatrixSolverCg
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class LambdaMatrixSolverCg : public LambdaMatrixSolver {
   
   public:
         
     LambdaMatrixSolverCg(SPAR_MAN & matrixTemplate, SPAR_MAN * shapeFunctionMatrix, int maxIterations, double tolerance);
         
     virtual ~LambdaMatrixSolverCg(){};
         
     /** execute the solver */
     virtual void execute(VECTOR & rhs, VECTOR & lambda); 
         
   protected:
 
 
   private:
 
     // DO NOT define this
     LambdaMatrixSolverCg();
   
   };
 
 };
 
 #endif
diff --git a/lib/atc/DenseMatrix.h b/lib/atc/DenseMatrix.h
index 39e267081..e77e2ac85 100644
--- a/lib/atc/DenseMatrix.h
+++ b/lib/atc/DenseMatrix.h
@@ -1,417 +1,437 @@
 #ifndef DENSEMATRIX_H
 #define DENSEMATRIX_H
 
 #include "Matrix.h"
 
 #include <iostream>
 
 namespace ATC_matrix {
 
   /**
    *  @class  DenseMatrix 
    *  @brief  Class for storing data in a "dense" matrix form 
    */
 
 template <typename T>
 class DenseMatrix : public Matrix<T>
 {
 public:
-  DenseMatrix(INDEX rows=0, INDEX cols=0, bool z=1) { _create(rows, cols, z); }
+  DenseMatrix(INDEX rows=0, INDEX cols=0, bool z=1): _data(NULL){ _create(rows, cols, z); }
   DenseMatrix(const DenseMatrix<T>& c) : _data(NULL){ _copy(c); }
   DenseMatrix(const SparseMatrix<T>& c): _data(NULL){ c.dense_copy(*this);}
   DenseMatrix(const Matrix<T>& c)      : _data(NULL){ _copy(c); }
 //  const SparseMatrix<T> * p = sparse_cast(&c);
 //  (p) ? p->dense_copy(*this) : _copy(c); }
   ~DenseMatrix()                                    { _delete();}
 
   void reset (INDEX rows, INDEX cols, bool zero=true);
+  void reset (const DenseMatrix<T>& c)   {_delete(); _copy(c); };
+  void reset (const SparseMatrix<T> & c) {_delete(); c.dense_copy(*this);};
+  void reset (const Matrix<T>& c)        {_delete(); _copy(c); }
   void resize(INDEX rows, INDEX cols, bool copy=false);
   void copy (const T * ptr, INDEX rows, INDEX cols);
   /** returns transpose(this) * B */
   DenseMatrix<T> transMat(const DenseMatrix<T>& B) const;
   /** returns by element multiply A_ij = this_ij * B_ij */
   DenseMatrix<T> mult_by_element(const DenseMatrix<T>& B) const;
   /** returns by element multiply A_ij = this_ij / B_ij */
   DenseMatrix<T> div_by_element(const DenseMatrix<T>& B) const;
   
   /** overloaded virtual functions */
   //T& operator()(INDEX i, INDEX j)       { MICK(i,j) return DATA(i,j); }
   T& operator()(INDEX i, INDEX j)       { MICK(i,j) return DATA(i,j); }
   T  operator()(INDEX i, INDEX j) const { MICK(i,j) return DATA(i,j); }
   T  operator[](INDEX i)          const { VICK(i) return _data[i]; }
   T& operator[](INDEX i)                { VICK(i) return _data[i]; }
   INDEX nRows()                   const { return _nRows; }
   INDEX nCols()                   const { return _nCols; }
   T * ptr()                   const { return _data;  }
   void write_restart(FILE *f)     const;
   void from_file(std::string & name);
   void set_all_elements_to(const T &v);
   DiagonalMatrix<T> diag()    const;
  
   DenseMatrix<T>& operator=(const T &v);
   DenseMatrix<T>& operator=(const Matrix<T> &c);
   DenseMatrix<T>& operator=(const DenseMatrix<T> &c);
   DenseMatrix<T>& operator=(const SparseMatrix<T> &c);
 
   //* checks if all values are within the prescribed range
   virtual bool check_range(T min, T max) const;
 
 protected:
+  void _set_equal(const Matrix<T> &r);
   void _delete();
   void _create(INDEX rows, INDEX cols, bool zero=false);
   void _copy(const Matrix<T> &c);
 
   T *_data;
   INDEX _nRows, _nCols;
 };
 
 //! Computes the cofactor matrix of A.
 template<typename T>
 DenseMatrix<T> adjugate(const Matrix<T> &A, bool symmetric=false);
 
 //! Returns a the tensor product of two vectors
 template<typename T>
 DenseMatrix<T> tensor_product(const Vector<T> &a, const Vector<T> &b);
 
 //----------------------------------------------------------------------------
 // Returns an identity matrix, defaults to 3x3.
 //----------------------------------------------------------------------------
 template<typename T>
 DenseMatrix<T> eye(INDEX rows=3, INDEX cols=3)
 {
   const double dij[] = {0.0, 1.0};
   DENS_MAT I(rows, cols, false);  // do not need to pre-zero
   for (INDEX j=0; j<cols; j++)
     for (INDEX i=0; i<rows; i++)
       I(i,j) = dij[i==j];
   return I;
 }
 //----------------------------------------------------------------------------
 // resizes the matrix and optionally zeros it out (default - zero)
 //----------------------------------------------------------------------------
 template <typename T>
 void DenseMatrix<T>::reset(INDEX rows, INDEX cols, bool zero)
 {
   if (!this->is_size(rows, cols))
   {
      _delete();
      _create(rows, cols);
   }
   if (zero) this->zero();
 }
 //----------------------------------------------------------------------------
 // resizes the matrix and optionally copies over what still fits
 //----------------------------------------------------------------------------
 template <typename T>
 void DenseMatrix<T>::resize(INDEX rows, INDEX cols, bool copy)
 {
   if (this->is_size(rows, cols)) return;  // if is correct size, done
   if (!copy)
   {
      _delete();
      _create(rows, cols);
      return;
   }
   DenseMatrix<T> temp(*this);
   _delete();
   _create(rows, cols);
   int szi = this->nRows();
   int szj = this->nCols(); 
   for (INDEX i = 0; i < szi; i++) 
     for (INDEX j = 0; j < szj; j++)
       (*this)(i,j) = temp.in_range(i,j) ? temp(i,j) : T(0);
 }
 //----------------------------------------------------------------------------
 // resizes the matrix and copies data
 //----------------------------------------------------------------------------
 template <typename T>
 void DenseMatrix<T>::copy(const T * ptr, INDEX rows, INDEX cols)
 {
   resize(rows, cols, false);
   memcpy(_data, ptr, this->size()*sizeof(T));
 }
 //----------------------------------------------------------------------------
 // returns transpose(this) * B
 //----------------------------------------------------------------------------
 template <typename T>
 DenseMatrix<T> DenseMatrix<T>::transMat(const DenseMatrix<T>& B)          const
 {
   DenseMatrix C;
   MultAB(*this, B, C, true);
   return C;
 }
 //----------------------------------------------------------------------------
 // returns this_ij * B_ij
 //----------------------------------------------------------------------------
 template <typename T>
 DenseMatrix<T> DenseMatrix<T>::mult_by_element(const DenseMatrix<T>& B)   const
 {
   DenseMatrix C;
   C.reset(_nRows,_nCols);
   if (B.nCols() == _nCols) {
     int szi = this->nRows(); 
     int szj = this->nCols(); 
     for (INDEX i = 0; i < szi; i++) 
       for (INDEX j = 0; j < szj; j++) 
         C(i,j) = (*this)(i,j)*B(i,j);
   }
   else if (B.nCols() == 1) {
     std::cout << "MULTIPLYING\n";
     int szi = this->nRows(); 
     int szj = this->nCols(); 
     for (INDEX i = 0; i < szi; i++) 
       for (INDEX j = 0; j < szj; j++) 
         C(i,j) = (*this)(i,j)*B(i,0);
   }
   else { 
     SSCK(B, *this, "DenseMatrix::mult_by_element"); 
   }
   return C;
 }
 //----------------------------------------------------------------------------
 // returns this_ij / B_ij
 //----------------------------------------------------------------------------
 template <typename T>
 DenseMatrix<T> DenseMatrix<T>::div_by_element(const DenseMatrix<T>& B)   const
 {
   DenseMatrix C;
   C.reset(_nRows,_nCols);
 
   if (B.nCols() == _nCols) {
     int szi = this->nRows(); 
     int szj = this->nCols(); 
     for (INDEX i = 0; i < szi; i++) 
       for (INDEX j = 0; j < szj; j++) 
         C(i,j) = (*this)(i,j)/B(i,j);
   }
   else if (B.nCols() == 1) {
     int szi = this->nRows(); 
     int szj = this->nCols(); 
     for (INDEX i = 0; i < szi; i++) 
       for (INDEX j = 0; j < szj; j++) 
         C(i,j) = (*this)(i,j)/B(i,0);
   }
   else { 
     SSCK(B, *this, "DenseMatrix::div_by_element"); 
   }
   return C;
 }
 //----------------------------------------------------------------------------
 // writes the matrix data to a file
 //----------------------------------------------------------------------------
 template <typename T>
 void DenseMatrix<T>::write_restart(FILE *f)                               const
 {
   fwrite(&_nRows, sizeof(INDEX),1,f);
   fwrite(&_nCols, sizeof(INDEX),1,f);
   if (this->size()) fwrite(_data, sizeof(T), this->size(), f);
 }
 //----------------------------------------------------------------------------
 // reads matrix from text file (matrix needs to be sized)
 //----------------------------------------------------------------------------
 template <typename T>
 void DenseMatrix<T>::from_file(std::string & name)       
 {
   GCHK(_nRows == 0,"from_file needs nRows > 0");
   GCHK(_nCols == 0,"from_file needs nCols > 0");
   std::ifstream in(name.c_str(),std::ifstream::in);
   const int lineSize = 256;
   char line[lineSize];
   if (! in.good()) gerror(name+" is not available");
   in.getline(line,lineSize); // header
   int szi = this->nRows(); 
   int szj = this->nCols(); 
   for (INDEX i = 0; i < szi; i++) 
     for (INDEX j = 0; j < szj; j++) 
       in >> (*this)(i,j);
 }
 //----------------------------------------------------------------------------
 // sets all elements to a value (optimized)
 //----------------------------------------------------------------------------
 template <typename T>
 inline void DenseMatrix<T>::set_all_elements_to(const T &v)
 {
   int sz = this->size();
   for (INDEX i = 0; i < sz; i++) _data[i] = v;
 }
 //-----------------------------------------------------------------------------
 // Return a diagonal matrix containing the diagonal entries of this matrix 
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T> DenseMatrix<T>::diag() const 
 {
   DiagonalMatrix<T> D(nRows(), true); // initialized to zero
   INDEX i;
   for (i=0; i<nRows(); i++)
   { 
     D(i,i) = DATA(i,i);
   }
   return D;
 }
 //----------------------------------------------------------------------------
 // clears allocated memory
 //----------------------------------------------------------------------------
 template <typename T>
 void DenseMatrix<T>::_delete()
 {
   _nRows = _nCols = 0;
   if (_data){ 
     delete [] _data;
+    _data = NULL;
   }
 }
 //----------------------------------------------------------------------------
 // allocates memory for an rows by cols DenseMatrix
 //----------------------------------------------------------------------------
 template <typename T>
 void DenseMatrix<T>::_create(INDEX rows, INDEX cols, bool zero)
 {
 
   _nRows=rows; 
   _nCols=cols;
   _data = (this->size() ? new T [_nCols*_nRows] : NULL);
   if (zero) this->zero();
 }
 //----------------------------------------------------------------------------
 // creates a deep memory copy from a general matrix
 //----------------------------------------------------------------------------
 template <typename T>
 void DenseMatrix<T>::_copy(const Matrix<T> &c) 
 {
   if (!_data || this->size()!=c.size())
   {
     _delete(); 
     _create(c.nRows(), c.nCols());
   }
   else 
   {
     _nRows = c.nRows();
     _nCols = c.nCols();
   }
   memcpy(_data, c.ptr(), c.size()*sizeof(T));
 }
 //----------------------------------------------------------------------------
 // sets all elements to a constant 
 //----------------------------------------------------------------------------
 template <typename T>
 DenseMatrix<T>& DenseMatrix<T>::operator=(const T &v)
 {
   this->set_all_elements_to(v);
   return *this;
 }
 //----------------------------------------------------------------------------
 // copys c with a deep copy
 //----------------------------------------------------------------------------
 template <typename T>
 DenseMatrix<T>& DenseMatrix<T>::operator=(const Matrix<T> &c)
 {
   _copy(c);
   return *this;
 }
 //----------------------------------------------------------------------------
 // copys c with a deep copy
 //----------------------------------------------------------------------------
 template <typename T>
 DenseMatrix<T>& DenseMatrix<T>::operator=(const DenseMatrix<T> &c)
 {
   _copy(c);
   return *this;
 }
 //-----------------------------------------------------------------------------
 // copys c with a deep copy, including zeros
 //-----------------------------------------------------------------------------
 template <typename T>
 DenseMatrix<T>& DenseMatrix<T>::operator=(const SparseMatrix<T> &c)
 {
   _delete();
   _create(c.nRows(), c.nCols(), true);
   SparseMatrix<T>::compress(c);
   for (INDEX i=0; i<c.size(); i++)
   {
     TRIPLET<T> x = c.triplet(i);
     std::cout << "x.i: "<< x.i << "\nx.j: "<< x.j << "\nv.j: "<< x.v << std::endl << std::endl;
     (*this)(x.i, x.j) =  x.v;
   }
   return *this;
 }
-
+//----------------------------------------------------------------------------
+// general matrix assignment (for densely packed matrices)
+//----------------------------------------------------------------------------
+template<typename T>
+void DenseMatrix<T>::_set_equal(const Matrix<T> &r)
+{
+  this->resize(r.nRows(), r.nCols());
+  const Matrix<T> *pr = &r;
+  const DenseMatrix<T>   *pdd = dynamic_cast<const DenseMatrix<T>*> (pr);
+  if (pdd) this->reset(*pdd);
+  else
+  {
+    std::cout <<"Error in general dense matrix assignment\n";
+    exit(1);
+  }
+}
 //* Returns the transpose of the cofactor matrix of A.
 //* see http://en.wikipedia.org/wiki/Adjugate_matrix 
 //* symmetric flag only affects cases N>3 
 template<typename T> 
 DenseMatrix<T> adjugate(const Matrix<T> &A, bool symmetric)
 {
   if (!A.is_square()) gerror("adjugate can only be computed for square matrices.");
   DenseMatrix<T> C(A.nRows(), A.nRows());
   switch (A.nRows()) {
     case 1:
       gerror("adjugate must be computed for matrixes of size greater than 1");
     case 2:   
       C(0,0) = A(1,1);  C(0,1) =-A(0,1);
       C(1,0) =-A(1,0);  C(1,1) = A(0,0);
       break;
     case 3:   // 3x3 case was tested vs matlab
       C(0,0) = A(1,1)*A(2,2)-A(1,2)*A(2,1);
       C(1,0) =-A(1,0)*A(2,2)+A(1,2)*A(2,0);   // i+j is odd (reverse sign)
       C(2,0) = A(1,0)*A(2,1)-A(1,1)*A(2,0);
       C(0,1) =-A(0,1)*A(2,2)+A(0,2)*A(2,1);   // i+j is odd
       C(1,1) = A(0,0)*A(2,2)-A(0,2)*A(2,0);
       C(2,1) =-A(0,0)*A(2,1)+A(0,1)*A(2,0);   // i+j is odd
       C(0,2) = A(0,1)*A(1,2)-A(0,2)*A(1,1);
       C(1,2) =-A(0,0)*A(1,2)+A(0,2)*A(1,0);   // i+j is odd 
       C(2,2) = A(0,0)*A(1,1)-A(0,1)*A(1,0);
       break;
     default:  
       
       // this feature is neither tested nor optimal - use at your own risk!!!
       DenseMatrix<T> m(A.nRows()-1, A.nRows()-1);
       double sign[] = {1.0, -1.0};
       for (INDEX j=0; j<A.nCols(); j++) {
         for (INDEX i=0; i<A.nRows(); i++) {
           for (INDEX mj=0; mj<m.nCols(); mj++) {
             for (INDEX mi=0; mi<m.nRows(); mi++) { 
               m(mi, mj) = A(mi+(mi>=i), mj+(mj>=j));  // skip row i and col j
             }
           }
           if (!symmetric) C(j,i)=det(m)*sign[(i+j)&1];
           if (symmetric && i>=j) C(i,j)=C(j,i)=det(m)*sign[(i+j)&1];
         }
       }
   }
   return C;
 }
 
 // Returns a the tensor product of two vectors
 template<typename T>
 DenseMatrix<T> tensor_product(const Vector<T> &a, const Vector<T> &b)
 {
   DenseMatrix<T> ab(a.size(), b.size(),false);
   for (INDEX j=0; j<b.size(); j++)
     for (INDEX i=0; i<a.size(); i++)
       ab(i,j) = a[i]*b[j];
   return ab;
 }
 
 //* Returns a DenseMatrix with random values (like matlab rand(m,n)
 template<typename T>
 DenseMatrix<T> rand(INDEX rows, INDEX cols, int seed=1234)
 {
   srand(seed);
   const double rand_max_inv = 1.0 / double(RAND_MAX);
   DenseMatrix<T> R(rows, cols, false);
   for (INDEX i=0; i<R.size(); i++) R[i]=double(::rand())*rand_max_inv;
   return R;
 }
 
 //-----------------------------------------------------------------------------
 //* returns true if no value is outside of the range
 template<typename T>
 inline bool DenseMatrix<T>::check_range(T min, T max) const
 {
   for (INDEX i = 0; i < this->size(); i++)
     if ( (_data[i] > max) || (_data[i] < min) ) return false;
   return true;
 }
 
 } // end namespace
 #endif
 
diff --git a/lib/atc/DiagonalMatrix.h b/lib/atc/DiagonalMatrix.h
index 2ec096cb5..ce51c3f36 100644
--- a/lib/atc/DiagonalMatrix.h
+++ b/lib/atc/DiagonalMatrix.h
@@ -1,506 +1,506 @@
 #ifndef DIAGONALMATRIX_H
 #define DIAGONALMATRIX_H
 
 #include "MatrixDef.h"
 
 namespace ATC_matrix {
 
   /**
    *  @class  DiagonalMatrix
    *  @brief  Class for storing data as a diagonal matrix         
    */
 
 template<typename T>
 class DiagonalMatrix : public Matrix<T>
 {
  public: 
   explicit DiagonalMatrix(INDEX nRows=0, bool zero=0);
   DiagonalMatrix(const DiagonalMatrix<T>& c);
   DiagonalMatrix(const Vector<T>& v);
   virtual ~DiagonalMatrix();
  
   //* resizes the matrix, ignores nCols, optionally zeros 
   void  reset(INDEX rows, INDEX cols=0, bool zero=true);
   //* resizes the matrix, ignores nCols, optionally copies what fits
   void resize(INDEX rows, INDEX cols=0, bool copy=false);
   //* resets based on full copy of vector v
   void reset(const Vector<T>& v);
   //* resets based on full copy of a DiagonalMatrix
   void reset(const DiagonalMatrix<T>& v);
   //* resets based on a one column DenseMatrix
   void reset(const DenseMatrix<T>& c);
   //* resizes the matrix, ignores nCols, optionally copies what fits
   void copy(const T * ptr, INDEX rows, INDEX cols=0);
 
   //* resets based on a "shallow" copy of a vector
   void shallowreset(const Vector<T> &v);
   //* resets based on a "shallow" copy of a DiagonalMatrix
   void shallowreset(const DiagonalMatrix<T> &c);
   //* resets based on a "shallow" copy of one column DenseMatrix
   void shallowreset(const DenseMatrix<T> &c);
 
   T& operator()(INDEX i, INDEX j);
   T  operator()(INDEX i, INDEX j) const;
   T& operator[](INDEX i);
   T  operator[](INDEX i)          const;
   INDEX nRows()                   const;
   INDEX nCols()                   const;
   T* ptr()                    const;
   void write_restart(FILE *f)     const;
 
   // Dump matrix contents to screen (not defined for all datatypes)
-  std::string to_string() const { return _data->to_string(); }
+  std::string to_string(int p=myPrecision) const { return _data->to_string(); }
 
   using Matrix<T>::matlab;
   void matlab(std::ostream &o, const std::string &s="D") const;
 
   // overloaded operators
   DiagonalMatrix<T>& operator=(const T s);
   DiagonalMatrix<T>& operator=(const DiagonalMatrix<T> &C);
   //DiagonalMatrix<T>& operator=(const Vector<T> &C);
 
   INDEX size() const { return _data->size(); }
   //* computes the inverse of this matrix
   DiagonalMatrix<T>& inv_this(); 
   //* returns a copy of the inverse of this matrix
   DiagonalMatrix<T>  inv() const;
 
   // DiagonalMatrix-matrix multiplication function
   virtual void MultAB(const Matrix<T>& B, DenseMatrix<T>& C) const
   {
     GCK(*this, B, this->nCols()!=B.nRows(), "DiagonalMatrix-Matrix multiplication");
     for (INDEX i=0; i<C.nRows(); i++) {
       T value = (*this)[i];
       for (INDEX j=0; j<C.nCols(); j++)
         C(i,j) = B(i,j) * value;
     }
   }
 
 protected:
   void _set_equal(const Matrix<T> &r);
   DiagonalMatrix& operator=(const Vector<T> &c) {}
   DiagonalMatrix& operator=(const Matrix<T> &c) {}
 
 private: 
   void _delete();
   Vector<T> *_data;
 }; 
 
 //-----------------------------------------------------------------------------
 // DiagonalMatrix-DiagonalMatrix multiplication
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T> operator*(const DiagonalMatrix<T>& A, const DiagonalMatrix<T>& B) 
 {
   SSCK(A, B, "DiagonalMatrix-DiagonalMatrix multiplication");
   DiagonalMatrix<T> R(A); 
   for (INDEX i=0; i<R.nRows(); i++) R[i] *= B[i];
   return R;
 }
 //-----------------------------------------------------------------------------
 // DiagonalMatrix-matrix multiplication
 //-----------------------------------------------------------------------------
 template<typename T>
 DenseMatrix<T> operator*(const DiagonalMatrix<T>& A, const Matrix<T> &B)
 {
   DenseMatrix<T> C(A.nRows(), B.nCols(), true);
   A.MultAB(B, C);
   return C;
 }
 //-----------------------------------------------------------------------------
 // matrix-DiagonalMatrix multiplication
 //-----------------------------------------------------------------------------
 template<typename T>
 DenseMatrix<T> operator*(const Matrix<T> &B, const DiagonalMatrix<T>& A)
 {
   GCK(B, A, B.nCols()!=A.nRows(), "Matrix-DiagonalMatrix multiplication");
   DenseMatrix<T> R(B);  // makes a copy of r to return
   for (INDEX j=0; j<R.nCols(); j++)
     for (INDEX i=0; i<R.nRows(); i++)
       R(i,j) *= A[j];
   return R;
 }
 //-----------------------------------------------------------------------------
 // DiagonalMatrix-vector multiplication
 //-----------------------------------------------------------------------------
 template<typename T>
 DenseVector<T> operator*(const DiagonalMatrix<T>& A, const Vector<T> &b)
 {
   GCK(A, b, A.nCols()!=b.size(), "DiagonalMatrix-Vector multiplication");
   DenseVector<T> r(b);  // makes a copy of r to return
   for (INDEX i=0; i<r.size(); i++)
     r[i] *= A[i];
   return r;
 }
 //-----------------------------------------------------------------------------
 // vector-DiagonalMatrix multiplication
 //-----------------------------------------------------------------------------
 template<typename T>
 DenseVector<T> operator*(const Vector<T> &b, const DiagonalMatrix<T>& A)
 {
   GCK(b, A, b.size()!=A.nRows(), "Matrix-DiagonalMatrix multiplication");
   DenseVector<T> r(b);  // makes a copy of r to return
   for (INDEX i=0; i<r.size(); i++)
     r[i] *= A[i];
   return r;
 }
 //-----------------------------------------------------------------------------
 // DiagonalMatrix-SparseMatrix multiplication
 //-----------------------------------------------------------------------------
 template<typename T>
 SparseMatrix<T> operator*(const DiagonalMatrix<T> &A, const SparseMatrix<T>& B) 
 {
   GCK(A, B, A.nCols()!=B.nRows() ,"DiagonalMatrix-SparseMatrix multiplication");
   SparseMatrix<T> R(B);
   CloneVector<T> d(A);
   R.row_scale(d);
   return R;
 }
 //-----------------------------------------------------------------------------
 // DiagonalMatrix-scalar multiplication
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T> operator*(DiagonalMatrix<T> &A, const T s)
 {
   DiagonalMatrix<T> R(A);
   R *= s;
   return R;
 }
 //-----------------------------------------------------------------------------
 // Commute with DiagonalMatrix * double
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T> operator*(const T s, const DiagonalMatrix<T>& A) 
 {
   DiagonalMatrix<T> R(A);
   R *= s;
   return R;
 }
 //-----------------------------------------------------------------------------
 // DiagonalMatrix addition
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T> operator+(const DiagonalMatrix<T> &A, const DiagonalMatrix<T> &B)
 {
   DiagonalMatrix<T> R(A);
   R+=B;
   return R;
 }
 //-----------------------------------------------------------------------------
 // DiagonalMatrix subtraction
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T> operator-(const DiagonalMatrix<T> &A, const DiagonalMatrix<T> &B)
 {
   DiagonalMatrix<T> R(A);
   return R-=B;
 }
 //-----------------------------------------------------------------------------
 // template member definitions
 //-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
 // Default constructor - optionally zeros the matrix
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T>::DiagonalMatrix(INDEX rows, bool zero)
  : _data(NULL)
 {
   reset(rows, zero);
 }
 //-----------------------------------------------------------------------------
 // copy constructor - makes a full copy
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T>::DiagonalMatrix(const DiagonalMatrix<T>& c)
  : _data(NULL)
 {
   reset(c);
 }
 //-----------------------------------------------------------------------------
 // copy constructor from vector
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T>::DiagonalMatrix(const Vector<T>& v)
  : _data(NULL)
 {
   reset(v);
 }
 //-----------------------------------------------------------------------------
 // destructor
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T>::~DiagonalMatrix() 
 {
   _delete();
 } 
 //-----------------------------------------------------------------------------
 // deletes the data stored by this matrix
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::_delete()
 {
   if (_data) delete _data;
 }
 //-----------------------------------------------------------------------------
 // resizes the matrix, ignores nCols, optionally zeros 
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::reset(INDEX rows, INDEX cols, bool zero)
 {
   _delete();
   _data = new DenseVector<T>(rows, zero);
 }
 //-----------------------------------------------------------------------------
 // resizes the matrix, ignores nCols, optionally copies what fits
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::resize(INDEX rows, INDEX cols, bool copy)
 {
   _data->resize(rows, copy);  
 }
 //-----------------------------------------------------------------------------
 // changes the diagonal of the matrix to a vector v (makes a copy)
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::reset(const Vector<T>& v) 
 {
   if (&v == _data) return; // check for self-reset
   _delete();
   _data = new DenseVector<T>(v);
 }
 //-----------------------------------------------------------------------------
 // copys from another DiagonalMatrix
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::reset(const DiagonalMatrix<T>& c) 
 {
   reset(*(c._data));
 }
 //-----------------------------------------------------------------------------
 // copys from a single column matrix
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::reset(const DenseMatrix<T>& c)
 {
   GCHK(c.nCols()!=1,"DiagonalMatrix reset from DenseMatrix");
   copy(c.ptr(),c.nRows(),c.nRows());
 }
 //-----------------------------------------------------------------------------
 // resizes the matrix and copies data
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::copy(const T * ptr, INDEX rows, INDEX cols)
 {
   if (_data) _data->reset(rows, false);
   else _data = new DenseVector<T>(rows, false);
   _data->copy(ptr,rows,cols);
 }
 //-----------------------------------------------------------------------------
 // shallow reset from another DiagonalMatrix
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::shallowreset(const DiagonalMatrix<T> &c)
 {
   _delete();
   _data = new CloneVector<T>(*(c._data));
 }
 //-----------------------------------------------------------------------------
 // shallow reset from Vector
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::shallowreset(const Vector<T> &v)
 {
   _delete();
   _data = new CloneVector<T>(v);
 }
 //-----------------------------------------------------------------------------
 // shallow reset from a DenseMatrix
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::shallowreset(const DenseMatrix<T> &c)
 {
   _delete();
   _data = new CloneVector<T>(c,CLONE_COL);
 }
 //-----------------------------------------------------------------------------
 // reference indexing operator - must throw an error if i!=j
 //-----------------------------------------------------------------------------
 template<typename T>
 T& DiagonalMatrix<T>::operator()(INDEX i, INDEX j)
 {
   GCK(*this,*this,i!=j,"DiagonalMatrix: tried to index off diagonal");
   return (*this)[i];
 }
 //-----------------------------------------------------------------------------
 // value indexing operator - returns 0 if i!=j
 //-----------------------------------------------------------------------------
 template<typename T>
 T DiagonalMatrix<T>::operator()(INDEX i, INDEX j)                         const 
 {
   return (i==j) ? (*_data)(i) : (T)0; 
 }
 //-----------------------------------------------------------------------------
 // flat reference indexing operator
 //-----------------------------------------------------------------------------
 template<typename T>
 T& DiagonalMatrix<T>::operator[](INDEX i)                
 {
   return (*_data)(i); 
 }
 //-----------------------------------------------------------------------------
 // flat value indexing operator
 //-----------------------------------------------------------------------------
 template<typename T>
 T DiagonalMatrix<T>::operator[](INDEX i)                                  const          
 { 
   return (*_data)(i); 
 }
 //-----------------------------------------------------------------------------
 // returns the number of rows
 //-----------------------------------------------------------------------------
 template<typename T>
 INDEX DiagonalMatrix<T>::nRows()                                          const          
 { 
   return _data->size(); 
 }
 //-----------------------------------------------------------------------------
 // returns the number of columns (same as nCols())
 //-----------------------------------------------------------------------------
 template<typename T>
 INDEX DiagonalMatrix<T>::nCols()                                          const  
 {
   return _data->size(); 
 }
 //-----------------------------------------------------------------------------
 // returns a pointer to the diagonal values, dangerous!
 //-----------------------------------------------------------------------------
 template<typename T>
 T* DiagonalMatrix<T>::ptr()                                           const
 {
   return _data->ptr(); 
 } 
 //-----------------------------------------------------------------------------
 // writes the diagonal to a binary data restart file
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::write_restart(FILE *f)                            const 
 {
   _data->write_restart(f);
 }
 //-----------------------------------------------------------------------------
 // sets the diagonal to a constant
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T>& DiagonalMatrix<T>::operator=(const T v) 
 {
   this->set_all_elements_to(v);
   return *this;
 }
 //-----------------------------------------------------------------------------
 // assignment operator with another diagonal matrix
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T>& DiagonalMatrix<T>::operator=(const DiagonalMatrix<T>& C) 
 {
   reset(C);
   return *this;
 }
 //-----------------------------------------------------------------------------
 // writes a matlab command to duplicate this sparse matrix
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::matlab(std::ostream &o, const std::string &s)               const 
 {
   _data->matlab(o, s);
   o << s <<"=diag("<<s<<",0);\n";
 }
 //-----------------------------------------------------------------------------
 // inverts this matrix, returns a reference
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T>& DiagonalMatrix<T>::inv_this()
 {
   for(INDEX i=0; i<nRows(); i++) 
   {
      if ((*this)[i]!=T(0)) (*this)[i] = 1.0/(*this)[i];
      else 
      {
         std::cout<<"DiagonalMatrix::inv(): ("<<i<<","<<i<<")=0\n";
         ERROR_FOR_BACKTRACE
         exit(EXIT_FAILURE);
      }
   }  
   // Error check info
   const double min_max = _data->minabs() / _data->maxabs();
   if (min_max > 1e-14)   return *this;
   std::cout << "DiagonalMatrix::inv_this(): Warning: Matrix is badly scaled.";
   std::cout << "  RCOND = "<<min_max<<"\n";
   return *this;
 }
 //-----------------------------------------------------------------------------
 // returns the inverse of this matrix
 //-----------------------------------------------------------------------------
 template<typename T>
 DiagonalMatrix<T> DiagonalMatrix<T>::inv() const
 {
   DiagonalMatrix<T> invA(*this); // Make copy of A to invert
 
   for(INDEX i=0; i<invA.nRows(); i++) 
   {
      if ((*this)[i]!=T(0)) invA[i]=1.0/(*this)[i];
      else 
      {
         std::cout<<"DiagonalMatrix::inv(): ("<<i<<","<<i<<")=0\n";
         ERROR_FOR_BACKTRACE
         exit(EXIT_FAILURE);
      }
   }
   // Error check info
   const double min_max = _data->minabs() / _data->maxabs();
   if (min_max > 1e-14)   return invA;
   std::cout << "DiagonalMatrix::inv(): Warning: Matrix is badly scaled.";
   std::cout << "  RCOND = "<<min_max<<"\n";
   return invA;
 }
 //-----------------------------------------------------------------------------
 // computes a matrix inverse
 //-----------------------------------------------------------------------------
 inline DiagonalMatrix<double> inv(const DiagonalMatrix<double>& A)
 {
   return A.inv();
 }
 //-----------------------------------------------------------------------------
 // general diagonalmatrix assigment 
 //-----------------------------------------------------------------------------
 template<typename T>
 void DiagonalMatrix<T>::_set_equal(const Matrix<T> &r)
 {
   this->resize(r.nRows(), r.nCols());
   const Matrix<T> *pr = &r;
 
   const SparseMatrix<T>   *ps = dynamic_cast<const SparseMatrix<T>*>   (pr);
   const DiagonalMatrix<T> *pd = dynamic_cast<const DiagonalMatrix<T>*> (pr);
   const Vector<T>         *pv = dynamic_cast<const Vector<T>*>         (pr);
 
   if (ps)       this->reset(ps->diag());
   else if (pd)  this->reset(*pd);
   else if (pv)  this->reset(*pv);
   else
   {
-    std::cout <<"Error in general sparse matrix assignment\n";
+    std::cout <<"Error in general diagonal matrix assignment\n";
     exit(1);
   }
 }
 //-----------------------------------------------------------------------------
 // casts a generic matrix pointer into a DiagonalMatrix pointer - null if fail 
 //-----------------------------------------------------------------------------
 template<typename T>
 const DiagonalMatrix<T> *diag_cast(const Matrix<T> *m)
 {
   return dynamic_cast<const DiagonalMatrix<T>*>(m);
 }
 
 } // end namespace
 
 #endif
diff --git a/lib/atc/ElectronDragPower.cpp b/lib/atc/ElectronDragPower.cpp
index b6bb45224..aff6be610 100644
--- a/lib/atc/ElectronDragPower.cpp
+++ b/lib/atc/ElectronDragPower.cpp
@@ -1,75 +1,77 @@
 #include "ElectronDragPower.h"
 #include "Material.h"
 #include "ATC_Error.h"
 
 #include <iostream>
 #include <vector>
 
 using ATC_Utility::command_line;
 using ATC_Utility::str2dbl;
 using std::map;
 using std::string;
 using std::fstream;
 using std::vector;
 
 namespace ATC {
 
 ElectronDragPowerLinear::ElectronDragPowerLinear(fstream &fileId,
                                                  map<string,double> & parameters,
                                                  Material * material) 
   : ElectronDragPower(),
     electronDragInvTau_(0),
     material_(material)
 {
   if (!fileId.is_open()) throw ATC_Error("cannot open material file");
   vector<string> line;
   while(fileId.good()) {
     command_line(fileId, line);
     if (line.size() == 0) continue;
     if (line[0] == "end") break;
     double value = str2dbl(line[1]);
     if (line[0] == "inv_momentum_relaxation_time") {
       electronDragInvTau_ = value;
       parameters["inv_momentum_relaxation_time"] = electronDragInvTau_;
     }
     else {
       throw ATC_Error( "unrecognized material function "+line[0]);
     }
   }
 }
 
   bool ElectronDragPowerLinear::electron_drag_power(const FIELD_MATS &fields,
                                                     const GRAD_FIELD_MATS &gradFields,
                                                     DENS_MAT & flux)
 {
   
   FIELD_MATS::const_iterator evField = fields.find(ELECTRON_VELOCITY);
   const DENS_MAT & v = evField->second;
 
   // -1/tau (m_e * n * v)
   electron_drag_velocity_coefficient(fields,dragCoefWorkspace_);
   for (int i = 0; i < v.nRows(); i++) {
     double velocityMagnitude = 0.;
     for (int j = 0; j < v.nCols(); j++)
       velocityMagnitude -= v(i,j)*v(i,j);
     flux(i,0) += velocityMagnitude*dragCoefWorkspace_(i,0); // adds flux to phonon temperature
   }
 
   return true;
 }
   
 void ElectronDragPowerLinear::electron_drag_velocity_coefficient(const FIELD_MATS &fields,
                                                                  DENS_MAT & dragCoef)
 {
   FIELD_MATS::const_iterator enField = fields.find(ELECTRON_DENSITY);
   const DENS_MAT & n = enField->second;
-
+  //n.print("DENS");
   // -1/tau (m_e * n)
   material_->inv_effective_mass(fields,invEffMassWorkspace_);
+  //invEffMassWorkspace_.print("INV MASS");
   dragCoef = n;
   dragCoef /= invEffMassWorkspace_;
   dragCoef *= -electronDragInvTau_;
+  //dragCoef.print("DRAG COEF");
 }
 
 }
 
diff --git a/lib/atc/ElectronFlux.h b/lib/atc/ElectronFlux.h
index c40ea475b..013f9aac4 100644
--- a/lib/atc/ElectronFlux.h
+++ b/lib/atc/ElectronFlux.h
@@ -1,224 +1,225 @@
 #ifndef ELECTRON_FLUX_H
 #define ELECTRON_FLUX_H
 
 #include <map>
 #include <string>
 #include "ATC_TypeDefs.h"
 
 namespace ATC {
 
   /**
    *  @class  ElectronFlux
    *  @brief  Base class for the flux appearing in the electron density transport equation
    */
 
   class ElectronFlux
   {
     public:
       ElectronFlux();
       virtual ~ElectronFlux() {};
       /** computes flux */
       virtual void electron_flux(const FIELD_MATS &fields,
                                  const GRAD_FIELD_MATS &gradFields,
                                        DENS_MAT_VEC &flux) 
       {
          
         
         
         
         FIELD_MATS::const_iterator etField = fields.find(ELECTRON_TEMPERATURE);
         const DENS_MAT & etMat = etField->second;
         zeroWorkspace_.reset(etMat.nRows(),etMat.nCols());
         flux[0] = zeroWorkspace_;
         flux[1] = zeroWorkspace_;
         flux[2] = zeroWorkspace_;
       };
       void electron_convection(const FIELD_MATS &fields,
                                      DENS_MAT_VEC &flux)
       {
         FIELD_MATS::const_iterator edField = fields.find(ELECTRON_DENSITY);
         FIELD_MATS::const_iterator evField = fields.find(ELECTRON_VELOCITY);
         const DENS_MAT & n = edField->second;
         const DENS_MAT & v = evField->second;
         const CLON_VEC vx(v,CLONE_COL,0);
         const CLON_VEC vy(v,CLONE_COL,1);
         const CLON_VEC vz(v,CLONE_COL,2);
         zeroWorkspace_.reset(v.nRows(),1);
 
         if (maskX_) {
           flux[0] = zeroWorkspace_;
         }
         else {
           flux[0] = vx;
           flux[0] *= n;  // scale by n
         }
 
         if (maskY_) {
           flux[1] = zeroWorkspace_;
         }
         else {
           flux[1] = vy;
           flux[1] *= n;
         }
 
         if (maskZ_) {
           flux[2] = zeroWorkspace_;
         }
         else {
           flux[2] = vz;
           flux[2] *= n;
         }
 
       };
     protected:
       bool maskX_, maskY_, maskZ_;
       DENS_MAT zeroWorkspace_;
   };
   //-----------------------------------------------------------------------
   
   /**
    *  @class  ElectronFluxLinear
    *  @brief  Class for drift-diffusion electron flux with linear dependency on the electron density gradient
    */  
   
   class ElectronFluxLinear : public ElectronFlux
   {
     public:
       ElectronFluxLinear(std::fstream &matfile, std::map<std::string,double> & parameters);
       virtual ~ElectronFluxLinear() {};
       virtual void electron_flux(const FIELD_MATS &fields,
                                  const GRAD_FIELD_MATS &gradFields,
                                        DENS_MAT_VEC &flux)
       {
         FIELD_MATS::const_iterator edField = fields.find(ELECTRON_DENSITY);
         GRAD_FIELD_MATS::const_iterator dEdField = gradFields.find(ELECTRON_DENSITY);
         GRAD_FIELD_MATS::const_iterator dPhiField = gradFields.find(ELECTRIC_POTENTIAL);
-         // J_n = - \mu n grad \phi  - D grad n
+         // J_n = - \mu n E  - D grad n
+        // note electrons move counter to electric field grad E = - grad \phi
         const DENS_MAT & n = edField->second;
         const DENS_MAT_VEC & dn   = dEdField->second;
         const DENS_MAT_VEC & dphi = dPhiField->second;
         
         //n.print("DENSITY");
         //for (int i = 0; i < 3; i++) {
         //  dn[i].print("GRAD N");
         //  dphi[i].print("GRAD PHI");
         //}
         //cout << "------------------------------------------------====\n";
 
         flux[0] = n;
         flux[1] = n;
         flux[2] = n;
 
         if (maskX_)
           flux[0] = 0.;
         else {
-          flux[0] *= -electronMobility_*dphi[0]; // scale by n to get : -n \mu grad(\phi)
+          flux[0] *= electronMobility_*dphi[0]; // scale by n to get : n \mu grad(\phi)
           flux[0] += -electronDiffusivity_* dn[0];
         }
 
         if (maskY_)
           flux[1] = 0.;
         else {
-          flux[1] *= -electronMobility_* dphi[1] ;
+          flux[1] *= electronMobility_* dphi[1] ;
           flux[1] += -electronDiffusivity_* dn[1];
         }
 
         if (maskZ_)
           flux[2] = 0.;
         else {
-          flux[2] *= -electronMobility_*dphi[2];
+          flux[2] *= electronMobility_*dphi[2];
           flux[2] += -electronDiffusivity_* dn[2];
         }
 
       }; 
     protected:
       double electronMobility_, electronDiffusivity_;
   };
   //-----------------------------------------------------------------------
   
   /**
    *  @class  ElectronFluxThermopower
    *  @brief  Class for defining the electron flux (i.e., current) to include the elctron velocity or have a electron temperature-dependent mobility
    */  
   
   class ElectronFluxThermopower : public ElectronFlux
   {
     public:
       ElectronFluxThermopower(std::fstream &matfile,std::map<std::string,double> & parameters);
       virtual ~ElectronFluxThermopower() {};
       virtual void electron_flux(const FIELD_MATS &fields,
                                  const GRAD_FIELD_MATS &gradFields,
                                  DENS_MAT_VEC &flux)
       {
         if (fields.find(ELECTRON_VELOCITY)!=fields.end()) {
           // J_n = - e n v, note the electron charge e is unity
           electron_convection(fields,flux);
           flux[0] *= -1;
           flux[1] *= -1;
           flux[2] *= -1;
         }
         else {
           FIELD_MATS::const_iterator edField = fields.find(ELECTRON_DENSITY);
           FIELD_MATS::const_iterator etField = fields.find(ELECTRON_TEMPERATURE);
           GRAD_FIELD_MATS::const_iterator dEdField = gradFields.find(ELECTRON_VELOCITY);
           GRAD_FIELD_MATS::const_iterator dPhiField = gradFields.find(ELECTRIC_POTENTIAL);
           GRAD_FIELD_MATS::const_iterator dEtField = gradFields.find(ELECTRON_TEMPERATURE);
 
           // J_n = - \mu n grad \phi  - \mu kB/e T_e grad n 
           //       - \mu S n grad T_e - \mu kB/e n grad T_e
           const DENS_MAT & n   = edField->second;
           const DENS_MAT_VEC & dn   = dEdField->second;
           const DENS_MAT_VEC & dphi = dPhiField->second;
           const DENS_MAT_VEC & dT = dEtField->second;
           
           flux[0] = -electronMobility_*dphi[0];
           flux[1] = -electronMobility_*dphi[1];
           flux[2] = -electronMobility_*dphi[2];
           double coef = -electronMobility_*(seebeckCoef_ + kBeV_);
           flux[0] += coef* dT[0];
           flux[1] += coef* dT[1];
           flux[2] += coef* dT[2];
           flux[0] *= n; // scale by n 
           flux[1] *= n;
           flux[2] *= n;
 
           //GRAD_FIELD tmp = dn;
           const DENS_MAT & Te   = etField->second;
           //tmp[0] *= Te;
           //tmp[1] *= Te;
           //tmp[2] *= Te;
           coef = -electronMobility_*kBeV_; 
           //flux[0] += tmp[0];
           flux[0] += dn[0].mult_by_element(Te);
           flux[1] += dn[1].mult_by_element(Te);
           flux[2] += dn[2].mult_by_element(Te);
         }
       }; 
   protected:
       double electronMobility_, seebeckCoef_;
   };
   //-----------------------------------------------------------------------
   
   /**
    *  @class  ElectronFluxConvection
    *  @brief  Class for electron flux based on the standard convection term
    */  
   
   class ElectronFluxConvection : public ElectronFlux
   {
     public:
       ElectronFluxConvection(std::fstream &matfile,std::map<std::string,double> & parameters);
       virtual ~ElectronFluxConvection() {};
       virtual void electron_flux(const FIELD_MATS &fields,
                                  const GRAD_FIELD_MATS &gradFields,
                                        DENS_MAT_VEC &flux)
       {
         // flux = n v
         electron_convection(fields,flux);
       };
   };
 }
 
 #endif 
 
 
diff --git a/lib/atc/ExtrinsicModelDriftDiffusion.cpp b/lib/atc/ExtrinsicModelDriftDiffusion.cpp
index f98467703..73beca3aa 100644
--- a/lib/atc/ExtrinsicModelDriftDiffusion.cpp
+++ b/lib/atc/ExtrinsicModelDriftDiffusion.cpp
@@ -1,558 +1,606 @@
 // ATC Headers
 #include "ExtrinsicModelDriftDiffusion.h"
 #include "ATC_Error.h"
 #include "FieldEulerIntegrator.h"
 #include "ATC_Coupling.h"
 #include "LammpsInterface.h"
 #include "PrescribedDataManager.h"
 #include "PhysicsModel.h"
 #include "LinearSolver.h"
 #include "PoissonSolver.h"
 #include "SchrodingerSolver.h"
 
 // timer
 #include "Utility.h"
 
 #include <utility>
 
 using ATC_Utility::to_string;
+using std::cout;
 using std::string;
 using std::set;
 using std::pair;
 using std::vector;
 
 const double tol = 1.e-8; 
 const double zero_tol = 1.e-12; 
 const double f_tol = 1.e-8; 
 
 namespace ATC {
 
-enum oneDconservationEnum {ONED_DENSITY=0, ONED_FLUX};
-
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ExtrinsicModelDriftDiffusion
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ExtrinsicModelDriftDiffusion::ExtrinsicModelDriftDiffusion
                                 (ExtrinsicModelManager * modelManager,
                                  ExtrinsicModelType modelType,
                                  string matFileName) :
     ExtrinsicModelTwoTemperature(modelManager,modelType,matFileName),
     continuityIntegrator_(NULL),
     
     poissonSolverType_(DIRECT), // ITERATIVE | DIRECT
     poissonSolver_(NULL),
     baseSize_(0),
     electronDensityEqn_(ELECTRON_CONTINUITY),
     fluxUpdateFreq_(1),
     schrodingerSolverType_(DIRECT), // ITERATIVE | DIRECT
     schrodingerSolver_(NULL),
     schrodingerPoissonMgr_(),
     schrodingerPoissonSolver_(NULL),
     maxConsistencyIter_(0), maxConstraintIter_(1), 
     safe_dEf_(0.1), Ef_shift_(0.0),
-    oneD_(false), oneDcoor_(0), oneDconserve_(ONED_DENSITY)
+    oneD_(false), oneDcoor_(0), oneDconserve_(0)
   {
      // delete base class's version of the physics model
      if (physicsModel_) delete physicsModel_; 
      if (modelType == DRIFT_DIFFUSION_EQUILIBRIUM) {
        physicsModel_ = new PhysicsModelDriftDiffusionEquilibrium(matFileName); 
        electronDensityEqn_ = ELECTRON_EQUILIBRIUM;
      }
      else if (modelType == DRIFT_DIFFUSION_SCHRODINGER) {
        physicsModel_ = new PhysicsModelDriftDiffusionSchrodinger(matFileName); 
        electronDensityEqn_ = ELECTRON_SCHRODINGER;
        maxConsistencyIter_ = 1;
      }
      else if (modelType == DRIFT_DIFFUSION_SCHRODINGER_SLICE) {
        physicsModel_ = new PhysicsModelDriftDiffusionSchrodingerSlice(matFileName); 
        electronDensityEqn_ = ELECTRON_SCHRODINGER;
        maxConsistencyIter_ = 1;
      }
      else {
        physicsModel_ = new PhysicsModelDriftDiffusion(matFileName); 
      }
      atc_->useConsistentMassMatrix_(ELECTRON_DENSITY) = true;
+     rhsMaskIntrinsic_(ELECTRON_TEMPERATURE,SOURCE) = true;
+     //atc_->fieldMask_(ELECTRON_TEMPERATURE,EXTRINSIC_SOURCE) = true;
   }
   
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ExtrinsicModelDriftDiffusion::~ExtrinsicModelDriftDiffusion()
   {
     if(continuityIntegrator_) delete continuityIntegrator_;
     if(poissonSolver_) delete poissonSolver_;
     if(schrodingerSolver_) delete schrodingerSolver_;
     if(schrodingerPoissonSolver_) delete schrodingerPoissonSolver_;
   }
 
   //--------------------------------------------------------
   // modify 
   //--------------------------------------------------------
   bool ExtrinsicModelDriftDiffusion::modify(int narg, char **arg)
   {
     bool match = false;
     int argIndx = 0;
     if (!match) {
       match = ExtrinsicModelTwoTemperature::modify(narg, arg);
     }
     return match;
   }
 
   //--------------------------------------------------------
   //  initialize
   //--------------------------------------------------------
   void ExtrinsicModelDriftDiffusion::initialize()
   {
     // xTTM sets rhsMaskIntrinsic_
     ExtrinsicModelTwoTemperature::initialize();
     nNodes_ = atc_->num_nodes();
     rhs_[ELECTRON_DENSITY].reset(nNodes_,1);
     rhs_[ELECTRIC_POTENTIAL].reset(nNodes_,1);
       
     // set up electron continuity integrator
     Array2D <bool> rhsMask(NUM_TOTAL_FIELDS,NUM_FLUX); 
     rhsMask = false;
     for (int i = 0; i < NUM_FLUX; i++) {
       rhsMask(ELECTRON_DENSITY,i) = atc_->fieldMask_(ELECTRON_DENSITY,i);
     }
     // need to create the bcs for the solver to configure properly
     atc_->set_fixed_nodes();
 
     if (continuityIntegrator_) delete continuityIntegrator_;
     if (electronTimeIntegration_ == TimeIntegrator::IMPLICIT) { 
       continuityIntegrator_ = new FieldImplicitEulerIntegrator(ELECTRON_DENSITY,
         physicsModel_, atc_->feEngine_, atc_, rhsMask);
     }
     else {
       continuityIntegrator_ = new FieldExplicitEulerIntegrator(ELECTRON_DENSITY,
         physicsModel_, atc_->feEngine_, atc_, rhsMask);
     }
 
 
     atc_->compute_mass_matrix(ELECTRON_DENSITY,physicsModel_);
     //(atc_->consistentMassMats_[ELECTRON_DENSITY].quantity()).print("PHYS MASS MAT");
     //DENS_MAT temp = atc_->consistentMassInverse_ - atc_->consistentMassMatInv_[ELECTRON_DENSITY];
     //temp.print("DIFF In MATS");
 
     // set up poisson solver
     rhsMask = false;
     for (int i = 0; i < NUM_FLUX; i++) {
       rhsMask(ELECTRIC_POTENTIAL,i) = atc_->fieldMask_(ELECTRIC_POTENTIAL,i);
     }
     int type = ATC::LinearSolver::ITERATIVE_SOLVE_SYMMETRIC;
     if (poissonSolverType_ == DIRECT) {  
       type = ATC::LinearSolver::DIRECT_SOLVE;
     }
     if (poissonSolver_) delete poissonSolver_;
     poissonSolver_ = new PoissonSolver(ELECTRIC_POTENTIAL,
       physicsModel_, atc_->feEngine_, atc_->prescribedDataMgr_, atc_,
       rhsMask,type, true);
     poissonSolver_->initialize();
 
     // set up schrodinger solver
     if ( electronDensityEqn_ == ELECTRON_SCHRODINGER ) {
-      int type = ATC::LinearSolver::ITERATIVE_SOLVE_SYMMETRIC;
-      if (schrodingerSolverType_ == DIRECT) {  
-        type = ATC::LinearSolver::DIRECT_SOLVE;
-      }
       if ( schrodingerSolver_ )  delete schrodingerSolver_;
       if ( oneD_ ) { 
         EfHistory_.reset(oneDslices_.size(),2);
         schrodingerSolver_ = new SliceSchrodingerSolver(ELECTRON_DENSITY,
           physicsModel_, atc_->feEngine_, atc_->prescribedDataMgr_, atc_,
-          oneDslices_, type, true);
+          oneDslices_,oneDdxs_);
       } 
       else {
         schrodingerSolver_ = new SchrodingerSolver(ELECTRON_DENSITY,
-          physicsModel_, atc_->feEngine_, atc_->prescribedDataMgr_, atc_,
-          type, true);
+          physicsModel_, atc_->feEngine_, atc_->prescribedDataMgr_, atc_);
       }
       schrodingerSolver_->initialize();
 
       if ( schrodingerPoissonSolver_ )  delete schrodingerPoissonSolver_;
       schrodingerPoissonSolver_ = schrodingerPoissonMgr_.initialize(
       atc_, schrodingerSolver_, poissonSolver_, physicsModel_);
 
     }
 
     if (electronDensityEqn_ == ELECTRON_SCHRODINGER && !(atc_->is_initialized())) {
       ((atc_->fields())[ELECTRON_WAVEFUNCTION].set_quantity()).reset(nNodes_,1);
       ((atc_->fields())[ELECTRON_WAVEFUNCTIONS].set_quantity()).reset(nNodes_,nNodes_);
       ((atc_->fields())[ELECTRON_WAVEFUNCTION_ENERGIES].set_quantity()).reset(nNodes_,1);
     }
 
+#if 0
+    cout << " RHS MASK\n";
+    print_mask(rhsMask);
+#endif
   }
 
   //--------------------------------------------------------
   //  pre initial integration
   //--------------------------------------------------------
   void ExtrinsicModelDriftDiffusion::pre_init_integrate()
   {
     double dt = atc_->lammpsInterface_->dt();
     double time = atc_->time();
     int step = atc_->step();
     if (step % fluxUpdateFreq_ != 0) return; 
 
     // set Dirchlet data
     atc_->set_fixed_nodes();
 
     // set Neumann data (atc does not set these until post_final)
     atc_->set_sources();
 
     // subcyle integration of fast electron variable/s
     
     double idt = dt/nsubcycle_;
     for (int i = 0; i < nsubcycle_ ; ++i) {
       if (electronDensityEqn_ == ELECTRON_CONTINUITY) {
         // update continuity eqn
         if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_DENSITY) ) 
           continuityIntegrator_->update(idt,time,atc_->fields_,rhs_);
         atc_->set_fixed_nodes(); 
         // solve poisson eqn for electric potential
         if (! atc_->prescribedDataMgr_->all_fixed(ELECTRIC_POTENTIAL) )
           poissonSolver_->solve(atc_->fields(),rhs_);
       } 
       else if (electronDensityEqn_ == ELECTRON_SCHRODINGER) {
-        schrodingerPoissonSolver_->solve(rhs_,fluxes_);
+        if ( (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_DENSITY) ) 
+          || (! atc_->prescribedDataMgr_->all_fixed(ELECTRIC_POTENTIAL) )  )
+          schrodingerPoissonSolver_->solve(rhs_,fluxes_);
       }
       // update electron temperature
-      if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_TEMPERATURE) ) 
+      if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_TEMPERATURE) 
+        && temperatureIntegrator_ )  {
+#ifdef ATC_VERBOSE
+        ATC::LammpsInterface::instance()->stream_msg_once("start temperature integration...",true,false);
+#endif
         temperatureIntegrator_->update(idt,time,atc_->fields_,rhs_);
+#ifdef ATC_VERBOSE
+        ATC::LammpsInterface::instance()->stream_msg_once(" done",false,true);
+#endif
+      }
       atc_->set_fixed_nodes(); 
     }
 
     
+  }
+  //--------------------------------------------------------
+  //  set coupling source terms
+  //-------------------------------------------------------
+  void ExtrinsicModelDriftDiffusion::set_sources(FIELDS & fields, FIELDS & sources)
+  {
+    atc_->evaluate_rhs_integral(rhsMaskIntrinsic_, fields,
+                            sources,
+                            atc_->source_integration(), physicsModel_);
+
   }
 
   //--------------------------------------------------------
   //  output
   //--------------------------------------------------------
   void ExtrinsicModelDriftDiffusion::output(OUTPUT_LIST & outputData)
-  {
+  { 
+#ifdef ATC_VERBOSE
+//  ATC::LammpsInterface::instance()->print_msg_once("start output",true,false);
+#endif
     ExtrinsicModelTwoTemperature::output(outputData);
     // fields
 
     outputData["dot_electron_density"] = & (atc_->dot_field(ELECTRON_DENSITY)).set_quantity();
-    outputData["joule_heating"]        = & rhs_[ELECTRON_TEMPERATURE].set_quantity();
+    DENS_MAT & JE = rhs_[ELECTRON_TEMPERATURE].set_quantity();
+    double totalJouleHeating =JE.sum();
+    outputData["joule_heating"]        = & JE;
+    atc_->feEngine_->add_global("total_joule_heating",totalJouleHeating);
     Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX); rhsMask = false;
     rhsMask(ELECTRON_DENSITY,FLUX) = true;
     rhsMask(ELECTRIC_POTENTIAL,FLUX) = true;
     atc_->compute_flux(rhsMask,atc_->fields_,fluxes_,physicsModel_);
 //(fluxes_[ELECTRON_DENSITY][0]).print("J_x");
     outputData["electron_flux_x"]      = & fluxes_[ELECTRON_DENSITY][0];
     outputData["electron_flux_y"]      = & fluxes_[ELECTRON_DENSITY][1];
     outputData["electron_flux_z"]      = & fluxes_[ELECTRON_DENSITY][2];
     outputData["electric_field_x"]     = & fluxes_[ELECTRIC_POTENTIAL][0];
     outputData["electric_field_y"]     = & fluxes_[ELECTRIC_POTENTIAL][1];
     outputData["electric_field_z"]     = & fluxes_[ELECTRIC_POTENTIAL][2];
     if (electronDensityEqn_ == ELECTRON_SCHRODINGER ) {
       SPAR_MAT K;
       Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
       rhsMask = false;
       rhsMask(ELECTRON_WAVEFUNCTION,FLUX) = true;
       pair<FieldName,FieldName> row_col(ELECTRON_WAVEFUNCTION,
                                         ELECTRON_WAVEFUNCTION);
       atc_->feEngine_->compute_tangent_matrix(
         rhsMask, row_col, atc_->fields(), physicsModel_,
         atc_->element_to_material_map(), K);
       phiTotal_.reset(K.nRows(),1);
       const DIAG_MAT & inv_dV = (atc_->invNodeVolumes_).quantity();
       for (int i = 0; i < K.nRows() ; i++) {
         phiTotal_(i,0) = 0.0;
         for (int j = 0; j < K.nCols() ; j++) {
           phiTotal_(i,0) += K(i,j);
         }
         phiTotal_(i,0) *= inv_dV(i,i);
       }
       outputData["V_total"]      = & phiTotal_;
     }
     // globals
     double nSum = ((atc_->field(ELECTRON_DENSITY)).quantity()).col_sum();
     atc_->feEngine_->add_global("total_electron_density",nSum);
+#ifdef ATC_VERBOSE
+//  ATC::LammpsInterface::instance()->print_msg_once("... done",false,true);
+#endif
   }
 
   //--------------------------------------------------------
   //  size_vector
   //--------------------------------------------------------
   int ExtrinsicModelDriftDiffusion::size_vector(int intrinsicSize)
   {
     int xSize = ExtrinsicModelTwoTemperature::size_vector(intrinsicSize);
     baseSize_ = intrinsicSize  + xSize;
-    xSize += 1;
+    xSize += 2;
     return xSize;
   }
 
   //--------------------------------------------------------
   //  compute_vector
   //--------------------------------------------------------
   bool ExtrinsicModelDriftDiffusion::compute_vector(int n, double & value)
   {
     // output[1] = total electron density
+    // output[2] = total joule heating
 
     bool match = ExtrinsicModelTwoTemperature::compute_vector(n,value);
     if (match) return match;
 
     if (n == baseSize_) {
       double nSum = ((atc_->field(ELECTRON_DENSITY)).quantity()).col_sum();
       value = nSum;
       return true;
     }
+    if (n == baseSize_+1) {
+      DENS_MAT & JE = rhs_[ELECTRON_TEMPERATURE].set_quantity();
+      double totalJouleHeating =JE.sum();
+      value = totalJouleHeating;
+      return true;
+    }
     return false;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ExtrinsicModelDriftDiffusionConvection
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ExtrinsicModelDriftDiffusionConvection::ExtrinsicModelDriftDiffusionConvection
                                 (ExtrinsicModelManager * modelManager,
                                  ExtrinsicModelType modelType,
                                  string matFileName) :
     ExtrinsicModelDriftDiffusion(modelManager,modelType,matFileName),
     cddmPoissonSolver_(NULL),
     baseSize_(0)
   {
      // delete base class's version of the physics model
      if (physicsModel_) delete physicsModel_; 
      if (modelType == CONVECTIVE_DRIFT_DIFFUSION_SCHRODINGER) {
        physicsModel_ = new PhysicsModelDriftDiffusionConvectionSchrodinger(matFileName); 
        electronDensityEqn_ = ELECTRON_SCHRODINGER;
      }
      else {
        physicsModel_ = new PhysicsModelDriftDiffusionConvection(matFileName); 
      }
-     atc_->useConsistentMassMatrix_(ELECTRON_VELOCITY) = true;
-     atc_->useConsistentMassMatrix_(ELECTRON_TEMPERATURE) = true;
+     atc_->useConsistentMassMatrix_(ELECTRON_VELOCITY) = false;
+     atc_->useConsistentMassMatrix_(ELECTRON_TEMPERATURE) = false;
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ExtrinsicModelDriftDiffusionConvection::~ExtrinsicModelDriftDiffusionConvection()
   {
     if (cddmPoissonSolver_) delete cddmPoissonSolver_;
     for (vector<LinearSolver * >::const_iterator iter=velocitySolvers_.begin();
                                    iter != velocitySolvers_.end(); iter++)
       if (*iter) delete *iter;
   }
 
   //--------------------------------------------------------
   //  initialize
   //--------------------------------------------------------
   void ExtrinsicModelDriftDiffusionConvection::initialize()
   {
     ExtrinsicModelDriftDiffusion::initialize();
-
-    // change temperature integrator to be Crank-Nicolson
-    if (electronTimeIntegration_ == TimeIntegrator::IMPLICIT) {
-      if (temperatureIntegrator_) delete temperatureIntegrator_;
-      Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
-      rhsMask = false;
-      for (int i = 0; i < NUM_FLUX; i++) {
-        rhsMask(ELECTRON_TEMPERATURE,i) = atc_->fieldMask_(ELECTRON_TEMPERATURE,i);
-      }
-      temperatureIntegrator_ = new FieldImplicitEulerIntegrator(ELECTRON_TEMPERATURE,
-                                                                physicsModel_,
-                                                                atc_->feEngine_, atc_, 
-                                                                rhsMask);
-    }
-
     nNodes_ = atc_->num_nodes();
     nsd_ = atc_->nsd();
     rhs_[ELECTRON_VELOCITY].reset(nNodes_,nsd_);
 
     
     atc_->set_fixed_nodes(); // needed to correctly set BC data
     // initialize Poisson solver
     if (cddmPoissonSolver_) delete cddmPoissonSolver_;
     Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
     rhsMask = false;
     rhsMask(ELECTRIC_POTENTIAL,FLUX) = true;
     pair<FieldName,FieldName> row_col(ELECTRIC_POTENTIAL,ELECTRIC_POTENTIAL);
     SPAR_MAT stiffness;
     (atc_->feEngine_)->compute_tangent_matrix(rhsMask,row_col, atc_->fields(), physicsModel_, 
                                                 atc_->element_to_material_map(), stiffness);
     
     const BC_SET & bcs = (atc_->prescribedDataMgr_->bcs(ELECTRIC_POTENTIAL))[0];
 
     cddmPoissonSolver_ = new LinearSolver(stiffness, bcs, poissonSolverType_,
                                           -1, true);
 
     // initialize velocity solver
     const BCS & velocityBcs = atc_->prescribedDataMgr_->bcs(ELECTRON_VELOCITY);
     DENS_MAT velocityRhs(nNodes_,nsd_);
     atc_->compute_mass_matrix(ELECTRON_VELOCITY,physicsModel_);
     SPAR_MAT & velocityMassMat = (atc_->consistentMassMats_[ELECTRON_VELOCITY]).set_quantity();
 
     for (int i = 0; i < nsd_; i++ ) {
       LinearSolver * myVelocitySolver =
         new LinearSolver(velocityMassMat, velocityBcs[i],
                          LinearSolver::AUTO_SOLVE, -1, true);
       velocitySolvers_.push_back(myVelocitySolver);
     }
   }
 
   //--------------------------------------------------------
   //  pre initial integration
   //--------------------------------------------------------
   void ExtrinsicModelDriftDiffusionConvection::pre_init_integrate()
   {
     double dt = atc_->lammpsInterface_->dt();
     double time = atc_->time();
     int step = atc_->step();
     if (step % fluxUpdateFreq_ != 0) return; 
 
     // set Dirchlet data
     atc_->set_fixed_nodes();
 
     // set Neumann data (atc does not set these until post_final)
     atc_->set_sources();
 
     // subcyle integration of fast electron variable/s
     
     double idt = dt/nsubcycle_;
     for (int i = 0; i < nsubcycle_ ; ++i) {
       // update electron temperature mass matrix
       atc_->compute_mass_matrix(ELECTRON_VELOCITY,physicsModel_);
       // update electron velocity
       if (!(atc_->prescribedDataMgr_)->all_fixed(ELECTRON_VELOCITY))  {
         //const BCS & bcs 
         //  = atc_->prescribedDataMgr_->bcs(ELECTRON_VELOCITY);
         Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX); 
         rhsMask = false;
         rhsMask(ELECTRON_VELOCITY,SOURCE) = atc_->fieldMask_(ELECTRON_VELOCITY,SOURCE);
         rhsMask(ELECTRON_VELOCITY,FLUX) = atc_->fieldMask_(ELECTRON_VELOCITY,FLUX);
+        rhsMask(ELECTRON_VELOCITY,OPEN_SOURCE) = atc_->fieldMask_(ELECTRON_VELOCITY,OPEN_SOURCE);
         FIELDS rhs;
         rhs[ELECTRON_VELOCITY].reset(nNodes_,nsd_);
         atc_->compute_rhs_vector(rhsMask, atc_->fields_, rhs, atc_->source_integration(), physicsModel_);
         const DENS_MAT & velocityRhs =  rhs[ELECTRON_VELOCITY].quantity();
+
         // add a solver for electron momentum  
         DENS_MAT & velocity = (atc_->field(ELECTRON_VELOCITY)).set_quantity();
         for (int j = 0; j < nsd_; ++j) {
           if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_VELOCITY,j) ) {
-            CLON_VEC v = column(velocity,j);
-            const CLON_VEC r = column(velocityRhs,j);
-            (velocitySolvers_[j])->solve(v,r);
+            if (atc_->useConsistentMassMatrix_(ELECTRON_VELOCITY)) {
+              //#ifdef ATC_PRINT_DEBUGGING
+              const SPAR_MAT & velocityMassMat = (atc_->consistentMassMats_[ELECTRON_VELOCITY]).quantity();
+              velocityMassMat.print("VMASS");
+              //#endif
+              CLON_VEC v = column(velocity,j);
+              const CLON_VEC r = column(velocityRhs,j);
+              (velocitySolvers_[j])->solve(v,r);
+            }
+            else {
+              //velocityRhs.print("VRHS");
+              //const DIAG_MAT & velocityMassMat = (atc_->massMats_[ELECTRON_VELOCITY]).quantity();
+              //velocityMassMat.print("MASS");
+              atc_->apply_inverse_mass_matrix(velocityRhs,velocity,ELECTRON_VELOCITY);
+            }
           }
         }
       }
       
       //atc_->set_fixed_nodes();
       
       if (electronDensityEqn_ == ELECTRON_CONTINUITY) {
         // update continuity eqn
+        Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX); 
+        rhsMask = false;
+        rhsMask(ELECTRON_DENSITY,FLUX) = atc_->fieldMask_(ELECTRON_DENSITY,FLUX);
+        rhsMask(ELECTRON_DENSITY,SOURCE) = atc_->fieldMask_(ELECTRON_DENSITY,SOURCE);
+        rhsMask(ELECTRON_DENSITY,PRESCRIBED_SOURCE) = atc_->fieldMask_(ELECTRON_DENSITY,PRESCRIBED_SOURCE);
+        FIELDS rhs;
+        rhs[ELECTRON_DENSITY].reset(nNodes_,1);
+        atc_->compute_rhs_vector(rhsMask, atc_->fields_, rhs, atc_->source_integration(), physicsModel_);
         if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_DENSITY) ) 
-          continuityIntegrator_->update(idt,time,atc_->fields_,rhs_);
+          continuityIntegrator_->update(idt,time,atc_->fields_,rhs);
         atc_->set_fixed_nodes(); 
         // solve poisson eqn for electric potential
         
         if (! atc_->prescribedDataMgr_->all_fixed(ELECTRIC_POTENTIAL) ) {
         //poissonSolver_->solve(atc_->fields_,rhs_);
-          Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX); 
           rhsMask = false;
           rhsMask(ELECTRIC_POTENTIAL,SOURCE) = atc_->fieldMask_(ELECTRIC_POTENTIAL,SOURCE);
           rhsMask(ELECTRIC_POTENTIAL,PRESCRIBED_SOURCE) = atc_->fieldMask_(ELECTRIC_POTENTIAL,PRESCRIBED_SOURCE);
-          FIELDS rhs;
+          // FIELDS rhs;
           rhs[ELECTRIC_POTENTIAL].reset(nNodes_,1);
           atc_->compute_rhs_vector(rhsMask, atc_->fields_, rhs, atc_->source_integration(), physicsModel_);
           CLON_VEC x =column((atc_->field(ELECTRIC_POTENTIAL)).set_quantity(),0);
           const CLON_VEC r =column(rhs[ELECTRIC_POTENTIAL].quantity(),0);
           cddmPoissonSolver_->solve(x,r);
         }
       } 
       else if (electronDensityEqn_ == ELECTRON_SCHRODINGER) {
         schrodingerPoissonSolver_->solve(rhs_,fluxes_);
       }
       
       atc_->set_fixed_nodes(); 
       // update electron temperature mass matrix
       atc_->compute_mass_matrix(ELECTRON_TEMPERATURE,physicsModel_);
       // update electron temperature
-      if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_TEMPERATURE) ) 
-        temperatureIntegrator_->update(idt,time,atc_->fields_,rhs_);
+      if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_TEMPERATURE) ) {
+        //if (atc_->useConsistentMassMatrix_(ELECTRON_TEMPERATURE)) {
+          temperatureIntegrator_->update(idt,time,atc_->fields_,rhs_);
+          //}
+          //else { // lumped mass matrix
+          
+        //}
+      }
       atc_->set_fixed_nodes(); 
       
     }
 
   }
 
   //--------------------------------------------------------
   //  output
   //--------------------------------------------------------
   void ExtrinsicModelDriftDiffusionConvection::output(OUTPUT_LIST & outputData)
   {
     ExtrinsicModelDriftDiffusion::output(outputData);
     
     
     //FIELD jouleHeating(atc_->num_nodes(),1);
     //set_kinetic_energy_source(atc_->fields(),jouleHeating);
     outputData["joule_heating"] = & (atc_->extrinsic_source(TEMPERATURE)).set_quantity();
 
     // globals
     DENS_MAT nodalKineticEnergy;
     compute_nodal_kinetic_energy(nodalKineticEnergy);
     double kineticEnergy = nodalKineticEnergy.sum();
     atc_->feEngine_->add_global("total_electron_kinetic_energy",kineticEnergy);
   }
 
   //--------------------------------------------------------
   //  size_vector
   //--------------------------------------------------------
   int ExtrinsicModelDriftDiffusionConvection::size_vector(int intrinsicSize)
   {
     int xSize = ExtrinsicModelDriftDiffusion::size_vector(intrinsicSize);
     baseSize_ = intrinsicSize  + xSize;
     xSize += 1;
     return xSize;
   }
 
   //--------------------------------------------------------
   //  compute_vector
   //--------------------------------------------------------
   bool ExtrinsicModelDriftDiffusionConvection::compute_vector(int n, double & value)
   {
     // output[1] = total electron kinetic energy
 
     bool match = ExtrinsicModelDriftDiffusion::compute_vector(n,value);
     if (match) return match;
 
     if (n == baseSize_) {
       DENS_MAT nodalKineticEnergy;
       compute_nodal_kinetic_energy(nodalKineticEnergy);
       value = nodalKineticEnergy.sum();
       return true;
     }
     return false;
   }
 
   //--------------------------------------------------------
   //  compute_kinetic_energy
   //--------------------------------------------------------
   void ExtrinsicModelDriftDiffusionConvection::compute_nodal_kinetic_energy(DENS_MAT & kineticEnergy)
   {
     DENS_MAT & velocity((atc_->field(ELECTRON_VELOCITY)).set_quantity());
     SPAR_MAT & velocityMassMat = (atc_->consistentMassMats_[ELECTRON_VELOCITY]).set_quantity();
     kineticEnergy.reset(nNodes_,1);
     
     for (int j = 0; j < nsd_; j++) {
       CLON_VEC myVelocity(velocity,CLONE_COL,j);
       DENS_MAT velocityMat(nNodes_,1);
       for (int i = 0; i < nNodes_; i++)
         velocityMat(i,0) = myVelocity(i);
       kineticEnergy += velocityMat.mult_by_element(myVelocity);
     }
 
     kineticEnergy = 0.5*velocityMassMat*kineticEnergy;
   }
 };
diff --git a/lib/atc/ExtrinsicModelDriftDiffusion.h b/lib/atc/ExtrinsicModelDriftDiffusion.h
index 92e2365dc..abc40e84d 100644
--- a/lib/atc/ExtrinsicModelDriftDiffusion.h
+++ b/lib/atc/ExtrinsicModelDriftDiffusion.h
@@ -1,187 +1,191 @@
 #ifndef EXTRINSIC_MODEL_DRIFT_DIFFUSION
 #define EXTRINSIC_MODEL_DRIFT_DIFFUSION
 
 #include <set>
 #include <string>
 #include <vector>
 
 #include "ExtrinsicModelTwoTemperature.h"
 #include "SchrodingerSolver.h"
 
 namespace ATC {
 
   class ATC_Coupling;
   class PrescribedDataManager;
   class ExtrinsicModel;
   class PhysicsModel;
   class PoissonSolver;
   class LinearSolver;
   class SchrodingerSolver;
   class SchrodingerPoissonSolver;
 
   /**
    *  @class  ExtrinsicModelDriftDiffusion
    *  @brief  add electron temperature physics to phonon physics
    *          owned fields ELECTRON_DENSITY
    */
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ExtrinsicModelDriftDiffusion
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   class ExtrinsicModelDriftDiffusion : public ExtrinsicModelTwoTemperature {
   
   public:
 
     // constructor
     ExtrinsicModelDriftDiffusion(ExtrinsicModelManager * modelManager,
                    ExtrinsicModelType modelType,
                    std::string matFileName);
 
     // destructor
     virtual ~ExtrinsicModelDriftDiffusion();
 
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
 
     /** pre time integration */
     virtual void initialize();
 
     /** Predictor phase, executed before Verlet */
     virtual void pre_init_integrate();
 
+    /** Set sources to AtC equation */
+    virtual void set_sources(FIELDS & fields, FIELDS & sources);
+
     /** Add model-specific output data */
     virtual void output(OUTPUT_LIST & outputData);
 
     /** set up LAMMPS display variables */
     virtual int size_vector(int externalSize);
 
     /** get LAMMPS display variables */
     virtual bool compute_vector(int n, double & value);
  
   protected:
     /** Poisson solve */
     void poisson_solve();
 
     /** Schrodinger-Poisson solve */
     void schrodinger_poisson_solve(void); // wrapper
     void schrodinger_poisson_solve(int iterations);
     void slice_schrodinger_poisson_solve(int consistencyIter, int constraintIter);
     double update_fermi_energy(double target,bool first = false);
 
     /** time integrator for the continuity eqn */
     FieldEulerIntegrator * continuityIntegrator_;
 
     /** poisson solver type */
     SolverType poissonSolverType_;
 
     /** poisson solver */
     PoissonSolver * poissonSolver_;
 
     /** offset/size for LAMMPS display output */
     int baseSize_;
 
     /** ways to determine the electron density */
     int  electronDensityEqn_;
     enum electronDensityEqnType { ELECTRON_CONTINUITY,
                                   ELECTRON_EQUILIBRIUM,
                                   ELECTRON_SCHRODINGER};
   
     /** frequency for updating the electron state */
     int fluxUpdateFreq_;
 
     /** Schrodinger solver type */
     SolverType schrodingerSolverType_;
 
     /** poisson solver */
     SchrodingerSolver * schrodingerSolver_;
 
     /** schrodinger-poisson solver */
     SchrodingerPoissonManager  schrodingerPoissonMgr_;
     SchrodingerPoissonSolver * schrodingerPoissonSolver_;
 
     /** schrodinger-poisson data */
     int maxConsistencyIter_, maxConstraintIter_;
     double safe_dEf_, Ef_shift_;
     DENS_MAT phiTotal_;
     double Tmax_;
 
     Array2D<double> EfHistory_;
 
     /** one dimensional restriction */
     bool oneD_;
     int oneDcoor_;
     int oneDstride_;
     std::string oneDnodesetName_;
     std::set<int> oneDnodeset_;
     Array< std::set<int> > oneDslices_;
+    Array< double > oneDdxs_;
     int oneDconserve_;
 
     DENS_MAT JE_;
 
   };
 
   /**
    *  @class  ExtrinsicModelDriftDiffusionConvection
    *  @brief  add electron temperature physics to phonon physics, including convective transport
    */
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ExtrinsicModelDriftDiffusionConvection
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   class ExtrinsicModelDriftDiffusionConvection : public ExtrinsicModelDriftDiffusion {
   
   public:
 
     // constructor
     ExtrinsicModelDriftDiffusionConvection(ExtrinsicModelManager * modelManager,
                    ExtrinsicModelType modelType,
                    std::string matFileName);
 
     // destructor
     virtual ~ExtrinsicModelDriftDiffusionConvection();
 
     /** pre time integration */
     virtual void initialize();
 
     /** Predictor phase, executed before Verlet */
     virtual void pre_init_integrate();
 
     /** Set sources to AtC equation */
     //virtual void set_sources(FIELDS & fields, FIELDS & sources);
 
     /** Add model-specific output data */
     virtual void output(OUTPUT_LIST & outputData);
 
     /** set up LAMMPS display variables */
     virtual int size_vector(int externalSize);
 
     /** get LAMMPS display variables */
     virtual bool compute_vector(int n, double & value);
  
   protected:
 
     /** compute the total kinetic energy of the electrons */
     void compute_nodal_kinetic_energy(DENS_MAT & kineticEnergy);
 
     /** Linear solver for velocity */
     std::vector<LinearSolver * > velocitySolvers_;
 
     
     /** Linear solver for solving the poisson equations */
     LinearSolver * cddmPoissonSolver_;
 
     /** offset/size for LAMMPS display output */
     int baseSize_;
 
     double timerStart_, timerCurrent_;
 
   };
 
 };
 #endif
diff --git a/lib/atc/ExtrinsicModelElectrostatic.cpp b/lib/atc/ExtrinsicModelElectrostatic.cpp
index d07af21c0..5f5321f65 100644
--- a/lib/atc/ExtrinsicModelElectrostatic.cpp
+++ b/lib/atc/ExtrinsicModelElectrostatic.cpp
@@ -1,1014 +1,1014 @@
 // ATC Headers
 #include "ExtrinsicModelElectrostatic.h"
 #include "PhysicsModel.h"
 #include "ATC_Error.h"
 #include "FieldEulerIntegrator.h"
 #include "ATC_Coupling.h"
 #include "LammpsInterface.h"
 #include "PrescribedDataManager.h"
 #include "PoissonSolver.h"
 #include "PerAtomQuantityLibrary.h"
 #include "AtomToMoleculeTransfer.h"
 #include "MoleculeSet.h"
 #include "ChargeRegulator.h"
 #include <set>
 
 using std::string;
 using std::vector;
 using std::map;
 using std::pair;
 using std::set;
 
 static const double kTol_ = 1.0e-8; 
 static const double tol_sparse = 1.e-30;//tolerance for compaction from dense
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ExtrinsicModelElectrostatic
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ExtrinsicModelElectrostatic::ExtrinsicModelElectrostatic
                               (ExtrinsicModelManager * modelManager,
                                ExtrinsicModelType modelType,
                                string matFileName) :
     ExtrinsicModel(modelManager,modelType,matFileName),
     poissonSolverType_(DIRECT), // ITERATIVE | DIRECT
     poissonSolverTol_(0),
     poissonSolverMaxIter_(0),
     poissonSolver_(NULL),
     maxSolves_(0),
     baseSize_(0),
     chargeRegulator_(NULL),
     useSlab_(false),
     includeShortRange_(true),
     atomForces_(NULL),
     nodalAtomicCharge_(NULL),
     nodalAtomicGhostCharge_(NULL)
   {
      physicsModel_ = new PhysicsModelSpeciesElectrostatic(matFileName);
      // set up correct masks for coupling
      rhsMaskIntrinsic_.reset(NUM_FIELDS,NUM_FLUX);
      rhsMaskIntrinsic_ = false;
      if (atc_->track_charge()) {
         
        if (! chargeRegulator_) chargeRegulator_ = new ChargeRegulator(atc_);
      }
   }
   
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ExtrinsicModelElectrostatic::~ExtrinsicModelElectrostatic()
   {
     if (poissonSolver_) delete poissonSolver_;
     if (chargeRegulator_) delete chargeRegulator_;
   }
 
   //--------------------------------------------------------
   // modify 
   //--------------------------------------------------------
   bool ExtrinsicModelElectrostatic::modify(int narg, char **arg)
   {
     bool match = false;
     int argIndx = 0;
 
     /** */
 
     if (strcmp(arg[argIndx],"poisson_solver")==0) {
       argIndx++;
       if (strcmp(arg[argIndx],"max_solves")==0) {
         argIndx++;
          maxSolves_ = atoi(arg[argIndx]) ; }
       
       else if (strcmp(arg[argIndx],"tolerance")==0) {
         argIndx++;
         poissonSolverTol_ = atof(arg[argIndx]);
       }
       else if (strcmp(arg[argIndx],"max_iterations")==0) {
         argIndx++;
         poissonSolverMaxIter_ = atoi(arg[argIndx]);
       }
       else if (strcmp(arg[argIndx],"iterative")==0) {
         poissonSolverType_ = ITERATIVE; }
       else {
         poissonSolverType_ = DIRECT; }
       match = true;
     } // end "poisson_solver"
     
 
 
     /** creates fixed charge on faceset
         units on surface charge density are lammps charge units / lammps length units ^ 2
         fix_modify ATC extrinsic fix_charge faceset_id value
     */
 #ifdef CHARGED_SURFACE
     else if (strcmp(arg[argIndx],"fix_charge")==0) {
       argIndx++;
       string facesetName(arg[argIndx]);
       argIndx++;
       double chargeDensity = atof(arg[argIndx]);
       surfaceCharges_[facesetName] = chargeDensity;
       match = true;
     }
 
     /** */
     else if (strcmp(arg[argIndx],"unfix_charge")==0) {
       argIndx++;
       string fsetName(arg[argIndx]);
       throw ATC_Error("Ability to unfix charge not yet implemented");
       match = true;
     }
 #endif
     else if (strcmp(arg[argIndx],"control")==0) {
       argIndx++;
       if (strcmp(arg[argIndx],"charge")==0) {
         argIndx++;
         if (!atc_->track_charge()) throw ATC_Error("must have charges to regulate");
         match = chargeRegulator_->modify(narg-argIndx,&arg[argIndx]);
       }
     }
 
     /** switch to use slabbing */
     else if (strcmp(arg[argIndx],"slab")==0) {
       argIndx++;
       if (strcmp(arg[argIndx],"on")==0) {
         useSlab_ = true;
         match = true;
       }
       else if (strcmp(arg[argIndx],"off")==0) {
         useSlab_ = false;
         match = true;
       }
     }
 
     /** switch to account for short range interaces */
     else if (strcmp(arg[argIndx],"short_range")==0) {
       argIndx++;
       if (strcmp(arg[argIndx],"on")==0) {
         includeShortRange_ = true;
         match = true;
       }
       else if (strcmp(arg[argIndx],"off")==0) {
         includeShortRange_ = false;
         match = true;
       }
     }
 
     return match;
   }
 
   //--------------------------------------------------------
   //  initialize
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::construct_transfers()
   {
     // add charge density transfer operator
     if (atc_->track_charge()) {
       InterscaleManager & interscaleManager(atc_->interscale_manager());
 
       // make sure we have gradients at atoms
       VectorDependencyManager<SPAR_MAT * > * interpolantGradient = interscaleManager.vector_sparse_matrix("InterpolantGradient");
       if (!interpolantGradient) {
         interpolantGradient = new PerAtomShapeFunctionGradient(atc_);
         interscaleManager.add_vector_sparse_matrix(interpolantGradient,
                                                    "InterpolantGradient");
       }
 
       FundamentalAtomQuantity * atomicCharge = 
         interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE);
       AtfShapeFunctionRestriction * nodalAtomicCharge = 
         new AtfShapeFunctionRestriction(atc_,atomicCharge,atc_->accumulant());
       interscaleManager.add_dense_matrix(nodalAtomicCharge,"NodalAtomicCharge");
       AtfShapeFunctionMdProjection * nodalAtomicChargeDensity =
         new AtfShapeFunctionMdProjection(atc_,nodalAtomicCharge,MASS_DENSITY);
       interscaleManager.add_dense_matrix(nodalAtomicChargeDensity,"NodalAtomicChargeDensity");
 
 
       // get the total charge and dipole moment at the node per molecule
       // small molecules require per atom quantities with ghosts
       const map<string,pair<MolSize,int> > & moleculeIds(atc_->molecule_ids());
       map<string,pair<MolSize,int> >::const_iterator molecule;
       PerAtomQuantity<double> * atomProcGhostCoarseGrainingPositions = interscaleManager.per_atom_quantity("AtomicProcGhostCoarseGrainingPositions");
       FundamentalAtomQuantity * charge = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE,
                                                                                       PROC_GHOST);
       for (molecule = moleculeIds.begin(); molecule != moleculeIds.end(); molecule++) {
         const string moleculeName = molecule->first;
         SmallMoleculeSet * smallMoleculeSet = interscaleManager.small_molecule_set(moleculeName);
         // calculate nodal charge from the molecules
         AtomToSmallMoleculeTransfer<double> * moleculeCharge = 
           new AtomToSmallMoleculeTransfer<double>(atc_,charge,smallMoleculeSet);
         interscaleManager.add_dense_matrix(moleculeCharge,"MoleculeCharge"+moleculeName);
         MotfShapeFunctionRestriction * nodalAtomicMoleculeCharge = 
           new MotfShapeFunctionRestriction(moleculeCharge,
                                            interscaleManager.sparse_matrix("ShapeFunction"+moleculeName));
         interscaleManager.add_dense_matrix(nodalAtomicMoleculeCharge,"NodalMoleculeCharge"+moleculeName);
         AtfShapeFunctionMdProjection * nodalAtomicMoleculeChargeDensity =
           new AtfShapeFunctionMdProjection(atc_,nodalAtomicMoleculeCharge,MASS_DENSITY);
         interscaleManager.add_dense_matrix(nodalAtomicMoleculeChargeDensity,"NodalMoleculeChargeDensity"+moleculeName);
 
         // dipole moment density
         // calculate the dipole moment of the molecules
         SmallMoleculeCentroid * moleculeCentroid = static_cast<SmallMoleculeCentroid*>(interscaleManager.dense_matrix("MoleculeCentroid"+moleculeName));
         SmallMoleculeDipoleMoment * dipoleMoment = 
           new SmallMoleculeDipoleMoment(atc_,charge,smallMoleculeSet,atomProcGhostCoarseGrainingPositions,moleculeCentroid);
         interscaleManager.add_dense_matrix(dipoleMoment,"DipoleMoment"+moleculeName);
         MotfShapeFunctionRestriction * nodalAtomicMoleculeDipole = 
           new MotfShapeFunctionRestriction(dipoleMoment,
                                            interscaleManager.sparse_matrix("ShapeFunction"+moleculeName));
         interscaleManager.add_dense_matrix(nodalAtomicMoleculeDipole,"NodalMoleculeDipole"+moleculeName);
         AtfShapeFunctionMdProjection * nodalAtomicMoleculeDipoleDensity =
           new AtfShapeFunctionMdProjection(atc_,nodalAtomicMoleculeDipole,MASS_DENSITY);
         interscaleManager.add_dense_matrix(nodalAtomicMoleculeDipoleDensity,"NodalMoleculeDipoleDensity"+moleculeName);
       }
     }
     
   }
 
   //--------------------------------------------------------
   //  initialize
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::initialize()
   {
     ExtrinsicModel::initialize();
     InterscaleManager & interscaleManager = atc_->interscale_manager();
 
     int nNodes = atc_->num_nodes();
     atomForces_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_FORCE);
     rhs_[ELECTRIC_POTENTIAL].reset(nNodes,1);
 
 #ifdef CHARGED_SURFACE
 
     // set fixed potential surfaces form charged surfaces
     map<string,double>::const_iterator isurface;
     for (isurface = surfaceCharges_.begin(); isurface != surfaceCharges_.end(); isurface++)
       add_charged_surface(isurface->first,isurface->second);
 #endif
 
     // set up poisson solver
     rhsMask_.reset(NUM_FIELDS,NUM_FLUX);
     rhsMask_ = false;
     for (int i = 0; i < NUM_FLUX; i++) {
       rhsMask_(ELECTRIC_POTENTIAL,i) = atc_->fieldMask_(ELECTRIC_POTENTIAL,i);
     }
     rhsMask_(ELECTRIC_POTENTIAL,FLUX) = false;// for poisson solve & rhs compute
     // need to create the bcs for the solver to configure properly
     atc_->set_fixed_nodes(); 
     if (poissonSolver_) delete poissonSolver_;
 
 
         int type = ATC::LinearSolver::ITERATIVE_SOLVE_SYMMETRIC;
     if (poissonSolverType_ == DIRECT) {
       type = ATC::LinearSolver::DIRECT_SOLVE;
     }
     poissonSolver_ = new PoissonSolver(ELECTRIC_POTENTIAL,
                                        physicsModel_, atc_->feEngine_,
                                        atc_->prescribedDataMgr_, atc_,
                                        rhsMask_,type, true);
     if (poissonSolverTol_) poissonSolver_->set_tolerance(poissonSolverTol_);
     if (poissonSolverMaxIter_) poissonSolver_->set_max_iterations(poissonSolverMaxIter_);
     poissonSolver_->initialize();
 
     // initialize localized Green's function for FE electric field correction
     if (atc_->track_charge() && includeShortRange_) {
       greensFunctions_.reserve(nNodes);
 
       // set up Green's function per node
       for (int i = 0; i < nNodes; i++) {
         set<int> localNodes;
         
         for (int j = 0; j < nNodes; j++)
           localNodes.insert(j);
 
         // call Poisson solver to get Green's function for node i
         DENS_VEC globalGreensFunction;
         poissonSolver_->greens_function(i,globalGreensFunction);
       
         // store green's functions as sparse vectors only on local nodes
         set<int>::const_iterator thisNode;
         SparseVector<double> sparseGreensFunction(nNodes);
         for (thisNode = localNodes.begin(); thisNode != localNodes.end(); thisNode++)
           sparseGreensFunction(*thisNode) = globalGreensFunction(*thisNode);
         greensFunctions_.push_back(sparseGreensFunction);
       }
     }
 
 
     if (atc_->track_charge()) {
       double *  q = LammpsInterface::instance()->atom_charge();
       if (!q) throw ATC_Error(" charge tracking requested but charge pointer is null");
 
       nodalAtomicCharge_ = interscaleManager.dense_matrix("NodalAtomicCharge");
       if (! nodalAtomicCharge_) {
         FundamentalAtomQuantity * atomCharge = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE);
         nodalAtomicCharge_ = new AtfShapeFunctionRestriction(atc_,atomCharge,
                                                              atc_->accumulant());
         interscaleManager.add_dense_matrix(nodalAtomicCharge_,"NodalAtomicCharge");
       }
       if (atc_->groupbitGhost_) {
         nodalAtomicGhostCharge_ = interscaleManager.dense_matrix("NodalAtomicGhostCharge");
         if (! nodalAtomicGhostCharge_) {
           FundamentalAtomQuantity * ghostCharge = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE, GHOST);
           
           PerAtomSparseMatrix<double> * ghostShapeFunctions = interscaleManager.per_atom_sparse_matrix("InterpolantGhost");
           if (!ghostShapeFunctions) {
             ghostShapeFunctions = new PerAtomShapeFunction(atc_,
                                                            interscaleManager.per_atom_quantity("AtomicGhostCoarseGrainingPositions"),
                                                            interscaleManager.per_atom_int_quantity("AtomGhostElement"),
                                                            GHOST);
             interscaleManager.add_per_atom_sparse_matrix(ghostShapeFunctions,"InterpolantGhost");
           }
 
           nodalAtomicGhostCharge_ = new AtfShapeFunctionRestriction(atc_,ghostCharge,
                                                                     ghostShapeFunctions);
           interscaleManager.add_dense_matrix(nodalAtomicGhostCharge_,"NodalAtomicGhostCharge");
         }
       }
     }
 
     if (chargeRegulator_) {
       if (! poissonSolver_) throw ATC_Error("passing of Poisson solver from ExtrinsicModelElectrostatic to ChargeRegulator failed");
       chargeRegulator_->assign_poisson_solver(poissonSolver_);
       chargeRegulator_->construct_methods();
       chargeRegulator_->initialize();
     }
 
     // set initial force
     post_force();
   }
 
   //--------------------------------------------------------
   //  pre final integration
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::post_init_integrate()
   {
     if (chargeRegulator_) chargeRegulator_->apply_pre_force(atc_->dt());
   }
   //--------------------------------------------------------
   //  post force
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::post_force()
   {
 
     if (chargeRegulator_) chargeRegulator_->apply_post_force(atc_->dt());
     // add in correction accounting for lumped mass matrix in charge density 
     // in atomistic part of domain & account for physics model fluxes,resets rhs
     
     
     // set Dirchlet data
     atc_->set_fixed_nodes();
 
     // set sources
     (atc_->prescribed_data_manager())->set_sources(atc_->time()+0.5*(atc_->dt()),atc_->sources());
 
     // compute Poisson equation RHS sources
     atc_->compute_rhs_vector(rhsMask_, atc_->fields_, rhs_, atc_->source_integration(), physicsModel_);
     
     // add atomic charges to rhs
     DENS_MAT & rhs = rhs_[ELECTRIC_POTENTIAL].set_quantity();
     if (atc_->track_charge()) {
 
       rhs += nodalAtomicCharge_->quantity();
       if (nodalAtomicGhostCharge_) {
         rhs += nodalAtomicGhostCharge_->quantity();
       }
     }
 
     
 
     
 
     // solve poisson eqn for electric potential
     // electron charge density added to Poisson RHS in solver
     DENS_MAT & potential = (atc_->field(ELECTRIC_POTENTIAL)).set_quantity();
     if ( maxSolves_ == 0 || (atc_->local_step() < maxSolves_) ) {
 //potential.print("POT");
 //    rhs.print("RHS");
     bool converged = poissonSolver_->solve(potential,rhs);
     if (! converged ) throw ATC_Error("Poisson solver did not converge in ExtrinsicModelElectrostatic");
     }
 
     // do this for intrinsic charges or effective electron charges at atoms
     if (atc_->track_charge() 
       || ( LammpsInterface::instance()->atom_charge() && atc_->source_atomic_quadrature(ELECTRIC_POTENTIAL) ) ) {
       _atomElectricalForce_.resize(atc_->nlocal(),atc_->nsd());
       add_electrostatic_forces(potential);
 #ifdef CHARGED_SURFACE
       if (includeShortRange_)
         apply_charged_surfaces(potential);
 #endif
 
       InterscaleManager & interscaleManager_ = atc_->interscale_manager(); 
       atomForces_ = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_FORCE); 
       (*atomForces_) += _atomElectricalForce_; // f_E in ours, f in lammps ultimately
     }
   }
 
   //--------------------------------------------------------
   //  output
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::output(OUTPUT_LIST & outputData)
   {
     double scale = 1./(LammpsInterface::instance()->ftm2v());
     double localF[3];
     if (_atomElectricalForce_.nRows() > 0) {
       localF[0] = scale*(_atomElectricalForce_).col_sum(0);
       localF[1] = scale*(_atomElectricalForce_).col_sum(1);
       localF[2] = scale*(_atomElectricalForce_).col_sum(2);
     }
     else {
       localF[0] = 0.;localF[1] = 0.; localF[2] = 0.;
     }
     LammpsInterface::instance()->allsum(localF,totalElectricalForce_,3);  
     if (LammpsInterface::instance()->rank_zero()) {
       atc_->feEngine_->add_global("electrostatic_force_x",  totalElectricalForce_[0]);
       atc_->feEngine_->add_global("electrostatic_force_y",  totalElectricalForce_[1]);
       atc_->feEngine_->add_global("electrostatic_force_z",  totalElectricalForce_[2]);
     }
 
     // add in FE fields related to charge
     FIELDS & fields(atc_->fields());
     FIELDS::const_iterator rhoField = fields.find(CHARGE_DENSITY);
     if (rhoField!=fields.end()) {
       InterscaleManager & interscaleManager(atc_->interscale_manager());
       const DENS_MAN * atomicChargeDensity(interscaleManager.dense_matrix("NodalAtomicChargeDensity"));
       atc_->nodal_atomic_field(CHARGE_DENSITY) = atomicChargeDensity->quantity();
       
       fields[CHARGE_DENSITY] = atomicChargeDensity->quantity();
       
       DENS_MAT & chargeDensity(fields[CHARGE_DENSITY].set_quantity());
       DENS_MAT & nodalAtomicChargeDensity((atc_->nodal_atomic_field(CHARGE_DENSITY)).set_quantity());
       if ((atc_->lammps_interface())->rank_zero()) {
         outputData["charge_density"] = &chargeDensity;
         outputData["NodalAtomicChargeDensity"] = &nodalAtomicChargeDensity;
       }
     }
 
     
     if (fields.find(ELECTRON_DENSITY)==fields.end()) {
       fields[ELECTRON_DENSITY].reset(fields[CHARGE_DENSITY].nRows(),1);
       DENS_MAT & electronDensity(fields[ELECTRON_DENSITY].set_quantity());
       if ((atc_->lammps_interface())->rank_zero()) {
         outputData["electron_density"] = &electronDensity;
       }
     }
     
     const map<string,pair<MolSize,int> > & moleculeIds(atc_->molecule_ids());
     map<string,pair<MolSize,int> >::const_iterator molecule;
     for (molecule = moleculeIds.begin(); molecule != moleculeIds.end(); molecule++) {
       // net charge
       DENS_MAN & nodalMoleculeChargeDensityOut(atc_->tagged_dens_man("NodalMoleculeChargeDensity"+molecule->first));
       DENS_MAN * nodalMoleculeChargeDensity((atc_->interscale_manager()).dense_matrix("NodalMoleculeChargeDensity"+molecule->first));
       nodalMoleculeChargeDensityOut = nodalMoleculeChargeDensity->quantity();
       // dipole moment
       DENS_MAN & nodalMoleculeDipoleDensityOut(atc_->tagged_dens_man("NodalMoleculeDipoleDensity"+molecule->first));
       DENS_MAN * nodalMoleculeDipoleDensity((atc_->interscale_manager()).dense_matrix("NodalMoleculeDipoleDensity"+molecule->first));
       nodalMoleculeDipoleDensityOut = nodalMoleculeDipoleDensity->quantity();
     }
 
     if(chargeRegulator_) chargeRegulator_->output(outputData);
   }
 
   //--------------------------------------------------------
   //  size_vector
   //--------------------------------------------------------
   int ExtrinsicModelElectrostatic::size_vector(int intrinsicSize)
   {
     baseSize_ = intrinsicSize;
     return 5;
   }
 
   //--------------------------------------------------------
   //  compute_scalar : added energy = - f.x
   //--------------------------------------------------------
   double ExtrinsicModelElectrostatic::compute_scalar(void)
   {
     //((atc_->interscale_manager()).fundamental_atom_quantity(LammpsInterface::ATOM_POSITION))->force_reset();
     const DENS_MAT & atomPosition = ((atc_->interscale_manager()).fundamental_atom_quantity(LammpsInterface::ATOM_POSITION))->quantity();
     double local_fdotx = 0, fdotx;
     
     for (int i = 0; i < _atomElectricalForce_.nRows() ; i++) {
       for (int j = 0; j < _atomElectricalForce_.nCols() ; j++) {
         local_fdotx -= _atomElectricalForce_(i,j)*atomPosition(i,j);
       }
     }
     LammpsInterface::instance()->allsum(&local_fdotx,&fdotx,1);
     // convert
     fdotx *=  LammpsInterface::instance()->mvv2e();
     return fdotx;
   }
   //--------------------------------------------------------
   //  compute_vector
   //--------------------------------------------------------
   bool ExtrinsicModelElectrostatic::compute_vector(int n, double & value)
   {
     if (n == baseSize_) {
       
       double nSum = ((atc_->field(ELECTRON_DENSITY)).quantity()).col_sum();
       value = nSum;
       return true;
     }
     else if (n > baseSize_ && n < baseSize_+4) {
       int dof = n-baseSize_-1;
       double localF = (_atomElectricalForce_).col_sum(dof), F=0;
       LammpsInterface::instance()->allsum(&localF,&F,1);
       double ftm2v = LammpsInterface::instance()->ftm2v();
       value = F/ftm2v;
       return true;
     }
     else if (n == baseSize_+4) {
       double nSum = ((atc_->field(ELECTRIC_POTENTIAL)).quantity()).col_sum();
       value = nSum;
       return true;
     }
     return false;
   }
 
   //--------------------------------------------------------
   //  add_electrostatic_forces
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::add_electrostatic_forces
     (MATRIX & potential)
   {
     
     //double qE2f = LammpsInterface::instance()->qe2f();
     double qV2e = LammpsInterface::instance()->qv2e(); // charge volts to our energy units
     //double ** f = LammpsInterface::instance()->fatom();
     double *  q = LammpsInterface::instance()->atom_charge();
     // f_ai = \sum_IJ N_Ia Bi_IJ phi_J = \sum_I N_Ia Ei_I
     int nsd = atc_->nsd();
     int nLocal = atc_->nlocal();
     DENS_MAT E(nLocal,nsd);
     const SPAR_MAT_VEC & shapeFucntionDerivatives(((atc_->interscale_manager()).vector_sparse_matrix("InterpolantGradient"))->quantity());
     if (nLocal > 0) {
       for (int i=0; i < nsd; i++) {
         CLON_VEC Ei = column(E,i);
         Ei = -1.*(*(shapeFucntionDerivatives[i])*potential);
       }
     }
    
     int dimOffset = 0;
     if (useSlab_) dimOffset = nsd - 1;
     for (int i = 0; i < nLocal; i++) {
       int atomIdx = atc_->internalToAtom_(i);
       double c = qV2e*q[atomIdx];
       for (int j = 0; j < dimOffset; j ++)
         _atomElectricalForce_(i,j) = 0.;
       for (int j = dimOffset; j < nsd; j ++)
         _atomElectricalForce_(i,j) = c*E(i,j);
     }
     
     // correct field for short range interactions
     if (includeShortRange_)
       correct_electrostatic_forces();
   }
 
   //--------------------------------------------------------
   //  correct_electrostatic_forces
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::correct_electrostatic_forces()
   {
     // compute restricted sparse shape function set for each atom
     // to account for its Green's Function
     //double qE2f = LammpsInterface::instance()->qe2f();
     double qV2e = LammpsInterface::instance()->qv2e();
     double *  q = LammpsInterface::instance()->atom_charge();
     vector<SparseVector<double> > atomicFePotential;
     int nLocal = atc_->nlocal();
     
     int nGhostLammps = LammpsInterface::instance()->nghost();
     int nLocalLammps = LammpsInterface::instance()->nlocal();
     int nLocalTotal = nLocalLammps + nGhostLammps; // total number of atoms on this processor
     atomicFePotential.reserve(nLocalTotal);
     SparseVector<double> dummy(atc_->num_nodes());
     for (int i = 0; i < nLocalTotal; i++)
       atomicFePotential.push_back(dummy);
 
     // compute local potential contributions from atoms on this processor
     InterscaleManager & interscaleManager(atc_->interscale_manager());
     const SPAR_MAT & myShpFcn((interscaleManager.per_atom_sparse_matrix("Interpolant"))->quantity());
     for (int i = 0; i < nLocal; i++) {
       DenseVector<INDEX> nodeIndices;
       DENS_VEC nodeValues;
       myShpFcn.row(i,nodeValues,nodeIndices);
       
       int atomIdx = atc_->internalToAtom_(i);
       //double c = qE2f*q[atomIdx];
       //double c = qV2e*q[atomIdx];
       //nodeValues *= c;
       nodeValues *= q[atomIdx];
       
       for (int j = 0; j < nodeIndices.size(); j++)
         atomicFePotential[atomIdx].add_scaled(greensFunctions_[nodeIndices(j)],nodeValues(j));
     }
 
     // compute local potential contribtutions for lammps ghost atoms 
     // which are known to ATC,
     // this will grab both processor and periodic neighbors,
     // so we need to add in neighbor contributions using lammps indices
     // rather than atc indices or we could potentially
     // double count periodic contributions
     double ** xatom = LammpsInterface::instance()->xatom();
     const int * mask = LammpsInterface::instance()->atom_mask();
     int nodesPerElement = ((atc_->feEngine_)->fe_mesh())->num_nodes_per_element();
     int nsd = atc_->nsd();
     for (int i = nLocalLammps; i < nLocalTotal; i++) {
       if (mask[i] & atc_->groupbit_) {
         DENS_VEC coords(nsd);
         coords.copy(xatom[i],nsd);
         Array<int> nodeIndices(nodesPerElement);
         DENS_VEC nodeValues(nodesPerElement);
         (atc_->feEngine_)->shape_functions(coords,nodeValues,nodeIndices);
         
         //double c = qV2e*q[i];
         //nodeValues *= c;
         nodeValues *= q[i];
 
         for (int j = 0; j < nodeIndices.size(); j++) {
           atomicFePotential[i].add_scaled(greensFunctions_[nodeIndices(j)],nodeValues(j));
         }
       }
     }
 
     // Get sparse vectors of derivatives at each atom
     
     //      to compute this only when the shape functions change
     vector<vector<SparseVector<double> > > atomicDerivatives;
     atomicDerivatives.reserve(nLocal);
     for (int i = 0; i < nLocal; i++) {
 
       // determine shape function derivatives at atomic location
       // and construct sparse vectors to store derivative data
       vector<SparseVector<double> > derivativeVectors;
       derivativeVectors.reserve(nsd);
       for (int j = 0; j < nsd; j++)
         derivativeVectors.push_back(dummy);
       atomicDerivatives.push_back(derivativeVectors);
       InterscaleManager & interscaleManager(atc_->interscale_manager());
       const SPAR_MAT_VEC & shapeFucntionDerivatives((interscaleManager.vector_sparse_matrix("InterpolantGradient"))->quantity());
       for (int j = 0; j < nsd; j++) {
         DenseVector<INDEX> nodeIndices;
         DENS_VEC nodeValues;
         shapeFucntionDerivatives[j]->row(i,nodeValues,nodeIndices);
         for (int k = 0; k < nodeIndices.size(); k++)
           atomicDerivatives[i][j](nodeIndices(k)) = nodeValues(k);
       }
     }
 
     // loop over all atoms and correct their efield based on all their 
     // neighbor's local efield response
     
     //      need to use specific coulombic cutoff from different pairs
     //      see pair_coul_cut for an example of the data structures
     //      unfortunately don't know how to get at this data in general
     //      beyond a cast from the LAMMPS pair object (see force.h).
     //      Until this is fixed, only use this method with the coulombic force
     //      the same for all pairs and equal to the largest force cutoff.
     //      Probably the best fix is to implement our own pair style for this.
 
     double cutoffRadius = LammpsInterface::instance()->pair_cutoff();
     double cutoffSq = cutoffRadius*cutoffRadius;
     
     int inum = LammpsInterface::instance()->neighbor_list_inum();
     int * ilist = LammpsInterface::instance()->neighbor_list_ilist();
     int * numneigh = LammpsInterface::instance()->neighbor_list_numneigh();
     int ** firstneigh = LammpsInterface::instance()->neighbor_list_firstneigh();
     
       // loop over neighbors of my atoms
     for (int ii = 0; ii < inum; ii++) {
       int i = ilist[ii];
       if (mask[i] & atc_->groupbit_) {
         double xtmp = xatom[i][0];
         double ytmp = xatom[i][1];
         double ztmp = xatom[i][2];
         
         int * jlist = firstneigh[i];
         int jnum = numneigh[i];
         
         for (int jj = 0; jj < jnum; jj++) {
           int j = jlist[jj];
           if (mask[j] & atc_->groupbit_) {
             //double factor_coul = LammpsInterface::instance()->coulomb_factor(j);
             LammpsInterface::instance()->neighbor_remap(j);
 
             double delx = xtmp - xatom[j][0];
             double dely = ytmp - xatom[j][1];
             double delz = ztmp - xatom[j][2];
             double rsq = delx*delx + dely*dely + delz*delz;      
             if (rsq < cutoffSq) {
               DENS_VEC efield(nsd);
               efield = 0.;
               int atcIdx = atc_->atomToInternal_[i];
               for (int k = 0; k < nsd; k++)
                 efield(k) = -1.*dot(atomicDerivatives[atcIdx][k],atomicFePotential[j]);
 
               // apply correction in atomic forces
               //double c = factor_coul*qE2f*q[i];
               //double c = factor_coul*qV2e*q[i];
               double c = qV2e*q[i];
               for (int k = 0; k < nsd; k++) {
                 if ((!useSlab_) || (k==nsd)) {
                   //f[i][k] -= c*efield(k);
                   _atomElectricalForce_(atcIdx,k) -= c*efield(k);
                 }
               }
             }
           }
         }
       }
     }
   }
 
 #ifdef CHARGED_SURFACE
 
   //--------------------------------------------------------
   //  add_charged_surface
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::add_charged_surface(const string & facesetName,
                                                         const double chargeDensity)
   {
     // get faceset information
     int nNodes = atc_->num_nodes();
     const FE_Mesh * feMesh = (atc_->feEngine_)->fe_mesh();
     const set< pair <int,int> > * faceset 
       = & ( feMesh->faceset(facesetName));
 
     // set face sources to all point at one function for use in integration
     SURFACE_SOURCE faceSources;
     XT_Function * f = XT_Function_Mgr::instance()->constant_function(1.);
     set< pair<int,int> >::const_iterator iset;
     for (iset = faceset->begin(); iset != faceset->end(); iset++) {
       pair<int,int>  face = *iset;
       // allocate
       Array < XT_Function * > & dof  = faceSources[ELECTRIC_POTENTIAL][face];
       dof.reset(1);
       dof(0) = f;
     }
 
     // Get associated nodeset
     set<int> nodeset;
     feMesh->faceset_to_nodeset(facesetName,nodeset);
 
     // Get coordinates of each node in face set
     map<int,pair<DENS_VEC,double> > & myFaceset = chargedSurfaces_[facesetName];
     set<int>::const_iterator myNode;
     for (myNode = nodeset.begin(); myNode != nodeset.end(); myNode++) {
       DENS_VEC myCoords = feMesh->nodal_coordinates(*myNode);
       pair<DENS_VEC,double> myPair(myCoords,0.);
       myFaceset[*myNode] = myPair;
     }
 
     // computed integrals of nodal shape functions on face
     FIELDS nodalFaceWeights;
     nodalFaceWeights[ELECTRIC_POTENTIAL].reset(nNodes,1);
     Array<bool> fieldMask(NUM_FIELDS);
     fieldMask(ELECTRIC_POTENTIAL) = true;
     
     (atc_->feEngine_)->add_fluxes(fieldMask,0.,faceSources,nodalFaceWeights);
     // set up data structure holding charged faceset information
     FIELDS sources;
     double coulombConstant = LammpsInterface::instance()->coulomb_constant();
     map<int,pair<DENS_VEC,double> >::iterator myNodeData;
     for (myNodeData = myFaceset.begin(); myNodeData != myFaceset.end(); myNodeData++) {
       // evaluate voltage at each node I
       // set up X_T function for integration: k*chargeDensity/||x_I - x_s||
       
       // integral is approximated in two parts:
       // 1) near part with all faces within r < rcrit evaluated as 2 * pi * rcrit * k sigma A/A0, A is area of this region and A0 = pi * rcrit^2, so 2 k sigma A / rcrit
       // 2) far part evaluated using Gaussian quadrature on faceset
       double rcritSq = LammpsInterface::instance()->pair_cutoff();
       rcritSq *= rcritSq;
       int nodalIndex = myNodeData->first;
       DENS_VEC myCoords((myNodeData->second).first);
       double xtArgs[8];
       xtArgs[0] = myCoords(0); xtArgs[1] = myCoords(1); xtArgs[2] = myCoords(2);
       xtArgs[3] = 1.; xtArgs[4] = 1.; xtArgs[5] = 1.;
       xtArgs[6] = coulombConstant*chargeDensity;
       xtArgs[7] = -1.;
       string radialPower = "radial_power";
       f = XT_Function_Mgr::instance()->function(radialPower,8,xtArgs);
 
       
       for (iset = faceset->begin(); iset != faceset->end(); iset++) {
         pair<int,int>  face = *iset;
         // allocate
         Array < XT_Function * > & dof  = faceSources[ELECTRIC_POTENTIAL][face];
         dof.reset(1);
           dof(0) = f;
       }
 
       // perform integration to get quantities at nodes on facesets
       // V_J' = int_S N_J k*sigma/|x_I - x_s| dS
       sources[ELECTRIC_POTENTIAL].reset(nNodes,1);
       (atc_->feEngine_)->add_fluxes(fieldMask,0.,faceSources,sources);
 
       double myPotential = 0.;
       // sum over all nodes in faceset to get total potential:
       // V_I = sum_J VJ'
       const DENS_MAT & myPotentialSource(sources[ELECTRIC_POTENTIAL].quantity());
       nodalChargePotential_[facesetName][nodalIndex] = myPotentialSource(nodalIndex,0);
       for (myNode = nodeset.begin(); myNode != nodeset.end(); myNode++)
         myPotential += myPotentialSource(*myNode,0);
 
       // assign an XT function per each node and
       // then call the prescribed data manager and fix each node individually.
       f = XT_Function_Mgr::instance()->constant_function(myPotential);
       (atc_->prescribedDataMgr_)->fix_field(nodalIndex,ELECTRIC_POTENTIAL,0,f);
 
       // compute effective charge at each node I
       // multiply charge density by integral of N_I over face
       (myNodeData->second).second = (nodalFaceWeights[ELECTRIC_POTENTIAL].quantity())(nodalIndex,0)*chargeDensity;
     }
   }
 
   //--------------------------------------------------------
   //  apply_charged_surfaces
   //--------------------------------------------------------
   void ExtrinsicModelElectrostatic::apply_charged_surfaces
     (MATRIX & potential)
   {
     //double qE2f = LammpsInterface::instance()->qe2f();
     double qV2e = LammpsInterface::instance()->qv2e();
     double qqrd2e = LammpsInterface::instance()->qqrd2e();
     //double ** fatom = LammpsInterface::instance()->fatom();
-    double *  qatom = LammpsInterface::instance()->atom_charge();
+    //double *  qatom = LammpsInterface::instance()->atom_charge();
+    InterscaleManager & interscaleManager(atc_->interscale_manager());
+    const DENS_MAT & qatom((interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE))->quantity());
     double cutoffRadius = LammpsInterface::instance()->pair_cutoff();
     double cutoffSq = cutoffRadius*cutoffRadius;
-    int nLocal = atc_->nlocal();
+    int nLocal = qatom.nRows();
     int nsd = atc_->nsd();
     int nNodes = atc_->num_nodes();
     double penalty = poissonSolver_->penalty_coefficient();
     if (penalty <= 0.0) throw ATC_Error("ExtrinsicModelElectrostatic::apply_charged_surfaces expecting non zero penalty");
     SparseVector<double> dummy(atc_->num_nodes());
 
     map<string,map<int,pair<DENS_VEC,double> > >::const_iterator isurface;
     for (isurface = chargedSurfaces_.begin(); isurface != chargedSurfaces_.end(); isurface++) {
       string facesetName = isurface->first;
       map<int,pair<DENS_VEC,double> >::const_iterator inode;
       for (inode = (isurface->second).begin(); inode != (isurface->second).end(); inode++) {
         
         int nodeId = inode->first;
         DENS_VEC nodalCoords = (inode->second).first;
         double nodalCharge = (inode->second).second;
         double nodalPotential = nodalChargePotential_[facesetName][nodeId];
         PerAtomQuantity<double> * atomicCoords = (atc_->interscale_manager()).per_atom_quantity("AtomicCoarseGrainingPositions");
         const DENS_MAT & myAtomicCoords(atomicCoords->quantity());
         for (int i = 0; i < nLocal; i++) {
-          int atomIdx = atc_->internalToAtom_(i);
-          if (abs(qatom[atomIdx]) > 0) { 
+          if (abs(qatom(i,0)) > 0) { 
             double distanceSq = 0.;
             double deltaX[3];
             for (int j = 0; j < nsd; j++) {
               deltaX[j] = myAtomicCoords(i,j) - nodalCoords(j);
               distanceSq += deltaX[j]*deltaX[j];
             }
             if (distanceSq < cutoffSq) { 
               // first apply pairwise coulombic interaction
               if (!useSlab_) { 
-                double coulForce = qqrd2e*nodalCharge*qatom[atomIdx]/(distanceSq*sqrtf(distanceSq));
+                double coulForce = qqrd2e*nodalCharge*qatom(i,0)/(distanceSq*sqrtf(distanceSq));
                 for (int j = 0; j < nsd; j++)
                   //fatom[atomIdx][j] += deltaX[j]*coulForce;
                   _atomElectricalForce_(i,j) += deltaX[j]*coulForce;
               }
               
               // second correct for FE potential induced by BCs
               // determine shape function derivatives at atomic location
               // and construct sparse vectors to store derivative data
               
               vector<SparseVector<double> > derivativeVectors;
               derivativeVectors.reserve(nsd);
-              InterscaleManager & interscaleManager(atc_->interscale_manager());
               const SPAR_MAT_VEC & shapeFunctionDerivatives((interscaleManager.vector_sparse_matrix("InterpolantGradient"))->quantity());
               for (int j = 0; j < nsd; j++) {
                 DenseVector<INDEX> nodeIndices;
                 DENS_VEC nodeValues;
                 shapeFunctionDerivatives[j]->row(i,nodeValues,nodeIndices);
                 derivativeVectors.push_back(dummy);
                 for (int k = 0; k < nodeIndices.size(); k++)
                   derivativeVectors[j](nodeIndices(k)) = nodeValues(k);
               }
               
               // compute greens function from charge quadrature
               
               SparseVector<double> shortFePotential(nNodes);
               shortFePotential.add_scaled(greensFunctions_[nodeId],penalty*nodalPotential);
               
               // compute electric field induced by charge
               DENS_VEC efield(nsd);
               efield = 0.;
               for (int j = 0; j < nsd; j++)
                 efield(j) = -.1*dot(derivativeVectors[j],shortFePotential);
               
               // apply correction in atomic forces
               //double c = qE2f*qatom[atomIdx];
-              double c = qV2e*qatom[atomIdx];
+              double c = qV2e*qatom(i,0);
               for (int j = 0; j < nsd; j++)
                 if ((!useSlab_) || (j==nsd)) { 
                   //fatom[atomIdx][j] -= c*efield(j);
                   _atomElectricalForce_(i,j) -= c*efield(j);
                 }
             }
           }
         }
       }
     }
   }
 #endif
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ExtrinsicModelElectrostaticMomentum
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ExtrinsicModelElectrostaticMomentum::ExtrinsicModelElectrostaticMomentum
                                      (ExtrinsicModelManager * modelManager,
                                       ExtrinsicModelType modelType,
                                       string matFileName) :
     ExtrinsicModelElectrostatic(modelManager,modelType,matFileName)
   {
      if (physicsModel_) delete physicsModel_; 
      if (modelType == ELECTROSTATIC) {
        physicsModel_ = new PhysicsModelElectrostatic(matFileName);
      }
      else {
        physicsModel_ = new PhysicsModelElectrostaticEquilibrium(matFileName);
      }
      // set up correct masks for coupling
      rhsMaskIntrinsic_(VELOCITY,SOURCE) = true;
      atc_->fieldMask_(VELOCITY,EXTRINSIC_SOURCE) = true;
   }
   
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ExtrinsicModelElectrostaticMomentum::~ExtrinsicModelElectrostaticMomentum()
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   // modify 
   //--------------------------------------------------------
   bool ExtrinsicModelElectrostaticMomentum::modify(int narg, char **arg)
   {
     bool match = false;
 
     if (!match)
       match = ExtrinsicModelElectrostatic::modify(narg,arg);
 
     return match;
   }
 
   //--------------------------------------------------------
   //  initialize
   //--------------------------------------------------------
   void ExtrinsicModelElectrostaticMomentum::initialize()
   {
     ExtrinsicModelElectrostatic::initialize();
 
     int nNodes = atc_->num_nodes();
     int nsd    = atc_->nsd();
     rhs_[VELOCITY].reset(nNodes,nsd);
   }
 
   //--------------------------------------------------------
   //  set coupling source terms
   //--------------------------------------------------------
   void ExtrinsicModelElectrostaticMomentum::set_sources(FIELDS & fields, FIELDS & sources)
   {
     // compute charge density
     if (modelType_ == ELECTROSTATIC_EQUILIBRIUM) { 
       DENS_MAN & n = atc_->field(ELECTRON_DENSITY);
       atc_->nodal_projection(ELECTRON_DENSITY,physicsModel_,n);
     }
     // else {
     //   FIELDS rhs;
     //   Array2D<bool> mask;
     //   mask(ELECTRON_DENSITY,SOURCE) = true;
     //   atc_->evaluate_rhs_integral(mask,fields,rhs,FULL_DOMAIN,physicsModel_);
     //   atc_->apply_inverse_mass_matrix(rhs[ELECTRON_DENSITY].quantity(),n.set_quantity(),ELECTRON_DENSITY);
     // }
 
     // compute source term with appropriate masking and physics model
     atc_->evaluate_rhs_integral(rhsMaskIntrinsic_, fields, sources,
                                 atc_->source_integration(), physicsModel_); 
 //(sources[VELOCITY].quantity()).print("V SRC");
   }
 
   //--------------------------------------------------------
   //  output
   //--------------------------------------------------------
   void ExtrinsicModelElectrostaticMomentum::output(OUTPUT_LIST & outputData)
   {
     ExtrinsicModelElectrostatic::output(outputData);
   }
 };
diff --git a/lib/atc/ExtrinsicModelTwoTemperature.cpp b/lib/atc/ExtrinsicModelTwoTemperature.cpp
index ddacbf229..2be6cfeb3 100644
--- a/lib/atc/ExtrinsicModelTwoTemperature.cpp
+++ b/lib/atc/ExtrinsicModelTwoTemperature.cpp
@@ -1,270 +1,295 @@
 // ATC Headers
 #include "ExtrinsicModelTwoTemperature.h"
 #include "ATC_Error.h"
 #include "FieldEulerIntegrator.h"
 #include "ATC_Coupling.h"
 #include "LammpsInterface.h"
 #include "PrescribedDataManager.h"
 #include "PhysicsModel.h"
 
 using std::string;
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ExtrinsicModelTwoTemperature
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ExtrinsicModelTwoTemperature::ExtrinsicModelTwoTemperature
                                 (ExtrinsicModelManager * modelManager,
                                  ExtrinsicModelType modelType,
                                  string matFileName) :
     ExtrinsicModel(modelManager,modelType,matFileName),
     electronTimeIntegration_(TimeIntegrator::IMPLICIT),
     temperatureIntegrator_(NULL),
     nsubcycle_(1),
     exchangeFlag_(true), 
     baseSize_(0)
   {
      physicsModel_ = new PhysicsModelTwoTemperature(matFileName);
 
      // set up correct masks for coupling
      rhsMaskIntrinsic_.reset(NUM_FIELDS,NUM_FLUX);
      rhsMaskIntrinsic_ = false;
      rhsMaskIntrinsic_(TEMPERATURE,SOURCE) = true;
      atc_->fieldMask_(TEMPERATURE,EXTRINSIC_SOURCE) = true;
   }
   
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ExtrinsicModelTwoTemperature::~ExtrinsicModelTwoTemperature()
   {
     if (temperatureIntegrator_) delete temperatureIntegrator_;
   }
 
   //--------------------------------------------------------
   // modify 
   //--------------------------------------------------------
   bool ExtrinsicModelTwoTemperature::modify(int narg, char **arg)
   {
     bool match = false;
     int argIndx = 0;
 
     // energy exchange switch
     /*! \page man_extrinsic_exchange fix_modify AtC extrinsic exchange
       \section syntax
       fix_modify AtC extrinsic exchange <on|off>
 
       \section examples
       <TT> fix_modify AtC extrinsic exchange on </TT> \n
 
       \section description
       Switches energy exchange between the MD system and electron system on and off
 
       \section restrictions
       Only valid for use with two_temperature type of AtC fix.
 
       \section related
       see \ref man_fix_atc
 
       \section default
       on
      */
     if (strcmp(arg[argIndx],"exchange")==0) {
       argIndx++;
       if (strcmp(arg[argIndx],"off")==0) {
         exchangeFlag_ = false;
         rhsMaskIntrinsic_(TEMPERATURE,SOURCE) = false;
         atc_->fieldMask_(ELECTRON_TEMPERATURE,SOURCE) = false;
         atc_->fieldMask_(TEMPERATURE,EXTRINSIC_SOURCE) = false;
       }
       else {
         exchangeFlag_ = true;
         rhsMaskIntrinsic_(TEMPERATURE,SOURCE) = true;
         atc_->fieldMask_(ELECTRON_TEMPERATURE,SOURCE) = true;
         atc_->fieldMask_(TEMPERATURE,EXTRINSIC_SOURCE) = true;
       }
       match = true;
     } // end "exchange"
 
     // electron integration type
     /*! \page man_electron_integration fix_modify AtC extrinsic electron_integration
       \section syntax
       fix_modify AtC extrinsic electron_integration <integration_type> <num_subcyle_steps(optional)> \n
         - integration_type (string) = explicit | implicit | steady  \n
         - num_subcycle_steps (int), optional = number of subcycle steps for the electron time integration
 
       \section examples
       <TT> fix_modify AtC extrinsic electron_integration implicit </TT> \n
       <TT> fix_modify AtC extrinsic electron_integration explicit 100 </TT> \n
 
       \section description
       Switches between integration scheme for the electron temperature.  The number of subcyling steps used to integrate the electron temperature 1 LAMMPS timestep can be manually adjusted to capture fast electron dynamics.
 
       \section restrictions
       For use only with two_temperature type of AtC fix ( see \ref man_fix_atc ) \n
       \section default
       implicit\n
       subcycle_steps = 1
      */
     else if (strcmp(arg[argIndx],"electron_integration")==0) {
       argIndx++;
       nsubcycle_ = 1;
-      if (strcmp(arg[argIndx],"explicit")==0) {
+      if      (strcmp(arg[argIndx],"explicit")==0) {
         electronTimeIntegration_ = TimeIntegrator::EXPLICIT;
         match = true;
       }
       else if (strcmp(arg[argIndx],"implicit")==0) {
         electronTimeIntegration_ = TimeIntegrator::IMPLICIT;
         match = true;
       }
+      else if (strcmp(arg[argIndx],"direct")==0) {
+        electronTimeIntegration_ = TimeIntegrator::DIRECT;
+        match = true;
+      }
       else if (strcmp(arg[argIndx],"steady")==0) {
         electronTimeIntegration_ = TimeIntegrator::STEADY;
         match = true;
       }
+      else if (strcmp(arg[argIndx],"off")==0) {
+        electronTimeIntegration_ = TimeIntegrator::NONE;
+        match = true;
+      }
       if (narg > ++argIndx) nsubcycle_ = atoi(arg[argIndx]);
     } // end "electron_integration"
 
     if (!match) {
       match = ExtrinsicModel::modify(narg, arg);
     }
 
     return match;
   }
 
   //--------------------------------------------------------
   //  initialize
   //--------------------------------------------------------
   void ExtrinsicModelTwoTemperature::initialize()
   {
     ExtrinsicModel::initialize();
 
     int nNodes = atc_->num_nodes();
     rhs_[TEMPERATURE].reset(nNodes,1);
     rhs_[ELECTRON_TEMPERATURE].reset(nNodes,1);
 
     // set up electron temperature integrator
     Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
     rhsMask = false;
     for (int i = 0; i < NUM_FLUX; i++) {
       rhsMask(ELECTRON_TEMPERATURE,i) = atc_->fieldMask_(ELECTRON_TEMPERATURE,i);
     }
+    if (electronTimeIntegration_ == TimeIntegrator::NONE) {
+      temperatureIntegrator_ = NULL;
+      return;
+    }
     if (temperatureIntegrator_) delete temperatureIntegrator_;
     if (electronTimeIntegration_ == TimeIntegrator::STEADY) {
       throw ATC_Error("not implemented");
     }
     else if (electronTimeIntegration_ == TimeIntegrator::IMPLICIT) {
       double alpha = 1; // backwards Euler
       temperatureIntegrator_ = new FieldImplicitEulerIntegrator(
         ELECTRON_TEMPERATURE, physicsModel_, atc_->feEngine_, atc_, 
         rhsMask, alpha);
     }
-    else {
+    else if (electronTimeIntegration_ == TimeIntegrator::EXPLICIT) {
       temperatureIntegrator_ = new FieldExplicitEulerIntegrator(
         ELECTRON_TEMPERATURE, physicsModel_, atc_->feEngine_, atc_, 
         rhsMask);
     }
+    double dt = atc_->lammpsInterface_->dt();
+    double time = atc_->time();
+    temperatureIntegrator_->initialize(dt,time,atc_->fields_);
 
 
     // set up mass matrix
     Array<FieldName> massMask(1);
     massMask = ELECTRON_TEMPERATURE;
     (atc_->feEngine_)->compute_lumped_mass_matrix(massMask,atc_->fields_,physicsModel_,atc_->elementToMaterialMap_,atc_->massMats_);
     atc_->massMatsInv_[ELECTRON_TEMPERATURE] = inv(atc_->massMats_[ELECTRON_TEMPERATURE].quantity());
   }
 
   //--------------------------------------------------------
   //  pre initial integration
   //--------------------------------------------------------
   void ExtrinsicModelTwoTemperature::pre_init_integrate()
   {
+#ifdef ATC_VERBOSE
+    ATC::LammpsInterface::instance()->print_msg_once("start ttm evolution",true,false);
+#endif
+
     double dt = atc_->lammpsInterface_->dt();
     double time = atc_->time();
 
     // integrate fast electron variable/s
     // note: atc calls set_sources in pre_final_integrate
     atc_->set_fixed_nodes();
-    double idt = dt/nsubcycle_;
-    for (int i = 0; i < nsubcycle_ ; ++i) {
-      temperatureIntegrator_->update(idt,time,atc_->fields_,rhs_);
+    if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_TEMPERATURE)
+      && temperatureIntegrator_ )  {
+      double idt = dt/nsubcycle_;
+      for (int i = 0; i < nsubcycle_ ; ++i) {
+        temperatureIntegrator_->update(idt,time,atc_->fields_,rhs_);
+      }
     }
 
+#ifdef ATC_VERBOSE
+    ATC::LammpsInterface::instance()->print_msg_once("...done",false,true);
+#endif
   }
 
   //--------------------------------------------------------
   //  set coupling source terms
   //--------------------------------------------------------
   void ExtrinsicModelTwoTemperature::set_sources(FIELDS & fields, FIELDS & sources)
   {
     // compute source term with appropriate masking and physics model
     atc_->evaluate_rhs_integral(rhsMaskIntrinsic_, fields,
                             sources,
                             atc_->source_integration(), physicsModel_);
   }
 
   //--------------------------------------------------------
   //  output
   //--------------------------------------------------------
   void ExtrinsicModelTwoTemperature::output(OUTPUT_LIST & outputData)
   {
     // nodal data
     outputData["dot_electron_temperature"] = & rhs_[ELECTRON_TEMPERATURE].set_quantity();
 
     // global data
     if (atc_->lammpsInterface_->rank_zero()) {
       double T_mean   = ((atc_->field(ELECTRON_TEMPERATURE)).quantity()).col_sum(0)/atc_->nNodes_;
       atc_->feEngine_->add_global("electron_temperature_mean",  T_mean);
       double T_stddev = ((atc_->field(ELECTRON_TEMPERATURE)).quantity()).col_stdev(0);
       atc_->feEngine_->add_global("electron_temperature_std_dev",  T_stddev);
     }
   }
 
   //--------------------------------------------------------
   //  size_vector
   //--------------------------------------------------------
   int ExtrinsicModelTwoTemperature::size_vector(int intrinsicSize)
   {
     baseSize_ = intrinsicSize;
     return 2;
   }
 
   //--------------------------------------------------------
   //  compute_vector
   //--------------------------------------------------------
   bool ExtrinsicModelTwoTemperature::compute_vector(int n, double & value)
   {
     // output[1] = total electron energy
     // output[2] = average electron temperature
 
     if (n == baseSize_) { 
       Array<FieldName> mask(1);
       FIELD_MATS energy;
       mask(0) = ELECTRON_TEMPERATURE;
       
       (atc_->feEngine_)->compute_energy(mask, 
                                           atc_->fields(),
                                           physicsModel_,
                                           atc_->elementToMaterialMap_,
                                           energy);
       // convert to lammps energy units
       double mvv2e = (atc_->lammps_interface())->mvv2e(); 
       double electronEnergy = mvv2e * energy[ELECTRON_TEMPERATURE].col_sum();
       value = electronEnergy;
       return true;
     }
     else if (n == baseSize_+1) {
       double electronTemperature = ((atc_->field(ELECTRON_TEMPERATURE)).quantity()).col_sum()/(atc_->nNodes_);
       value = electronTemperature;
       return true;
     }
     
     return false;
   }
 
 };
diff --git a/lib/atc/ExtrinsicModelTwoTemperature.h b/lib/atc/ExtrinsicModelTwoTemperature.h
index 4c3038bba..bf1979f40 100644
--- a/lib/atc/ExtrinsicModelTwoTemperature.h
+++ b/lib/atc/ExtrinsicModelTwoTemperature.h
@@ -1,79 +1,79 @@
 #ifndef EXTRINSIC_MODEL_TWO_TEMPERATURE
 #define EXTRINSIC_MODEL_TWO_TEMPERATURE
 
 #include <string>
 
 #include "ExtrinsicModel.h"
 #include "FieldEulerIntegrator.h"
 
 namespace ATC {
   class ATC_Coupling;
   class PrescribedDataManager;
   class ExtrinsicModel;
   class PhysicsModel;
 
   /**
    *  @class  ExtrinsicModelTwoTemperature
    *  @brief  add electron temperature physics to phonon physics
    *          owned field: ELECTRON_TEMPERATURE
    */
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ExtrinsicModelTwoTemperature
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   class ExtrinsicModelTwoTemperature : public ExtrinsicModel {
   
   public:
 
     // constructor
     ExtrinsicModelTwoTemperature(ExtrinsicModelManager * modelManager,
                    ExtrinsicModelType modelType,
                    std::string matFileName);
 
     // destructor
     virtual ~ExtrinsicModelTwoTemperature();
 
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
 
     /** pre time integration */
     virtual void initialize();
 
-    /** set up LAMMPS display variables */
-    virtual int size_vector(int externalSize);
-
-    /** get LAMMPS display variables */
-    virtual bool compute_vector(int n, double & value);
-
     /** Predictor phase, executed before Verlet */
     virtual void pre_init_integrate();
 
     /** Set sources to AtC equation */
     virtual void set_sources(FIELDS & fields, FIELDS & sources);
 
     /** Add model-specific output data */
     virtual void output(OUTPUT_LIST & outputData);
   
+    /** set up LAMMPS display variables */
+    virtual int size_vector(int externalSize);
+
+    /** get LAMMPS display variables */
+    virtual bool compute_vector(int n, double & value);
+
   protected:
     /** electron time integration flag */
     TimeIntegrator::TimeIntegrationType electronTimeIntegration_;
 
     /** electron time integration flag */
     FieldEulerIntegrator * temperatureIntegrator_;
 
     /** number of electron time integration subscycles */
     int nsubcycle_;
 
     /** flag for turning off exchange during equilibration */
     bool exchangeFlag_;
 
     /** offset/size for LAMMPS display output */
     int baseSize_;
 
   };
 
 };
 #endif
diff --git a/lib/atc/FE_Element.cpp b/lib/atc/FE_Element.cpp
index 6bc9d390a..cfc59aa60 100644
--- a/lib/atc/FE_Element.cpp
+++ b/lib/atc/FE_Element.cpp
@@ -1,727 +1,747 @@
 // ATC header files
 #include "ATC_Error.h"
 #include "FE_Mesh.h"
 #include "FE_Element.h"
 #include "FE_Interpolate.h"
 #include "LinearSolver.h"
 #include "PolynomialSolver.h"
 #include "Utility.h"
 
 // Other headers
 #include "math.h"
 
 using ATC_Utility::dbl_geq;
 using ATC_Utility::det3;
 using std::vector;
 
 namespace ATC {
 
 static const int localCoordinatesMaxIterations_ = 40;
 static const double localCoordinatesTolerance = 1.e-09;
 
 
   // =============================================================
   //   class FE_Element
   // =============================================================
   FE_Element::FE_Element(const int nSD,
                          int numFaces,
                          int numNodes,
                          int numFaceNodes,
                          int numNodes1d)
     : nSD_(nSD),
       numFaces_(numFaces),
       numNodes_(numNodes),
       numFaceNodes_(numFaceNodes),
       numNodes1d_(numNodes1d),
       tolerance_(localCoordinatesTolerance),
       projectionGuess_(COORDINATE_ALIGNED)
   {
     feInterpolate_ = NULL;
   }
 
   FE_Element::~FE_Element()
   {
     if (feInterpolate_) delete feInterpolate_;
   }
 
   int FE_Element::num_ips() const
   { 
     return feInterpolate_->num_ips(); 
   }
 
   int FE_Element::num_face_ips() const
   { 
     return feInterpolate_->num_face_ips(); 
   }
 
   void FE_Element::face_coordinates(const DENS_MAT &eltCoords, 
                                     const int faceID,
                                     DENS_MAT & faceCoords) const
   {
     faceCoords.reset(nSD_, numFaceNodes_);
 
     for (int inode=0; inode < numFaceNodes_; inode++) 
     {
       int id = localFaceConn_(faceID,inode);
       for (int isd=0; isd<nSD_; isd++) {
         faceCoords(isd,inode) = eltCoords(isd,id);
       }
     }
   }
 
   void FE_Element::mapping(const int inode, vector<int> &mapping) const
   {
     for (int iSD=0; iSD<nSD_; ++iSD) {
       mapping[iSD] = static_cast<int>((localCoords_(iSD,inode)+1)/2*
                                       (numNodes1d_-1));
     }
   }
 
   DENS_VEC FE_Element::local_coords_1d() const
   {
     DENS_VEC localCoords1d(numNodes1d_);
     for (int inode1d=0; inode1d<numNodes1d_; ++inode1d) {
        localCoords1d(inode1d) = (double(inode1d)/double(numNodes1d_-1))*2 - 1;
     }
     return localCoords1d;
   }
 
   void FE_Element::centroid(const DENS_MAT &eltCoords,
                                   DENS_VEC &centroid) const
   {
     centroid.reset(nSD_);
     for (int i = 0; i < nSD_; i++) {
       centroid(i) = eltCoords.row_mean(i);
     }
   }
  
   // -------------------------------------------------------------
   //  generic conversion from global to local coordinates using
   //  Newton's method to solve the nonliear equation that arises
   // -------------------------------------------------------------
   bool FE_Element::local_coordinates(const DENS_MAT &eltCoords,
                                      const DENS_VEC &x,
                                      DENS_VEC &xi) const
   {
     // initial guess
     DENS_VEC xiGuess(nSD_);
     this->initial_local_coordinates(eltCoords,x,xiGuess);
     // clip out-of-range guesses
     if (fabs(xiGuess(0)) > 1.0) xiGuess(0) = 0.;
     if (fabs(xiGuess(1)) > 1.0) xiGuess(1) = 0.;
     if (fabs(xiGuess(2)) > 1.0) xiGuess(2) = 0.;
     
     // iteratively solve the equation by calculating the global 
     // position of the guess and bringing the difference between it
     // and the actual global position of x to zero
     //
     // uses Newton's method
     DENS_VEC N(numNodes_);
     DENS_MAT dNdr(nSD_,numNodes_);
 
     DENS_VEC xGuess(nSD_);
     DENS_VEC xDiff(nSD_);
     DENS_MAT eltCoordsT = transpose(eltCoords);
     int count = 0;
     bool converged = false;
     while (count < localCoordinatesMaxIterations_) {
       feInterpolate_->compute_N_dNdr(xiGuess,N,dNdr);
       xGuess = N*eltCoordsT;
       xDiff  = xGuess-x; 
       // determine if the guess is close enough.
       // if it is, take it and run
       // if not, use Newton's method to update the guess
       if (!dbl_geq(abs(xDiff(0)),tolerance_) && 
           !dbl_geq(abs(xDiff(1)),tolerance_) && 
           !dbl_geq(abs(xDiff(2)),tolerance_)) {
         converged = true;
         xi = xiGuess;
         break;
       } else {
         xiGuess = xiGuess - transpose(inv(dNdr*eltCoordsT))*xDiff;
       }
       ++count;
     }
     return converged;
   }
 
   // -------------------------------------------------------------
   //  guess for initial local coordinates
   // -------------------------------------------------------------
   void FE_Element::initial_local_coordinates(const DENS_MAT &eltCoords,
                                              const DENS_VEC &x,
                                              DENS_VEC &xi) const
   {
     xi.reset(nSD_);
     if      (projectionGuess_ == COORDINATE_ALIGNED) {
       double min=0; double max=0;
       for (int i=0; i<nSD_; ++i) {
         bounds_in_dim(eltCoords,i,min,max);
         xi(i) = 2.0*(x(i)-min)/(max-min) - 1.0;
       }
     }
     else if (projectionGuess_ == CENTROID_LINEARIZED) { 
       DENS_VEC xi0(nSD_); xi0 = 0;
       DENS_VEC x0(nSD_), dx(nSD_);
       centroid(eltCoords,x0); 
       dx = x - x0; 
       vector<DENS_VEC> ts; ts.reserve(nSD_);
       tangents(eltCoords,xi0,ts);
       DENS_VEC & t1 = ts[0];
       DENS_VEC & t2 = ts[1];
       DENS_VEC & t3 = ts[2];
       double J = det3(t1.ptr(),t2.ptr(),t3.ptr());
       double J1 = det3(dx.ptr(),t2.ptr(),t3.ptr());
       double J2 = det3(t1.ptr(),dx.ptr(),t3.ptr());
       double J3 = det3(t1.ptr(),t2.ptr(),dx.ptr());
       xi(0) = J1/J;
       xi(1) = J2/J;
       xi(2) = J3/J;
     }
+    else if (projectionGuess_ == TWOD_ANALYTIC) { 
+      // assume x-y planar and HEX8
+      double x0 = x(0), y0 = x(1);
+      double X[4] = {eltCoords(0,0),eltCoords(0,1),eltCoords(0,2),eltCoords(0,3)};
+      double Y[4] = {eltCoords(1,0),eltCoords(1,1),eltCoords(1,2),eltCoords(1,3)};
+      double c[3]={0,0,0};
+      c[0] = y0*X[0] - y0*X[1] - y0*X[2] + y0*X[3] - x0*Y[0] + (X[1]*Y[0])*0.5 + (X[2]*Y[0])*0.5 + x0*Y[1] - (X[0]*Y[1])*0.5 - (X[3]*Y[1])*0.5 + x0*Y[2] - (X[0]*Y[2])*0.5 - (X[3]*Y[2])*0.5 - x0*Y[3] + (X[1]*Y[3])*0.5 + (X[2]*Y[3])*0.5;
+      c[1] = -(y0*X[0]) + y0*X[1] - y0*X[2] + y0*X[3] + x0*Y[0] - X[1]*Y[0] - x0*Y[1] + X[0]*Y[1] + x0*Y[2] - X[3]*Y[2] - x0*Y[3] + X[2]*Y[3];
+      c[1] = (X[1]*Y[0])*0.5 - (X[2]*Y[0])*0.5 - (X[0]*Y[1])*0.5 + (X[3]*Y[1])*0.5 + (X[0]*Y[2])*0.5 - (X[3]*Y[2])*0.5 - (X[1]*Y[3])*0.5 + (X[2]*Y[3])*0.5;
+      double xi2[2]={0,0};
+      int nroots = solve_quadratic(c,xi2);
+      if (nroots == 0) throw ATC_Error("no real roots in 2D analytic projection guess");
+      double xi1[2]={0,0};
+      xi1[0] = (4*x0 - X[0] + xi2[0]*X[0] - X[0] + xi2[0]*X[0] - X[0] - xi2[0]*X[0] - X[0] - xi2[0]*X[0])/(-X[0] + xi2[0]*X[0] + X[0] - xi2[0]*X[0] + X[0] + xi2[0]*X[0] - X[0] - xi2[0]*X[0]);
+      xi1[1] = (4*x0 - X[0] + xi2[0]*X[0] - X[0] + xi2[0]*X[0] - X[0] - xi2[0]*X[0] - X[0] - xi2[0]*X[0])/(-X[0] + xi2[0]*X[0] + X[0] - xi2[0]*X[0] + X[0] + xi2[0]*X[0] - X[0] - xi2[0]*X[0]);
+      // choose which one gives back x
+      xi(0) = xi1[0]; 
+      xi(1) = xi2[0]; 
+      xi(2) = 0; 
+    }
   }
 
  
   bool FE_Element::range_check(const DENS_MAT &eltCoords,
                                const DENS_VEC &x) const
   {
     double min=0; double max=0;
     for (int i=0; i<nSD_; ++i) {
       bounds_in_dim(eltCoords,i,min,max);
       if (!dbl_geq(x(i),min) || !dbl_geq(max,x(i))) return false;
     }
     return true;
   }
 
 
   // -------------------------------------------------------------
   //   Note: Only works for convex elements with planar faces with 
   //   outward normals
   // -------------------------------------------------------------
   bool FE_Element::contains_point(const DENS_MAT &eltCoords,
                                   const DENS_VEC &x) const
   {
     if (! range_check(eltCoords,x) ) return false;
     DENS_MAT faceCoords;
     DENS_VEC normal;
     normal.reset(nSD_);
     DENS_VEC faceToPoint;
     double dot;
     bool inside = true;
     for (int faceID=0; faceID<numFaces_; ++faceID) {
       face_coordinates(eltCoords, faceID, faceCoords);
       feInterpolate_->face_normal(faceCoords, 
                                   0,
                                   normal);
       faceToPoint = x - column(faceCoords, 0);
       dot = normal.dot(faceToPoint);
       if (dbl_geq(dot,0)) {
         inside = false;
         break;
       }
     }
     return inside;
   }
 
   // -------------------------------------------------------------
   //   returns the minimum and maximum values of an element in the
   //   specified dimension
   // -------------------------------------------------------------
   void FE_Element::bounds_in_dim(const DENS_MAT &eltCoords, const int dim,
                                  double &min, double &max) const
   {
     int it;
     // iterate over all nodes
     min = eltCoords(dim,0);
     it = 1;
     while (it < numNodes_) {
       if (dbl_geq(min,eltCoords(dim,it))) {
         if (dbl_geq(eltCoords(dim,it),min)) {
           ++it;
         } else {
           // set min to this node's coord in the specified dim, if it's 
           // smaller than the value previously stored 
           min = eltCoords(dim,it);
         }
       } else {
         ++it;
       }
     }
     max = eltCoords(dim,0);
     it = 1;
     while (it < numNodes_) {
       if (dbl_geq(max,eltCoords(dim,it))) {
         ++it;
       } else {
         // same, except max/larger
         max = eltCoords(dim,it);
       }
     }
   }
   
   // -------------------------------------------------------------
   //   shape_function calls should stay generic at all costs
   // -------------------------------------------------------------
   void FE_Element::shape_function(const VECTOR &xi,
                                   DENS_VEC &N) const
   {
     feInterpolate_->shape_function(xi, N);
   }
 
   void FE_Element::shape_function(const DENS_MAT eltCoords,
                                   const VECTOR &x,
                                   DENS_VEC &N)
   {
     DENS_VEC xi;
     local_coordinates(eltCoords, x, xi);
 
     feInterpolate_->shape_function(xi, N);
   }
 
   void FE_Element::shape_function(const DENS_MAT eltCoords,
                                   const VECTOR &x,
                                   DENS_VEC &N,
                                   DENS_MAT &dNdx)
   {
     DENS_VEC xi;
     local_coordinates(eltCoords, x, xi);
 
     feInterpolate_->shape_function(eltCoords, xi, N, dNdx);
   }  
 
   void FE_Element::shape_function_derivatives(const DENS_MAT eltCoords,
                                   const VECTOR &x,
                                   DENS_MAT &dNdx)
   {
     DENS_VEC xi;
     local_coordinates(eltCoords, x, xi);
 
     feInterpolate_->shape_function_derivatives(eltCoords, xi, dNdx);
   }  
 
 
   void FE_Element::shape_function(const DENS_MAT eltCoords,
                                   DENS_MAT &N,
                                   vector<DENS_MAT> &dN,
                                   DIAG_MAT &weights)
   {
     feInterpolate_->shape_function(eltCoords, N, dN, weights);
   }
 
   void FE_Element::face_shape_function(const DENS_MAT &eltCoords,
                                        const int faceID,
                                        DENS_MAT &N,
                                        DENS_MAT &n,
                                        DIAG_MAT &weights)
   {
     DENS_MAT faceCoords;
     face_coordinates(eltCoords, faceID, faceCoords); 
     
     feInterpolate_->face_shape_function(eltCoords, faceCoords, faceID,
                                         N, n, weights);
   }
 
   void FE_Element::face_shape_function(const DENS_MAT &eltCoords,
                                        const int faceID,
                                        DENS_MAT &N,
                                        vector<DENS_MAT> &dN,
                                        vector<DENS_MAT> &Nn,
                                        DIAG_MAT &weights)
   {
     DENS_MAT faceCoords;
     face_coordinates(eltCoords, faceID, faceCoords); 
     
     feInterpolate_->face_shape_function(eltCoords, faceCoords, faceID,
                                         N, dN, Nn, weights);
   }
 
   double FE_Element::face_normal(const DENS_MAT &eltCoords,
                                  const int faceID,
                                  int ip,
                                  DENS_VEC &normal) 
   {
     DENS_MAT faceCoords;
     face_coordinates(eltCoords, faceID, faceCoords);
 
     double J = feInterpolate_->face_normal(faceCoords, ip, normal);
     return J;
   }
 
   void FE_Element::tangents(const DENS_MAT &eltCoords,
                             const DENS_VEC & localCoords,
                             vector<DENS_VEC> &tangents,
                             const bool normalize)  const
   {
     feInterpolate_->tangents(eltCoords,localCoords,tangents,normalize);
   }
   
   
   // =============================================================
   //   class FE_ElementHex
   // =============================================================
   FE_ElementHex::FE_ElementHex(int numNodes, 
                                int numFaceNodes,
                                int numNodes1d)
     : FE_Element(3,                 // number of spatial dimensions
                  6,                 // number of faces
                  numNodes,
                  numFaceNodes,
                  numNodes1d)
   {
     //       3 --- 2
     //      /|    /|
     //     / 0 --/ 1     y
     //    7 --- 6 /      |
     //    |     |/       |
     //    4 --- 5         -----x
     //                  /
     //                 /
     //                z
   
     // Basic properties of element:
     vol_ = 8.0;
     faceArea_ = 4.0;
     
     // Order-specific information:
     if (numNodes != 8  &&
         numNodes != 20 &&
         numNodes != 27) {
       throw ATC_Error("Unrecognized interpolation order specified " 
                       "for element class: \n"                       
                       "  element only knows how to construct lin "  
                         "and quad elments.");
     }
 
     localCoords_.resize(nSD_,numNodes_);
     localFaceConn_ = Array2D<int>(numFaces_,numFaceNodes_);
     
     // Matrix of local nodal coordinates
     localCoords_(0,0) = -1; localCoords_(0,4) = -1; 
     localCoords_(1,0) = -1; localCoords_(1,4) = -1; 
     localCoords_(2,0) = -1; localCoords_(2,4) =  1;
     // 
     localCoords_(0,1) =  1; localCoords_(0,5) =  1; 
     localCoords_(1,1) = -1; localCoords_(1,5) = -1; 
     localCoords_(2,1) = -1; localCoords_(2,5) =  1;
     //
     localCoords_(0,2) =  1; localCoords_(0,6) =  1; 
     localCoords_(1,2) =  1; localCoords_(1,6) =  1; 
     localCoords_(2,2) = -1; localCoords_(2,6) =  1;
     //
     localCoords_(0,3) = -1; localCoords_(0,7) = -1; 
     localCoords_(1,3) =  1; localCoords_(1,7) =  1; 
     localCoords_(2,3) = -1; localCoords_(2,7) =  1;
     if (numNodes >= 20) {
       // only for quads
       localCoords_(0,8) =  0;  localCoords_(0,14) =  1; 
       localCoords_(1,8) = -1;  localCoords_(1,14) =  1; 
       localCoords_(2,8) = -1;  localCoords_(2,14) =  0;
       // 
       localCoords_(0,9) =  1;  localCoords_(0,15) = -1; 
       localCoords_(1,9) =  0;  localCoords_(1,15) =  1; 
       localCoords_(2,9) = -1;  localCoords_(2,15) =  0;
       //
       localCoords_(0,10) =  0; localCoords_(0,16) =  0; 
       localCoords_(1,10) =  1; localCoords_(1,16) = -1; 
       localCoords_(2,10) = -1; localCoords_(2,16) =  1;
       //
       localCoords_(0,11) = -1; localCoords_(0,17) =  1; 
       localCoords_(1,11) =  0; localCoords_(1,17) =  0; 
       localCoords_(2,11) = -1; localCoords_(2,17) =  1;
       //
       localCoords_(0,12) = -1; localCoords_(0,18) =  0; 
       localCoords_(1,12) = -1; localCoords_(1,18) =  1; 
       localCoords_(2,12) =  0; localCoords_(2,18) =  1;
       //
       localCoords_(0,13) =  1; localCoords_(0,19) = -1; 
       localCoords_(1,13) = -1; localCoords_(1,19) =  0; 
       localCoords_(2,13) =  0; localCoords_(2,19) =  1;
       if (numNodes >= 27) {
         // only for quads
         localCoords_(0,20) =  0; localCoords_(0,24) =  1; 
         localCoords_(1,20) =  0; localCoords_(1,24) =  0; 
         localCoords_(2,20) =  0; localCoords_(2,24) =  0;
         //
         localCoords_(0,21) =  0; localCoords_(0,25) =  0; 
         localCoords_(1,21) =  0; localCoords_(1,25) = -1; 
         localCoords_(2,21) = -1; localCoords_(2,25) =  0;
         //
         localCoords_(0,22) =  0; localCoords_(0,26) =  0; 
         localCoords_(1,22) =  0; localCoords_(1,26) =  1; 
         localCoords_(2,22) =  1; localCoords_(2,26) =  0;
         //
         localCoords_(0,23) = -1; 
         localCoords_(1,23) =  0; 
         localCoords_(2,23) =  0;
       }
     }
 
     // Matrix of local face connectivity
     // -x                    // +x
     localFaceConn_(0,0) = 0; localFaceConn_(1,0) = 1; 
     localFaceConn_(0,1) = 4; localFaceConn_(1,1) = 2; 
     localFaceConn_(0,2) = 7; localFaceConn_(1,2) = 6; 
     localFaceConn_(0,3) = 3; localFaceConn_(1,3) = 5; 
     if (numNodes >= 20) {
       localFaceConn_(0,4) = 12; localFaceConn_(1,4) = 9; 
       localFaceConn_(0,5) = 19; localFaceConn_(1,5) = 14; 
       localFaceConn_(0,6) = 15; localFaceConn_(1,6) = 17; 
       localFaceConn_(0,7) = 11; localFaceConn_(1,7) = 13; 
       if (numNodes >= 27) {
         localFaceConn_(0,8) = 23; localFaceConn_(1,8) = 24;
       }
     }
 
     // -y                    // +y
     localFaceConn_(2,0) = 0; localFaceConn_(3,0) = 3; 
     localFaceConn_(2,1) = 1; localFaceConn_(3,1) = 7; 
     localFaceConn_(2,2) = 5; localFaceConn_(3,2) = 6; 
     localFaceConn_(2,3) = 4; localFaceConn_(3,3) = 2; 
     if (numNodes >= 20) {
       localFaceConn_(2,4) = 8;  localFaceConn_(3,4) = 15; 
       localFaceConn_(2,5) = 13; localFaceConn_(3,5) = 18; 
       localFaceConn_(2,6) = 16; localFaceConn_(3,6) = 14; 
       localFaceConn_(2,7) = 12; localFaceConn_(3,7) = 10; 
       if (numNodes >= 27) {
         localFaceConn_(2,8) = 25; localFaceConn_(3,8) = 26;
       }
     }
  
     // -z                    // +z
     localFaceConn_(4,0) = 0; localFaceConn_(5,0) = 4; 
     localFaceConn_(4,1) = 3; localFaceConn_(5,1) = 5; 
     localFaceConn_(4,2) = 2; localFaceConn_(5,2) = 6; 
     localFaceConn_(4,3) = 1; localFaceConn_(5,3) = 7; 
     if (numNodes >= 20) {
       localFaceConn_(4,4) = 8;  localFaceConn_(5,4) = 16; 
       localFaceConn_(4,5) = 11; localFaceConn_(5,5) = 17; 
       localFaceConn_(4,6) = 10; localFaceConn_(5,6) = 18; 
       localFaceConn_(4,7) = 9;  localFaceConn_(5,7) = 19; 
       if (numNodes >= 27) {
         localFaceConn_(4,8) = 21; localFaceConn_(5,8) = 22;
       }
     }
 
     if (numNodes == 8) {
       feInterpolate_ = new FE_InterpolateCartLin(this);
     } else if (numNodes == 20) {
       feInterpolate_ = new FE_InterpolateCartSerendipity(this);
     } else if (numNodes == 27) {
       feInterpolate_ = new FE_InterpolateCartLagrange(this);
     }
 
     // determine alignment and skewness to see which guess we should use
     
   }
 
   FE_ElementHex::~FE_ElementHex()
   {
     // Handled by base class
   }
 
   void FE_ElementHex::set_quadrature(FeIntQuadrature type) 
   { 
     feInterpolate_->set_quadrature(HEXA,type);
   }
   
   bool FE_ElementHex::contains_point(const DENS_MAT &eltCoords,
                                      const DENS_VEC &x) const
   {
     if (! range_check(eltCoords,x) ) return false;
 
     DENS_VEC xi;
     bool converged = local_coordinates(eltCoords,x,xi); 
     if (!converged) return false;
     for (int i=0; i<nSD_; ++i) {
       if (!dbl_geq(1.0,abs(xi(i)))) return false;
     }
     return true;
   }
 
   // =============================================================
   //   class FE_ElementRect
   // =============================================================
   FE_ElementRect::FE_ElementRect()
     : FE_ElementHex(8,4,2)
   {
     // Handled by hex class
   }
 
   FE_ElementRect::~FE_ElementRect()
   {
     // Handled by base class
   }
 
   bool FE_ElementRect::contains_point(const DENS_MAT &eltCoords,
                                       const DENS_VEC &x) const
   {
     return range_check(eltCoords,x);
   }
 
   // much faster than the unstructured method
   bool FE_ElementRect::local_coordinates(const DENS_MAT &eltCoords,
                                          const DENS_VEC &x,
                                          DENS_VEC &xi) const
   {
     xi.reset(nSD_);
     double min = 0.0;
     double max = 0.0;
     for (int iSD=0; iSD<nSD_; ++iSD) {
       min = eltCoords(iSD,0);
       max = eltCoords(iSD,6);
       xi(iSD) = 2.0*(x(iSD)-min)/(max-min) - 1.0;
     }
     return true;
   }
   
 
   // =============================================================
   //   class FE_ElementTet
   // =============================================================
   FE_ElementTet::FE_ElementTet(int numNodes,
                                int numFaceNodes,
                                int numNodes1d)
     : FE_Element(3,                 // number of spatial dimensions
                  4,                 // number of faces
                  numNodes,
                  numFaceNodes,
                  numNodes1d)
   {
     // t
     // ^
     // |
     // |
     //                          s
     // 3                     .7
     // |\```---           .
     // |  \     ```--2 .
     // |    \       .| 
     // |      \  .   |
     // |      . \    |
     // |   .      \  |
     // |.___________\|  -------> r
     // 0             1  
     //
     // (This is as dictated by the EXODUSII standard.)
     //
     // The face opposite point 1 has r = 0,
     //                         2 has s = 0,
     //                         3 has t = 0,
     //                         0 has u = 0.
 
     // Basic properties of element:
     vol_ = 1.0/6.0; // local volume
     faceArea_ = 1.0/2.0;
  
     // Order-specific information:
     if (numNodes != 4 && numNodes != 10) {
       throw ATC_Error("Unrecognized interpolation order specified " 
                       "for element class: \n"                       
                       "  element only knows how to construct lin "  
                         "and quad elments.");
     }
     
     localCoords_.resize(nSD_+1, numNodes_);
     localFaceConn_ = Array2D<int>(numFaces_,numFaceNodes_);
     
     // Matrix of local nodal coordinates
     //
     // Remember, there's actually another coordinate too (u), coming
     // out from the third non-normal face. But we can deal with it on
     // the fly; these coordinates are barycentric, such that
     // r + s + t + u = 1 always. As such we only need to deal with r,
     // s, and t and the computations become easy.
     //
     // The first three axes correspond to x, y, and z (essentially),
     // for the canonical element.
     
     // Everyone gets these nodes...
     localCoords_(0,0) = 0; localCoords_(0,2) = 0;
     localCoords_(1,0) = 0; localCoords_(1,2) = 1; 
     localCoords_(2,0) = 0; localCoords_(2,2) = 0;
     localCoords_(3,0) = 1; localCoords_(3,2) = 0;
     //
     localCoords_(0,1) = 1; localCoords_(0,3) = 0; 
     localCoords_(1,1) = 0; localCoords_(1,3) = 0; 
     localCoords_(2,1) = 0; localCoords_(2,3) = 1; 
     localCoords_(3,1) = 0; localCoords_(3,3) = 0;
     if (numNodes >= 10) {
       // ...quads get even more!
       localCoords_(0,4) = 0.5; localCoords_(0,5) = 0.5;
       localCoords_(1,4) = 0.0; localCoords_(1,5) = 0.5; 
       localCoords_(2,4) = 0.0; localCoords_(2,5) = 0.0;
       localCoords_(3,4) = 0.5; localCoords_(3,5) = 0.0;
       //
       localCoords_(0,6) = 0.0; localCoords_(0,7) = 0.0; 
       localCoords_(1,6) = 0.5; localCoords_(1,7) = 0.0; 
       localCoords_(2,6) = 0.0; localCoords_(2,7) = 0.5; 
       localCoords_(3,6) = 0.5; localCoords_(3,7) = 0.5;
       //
       localCoords_(0,8) = 0.5; localCoords_(0,9) = 0.0; 
       localCoords_(1,8) = 0.0; localCoords_(1,9) = 0.5; 
       localCoords_(2,8) = 0.5; localCoords_(2,9) = 0.5; 
       localCoords_(3,8) = 0.0; localCoords_(3,9) = 0.0;
     }
   
     // Matrix of local face connectivity:
     // ...opposite point 0,     ...opposite point 2, 
     localFaceConn_(0,0) = 1; localFaceConn_(2,0) = 0;
     localFaceConn_(0,1) = 2; localFaceConn_(2,1) = 1;
     localFaceConn_(0,2) = 3; localFaceConn_(2,2) = 3;
    
     // ...opposite point 1,     ...opposite point 3.
     localFaceConn_(1,0) = 2; localFaceConn_(3,0) = 0; 
     localFaceConn_(1,1) = 0; localFaceConn_(3,1) = 2; 
     localFaceConn_(1,2) = 3; localFaceConn_(3,2) = 1; 
 
     feInterpolate_ = new FE_InterpolateSimpLin(this);
   }
 
   FE_ElementTet::~FE_ElementTet()
   {
     // Handled by base class
   }
 
   void FE_ElementTet::set_quadrature(FeIntQuadrature type) 
   { 
     feInterpolate_->set_quadrature(TETRA,type);
   }
 
   bool FE_ElementTet::local_coordinates(const DENS_MAT &eltCoords,
                                         const DENS_VEC &x,
                                         DENS_VEC &xi) const
   {
     DENS_MAT T(nSD_, numNodes_-1);
     DENS_VEC r(nSD_);
     for (int iSD=0; iSD<nSD_; ++iSD) {
       for (int inode=1; inode<numNodes_; ++inode) {
         T(iSD, inode-1) = eltCoords(iSD, inode) -
                           eltCoords(iSD, 0);
       }
       r(iSD) = x(iSD) - eltCoords(iSD, 0);
     }
     MultMv(inv(T), r, xi, false, 1.0, 0.0);
     return true;
   }
 
   bool FE_ElementTet::contains_point(const DENS_MAT &eltCoords,
                                      const DENS_VEC &x) const
   {
     if (! range_check(eltCoords,x) ) return false;
     DENS_VEC xi(nSD_);
     bool converged = local_coordinates(eltCoords, x, xi);
     if (! converged) return false;
     double sum = 0.0;
     bool inside = true;
     for (int iSD = 0; iSD < nSD_; ++iSD) {
       if (dbl_geq(xi(iSD),1.0) || dbl_geq(0.0,xi(iSD))) {
         inside = false;
         break;
       }
       sum += xi(iSD);
     }
     if (dbl_geq(sum,1.0)) inside = false;
     return inside;
   }
 
 
 }; // namespace ATC
diff --git a/lib/atc/FE_Engine.cpp b/lib/atc/FE_Engine.cpp
index a87a03032..4b519e336 100644
--- a/lib/atc/FE_Engine.cpp
+++ b/lib/atc/FE_Engine.cpp
@@ -1,2713 +1,2975 @@
 #include "FE_Engine.h"
 
 #include "ATC_Transfer.h"
 #include "FE_Element.h"
 #include "Function.h"
 #include "PhysicsModel.h"
 #include "KernelFunction.h"
 #include "Utility.h"
 #include "MPI_Wrappers.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <map>
 #include <string>
 
 
 
 
 
 using namespace std;
 using ATC_Utility::is_numeric;
 using ATC_Utility::to_string;;
 using MPI_Wrappers::allsum;
 using MPI_Wrappers::int_allsum;
 using MPI_Wrappers::rank_zero;
 using MPI_Wrappers::print_msg;
 using MPI_Wrappers::print_msg_once;
 
 namespace ATC{
 
   static const double tol_sparse = 1.e-30;//tolerance for compaction from dense
 
   //-----------------------------------------------------------------
   FE_Engine::FE_Engine(MPI_Comm comm)
     : communicator_(comm),
       feMesh_(NULL),
       initialized_(false),
       outputManager_()
   {
     // Nothing to do here
   }
   
   //-----------------------------------------------------------------
   FE_Engine::~FE_Engine()
   {
     if (feMesh_) delete feMesh_;
   }
   //-----------------------------------------------------------------
   
   void FE_Engine::initialize()
   {
     if (!feMesh_) throw ATC_Error("FE_Engine has no mesh");
 
     if (!initialized_) {
       // set up work spaces
       nNodesPerElement_ = feMesh_->num_nodes_per_element();
       nIPsPerElement_ = feMesh_->num_ips_per_element();
       nIPsPerFace_ = feMesh_->num_ips_per_face();
       nSD_ = feMesh_->num_spatial_dimensions();
       nElems_ = feMesh_->num_elements();
       nNodesUnique_ = feMesh_->num_nodes_unique();
       nNodes_ = feMesh_->num_nodes();
     
       // arrays & matrices
       _weights_.reset(nIPsPerElement_,nIPsPerElement_);
       _N_.reset(nIPsPerElement_,nNodesPerElement_);
       _dN_.assign(nSD_, DENS_MAT(nIPsPerElement_,nNodesPerElement_));
       _Nw_.reset(nIPsPerElement_,nNodesPerElement_);
       _dNw_.assign(nSD_, DENS_MAT(nIPsPerElement_,nNodesPerElement_));
       _Bfluxes_.assign(nSD_, DENS_MAT());
       // faces
       _fweights_.reset(nIPsPerElement_,nIPsPerElement_);
       _fN_.reset(nIPsPerFace_,nNodesPerElement_); 
       _fdN_.assign(nSD_, DENS_MAT(nIPsPerFace_, nNodesPerElement_));
       _nN_.assign(nSD_, DENS_MAT(nIPsPerFace_, nNodesPerElement_));
 
       // remove specified elements
       if (nullElements_.size() > 0) delete_elements(nullElements_);
  
       initialized_ = true;
     }
   }
 
   void FE_Engine::partition_mesh()
   {
     if (is_partitioned()) return;
 
     feMesh_->partition_mesh();  
     
     // now do all FE_Engine data structure partitioning
 
     // partition nullElements_
-    /*for (vector<int>::const_iterator elemsIter = feMesh_->processor_elts().begin();
+    /*for (vector<int>::iterator elemsIter = feMesh_->processor_elts().begin();
          elemsIter != feMesh_->processor_elts().end();
          ++elemsIter)
     {
       if (nullElements_.find(*elemsIter) != nullElements_.end()) {
         myNullElements_.insert(map_elem_to_myElem(*elemsIter));
       }
     }*/
   }
 
   void FE_Engine::departition_mesh()
   {
     if (!is_partitioned()) return;
 
     feMesh_->departition_mesh();
   }
 
   void FE_Engine::set_quadrature(FeIntQuadrature type, bool temp) const
   {
     if (!feMesh_) throw ATC_Error("FE_Engine has no mesh");
 
     feMesh_->set_quadrature(type);
     if (!temp) quadrature_ = type;
 
     int nIPsPerElement_new = feMesh_->num_ips_per_element();
     int nIPsPerFace_new = feMesh_->num_ips_per_face();
   
     if (nIPsPerElement_ != nIPsPerElement_new) {
       // arrays & matrices
       nIPsPerElement_ = nIPsPerElement_new;
       _weights_.resize(nIPsPerElement_,nIPsPerElement_);
       _N_.resize(nIPsPerElement_,nNodesPerElement_);
       _dN_.assign(nSD_, DENS_MAT(nIPsPerElement_,nNodesPerElement_));
       _Nw_.reset(nIPsPerElement_,nNodesPerElement_);
       _dNw_.assign(nSD_, DENS_MAT(nIPsPerElement_,nNodesPerElement_));
     }
     if (nIPsPerFace_ != nIPsPerFace_new) {
       // faces
       nIPsPerFace_ = nIPsPerFace_new;
       _fweights_.reset(nIPsPerElement_,nIPsPerElement_);
       _fN_.reset(nIPsPerFace_,nNodesPerElement_); 
       _fdN_.assign(nSD_, DENS_MAT(nIPsPerFace_, nNodesPerElement_));
       _nN_.assign(nSD_, DENS_MAT(nIPsPerFace_, nNodesPerElement_));
     }
     
   }
 
   //-----------------------------------------------------------------
   bool FE_Engine::modify(int narg, char **arg)
   {
     bool match = false;
     /*! \page man_mesh_create fix_modify AtC mesh create
       \section syntax
       fix_modify AtC mesh create <nx> <ny> <nz> <region-id> 
       <f|p> <f|p> <f|p> \n
       - nx ny nz = number of elements in x, y, z
       - region-id = id of region that is to be meshed
       - f p p = periodicity flags for x, y, z
       \section examples
       <TT> fix_modify AtC mesh create 10 1  1  feRegion p p p </TT> \n
       \section description
       Creates a uniform mesh in a rectangular region
       \section restrictions
       Creates only uniform rectangular grids in a rectangular region
       \section related
       \ref man_mesh_quadrature
       \section default
       When created, mesh defaults to gauss2 (2-point Gaussian) quadrature. 
       Use "mesh quadrature" command to change quadrature style.
     */
     int argIdx = 0;
     if (strcmp(arg[argIdx],"mesh")==0) { 
       argIdx++;
       // create mesh
       if (strcmp(arg[argIdx],"create")==0) {
         if (feMesh_) throw ATC_Error("FE Engine already has a mesh");
         argIdx++;
         int nx = atoi(arg[argIdx++]);
         int ny = atoi(arg[argIdx++]);
         int nz = atoi(arg[argIdx++]);
         string box = arg[argIdx++];
 
         Array<bool> periodicity(3);
         periodicity(0) = (strcmp(arg[argIdx++],"p")==0) ? true : false; 
         periodicity(1) = (strcmp(arg[argIdx++],"p")==0) ? true : false;
         periodicity(2) = (strcmp(arg[argIdx++],"p")==0) ? true : false;
 
         if (argIdx < narg ) {
           Array<double> dx(nx),dy(ny),dz(nz);
 
           dx = 0;
           dy = 0;
           dz = 0;
-          double x[3] = {0,0,0}; 
           while (argIdx < narg) {
-            if      (strcmp(arg[argIdx++],"dx")==0) {
-              // parse relative values for each element
-              if (is_numeric(arg[argIdx])) {
-                for (int i = 0; i < nx; ++i) { 
-                  if (is_numeric(arg[argIdx])) { dx(i) = atof(arg[argIdx++]); }
-                  else throw ATC_Error("not enough element partitions");
-                }
-              }
-              // construct relative values from a density function
-              // evaluate for a domain (0,1)
-              else {
-                XT_Function * f = XT_Function_Mgr::instance()->function(&(arg[argIdx]),narg-argIdx);
-                for (int i = 0; i < nx; ++i) { 
-                  x[0] = (i+0.5)/nx; dx(i) = f->f(x,0.); 
-                }
-              }
-
-
-              break ;
+            if      (strcmp(arg[argIdx],"dx")==0) {
+              parse_partitions(++argIdx, narg, arg, 0, dx);
             }
-            else if (strcmp(arg[argIdx++],"dy")==0) {
-              for (int i = 0; i < ny; ++i) { dy(i) = atof(arg[argIdx++]); }
+            else if (strcmp(arg[argIdx],"dy")==0) {
+              parse_partitions(++argIdx, narg, arg, 1, dy);
             }
-            else if (strcmp(arg[argIdx++],"dz")==0) {
-              for (int i = 0; i < nz; ++i) { dz(i) = atof(arg[argIdx++]); }
+            else if (strcmp(arg[argIdx],"dz")==0) {
+              parse_partitions(++argIdx, narg, arg, 2, dz);
             }
           }
 
           create_mesh(dx, dy, dz, box.c_str(), periodicity);
         }
         else  {
           create_mesh(nx, ny, nz, box.c_str(), periodicity);
         }
         quadrature_ = GAUSS2;
         match = true;
       }
     /*! \page man_mesh_quadrature fix_modify AtC mesh quadrature
       \section syntax
       fix_modify AtC mesh quadrature <quad>
       - quad = one of <nodal|gauss1|gauss2|gauss3|face> --- when a mesh is created it defaults to gauss2, use this call to change it after the fact
       \section examples
       <TT> fix_modify AtC mesh quadrature face </TT>
       \section description
       (Re-)assigns the quadrature style for the existing mesh.
       \section restrictions
       \section related
       \ref man_mesh_create
       \section default
       none 
     */
       else if (strcmp(arg[argIdx],"quadrature")==0) {
         argIdx++;
         string quadStr = arg[argIdx];
         FeIntQuadrature quadEnum = string_to_FIQ(quadStr);
         set_quadrature(quadEnum);
         match = true;
       }
     /*! \page man_mesh_read fix_modify AtC mesh read 
       \section syntax
       fix_modify AtC mesh read <filename> <f|p> <f|p> <f|p> 
       - filename = name of file containing mesh to be read 
       - f p p = periodicity flags for x, y, z
       \section examples
       <TT> fix_modify AtC mesh read myComponent.mesh p p p </TT> \n
       <TT> fix_modify AtC mesh read myOtherComponent.exo </TT>
       \section description
       Reads a mesh from a text or exodus file, and assigns periodic
       boundary conditions if needed. 
       \section restrictions
       \section related
       \section default
       periodicity flags are false by default 
     */
       else if (strcmp(arg[argIdx],"read")==0) {
         argIdx++;
         string meshFile = arg[argIdx++];
         
         Array<bool> periodicity(3);
         periodicity = false;
         if (argIdx < narg)  {
           periodicity(0) = (strcmp(arg[argIdx++],"p")==0) ? true : false; 
           periodicity(1) = (strcmp(arg[argIdx++],"p")==0) ? true : false;
           periodicity(2) = (strcmp(arg[argIdx++],"p")==0) ? true : false;
         }
         read_mesh(meshFile,periodicity);
 
         if (periodicity(0) || periodicity(1) || periodicity(2)) {
           meshFile = "periodic_"+meshFile;
           stringstream ss; 
           ss << "writing periodicity corrected mesh: " << meshFile;
           print_msg(communicator_,ss.str());
           feMesh_->write_mesh(meshFile);
           feMesh_->output(meshFile);
         }
         match = true;
       }
     /*! \page man_mesh_write fix_modify AtC mesh write 
       \section syntax
       fix_modify AtC mesh write <filename> 
       - filename = name of file to write mesh
       \section examples
       <TT> fix_modify AtC mesh write myMesh.mesh </TT> \n
       \section description
       Writes a mesh to a text file. 
       \section restrictions
       \section related
       \section default
     */
       else if (strcmp(arg[argIdx],"write")==0) {
         argIdx++;
         string meshFile = arg[argIdx];
         feMesh_->write_mesh(meshFile);
         match = true;
       }
       /*! \page man_mesh_delete_elements fix_modify AtC mesh delete_elements
         \section syntax
         fix_modify AtC mesh delete_elements <element_set>
         - <element_set> = name of an element set
         \section examples
         <TT> fix_modify AtC delete_elements gap </TT>
         \section description
         Deletes a group of elements from the mesh.
         \section restrictions
         \section related
         \section default
         none
       */
       else if (strcmp(arg[argIdx],"delete_elements")==0) {
         argIdx++;
         string esetName = arg[argIdx];
         set<int> elemSet = feMesh_->elementset(esetName);
         nullElements_.insert(elemSet.begin(), elemSet.end());
         match = true;
       }
       else if (strcmp(arg[argIdx],"cut")==0) {
         argIdx++;
         string fsetName = arg[argIdx++];
         set<PAIR> faceSet = feMesh_->faceset(fsetName);
         cutFaces_.insert(faceSet.begin(), faceSet.end());
         if (narg > argIdx && strcmp(arg[argIdx],"edge")==0) {
           argIdx++;
           string nsetName = arg[argIdx];
           set<int> nodeSet = feMesh_->nodeset(nsetName);
           cutEdge_.insert(nodeSet.begin(), nodeSet.end());
         }
         // cut mesh
         if (cutFaces_.size() > 0) cut_mesh(cutFaces_,cutEdge_);
 
         match = true;
       }
       else if (strcmp(arg[argIdx],"lammps_partition")==0) {
         feMesh_->set_lammps_partition(true);
         match = true;
       }
       else if (strcmp(arg[argIdx],"data_decomposition")==0) {
         feMesh_->set_data_decomposition(true);
         match = true;
       }
       else {
         if ( ! feMesh_ ) throw ATC_Error("need mesh for parsing");
         match = feMesh_->modify(narg,arg);
       }
     }
     // FE_Mesh
     else {
       if ( ! feMesh_ ) throw ATC_Error("need mesh for parsing");
       match = feMesh_->modify(narg,arg);
     }
     return match;
   }
+  //-----------------------------------------------------------------
+  void FE_Engine::parse_partitions(int & argIdx, int narg, char ** arg, 
+    int idof, Array<double> & dx ) const
+  {
+    double x[3] = {0,0,0}; 
+    int nx = dx.size();
+    // parse relative values for each element
+    if (is_numeric(arg[argIdx])) {
+      for (int i = 0; i < nx; ++i) { 
+        if (is_numeric(arg[argIdx])) { dx(i) = atof(arg[argIdx++]); }
+        else throw ATC_Error("not enough element partitions");
+      }
+    }
+    // each segment of the piecewise funcion is length-normalized separately
+    else if (strcmp(arg[argIdx],"position-number-density")==0) { 
+      argIdx++;
+      double y[nx],w[nx];
+      int n[nx];
+      int nn = 0;
+      while (argIdx < narg) { 
+        if (! is_numeric(arg[argIdx])) break;
+        y[nn]   = atof(arg[argIdx++]);
+        n[nn]   = atoi(arg[argIdx++]);
+        w[nn++] = atof(arg[argIdx++]);
+      }
+      if (n[nn-1] != nx)  throw ATC_Error("total element partitions do not match");
+      int k = 0;
+      for (int i = 1; i < nn; ++i) { 
+        int dn = n[i]-n[i-1];
+        double dy = y[i]-y[i-1];
+        double w0 = w[i-1];
+        double dw = w[i]-w0;
+        double lx = 0;
+        double l[dn];
+        for (int j = 0; j < dn; ++j) {
+          double x = (j+0.5)/dn; 
+          double dl = w0+x*dw;
+          lx += dl;
+          l[j]= dl;
+        }
+        double scale = dy/lx;
+        for (int j = 0; j < dn; ++j) {
+          dx(k++) = scale*l[j];
+        }
+      }
+    }
+    // construct relative values from a density function
+    // evaluate for a domain (0,1)
+    else {
+      XT_Function * f = XT_Function_Mgr::instance()->function(&(arg[argIdx]),narg-argIdx);
+      argIdx++;
+      while (argIdx < narg) { 
+        if (! is_numeric(arg[argIdx++])) break;
+      }
+      for (int i = 0; i < nx; ++i) { 
+        x[idof] = (i+0.5)/nx; dx(i) = f->f(x,0.); 
+      }
+    }
+  }
 
   //-----------------------------------------------------------------
   void FE_Engine::finish()
   {
     // Nothing to do
   }
 
   //-----------------------------------------------------------------
   //  write geometry
   //-----------------------------------------------------------------
   void FE_Engine::initialize_output(int rank,
     string outputPrefix, set<int> otypes)
   {
     outputManager_.initialize(outputPrefix, otypes);
     if (!feMesh_) throw ATC_Error("output needs mesh");
     if (!initialized_) initialize();
     if (!feMesh_->coordinates() || !feMesh_->connectivity()) 
       throw ATC_Error("output mesh not properly initialized");
     if (!feMesh_->coordinates()->nCols() || 
         !feMesh_->connectivity()->nCols()) 
       throw ATC_Error("output mesh is empty");
     if (rank == 0) 
       outputManager_.write_geometry(feMesh_->coordinates(), 
                                     feMesh_->connectivity());
      outputManager_.print_custom_names();
   }
 
   //-----------------------------------------------------------------
   //  write geometry
   //-----------------------------------------------------------------
   void FE_Engine::write_geometry(void)
   {
     outputManager_.write_geometry(feMesh_->coordinates(), 
                                   feMesh_->connectivity());
   }
 
   // -------------------------------------------------------------
   //  write data  
   // -------------------------------------------------------------
   void FE_Engine::write_data(double time, 
                              FIELDS &soln, 
                              OUTPUT_LIST *data)
   {
     outputManager_.write_data(
                         time, &soln, data,
                         (feMesh_->node_map())->data());
   }
 
   // -------------------------------------------------------------
   //  write data  
   // -------------------------------------------------------------
   void FE_Engine::write_data(double time, OUTPUT_LIST *data)
   {
     outputManager_.write_data(
                         time, data, 
                         feMesh_->node_map()->data());
   }
 
   // -------------------------------------------------------------
   //  amend mesh for deleted elements
   // -------------------------------------------------------------
   void FE_Engine::delete_elements(const set<int> & elementList)
   {
     feMesh_->delete_elements(elementList);
   }
 
   // -------------------------------------------------------------
   //  amend mesh for cut at specified faces
   // -------------------------------------------------------------
   void FE_Engine::cut_mesh(const set<PAIR> &faceSet, 
                            const set<int> &nodeSet)
   {
     feMesh_->cut_mesh(faceSet,nodeSet);
   }
   // -------------------------------------------------------------
   //  interpolate one value
   // -------------------------------------------------------------
   DENS_VEC  FE_Engine::interpolate_field(const DENS_VEC & x, const FIELD & f) const
   {
     DENS_VEC N;
     Array<int> nodelist;
     feMesh_->shape_functions(x, N, nodelist);
     const DENS_MAT &vI = f.quantity();
     int dof = vI.nCols();
     DENS_MAT vIe(nNodesPerElement_, dof);
     for (int i = 0; i < nNodesPerElement_; i++)
       for (int j = 0; j < dof; j++)
         vIe(i,j) = vI(nodelist(i),j);
     DENS_VEC vP;
     vP = N*vIe;
     return vP;
   }
 
   // -------------------------------------------------------------
   //  interpolate fields and gradients
   //  Currently, this function will break if called with an unowned ielem.
   //  Currently, this function is only called with owned ielems.
   // -------------------------------------------------------------
   void FE_Engine::interpolate_fields(
     const int ielem,
     const FIELDS &fields,
     AliasArray<int> & conn,
     DENS_MAT & N,
     DENS_MAT_VEC & dN,
     DIAG_MAT & _weights_,
     FIELD_MATS &fieldsAtIPs,
     GRAD_FIELD_MATS &gradFieldsAtIPs) const
   {
     // evaluate shape functions
     feMesh_->shape_function(ielem, N, dN, _weights_);
     // get connectivity
     _conn_ = feMesh_->element_connectivity_unique(ielem);
     // compute fields and gradients of fields ips of this element
     FIELD_MATS localElementFields;
     for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++)  {
       // field values at all nodes
       _fieldName_ = _fieldItr_->first;
       const DENS_MAT &vI = (_fieldItr_->second).quantity();
       int dof = vI.nCols();
       // field values at integration points -> to be computed
       DENS_MAT &vP = fieldsAtIPs[_fieldName_];
       // gradients of field at integration points -> to be computed
       DENS_MAT_VEC &dvP = gradFieldsAtIPs[_fieldName_];
       
       if (_fieldName_ == ELECTRON_WAVEFUNCTION_ENERGIES ) {
         vP = vI;
         continue;
       }
       // field values at element nodes
       DENS_MAT &vIe = localElementFields[_fieldName_];
       // gather local field
       vIe.reset(nNodesPerElement_, dof);
       for (int i = 0; i < nNodesPerElement_; i++)
         for (int j = 0; j < dof; j++)
           vIe(i,j) = vI(conn(i),j);
       // interpolate field at integration points
       vP = N*vIe;
       // gradients
       dvP.assign(nSD_, DENS_MAT(nIPsPerElement_, dof));
       for (int j = 0; j < nSD_; ++j) dvP[j] = dN[j]*vIe;
     }
   }
   // -------------------------------------------------------------
   //  interpolate fields 
   //  Currently, this function will break if called with an unowned ielem.
   //  Currently, this function is only called with owned ielems.
   // -------------------------------------------------------------
   void FE_Engine::interpolate_fields(
     const int ielem,
     const FIELDS &fields,
     AliasArray<int> & conn,
     DENS_MAT & N,
     DIAG_MAT & _weights_,
     FIELD_MATS &fieldsAtIPs) const
   {
     // evaluate shape functions
     feMesh_->shape_function(ielem, N, _weights_);
     // get connectivity
     _conn_ = feMesh_->element_connectivity_unique(ielem);
     // compute fields and gradients of fields ips of this element
     FIELD_MATS localElementFields;
     for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++)  {
       // field values at all nodes
       _fieldName_ = _fieldItr_->first;
       const DENS_MAT &vI = (_fieldItr_->second).quantity();
       int dof = vI.nCols();
       // field values at integration points -> to be computed
       DENS_MAT &vP = fieldsAtIPs[_fieldName_];
       // field values at element nodes
       DENS_MAT &vIe = localElementFields[_fieldName_];
       
       if (_fieldName_ == ELECTRON_WAVEFUNCTION_ENERGIES ) {
         vP = vI;
         continue;
       }
 
       // gather local field
       vIe.reset(nNodesPerElement_, dof);
       for (int i = 0; i < nNodesPerElement_; i++)
         for (int j = 0; j < dof; j++)
           vIe(i,j) = vI(conn(i),j);
       // interpolate field at integration points
       vP = N*vIe;
     }
   }
 
   // -------------------------------------------------------------
   // compute dimensionless stiffness matrix using native quadrature 
   // -------------------------------------------------------------
   void FE_Engine::stiffness_matrix(SPAR_MAT &matrix) const
   {
     // assemble consistent mass 
     matrix.reset(nNodesUnique_,nNodesUnique_);// zero since partial fill
     DENS_MAT elementMassMatrix(nNodesPerElement_,nNodesPerElement_); 
 
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       // evaluate shape functions
       feMesh_->shape_function(ielem, _N_, _dN_, _weights_); // _N_ unused
       // perform quadrature
       elementMassMatrix = _dN_[0].transMat(_weights_*_dN_[0]); 
       for (int i = 1; i < nSD_; ++i) {
         elementMassMatrix += _dN_[i].transMat(_weights_*_dN_[i]); 
       }
       // get connectivity
       _conn_ = feMesh_->element_connectivity_unique(ielem);
       for (int i = 0; i < nNodesPerElement_; ++i) 
       {
         int inode = _conn_(i);
         for (int j = 0; j < nNodesPerElement_; ++j) 
         {
           int jnode = _conn_(j);
           matrix.add(inode, jnode, elementMassMatrix(i,j));
         }
       }
     }
 #ifdef ISOLATE_FE
     sparse_allsum(communicator_,matrix);
 #else
     LammpsInterface::instance()->sparse_allsum(matrix);
 #endif
     matrix.compress();
   }
 
   // -------------------------------------------------------------
   // compute tangent using native quadrature for one (field,field) pair
   // -------------------------------------------------------------
   void FE_Engine::compute_tangent_matrix(
                                      const Array2D<bool> &rhsMask,
                                      const pair<FieldName,FieldName> row_col,
                                      const FIELDS &fields,
                                      const PhysicsModel * physicsModel,
                                      const Array<int>   & elementMaterials,
                                      SPAR_MAT &tangent,
                                      const DenseMatrix<bool> *elementMask) const
   {
 
     tangent.reset(nNodesUnique_,nNodesUnique_);
     FieldName rowField = row_col.first;
     FieldName colField = row_col.second;
     bool BB = rhsMask(rowField,FLUX);
     bool NN = rhsMask(rowField,SOURCE);
     DENS_MAT elementMatrix(nNodesPerElement_,nNodesPerElement_); 
     DENS_MAT coefsAtIPs;
 
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       // if element is masked, skip it
       if (elementMask && !(*elementMask)(ielem,0)) continue;
       // material id
       int imat = elementMaterials(ielem);
       const Material * mat = physicsModel->material(imat);
       // interpolate fields and gradients (nonlinear only)
       interpolate_fields(ielem,fields,_conn_,_N_,_dN_,_weights_,
         _fieldsAtIPs_,_gradFieldsAtIPs_);
         
       // evaluate Physics model
       
       if (! (physicsModel->null(rowField,imat)) ) {
         if (BB && physicsModel->weak_equation(rowField)-> 
           has_BB_tangent_coefficients() ) {
           physicsModel->weak_equation(rowField)->
             BB_tangent_coefficients(colField, _fieldsAtIPs_, mat, coefsAtIPs);
           DIAG_MAT D(column(coefsAtIPs,0)); 
           D = _weights_*D;
           elementMatrix = _dN_[0].transMat(D*_dN_[0]);
           for (int i = 1; i < nSD_; i++) {
             elementMatrix += _dN_[i].transMat(D*_dN_[i]);
           } 
         }
         else {
           elementMatrix.reset(nNodesPerElement_,nNodesPerElement_);
         }
         if (NN && physicsModel->weak_equation(rowField)->
           has_NN_tangent_coefficients() ) {
           physicsModel->weak_equation(rowField)->
             NN_tangent_coefficients(colField, _fieldsAtIPs_, mat, coefsAtIPs);
           DIAG_MAT D(column(coefsAtIPs,0)); 
           D = _weights_*D;
           elementMatrix += _N_.transMat(D*_N_);
         }
         // assemble
         for (int i = 0; i < nNodesPerElement_; ++i) 
         {  
           int inode = _conn_(i); 
           for (int j = 0; j < nNodesPerElement_; ++j)
           {
             int jnode = _conn_(j);
             tangent.add(inode, jnode, elementMatrix(i,j));
           }
         } 
       }
     } 
 #ifdef ISOLATE_FE
     sparse_allsum(communicator_,tangent);
 #else
     LammpsInterface::instance()->sparse_allsum(tangent);
 #endif
     tangent.compress(); 
   }  
 
   // -------------------------------------------------------------
   // compute tangent using given quadrature for one (field,field) pair
   // -------------------------------------------------------------
   void FE_Engine::compute_tangent_matrix(const Array2D<bool> &rhsMask,
                             const pair<FieldName,FieldName> row_col,
                             const FIELDS        &fields,
                             const PhysicsModel * physicsModel,
                             const Array<set<int> > & pointMaterialGroups,
                             const DIAG_MAT      &weights,
                             const SPAR_MAT      &N,
                             const SPAR_MAT_VEC  &dN,
                             SPAR_MAT &tangent,
                             const DenseMatrix<bool> *elementMask ) const
   {
     int nn = nNodesUnique_;
     FieldName rowField = row_col.first;
     FieldName colField = row_col.second;
     bool BB = rhsMask(rowField,FLUX);
     bool NN = rhsMask(rowField,SOURCE);
     DENS_MAT K(nn,nn);
     DENS_MAT coefsAtIPs;
     int nips = weights.nCols();
     if (nips>0) {
       // compute fields and gradients of fields at given ips
       
       GRAD_FIELD_MATS gradFieldsAtIPs;
       FIELD_MATS fieldsAtIPs;
       for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++) {
         _fieldName_          = _fieldItr_->first;
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         int dof = field.nCols();
         gradFieldsAtIPs[_fieldName_].assign(nSD_,DENS_MAT(nips,dof));
         fieldsAtIPs[_fieldName_] = N*field;
         for (int j = 0; j < nSD_; ++j) {
           gradFieldsAtIPs[_fieldName_][j] = (*dN[j])*field;
         }
       }
 
       // treat single material point sets specially
       int nMatls = pointMaterialGroups.size();
       int atomMatls = 0;
       for (int imat = 0; imat < nMatls; imat++) {
         const set<int> & indices = pointMaterialGroups(imat);
         if ( indices.size() > 0) atomMatls++;
       }
       bool singleMaterial = ( atomMatls == 1 );
       
       if (! singleMaterial ) throw ATC_Error("FE_Engine::compute_tangent_matrix-given quadrature can not handle multiple atom material currently");
       if (singleMaterial)
       {
         int imat = 0; 
         const Material *   mat = physicsModel->material(imat);
         // evaluate Physics model
         if (! (physicsModel->null(rowField,imat)) ) {
           if (BB && physicsModel->weak_equation(rowField)->
             has_BB_tangent_coefficients() ) {
             physicsModel->weak_equation(rowField)->
               BB_tangent_coefficients(colField, fieldsAtIPs, mat, coefsAtIPs);
             DIAG_MAT D(column(coefsAtIPs,0)); 
             D = weights*D;
             K = (*dN[0]).transMat(D*(*dN[0]));
             for (int i = 1; i < nSD_; i++) {
               K += (*dN[i]).transMat(D*(*dN[i]));
             } 
           }
           if (NN && physicsModel->weak_equation(rowField)->
             has_NN_tangent_coefficients() ) {
             physicsModel->weak_equation(rowField)->
               NN_tangent_coefficients(colField, fieldsAtIPs, mat, coefsAtIPs);
             DIAG_MAT D(column(coefsAtIPs,0)); 
             D = weights*D;
             K += N.transMat(D*N);
           }
         }
       }
     }
     // share information between processors
     int count = nn*nn; 
     DENS_MAT K_sum(nn,nn);
     allsum(communicator_, K.ptr(), K_sum.ptr(), count);
     // create sparse from dense
     tangent.reset(K_sum,tol_sparse);
     tangent.compress();
   }  
 
   // -------------------------------------------------------------
   //  compute a consistent mass matrix for native quadrature
   // -------------------------------------------------------------
   void FE_Engine::compute_mass_matrix(
      const Array<FieldName>& field_mask,
      const FIELDS &fields,
      const PhysicsModel * physicsModel,
      const Array<int>   & elementMaterials,
      
      CON_MASS_MATS & massMatrices,
      const DenseMatrix<bool> *elementMask) const
   {
     int nfields = field_mask.size();
     vector<FieldName> usedFields;
 
     
     DENS_MAT elementMassMatrix(nNodesPerElement_,nNodesPerElement_); 
     
     // (JAT, 04/21/11) FIX THIS
     DENS_MAT capacity;
 
     // zero, use incoming matrix as template if possible
     for (int j = 0; j < nfields; ++j) {
       _fieldName_ = field_mask(j);
       SPAR_MAT & M = massMatrices[_fieldName_].set_quantity();
       
       // compresses 2May11
       if   (M.has_template()) { M = 0; }
       else                    { M.reset(nNodesUnique_,nNodesUnique_); }
       M.reset(nNodesUnique_,nNodesUnique_);
     }
 
     // element wise assembly
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin(); 
+    for (vector<int>::iterator elemsIter = myElems.begin(); 
          elemsIter != myElems.end();
          ++elemsIter) 
     {
       int ielem = *elemsIter;
       // if element is masked, skip 
       if (elementMask && !(*elementMask)(ielem,0)) continue;
       // material id
       int imat = elementMaterials(ielem);
       const Material * mat = physicsModel->material(imat);
       // interpolate fields
       interpolate_fields(ielem,fields,_conn_,_N_,_weights_,_fieldsAtIPs_);
       for (int j = 0; j < nfields; ++j) {
         _fieldName_ = field_mask(j);
         SPAR_MAT & M = massMatrices[_fieldName_].set_quantity();
         // skip null weakEqns by material
         if (! (physicsModel->null(_fieldName_,imat)) ) {
           physicsModel->weak_equation(_fieldName_)->
             M_integrand(_fieldsAtIPs_, mat, capacity);
           DIAG_MAT rho(column(capacity,0)); 
           elementMassMatrix = _N_.transMat(_weights_*rho*_N_);
           // assemble
           for (int i = 0; i < nNodesPerElement_; ++i) {  
             int inode = _conn_(i); 
             for (int j = 0; j < nNodesPerElement_; ++j) {
               int jnode = _conn_(j);
               M.add(inode, jnode, elementMassMatrix(i,j));
             }
           }
         }
       }
     }
 
     for (int j = 0; j < nfields; ++j) {
       _fieldName_ = field_mask(j);
       SPAR_MAT & M = massMatrices[_fieldName_].set_quantity();
 #ifdef ISOLATE_FE
     sparse_allsum(communicator_,M);
 #else
     LammpsInterface::instance()->sparse_allsum(M);
 #endif
     }
     // fix zero diagonal entries due to null material elements
     for (int j = 0; j < nfields; ++j) {
       _fieldName_ = field_mask(j);
       
       SPAR_MAT & M = massMatrices[_fieldName_].set_quantity(); 
       for (int inode = 0; inode < nNodesUnique_; ++inode) {
         if (! M.has_entry(inode,inode)) {
           M.set(inode,inode,1.0); 
         } 
       }
       M.compress();
     }
 
   } 
 
   // -------------------------------------------------------------
   // compute dimensionless consistent mass using native quadrature 
   // -------------------------------------------------------------
   void FE_Engine::compute_mass_matrix(SPAR_MAT &massMatrix) const
   {
     // assemble nnodes X nnodes matrix
 
     massMatrix.reset(nNodesUnique_,nNodesUnique_);// zero since partial fill
     DENS_MAT elementMassMatrix(nNodesPerElement_,nNodesPerElement_); 
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       // evaluate shape functions
       feMesh_->shape_function(ielem, _N_, _weights_);
       // perform quadrature
       elementMassMatrix = _N_.transMat(_weights_*_N_); 
       // get connectivity
       _conn_ = feMesh_->element_connectivity_unique(ielem);
       for (int i = 0; i < nNodesPerElement_; ++i) {
         int inode = _conn_(i);
         for (int j = 0; j < nNodesPerElement_; ++j) {
           int jnode = _conn_(j);
           massMatrix.add(inode, jnode, elementMassMatrix(i,j));
         }
       }
     }
     // Assemble partial results
 #ifdef ISOLATE_FE
     sparse_allsum(communicator_,massMatrix);
 #else
     LammpsInterface::instance()->sparse_allsum(massMatrix);
 #endif
   }
 
   // -------------------------------------------------------------
   // compute dimensionless consistent mass using given quadrature
   // -------------------------------------------------------------
   void FE_Engine::compute_mass_matrix(const DIAG_MAT &weights,
                                       const SPAR_MAT &N,
                                       SPAR_MAT &massMatrix) const
   {
     int nn   = N.nCols();
     int nips = N.nRows();
     DENS_MAT tmp_mass_matrix_local(nn,nn), tmp_mass_matrix(nn,nn);
     if (nips>0) { tmp_mass_matrix_local = N.transMat(weights*N); } 
     // share information between processors
     int count = nn*nn; 
     allsum(communicator_,
       tmp_mass_matrix_local.ptr(),
       tmp_mass_matrix.ptr(), count);
     // create sparse from dense
     massMatrix.reset(tmp_mass_matrix,tol_sparse);
   }
 
   // -------------------------------------------------------------
   // compute dimensionless lumped mass using native quadrature 
   // -------------------------------------------------------------
   void FE_Engine::compute_lumped_mass_matrix(DIAG_MAT & M) const
   {
     M.reset(nNodesUnique_,nNodesUnique_); // zero since partial fill
     // assemble lumped diagonal mass 
     DENS_VEC Nvec(nNodesPerElement_);
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       // evaluate shape functions
       feMesh_->shape_function(ielem, _N_, _weights_);
       CLON_VEC w(_weights_);
       // get connectivity
       _conn_ = feMesh_->element_connectivity_unique(ielem);
       Nvec = w*_N_;
       for (int i = 0; i < nNodesPerElement_; ++i) {
         int inode = _conn_(i);
         M(inode,inode) += Nvec(i);
       }
     }
     // Assemble partial results
     allsum(communicator_,MPI_IN_PLACE, M.ptr(), M.size());
   }
 
   // -------------------------------------------------------------
   // compute physical lumped mass using native quadrature 
   // -------------------------------------------------------------
   void FE_Engine::compute_lumped_mass_matrix(
     const Array<FieldName>& field_mask,
     const FIELDS          & fields,
     const PhysicsModel * physicsModel,
     const Array<int> &elementMaterials,
     MASS_MATS & massMatrices, // mass matrix
     const DenseMatrix<bool> *elementMask) const
   {
     int nfields = field_mask.size();
     // zero initialize for assembly
     for (int j = 0; j < nfields; ++j) { 
       DIAG_MAT & M = massMatrices[field_mask(j)].set_quantity();
       M.reset(nNodesUnique_,nNodesUnique_); 
     }
     // assemble diagonal matrix
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       // if element is masked, skip it
       if (elementMask && !(*elementMask)(ielem,0)) continue;
       // material id
       int imat = elementMaterials(ielem);
       const Material * mat = physicsModel->material(imat);
       interpolate_fields(ielem,fields,_conn_,_N_,_weights_,_fieldsAtIPs_);
       // compute densities, integrate & assemble
       DENS_MAT capacity;
       for (int j = 0; j < nfields; ++j) {
         _fieldName_ = field_mask(j);
         if (! physicsModel->null(_fieldName_,imat)) { 
           physicsModel->weak_equation(_fieldName_)->
             M_integrand(_fieldsAtIPs_, mat, capacity);
           _Nmat_ = _N_.transMat(_weights_*capacity);
           DIAG_MAT & M = massMatrices[_fieldName_].set_quantity();
           for (int i = 0; i < nNodesPerElement_; ++i) {
             int inode = _conn_(i);  
             M(inode,inode) += _Nmat_(i,0);
 
           }
         }
       }
     }
     // Assemble partial results
     for (int j = 0; j < nfields; ++j) {
       _fieldName_ = field_mask(j);
       DIAG_MAT & M = massMatrices[_fieldName_].set_quantity();
       allsum(communicator_,MPI_IN_PLACE, M.ptr(), M.size());
     }
 
     // fix zero diagonal entries due to null material elements
     for (int inode = 0; inode < nNodesUnique_; ++inode) {
       for (int j = 0; j < nfields; ++j) {
         _fieldName_ = field_mask(j);
         DIAG_MAT & M = massMatrices[_fieldName_].set_quantity();
         if (M(inode,inode) == 0.0) { 
           M(inode,inode) = 1.0; 
         }
       }
     }
   }
 
   // -------------------------------------------------------------
   // compute physical lumped mass using given quadrature 
   // -------------------------------------------------------------
   void FE_Engine::compute_lumped_mass_matrix(
     const Array<FieldName>   &field_mask, 
     const FIELDS &fields,
     const PhysicsModel * physicsModel,
     const Array<set<int> > & pointMaterialGroups,
     const DIAG_MAT      &weights, 
     const SPAR_MAT      &N,
     MASS_MATS &M) const // mass matrices 
   {
     int nips = weights.nCols();
     int nfields = field_mask.size();
     // initialize
     map<FieldName, DIAG_MAT> M_local;
     for (int j = 0; j < nfields; ++j) {
       _fieldName_ = field_mask(j);
       M_local[_fieldName_].reset(nNodesUnique_,nNodesUnique_);
       M[_fieldName_].reset(nNodesUnique_,nNodesUnique_);
     }
     
     if (nips>0) {
       // compute fields at given ips
       // compute all fields since we don't the capacities dependencies
       FIELD_MATS fieldsAtIPs;
       for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++) {
         _fieldName_ = _fieldItr_->first;
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         int dof = field.nCols();
         fieldsAtIPs[_fieldName_].reset(nips,dof);
         fieldsAtIPs[_fieldName_] = N*field;
       }
     
       // treat single material point sets specially
       int nMatls = pointMaterialGroups.size();
       int atomMatls = 0;
+      int iatomMat = 0;
       for (int imat = 0; imat < nMatls; imat++) {
         const set<int> & indices = pointMaterialGroups(imat);
-        if ( indices.size() > 0) atomMatls++;
+        if ( indices.size() > 0) {
+          iatomMat = imat;
+          atomMatls++;
+        }
       }
       if (atomMatls == 0) {
         throw ATC_Error("no materials in atom region - atoms may have migrated to FE-only region");
       }
       bool singleMaterial = ( atomMatls == 1 );
       if (! singleMaterial ) {
         stringstream ss; ss << " WARNING: multiple materials in atomic region";
        print_msg(communicator_,ss.str());
       }
     
       // setup data structures
       FIELD_MATS capacities;
       // evaluate physics model & compute capacity|density for requested fields
       if (singleMaterial) {
-        int imat = 0; 
-        const Material * mat = physicsModel->material(imat);
+        const Material * mat = physicsModel->material(iatomMat);
         for (int j = 0; j < nfields; ++j) {
           _fieldName_ = field_mask(j);
           // mass matrix needs to be invertible so null matls have cap=1
-          if (physicsModel->null(_fieldName_,imat)) {
+          if (physicsModel->null(_fieldName_,iatomMat)) {
              throw ATC_Error("null material not supported for atomic region (single material)");
              const FIELD &  f = (fields.find(_fieldName_))->second;
              capacities[_fieldName_].reset(f.nRows(),f.nCols());
              capacities[_fieldName_] = 1.;
              
           } 
           else {
             physicsModel->weak_equation(_fieldName_)->
               M_integrand(fieldsAtIPs, mat, capacities[_fieldName_]);
           }
         }
       }
       else {
         FIELD_MATS groupCapacities, fieldsGroup;
         for (int j = 0; j < nfields; ++j) {
           _fieldName_ = field_mask(j);
           capacities[_fieldName_].reset(nips,1);
         }
         for ( int imat = 0; imat < pointMaterialGroups.size(); imat++) {
           const Material * mat = physicsModel->material(imat);
           const set<int> & indices = pointMaterialGroups(imat);
           int npts = indices.size();
           if (npts > 0) {
             for (int j = 0; j < nfields; ++j) {
               _fieldName_ = field_mask(j);
               groupCapacities[_fieldName_].reset(npts,1);
               const FIELD &  f = (fields.find(_fieldName_))->second;
               int ndof = f.nCols();
               fieldsGroup[_fieldName_].reset(npts,ndof);
               int i = 0;
               for (set<int>::const_iterator iter=indices.begin();
                    iter != indices.end(); iter++, i++ ) {
                 for (int dof = 0; dof < ndof; ++dof) {
                   fieldsGroup[_fieldName_](i,dof) 
                     = fieldsAtIPs[_fieldName_](*iter,dof);
                 }
               }
             }
             for (int j = 0; j < nfields; ++j) {
               _fieldName_ = field_mask(j);
               if (physicsModel->null(_fieldName_,imat)) {
                 throw ATC_Error("null material not supported for atomic region (multiple materials)");
                 const FIELD &  f = (fields.find(_fieldName_))->second;
                 groupCapacities[_fieldName_].reset(f.nRows(),f.nCols());
                 groupCapacities[_fieldName_] = 1.;
               } 
               else {
                 physicsModel->weak_equation(_fieldName_)->
                   M_integrand(fieldsGroup, mat, groupCapacities[_fieldName_]);
               }
               int i = 0;
               for (set<int>::const_iterator iter=indices.begin();
                    iter != indices.end(); iter++, i++ ) {
                 capacities[_fieldName_](*iter,0) 
                   = groupCapacities[_fieldName_](i,0);
               }
             }
           }
         }
       }
       
       // integrate & assemble
       for (int j = 0; j < nfields; ++j) {
         _fieldName_ = field_mask(j);
         M_local[_fieldName_].reset( // assume all columns same
           column(N.transMat(weights*capacities[_fieldName_]),0) );
       }
     }
     
     // Share information between processors
     for (int j = 0; j < nfields; ++j) {
       _fieldName_ = field_mask(j);
       DIAG_MAT & myMassMat(M[_fieldName_].set_quantity());
       int count = M_local[_fieldName_].size();
       allsum(communicator_, M_local[_fieldName_].ptr(), myMassMat.ptr(), count);
     }
   }
   
   //-----------------------------------------------------------------
   // compute assembled average gradient evaluated at the nodes
   //-----------------------------------------------------------------
   void FE_Engine::compute_gradient_matrix(SPAR_MAT_VEC & grad_matrix) const
   {
     // zero
     DENS_MAT_VEC tmp_grad_matrix(nSD_);  
     for (int i = 0; i < nSD_; i++) {
       tmp_grad_matrix[i].reset(nNodesUnique_,nNodesUnique_); 
     }
     // element wise assembly
     Array<int> count(nNodesUnique_); count = 0;
     set_quadrature(NODAL);
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       // evaluate shape functions
       feMesh_->shape_function(ielem, _N_, _dN_, _weights_);
       // get connectivity
       _conn_ = feMesh_->element_connectivity_unique(ielem);
       for (int j = 0; j < nIPsPerElement_; ++j) {
         int jnode = _conn_(j); 
         count(jnode) += 1;
         for (int i = 0; i < nNodesPerElement_; ++i) {
           int inode = _conn_(i);
           for (int k = 0; k < nSD_; ++k) {
             tmp_grad_matrix[k](jnode,inode) += _dN_[k](j,i);
 
           }
         }
       }
     }
     // Assemble partial results
     for (int k = 0; k < nSD_; ++k) {
       allsum(communicator_,MPI_IN_PLACE, tmp_grad_matrix[k].ptr(), tmp_grad_matrix[k].size());
     }
     int_allsum(communicator_,MPI_IN_PLACE, count.ptr(), count.size());
     set_quadrature(quadrature_); //reset to default
     for (int inode = 0; inode < nNodesUnique_; ++inode) {
       for (int jnode = 0; jnode < nNodesUnique_; ++jnode) {
         for (int k = 0; k < nSD_; ++k) {
           tmp_grad_matrix[k](jnode,inode) /= count(jnode);
         }
       }
     }
     // compact dense matrices
     for (int k = 0; k < nSD_; ++k) {
       grad_matrix[k]->reset(tmp_grad_matrix[k],tol_sparse);
     }
   }
 
   // -------------------------------------------------------------
   // compute energy per node using native quadrature
   // -------------------------------------------------------------
   void FE_Engine::compute_energy(const Array<FieldName> &mask,
     const FIELDS &fields,
     const PhysicsModel * physicsModel,
     const Array<int>   & elementMaterials,
     FIELD_MATS &energies,
     const DenseMatrix<bool> *elementMask,
     const IntegrationDomainType domain) const
   {
     // Zero out all fields
     for (int n = 0; n < mask.size(); n++) {
       _fieldName_ = mask(n);
       _fieldItr_ = fields.find(_fieldName_);
       const DENS_MAT & field = (_fieldItr_->second).quantity();
       energies[_fieldName_].reset(field.nRows(), 1);
     }
 
     DENS_MAT elementEnergy(nNodesPerElement_,1); // workspace
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       // if element is masked, skip it
       if (domain != FULL_DOMAIN && elementMask && !(*elementMask)(ielem,0)) continue;
       // material id
       int imat = elementMaterials(ielem);
       const Material * mat = physicsModel->material(imat);
       interpolate_fields(ielem,fields,_conn_,_N_,_dN_,_weights_,
         _fieldsAtIPs_,_gradFieldsAtIPs_);
       
       // assemble
       for (int n = 0; n < mask.size(); n++) {
         _fieldName_ = mask(n);
         if (physicsModel->null(_fieldName_,imat)) continue;
         if( ! (physicsModel->weak_equation(_fieldName_)-> has_E_integrand()))  continue;
         physicsModel->weak_equation(_fieldName_)->
           E_integrand(_fieldsAtIPs_, _gradFieldsAtIPs_, mat, elementEnergy);
         _fieldItr_ = fields.find(_fieldName_);
         _Nmat_ = _N_.transMat(_weights_*elementEnergy);
         DENS_MAT & energy = energies[_fieldName_];
         for (int i = 0; i < nNodesPerElement_; ++i) {  
           int inode = _conn_(i);  
           energy(inode,0) += _Nmat_(i,0);
         }
       }
     }
 
     for (int n = 0; n < mask.size(); n++) {
       _fieldName_ = mask(n);
       DENS_MAT& myEnergy(energies[_fieldName_]);
       allsum(communicator_,MPI_IN_PLACE, myEnergy.ptr(), myEnergy.size());
     }
   }
 
   // -------------------------------------------------------------
   // compute rhs using native quadrature
   // -------------------------------------------------------------
   void FE_Engine::compute_rhs_vector(const Array2D<bool> &rhsMask,
     const FIELDS &fields,
     const PhysicsModel * physicsModel,
     const Array<int>   & elementMaterials,
     FIELDS &rhs,
+    bool freeOnly,
     const DenseMatrix<bool> *elementMask) const
   {
     vector<FieldName> usedFields;
 
 
     // size and zero output
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       if (rhsMask(_fieldName_, FLUX) || rhsMask(_fieldName_, SOURCE)) {
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         rhs[_fieldName_].reset(field.nRows(), field.nCols());
 
         // Save field names for easy lookup later.
         usedFields.push_back(_fieldName_);
       }
     }
 
     // Iterate over elements partitioned onto current processor.
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin(); 
+    for (vector<int>::iterator elemsIter = myElems.begin(); 
          elemsIter != myElems.end();
          ++elemsIter) 
     {
       int ielem = *elemsIter;
       // Skip masked elements 
       if (elementMask && !(*elementMask)(ielem,0)) continue;
       int imat = elementMaterials(ielem); // material id
       const Material * mat = physicsModel->material(imat);
       
       // interpolate field values to integration points
       interpolate_fields(ielem,fields,_conn_,_N_,_dN_,_weights_,
         _fieldsAtIPs_,_gradFieldsAtIPs_);
       
       // rescale by _weights_, a diagonal matrix
       _Nw_ = _weights_*_N_;
       for (int j = 0; j < nSD_; ++j) _dNw_[j] = _weights_*_dN_[j];
       
       // evaluate physics model and assemble
       // _Nfluxes is a set of fields
       for (int n = 0; n < rhsMask.nRows(); n++) {
         _fieldName_ = FieldName(n);
         if (!rhsMask(_fieldName_,SOURCE)) continue;
         if (physicsModel->null(_fieldName_,imat)) continue;
 
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         DENS_MAT & myRhs(rhs[_fieldName_].set_quantity());
        
         int dof = field.nCols();
         bool has = physicsModel->weak_equation(_fieldName_)->
           N_integrand(_fieldsAtIPs_,_gradFieldsAtIPs_, mat, _Nfluxes_);
         if (!has) continue;
         _Nmat_ = _Nw_.transMat(_Nfluxes_);
         
         for (int i = 0; i < nNodesPerElement_; ++i) {  
           int inode = _conn_(i);  
           for (int k = 0; k < dof; ++k) {
             myRhs(inode,k) += _Nmat_(i,k);
           }
         }
       }
       // _Bfluxes_ is a set of field gradients
       for (int n = 0; n < rhsMask.nRows(); n++) {
         _fieldName_ = FieldName(n);
         if (!rhsMask(_fieldName_,FLUX)) continue;
         if (physicsModel->null(_fieldName_,imat)) continue;
         
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         DENS_MAT & myRhs(rhs[_fieldName_].set_quantity());
          
         int dof = field.nCols();
         physicsModel->weak_equation(_fieldName_)->
           B_integrand(_fieldsAtIPs_, _gradFieldsAtIPs_, mat, _Bfluxes_);
 
         for (int j = 0; j < nSD_; j++) {
           _Nmat_ = _dNw_[j].transMat(_Bfluxes_[j]);
           for (int i = 0; i < nNodesPerElement_; ++i) {  
             int inode = _conn_(i); 
             for (int k = 0; k < dof; ++k) {
               myRhs(inode,k) += _Nmat_(i,k);
             } 
           }
         }
       } 
     }
 
-    vector<FieldName>::const_iterator _fieldIter_;
+    vector<FieldName>::iterator _fieldIter_;
     for (_fieldIter_ = usedFields.begin(); _fieldIter_ != usedFields.end(); 
          ++_fieldIter_) {
       // myRhs is where we put the global result for this field.
       _fieldName_ = *_fieldIter_;
       DENS_MAT & myRhs(rhs[_fieldName_].set_quantity());
 
       // Sum matrices in-place across all processors into myRhs.
       allsum(communicator_,MPI_IN_PLACE, myRhs.ptr(), myRhs.size());
     }
   }  
 
   // -------------------------------------------------------------
   // compute rhs using given quadrature
   // -------------------------------------------------------------
   void FE_Engine::compute_rhs_vector(const Array2D<bool> &rhsMask,
     const FIELDS        &fields,
     const PhysicsModel  *physicsModel,
     const Array<set<int> >&pointMaterialGroups,
     const DIAG_MAT      &weights,
     const SPAR_MAT      &N,
     const SPAR_MAT_VEC  &dN,
     FIELDS              &rhs) const
   {
     FIELD_MATS rhs_local;
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       if (rhsMask(_fieldName_,FLUX) || rhsMask(_fieldName_,SOURCE)) {
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         int nrows = field.nRows();
         int ncols = field.nCols();
         rhs      [_fieldName_].reset(nrows,ncols);
         rhs_local[_fieldName_].reset(nrows,ncols);
       }
     }
     
     int nips = weights.nCols();
 
     if (nips>0) {
       // compute fields and gradients of fields at given ips
       
       GRAD_FIELD_MATS gradFieldsAtIPs;
       FIELD_MATS fieldsAtIPs;
       for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++) {
         _fieldName_          = _fieldItr_->first;
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         int dof = field.nCols();
         gradFieldsAtIPs[_fieldName_].assign(nSD_,DENS_MAT(nips,dof));
         fieldsAtIPs[_fieldName_] = N*field;
         for (int j = 0; j < nSD_; ++j) {
           gradFieldsAtIPs[_fieldName_][j] = (*dN[j])*field;
         }
       }
 
       // setup data structures
       FIELD_MATS Nfluxes; 
       GRAD_FIELD_MATS Bfluxes; 
       for (int n = 0; n < rhsMask.nRows(); n++) {
         _fieldName_ = FieldName(n);
         int index = (int) _fieldName_;
         if ( rhsMask(index,FLUX) ) {
           Bfluxes[_fieldName_].assign(nSD_, DENS_MAT()); 
         }
       }
  
       // treat single material point sets specially
       int nMatls = pointMaterialGroups.size();
       int atomMatls = 0;
       for (int imat = 0; imat < nMatls; imat++) {
         const set<int> & indices = pointMaterialGroups(imat);
         if ( indices.size() > 0) atomMatls++;
       }
       bool singleMaterial = ( atomMatls == 1 );
       
       // evaluate physics model
       if (singleMaterial) 
       {
         int imat = 0;
         const Material *   mat = physicsModel->material(imat);
         for (int n = 0; n < rhsMask.nRows(); n++) {
           _fieldName_ = FieldName(n);
           int index = (int) _fieldName_;
           if (! physicsModel->null(_fieldName_,imat)) {
             if ( rhsMask(index,SOURCE) ) {
               physicsModel->weak_equation(_fieldName_)->
                 N_integrand(fieldsAtIPs, gradFieldsAtIPs, mat, Nfluxes[_fieldName_]);
             }
             if ( rhsMask(index,FLUX) ) {
               physicsModel->weak_equation(_fieldName_)->
                 B_integrand(fieldsAtIPs, gradFieldsAtIPs, mat, Bfluxes[_fieldName_]);
             }
           }
         }
       }
       else 
       {
         
         
         // 1) permanent workspace with per-row mapped clones per matl
         //    from caller/atc
         // 2) per point calls to N/B_integrand
         // 3) collect internalToAtom into materials and use mem-cont clones
         //    what about dof for matrices and data storage: clone _matrix_
         
         // for each material group: 
         // set up storage
         DENS_MAT        group_Nfluxes;
         DENS_MAT_VEC    group_Bfluxes; 
         group_Bfluxes.reserve(nSD_); 
         FIELD_MATS      fieldsGroup;
         GRAD_FIELD_MATS gradFieldsGroup;
         for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++) {
           _fieldName_          = _fieldItr_->first;
           const DENS_MAT & field = (_fieldItr_->second).quantity();
           int ndof = field.nCols();
           gradFieldsGroup[_fieldName_].assign(nSD_,DENS_MAT(nips,ndof));
           
           Nfluxes[_fieldName_].reset(nips,ndof);
           Bfluxes[_fieldName_].assign(nSD_,DENS_MAT(nips,ndof));
           //}
         }
 
         // copy fields
         for ( int imat = 0; imat < pointMaterialGroups.size(); imat++) 
         {
           const set<int> & indices = pointMaterialGroups(imat);
           const Material *   mat = physicsModel->material(0);
           int npts = indices.size();
           int i = 0;
           for (set<int>::const_iterator iter=indices.begin();
                                         iter != indices.end(); iter++, i++ ) {
             for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++) {
               _fieldName_          = _fieldItr_->first;
               const DENS_MAT & field = (_fieldItr_->second).quantity();
               int ndof = field.nCols();
               fieldsGroup[_fieldName_].reset(npts,ndof);
               for (int j = 0; j < nSD_; ++j) {
                 (gradFieldsGroup[_fieldName_][j]).reset(npts,ndof);
               }
               for (int dof = 0; dof < ndof; ++dof) {
                 fieldsGroup[_fieldName_](i,dof) 
                   = fieldsAtIPs[_fieldName_](*iter,dof);
                 for (int j = 0; j < nSD_; ++j) {
                   gradFieldsGroup[_fieldName_][j](i,dof) 
                     = gradFieldsAtIPs[_fieldName_][j](*iter,dof);
                 }
               }
             }
           }
           // calculate forces, & assemble 
           for (int n = 0; n < rhsMask.nRows(); n++) {
             _fieldName_ = FieldName(n);
             _fieldItr_ = fields.find(_fieldName_);
             int index = (int) _fieldName_;
             if (physicsModel->null(_fieldName_,imat)) continue;
             if ( rhsMask(index,SOURCE) ) {
               const DENS_MAT & field = (_fieldItr_->second).quantity();
               int ndof = field.nCols();
               bool has = physicsModel->weak_equation(_fieldName_)->
                 N_integrand(fieldsGroup, gradFieldsGroup, mat, group_Nfluxes);
               if (! has) throw ATC_Error("atomic source can not be null currently");
               int i = 0;
               for (set<int>::const_iterator iter=indices.begin();
                                    iter != indices.end(); iter++, i++ ) {
                 for (int dof = 0; dof < ndof; ++dof) {
                   Nfluxes[_fieldName_](*iter,dof) += group_Nfluxes(i,dof);
                 }
               }
             }
           }
           // calculate forces, & assemble 
           for (int n = 0; n < rhsMask.nRows(); n++) {
             _fieldName_ = FieldName(n);
             if (physicsModel->null(_fieldName_,imat)) continue;
             int index = (int) _fieldName_;
             if ( rhsMask(index,FLUX) ) {
               _fieldItr_ = fields.find(_fieldName_);
               const DENS_MAT & field = (_fieldItr_->second).quantity();   
               int ndof = field.nCols();
               physicsModel->weak_equation(_fieldName_)->
                 B_integrand(fieldsGroup, gradFieldsGroup, mat, group_Bfluxes);
               int i = 0;
               for (set<int>::const_iterator iter=indices.begin();
                                    iter != indices.end(); iter++, i++ ) {
                 for (int dof = 0; dof < ndof; ++dof) {
                   for (int j = 0; j < nSD_; ++j) {
                     Bfluxes[_fieldName_][j](*iter,dof) += group_Bfluxes[j](i,dof);
                   }
                 }
               }
             }
           }
         }
       } // endif multiple materials
       
       // assemble : N/Bfluxes -> rhs_local
       for (int n = 0; n < rhsMask.nRows(); n++) {
         _fieldName_ = FieldName(n);
         int index = (int) _fieldName_;
         if ( rhsMask(index,SOURCE) && Nfluxes[_fieldName_].nCols() > 0 ) {
           rhs_local[_fieldName_] 
              += N.transMat(weights*Nfluxes[_fieldName_]);
         }
         if ( rhsMask(index,FLUX) && (Bfluxes[_fieldName_][0]).nCols() > 0 ) {
           for (int j = 0; j < nSD_; ++j) {
             rhs_local[_fieldName_] 
               += dN[j]->transMat(weights*Bfluxes[_fieldName_][j]);
           }
         }
       }
     } // end nips > 0
     
     // Share information between processors: rhs_local -> rhs
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       if (rhsMask(_fieldName_,FLUX) || rhsMask(_fieldName_,SOURCE)) {
         DENS_MAT & myRhs(rhs[_fieldName_].set_quantity());
         int count = rhs_local[_fieldName_].size();
         allsum(communicator_, rhs_local[_fieldName_].ptr(), myRhs.ptr(), count);
       }
     }
   }
 
   // -------------------------------------------------------------
   // compute sources using given quadrature
   // -------------------------------------------------------------
   void FE_Engine::compute_source(const Array2D<bool> &rhsMask,
     const FIELDS        &fields,
     const PhysicsModel  *physicsModel,
     const Array<set<int> >&pointMaterialGroups,
     const DIAG_MAT      &weights,
     const SPAR_MAT      &N,
     const SPAR_MAT_VEC  &dN,
     FIELD_MATS          &sources) const
   {
     int nips = weights.nCols();
 
 
     if (nips>0) {
       FIELD_MATS  Nfluxes;
       // compute fields and gradients of fields at given ips
       
       GRAD_FIELD_MATS gradFieldsAtIPs;
       FIELD_MATS fieldsAtIPs;
       for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++) {
         _fieldName_          = _fieldItr_->first;
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         int dof = field.nCols();
         gradFieldsAtIPs[_fieldName_].assign(nSD_,DENS_MAT(nips,dof));
         fieldsAtIPs[_fieldName_] = N*field;
         for (int j = 0; j < nSD_; ++j) {
           gradFieldsAtIPs[_fieldName_][j] = (*dN[j])*field;
         }
       }
 
       // treat single material point sets specially
       int nMatls = pointMaterialGroups.size();
       int atomMatls = 0;
       for (int imat = 0; imat < nMatls; imat++) {
         const set<int> & indices = pointMaterialGroups(imat);
         if ( indices.size() > 0) atomMatls++;
       }
       bool singleMaterial = ( atomMatls == 1 );
       
       
       // evaluate physics model
       if (singleMaterial) 
       {
         int imat = 0;
         const Material *   mat = physicsModel->material(imat);
         for (int n = 0; n < rhsMask.nRows(); n++) {
           _fieldName_ = FieldName(n);
           int index = (int) _fieldName_;
           if (! physicsModel->null(_fieldName_,imat)) {
             if ( rhsMask(index,SOURCE) ) {
               bool has = physicsModel->weak_equation(_fieldName_)->
                 N_integrand(fieldsAtIPs, gradFieldsAtIPs, mat, Nfluxes[_fieldName_]);
               if (! has) throw ATC_Error("atomic source can not be null currently");
             }
           }
         }
       }
       else 
       {
         throw ATC_Error("compute source does not handle multiple materials currently");
       }
       
       // assemble
       for (int n = 0; n < rhsMask.nRows(); n++) {
         _fieldName_ = FieldName(n);
         int index = (int) _fieldName_;
         if ( rhsMask(index,SOURCE) ) {
           sources[_fieldName_] =weights*Nfluxes[_fieldName_];
         }
       }
     }
     
     // no need to share information between processors
   }
 
   // -------------------------------------------------------------
   // compute flux for post processing
   // -------------------------------------------------------------
   void FE_Engine::compute_flux(const Array2D<bool> &rhsMask,
     const FIELDS &fields,
     const PhysicsModel * physicsModel,
     const Array<int>   & elementMaterials,
     GRAD_FIELD_MATS &fluxes,
     const DenseMatrix<bool> *elementMask) const
   {
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       if (rhsMask(_fieldName_,FLUX)) {
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
 
         fluxes[_fieldName_].assign(nSD_, DENS_MAT(field.nRows(),field.nCols()));
       }
     }
 
     // element wise assembly
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       // if element is masked, skip it
       if (elementMask && !(*elementMask)(ielem,0)) continue;
       // material id
       int imat = elementMaterials(ielem);
       const Material * mat = physicsModel->material(imat);
       interpolate_fields(ielem,fields,_conn_,_N_,_dN_,_weights_,
         _fieldsAtIPs_,_gradFieldsAtIPs_);
       _Nw_ = _weights_*_N_;
       // evaluate Physics model & assemble
       for (int n = 0; n < rhsMask.nRows(); n++) {
         _fieldName_ = FieldName(n);
         if (!rhsMask(_fieldName_,FLUX)) continue;
         if (physicsModel->null(_fieldName_,imat)) continue;
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         int dof = field.nCols();
         physicsModel->weak_equation(_fieldName_)->
           B_integrand(_fieldsAtIPs_, _gradFieldsAtIPs_, mat, _Bfluxes_);
         for (int j = 0; j < nSD_; j++) {
           _Nmat_ = _Nw_.transMat(_Bfluxes_[j]);
           for (int i = 0; i < nNodesPerElement_; ++i) {  
             int inode = _conn_(i); 
             for (int k = 0; k < dof; ++k) {
               fluxes[_fieldName_][j](inode,k) += _Nmat_(i,k); 
             } 
           } 
         }
       } 
     } 
     // Assemble partial results
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       if (!rhsMask(_fieldName_,FLUX)) continue;
       for (int j = 0; j < nSD_; j++) {
         allsum(communicator_,MPI_IN_PLACE, fluxes[_fieldName_][j].ptr(), fluxes[_fieldName_][j].size());  
       } 
     }
   }  
 
   //-----------------------------------------------------------------
   // boundary flux using native quadrature
   //-----------------------------------------------------------------
   void FE_Engine::compute_boundary_flux(const Array2D<bool> & rhsMask,
     const FIELDS        & fields,
     const PhysicsModel  * physicsModel,
     const Array<int>    & elementMaterials,
     const set< pair <int,int> > &  faceSet,
     FIELDS & rhs) const
   {
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       if (rhsMask(_fieldName_,FLUX)) {
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         rhs[_fieldName_].reset(field.nRows(),field.nCols());
       }
     }
 
     FIELD_MATS localElementFields; 
     GRAD_FIELD_MATS gradFieldsAtIPs; 
     FIELD_MATS fieldsAtIPs;
 
     for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++) {
       _fieldName_ = _fieldItr_->first;
       const FIELD & field = _fieldItr_->second;
       int dof = field.nCols();
       gradFieldsAtIPs[_fieldName_].reserve(nSD_);
       for (int i = 0; i < nSD_; ++i) {
         gradFieldsAtIPs[_fieldName_].push_back(DENS_MAT(nIPsPerFace_,dof));
       }
       fieldsAtIPs[_fieldName_].reset(nIPsPerFace_,dof);
       localElementFields[_fieldName_].reset(nNodesPerElement_,dof);
     }
   
     // element wise assembly
-    set< PAIR >::const_iterator iter;
+    set< PAIR >::iterator iter;
     for (iter = faceSet.begin(); iter != faceSet.end(); iter++) {
       // get connectivity
       int ielem = iter->first;
       // if this is not our element, do not do calculations
       if (!feMesh_->is_owned_elt(ielem)) continue;
       int imat = elementMaterials(ielem);
       const Material * mat = physicsModel->material(imat);
       _conn_ = feMesh_->element_connectivity_unique(ielem);
 
       // evaluate shape functions at ips
       feMesh_->face_shape_function(*iter, _fN_, _fdN_, _nN_, _fweights_);
 
       // interpolate fields and gradients of fields ips of this element
 
       for (_fieldItr_ = fields.begin(); _fieldItr_ != fields.end(); _fieldItr_++) {
         _fieldName_          = _fieldItr_->first;
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         int dof = field.nCols();
         
         for (int i = 0; i < nNodesPerElement_; i++) {
           for (int j = 0; j < dof; j++) {
             localElementFields[_fieldName_](i,j) = field(_conn_(i),j);
           }
         }
         //  ips X dof    = ips X nodes * nodes X dof
         fieldsAtIPs[_fieldName_] = _fN_*localElementFields[_fieldName_];
         for (int j = 0; j < nSD_; ++j) {
           gradFieldsAtIPs[_fieldName_][j] = _fdN_[j]*localElementFields[_fieldName_];
         }
       }
 
       // Evaluate- physics model
       // do nothing for N_integrand
       // nN : precomputed and held by ATC_Transfer
       // assemble
       for (int n = 0; n < rhsMask.nRows(); n++) {
         _fieldName_ = FieldName(n);
         int index = (int) _fieldName_;
         if ( rhsMask(index,FLUX) ) {
           _fieldItr_ = fields.find(_fieldName_);
           const DENS_MAT & field = (_fieldItr_->second).quantity();
           DENS_MAT & myRhs(rhs[_fieldName_].set_quantity());
           physicsModel->weak_equation(_fieldName_)->
             B_integrand(fieldsAtIPs, gradFieldsAtIPs, mat, _Bfluxes_);
           int dof = field.nCols();
           for (int j = 0; j < nSD_; j++) {
             _Nmat_ = _nN_[j].transMat(_fweights_*_Bfluxes_[j]);
             for (int i = 0; i < nNodesPerElement_; ++i) {
               int inode = _conn_(i);
               for (int k = 0; k < dof; ++k) {
                 myRhs(inode,k) += _Nmat_(i,k);
               }
             }
           }
         }
       }
     }
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       int index = (int) _fieldName_;
       if ( rhsMask(index,FLUX) ) {
         DENS_MAT & myRhs(rhs[_fieldName_].set_quantity());
         allsum(communicator_,MPI_IN_PLACE, myRhs.ptr(), myRhs.size());
       }
     }
   }
 
   // -------------------------------------------------------------
   // compute boundary flux using given quadrature and interpolation
   // -------------------------------------------------------------
   void FE_Engine::compute_boundary_flux(const Array2D<bool>      & rhsMask,
     const FIELDS             & fields,
     const PhysicsModel       * physicsModel,
     const Array< int >       & elementMaterials,
     const Array< set<int> >  & pointMaterialGroups,
     const DIAG_MAT           & _weights_,
     const SPAR_MAT           & N,
     const SPAR_MAT_VEC       & dN,
     const DIAG_MAT           & flux_mask,
     FIELDS                   & flux,
     const DenseMatrix<bool>  * elementMask,
     const set<int>           * nodeSet) const
   {
     
     
     FIELDS rhs, rhsSubset;
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       if (rhsMask(_fieldName_,FLUX)) {
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         int nrows = field.nRows();
         int ncols = field.nCols();
         rhs      [_fieldName_].reset(nrows,ncols);
         rhsSubset[_fieldName_].reset(nrows,ncols);
       }
     }
     
     // R_I    = - int_Omega    Delta _N_I .q dV
     compute_rhs_vector(rhsMask, fields, physicsModel, elementMaterials, rhs, elementMask);
+
     // R_I^md = - int_Omega^md Delta _N_I .q dV
     compute_rhs_vector(rhsMask, fields, physicsModel, pointMaterialGroups, 
       _weights_, N, dN, rhsSubset);
-    
+
     // flux_I = 1/Delta V_I V_I^md R_I + R_I^md
     //   where : Delta V_I = int_Omega _N_I dV
     for (int n = 0; n < rhsMask.nRows(); n++) {
       _fieldName_ = FieldName(n);
       if ( rhsMask(_fieldName_,FLUX) ) { 
         if (nodeSet) {
           _fieldItr_ = fields.find(_fieldName_);
           const DENS_MAT & field = (_fieldItr_->second).quantity();
           int nrows = field.nRows();
           int ncols = field.nCols();
           DENS_MAT & myFlux(flux[_fieldName_].set_quantity());
           const DENS_MAT & myRhsSubset(rhsSubset[_fieldName_].quantity());
           const DENS_MAT & myRhs(rhs[_fieldName_].quantity());
           myFlux.reset(nrows,ncols);
           set<int>::const_iterator iset;
           for (iset = nodeSet->begin(); iset != nodeSet->end(); iset++) {
             for (int j = 0; j < ncols; j++) {
               myFlux(*iset,j) = myRhsSubset(*iset,j) - flux_mask(*iset,*iset)*myRhs(*iset,j);
             }
           }
         }
         else {
           flux[_fieldName_] 
             = rhsSubset[_fieldName_].quantity() - flux_mask*(rhs[_fieldName_].quantity());
         }
       }
     }
   }
 
   /** integrate a nodal field over an element set */
   DENS_VEC FE_Engine::integrate(const DENS_MAT  &field, const ESET & eset) const
   {
     int dof = field.nCols();
     DENS_MAT eField(nNodesPerElement_, dof);
     int nips = nIPsPerElement_; 
     DENS_MAT ipField(nips, dof);
     DENS_VEC integral(dof); integral = 0;
     for (ESET::const_iterator itr = eset.begin(); itr != eset.end(); ++itr) {
       int ielem = *itr;
       // if this is not our element, do not do calculations
       if (!feMesh_->is_owned_elt(ielem)) continue;
       feMesh_->shape_function(ielem,_N_, _weights_);
       _conn_ = feMesh_->element_connectivity_unique(ielem);
       for (int i = 0; i < nNodesPerElement_; i++) {
         for (int j = 0; j < dof; j++) {
           eField(i,j) = field(_conn_(i),j); }}
       ipField = _N_*eField;
       for (int i = 0; i < nips; ++i) {  
         for (int j = 0; j < dof; ++j) {
           integral(j) += ipField(i,j)*_weights_[i]; 
         }
       }
     } 
     // assemble partial results
     allsum(communicator_,MPI_IN_PLACE, integral.ptr(), integral.size());
     return integral;
   }
 
   //-----------------------------------------------------------------
   // Robin boundary flux using native quadrature 
   // integrate \int_delV _N_I s(x,t).n dA
   //-----------------------------------------------------------------
   void FE_Engine::add_robin_fluxes(const Array2D<bool> &rhsMask,
     const FIELDS        & fields,
     const double time,
     const ROBIN_SURFACE_SOURCE & sourceFunctions,
     FIELDS &nodalSources) const
   {
     
     // sizing working arrays
     DENS_MAT xCoords(nSD_,nNodesPerElement_);
     DENS_MAT faceSource;
     DENS_MAT localField;
     DENS_MAT xAtIPs(nSD_,nIPsPerFace_);
     DENS_MAT uAtIPs(nIPsPerFace_,1); 
-
+    FIELDS myNodalSources;
 
     // element wise assembly
     ROBIN_SURFACE_SOURCE::const_iterator src_iter;
-    if (!(rank_zero(communicator_))) {
-      // Zero out unmasked nodal sources on all non-main processors.
-      // This is to avoid counting the previous nodal source values
-      // multiple times when we aggregate.
-      for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++)
-      {
-        _fieldName_ = src_iter->first;
-        if (!rhsMask((int)_fieldName_,ROBIN_SOURCE)) continue; 
-        DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
-        myNodalSources.reset(myNodalSources.nRows(), myNodalSources.nCols());
-      }
+    for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++)
+    {
+      _fieldName_ = src_iter->first;
+      if (!rhsMask((int)_fieldName_,ROBIN_SOURCE)) continue; 
+      DENS_MAT & s(nodalSources[_fieldName_].set_quantity());
+      myNodalSources[_fieldName_] = DENS_MAT(s.nRows(),s.nCols());
     }
     for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++)
     {
       _fieldName_ = src_iter->first;
       if (!rhsMask((int)_fieldName_,ROBIN_SOURCE)) continue; 
       
       typedef map<PAIR,Array<UXT_Function*> > FSET;
       const FSET *fset = (const FSET *)&(src_iter->second);
       FSET::const_iterator fset_iter;
       for (fset_iter = fset->begin(); fset_iter != fset->end(); fset_iter++)
       {
         const PAIR &face = fset_iter->first;
         const int elem = face.first;
         // if this is not our element, do not do calculations
         if (!feMesh_->is_owned_elt(elem)) continue;
         const Array <UXT_Function*> &fs = fset_iter->second;
         _conn_ = feMesh_->element_connectivity_unique(elem);
         // evaluate location at ips
         feMesh_->face_shape_function(face, _fN_, _fdN_, _nN_, _fweights_);
         feMesh_->element_coordinates(elem, xCoords);
         xAtIPs = xCoords*(_fN_.transpose()); 
         // collect field
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         feMesh_->element_field(elem, field, localField);
         uAtIPs = _fN_*localField;
 
         // interpolate prescribed flux at ips of this element
         FSET::const_iterator face_iter = fset->find(face);
         int nFieldDOF = (face_iter->second).size();
         faceSource.reset(nIPsPerFace_,nFieldDOF);
         for (int ip = 0; ip < nIPsPerFace_; ++ip) {
           for (int idof = 0; idof<nFieldDOF; ++idof) {
             UXT_Function * f = fs(idof);
             if (!f) continue;
 
             faceSource(ip,idof) = f->f(&(uAtIPs(ip,0)),
                                        column(xAtIPs,ip).ptr(),time);
 
             DENS_MAT coefsAtIPs(nIPsPerFace_,1);
             coefsAtIPs(ip,idof) = f->dfdu(&(uAtIPs(ip,0)),
                                        column(xAtIPs,ip).ptr(),time);
             faceSource(ip,idof) -= coefsAtIPs(ip,0)*uAtIPs(ip,0);
           }
         }
         
         // assemble
-        DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
+        DENS_MAT & s(myNodalSources[_fieldName_].set_quantity());
         _Nmat_ = _fN_.transMat(_fweights_*faceSource);
         for (int i = 0; i < nNodesPerElement_; ++i) {
           int inode = _conn_(i);
           for (int idof = 0; idof < nFieldDOF; ++idof) {
-            myNodalSources(inode,idof) += _Nmat_(i,idof);
+            s(inode,idof) += _Nmat_(i,idof);
           }  
         } 
       }  
     } 
     // assemble partial result matrices
     for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++) {
       _fieldName_ = src_iter->first;
       if (!rhsMask((int) _fieldName_,ROBIN_SOURCE)) continue; 
-      DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
-      allsum(communicator_,MPI_IN_PLACE, myNodalSources.ptr(), myNodalSources.size());  
+      DENS_MAT & s(myNodalSources[_fieldName_].set_quantity());
+      allsum(communicator_,MPI_IN_PLACE, s.ptr(), s.size());  
+      DENS_MAT & src(nodalSources[_fieldName_].set_quantity());
+      src += s;
     }
   }
 
   //-----------------------------------------------------------------
   // Robin boundary flux stiffness using native quadrature 
   // integrate \int_delV _N_I ds/du(x,t).n dA
   //-----------------------------------------------------------------
   void FE_Engine::add_robin_tangent(const Array2D<bool> &rhsMask,
     const FIELDS        & fields,
     const double time,
     const ROBIN_SURFACE_SOURCE & sourceFunctions,
     SPAR_MAT &tangent) const
   {
     
     // sizing working arrays
     DENS_MAT xCoords(nSD_,nNodesPerElement_);
     DENS_MAT coefsAtIPs;
     DENS_MAT localField;
     DENS_MAT xAtIPs(nSD_,nIPsPerFace_);
     DENS_MAT uAtIPs(nIPsPerFace_,1);
 
     // element wise assembly
     ROBIN_SURFACE_SOURCE::const_iterator src_iter;
-    if (!(rank_zero(communicator_))) {
-      // Zero out result (tangent) matrix on all non-main processors
-      // to avoid multiple-counting of the values already in tangent 
-      tangent.reset(tangent.nRows(), tangent.nCols());
-    }
+    SPAR_MAT K(tangent.nRows(), tangent.nCols());
     for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++)
     {
       _fieldName_ = src_iter->first;
       if (!rhsMask((int)_fieldName_,ROBIN_SOURCE)) continue; 
       
       typedef map<PAIR,Array<UXT_Function*> > FSET;
       const FSET *fset = (const FSET *)&(src_iter->second);
       FSET::const_iterator fset_iter;
       for (fset_iter = fset->begin(); fset_iter != fset->end(); fset_iter++)
       {
         const PAIR &face = fset_iter->first;
         const int elem = face.first;
         // if this is not our element, do not do calculations
         if (!feMesh_->is_owned_elt(elem)) continue;
         const Array <UXT_Function*> &fs = fset_iter->second;
         _conn_ = feMesh_->element_connectivity_unique(elem);
         // evaluate location at ips
         feMesh_->face_shape_function(face, _fN_, _fdN_, _nN_, _fweights_);
         feMesh_->element_coordinates(elem, xCoords);
         xAtIPs = xCoords*(_fN_.transpose()); 
         // collect field
         _fieldItr_ = fields.find(_fieldName_);
         const DENS_MAT & field = (_fieldItr_->second).quantity();
         feMesh_->element_field(elem, field, localField);
         uAtIPs = _fN_*localField;
 
         // interpolate prescribed flux at ips of this element
         FSET::const_iterator face_iter = fset->find(face);
         int nFieldDOF = (face_iter->second).size();
         coefsAtIPs.reset(nIPsPerFace_,nFieldDOF);
         for (int ip = 0; ip < nIPsPerFace_; ++ip) {
           for (int idof = 0; idof<nFieldDOF; ++idof) {
             UXT_Function * f = fs(idof);
             if (!f) continue;
             coefsAtIPs(ip,idof) = f->dfdu(&(uAtIPs(ip,0)),
                                        column(xAtIPs,ip).ptr(),time);
           }
         }
         
         // assemble
         DIAG_MAT D(column(coefsAtIPs,0)); 
         D *= -1; 
-
         D *= _fweights_; 
         _Nmat_ = _fN_.transMat(D*_fN_);
         for (int i = 0; i < nNodesPerElement_; ++i) {
           int inode = _conn_(i);
           for (int j = 0; j < nNodesPerElement_; ++j) {
             int jnode = _conn_(j);
-            tangent.add(inode, jnode, _Nmat_(i,j));
+            K.add(inode, jnode, _Nmat_(i,j));
           }  
         } 
       }  
     } 
     // assemble partial result matrices
 #ifdef ISOLATE_FE
-    sparse_allsum(communicator_,tangent);
+    sparse_allsum(communicator_,K);
 #else
-    LammpsInterface::instance()->sparse_allsum(tangent);
+    LammpsInterface::instance()->sparse_allsum(K);
+#endif
+    tangent += K;
+  }
+
+  //-----------------------------------------------------------------
+  // Robin boundary flux using native quadrature 
+  // integrate \int_delV _N_I s(x,t).n dA
+  //-----------------------------------------------------------------
+  void FE_Engine::add_open_fluxes(const Array2D<bool> &rhsMask,
+                                  const FIELDS        & fields,
+                                  const OPEN_SURFACE  & openFaces,
+                                  FIELDS &nodalSources,
+                                  const FieldName Velocity) const
+  {
+    
+    // sizing working arrays
+    DENS_MAT xCoords(nSD_,nNodesPerElement_);
+    DENS_MAT faceSource;
+    DENS_MAT localField;
+    DENS_MAT xAtIPs(nSD_,nIPsPerFace_);
+    DENS_MAT uAtIPs; // (nIPsPerFace_,field nCols);
+    DENS_MAT aAtIPs(nIPsPerFace_,1);
+    FIELDS myNodalSources;
+
+    // throw error if electron velocity is not defined
+
+    // element wise assembly
+    OPEN_SURFACE::const_iterator face_iter;
+    for (face_iter=openFaces.begin(); face_iter!=openFaces.end(); face_iter++)
+    {
+      _fieldName_ = face_iter->first;
+      if (!rhsMask((int)_fieldName_,OPEN_SOURCE)) continue; 
+      DENS_MAT & s(nodalSources[_fieldName_].set_quantity());
+      myNodalSources[_fieldName_] = DENS_MAT(s.nRows(),s.nCols());
+    }
+    for (face_iter=openFaces.begin(); face_iter!=openFaces.end(); face_iter++)
+    {
+      _fieldName_ = face_iter->first;
+      if (!rhsMask((int)_fieldName_,OPEN_SOURCE)) continue; 
+      
+      typedef set<PAIR> FSET;
+      const FSET *fset = (const FSET *)&(face_iter->second);
+      FSET::const_iterator fset_iter;
+      for (fset_iter = fset->begin(); fset_iter != fset->end(); fset_iter++)
+      {
+        const PAIR &face = *fset_iter;
+        const int elem = face.first;
+        // if this is not our element, do not do calculations
+        if (!feMesh_->is_owned_elt(elem)) continue;
+        // get velocity, multiply with field (vector gives tensor)
+        // dot with face normal
+        _conn_ = feMesh_->element_connectivity_unique(elem);
+        // evaluate location at ips
+        feMesh_->face_shape_function(face, _fN_, _fdN_, _nN_, _fweights_);
+        // collect field at ips
+        _fieldItr_ = fields.find(_fieldName_);
+        const DENS_MAT & field = (_fieldItr_->second).quantity();
+        feMesh_->element_field(elem, field, localField);
+        int nFieldDOF = field.nCols();
+        // "u" is the quantity being advected
+        uAtIPs.reset(nIPsPerFace_,nFieldDOF);
+        uAtIPs = _fN_*localField;
+        // collect velocity at ips for "advection" = v.n
+        _fieldItr_ = fields.find(Velocity);
+        const DENS_MAT & advection = (_fieldItr_->second).quantity(); // advection velocity
+        feMesh_->element_field(elem, advection, localField);
+        for (int j = 0; j < nSD_; ++j) { // nSD_ == nDOF for the velocity
+          for (int ip = 0; ip < nIPsPerFace_; ++ip) {
+            for (int I = 0; I < nNodesPerElement_; ++I) {
+              aAtIPs(ip,0) += (_nN_[j])(ip,I)*localField(I,j);
+            }
+          }
+        }
+        // construct open flux at ips of this element
+        // flux = field \otimes advection_vector \dot n
+        FSET::const_iterator face_iter = fset->find(face);
+        faceSource.reset(nIPsPerFace_,nFieldDOF);
+        for (int ip = 0; ip < nIPsPerFace_; ++ip) {
+          for (int idof = 0; idof<nFieldDOF; ++idof) {
+            // multiply field DOF value times advection vector
+            faceSource(ip,idof) = aAtIPs(ip,1)*uAtIPs(ip,idof);//(v.n) u
+          }
+        }
+        // assemble contributions for this direction of the face normal
+        // _nN_[j](ip,I) nodal shapefunction(I) at ip X face normal(j)
+        // _fweights_ diagonal nips X nips ==> facesource is nips X ndofs
+        DENS_MAT & s(myNodalSources[_fieldName_].set_quantity());
+        _Nmat_ = _fN_.transMat(_fweights_*faceSource);
+        // s_Ii = \sum_ip N_I (u_i v.n)_ip wg_ip
+        for (int i = 0; i < nNodesPerElement_; ++i) {
+          int inode = _conn_(i);
+          for (int idof = 0; idof < nFieldDOF; ++idof) {
+            s(inode,idof) += _Nmat_(i,idof);
+          }  
+        }
+      }  
+    } 
+    // assemble partial result matrices
+    for (face_iter=openFaces.begin(); face_iter!=openFaces.end(); face_iter++) {
+      _fieldName_ = face_iter->first;
+      if (!rhsMask((int) _fieldName_,OPEN_SOURCE)) continue; 
+      DENS_MAT & s(myNodalSources[_fieldName_].set_quantity());
+      allsum(communicator_,MPI_IN_PLACE, s.ptr(), s.size());  
+      DENS_MAT & src(nodalSources[_fieldName_].set_quantity());
+      src += s;
+    }
+  }
+
+  //-----------------------------------------------------------------
+  // Open boundary flux stiffness using native quadrature 
+  // integrate \int_delV _N_I ds/du(x,t).n dA
+  //-----------------------------------------------------------------
+  void FE_Engine::add_open_tangent(const Array2D<bool> &rhsMask,
+    const FIELDS        & fields,
+    const OPEN_SURFACE  & openFaces,
+    SPAR_MAT &tangent,
+    const FieldName Velocity) const
+  {
+    
+    // sizing working arrays
+    DENS_MAT xCoords(nSD_,nNodesPerElement_);
+    DENS_MAT faceSource;
+    DENS_MAT localField;
+    DENS_MAT xAtIPs(nSD_,nIPsPerFace_);
+    DENS_MAT uAtIPs; // (nIPsPerFace_,field nCols);
+    DENS_MAT aAtIPs(nIPsPerFace_,nSD_);
+    SPAR_MAT K(tangent.nRows(), tangent.nCols());
+    // element wise assembly
+    OPEN_SURFACE::const_iterator face_iter;
+    for (face_iter=openFaces.begin(); face_iter!=openFaces.end(); face_iter++)
+    {
+      _fieldName_ = face_iter->first;
+      if (!rhsMask((int)_fieldName_,OPEN_SOURCE)) continue; 
+      bool convective = false;
+      if (_fieldName_ == Velocity) convective = true;
+      
+      typedef set<PAIR> FSET;
+      const FSET *fset = (const FSET *)&(face_iter->second);
+      FSET::const_iterator fset_iter;
+      for (fset_iter = fset->begin(); fset_iter != fset->end(); fset_iter++)
+      {
+        const PAIR &face = *fset_iter;
+        const int elem = face.first;
+        // if this is not our element, do not do calculations
+        if (!feMesh_->is_owned_elt(elem)) continue;
+        _conn_ = feMesh_->element_connectivity_unique(elem);
+        // evaluate location at ips
+        feMesh_->face_shape_function(face, _fN_, _fdN_, _nN_, _fweights_);
+        // collect field at ips
+        _fieldItr_ = fields.find(_fieldName_);
+        const DENS_MAT & field = (_fieldItr_->second).quantity();
+        feMesh_->element_field(elem, field, localField);
+        int nFieldDOF = field.nCols();
+        // "u" is the quantity being advected
+        uAtIPs.reset(nIPsPerFace_,nFieldDOF);
+        uAtIPs = _fN_*localField;
+        // collect velocity at ips for "advection" = v.n
+        _fieldItr_ = fields.find(Velocity);
+        const DENS_MAT & advection = (_fieldItr_->second).quantity(); // advection velocity
+        feMesh_->element_field(elem, advection, localField);
+        for (int j = 0; j < nSD_; ++j) { // nSD_ == nDOF for the velocity
+          for (int ip = 0; ip < nIPsPerFace_; ++ip) {
+            for (int I = 0; I < nNodesPerElement_; ++I) {
+              aAtIPs(ip,0) += (_nN_[j])(ip,I)*localField(I,j);
+            }
+          }
+        }
+        // K_IJ = \sum_ip N_I ( v.n I + u (x) n ) N_J wg_ip
+        DENS_MAT D(nFieldDOF,nFieldDOF);
+        DENS_VEC n(nSD_);
+        for (int ip = 0; ip < nIPsPerFace_; ++ip) {
+          for (int idof = 0; idof<nFieldDOF; ++idof) {
+            D(idof,idof) -= aAtIPs(ip,0);
+            if (convective) {
+              feMesh_->face_normal(face,ip,n);
+              for (int jdof = 0; jdof<nFieldDOF; ++jdof) {
+                D(idof,jdof) -=  uAtIPs(ip,idof)*n(jdof);
+              }
+            }
+          }
+        }
+        // assemble
+        _Nmat_ = _fN_.transMat(D*_fN_);
+        for (int i = 0; i < nNodesPerElement_; ++i) {
+          int inode = _conn_(i);
+          for (int j = 0; j < nNodesPerElement_; ++j) {
+            int jnode = _conn_(j);
+            K.add(inode, jnode, _Nmat_(i,j));
+          }  
+        } 
+      }  
+    } 
+    // assemble partial result matrices
+#ifdef ISOLATE_FE
+    sparse_allsum(communicator_,K);
+#else
+    LammpsInterface::instance()->sparse_allsum(K);
 #endif
+    tangent += K;
   }
   
   //-----------------------------------------------------------------
   // prescribed boundary flux using native quadrature 
   // integrate \int_delV _N_I s(x,t).n dA
   //-----------------------------------------------------------------
   void FE_Engine::add_fluxes(const Array<bool> &fieldMask,
     const double time,
     const SURFACE_SOURCE & sourceFunctions,
     FIELDS &nodalSources) const
   {
     
     // sizing working arrays
     DENS_MAT xCoords(nSD_,nNodesPerElement_);
     DENS_MAT xAtIPs(nSD_,nIPsPerFace_);
     DENS_MAT faceSource;
+    FIELDS myNodalSources;
 
     // element wise assembly
     SURFACE_SOURCE::const_iterator src_iter;
-    if (!(rank_zero(communicator_))) {
-      // Zero out unmasked nodal sources on all non-main processors.
-      // This is to avoid counting the previous nodal source values
-      // multiple times when we aggregate.
-      for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++)
-      {
-        _fieldName_ = src_iter->first;
-        if (!fieldMask((int)_fieldName_)) continue; 
-        DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
-        myNodalSources.reset(myNodalSources.nRows(), myNodalSources.nCols());
-      }
+    for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++)
+    {
+      _fieldName_ = src_iter->first;
+      if (!fieldMask((int)_fieldName_)) continue; 
+      DENS_MAT & s(nodalSources[_fieldName_].set_quantity());
+      myNodalSources[_fieldName_] = DENS_MAT(s.nRows(),s.nCols());
     }
     for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++)
     {
       _fieldName_ = src_iter->first;
       if (!fieldMask((int)_fieldName_)) continue; 
       
       typedef map<PAIR,Array<XT_Function*> > FSET;
       const FSET *fset = (const FSET *)&(src_iter->second);
       FSET::const_iterator fset_iter;
       for (fset_iter = fset->begin(); fset_iter != fset->end(); fset_iter++)
       {
         const PAIR &face = fset_iter->first;
         const int elem = face.first;
         // if this is not our element, do not do calculations
         if (!feMesh_->is_owned_elt(elem)) continue;
         const Array <XT_Function*> &fs = fset_iter->second;
         _conn_ = feMesh_->element_connectivity_unique(elem);
         // evaluate location at ips
         feMesh_->face_shape_function(face, _fN_, _fdN_, _nN_, _fweights_);
         feMesh_->element_coordinates(elem, xCoords);
 
         MultAB(xCoords,_fN_,xAtIPs,0,1); //xAtIPs = xCoords*(N.transpose());
 
         // interpolate prescribed flux at ips of this element
         
         FSET::const_iterator face_iter = fset->find(face);
         if (face_iter == fset->end()) 
         {  
           stringstream ss;
           ss << "face not found" << std::endl;
           print_msg(communicator_,ss.str());
           
         }
         
         
         int nFieldDOF = (face_iter->second).size();
         faceSource.reset(nIPsPerFace_,nFieldDOF);
         for (int ip = 0; ip < nIPsPerFace_; ++ip) {
           for (int idof = 0; idof<nFieldDOF; ++idof) {
             XT_Function * f = fs(idof);
             if (!f) continue;
             faceSource(ip,idof) = f->f(column(xAtIPs,ip).ptr(),time);
           }
         }
         
         // assemble
-        DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
+        DENS_MAT & s(myNodalSources[_fieldName_].set_quantity());
         _Nmat_ = _fN_.transMat(_fweights_*faceSource);
         for (int i = 0; i < nNodesPerElement_; ++i) 
         {
           int inode = _conn_(i);
           for (int idof = 0; idof < nFieldDOF; ++idof) 
           {
-            myNodalSources(inode,idof) += _Nmat_(i,idof);
+            s(inode,idof) += _Nmat_(i,idof);
           }  // end assemble nFieldDOF
         }  // end assemble nNodesPerElement_
       }  // end fset loop
     } // field loop
     // assemble partial result matrices
     for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++) {
       _fieldName_ = src_iter->first;
       if (!fieldMask((int)_fieldName_)) continue; 
-      DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
-      allsum(communicator_,MPI_IN_PLACE, myNodalSources.ptr(), myNodalSources.size());  
+      DENS_MAT & s(myNodalSources[_fieldName_].set_quantity());
+      allsum(communicator_,MPI_IN_PLACE, s.ptr(), s.size());  
+      DENS_MAT & src(nodalSources[_fieldName_].set_quantity());
+      src += s;
     }
   }
 
   //-----------------------------------------------------------------
   // prescribed volume flux using native quadrature 
   // integrate \int_V _N_I s(x,t) dV
   //-----------------------------------------------------------------
   void FE_Engine::add_sources(const Array<bool> &fieldMask,
     const double time,
     const VOLUME_SOURCE &sourceFunctions,
     FIELDS &nodalSources) const
   {
     
     // sizing working arrays
     DENS_MAT elemSource;
     DENS_MAT xCoords(nSD_,nNodesPerElement_);
     DENS_MAT xAtIPs(nSD_,nIPsPerElement_);
+    FIELDS myNodalSources;
 
-    if (!(rank_zero(communicator_))) {
-      // Zero out unmasked nodal sources on all non-main processors.
-      // This is to avoid counting the previous nodal source values
-      // multiple times when we aggregate.
-      for (VOLUME_SOURCE::const_iterator src_iter = sourceFunctions.begin(); 
-           src_iter != sourceFunctions.end(); src_iter++) {
-        _fieldName_ = src_iter->first;
-        int index = (int) _fieldName_;
-        if (fieldMask(index)) {
-          DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
-          myNodalSources.reset(myNodalSources.nRows(), myNodalSources.nCols());
-        }
-      }
+    for (VOLUME_SOURCE::const_iterator src_iter = sourceFunctions.begin(); 
+         src_iter != sourceFunctions.end(); src_iter++) {
+      _fieldName_ = src_iter->first;
+      int index = (int) _fieldName_;
+      if (! fieldMask(index)) continue;
+      DENS_MAT & s(nodalSources[_fieldName_].set_quantity());
+      myNodalSources[_fieldName_] = DENS_MAT(s.nRows(),s.nCols());
     }
-
     vector<int> myElems = feMesh_->owned_elts();
-    for (vector<int>::const_iterator elemsIter = myElems.begin();
+    for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
     {
       int ielem = *elemsIter;
       _conn_ = feMesh_->element_connectivity_unique(ielem);
       // evaluate location at ips
       feMesh_->shape_function(ielem, _N_, _weights_);
       feMesh_->element_coordinates(ielem, xCoords);
       xAtIPs =xCoords*(_N_.transpose());
       for (VOLUME_SOURCE::const_iterator src_iter = sourceFunctions.begin(); 
            src_iter != sourceFunctions.end(); src_iter++) {
         _fieldName_ = src_iter->first;
         int index = (int) _fieldName_; 
         if ( fieldMask(index) ) {
           const Array2D<XT_Function *> * thisSource 
             = (const Array2D<XT_Function *> *) &(src_iter->second);
           int nFieldDOF = thisSource->nCols();
           elemSource.reset(nIPsPerElement_,nFieldDOF);
           // interpolate prescribed flux at ips of this element
           for (int ip = 0; ip < nIPsPerElement_; ++ip) {
             for (int idof = 0; idof < nFieldDOF; ++idof) {
               XT_Function * f = (*thisSource)(ielem,idof);
               if (f) {
                 elemSource(ip,idof) = f->f(column(xAtIPs,ip).ptr(),time);
               }
             }
           }
           // assemble
           _Nmat_ = _N_.transMat(_weights_*elemSource);
-          DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
+          DENS_MAT & s(myNodalSources[_fieldName_].set_quantity());
           
           for (int i = 0; i < nNodesPerElement_; ++i) {
             int inode = _conn_(i);
             for (int idof = 0; idof < nFieldDOF; ++idof) {
-              myNodalSources(inode,idof) += _Nmat_(i,idof);
+              s(inode,idof) += _Nmat_(i,idof);
             }
           }
         }
       }
     }
     // Aggregate unmasked nodal sources on all processors.
     for (VOLUME_SOURCE::const_iterator src_iter = sourceFunctions.begin(); 
          src_iter != sourceFunctions.end(); src_iter++) {
       _fieldName_ = src_iter->first;
       int index = (int) _fieldName_;
-      if (fieldMask(index)) {
-        DENS_MAT & myNodalSources(nodalSources[_fieldName_].set_quantity());
-        allsum(communicator_,MPI_IN_PLACE, myNodalSources.ptr(), myNodalSources.size());  
+      if (!fieldMask(index)) continue;
+      DENS_MAT & s(myNodalSources[_fieldName_].set_quantity());
+      allsum(communicator_,MPI_IN_PLACE, s.ptr(), s.size());  
+      DENS_MAT & src(nodalSources[_fieldName_].set_quantity());
+      src += s;
+    }
+  }
+  //-----------------------------------------------------------------
+  // previously computed nodal sources
+  //-----------------------------------------------------------------
+  void FE_Engine::add_sources(const Array<bool> &fieldMask,
+    const double time,
+    const FIELDS &sources,
+    FIELDS &nodalSources) const
+  {
+    FIELDS::const_iterator itr;
+    for (itr=sources.begin(); itr!=sources.end(); itr++) {
+      _fieldName_ = itr->first;
+      if (!fieldMask((int)_fieldName_)) continue; 
+      DENS_MAT & src(nodalSources[_fieldName_].set_quantity());
+      const DENS_MAT &  s((sources.find(_fieldName_)->second).quantity());
+      for (int inode = 0; inode < nNodesUnique_; ++inode) {
+        for (int j = 0; j < src.nCols(); ++j) {
+          src(inode,j) += s(inode,j);
+        }
       }
     }
   }
 
   //-----------------------------------------------------------------
   // boundary integral of a nodal field
   //-----------------------------------------------------------------
   void FE_Engine::field_surface_flux(
     const DENS_MAT & field,
     const set< PAIR > &  faceSet,
     DENS_MAT & values,
     const bool contour,
     const int axis) const
   {
     int dof = field.nCols();
 
     double a[3] = {0,0,0};
     a[axis] = 1;
 
     // sizing working arrays
     DENS_MAT n(nSD_,nIPsPerFace_);
     DENS_MAT localElementFields(nNodesPerElement_,dof);
     DENS_MAT integrals(dof,nSD_); 
     DENS_MAT fieldsAtIPs; 
                           // SJL shouldn't this just be _fieldsAtIPs_
                           // the data member?
 
     // element wise assembly
-    set< pair <int,int> >::const_iterator iter;
+    set< pair <int,int> >::iterator iter;
     for (iter = faceSet.begin(); iter != faceSet.end(); iter++) {
       int ielem = iter->first;
       // if this is not our element, do not do calculations
       //if (!feMesh_->is_owned_elt(ielem)) continue;
 
       // evaluate shape functions at ips
       feMesh_->face_shape_function(*iter, _N_, n, _fweights_);
       // cross n with axis to get tangent
       if (contour) {
         double t[3];
         for (int i = 0; i < nIPsPerFace_; i++) {
           t[0] = a[1]*n(2,i) - a[2]*n(1,i);
           t[1] = a[2]*n(0,i) - a[0]*n(2,i);
           t[2] = a[0]*n(1,i) - a[1]*n(0,i);
           n(0,i) = t[0];
           n(1,i) = t[1];
           n(2,i) = t[2];
         }
       }
 
       // get connectivity
       _conn_ = feMesh_->element_connectivity_unique(ielem);
 
       // interpolate fields and gradients of fields ips of this element
       for (int i = 0; i < nNodesPerElement_; i++) {
         for (int j = 0; j < dof; j++) {
           localElementFields(i,j) = field(_conn_(i),j);
         }
       }
       //  ips X dof    = ips X nodes * nodes X dof
       fieldsAtIPs = _N_*localElementFields;
 
       // assemble : integral(k,j) = sum_ip n(j,ip) wg(ip,ip) field(ip,k)
       _Nmat_ = n*_fweights_*fieldsAtIPs;
       for (int j = 0; j < nSD_; j++) {
         for (int k = 0; k < dof; ++k) {
           integrals(k,j) += _Nmat_(j,k);
         }
       }
     }
     // assemble partial results
     //LammpsInterface::instance()->allsum(MPI_IN_PLACE, integrals.ptr(), integrals.size());
     // (S.n)_1 = S_1j n_j = S_11 n_1 + S_12 n_2 + S_13 n_3
     // (S.n)_2 = S_2j n_j = S_21 n_1 + S_22 n_2 + S_23 n_3
     // (S.n)_3 = S_3j n_j = S_31 n_1 + S_32 n_2 + S_33 n_3
     if (dof == 9) { // tensor
       values.reset(nSD_,1);
       values(0,0) = integrals(0,0)+integrals(1,1)+integrals(2,2);
       values(1,0) = integrals(3,0)+integrals(4,1)+integrals(5,2);
       values(2,0) = integrals(6,0)+integrals(7,1)+integrals(8,2);
     }
     else if (dof == 6) { // sym tensor
       values.reset(nSD_,1);
       values(0,0) = integrals(0,0)+integrals(3,1)+integrals(4,2);
       values(1,0) = integrals(3,0)+integrals(1,1)+integrals(5,2);
       values(2,0) = integrals(4,1)+integrals(5,1)+integrals(2,2);
     }
     // (v.n) = v_j n_j 
     else if (dof == 3) { // vector
       values.reset(1,1);
       values(0,0) = integrals(0,0)+integrals(1,1)+integrals(2,2);
     }
     // s n = s n_j e_j
     else if (dof == 1) { // scalar
       values.reset(nSD_,1);
       values(0,0) = integrals(0,0);
       values(1,0) = integrals(0,1);
       values(2,0) = integrals(0,2);
     }
     else {
       string msg = "FE_Engine::field_surface_flux unsupported field width: ";
       msg += to_string(dof);
       throw ATC_Error(msg);
     }
   }
 
   //-----------------------------------------------------------------
   // evaluate shape functions at given points
   //-----------------------------------------------------------------
   
   void FE_Engine::evaluate_shape_functions(
     const MATRIX & pt_coords,
     SPAR_MAT & N) const
   {
     // Get shape function and derivatives at atomic locations
     int nnodes = feMesh_->num_nodes_unique();
     int npts = pt_coords.nRows();
     
     // loop over point (atom) coordinates
     DENS_VEC x(nSD_);
     Array<int> node_index(nNodesPerElement_);
     DENS_VEC shp(nNodesPerElement_);
     
     N.reset(npts,nnodes);
     for (int i = 0; i < npts; ++i) {
       for (int k = 0; k < nSD_; ++k) { x(k) = pt_coords(i,k); }
       feMesh_->shape_functions(x,shp,node_index);
       for (int j = 0; j < nNodesPerElement_; ++j) {
         int jnode = node_index(j);
         N.add(i,jnode,shp(j));
       }
     }
     N.compress();   
   }
 
   //-----------------------------------------------------------------
   // evaluate shape functions and their spatial derivatives at given points
   //-----------------------------------------------------------------
   void FE_Engine::evaluate_shape_functions(
     const MATRIX & pt_coords,
     SPAR_MAT & N,
     SPAR_MAT_VEC & dN) const
   {
     // Get shape function and derivatives at atomic locations
     int nnodes = feMesh_->num_nodes_unique();
     int npts = pt_coords.nRows();
 
     // loop over point (atom) coordinates
     DENS_VEC x(nSD_);
     Array<int> node_index(nNodesPerElement_);
     DENS_VEC shp(nNodesPerElement_);
     DENS_MAT dshp(nSD_,nNodesPerElement_);
     
     for (int k = 0; k < nSD_; ++k) {
       dN[k]->reset(npts,nnodes);    
     }
           
     N.reset(npts,nnodes); 
     for (int i = 0; i < npts; ++i) {
       for (int k = 0; k < nSD_; ++k) { x(k) = pt_coords(i,k); }
       feMesh_->shape_functions(x,shp,dshp,node_index);
       for (int j = 0; j < nNodesPerElement_; ++j) {
         int jnode = node_index(j);
         N.add(i,jnode,shp(j));
         for (int k = 0; k < nSD_; ++k) {
           dN[k]->add(i,jnode,dshp(k,j));
         }
       }
     }
     N.compress();   
     for (int k = 0; k < nSD_; ++k) { 
       dN[k]->compress();   
     }
   }
 
   //-----------------------------------------------------------------
   // evaluate shape functions at given points
   //-----------------------------------------------------------------
     void FE_Engine::evaluate_shape_functions(
     const MATRIX & pt_coords,
     const INT_ARRAY & pointToEltMap,
     SPAR_MAT & N) const
   {
     // Get shape function and derivatives at atomic locations
     int nnodes = feMesh_->num_nodes_unique();
     int npts = pt_coords.nRows();
     
     // loop over point (atom) coordinates
     DENS_VEC x(nSD_);
     Array<int> node_index(nNodesPerElement_);
     DENS_VEC shp(nNodesPerElement_);
     
     N.reset(npts,nnodes);
     for (int i = 0; i < npts; ++i) {
       for (int k = 0; k < nSD_; ++k) { x(k) = pt_coords(i,k); }
       int eltId = pointToEltMap(i,0);
       feMesh_->shape_functions(x,eltId,shp,node_index);
       for (int j = 0; j < nNodesPerElement_; ++j) {
         int jnode = node_index(j);
         N.add(i,jnode,shp(j));
       }
     }
     N.compress();   
   }
 
   //-----------------------------------------------------------------
   // evaluate shape functions and their spatial derivatives at given points
   //-----------------------------------------------------------------
   void FE_Engine::evaluate_shape_functions(
     const MATRIX & pt_coords,
     const INT_ARRAY & pointToEltMap,
     SPAR_MAT & N,
     SPAR_MAT_VEC & dN) const
   {
     // Get shape function and derivatives at atomic locations
     int nnodes = feMesh_->num_nodes_unique();
     int npts = pt_coords.nRows();
 
     // loop over point (atom) coordinates
     DENS_VEC x(nSD_);
     Array<int> node_index(nNodesPerElement_);
     DENS_VEC shp(nNodesPerElement_);
     DENS_MAT dshp(nSD_,nNodesPerElement_);
     for (int k = 0; k < nSD_; ++k) {
       dN[k]->reset(npts,nnodes);    
     }
           
     N.reset(npts,nnodes); 
     for (int i = 0; i < npts; ++i) {
       for (int k = 0; k < nSD_; ++k) { x(k) = pt_coords(i,k); }
       int eltId = pointToEltMap(i,0);
       feMesh_->shape_functions(x,eltId,shp,dshp,node_index);
       for (int j = 0; j < nNodesPerElement_; ++j) {
         int jnode = node_index(j);
         N.add(i,jnode,shp(j));
         for (int k = 0; k < nSD_; ++k) {
           dN[k]->add(i,jnode,dshp(k,j));
         }
       }
     }
     N.compress();   
     for (int k = 0; k < nSD_; ++k) { 
       dN[k]->compress();   
     }
   }
   //-----------------------------------------------------------------
   // evaluate shape functions spatial derivatives at given points
   //-----------------------------------------------------------------
   void FE_Engine::evaluate_shape_function_derivatives(
     const MATRIX & pt_coords,
     const INT_ARRAY & pointToEltMap,
     SPAR_MAT_VEC & dNdx ) const
   {
     int nnodes = feMesh_->num_nodes_unique();
     int npts = pt_coords.nRows();
     for (int k = 0; k < nSD_; ++k) {
       dNdx[k]->reset(npts,nnodes);    
     }
 
     // loop over point (atom) coordinates
     DENS_VEC x(nSD_);
     Array<int> node_index(nNodesPerElement_);
     DENS_MAT dshp(nSD_,nNodesPerElement_);
     
     for (int i = 0; i < npts; ++i) {
       for (int k = 0; k < nSD_; ++k) { x(k) = pt_coords(i,k); }
       int eltId = pointToEltMap(i,0);
       feMesh_->shape_function_derivatives(x,eltId,dshp,node_index);
       for (int j = 0; j < nNodesPerElement_; ++j) {
         int jnode = node_index(j);
         for (int k = 0; k < nSD_; ++k) {
           dNdx[k]->add(i,jnode,dshp(k,j));
         }
       }
     }
     for (int k = 0; k < nSD_; ++k) { 
       dNdx[k]->compress();   
     }
   }
 
   //-------------------------------------------------------------------
   // set kernels
   //-------------------------------------------------------------------
   void FE_Engine::set_kernel(KernelFunction* ptr){kernelFunction_=ptr;}
 
   //-------------------------------------------------------------------
   // kernel_matrix_bandwidth
   //-------------------------------------------------------------------
   int FE_Engine::kernel_matrix_bandwidth(
     const MATRIX & ptCoords) const
   {
 
     if (! kernelFunction_) throw ATC_Error("no kernel function specified");
     int npts = ptCoords.nRows();
     int bw = 0;
     if (npts>0) {
       DENS_VEC xI(nSD_),x(nSD_),dx(nSD_);
       for (int i = 0; i < nNodes_; i++) {
         xI = feMesh_->global_coordinates(i);
         for (int j = 0; j < npts; j++) {
           for (int k = 0; k < nSD_; ++k) { x(k) = ptCoords(j,k); } 
           dx = x - xI;
           if (kernelFunction_->in_support(dx)) bw = max(bw,abs(j-map_global_to_unique(i)));
         }
       }
     }
     return bw;
   }
   //-------------------------------------------------------------------
   // evaluate kernels
   //-------------------------------------------------------------------
   void FE_Engine::evaluate_kernel_functions(
     const MATRIX & ptCoords,
     SPAR_MAT & N ) const
   {
 #ifdef EXTENDED_ERROR_CHECKING
 
    print_msg_once(communicator_,"kernel matrix bandwidth " +to_string(kernel_matrix_bandwidth(ptCoords)));
 #endif
 
     if (! kernelFunction_) throw ATC_Error("no kernel function specified");
     int npts = ptCoords.nRows();
     if (npts>0) {
       N.reset(npts,nNodesUnique_); // transpose of N_Ia
       DENS_VEC xI(nSD_),x(nSD_),dx(nSD_);
       for (int i = 0; i < nNodes_; i++) {
         xI = feMesh_->global_coordinates(i);
         for (int j = 0; j < npts; j++) {
           for (int k = 0; k < nSD_; ++k) { x(k) = ptCoords(j,k); } 
           dx = x - xI;
           double val = kernelFunction_->value(dx);
           val *= kernelFunction_->dimensionality_factor();
           if (val > 0) N.add(j,map_global_to_unique(i),val);
         }
       }
       N.compress();
     }
   }
 
   //-----------------------------------------------------------------
   // create a non-uniform rectangular mesh on a rectangular region
   //-----------------------------------------------------------------
 
   void FE_Engine::create_mesh(Array<double> & dx, 
     Array<double> & dy, 
     Array<double> & dz, 
     const char * regionName,
     Array<bool> periodicity)
   {
     double xmin, xmax, ymin, ymax, zmin, zmax;
     double xscale, yscale, zscale;
 
     // check to see if region exists and is it a box, and if so get the bounds
     bool isBox;
     isBox = ATC::LammpsInterface::instance()->region_bounds(
                                     regionName,
                                     xmin, xmax,
                                     ymin, ymax,
                                     zmin, zmax,
                                     xscale,
                                     yscale,
                                     zscale);
     if (!isBox) throw ATC_Error("Region for FE mesh is not a box");
 
 
     if (dx(0) == 0.0) dx = (xmax-xmin)/dx.size();
     if (dy(0) == 0.0) dy = (ymax-ymin)/dy.size();
     if (dz(0) == 0.0) dz = (zmax-zmin)/dz.size();
 
     
     feMesh_ = new FE_Rectangular3DMesh(dx,dy,dz,
                                        xmin, xmax,
                                        ymin, ymax,
                                        zmin, zmax,
                                        periodicity,
                                        xscale, yscale, zscale);
     stringstream ss;
     ss << "created structured mesh with " << feMesh_->num_nodes() << " nodes, " 
        << feMesh_->num_nodes_unique() << " unique nodes, and " 
        << feMesh_->num_elements() << " elements";
     print_msg_once(communicator_,ss.str());
 #ifdef ATC_VERBOSE
-    string msg = "element sizes in x:\n";
+    print_partitions(xmin,xmax,dx);
+    print_partitions(ymin,ymax,dy);
+    print_partitions(zmin,zmax,dz);
+#endif
+  }
+  //-----------------------------------------------------------------
+  void FE_Engine::print_partitions(double xmin, double xmax, Array<double> & dx) const {
+    stringstream msg;
+    msg.precision(3);
+    msg << std::fixed;
+    msg <<  "\nindex weight fraction location size[A] size[uc]:\n";
     double sum = 0;
     for (int i = 0; i < dx.size(); ++i) { sum += dx(i); }
     double xn= 1.0/sum;
     double xs= xn*(xmax-xmin);
     double xl= xs/(ATC::LammpsInterface::instance()->xlattice());
     double sumn = 0, sums = 0, suml = 0;
+    double x = xmin;
     for (int i = 0; i < dx.size(); ++i) { 
        double dxn = dx(i)*xn; sumn += dxn;
        double dxs = dx(i)*xs; sums += dxs;
        double dxl = dx(i)*xl; suml += dxl;
-       msg += "   "+to_string(i+1)
-             +" "+to_string(dx(i))
-             +" "+to_string(dxn)
-             +" "+to_string(dxs)
-             +" "+to_string(dxl)+"\n";
+       msg << std::setw(5) << i+1
+           << std::setw(7) << dx(i)
+           << std::setw(9) << dxn
+           << std::setw(9) << x
+           << std::setw(8) << dxs
+           << std::setw(9) << dxl << "\n";
+       x += dxs;
      }
-     msg += "sum "+to_string(sum)+" "
-                  +to_string(sumn)+" "
-                  +to_string(sums)+" "
-                  +to_string(suml)+"\n";
-     print_msg_once(communicator_,msg);
-#endif
+     msg << "sum  " << setw(7) << sum
+                    << setw(9) << sumn
+                    << setw(9) << x
+                    << setw(8) << sums
+                    << setw(9) << suml << "\n";
+     print_msg_once(communicator_,msg.str());
   }
-
   //-----------------------------------------------------------------
   // create a uniform rectangular mesh on a rectangular region
   //-----------------------------------------------------------------
   void FE_Engine::create_mesh(int nx, int ny, int nz, const char * regionName,
                               Array<bool> periodicity)
   {
     double xmin, xmax, ymin, ymax, zmin, zmax;
     double xscale, yscale, zscale;
 
     // check to see if region exists and is it a box, and if so get the bounds
     bool isBox;
     isBox = ATC::LammpsInterface::instance()->region_bounds(
                                     regionName,
                                     xmin, xmax,
                                     ymin, ymax,
                                     zmin, zmax,
                                     xscale, yscale, zscale);
     if (!isBox) throw ATC_Error("Region for FE mesh is not a box");
     
     feMesh_ = new FE_Uniform3DMesh(nx,ny,nz,
                                    xmin, xmax,
                                    ymin, ymax,
                                    zmin, zmax,
                                    periodicity,
                                    xscale, yscale, zscale);
     stringstream ss;
     ss << "created uniform mesh with " << feMesh_->num_nodes() << " nodes, " 
        << feMesh_->num_nodes_unique() << " unique nodes, and " 
        << feMesh_->num_elements() << " elements";
     print_msg_once(communicator_,ss.str());
   }
 
   //-----------------------------------------------------------------
   // read a mesh from an input file using MeshReader object
   //-----------------------------------------------------------------
   void FE_Engine::read_mesh(string meshFile, Array<bool> & periodicity)
   {
     if (feMesh_) throw ATC_Error("FE_Engine already has a mesh");
     feMesh_ = MeshReader(meshFile,periodicity).create_mesh();
     feMesh_->initialize();
   }
 };
diff --git a/lib/atc/FE_Engine.h b/lib/atc/FE_Engine.h
index ab902fe60..bc3fb0e4a 100644
--- a/lib/atc/FE_Engine.h
+++ b/lib/atc/FE_Engine.h
@@ -1,556 +1,579 @@
 #ifndef FE_ENGINE_H
 #define FE_ENGINE_H
 
 #include <vector>
 #include <map>
 #include <set>
 #include <utility>
 #include <string>
 #include "ATC_TypeDefs.h"
 #include "Array.h"
 #include "Array2D.h"
 #include "FE_Mesh.h"
 #include "PhysicsModel.h"
 #include "OutputManager.h"
 #include "MeshReader.h"
 #include "mpi.h"
 
 namespace ATC {
   
   class ATC_Method;
   class FE_Element;
   class XT_Function;
   class KernelFunction;
   
   /**
    *  @class  FE_Engine 
    *  @brief  Base class for computing and assembling mass matrix 
    *                                              and rhs vectors
    */  
   
   class FE_Engine{
   public:
     /** constructor/s  */
     FE_Engine(MPI_Comm comm);
   
     /** destructor */
     ~FE_Engine();
   
     /** initialize */
     void initialize();
   
     MPI_Comm communicator() {return communicator_;}
     void partition_mesh();
     void departition_mesh();
     bool is_partitioned() const { return feMesh_->is_partitioned(); }
     int map_elem_to_myElem(int elemID) const 
     { return feMesh_->map_elem_to_myElem(elemID); }
     int map_myElem_to_elem(int myElemID) const 
     { return feMesh_->map_myElem_to_elem(myElemID); }
 
     // note: it is misleading to declare the following const
     //       because it touches the nIPsPer* data members, which
     //       are now declared mutable. Why? Well, set_quadrature
     //       has to be called from a const function, and all the
     //       matrices dependent on nIPsPer* are declared mutable
     //       as well (and have been). I think this is because a
     //       const engine needs to be able to deal with various
     //       quadratures and update its data members directly, which
     //       are really convenience-copies of data members that
     //       are more pertinent to other classes (FE_Interpolate,
     //       for the most part) that it uses temporarily for space/
     //       time speedups while doing it's computations.
     //       
     //       I approve of this usage of mutable, but the const/
     //       non-const member function declaring in this class is
     //       really all wrong to begin with.
 
     /** set quadrature scheme, resize matrices if necessary as per
      *  initialize() */
     void set_quadrature(FeIntQuadrature quadType, bool temp=true) const;
 
     /** parser/modifier */
     bool modify(int narg, char **arg);
   
     /** finish up */
     void finish();
 
     /** print out the "global connectivity" of all elements */
     void print_mesh() const;
 
     //----------------------------------------------------------------
     /** \name output */
     //----------------------------------------------------------------
     /*@{*/
     /** these assume the caller is handling the parallel collection */
     void initialize_output(int rank, std::string outputPrefix, std::set<int> otypes);
   
     /** write geometry */
     void write_geometry(void);
   
     /** write data: data is arrayed over _unique_ nodes 
                     and then mapped by the engine */
     void write_data(double time, FIELDS &soln, OUTPUT_LIST *data=NULL);
     void write_data(double time, OUTPUT_LIST *data);
 
     void write_restart_file(std::string fileName, RESTART_LIST *data)
     { outputManager_.write_restart_file(fileName,data); }
 
     void read_restart_file(std::string fileName, RESTART_LIST *data)
     { outputManager_.read_restart_file(fileName,data); }
 
     void delete_elements(const std::set<int> &elementList);
     void cut_mesh(const std::set<PAIR> &cutFaces, const std::set<int> &edgeNodes);
 
     void add_global(const std::string name, const double value) 
     { outputManager_.add_global(name,value); }
 
     void add_field_names(const std::string field, const std::vector<std::string> & names)
     { outputManager_.add_field_names(field,names); }
 
     void reset_globals() { outputManager_.reset_globals(); }
 
     /** pass through to access output manager */
     OutputManager *output_manager() { return &outputManager_; }
     /*@}*/
 
     //----------------------------------------------------------------
     /** \name assembled matrices and vectors */
     //----------------------------------------------------------------
     /*@{*/
     DENS_VEC interpolate_field(const DENS_VEC & x, const FIELD & f) const;
 
     /** interpolate fields */
     void interpolate_fields(const int               ielem,
                             const FIELDS            &fields,
                             AliasArray<int>         &conn,
                             DENS_MAT                &N,
                             DIAG_MAT                &weights,
                             std::map<FieldName,DENS_MAT> &fieldsAtIPs) const;
 
     /** interpolate fields & gradients */
     void interpolate_fields(const int       ielem,
                             const FIELDS    &fields,
                             AliasArray<int> &conn,
                             DENS_MAT        &N,
                             DENS_MAT_VEC    &dN,
                             DIAG_MAT        &weights,
                             FIELD_MATS      &fieldsAtIPs,
                             GRAD_FIELD_MATS &grad_fieldsAtIPs) const;
 
     /** compute a dimensionless stiffness matrix */
     void stiffness_matrix(SPAR_MAT &matrix) const;
 
 
     /** compute tangent matrix for a pair of fields - native quadrature */
     void compute_tangent_matrix(
                 const RHS_MASK          &rhsMask,
                 const std::pair<FieldName,FieldName> row_col,
                 const FIELDS            &fields,
                 const PhysicsModel      *physicsModel,
                 const Array<int>        &elementMaterials,
                 SPAR_MAT                &tangent,
                 const DenseMatrix<bool> *elementMask=NULL) const;
 
     /** compute tangent matrix for a pair of fields - given quadrature */
     void compute_tangent_matrix(const RHS_MASK &rhsMask,
                 const std::pair<FieldName,FieldName> row_col,
                 const FIELDS            &fields,
                 const PhysicsModel      *physicsModel,
                 const Array<std::set<int> >  &pointMaterialGroups,
                 const DIAG_MAT          &weights,
                 const SPAR_MAT          &N,
                 const SPAR_MAT_VEC      &dN,
                 SPAR_MAT                &tangent,
                 const DenseMatrix<bool> *elementMask=NULL) const;
 
     /** compute a consistent mass matrix for a field */
     void compute_mass_matrix(
                 const Array<FieldName>  &mask,
                 const FIELDS            &fields,
                 const PhysicsModel      *physicsModel,
                 const Array<int>        &elementMaterials,
                 CON_MASS_MATS           &mass_matrix,
                 const DenseMatrix<bool> *elementMask=NULL) const;
 
     /** compute a dimensionless mass matrix */
     void compute_mass_matrix(SPAR_MAT &mass_matrix) const;
     
     /** computes a dimensionless mass matrix for the given-quadrature */
     void compute_mass_matrix(const DIAG_MAT &weights,
                              const SPAR_MAT &N,
                              SPAR_MAT       &mass_matrix) const;
     
     /** compute a single dimensionless mass matrix */
     void compute_lumped_mass_matrix(DIAG_MAT &lumped_mass_matrix) const;
 
     /** compute lumped mass matrix = diag (\int \rho N_I dV) */
     void compute_lumped_mass_matrix(
                 const Array<FieldName>  &mask, 
                 const FIELDS            &fields,
                 const PhysicsModel      *physicsModel,
                 const Array<int>        &elementMaterials,
                 MASS_MATS               &mass_matrix,
                 const DenseMatrix<bool> *elementMask=NULL) const;
 
     /** compute dimensional lumped mass matrix using given quadrature */
     void compute_lumped_mass_matrix(
                        const Array<FieldName> &mask, 
                        const FIELDS           &fields,
                        const PhysicsModel     *physicsModel,
                        const Array<std::set<int> > &pointMaterialGroups,
                        const DIAG_MAT         &weights,
                        const SPAR_MAT         &N,
                        MASS_MATS              &mass_matrix) const;
 
     /** compute an approximation to a finite difference gradient from mesh */
     void compute_gradient_matrix(SPAR_MAT_VEC &grad_matrix) const;
 
     /** compute energy */
     void compute_energy(const Array<FieldName>  &mask,
                         const FIELDS            &fields,
                         const PhysicsModel      *physicsModel,
                         const Array<int>        &elementMaterials,
                         FIELD_MATS              &energy, 
                         const DenseMatrix<bool> *elementMask=NULL,
                         const IntegrationDomainType domain=FULL_DOMAIN) const;
 
     /** compute residual or RHS of the dynamic weak eqn */
     void compute_rhs_vector(
                     const RHS_MASK          &rhsMask,
                     const FIELDS            &fields,
                     const PhysicsModel      *physicsModel,
                     const Array<int>        &elementMaterials,
                     FIELDS                  &rhs,
+                    bool                     freeOnly=false,
                     const DenseMatrix<bool> *elementMask=NULL) const;
 
     /** compute RHS for given quadrature */
     void compute_rhs_vector(const RHS_MASK         &rhsMask,
                             const FIELDS           &fields,
                             const PhysicsModel     *physicsModel,
                             const Array<std::set<int> > &pointMaterialGroups,
                             const DIAG_MAT         &weights,
                             const SPAR_MAT         &N,
                             const SPAR_MAT_VEC     &dN,
                             FIELDS                 &rhs) const;
 
     /** compute pointwise source for given quadrature */
     void compute_source(const Array2D<bool>    &rhsMask,
                         const FIELDS           &fields,
                         const PhysicsModel     *physicsModel,
                         const Array<std::set<int> > &pointMaterialGroups,
                         const DIAG_MAT         &weights,
                         const SPAR_MAT         &N,
                         const SPAR_MAT_VEC     &dN,
                         FIELD_MATS             &sources) const;
 
     /** compute flux in domain i.e. N^T B_integrand */
     void compute_flux(const RHS_MASK          &rhsMask,
                       const FIELDS            &fields,
                       const PhysicsModel      *physicsModel,
                       const Array<int>        &elementMaterials,
                       GRAD_FIELD_MATS         &flux, 
                       const DenseMatrix<bool> *elementMask=NULL) const;
 
     /** compute the flux on the MD/FE boundary */
     void compute_boundary_flux(const RHS_MASK     &rhsMask, 
                                const FIELDS       &fields,
                                const PhysicsModel *physicsModel,
                                const Array<int>   &elementMaterials,
                                const std::set<PAIR>    &faceSet, 
                                FIELDS             &rhs) const;
 
     /** compute the flux on using an L2 interpolation of the flux */
     void compute_boundary_flux(const RHS_MASK         &rhsMask,
                                const FIELDS           &fields,
                                const PhysicsModel     *physicsModel,
                                const Array<int>       &elementMaterials,
                                const Array<std::set<int> > &pointMaterialGroups,
                                const DIAG_MAT         &weights,
                                const SPAR_MAT         &N,
                                const SPAR_MAT_VEC     &dN,
                                const DIAG_MAT         &flux_mask,
                                FIELDS                 &rhs,
                                const DenseMatrix<bool> *elementMask=NULL,
                                const std::set<int>          *nodeSet=NULL) const;
 
     /** compute prescribed flux given an array of functions of x & t */
     void add_fluxes(const Array<bool>    &fieldMask,  
                     const double         time,
                     const SURFACE_SOURCE &sourceFunctions, 
                     FIELDS               &nodalSources) const;
     void compute_fluxes(const Array<bool>    &fieldMask,  
                     const double         time,
                     const SURFACE_SOURCE &sourceFunctions, 
                     FIELDS               &nodalSources) const
     {
       SURFACE_SOURCE::const_iterator src_iter;
       for (src_iter=sourceFunctions.begin(); src_iter!=sourceFunctions.end(); src_iter++) {
         _fieldName_ = src_iter->first;
         if (!fieldMask((int)_fieldName_)) continue;
         if (nodalSources[_fieldName_].nRows()==0) { 
            nodalSources[_fieldName_].reset(nNodesUnique_,1); 
         }
       }
       add_fluxes(fieldMask,  time, sourceFunctions, nodalSources);
     }
 
-    /** compute prescribed flux given an array of functions of u, x & t */
+    /** compute robin flux given an array of functions of u, x & t */
     void add_robin_fluxes(const Array2D<bool> &rhsMask,
                           const FIELDS        &fields,
                           const double        time,
                           const ROBIN_SURFACE_SOURCE &sourceFunctions,
                           FIELDS              &nodalSources) const;
 
     void add_robin_tangent(const Array2D<bool> &rhsMask,
                            const FIELDS        &fields,
                            const double        time,
                            const ROBIN_SURFACE_SOURCE &sourceFunctions,
                            SPAR_MAT            &tangent) const;
 
+    /** compute open flux given a face set */
+    
+    void add_open_fluxes(const Array2D<bool> &rhsMask,
+                         const FIELDS        &fields,
+                         const OPEN_SURFACE &openFaces,
+                         FIELDS              &nodalSources,
+                         const FieldName velocity = ELECTRON_VELOCITY) const;
+
+    void add_open_tangent(const Array2D<bool> &rhsMask,
+                          const FIELDS        &fields,
+                          const OPEN_SURFACE &openFaces,
+                          SPAR_MAT            &tangent,
+                          const FieldName velocity = ELECTRON_VELOCITY) const;
+
     /** compute nodal vector of volume based sources */
     void add_sources(const Array<bool>   &fieldMask, 
                      const double        time,
                      const VOLUME_SOURCE &sourceFunctions, 
                      FIELDS              &nodalSources) const;
+    void add_sources(const Array<bool>   &fieldMask, 
+                     const double        time,
+                     const FIELDS        &sources, 
+                     FIELDS              &nodalSources) const;
 
     /** compute surface flux of a nodal field */
     void field_surface_flux(const DENS_MAT  &field,
                             const std::set<PAIR> &faceSet,
                             DENS_MAT        &values,
                             const bool      contour=false,
                             const int       axis=2) const;
 
     /** integrate a nodal field over an element set */
     DENS_VEC integrate(const DENS_MAT  &field, const ESET & eset) const;
 
 
     /** integrate a nodal field over an face set */
     DENS_VEC integrate(const DENS_MAT  &field, const FSET & fset) const
     { throw ATC_Error(FILELINE,"unimplemented function"); }
 
     /*@}*/
 
     //----------------------------------------------------------------
     /** \name shape functions */
     //----------------------------------------------------------------
     /*@{*/
 
     /** evaluate shape function at a list of points in R^3 */
     void evaluate_shape_functions(const MATRIX &coords, 
                                   SPAR_MAT &N) const;
 
     /** evaluate shape function & derivatives at a list of points in R^3 */
     void evaluate_shape_functions(const MATRIX &coords, 
                                   SPAR_MAT &N,
                                   SPAR_MAT_VEC &dN) const;
 
     /** evaluate shape function at a list of points in R^3 */
     void evaluate_shape_functions(const MATRIX &coords, 
                                   const INT_ARRAY &pointToEltMap,
                                   SPAR_MAT &N) const;
 
     /** evaluate shape function & derivatives at a list of points in R^3 */
     void evaluate_shape_functions(const MATRIX &coords, 
                                   const INT_ARRAY &pointToEltMap,
                                   SPAR_MAT &N,
                                   SPAR_MAT_VEC &dN) const;   
 
     /** evaluate shape derivatives at a list of points in R^3 */
     void evaluate_shape_function_derivatives(const MATRIX &coords, 
                                              const INT_ARRAY &pointToEltMap,
                                              SPAR_MAT_VEC &dN) const;
 
     void shape_functions(const VECTOR &x, 
                          DENS_VEC &shp,
                          Array<int> &node_list) const
     { feMesh_->shape_functions(x,shp,node_list); }
 
     void shape_functions(const VECTOR & x,
                          DENS_VEC& shp, 
                          DENS_MAT& dshp,
                          Array<int> &node_list) const
     { feMesh_->shape_functions(x,shp,dshp,node_list); }
 
     void shape_functions(const VECTOR &x,
                          const int eltId,
                          DENS_VEC& shp,
                          Array<int> &node_list) const
     { feMesh_->shape_functions(x,eltId,shp,node_list); }
 
     void shape_functions(const VECTOR &x,
                          DENS_VEC& shp,
                          Array<int> &node_list,
                          int &eltId) const
     { feMesh_->shape_functions(x,shp,node_list,eltId); }
 
     void shape_functions(const VECTOR &x,
                          const int eltId,
                          DENS_VEC &shp, 
                          DENS_MAT &dshp,
                          Array<int> &node_list) const
     { feMesh_->shape_functions(x,eltId,shp,dshp,node_list); }
     /*@}*/
 
     //----------------------------------------------------------------
     /** \name kernel functions */
     //----------------------------------------------------------------
     /** evaluate kernel function */
     void evaluate_kernel_functions(const MATRIX &pt_coords,
                                    SPAR_MAT &N) const;
 
     /**  kernel matrix bandwidth */
     int kernel_matrix_bandwidth(const MATRIX &pt_coords) const;
 
     //----------------------------------------------------------------
     /** \name nodeset */
     //----------------------------------------------------------------
     /** pass through */
     void create_nodeset(const std::string &name, const std::set<int> &nodeset) 
     { feMesh_->create_nodeset(name,nodeset); }
 
     //----------------------------------------------------------------
     /** \name accessors */
     //----------------------------------------------------------------
     /*@{*/
     /** even though these are pass-throughs there is a necessary 
      *  translation */
     /** return number of unique nodes */
     int num_nodes() const { return feMesh_->num_nodes_unique(); }
   
     /** return number of total nodes */
     int nNodesTotal() const { return feMesh_->num_nodes(); }
   
     /** return number of elements */
     int num_elements() const { return feMesh_->num_elements(); }
     int my_num_elements() const { return feMesh_->my_num_elements(); }
 
     /** return number of nodes per element */
     int num_nodes_per_element() const { return feMesh_->num_nodes_per_element(); }
 
     /** return element connectivity */
     void element_connectivity(const int eltID, 
                               Array<int> & nodes) const
     { feMesh_->element_connectivity_unique(eltID, nodes); }
   
     /** return face connectivity */
     void face_connectivity(const PAIR &faceID, 
                            Array<int> &nodes) const
     { feMesh_->face_connectivity_unique(faceID, nodes); }
 
     /** in lieu of pass-throughs const accessors ... */
     /** return const ptr to mesh */
     const FE_Mesh* fe_mesh() const { return feMesh_; }
   
     /** return number of spatial dimensions */
     int nsd() const { return feMesh_->num_spatial_dimensions(); }
   
     /** return if the FE mesh has been created */
     int has_mesh() const { return feMesh_!=NULL; }
   
     /** get nodal coordinates for a given element */
     void element_coordinates(const int eltIdx, DENS_MAT &coords)
     { feMesh_->element_coordinates(eltIdx,coords); }
 
     /** get nodal coordinates for a given element */
     void element_field(const int eltIdx, const DENS_MAT field, 
                        DENS_MAT &local_field)
     { feMesh_->element_field(eltIdx, field, local_field); }
 
     /** access list of elements to be deleted */
     const std::set<int> &null_elements(void) const
     { return nullElements_; } 
 
     /** access to the amended nodal coordinate values */
     const DENS_MAT &nodal_coordinates(void) const 
     { return (*feMesh_->coordinates()); }
 
     /** map global node numbering to unique node numbering for 
      *  amended mesh */
     int map_global_to_unique(const int global_id) const 
     { return (*feMesh_->node_map())(global_id); }
     
     int number_of_global_nodes(void) const { return nNodes_; }
 
     /*@}*/
 
     /** set kernel */
     
     void set_kernel(KernelFunction* ptr);
     KernelFunction *kernel(int i=0) { return kernelFunction_; }
 
   private:
     //----------------------------------------------------------------
     /** mesh setup commands (called from modify) */
     //----------------------------------------------------------------
     /*@{*/
 
     MPI_Comm communicator_;
 
     /** finite element mesh */
     FE_Mesh *feMesh_;
 
     /** auxillary kernel function */
     KernelFunction *kernelFunction_;
  
     /** initialized flag */ 
     bool initialized_;
 
+    void parse_partitions(int & argIdx, int narg, char ** arg,
+      int idof, Array<double> & dx ) const;
+    void print_partitions(double xmin, double xmax, Array<double> &dx) const;
+
     /** create a uniform, structured mesh */
     void create_mesh(Array<double> &dx, 
                      Array<double> &dy, 
                      Array<double> &dz, 
                      const char *regionName,
                      Array<bool> periodic);
 
     void create_mesh(int nx, int ny, int nz, 
                      const char *regionName,
                      Array<bool> periodic);
 
     /** read an unstructured mesh from a file */
     void read_mesh(std::string meshFile, Array<bool> & periodicity);
     /*@}*/
 
     /** data that can be used for a subset of original mesh */
     std::set<int> nullElements_;
     
     /** faces upon which nodes are duplicated */
     std::set<PAIR> cutFaces_;
     std::set<int> cutEdge_;
   
     /** workspace */
     int nNodesPerElement_;
     int nSD_;
     int nElems_;
     int nNodes_;       /** number of global nodes */
     int nNodesUnique_; /** number of unique nodes */
     mutable int nIPsPerElement_;
     mutable int nIPsPerFace_;
     mutable FeIntQuadrature quadrature_;
     mutable FIELDS::const_iterator _fieldItr_; 
     mutable FieldName _fieldName_;
     
     /** sized arrays */
     mutable DIAG_MAT _weights_;
     mutable DENS_MAT _N_, _Nw_;
     mutable DENS_MAT_VEC _dN_, _dNw_;
     mutable DIAG_MAT _fweights_;
     mutable DENS_MAT _fN_;
     mutable DENS_MAT_VEC _fdN_, _nN_;
 
     /** unsized arrays */
     mutable DENS_MAT _Nmat_;
     mutable FIELD_MATS _fieldsAtIPs_;
     mutable GRAD_FIELD_MATS _gradFieldsAtIPs_; 
     mutable DENS_MAT _Nfluxes_;
     mutable AliasArray<int> _conn_;
     mutable DENS_MAT_VEC _Bfluxes_;
   
     /** output object */
     OutputManager outputManager_;
   
   };
 
 }; // end namespace ATC
 
 #endif
diff --git a/lib/atc/FE_Mesh.cpp b/lib/atc/FE_Mesh.cpp
index 6e7036a0c..6225a1b19 100644
--- a/lib/atc/FE_Mesh.cpp
+++ b/lib/atc/FE_Mesh.cpp
@@ -1,3038 +1,3061 @@
 // ATC header files
 #include "FE_Element.h"
 #include "FE_Mesh.h"
 #include "LammpsInterface.h"
 #include "ATC_Error.h"
 #include "OutputManager.h"
 #include "Utility.h"
 #include <sstream>
 #include <assert.h>
 #include <algorithm>
 #include <cmath>
 #include <functional>
 
 // Other headers
 #include <iostream>
 
 
 using namespace std;
 using ATC_Utility::dbl_geq;
 using ATC_Utility::parse_min;
 using ATC_Utility::parse_max;
 using ATC_Utility::parse_minmax;
 using ATC_Utility::split_values;
 using ATC_Utility::plane_coords;
 using ATC_Utility::norm3;
 using ATC_Utility::to_string;
+using ATC_Utility::tolerance;
 
 
 
 
 
 namespace ATC {
 
   // constants
   const static double tangentTolerance = 0.01;
   const static double tol = 1.0e-10;
 
 
   // =============================================================
   //   class FE_Mesh
   // =============================================================
   FE_Mesh::FE_Mesh()
     : decomposition_(false), 
     lammpsPartition_(false),
     partitioned_(false),
     nNodes_(0), 
     nNodesUnique_(0),
     feElement_(NULL),
     twoDimensional_(false),
     hasPlanarFaces_(false)
 
   {
   }
 
   // -------------------------------------------------------------
   FE_Mesh::~FE_Mesh()
   {
     if (feElement_) delete feElement_;
   }
 
   // -------------------------------------------------------------
   //  modify
   // -------------------------------------------------------------
   bool FE_Mesh::modify(int narg, char **arg)
   {
     bool match = false;
 
     if (strcmp(arg[0],"mesh")==0) 
     {
      /*! \page man_mesh_create_faceset_box fix_modify AtC mesh create_faceset box
         \section syntax
          fix_modify AtC mesh create_faceset <id> box
          <xmin> <xmax> <ymin> <ymax> <zmin> <zmax> <in|out> [units]
          - <id> = id to assign to the collection of FE faces
          - <xmin> <xmax> <ymin> <ymax> <zmin> <zmax> = coordinates of
          the bounding box that is coincident with the desired FE faces
          - <in|out> = "in" gives inner faces to the box, 
                       "out" gives the outer faces to the box
          - units = option to specify real as opposed to lattice units
         \section examples
          <TT> fix_modify AtC mesh create_faceset obndy box -4.0 4.0 -12 12 -12 12 out </TT>
         \section description
           Command to assign an id to a set of FE faces.
         \section restrictions
         Only viable for rectangular grids.
         \section related
         \section default
         The default options are units = lattice and the use of outer faces
        */
      /*! \page man_mesh_create_faceset_plane fix_modify AtC mesh create_faceset plane 
         \section syntax
          fix_modify AtC mesh create_faceset <id> plane 
          <x|y|z> <val1> <x|y|z> <lval2> <uval2> [units]
          - <id> = id to assign to the collection of FE faces
          - <x|y|z> = coordinate directions that define plane on which faceset lies 
          - <val1>,<lval2>,<uval2> = plane is specified as the x|y|z=val1 plane bounded by
               the segments x|y|z = [lval2,uval2]  
          - units = option to specify real as opposed to lattice units
         \section examples
          <TT> fix_modify AtC mesh create_faceset xyplane plane y 0 x -4 0 </TT>
         \section description
           Command to assign an id to a set of FE faces. 
         \section restrictions
         Only viable for rectangular grids. 
         \section related
         \section default
         The default option is units = lattice.
        */
       if (strcmp(arg[1],"create_faceset")==0) 
       {
         int argIdx = 2;
         string tag = arg[argIdx++];
         if (strcmp(arg[argIdx],"plane")==0) 
         {
           argIdx++;
-          string n(arg[argIdx++]);
-          int idir = -1, isgn = 0; 
-          int i2dir = -1, i3dir = -1;
-          double x2min = 0.0, x2max = 0.0, x3min = 0.0, x3max = 0.0;
-          string_to_index(n, idir, isgn);
-          double x =  parse_minmax(arg[argIdx++]);
-          if (narg > argIdx ) {
-            if (string_to_index(arg[argIdx],i2dir)) {
-              argIdx++;
-              x2min = parse_min(arg[argIdx++]); 
-              x2max = parse_max(arg[argIdx++]);
-            }
-          }
-          if (narg > argIdx ) {
-            if (string_to_index(arg[argIdx],i3dir)) {
-              argIdx++;
-              x3min = parse_min(arg[argIdx++]);
-              x3max = parse_max(arg[argIdx++]);
-            }
-          }
-          if (i2dir >= 0 && 
-            ((i2dir == idir) || (i2dir == idir) || (i2dir == idir) ) ) 
-          {
-            throw ATC_Error( "inconsistent directions in create_faceset plane");  
-          }
-          if (narg > argIdx && (strcmp(arg[argIdx++],"units") == 0)) 
-          {} 
-          else 
-          {
-            if      (idir == 0) { x *= xscale_; }
-            else if (idir == 1) { x *= yscale_; }
-            else if (idir == 2) { x *= zscale_; }
-            if (i2dir >=0) {
-              if      (i2dir == 0) { x2min *= xscale_;  x2max *= xscale_; }
-              else if (i2dir == 1) { x2min *= yscale_;  x2max *= yscale_; }
-              else if (i2dir == 2) { x2min *= zscale_;  x2max *= zscale_; }
-            }
-            if (i3dir >=0) {
-              if      (i3dir == 0) { x3min *= xscale_;  x2max *= xscale_; }
-              else if (i3dir == 1) { x3min *= yscale_;  x3max *= yscale_; }
-              else if (i3dir == 2) { x3min *= zscale_;  x3max *= zscale_; }
-            }
-          }
-          if (i2dir >=0) {
-            create_faceset(tag, x, idir, isgn, i2dir, x2min, x2max, 
-                                               i3dir, x3min, x3max);
+          int ndir, idir[3], isgn;
+          double xlimits[3][2];
+          parse_plane(argIdx, narg, arg, ndir, idir, isgn, xlimits);
+          if (xlimits[idir[1]][0] == xlimits[idir[1]][1]) 
+            split_values(xlimits[idir[1]][0],xlimits[idir[1]][1]);
+          if (xlimits[idir[2]][0] == xlimits[idir[2]][1]) 
+            split_values(xlimits[idir[2]][0],xlimits[idir[2]][1]);
+          parse_units(argIdx,narg,arg,
+            xlimits[0][0],xlimits[0][1],
+            xlimits[1][0],xlimits[1][1],
+            xlimits[2][0],xlimits[2][1]);
+          if (ndir > 1) {
+            create_faceset(tag, xlimits[idir[0]][0], idir[0], isgn, 
+              idir[1], xlimits[idir[1]][0], xlimits[idir[1]][1], 
+              idir[2], xlimits[idir[2]][0], xlimits[idir[2]][1]);
           }
           else {
-            create_faceset(tag, x, idir, isgn);
+            create_faceset(tag, xlimits[idir[0]][0], idir[0], isgn);
           }
           match = true;
         }
         // bounding_box
         else 
         {
           if (strcmp(arg[argIdx],"box")==0) argIdx++;
           double xmin = parse_min(arg[argIdx++]);
           double xmax = parse_max(arg[argIdx++]);
           double ymin = parse_min(arg[argIdx++]);
           double ymax = parse_max(arg[argIdx++]);
           double zmin = parse_min(arg[argIdx++]);
           double zmax = parse_max(arg[argIdx++]);
           bool outward = true;
           if (narg > argIdx && (strcmp(arg[argIdx++],"in") == 0)) 
             outward = false;
-
-          if (narg > argIdx && (strcmp(arg[argIdx++],"units") == 0)) {}
-          else 
-          { // scale from lattice units to physical units
-            xmin *= xscale_;
-            xmax *= xscale_;
-            ymin *= yscale_;
-            ymax *= yscale_;
-            zmin *= zscale_;
-            zmax *= zscale_;
-          }
-          
+          parse_units(argIdx,narg,arg, xmin,xmax,ymin,ymax,zmin,zmax);
           create_faceset(tag, xmin, xmax, ymin, ymax, zmin, zmax, outward);
           match = true;
         }
       }
    /*! \page man_mesh_create_nodeset fix_modify AtC mesh create_nodeset
       \section syntax
       fix_modify AtC mesh create_nodeset <id>
       <xmin> <xmax> <ymin> <ymax> <zmin> <zmax>
       - <id> = id to assign to the collection of FE nodes
       - <xmin> <xmax> <ymin> <ymax> <zmin> <zmax> = coordinates of
       the bounding box that contains only the desired nodes
       \section examples
       <TT> fix_modify AtC mesh create_nodeset lbc -12.1 -11.9 -12 12 -12 12 </TT>
       \section description
       Command to assign an id to a set of FE nodes to be used subsequently
       in defining boundary conditions.
       \section restrictions
       \section related
       \section default
       Coordinates are assumed to be in lattice units.
     */
       else if (strcmp(arg[1],"create_nodeset")==0) {
-        string tag  = arg[2];
-        double xmin = parse_min(arg[3]);
-        double xmax = parse_max(arg[4]);
-        double ymin = parse_min(arg[5]);
-        double ymax = parse_max(arg[6]);
-        double zmin = parse_min(arg[7]);
-        double zmax = parse_max(arg[8]);
+        int argIdx = 2;
+        string tag  = arg[argIdx++];
+        double xmin, xmax, ymin, ymax, zmin, zmax;
+        if (strcmp(arg[argIdx],"plane")==0) {
+          argIdx++;
+          int ndir, idir[3], isgn;
+          double xlimits[3][2];
+          parse_plane(argIdx, narg, arg, ndir, idir, isgn, xlimits);
+          xmin = xlimits[0][0];
+          xmax = xlimits[0][1];
+          ymin = xlimits[1][0];
+          ymax = xlimits[1][1];
+          zmin = xlimits[2][0];
+          zmax = xlimits[2][1];
+        }
+        else {
+          xmin = parse_min(arg[argIdx++]);
+          xmax = parse_max(arg[argIdx++]);
+          ymin = parse_min(arg[argIdx++]);
+          ymax = parse_max(arg[argIdx++]);
+          zmin = parse_min(arg[argIdx++]);
+          zmax = parse_max(arg[argIdx++]);
+        }
+        if (xmin == xmax) split_values(xmin,xmax);
+        if (ymin == ymax) split_values(ymin,ymax);
+        if (zmin == zmax) split_values(zmin,zmax);
+        parse_units(argIdx,narg,arg, xmin,xmax,ymin,ymax,zmin,zmax);
         create_nodeset(tag, xmin, xmax, ymin, ymax, zmin, zmax);
         match = true;
       }
    /*! \page man_mesh_add_to_nodeset fix_modify AtC mesh add_to_nodeset
       \section syntax
       fix_modify AtC mesh add_to_nodeset <id>
       <xmin> <xmax> <ymin> <ymax> <zmin> <zmax>
       - <id> = id of FE nodeset to be added to 
       - <xmin> <xmax> <ymin> <ymax> <zmin> <zmax> = coordinates of
       the bounding box that contains the desired nodes to be added
       \section examples
       <TT> fix_modify AtC mesh add_to_nodeset lbc -11.9 -11 -12 12 -12 12 </TT>
       \section description
       Command to add nodes to an already existing FE nodeset.
       \section restrictions
       \section related
       \section default
       Coordinates are assumed to be in lattice units.
     */
       else if (strcmp(arg[1],"add_to_nodeset")==0) {
         string tag  = arg[2];
         double xmin = parse_min(arg[3]);
         double xmax = parse_max(arg[4]);
         double ymin = parse_min(arg[5]);
         double ymax = parse_max(arg[6]);
         double zmin = parse_min(arg[7]);
         double zmax = parse_max(arg[8]);
         add_to_nodeset(tag, xmin, xmax, ymin, ymax, zmin, zmax);
         match = true;
       }
    /*! \page man_mesh_create_elementset fix_modify AtC mesh create_elementset
       \section syntax
       fix_modify AtC create_elementset <id>
       <xmin> <xmax> <ymin> <ymax> <zmin> <zmax>
       - <id> = id to assign to the collection of FE element
       - <xmin> <xmax> <ymin> <ymax> <zmin> <zmax> = coordinates of
       the bounding box that contains only the desired elements
       \section examples
       <TT> fix_modify AtC mesh create_elementset middle -4.1 4.1 -100 100 -100 1100 </TT>
       \section description
       Command to assign an id to a set of FE elements to be used subsequently
       in defining material and mesh-based operations.
       \section restrictions
       Only viable for rectangular grids.
       \section related
       \section default
       Coordinates are assumed to be in lattice units.
     */
       else if (strcmp(arg[1],"create_elementset")==0) {
-        string tag  = arg[2];
+        int argIdx = 2;
+        string tag  = arg[argIdx++];
         double xmin = 0;
         double xmax = 0;
         double ymin = 0;
         double ymax = 0;
         double zmin = 0;
         double zmax = 0;
         if (narg > 4) {
-          xmin = parse_min(arg[3]);
-          xmax = parse_max(arg[4]);
-          ymin = parse_min(arg[5]);
-          ymax = parse_max(arg[6]);
-          zmin = parse_min(arg[7]);
-          zmax = parse_max(arg[8]);
+          xmin = parse_min(arg[argIdx++]);
+          xmax = parse_max(arg[argIdx++]);
+          ymin = parse_min(arg[argIdx++]);
+          ymax = parse_max(arg[argIdx++]);
+          zmin = parse_min(arg[argIdx++]);
+          zmax = parse_max(arg[argIdx++]);
+          if (xmin == xmax) split_values(xmin,xmax);
+          if (ymin == ymax) split_values(ymin,ymax);
+          if (zmin == zmax) split_values(zmin,zmax);
+          parse_units(argIdx,narg,arg, xmin,xmax,ymin,ymax,zmin,zmax);
         }
         else {
-          string regionName = arg[3];
+          string regionName = arg[argIdx++];
           LammpsInterface::instance()->
           region_bounds(regionName.c_str(),xmin,xmax,ymin,ymax,zmin,zmax);
         }
         create_elementset(tag, xmin, xmax, ymin, ymax, zmin, zmax);
         match = true;
       }
 /*! \page man_mesh_nodeset_to_elementset fix_modify AtC mesh nodeset_to_elementset
       \section syntax
       fix_modify AtC nodeset_to_elementset <nodeset_id> <elementset_id> <max/min>
       - <nodeset_id> = id of desired nodeset from which to create elementset
       - <elementset_id> = id to assign to the collection of FE element
       - <max/min> = flag to choose either the maximal or minimal elementset
       \section examples
       <TT> fix_modify AtC mesh nodeset_to_elementset myNodeset myElementset min </TT>
       \section description
       Command to create an elementset from an existing nodeset.  Either the minimal element set
       of elements with all nodes in the set, or maximal element set with all elements with at
       least one node in the set, can be created
       \section restrictions
       None.
       \section related
       \section default
       Unless specified, the maximal element set is created
     */
       else if (strcmp(arg[1],"nodeset_to_elementset")==0) {
         string nodesetId = arg[2];
         string elementsetId = arg[3];
         set<int> elementSet;
         if (narg < 5) {
           this->nodeset_to_maximal_elementset(nodesetId,elementSet);
         }
         else {
           if (strcmp(arg[4],"max")==0) {
             this->nodeset_to_maximal_elementset(nodesetId,elementSet);
           }
           else if (strcmp(arg[4],"min")==0) {
             this->nodeset_to_minimal_elementset(nodesetId,elementSet);
           }
           else {
             return false;
           }
         }
         elementSetMap_[elementsetId] = elementSet;
         match = true;
       }
    /*! \page man_mesh_output fix_modify AtC mesh output
       \section syntax
       fix_modify AtC mesh output <file_prefix> 
       \section examples
       <TT> fix_modify AtC mesh output meshData </TT> \n
       \section description
       Command to output mesh and associated data: nodesets, facesets, and
       elementsets. This data is only output once upon initialization since
       currently the mesh is static. Creates (binary, "gold" format) Ensight 
       output of mesh data.
       \section restrictions
       none
       \section related
       \section default
       none
     */
       else if (strcmp(arg[1],"output")==0) {
         string outputPrefix  = arg[2];
         output(outputPrefix);
         match = true;
       }
     }
     return match;
   }
   // -------------------------------------------------------------
+  void FE_Mesh::parse_units(int & argIdx, int narg, char ** arg,
+    double & xmin, double & xmax, double & ymin, double & ymax, 
+    double & zmin, double & zmax)
+  {
+    if (narg > argIdx && (strcmp(arg[argIdx++],"units") == 0)) {}
+    else 
+    { // scale from lattice units to physical units
+      xmin *= xscale_; xmax *= xscale_;
+      ymin *= yscale_; ymax *= yscale_;
+      zmin *= zscale_; zmax *= zscale_;
+    }
+  }
+  // -------------------------------------------------------------
+  //   parse plane
+  // -------------------------------------------------------------
+  void FE_Mesh::parse_plane(int & argIdx, int narg, char ** arg,  
+    int & ndir, int * idir, int & isgn, double xlimits[][2])
+  {
+    ndir = 0;
+    xlimits[0][0] = parse_min("-INF");
+    xlimits[0][1] = parse_max("INF");
+    xlimits[1][0] = parse_min("-INF");
+    xlimits[1][1] = parse_max("INF");
+    xlimits[2][0] = parse_min("-INF");
+    xlimits[2][1] = parse_max("INF");
+    string n(arg[argIdx++]);
+    int i1dir = -1, i2dir = -1, i3dir = -1;
+    string_to_index(n, i1dir, isgn);
+    idir[ndir++] = i1dir;
+    idir[ndir]   = (i1dir+1) % 3;
+    idir[ndir+1] = (i1dir+2) % 3;
+    xlimits[i1dir][0] =  parse_minmax(arg[argIdx++]);
+    xlimits[i1dir][1] = xlimits[i1dir][0];
+    if (narg > argIdx ) {
+      if (string_to_index(arg[argIdx],i2dir)) {
+        argIdx++;
+        xlimits[i2dir][0] = parse_min(arg[argIdx++]); 
+        xlimits[i2dir][1] = parse_max(arg[argIdx++]);
+        idir[ndir++] = i2dir;
+      }
+      if (narg > argIdx ) {
+        if (string_to_index(arg[argIdx],i3dir)) {
+          argIdx++;
+          xlimits[i3dir][0] = parse_min(arg[argIdx++]); 
+          xlimits[i3dir][1] = parse_max(arg[argIdx++]);
+        }
+      }
+      else {
+        i3dir = 0;
+        if      ((i1dir == 0 && i2dir == 1) || (i1dir == 1 && i2dir == 0) ) {
+          i3dir = 2;
+        }
+        else if ((i1dir == 0 && i2dir == 2) || (i1dir == 2 && i2dir == 0) ) {
+          i3dir = 1;
+        }
+      }
+      idir[ndir++] = i3dir;
+    }
+    if ((idir[0]==idir[1]) || (idir[0]==idir[2]) || (idir[1]==idir[2]) ) {
+      throw ATC_Error( "inconsistent directions in plane:"+to_string(idir[0]+1)+" "+to_string(idir[1]+1)+" "+to_string(idir[2]+1));  
+    }
+  }
+  // -------------------------------------------------------------
   //   initialize
   // -------------------------------------------------------------
   void FE_Mesh::initialize(void) 
   {
+
     bool aligned = is_aligned();
     if (!aligned) {
       feElement_->set_projection_guess(CENTROID_LINEARIZED);
       ATC::LammpsInterface::instance()->print_msg_once("WARNING: mesh is not aligned with the coordinate directions atom-to-element mapping will be expensive");
       // if HEX8 -> orient();
     }
+    bool twoD = is_two_dimensional(); 
+    if (twoD) {
+      feElement_->set_projection_guess(TWOD_ANALYTIC);
+      if (feElement_->order()< 3) hasPlanarFaces_ = true; 
+      ATC::LammpsInterface::instance()->print_msg_once(" mesh is two dimensional");
+    }
   }
   //-----------------------------------------------------------------
   
   //-----------------------------------------------------------------
   void FE_Mesh::write_mesh(string meshFile)
   {
     ofstream out;
     out.open(meshFile.c_str());
     DENS_MAT & x = *(coordinates());
     Array2D<int> & conn = *(connectivity());
     int nNodes = x.nCols(); // transpose
     int ndm = x.nRows();
     int nElems = conn.nCols();
     int nodesPerElem = conn.nRows(); // transpose
     out << "Coordinates " << nNodes << "\n";
     for (int n = 0; n < nNodes; n++) {
       for (int i = 0; i < ndm; i++) {
         out << "  " << std::setprecision(16) << x(i,n);
       }
       out << "\n";
     }
     out << "\n";
     string type = element_type();
     out << "Elements " << nElems << " " << type << "\n";
     for (int n = 0; n < nElems; n++) {
       for (int i = 0; i < nodesPerElem; i++) {
         out << 1+conn(i,n) << " ";
       }
       out << "\n";
     }
     out << "\n";
     if (nodeSetMap_.size()) {
       out << "Nodesets " << nodeSetMap_.size() <<"\n";
       NODE_SET_MAP::const_iterator niter;
       map<string,DENS_MAT> nodesets;
       for (niter = nodeSetMap_.begin(); niter != nodeSetMap_.end(); niter++) {
         string name = niter->first;
         const set<int> & nset = niter->second;
         out << name << " " << nset.size() << "\n";
         set<int>::const_iterator iter;
         for (iter = nset.begin(); iter != nset.end(); iter++) {
           out << *iter << "  " ;   
         }
         out << "\n";
       }
     }
   }
   // -------------------------------------------------------------
   //   test whether almost structured
   // -------------------------------------------------------------
   bool FE_Mesh::is_aligned(void) const
   {
     vector<bool> foundBestMatch(nSD_,false);
     vector<DENS_VEC> tangents(nSD_);
     DENS_VEC xi0(nSD_);
     xi0 = 0;
     DENS_MAT eltCoords;
     for (int ielem = 0; ielem < nElts_; ielem++) {
        element_coordinates(ielem,eltCoords);
        feElement_->tangents(eltCoords,xi0,tangents,true); 
 
       for (unsigned i = 0; i < tangents.size(); i++) {
         // find maximum value for which global axis its closest to
         int maxIndex = 0;
         double maxValue = abs(tangents[i](0));
         for (int j = 1; j < nSD_; j++) {
           if (abs(tangents[i](j)) > maxValue) {
             maxValue = abs(tangents[i](j));
             maxIndex = j;
           }
         }
 
         // make sure no other tangent is associated with this direction
         if (foundBestMatch[maxIndex]) {
           return false;
         }
         else {
           foundBestMatch[maxIndex] = true;
         }
 
         // compute deviation from a perfectly aligned vector
         double error = 0.;
         for (int j = 1; j < nSD_; j++) {
           if (j != maxIndex) {
             error += abs(tangents[i](j));
           }
         }
         error /= maxValue;
         if (error > tangentTolerance) {
           return false;
         }
       }
     }
     return true;
   }
 
   // -------------------------------------------------------------
   //   element_type
   // -------------------------------------------------------------
   string FE_Mesh::element_type(void) const  {
       int npe = feElement_->num_elt_nodes(); 
       if      (npe == 4)  { return "TET4"; }
       else if (npe == 8)  { return "HEX8"; }
       else if (npe == 20) { return "HEX20"; }
       else if (npe == 27) { return "HEX27"; }
       return "UNKNOWN";
   }
 
   // -------------------------------------------------------------
   //   element_coordinates
   // -------------------------------------------------------------
   void FE_Mesh::element_coordinates(const int eltID,
                                     DENS_MAT & xCoords) const
   {
     const int nne = num_nodes_per_element();
     xCoords.reset(nSD_, nne, false);
     for (int inode=0; inode<nne; inode++) {
       const int id = element_connectivity_global(eltID, inode);
       for (int isd=0; isd<nSD_; isd++) {
         xCoords(isd,inode) = nodalCoords_(isd,id);
       }
     }
   
   }
   // -------------------------------------------------------------
   //   position
   // -------------------------------------------------------------
   void FE_Mesh::position(const int eltID,
                          const VECTOR & xi,
                                DENS_VEC & x) const
   {
     const int nne = num_nodes_per_element();
     DENS_VEC N;
     feElement_->shape_function(xi,N);
     x.reset(nSD_); 
     for (int inode=0; inode<nne; inode++) {
       const int id = element_connectivity_global(eltID, inode);
       for (int isd=0; isd<nSD_; isd++) {
         x(isd) += nodalCoords_(isd,id)*N(inode);
       }
     }
   }
 
   // -------------------------------------------------------------
   // element size in each direction
   // -------------------------------------------------------------
   void FE_Mesh::bounding_box(const int ielem,
                               DENS_VEC & xmin, DENS_VEC & xmax) 
   {
     xmin.reset(nSD_);
     xmax.reset(nSD_);
     int nne = num_nodes_per_element();
     for (int isd=0; isd<nSD_; isd++) {
       int id = element_connectivity_global(ielem, 0);
       double x = nodalCoords_(isd,id);
       xmin(isd) = x;
       xmax(isd) = x;
       for (int inode=1; inode<nne; inode++) {
         id = element_connectivity_global(ielem, inode);
         x = nodalCoords_(isd,id);
         xmin(isd) = min(xmin(isd), x );
         xmax(isd) = max(xmax(isd), x );
       }
     }
   }
 
   // -------------------------------------------------------------
   // element size in each direction 
   // -------------------------------------------------------------
   void FE_Mesh::element_size(const int ielem,
                               double & hx, double & hy, double & hz) 
   {
     DENS_VEC xmin(nSD_), xmax(nSD_);
     bounding_box(ielem,xmin,xmax);
     hx = xmax(0)-xmin(0);
     hy = xmax(1)-xmin(1);
     hz = xmax(2)-xmin(2);
   }
 
   // -------------------------------------------------------------
   //   face_coordinates
   // -------------------------------------------------------------
   void FE_Mesh::face_coordinates(const PAIR face, DENS_MAT & xCoords) const
   {
     const int eltID=face.first, faceID=face.second;
     const int nnf = num_nodes_per_face();
     const Array2D <int> & local_conn = local_face_connectivity();
 
     xCoords.reset(nSD_, nnf, false);
 
     for (int inode=0; inode < nnf; inode++) 
     {
       int id = element_connectivity_global(eltID, local_conn(faceID,inode));
       for (int isd=0; isd<nSD_; isd++) 
         xCoords(isd,inode) = nodalCoords_(isd,id);
     }
   }
 
   // -------------------------------------------------------------
   //   nodal_coordinates
   // -------------------------------------------------------------
   DENS_VEC FE_Mesh::nodal_coordinates(const int nodeID) const
   {
     DENS_VEC xCoords(nSD_, false);
     const int id = uniqueToGlobalMap_(nodeID);
     for (int isd=0; isd<nSD_; isd++)
       xCoords(isd) = nodalCoords_(isd, id);
     return xCoords;
   }
   DENS_VEC FE_Mesh::global_coordinates(const int nodeID) const
   {
     DENS_VEC xCoords(nSD_, false);
     for (int isd=0; isd<nSD_; isd++)
       xCoords(isd) = nodalCoords_(isd, nodeID);
     return xCoords;
   }
 
   // -------------------------------------------------------------
   //   query_nodeset
   // -------------------------------------------------------------
   bool FE_Mesh::query_nodeset(const string & name) const
   {
     if (name == "all")  return true;
     if (nodeSetMap_.find(name) == nodeSetMap_.end()) return false;
     return true;
   }
 
   // -------------------------------------------------------------
   //   get_nodeset
   // -------------------------------------------------------------
   const set<int> & FE_Mesh::nodeset(const string & name) const
   {
     NODE_SET_MAP::const_iterator iter = nodeSetMap_.find(name);
     if (name == "all") return nodeSetAll_;
     else if (iter == nodeSetMap_.end()) 
       throw ATC_Error( "No nodeset with name " + name + " found.");  
     else return iter->second;
   }
 
   // -------------------------------------------------------------
   //   get_elementset
   // -------------------------------------------------------------
   const set<int> & FE_Mesh::elementset(const string & name) const
   {
     NODE_SET_MAP::const_iterator iter = elementSetMap_.find(name);
     if (name == "all") return elementSetAll_;
     else if (iter == elementSetMap_.end()) 
       throw ATC_Error( "No elementset with name " + name + " found.");  
     else return iter->second;
   }
 
   // -------------------------------------------------------------
   //   nodeset_to_minimal_elementset
   // -------------------------------------------------------------
   void FE_Mesh::nodeset_to_minimal_elementset
     (const string & name, set<int> & elemSet) const
   {
     if (name == "all") {
       for (int ielem = 0; ielem < nElts_; ielem++) {
         elemSet.insert(ielem);
       }
     }
     else {
       NODE_SET_MAP::const_iterator iter = nodeSetMap_.find(name);
       if (iter == nodeSetMap_.end()) 
         throw ATC_Error( "No nodeset with name " + name + " found.");
       nodeset_to_minimal_elementset(iter->second,elemSet);
       if (elemSet.size()==0) {
         throw ATC_Error("No elements found in minimal condensation of nodeset " + name);
       }
     }
   }
 
   // -------------------------------------------------------------
   //   nodeset_to_minimal_elementset
   // -------------------------------------------------------------
   void FE_Mesh::nodeset_to_minimal_elementset
   (const set<int> & nodeSet, set<int> & elemSet) const
   {
     int npe = num_nodes_per_element();
     for (int ielem=0; ielem < nElts_; ielem++) {
       int inode = 0;
       bool in = true;
       while (in && inode < npe) {
         int node = element_connectivity_unique(ielem, inode);
         set<int>::const_iterator iter = nodeSet.find(node);
         if (iter == nodeSet.end()) { in=false; }
         inode++;
       }
       if (in) elemSet.insert(ielem);
     }
   }
 
   // -------------------------------------------------------------
   //   nodeset_to_maximal_elementset
   // -------------------------------------------------------------
   void FE_Mesh::nodeset_to_maximal_elementset(const string &name, set<int> &elemSet) const
   {
     if (name == "all") {
       for (int ielem = 0; ielem < nElts_; ielem++) {
         elemSet.insert(ielem);
       }
     }
     else {
       NODE_SET_MAP::const_iterator iter = nodeSetMap_.find(name);
       if (iter == nodeSetMap_.end()) 
         throw ATC_Error( "No nodeset with name " + name + " found.");
       nodeset_to_maximal_elementset(iter->second,elemSet);
       if (elemSet.size()==0) {
         throw ATC_Error("No elements found in maximal condensation of nodeset " + name);
       }
     }
   }
 
   // -------------------------------------------------------------
   //   nodeset_to_maximal_elementset
   // -------------------------------------------------------------
   void FE_Mesh::nodeset_to_maximal_elementset(const set<int> &nodeSet, set<int> &elemSet) const
   {
     int npe = num_nodes_per_element();
     for (int ielem = 0; ielem < nElts_; ielem++) {
       int inode = 0;
       bool in = false;
       while (!in && inode < npe) {
         int node = element_connectivity_unique(ielem, inode);
         set<int>::const_iterator iter = nodeSet.find(node);
         if (iter != nodeSet.end()) { in = true; }
         inode++;
       }
       if (in) elemSet.insert(ielem);
     }
   }
 
   // -------------------------------------------------------------
   //   elementset_to_nodeset
   // -------------------------------------------------------------
   void FE_Mesh::elementset_to_nodeset
-    (const set<int> & elemSet, set<int> & nodeSet) const
+    (const set<int> & elemSet, set<int>  nodeSet) const
   {
     int npe = num_nodes_per_element();
     set<int>::const_iterator itr;
     for (itr = elemSet.begin(); itr != elemSet.end(); itr++) 
     {
       int ielem = *itr;
       for (int inode=0; inode < npe; inode++) 
       {
         int node = element_connectivity_global(ielem, inode);
         nodeSet.insert(node);
       }
     }
   }
 
   // -------------------------------------------------------------
   //   elementset_to_nodeset
   // -------------------------------------------------------------
   void FE_Mesh::elementset_to_nodeset
-    (const string & name, set<int> & nodeSet) const
+    (const string & name, set<int>  nodeSet) const
   {
     if (name == "all")
       for (int ielem = 0; ielem < nElts_; ielem++) 
         nodeSet.insert(ielem);
 
     else 
     {
       ELEMENT_SET_MAP::const_iterator iter = elementSetMap_.find(name);
       if (iter == elementSetMap_.end()) 
         throw ATC_Error( "No elementset with name " + name + " found.");
 
       int npe = num_nodes_per_element();
       const set<int> &elemSet = iter->second;
       set<int>::const_iterator itr;
       for (itr = elemSet.begin(); itr != elemSet.end(); itr++) 
       {
         int ielem = *itr;
         for (int inode=0; inode < npe; inode++) 
         {
           int node = element_connectivity_unique(ielem, inode);
           nodeSet.insert(node);
           inode++;
         }
       }
     }
   }
+  set<int>  FE_Mesh::elementset_to_nodeset
+    (const string & name) const
+  {
+    set<int> nset;
+    elementset_to_nodeset(name,nset);
+    return nset;
+  }
 
   // -------------------------------------------------------------
   //   elementset_to_minimal_nodeset
   // -------------------------------------------------------------
   void FE_Mesh::elementset_to_minimal_nodeset
     (const string & name, set<int> & nodeSet) const
   {
     // return:  set - complement_of_set
     if (name == "all")  { return;}
     else 
     {
       elementset_to_nodeset(name,nodeSet);
       set<int> compElemSet;
       elementset_complement(name,compElemSet);
       int npe = num_nodes_per_element();
       set<int>::const_iterator itr;
       for (itr = compElemSet.begin(); itr != compElemSet.end(); itr++) 
       {
         int ielem = *itr;
         for (int inode=0; inode < npe; inode++) 
         {
           int node = element_connectivity_unique(ielem, inode);
           nodeSet.erase(node);
           inode++;
         }
       }
     }
   }
 
   // -------------------------------------------------------------
   //   elementset_complement
   // -------------------------------------------------------------
   void FE_Mesh::elementset_complement
     (const string & name, set<int> & cElemSet) const
   {
     // return:  set - complement_of_set
     if (name == "all")  { return;}
     else 
     {
       ELEMENT_SET_MAP::const_iterator iter = elementSetMap_.find(name);
       if (iter == elementSetMap_.end()) 
         throw ATC_Error( "No elementset with name " + name + " found.");
 
       const set<int> &elemSet = iter->second;
       for (int ielem = 0; ielem < nElts_; ielem++) 
       {
         if(elemSet.find(ielem) == elemSet.end() ) cElemSet.insert(ielem);
       }
     }
   }
 
   // -------------------------------------------------------------
   //   elementset_complement
   // -------------------------------------------------------------
   void FE_Mesh::elementset_complement
     (const set<int> & elemSet, set<int> & cElemSet) const
   {
     for (int ielem = 0; ielem < nElts_; ielem++) 
     {
       if(elemSet.find(ielem) == elemSet.end() ) cElemSet.insert(ielem);
     }
   }
   // -------------------------------------------------------------
   //   faceset_to_nodeset
   // -------------------------------------------------------------
   void FE_Mesh::faceset_to_nodeset(const string &name, set<int> &nodeSet) const
   {
     if (name == "all") {
       for (int inode = 0; inode < nNodesUnique_; inode++)
         nodeSet.insert(inode);
     }
     else 
     {
       FACE_SET_MAP::const_iterator faceset = faceSetMap_.find(name);
       if (faceset == faceSetMap_.end()) 
         throw ATC_Error( "No faceset with name " + name + " found.");
       const set<PAIR> & faceSet = faceset->second;
       set<PAIR>::const_iterator iter;
       Array <int> conn;
       for (iter = faceSet.begin(); iter != faceSet.end(); iter++) 
       {
         PAIR face = *iter;
         face_connectivity_unique(face,conn);
         for (int i = 0; i < conn.size() ; ++i) {
           int inode = conn(i);
           nodeSet.insert(inode);
         }
       }
     }
   }
   void FE_Mesh::faceset_to_nodeset(const set<PAIR> &faceSet, set<int> &nodeSet) const
   {
     set<PAIR>::const_iterator iter;
     Array <int> conn;
     for (iter = faceSet.begin(); iter != faceSet.end(); iter++) 
     {
       PAIR face = *iter;
       face_connectivity_unique(face,conn);
       for (int i = 0; i < conn.size() ; ++i) {
         int inode = conn(i);
         nodeSet.insert(inode);
       }
     }
   }
   // -------------------------------------------------------------
   //   faceset_to_nodeset
   // -------------------------------------------------------------
   void FE_Mesh::faceset_to_nodeset_global(const string &name, set<int> &nodeSet) const
   {
     if (name == "all") {
       for (int inode = 0; inode < nNodes_; inode++)
         nodeSet.insert(inode);
     }
     else 
     {
       FACE_SET_MAP::const_iterator faceset = faceSetMap_.find(name);
       if (faceset == faceSetMap_.end()) 
         throw ATC_Error( "No faceset with name " + name + " found.");
       const set<PAIR> & faceSet = faceset->second;
       set<PAIR>::const_iterator iter;
       Array <int> conn;
       for (iter = faceSet.begin(); iter != faceSet.end(); iter++) 
       {
         PAIR face = *iter;
         face_connectivity(face,conn);
         for (int i = 0; i < conn.size() ; ++i) {
           int inode = conn(i);
           nodeSet.insert(inode);
         }
       }
     }
   }
   void FE_Mesh::faceset_to_nodeset_global(const set<PAIR> &faceSet, set<int> &nodeSet) const
   {
     set<PAIR>::const_iterator iter;
     Array <int> conn;
     for (iter = faceSet.begin(); iter != faceSet.end(); iter++) 
     {
       PAIR face = *iter;
       face_connectivity(face,conn);
       for (int i = 0; i < conn.size() ; ++i) {
         int inode = conn(i);
         nodeSet.insert(inode);
       }
     }
   }
 
   // -------------------------------------------------------------
   //   get_faceset
   // -------------------------------------------------------------
   const set<PAIR> &FE_Mesh::faceset(const string & name) const
   {
     FACE_SET_MAP::const_iterator iter = faceSetMap_.find(name);
     if (iter == faceSetMap_.end())
     {
       throw ATC_Error( "No faceset with name " + name + " found.");
     }
     return iter->second;
   }
 
   // -------------------------------------------------------------
   //   create_nodeset
   // -------------------------------------------------------------
   void FE_Mesh::create_nodeset(const string & name,
                                const set<int> & nodeSet)
   {
     // Make sure we don't already have a nodeset with this name
     NODE_SET_MAP::iterator iter = nodeSetMap_.find(name);
     if (iter != nodeSetMap_.end()) {
       string message("A nodeset with name " + name + " is already defined.");
       throw ATC_Error( message);
     }
     nodeSetMap_[name] = nodeSet;
 
     if (ATC::LammpsInterface::instance()->rank_zero()) { 
       stringstream ss;
       ss << "created nodeset " << name 
          << " with " << nodeSet.size() << " nodes";
       ATC::LammpsInterface::instance()->print_msg_once(ss.str());
     }
   }
   void FE_Mesh::create_nodeset(const string & name,
                                double xmin, 
                                double xmax,
                                double ymin, 
                                double ymax,
                                double zmin, 
                                double zmax)
   {
     // Make sure we don't already have a nodeset with this name
     NODE_SET_MAP::iterator iter = nodeSetMap_.find(name);
     if (iter != nodeSetMap_.end()) {
       string message("A nodeset with name " + name + " is already defined.");
       throw ATC_Error( message);
     }
 
-    if (xmin == xmax) split_values(xmin,xmax);
-    if (ymin == ymax) split_values(ymin,ymax);
-    if (zmin == zmax) split_values(zmin,zmax);
-
-    xmin *= xscale_;
-    xmax *= xscale_;
-    ymin *= yscale_;
-    ymax *= yscale_;
-    zmin *= zscale_;
-    zmax *= zscale_;
-
     set<int> nodeSet;
 
     // Loop over nodes and add their unique id's to the set if they're
     // in the correct range
     for (int inode = 0; inode < nNodes_; inode++) {
       double x = nodalCoords_(0,inode);
       double y = nodalCoords_(1,inode);
       double z = nodalCoords_(2,inode);
       if ( (xmin <= x) && (x <= xmax) &&
            (ymin <= y) && (y <= ymax) &&
            (zmin <= z) && (z <= zmax) ) {
         int uid = globalToUniqueMap_(inode);
         nodeSet.insert(uid);
       }
     }
     if (nodeSet.size() == 0) {
       string message("nodeset " + name + " has zero size.");
       throw ATC_Error( message);
     }
 
     nodeSetMap_[name] = nodeSet;
 
     if (ATC::LammpsInterface::instance()->rank_zero()) { 
       stringstream ss;
       ss << "created nodeset " << name 
          << " with " << nodeSet.size() << " nodes";
       ATC::LammpsInterface::instance()->print_msg_once(ss.str());
     }
   }
 
   // -------------------------------------------------------------
   //   add_to_nodeset
   // -------------------------------------------------------------
   void FE_Mesh::add_to_nodeset(const string & name,
                                double xmin, 
                                double xmax,
                                double ymin, 
                                double ymax,
                                double zmin, 
                                double zmax)
   {
     // Make sure we already have a nodeset with this name
     NODE_SET_MAP::iterator iter = nodeSetMap_.find(name);
     if (iter == nodeSetMap_.end()) {
       string message("A nodeset with name " +name + " is not already defined.");
       throw ATC_Error( message);
     }
 
-    if (xmin == xmax) split_values(xmin,xmax);
-    if (ymin == ymax) split_values(ymin,ymax);
-    if (zmin == zmax) split_values(zmin,zmax);
-
-    xmin *= xscale_;
-    xmax *= xscale_;
-    ymin *= yscale_;
-    ymax *= yscale_;
-    zmin *= zscale_;
-    zmax *= zscale_;
-
     set<int> nodeSet;
 
     // Loop over nodes and add their unique id's to the set if they're
     // in the correct range
     for (int inode = 0; inode < nNodes_; inode++) {
       double x = nodalCoords_(0,inode);
       double y = nodalCoords_(1,inode);
       double z = nodalCoords_(2,inode);
       if ( (xmin <= x) && (x <= xmax) &&
            (ymin <= y) && (y <= ymax) &&
            (zmin <= z) && (z <= zmax) ) {
         int uid = globalToUniqueMap_(inode);
         nodeSet.insert(uid);
       }
     }
     if (nodeSet.size() == 0) {
       string message("nodeset " + name + " has zero size.");
       throw ATC_Error( message);
     }
 
     nodeSetMap_[name].insert(nodeSet.begin(),nodeSet.end());
 
     if (ATC::LammpsInterface::instance()->rank_zero()) { 
       stringstream ss;
       ss   << "added " << nodeSet.size() << " nodes to nodeset " << name ;
       ATC::LammpsInterface::instance()->print_msg_once(ss.str());
     }
   }
 
   // -------------------------------------------------------------
   //   create_faceset
   // -------------------------------------------------------------
   void FE_Mesh::create_faceset(const string & name,
                                double xmin, 
                                double xmax,
                                double ymin, 
                                double ymax,
                                double zmin, 
                                double zmax, 
                                bool outward)
   {
     // Make sure we don't already have a nodeset with this name
     FACE_SET_MAP::iterator iter = faceSetMap_.find(name);
     if (iter != faceSetMap_.end()) 
       throw ATC_Error( "A faceset with name " + name + " is already defined.");
 
-    if (xmin == xmax) split_values(xmin,xmax);
-    if (ymin == ymax) split_values(ymin,ymax);
-    if (zmin == zmax) split_values(zmin,zmax);
-
     set<PAIR> faceSet;
     // Loop over face and add their unique id's to the set if they concide
     // with region
     const int nf = num_faces_per_element();
     const int npf = num_nodes_per_face();
     const Array2D<int> & face_conn = local_face_connectivity();
     for (int ielem = 0; ielem < nElts_; ielem++) 
     {
       for (int iface = 0; iface < nf; iface++) 
       {
         bool in = true;
         bool on_xmin = true, on_xmax = true; 
         bool on_ymin = true, on_ymax = true;
         bool on_zmin = true, on_zmax = true;
         bool x_neg = false, x_pos = false;
         bool y_neg = false, y_pos = false;
         bool z_neg = false, z_pos = false;
         double x,y,z;
         for (int inode = 0; inode < npf; inode++) 
         {
           x = nodalCoords_(0,connectivity_(face_conn(iface,inode),ielem));
           y = nodalCoords_(1,connectivity_(face_conn(iface,inode),ielem));
           z = nodalCoords_(2,connectivity_(face_conn(iface,inode),ielem));
           
           if ( x + tol < xmin) { in = false; break; }
           if ( x - tol > xmax) { in = false; break; }
           if ( y + tol < ymin) { in = false; break; }
           if ( y - tol > ymax) { in = false; break; }
           if ( z + tol < zmin) { in = false; break; }
           if ( z - tol > zmax) { in = false; break; }
 
           on_xmin = on_xmin &&  fabs(x-xmin) <= tol;
           on_xmax = on_xmax &&  fabs(x-xmax) <= tol;
           on_ymin = on_ymin &&  fabs(y-ymin) <= tol;
           on_ymax = on_ymax &&  fabs(y-ymax) <= tol;
           on_zmin = on_zmin &&  fabs(z-zmin) <= tol;
           on_zmax = on_zmax &&  fabs(z-zmax) <= tol;
         }
         if (in) {
           // note based on structured grid
           if (outward) 
           {
             if (on_xmin && iface==0) { x_neg = true;}
             if (on_xmax && iface==1) { x_pos = true;}
             if (on_ymin && iface==2) { y_neg = true;}
             if (on_ymax && iface==3) { y_pos = true;}
             if (on_zmin && iface==4) { z_neg = true;}
             if (on_zmax && iface==5) { z_pos = true;}
           }
           else 
           {
             if (on_xmin && iface==1) { x_pos = true;}
             if (on_xmax && iface==0) { x_neg = true;}
             if (on_ymin && iface==3) { y_pos = true;}
             if (on_ymax && iface==2) { y_neg = true;}
             if (on_zmin && iface==5) { z_pos = true;}
             if (on_zmax && iface==4) { z_neg = true;}
           }
   
           if (  (x_neg || x_pos) || (y_neg || y_pos) || (z_neg || z_pos) ) {
             PAIR face(ielem,iface);
             faceSet.insert(face);
           }
         }
       }
     }
     if (faceSet.empty()) throw ATC_Error( "faceset "+name+" is empty.");
 
     faceSetMap_[name] = faceSet;
     if (ATC::LammpsInterface::instance()->comm_rank() == 0) { 
       stringstream ss;
       ss   << "created faceset " << name 
            << " with " << faceSet.size() << " faces";
       ATC::LammpsInterface::instance()->print_msg_once(ss.str());
     }
   }
 
   void FE_Mesh::create_faceset(const string & name,
                                double xRef, 
                                int nIdx, int nSgn,
                                int nIdx2, double x2lo, double x2hi,
                                int nIdx3, double x3lo, double x3hi)
   {
-    // note scaling done by caller and split_values is tricky with orientation
+    double xtol = tolerance(xRef);
     // Make sure we don't already have a faceset with this name
     FACE_SET_MAP::iterator iter = faceSetMap_.find(name);
     if (iter != faceSetMap_.end()) 
       throw ATC_Error( "A faceset with name "+name+" is already defined.");
 
     bool finite2 = (nIdx2 >= 0);
     bool finite3 = (nIdx3 >= 0);
 
     set<PAIR> faceSet;
     // Loop over faces i& add unique id's to the set if concide w/ plane
     int nf = num_faces_per_element();
     int npf = num_nodes_per_face();
     const Array2D<int> & face_conn = local_face_connectivity();
     for (int ielem = 0; ielem < nElts_; ielem++) 
     {
       for (int iface = 0; iface < nf; iface++) 
       {
         bool in = true;
         // all nodes must be on the plane
         for (int inode = 0; inode < npf; inode++) {
           int node = connectivity_(face_conn(iface,inode),ielem);
           double x = nodalCoords_(nIdx,node);
-          if ( fabs(x-xRef) > tol){ in = false; break;}
+          if ( fabs(x-xRef) > xtol){ in = false; break;}
           if (finite2) {
             double y = nodalCoords_(nIdx2,node);
             if ( y < x2lo || y > x2hi){ in = false; break;}
           }
           if (finite3) {
             double y = nodalCoords_(nIdx3,node);
             if ( y < x3lo || y > x3hi){ in = false; break;}
           }
         }
         // check correct orientation
         if (in) 
         {
           if ( (nIdx == 0 && iface==0 && nSgn == -1) 
             || (nIdx == 0 && iface==1 && nSgn ==  1)
             || (nIdx == 1 && iface==2 && nSgn == -1)
             || (nIdx == 1 && iface==3 && nSgn ==  1)
             || (nIdx == 2 && iface==4 && nSgn == -1)
             || (nIdx == 3 && iface==5 && nSgn ==  1) )
           {
             PAIR face(ielem,iface);
             faceSet.insert(face);
           }
         }
       }
     }
 
     if (faceSet.empty()) 
       throw ATC_Error( "faceset "+name+" is empty.");
 
     faceSetMap_[name] = faceSet;
     if (ATC::LammpsInterface::instance()->comm_rank() == 0) { 
       stringstream ss;
       ss   << "created faceset " << name 
            << " with " << faceSet.size() << " faces";
       ATC::LammpsInterface::instance()->print_msg_once(ss.str());
     }
   }
 
   // -------------------------------------------------------------
   //   create_elementset
   // -------------------------------------------------------------
   void FE_Mesh::create_elementset(const string & name,
                                double xmin, 
                                double xmax,
                                double ymin, 
                                double ymax,
                                double zmin, 
                                double zmax)
   {
     // Make sure we don't already have a elementset with this name
     ELEMENT_SET_MAP::iterator iter = elementSetMap_.find(name);
     if (iter != elementSetMap_.end()) {
       string message("An elementset with name "+name+" is already defined.");
       throw ATC_Error( message);
     }
 
-    if (xmin == xmax) split_values(xmin,xmax);
-    if (ymin == ymax) split_values(ymin,ymax);
-    if (zmin == zmax) split_values(zmin,zmax);
-
-    xmin *= xscale_;
-    xmax *= xscale_;
-    ymin *= yscale_;
-    ymax *= yscale_;
-    zmin *= zscale_;
-    zmax *= zscale_;
-
     set<int> nodeSet;
 
     // Loop over nodes and add their unique id's to the set if they're
     // in the correct range
     for (int inode = 0; inode < nNodes_; inode++) {
       double x = nodalCoords_(0,inode);
       double y = nodalCoords_(1,inode);
       double z = nodalCoords_(2,inode);
       if ( (xmin <= x) && (x <= xmax) &&
            (ymin <= y) && (y <= ymax) &&
            (zmin <= z) && (z <= zmax) ) {
         int uid = globalToUniqueMap_(inode);
         nodeSet.insert(uid);
       }
     }
     if (nodeSet.size() == 0) {
       string message("elementset " + name + " has zero size.");
       throw ATC_Error( message);
     }
 
     // create a minimal element set from all the nodes included in the region
     set<int> elemSet;
     int npe = num_nodes_per_element();
     for (int ielem=0; ielem < nElts_; ielem++) 
     {
       int inode = 0;
       bool in = true;
       while (in && inode < npe) 
       {
         int node = connectivityUnique_(inode, ielem);
         set<int>::const_iterator iter = nodeSet.find(node);
         if (iter == nodeSet.end()) { in=false; }
         inode++;
       }
       if (in) elemSet.insert(ielem);
     }
     if (elemSet.size() == 0) {
       string message("element set " + name + " has zero size.");
       throw ATC_Error( message);
     }
     elementSetMap_[name] = elemSet;
 
     if (ATC::LammpsInterface::instance()->comm_rank() == 0) { 
       stringstream ss;
       ss   << "created elementset " << name 
            << " with " << elemSet.size() << " elements";
       ATC::LammpsInterface::instance()->print_msg_once(ss.str());
     }
   }
   // -------------------------------------------------------------
   //   get_numIPsPerElement()
   // -------------------------------------------------------------
   int FE_Mesh::num_ips_per_element() const
   {
     return feElement_->num_ips();
   }
   // -------------------------------------------------------------
   //   get_numNodesPerElement()
   // -------------------------------------------------------------
   int FE_Mesh::num_nodes_per_element() const
   {
     return feElement_->num_elt_nodes();
   }
   // -------------------------------------------------------------
   //   get_numFacesPerElement()
   // -------------------------------------------------------------
   int FE_Mesh::num_faces_per_element() const
   {
     return feElement_->num_faces();
   }
   // -------------------------------------------------------------
   //   get_num_ips_per_face()
   // -------------------------------------------------------------
   int FE_Mesh::num_ips_per_face() const
   {
     return feElement_->num_face_ips();
   }
   // -------------------------------------------------------------
   //   get_num_nodes_per_face()
   // -------------------------------------------------------------
   int FE_Mesh::num_nodes_per_face() const
   {
     return feElement_->num_face_nodes();
   }
   // -------------------------------------------------------------
   //   mappings from element id to associated nodes
   // -------------------------------------------------------------
   
   
   void FE_Mesh::element_connectivity_global(const int eltID,
                                             Array<int> & nodes) const
   {
     const int npe = num_nodes_per_element();
     nodes.reset(npe);
 
     // use connectivity arrays
     if (decomposition_ && partitioned_) {
       for (int inode = 0; inode < npe; inode++) {
         nodes(inode) = myConnectivity_(inode, map_elem_to_myElem(eltID)); 
       }
     } else {
       for (int inode = 0; inode < npe; inode++) {
         nodes(inode) = connectivity_(inode, eltID); 
       }
     }
   }
   // -------------------------------------------------------------
   //   
   // -------------------------------------------------------------
   void FE_Mesh::element_connectivity_unique(const int eltID,
                                             Array<int> & nodes) const
   {
     const int npe = num_nodes_per_element();
     nodes.reset(npe);
 
     // use connectivity arrays
     if (decomposition_ && partitioned_) {
       for (int inode = 0; inode < npe; inode++) {
         nodes(inode) = myConnectivityUnique_(inode, map_elem_to_myElem(eltID)); 
       }
     } else {
       for (int inode = 0; inode < npe; inode++) {
         nodes(inode) = connectivityUnique_(inode, eltID); 
       }
     }
   }
 
   // -------------------------------------------------------------
   //  
   // -------------------------------------------------------------
   int FE_Mesh::element_connectivity_global(const int eltID,
                                             const int inode) const
   {
     if (decomposition_ && partitioned_) {
       return myConnectivity_(inode, map_elem_to_myElem(eltID));
     } else {
       return connectivity_(inode, eltID);
     }
   }
   // -------------------------------------------------------------
   //   
   // -------------------------------------------------------------
   int FE_Mesh::element_connectivity_unique(const int eltID,
                                             const int inode) const
   {
     if (decomposition_ && partitioned_) {
       return myConnectivityUnique_(inode, map_elem_to_myElem(eltID));
     } else {
       return connectivityUnique_(inode, eltID);
     }
   }
   // -------------------------------------------------------------
   //  
   // -------------------------------------------------------------
   AliasArray<int> FE_Mesh::element_connectivity_global(const int eltID) const
   {
     if (decomposition_ && partitioned_) {
       return myConnectivity_.column(map_elem_to_myElem(eltID));
     } else {
       return connectivity_.column(eltID);
     }
   }
   // -------------------------------------------------------------
   //   
   // -------------------------------------------------------------
   AliasArray<int> FE_Mesh::element_connectivity_unique(const int eltID) const
   {
     if (decomposition_ && partitioned_) {
       return myConnectivityUnique_.column(map_elem_to_myElem(eltID));
     } else {
       return connectivityUnique_.column(eltID);
     }
   }
   // -------------------------------------------------------------
   //   local_face_connectivity()
   // -------------------------------------------------------------
   const Array2D<int> &FE_Mesh::local_face_connectivity() const
   {
     return feElement_->local_face_conn();
   }
 
   // -------------------------------------------------------------
   //   maps to/from partitioned element data
   // -------------------------------------------------------------
 
   int FE_Mesh::map_elem_to_myElem(int elemID) const
   {
     
     return elemToMyElemMap_.find(elemID)->second;
   }
 
   int FE_Mesh::map_myElem_to_elem(int myElemID) const
   {
     return myElts_[myElemID]; 
   }
   
   // -------------------------------------------------------------
   //   shape function evaluation
   // -------------------------------------------------------------
   
   // set quadrature scheme pass-through
   void FE_Mesh::set_quadrature(FeIntQuadrature type) 
   { 
     feElement_->set_quadrature(type); 
   }
 
   // shape function evaluation
   void FE_Mesh::shape_functions(const VECTOR &x,
                                 DENS_VEC &N,
                                 Array<int> &nodeList) const
   {
     // get element id from global coordinates
     int eltID = map_to_element(x);
     
     // call appropriate function below, with eltID
     shape_functions(x,eltID,N,nodeList);
   }
 
   void FE_Mesh::shape_functions(const DENS_VEC &x, 
                                 DENS_VEC &N,
                                 DENS_MAT &dNdx,
                                 Array<int> &nodeList) const
   {
     // get element id from global coordinates
     int eltID = map_to_element(x);
 
     // call appropriate function below, with eltID
     shape_functions(x,eltID,N,dNdx,nodeList);
   }
 
   void FE_Mesh::shape_functions(const VECTOR &x,
                                 const int eltID,
                                 DENS_VEC &N,
                                 Array<int> &nodeList) const
   {
     // Get element node coordinates from mesh
     DENS_MAT eltCoords;
     element_coordinates(eltID, eltCoords);
     
     // pass through call
     feElement_->shape_function(eltCoords,x,N);
     
     // determine nodes which correspond to shape function indices
     element_connectivity_unique(eltID,nodeList);
   }
 
   void FE_Mesh::shape_functions(const DENS_VEC &x,
                                 const int eltID,
                                 DENS_VEC &N,
                                 DENS_MAT &dNdx,
                                 Array<int> &nodeList) const
   {
     // Get element node coordinates from mesh
     DENS_MAT eltCoords;
     element_coordinates(eltID,eltCoords);
 
     // pass through call
     feElement_->shape_function(eltCoords,x,N,dNdx);
     
     // determine nodes which correspond to shp function indices
     element_connectivity_unique(eltID,nodeList);
   }
 
   void FE_Mesh::shape_function_derivatives(const DENS_VEC &x,
                                 const int eltID,
                                 DENS_MAT &dNdx,
                                 Array<int> &nodeList) const
   {
     // Get element node coordinates from mesh
     DENS_MAT eltCoords;
     element_coordinates(eltID,eltCoords);
 
     // pass through call
     feElement_->shape_function_derivatives(eltCoords,x,dNdx);
     
     // determine nodes which correspond to shp function indices
     element_connectivity_unique(eltID,nodeList);
   }
 
   void FE_Mesh::shape_function(const int eltID,
                                DENS_MAT &N, 
                                DIAG_MAT &weights) const
   {
     // unused data (but required to calc weights)
     vector<DENS_MAT> dN;
 
     // call below function with dN to avoid duplicated code
     shape_function(eltID,N,dN,weights);
   }
 
   void FE_Mesh::shape_function(int eltID,
                                DENS_MAT &N, 
                                vector<DENS_MAT> &dN,
                                DIAG_MAT &weights) const
   {
     // Get element node coordinates from mesh
     DENS_MAT eltCoords;
     element_coordinates(eltID,eltCoords);
 
     // pass through call
     feElement_->shape_function(eltCoords,N,dN,weights);
   }
 
   void FE_Mesh::face_shape_function(const PAIR &face,
                                     DENS_MAT &N,
                                     DENS_MAT &n,
                                     DIAG_MAT &weights) const
   {
     int eltID = face.first;
     int faceID = face.second;
     
     // Get element node coordinates from mesh
     DENS_MAT eltCoords;
     element_coordinates(eltID,eltCoords);
 
     // pass through call
     feElement_->face_shape_function(eltCoords,faceID,N,n,weights);
   }
 
   void FE_Mesh::face_shape_function(const PAIR &face,
                                     DENS_MAT &N,
                                     vector<DENS_MAT> &dN,
                                     vector<DENS_MAT> &Nn,
                                     DIAG_MAT &weights) const
   {
     int eltID = face.first;
     int faceID = face.second;
     
     // Get element node coordinates from mesh
     DENS_MAT eltCoords;
     element_coordinates(eltID,eltCoords);
 
     // pass through call
     feElement_->face_shape_function(eltCoords,faceID,N,dN,Nn,weights);
   }
 
   double FE_Mesh::face_normal(const PAIR &face,
                               int ip,
                               DENS_VEC &normal)  const
   {
     int eltID = face.first;
     int faceID = face.second;
     
     // Get element node coordinates from mesh
     DENS_MAT eltCoords;
     element_coordinates(eltID,eltCoords);
 
     // pass through call
     double J = feElement_->face_normal(eltCoords,faceID,ip,normal);
     return J;
   }
 
   //-----------------------------------------------------------------------
   void FE_Mesh::output(string prefix) const
   {
     set<int> otypes;
     otypes.insert(ENSIGHT);
     otypes.insert(FULL_GNUPLOT);
     OutputManager meshSets(prefix,otypes);
     meshSets.write_geometry(&nodalCoords_, & connectivity_);
     OUTPUT_LIST subsetData;
     int size = nNodesUnique_;
     // material
 //  DENS_MAT material(nNodes_,1);
 //  material = 1;
 //  subsetData["material"] = &material;
     //string name = "global_to_unique_map";
     // nodesets
     NODE_SET_MAP::const_iterator niter;
     map<string,DENS_MAT> nodesets;
     for (niter = nodeSetMap_.begin(); niter != nodeSetMap_.end(); niter++) {
       string name = niter->first;
       const set<int> & nset = niter->second;
       string nodeset = "nodeset_"+name;
       nodesets[nodeset].reset(size,1);
       set<int>::const_iterator iter;
       for (iter = nset.begin(); iter != nset.end(); iter++) {
         (nodesets[nodeset])(*iter,0) = 1;  
       }
       subsetData[nodeset] = & nodesets[nodeset];
     }
     // facesets
     FACE_SET_MAP::const_iterator fiter;
     map<string,DENS_MAT> facesets;
     for (fiter = faceSetMap_.begin(); fiter != faceSetMap_.end(); fiter++) {
       string name = fiter->first;
       string faceset = "faceset_"+name;
       facesets[faceset].reset(size,1);
       set<int> nset;
       faceset_to_nodeset(name,nset);
       set<int>::const_iterator iter;
       for (iter = nset.begin(); iter != nset.end(); iter++) {
         (facesets[faceset])(*iter,0) = 1;
       }
       subsetData[faceset] = & facesets[faceset];
     }
     // elementsets
     ELEMENT_SET_MAP::const_iterator eiter;
     map<string,DENS_MAT> elemsets;
     for (eiter = elementSetMap_.begin();eiter != elementSetMap_.end();eiter++) {
       string name = eiter->first;
       const set<int> & eset = eiter->second;
       string elemset = "elementset_"+name;
       elemsets[elemset].reset(size,1);
       set<int>::const_iterator iter;
       for (iter = eset.begin(); iter != eset.end(); iter++) {
         Array<int> nodes;
         element_connectivity_unique(*iter, nodes);
         for(int i = 0; i < nodes.size(); ++i) {
           (elemsets[elemset])(nodes(i),0) = 1; 
         }
       }
       subsetData[elemset] = & elemsets[elemset];
     }
     // output
     const int * map = globalToUniqueMap_.data();
     if (subsetData.size() > 0 )
       meshSets.write_data(0.0,&subsetData,map);
     else
       if (LammpsInterface::instance()->comm_rank() == 0) {
         stringstream ss;
         ss << "Warning mesh output requested without any mesh entities, output suppressed";
         ATC::LammpsInterface::instance()->print_msg(ss.str());
       }
   }
 
   bool FE_Mesh::is_owned_elt(int elt) const
   {
     return (find(myElts_.begin(), myElts_.end(), elt) != myElts_.end()); 
   }
 
 
   // -------------------------------------------------------------
   // -------------------------------------------------------------
   //   class FE_3DMesh
   // -------------------------------------------------------------
   // -------------------------------------------------------------
   FE_3DMesh::FE_3DMesh(const string elementType,
                        const int nNodes, 
                        const int nElements,
                        const Array2D<int> *connectivity, 
                        const DENS_MAT *nodalCoordinates,
                        const Array<bool> periodicity,
                        const Array< pair< string, set<int> > > *nodeSets):
     FE_Mesh(),
     minEltSize_(0),
     tree_(NULL)
   {
     // Pick which element class to make
     if (elementType == "HEX8") {
       feElement_ = new FE_ElementHex(8,4,2);
     } else if (elementType == "HEX20") {
       feElement_ = new FE_ElementHex(20,8,3);
     } else if (elementType == "HEX27") {
       feElement_ = new FE_ElementHex(27,9,3);
     } else if (elementType == "TET4") {
       feElement_ = new FE_ElementTet(4,3,2);
       hasPlanarFaces_ = true;
     } else {
       throw ATC_Error("Unrecognized element type specified.");
     }
 
     
     nSD_ = 3;
     nNodes_ = nNodes;
     nNodesUnique_ = nNodes;
     nElts_ = nElements;
     xscale_ = yscale_ = zscale_ = 1;
     periodicity_ = periodicity;
 
     // Connectivity and coordinates describe the mesh geometry.
     connectivity_.reset(connectivity->nRows(),connectivity->nCols());
     connectivity_ = (*connectivity);
     nodalCoords_.reset(nodalCoordinates->nRows(),nodalCoordinates->nCols());
     nodalCoords_ = (*nodalCoordinates);
 
     // set minimum element size
     minEltSize_ = 1.e20; 
     for (int i=0; i< connectivity_.nCols(); ++i) {
       int n1 = connectivity_(0,i);
       int n2 = connectivity_(1,i);
       double dx[3] = {fabs(nodalCoords_(0,n1)-nodalCoords_(0,n2)),
                       fabs(nodalCoords_(1,n1)-nodalCoords_(1,n2)),
                       fabs(nodalCoords_(2,n1)-nodalCoords_(2,n2))};
       minEltSize_ = min(minEltSize_,norm3(dx));
     }
 
     // create global-unique maps
     coordTol_ = this->coordinate_tolerance();
     setup_periodicity();
 
     // Create the "all" elementset, the "all" nodeset, and the read-in nodesets.
     for (int elem = 0; elem < nElts_; elem++) elementSetAll_.insert(elem); 
     for (int node = 0; node < nNodesUnique_; node++) nodeSetAll_.insert(node);
     const Array<pair<string,set<int> > > & sets = *nodeSets;
     for (int nodeSet = 0; nodeSet < sets.size(); ++nodeSet) {
       const set<int> & nset = sets(nodeSet).second;
       set<int> copy; 
       if (compactRemap_.size() > 0) {
         for (set<int>::iterator itr = nset.begin(); itr != nset.end(); itr++) {
           copy.insert(globalToUniqueMap_(compactRemap_(*itr)));
         }
       }
       else {
         for (set<int>::iterator itr = nset.begin(); itr != nset.end(); itr++) {
           copy.insert(globalToUniqueMap_(*itr));
         }
       }
       create_nodeset(sets(nodeSet).first, copy);
     }
     
     // Insert nodes and elements into KD-tree for PIE search.
     if (tree_ == NULL) {
       tree_ = KD_Tree::create_KD_tree(feElement_->num_elt_nodes(), nNodes_, 
         &nodalCoords_, nElts_, connectivity_);
     }
 
   }
 
   FE_3DMesh::~FE_3DMesh() {
-    //if (tree_)               delete tree_; 
-    
-    // not sure why, commenting out for now - JZ 2/28/13
+    if (tree_) delete tree_; 
   }
 
   // -------------------------------------------------------------
   //  setup_periodicity
   // -------------------------------------------------------------
   void FE_3DMesh::setup_periodicity(double tol)
   {
     // unique <-> global id maps
     globalToUniqueMap_.reset(nNodes_);
     uniqueToGlobalMap_.reset(nNodes_);
 
     for (int node = 0; node < nNodes_; node++) {
       globalToUniqueMap_(node) = node;
     }
 
     // recursive fix and setup global to unique map
     if (periodicity_(2)) { fix_periodicity(3); }
     if (periodicity_(1)) { fix_periodicity(2); }
     if (periodicity_(0)) { fix_periodicity(1); }
     
 
     // renumber to compact unique numbering
     // unique nodes map to the same id with global to unique
     if (nNodesUnique_ < nNodes_) {
       int n = 0;
       int m = nNodesUnique_;
       compactRemap_.reset(nNodes_); // old to new global numbering
       compactRemap_ = -1;
       for (int node = 0; node < nNodes_; node++) {
         if (globalToUniqueMap_(node) == node) { // unique nodes
           compactRemap_(node) = n++;
         }
         else { // periodic nodes
           compactRemap_(node) = m++;
         }
       }
       if (n != nNodesUnique_) throw ATC_Error("didn't compact numbering");
       int npe = num_nodes_per_element();
       // temporary copy
       DENS_MAT  coor = DENS_MAT(nodalCoords_);
       Array2D<int> conn(connectivity_);
       Array<int> oldGlobalToUniqueMap = globalToUniqueMap_;
       for (int node = 0; node < nNodes_; node++) {
         // unique = remap * global2unique  global
         globalToUniqueMap_(compactRemap_(node)) = compactRemap_(oldGlobalToUniqueMap(node));
         if (compactRemap_(node) < 0) throw ATC_Error("mis-map to compact numbering");
         // swap coordinates
         for (int i = 0; i < nSD_; i++) {
           nodalCoords_(i,compactRemap_(node)) = coor(i,node);
         }
       }
       for (int elem = 0; elem < nElts_; elem++) {
         for (int i = 0; i < npe; i++) {
           connectivity_(i,elem) = compactRemap_(conn(i,elem));
         }
       }
     }
 
     for (int node = 0; node < nNodes_; node++) {
       uniqueToGlobalMap_(globalToUniqueMap_(node)) = node;
     }
     set_unique_connectivity();
     //amended_ = true; // would always be true since setup_always called
   }
 
   void FE_3DMesh::fix_periodicity(int idir)
   {
     set<int> topNodes,botNodes;
     int ntop = find_boundary_nodes( idir,topNodes);
     int nbot = find_boundary_nodes(-idir,botNodes);
     if (ntop != nbot)
       throw ATC_Error("can't fix periodicity, number of top and bottom nodes are different ");
     bool match = match_nodes(idir,topNodes,botNodes,globalToUniqueMap_);
     if (!match) {
       stringstream ss;
       ss << "can't match periodic nodes with tolerance " << coordTol_;
       throw ATC_Error(ss.str());
     }
   }
 
   int FE_3DMesh::find_boundary_nodes(int idir, set<int> & nodes)
   {
     nodes.clear();
     double limit = 0;
     int idm = abs(idir)-1;
     DENS_MAT & x = nodalCoords_;
     if (idir > 0) limit = x.row_max(idm);
     else          limit = x.row_min(idm);
     for (int i=0; i < x.nCols(); ++i) {
       double xi = x(idm,i);
       if (fabs(xi-limit) < coordTol_) nodes.insert(i);
     }
 //  stringstream ss;
 //  ss << "found " << nodes.size() << " nodes at x_" << abs(idir) << "= "<< limit ;
 //  ATC::LammpsInterface::instance()->print_msg_once(ss.str());
     return nodes.size();
   }
 
   bool FE_3DMesh::match_nodes(int idir, set<int> & nodes1, set<int> & nodes2,
      Array<int> & map)
   {
     int i1=0,i2=1;
     plane_coords(idir-1,i1,i2);
     vector<bool> found(nNodes_,false);
     DENS_MAT & x = nodalCoords_;
     for (set<int>::iterator it1=nodes1.begin(); it1 != nodes1.end(); it1++) {
       int n1 = *it1;
       double x1 = x(i1,n1);
       double x2 = x(i2,n1);
       for (set<int>::iterator it2=nodes2.begin(); it2 != nodes2.end(); it2++) {
         int n2 = *it2;
         if (!found[n2]) {
           double y1 = x(i1,n2);
           double y2 = x(i2,n2);
           if (fabs(x1-y1) < coordTol_ && fabs(x2-y2) < coordTol_) {
             map(n1) = n2;
             found[n2] = true;
             // coincidence
             x(i1,n2) = x1;
             x(i2,n2) = x2;
           }
         }
       }
       if (map(n1) == n1) return false;
     }
     nNodesUnique_ -= nodes1.size();
     stringstream ss;
     ss << "condensed " << nodes1.size() << " periodic nodes in the " << abs(idir) << " direction";
     ATC::LammpsInterface::instance()->print_msg_once(ss.str());
     return true;
   }
   
   void FE_3DMesh::set_unique_connectivity(void) 
   {
     int numEltNodes = feElement_->num_elt_nodes();
     connectivityUnique_.reset(numEltNodes, nElts_);
     uniqueNodeToElementMap_.reset(nNodes_);
     for (int node = 0; node < nNodes_; node++) {
       uniqueNodeToElementMap_(node) = vector<int>();
     }
     for (int elem = 0; elem < nElts_; elem++) {
       for (int node = 0; node < numEltNodes; node++) {
         int global_node = connectivity_(node, elem);
         int unique_node = globalToUniqueMap_(global_node);
         connectivityUnique_(node,elem) = unique_node;
         uniqueNodeToElementMap_(unique_node).push_back(elem);
       }
     }
   }
 
   // orient the local coordinate with the global one
   bool FE_3DMesh::orient(int idm)
   {
     int numEltNodes = feElement_->num_elt_nodes();
     if (numEltNodes != 8) throw ATC_Error("can't currently orient non HEX8 elements");
     DENS_MAT x;
     for (int elem = 0; elem < nElts_; elem++) {
       element_coordinates(elem,x);
       double xmax = x.row_max(idm);
       double xmin = x.row_min(idm);
       set<int> top,bot;
       for (int node = 0; node < numEltNodes; node++) {
         // find top nodes
         if      ((x(idm,node) - xmax) < coordTol_) top.insert(node);
         // find bottom nodes
         else if ((x(idm,node) - xmin) < coordTol_) bot.insert(node);
         else return false;
       }
       // order by rh rule
       // start with one
     }
     throw ATC_Error("not completely implemented function: FE_3DMesh::orient");
     return true;
   }
 
   // -------------------------------------------------------------
   //  amend mesh for cut at specified faces
   // -------------------------------------------------------------
   void FE_3DMesh::cut_mesh(const set<PAIR> & faceSet, const set<int> & nodeSet)
   {
     int nsd = nSD_;
     // get all nodes to create an old to new number map
     set<int> dupNodes;
     map<int,int> oldToNewMap;
     faceset_to_nodeset_global(faceSet,dupNodes);
     // remove edge nodes
     Array<int> & node_map = globalToUniqueMap_;
     set<int>::const_iterator itr;
     for (itr = dupNodes.begin(); itr != dupNodes.end(); itr++) {
       int gnode = *itr;
       int unode = node_map(gnode);
       if (nodeSet.find(unode) != nodeSet.end()) {
         dupNodes.erase(gnode);
       }
     }
     int nNodesAdded = dupNodes.size();
     // copy coordinates and nodemap
     DENS_MAT &coordinates = nodalCoords_;
     int nNodesNew = coordinates.nCols() + nNodesAdded;
     coordinates.resize(nsd,nNodesNew,true);
     node_map.resize(nNodesNew,true);
     // add duplicate coordinates
     int iNew = nNodes_;
     int iNewUnique = nNodesUnique_;
     for (itr = dupNodes.begin(); itr != dupNodes.end(); 
          itr++,iNew++) {
       int iOld = *itr;
       oldToNewMap[iOld] = iNew;      // global ids
       if (iOld == node_map(iOld)) {  // non-image atom
         node_map(iNew) = iNewUnique++; 
       } else { 
         node_map(iNew) = -1; 
       }
       for(int j = 0; j < nsd; j++) {
         coordinates(j,iNew) = coordinates(j,iOld);
       }
     }
     nNodes_ = iNew;
     nNodesUnique_ = iNewUnique;
     for (itr = dupNodes.begin(); itr != dupNodes.end(); 
          itr++,iNew++) {
       int iOld = *itr;
       iNew = oldToNewMap[iOld];        // global ids
       int iOldImage = node_map(iOld);
       if (iOld != iOldImage) {         // image atom
         int iNewImage = oldToNewMap[iOldImage];
         node_map(iNew) = node_map(iNewImage);
       }
     }
     // update element connectivities
     const int nnf = num_nodes_per_face();
     const Array2D <int> & local_conn = feElement_->local_face_conn();
     set< PAIR >::iterator iter;
     for (iter = faceSet.begin(); iter != faceSet.end(); iter++) 
     {
       PAIR face = *iter;
       int eltID=face.first, faceID=face.second;
       for (int inode=0; inode < nnf; inode++) {
         int lid = local_conn(faceID,inode);
         int id = connectivity_(lid, eltID);
         if (oldToNewMap.find(id) != oldToNewMap.end() ) {
           int new_id = (*oldToNewMap.find(id)).second;
           connectivity_(lid,eltID)        = new_id;
           connectivityUnique_(lid, eltID) = node_map(new_id); 
         }
       }
     }
   }
 
 
   // -------------------------------------------------------------
   //  amend mesh for deleted elements
   // -------------------------------------------------------------
   void FE_3DMesh::delete_elements(const set<int> &elementList)
   {
     int nPE = num_nodes_per_element();
     set<int> elementsNew;
     elementset_complement(elementList,elementsNew);
     int nElementsNew = elementsNew.size();
     set<int> newToOld;
     map<int,int> oldToNewMap;
     elementset_to_nodeset(elementsNew,newToOld);
     int nNodesNew = newToOld.size(); 
     set<int>::const_iterator itr;
 
     // coordinates & node map (from nodes to data)
     const DENS_MAT &coordinates = nodal_coordinates();
     const Array<int> & node_map = global_to_unique_map();
 
     DENS_MAT *newCoords = new DENS_MAT(nSD_,nNodesNew);
     Array<int> *newNodeMap = new Array<int> (nNodesNew);
     Array2D<int> * newConnectivity = new Array2D<int>(nPE,nElementsNew);
     int k = 0, i = 0;
     for (itr = newToOld.begin(); itr != newToOld.end(); itr++) {
       int node = *itr;
       oldToNewMap[node] = i++;
       (*newNodeMap)(k) = node_map(node);
       for(int j = 0; j < nSD_; j++) {
         (*newCoords)(j,k) = coordinates(j,node);
       }
       k++;
     }
     // nNodes_ = nNodesNew; ???
     // connectivity
     k = 0;
     for (itr = elementsNew.begin(); itr != elementsNew.end(); itr++) {
       int ielem = *itr;
       for(int j = 0; j < nPE; j++) {
         int old_node = connectivity_(j,ielem);
         map<int,int>::iterator map_itr = oldToNewMap.find(old_node);
         if (map_itr == oldToNewMap.end()) { 
           stringstream ss; 
           ss << "map failure " << old_node << "\n"; 
           ATC::LammpsInterface::instance()->print_msg(ss.str());
         }
         int node = map_itr->second;
         (*newConnectivity)(j,k) = node;
       }
       k++;
     }
     delete newCoords;
     delete newNodeMap;
     delete newConnectivity;
   }
 
   // -------------------------------------------------------------
   //  partition_mesh 
   // -------------------------------------------------------------
   
   void FE_3DMesh::partition_mesh()
   {
     if (lammpsPartition_) {
       lammps_partition_mesh();
     }
 
     if (partitioned_) return;
 
 
     int nProcs, myrank;
     MPI_Comm_size(MPI_COMM_WORLD, &nProcs); // get the number of processors
     MPI_Comm_rank(MPI_COMM_WORLD, &myrank); // get the current processor's rank
 
     // use the KD tree for partitioning, getting more blocks than
     // processors
     if (tree_ == NULL) {
       tree_ = KD_Tree::create_KD_tree(feElement_->num_elt_nodes(), 
                                       nNodes_, &nodalCoords_, 
                                       nElts_, connectivity_);
     }
 
     // Get the divisions of the elements from the KD-tree.
     int depth = ceil(log(nProcs)/log(2));
       // In order to make sure there are enough divisions to evenly
       // divide between all processors, we get the next-highest
       // power of 2.
     vector<vector<int> > procEltLists = tree_->getElemIDs(depth);
     int numEltLists = procEltLists.size();
     
     // Make sure the KD tree is behaving as expected.
     assert(numEltLists >= nProcs);
  
     // If the KD-tree was not able to return enough divisions,
     // duplicate the largest list.
       
       // elements, then the division would be more even. 
     vector<vector<int> >::iterator it;
     if (numNonempty(procEltLists) < nProcs) {
       // Find the list of maximum size and assign it to empty processors
       vector<int> maxSizeList (0);
       for (it = procEltLists.begin(); it != procEltLists.end(); ++it) {
         if (it->size() > maxSizeList.size())
           maxSizeList.assign(it->begin(), it->end());
       }
       for (it = procEltLists.begin(); it != procEltLists.end(); ++it) {
         if (it->empty()) {
           if (numNonempty(procEltLists) >= nProcs) break;
           it->assign(maxSizeList.begin(), maxSizeList.end());
         }
       }
     }
    
     // We will store the owning processor for each element.
     int * eltToOwners = new int[nElts_];
     for (int i = 0; i < nElts_; ++i) {
       eltToOwners[i] = -1; // -1 here means the element is unowned.
     }
 
     // Prune elements that appear on more than one processor.
     // Simultaneously fill in the ownership array.
     prune_duplicate_elements( procEltLists, eltToOwners);
 
     // If we have more lists than processors, get rid of the
     // extras and redistribute their elements.
     if (numNonempty(procEltLists) > nProcs) {
       redistribute_extra_proclists(procEltLists, eltToOwners, nProcs);
     }
 
     // Sort the lists so that the fuller ones are in the front.
     sort(procEltLists.begin(), procEltLists.end(), vectorCompSize);
 
     // Assign each processor a list of elements.
     myElts_ = procEltLists[myrank];
 
     //mesh_distribute(eltStartIDs);
     delete[] eltToOwners;
 
     // We should do nodes later.
 
     if (decomposition_) distribute_mesh_data();
     partitioned_ = true;
   }
 
   void FE_3DMesh::departition_mesh()
   {
     if (!partitioned_) return;
     partitioned_ = false;
   }
 
   void FE_3DMesh::prune_duplicate_elements(vector<vector<int> > & procEltLists, 
                                            int * eltToOwners)
   {
     int procID = 0;
     vector<vector<int> >::iterator topIt;
     vector<int> * conflictingProc;
     vector<int>::iterator it, toErase;
     for (topIt = procEltLists.begin(); topIt != procEltLists.end(); ++topIt) {
       // Simultaneously fill in eltToOwners and prune, if an element
       // appears on multiple processors.
       for (it = topIt->begin(); it != topIt->end(); ++it) {
         // If the element has no corresponding processor in eltToOwners,
         // record it as belonging to processor *it.
         if (eltToOwners[*it] == -1) {
           eltToOwners[*it] = procID;
         } 
         else {
           // If it does have a processor in eltToOwners, then we need
           // to remove it from either processor *topIt or from the processor
           // listed in eltToOwners. We discriminate based on size.
           conflictingProc = &(procEltLists[eltToOwners[*it]]);
           if (conflictingProc->size() <= procEltLists[procID].size()) {
             // Delete element from processor *topIt, if it has more elements.
             it = topIt->erase(it);
             --it;
           } 
           else {
             // Delete element from conflicting processor otherwise.
             toErase = find(conflictingProc->begin(), conflictingProc->end(), *it);
             conflictingProc->erase(toErase);
             eltToOwners[*it] = procID;
           }
         }
       }
       ++procID;
     }
   }
 
   // -------------------------------------------------------------
   //  lammps_partition_mesh 
   // -------------------------------------------------------------
   
   void FE_3DMesh::lammps_partition_mesh()
   {
     if (LammpsInterface::instance()->domain_triclinic()) {
       LammpsInterface::instance()->print_msg_once("Cannot use lammps partitioning, domain is triclinic");
       return;
     }
     LammpsInterface::instance()->print_msg_once("Warning: Using native lammps partitioning");
     double xlo, xhi, ylo, yhi, zlo, zhi;
     double boxxlo, boxxhi, boxylo, boxyhi, boxzlo, boxzhi;
     LammpsInterface::instance()->sub_bounds(xlo, xhi, ylo, yhi, zlo, zhi);
     LammpsInterface::instance()->box_bounds(boxxlo, boxxhi, boxylo, boxyhi, boxzlo, boxzhi);
 
     
     myElts_.clear();
     double xCent, yCent, zCent;
     
     // Assign elements to processors based on the centroid of the element.
     int numNodes = num_nodes_per_element();
     for (int i = 0; i < nElts_; ++i)
     {
       xCent = 0.0;
       yCent = 0.0;
       zCent = 0.0;
       for (int j = 0; j < numNodes; ++ j)
       {
         xCent += nodalCoords_(0, connectivity_(j,i));
         yCent += nodalCoords_(1, connectivity_(j,i));
         zCent += nodalCoords_(2, connectivity_(j,i));
       }
       xCent /= numNodes;
       yCent /= numNodes;
       zCent /= numNodes;
       if (xCent < boxxlo) xCent = boxxlo;
       if (xCent < boxxhi) xCent = boxxhi;
       if (yCent < boxylo) yCent = boxylo;
       if (yCent < boxyhi) yCent = boxyhi;
       if (zCent < boxzlo) zCent = boxzlo;
       if (zCent < boxzhi) zCent = boxzhi; 
       if ( dbl_geq(xCent, xlo) &&
           ((xhi == boxxhi) || !dbl_geq(xCent, xhi)) &&
            dbl_geq(yCent, ylo) &&
           ((yhi == boxyhi) || !dbl_geq(yCent, yhi)) &&
            dbl_geq(zCent, zlo) &&
           ((zhi == boxzhi) || !dbl_geq(zCent, zhi))) {
         myElts_.push_back(i);
       }
     }
 
 
     // if decomposing add in myAtomElts list based on nodal locations, i.e., all elements with a local node
     // myElts: for FE assembly
     // myAndGhost : for atom ops like restrict
     if (decomposition_) {
       set<int> elms;
       vector<int>::const_iterator itr;
       for (itr=myElts_.begin(); itr!=myElts_.end(); itr++) {elms.insert(*itr); }
       set<int> nodes;
       elementset_to_nodeset(elms,nodes);
       elms.clear();
       nodeset_to_maximal_elementset(nodes,elms);
       myAndGhostElts_.clear();
       set<int>::const_iterator iter;
       for (iter=elms.begin(); iter!=elms.end(); iter++) 
         {myAndGhostElts_.push_back(*iter);}
       distribute_mesh_data();
     }
     partitioned_ = true;
     return;
     
   }
 
   void FE_3DMesh::redistribute_extra_proclists(vector<vector<int> > &procEltLists,
                                                int *eltToOwners, int nProcs)
   {
       DENS_MAT faceAdjacencies(nElts_, num_faces_per_element());
       faceAdjacencies = -1; // Set all values to -1, indicating uninitialized/uncalculated
 
       int currentElt, adjacentElt, procID;
       
       // Put all of the hobos onto one master list, allHomelessElts.
       list<int> allHomelessElts;
       vector<int> oneHomelessList;
       vector<vector<int> >::iterator current;
       int nHoboLists = numNonempty(procEltLists) - nProcs;
       for (int i = 0; i < nHoboLists; ++i) {
         current = min_element(procEltLists.begin(), procEltLists.end(), vectorCompSize);
         oneHomelessList = *current;
         allHomelessElts.insert(allHomelessElts.end(), 
                                oneHomelessList.begin(), oneHomelessList.end());
         current->clear();
       }
       
       // Make sure the hobos lose their association with their old processor.
       list<int>::iterator it;
       for (it = allHomelessElts.begin(); it != allHomelessElts.end(); it++){
         eltToOwners[*it] = -1;
       }
 
       // Figure out which elements the hobos are adjacent to. That way, they
       // will know what processors they can be redistributed to.
       compute_face_adjacencies(allHomelessElts, faceAdjacencies); 
 
       // Place homeless elements onto lists that correspond to actual processors.
       while (!allHomelessElts.empty()) {
         currentElt = allHomelessElts.back();
         
         // This will store the ID of the processor with the fewest elements
         // so far that has an element adjacent to currentElt.
         PAIR smallestProc(-1, INT_MAX);
         
         // Iterate over the faces, check the processors of adjacent elements,
         // and slate the element to go on the adjacent processor with the fewest 
         // elements.
         for (int localFaceID = 0; localFaceID < num_faces_per_element(); ++localFaceID) {
           adjacentElt = faceAdjacencies(currentElt, localFaceID); 
           
           // This means that there is no adjacency through this face.
           if (adjacentElt >= nElts_) continue;
           
           procID = eltToOwners[adjacentElt];
           // The procID > -1 check makes sure we're not adjacent to another
           // homeless element by this face, in which case it won't have a
           // processor to put currentElt onto yet.
           if (procID > -1 && ((int) procEltLists[procID].size()) < smallestProc.second) {
             smallestProc = PAIR(procID, procEltLists[procID].size());
           } 
         }
         
         allHomelessElts.pop_back();
 
         // If we couldn't find an adjacent element that had a processor,
         // skip for now and come back to it later.
         if (smallestProc.first == -1) {
           allHomelessElts.push_front(currentElt);
         }
         // Otherwise, put it onto the processor with the fewest elements that 
         // we found.
         else {
           procEltLists[smallestProc.first].push_back(currentElt);
           eltToOwners[currentElt] = smallestProc.first;
         }
       }
   }
 
   
   void FE_3DMesh::compute_face_adjacencies(const list<int> &elts, 
                                          DENS_MAT &faceAdjacencies)
   {
     list<int>::const_iterator cit;
     for (cit = elts.begin(); cit != elts.end(); ++cit) {
       // For each element, look at ever face, get the nodes on that face,
       // and find out which elements are in the intersection of elements
       // containing that node. Those two elements are adjacent, and we
       // mark it as such in the faceAdjacencies array.
       for (int localFaceID = 0; localFaceID < num_faces_per_element(); ++localFaceID) {
         Array<int> faceNodes;
         face_connectivity(PAIR(*(cit), localFaceID), faceNodes);
         // Put the first node's elements into the accumulator to start.
         vector<int> vIntersect = uniqueNodeToElementMap_(faceNodes(0));
         vector<int> vCurrent;
         // set_intersect requires a vector large enough to contain the 
         // max possible intersect, which cannot be larger than the entirety 
         // of the first vector involved. 
         vector<int> vTemp(vIntersect.size(), -1);
         // Find the intersection of each of the nodes' element vectors.
         for (int ithOnFace = 1; ithOnFace < num_nodes_per_face(); ++ithOnFace) {
           vCurrent = uniqueNodeToElementMap_(faceNodes(ithOnFace)); // Vector of elements for this node
           set_intersection(vCurrent.begin(), vCurrent.end(),
                            vIntersect.begin(), vIntersect.end(), vTemp.begin());
           vIntersect = vTemp;
           // Because we initialized the vector to be larger than necessary, maybe,
           // we remove all of the meaningless values used in initialization.
           while (vIntersect.back() == -1)
             vIntersect.pop_back();
           vTemp.clear();
           vTemp.resize(vIntersect.size(),-1);
         }
         // This means there is an adjacent face, since there
         // are two elements sharing all of the nodes on the face.
         if (vIntersect.size() == 2) {
           // We want to choose the element id of NOT the current
           // element to be listed as the adjacency.
           
           //    well, but that requires more complicated memoization and 
           //    this doesn't take much extra time.
           if (*cit == vIntersect[0]) {
             faceAdjacencies(*cit, localFaceID) = vIntersect[1];
           } 
           else {
             faceAdjacencies(*cit, localFaceID) = vIntersect[0];
           }
         } 
         // This means the element is on the border.
         else if (vIntersect.size() == 1) {
           faceAdjacencies(*cit, localFaceID) = INT_MAX;
         } 
         else {
           // This should never ever happen! The nodes should at least
           // share one element, since they are all on one face!
           // There should also never be more than two elements on the
           // same face... that would defy mathematics and physics in 
           // every way.
         }
       }
     }
   }
 
   // Sometimes we want to count the number of vectors that actually 
   // have stuff in them. We use this.
   int FE_3DMesh::numNonempty(vector<vector<int> > & v)
   {
     int result = 0;
     vector<vector<int> >::iterator it;
     for (it = v.begin(); it != v.end(); ++it){
       if (!(it->empty())){
         result++;
       }
     }
     return result;
   }
 
   int FE_3DMesh::map_to_element(const DENS_VEC &query) const
   {
     DENS_MAT eltCoords;
     vector<int> candidates = tree_->find_nearest(query);
     vector<int> matches = vector<int>();
 
     // Search through each of the nearest elements
     for (vector<int>::iterator elem = candidates.begin(); 
                                elem < candidates.end(); elem++) {
       if (contains_point(*elem, query)) {
         matches.push_back(*elem); // Keep track of the elements 
                                   // which contain it
       }
     }
 
     // Return the index of the parent element which does contain the point
     if (matches.size() == 1) {  // x is conclusively in a single element
       return matches[0];
     } else if (matches.size() == 0) {  // not so much
       throw ATC_Error("FE_3DMesh::map_to_element could not find an element");
     } else {  // definitely not so much
       throw ATC_Error("FE_3DMesh::map_to_element found multiple elements");
     }
   }
 
   bool FE_3DMesh::contains_point(const int eltID,
                                  const DENS_VEC &x) const
   {
     DENS_MAT eltCoords;
     element_coordinates(eltID, eltCoords);
     return feElement_->contains_point(eltCoords, x);
   }
 
   //-----------------------------------------------------------------------
   void FE_3DMesh::distribute_mesh_data() 
   {
     myNElts_ = myElts_.size();
 
     //create elemToMyElemMap_
     elemToMyElemMap_.clear();
     for (int myID = 0; myID < myNElts_; ++myID) {
       int baseID = myElts_[myID];
       elemToMyElemMap_[baseID] = myID;
     }
 
     // create myConnectivity_, myConnectivityUnique_
     int numEltNodes = feElement_->num_elt_nodes();
     myConnectivity_.reset(numEltNodes, myNElts_);
     myConnectivityUnique_.reset(numEltNodes, myNElts_);
     for (int elem = 0; elem < myNElts_; ++elem) {
       for (int node = 0; node < numEltNodes; ++node) {
         myConnectivity_(node,elem) = connectivity_(node,map_myElem_to_elem(elem));
         myConnectivityUnique_(node,elem) = connectivityUnique_(node,map_myElem_to_elem(elem));
       }
     }
   }
 
   // -------------------------------------------------------------
   // -------------------------------------------------------------
   //   class FE_Rectangular3DMesh
   // -------------------------------------------------------------
   // -------------------------------------------------------------
 
   FE_Rectangular3DMesh::FE_Rectangular3DMesh(
                                      const Array<double> & hx,
                                      const Array<double> & hy,
                                      const Array<double> & hz,
                                      const double xmin, const double xmax,
                                      const double ymin, const double ymax,
                                      const double zmin, const double zmax,
                                      const Array<bool> periodicity,
                                      const double xscale,
                                      const double yscale,
                                      const double zscale)
     : hx_(hx), hy_(hy), hz_(hz)
   {
+    tree_ = NULL;
     hasPlanarFaces_ = true;
     xscale_ = xscale;
     yscale_ = yscale;
     zscale_ = zscale;
 
     borders_[0][0] = xmin;
     borders_[0][1] = ymin;
     borders_[0][2] = zmin;
     borders_[1][0] = xmax;
     borders_[1][1] = ymax;
     borders_[1][2] = zmax;
     L_[0] = xmax-xmin; 
     L_[1] = ymax-ymin;
     L_[2] = zmax-zmin;
     n_[0] = hx_.size(); 
     n_[1] = hy_.size();
     n_[2] = hz_.size();
     // Compute region size and element size
     double Lx = 0;
     for (int i = 0; i < n_[0]; ++i) { Lx += hx_(i); }
     double Ly = 0;
     for (int i = 0; i < n_[1]; ++i) { Ly += hy_(i); }
     double Lz = 0;
     for (int i = 0; i < n_[2]; ++i) { Lz += hz_(i); }
     // rescale to fit box
     double ax = L_[0]/Lx;
     for (int i = 0; i < n_[0]; ++i) { hx_(i) *= ax; }
     double ay = L_[1]/Ly;
     for (int i = 0; i < n_[1]; ++i) { hy_(i) *= ay; }
     double az = L_[2]/Lz;
     for (int i = 0; i < n_[2]; ++i) { hz_(i) *= az; }
 
     // fill node locations
     nSD_ = 3;
     x_.reserve(nSD_);
     for (int i = 0; i < nSD_; ++i) {x_.push_back(Array<double>(n_[i]+1)); }
     Array<double> & xI = x_[0]; 
     xI(0) = xmin;
     for (int i = 0; i < n_[0]; ++i) { xI(i+1) = xI(i)+hx_(i); }
     Array<double> & yI = x_[1]; 
     yI(0) = ymin;
     for (int i = 0; i < n_[1]; ++i) { yI(i+1) = yI(i)+hy_(i); }
     Array<double> & zI = x_[2]; 
     zI(0) = zmin;
     for (int i = 0; i < n_[2]; ++i) { zI(i+1) = zI(i)+hz_(i); }
 
     // Member data setup
     nElts_ = n_[0] * n_[1] * n_[2];
     nNodes_ = (n_[0]+1) * (n_[1]+1) * (n_[2]+1);
 
     periodicity_ = Array<bool>(periodicity);
 
     feElement_ = new FE_ElementRect();
     nodalCoords_.reset(3, nNodes_);
     connectivity_.reset(feElement_->num_elt_nodes(), nElts_);
 
     // Fill nodal coordinates
     double x[3] = {xmin,ymin,zmin};
     int inode = 0;
     for (int k = 0; k <= n_[2]; ++k) {
       for (int j = 0; j <= n_[1]; ++j) {
         for (int i = 0; i <= n_[0]; ++i) {
           for (int m = 0; m < 3; ++m) {
             nodalCoords_(m,inode) = x[m];
           }
           ++inode;
           if (i < n_[0]) x[0] += hx_(i);
         }
         if (j < n_[1]) x[1] += hy_(j);
         x[0] = xmin;
       }
       if (k < n_[2]) x[2] += hz_(k);
       x[1] = ymin;
     }
 
     // Compute element connectivities
     int ielt = 0;
     int noffx = 1;
     int noffy = n_[0] + 1;
     int noffz = (n_[0]+1) * (n_[1]+1);
     for (int k = 0; k < n_[2]; ++k) {
       for (int j = 0; j < n_[1]; ++j) {
         for (int i = 0; i < n_[0]; ++i) {
           int i1 = i + j*noffy + k*noffz;
           connectivity_(0,ielt) = i1;
           connectivity_(1,ielt) = i1 + noffx;
           connectivity_(2,ielt) = i1 + noffx + noffy;
           connectivity_(3,ielt) = i1 + noffy;
           connectivity_(4,ielt) = i1 + noffz;
           connectivity_(5,ielt) = i1 + noffx + noffz;
           connectivity_(6,ielt) = i1 + noffx + noffy + noffz;
           connectivity_(7,ielt) = i1 + noffy + noffz;
           ++ielt;
         }
       }
     }
     setup_periodicity();
   }
 
   // -------------------------------------------------------------
   //  partition_mesh 
   // -------------------------------------------------------------
   
   void FE_Rectangular3DMesh::partition_mesh()
   {
     if (lammpsPartition_) {
       lammps_partition_mesh();
     }
 
     if (partitioned_) return;
 
 
     // Currently this code has been rather naively copied from 
     // FE_Uniform3DMesh::partition_mesh()
 
     // Determine dimensions of mesh in order to partition according to largest dimension.
     double xmin = borders_[0][0];
     double xmax = borders_[1][0];
     double ymin = borders_[0][1];
     double ymax = borders_[1][1];
     double zmin = borders_[0][2];
     double zmax = borders_[1][2];
 
     int numProcs;
     MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
     
     int processorRank;
     MPI_Comm_rank(MPI_COMM_WORLD, &processorRank);
       
     // Spatially partition along the largest dimension.
     procs_.clear();
     if (max(max(L_[0], L_[1]), L_[2]) == L_[0]) {
       partitionAxis_ = 0;
       for (int i = 0; i < numProcs; ++i) {
         procs_.push_back(xmin + (L_[0]*i)/numProcs);
       }
       procs_.push_back(xmax);
     }
     else if (max(max(L_[0], L_[1]), L_[2]) == L_[1]) {
       partitionAxis_ = 1;
       for (int i = 0; i < numProcs; ++i) {
         procs_.push_back(ymin + (L_[1]*i)/numProcs);
       }
       procs_.push_back(ymax);
     }
     else {
       partitionAxis_ = 2;
       for (int i = 0; i < numProcs; ++i) {
         procs_.push_back(zmin + (L_[2]*i)/numProcs);
       }
       procs_.push_back(zmax);
     }
 
     // Distribute each node to the correct processor
     myNodes_.clear();
     for (int i = 0; i < nNodes_; ++i) {
       // Allocate node to this processor if it lies between processor's left and right boundaries.
       if ( dbl_geq(nodalCoords_(partitionAxis_, i), procs_[processorRank]) &&
           !dbl_geq(nodalCoords_(partitionAxis_, i), procs_[processorRank + 1])) {
         myNodes_.push_back(i);
       }
       // Also allocate nodes on the right boundary to the last processor.
       if ((processorRank == numProcs - 1) &&
            dbl_geq(nodalCoords_(partitionAxis_, i), procs_[processorRank + 1])) {
         myNodes_.push_back(i);
       }
     }
    
     // Distribute each element to the correct processor - assign it to the processor
     // which owns its node of lowest index. (this partitioning scheme is unambiguous) 
     myElts_.clear();
     for (int i = 0; i < nElts_; ++i) {
       int min = INT_MAX;
       for (int j = 0; j < connectivity_.nRows(); j++) {
         if (connectivity_(j, i) < min)
           min = connectivity_(j, i);
       }
       if (find(myNodes_.begin(), myNodes_.end(), min) != myNodes_.end()) {
         myElts_.push_back(i);
       }
     }
 
     /* Commented out because ghost nodes are never used and dx_ is not a member of
        FE_Rectangular3DMesh.
 
     // Compute the facesets that describes the left and right boundaries 
     // in order to determine ghost nodes.
     int leftMult = 0;
     while ((leftMult+1)*dx_[partitionAxis_] < procs_[processorRank]) {
       ++leftMult;
     }
     int rightMult = 0;
     while ((rightMult)*dx_[partitionAxis_] < procs_[processorRank+1]) {
       ++rightMult;
     }
     // Compute our ghost nodes - nodes that we need that belong to adjacent processors,
     // and our shared nodes - our nodes that are ghosted on the adjacent processors.
     for (int i = 0; i < nNodes_; ++i) {
       if (nodalCoords_(partitionAxis_, i) == leftMult*dx_[partitionAxis_])
         ghostNodesL_.push_back(i);
       else if (nodalCoords_(partitionAxis_, i) == rightMult*dx_[partitionAxis_])
         ghostNodesR_.push_back(i);
       else if (nodalCoords_(partitionAxis_, i) == (leftMult+1)*dx_[partitionAxis_])
         shareNodesL_.push_back(i);
       else if (nodalCoords_(partitionAxis_, i) == (rightMult-1)*dx_[partitionAxis_])
         shareNodesR_.push_back(i);
     }*/
     if (decomposition_) distribute_mesh_data();
     partitioned_ = true;
   }
 
   void FE_Rectangular3DMesh::departition_mesh()
   {
     if (!partitioned_) return;
     partitioned_ = false;
   }
 
   // -------------------------------------------------------------
   //   setup_periodicity
   // -------------------------------------------------------------
   void FE_Rectangular3DMesh::setup_periodicity()
   {
     nNodesUnique_ = 1;
     for (int i = 0; i < 3; i++) {
       nNodesUnique_ *= (n_[i] + 1 - periodicity_(i));
     } 
     
     // form maximal nodeset
     for (int i = 0; i < nNodesUnique_; i++) {
       nodeSetAll_.insert(i); 
     }
     
     // Create global-to-unique map: globalToUniqueMap_(ig) = iu
     globalToUniqueMap_.reset(nNodes_);
     uniqueToGlobalMap_.reset(nNodesUnique_);
     for (int k = 0; k <= n_[2]; ++k) {
       int kper = (k == n_[2] && periodicity_(2)) ? 0 : k;
       for (int j = 0; j <= n_[1]; ++j) {
         int jper = (j == n_[1] && periodicity_(1)) ? 0 : j;
         for (int i = 0; i <= n_[0]; ++i) {
           int iper = (i == n_[0] && periodicity_(0)) ? 0 : i;
           int id = i + j*(n_[0]+1) + k*(n_[0]+1)*(n_[1]+1);
           int uid = iper + jper*(n_[0]+1-periodicity_(0)) 
             + kper*(n_[0]+1-periodicity_(0))*(n_[1]+1-periodicity_(1));
           globalToUniqueMap_(id) = uid;
           uniqueToGlobalMap_(uid) = id;
         }
       }
     }
     set_unique_connectivity();
 
     // form maximal elementset
     for (int i = 0; i < nElts_; i++) {
       elementSetAll_.insert(i); 
     }
   }
 
   int FE_Rectangular3DMesh::map_to_element(const DENS_VEC &x) const
   {
     int ix[3]; // ix[i] is the element in the ith direction
     for (int i = 0; i < 3; i++) {
       // map to box
       double y = x(i);
       if (periodicity_(i)) {
          double diff = y-borders_[0][i];
          int shift = int(diff/L_[i]);
          if (diff < 0.) shift--;
          y -= shift*L_[i];
       } 
       // project into element
       ix[i] = x_[i].index(y);
       if (fabs(y-borders_[0][i]) < tol) { ix[i] = 0; } // on the lower boundary
       if (ix[i] < 0 || ix[i] >= n_[i]) {
         string msg = "FE_Rectangular3DMesh:: point maps outside of mesh, coordinate "
          + index_to_string(i) + "=" + to_string(x(i)) + " image=" + to_string(y)
          + " not in " + to_string(borders_[0][i]) + ":" + to_string(borders_[1][i]);
         throw ATC_Error(msg);
       }
     }
     int elt = ix[2]*(n_[0]*n_[1]) + ix[1]*n_[0] + ix[0];
     return elt;
   }
   // -------------------------------------------------------------
   // -------------------------------------------------------------
   //   class FE_Uniform3DMesh
   // -------------------------------------------------------------
   // -------------------------------------------------------------
 
   FE_Uniform3DMesh::FE_Uniform3DMesh(const int nx,
                                      const int ny,
                                      const int nz,
                                      const double xmin, const double xmax,
                                      const double ymin, const double ymax,
                                      const double zmin, const double zmax,
                                      const Array<bool> periodicity,
                                      const double xscale,
                                      const double yscale,
                                      const double zscale)
   {
     hasPlanarFaces_ = true;
     tree_ = NULL;
     xscale_ = xscale;
     yscale_ = yscale;
     zscale_ = zscale;
     n_[0] = nx;
     n_[1] = ny;
     n_[2] = nz;
 
     borders_[0][0] = xmin;
     borders_[1][0] = xmax;
     borders_[0][1] = ymin;
     borders_[1][1] = ymax;
     borders_[0][2] = zmin;
     borders_[1][2] = zmax;
 
     periodicity_ = Array<bool>(periodicity);
 
     // Compute region size and element size
     for (int i = 0; i < 3; i++) {
       L_[i] = borders_[1][i] - borders_[0][i];
       dx_[i] = L_[i]/n_[i];
     }
 
     // Member data setup
     nSD_ = 3;
     nElts_ = n_[0] * n_[1] * n_[2];
     nNodes_ = (n_[0]+1) * (n_[1]+1) * (n_[2]+1);
 
     feElement_ = new FE_ElementRect();
 
     nodalCoords_.reset(3, nNodes_);
     connectivity_.reset(feElement_->num_elt_nodes(), nElts_);
 
     // Fill nodal coordinates
     double ix[3];
     int inode = 0;
     for (int k = 0; k <= n_[2]; ++k) {
       ix[2] = borders_[0][2] + k*dx_[2];
       for (int j = 0; j <= n_[1]; ++j) {
         ix[1] = borders_[0][1] + j*dx_[1];
         for (int i = 0; i <= n_[0]; ++i) {
           ix[0] = borders_[0][0] + i*dx_[0];
           for (int m = 0; m < 3; ++m) {
             nodalCoords_(m,inode) = ix[m];
           }
           ++inode;
         }
       }
     }
 
     // Compute element connectivities
     int ielt = 0;
     int noffx = 1;
     int noffy = n_[0] + 1;
     int noffz = (n_[0]+1) * (n_[1]+1);
     for (int k = 0; k < n_[2]; ++k) {
       for (int j = 0; j < n_[1]; ++j) {
         for (int i = 0; i < n_[0]; ++i) {
           int i1 = i + j*noffy + k*noffz;
           connectivity_(0,ielt) = i1;
           connectivity_(1,ielt) = i1 + noffx;
           connectivity_(2,ielt) = i1 + noffx + noffy;
           connectivity_(3,ielt) = i1 + noffy;
           connectivity_(4,ielt) = i1 + noffz;
           connectivity_(5,ielt) = i1 + noffx + noffz;
           connectivity_(6,ielt) = i1 + noffx + noffy + noffz;
           connectivity_(7,ielt) = i1 + noffy + noffz;
           ++ielt;
         }
       }
     }
 
     setup_periodicity();
   }
 
   // -------------------------------------------------------------
   //  destructor
   // -------------------------------------------------------------
   FE_Uniform3DMesh::~FE_Uniform3DMesh() 
   {
     // Clean up is currently unimplemented
   }
 
   // -------------------------------------------------------------
   //  partition_mesh 
   // -------------------------------------------------------------
   
   void FE_Uniform3DMesh::partition_mesh()
   {
     if (lammpsPartition_) {
       lammps_partition_mesh();
     }
 
     if (partitioned_) return;
 
 
     // Determine dimensions of mesh in order to partition according to largest dimension.
     double xmin = borders_[0][0];
     double xmax = borders_[1][0];
     double ymin = borders_[0][1];
     double ymax = borders_[1][1];
     double zmin = borders_[0][2];
     double zmax = borders_[1][2];
 
     int numProcs;
     MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
     
     int processorRank;
     MPI_Comm_rank(MPI_COMM_WORLD, &processorRank);
       
     // Spatially partition along the largest dimension.
     procs_.clear();
     if (max(max(L_[0], L_[1]), L_[2]) == L_[0]) {
       partitionAxis_ = 0;
       for (int i = 0; i < numProcs; ++i) {
         procs_.push_back(xmin + (L_[0]*i)/numProcs);
       }
       procs_.push_back(xmax);
     }
     else if (max(max(L_[0], L_[1]), L_[2]) == L_[1]) {
       partitionAxis_ = 1;
       for (int i = 0; i < numProcs; ++i) {
         procs_.push_back(ymin + (L_[1]*i)/numProcs);
       }
       procs_.push_back(ymax);
     }
     else {
       partitionAxis_ = 2;
       for (int i = 0; i < numProcs; ++i) {
         procs_.push_back(zmin + (L_[2]*i)/numProcs);
       }
       procs_.push_back(zmax);
     }
 
     // Distribute each node to the correct processor
     myNodes_.clear();
     for (int i = 0; i < nNodes_; ++i) {
       // Allocate node to this processor if it lies between processor's left and right boundaries.
       if ( dbl_geq(nodalCoords_(partitionAxis_, i), procs_[processorRank]) &&
           !dbl_geq(nodalCoords_(partitionAxis_, i), procs_[processorRank + 1])) {
         myNodes_.push_back(i);
       }
       // Also allocate nodes on the right boundary to the last processor.
       if ((processorRank == numProcs - 1) &&
            dbl_geq(nodalCoords_(partitionAxis_, i), procs_[processorRank + 1])) {
         myNodes_.push_back(i);
       }
     }
    
     // Distribute each element to the correct processor - assign it to the processor
     // which owns its node of lowest index. (this partitioning scheme is unambiguous) 
     myElts_.clear();
     for (int i = 0; i < nElts_; ++i) {
       int min = INT_MAX;
       for (int j = 0; j < connectivity_.nRows(); j++) {
         if (connectivity_(j, i) < min)
           min = connectivity_(j, i);
       }
       if (find(myNodes_.begin(), myNodes_.end(), min) != myNodes_.end()) {
         myElts_.push_back(i);
       }
     }
 
     // Compute the facesets that describes the left and right boundaries 
     // in order to determine ghost nodes.
     int leftMult = 0;
     while ((leftMult+1)*dx_[partitionAxis_] < procs_[processorRank]) {
       ++leftMult;
     }
     int rightMult = 0;
     while ((rightMult)*dx_[partitionAxis_] < procs_[processorRank+1]) {
       ++rightMult;
     }
     // Compute our ghost nodes - nodes that we need that belong to adjacent processors,
     // and our shared nodes - our nodes that are ghosted on the adjacent processors.
     for (int i = 0; i < nNodes_; ++i) {
       if (nodalCoords_(partitionAxis_, i) == leftMult*dx_[partitionAxis_])
         ghostNodesL_.push_back(i);
       else if (nodalCoords_(partitionAxis_, i) == rightMult*dx_[partitionAxis_])
         ghostNodesR_.push_back(i);
       else if (nodalCoords_(partitionAxis_, i) == (leftMult+1)*dx_[partitionAxis_])
         shareNodesL_.push_back(i);
       else if (nodalCoords_(partitionAxis_, i) == (rightMult-1)*dx_[partitionAxis_])
         shareNodesR_.push_back(i);
     }
     if (decomposition_) distribute_mesh_data();
     partitioned_ = true;
   }
 
   void FE_Uniform3DMesh::departition_mesh()
   {
     if (!partitioned_) return;
     partitioned_ = false;
   }
 
   // -------------------------------------------------------------
   //   map_to_element
   // -------------------------------------------------------------
   int FE_Uniform3DMesh::map_to_element(const DENS_VEC &x) const
   {
     // countx[i] is the number of the element, where 1 is the 
     // element adjacent to the lower border, in the ith direction
     int countx[3];
     for (int i = 0; i < 3; ++i) {
       // handle points on upper boundary; not sure why this is 
       // hard-coded in, though...
       if (fabs(x(i)-borders_[1][i]) < tol) {
         countx[i] = n_[i] - 1;
       } else {
         // find the x, y, and z bins for the point in the mesh
         countx[i] = (int)floor((x(i)-borders_[0][i])/dx_[i]);
       }
       
       // handle points out-of-range [0:nx-1] w/ periodicity
       if (countx[i] < 0 || countx[i] >= n_[i]) {
         if (periodicity_(i)) {
           countx[i] = countx[i] % n_[i];
           // handles c++ ambiguous mod problems
           if (countx[i] < 0) countx[i] += n_[i]; 
         } else {
           string msg = " point maps outside " 
                        "of mesh, coordinate "                     + 
                        index_to_string(i) + " " + to_string(x(i)) + 
                        " not in " + to_string(borders_[0][i])     + 
                        " : "      + to_string(borders_[1][i]);
           throw ATC_Error(FILELINE,msg);
         }
       }
     }
 
     int elt = countx[2]*(n_[0]*n_[1]) + 
               countx[1]*n_[0]          + 
               countx[0];
     return elt;
   }
 
 
 } // namespace ATC
diff --git a/lib/atc/FE_Mesh.h b/lib/atc/FE_Mesh.h
index b832a5b70..c7709168d 100644
--- a/lib/atc/FE_Mesh.h
+++ b/lib/atc/FE_Mesh.h
@@ -1,704 +1,711 @@
 #ifndef FE_MESH_H
 #define FE_MESH_H
 
 #include "Array.h"
 #include "Array2D.h"
 #include "MatrixLibrary.h"
 #include "ATC_TypeDefs.h"
 #include "KD_Tree.h"
 #include <vector>
 #include <deque>
 #include <list>
 #include <map>
 #include <set>
 #include <utility>
 #include <float.h>
 #include <string>
 #include <vector>
 #include "mpi.h"
 
 namespace ATC {
 
   class FE_Element;
 
   /**
    *  @class  FE_Mesh
    *  @brief  Base class for a finite element mesh
    */
   class FE_Mesh {
 
   public:
 
     /** constructor */
     FE_Mesh();
   
     /** destructor */
     virtual ~FE_Mesh();
 
     /** parser/modifier */
     bool modify(int narg, char **arg);
 
     /** initialization */
     void initialize(void);
 
     /** write an unstructured mesh */
     void write_mesh(std::string meshFile);
 
 
 
 // SJL why? will they ever be overridden by derived classes? in what
 //     situation would that be required, or desirable? virtual functions
 //     are slightly less efficient because they cannot be hard-linked at
 //     compile time.
 
     bool is_partitioned() const { return partitioned_; }
     virtual void partition_mesh() = 0;
     virtual void departition_mesh() = 0;
 
     int map_elem_to_myElem(int elemID) const;
     int map_myElem_to_elem(int myElemID) const;
     void set_lammps_partition(bool t) {lammpsPartition_ = t;}
     void set_data_decomposition(bool t) {decomposition_ = t;}
 
     /** set quadrature on element from within interpolate class */
     void set_quadrature(FeIntQuadrature type);
 
     /** evaluate shape function at real coordinates */
     void position(const int elem,
                   const VECTOR &xi, 
                         DENS_VEC &x) const;
 
     /** evaluate shape function at real coordinates */
     void shape_functions(const VECTOR &x, 
                          DENS_VEC &N,
                          Array<int> &nodeList) const;
 
     /** evaluate shape function at real coordinates */
     void shape_functions(const VECTOR &x, 
                                  DENS_VEC &N,
                                  Array<int> &nodeList,
                                  const Array<bool> &) const;
 
     /** evaluate shape function at real coordinates */
     void shape_functions(const DENS_VEC &x, 
                          DENS_VEC &N,
                          DENS_MAT &dNdx,
                          Array<int> &nodeList) const;
 
     /** evaluate shape function at real coordinates */
     void shape_functions(const VECTOR &x, 
                          const int eltID,
                          DENS_VEC &N,
                          Array<int> &nodeList) const;
 
     /** evaluate shape function at real coordinates */
     void shape_functions(const DENS_VEC &x, 
                          const int eltID,
                          DENS_VEC &N,
                          DENS_MAT &dNdx,
                          Array<int> &nodeList) const;
 
     /** evaluate shape function at real coordinates */
     void shape_function_derivatives(const DENS_VEC &x, 
                          const int eltID,
                          DENS_MAT &dNdx,
                          Array<int> &nodeList) const;
 
     /** evaluate shape functions for all ip's on an element */
     // N is numIPsInElement X numNodesInElement
     void shape_function(const int eltID,
                         DENS_MAT &N,
                         DIAG_MAT &weights) const;
 
     /** evaluate shape functions for all ip's on an element */
     // N is numIPsInElement X numNodesInElement
     void shape_function(const int eltID,
                         DENS_MAT &N,
                         std::vector<DENS_MAT> &dN,
                         DIAG_MAT &weights) const;
 
     /** evaluate shape functions for all ip's on a face */
     // N is numIPsInFace X numNodesInElement
     void face_shape_function(const PAIR &face,
                              DENS_MAT &N,
                              DENS_MAT &n,
                              DIAG_MAT &weights) const;
 
     void face_shape_function(const PAIR &face,
                              DENS_MAT &N,
                              std::vector<DENS_MAT> &dN,
                              std::vector<DENS_MAT> &Nn,
                              DIAG_MAT &weights) const;
 
     /** compute normal vector from the specified face */
     double face_normal(const PAIR &face,
                        const int ip,
                        DENS_VEC &normal) const;
 
 
     /** return connectivity (global ID numbers) for element eltID */
     void element_connectivity_global(const int eltID,
                                      Array<int> & nodes) const;
 
     void element_connectivity_unique(const int eltID,
                                      Array<int> & nodes) const;
 
     int element_connectivity_global(const int eltID,
                                      const int inode) const;
 
     int element_connectivity_unique(const int eltID,
                                      const int inode) const;
 
     AliasArray<int> element_connectivity_global(const int eltID) const;
 
     AliasArray<int> element_connectivity_unique(const int eltID) const;
 
     void face_connectivity(const PAIR & faceID,
-                                  Array<int> & nodes) const
+                           Array<int> & nodes) const
     { int nNodesPerFace = num_nodes_per_face();
       nodes.reset(nNodesPerFace);
       int eltID = faceID.first;
       int localFace = faceID.second;
       const Array2D<int> & localFaceConn = local_face_connectivity();
       for(int i = 0; i < nNodesPerFace; ++i) {
         nodes(i) = element_connectivity_global(eltID, localFaceConn(localFace,i));
       }
     }
     void face_connectivity_unique(const PAIR & faceID,
                                   Array<int> & nodes) const
     { int nNodesPerFace = num_nodes_per_face();
       nodes.reset(nNodesPerFace);
       int eltID = faceID.first;
       int localFace = faceID.second;
       const Array2D<int> & localFaceConn = local_face_connectivity();
       for(int i = 0; i < nNodesPerFace; ++i) {
         nodes(i) = element_connectivity_unique(eltID, localFaceConn(localFace,i));
       }
     }
 
     /** 
      *  return spatial coordinates for element nodes on eltID,
      *  indexed xCoords(isd,inode)
      */
     void element_coordinates(const int eltID,
                              DENS_MAT & xCoords) const;
 
     void face_coordinates(const PAIR face,
                           DENS_MAT & xCoords) const;
 
     /** access to the nodal coordinate values */
     const DENS_MAT & nodal_coordinates(void) const {return nodalCoords_  ;}
 
     /** access to nodal coordinates of a unique node */
     DENS_VEC nodal_coordinates(const int nodeID) const;
 
     /** access to nodal coordinates of a node */
     DENS_VEC global_coordinates(const int nodeID) const;
 
     /** map spatial location to element */
     virtual int map_to_element(const DENS_VEC &x) const = 0;
 
     /** map global node numbering to unique node numbering */
     int map_global_to_unique(const int global_id) const 
     {
       return globalToUniqueMap_(global_id);
     }
     inline const Array<int>& global_to_unique_map(void) const 
     {
       return globalToUniqueMap_;
     }
 
     /** map unique node numbering a global node numbering */
     int map_unique_to_global(const int unique_id) 
     {
       return uniqueToGlobalMap_(unique_id);
     }
     inline const Array<int>& unique_to_global_map(void) const 
     {
       return uniqueToGlobalMap_;
     }
 
     /** query whether a nodeset with the given name exists */
     bool query_nodeset(const std::string & name) const;
 
     /** get node set (unique ID's) from the string name assigned to the set */
     const std::set<int> & nodeset(const std::string & name) const;
 
     /** create node set with tag "name" from nodes in given spatial range */
     void create_nodeset(const std::string & name, const std::set<int> & nodeset);
     void create_nodeset(const std::string & name,
                         double xmin, double xmax,
                         double ymin, double ymax,
                         double zmin, double zmax);
 
     /** add to node set with tag "name" from nodes in given spatial range */
     void add_to_nodeset(const std::string & name,
                         double xmin, double xmax,
                         double ymin, double ymax,
                         double zmin, double zmax);
 
     /** get element set from the string name assigned to the set */
     const std::set<int> & elementset(const std::string & name) const;
 
     /** create element set with tag "name" from nodes in given spatial range */
     void create_elementset(const std::string & name,
                            double xmin, double xmax,
                            double ymin, double ymax,
                            double zmin, double zmax);
 
 
     /** get the minimal element set from a nodeset by name */
     void nodeset_to_minimal_elementset(const std::string &name, 
                                        std::set<int> &elemSet) const;
     /** get the minimal element set from a set of nodes */
     void nodeset_to_minimal_elementset(const std::set<int> &nodeSet, 
                                        std::set<int> &elemSet) const;
     /** get the maximal element set from a nodeset by name */
     void nodeset_to_maximal_elementset(const std::string &name, 
                                        std::set<int> &elemSet) const;
     /** get the maximal element set from a set of nodes */
     void nodeset_to_maximal_elementset(const std::set<int> &nodeSet, 
                                        std::set<int> &elemSet) const;
 
     /** get complement of element set by name */
     void elementset_complement(const std::string &name, 
                                std::set<int> &elemSet) const;
     void elementset_complement(const std::set<int> &elemSet, 
                                std::set<int> &elemSetComplement) const;
 
     /** get the node set from an element set by name */
     void elementset_to_minimal_nodeset(const std::string &name, 
                                        std::set<int> &nodeSet) const;
 
     void elementset_to_nodeset(const std::string &name, 
-                               std::set<int> &nodeSet) const;
+                               std::set<int> nodeSet) const;
     void elementset_to_nodeset(const std::set<int> &elemSet, 
-                               std::set<int> &nodeSet) const;
+                               std::set<int> nodeSet) const;
+    std::set<int> elementset_to_nodeset(const std::string &name) const;
 
     /** convert faceset to nodeset in _unique_ node numbering */
     void faceset_to_nodeset(const std::string &name, 
                             std::set<int> &nodeSet) const;
     void faceset_to_nodeset(const std::set<PAIR> &faceSet, 
                             std::set<int> &nodeSet) const;
 
     void faceset_to_nodeset_global(const std::string &name, 
                                    std::set<int> &nodeSet) const;
     void faceset_to_nodeset_global(const std::set<PAIR> &faceSet, 
                                    std::set<int> &nodeSet) const;
 
     /** get face set from the string name assigned to the set */
     const std::set< std::pair<int,int> > & faceset(const std::string & name) const;
 
     /** create face set with tag "name" from faces aligned with box */
     void create_faceset(const std::string & name,
                         double xmin, double xmax,
                         double ymin, double ymax,
                         double zmin, double zmax, 
                         bool outward);
     /** create face set with tag "name" from faces aligned with plane */
     void create_faceset(const std::string & name, double x, int idir, int isgn,
                         int nIdx2=-1, double x2lo=0.0, double x2hi=0.0,
                         int nIdx3=-1, double x3lo=0.0, double x3hi=0.0);
 
     /** cut mesh */
     virtual void cut_mesh(const std::set<PAIR> & faceSet, const std::set<int> & nodeSet) = 0;
     
     /** delete elements */
     virtual void delete_elements(const std::set<int> & elementList) = 0;
 
     /** return number of spatial dimensions */
     int num_spatial_dimensions() const { return nSD_; }
 
     /** return total number of nodes */
     int num_nodes() const { return nNodes_; }
 
     /** return number of unique nodes */
     int num_nodes_unique() const { return nNodesUnique_; }
 
     /** return number of elements */
     int num_elements() const { return nElts_; }
 
     /** return number of elements partitioned to my processor */
     int my_num_elements() const { return myNElts_; }
 
     /** return number of integration points per element */
     int num_ips_per_element() const;
 
     /** return number of nodes per element */
     int num_nodes_per_element() const;
 
     /** return number of faces per element */
     int num_faces_per_element() const;
   
     /** return number of nodes per face */
     int num_nodes_per_face() const;
   
     /** return number of integration points per face */
     int num_ips_per_face() const;
 
     /** return a pointer to the connectivity. This function will only work
         when mesh is not partitioned. */
     Array2D<int> * connectivity(void) { return &connectivity_; }
     /** return a pointer to the connectivity */
     DENS_MAT * coordinates(void) { return &nodalCoords_;} 
     /** Engine nodeMap stuff  */
     Array<int> *node_map(void) { return &globalToUniqueMap_;}
 
 
     /** return scale in x,y,z */
     double xscale() const { return xscale_; }
     double yscale() const { return yscale_; }
     double zscale() const { return zscale_; }
 
     /** local face connectivity */
     const Array2D<int> & local_face_connectivity() const;
  
     /** element size in each direction */
     virtual void bounding_box(const int ielem, 
                               DENS_VEC & xmin, DENS_VEC & xmax); 
 
     /** element size in each direction */
     virtual void element_size(const int ielem, 
                               double & hx, double & hy, double & hz); 
 
     /** element size in each direction */
     virtual double min_element_size(void) const {return 0.0 ;} 
 
     /** get nodal coordinates for a given element */ 
     void element_field(const int eltIdx, const DENS_MAT f,
                        DENS_MAT &local_field)
     {
       int dof = f.nCols();
       Array<int> nodes;
       element_connectivity_unique(eltIdx,nodes);
       local_field.reset(num_nodes_per_element(), dof);
       for (int i = 0; i < nodes.size(); i++) {
         for (int j = 0; j < dof; j++) local_field(i,j) = f(nodes(i),j);
       }
     }
 
     /** almost structured */
     bool is_aligned(void) const;
 
     /** extruded */
     bool is_two_dimensional(void) const {return twoDimensional_;}
 
    virtual double coordinate_tolerance(void) const {return 1.e-8;}
 
     /** element type */
     std::string element_type(void) const ; 
 
     /** output mesh subsets */
     void output(std::string prefix) const; 
   
     /* Parallelization data members */
  
     /** return element vector for this processor */
     const std::vector<int> & owned_elts() const { return myElts_; }
     const std::vector<int> & owned_and_ghost_elts() const { 
       return (decomposition_) ? myAndGhostElts_: myElts_; }
     bool is_owned_elt(int elt) const;
     
   protected:
 
+    void parse_plane(int & argIdx, int narg, char ** arg,  
+      int & ndir, int * idir, int & isgn, double xlimits[][2]);
+
+    void parse_units(int & argIdx, int narg, char ** arg,  
+      double & xmin, double & xmax, double & ymin, double & ymax, double & zmin, double & zmax);
+
     /** will this mesh use data decomposition? */
     bool decomposition_;
 
     /** should the mesh use the native lammps partitioning? */
     bool lammpsPartition_;
 
     /** is the element/node data currently partitioned among processors? */
     bool partitioned_;
 
     /** number of spatial dimensions */
     int nSD_;
 
     /** number of elements */
     int nElts_;
     /** number of elements partitioned to this processor */
     int myNElts_;
 
     /** number of nodes */
     int nNodes_;
     int nNodesUnique_;
 
     /** periodicity flags */
     Array<bool> periodicity_;
 
     /** element type for this mesh */
     FE_Element *feElement_;
 
     /** Nodal coordinates: nodalCoords_(nsd, numnode) */
     DENS_MAT nodalCoords_;
 
     /** Element connectivity: connectivity_(neltnode, nelt) */
     Array2D<int> connectivity_;
     Array2D<int> myConnectivity_;
     Array2D<int> connectivityUnique_;
     Array2D<int> myConnectivityUnique_;
 
     /** map from unique node id to associated elements for periodic meshes */
     /** this data structure is only ever accessed from an unpartitioned context */
     Array<std::vector<int> > uniqueNodeToElementMap_;
 
     /** map of global to unique node ID's */
     Array<int> globalToUniqueMap_;
     Array<int> compactRemap_; // for condensing unique numbering
 
     /** map of unique to global node ID's */
     Array<int> uniqueToGlobalMap_;
 
     /** map of string names to node sets */
     NODE_SET_MAP nodeSetMap_;
 
     /** maximal nodeset */
     std::set<int> nodeSetAll_;
 
     /** map of string names to node sets */
     FACE_SET_MAP faceSetMap_;
 
     /** map of string names to element sets */
     ELEMENT_SET_MAP elementSetMap_;
 
     /** maximal elementset */
     std::set<int> elementSetAll_;
 
     /** length scaling used by lammps */
     double xscale_, yscale_, zscale_;
 
     /** Processor demarcations */
     std::vector<double> procs_;
 
     /** Dimension (x=0, y=1, or z=2) */
     int partitionAxis_;
 
     /** List of nodes for this processor */
     std::vector<int> myNodes_;
 
     /** List of elements for this processor */
     std::vector<int> myElts_;
     std::vector<int> myAndGhostElts_;
 
     /** maps between my IDs and the total IDs */
     std::map<int,int> elemToMyElemMap_;
    
     /** Lists of ghost nodes/neighbor ghost nodes */
     std::vector<int> ghostNodesL_; 
     std::vector<int> ghostNodesR_;
     std::vector<int> shareNodesL_;
     std::vector<int> shareNodesR_;
 
     /** extruded */
     bool twoDimensional_;
     bool hasPlanarFaces_;
     double coordTol_;
 
   };
 
   /**
    *  @class  FE_3DMesh
    *  @brief  Derived class for an unstructured 3D mesh
    */
   class FE_3DMesh : public FE_Mesh {
   public:
     /** constructor */
     FE_3DMesh(){}; 
 
     /** constructor for read-in mesh **/
     // can later be extended to take nodesets, elementsets, etc.
     FE_3DMesh(const std::string elementType, 
               const int nNodes,
               const int nElements,
               const Array2D<int> *connectivity,
               const DENS_MAT *nodalCoordinates,
               const Array<bool> periodicity,
               const Array<std::pair<std::string,std::set<int> > > *nodeSets);
 
     /** destructor */
     virtual ~FE_3DMesh();
 
     void partition_mesh(void);
 
     void departition_mesh(void);
 
     void lammps_partition_mesh(void);
 
     /** Removes duplicate elements that appear in more than one vector
          within procEltLists. **/
     void prune_duplicate_elements(std::vector<std::vector<int> > &procEltLists, 
                                   int *eltToOwners);
     
     /** Takes procEltLists, and if there are more than nProcs of them
         it takes the extra elements and distributes them to other vectors
         in procEltLists. */
           
           //       processors if during pruning processors end up
           //       elementless. This is slightly complicated because of
           //       ghost nodes.
     void redistribute_extra_proclists(std::vector<std::vector<int> > &procEltLists,
                                       int *eltToOwners, int nProcs);
                                         
     /** This takes in a dense matrix and a list of elements
         and fills in a standard adjacency list (within the matrix)
         for those elements. **/
           
           //       the set intersection, which does redundant computations
           //       right now, and filling in the adjacencies for both elements
           //       simultaneously when two elements share a face.
     void compute_face_adjacencies(const std::list<int> &elts, 
                                   DENS_MAT &faceAdjacencies);
 
     /** Counts the number of nonempty vectors in a vector of vectors. **/
     int numNonempty(std::vector<std::vector<int> > &v);
       
     /**  In the partitioning, we want to sort vectors of integers by size, 
           and furthermore we want empty vectors to count as the "largest" 
           possible vector because they dont want to count in the minimum. **/
     struct vectorComparer {
         bool operator() (std::vector<int> l, std::vector<int> r) {
           if (l.empty())
             return false;
           if (r.empty())
             return true;
           return (l.size() < r.size());
         }
     } vectorCompSize;
 
     virtual double min_element_size(void) const {return minEltSize_; }
     virtual double coordinate_tolerance(void) const {
       return 0.25*(this->min_element_size()); // loose
       //return 0.5;
     }
     virtual void cut_mesh(const std::set<PAIR> &faceSet,
                           const std::set<int> &nodeSet);
     
     virtual void delete_elements(const std::set<int> &elementSet);
 
     /** map spatial location to element */
     virtual int map_to_element(const DENS_VEC &x) const;
     
     /** sends out data to processors during partitioning */
     void distribute_mesh_data();
   protected:
     /** create global-to-unique node mapping */
     virtual void setup_periodicity(double tol = 1.e-8);
     void fix_periodicity  (int idim);
     int find_boundary_nodes(int idim, std::set<int> & nodes);
     bool match_nodes(int idim, std::set<int> & top, std::set<int> & bot,
                      Array<int> & map);
     void set_unique_connectivity(void);
     bool orient(int idir);
 
     double minEltSize_;
     KD_Tree *tree_;
 
     /** test if a specified element actually contains the given point */
     bool contains_point(const int eltID, const DENS_VEC & x) const;
 
   private:
     Array<std::vector<int> > nodeToParentElements_;
 
   };
 
   /**
    *  @class  FE_Rectangular3DMesh
    *  @brief  Derived class for a structured mesh with 
    *          variable element sizes in x, y, and z directions 
    */
   class FE_Rectangular3DMesh : public FE_3DMesh {
   public:
     /** constructor */
     FE_Rectangular3DMesh(){}; 
     FE_Rectangular3DMesh(
               const Array<double> & hx,
               const Array<double> & hy,
               const Array<double> & hz,
               const double xmin, const double xmax, 
               const double ymin, const double ymax,
               const double zmin, const double zmax,
               const Array<bool> periodicity,
               const double xscale=1,
               const double yscale=1,
               const double zscale=1);
 
     /** destructor */
     virtual ~FE_Rectangular3DMesh() {};
     
     void partition_mesh(void);
 
     void departition_mesh(void);
 
     /** map spatial location to element */
     virtual int map_to_element(const DENS_VEC &x) const; 
 
   protected:
 
     /** Number of elements in each spatial direction */
     int n_[3];
 
     /** Bounds of region on which mesh is defined */
     double borders_[2][3];
 
     /** Region size in each direction */
     double L_[3];
 
     
 
     /** create global-to-unique node mapping */
     virtual void setup_periodicity(); // note no "tol"
 
   private: // only used by this class
     /** partitions in x,y,z */
     Array<double> hx_, hy_, hz_;
 
     /** nodal locations */
     std::vector< Array<double> > x_;
   };
 
   /**
    *  @class  FE_Uniform3DMesh
    *  @brief  Derived class for a uniform structured mesh with 
    *          fixed element sizes in x, y, and z directions 
    */
   class FE_Uniform3DMesh : public FE_Rectangular3DMesh {
   
   public:
 
     /** constructor */
     FE_Uniform3DMesh(const int nx,
                      const int ny,
                      const int nz,
                      const double xmin, const double xmax,
                      const double ymin, const double ymax,
                      const double zmin, const double zmax,
                      const Array<bool> periodicity,
                      const double xscale=1,
                      const double yscale=1,
                      const double zscale=1);
 
     /** destructor */
     virtual ~FE_Uniform3DMesh();
 
     void partition_mesh(void);
 
     void departition_mesh(void);
     
     virtual void element_size(const int ielem, 
                               double hx, double hy, double hz) 
     { hx = L_[0]/n_[0]; hy = L_[1]/n_[1]; hz = L_[2]/n_[2]; }
 
     virtual double min_element_size(void) const
     { return std::min(L_[0]/n_[0], std::min(L_[1]/n_[1], L_[2]/n_[2])); }
 
     /** map spatial location to element */
     virtual int map_to_element(const DENS_VEC &x) const; 
 
   private: // only used by this class
     /** Element size in each direction */
     double dx_[3];
 
   };
 
 }; // namespace ATC_Transfer
 
 #endif // FE_MESH_H
diff --git a/lib/atc/FieldEulerIntegrator.cpp b/lib/atc/FieldEulerIntegrator.cpp
index 2375a33ff..eeea0cd4e 100644
--- a/lib/atc/FieldEulerIntegrator.cpp
+++ b/lib/atc/FieldEulerIntegrator.cpp
@@ -1,102 +1,153 @@
 #include "FieldEulerIntegrator.h"
 #include "ATC_Coupling.h"
 #include "FE_Engine.h"
 #include "PhysicsModel.h"
-#include "GMRES.h"
-#include "CG.h"
+#include "PrescribedDataManager.h"
+//#include "GMRES.h"
+//#include "CG.h"
 #include "ImplicitSolveOperator.h"
+#include "MatrixDef.h"
+#include "LinearSolver.h"
 
 namespace ATC {
 
 // ====================================================================
 // FieldEulerIntegrator
 // ====================================================================
 FieldEulerIntegrator::FieldEulerIntegrator(
   const FieldName fieldName,
   const PhysicsModel * physicsModel, 
   /*const*/ FE_Engine * feEngine,
   /*const*/ ATC_Coupling * atc,
   const Array2D< bool > & rhsMask  // copy 
 )
   : atc_(atc),
     feEngine_(feEngine),
     physicsModel_(physicsModel),
     fieldName_(fieldName),
     rhsMask_(rhsMask)
 {
   nNodes_ = feEngine->num_nodes();
 }
 
 // ====================================================================
 // FieldImplicitIntegrator
 // ====================================================================
 FieldExplicitEulerIntegrator::FieldExplicitEulerIntegrator(
   const FieldName fieldName,
   const PhysicsModel * physicsModel, 
   /*const*/ FE_Engine * feEngine,
   /*const*/ ATC_Coupling * atc,
   const Array2D< bool > & rhsMask  // copy 
 ) : FieldEulerIntegrator(fieldName,physicsModel,feEngine,atc,rhsMask)
 {
 }
 
 // --------------------------------------------------------------------
 // update 
 // --------------------------------------------------------------------
 void FieldExplicitEulerIntegrator::update(const double dt, double time,
   FIELDS & fields, FIELDS & rhs)
 { 
   // write and add update mass matrix to handled time variation
   // update mass matrix to be consistent/lumped, and handle this in apply_inverse_mass_matrix
   atc_->compute_rhs_vector(rhsMask_, fields, rhs,
     FULL_DOMAIN, physicsModel_);
   DENS_MAT & myRhs(rhs[fieldName_].set_quantity());
   atc_->apply_inverse_mass_matrix(myRhs,fieldName_);
   fields[fieldName_] += dt*myRhs;
 }
 
 // ====================================================================
 // FieldImplicitEulerIntegrator
 // ====================================================================
 FieldImplicitEulerIntegrator::FieldImplicitEulerIntegrator(
   const FieldName fieldName,
   const PhysicsModel * physicsModel, 
   /*const*/ FE_Engine * feEngine,
   /*const*/ ATC_Coupling * atc,
   const Array2D< bool > & rhsMask,  // copy 
   const double alpha
 ) : FieldEulerIntegrator(fieldName,physicsModel,feEngine,atc,rhsMask),
   alpha_(alpha),
   dT_(1.0e-6), 
   maxRestarts_(50),
   maxIterations_(1000),
   tol_(1.0e-8)
 {
 }
 
 // --------------------------------------------------------------------
 // update 
 // --------------------------------------------------------------------
 void FieldImplicitEulerIntegrator::update(const double dt, double time,
   FIELDS & fields, FIELDS & rhs) 
 { // solver handles bcs
-  FieldImplicitSolveOperator solver(atc_, feEngine_, 
+  FieldImplicitSolveOperator solver(atc_, 
     fields, fieldName_, rhsMask_, physicsModel_,
     time, dt, alpha_);
-  DiagonalMatrix<double> preconditioner = solver.preconditioner(fields);
-  DENS_VEC myRhs = solver.rhs();
+  DiagonalMatrix<double> preconditioner = solver.preconditioner();
+  DENS_VEC rT = solver.r();
   DENS_VEC dT(nNodes_); dT = dT_; 
   DENS_MAT H(maxRestarts_+1, maxRestarts_);
   double tol = tol_; // tol returns the residual
   int iterations = maxIterations_; // iterations returns number of iterations
   int restarts = maxRestarts_;
   int convergence = GMRES(solver,
-    dT, myRhs, preconditioner, H, restarts, iterations, tol);
+    dT, rT, preconditioner, H, restarts, iterations, tol);
   if (convergence != 0) {
     throw ATC_Error(field_to_string(fieldName_) + " evolution did not converge");
   }
-  fields[fieldName_] += dT;
-  rhs[fieldName_] = myRhs;
+  solver.solution(dT,fields[fieldName_].set_quantity());
 }
 
+// ====================================================================
+// FieldImplicitDirectEulerIntegrator
+// ====================================================================
+FieldImplicitDirectEulerIntegrator::FieldImplicitDirectEulerIntegrator(
+  const FieldName fieldName,
+  const PhysicsModel * physicsModel, 
+  /*const*/ FE_Engine * feEngine,
+  /*const*/ ATC_Coupling * atc,
+  const Array2D< bool > & rhsMask,  // copy 
+  const double alpha
+) : FieldEulerIntegrator(fieldName,physicsModel,feEngine,atc,rhsMask),
+  alpha_(alpha),solver_(NULL)
+{
+   rhsMask_(fieldName_,FLUX) = false; // handle laplacian term with stiffness
+   const BC_SET & bcs = (atc_->prescribed_data_manager()->bcs(fieldName_))[0];
+   solver_ = new LinearSolver(_lhsMK_,bcs);
+   solver_->allow_reinitialization();
+}
+FieldImplicitDirectEulerIntegrator::~FieldImplicitDirectEulerIntegrator()
+{
+   if (solver_) delete solver_;
+}
+
+// --------------------------------------------------------------------
+// initialize 
+// --------------------------------------------------------------------
+void FieldImplicitDirectEulerIntegrator::initialize(const double dt, double time,
+  FIELDS & fields) 
+{ 
+   std::pair<FieldName,FieldName> p(fieldName_,fieldName_);
+   Array2D <bool>  rmask = atc_->rhs_mask();
+   rmask(fieldName_,FLUX) = true; 
+   atc_->tangent_matrix(p,rmask,physicsModel_,_K_);
+   _lhsMK_ = (1./dt)*(_M_)-     alpha_*(_K_);
+   _rhsMK_ = (1./dt)*(_M_)+(1.+alpha_)*(_K_);
+}
+// --------------------------------------------------------------------
+// update 
+// --------------------------------------------------------------------
+void FieldImplicitDirectEulerIntegrator::update(const double dt, double time,
+  FIELDS & fields, FIELDS & rhs) 
+{ 
+  atc_->compute_rhs_vector(rhsMask_, fields, rhs,
+    FULL_DOMAIN, physicsModel_);
+  CLON_VEC myRhs   = column(   rhs[fieldName_].set_quantity(),0);
+  CLON_VEC myField = column(fields[fieldName_].set_quantity(),0);
+  myRhs += _rhsMK_*myField; // f = (1/dt M + (1+alpha) K) T + f
+  solver_->solve(myField,myRhs); // (1/dt M -alpha K)^-1 f
+}
 } // namespace ATC
diff --git a/lib/atc/FieldEulerIntegrator.h b/lib/atc/FieldEulerIntegrator.h
index 174f37435..f349ada5d 100644
--- a/lib/atc/FieldEulerIntegrator.h
+++ b/lib/atc/FieldEulerIntegrator.h
@@ -1,138 +1,183 @@
 #ifndef FIELD_EULER_INTEGRATOR_H
 #define FIELD_EULER_INTEGRATOR_H
 
 // ATC includes
 #include "Array2D.h"
 #include "MatrixLibrary.h"
 #include "PhysicsModel.h"
 #include "TimeIntegrator.h"
 #include "ImplicitSolveOperator.h"
 
 // other includes
 #include <vector>
 #include <map>
 
 namespace ATC {
 
 // Forward class declarations
 class ATC_Coupling;
 class FE_Engine;
 
 /**
  *  @class FieldEulerIntegrator
  *  @brief method for integrating fast fields
  */
 
 class FieldEulerIntegrator {
 
  public:
 
   /** Constructor */
   FieldEulerIntegrator(
     const FieldName fieldName,
     const PhysicsModel * physicsModel,
     /*const*/ FE_Engine * feEngine,
     /*const*/ ATC_Coupling * atc,
     const Array2D< bool > & rhsMask  // copy
   );
 
 
   /** Destructor */
   virtual ~FieldEulerIntegrator() {};
 
+  /** initialize */
+  virtual void initialize(const double dt, const double time,
+    FIELDS & fields) {};
+
   /** update */
   virtual void update(const double dt, const double time,
     FIELDS & fields,  FIELDS & rhs) = 0;
 
  protected:
 
   /** Pointer to ATC_Tranfer */
   ATC_Coupling * atc_;
 
   /** Pointer to FE_Engine */
   /*const*/ FE_Engine * feEngine_;
 
   /** Pointer to PhysicsModel */
   const PhysicsModel * physicsModel_;
 
   /** field name */
   FieldName fieldName_; 
 
   /** rhs mask */
   Array2D <bool> rhsMask_;
 
   /** number of nodes */
   int nNodes_;
 };
 
 /**
  *  @class FieldExplicitEulerIntegrator
  *  @brief explicit Euler method for integrating fast electron fields
  */
 class FieldExplicitEulerIntegrator : public FieldEulerIntegrator {
 
  public:
 
   /** Constructor */
   FieldExplicitEulerIntegrator(
     const FieldName fieldName,
     const PhysicsModel * physicsModel,
     /*const*/ FE_Engine * feEngine,
     /*const*/ ATC_Coupling * atc,
     const Array2D< bool > & rhsMask  // copy
   );
 
   /** Destructor */
   virtual ~FieldExplicitEulerIntegrator() {};
 
   /** update */
   void update(const double dt, const double time,
     FIELDS & fields,  FIELDS & rhs);
 
 };
 
 /**
  *  @class FieldImplicitEulerIntegrator
  *  @brief explicit Euler method for integrating fast electron fields
  */
 class FieldImplicitEulerIntegrator : public FieldEulerIntegrator {
 
  public:
 
   /** Constructor */
   FieldImplicitEulerIntegrator(
     const FieldName fieldName,
     const PhysicsModel * physicsModel,
     /*const*/ FE_Engine * feEngine,
     /*const*/ ATC_Coupling * atc,
     const Array2D< bool > & rhsMask, // copy
     const double alpha = 0.5 // default to trap/midpt
   );
 
   /** Destructor */
   virtual ~FieldImplicitEulerIntegrator() {};
 
   /** update */
   void update(const double dt, const double time,
     FIELDS & fields,  FIELDS & rhs);
 
  protected:
   /** euler update factor */
   double alpha_;
 
   /** perturbation */
   double dT_;
 
   /** max number of restarts = size of basis */
   int maxRestarts_;
 
   /** max number of iterations */
   int maxIterations_;
 
   /** convergence tolerance */
   double tol_;
 };
 
+/**
+ *  @class FieldImplicitDirectEulerIntegrator
+ *  @brief implicit Euler method with direct solve
+ */
+class FieldImplicitDirectEulerIntegrator : public FieldEulerIntegrator {
+
+ public:
+
+  /** Constructor */
+  FieldImplicitDirectEulerIntegrator(
+    const FieldName fieldName,
+    const PhysicsModel * physicsModel,
+    /*const*/ FE_Engine * feEngine,
+    /*const*/ ATC_Coupling * atc,
+    const Array2D< bool > & rhsMask, // copy
+    const double alpha = 0.5 // default to trap/midpt
+  );
+
+  /** Destructor */
+  virtual ~FieldImplicitDirectEulerIntegrator();
+
+  /** initalize - init the matrices and inverses */
+  void initialize(const double dt, const double time,
+    FIELDS & fields);
+
+  /** update */
+  void update(const double dt, const double time,
+    FIELDS & fields,  FIELDS & rhs);
+
+ protected:
+  /** euler update factor */
+  double alpha_;
+
+  /** matrices */
+  SPAR_MAT  _M_;
+  SPAR_MAT  _K_;
+  SPAR_MAT  _lhsMK_;
+  SPAR_MAT  _rhsMK_;
+  class LinearSolver * solver_;
+};
+
 } // namespace ATC
 
 #endif
diff --git a/lib/atc/FieldManager.cpp b/lib/atc/FieldManager.cpp
index 9a74fc22c..ce9f85953 100644
--- a/lib/atc/FieldManager.cpp
+++ b/lib/atc/FieldManager.cpp
@@ -1,548 +1,549 @@
 #include "FieldManager.h"
 #include "ATC_Method.h"
 #include "LammpsInterface.h"
 #include "PerAtomQuantity.h"
 #include "TransferOperator.h"
 
 using std::string;
 
 namespace ATC {
 
 typedef PerAtomQuantity<double> PAQ;
 
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
   FieldManager::FieldManager(ATC_Method * atc):
     atc_(atc),
     interscaleManager_(atc->interscale_manager())
   {};
 
 
 //-----------------------------------------------------------------------------
 //* restricted_atom_quantity
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::restricted_atom_quantity(FieldName field, string name, PAQ * atomicQuantity) 
   {
     if (name == "default") { name = field_to_restriction_name(field); }
     DENS_MAN * quantity = interscaleManager_.dense_matrix(name);
 
     if (!quantity){
       if      (field == CHARGE_DENSITY) {
         atomicQuantity = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE);
       }
       else if (field == MASS_DENSITY) {
         atomicQuantity = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_MASS);
       }
       else {
         
         if (!atomicQuantity) {
           throw ATC_Error("FieldManager::restricted_atom_quantity - need to supply PAQ if restricted quantity does not already exist");
         }
       }
       quantity = new AtfShapeFunctionRestriction(atc_,atomicQuantity,atc_->accumulant());
       interscaleManager_.add_dense_matrix(quantity,name);
     }
     return quantity;
   }
 
 //-----------------------------------------------------------------------------
 //* restricted_atom_quantity
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::projected_atom_quantity(FieldName field,string name, PAQ * atomic,  DIAG_MAN * normalization)
   {
     if (atc_->use_md_mass_normalization()) {
       if (name == "default") { name = field_to_intrinsic_name(field); }
       DENS_MAN * quantity = interscaleManager_.dense_matrix(name);
       if (!quantity) {
         DENS_MAN * restricted = restricted_atom_quantity(field,field_to_restriction_name(field),atomic);
         quantity = new AtfShapeFunctionMdProjection(atc_,restricted,use_mass_matrix(field));
         interscaleManager_.add_dense_matrix(quantity,name);
       }
       return quantity;
     }
     else {
       if (name == "default") { name = field_to_string(field); }
       DENS_MAN * quantity = interscaleManager_.dense_matrix(name);
       if (quantity) return quantity;
 
       if (atc_->kernel_on_the_fly()) {
         if (atc_->kernel_based()) {
           quantity = new OnTheFlyKernelAccumulationNormalized(atc_, atomic, 
             atc_->kernel_function(), 
             atc_->atom_coarsegraining_positions(), 
             normalization);
         } else {
           quantity = new OnTheFlyMeshAccumulationNormalized(atc_, atomic, 
             atc_->atom_coarsegraining_positions(), 
             normalization);
         }
       } else {
         quantity = new AtfProjection(atc_, atomic, 
                                      atc_->accumulant(), 
                                      normalization);
       }
       interscaleManager_.add_dense_matrix(quantity,name);
       return quantity;
     }
   }
 
 //-----------------------------------------------------------------------------
 //* referenced_projected_atom_quantity
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::referenced_projected_atom_quantity(FieldName field,string name, PAQ * atomic, DENS_MAN * reference, DIAG_MAN * normalization)
   {
     if (name == "default") { name = field_to_string(field); }
     DENS_MAN * quantity = interscaleManager_.dense_matrix(name);
     if (quantity) return quantity;
 
     if (atc_->use_md_mass_normalization()) {
       DENS_MAN * restricted = restricted_atom_quantity(field,field_to_restriction_name(field),atomic);
       quantity = new AtfShapeFunctionMdProjectionReferenced(atc_,restricted,reference,use_mass_matrix(field));
     }
     else if (atc_->kernel_on_the_fly()) {
       if (atc_->kernel_based()) {
         quantity = new OnTheFlyKernelAccumulationNormalizedReferenced(atc_, 
           atomic, 
           atc_->kernel_function(), 
           atc_->atom_coarsegraining_positions(), 
           normalization,
           reference);
       } else {
         quantity = new OnTheFlyMeshAccumulationNormalizedReferenced(atc_, 
           atomic, 
           atc_->atom_coarsegraining_positions(), 
           normalization,
           reference);
       }
     } else {
       quantity = new AtfProjectionReferenced(atc_, atomic, 
           atc_->accumulant(),
           reference,
           normalization);
     }
     interscaleManager_.add_dense_matrix(quantity,name);
     return quantity;
   }
 
 //-----------------------------------------------------------------------------
 //* scaled_projected_atom_quantity
 //-----------------------------------------------------------------------------
 
   DENS_MAN * FieldManager::scaled_projected_atom_quantity(FieldName field,string name, PAQ * atomic, double scale, DIAG_MAN * normalization)
   {
     if (name == "default") { name = field_to_string(field); }
     DENS_MAN * quantity = interscaleManager_.dense_matrix(name);
     if (quantity) return quantity;
 
     if (atc_->use_md_mass_normalization()) {
       DENS_MAN * restricted = restricted_atom_quantity(field,field_to_restriction_name(field),atomic);
       quantity = new AtfShapeFunctionMdProjectionScaled(atc_,restricted,scale,use_mass_matrix(field));
     }
     else if (atc_->kernel_on_the_fly()) {
       if (atc_->kernel_based()) {
         quantity = new OnTheFlyKernelAccumulationNormalizedScaled(atc_, atomic, 
           atc_->kernel_function(), 
           atc_->atom_coarsegraining_positions(), 
           normalization,
           scale);
       } else {
         quantity = new OnTheFlyMeshAccumulationNormalizedScaled(atc_, atomic, 
           atc_->atom_coarsegraining_positions(), 
           normalization,
           scale);
       }
     } else {
       quantity = new AtfProjectionScaled(atc_, atomic,
           atc_->accumulant(),
           scale,
           normalization);
     }
     interscaleManager_.add_dense_matrix(quantity,name);
     return quantity;
   }
 
 //-----------------------------------------------------------------------------
 //* CHARGE_DENSITY
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::charge_density(string name)
   {
     FundamentalAtomQuantity * atomic = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE);
     return projected_atom_quantity(CHARGE_DENSITY,name,atomic,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* MASS_DENSITY
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::mass_density(string name)
   {
     FundamentalAtomQuantity * atomic = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_MASS);
     return projected_atom_quantity(MASS_DENSITY,name,atomic,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* SPECIES_CONCENTRATION
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::species_concentration(string name)
   {
     PerAtomQuantity<double> * atomTypeVector = interscaleManager_.per_atom_quantity("atom_species_vector");
     if (!atomTypeVector) {
       atomTypeVector = new AtomTypeVector(atc_,atc_->type_list(),atc_->group_list());
       interscaleManager_.add_per_atom_quantity(atomTypeVector,"atom_species_vector");
     }
     return projected_atom_quantity(SPECIES_CONCENTRATION,name,atomTypeVector,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* NUMBER_DENSITY
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::number_density(string name)
   {
     PAQ * atomic = interscaleManager_.per_atom_quantity("atomNumber");
     if (!atomic) {
       atomic = new AtomNumber(atc_);
       interscaleManager_.add_per_atom_quantity(atomic, "atomNumber");
     }
     return projected_atom_quantity(NUMBER_DENSITY,name,atomic,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* MOMENTUM 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::momentum(string name)
   {
     PAQ * atomic = interscaleManager_.per_atom_quantity("atomMomentum");
     if (!atomic) {
       atomic = new AtomicMomentum(atc_);
       interscaleManager_.add_per_atom_quantity(atomic, "atomMomentum");
     }
     return projected_atom_quantity(MOMENTUM,name,atomic,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* VELOCITY 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::velocity(string name)
   {
     if (name == "default") { name = field_to_string(VELOCITY); }
     DENS_MAN * v = interscaleManager_.dense_matrix(name);
     if (v) return v;
 
     if (atc_->use_md_mass_normalization()) {
       PAQ * atomic = interscaleManager_.per_atom_quantity("atomMomentum");
       if (!atomic) {
         atomic = new AtomicMomentum(atc_);
         interscaleManager_.add_per_atom_quantity(atomic, "atomMomentum");
       }
       DENS_MAN * restricted = restricted_atom_quantity(VELOCITY,field_to_restriction_name(VELOCITY),atomic);
       v = new AtfShapeFunctionMdProjection(atc_,restricted,VELOCITY);
     }
     else {
       DENS_MAN* p = interscaleManager_.dense_matrix(field_to_string(MOMENTUM));
       if (!p) p = nodal_atomic_field(MOMENTUM);
       DENS_MAN* m = interscaleManager_.dense_matrix(field_to_string(MASS_DENSITY));
       if (!m) m = nodal_atomic_field(MASS_DENSITY);
       v = new DenseMatrixQuotient(p,m);
     }
     interscaleManager_.add_dense_matrix(v,field_to_string(VELOCITY));
     return v;
   }
 //-----------------------------------------------------------------------------
 //* PROJECTED_VELOCITY 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::projected_velocity(string name)
   {
     FundamentalAtomQuantity * atomic = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY);
     return projected_atom_quantity(PROJECTED_VELOCITY,name,atomic,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* DISPLACEMENT 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::displacement(string name)
   {
     if (name == "default") { name = field_to_string(DISPLACEMENT); }
     DENS_MAN * u = interscaleManager_.dense_matrix(name);
     if (u) return u;
 
     PAQ * atomic = interscaleManager_.per_atom_quantity("AtomicMassWeightedDisplacement");
     if (!atomic) {
       FundamentalAtomQuantity * atomMasses = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_MASS);    
       FundamentalAtomQuantity * atomPositions = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_POSITION);    
       atomic = new AtomicMassWeightedDisplacement(atc_,atomPositions, atomMasses, atc_->atom_reference_positions(), INTERNAL);
       interscaleManager_.add_per_atom_quantity(atomic,"AtomicMassWeightedDisplacement");
     }
     if (atc_->use_md_mass_normalization()) {
       DENS_MAN * restricted = restricted_atom_quantity(DISPLACEMENT,field_to_restriction_name(DISPLACEMENT),atomic);
       u = new AtfShapeFunctionMdProjection(atc_,restricted,VELOCITY);
     }
     else {
       DENS_MAN * q = NULL;
       if (atc_->kernel_on_the_fly()) {
         if (atc_->kernel_based()) {
           q = new OnTheFlyKernelAccumulationNormalized(atc_, atomic,
             atc_->kernel_function(),
             atc_->atom_coarsegraining_positions(),
             atc_->accumulant_inverse_volumes());
         } else {
           q = new OnTheFlyMeshAccumulationNormalized(atc_, atomic,
             atc_->atom_coarsegraining_positions(),
             atc_->accumulant_inverse_volumes());
         }
       } else {
         q = new AtfProjection(atc_, atomic,
                               atc_->accumulant(),
                               atc_->accumulant_inverse_volumes());
       }
       interscaleManager_.add_dense_matrix(q,"CoarseGrainedAMWD");
       DENS_MAN* m  = interscaleManager_.dense_matrix(field_to_string(MASS_DENSITY));
       u = new DenseMatrixQuotient(q,m);
     }
     interscaleManager_.add_dense_matrix(u,name);
     return u;
   }
 //-----------------------------------------------------------------------------
 //* REFERENCE_POTENTIAL_ENERGY 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::reference_potential_energy(string name)
   {
     DENS_MAN * rpe = interscaleManager_.dense_matrix(field_to_string(REFERENCE_POTENTIAL_ENERGY));
     if (! rpe ) { 
       PAQ * atomic = interscaleManager_.per_atom_quantity("AtomicReferencePotential");
       if (!atomic) {
         atomic = new AtcAtomQuantity<double>(atc_);
         interscaleManager_.add_per_atom_quantity(atomic, "AtomicReferencePotential");
         atomic->set_memory_type(PERSISTENT);
       }
 
       SPAR_MAN * referenceAccumulant = interscaleManager_.sparse_matrix("ReferenceAccumulant");
       if (!referenceAccumulant) {
         referenceAccumulant = new SPAR_MAN();
         referenceAccumulant->set_memory_type(PERSISTENT);
         interscaleManager_.add_sparse_matrix(referenceAccumulant,
                                              "ReferenceAccumulant");
       }
 
       DIAG_MAN * referenceAccumulantInverseVolumes = interscaleManager_.diagonal_matrix("ReferenceAccumulantInverseVolumes");
       if (!referenceAccumulantInverseVolumes) {
         referenceAccumulantInverseVolumes = new DIAG_MAN();
         referenceAccumulantInverseVolumes->set_memory_type(PERSISTENT);
         interscaleManager_.add_diagonal_matrix(referenceAccumulantInverseVolumes,
                                                "ReferenceAccumulantInverseVolumes");
       }
 
       rpe = new AtfProjection(atc_, atomic,
         referenceAccumulant,
         referenceAccumulantInverseVolumes);
       interscaleManager_.add_dense_matrix(rpe,field_to_string(REFERENCE_POTENTIAL_ENERGY));
       rpe->set_memory_type(PERSISTENT);
     }
     return rpe;
   }
 //-----------------------------------------------------------------------------
 //* POTENTIAL_ENERGY 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::potential_energy(string name)
   {
     PerAtomQuantity<double> * atomic = interscaleManager_.per_atom_quantity("AtomicPotentialEnergy");
     if (!atomic) {
       atomic = new ComputedAtomQuantity(atc_,(atc_->lammps_interface())->compute_pe_name(), atc_->pe_scale());
       interscaleManager_.add_per_atom_quantity(atomic,"AtomicPotentialEnergy");
     }
     DENS_MAN * reference = interscaleManager_.dense_matrix(field_to_string(REFERENCE_POTENTIAL_ENERGY));
     if (reference) {
       return referenced_projected_atom_quantity(POTENTIAL_ENERGY,name,atomic,reference,atc_->accumulant_inverse_volumes());
     }
     else {
       return projected_atom_quantity(POTENTIAL_ENERGY,name,atomic,atc_->accumulant_inverse_volumes());
     }
   }
 //-----------------------------------------------------------------------------
 //* TEMPERATURE 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::temperature(string name)
  {
     double Tcoef = 1./((atc_->nsd())*(atc_->lammps_interface())->kBoltzmann());
     PAQ * atomic = per_atom_quantity("AtomicTwiceFluctuatingKineticEnergy");
     return scaled_projected_atom_quantity(TEMPERATURE,name,atomic,Tcoef,atc_->accumulant_weights());
   }
 //-----------------------------------------------------------------------------
 //* KINETIC_TEMPERATURE
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::kinetic_temperature(string name)
   {
     double Tcoef = 1./((atc_->nsd())*(atc_->lammps_interface())->kBoltzmann());
     PAQ * atomic = per_atom_quantity("AtomicTwiceKineticEnergy");
     return scaled_projected_atom_quantity(KINETIC_TEMPERATURE,name,atomic,Tcoef,atc_->accumulant_weights());  
   }
 //-----------------------------------------------------------------------------
 //* THERMAL_ENERGY 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::thermal_energy(string name)
   {
     double Ecoef = 0.5*atc_->ke_scale();
     PAQ * atomic = per_atom_quantity("AtomicTwiceFluctuatingKineticEnergy");
     return scaled_projected_atom_quantity(THERMAL_ENERGY,name,atomic,Ecoef,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* KINETIC_ENERGY 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::kinetic_energy(string name)
   {
     double Ecoef = 0.5*atc_->ke_scale();
     PAQ * atomic = per_atom_quantity("AtomicTwiceKineticEnergy");
     return scaled_projected_atom_quantity(KINETIC_ENERGY,name,atomic,Ecoef,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* CHARGE_FLUX
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::charge_flux(string name)
   {
 
     PAQ * atomic = per_atom_quantity("AtomicChargeVelocity");
     return projected_atom_quantity(CHARGE_FLUX,name,atomic,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* SPECIES_FLUX
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::species_flux(string name)
   {
     PAQ * atomic = per_atom_quantity("AtomicSpeciesVelocity");
     return projected_atom_quantity(SPECIES_FLUX,name,atomic,atc_->accumulant_inverse_volumes());
   }
 //-----------------------------------------------------------------------------
 //* INTERNAL_ENERGY 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::internal_energy(string name)
   {
     if (name == "default") { name = field_to_string(INTERNAL_ENERGY); }
     DENS_MAN * te = thermal_energy(field_to_string(THERMAL_ENERGY));
     DENS_MAN * pe = potential_energy(field_to_string(POTENTIAL_ENERGY));
     DenseMatrixSum * ie = new DenseMatrixSum(te,pe);
     interscaleManager_.add_dense_matrix(ie,name);
     return ie;
   }
 //-----------------------------------------------------------------------------
 //* ENERGY 
 //-----------------------------------------------------------------------------
   DENS_MAN * FieldManager::energy(string name)
   {
     if (name == "default") { name = field_to_string(ENERGY); }
     DENS_MAN * ke = kinetic_energy(field_to_string(KINETIC_ENERGY));
     DENS_MAN * pe = potential_energy(field_to_string(POTENTIAL_ENERGY));
     DenseMatrixSum * e = new DenseMatrixSum(ke,pe);
     interscaleManager_.add_dense_matrix(e,name);
 
     return e;
   }
 
 
 
 
 
 //=============================================================================
 //* PER ATOM QUANTITIES
 //=============================================================================
 
 //-----------------------------------------------------------------------------
 //* 2 KE '
 //-----------------------------------------------------------------------------
   PAQ * FieldManager::atomic_twice_fluctuating_kinetic_energy()
   {
     PAQ * atomic = interscaleManager_.per_atom_quantity("AtomicTwiceFluctuatingKineticEnergy");
     if (!atomic) {
       FundamentalAtomQuantity * atomMass = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_MASS);
       FundamentalAtomQuantity * atomVelocity = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY);
       PAQ * vbar = per_atom_quantity(field_to_prolongation_name(VELOCITY));
       atomic = new TwiceFluctuatingKineticEnergy(atc_,atomVelocity,atomMass,vbar);
       interscaleManager_.add_per_atom_quantity(atomic, "AtomicTwiceFluctuatingKineticEnergy");
     }
     return atomic;
   }
 //-----------------------------------------------------------------------------
 //* 2 KE 
 //-----------------------------------------------------------------------------
   PAQ * FieldManager::atomic_twice_kinetic_energy()
   {
     PAQ * atomic = interscaleManager_.per_atom_quantity("AtomicTwiceKineticEnergy");
     if (!atomic) {
       FundamentalAtomQuantity * atomMass = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_MASS);
       FundamentalAtomQuantity * atomVelocity = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY);
       atomic = new TwiceKineticEnergy(atc_,atomVelocity,atomMass);
       interscaleManager_.add_per_atom_quantity(atomic, "AtomicTwiceKineticEnergy");
     }
     return atomic;
   }
 //-----------------------------------------------------------------------------
 //* v'
 //-----------------------------------------------------------------------------
   PAQ * FieldManager::atomic_fluctuating_velocity()
   {
     PAQ * atomic = interscaleManager_.per_atom_quantity("AtomicFluctuatingVelocity");
     if (!atomic) {
       FundamentalAtomQuantity * atomVelocity = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY);
       PAQ * atomMeanVelocity = per_atom_quantity(field_to_prolongation_name(VELOCITY));
       atomic = new FluctuatingVelocity(atc_,atomVelocity,atomMeanVelocity);
       interscaleManager_.add_per_atom_quantity(atomic, "AtomicFluctuatingVelocity");
     }
     return atomic;
   }
 //-----------------------------------------------------------------------------
 //* q v'
 //-----------------------------------------------------------------------------
   PAQ * FieldManager::atomic_charge_velocity()
   {
     PAQ * atomic = interscaleManager_.per_atom_quantity("AtomicChargeVelocity");
     if (!atomic) {
       PAQ * atomVelocity = atomic_fluctuating_velocity();
       FundamentalAtomQuantity * atomCharge = interscaleManager_.fundamental_atom_quantity(LammpsInterface::ATOM_CHARGE);
       atomic = new ChargeVelocity(atc_,atomVelocity,atomCharge);
       interscaleManager_.add_per_atom_quantity(atomic, "AtomicChargeVelocity");
     }
     return atomic;
   }
 //-----------------------------------------------------------------------------
 //* m^a v'
 //-----------------------------------------------------------------------------
   PAQ * FieldManager::atomic_species_velocity()
   {
     PAQ * atomic = interscaleManager_.per_atom_quantity("AtomicSpeciesVelocity");
     if (!atomic) {
       PAQ * atomVelocity = atomic_fluctuating_velocity();
       PAQ * atomSpecies = atomic_species_vector(); 
       atomic = new SpeciesVelocity(atc_,atomVelocity,atomSpecies);
       interscaleManager_.add_per_atom_quantity(atomic, "AtomicSpeciesVelocity");
     }
     return atomic;
   }
 
 //-----------------------------------------------------------------------------
 //* [0 1 0 0 ] for type 2 atom
 //-----------------------------------------------------------------------------
   PAQ * FieldManager::atomic_species_vector()
   {
     PAQ * atomic = interscaleManager_.per_atom_quantity("AtomicSpeciesVector");
     if (!atomic) {
       atomic = new AtomTypeVector(atc_,atc_->type_list(),atc_->group_list());
       interscaleManager_.add_per_atom_quantity(atomic,"AtomicSpeciesVector");
     }
     return atomic;
   }
   //-----------------------------------------------------------------------------
   //* Prolonged coarse scale field
   //-----------------------------------------------------------------------------
   PAQ * FieldManager::prolonged_field(FieldName field)
   {
     PAQ * quantity = interscaleManager_.per_atom_quantity(field_to_prolongation_name(field));
     if (!quantity) {
       
+      
       DENS_MAN * coarseQuantity = interscaleManager_.dense_matrix(field_to_string(field));
       if (!coarseQuantity) coarseQuantity = nodal_atomic_field(field);
       if (!coarseQuantity) throw ATC_Error("can not prolong quantity: " + field_to_string(field) + " no field registered");
       if (atc_->kernel_on_the_fly()) {
         quantity = new OnTheFlyShapeFunctionProlongation(atc_,
           coarseQuantity,atc_->atom_coarsegraining_positions());
       } else {
         quantity = new FtaShapeFunctionProlongation(atc_,
           coarseQuantity,atc_->interpolant());
       }
       interscaleManager_.add_per_atom_quantity(quantity,
           field_to_prolongation_name(field));
     }
     return quantity;
   }
 }
diff --git a/lib/atc/Function.cpp b/lib/atc/Function.cpp
index 36d3e9a09..0bd759695 100644
--- a/lib/atc/Function.cpp
+++ b/lib/atc/Function.cpp
@@ -1,548 +1,554 @@
 #include "Function.h"
 #include "ATC_Error.h"
 #include "LammpsInterface.h"
 #include <sstream>
 
 using std::stringstream;
 using std::string;
 using std::set;
 using std::fstream;
 
 namespace ATC {
 
   //====================================================================
   //  UXT_Function
   //===================================================================
   UXT_Function::UXT_Function(int narg, double* args) { }
   //====================================================================
   //  UXT_Function_Mgr
   //====================================================================
   UXT_Function_Mgr * UXT_Function_Mgr::myInstance_ = NULL;
   // -----------------------------------------------------------------
   //  instance()
   // -----------------------------------------------------------------
   UXT_Function_Mgr * UXT_Function_Mgr::instance()
   {
     if (myInstance_ == NULL) {
       myInstance_ = new UXT_Function_Mgr();
     }
     return myInstance_;
   }
 
   // Destructor
   UXT_Function_Mgr::~UXT_Function_Mgr()
   {
     // Delete all functions created using "new"
     set<UXT_Function * >::iterator it;
     for (it = pointerSet_.begin(); it != pointerSet_.end(); it++)
       if (*it) delete *it;
   }
 
   // add user function into the if statement and assign returnFunction to it
   UXT_Function* UXT_Function_Mgr::function(string & type, int nargs, double * args)
   {
     UXT_Function * returnFunction;
     if      (type=="linear") {
       returnFunction = new ScalarLinearFunction(nargs,args);
     }
     else
       throw ATC_Error("Bad user function name");
 
     pointerSet_.insert(returnFunction);
 
     return returnFunction;
   }
 
   // add user function into the if statement and assign returnFunction to it
   UXT_Function* UXT_Function_Mgr::function(char ** args, int nargs)
   {
     string type = args[0];
     int narg = nargs -1;
     double dargs[narg];
     for (int i = 0; i < narg; ++i) dargs[i] = atof(args[i+1]);
   
     return function(type, narg, dargs);
   }
 
   // add constant function
   UXT_Function* UXT_Function_Mgr::linear_function(double c0, double c1)
   {
     double args[2] = {c0,c1};
     UXT_Function * returnFunction = new ScalarLinearFunction(2,args);
     pointerSet_.insert(returnFunction);
     return (returnFunction);
   }
 
   UXT_Function* UXT_Function_Mgr::copy_UXT_function(UXT_Function* other)
   {
     string tag = other->tag();
   
     UXT_Function * returnFunction = NULL;
     if (tag=="linear") {
       ScalarLinearFunction * other_cast = (ScalarLinearFunction*) other;
       returnFunction = new ScalarLinearFunction(*other_cast);
     }
     pointerSet_.insert(returnFunction);
     return returnFunction;
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  ScalarLinearFunction
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   ScalarLinearFunction::ScalarLinearFunction(int narg, double* args) 
     : UXT_Function(narg,args)
   {
     tag_ = "linear";
     c0_ = args[0];
     c1_ = args[1];
     stringstream ss;
     ss << "created function : " << c0_ << " + " << c1_ << "*u";
     ATC::LammpsInterface::instance()->print_msg_once(ss.str());
   }
 
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  XT_Function
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   XT_Function::XT_Function(int narg, double* args) 
   {
 
     if (narg > 5 ) { 
       x0[0] = args[0]; 
       x0[1] = args[1];
       x0[2] = args[2];
       mask[0] = args[3];
       mask[1] = args[4];
       mask[2] = args[5];
     } 
     else {
       x0[0] = 0.0; 
       x0[1] = 0.0;
       x0[2] = 0.0;
       mask[0] = 0.0;
       mask[1] = 0.0;
       mask[2] = 0.0;
     }
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  XT_Function_Mgr
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
 XT_Function_Mgr * XT_Function_Mgr::myInstance_ = NULL;
 
 // -----------------------------------------------------------------
 //  instance()
 // -----------------------------------------------------------------
   XT_Function_Mgr * XT_Function_Mgr::instance()
   {
     if (myInstance_ == NULL) {
       myInstance_ = new XT_Function_Mgr();
     }
     return myInstance_;
   }
 
   // Destructor
   XT_Function_Mgr::~XT_Function_Mgr()
   {
     // Delete all functions created using "new"
     set<XT_Function * >::iterator it;
     for (it = pointerSet_.begin(); it != pointerSet_.end(); it++)
       if (*it) delete *it;
   }
 
   // add user function into the if statement and assign returnFunction to it
   XT_Function* XT_Function_Mgr::function(string & type, int nargs, double * args)
   {
     XT_Function * returnFunction;
     if      (type=="constant") {
       returnFunction = new ConstantFunction(nargs,args);
     }
     else if (type=="temporal_ramp") {
       returnFunction = new TemporalRamp(nargs,args);
     }
     else if (type=="linear")
       returnFunction = new LinearFunction(nargs,args);
     else if (type=="piecewise_linear")
       returnFunction = new PiecewiseLinearFunction(nargs,args);
     else if (type=="linear_temporal_ramp")
       returnFunction = new LinearTemporalRamp(nargs,args);
     else if (type=="quadratic")
       returnFunction = new QuadraticFunction(nargs,args);
     else if (type=="sine")
       returnFunction = new SineFunction(nargs,args);
     else if (type=="gaussian")
       returnFunction = new GaussianFunction(nargs,args);
     else if (type=="gaussian_temporal_ramp")
       returnFunction = new GaussianTemporalRamp(nargs,args);
     else if (type=="radial_power")
       returnFunction = new RadialPower(nargs,args);
     else
       throw ATC_Error("Bad user function name");
 
     pointerSet_.insert(returnFunction);
 
     return returnFunction;
   }
 
   // add user function into the if statement and assign returnFunction to it
   XT_Function* XT_Function_Mgr::function(char ** args, int nargs)
   {
     string type = args[0];
     int narg = nargs -1;
     double dargs[narg];
     for (int i = 0; i < narg; ++i) dargs[i] = atof(args[i+1]);
   
     return function(type, narg, dargs);
   }
 
   // add constant function
   XT_Function* XT_Function_Mgr::constant_function(double c)
   {
     XT_Function * returnFunction = new ConstantFunction(c);
     pointerSet_.insert(returnFunction);
     return (returnFunction);
   }
 
   XT_Function* XT_Function_Mgr::copy_XT_function(XT_Function* other)
   {
     string tag = other->tag();
   
     XT_Function * returnFunction = NULL;
     if (tag=="linear") {
       LinearFunction * other_cast = (LinearFunction*) other;
       returnFunction = new LinearFunction(*other_cast);
     }
     else if (tag=="piecewise_linear") {
       PiecewiseLinearFunction * other_cast = (PiecewiseLinearFunction*) other;
       returnFunction = new PiecewiseLinearFunction(*other_cast);
     }
     else if (tag=="quadratic") {
       QuadraticFunction * other_cast = (QuadraticFunction*) other;
       returnFunction = new QuadraticFunction(*other_cast);
     }
     else if (tag=="sine") {
       SineFunction * other_cast = (SineFunction*) other;
       returnFunction = new SineFunction(*other_cast);
     }
     else if (tag=="gaussian") {
       GaussianFunction * other_cast = (GaussianFunction*) other;
       returnFunction = new GaussianFunction(*other_cast);
     }
     else if (tag=="gaussian_temporal_ramp") {
       GaussianTemporalRamp * other_cast = (GaussianTemporalRamp*) other;
       returnFunction = new GaussianTemporalRamp(*other_cast);
     }
     else if (tag=="temporal_ramp") {
       TemporalRamp * other_cast = (TemporalRamp*) other;
       returnFunction = new TemporalRamp(*other_cast);
     }
     else if (tag=="radial_power") {
       RadialPower * other_cast = (RadialPower*) other;
       returnFunction = new RadialPower(*other_cast);
     }
     pointerSet_.insert(returnFunction);
     return returnFunction;
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  ConstantFunction
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   ConstantFunction::ConstantFunction(int narg, double* args) 
     : XT_Function(narg,args),
       C0(args[0])
   {
     tag_ = "constant";
   }
   //--------------------------------------------------------------------
   ConstantFunction::ConstantFunction(double arg) 
     : XT_Function(1,&arg),
       C0(arg)
   {
     tag_ = "constant";
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  LinearFunction
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   LinearFunction::LinearFunction(int narg, double* args) 
     : XT_Function(narg,args)
   {
     C0 = args[6];
     tag_ = "linear";
     stringstream ss;
     ss << "created function : " << C0 << " + " << mask[0] << "(x-"<< x0[0] << ")+"<< mask[1] << "(y-"<<x0[1]<<")+"<<mask[2]<<"(z-"<<x0[2] << ")";
     ATC::LammpsInterface::instance()->print_msg_once(ss.str());
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  PiecewiseLinearFunction
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   PiecewiseLinearFunction::PiecewiseLinearFunction(int narg, double* args) 
     : XT_Function(narg,args)
   {
     int i=0, idx = 6, n = (narg-idx)/2;
     xi.reset(n);
     fi.reset(n);
     while (idx < narg) {
       xi(i)   = args[idx++];
       fi(i++) = args[idx++];
     }
     tag_ = "piecewise_linear";
+    stringstream ss;
+    ss << "created piecewise function : " << n << " \n";
+    for (i = 0; i < n; i++) {
+      ss << xi(i) << " " << fi(i) << "\n";
+    }
+    ATC::LammpsInterface::instance()->print_msg_once(ss.str());
   }
   double PiecewiseLinearFunction::f(double * x, double t)
   {
 
     double s = mask[0]*(x[0]-x0[0])+mask[1]*(x[1]-x0[1])+mask[2]*(x[2]-x0[2]);
     int index = xi.index(s);
 
     if      (index < 0)              return fi(0);
     else if (index >= xi.size()-1 )  return fi(xi.size()-1);
     else {
       double f = fi(index) 
         + (fi(index+1)-fi(index))*(s-xi(index))/(xi(index+1)-xi(index));
       return f;
     }
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  LinearTemporalRamp
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   LinearTemporalRamp::LinearTemporalRamp(int narg, double* args)
     : XT_Function(narg,args)
   {
     double mask_final[3];
     mask_final[0] = args[6];
     mask_final[1] = args[7];
     mask_final[2] = args[8];
     C0_initial = args[9];
     double C0_final = args[10];
     double delta_t = args[11];
 
     for (int i = 0; i < 3; i++)
       mask_slope[i] = (mask_final[i] - mask[i])/delta_t;
     C0_slope = (C0_initial - C0_final)/delta_t;
   }
 
   double LinearTemporalRamp::f(double* x, double t) {
     double slope[3];
     for (int i = 0; i < 3; i++)
       slope[i] = mask[i] + mask_slope[i]*t;
     double C0 = C0_initial + C0_slope*t;
     return slope[0]*(x[0]-x0[0])+slope[1]*(x[1]-x0[1])+slope[2]*(x[2]-x0[2]) + C0;
   }
 
   double LinearTemporalRamp::dfdt(double* x, double t) {
     return mask_slope[0]*(x[0]-x0[0])+mask_slope[1]*(x[1]-x0[1])+mask_slope[2]*(x[2]-x0[2]) + C0_slope;
   }
 
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  QuadraticFunction
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   QuadraticFunction::QuadraticFunction(int narg, double* args) 
     : XT_Function(narg,args)
   {
     C0 = args[6];
     C2[0] = args[7];
     C2[1] = args[8];
     C2[2] = args[9];
     C2[3] = args[10];
     C2[4] = args[11];
     C2[5] = args[12];
     tag_ = "quadratic";
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  SineFunction
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   SineFunction::SineFunction(int narg, double* args) 
     : XT_Function(narg,args)
   {
     C = args[6];
     w = args[7];
     C0 = args[8];
     tag_ = "sine";
     stringstream ss;
     ss << "created function : " << C << " sin( " << mask[0] << "(x-"<< x0[0] << ")+"<< mask[1] << "(y-"<<x0[1]<<")+"<<mask[2]<<"(z-"<<x0[2] << ") - " << w << "t ) + " << C0;
     ATC::LammpsInterface::instance()->print_msg_once(ss.str());
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  GaussianFunction
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   GaussianFunction::GaussianFunction(int narg, double* args) 
     : XT_Function(narg,args)
   {
     tau = args[6];
     C   = args[7];
     C0  = args[8];
     tag_ = "gaussian";
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  GaussianTemporalRamp
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   GaussianTemporalRamp::GaussianTemporalRamp(int narg, double* args) 
     : GaussianFunction(narg,args)
   {
     tau_initial = args[9];
     C_initial   = args[10];
     C0_initial  = args[11];
     double delta_t = args[12];
 
     tau_slope = (tau - tau_initial)/delta_t;
     C_slope   = (C - C_initial)/delta_t;
     C0_slope  = (C0 - C0_initial)/delta_t;
 
     tag_ = "gaussian_temporal_ramp";
   }
   double GaussianTemporalRamp::f(double* x, double t) {
     tau = tau_initial + tau_slope*t;
     C   = C_initial + C_slope*t;
     C0  = C0_initial + C0_slope*t;
     return GaussianFunction::f(x,t);
   }
   double GaussianTemporalRamp::dfdt(double* x, double t) {
     tau = tau_initial + tau_slope*t;
     C   = C_initial + C_slope*t;
     C0  = C0_initial + C0_slope*t;
     double dfdt = 0.;
     dfdt += C_slope*exp(-(mask[0]*(x[0]-x0[0])*(x[0]-x0[0])
                           +mask[1]*(x[1]-x0[1])*(x[1]-x0[1])
                           +mask[2]*(x[2]-x0[2])*(x[2]-x0[2]))
                         /tau/tau);
     dfdt += C*exp(2.*tau_slope*(mask[0]*(x[0]-x0[0])*(x[0]-x0[0])
                                 +mask[1]*(x[1]-x0[1])*(x[1]-x0[1])
                                 +mask[2]*(x[2]-x0[2])*(x[2]-x0[2]))
                   /tau/tau/tau);
     dfdt += C0_slope;
     return dfdt;
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  TemporalRamp
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   TemporalRamp::TemporalRamp(int narg, double* args) 
     : XT_Function(narg,args)
   {
     f_initial = args[0];
     double f_final = args[1];
     double delta_t = args[2];
     slope = (f_final - f_initial)/delta_t;
     tag_ = "temporal_ramp";
   }
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  RadialPower
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   RadialPower::RadialPower(int narg, double* args) 
     : XT_Function(narg,args)
   {
     C0 = args[6];
     n = args[7];
     tag_ = "radial_power";
   }
 
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   //  InterpolationFunction
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   void InterpolationFunction::initialize(int npts, fstream &fileId, double coef)
   {  // read data
      npts_ = npts;
      xs_.reset(npts);
      fs_.reset(npts);
      fps_.reset(npts);
      double x,f,fp;
      int i = 0;
      while(fileId.good() && i < npts) {
        fileId >> x >> f >> fp;
        xs_(i)=x;
        fs_(i)=coef*f;
        fps_(i)=coef*fp;
        i++;
      }
      // scale tangents 
      double dx, dx0 = xs_(1)-xs_(0); 
      for (int i = 0; i < npts_ ; i++) {
        if      (i   == 0)     { dx = xs_(1)-xs_(0); }
        else if (i+1 == npts_) { dx = xs_(npts_-1)-xs_(npts_-2); }
        else { dx= 0.5*(xs_(i+1)-xs_(i-1)); }
        if (abs(dx-dx0) > 1.e-8) throw ATC_Error("InterpolationFunction::initialize non-uniform data spacing not handled currently");
        fps_(i) *= dx;
      }
      // options: calculate / adjust tangents for monotonicity
 
   }
 
   double InterpolationFunction::coordinate(double x, 
     double & f0, double & fp0, double & f1, double & fp1, double & inv_dx ) const
   {
     int i0 = xs_.index(x);
     int i1 = i0+1;
     if      (i0 < 0) {
       double x0 = xs_(0),   x1 = xs_(1);
       inv_dx = 1./(x1-x0); 
       fp0 = fp1 = fps_(0);
       f1 = fs_(0);
       f0 = fp0*(x-xs_(0))+f1;
       return 0;
     }
     else if (i1 >= npts_) {
       double x0 = xs_(npts_-2),   x1 = xs_(npts_-1);
       inv_dx = 1./(x1-x0); 
       fp0 = fp1 = fps_(i0);
       f0 = fs_(i0);
       f1 = fp0*(x-xs_(i0))+f0;
       return 1;
     }
     else {
       double x0 = xs_(i0),   x1 = xs_(i1);
       inv_dx = 1./(x1-x0); 
       f0  = fs_ (i0); f1  = fs_ (i1);
       fp0 = fps_(i0); fp1 = fps_(i1);
       double t = (x-x0)*inv_dx;
       return t;
     }
   }
   double InterpolationFunction::f(const double x) const
   {
     double f0,fp0,f1,fp1,inv_dx;
     double t = coordinate(x,f0,fp0,f1,fp1,inv_dx);
     double t2 = t*t; 
     double t3 = t*t2;
     double h00 = 2*t3 - 3*t2     + 1;
     double h10 =   t3 - 2*t2 + t;
     double h01 =-2*t3 + 3*t2;
     double h11 =   t3 -   t2;
     double f = h00 * f0 + h10 * fp0 + h01 * f1 + h11 * fp1;
     return f;
   }
   double InterpolationFunction::dfdt(const double x) const
   {
     double f0,fp0,f1,fp1,inv_dx;
     double t = coordinate(x,f0,fp0,f1,fp1,inv_dx);
     double t2 = t*t; 
     double d00 = 6*t2 - 6*t;
     double d10 = 3*t2 - 4*t + 1;
     double d01 =-6*t2 + 6*t;
     double d11 = 3*t2 - 2*t;
     double fp = d00 * f0 + d10 * fp0 + d01 * f1 + d11 * fp1;
     fp *= inv_dx;
     return fp;
   }
 }
diff --git a/lib/atc/GhostManager.cpp b/lib/atc/GhostManager.cpp
index 1f7fc8c83..3c9e54b4f 100644
--- a/lib/atc/GhostManager.cpp
+++ b/lib/atc/GhostManager.cpp
@@ -1,504 +1,785 @@
 // ATC transfer headers
 #include "GhostManager.h"
 #include "ATC_Method.h"
 #include "LammpsInterface.h"
 #include "ATC_Error.h"
 
+using std::vector;
+using std::set;
+using std::pair;
+using std::map;
+using std::stringstream;
+using ATC_Utility::to_string;
+
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class GhostManager
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   GhostManager::GhostManager(ATC_Method * atc) :
     ghostModifier_(NULL),
     atc_(atc),
     boundaryDynamics_(NO_BOUNDARY_DYNAMICS),
-    needReset_(true),
-    kappa_(0.),
-    gamma_(0.),
-    mu_(0.)
+    needReset_(true)
   {
     // do nothing
   }
   
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   GhostManager::~GhostManager()
   {
     if (ghostModifier_) delete ghostModifier_;
   }
 
   //--------------------------------------------------------
   //  modify
   //    parses inputs and modifies state of the integrator
   //--------------------------------------------------------
   bool GhostManager::modify(int narg, char **arg)
   {
     int argIndex = 0;
     
     /*! \page man_boundary_dynamics fix_modify AtC boundary_dynamics
       \section syntax
       fix_modify AtC boundary_dynamics < on | damped_harmonic | prescribed | coupled | none > [args] \n
       \section description
       Sets different schemes for controlling boundary atoms.  On will integrate the boundary atoms using the velocity-verlet algorithm.  Damped harmonic uses a mass/spring/dashpot for the boundary atoms with added arguments of the damping and spring constants followed by the ratio of the boundary type mass to the desired mass.  Prescribed forces the boundary atoms to follow the finite element displacement.  Coupled does the same.
       \section restrictions
       Boundary atoms must be specified.  When using swaps between internal and boundary atoms, the initial configuration must have already correctly partitioned the two.
       \section related
       \man_boundary
       \section default
       prescribed
       on
     */
     if (strcmp(arg[argIndex],"none")==0) {
       boundaryDynamics_ = NO_BOUNDARY_DYNAMICS;
       needReset_ = true;
       return true;
     }
     else if (strcmp(arg[argIndex],"on")==0) {
       boundaryDynamics_ = VERLET;
       needReset_ = true;
       return true;
     }
     else if (strcmp(arg[argIndex],"prescribed")==0) {
       boundaryDynamics_ = PRESCRIBED;
       needReset_ = true;
       return true;
     }
     else if (strcmp(arg[argIndex],"damped_harmonic")==0) {
       argIndex++;
-      kappa_ = atof(arg[argIndex++]);
-      gamma_ = atof(arg[argIndex++]);
-      mu_    = atof(arg[argIndex]);
+      kappa_.push_back(atof(arg[argIndex++]));
+      gamma_.push_back(atof(arg[argIndex++]));
+      mu_.push_back(atof(arg[argIndex]));
       boundaryDynamics_ = DAMPED_HARMONIC;
       needReset_ = true;
       return true;
     }
+    else if (strcmp(arg[argIndex],"damped_layers")==0) {
+      argIndex++;
+      while (argIndex < narg) {
+        kappa_.push_back(atof(arg[argIndex++]));
+        gamma_.push_back(atof(arg[argIndex++]));
+        mu_.push_back(atof(arg[argIndex++]));
+      }
+      
+      boundaryDynamics_ = DAMPED_LAYERS;
+      needReset_ = true;
+      return true;
+    }
     else if (strcmp(arg[argIndex],"coupled")==0) {
       boundaryDynamics_ = COUPLED;
-      kappa_ = 0.;
-      gamma_ = 0.;
-      mu_    = 0.;
+      kappa_.push_back(0.);
+      gamma_.push_back(0.);
+      mu_.push_back(0.);
       needReset_ = true;
       return true;
     }
 
     return false;
   }
 
   //--------------------------------------------------------
   //  construct_methods
   //    constructs the specific method to modify the ghosts
   //--------------------------------------------------------
   void GhostManager::construct_methods()
   {
     if (ghostModifier_) {
       delete ghostModifier_;
       ghostModifier_ = NULL;
     }
 
     if (!atc_->groupbit_ghost()) {
       ghostModifier_ = new GhostModifier(this);
       return;
     }
     
     switch (boundaryDynamics_) {
     case VERLET: {
       ghostModifier_ = new GhostModifier(this);
       ghostModifier_->set_integrate_atoms(true);
       break;
     }
     case PRESCRIBED: {
       ghostModifier_ = new GhostModifierPrescribed(this);
       break;
     }
     case COUPLED:
     case DAMPED_HARMONIC: {
       ghostModifier_ = new GhostModifierDampedHarmonic(this,kappa_,gamma_,mu_);
       ghostModifier_->set_integrate_atoms(true);
       break;
     }
+    case DAMPED_LAYERS: {
+      ghostModifier_ = new GhostModifierDampedHarmonicLayers(this,kappa_,gamma_,mu_);
+      ghostModifier_->set_integrate_atoms(true);
+      break;
+    }
     case SWAP: {
       // if regions based on element sets, use verlet on ghosts and swap ghosts and internal when they move between regions
       const std::string & internalElementSet(atc_->internal_element_set());
       if (internalElementSet.size() && (atc_->atom_to_element_map_type()==EULERIAN)) {
         LammpsInterface * lammpsInterface = LammpsInterface::instance();
         if (atc_->atom_to_element_map_frequency() % lammpsInterface->reneighbor_frequency() != 0) {
           throw ATC_Error("GhostManager::construct_methods - eulerian frequency and lammsp reneighbor frequency must be consistent to swap boundary and internal atoms");
         }
         ghostModifier_ = new GhostIntegratorSwap(this);
       }
       break;
     }
     case SWAP_VERLET: {
       // if regions based on element sets, use verlet on ghosts and swap ghosts and internal when they move between regions
       const std::string & internalElementSet(atc_->internal_element_set());
       if (internalElementSet.size() && (atc_->atom_to_element_map_type()==EULERIAN)) {
         LammpsInterface * lammpsInterface = LammpsInterface::instance();
         if (atc_->atom_to_element_map_frequency() % lammpsInterface->reneighbor_frequency() != 0) {
           throw ATC_Error("GhostManager::construct_methods - eulerian frequency and lammsp reneighbor frequency must be consistent to swap boundary and internal atoms");
         }
         ghostModifier_ = new GhostIntegratorSwap(this);
         ghostModifier_->set_integrate_atoms(true);
       }
       break;
     }
     default: {
       ghostModifier_ = new GhostModifier(this);
     }
     }
   }
   
   //--------------------------------------------------------
   //  construct_transfers
   //    sets/constructs all required dependency managed data
   //--------------------------------------------------------
   void GhostManager::construct_transfers()
   {
     ghostModifier_->construct_transfers();
   }
   
   //--------------------------------------------------------
   //  initialize
   //    initialize all data and variables before a run
   //--------------------------------------------------------
   void GhostManager::initialize()
   {
     ghostModifier_->initialize();
     needReset_ = false;
   }
 
   //--------------------------------------------------------
   //  pre_exchange
   //    makes any updates required before lammps exchanges
   //    atoms
   //--------------------------------------------------------
   void GhostManager::pre_exchange()
   {
     ghostModifier_->pre_exchange();
   }
   
   //--------------------------------------------------------
   //  initial_integrate_velocity
   //    velocity update in first part of velocity-verlet
   //--------------------------------------------------------
   void GhostManager::init_integrate_velocity(double dt)
   {
     ghostModifier_->init_integrate_velocity(dt);
   }
       
   //--------------------------------------------------------
   //  initial_integrate_position
   //    position update in first part of velocity-verlet
   //--------------------------------------------------------
   void GhostManager::init_integrate_position(double dt)
   {
     ghostModifier_->init_integrate_position(dt);
   }
 
   //--------------------------------------------------------
   //  post_init_integrate
   //    makes any updates required after first integration
   //--------------------------------------------------------
   void GhostManager::post_init_integrate()
   {
     ghostModifier_->post_init_integrate();
   }
 
   //--------------------------------------------------------
   //  final_integrate
   //    velocity update in second part of velocity-verlet
   //--------------------------------------------------------
   void GhostManager::final_integrate(double dt)
   {
     ghostModifier_->final_integrate(dt);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class GhostModifier
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   GhostModifier::GhostModifier(GhostManager * ghostManager) :
     ghostManager_(ghostManager),
     atomTimeIntegrator_(NULL),
     integrateAtoms_(false)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   GhostModifier::~GhostModifier()
   {
     if (atomTimeIntegrator_) delete atomTimeIntegrator_;
   }
 
   //--------------------------------------------------------
   //  construct_transfers
   //    sets/constructs all required dependency managed data
   //--------------------------------------------------------
   void GhostModifier::construct_transfers()
   {
     if (atomTimeIntegrator_) delete atomTimeIntegrator_;
     if (integrateAtoms_) {
       atomTimeIntegrator_ = new AtomTimeIntegratorType(ghostManager_->atc(),GHOST);
       atomTimeIntegrator_->construct_transfers();
     }
     else {
       atomTimeIntegrator_ = new AtomTimeIntegrator();
     }
 
   }
 
   //--------------------------------------------------------
   //  initial_integrate_velocity
   //    velocity update in first part of velocity-verlet
   //--------------------------------------------------------
   void GhostModifier::init_integrate_velocity(double dt)
   {
     atomTimeIntegrator_->init_integrate_velocity(dt);
   }
       
   //--------------------------------------------------------
   //  initial_integrate_position
   //    position update in first part of velocity-verlet
   //--------------------------------------------------------
   void GhostModifier::init_integrate_position(double dt)
   {
     atomTimeIntegrator_->init_integrate_position(dt);
   }
 
   //--------------------------------------------------------
   //  final_integrate
   //    velocity update in second part of velocity-verlet
   //--------------------------------------------------------
   void GhostModifier::final_integrate(double dt)
   {
     atomTimeIntegrator_->final_integrate(dt);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class GhostModifierPrescribed
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   GhostModifierPrescribed::GhostModifierPrescribed(GhostManager * ghostManager) :
     GhostModifier(ghostManager),
     atomPositions_(NULL),
     atomFeDisplacement_(NULL),
     atomRefPositions_(NULL)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  construct_transfers
   //    sets/constructs all required dependency managed data
   //--------------------------------------------------------
   void GhostModifierPrescribed::construct_transfers()
   {
     GhostModifier::construct_transfers();
 
     InterscaleManager & interscaleManager((ghostManager_->atc())->interscale_manager());
     atomPositions_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_POSITION,GHOST);
 
     // prolongation from displacement field to atoms
     PerAtomSparseMatrix<double> * atomShapeFunctions = interscaleManager.per_atom_sparse_matrix("InterpolantGhost");
     if (!atomShapeFunctions) {
       atomShapeFunctions = new PerAtomShapeFunction(ghostManager_->atc(),
                                                     interscaleManager.per_atom_quantity("AtomicGhostCoarseGrainingPositions"),
                                                     interscaleManager.per_atom_int_quantity("AtomGhostElement"),
                                                     GHOST);
       interscaleManager.add_per_atom_sparse_matrix(atomShapeFunctions,"InterpolantGhost");
     }
     atomFeDisplacement_ = new FtaShapeFunctionProlongation(ghostManager_->atc(),
                                                            &(ghostManager_->atc())->field(DISPLACEMENT),
                                                            atomShapeFunctions,
                                                            GHOST);
     interscaleManager.add_per_atom_quantity(atomFeDisplacement_,field_to_prolongation_name(DISPLACEMENT)+"Ghost");
     
     atomRefPositions_ = interscaleManager.per_atom_quantity("AtomicGhostCoarseGrainingPositions");
   }
       
   //--------------------------------------------------------
   //  post_init_integrate
   //    after integration, fix ghost atoms' positions
   //--------------------------------------------------------
   void GhostModifierPrescribed::post_init_integrate()
   {
     const DENS_MAT & atomFeDisplacement(atomFeDisplacement_->quantity());
     const DENS_MAT & atomRefPositions(atomRefPositions_->quantity());
     *atomPositions_ = atomFeDisplacement + atomRefPositions;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class GhostModifierDampedHarmonic
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   GhostModifierDampedHarmonic::GhostModifierDampedHarmonic(GhostManager * ghostManager,
-                                                           double kappa,
-                                                           double gamma, double mu) :
+                                                           const vector<double> & kappa,
+                                                           const vector<double> & gamma,
+                                                           const vector<double> & mu) :
     GhostModifierPrescribed(ghostManager),
     atomVelocities_(NULL),
     atomFeVelocity_(NULL),
     atomForces_(NULL),
     kappa_(kappa),
     gamma_(gamma),
     mu_(mu)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  construct_transfers
   //    sets/constructs all required dependency managed data
   //--------------------------------------------------------
   void GhostModifierDampedHarmonic::construct_transfers()
   {
     GhostModifierPrescribed::construct_transfers();
     
     InterscaleManager & interscaleManager((ghostManager_->atc())->interscale_manager());
     atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,GHOST);
     atomForces_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_FORCE,GHOST);
 
     // prolongation from displacement field to atoms
     PerAtomSparseMatrix<double> * atomShapeFunctions = interscaleManager.per_atom_sparse_matrix("InterpolantGhost");
     atomFeVelocity_ = new FtaShapeFunctionProlongation(ghostManager_->atc(),
                                                        &(ghostManager_->atc())->field(VELOCITY),
                                                        atomShapeFunctions,
                                                        GHOST);
     interscaleManager.add_per_atom_quantity(atomFeVelocity_,field_to_prolongation_name(VELOCITY)+"Ghost");
     // calculate nominal bond stiffness
     int i = 0, j = 1;// HACk should be an atom and its neighbor in the boundary
     double rsq = 0.0;
     //k0_ = LammpsInterface_->bond_stiffness(i,j,rsq);
     k0_ = LammpsInterface::instance()->bond_stiffness(i,j,rsq);
   }
 
+#if true
   //--------------------------------------------------------
   //  initial_integrate_velocity
   //    velocity update in first part of velocity-verlet
   //--------------------------------------------------------
   void GhostModifierDampedHarmonic::init_integrate_velocity(double dt)
   {
-    atomTimeIntegrator_->init_integrate_velocity(mu_*dt);
+#if true
+    atomTimeIntegrator_->init_integrate_velocity(mu_[0]*dt);
+#else
+    atomTimeIntegrator_->init_integrate_velocity(dt);
+#endif
   }
       
   //--------------------------------------------------------
   //  initial_integrate_position
   //    position update in first part of velocity-verlet
   //--------------------------------------------------------
   void GhostModifierDampedHarmonic::init_integrate_position(double dt)
   {
     atomTimeIntegrator_->init_integrate_position(dt);
   }
-
+#endif
   //--------------------------------------------------------
   //  final_integrate
   //    velocity update in second part of velocity-verlet
   //--------------------------------------------------------
   void GhostModifierDampedHarmonic::final_integrate(double dt)
   {
 
     const DENS_MAT & atomPositions(atomPositions_->quantity());
     const DENS_MAT & atomVelocities(atomVelocities_->quantity());
     const DENS_MAT & atomFeDisplacement(atomFeDisplacement_->quantity());
     const DENS_MAT & atomFeVelocity(atomFeVelocity_->quantity());
     const DENS_MAT & atomRefPositions(atomRefPositions_->quantity());
 
     _forces_ = atomFeDisplacement;
     _forces_ += atomRefPositions;
     _forces_ -= atomPositions;
-    _forces_ *= kappa_;
-    _forces_ += gamma_*(atomFeVelocity - atomVelocities);
+    _forces_ *= kappa_[0];
+    _forces_ += gamma_[0]*(atomFeVelocity - atomVelocities);
+#if true
+#else
+    _forces_ *= 1./mu_[0];
+#endif
     *atomForces_ = _forces_;
 
-    atomTimeIntegrator_->final_integrate(mu_*dt);
+#if true
+    atomTimeIntegrator_->final_integrate(mu_[0]*dt);
+#else
+    atomTimeIntegrator_->final_integrate(dt);
+#endif
+  }
+
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class GhostModifierDampedHarmonicLayers
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  
+  //--------------------------------------------------------
+  //  Constructor
+  //--------------------------------------------------------
+  GhostModifierDampedHarmonicLayers::GhostModifierDampedHarmonicLayers(GhostManager * ghostManager,
+                                                                       const vector<double> & kappa,
+                                                                       const vector<double> & gamma,
+                                                                       const vector<double> & mu) :
+    GhostModifierDampedHarmonic(ghostManager,kappa,gamma,mu),
+    ghostToBoundaryDistance_(NULL),
+    layerId_(NULL)
+  {
+   
+    // do nothing
+  }
+
+  //--------------------------------------------------------
+  //  construct_transfers
+  //    sets/constructs all required dependency managed data
+  //--------------------------------------------------------
+  void GhostModifierDampedHarmonicLayers::construct_transfers()
+  {
+    GhostModifierDampedHarmonic::construct_transfers();
+    
+    InterscaleManager & interscaleManager((ghostManager_->atc())->interscale_manager());
+
+    // transfer for distance to boundary
+    ghostToBoundaryDistance_ = new AtcAtomQuantity<double>(ghostManager_->atc(),
+                                                           1,GHOST);
+    interscaleManager.add_per_atom_quantity(ghostToBoundaryDistance_,
+                                            "GhostToBoundaryDistance");
+
+    // transfer from ghost atom to its layer id
+    layerId_ = new AtcAtomQuantity<int>(ghostManager_->atc(),
+                                        1,GHOST);
+    interscaleManager.add_per_atom_int_quantity(layerId_,"GhostLayerId");
+  }
+
+  //--------------------------------------------------------
+  //  initialize
+  //    initialize all data and variables before a run
+  //--------------------------------------------------------
+  void GhostModifierDampedHarmonicLayers::initialize()
+  {
+     compute_distances();
+     int nlayers = find_layers();
+     if (nlayers > ((int)gamma_.size())) throw ATC_Error("GhostModifierDampedHarmonicLayers::initialize not enough damping factors specfied " + to_string(gamma_.size()));
+  }
+
+  //--------------------------------------------------------
+  //  find atomic mononlayers
+  //--------------------------------------------------------
+  bool compare( pair<int,double> a, pair<int,double> b) { 
+    return (a.second < b.second);
+  }
+  int GhostModifierDampedHarmonicLayers::find_layers()
+  {
+    DENS_MAT & d(ghostToBoundaryDistance_->set_quantity());
+    DenseMatrix<int> & ids = layerId_->set_quantity();
+    
+    // get distances for every ghost atom for sorting
+    // size arrays of length number of processors
+    int commSize = LammpsInterface::instance()->comm_size();
+    int * procCounts = new int[commSize];
+    int * procOffsets = new int[commSize];
+
+    // get size information from all processors
+    int localGhosts = d.nRows();
+    LammpsInterface::instance()->int_allgather(localGhosts,procCounts);
+    procOffsets[0] = 0;
+    int totalGhosts = 0;
+    for (int i = 0; i < commSize-1; ++i) {
+      totalGhosts += procCounts[i];
+      procOffsets[i+1] = totalGhosts;
+    }
+    totalGhosts += procCounts[commSize-1];
+    double * globalDistances = new double[totalGhosts];
+
+    // allgather distances
+    LammpsInterface::instance()->allgatherv(d.ptr(), localGhosts,
+                                            globalDistances, procCounts, procOffsets);
+
+    // add to distances vector with -1 ids
+    // convert to STL for sort
+    vector< pair <int,double> > distances;
+    distances.resize(totalGhosts);
+    int myRank = LammpsInterface::instance()->comm_rank();
+    int j = 0;
+    for (int i = 0; i < totalGhosts; ++i) {
+      if (i >= procOffsets[myRank] && i < procOffsets[myRank] + procCounts[myRank]) {
+        distances[i] = pair <int,double> (j++,globalDistances[i]);
+      }
+      else {
+        distances[i] = pair <int,double> (-1,globalDistances[i]);
+      }
+    }
+    delete [] globalDistances;
+    delete [] procCounts;
+    delete [] procOffsets;
+
+    std::sort(distances.begin(),distances.end(),compare);
+    double min = (distances[0]).second;
+    double a = LammpsInterface::instance()->max_lattice_constant();
+    double tol = a/4;
+    double xlayer = min; // nominal position of layer
+    int ilayer =0;
+    vector<int> counts(1);
+    counts[0] = 0;
+    for (vector<pair<int,double> >::const_iterator itr = distances.begin();
+         itr != distances.end(); itr++) {
+       int id = (*itr).first;
+       double d = (*itr).second;
+       if (fabs(d-xlayer) > tol) {
+         counts.push_back(0);
+         ilayer++;
+         xlayer = d;
+       }
+       if (id > -1) {
+         ids(id,0) = ilayer;
+       }
+       counts[ilayer]++;
+    }
+    int nlayers = ilayer;
+    stringstream msg;
+    msg << nlayers << " boundary layers:\n";
+    for (int i = 0; i < nlayers; ++i) {
+      msg << i+1 << ": " << counts[i] << "\n";
+    }
+    ATC::LammpsInterface::instance()->print_msg_once(msg.str());
+    return nlayers;
+  }
+   
+  //--------------------------------------------------------
+  //  compute distances to boundary faces
+  //--------------------------------------------------------
+  void GhostModifierDampedHarmonicLayers::compute_distances()
+  {
+    // get fe mesh
+    const FE_Mesh * feMesh = ((ghostManager_->atc())->fe_engine())->fe_mesh();
+    InterscaleManager & interscaleManager((ghostManager_->atc())->interscale_manager());
+
+    // get elements in which ghosts reside
+    const DenseMatrix<int> & elementHasGhost((interscaleManager.dense_matrix_int("ElementHasGhost"))->quantity());
+    // get type of each node
+    const DenseMatrix<int> & nodeType((interscaleManager.dense_matrix_int("NodalGeometryType"))->quantity());
+
+    // create map from those elements to pair<DENS_VEC,DENS_VEC> (centroid, normal)
+    map<int, pair<DENS_VEC,DENS_VEC> > elementToFace;
+    int nsd = (ghostManager_->atc())->nsd();
+    int nfe = feMesh->num_faces_per_element();
+    DENS_MAT nodalCoords(nsd,nfe);
+    DENS_VEC centroid(nsd), normal(nsd);
+    Array<int> faceNodes;
+    bool isBoundaryFace;
+    for (int elt = 0; elt < elementHasGhost.nRows(); ++elt) {
+      if (elementHasGhost(elt,0)) {
+        // loop over all faces
+        int face;
+        for (face = 0; face < nfe; ++face) {
+          // get the nodes in a face
+          feMesh->face_connectivity_unique(PAIR(elt,face),faceNodes);
+
+          // identify the boundary face by the face which contains only boundary nodes
+          isBoundaryFace = true; 
+          for (int i = 0; i < faceNodes.size(); ++i) {
+            if (nodeType(faceNodes(i),0) != BOUNDARY) {
+              isBoundaryFace = false;
+              break;
+            }
+          }
+
+          if (isBoundaryFace) {
+            break;
+          }
+        }
+        if (face == nfe) {
+          throw ATC_Error("GhostModifierDampedHarmonicLayers::initialize - Could not find boundary face for element " + to_string(elt));
+        }
+
+        // for each boundary face get the centroid by the average position of the nodes comprising it
+        feMesh->face_coordinates(PAIR(elt,face),nodalCoords);
+        centroid = 0.;
+        for (int i = 0; i < nodalCoords.nRows(); ++i) {
+          for (int j = 0; j < nodalCoords.nCols(); ++j) {
+            centroid(i) += nodalCoords(i,j);
+          }
+        }
+        centroid *= -1./double(nfe); // -1 gets outward normal from ATC region => all distances should be > 0
+        
+        // for each boundary face get the normal
+        // ASSUMES all faces are planar
+        feMesh->face_normal(PAIR(elt,face),0,normal);
+
+        elementToFace[elt] = pair<DENS_VEC,DENS_VEC>(centroid,normal);
+      }
+    }
+
+    // for each atom compute (atom_pos - element->face_centroid) dot element_->face_normal
+    // get atom to element map for ghosts
+    PerAtomQuantity<int> * ghostToElementMap = interscaleManager.per_atom_int_quantity("AtomGhostElement");
+    const DenseMatrix<int> & ghostToElement(ghostToElementMap->quantity());
+    DENS_MAT & distance(ghostToBoundaryDistance_->set_quantity());
+    const DENS_MAT & atomPositions(atomPositions_->quantity());
+    DENS_VEC diff(nsd);
+    for (int i = 0; i < distance.nRows(); ++i) {
+      int elt = ghostToElement(i,0);
+      const DENS_VEC & c(elementToFace[elt].first);
+      const DENS_VEC & n(elementToFace[elt].second);
+      for (int j = 0; j < nsd; ++j) {
+        diff(j) = atomPositions(i,j) - c(j);
+      }
+      distance(i,0) = diff.dot(n); // should always be positive
+    }
+  }
+
+  
+  //--------------------------------------------------------
+  //  final_integrate
+  //    velocity update in second part of velocity-verlet
+  //--------------------------------------------------------
+  void GhostModifierDampedHarmonicLayers::final_integrate(double dt)
+  {
+
+    const DENS_MAT & atomPositions(atomPositions_->quantity());
+    const DENS_MAT & atomVelocities(atomVelocities_->quantity());
+    const DENS_MAT & atomFeDisplacement(atomFeDisplacement_->quantity());
+    const DENS_MAT & atomFeVelocity(atomFeVelocity_->quantity());
+    const DENS_MAT & atomRefPositions(atomRefPositions_->quantity());
+
+    _forces_ = atomFeDisplacement;
+    _forces_ += atomRefPositions;
+    _forces_ -= atomPositions;
+
+    _forces_ *= kappa_[0];
+    _forces_ += gamma_[0]*(atomFeVelocity - atomVelocities);
+    _forces_ *= 1./mu_[0];
+    *atomForces_ = _forces_;
+
+    atomTimeIntegrator_->final_integrate(dt);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class GhostIntegratorVerletSwap
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   GhostIntegratorSwap::GhostIntegratorSwap(GhostManager * ghostManager) :
     GhostModifier(ghostManager),
     lammpsInterface_(LammpsInterface::instance()),
     elementSet_((((ghostManager_->atc())->fe_engine())->fe_mesh())->elementset((ghostManager_->atc())->internal_element_set())),
     atomElement_(NULL),
     atomGhostElement_(NULL),
     internalToAtom_((ghostManager_->atc())->internal_to_atom_map()),
     ghostToAtom_((ghostManager_->atc())->ghost_to_atom_map()),
     groupbit_((ghostManager_->atc())->groupbit()),
     groupbitGhost_((ghostManager_->atc())->groupbit_ghost())
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  construct_transfers
   //    sets/constructs all required dependency managed data
   //--------------------------------------------------------
   void GhostIntegratorSwap::construct_transfers()
   {
     GhostModifier::construct_transfers();
 
     InterscaleManager & interscaleManager((ghostManager_->atc())->interscale_manager());
     atomElement_ = interscaleManager.per_atom_int_quantity("AtomElement");
     atomGhostElement_ = interscaleManager.per_atom_int_quantity("AtomGhostElement");
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initialize all data and variables before a run
   //--------------------------------------------------------
   void GhostIntegratorSwap::initialize()
   {
     if ((ghostManager_->atc())->atom_to_element_map_frequency() % lammpsInterface_->reneighbor_frequency() != 0) {
       throw ATC_Error("GhostIntegratorSwap::initialize - AtC Eulerian reset frequency must be a multiple of the Lammps reneighbor frequency when using internal/boundary atom swapping");
     }
   }
 
   //--------------------------------------------------------
   //  pre_exchange
   //    swaps atoms between types depending on region
   //--------------------------------------------------------
   void GhostIntegratorSwap::pre_exchange()
   {
     // lammps mask to change type
     int * mask = lammpsInterface_->atom_mask();
 
     const DenseMatrix<int> & atomElement(atomElement_->quantity());
     for (int i = 0; i < atomElement.nRows(); ++i) {
       if (elementSet_.find(atomElement(i,0)) == elementSet_.end()) {
         mask[internalToAtom_(i)] |= groupbitGhost_;
         // remove from internal
       }
     }
   }
 };
diff --git a/lib/atc/GhostManager.h b/lib/atc/GhostManager.h
index c146644db..9c3bbbe93 100644
--- a/lib/atc/GhostManager.h
+++ b/lib/atc/GhostManager.h
@@ -1,327 +1,383 @@
 #ifndef GHOST_MANAGER_H
 #define GHOST_MANAGER_H
 
 // ATC headers
 #include "MatrixLibrary.h"
 #include "PerAtomQuantityLibrary.h"
 #include "TimeIntegrator.h"
 #include "ATC_TypeDefs.h"
 
 namespace ATC {
 
   // forward declarations
   class ATC_Method;
   class GhostModifier;
   class LammpsInterface;
 
   /**
    *  @class  GhostManager
    *  @brief  Manages methods for modifying ghost atoms
    */
 
   class GhostManager {
 
   public:
 
     /** types of ghost boundary conditions in momentum */
     enum BoundaryDynamicsType {
       NO_BOUNDARY_DYNAMICS=0,
-      VERLET,
-      PRESCRIBED,
-      DAMPED_HARMONIC,
-      COUPLED,
-      SWAP,
-      SWAP_VERLET
+      VERLET,  // performs velocity-verlet 
+      PRESCRIBED,  // forces ghost locations to conform to interpolated finite element locations
+      DAMPED_HARMONIC, // turns ghost atoms into spring-mass-dashpot systems
+      DAMPED_LAYERS, // oer layer DAMPED_HARMONIC
+      COUPLED,  // applies a spring-dashpot force to the ghosts
+      SWAP, // exchanges ghost and real atoms when they cross AtC boundaries
+      SWAP_VERLET // like above, but integrates the ghosts using velocity verlet
     };
 
     // constructor
     GhostManager(ATC_Method * atc);
 
     // destructor
     virtual ~GhostManager();
 
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
 
     /** create objects to implement requested numerical method */
     virtual void construct_methods();
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers();
 
     /** pre time integration initialization of data */
     virtual void initialize();
 
     /** prior to lammps exchange */
     virtual void pre_exchange();
 
     /** Predictor phase, Verlet first step for velocity */
     virtual void init_integrate_velocity(double dt);
 
     /** Predictor phase, Verlet first step for position */
     virtual void init_integrate_position(double dt);
 
     /** set positions after integration */
     virtual void post_init_integrate();
 
     /** Corrector phase, Verlet second step for velocity */
     virtual void final_integrate(double dt);
 
     /** sets the boundary dynamics flag as desired */
     void set_boundary_dynamics(BoundaryDynamicsType boundaryDynamics) {boundaryDynamics_ = boundaryDynamics;}
 
     /** flag for reset */
     bool need_reset() const {return needReset_;};
 
     /** access to ATC method object */
     ATC_Method * atc() {return atc_;};
 
   protected:
 
     /** pointer to routines that modify ghosts */
     GhostModifier* ghostModifier_;
 
     /** pointer to access ATC methods */
     ATC_Method * atc_;
 
     /** boundary dynamics method type */
     BoundaryDynamicsType boundaryDynamics_;
 
     /** flag for reset */
     bool needReset_;
 
     /** spring constant for some models */
-    double kappa_;
+    std::vector<double> kappa_;
 
     /** damping constant for some models */
-    double gamma_;
+    std::vector<double> gamma_;
 
     /** ratio between mass of ghost types and desired mass for some models */
-    double mu_;
+    std::vector<double> mu_;
 
   private:
 
     // DO NOT define this
     GhostManager();
 
   };
 
   /**
    *  @class  GhostModifier
    *  @brief  Base class for objects which modify the ghost atoms, integrates ghost atoms using velocity-verlet if requested
    */
 
   class GhostModifier {
   
   public:
 
     // constructor
     GhostModifier(GhostManager * ghostManager);
 
     // destructor
     virtual ~GhostModifier();
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers();
 
     /** pre time integration initialization of data */
     virtual void initialize(){};
 
     /** Predictor phase, Verlet first step for velocity */
     virtual void init_integrate_velocity(double dt);
 
     /** Predictor phase, Verlet first step for position */
     virtual void init_integrate_position(double dt);
 
     /** set positions after integration */
     virtual void post_init_integrate(){};
 
     /** prior to lammps exchange */
     virtual void pre_exchange(){};
 
     /** Corrector phase, Verlet second step for velocity */
     virtual void final_integrate(double dt);
 
     /** sets the verlet integration flag as desired */
     void set_integrate_atoms(bool integrateAtoms) {integrateAtoms_ = integrateAtoms;}
 
   protected:
 
     /** owning ghost manager */
     GhostManager * ghostManager_;
 
     /** object which integrates atoms */
     AtomTimeIntegrator * atomTimeIntegrator_;
 
     /** flag to perform velocity-verlet integration of ghosts */
     bool integrateAtoms_;
 
 
   private:
 
     // DO NOT define this
     GhostModifier();
 
   };
 
   /**
    *  @class  GhostModifierPrescribed
    *  @brief  sets ghost atom positions based on FE displacement
    */
 
   class GhostModifierPrescribed : public GhostModifier {
   
   public:
 
     // constructor
     GhostModifierPrescribed(GhostManager * ghostManager);
 
     // destructor
     virtual ~GhostModifierPrescribed(){};
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers();
 
     /** set positions after integration */
     virtual void post_init_integrate();
 
   protected:
 
     /** positions of atoms */
     PerAtomQuantity<double> * atomPositions_;
 
     /** FE displacement at ghost locations */
     PerAtomQuantity<double> * atomFeDisplacement_;
 
     /** atom reference positions */
     PerAtomQuantity<double> * atomRefPositions_;
 
   private:
 
     // DO NOT define this
     GhostModifierPrescribed();
 
   };
 
   /**
    *  @class  GhostModifierDampedHarmonic
    *  @brief  Integrates ghost atoms using velocity-verlet with a damped harmonic force
    */
 
   class GhostModifierDampedHarmonic : public GhostModifierPrescribed {
   
   public:
 
     // constructor
     GhostModifierDampedHarmonic(GhostManager * ghostManager,
-                                double kappa_, double gamma, double mu);
+                                const std::vector<double> & kappa,
+                                const std::vector<double> & gamma,
+                                const std::vector<double> & mu);
 
     // destructor
     virtual ~GhostModifierDampedHarmonic(){};
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers();
-
+#if true
     /** Predictor phase, Verlet first step for velocity */
     virtual void init_integrate_velocity(double dt);
 
     /** Predictor phase, Verlet first step for position */
     virtual void init_integrate_position(double dt);
-
+#endif
     /** set positions after integration */
     virtual void post_init_integrate(){};
 
     /** Corrector phase, Verlet second step for velocity */
     virtual void final_integrate(double dt);
 
   protected:
 
     /** velocities of atoms */
     PerAtomQuantity<double> * atomVelocities_;
 
     /** FE velocity at ghost locations */
     PerAtomQuantity<double> * atomFeVelocity_;
 
     /** atom forces */
     PerAtomQuantity<double> * atomForces_;
 
+    /** effective spring constant for potential */
+    double k0_;
+
     /** spring constant */
-    double kappa_, k0_;
+    const std::vector<double> & kappa_;
 
     /** damping constant */
-    double gamma_;
+    const std::vector<double> & gamma_;
 
     /** ratio between mass of ghost types and desired mass */
-    double mu_;
+    const std::vector<double> & mu_;
 
     // workspace
     DENS_MAT _forces_;
 
   private:
 
     // DO NOT define this
     GhostModifierDampedHarmonic();
 
   };
 
+  /**
+   *  @class  GhostModifierDampedHarmonicLayers
+   *  @brief  Integrates ghost atoms using velocity-verlet with a damped harmonic force based on which layer the atom resides in
+   */
+
+  class GhostModifierDampedHarmonicLayers : public GhostModifierDampedHarmonic {
+  
+  public:
+
+    // constructor
+    GhostModifierDampedHarmonicLayers(GhostManager * ghostManager,
+                                      const std::vector<double> & kappa,
+                                      const std::vector<double> & gamma,
+                                      const std::vector<double> & mu);
+
+    // destructor
+    virtual ~GhostModifierDampedHarmonicLayers(){};
+
+    /** create and get necessary transfer operators */
+    virtual void construct_transfers();
+
+    /** pre time integration initialization of data */
+    virtual void initialize();
+
+    /** Corrector phase, Verlet second step for velocity */
+    virtual void final_integrate(double dt);
+
+  protected:
+
+    // methods
+    /** compute distance of ghost atom to boundary */
+    void compute_distances();
+    /** sorting heuristics to identify layers */
+    int find_layers();
+
+    // data
+    /** distance from all ghost atoms to boundary, i.e. boundary face of containing element */
+    PerAtomQuantity<double> * ghostToBoundaryDistance_;
+    
+    /** layer id for ghost atoms */
+    PerAtomQuantity<int> * layerId_;
+
+  private:
+
+    // DO NOT define this
+    GhostModifierDampedHarmonicLayers();
+
+  };
+
+
   /**
    *  @class  GhostIntegratorSwap
    *  @brief  Integrates ghost atoms using velocity-verlet, and swaps atoms between ghost
    *          and internal depending on what element they are in
    */
 
   class GhostIntegratorSwap : public GhostModifier {
   
   public:
 
     // constructor
     GhostIntegratorSwap(GhostManager * ghostManager);
 
     // destructor
     virtual ~GhostIntegratorSwap(){};
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers();
 
     /** pre time integration initialization of data */
     virtual void initialize();
 
     /** prior to lammps exchange */
     virtual void pre_exchange();
 
   protected:
 
     /** pointer to lammps interface */
     LammpsInterface * lammpsInterface_;
 
     /** internal element set */
     const std::set<int> & elementSet_;
 
     /** internal to element map */
     PerAtomQuantity<int> * atomElement_;
     
     /** ghost to element map */
     PerAtomQuantity<int> * atomGhostElement_;
 
     /** internal to atom map */
     const Array<int> & internalToAtom_;
 
     /** ghost to atom map */
     const Array<int> & ghostToAtom_;
 
     /** group bit for internal */
     int groupbit_;
 
     /** group bit for ghost */
     int groupbitGhost_;
 
   private:
 
     // DO NOT define this
     GhostIntegratorSwap();
 
   };
 
 
 };
 #endif
diff --git a/lib/atc/ImplicitSolveOperator.cpp b/lib/atc/ImplicitSolveOperator.cpp
index 93ee362e5..d66da8a0e 100644
--- a/lib/atc/ImplicitSolveOperator.cpp
+++ b/lib/atc/ImplicitSolveOperator.cpp
@@ -1,160 +1,200 @@
 // Header file for this class
 #include "ImplicitSolveOperator.h"
 
 // Other ATC includes
 #include "ATC_Coupling.h"
 #include "FE_Engine.h"
 #include "PhysicsModel.h"
 #include "PrescribedDataManager.h"
 
+
+using std::set;
+using std::vector;
+
 namespace ATC {
 
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 //  ImplicitSolveOperator
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 ImplicitSolveOperator::
-ImplicitSolveOperator(ATC_Coupling * atc,
-                      /*const*/ FE_Engine * feEngine,
-                      const PhysicsModel * physicsModel)
-  : atc_(atc),
-    feEngine_(feEngine),
-    physicsModel_(physicsModel)
-{
-  // Nothing else to do here
-}
-
-// --------------------------------------------------------------------
-// --------------------------------------------------------------------
-//  FieldImplicitSolveOperator
-// --------------------------------------------------------------------
-// --------------------------------------------------------------------
-FieldImplicitSolveOperator::
-FieldImplicitSolveOperator(ATC_Coupling * atc,
-                           /*const*/ FE_Engine * feEngine,
-                           FIELDS & fields,
-                           const FieldName fieldName,
-                           const Array2D< bool > & rhsMask,
-                           const PhysicsModel * physicsModel,
-                           double simTime,
-                           double dt,
-                           double alpha)
-  : ImplicitSolveOperator(atc, feEngine, physicsModel),
-    fieldName_(fieldName),
-    fields_(fields), // ref to fields
-    time_(simTime),
+ImplicitSolveOperator(double alpha, double dt)
+  : n_(0),
+    dof_(0),
     dt_(dt),
     alpha_(alpha),
     epsilon0_(1.0e-8)
 {
-  // find field associated with ODE
-  rhsMask_.reset(NUM_FIELDS,NUM_FLUX);
-  rhsMask_ = false;
-  for (int i = 0; i < rhsMask.nCols(); i++) {
-    rhsMask_(fieldName_,i) =  rhsMask(fieldName_,i);
-  }
-  massMask_.reset(1);
-  massMask_(0) = fieldName_;
-
-  // Save off current field
-  TnVect_ = column(fields_[fieldName_].quantity(),0); 
-
-  // Allocate vectors for fields and rhs
-  int nNodes = atc_->num_nodes();
-  // copy fields
-  fieldsNp1_ = fields_;
-  // size rhs
-  int dof = fields_[fieldName_].nCols();
-  RnMap_ [fieldName_].reset(nNodes,dof);
-  RnpMap_[fieldName_].reset(nNodes,dof);
- 
-  // Compute the RHS vector R(T^n) 
-  // Set BCs on Rn, multiply by inverse mass and then extract its vector
-  atc_->compute_rhs_vector(rhsMask_, fields_, RnMap_,
-                                   FULL_DOMAIN, physicsModel_);
-  DENS_MAT & Rn = RnMap_[fieldName_].set_quantity();
-  atc_->prescribed_data_manager()
-    ->set_fixed_dfield(time_, fieldName_, Rn);
-  atc_->apply_inverse_mass_matrix(Rn,fieldName_);
-  RnVect_ = column(Rn,0);
+  // Nothing else to do here
 }
 
-
 // --------------------------------------------------------------------
-//  operator *(Vector)
+//  operator *
 // --------------------------------------------------------------------
 DENS_VEC
-FieldImplicitSolveOperator::operator * (DENS_VEC x) const
+ImplicitSolveOperator::operator * (const DENS_VEC & x) const
 {
   // This method uses a matrix-free approach to approximate the
   // multiplication by matrix A in the matrix equation Ax=b, where the
   // matrix equation results from an implicit treatment of the
-  // fast field solve for the Two Temperature Model.  In
-  // brief, if the ODE for the fast field can be written:
+  // fast field. In brief, if the ODE for the fast field can be written:
   //
-  //  dT/dt = R(T)
+  //  dx/dt = R(x)
   // 
   // A generalized discretization can be written:
   //
-  //  1/dt * (T^n+1 - T^n) = alpha * R(T^n+1) + (1-alpha) * R(T^n)
+  //  1/dt * (x^n+1 - x^n) = alpha * R(x^n+1) + (1-alpha) * R(x^n)
   //
-  // Taylor expanding the R(T^n+1) term and rearranging gives the
-  // equation to be solved for dT at each timestep:
+  // Taylor expanding the R(x^n+1) term and rearranging gives the
+  // equation to be solved for dx at each timestep:
   //
-  //  [1 - dt * alpha * dR/dT] * dT = dt * R(T^n)
+  //  [1 - dt * alpha * dR/dx] * dx = dt * R(x^n)
   //
   // The operator defined in this method computes the left-hand side,
-  // given a vector dT.  It uses a finite difference, matrix-free
-  // approximation of dR/dT * dT, giving:
+  // given a vector dx.  It uses a finite difference, matrix-free
+  // approximation of dR/dx * dx, giving:
   //
-  //  [1 - dt * alpha * dR/dT] * dT = dt * R(T^n)
-  //      ~=  dT - dt*alpha/epsilon * ( R(T^n + epsilon*dT) - R(T^n) )
+  //  [1 - dt * alpha * dR/dx] * dx = dt * R(x^n)
+  //      ~=  dx - dt*alpha/epsilon * ( R(x^n + epsilon*dx) - R(x^n) )
   //
-  
-  
   // Compute epsilon
-  double epsilon = (x.norm() > 0.0) ? epsilon0_ * TnVect_.norm()/x.norm() : epsilon0_;
-
-  // Compute incremented vector = T + epsilon*dT
-  fieldsNp1_[fieldName_] = TnVect_ + epsilon * x;
-
-  // Evaluate R(b)
-  atc_->compute_rhs_vector(rhsMask_, fieldsNp1_, RnpMap_,
-                                   FULL_DOMAIN, physicsModel_);
-  DENS_MAT & Rnp = RnpMap_[fieldName_].set_quantity();
-  atc_->prescribed_data_manager()
-    ->set_fixed_dfield(time_, fieldName_, Rnp);
-  atc_->apply_inverse_mass_matrix(Rnp,fieldName_);
-  RnpVect_ = column(Rnp,0);
-
+  double epsilon = (x.norm()>0.0) ? epsilon0_*x0_.norm()/x.norm():epsilon0_;
+  // Compute incremented vector x^n+1 = x^n + epsilon*dx
+  x_ = x0_ + epsilon * x;
+  // Evaluate R(x)
+  this->R(x_,R_);
   // Compute full left hand side and return it
-  DENS_VEC Ax = x - dt_ * alpha_ / epsilon * (RnpVect_ - RnVect_);
+  DENS_VEC Ax = x - dt_ * alpha_ / epsilon * (R_ - R0_);
   return Ax;
 }
 
 // --------------------------------------------------------------------
-//  rhs
+//  rhs of Ax = r
 // --------------------------------------------------------------------
 DENS_VEC
-FieldImplicitSolveOperator::rhs()
+ImplicitSolveOperator::r() const
 {
-  // Return dt * R(T^n)
-  return dt_ * RnVect_;
+  return dt_ * R0_; // dt * R(T^n)
 }
 
 // --------------------------------------------------------------------
 //  preconditioner
 // --------------------------------------------------------------------
 DIAG_MAT
-FieldImplicitSolveOperator::preconditioner(FIELDS & fields)
+ImplicitSolveOperator::preconditioner() const
+{
+  DENS_VEC diag(n_);
+  diag = 1.0;
+  DIAG_MAT preconditioner(diag);
+  return preconditioner;
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+//  FieldImplicitSolveOperator
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+FieldImplicitSolveOperator::
+FieldImplicitSolveOperator(ATC_Coupling * atc,
+                           FIELDS & fields,
+                           const FieldName fieldName,
+                           const Array2D< bool > & rhsMask,
+                           const PhysicsModel * physicsModel,
+                           double simTime,
+                           double dt,
+                           double alpha)
+  : ImplicitSolveOperator(alpha, dt),
+    fieldName_(fieldName),
+    atc_(atc),
+    physicsModel_(physicsModel),
+    fields0_(fields), // ref to fields
+    fields_ (fields), // copy of fields
+    rhsMask_(rhsMask),
+    time_(simTime)
 {
-  // Just create and return identity matrix
-  int nNodes = atc_->num_nodes();
-  DENS_VEC ones(nNodes);
-  ones = 1.0;
-  DIAG_MAT identity(ones);
-  return identity;
+  const DENS_MAT & f = fields0_[fieldName_].quantity();
+  dof_ = f.nCols();
+  if (dof_ > 1) throw ATC_Error("Implicit solver operator can only handle scalar fields");
+  // create all to free map
+  int nNodes = f.nRows();
+  set<int> fixedNodes_ = atc_->prescribed_data_manager()->fixed_nodes(fieldName_);
+  n_ = nNodes;
+  vector<bool> tag(nNodes); 
+  set<int>::const_iterator it;  int i = 0;
+  for (i = 0; i < nNodes; ++i) { tag[i] = true; }
+  for (it=fixedNodes_.begin();it!=fixedNodes_.end();++it) {tag[*it]=false;}
+  int m = 0;
+  for (i = 0; i < nNodes; ++i) { if (tag[i]) freeNodes_[i]= m++; }
+//std::cout << " nodes " << n_ << " " << nNodes << "\n";
+  
+  // Save current field
+  x0_.reset(n_);
+  to_free(f,x0_);
+  x_  = x0_; // initialize
+
+  // righthand side/forcing vector
+  rhsMask_.reset(NUM_FIELDS,NUM_FLUX);
+  rhsMask_ = false;
+  for (int i = 0; i < rhsMask.nCols(); i++) {
+    rhsMask_(fieldName_,i) =  rhsMask(fieldName_,i);
+  }
+//std::cout << print_mask(rhsMask_) << "\n";
+  massMask_.reset(1);
+  massMask_(0) = fieldName_;
+  rhs_[fieldName_].reset(nNodes,dof_);
+  // Compute the RHS vector R(T^n) 
+  R0_.reset(n_);
+  R_ .reset(n_);
+  R(x0_, R0_);
+}
+
+void FieldImplicitSolveOperator::to_all(const VECTOR &x, MATRIX &f) const
+{
+  f.reset(x.nRows(),1);
+  for (int i = 0; i < x.nRows(); ++i) {
+    f(i,0) = x(i);
+  }
+}
+void FieldImplicitSolveOperator::to_free(const MATRIX &r, VECTOR &v) const
+{
+  v.reset(r.nRows());
+  for (int i = 0; i < r.nRows(); ++i) {
+    v(i) = r(i,0);
+  }
+}
+void 
+FieldImplicitSolveOperator::R(const DENS_VEC &x, DENS_VEC &v ) const
+{
+  DENS_MAT & f = fields_[fieldName_].set_quantity();
+  atc_->prescribed_data_manager()->set_fixed_field(time_, fieldName_, f);
+  to_all(x,f);
+  atc_->compute_rhs_vector(rhsMask_,fields_,rhs_,FULL_DOMAIN,physicsModel_);
+  DENS_MAT & r = rhs_[fieldName_].set_quantity();
+  atc_->prescribed_data_manager()->set_fixed_dfield(time_, fieldName_, r);
+  atc_->apply_inverse_mass_matrix(r,fieldName_);
+  to_free(r,v);
+#if 0
+int n = 6;
+//std::cout << "# x "; for (int i = 0; i < n_; ++i)  std::cout << x(i) << " "; std::cout << "\n";
+//std::cout << "# f "; for (int i = 0; i < n; ++i)  std::cout << f(i,0) << " "; std::cout << "\n";
+std::cout << "# r "; for (int i = 0; i < n; ++i)  std::cout << r(i,0) << " "; std::cout << "\n";
+//std::cout << "# v "; for (int i = 0; i < n; ++i)  std::cout << v(i) << " "; std::cout << "\n";
+#endif
+}
+
+void FieldImplicitSolveOperator::solution(const DENS_MAT & dx, DENS_MAT &f) const
+{
+  DENS_MAT & df = fields_[fieldName_].set_quantity();
+  to_all(column(dx,0),df);
+  atc_->prescribed_data_manager()->set_fixed_dfield(time_, fieldName_, df);
+  f += df;
 }
+void FieldImplicitSolveOperator::rhs(const DENS_MAT & r, DENS_MAT &rhs) const
+{
+  
+  to_all(column(r,0),rhs);
+}
+
 
 } // namespace ATC
diff --git a/lib/atc/ImplicitSolveOperator.h b/lib/atc/ImplicitSolveOperator.h
index 670f20d2c..8b9f28dc5 100644
--- a/lib/atc/ImplicitSolveOperator.h
+++ b/lib/atc/ImplicitSolveOperator.h
@@ -1,129 +1,91 @@
 #ifndef IMPLICIT_SOLVE_OPERATOR_H
 #define IMPLICIT_SOLVE_OPERATOR_H
 
 // ATC includes
 #include "Array2D.h"
 #include "MatrixLibrary.h"
 #include "PhysicsModel.h"
 
 // other includes
 #include <vector>
 #include <map>
 
 namespace ATC {
 
 // Forward class declarations
 class ATC_Coupling;
 class FE_Engine;
 
 /**
  *  @class ImplicitSolveOperator
  *  @brief Helper class to compute matrix-free product for use with IML++ solvers
  */
 class ImplicitSolveOperator {
-
  public:
-
   /** Constructor */
-  ImplicitSolveOperator(ATC_Coupling * atc,
-                        /*const*/ FE_Engine * feEngine,
-                        const PhysicsModel * physicsModel);
-
+  ImplicitSolveOperator(double alpha, double dt);
   /** Destructor */
   virtual ~ImplicitSolveOperator() {};
-
   /** pure virtual operator to compute Ax, for equation Ax=b */
-  virtual DENS_VEC operator * (DENS_VEC x) const = 0;
-
+  virtual DENS_VEC operator * (const DENS_VEC &x) const;
   /** pure virtual method to return the rhs vector b */
-  virtual DENS_VEC rhs() = 0;
-
+  virtual void R(const DENS_VEC &f, DENS_VEC &v) const = 0;
+  /** pure virtual method to return the rhs vector b */
+  virtual DENS_VEC r() const;
   /** pure virtual method to return preconditioner */
-  virtual DiagonalMatrix<double> preconditioner(FIELDS & fields) = 0;
-
+  virtual DiagonalMatrix<double> preconditioner() const;
+  /** finalize */
+  virtual void solution(const DENS_MAT & dx, DENS_MAT &x) const = 0;
+  virtual void rhs(const DENS_MAT & r, DENS_MAT &rhs) const = 0;
  protected:
-
-  /** Pointer to atc */
-  ATC_Coupling * atc_;
-
-  /** Pointer to FE_Engine */
-  /*const*/ FE_Engine * feEngine_;
-
-  /** Pointer to PhysicsModel */
-  const PhysicsModel * physicsModel_;
-
+  int n_,dof_;
+  DENS_VEC x0_;             // condensed previous
+  mutable DENS_VEC x_;      // condensed current
+  DENS_VEC R0_;        // condensed previous
+  mutable DENS_VEC R_; // condensed current
+  double dt_; // timestep
+  double alpha_; // implicit/explicit parameter (0 -> explicit, else implicit)
+  double epsilon0_; // small parameter to compute increment 
 };
 
 /**
  *  @class FieldImplicitSolveOperator
  *  @brief Class to perform A*x operation for electron temperature solution
  */
 class FieldImplicitSolveOperator : public ImplicitSolveOperator {
-
  public:
-
   /** Constructor */
   FieldImplicitSolveOperator(ATC_Coupling * atc,
-                             /*const*/ FE_Engine * fe_Engine,
                              FIELDS & fields,
-                             const FieldName electronField,
+                             const FieldName f,
                              const Array2D< bool > & rhsMask,
                              const PhysicsModel * physicsModel,
-                             double simTime,
-                             double dt,
-                             double alpha);
-
+                             double simTime, double dt, double alpha = 0.5);
   /** Destructor */
   virtual ~FieldImplicitSolveOperator() {};
-
-  /** operator to compute A*x for the electron temperature equation */
-  virtual DENS_VEC operator * (DENS_VEC x) const;
-
-  /** method to return the rhs vector b */
-  virtual DENS_VEC rhs();
-
-  /** method to return preconditioner (identity matrix) */
-  virtual DIAG_MAT preconditioner(FIELDS & fields);
-
+  virtual void R(const DENS_VEC &f, DENS_VEC &v) const;
+  virtual void solution(const DENS_MAT & dx, DENS_MAT &x) const;
+  virtual void rhs(const DENS_MAT & r, DENS_MAT &rhs) const;
  protected:
-  // field name of ODE to solve
-  FieldName fieldName_;
-
-  // Reference to current fields (passed in constructor)
-  FIELDS & fields_;
-
+  void to_all(const VECTOR& free, MATRIX& all) const;
+  void to_free(const MATRIX& all, VECTOR& free) const;
+  FieldName fieldName_; // field name of ODE to solve
+  ATC_Coupling * atc_; /** Pointer to atc */
+  const PhysicsModel * physicsModel_; /** Pointer to PhysicsModel */
+  FIELDS & fields0_; // Reference to current fields (passed in constructor)
   // Local fields
-  mutable FIELDS fieldsNp1_;
-
-  // Vector to hold current temperature
-  DENS_VEC TnVect_;
-
-  // Old and new RHS maps (not including inverse mass)
-  FIELDS RnMap_;
-  mutable FIELDS RnpMap_;
-
-  // Matrices/vectors to hold electron temperature components of RHS
-  // vectors (including inverse mass)
-  DENS_VEC RnVect_;
-  mutable DENS_VEC RnpVect_;
-
+  mutable FIELDS fields_; // full
+  // set of fixed nodes
+  std::map<int,int> freeNodes_;
+  // masks
   Array2D<bool> rhsMask_;
   Array<FieldName> massMask_;
-
+  // right hand side of dot x = R(x)
+  mutable FIELDS rhs_; // full
   // simulation time
   double time_;
-
-  // timestep
-  double dt_;
-
-  // implicit/explicit parameter (0 -> explicit, else implicit)
-  double alpha_;
-
-  // small parameter to compute increment 
-  double epsilon0_;
-
 };
 
 } // namespace ATC
 
 #endif
diff --git a/lib/atc/KD_Tree.cpp b/lib/atc/KD_Tree.cpp
index a28e54b7a..362bd70d3 100644
--- a/lib/atc/KD_Tree.cpp
+++ b/lib/atc/KD_Tree.cpp
@@ -1,164 +1,169 @@
 #include "KD_Tree.h"
 #include <assert.h>
 
 using std::vector;
 
 KD_Tree *KD_Tree::create_KD_tree(const int nNodesPerElem, const int nNodes, 
                                  const DENS_MAT *nodalCoords, const int nElems, 
                                  const Array2D<int> &conn) {
   vector<Node> *points = new vector<Node>(); // Initialize an empty list of Nodes
   for (int node = 0; node < nNodes; node++) { // Insert all nodes into list
     points->push_back(Node(node, (*nodalCoords)(0, node),
                                  (*nodalCoords)(1, node),
                                  (*nodalCoords)(2, node)));
   }
   vector<Elem> *elements = new vector<Elem>();
   for (int elem = 0; elem < nElems; elem++) {
     vector<Node> nodes = vector<Node>();
     for (int node = 0; node < nNodesPerElem; node++) {
       nodes.push_back((*points)[conn(node, elem)]);
     }
     elements->push_back(Elem(elem, nodes));
   }
   return new KD_Tree(points, elements);
 }
 
 KD_Tree::~KD_Tree() {
   delete sortedPts_;
+  delete candElems_;
   delete leftChild_;
   delete rightChild_;
 }
 
 KD_Tree::KD_Tree(vector<Node> *points, vector<Elem> *elements, 
                  int dimension)
   : candElems_(elements) {
   // Set up comparison functions
   bool (*compare)(Node, Node);
   if (dimension == 0) {
     compare = Node::compareX;
   } else if (dimension == 1) {
     compare = Node::compareY;
   } else {
     compare = Node::compareZ;
   }
 
   // Sort points by their coordinate in the current dimension
   sort(points->begin(), points->end(), compare); 
   sortedPts_ = points;
 
   // Pick the median point as the root of the tree
   size_t nNodes = points->size();
   size_t med = nNodes/2;
   value_ = (*sortedPts_)[med];
   
   // Recursively construct the left sub-tree
   vector<Node> *leftPts   = new vector<Node>;
   vector<Elem> *leftElems = new vector<Elem>;
   // Recursively construct the right sub-tree
   vector<Node> *rightPts   = new vector<Node>;
   vector<Elem> *rightElems = new vector<Elem>;
   for (vector<Elem>::iterator elit = candElems_->begin();
        elit != candElems_->end(); elit++) {
     // Identify elements that should be kept on either side
     bool foundElemLeft  = false;
     bool foundElemRight = false;
     for (vector<Node>::iterator ndit = elit->second.begin();
          ndit != elit->second.end(); ndit++) {
       // Search this node
       if (compare(*ndit, value_)) {
         if (find(leftPts->begin(), leftPts->end(), *ndit) == leftPts->end()) {
           leftPts->push_back(*ndit);
         }
         foundElemLeft = true;
       }
       if (compare(value_, *ndit)) {
         if (find(rightPts->begin(), rightPts->end(), *ndit) == rightPts->end()) {
           rightPts->push_back(*ndit);
         }
         foundElemRight = true;
       }
     }
     if (foundElemLeft) leftElems->push_back(*elit);
     if (foundElemRight) rightElems->push_back(*elit);
   }
 
   // Create child tree, or NULL if there's nothing to create
   if (candElems_->size() - leftElems->size() < 4 || leftElems->size() == 0) {
     leftChild_ = NULL;
+    delete leftPts;
+    delete leftElems;
   } else {
     leftChild_ = new KD_Tree(leftPts, leftElems, (dimension+1) % 3);
   }
   // Create child tree, or NULL if there's nothing to create
   if (candElems_->size() - rightElems->size() < 4 || rightElems->size() == 0) {
     rightChild_ = NULL;
+    delete rightPts;
+    delete rightElems;
   } else {
     rightChild_ = new KD_Tree(rightPts, rightElems, (dimension+1) % 3);
   }
 }
 
 vector<int> KD_Tree::find_nearest_elements(Node query, int dimension) {
   // if the root coordinate is less than the query coordinate
   
  
   // If the query point is less that the value (split) point of this
   // tree, either recurse to the left or return this node's elements
   // if there is no left child.
   if (query.lessThanInDimension(value_, dimension)) {
     if (leftChild_ == NULL) {
       vector<int> result = vector<int>();
       for (vector<Elem>::iterator elem = candElems_->begin();
            elem != candElems_->end(); elem++) {
         result.push_back(elem->first);
       }
       return result;
     }
     return leftChild_->find_nearest_elements(query, (dimension+1) % 3);
   } else {
     if (rightChild_ == NULL) {
       vector<int> result = vector<int>();
       for (vector<Elem>::iterator elem = candElems_->begin();
            elem != candElems_->end(); elem++) {
         result.push_back(elem->first);
       }
       return result;
     }
     return rightChild_->find_nearest_elements(query, (dimension+1) % 3);
   }
 }
 
 vector<vector<int> > KD_Tree::getElemIDs(int depth) {
   
   vector<vector<int> > result;
   vector<vector<int> > temp;
   
   assert(depth >= 0 );
   if (depth == 0) {
     vector<int> candElemIDs;
     vector<Elem>::iterator it;
     for(it = candElems_->begin(); it != candElems_->end(); ++it) {
       candElemIDs.push_back((*it).first);
     }
 
     sort(candElemIDs.begin(), candElemIDs.end());
     result.push_back(candElemIDs);
 
   } else if (leftChild_ == NULL || rightChild_ == NULL) {
     // Insert all nodes at this level once,
     // then insert a bunch of empty vectors.
     temp = this->getElemIDs(0);
     result.insert(result.end(), temp.begin(), temp.end());
     int numRequested = floor(pow(2,depth));
     for (int i = 0; i < numRequested - 1; ++i) {
       vector<int> emptyVec;
       result.push_back(emptyVec);
     }
   } else {
     --depth;
     temp = leftChild_->getElemIDs(depth);
     result.insert(result.end(), temp.begin(), temp.end());
     temp = rightChild_->getElemIDs(depth);
     result.insert(result.end(), temp.begin(), temp.end());
   }
   
   return result;
 }
diff --git a/lib/atc/KernelFunction.cpp b/lib/atc/KernelFunction.cpp
index 214d81f5d..91f99a614 100644
--- a/lib/atc/KernelFunction.cpp
+++ b/lib/atc/KernelFunction.cpp
@@ -1,726 +1,726 @@
 #include "KernelFunction.h"
 #include "math.h"
 #include <vector>
 #include "ATC_Error.h"
 #include "Quadrature.h"
 #include "Utility.h"
 
 
 using namespace std;
 using namespace ATC_Utility;
 
 static const double tol = 1.0e-8;
 
 static const int line_ngauss = 10; 
 static double line_xg[line_ngauss], line_wg[line_ngauss];
 
 namespace ATC {
 
   
   //========================================================================
   //  KernelFunctionMgr
   //========================================================================
   KernelFunctionMgr * KernelFunctionMgr::myInstance_ = NULL;
   //------------------------------------------------------------------------
   //  instance
   //------------------------------------------------------------------------
   KernelFunctionMgr * KernelFunctionMgr::instance()
   {
     if (myInstance_ == NULL) {
       myInstance_ = new KernelFunctionMgr();
     }
     return myInstance_;
   }
   //------------------------------------------------------------------------
   // get function from args
   //------------------------------------------------------------------------
   KernelFunction* KernelFunctionMgr::function(char ** arg, int narg)
   {
     /*! \page man_kernel_function fix_modify AtC kernel 
       \section syntax
       fix_modify AtC kernel <type> <parameters>
       - type (keyword) = step, cell, cubic_bar, cubic_cylinder, cubic_sphere, 
                          quartic_bar, quartic_cylinder, quartic_sphere \n
       - parameters :\n
       step = radius (double) \n
       cell = hx, hy, hz (double) or h (double) \n
       cubic_bar = half-width (double) \n
       cubic_cylinder = radius (double) \n
       cubic_sphere = radius (double) \n
       quartic_bar = half-width (double) \n
       quartic_cylinder = radius (double) \n
       quartic_sphere = radius (double) \n
       \section examples
       fix_modify AtC kernel cell 1.0 1.0 1.0
       fix_modify AtC kernel quartic_sphere 10.0
       \section description
       
       \section restrictions
       Must be used with the hardy AtC fix \n
       For bar kernel types, half-width oriented along x-direction \n
       For cylinder kernel types, cylindrical axis is assumed to be in z-direction \n
       ( see \ref man_fix_atc )
       \section related
       \section default
       No default
     */
     int argIdx = 0;
     KernelFunction * ptr = NULL;
     char* type = arg[argIdx++];
     if (strcmp(type,"step")==0) {
       double parameters[1] = {atof(arg[argIdx])}; // cutoff radius
       ptr = new KernelFunctionStep(1,parameters);
     }
     else if (strcmp(type,"cell")==0) {
       double parameters[3];
       parameters[0] = parameters[1] = parameters[2] = atof(arg[argIdx++]);
       if (narg > argIdx) { // L_x, L_y, L_z
         for (int i = 1; i < 3; i++) { parameters[i] = atof(arg[argIdx++]); }
       }
       ptr = new KernelFunctionCell(2,parameters);
     }
     else if (strcmp(type,"cubic_bar")==0) {
       double parameters[1] = {atof(arg[argIdx])}; // cutoff half-length 
       ptr = new KernelFunctionCubicBar(1,parameters);
     }
     else if (strcmp(type,"linear_bar")==0) {
       double parameters[1] = {atof(arg[argIdx])}; // cutoff half-length 
       ptr = new KernelFunctionLinearBar(1,parameters);
     }
     else if (strcmp(type,"cubic_cylinder")==0) {
       double parameters[1] = {atof(arg[argIdx])}; // cutoff radius
       ptr = new KernelFunctionCubicCyl(1,parameters);
     }
     else if (strcmp(type,"cubic_sphere")==0) {
       double parameters[1] = {atof(arg[argIdx])}; // cutoff radius
       ptr = new KernelFunctionCubicSphere(1,parameters);
     }
     else if (strcmp(type,"quartic_bar")==0) {
       double parameters[1] = {atof(arg[argIdx])}; // cutoff half-length 
       ptr = new KernelFunctionQuarticBar(1,parameters);
     }
     else if (strcmp(type,"quartic_cylinder")==0) {
       double parameters[1] = {atof(arg[argIdx])}; // cutoff radius
       ptr = new KernelFunctionQuarticCyl(1,parameters);
     }
     else if (strcmp(type,"quartic_sphere")==0) {
       double parameters[1] = {atof(arg[argIdx])}; // cutoff radius
       ptr = new KernelFunctionQuarticSphere(1,parameters);
     }
     pointerSet_.insert(ptr);
     return ptr;
   }
 
   // Destructor
   KernelFunctionMgr::~KernelFunctionMgr()
   {
      set<KernelFunction * >::iterator it;
     for (it = pointerSet_.begin(); it != pointerSet_.end(); it++)
       if (*it) delete *it;
   }
 
   //------------------------------------------------------------------------
   //  KernelFunction
   //------------------------------------------------------------------------
   // constructor
   KernelFunction::KernelFunction(int nparameters, double* parameters):
     Rc_(0),invRc_(0),nsd_(3),
     lammpsInterface_(LammpsInterface::instance())
   { 
     Rc_ = parameters[0];
     invRc_ = 1.0/Rc_;
     Rc_ = parameters[0];
     invRc_ = 1.0/Rc_;
-    invVol_ = 1.0/(4.0/3.0*Pi*pow(Rc_,3));
+    invVol_ = 1.0/(4.0/3.0*Pi_*pow(Rc_,3));
 
     ATC::Quadrature::instance()->set_line_quadrature(line_ngauss,line_xg,line_wg);
 
     // get periodicity and box bounds/lengths
     lammpsInterface_->box_periodicity(periodicity[0],
                                           periodicity[1],periodicity[2]);
     lammpsInterface_->box_bounds(box_bounds[0][0],box_bounds[1][0],
                                      box_bounds[0][1],box_bounds[1][1],
                                      box_bounds[0][2],box_bounds[1][2]);
     for (int k = 0; k < 3; k++) {
       box_length[k] = box_bounds[1][k] - box_bounds[0][k]; 
     } 
   }
 
   // does an input node's kernel intersect bonds on this processor
   bool KernelFunction::node_contributes(DENS_VEC node) const
   {
     DENS_VEC ghostNode = node;
     bool contributes = true;
     bool ghostContributes = lammpsInterface_->nperiodic();
     double kernel_bounds[2][3];
     lammpsInterface_->sub_bounds(kernel_bounds[0][0],kernel_bounds[1][0],
                                      kernel_bounds[0][1],kernel_bounds[1][1],
                                      kernel_bounds[0][2],kernel_bounds[1][2]);
     for (int i=0; i<3; ++i) {
       if (i < nsd_) {
         kernel_bounds[0][i] -= (Rc_+lammpsInterface_->pair_cutoff());
         kernel_bounds[1][i] += (Rc_+lammpsInterface_->pair_cutoff());
         contributes = contributes && (node(i) >= kernel_bounds[0][i]) 
                                   && (node(i) <  kernel_bounds[1][i]);
         if (periodicity[i]) {
           if (node[i] <= box_bounds[0][i] + box_length[i]/2) {
             ghostNode[i] += box_length[i];
           } else {
             ghostNode[i] -= box_length[i];
           }
           ghostContributes = ghostContributes 
                           && ((ghostNode(i) >= kernel_bounds[0][i]) || 
                                    (node(i) >= kernel_bounds[0][i]))
                           && ((ghostNode(i) <  kernel_bounds[1][i]) ||
                                    (node(i) <  kernel_bounds[1][i]));
         }
       }
       if (!(contributes || ghostContributes)) break;
     }
     return true;
   }
 
   bool KernelFunction::in_support(DENS_VEC dx) const
   {
     if (dx.norm() > Rc_) return false;
     return true;
   }
 
   // bond function value via quadrature
   double KernelFunction::bond(DENS_VEC& xa, DENS_VEC&xb, double lam1, double lam2) const
   {
     DENS_VEC xab(nsd_), q(nsd_);
     double lamg;
     double bhsum=0.0;
     xab = xa - xb;
     for (int i = 0; i < line_ngauss; i++) {
       lamg=0.5*((lam2-lam1)*line_xg[i]+(lam2+lam1));
       q = lamg*xab + xb;
       double locg_value=this->value(q);
       bhsum+=locg_value*line_wg[i];
     }
     return 0.5*(lam2-lam1)*bhsum;
   }
 
   // localization-volume intercepts for bond calculation 
   // bond intercept values assuming spherical support
   void KernelFunction::bond_intercepts(DENS_VEC& xa,
                  DENS_VEC& xb, double &lam1, double &lam2) const
   {
     if (nsd_ == 2) {// for cylinders, axis is always z! 
       const int iaxis = 2;
       xa[iaxis] = 0.0;
       xb[iaxis] = 0.0;
     } else if (nsd_ == 1) {// for bars, analysis is 1D in x
       xa[1] = 0.0;
       xa[2] = 0.0;
       xb[1] = 0.0;
       xb[2] = 0.0;
     }
     lam1 = lam2 = -1;
     double ra_n = invRc_*xa.norm(); // lambda = 1
     double rb_n = invRc_*xb.norm(); // lambda = 0
     bool a_in = (ra_n <= 1.0);
     bool b_in = (rb_n <= 1.0);
     if (a_in && b_in) {
       lam1 = 0.0; 
       lam2 = 1.0; 
       return;
     }
     DENS_VEC xab = xa - xb;
     double rab_n = invRc_*xab.norm();
     double a = rab_n*rab_n; // always at least an interatomic distance
     double b = 2.0*invRc_*invRc_*xab.dot(xb);
     double c = rb_n*rb_n - 1.0;
     double discrim = b*b - 4.0*a*c; // discriminant
     if (discrim < 0) return; // no intersection
     // num recipes:
     double s1, s2;
     if (b < 0.0) {
       double aux = -0.5*(b-sqrt(discrim));
       s1 = c/aux;
       s2 = aux/a;
     } 
     else {
       double aux = -0.5*(b+sqrt(discrim));
       s1 = aux/a;
       s2 = c/aux;
     }
     if (a_in && !b_in) {
       lam1 = s1;
       lam2 = 1.0;
     } 
     else if (!a_in && b_in) { 
       lam1 = 0.0;
       lam2 = s2; 
     }
     else {
       if (s1 >= 0.0 && s2 <= 1.0) { 
         lam1 = s1; 
         lam2 = s2; 
       }
     }
   }
 
   //------------------------------------------------------------------------
   // constructor
   KernelFunctionStep::KernelFunctionStep
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters) 
   {
     for (int k = 0; k < nsd_; k++ ) {
       if ((bool) periodicity[k]) {
         if (Rc_ > 0.5*box_length[k]) {
           throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
         }
       }
     } 
   }
 
   // function value
   double KernelFunctionStep::value(DENS_VEC& x_atom) const
   {
     double rn=invRc_*x_atom.norm();
     if (rn <= 1.0) { return 1.0; }
     else           { return 0.0; }
   }
   
   // function derivative value
   void KernelFunctionStep::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
   }
 
   //------------------------------------------------------------------------
   /** a step with rectangular support suitable for a rectangular grid */
   // constructor
   KernelFunctionCell::KernelFunctionCell
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters) 
   {
     hx = parameters[0];
     hy = parameters[1];
     hz = parameters[2];
     invVol_ = 1.0/8.0/(hx*hy*hz);
     cellBounds_.reset(6);
     cellBounds_(0) = -hx;
     cellBounds_(1) =  hx;
     cellBounds_(2) = -hy;
     cellBounds_(3) =  hy;
     cellBounds_(4) = -hz;
     cellBounds_(5) =  hz;
       
     for (int k = 0; k < nsd_; k++ ) {
       if ((bool) periodicity[k]) {
         if (parameters[k] > 0.5*box_length[k]) {
           throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
         }
       }
     }
   }
 
   // does an input node's kernel intersect bonds on this processor
   bool KernelFunctionCell::node_contributes(DENS_VEC node) const
   {
     DENS_VEC ghostNode = node;
     bool contributes = true;
     bool ghostContributes = lammpsInterface_->nperiodic();
     double kernel_bounds[2][3];
     lammpsInterface_->sub_bounds(kernel_bounds[0][0],kernel_bounds[1][0],
                                      kernel_bounds[0][1],kernel_bounds[1][1],
                                      kernel_bounds[0][2],kernel_bounds[1][2]);
     for (int i=0; i<3; ++i) {
       kernel_bounds[0][i] -= (cellBounds_(i*2+1) +
                               lammpsInterface_->pair_cutoff());
       kernel_bounds[1][i] += (cellBounds_(i*2+1) + 
                               lammpsInterface_->pair_cutoff());
       contributes = contributes && (node(i) >= kernel_bounds[0][i]) 
                                 && (node(i) <  kernel_bounds[1][i]);
       if (periodicity[i]) {
         if (node[i] <= box_bounds[0][i] + box_length[i]/2) {
           ghostNode[i] += box_length[i];
         } else {
           ghostNode[i] -= box_length[i];
         }
         ghostContributes = ghostContributes 
                         && ((ghostNode(i) >= kernel_bounds[0][i]) ||
                                  (node(i) >= kernel_bounds[0][i]))
                         && ((ghostNode(i) <  kernel_bounds[1][i]) ||
                                  (node(i) <  kernel_bounds[1][i]));
       }
       if (!(contributes || ghostContributes)) break;
     }
     return true;
   }
 
   bool KernelFunctionCell::in_support(DENS_VEC dx) const
   {
     if (dx(0) < cellBounds_(0)
      || dx(0) > cellBounds_(1)
      || dx(1) < cellBounds_(2)
      || dx(1) > cellBounds_(3)
      || dx(2) < cellBounds_(4)
      || dx(2) > cellBounds_(5) ) return false;
     return true;
   }
 
   // function value
   double KernelFunctionCell::value(DENS_VEC& x_atom) const
   {
     if ((cellBounds_(0) <= x_atom(0)) && (x_atom(0) < cellBounds_(1)) 
      && (cellBounds_(2) <= x_atom(1)) && (x_atom(1) < cellBounds_(3)) 
      && (cellBounds_(4) <= x_atom(2)) && (x_atom(2) < cellBounds_(5))) { 
       return 1.0; 
     } 
     else { 
       return 0.0; 
     }
   }
 
   // function derivative value
   void KernelFunctionCell::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
   }
  
   // bond intercept values for rectangular region : origin is the node position
   void KernelFunctionCell::bond_intercepts(DENS_VEC& xa,
                  DENS_VEC& xb, double &lam1, double &lam2) const
   {
     lam1 = 0.0; // start
     lam2 = 1.0; // end
 
     bool a_in = (value(xa) > 0.0);
     bool b_in = (value(xb) > 0.0);
 
     // (1) both in, no intersection needed
     if (a_in && b_in) {
       return;
     }
     // (2) for one in & one out -> one plane intersection
     // determine the points of intersection between the line joining
     // atoms a and b and the bounding planes of the localization volume
     else if (a_in || b_in) {
       DENS_VEC xab = xa - xb;
       for (int i = 0; i < nsd_; i++) {
         // check if segment is parallel to face
         if (fabs(xab(i)) > tol) {
           for (int j = 0; j < 2; j++) {
             double s = (cellBounds_(2*i+j) - xb(i))/xab(i);
             // check if between a & b
             if (s >= 0 && s <= 1) {
               bool in_bounds = false; 
               DENS_VEC x = xb + s*xab;
               if (i == 0) { 
                 if ((cellBounds_(2) <= x(1)) && (x(1) <= cellBounds_(3))
                  && (cellBounds_(4) <= x(2)) && (x(2) <= cellBounds_(5))) {
                   in_bounds = true;
                 }
               }
               else if (i == 1) { 
                 if ((cellBounds_(0) <= x(0)) && (x(0) <= cellBounds_(1))
                  && (cellBounds_(4) <= x(2)) && (x(2) <= cellBounds_(5))) {
                   in_bounds = true;
                 }
               }
               else if (i == 2) { 
                 if ((cellBounds_(0) <= x(0)) && (x(0) <= cellBounds_(1))
                  && (cellBounds_(2) <= x(1)) && (x(1) <= cellBounds_(3))) {
                   in_bounds = true;
                 }
               }
               if (in_bounds) {
                 if (a_in) { lam1 = s;}
                 else      { lam2 = s;}
                 return;
               }
             }
           }
         } 
       }
       throw ATC_Error("logic failure in HardyKernel Cell for single intersection\n");
     }
     // (3) both out -> corner intersection
     else {
       lam2 = lam1; // default to no intersection
       DENS_VEC xab = xa - xb;
       double ss[6] = {-1,-1,-1,-1,-1,-1};
       int is = 0;
       for (int i = 0; i < nsd_; i++) {
         // check if segment is parallel to face
         if (fabs(xab(i)) > tol) {
           for (int j = 0; j < 2; j++) {
             double s = (cellBounds_(2*i+j) - xb(i))/xab(i);
             // check if between a & b
             if (s >= 0 && s <= 1) {
               // check if in face
               DENS_VEC x = xb + s*xab;
               if (i == 0) { 
                 if ((cellBounds_(2) <= x(1)) && (x(1) <= cellBounds_(3))
                  && (cellBounds_(4) <= x(2)) && (x(2) <= cellBounds_(5))) {
                   ss[is++] = s;
                 }
               }
               else if (i == 1) { 
                 if ((cellBounds_(0) <= x(0)) && (x(0) <= cellBounds_(1))
                  && (cellBounds_(4) <= x(2)) && (x(2) <= cellBounds_(5))) {
                   ss[is++] = s;
                 }
               }
               else if (i == 2) { 
                 if ((cellBounds_(0) <= x(0)) && (x(0) <= cellBounds_(1))
                  && (cellBounds_(2) <= x(1)) && (x(1) <= cellBounds_(3))) {
                   ss[is++] = s;
                 }
               }
             }
           }
         } 
       }
       if (is == 1) {
       // intersection occurs at a box edge - leave lam1 = lam2
       }
       else if (is == 2) {
         lam1 = min(ss[0],ss[1]);
         lam2 = max(ss[0],ss[1]);
       }
       else if (is == 3) {
       // intersection occurs at a box vertex - leave lam1 = lam2
       }
       else {
         if (is != 0) throw ATC_Error("logic failure in HardyKernel Cell for corner intersection\n");
       }
     }
   }
 
   //------------------------------------------------------------------------
   // constructor
   KernelFunctionCubicSphere::KernelFunctionCubicSphere
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters) 
   {
     for (int k = 0; k < nsd_; k++ ) {
       if ((bool) periodicity[k]) {
         if (Rc_ > 0.5*box_length[k]) {
           throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
         };
       };
     };
   }
 
   // function value
   double KernelFunctionCubicSphere::value(DENS_VEC& x_atom) const
   {
      double r=x_atom.norm();
      double rn=r/Rc_;
      if (rn < 1.0) { return 5.0*(1.0-3.0*rn*rn+2.0*rn*rn*rn); }
      else          { return 0.0; }
   } 
 
   // function derivative value
   void KernelFunctionCubicSphere::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
   }
 
   //------------------------------------------------------------------------
   // constructor
   KernelFunctionQuarticSphere::KernelFunctionQuarticSphere
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters) 
   {
     for (int k = 0; k < nsd_; k++ ) {
       if ((bool) periodicity[k]) {
         if (Rc_ > 0.5*box_length[k]) {
           throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
         };
       };
     };
   }
 
   // function value
   double KernelFunctionQuarticSphere::value(DENS_VEC& x_atom) const 
   {
      double r=x_atom.norm();
      double rn=r/Rc_;
      if (rn < 1.0) { return 35.0/8.0*pow((1.0-rn*rn),2); }
      else          { return 0.0; }
   } 
 
   // function derivative value
   void KernelFunctionQuarticSphere::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
   }
 
   //------------------------------------------------------------------------
   // constructor
   KernelFunctionCubicCyl::KernelFunctionCubicCyl
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters)
   {
     nsd_ = 2;
     double Lz = box_length[2];
-    invVol_ = 1.0/(Pi*pow(Rc_,2)*Lz);
+    invVol_ = 1.0/(Pi_*pow(Rc_,2)*Lz);
     for (int k = 0; k < nsd_; k++ ) {
       if ((bool) periodicity[k]) {
         if (Rc_ > 0.5*box_length[k]) {
           throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
         };
       };
     };
   }
 
   // function value
   double KernelFunctionCubicCyl::value(DENS_VEC& x_atom) const
   {
      double r=sqrt(pow(x_atom(0),2)+pow(x_atom(1),2));
      double rn=r/Rc_;
      if (rn < 1.0) { return 10.0/3.0*(1.0-3.0*rn*rn+2.0*rn*rn*rn); }
      else          { return 0.0; }
   } 
 
   // function derivative value
   void KernelFunctionCubicCyl::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
   }
 
   //------------------------------------------------------------------------
   // constructor
   KernelFunctionQuarticCyl::KernelFunctionQuarticCyl
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters)
   {
     nsd_ = 2;
     double Lz = box_length[2];
-    invVol_ = 1.0/(Pi*pow(Rc_,2)*Lz);
+    invVol_ = 1.0/(Pi_*pow(Rc_,2)*Lz);
     for (int k = 0; k < nsd_; k++ ) {
       if ((bool) periodicity[k]) {
         if (Rc_ > 0.5*box_length[k]) {
           throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
         };
       };
     };
   }
 
   // function value
   double KernelFunctionQuarticCyl::value(DENS_VEC& x_atom) const
   {
     double r=sqrt(pow(x_atom(0),2)+pow(x_atom(1),2));
     double rn=r/Rc_;
     if (rn < 1.0) { return 3.0*pow((1.0-rn*rn),2); }
     else          { return 0.0; }
   } 
 
   // function derivative value
   void KernelFunctionQuarticCyl::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
   }
   //------------------------------------------------------------------------
   // constructor
   KernelFunctionCubicBar::KernelFunctionCubicBar
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters)
   {
     // Note: Bar is assumed to be oriented in the x(0) direction
     nsd_ = 1;
     double Ly = box_length[1];
     double Lz = box_length[2];
     invVol_ = 1.0/(2*Rc_*Ly*Lz);
     if ((bool) periodicity[0]) {
       if (Rc_ > 0.5*box_length[0]) {
         throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
       };
     };
   }
 
   // function value
   double KernelFunctionCubicBar::value(DENS_VEC& x_atom) const
   {
      double r=abs(x_atom(0));
      double rn=r/Rc_;
      if (rn < 1.0) { return 2.0*(1.0-3.0*rn*rn+2.0*rn*rn*rn); }
      else          { return 0.0; }
   } 
 
   // function derivative value
   void KernelFunctionCubicBar::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
   }
 
   //------------------------------------------------------------------------
   // constructor
   KernelFunctionLinearBar::KernelFunctionLinearBar
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters)
   {
     // Note: Bar is assumed to be oriented in the z(0) direction
     double Lx = box_length[0];
     double Ly = box_length[1];
     invVol_ = 1.0/(Lx*Ly*Rc_);
     if ((bool) periodicity[2]) {
       if (Rc_ > 0.5*box_length[2]) {
         throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
       };
     };
   }
 
   // function value
   double KernelFunctionLinearBar::value(DENS_VEC& x_atom) const
   {
      double r=abs(x_atom(2));
      double rn=r/Rc_;
      if (rn < 1.0) { return 1.0-rn; }
      else          { return 0.0; }
   } 
 
   // function derivative value
   void KernelFunctionLinearBar::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
      deriv(0) = 0.0;
      deriv(1) = 0.0;
      double r=abs(x_atom(2));
      double rn=r/Rc_;
      if (rn < 1.0 && x_atom(2) <= 0.0) { deriv(2) = 1.0/Rc_; }
      else if (rn < 1.0 && x_atom(2) > 0.0) { deriv(2) = -1.0/Rc_; }
      else { deriv(2) = 0.0; }
   }
 
   //------------------------------------------------------------------------
   // constructor
   KernelFunctionQuarticBar::KernelFunctionQuarticBar
     (int nparameters, double* parameters): 
     KernelFunction(nparameters, parameters)
   {
     // Note: Bar is assumed to be oriented in the x(0) direction
     nsd_ = 1;
     double Ly = box_length[1];
     double Lz = box_length[2];
     invVol_ = 1.0/(2*Rc_*Ly*Lz);
     if ((bool) periodicity[0]) {
       if (Rc_ > 0.5*box_length[0]) {
         throw ATC_Error("Size of localization volume is too large for periodic boundary condition");
       };
     };
   }
 
   // function value
   double KernelFunctionQuarticBar::value(DENS_VEC& x_atom) const
   {
      double r=abs(x_atom(0));
      double rn=r/Rc_;
      // if (rn < 1.0) { return 5.0/2.0*(1.0-6*rn*rn+8*rn*rn*rn-3*rn*rn*rn*rn); } - alternative quartic
      if (rn < 1.0) { return 15.0/8.0*pow((1.0-rn*rn),2); }
      else          { return 0.0; }
   } 
 
   // function derivative value
   void KernelFunctionQuarticBar::derivative(const DENS_VEC& x_atom, DENS_VEC& deriv) const
   {
      deriv.reset(nsd_);
   }
 };
diff --git a/lib/atc/KinetoThermostat.cpp b/lib/atc/KinetoThermostat.cpp
index cf3b9c29c..bdc11238a 100644
--- a/lib/atc/KinetoThermostat.cpp
+++ b/lib/atc/KinetoThermostat.cpp
@@ -1,436 +1,703 @@
 #include "KinetoThermostat.h"
 #include "ATC_Coupling.h"
 #include "ATC_Error.h"
 #include "PrescribedDataManager.h"
 #include "ElasticTimeIntegrator.h"
 #include "ThermalTimeIntegrator.h"
 #include "TransferOperator.h"
 
 using namespace std;
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class KinetoThermostat
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   KinetoThermostat::KinetoThermostat(ATC_Coupling * atc,
                                      const string & regulatorPrefix) :
     AtomicRegulator(atc,regulatorPrefix),
-    kinetostat_(atc,"Momentum"),
-    thermostat_(atc,"Energy")
+    couplingMaxIterations_(myCouplingMaxIterations)
   {
     // nothing to do
   }
 
   //--------------------------------------------------------
   //  modify:
   //    parses and adjusts thermostat state based on
   //    user input, in the style of LAMMPS user input
   //--------------------------------------------------------
   bool KinetoThermostat::modify(int narg, char **arg)
   {
     bool foundMatch = false;
     return foundMatch;
   }
 
   //--------------------------------------------------------
   //  reset_lambda_contribution:
   //    resets the thermostat generated power to a
   //    prescribed value
   //--------------------------------------------------------
   void KinetoThermostat::reset_lambda_contribution(const DENS_MAT & target,
                                                    const FieldName field)
   {
-    //TEMP_JAT
     if (field==VELOCITY) {
-      kinetostat_.reset_lambda_contribution(target);
+      DENS_MAN * lambdaForceFiltered = regulator_data("LambdaForceFiltered",atc_->nsd());
+      *lambdaForceFiltered = target;
     }
     else if (field == TEMPERATURE) {
-      thermostat_.reset_lambda_contribution(target);
+      DENS_MAN * lambdaPowerFiltered = regulator_data("LambdaPowerFiltered",1);
+      *lambdaPowerFiltered = target;
     }
     else {
       throw ATC_Error("KinetoThermostat::reset_lambda_contribution - invalid field given");
     }
   }
 
   //--------------------------------------------------------
   //  construct_methods:
   //    instantiations desired regulator method(s)
   
   //    dependence, but in general there is also a
   //    time integrator dependence.  In general the 
   //    precedence order is:
   //    time filter -> time integrator -> thermostat
   //    In the future this may need to be added if
   //    different types of time integrators can be
   //    specified.
   //--------------------------------------------------------
   void KinetoThermostat::construct_methods()
   {
-// #ifdef WIP_JAT
-//     // get data associated with stages 1 & 2 of ATC_Method::initialize
-//     AtomicRegulator::construct_methods();
-
-//     if (atc_->reset_methods()) {
-//       // eliminate existing methods
-//       delete_method();
-
-//       // update time filter
-//       TimeIntegrator::TimeIntegrationType myIntegrationType = (atc_->time_integrator(TEMPERATURE))->time_integration_type();
-//       TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
-//       if (timeFilterManager->need_reset() ) {
-//         if (myIntegrationType == TimeIntegrator::GEAR)
-//          timeFilter_ = timeFilterManager->construct(TimeFilterManager::EXPLICIT);
-//         else if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP)
-//          timeFilter_ = timeFilterManager->construct(TimeFilterManager::EXPLICIT_IMPLICIT);
-//       }
+    // get data associated with stages 1 & 2 of ATC_Method::initialize
+    AtomicRegulator::construct_methods();
+
+    if (atc_->reset_methods()) {
+      // eliminate existing methods
+      delete_method();
+
+      // error check time integration methods
+      TimeIntegrator::TimeIntegrationType myEnergyIntegrationType = (atc_->time_integrator(TEMPERATURE))->time_integration_type();
+      TimeIntegrator::TimeIntegrationType myMomentumIntegrationType = (atc_->time_integrator(VELOCITY))->time_integration_type();
+      if (myEnergyIntegrationType != TimeIntegrator::FRACTIONAL_STEP || myMomentumIntegrationType != TimeIntegrator::FRACTIONAL_STEP) {
+        throw ATC_Error("KinetoThermostat::construct_methods - this scheme only valid with fractional step integration");
+      }
+
+      // update time filter
+      TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
+      if (timeFilterManager->need_reset() ) {
+        timeFilter_ = timeFilterManager->construct(TimeFilterManager::EXPLICIT_IMPLICIT);
+      }
       
-//       if (timeFilterManager->filter_dynamics()) {
-//         switch (regulatorTarget_) {
-//         case NONE: {
-//           regulatorMethod_ = new RegulatorMethod(this);
-//           break;
-//         }
-//         case FIELD: { // error check, rescale and filtering not supported together
-//           throw ATC_Error("Cannot use rescaling thermostat with time filtering");
-//           break;
-//         }
-//         case DYNAMICS: {
-//           switch (couplingMode_) {
-//           case FIXED: {
-//             if (use_lumped_lambda_solve()) {
-//               throw ATC_Error("Thermostat:construct_methods - lumped lambda solve cannot be used with Hoover thermostats");
-//             }
-//             if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
-//               if (md_flux_nodes(TEMPERATURE)) {
-//                 if (!md_fixed_nodes(TEMPERATURE) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
-//                   // there are fluxes but no fixed or coupled nodes
-//                   regulatorMethod_ = new ThermostatFluxFiltered(this);
-//                 }
-//                 else {
-//                   // there are both fixed and flux nodes
-//                   regulatorMethod_ = new ThermostatFluxFixedFiltered(this);
-//                 }
-//               }
-//               else {
-//                 // there are only fixed nodes
-//                 regulatorMethod_ = new ThermostatFixedFiltered(this);
-//               }
-//             }
-//             else {
-//               regulatorMethod_ = new ThermostatHooverVerletFiltered(this);
-//             }
-//             break;
-//           }
-//           case FLUX: {
-//             if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
-//               if (use_lumped_lambda_solve()) {
-//                 throw ATC_Error("Thermostat:construct_methods - lumped lambda solve has been depricated for fractional step thermostats");
-//               }
-//               if (md_fixed_nodes(TEMPERATURE)) {
-//                 if (!md_flux_nodes(TEMPERATURE) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
-//                 // there are fixed nodes but no fluxes
-//                 regulatorMethod_ = new ThermostatFixedFiltered(this);
-//                 }
-//                 else {
-//                   // there are both fixed and flux nodes
-//                   regulatorMethod_ = new ThermostatFluxFixedFiltered(this);
-//                 }
-//               }
-//               else {
-//                 // there are only flux nodes
-//                 regulatorMethod_ = new ThermostatFluxFiltered(this);
-//               }
-//             }
-//             else {
-//               if (use_localized_lambda()) {
-//                 if (!((atc_->prescribed_data_manager())->no_fluxes(TEMPERATURE)) &&
-//                     atc_->boundary_integration_type() != NO_QUADRATURE) {
-//                   throw ATC_Error("Cannot use flux coupling with localized lambda");
-//                 }
-//               }
-//               regulatorMethod_ = new ThermostatPowerVerletFiltered(this);
-//             }
-//             break;
-//           }
-//           default:
-//             throw ATC_Error("Unknown coupling mode in Thermostat::initialize");
-//           }
-//           break;
-//         }
-//         default:
-//           throw ATC_Error("Unknown thermostat type in Thermostat::initialize");
-//         }
-//       }
-//       else {
-//         switch (regulatorTarget_) {
-//         case NONE: {
-//           regulatorMethod_ = new RegulatorMethod(this);
-//           break;
-//         }
-//         case FIELD: {
-//           if (atc_->temperature_def()==KINETIC)
-//             regulatorMethod_ = new ThermostatRescale(this);
-//           else if (atc_->temperature_def()==TOTAL)
-//             regulatorMethod_ = new ThermostatRescaleMixedKePe(this);
-//           else
-//             throw ATC_Error("Unknown temperature definition");
-//           break;
-//         }
-//         case DYNAMICS: {
-//           switch (couplingMode_) {
-//           case FIXED: {
-//             if (use_lumped_lambda_solve()) {
-//               throw ATC_Error("Thermostat:construct_methods - lumped lambda solve cannot be used with Hoover thermostats");
-//             }
-//             if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
-//               if (md_flux_nodes(TEMPERATURE)) {
-//                 if (!md_fixed_nodes(TEMPERATURE) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
-//                   // there are fluxes but no fixed or coupled nodes
-//                   regulatorMethod_ = new ThermostatFlux(this);
-//                 }
-//                 else {
-//                   // there are both fixed and flux nodes
-//                   regulatorMethod_ = new ThermostatFluxFixed(this);
-//                 }
-//               }
-//               else {
-//                 // there are only fixed nodes
-//                 regulatorMethod_ = new ThermostatFixed(this);
-//               }
-//             }
-//             else {
-//               regulatorMethod_ = new ThermostatHooverVerlet(this);
-//             }
-//             break;
-//           }
-//           case FLUX: {
-//             if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
-//               if (use_lumped_lambda_solve()) {
-//                 throw ATC_Error("Thermostat:construct_methods - lumped lambda solve has been depricated for fractional step thermostats");
-//               }
-//               if (md_fixed_nodes(TEMPERATURE)) {
-//                 if (!md_flux_nodes(TEMPERATURE) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
-//                   // there are fixed nodes but no fluxes
-//                   regulatorMethod_ = new ThermostatFixed(this);
-//                 }
-//                 else {
-//                   // there are both fixed and flux nodes
-//                   regulatorMethod_ = new ThermostatFluxFixed(this);
-//                 }
-//               }
-//               else {
-//                 // there are only flux nodes
-//                 regulatorMethod_ = new ThermostatFlux(this);
-//               }
-//             }
-//             else {
-//               if (use_localized_lambda()) {
-//                 if (!((atc_->prescribed_data_manager())->no_fluxes(TEMPERATURE)) &&
-//                     atc_->boundary_integration_type() != NO_QUADRATURE) {
-//                   throw ATC_Error("Cannot use flux coupling with localized lambda");
-//                 }
-//               }
-//               regulatorMethod_ = new ThermostatPowerVerlet(this);
-//             }
-//             break;
-//           }
-//           default:
-//             throw ATC_Error("Unknown coupling mode in Thermostat::initialize");
-//           }
-//           break;
-//         }
-//         default:
-//           throw ATC_Error("Unknown thermostat target in Thermostat::initialize");
-//         }
-//       }
+      if (timeFilterManager->filter_dynamics()) {
+        switch (regulatorTarget_) {
+        case NONE: {
+          regulatorMethod_ = new RegulatorMethod(this);
+          break;
+        }
+        case FIELD: { // error check, rescale and filtering not supported together
+          throw ATC_Error("KinetoThermostat::construct_methods - Cannot use rescaling thermostat with time filtering");
+          break;
+        }
+        case DYNAMICS: {
+        }
+        default:
+          throw ATC_Error("Unknown thermostat type in Thermostat::initialize");
+        }
+      }
+      else {
+        switch (regulatorTarget_) {
+        case NONE: {
+          regulatorMethod_ = new RegulatorMethod(this);
+          break;
+        }
+        case FIELD: {
+          if (atc_->temperature_def()==KINETIC) {
+            regulatorMethod_ = new KinetoThermostatRescale(this,couplingMaxIterations_);
+          }
+          else if (atc_->temperature_def()==TOTAL) {
+            regulatorMethod_ = new KinetoThermostatRescaleMixedKePe(this,couplingMaxIterations_);
+          }
+          else
+            throw ATC_Error("Unknown temperature definition");
+          break;
+        }
+        default:
+          throw ATC_Error("Unknown thermostat target in Thermostat::initialize");
+        }
+      }
       
-//       AtomicRegulator::reset_method();
-//     }
-//     else {
-//       set_all_data_to_used();
-//     }
-// #endif
-    //TEMP_JAT
-    kinetostat_.construct_methods();
-    thermostat_.construct_methods();
+      AtomicRegulator::reset_method();
+    }
+    else {
+      set_all_data_to_used();
+    }
   }
 
-  //TEMP_JAT all functions which have explicit thermo and kinetostats need to be removed
-    //--------------------------------------------------------
-  //  reset_nlocal:
-  //    resizes lambda force if necessary
   //--------------------------------------------------------
-  void KinetoThermostat::reset_nlocal()
+  //--------------------------------------------------------
+  //  Class VelocityRescaleCombined
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+ 
+  //--------------------------------------------------------
+  //  Constructor
+  //         Grab references to ATC and kinetostat data
+  //--------------------------------------------------------
+  VelocityRescaleCombined::VelocityRescaleCombined(AtomicRegulator * kinetostat) :
+    VelocityGlc(kinetostat),
+    velocity_(atc_->field(VELOCITY)),
+    thermostatCorrection_(NULL)
   {
-    kinetostat_.reset_nlocal();
-    thermostat_.reset_nlocal();
+    // do nothing
   }
+
   //--------------------------------------------------------
-  //  reset_atom_materials:
-  //    resets the localized atom to material map
+  //  initialize
+  //    initializes all data
   //--------------------------------------------------------
-  void KinetoThermostat::reset_atom_materials(const Array<int> & elementToMaterialMap,
-                                             const MatrixDependencyManager<DenseMatrix, int> * atomElement)
+  void VelocityRescaleCombined::initialize()
   {
-    kinetostat_.reset_atom_materials(elementToMaterialMap,
-                                     atomElement);
-    thermostat_.reset_atom_materials(elementToMaterialMap,
-                                     atomElement);
+    VelocityGlc::initialize();
+    thermostatCorrection_ = (atc_->interscale_manager()).dense_matrix("NodalAtomicFluctuatingMomentumRescaled");
   }
+
   //--------------------------------------------------------
-  //  construct_transfers:
-  //    pass through to appropriate transfer constuctors
+  //  set_kinetostat_rhs
+  //            sets up the right-hand side of the
+  //            kinetostat equations
   //--------------------------------------------------------
-  void KinetoThermostat::construct_transfers()
+  void VelocityRescaleCombined::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
-    kinetostat_.construct_transfers();
-    thermostat_.construct_transfers();
+    rhs = ((atc_->mass_mat_md(VELOCITY)).quantity())*(velocity_.quantity());
+    rhs -= thermostatCorrection_->quantity();
   }
+
+  //--------------------------------------------------------
   //--------------------------------------------------------
-  //  initialize:
-  //    sets up methods before a run
+  //  Class ThermostatRescaleCombined
   //--------------------------------------------------------
-  void KinetoThermostat::initialize()
+  //--------------------------------------------------------
+ 
+  //--------------------------------------------------------
+  //  Constructor
+  //--------------------------------------------------------
+  ThermostatRescaleCombined::ThermostatRescaleCombined(AtomicRegulator * thermostat) :
+    ThermostatRescale(thermostat),
+    kinetostatCorrection_(NULL)
   {
-    kinetostat_.initialize();
-    thermostat_.initialize();
-    needReset_ = false;
+    // do nothing
   }
+
   //--------------------------------------------------------
-  //  output:
-  //    pass through to appropriate output methods
+  //  initialize
+  //    initializes all data
   //--------------------------------------------------------
-  void KinetoThermostat::output(OUTPUT_LIST & outputData) const
+  void ThermostatRescaleCombined::initialize()
   {
-    kinetostat_.output(outputData);
-    thermostat_.output(outputData);
+    ThermostatRescale::initialize();
+    kinetostatCorrection_ = (atc_->interscale_manager()).dense_matrix("NodalAtomicCombinedRescaleThermostatError");
   }
+
   //--------------------------------------------------------
-  //  finish:
-  //    pass through to appropriate end-of-run methods
+  //  set_rhs:
+  //    constructs the RHS vector with the target
+  //    temperature
   //--------------------------------------------------------
-  void KinetoThermostat::finish()
+  void ThermostatRescaleCombined::set_rhs(DENS_MAT & rhs)
   {
-    kinetostat_.finish();
-    thermostat_.finish();
+    ThermostatRescale::set_rhs(rhs);
+    rhs -= kinetostatCorrection_->quantity();
   }
-    //--------------------------------------------------
-  // pack_fields
-  //   bundle all allocated field matrices into a list
-  //   for output needs
-  //--------------------------------------------------
-  void KinetoThermostat::pack_fields(RESTART_LIST & data)
+
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class KinetoThermostatRescale
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+ 
+  //--------------------------------------------------------
+  //  Constructor
+  //--------------------------------------------------------
+  KinetoThermostatRescale::KinetoThermostatRescale(AtomicRegulator * kinetoThermostat,
+                                                   int couplingMaxIterations) :
+    KinetoThermostatShapeFunction(kinetoThermostat,couplingMaxIterations),
+    atomVelocities_(NULL),
+    nodalVelocities_(atc_->field(VELOCITY)),
+    lambdaMomentum_(NULL),
+    lambdaEnergy_(NULL),
+    atomicFluctuatingVelocityRescaled_(NULL),
+    atomicStreamingVelocity_(NULL),
+    thermostat_(NULL),
+    kinetostat_(NULL)
   {
-    kinetostat_.pack_fields(data);
-    thermostat_.pack_fields(data);
+    thermostat_ = this->construct_rescale_thermostat();
+    kinetostat_ = new VelocityRescaleCombined(kinetoThermostat);
+    // data associated with stage 3 in ATC_Method::initialize
+    lambdaMomentum_ = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaMomentum",atc_->nsd());
+    lambdaEnergy_ = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaEnergy",1); 
   }
+
   //--------------------------------------------------------
-  //  compute_boundary_flux:
-  //    computes the boundary flux to be consistent with
-  //    the controller
+  //  Destructor
   //--------------------------------------------------------
-  void KinetoThermostat::compute_boundary_flux(FIELDS & fields)
+  KinetoThermostatRescale::~KinetoThermostatRescale()
   {
-    kinetostat_.compute_boundary_flux(fields);
-    thermostat_.compute_boundary_flux(fields);
+    if (thermostat_) delete thermostat_;
+    if (kinetostat_) delete kinetostat_;
   }
+
   //--------------------------------------------------------
-  //  add_to_rhs:
-  //    adds any controller contributions to the FE rhs 
+  //  constructor_transfers
+  //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
-  void KinetoThermostat::add_to_rhs(FIELDS & rhs)
+  void KinetoThermostatRescale::construct_transfers()
   {
-    thermostat_.add_to_rhs(rhs);
-    kinetostat_.add_to_rhs(rhs);
+    // construct independent transfers first
+    thermostat_->construct_transfers();
+    kinetostat_->construct_transfers();
+
+    InterscaleManager & interscaleManager(atc_->interscale_manager());
+
+    // get atom velocity data from manager
+    atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY);
+
+    // transfers requiring terms from both regulators
+    // rescaled velocity fluctuations
+    atomicFluctuatingVelocityRescaled_ = new AtomicFluctuatingVelocityRescaled(atc_);
+    interscaleManager.add_per_atom_quantity(atomicFluctuatingVelocityRescaled_,
+                                            "AtomFluctuatingVelocityRescaled");
+
+    // streaming velocity component
+    atomicStreamingVelocity_ = interscaleManager.per_atom_quantity("AtomLambdaMomentum");
+
+    // rescaled momentum fluctuations, error term for kinetostat rhs
+    PerAtomQuantity<double> * tempAtom = new AtomicMomentum(atc_,
+                                                            atomicFluctuatingVelocityRescaled_);
+    interscaleManager.add_per_atom_quantity(tempAtom,"AtomFluctuatingMomentumRescaled");
+    DENS_MAN * tempNodes = new AtfShapeFunctionRestriction(atc_,
+                                                           tempAtom,
+                                                           interscaleManager.per_atom_sparse_matrix("Interpolant"));
+    interscaleManager.add_dense_matrix(tempNodes,
+                                       "NodalAtomicFluctuatingMomentumRescaled");
+
+    // error term for thermostat rhs
+    tempAtom = new AtomicCombinedRescaleThermostatError(atc_);
+    interscaleManager.add_per_atom_quantity(tempAtom,"AtomCombinedRescaleThermostatError");
+    tempNodes = new AtfShapeFunctionRestriction(atc_,
+                                                tempAtom,
+                                                interscaleManager.per_atom_sparse_matrix("Interpolant"));
+    interscaleManager.add_dense_matrix(tempNodes,
+                                       "NodalAtomicCombinedRescaleThermostatError");
   }
+
   //--------------------------------------------------------
-  //  apply_pre_predictor:
-  //    applies the controller in the pre-predictor
-  //    phase of the time integrator  
+  //  construct_rescale_thermostat
+  //    constructs the appropriate rescaling thermostat
+  //    varied through inheritance
   //--------------------------------------------------------
-  void KinetoThermostat::apply_pre_predictor(double dt, int timeStep)
+  ThermostatRescale * KinetoThermostatRescale::construct_rescale_thermostat()
   {
-    thermostat_.apply_pre_predictor(dt,timeStep);
-    kinetostat_.apply_pre_predictor(dt,timeStep);
+    return new ThermostatRescaleCombined(atomicRegulator_);
   }
+
   //--------------------------------------------------------
-  //  apply_mid_predictor:
-  //    applies the controller in the mid-predictor
-  //    phase of the time integrator  
+  //  initialize
+  //    initializes all data
   //--------------------------------------------------------
-  void KinetoThermostat::apply_mid_predictor(double dt, int timeStep)
+  void KinetoThermostatRescale::initialize()
   {
-    thermostat_.apply_mid_predictor(dt,timeStep);
-    kinetostat_.apply_mid_predictor(dt,timeStep);
+    KinetoThermostatShapeFunction::initialize();
+    thermostat_->initialize();
+    kinetostat_->initialize();
   }
+
+  //--------------------------------------------------------
+  //  apply_post_corrector:
+  //    apply the thermostat in the post corrector phase
+  //--------------------------------------------------------
+  void KinetoThermostatRescale::apply_post_corrector(double dt)
+  {
+    // initial guesses
+    lambdaMomentum_->set_quantity() = nodalVelocities_.quantity();
+    lambdaEnergy_->set_quantity() = 1.;
+
+    int iteration = 0;
+    double eErr, pErr;
+    while (iteration < couplingMaxIterations_) {
+      _lambdaMomentumOld_ = lambdaMomentum_->quantity();
+      _lambdaEnergyOld_ = lambdaEnergy_->quantity();
+
+      // update thermostat
+      thermostat_->compute_thermostat(dt);
+      
+      // update kinetostat
+      kinetostat_->compute_kinetostat(dt);
+
+      // check convergence
+      _diff_ = lambdaEnergy_->quantity() - _lambdaEnergyOld_;
+      eErr = _diff_.col_norm()/_lambdaEnergyOld_.col_norm();
+      _diff_ = lambdaMomentum_->quantity() - _lambdaMomentumOld_;
+      pErr = _diff_.col_norm()/_lambdaMomentumOld_.col_norm();
+      if (eErr < tolerance_ && pErr < tolerance_) {
+        break;
+      }
+      iteration++;
+    }
+    if (iteration == couplingMaxIterations_) {
+      stringstream message;
+      message << "WARNING: Iterative solve for lambda failed to converge after " << couplingMaxIterations_ << " iterations, final tolerance was " << std::max(eErr,pErr) << "\n";
+      ATC::LammpsInterface::instance()->print_msg(message.str());
+    }
+
+    // application of rescaling lambda due
+    apply_to_atoms(atomVelocities_);
+  }
+
   //--------------------------------------------------------
-  //  apply_post_predictor:
-  //    applies the controller in the post-predictor
-  //    phase of the time integrator  
+  //  apply_lambda_to_atoms:
+  //    applies the velocity rescale with an existing lambda
+  //    note oldAtomicQuantity and dt are not used
   //--------------------------------------------------------
-  void KinetoThermostat::apply_post_predictor(double dt, int timeStep)
+  void KinetoThermostatRescale::apply_to_atoms(PerAtomQuantity<double> * atomVelocities)
   {
-    thermostat_.apply_post_predictor(dt,timeStep);
-    kinetostat_.apply_post_predictor(dt,timeStep);
+    *atomVelocities = atomicFluctuatingVelocityRescaled_->quantity() + atomicStreamingVelocity_->quantity();
   }
+
   //--------------------------------------------------------
-  //  apply_pre_corrector:
-  //    applies the controller in the pre-corrector phase
-  //    of the time integrator
+  //  output:
+  //    adds all relevant output to outputData
   //--------------------------------------------------------
-  void KinetoThermostat::apply_pre_corrector(double dt, int timeStep)
+  void KinetoThermostatRescale::output(OUTPUT_LIST & outputData)
   {
-    thermostat_.apply_pre_corrector(dt,timeStep);
-    kinetostat_.apply_pre_corrector(dt,timeStep);
+    thermostat_->output(outputData);
+    kinetostat_->output(outputData);
   }
+
   //--------------------------------------------------------
-  //  apply_post_corrector:
-  //    applies the controller in the post-corrector phase
-  //    of the time integrator
   //--------------------------------------------------------
-  void KinetoThermostat::apply_post_corrector(double dt, int timeStep)
+  //  Class ThermostatRescaleMixedKePeCombined
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+ 
+  //--------------------------------------------------------
+  //  Constructor
+  //--------------------------------------------------------
+  ThermostatRescaleMixedKePeCombined::ThermostatRescaleMixedKePeCombined(AtomicRegulator * thermostat) :
+    ThermostatRescaleMixedKePe(thermostat),
+    kinetostatCorrection_(NULL)
   {
-    thermostat_.apply_post_corrector(dt,timeStep);
-    kinetostat_.apply_post_corrector(dt,timeStep);
+    // do nothing
   }
+
   //--------------------------------------------------------
-  //  pre_exchange
+  //  initialize
+  //    initializes all data
   //--------------------------------------------------------
-  void KinetoThermostat::pre_exchange()
+  void ThermostatRescaleMixedKePeCombined::initialize()
   {
-    thermostat_.pre_exchange();
-    kinetostat_.pre_exchange();
+    ThermostatRescaleMixedKePe::initialize();
+    kinetostatCorrection_ = (atc_->interscale_manager()).dense_matrix("NodalAtomicCombinedRescaleThermostatError");
   }
+
   //--------------------------------------------------------
-  //  pre_force
+  //  set_rhs:
+  //    constructs the RHS vector with the target
+  //    temperature
   //--------------------------------------------------------
-  void KinetoThermostat::pre_force()
+  void ThermostatRescaleMixedKePeCombined::set_rhs(DENS_MAT & rhs)
   {
-    thermostat_.pre_force();
-    kinetostat_.pre_force();
+    ThermostatRescaleMixedKePe::set_rhs(rhs);
+    rhs -= kinetostatCorrection_->quantity();
   }
+
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class KinetoThermostatRescaleMixedKePe
+  //--------------------------------------------------------
   //--------------------------------------------------------
-  // coupling_mode
-  //-------------------------------------------------------
-  AtomicRegulator::RegulatorCouplingType KinetoThermostat::coupling_mode(const FieldName field) const
+
+  //--------------------------------------------------------
+  //  Constructor
+  //--------------------------------------------------------
+  KinetoThermostatRescaleMixedKePe::KinetoThermostatRescaleMixedKePe(AtomicRegulator * kinetoThermostat,
+                                                                     int couplingMaxIterations) :
+    KinetoThermostatRescale(kinetoThermostat,couplingMaxIterations)
   {
-    //TEMP_JAT
-    if (field==VELOCITY) {
-      return kinetostat_.coupling_mode();
-    }
-    else if (field == TEMPERATURE) {
-      return thermostat_.coupling_mode();
-    }
-    else {
-      throw ATC_Error("KinetoThermostat::coupling_mode - invalid field given");
+    // do nothing
+  }
+
+  //--------------------------------------------------------
+  //  construct_rescale_thermostat
+  //    constructs the appropriate rescaling thermostat
+  //    varied through inheritance
+  //--------------------------------------------------------
+  ThermostatRescale * KinetoThermostatRescaleMixedKePe::construct_rescale_thermostat()
+  {
+    return new ThermostatRescaleMixedKePeCombined(atomicRegulator_);
+  }
+
+
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class KinetoThermostatGlcFs
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+ 
+  //--------------------------------------------------------
+  //  Constructor
+  //--------------------------------------------------------
+  KinetoThermostatGlcFs::KinetoThermostatGlcFs(AtomicRegulator * kinetoThermostat,
+                                               int couplingMaxIterations,
+                                               const string & regulatorPrefix) :
+    KinetoThermostatShapeFunction(kinetoThermostat,couplingMaxIterations,regulatorPrefix),
+    velocity_(atc_->field(VELOCITY)),
+    temperature_(atc_->field(TEMPERATURE)),
+    timeFilter_(atomicRegulator_->time_filter()),
+    nodalAtomicLambdaForce_(NULL),
+    lambdaForceFiltered_(NULL),
+    nodalAtomicLambdaPower_(NULL),
+    lambdaPowerFiltered_(NULL),
+    atomRegulatorForces_(NULL),
+    atomThermostatForces_(NULL),
+    atomMasses_(NULL),
+    atomVelocities_(NULL),
+    isFirstTimestep_(true),
+    nodalAtomicMomentum_(NULL),
+    nodalAtomicEnergy_(NULL),
+    atomPredictedVelocities_(NULL),
+    nodalAtomicPredictedMomentum_(NULL),
+    nodalAtomicPredictedEnergy_(NULL),
+    firstHalfAtomForces_(NULL),
+    dtFactor_(0.)
+  {
+    // construct/obtain data corresponding to stage 3 of ATC_Method::initialize
+    //nodalAtomicLambdaPower_ = thermostat->regulator_data(regulatorPrefix_+"NodalAtomicLambdaPower",1);
+    //lambdaPowerFiltered_ = thermostat_->regulator_data(regulatorPrefix_+"LambdaPowerFiltered",1);
+  }
+
+  //--------------------------------------------------------
+  //  constructor_transfers
+  //    instantiates or obtains all dependency managed data
+  //--------------------------------------------------------
+  void KinetoThermostatGlcFs::construct_transfers()
+  {
+    // BASES INITIALIZE
+    // GRAB ANY COPIES FROM BASES
+
+    // TOTAL REGULATOR FORCE
+    // TOTAL FIRST HALF FORCE, IF NECESSARY
+  }
+
+  //--------------------------------------------------------
+  //  initialize
+  //    initializes all method data
+  //--------------------------------------------------------
+  void KinetoThermostatGlcFs::initialize()
+  {
+    RegulatorMethod::initialize();
+
+    // INITIALIZE BASES
+
+    // MAKE SURE ANY NEEDED POINTERS FROM BASES ARE COPIED BY HERE
+  }
+
+  //--------------------------------------------------------
+  //  apply_to_atoms:
+  //     determines what if any contributions to the
+  //     atomic moition is needed for
+  //     consistency with the thermostat
+  //     and computes the instantaneous induced power
+  //--------------------------------------------------------
+  void KinetoThermostatGlcFs::apply_to_atoms(PerAtomQuantity<double> * atomicVelocity,
+                                             const DENS_MAN * nodalAtomicMomentum,
+                                             const DENS_MAN * nodalAtomicEnergy,
+                                             const DENS_MAT & lambdaForce,
+                                             DENS_MAT & nodalAtomicLambdaForce,
+                                             DENS_MAT & nodalAtomicLambdaPower,
+                                             double dt)
+  {
+    // compute initial contributions to lambda force and power
+    nodalAtomicLambdaPower = nodalAtomicEnergy->quantity();
+    nodalAtomicLambdaPower *= -1.;
+    nodalAtomicLambdaForce = nodalAtomicMomentum->quantity();
+    nodalAtomicLambdaForce *= -1.;
+
+    // apply lambda force to atoms
+    _velocityDelta_ = lambdaForce;
+    _velocityDelta_ /= atomMasses_->quantity();
+    _velocityDelta_ *= dt;
+    (*atomicVelocity) += _velocityDelta_;
+
+    // finalize lambda force and power
+    nodalAtomicLambdaForce += nodalAtomicMomentum->quantity();
+    nodalAtomicLambdaPower += nodalAtomicEnergy->quantity();
+  }
+
+  //--------------------------------------------------------
+  //  full_prediction:
+  //    flag to perform a full prediction calcalation
+  //    for lambda rather than using the old value
+  //--------------------------------------------------------
+  bool KinetoThermostatGlcFs::full_prediction()
+  {
+    // CHECK BOTH BASES
+    return false;
+  }
+
+  //--------------------------------------------------------
+  //  apply_predictor:
+  //    apply the thermostat to the atoms in the first step
+  //    of the Verlet algorithm
+  //--------------------------------------------------------
+  void KinetoThermostatGlcFs::apply_pre_predictor(double dt)
+  {
+    DENS_MAT & lambdaForceFiltered(lambdaForceFiltered_->set_quantity());
+    DENS_MAT & nodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
+    DENS_MAT & myLambdaPowerFiltered(lambdaPowerFiltered_->set_quantity());
+    DENS_MAT & myNodalAtomicLambdaPower(nodalAtomicLambdaPower_->set_quantity());
+
+    // update filtered forces power, equivalent to measuring changes in momentum and energy
+    timeFilter_->apply_pre_step1(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
+    timeFilter_->apply_pre_step1(myLambdaPowerFiltered,myNodalAtomicLambdaPower,dt);
+
+    // apply lambda force to atoms and compute instantaneous lambda power for first half of time step
+    this->apply_to_atoms(atomVelocities_,nodalAtomicMomentum_,nodalAtomicEnergy_,
+                         firstHalfAtomForces_->quantity(),
+                         nodalAtomicLambdaForce,myNodalAtomicLambdaPower,0.5*dt);
+
+    // update nodal variables for first half of time step
+    // velocity
+    this->add_to_momentum(nodalAtomicLambdaForce,deltaMomentum_,0.5*dt);
+    atc_->apply_inverse_mass_matrix(deltaMomentum_,VELOCITY);
+    velocity_ += deltaMomentum_;
+    // temperature
+    this->add_to_energy(myNodalAtomicLambdaPower,deltaEnergy1_,0.5*dt);
+
+    // start update of filtered lambda force and power using temporary (i.e., 0 valued) quantities for first part of update
+    nodalAtomicLambdaForce = 0.;
+    timeFilter_->apply_post_step1(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
+    myNodalAtomicLambdaPower = 0.;
+    timeFilter_->apply_post_step1(myLambdaPowerFiltered,myNodalAtomicLambdaPower,dt);
+  }
+
+  //--------------------------------------------------------
+  //  apply_pre_corrector:
+  //    apply the thermostat to the atoms in the first part
+  //    of the corrector step of the Verlet algorithm
+  //--------------------------------------------------------
+  void KinetoThermostatGlcFs::apply_pre_corrector(double dt)
+  {
+    // CHECK WHEN CREATING PREDICTED VELOCITIES IN BASE REGULATORS, ONLY NEED ONE
+    (*atomPredictedVelocities_) = atomVelocities_->quantity();
+
+    // do full prediction if we just redid the shape functions
+    if (full_prediction()) {
+      this->compute_lambda(dt);
+      
+      atomThermostatForces_->unfix_quantity();  // allow update of atomic force applied by lambda
     }
+
+    // apply lambda force to atoms and compute instantaneous lambda power to predict second half of time step
+    DENS_MAT & myNodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
+    DENS_MAT & myNodalAtomicLambdaPower(nodalAtomicLambdaPower_->set_quantity());
+    apply_to_atoms(atomPredictedVelocities_,
+                   nodalAtomicPredictedMomentum_,nodalAtomicPredictedEnergy_,
+                   firstHalfAtomForces_->quantity(),
+                   myNodalAtomicLambdaForce,myNodalAtomicLambdaPower,0.5*dt);
+
+    if (full_prediction())
+      atomThermostatForces_->fix_quantity();
+    
+    // SPLIT OUT FUNCTION TO CREATE DELTA VARIABLES IN BASES, ONLY NEED THESE
+    // update predicted nodal variables for second half of time step
+    // velocity
+    this->add_to_momentum(myNodalAtomicLambdaForce,deltaMomentum_,0.5*dt);
+    atc_->apply_inverse_mass_matrix(deltaMomentum_,VELOCITY);
+    velocity_ += deltaMomentum_;
+    // temperature
+    this->add_to_energy(myNodalAtomicLambdaPower,deltaEnergy2_,0.5*dt);
+    // following manipulations performed this way for efficiency
+    deltaEnergy1_ += deltaEnergy2_;
+    atc_->apply_inverse_mass_matrix(deltaEnergy1_,TEMPERATURE);
+    temperature_ += deltaEnergy1_;
+  }
+
+  //--------------------------------------------------------
+  //  apply_post_corrector:
+  //    apply the thermostat to the atoms in the second part
+  //    of the corrector step of the Verlet algorithm
+  //--------------------------------------------------------
+  void KinetoThermostatGlcFs::apply_post_corrector(double dt)
+  {
+    // remove predicted power effects
+    // velocity
+    DENS_MAT & myVelocity(velocity_.set_quantity());
+    myVelocity -= deltaMomentum_;
+    // temperature
+    DENS_MAT & myTemperature(temperature_.set_quantity());
+    atc_->apply_inverse_mass_matrix(deltaEnergy2_,TEMPERATURE);
+    myTemperature -= deltaEnergy2_;
+
+    // set up equation and update lambda
+    this->compute_lambda(dt);
+
+    // apply lambda force to atoms and compute instantaneous lambda power for second half of time step
+    DENS_MAT & nodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
+    DENS_MAT & myNodalAtomicLambdaPower(nodalAtomicLambdaPower_->set_quantity());
+    // allow computation of force applied by lambda using current velocities
+    atomThermostatForces_->unfix_quantity();
+    atomThermostatForces_->quantity();
+    atomThermostatForces_->fix_quantity();
+    apply_to_atoms(atomVelocities_,nodalAtomicMomentum_,nodalAtomicEnergy_,
+                   atomRegulatorForces_->quantity(),
+                   nodalAtomicLambdaForce,myNodalAtomicLambdaPower,0.5*dt);
+
+    // finalize filtered lambda force and power by adding latest contribution
+    timeFilter_->apply_post_step2(lambdaForceFiltered_->set_quantity(),
+                                  nodalAtomicLambdaForce,dt);
+    timeFilter_->apply_post_step2(lambdaPowerFiltered_->set_quantity(),
+                                  myNodalAtomicLambdaPower,dt);
+
+    // update nodal variables for second half of time step
+    // velocity
+    this->add_to_momentum(nodalAtomicLambdaForce,deltaMomentum_,0.5*dt);
+    atc_->apply_inverse_mass_matrix(deltaMomentum_,VELOCITY);
+    velocity_ += deltaMomentum_;
+    // temperature
+    this->add_to_energy(myNodalAtomicLambdaPower,deltaEnergy2_,0.5*dt);
+    atc_->apply_inverse_mass_matrix(deltaEnergy2_,TEMPERATURE);
+    myTemperature += deltaEnergy2_;
+    
+    
+    isFirstTimestep_ = false;
+  }
+
+  //--------------------------------------------------------
+  //  compute_lambda:
+  //   sets up and solves linear system for lambda, if the
+  //   bool is true it iterators to a non-linear solution
+  //--------------------------------------------------------
+  void KinetoThermostatGlcFs::compute_lambda(double dt,
+                                       bool iterateSolution)
+  {
+    // ITERATIVE SOLUTION
+  }
+
+  //--------------------------------------------------------
+  //  output:
+  //    adds all relevant output to outputData
+  //--------------------------------------------------------
+  void KinetoThermostatGlcFs::output(OUTPUT_LIST & outputData)
+  {
+    // DO NOT CALL INDIVIDUAL REGULATORS
+    // OUTPUT TOTAL FORCE AND TOTAL POWER 
+    // OUTPUT EACH LAMBDA
   }
 
+
 };
diff --git a/lib/atc/KinetoThermostat.h b/lib/atc/KinetoThermostat.h
index 00c43f666..465da6b49 100644
--- a/lib/atc/KinetoThermostat.h
+++ b/lib/atc/KinetoThermostat.h
@@ -1,689 +1,798 @@
 #ifndef KINETOTHERMOSTAT_H
 #define KINETOTHERMOSTAT_H
 
 #include "AtomicRegulator.h"
 #include "PerAtomQuantityLibrary.h"
-//TEMP_JAT - transitional headers until we have a new method
 #include "Kinetostat.h"
 #include "Thermostat.h"
 #include <map>
 #include <set>
 #include <string>
 
 namespace ATC {
-/* #ifdef WIP_JAT */
-/*   static const int myLambdaMaxIterations = 50; */
-/* #endif */
+
+  static const int myCouplingMaxIterations = 50;
+
   // forward declarations
   class MomentumTimeIntegrator;
   class ThermalTimeIntegrator;
   class AtfShapeFunctionRestriction;
   class FundamentalAtomQuantity;
   class PrescribedDataManager;
 
   /**
    *  @class  KinetoThermostat
    *  @brief  Manager class for atom-continuum simulataneous control of momentum and thermal energy
    */
   class KinetoThermostat : public AtomicRegulator {
   
   public:
 
     // constructor
     KinetoThermostat(ATC_Coupling * atc,
                      const std::string & regulatorPrefix = "");
         
     // destructor
     virtual ~KinetoThermostat(){};
         
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
 
     /** instantiate up the desired method(s) */
     virtual void construct_methods();
 
-    //TEMP_JAT - required temporarily while we have two regulators
-    
-    /** initialization of method data */
-    virtual void initialize();
-    /** method(s) create all necessary transfer operators */
-    virtual void construct_transfers();
-    /** reset number of local atoms, as well as atomic data */
-    virtual void reset_nlocal();
-    /** set up atom to material identification */
-    virtual void reset_atom_materials(const Array<int> & elementToMaterialMap,
-                                      const MatrixDependencyManager<DenseMatrix, int> * atomElement);
-    /** apply the regulator in the pre-predictor phase */
-    virtual void apply_pre_predictor(double dt, int timeStep);
-    /** apply the regulator in the mid-predictor phase */
-    virtual void apply_mid_predictor(double dt, int timeStep);
-    /** apply the regulator in the post-predictor phase */
-    virtual void apply_post_predictor(double dt, int timeStep);
-    /** apply the regulator in the pre-correction phase */
-    virtual void apply_pre_corrector(double dt, int timeStep);
-    /** apply the regulator in the post-correction phase */
-    virtual void apply_post_corrector(double dt, int timeStep);
-    /** prior to exchanges */
-    virtual void pre_exchange();
-    /** prior to force calculation */
-    virtual void pre_force();
-    /** force a reset to occur */
-    void force_reset() {kinetostat_.force_reset();thermostat_.force_reset();};
-    /** compute the thermal boundary flux, must be consistent with regulator */
-    virtual void compute_boundary_flux(FIELDS & fields);
-    /** type of boundary coupling */
-    virtual RegulatorCouplingType coupling_mode(const FieldName) const;
-    virtual void output(OUTPUT_LIST & outputData) const;
-    /** final work at the end of a run */
-    virtual void finish();
-    /** add contributions (if any) to the finite element right-hand side */
-    virtual void add_to_rhs(FIELDS & rhs);
-
-    /** pack fields for restart */
-    virtual void pack_fields(RESTART_LIST & data);
         
     // data access, intended for method objects
     /** reset the nodal power to a prescribed value */
     virtual void reset_lambda_contribution(const DENS_MAT & target,
                                            const FieldName field);
-    //TEMP_JAT - will use real accessor
-    /** return value for the correction maximum number of iterations */
-    int lambda_max_iterators() {return thermostat_.lambda_max_iterations();};
+
+    /** return value for the max number of mechanical/thermal coupling iterations */
+    int coupling_max_iterations() const {return couplingMaxIterations_;};
 
   protected:
 
-    //TEMP_JAT - individual controllers for now
-    Kinetostat kinetostat_;
-    Thermostat thermostat_;
+    /** maximum number of iterations used to solved coupled thermo/mechanical problem */
+    int couplingMaxIterations_;
+
   private:
     
     // DO NOT define this
     KinetoThermostat();
         
   };
-/* #ifdef WIP_JAT */
-/*   /\** */
-/*    *  @class  ThermostatShapeFunction */
-/*    *  @brief  Class for thermostat algorithms using the shape function matrices */
-/*    *          (thermostats have general for of N^T w N lambda = rhs) */
-/*    *\/ */
+
+  /**
+   *  @class  KinetoThermostatShapeFunction
+   *  @brief  Class for kinetostat/thermostat algorithms using the shape function matrices
+   *          (thermostats have general for of N^T w N lambda = rhs)
+   */
   
-/*   class ThermostatShapeFunction : public RegulatorShapeFunction { */
+  class KinetoThermostatShapeFunction : public RegulatorMethod {
 
   
-/*   public: */
+  public:
   
-/*     ThermostatShapeFunction(Thermostat * thermostat, */
-/*                             const std::string & regulatorPrefix = ""); */
+    KinetoThermostatShapeFunction(AtomicRegulator * kinetoThermostat,
+                                  int couplingMaxIterations,
+                                  const std::string & regulatorPrefix = "") : RegulatorMethod(kinetoThermostat),
+      couplingMaxIterations_(couplingMaxIterations) {};
         
-/*     virtual ~ThermostatShapeFunction() {}; */
+    virtual ~KinetoThermostatShapeFunction() {};
 
-/*     /\** instantiate all needed data *\/ */
-/*     virtual void construct_transfers(); */
+    /** instantiate all needed data */
+    virtual void construct_transfers() = 0;
 
-/*   protected: */
+    /** initialize all data */
+    virtual void initialize() {tolerance_ = atomicRegulator_->tolerance();};
 
-/*     // methods */
-/*     /\** set weighting factor for in matrix Nhat^T * weights * Nhat *\/ */
-/*     virtual void set_weights(); */
+  protected:
 
-/*     // member data */
-/*     /\** pointer to thermostat object for data *\/ */
-/*     Thermostat * thermostat_; */
+    /** maximum number of iterations between energy and momentum regulators */
+    int couplingMaxIterations_;
 
-/*     
-/*     /\** MD mass matrix *\/ */
-/*     DIAG_MAN & mdMassMatrix_;  
+    /** tolerance */
+    double tolerance_;
 
-/*     /\** pointer to atom velocities *\/ */
-/*     FundamentalAtomQuantity * atomVelocities_; */
+  private:
 
-/*     /\** workspace variables *\/ */
-/*     DENS_VEC _weightVector_, _maskedWeightVector_; */
+    // DO NOT define this
+    KinetoThermostatShapeFunction();
 
-/*   private: */
+  };
 
-/*     // DO NOT define this */
-/*     ThermostatShapeFunction(); */
+  /**
+   *  @class  VelocityRescaleCombined
+   *  @brief  Enforces constraints on atomic velocity based on FE temperature and velocity
+   */
+  
+  class VelocityRescaleCombined : public VelocityGlc {
+  
+  public:
 
-/*   }; */
+    friend class KinetoThermostatRescale; // since this is basically a set of member functions for friend
+  
+    VelocityRescaleCombined(AtomicRegulator * kinetostat);
+        
+    virtual ~VelocityRescaleCombined(){};
 
-/*   /\** */
-/*    *  @class  ThermostatRescale */
-/*    *  @brief  Enforces constraint on atomic kinetic energy based on FE temperature */
-/*    *\/ */
+    /** pre-run initialization of method data */
+    virtual void initialize();
+    
+    /** applies kinetostat to atoms */
+    virtual void apply_mid_predictor(double dt){};
+    /** applies kinetostat to atoms */
+    virtual void apply_post_corrector(double dt){};
+    
+    /** local shape function matrices are incompatible with this mode */
+    virtual bool use_local_shape_functions() const {return false;};
+
+  protected:
+
+    // data
+    /** reference to AtC FE velocity */
+    DENS_MAN & velocity_;
+    
+    /** RHS correct based on thermostat */
+    DENS_MAN * thermostatCorrection_;
+  
+    // methods
+    /** sets up appropriate rhs for kinetostat equations */
+    virtual void set_kinetostat_rhs(DENS_MAT & rhs, double dt);
+
+    // disable un-needed functionality
+    /** does initial filtering operations before main computation */
+    virtual void apply_pre_filtering(double dt){};
+    /** applies kinetostat correction to atoms */
+    virtual void apply_kinetostat(double dt) {};
+    /** computes the nodal FE force applied by the kinetostat */
+    virtual void compute_nodal_lambda_force(double dt){};
+    /** apply any required corrections for localized kinetostats */
+    virtual void apply_localization_correction(const DENS_MAT & source,
+                                               DENS_MAT & nodalField,
+                                               double weight = 1.){};
+
+  private:
+
+    // DO NOT define this
+    VelocityRescaleCombined();
+  
+  };
+
+  /**
+   *  @class  ThermostatRescaleCombined
+   *  @brief  Enforces constraint on atomic kinetic energy based on FE temperature and velocity
+   */
   
-/*   class ThermostatRescale : public ThermostatShapeFunction { */
+  class ThermostatRescaleCombined : public ThermostatRescale {
   
-/*   public: */
+  public:
   
-/*     ThermostatRescale(Thermostat * thermostat); */
+    ThermostatRescaleCombined(AtomicRegulator * thermostat);
         
-/*     virtual ~ThermostatRescale() {}; */
+    virtual ~ThermostatRescaleCombined() {};
 
-/*     /\** instantiate all needed data *\/ */
-/*     virtual void construct_transfers(); */
+    /** pre-run initialization of method data */
+    virtual void initialize();
         
-/*     /\** applies thermostat to atoms in the post-corrector phase *\/ */
-/*     virtual void apply_post_corrector(double dt); */
-/* #ifdef WIP_JAT */
-/*     /\** compute boundary flux, requires thermostat input since it is part of the coupling scheme *\/ */
-/*     virtual void compute_boundary_flux(FIELDS & fields) */
-/*       {boundaryFlux_[TEMPERATURE] = 0.;}; */
-/* #endif */
+    // deactivate un-needed methods
+    /** applies thermostat to atoms in the post-corrector phase */
+    virtual void apply_post_corrector(double dt){};
+        
+  protected:
 
-/*     /\** get data for output *\/ */
-/*     virtual void output(OUTPUT_LIST & outputData); */
+    // data
+    /** RHS correct based on kinetostat */
+    DENS_MAN * kinetostatCorrection_;
+
+    // deactivate un-needed methods
+    /** apply solution to atomic quantities */
+    virtual void apply_to_atoms(PerAtomQuantity<double> * atomVelocities){};
+
+    /** construct the RHS vector */
+    virtual void set_rhs(DENS_MAT & rhs);
+
+  private:
+
+    // DO NOT define this
+    ThermostatRescaleCombined();
+  
+  };
+
+  /**
+   *  @class  KinetoThermostatRescale
+   *  @brief  Enforces constraints on atomic kinetic energy and velocity based on FE temperature and velocity
+   */
+  
+  class KinetoThermostatRescale : public KinetoThermostatShapeFunction {
+  
+  public:
+  
+    KinetoThermostatRescale(AtomicRegulator * kinetoThermostat,
+                            int couplingMaxIterations);
         
-/*   protected: */
+    virtual ~KinetoThermostatRescale();
 
-/*     /\** apply solution to atomic quantities *\/ */
-/*     void apply_to_atoms(PerAtomQuantity<double> * atomVelocities); */
+    /** instantiate all needed data */
+    virtual void construct_transfers();
 
-/*     /\** correct the RHS for complex temperature definitions *\/ */
-/*     virtual void correct_rhs(DENS_MAT & rhs) {};  // base class does no correction, assuming kinetic definition */
+    /** pre-run initialization of method data */
+    virtual void initialize();
         
-/*     /\** FE temperature field *\/ */
-/*     DENS_MAN & nodalTemperature_; */
+    /** applies thermostat to atoms in the post-corrector phase */
+    virtual void apply_post_corrector(double dt);
 
-/*     /\** construction for prolongation of lambda to atoms *\/ */
-/*     AtomicVelocityRescaleFactor * atomVelocityRescalings_; */
+    /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
+    virtual void compute_boundary_flux(FIELDS & fields)
+    {boundaryFlux_[TEMPERATURE] = 0.; boundaryFlux_[VELOCITY] = 0.;};
 
-/*     /\** workspace variables *\/ */
-/*     DENS_MAT _rhs_; */
+    /** get data for output */
+    virtual void output(OUTPUT_LIST & outputData);
+        
+  protected:
 
-/*   private: */
+    // methods
+    /** apply solution to atomic quantities */
+    virtual void apply_to_atoms(PerAtomQuantity<double> * atomVelocities);
 
-/*     // DO NOT define this */
-/*     ThermostatRescale(); */
+    /** creates the appropriate rescaling thermostat */
+    virtual ThermostatRescale * construct_rescale_thermostat();
+
+    // data
+    /** pointer to atom velocities */
+    FundamentalAtomQuantity * atomVelocities_;
+
+    /** clone of FE velocity field */
+    DENS_MAN & nodalVelocities_;
+
+    /** lambda coupling parameter for momentum */
+    DENS_MAN * lambdaMomentum_;
+
+    /** lambda coupling parameter for energy */
+    DENS_MAN * lambdaEnergy_;
+
+    /** pointer to rescaled velocity fluctuations */
+    PerAtomQuantity<double> * atomicFluctuatingVelocityRescaled_;
+
+    /** pointer to streaming velocity */
+    PerAtomQuantity<double> * atomicStreamingVelocity_;
+
+    /** rescaling thermostat */
+    ThermostatRescale * thermostat_;
+
+    /** velocity regulating kinetostat */
+    VelocityRescaleCombined * kinetostat_;
+
+    // workspace
+    DENS_MAT _lambdaEnergyOld_, _lambdaMomentumOld_, _diff_;
+
+  private:
+
+    // DO NOT define this
+    KinetoThermostatRescale();
   
-/*   }; */
+  };
 
-/*   /\** */
-/*    *  @class  ThermostatRescaleMixedKePe */
-/*    *  @brief  Enforces constraint on atomic kinetic energy based on FE temperature */
-/*    *          when the temperature is a mix of the KE and PE */
-/*    *\/ */
+  /**
+   *  @class  ThermostatRescaleMixedKePeCombined
+   *  @brief  Enforces constraint on atomic kinetic energy based on FE temperature and velocity when the temperature is comprised of both KE and PE contributions
+   */
   
-/*   class ThermostatRescaleMixedKePe : public ThermostatRescale { */
+  class ThermostatRescaleMixedKePeCombined : public ThermostatRescaleMixedKePe {
   
-/*   public: */
+  public:
   
-/*     ThermostatRescaleMixedKePe(Thermostat * thermostat); */
+    ThermostatRescaleMixedKePeCombined(AtomicRegulator * thermostat);
         
-/*     virtual ~ThermostatRescaleMixedKePe() {}; */
-
-/*     /\** instantiate all needed data *\/ */
-/*     virtual void construct_transfers(); */
+    virtual ~ThermostatRescaleMixedKePeCombined() {};
 
-/*     /\** pre-run initialization of method data *\/ */
-/*     virtual void initialize(); */
+    /** pre-run initialization of method data */
+    virtual void initialize();
         
-/*   protected: */
+    // deactivate un-needed methods
+    /** applies thermostat to atoms in the post-corrector phase */
+    virtual void apply_post_corrector(double dt){};
+        
+  protected:
 
-/*     /\** correct the RHS for inclusion of the PE *\/ */
-/*     virtual void correct_rhs(DENS_MAT & rhs); */
+    // data
+    /** RHS correct based on kinetostat */
+    DENS_MAN * kinetostatCorrection_;
 
-/*     /\** nodal fluctuating potential energy *\/ */
-/*     DENS_MAN * nodalAtomicFluctuatingPotentialEnergy_; */
+    // deactivate un-needed methods
+    /** apply solution to atomic quantities */
+    virtual void apply_to_atoms(PerAtomQuantity<double> * atomVelocities){};
 
-/*     /\** fraction of temperature from KE *\/ */
-/*     double keMultiplier_; */
+    /** construct the RHS vector */
+    virtual void set_rhs(DENS_MAT & rhs);
 
-/*     /\** fraction of temperature from PE *\/ */
-/*     double peMultiplier_; */
+  private:
 
-/*   private: */
+    // DO NOT define this
+    ThermostatRescaleMixedKePeCombined();
+  
+  };
 
-/*     // DO NOT define this */
-/*     ThermostatRescaleMixedKePe(); */
+  /**
+   *  @class  KinetoThermostatRescaleMixedKePe
+   *  @brief  Enforces constraint on atomic kinetic energy based on FE temperature
+   *          when the temperature is a mix of the KE and PE
+   */
   
-/*   }; */
+  class KinetoThermostatRescaleMixedKePe : public KinetoThermostatRescale {
+  
+  public:
+  
+    KinetoThermostatRescaleMixedKePe(AtomicRegulator * kinetoThermostat,
+                                     int couplingMaxIterations);
 
-/*   /\** */
-/*    *  @class  ThermostatGlcFs */
-/*    *  @brief  Class for thermostat algorithms based on Gaussian least constraints (GLC) for fractional step (FS) algorithsm */
-/*    *\/ */
+    virtual ~KinetoThermostatRescaleMixedKePe() {};
+        
+  protected:
+
+    /** creates the appropriate rescaling thermostat */
+    virtual ThermostatRescale * construct_rescale_thermostat();
+
+  private:
+
+    // DO NOT define this
+    KinetoThermostatRescaleMixedKePe();
+  
+  };
+
+  /**
+   *  @class  KinetoThermostatGlcFs
+   *  @brief  Class for regulation algorithms based on Gaussian least constraints (GLC) for fractional step (FS) algorithsm
+   */
   
-/*   class ThermostatGlcFs : public ThermostatShapeFunction { */
+  class KinetoThermostatGlcFs : public KinetoThermostatShapeFunction {
   
-/*   public: */
+  public:
   
-/*     ThermostatGlcFs(Thermostat * thermostat, */
-/*                     const std::string & regulatorPrefix = ""); */
+    KinetoThermostatGlcFs(AtomicRegulator * kinetoThermostat,
+                          int couplingMaxIterations,
+                          const std::string & regulatorPrefix = "");
         
-/*     virtual ~ThermostatGlcFs() {}; */
+    virtual ~KinetoThermostatGlcFs() {};
 
-/*     /\** instantiate all needed data *\/ */
-/*     virtual void construct_transfers(); */
+    /** instantiate all needed data */
+    virtual void construct_transfers();
 
-/*     /\** pre-run initialization of method data *\/ */
-/*     virtual void initialize(); */
+    /** pre-run initialization of method data */
+    virtual void initialize();
 
-/*     /\** applies thermostat to atoms in the predictor phase *\/ */
-/*     virtual void apply_pre_predictor(double dt); */
+    /** applies thermostat to atoms in the predictor phase */
+    virtual void apply_pre_predictor(double dt);
 
-/*     /\** applies thermostat to atoms in the pre-corrector phase *\/ */
-/*     virtual void apply_pre_corrector(double dt); */
+    /** applies thermostat to atoms in the pre-corrector phase */
+    virtual void apply_pre_corrector(double dt);
 
-/*     /\** applies thermostat to atoms in the post-corrector phase *\/ */
-/*     virtual void apply_post_corrector(double dt); */
+    /** applies thermostat to atoms in the post-corrector phase */
+    virtual void apply_post_corrector(double dt);
     
-/*     /\** get data for output *\/ */
-/*     virtual void output(OUTPUT_LIST & outputData); */
+    /** get data for output */
+    virtual void output(OUTPUT_LIST & outputData);
 
-/*     /\* flag for performing the full lambda prediction calculation *\/ */
-/*     bool full_prediction(); */
+    /* flag for performing the full lambda prediction calculation */
+    bool full_prediction();
 
-/*   protected: */
+  protected:
 
-/*     // methods */
-/*     /\** determine mapping from all nodes to those to which the thermostat applies *\/ */
-/*     void compute_rhs_map(); */
+    // methods
 
-/*     /\** sets up appropriate rhs for thermostat equations *\/ */
-/*     virtual void set_thermostat_rhs(DENS_MAT & rhs, */
-/*                                     double dt) = 0; */
+    /** apply forces to atoms */
+    virtual void apply_to_atoms(PerAtomQuantity<double> * atomicVelocity,
+                                const DENS_MAN * nodalAtomicMomentum,
+                                const DENS_MAN * nodalAtomicEnergy,
+                                const DENS_MAT & lambdaForce,
+                                DENS_MAT & nodalAtomicLambdaForce,
+                                DENS_MAT & nodalAtomicLambdaPower,
+                                double dt);
 
-/*     /\** apply forces to atoms *\/ */
-/*     virtual void apply_to_atoms(PerAtomQuantity<double> * atomicVelocity, */
-/*                                 const DENS_MAN * nodalAtomicEnergy, */
-/*                                 const DENS_MAT & lambdaForce, */
-/*                                 DENS_MAT & nodalAtomicLambdaPower, */
-/*                                 double dt); */
+    // USE BASE CLASSES FOR THESE
+    /** add contributions from regulator to FE momentum */
+    virtual void add_to_momentum(const DENS_MAT & nodalLambdaForce,
+                               DENS_MAT & deltaForce,
+                               double dt) = 0;
 
-/*     /\** add contributions from thermostat to FE energy *\/ */
-/*     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower, */
-/*                                DENS_MAT & deltaEnergy, */
-/*                                double dt) = 0; */
+    /** add contributions from regulator to FE energy */
+    virtual void add_to_energy(const DENS_MAT & nodalLambdaPower,
+                               DENS_MAT & deltaEnergy,
+                               double dt) = 0;
 
-/*     /\* sets up and solves the linear system for lambda *\/ */
-/*     virtual void compute_lambda(double dt, */
-/*                                 bool iterateSolution = true); */
+    /* sets up and solves the linear system for lambda */
+    virtual void compute_lambda(double dt,
+                                bool iterateSolution = true);
 
-/*     /\** solves the non-linear equation for lambda iteratively *\/ */
-/*     void iterate_lambda(const MATRIX & rhs); */
+    // member data
+    /** reference to AtC FE velocity */
+    DENS_MAN & velocity_;
 
-/*     // member data */
-/*     /\** reference to AtC FE temperature *\/ */
-/*     DENS_MAN & temperature_; */
+    /** reference to AtC FE temperature */
+    DENS_MAN & temperature_;
 
-/*     /\** pointer to a time filtering object *\/ */
-/*     TimeFilter * timeFilter_; */
+    /** pointer to a time filtering object */
+    TimeFilter * timeFilter_;
 
-/*     /\** power induced by lambda *\/ */
-/*     DENS_MAN * nodalAtomicLambdaPower_; */
+    /** force induced by lambda */
+    DENS_MAN * nodalAtomicLambdaForce_;
 
-/*     /\** filtered lambda power *\/ */
-/*     DENS_MAN * lambdaPowerFiltered_; */
+    /** filtered lambda force */
+    DENS_MAN * lambdaForceFiltered_;
 
-/*     /\** atomic force induced by lambda *\/ */
-/*     AtomicThermostatForce * atomThermostatForces_; */
+    /** power induced by lambda */
+    DENS_MAN * nodalAtomicLambdaPower_;
 
-/*     /\** pointer to atom masses *\/ */
-/*     FundamentalAtomQuantity * atomMasses_; */
+    /** filtered lambda power */
+    DENS_MAN * lambdaPowerFiltered_;
 
-/*     /\** pointer to the values of lambda interpolated to atoms *\/ */
-/*     DENS_MAN * rhsLambdaSquared_; */
+    /** atomic force induced by lambda */
+    AtomicThermostatForce * atomRegulatorForces_;
 
-/*     /\** hack to determine if first timestep has been passed *\/ */
-/*     bool isFirstTimestep_; */
+    /** atomic force induced by thermostat lambda */
+    AtomicThermostatForce * atomThermostatForces_;
 
-/*     /\** maximum number of iterations used in iterative solve for lambda *\/ */
-/*     int lambdaMaxIterations_; */
+    /** pointer to atom masses */
+    FundamentalAtomQuantity * atomMasses_;
 
-/*     /\** nodal atomic energy *\/ */
-/*     DENS_MAN * nodalAtomicEnergy_; */
+    /** pointer to atom velocities */
+    FundamentalAtomQuantity * atomVelocities_;
 
-/*     /\** local version of velocity used as predicted final veloctiy *\/ */
-/*     PerAtomQuantity<double> * atomPredictedVelocities_; */
+    /** hack to determine if first timestep has been passed */
+    bool isFirstTimestep_;
 
-/*     /\** predicted nodal atomic energy *\/ */
-/*     AtfShapeFunctionRestriction * nodalAtomicPredictedEnergy_; */
+    /** nodal atomic momentum */
+    DENS_MAN * nodalAtomicMomentum_;
 
-/*     /\** pointer for force applied in first time step *\/ */
-/*     DENS_MAN * firstHalfAtomForces_; */
+    /** nodal atomic energy */
+    DENS_MAN * nodalAtomicEnergy_;
 
-/*     /\** FE temperature change from thermostat during predictor phase in second half of timestep *\/ */
-/*     DENS_MAT deltaEnergy1_; */
+    /** local version of velocity used as predicted final veloctiy */
+    PerAtomQuantity<double> * atomPredictedVelocities_;
 
-/*     /\** FE temperature change from thermostat during corrector phase in second half of timestep *\/ */
-/*     DENS_MAT deltaEnergy2_; */
+    /** predicted nodal atomic momentum */
+    AtfShapeFunctionRestriction * nodalAtomicPredictedMomentum_;
 
-/*     /\** right-hand side data for thermostat equation *\/ */
-/*     DENS_MAT rhs_; */
+    /** predicted nodal atomic energy */
+    AtfShapeFunctionRestriction * nodalAtomicPredictedEnergy_;
 
-/*     /\** mapping from all to regulated nodes *\/ */
-/*     DENS_MAT rhsMap_; */
+    /** pointer for force applied in first time step */
+    DENS_MAN * firstHalfAtomForces_;
 
-/*     /\** fraction of timestep over which constraint is exactly enforced *\/ */
-/*     double dtFactor_; */
+    /** FE momentum change from regulator during predictor phase in second half of timestep */
+    DENS_MAT deltaMomentum_;
 
-/*     // workspace */
-/*     DENS_MAT _lambdaPowerOutput_; // power applied by lambda in output format */
-/*     DENS_MAT _velocityDelta_; // change in velocity when lambda force is applied */
-/*     DENS_VEC _lambdaOverlap_; // lambda in MD overlapping FE nodes */
-/*     DENS_MAT _lambdaOld_; // lambda from previous iteration */
-/*     DENS_MAT _rhsOverlap_; // normal RHS vector mapped to overlap nodes */
-/*     DENS_VEC _rhsTotal_; // normal + 2nd order RHS for the iteration loop */
+    /** FE temperature change from regulator during predictor phase in second half of timestep */
+    DENS_MAT deltaEnergy1_;
 
-/*   private: */
+    /** FE temperature change from regulator during corrector phase in second half of timestep */
+    DENS_MAT deltaEnergy2_;
 
-/*     // DO NOT define this */
-/*     ThermostatGlcFs(); */
+    /** fraction of timestep over which constraint is exactly enforced */
+    double dtFactor_;
 
-/*   }; */
+    // workspace
+    DENS_MAT _lambdaForceOutput_; // force applied by lambda in output format
+    DENS_MAT _lambdaPowerOutput_; // power applied by lambda in output format
+    DENS_MAT _velocityDelta_; // change in velocity when lambda force is applied
 
+  private:
+
+    // DO NOT define this
+    KinetoThermostatGlcFs();
+
+  };
+/* #ifdef WIP_JAT */
 /*   /\** */
 /*    *  @class  ThermostatFlux */
 /*    *  @brief  Class enforces GLC on atomic forces based on FE power when using fractional step time integration */
 /*    *\/ */
 
 /*   class ThermostatFlux : public ThermostatGlcFs { */
   
 /*   public: */
   
 /*     ThermostatFlux(Thermostat * thermostat, */
 /*                    const std::string & regulatorPrefix = ""); */
         
 /*     virtual ~ThermostatFlux() {}; */
 
 /*     /\** instantiate all needed data *\/ */
 /*     virtual void construct_transfers(); */
 
 /*     /\** pre-run initialization of method data *\/ */
 /*     virtual void initialize(); */
        
 /*   protected: */
 
 /*     /\** sets up appropriate rhs for thermostat equations *\/ */
 /*     virtual void set_thermostat_rhs(DENS_MAT & rhs, */
 /*                                     double dt); */
 
 /*     /\** add contributions from thermostat to FE energy *\/ */
 /*     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower, */
 /*                                DENS_MAT & deltaEnergy, */
 /*                                double dt); */
 
 /*     /\** sets up the transfer which is the set of nodes being regulated *\/ */
 /*     virtual void construct_regulated_nodes(); */
 
 /*     // data */
 /*     /\** reference to ATC sources coming from prescribed data, AtC coupling, and extrinsic coupling *\/ */
 /*     DENS_MAN & heatSource_; */
 
 /*   private: */
 
 /*     // DO NOT define this */
 /*     ThermostatFlux(); */
 
 /*   }; */
 
 /*   /\** */
 /*    *  @class  ThermostatFixed */
 /*    *  @brief  Class enforces GLC on atomic forces based on FE power when using fractional step time integration */
 /*    *\/ */
 
 /*   class ThermostatFixed : public ThermostatGlcFs { */
   
 /*   public: */
   
 /*     ThermostatFixed(Thermostat * thermostat, */
 /*                     const std::string & regulatorPrefix = ""); */
         
 /*     virtual ~ThermostatFixed() {}; */
 
 /*     /\** instantiate all needed data *\/ */
 /*     virtual void construct_transfers(); */
 
 /*     /\** pre-run initialization of method data *\/ */
 /*     virtual void initialize(); */
         
 /*     /\** applies thermostat to atoms in the predictor phase *\/ */
 /*     virtual void apply_pre_predictor(double dt); */
 
 /*     /\** applies thermostat to atoms in the pre-corrector phase *\/ */
 /*     virtual void apply_pre_corrector(double dt); */
 
 /*     /\** applies thermostat to atoms in the post-corrector phase *\/ */
 /*     virtual void apply_post_corrector(double dt); */
 
 /*     /\** compute boundary flux, requires thermostat input since it is part of the coupling scheme *\/ */
 /*     virtual void compute_boundary_flux(FIELDS & fields) */
 /*       {boundaryFlux_[TEMPERATURE] = 0.;}; */
 
 /*     /\** determine if local shape function matrices are needed *\/ */
 /*     virtual bool use_local_shape_functions() const {return atomicRegulator_->use_localized_lambda();}; */
         
 /*   protected: */
 
 /*     // methods */
 /*     /\** initialize data for tracking the change in nodal atomic temperature *\/ */
 /*     virtual void initialize_delta_nodal_atomic_energy(double dt); */
 
 /*     /\** compute the change in nodal atomic temperature *\/ */
 /*     virtual void compute_delta_nodal_atomic_energy(double dt); */
 
 /*     /\** sets up appropriate rhs for thermostat equations *\/ */
 /*     virtual void set_thermostat_rhs(DENS_MAT & rhs, */
 /*                                     double dt); */
 
 /*     /\** add contributions from thermostat to FE energy *\/ */
 /*     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower, */
 /*                                DENS_MAT & deltaEnergy, */
 /*                                double dt); */
 
 /*     /\* sets up and solves the linear system for lambda *\/ */
 /*     virtual void compute_lambda(double dt, */
 /*                                 bool iterateSolution = true); */
 
 /*     /\** flag for halving the applied force to mitigate numerical errors *\/ */
 /*     bool halve_force(); */
 
 /*     /\** sets up the transfer which is the set of nodes being regulated *\/ */
 /*     virtual void construct_regulated_nodes(); */
 
 /*     // data */
 /*     /\** change in FE energy over a timestep *\/ */
 /*     DENS_MAT deltaFeEnergy_; */
 
 /*     /\** initial FE energy used to compute change *\/ */
 /*     DENS_MAT initialFeEnergy_; */
 
 /*     /\** change in restricted atomic FE energy over a timestep *\/ */
 /*     DENS_MAT deltaNodalAtomicEnergy_; */
 
 /*     /\** intial restricted atomic FE energy used to compute change *\/ */
 /*     DENS_MAT initialNodalAtomicEnergy_; */
 
 /*     /\** filtered nodal atomic energy *\/ */
 /*     DENS_MAN nodalAtomicEnergyFiltered_; */
 
 /*     /\** forces depending on predicted velocities for correct updating with fixed nodes *\/ */
 /*     AtomicThermostatForce * atomThermostatForcesPredVel_; */
 
 /*     /\** coefficient to account for effect of time filtering on rhs terms *\/ */
 /*     double filterCoefficient_; */
 
 /*     /\** kinetic energy multiplier in total energy (used for temperature expression) *\/ */
 /*     double keMultiplier_; */
 
 /*     // workspace */
 /*     DENS_MAT _tempNodalAtomicEnergyFiltered_; // stores filtered energy change in atoms for persistence during predictor */
 
 /*   private: */
 
 /*     // DO NOT define this */
 /*     ThermostatFixed(); */
 
 /*   }; */
 
 /*   /\** */
 /*    *  @class  ThermostatFluxFiltered */
 /*    *  @brief  Class enforces GLC on atomic forces based on FE power when using fractional step time integration */
 /*    *          in conjunction with time filtering */
 /*    *\/ */
 
 /*   class ThermostatFluxFiltered : public ThermostatFlux { */
   
 /*   public: */
   
 /*     ThermostatFluxFiltered(Thermostat * thermostat, */
 /*                            const std::string & regulatorPrefix = ""); */
         
 /*     virtual ~ThermostatFluxFiltered() {}; */
 
 /*     /\** pre-run initialization of method data *\/ */
 /*     virtual void initialize(); */
 
 /*     /\** applies thermostat to atoms in the post-corrector phase *\/ */
 /*     virtual void apply_post_corrector(double dt); */
 
 /*     /\** get data for output *\/ */
 /*     virtual void output(OUTPUT_LIST & outputData); */
        
 /*   protected: */
 
 /*     /\** sets up appropriate rhs for thermostat equations *\/ */
 /*     virtual void set_thermostat_rhs(DENS_MAT & rhs, */
 /*                                     double dt); */
 
 /*     /\** add contributions from thermostat to FE energy *\/ */
 /*     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower, */
 /*                                DENS_MAT & deltaEnergy, */
 /*                                double dt); */
 
 /*     // data */
 /*     /\** heat source time history required to get instantaneous heat sources *\/ */
 /*     DENS_MAT heatSourceOld_; */
 /*     DENS_MAT instantHeatSource_; */
 /*     DENS_MAT timeStepSource_; */
 
 /*   private: */
 
 /*     // DO NOT define this */
 /*     ThermostatFluxFiltered(); */
 
 /*   }; */
 
 /*   /\** */
 /*    *  @class  ThermostatFixedFiltered */
 /*    *  @brief  Class for thermostatting using the temperature matching constraint and is compatible with */
 /*  the fractional step time-integration with time filtering */
 /*    *\/ */
   
 /*   class ThermostatFixedFiltered : public ThermostatFixed { */
   
 /*   public: */
   
 /*     ThermostatFixedFiltered(Thermostat * thermostat, */
 /*                             const std::string & regulatorPrefix = ""); */
         
 /*     virtual ~ThermostatFixedFiltered() {}; */
 
 /*     /\** get data for output *\/ */
 /*     virtual void output(OUTPUT_LIST & outputData); */
         
 /*   protected: */
 
 /*     // methods */
 /*     /\** initialize data for tracking the change in nodal atomic temperature *\/ */
 /*     virtual void initialize_delta_nodal_atomic_energy(double dt); */
 
 /*     /\** compute the change in nodal atomic temperature *\/ */
 /*     virtual void compute_delta_nodal_atomic_energy(double dt); */
 
 /*     /\** sets up appropriate rhs for thermostat equations *\/ */
 /*     virtual void set_thermostat_rhs(DENS_MAT & rhs, */
 /*                                     double dt); */
 
 /*     /\** add contributions from thermostat to temperature for uncoupled nodes *\/ */
 /*     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower, */
 /*                                DENS_MAT & deltaEnergy, */
 /*                                double dt); */
 
 /*   private: */
 
 /*     // DO NOT define this */
 /*     ThermostatFixedFiltered(); */
 
 /*   }; */
 
 /*   /\** */
 /*    *  @class  ThermostatFluxFixed */
 /*    *  @brief  Class for thermostatting using the temperature matching constraint one one set of nodes and the flux matching constraint on another */
 /*    *\/ */
 
 /*   class ThermostatFluxFixed : public RegulatorMethod { */
 
 /*   public: */
 
 /*     ThermostatFluxFixed(Thermostat * thermostat, */
 /*                         bool constructThermostats = true); */
         
 /*     virtual ~ThermostatFluxFixed(); */
 
 /*     /\** instantiate all needed data *\/ */
 /*     virtual void construct_transfers(); */
 
 /*     /\** pre-run initialization of method data *\/ */
 /*     virtual void initialize(); */
 
 /*     /\** applies thermostat to atoms in the predictor phase *\/ */
 /*     virtual void apply_pre_predictor(double dt); */
 
 /*     /\** applies thermostat to atoms in the pre-corrector phase *\/ */
 /*     virtual void apply_pre_corrector(double dt); */
 
 /*     /\** applies thermostat to atoms in the post-corrector phase *\/ */
 /*     virtual void apply_post_corrector(double dt); */
     
 /*     /\** get data for output *\/ */
 /*     virtual void output(OUTPUT_LIST & outputData); */
 
 /*     /\** compute boundary flux, requires thermostat input since it is part of the coupling scheme *\/ */
 /*     virtual void compute_boundary_flux(FIELDS & fields) */
 /*       {thermostatBcs_->compute_boundary_flux(fields);}; */
 
 /*   protected: */
 
 /*     // data */
 /*     /\** thermostat for imposing the fluxes *\/ */
 /*     ThermostatFlux * thermostatFlux_; */
 
 /*     /\** thermostat for imposing fixed nodes *\/ */
 /*     ThermostatFixed * thermostatFixed_; */
 
 /*     /\** pointer to whichever thermostat should compute the flux, based on coupling method *\/ */
 /*     ThermostatGlcFs * thermostatBcs_; */
 
 /*   private: */
 
 /*     // DO NOT define this */
 /*     ThermostatFluxFixed(); */
 /*   }; */
 
 /*   /\** */
 /*    *  @class  ThermostatFluxFixedFiltered */
 /*    *  @brief  Class for thermostatting using the temperature matching constraint one one set of nodes and the flux matching constraint on another with time filtering */
 /*    *\/ */
 
 /*   class ThermostatFluxFixedFiltered : public ThermostatFluxFixed { */
 
 /*   public: */
 
 /*     ThermostatFluxFixedFiltered(Thermostat * thermostat); */
         
 /*     virtual ~ThermostatFluxFixedFiltered(){}; */
 
 /*   private: */
 
 /*     // DO NOT define this */
 /*     ThermostatFluxFixedFiltered(); */
 
 /*   }; */
 /* #endif */
 
 };
 
 #endif
diff --git a/lib/atc/Kinetostat.cpp b/lib/atc/Kinetostat.cpp
index c104efc72..17c5b6caf 100644
--- a/lib/atc/Kinetostat.cpp
+++ b/lib/atc/Kinetostat.cpp
@@ -1,2246 +1,2508 @@
 #include "Kinetostat.h"
 #include "ATC_Error.h"
 #include "ATC_Coupling.h"
 #include "LammpsInterface.h"
 #include "PerAtomQuantityLibrary.h"
 #include "PrescribedDataManager.h"
 #include "ElasticTimeIntegrator.h"
 #include "TransferOperator.h"
 
 using std::set;
 using std::pair;
 using std::string;
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class Kinetostat
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   Kinetostat::Kinetostat(ATC_Coupling * atc,
                          const string & regulatorPrefix) :
     AtomicRegulator(atc,regulatorPrefix)
   {
     // do nothing
   }
   
   //--------------------------------------------------------
   //  modify:
   //    parses and adjusts kinetostat state based on
   //    user input, in the style of LAMMPS user input
   //--------------------------------------------------------
   bool Kinetostat::modify(int narg, char **arg)
   {
     bool foundMatch = false;
 
     int argIndex = 0;
     if (strcmp(arg[argIndex],"momentum")==0) {
       argIndex++;
 
       // fluxstat type
       /*! \page man_control_momentum fix_modify AtC control momentum
         \section syntax
         fix_modify AtC control momentum none \n
       
         fix_modify AtC control momentum rescale <frequency>\n
         - frequency (int) = time step frequency for applying displacement and velocity rescaling \n
       
         fix_modify AtC control momentum glc_displacement \n
   
         fix_modify AtC control momentum glc_velocity \n
 
         fix_modify AtC control momentum hoover \n
 
         fix_modify AtC control momentum flux [faceset face_set_id, interpolate] 
         - face_set_id (string) = id of boundary face set, if not specified
         (or not possible when the atomic domain does not line up with 
         mesh boundaries) defaults to an atomic-quadrature approximate 
         evaulation\n
         \section examples
         fix_modify AtC control momentum glc_velocity \n
         fix_modify AtC control momentum flux faceset bndy_faces \n
         \section description
         \section restrictions
         only to be used with specific transfers :
         elastic \n
         rescale not valid with time filtering activated
         \section related
         \section default
         none
       */
       boundaryIntegrationType_ = NO_QUADRATURE;
       howOften_ = 1;
       if (strcmp(arg[argIndex],"none")==0) { // restore defaults
         regulatorTarget_ = NONE;
         couplingMode_ = UNCOUPLED;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"glc_displacement")==0) {
         regulatorTarget_ = FIELD;
         couplingMode_ = FIXED;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"glc_velocity")==0) {
         regulatorTarget_ = DERIVATIVE;
         couplingMode_ = FIXED;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"hoover")==0) {
         regulatorTarget_ = DYNAMICS;
         couplingMode_ = FIXED;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"flux")==0) {
         regulatorTarget_ = DYNAMICS;
         couplingMode_ = FLUX;
         argIndex++;
         boundaryIntegrationType_ = atc_->parse_boundary_integration(narg-argIndex,&arg[argIndex],boundaryFaceSet_);
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"ghost_flux")==0) {
         regulatorTarget_ = DYNAMICS;
         couplingMode_ = GHOST_FLUX;
         foundMatch = true;
       }
     }
   
     if (!foundMatch)
       foundMatch = AtomicRegulator::modify(narg,arg);
     if (foundMatch)
       needReset_ = true;
     return foundMatch;
   }
 
   //--------------------------------------------------------
   //  reset_lambda_contribution
   //    resets the kinetostat generated force to a
   //    prescribed value
   //--------------------------------------------------------
   void Kinetostat::reset_lambda_contribution(const DENS_MAT & target)
   {
     DENS_MAN * lambdaForceFiltered = regulator_data("LambdaForceFiltered",nsd_);
     lambdaForceFiltered->set_quantity() = target;
   }
  
   //--------------------------------------------------------
   //  initialize:
   //    sets up methods before a run
   
   //    dependence, but in general there is also a
   //    time integrator dependence.  In general the 
   //    precedence order is:
   //    time filter -> time integrator -> kinetostat
   //    In the future this may need to be added if
   //    different types of time integrators can be
   //    specified.
   //--------------------------------------------------------
   void Kinetostat::construct_methods()
   {
     // get data associated with stages 1 & 2 of ATC_Method::initialize
     AtomicRegulator::construct_methods();
 
     if (atc_->reset_methods()) {
       // eliminate existing methods
       delete_method();
       
       DENS_MAT nodalGhostForceFiltered;
       TimeIntegrator::TimeIntegrationType myIntegrationType = (atc_->time_integrator(VELOCITY))->time_integration_type();
       TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
       if (timeFilterManager->end_equilibrate() && regulatorTarget_==AtomicRegulator::DYNAMICS) {
         StressFlux * myMethod;
         myMethod = dynamic_cast<StressFlux *>(regulatorMethod_);
         nodalGhostForceFiltered = (myMethod->filtered_ghost_force()).quantity();
       }
       
       // update time filter
       
       if (timeFilterManager->need_reset()) {
-        
-        timeFilter_ = timeFilterManager->construct(TimeFilterManager::IMPLICIT_UPDATE);
+        if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
+          timeFilter_ = timeFilterManager->construct(TimeFilterManager::EXPLICIT_IMPLICIT);
+        }
+        else {
+          timeFilter_ = timeFilterManager->construct(TimeFilterManager::IMPLICIT_UPDATE);
+        }
       }
                          
       if (timeFilterManager->filter_dynamics()) {
         switch (regulatorTarget_) {
         case NONE: {
           regulatorMethod_ = new RegulatorMethod(this);
           break;
         }
         case FIELD: {
           regulatorMethod_ = new DisplacementGlcFiltered(this);
           break;
         }
         case DERIVATIVE: {
           regulatorMethod_ = new VelocityGlcFiltered(this);
           break;
         }
         case DYNAMICS: {
           throw ATC_Error("Kinetostat::initialize - force based kinetostats not yet implemented with time filtering");
           regulatorMethod_ = new StressFluxFiltered(this);
           if (timeFilterManager->end_equilibrate()) {
             StressFlux * myMethod;
             myMethod = dynamic_cast<StressFlux *>(regulatorMethod_);
             myMethod->reset_filtered_ghost_force(nodalGhostForceFiltered);
           }
           break;
         }
         default:
-          throw ATC_Error("Unknown kinetostat type in Kinetostat::initialize");
+          throw ATC_Error("Kinetostat::construct_methods - Unknown filtered kinetostat type");
         }
       }
       else {
         switch (regulatorTarget_) {
         case NONE: {
           regulatorMethod_ = new RegulatorMethod(this);
           break;
         }
         case FIELD: {
           regulatorMethod_ = new DisplacementGlc(this);
           break;
         }
         case DERIVATIVE: {
           regulatorMethod_ = new VelocityGlc(this);
           break;
         }
         case DYNAMICS: {
           if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
             if (couplingMode_ == GHOST_FLUX) {
-              regulatorMethod_ = new KinetostatFluxGhost(this);
+              if (md_fixed_nodes(VELOCITY)) {
+                if (!md_flux_nodes(VELOCITY) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
+                  // there are fixed nodes but no fluxes
+                  regulatorMethod_ = new KinetostatFixed(this);
+                }
+                else {
+                  // there are both fixed and flux nodes
+                  regulatorMethod_ = new KinetostatFluxFixed(this);
+                }
+              }
+              else {
+                // there are only flux nodes
+                regulatorMethod_ = new KinetostatFluxGhost(this);
+              }
             }
             else if (couplingMode_ == FIXED) {
-              regulatorMethod_ = new KinetostatFixed(this);
+              if (md_flux_nodes(VELOCITY)) {
+                if (!md_fixed_nodes(VELOCITY) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
+                  // there are fluxes but no fixed or coupled nodes
+                  regulatorMethod_ = new KinetostatFlux(this);
+                }
+                else {
+                  // there are both fixed and flux nodes
+                  regulatorMethod_ = new KinetostatFluxFixed(this);
+                }
+              }
+              else {
+                // there are only fixed nodes
+                regulatorMethod_ = new KinetostatFixed(this);
+              }
             }
             else if (couplingMode_ == FLUX) {
-              regulatorMethod_ = new KinetostatFlux(this);
+              if (md_fixed_nodes(VELOCITY)) {
+                if (!md_flux_nodes(VELOCITY) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
+                  // there are fixed nodes but no fluxes
+                  regulatorMethod_ = new KinetostatFixed(this);
+                }
+                else {
+                  // there are both fixed and flux nodes
+                  regulatorMethod_ = new KinetostatFluxFixed(this);
+                }
+              }
+              else {
+                // there are only flux nodes
+                regulatorMethod_ = new KinetostatFlux(this);
+              }
             }
             break;
           }
           if (myIntegrationType == TimeIntegrator::GEAR) {
             if (couplingMode_ == FIXED) {
               regulatorMethod_ = new KinetostatFixed(this);
             }
             else if (couplingMode_ == FLUX) {
               regulatorMethod_ = new KinetostatFlux(this);
             }
             break;
           }
           else {
             if (couplingMode_ == GHOST_FLUX) {
               regulatorMethod_ = new StressFluxGhost(this);
             }
             else {
               regulatorMethod_ = new StressFlux(this);
             }
             break;
           }
         }
         default:
-          throw ATC_Error("Unknown kinetostat type in Kinetostat::initialize");
+          throw ATC_Error("Kinetostat::construct_methods - Unknown kinetostat type");
         }
         AtomicRegulator::reset_method();
       }
     }
     else {
       set_all_data_to_used();
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class KinetostatShapeFunction
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  KinetostatShapeFunction::KinetostatShapeFunction(Kinetostat *kinetostat,
+  KinetostatShapeFunction::KinetostatShapeFunction(AtomicRegulator *kinetostat,
                                                    const string & regulatorPrefix) :
     RegulatorShapeFunction(kinetostat,regulatorPrefix),
-    kinetostat_(kinetostat),
+    mdMassMatrix_(atc_->set_mass_mat_md(VELOCITY)),
     timeFilter_(atomicRegulator_->time_filter()),
     nodalAtomicLambdaForce_(NULL),
     lambdaForceFiltered_(NULL),
     atomKinetostatForce_(NULL),
     atomVelocities_(NULL),
     atomMasses_(NULL)
   {
     // data associated with stage 3 in ATC_Method::initialize
-    lambda_ = kinetostat->regulator_data(regulatorPrefix_+"LambdaMomentum",nsd_);
-    lambdaForceFiltered_ = kinetostat_->regulator_data("LambdaForceFiltered",nsd_);
+    lambda_ = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaMomentum",nsd_);
+    lambdaForceFiltered_ = atomicRegulator_->regulator_data("LambdaForceFiltered",nsd_);
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void KinetostatShapeFunction::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // needed fundamental quantities
     atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY);
     atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS);
 
     // base class transfers
     RegulatorShapeFunction::construct_transfers();
 
     // lambda interpolated to the atomic coordinates
     atomLambdas_ = new FtaShapeFunctionProlongation(atc_,
                                                    lambda_,
                                                     interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_per_atom_quantity(atomLambdas_,
                                             regulatorPrefix_+"AtomLambdaMomentum");
   }
 
   //--------------------------------------------------------
   //  set_weights
   //            sets diagonal weighting matrix used in
   //            solve_for_lambda
   //--------------------------------------------------------
   void KinetostatShapeFunction::set_weights()
   {
     if (this->use_local_shape_functions()) {
       ConstantQuantityMapped<double> * myWeights = new ConstantQuantityMapped<double>(atc_,1.,lambdaAtomMap_);
       weights_ = myWeights;
       (atc_->interscale_manager()).add_per_atom_quantity(myWeights,
                                                          "AtomOnesMapped");
     }
     else {
       weights_ = (atc_->interscale_manager()).per_atom_quantity("AtomicOnes");
       if (!weights_) {
         weights_ = new ConstantQuantity<double>(atc_,1.);
         (atc_->interscale_manager()).add_per_atom_quantity(weights_,
                                                            "AtomicOnes");
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class GlcKinetostat
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  GlcKinetostat::GlcKinetostat(Kinetostat *kinetostat) :
+  GlcKinetostat::GlcKinetostat(AtomicRegulator *kinetostat) :
     KinetostatShapeFunction(kinetostat),
-    mdMassMatrix_(atc_->set_mass_mat_md(VELOCITY)),
     atomPositions_(NULL)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void GlcKinetostat::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // needed fundamental quantities
     atomPositions_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_POSITION);
     
     // base class transfers
     KinetostatShapeFunction::construct_transfers();
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void GlcKinetostat::initialize()
   {
     KinetostatShapeFunction::initialize();
 
     
     // set up list of nodes using Hoover coupling
     // (a) nodes with prescribed values
     PrescribedDataManager * prescribedDataMgr(atc_->prescribed_data_manager());
     for (int i = 0; i < nNodes_; ++i)
       for (int j = 0; j < nsd_; ++j)
         if (prescribedDataMgr->is_fixed(i,VELOCITY,j))
           hooverNodes_.insert(pair<int,int>(i,j));
 
     // (b) AtC coupling nodes
     if (atomicRegulator_->coupling_mode()==AtomicRegulator::FIXED) {
       InterscaleManager & interscaleManager(atc_->interscale_manager());
       const INT_ARRAY & nodeType((interscaleManager.dense_matrix_int("NodalGeometryType"))->quantity());
       if (atomicRegulator_->use_localized_lambda()) {
         for (int i = 0; i < nNodes_; ++i) {
           if (nodeType(i,0)==BOUNDARY) {
             for (int j = 0; j < nsd_; ++j) {
               hooverNodes_.insert(pair<int,int>(i,j));
             }
           }
         }
       }
       else {
         for (int i = 0; i < nNodes_; ++i) {
           if (nodeType(i,0)==BOUNDARY || nodeType(i,0)==MD_ONLY) {
             for (int j = 0; j < nsd_; ++j) {
               hooverNodes_.insert(pair<int,int>(i,j));
             }
           }
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //  apply_lambda_to_atoms
   //            uses existing lambda to modify given
   //            atomic quantity
   //--------------------------------------------------------
   void GlcKinetostat::apply_to_atoms(PerAtomQuantity<double> * quantity,
                                      const DENS_MAT & lambdaAtom,
                                      double dt)
   {
     *quantity -= lambdaAtom;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class DisplacementGlc
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  DisplacementGlc::DisplacementGlc(Kinetostat * kinetostat) :
+  DisplacementGlc::DisplacementGlc(AtomicRegulator * kinetostat) :
     GlcKinetostat(kinetostat),
     nodalAtomicMassWeightedDisplacement_(NULL),
     nodalDisplacements_(atc_->field(DISPLACEMENT))
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void DisplacementGlc::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
     // set up shape function matrix
     if (this->use_local_shape_functions()) {
       lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
       interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
                                                   regulatorPrefix_+"LambdaAtomMap");
       shapeFunctionMatrix_ = new LocalLambdaCouplingMatrix(atc_,
                                                            lambdaAtomMap_,
                                                            nodeToOverlapMap_);
     }
     else {
       shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
     }
     interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
                                                  regulatorPrefix_+"LambdaCouplingMatrixMomentum");
 
     // set linear solver strategy
     if (atomicRegulator_->use_lumped_lambda_solve()) {
       linearSolverType_ = AtomicRegulator::RSL_SOLVE;
     }
     else {
       linearSolverType_ = AtomicRegulator::CG_SOLVE;
     }
     
 
     // base class transfers
     GlcKinetostat::construct_transfers();
 
     // atomic force induced by kinetostat
     atomKinetostatForce_ = new AtomicKinetostatForceDisplacement(atc_);
     interscaleManager.add_per_atom_quantity(atomKinetostatForce_,
                                             regulatorPrefix_+"AtomKinetostatForce");
         
     // restricted force due to kinetostat
     nodalAtomicLambdaForce_ = new AtfShapeFunctionRestriction(atc_,
                                                               atomKinetostatForce_,
                                                               interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_dense_matrix(nodalAtomicLambdaForce_,
                                        regulatorPrefix_+"NodalAtomicLambdaForce");
     
     // nodal displacement restricted from atoms
     nodalAtomicMassWeightedDisplacement_ = interscaleManager.dense_matrix("NodalAtomicMassWeightedDisplacement");
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void DisplacementGlc::initialize()
   {
     GlcKinetostat::initialize();
 
     // sets up time filter for cases where variables temporally filtered
     TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
     if (!timeFilterManager->end_equilibrate()) {
       *lambdaForceFiltered_ = 0.;
       timeFilter_->initialize(lambdaForceFiltered_->quantity());
     }
   }
 
   //--------------------------------------------------------
   //  apply:
   //    apply the kinetostat to the atoms
   //--------------------------------------------------------
   void DisplacementGlc::apply_post_predictor(double dt)
   {
     compute_kinetostat(dt);
   }
 
   //--------------------------------------------------------
   //  compute_kinetostat
   //            manages the solution and application of the
   //            kinetostat equations and variables
   //--------------------------------------------------------
   void DisplacementGlc::compute_kinetostat(double dt)
   {
     // initial filtering update
     apply_pre_filtering(dt);
 
     // set up rhs
     DENS_MAT rhs(nNodes_,nsd_);
     set_kinetostat_rhs(rhs,dt);
 
     // solve linear system for lambda
     solve_for_lambda(rhs,lambda_->set_quantity());
 
     // compute nodal atomic power
     compute_nodal_lambda_force(dt);
 
     // apply kinetostat to atoms
     apply_to_atoms(atomPositions_,atomLambdas_->quantity());
   }
 
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the right-hand side of the
   //            kinetostat equations
   //--------------------------------------------------------
   void DisplacementGlc::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // form rhs : sum_a (hatN_Ia * x_ai) - (Upsilon)_Ii
     rhs = nodalAtomicMassWeightedDisplacement_->quantity();
-    rhs -= ((atc_->mass_mat_md(VELOCITY)).quantity())*(nodalDisplacements_.quantity());
+    rhs -= (mdMassMatrix_.quantity())*(nodalDisplacements_.quantity());
   }
 
   //--------------------------------------------------------
   //  compute_nodal_lambda_force
   //            compute the effective FE force applied
   //            by the kinetostat
   //--------------------------------------------------------
   void DisplacementGlc::compute_nodal_lambda_force(double dt)
   {
     const DENS_MAT & myNodalAtomicLambdaForce(nodalAtomicLambdaForce_->quantity());
     timeFilter_->apply_post_step1(lambdaForceFiltered_->set_quantity(),
                                   myNodalAtomicLambdaForce,dt);
 
     // update FE displacements for localized thermostats
     apply_localization_correction(myNodalAtomicLambdaForce,
                                   nodalDisplacements_.set_quantity(),
                                   dt*dt);
   }
 
   //--------------------------------------------------------
   //  apply_pre_filtering
   //            applies first step of filtering to
   //            relevant variables
   //--------------------------------------------------------
   void DisplacementGlc::apply_pre_filtering(double dt)
   {
     // apply time filtered lambda force
     DENS_MAT lambdaZero(nNodes_,nsd_);
     timeFilter_->apply_pre_step1(lambdaForceFiltered_->set_quantity(),(-1./dt/dt)*lambdaZero,dt);
   }
 
   //--------------------------------------------------------
   //  set_weights
   //            sets diagonal weighting matrix used in
   //            solve_for_lambda
   //--------------------------------------------------------
   void DisplacementGlc::set_weights()
   {
     if (lambdaAtomMap_) {
       MappedAtomQuantity * myWeights = new MappedAtomQuantity(atc_,atomMasses_,lambdaAtomMap_);
       weights_ = myWeights;
       (atc_->interscale_manager()).add_per_atom_quantity(myWeights,
                                                          "AtomMassesMapped");
     }
     else {
       weights_ = atomMasses_;
     }
   }
 
   //--------------------------------------------------------
   //  apply_localization_correction
   //            corrects for localized kinetostats only
   //            solving kinetostat equations on a subset
   //            of the MD region
   //--------------------------------------------------------
   void DisplacementGlc::apply_localization_correction(const DENS_MAT & source,
                                                       DENS_MAT & nodalField,
                                                       double weight)
   {
     
     DENS_MAT nodalLambdaRoc(nNodes_,nsd_);
     atc_->apply_inverse_mass_matrix(source,
                                     nodalLambdaRoc,
                                     VELOCITY);
     set<pair<int,int> >::const_iterator iter;
     for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
       nodalLambdaRoc(iter->first,iter->second) = 0.;
     }
 
     nodalField += weight*nodalLambdaRoc;
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void DisplacementGlc::output(OUTPUT_LIST & outputData)
   {
     _nodalAtomicLambdaForceOut_ = nodalAtomicLambdaForce_->quantity();
     DENS_MAT & lambda(lambda_->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
-      outputData[regulatorPrefix_+"Lambda"] = &lambda;
+      outputData[regulatorPrefix_+"LambdaMomentum"] = &lambda;
       outputData[regulatorPrefix_+"NodalLambdaForce"] = &(_nodalAtomicLambdaForceOut_);
     }
   }
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class DisplacementGlcFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  DisplacementGlcFiltered::DisplacementGlcFiltered(Kinetostat * kinetostat) :
+  DisplacementGlcFiltered::DisplacementGlcFiltered(AtomicRegulator * kinetostat) :
     DisplacementGlc(kinetostat),
     nodalAtomicDisplacements_(atc_->nodal_atomic_field(DISPLACEMENT))
   {
     // do nothing
   }
  
   //--------------------------------------------------------
   //  apply_pre_filtering
   //            applies first step of filtering to
   //            relevant variables
   //--------------------------------------------------------
   void DisplacementGlcFiltered::apply_pre_filtering(double dt)
   {
     // apply time filtered lambda to atomic fields
     DisplacementGlc::apply_pre_filtering(dt);
     DENS_MAT nodalAcceleration(nNodes_,nsd_);
     atc_->apply_inverse_md_mass_matrix(lambdaForceFiltered_->set_quantity(),
                                        nodalAcceleration,
                                        VELOCITY);
     nodalAtomicDisplacements_ += dt*dt*nodalAcceleration;
   }
 
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the right-hand side of the
   //            kinetostat equations
   //--------------------------------------------------------
   void DisplacementGlcFiltered::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // form rhs : sum_a (hatN_Ia * x_ai) - (Upsilon)_Ii
     double coef = 1./(timeFilter_->unfiltered_coefficient_pre_s1(dt));
-    rhs = coef*((atc_->mass_mat_md(VELOCITY)).quantity())*(nodalAtomicDisplacements_.quantity() - nodalDisplacements_.quantity());
+    rhs = coef*(mdMassMatrix_.quantity())*(nodalAtomicDisplacements_.quantity() - nodalDisplacements_.quantity());
   }
 
   //--------------------------------------------------------
   //  compute_nodal_lambda_force
   //            compute the effective FE force applied
   //            by the kinetostat
   //--------------------------------------------------------
   void DisplacementGlcFiltered::compute_nodal_lambda_force(double dt)
   {
     const DENS_MAT & myNodalAtomicLambdaForce(nodalAtomicLambdaForce_->quantity());
     DENS_MAT & myLambdaForceFiltered(lambdaForceFiltered_->set_quantity());
     timeFilter_->apply_post_step1(myLambdaForceFiltered,
                                   myNodalAtomicLambdaForce,dt);
 
     // update filtered atomic displacements
     DENS_MAT nodalLambdaRoc(myNodalAtomicLambdaForce.nRows(),myNodalAtomicLambdaForce.nCols());
     atc_->apply_inverse_md_mass_matrix(myNodalAtomicLambdaForce,
                                        nodalLambdaRoc,
                                        VELOCITY);
     timeFilter_->apply_post_step1(nodalAtomicDisplacements_.set_quantity(),dt*dt*nodalLambdaRoc,dt);
 
     // update FE displacements for localized thermostats
     apply_localization_correction(myLambdaForceFiltered,
                                   nodalDisplacements_.set_quantity(),
                                   dt*dt);
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void DisplacementGlcFiltered::output(OUTPUT_LIST & outputData)
   {
     DENS_MAT & lambda(lambda_->set_quantity());
     DENS_MAT & lambdaForceFiltered(lambdaForceFiltered_->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
-      outputData[regulatorPrefix_+"Lambda"] = &lambda;
+      outputData[regulatorPrefix_+"LambdaMomentum"] = &lambda;
       outputData[regulatorPrefix_+"NodalLambdaForce"] = &lambdaForceFiltered;
     }
   }
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class VelocityGlc
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  VelocityGlc::VelocityGlc(Kinetostat * kinetostat) :
+  VelocityGlc::VelocityGlc(AtomicRegulator * kinetostat) :
     GlcKinetostat(kinetostat),
     nodalAtomicMomentum_(NULL),
     nodalVelocities_(atc_->field(VELOCITY))
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void VelocityGlc::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
     // set up shape function matrix
-    if (this->use_local_shape_functions()) {
-      lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
-      interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
-                                                  regulatorPrefix_+"LambdaAtomMap");
-      shapeFunctionMatrix_ = new LocalLambdaCouplingMatrix(atc_,
-                                                           lambdaAtomMap_,
-                                                           nodeToOverlapMap_);
-    }
-    else {
-      shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
+    shapeFunctionMatrix_ = interscaleManager.per_atom_sparse_matrix(regulatorPrefix_+"LambdaCouplingMatrixMomentum");
+    if (!shapeFunctionMatrix_) {
+      if (this->use_local_shape_functions()) {
+        lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
+        interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
+                                                    regulatorPrefix_+"LambdaAtomMap");
+        shapeFunctionMatrix_ = new LocalLambdaCouplingMatrix(atc_,
+                                                             lambdaAtomMap_,
+                                                             nodeToOverlapMap_);
+      }
+      else {
+        shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
+      }
+      interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
+                                                   regulatorPrefix_+"LambdaCouplingMatrixMomentum");
     }
-    interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
-                                                 regulatorPrefix_+"LambdaCouplingMatrixMomentum");
 
     // set linear solver strategy
     if (atomicRegulator_->use_lumped_lambda_solve()) {
       linearSolverType_ = AtomicRegulator::RSL_SOLVE;
     }
     else {
       linearSolverType_ = AtomicRegulator::CG_SOLVE;
     }
     
     // base class transfers
     GlcKinetostat::construct_transfers();
 
     // atomic force induced by kinetostat
     atomKinetostatForce_ = new AtomicKinetostatForceVelocity(atc_);
     interscaleManager.add_per_atom_quantity(atomKinetostatForce_,
                                             regulatorPrefix_+"AtomKinetostatForce");
         
     // restricted force due to kinetostat
     nodalAtomicLambdaForce_ = new AtfShapeFunctionRestriction(atc_,
                                                               atomKinetostatForce_,
                                                               interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_dense_matrix(nodalAtomicLambdaForce_,
-                                            regulatorPrefix_+"NodalAtomicLambdaForce");
+                                       regulatorPrefix_+"NodalAtomicLambdaForce");
     
     // nodal momentum restricted from atoms
     nodalAtomicMomentum_ = interscaleManager.dense_matrix("NodalAtomicMomentum");
 
     
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void VelocityGlc::initialize()
   {
     GlcKinetostat::initialize();
 
     // sets up time filter for cases where variables temporally filtered
     TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
     if (!timeFilterManager->end_equilibrate()) {
       lambdaForceFiltered_->set_quantity() = 0.;
       timeFilter_->initialize(lambdaForceFiltered_->quantity());
     }
   }
 
   //--------------------------------------------------------
   //  apply_mid_corrector:
   //    apply the kinetostat during the middle of the
   //    predictor phase
   //--------------------------------------------------------
   void VelocityGlc::apply_mid_predictor(double dt)
   {
     double dtLambda = 0.5*dt;
     compute_kinetostat(dtLambda);
+    apply_kinetostat(dtLambda);
   }
 
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the kinetostat after the corrector phase
   //--------------------------------------------------------
   void VelocityGlc::apply_post_corrector(double dt)
   {
     double dtLambda = 0.5*dt;
     compute_kinetostat(dtLambda);
+    apply_kinetostat(dtLambda);
   }
 
   //--------------------------------------------------------
   //  apply_pre_filtering
   //            applies first step of filtering to
   //            relevant variables
   //--------------------------------------------------------
   void VelocityGlc::apply_pre_filtering(double dt)
   {
     // apply time filtered lambda to atomic fields
     DENS_MAT lambdaZero(nNodes_,nsd_);
     timeFilter_->apply_pre_step1(lambdaForceFiltered_->set_quantity(),(-1./dt)*lambdaZero,dt);
   }
 
   //--------------------------------------------------------
   //  compute_kinetostat
   //            manages the solution and application of the
   //            kinetostat equations and variables
   //--------------------------------------------------------
   void VelocityGlc::compute_kinetostat(double dt)
   {
     // initial filtering update
     apply_pre_filtering(dt);
 
     // set up rhs
     DENS_MAT rhs(nNodes_,nsd_);
-    set_kinetostat_rhs(rhs,dt);
+    this->set_kinetostat_rhs(rhs,dt);
     
     // solve linear system for lambda
     solve_for_lambda(rhs,lambda_->set_quantity());
+#ifdef OBSOLETE
+    // compute nodal atomic power
+    compute_nodal_lambda_force(dt);
+
+    // apply kinetostat to atoms
+    apply_to_atoms(atomVelocities_,atomLambdas_->quantity());
+#endif
+  }
 
+  //--------------------------------------------------------
+  //  apply_kinetostat
+  //            manages the application of the
+  //            kinetostat equations and variables
+  //--------------------------------------------------------
+  void VelocityGlc::apply_kinetostat(double dt)
+  {
     // compute nodal atomic power
     compute_nodal_lambda_force(dt);
 
     // apply kinetostat to atoms
     apply_to_atoms(atomVelocities_,atomLambdas_->quantity());
   }
 
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the right-hand side of the
   //            kinetostat equations
   //--------------------------------------------------------
   void VelocityGlc::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // form rhs : sum_a (hatN_Ia * x_ai) - (\dot{Upsilon})_Ii
     rhs = nodalAtomicMomentum_->quantity();
-    rhs -= ((atc_->mass_mat_md(VELOCITY)).quantity())*(nodalVelocities_.quantity());
+    rhs -= (mdMassMatrix_.quantity())*(nodalVelocities_.quantity());
   }
 
   //--------------------------------------------------------
   //  compute_nodal_lambda_force
   //            compute the effective FE force applied
   //            by the kinetostat
   //--------------------------------------------------------
   void VelocityGlc::compute_nodal_lambda_force(double dt)
   {
     const DENS_MAT & myNodalAtomicLambdaForce(nodalAtomicLambdaForce_->quantity());
 
     timeFilter_->apply_pre_step1(lambdaForceFiltered_->set_quantity(),
                                  myNodalAtomicLambdaForce,dt);
 
     // update FE displacements for localized thermostats
     apply_localization_correction(myNodalAtomicLambdaForce,
                                   nodalVelocities_.set_quantity(),
                                   dt);
   }
 
   //--------------------------------------------------------
   //  set_weights
   //            sets diagonal weighting matrix used in
   //            solve_for_lambda
   //--------------------------------------------------------
   void VelocityGlc::set_weights()
   {
     if (lambdaAtomMap_) {
       MappedAtomQuantity * myWeights = new MappedAtomQuantity(atc_,atomMasses_,lambdaAtomMap_);
       weights_ = myWeights;
       (atc_->interscale_manager()).add_per_atom_quantity(myWeights,
                                                          "AtomMassesMapped");
     }
     else {
       weights_ = atomMasses_;
     }
   }
 
   //--------------------------------------------------------
   //  apply_localization_correction
   //            corrects for localized kinetostats only
   //            solving kinetostat equations on a subset
   //            of the MD region
   //--------------------------------------------------------
   void VelocityGlc::apply_localization_correction(const DENS_MAT & source,
                                                   DENS_MAT & nodalField,
                                                   double weight)
   {
     
     DENS_MAT nodalLambdaRoc(nNodes_,nsd_);
     atc_->apply_inverse_mass_matrix(source,
                                     nodalLambdaRoc,
                                     VELOCITY);
     set<pair<int,int> >::const_iterator iter;
     for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
       nodalLambdaRoc(iter->first,iter->second) = 0.;
     }
    
     nodalField += weight*nodalLambdaRoc;
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void VelocityGlc::output(OUTPUT_LIST & outputData)
   {
     _nodalAtomicLambdaForceOut_ = nodalAtomicLambdaForce_->quantity();
     if ((atc_->lammps_interface())->rank_zero()) {
-      outputData[regulatorPrefix_+"Lambda"] = &(lambda_->set_quantity());
+      outputData[regulatorPrefix_+"LambdaMomentum"] = &(lambda_->set_quantity());
       outputData[regulatorPrefix_+"NodalLambdaForce"] = &(_nodalAtomicLambdaForceOut_);
     }
   }
  
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class VelocityGlcFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  VelocityGlcFiltered::VelocityGlcFiltered(Kinetostat *kinetostat) 
+  VelocityGlcFiltered::VelocityGlcFiltered(AtomicRegulator *kinetostat) 
     : VelocityGlc(kinetostat),
       nodalAtomicVelocities_(atc_->nodal_atomic_field(VELOCITY))
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  apply_pre_filtering
   //            applies first step of filtering to
   //            relevant variables
   //--------------------------------------------------------
   void VelocityGlcFiltered::apply_pre_filtering(double dt)
   {
     // apply time filtered lambda to atomic fields
     VelocityGlc::apply_pre_filtering(dt);
     DENS_MAT nodalAcceleration(nNodes_,nsd_);
     atc_->apply_inverse_md_mass_matrix(lambdaForceFiltered_->quantity(),
                                        nodalAcceleration,
                                        VELOCITY);
     nodalAtomicVelocities_ += dt*nodalAcceleration;
   }
 
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the right-hand side of the
   //            kinetostat equations
   //--------------------------------------------------------
   void VelocityGlcFiltered::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // form rhs : sum_a (hatN_Ia * x_ai) - (Upsilon)_Ii
     double coef = 1./(timeFilter_->unfiltered_coefficient_pre_s1(dt));
-    rhs = coef*((atc_->mass_mat_md(VELOCITY)).quantity())*(nodalAtomicVelocities_.quantity() - nodalVelocities_.quantity());
+    rhs = coef*(mdMassMatrix_.quantity())*(nodalAtomicVelocities_.quantity() - nodalVelocities_.quantity());
   }
 
   //--------------------------------------------------------
   //  compute_nodal_lambda_force
   //            compute the effective FE force applied
   //            by the kinetostat
   //--------------------------------------------------------
   void VelocityGlcFiltered::compute_nodal_lambda_force(double dt)
   {
     const DENS_MAT & myNodalAtomicLambdaForce(nodalAtomicLambdaForce_->quantity());
     DENS_MAT & myLambdaForceFiltered(lambdaForceFiltered_->set_quantity());
     timeFilter_->apply_post_step1(myLambdaForceFiltered,myNodalAtomicLambdaForce,dt);
 
     // update filtered atomic displacements
     DENS_MAT nodalLambdaRoc(myNodalAtomicLambdaForce.nRows(),myNodalAtomicLambdaForce.nCols());
     atc_->apply_inverse_md_mass_matrix(myNodalAtomicLambdaForce,
                                        nodalLambdaRoc,
                                        VELOCITY);
     timeFilter_->apply_post_step1(nodalAtomicVelocities_.set_quantity(),dt*nodalLambdaRoc,dt);
 
     // update FE displacements for localized thermostats
     apply_localization_correction(myLambdaForceFiltered,
                                   nodalVelocities_.set_quantity(),
                                   dt);
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void VelocityGlcFiltered::output(OUTPUT_LIST & outputData)
   {
     if ((atc_->lammps_interface())->rank_zero()) {
       outputData[regulatorPrefix_+"Lambda"] = &(lambda_->set_quantity());
       outputData[regulatorPrefix_+"NodalLambdaForce"] = &(lambdaForceFiltered_->set_quantity());
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class StressFlux
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  StressFlux::StressFlux(Kinetostat * kinetostat) :
+  StressFlux::StressFlux(AtomicRegulator * kinetostat) :
     GlcKinetostat(kinetostat),
     nodalForce_(atc_->field_rhs(VELOCITY)),
     nodalAtomicForce_(NULL),
     nodalGhostForce_(NULL),
     momentumSource_(atc_->atomic_source(VELOCITY))
   {
     // flag for performing boundary flux calculation
     fieldMask_(VELOCITY,FLUX) = true;
   }
 
   StressFlux::~StressFlux()
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void StressFlux::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
     // set up shape function matrix
     if (this->use_local_shape_functions()) {
       lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
       interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
                                                   regulatorPrefix_+"LambdaAtomMap");
       shapeFunctionMatrix_ = new LocalLambdaCouplingMatrix(atc_,
                                                            lambdaAtomMap_,
                                                            nodeToOverlapMap_);
     }
     else {
       shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
     }
     interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
                                                  regulatorPrefix_+"LambdaCouplingMatrixMomentum");
 
     // set linear solver strategy
     if (atomicRegulator_->use_lumped_lambda_solve()) {
       linearSolverType_ = AtomicRegulator::RSL_SOLVE;
     }
     else {
       linearSolverType_ = AtomicRegulator::CG_SOLVE;
     }
 
     // base class transfers
     GlcKinetostat::construct_transfers();
 
     // force at nodes due to atoms
     nodalAtomicForce_ = interscaleManager.dense_matrix("NodalAtomicForce");
 
     // atomic force induced by kinetostat
     atomKinetostatForce_ = new AtomicKinetostatForceStress(atc_,atomLambdas_);
     interscaleManager.add_per_atom_quantity(atomKinetostatForce_,
                                             regulatorPrefix_+"AtomKinetostatForce");
         
     // restricted force due to kinetostat
     nodalAtomicLambdaForce_ = new AtfShapeFunctionRestriction(atc_,
                                                               atomKinetostatForce_,
                                                               interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_dense_matrix(nodalAtomicLambdaForce_,
                                        regulatorPrefix_+"NodalAtomicLambdaForce");
 
     // sets up space for ghost force related variables
     if (atc_->groupbit_ghost()) {
       GhostCouplingMatrix * shapeFunctionGhost = new GhostCouplingMatrix(atc_,interscaleManager.per_atom_sparse_matrix("InterpolantGhost"),
                                                                          regulatedNodes_,nodeToOverlapMap_);
       interscaleManager.add_sparse_matrix(shapeFunctionGhost,
                                           regulatorPrefix_+"GhostCouplingMatrix");
       FundamentalAtomQuantity * atomGhostForce = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_FORCE,
                                                                                                  GHOST);
       nodalGhostForce_ = new AtfShapeFunctionRestriction(atc_,atomGhostForce,
                                                          shapeFunctionGhost);
       interscaleManager.add_dense_matrix(nodalGhostForce_,
                                          regulatorPrefix_+"NodalGhostForce");
       nodalGhostForceFiltered_.reset(nNodes_,nsd_);
     }
   }
 
   //--------------------------------------------------------
   //  compute_boundary_flux:
   //    computes the boundary flux to be consistent with
   //    the controller
   //--------------------------------------------------------
   void StressFlux::compute_boundary_flux(FIELDS & fields)
   {
     GlcKinetostat::compute_boundary_flux(fields);
   }
 
   //--------------------------------------------------------
   //  apply_pre_predictor:
   //    apply the kinetostat to the atoms in the
   //    mid-predictor integration phase
   //--------------------------------------------------------
   void StressFlux::apply_pre_predictor(double dt)
   {
     double dtLambda = 0.5*dt;
     // apply lambda force to atoms
     apply_to_atoms(atomVelocities_,atomKinetostatForce_->quantity(),dtLambda);
   }
 
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the kinetostat to the atoms in the
   //    post-corrector integration phase
   //--------------------------------------------------------
   void StressFlux::apply_post_corrector(double dt)
   {
     double dtLambda = 0.5*dt;
     // apply lambda force to atoms
     apply_to_atoms(atomVelocities_,atomKinetostatForce_->quantity(),dtLambda);
   }
 
   //--------------------------------------------------------
   //  compute_kinetostat
   //            manages the solution and application of the
   //            kinetostat equations and variables
   //--------------------------------------------------------
   void StressFlux::compute_kinetostat(double dt)
   {
     // initial filtering update
     apply_pre_filtering(dt);
 
     // set up rhs
     DENS_MAT rhs(nNodes_,nsd_);
     set_kinetostat_rhs(rhs,dt);
 
     // solve linear system for lambda
     solve_for_lambda(rhs,lambda_->set_quantity());
 
     // compute nodal atomic power
     compute_nodal_lambda_force(dt);
   }
 
   //--------------------------------------------------------
   //  apply_pre_filtering
   //            applies first step of filtering to
   //            relevant variables
   //--------------------------------------------------------
   void StressFlux::apply_pre_filtering(double dt)
   {
     // apply time filtered lambda force
     DENS_MAT lambdaZero(nNodes_,nsd_);
     timeFilter_->apply_pre_step1(lambdaForceFiltered_->set_quantity(),lambdaZero,dt);
     if (nodalGhostForce_) {
       timeFilter_->apply_pre_step1(nodalGhostForceFiltered_.set_quantity(),
                                    nodalGhostForce_->quantity(),dt);
     }
   }
 
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the RHS of the kinetostat equations
   //            for the coupling parameter lambda
   //--------------------------------------------------------
   void StressFlux::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // (a) for flux based : 
     // form rhs :  \int N_I r dV - \sum_g N_Ig^* f_g
     // sources are set in ATC transfer
     rhs.reset(nNodes_,nsd_);
     rhs = momentumSource_.quantity();
     if (nodalGhostForce_) {
       rhs -= nodalGhostForce_->quantity();
     }
     
     // (b) for ess. bcs
     
     // form rhs : {sum_a (N_Ia * f_ia) - M_md * (ddupsilon/dt)_I}
     DENS_MAT rhsPrescribed = -1.*nodalForce_.quantity();
     atc_->apply_inverse_mass_matrix(rhsPrescribed,VELOCITY);
     rhsPrescribed = (mdMassMatrix_.quantity())*rhsPrescribed;
     rhsPrescribed += nodalAtomicForce_->quantity();
 
     set<pair<int,int> >::const_iterator iter;
     for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
       rhs(iter->first,iter->second) = rhsPrescribed(iter->first,iter->second);
     }
   }
 
   //--------------------------------------------------------
   //  compute_nodal_lambda_force
   //            computes the force induced on the FE
   //            by applying lambdaForce on the atoms
   //--------------------------------------------------------
   void StressFlux::compute_nodal_lambda_force(double dt)
   {
     DENS_MAT myNodalAtomicLambdaForce = nodalAtomicLambdaForce_->quantity();
     set<pair<int,int> >::const_iterator iter;
     for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
       myNodalAtomicLambdaForce(iter->first,iter->second) = 0.;
     }
 
     timeFilter_->apply_post_step1(lambdaForceFiltered_->set_quantity(),
                                   myNodalAtomicLambdaForce,dt);
   }
 
   //--------------------------------------------------------
   //  add_to_rhs:
   //            determines what if any contributions to the
   //            finite element equations are needed for
   //            consistency with the kinetostat
   //--------------------------------------------------------
   void StressFlux::add_to_rhs(FIELDS & rhs)
   {
     // compute the kinetostat force
     compute_kinetostat(atc_->dt());
 
     rhs[VELOCITY] += nodalAtomicLambdaForce_->quantity() + boundaryFlux_[VELOCITY].quantity();
   }
 
   //--------------------------------------------------------
   //  apply_lambda_to_atoms
   //            uses existing lambda to modify given
   //            atomic quantity
   //--------------------------------------------------------
   void StressFlux::apply_to_atoms(PerAtomQuantity<double> * atomVelocities,
                                   const DENS_MAT & lambdaForce,
                                   double dt)
   {
     _deltaVelocity_ = lambdaForce;
     _deltaVelocity_ /= atomMasses_->quantity();
     _deltaVelocity_ *= dt;
     *atomVelocities += _deltaVelocity_;
   }
 
   //--------------------------------------------------------
   //  reset_filtered_ghost_force:
   //    resets the kinetostat generated ghost force to a
   //    prescribed value
   //--------------------------------------------------------
   void StressFlux::reset_filtered_ghost_force(DENS_MAT & target)
   {
     nodalGhostForceFiltered_ = target;
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void StressFlux::output(OUTPUT_LIST & outputData)
   {
     _nodalAtomicLambdaForceOut_ = nodalAtomicLambdaForce_->quantity();
     DENS_MAT & lambda(lambda_->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
       outputData[regulatorPrefix_+"Lambda"] = &lambda;
       outputData[regulatorPrefix_+"NodalLambdaForce"] = &(_nodalAtomicLambdaForceOut_);
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class StressFluxGhost
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  StressFluxGhost::StressFluxGhost(Kinetostat * kinetostat) :
+  StressFluxGhost::StressFluxGhost(AtomicRegulator * kinetostat) :
     StressFlux(kinetostat)
   {
     // flag for performing boundary flux calculation
     fieldMask_(VELOCITY,FLUX) = false;
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void StressFluxGhost::construct_transfers()
   {
     StressFlux::construct_transfers();
     if (!nodalGhostForce_) {
       throw ATC_Error("StressFluxGhost::StressFluxGhost - ghost atoms must be specified");
     }
   }
 
   //--------------------------------------------------------
   //  compute_boundary_flux:
   //    computes the boundary flux to be consistent with
   //    the controller
   //--------------------------------------------------------
   void StressFluxGhost::compute_boundary_flux(FIELDS & fields)
   {
     // This is only used in computation of atomic sources
     boundaryFlux_[VELOCITY] = 0.;
   }
 
   //--------------------------------------------------------
   //  add_to_rhs:
   //            determines what if any contributions to the
   //            finite element equations are needed for
   //            consistency with the kinetostat
   //--------------------------------------------------------
   void StressFluxGhost::add_to_rhs(FIELDS & rhs)
   {
     // compute the kinetostat force
     compute_kinetostat(atc_->dt());
 
     // uses ghost force as the boundary flux to add to the RHS
     rhs[VELOCITY] += nodalAtomicLambdaForce_->quantity() + nodalGhostForce_->quantity();
   }
 
     //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the RHS of the kinetostat equations
   //            for the coupling parameter lambda
   //--------------------------------------------------------
   void StressFluxGhost::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // (a) for flux based : 
     // form rhs :  \int N_I r dV - \sum_g N_Ig^* f_g
     // sources are set in ATC transfer
     rhs.reset(nNodes_,nsd_);
     rhs = momentumSource_.quantity();
     
     // (b) for ess. bcs
     
     // form rhs : {sum_a (N_Ia * f_ia) - M_md * (ddupsilon/dt)_I}
     DENS_MAT rhsPrescribed = -1.*nodalForce_.quantity();
     atc_->apply_inverse_mass_matrix(rhsPrescribed,VELOCITY);
     rhsPrescribed = (mdMassMatrix_.quantity())*rhsPrescribed;
     rhsPrescribed += nodalAtomicForce_->quantity();
 
     set<pair<int,int> >::const_iterator iter;
     for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
       rhs(iter->first,iter->second) = rhsPrescribed(iter->first,iter->second);
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class StressFluxFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
-  StressFluxFiltered::StressFluxFiltered(Kinetostat * kinetostat) :
+  StressFluxFiltered::StressFluxFiltered(AtomicRegulator * kinetostat) :
     StressFlux(kinetostat),
     nodalAtomicVelocity_(atc_->nodal_atomic_field(VELOCITY))
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the RHS of the kinetostat equations
   //            for the coupling parameter lambda
   //--------------------------------------------------------
   void StressFluxFiltered::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // set basic terms
     // (a) for flux based : 
     // form rhs :  \int N_I r dV - \sum_g N_Ig^* f_g
     // sources are set in ATC transfer
     rhs.reset(nNodes_,nsd_);
     rhs = momentumSource_.quantity() - nodalGhostForceFiltered_.quantity();
     
     // (b) for ess. bcs
     
     // form rhs : {sum_a (N_Ia * f_ia) - M_md * (ddupsilon/dt)_I}
     DENS_MAT rhsPrescribed = -1.*nodalForce_.quantity();
     atc_->apply_inverse_mass_matrix(rhsPrescribed,VELOCITY);
     rhsPrescribed = (mdMassMatrix_.quantity())*rhsPrescribed;
     rhsPrescribed += nodalAtomicForce_->quantity();
 
     set<pair<int,int> >::const_iterator iter;
     for (iter = hooverNodes_.begin(); iter != hooverNodes_.end(); ++iter) {
       rhs(iter->first,iter->second) = rhsPrescribed(iter->first,iter->second);
     }
 
     // adjust for application of current lambda force
     rhs += lambdaForceFiltered_->quantity();
 
     // correct for time filtering
     rhs *= 1./(timeFilter_->unfiltered_coefficient_pre_s1(dt));
   }
 
   //--------------------------------------------------------
   //  apply_lambda_to_atoms
   //            uses existing lambda to modify given
   //            atomic quantity
   //--------------------------------------------------------
   void StressFluxFiltered::apply_to_atoms(PerAtomQuantity<double> * atomVelocities,
                                           const DENS_MAT & lambdaForce,
                                           double dt)
   {
     StressFlux::apply_to_atoms(atomVelocities,lambdaForce,dt);
 
     // add in corrections to filtered nodal atomice velocity
     DENS_MAT velocityRoc(nNodes_,nsd_);
     atc_->apply_inverse_md_mass_matrix(lambdaForceFiltered_->quantity(),
                                        velocityRoc,
                                        VELOCITY);
     nodalAtomicVelocity_ += dt*velocityRoc;
   }
 
   //--------------------------------------------------------
   //  add_to_rhs:
   //            determines what if any contributions to the
   //            finite element equations are needed for
   //            consistency with the kinetostat
   //--------------------------------------------------------
   void StressFluxFiltered::add_to_rhs(FIELDS & rhs)
   {
     // compute kinetostat forces
     compute_kinetostat(atc_->dt());
     rhs[VELOCITY] += lambdaForceFiltered_->quantity() + boundaryFlux_[VELOCITY].quantity();
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void StressFluxFiltered::output(OUTPUT_LIST & outputData)
   {
     DENS_MAT & lambda(lambda_->set_quantity());
     DENS_MAT & lambdaForceFiltered(lambdaForceFiltered_->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
       outputData[regulatorPrefix_+"Lambda"] = &lambda;
       outputData[regulatorPrefix_+"NodalLambdaForce"] = &lambdaForceFiltered;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class KinetostatGlcFs
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  KinetostatGlcFs::KinetostatGlcFs(Kinetostat * kinetostat,
+  KinetostatGlcFs::KinetostatGlcFs(AtomicRegulator * kinetostat,
                                    const string & regulatorPrefix) :
     KinetostatShapeFunction(kinetostat,regulatorPrefix),
-    velocity_(atc_->field(VELOCITY))
+    velocity_(atc_->field(VELOCITY)),
+    //timeFilter_(atomicRegulator_->time_filter()),
+    //nodalAtomicLambdaForce_(NULL),
+    //lambdaPowerFiltered_(NULL),
+    //atomKinetostatForces_(NULL),
+    //atomMasses_(NULL),
+    nodalAtomicMomentum_(NULL),
+    isFirstTimestep_(true),
+    atomPredictedVelocities_(NULL),
+    nodalAtomicPredictedMomentum_(NULL),
+    dtFactor_(0.)
   {
     // constuct/obtain data corresponding to stage 3 of ATC_Method::initialize
-    nodalAtomicLambdaForce_ = kinetostat_->regulator_data(regulatorPrefix_+"NodalAtomicLambdaForce",nsd_);
+    nodalAtomicLambdaForce_ = atomicRegulator_->regulator_data(regulatorPrefix_+"NodalAtomicLambdaForce",nsd_);
+    lambdaForceFiltered_ = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaForceFiltered",1);
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void KinetostatGlcFs::construct_transfers()
   {
-    InterscaleManager & interscaleManager(atc_->interscale_manager());
-
     // base class transfers
     KinetostatShapeFunction::construct_transfers();
+    InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // get data from manager
     nodalAtomicMomentum_ = interscaleManager.dense_matrix("NodalAtomicMomentum");
 
     // atomic force induced by kinetostat
     PerAtomQuantity<double> * atomLambdas = interscaleManager.per_atom_quantity(regulatorPrefix_+"AtomLambdaMomentum");
     atomKinetostatForce_ = new AtomicKinetostatForceStress(atc_,atomLambdas);
     interscaleManager.add_per_atom_quantity(atomKinetostatForce_,
                                             regulatorPrefix_+"AtomKinetostatForce");
+
+    // predicted momentum quantities:  atom velocities, atom momenta, and restricted atom momenta
+    // MAKE THINGS WORK WITH ONLY ONE PREDICTED VELOCITY AND DERIVED QUANTITIES, CHECK IT EXISTS
+    atomPredictedVelocities_ = new AtcAtomQuantity<double>(atc_,nsd_);
+    interscaleManager.add_per_atom_quantity(atomPredictedVelocities_,
+                                            regulatorPrefix_+"AtomicPredictedVelocities");
+    AtomicMomentum * atomPredictedMomentum = new AtomicMomentum(atc_,
+                                                                atomPredictedVelocities_);
+    interscaleManager.add_per_atom_quantity(atomPredictedMomentum,
+                                            regulatorPrefix_+"AtomicPredictedMomentum");
+    nodalAtomicPredictedMomentum_ = new AtfShapeFunctionRestriction(atc_,
+                                                                    atomPredictedMomentum,
+                                                                    interscaleManager.per_atom_sparse_matrix("Interpolant"));
+    interscaleManager.add_dense_matrix(nodalAtomicPredictedMomentum_,
+                                       regulatorPrefix_+"NodalAtomicPredictedMomentum");
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void KinetostatGlcFs::initialize()
   {
     KinetostatShapeFunction::initialize();
-
-    // set up workspaces
-    _deltaMomentum_.reset(nNodes_,nsd_);
-    _lambdaForceOutput_.reset(nNodes_,nsd_);
     
     TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
     if (!timeFilterManager->end_equilibrate()) {
       // we should reset lambda and lambdaForce to zero in this case
       // implies an initial condition of 0 for the filtered nodal lambda power
       // initial conditions will always be needed when using time filtering
       // however, the fractional step scheme must assume the instantaneous
       // nodal lambda power is 0 initially because all quantities are in delta form
       *lambda_ = 0.; // ensures initial lambda force is zero
       *nodalAtomicLambdaForce_ = 0.; // momentum change due to kinetostat
       *lambdaForceFiltered_ = 0.; // filtered momentum change due to kinetostats
     }
     else {
       // we can grab lambda power variables using time integrator and atc transfer in cases for equilibration
     }
 
     // sets up time filter for cases where variables temporally filtered
     if (timeFilterManager->need_reset()) {
       // the form of this integrator implies no time filters that require history data can be used
       timeFilter_->initialize(nodalAtomicLambdaForce_->quantity());
     }
 
-    compute_rhs_map();
+    atomKinetostatForce_->quantity(); // initialize
   }
 
   //--------------------------------------------------------
-  //  compute_rhs_map
-  //    creates mapping from all nodes to those to which
-  //    the kinetostat applies
+  //  apply_lambda_to_atoms
+  //            uses existing lambda to modify given
+  //            atomic quantity
   //--------------------------------------------------------
-  void KinetostatGlcFs::compute_rhs_map()
+  void KinetostatGlcFs::apply_to_atoms(PerAtomQuantity<double> * atomVelocity,
+                                      const DENS_MAN * nodalAtomicMomentum,
+                                      const DENS_MAT & lambdaForce,
+                                      DENS_MAT & nodalAtomicLambdaForce,
+                                      double dt)
   {
-    rhsMap_.resize(overlapToNodeMap_->nRows(),1);
-    DENS_MAT rhsMapGlobal(nNodes_,1);
-    const set<int> & applicationNodes(applicationNodes_->quantity());
-    for (int i = 0; i < nNodes_; i++) {
-      if (applicationNodes.find(i) != applicationNodes.end()) {
-        rhsMapGlobal(i,0) = 1.;
-      }
-      else {
-        rhsMapGlobal(i,0) = 0.;
-      }
+    // compute initial contributions to lambda force
+    nodalAtomicLambdaForce = nodalAtomicMomentum->quantity();
+    nodalAtomicLambdaForce *= -1.;
+
+    // apply lambda force to atoms
+    _velocityDelta_ = lambdaForce;
+    _velocityDelta_ /= atomMasses_->quantity();
+    _velocityDelta_ *= dt;
+    (*atomVelocity) += _velocityDelta_;
+
+    // finalize lambda force
+    nodalAtomicLambdaForce += nodalAtomicMomentum->quantity();
+  }
+
+  //--------------------------------------------------------
+  //  full_prediction:
+  //    flag to perform a full prediction calcalation
+  //    for lambda rather than using the old value
+  //--------------------------------------------------------
+  bool KinetostatGlcFs::full_prediction()
+  {
+    if (isFirstTimestep_ || ((atc_->atom_to_element_map_type() == EULERIAN)
+                             && (atc_->atom_to_element_map_frequency() > 1)
+                             && (atc_->step() % atc_->atom_to_element_map_frequency() == 0 ))) {
+      return true;
     }
-    map_unique_to_overlap(rhsMapGlobal,rhsMap_);
+    return false;
   }
 
   //--------------------------------------------------------
   //  apply_pre_predictor:
   //    apply the kinetostat to the atoms in the
   //    pre-predictor integration phase
   //--------------------------------------------------------
   void KinetostatGlcFs::apply_pre_predictor(double dt)
   {
     DENS_MAT & lambdaForceFiltered(lambdaForceFiltered_->set_quantity());
     DENS_MAT & nodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
 
     // update filtered forces
     timeFilter_->apply_pre_step1(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
 
     // apply lambda force to atoms and compute instantaneous lambda force 
     this->apply_to_atoms(atomVelocities_,nodalAtomicMomentum_,
                          atomKinetostatForce_->quantity(),
                          nodalAtomicLambdaForce,0.5*dt);
 
     // update nodal variables for first half of timestep
-    this->add_to_momentum(nodalAtomicLambdaForce,_deltaMomentum_,0.5*dt);
-    atc_->apply_inverse_mass_matrix(_deltaMomentum_,VELOCITY);
-    velocity_ += _deltaMomentum_;
+    this->add_to_momentum(nodalAtomicLambdaForce,deltaMomentum_,0.5*dt);
+    atc_->apply_inverse_mass_matrix(deltaMomentum_,VELOCITY);
+    velocity_ += deltaMomentum_;
 
     // start update of filtered lambda force
     nodalAtomicLambdaForce = 0.;
     timeFilter_->apply_post_step1(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
   }
+
+  //--------------------------------------------------------
+  //  apply_pre_corrector:
+  //    apply the thermostat to the atoms in the first part
+  //    of the corrector step of the Verlet algorithm
+  //--------------------------------------------------------
+  void KinetostatGlcFs::apply_pre_corrector(double dt)
+  {
+    (*atomPredictedVelocities_) = atomVelocities_->quantity();
+
+    // do full prediction if we just redid the shape functions
+    if (full_prediction()) {
+      this->compute_lambda(dt);
+    }
+
+    // apply lambda force to atoms and compute instantaneous lambda power to predict second half of time step
+    DENS_MAT & myNodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
+    apply_to_atoms(atomPredictedVelocities_,
+                   nodalAtomicPredictedMomentum_,
+                   atomKinetostatForce_->quantity(),
+                   myNodalAtomicLambdaForce,0.5*dt);
+    
+    // update predicted nodal variables for second half of time step
+    this->add_to_momentum(myNodalAtomicLambdaForce,deltaMomentum_,0.5*dt);
+    atc_->apply_inverse_mass_matrix(deltaMomentum_,VELOCITY);
+    velocity_ += deltaMomentum_;
+  }
  
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the kinetostat to the atoms in the
   //    post-corrector integration phase
   //--------------------------------------------------------
   void KinetostatGlcFs::apply_post_corrector(double dt)
   {
+    // remove predicted force effects
+    DENS_MAT & myVelocity(velocity_.set_quantity());
+    myVelocity -= deltaMomentum_;
+
     // compute the kinetostat equation and update lambda
     this->compute_lambda(dt);
 
-    DENS_MAT & lambdaForceFiltered(lambdaForceFiltered_->set_quantity());
+    // apply lambda force to atoms and compute instantaneous lambda force for second half of time step
     DENS_MAT & nodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
-
-    // update filtered force
-    timeFilter_->apply_pre_step1(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
-
-    // apply lambda force to atoms and compute instantaneous lambda force 
     this->apply_to_atoms(atomVelocities_,nodalAtomicMomentum_,
                          atomKinetostatForce_->quantity(),
                          nodalAtomicLambdaForce,0.5*dt);
 
+    // start update of filtered lambda force
+    timeFilter_->apply_post_step2(lambdaForceFiltered_->set_quantity(),
+                                  nodalAtomicLambdaForce,dt);
+
     // update nodal variables for first half of timestep
-    this->add_to_momentum(nodalAtomicLambdaForce,_deltaMomentum_,0.5*dt);
-    nodalAtomicLambdaForce *= 2./dt;
-    atc_->apply_inverse_mass_matrix(_deltaMomentum_,VELOCITY);
-    velocity_ += _deltaMomentum_;
+    this->add_to_momentum(nodalAtomicLambdaForce,deltaMomentum_,0.5*dt);
+    atc_->apply_inverse_mass_matrix(deltaMomentum_,VELOCITY);
+    velocity_ += deltaMomentum_;
 
-    // start update of filtered lambda force
-    timeFilter_->apply_post_step2(lambdaForceFiltered,nodalAtomicLambdaForce,dt);
+    
+    isFirstTimestep_ = false;
   }
 
   //--------------------------------------------------------
   //  compute_kinetostat
   //            manages the solution and application of the
   //            kinetostat equations and variables
   //--------------------------------------------------------
   void KinetostatGlcFs::compute_lambda(double dt)
   {
     // set up rhs for lambda equation
     this->set_kinetostat_rhs(rhs_,0.5*dt);
 
     // solve linear system for lambda
     DENS_MAT & lambda(lambda_->set_quantity());
     solve_for_lambda(rhs_,lambda);
   }
 
-  //--------------------------------------------------------
-  //  apply_lambda_to_atoms
-  //            uses existing lambda to modify given
-  //            atomic quantity
-  //--------------------------------------------------------
-  void KinetostatGlcFs::apply_to_atoms(PerAtomQuantity<double> * atomVelocity,
-                                      const DENS_MAN * nodalAtomicMomentum,
-                                      const DENS_MAT & lambdaForce,
-                                      DENS_MAT & nodalAtomicLambdaForce,
-                                      double dt)
-  {
-    // compute initial contributions to lambda force
-    nodalAtomicLambdaForce = nodalAtomicMomentum->quantity();
-    nodalAtomicLambdaForce *= -1.;
-
-    // apply lambda force to atoms
-    _velocityDelta_ = lambdaForce;
-    _velocityDelta_ /= atomMasses_->quantity();
-    _velocityDelta_ *= dt;
-    (*atomVelocity) += _velocityDelta_;
-
-    // finalize lambda force
-    nodalAtomicLambdaForce += nodalAtomicMomentum->quantity();
-  }
-
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void KinetostatGlcFs::output(OUTPUT_LIST & outputData)
   {
     _lambdaForceOutput_ = nodalAtomicLambdaForce_->quantity();
     // approximate value for lambda force
     double dt =  LammpsInterface::instance()->dt();
     _lambdaForceOutput_ *= (2./dt);
     DENS_MAT & lambda(lambda_->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
-      outputData[regulatorPrefix_+"Lambda"] = &lambda;
+      outputData[regulatorPrefix_+"LambdaMomentum"] = &lambda;
       outputData[regulatorPrefix_+"NodalLambdaForce"] = &(_lambdaForceOutput_);
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class KinetostatFlux
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  KinetostatFlux::KinetostatFlux(Kinetostat * kinetostat,
+  KinetostatFlux::KinetostatFlux(AtomicRegulator * kinetostat,
                                  const string & regulatorPrefix) :
     KinetostatGlcFs(kinetostat,regulatorPrefix),
     momentumSource_(atc_->atomic_source(VELOCITY)),
     nodalGhostForce_(NULL),
     nodalGhostForceFiltered_(NULL)
   {
     // flag for performing boundary flux calculation
     fieldMask_(VELOCITY,FLUX) = true;
 
     // constuct/obtain data corresponding to stage 3 of ATC_Method::initialize
-    nodalGhostForceFiltered_ = kinetostat_->regulator_data(regulatorPrefix_+"NodalGhostForceFiltered",nsd_);
+    nodalGhostForceFiltered_ = atomicRegulator_->regulator_data(regulatorPrefix_+"NodalGhostForceFiltered",nsd_);
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void KinetostatFlux::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
-    
-    // set up linear solver
     // set up data for linear solver
     shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
     interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
                                                  regulatorPrefix_+"LambdaCouplingMatrixMomentum");
     if (elementMask_) {
       lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
       interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
                                                   regulatorPrefix_+"LambdaAtomMap");
     }
     if (atomicRegulator_->use_localized_lambda()) {
       linearSolverType_ = AtomicRegulator::RSL_SOLVE;
     }
     else {
       linearSolverType_ = AtomicRegulator::CG_SOLVE;
     }
 
     // base class transfers
     KinetostatGlcFs::construct_transfers();
 
     // sets up space for ghost force related variables
     if (atc_->groupbit_ghost()) {
       MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap = 
         interscaleManager.dense_matrix_int(regulatorPrefix_+"NodeToOverlapMap");
       GhostCouplingMatrix * shapeFunctionGhost = new GhostCouplingMatrix(atc_,interscaleManager.per_atom_sparse_matrix("InterpolantGhost"),
                                                                          regulatedNodes_,
                                                                          nodeToOverlapMap);
       interscaleManager.add_sparse_matrix(shapeFunctionGhost,
                                           regulatorPrefix_+"GhostCouplingMatrix");
       FundamentalAtomQuantity * atomGhostForce = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_FORCE,
                                                                                              GHOST);
       nodalGhostForce_ = new AtfShapeFunctionRestriction(atc_,atomGhostForce,
                                                          shapeFunctionGhost);
       interscaleManager.add_dense_matrix(nodalGhostForce_,
                                          regulatorPrefix_+"NodalGhostForce");
     }
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void KinetostatFlux::initialize()
   {
     KinetostatGlcFs::initialize();
     
     TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
     if (!timeFilterManager->end_equilibrate()) {
       // we should reset lambda and lambdaForce to zero in this case
       // implies an initial condition of 0 for the filtered nodal lambda power
       // initial conditions will always be needed when using time filtering
       // however, the fractional step scheme must assume the instantaneous
       // nodal lambda power is 0 initially because all quantities are in delta form
       *nodalGhostForceFiltered_ = 0.; // filtered force from ghost atoms
     }
     else {
       // we can grab lambda power variables using time integrator and atc transfer in cases for equilibration
     }
+
+    // timestep factor
+    dtFactor_ = 1.;
   }
 
   //--------------------------------------------------------
   //  construct_regulated_nodes:
   //    constructs the set of nodes being regulated
   //--------------------------------------------------------
   void KinetostatFlux::construct_regulated_nodes()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // matrix requires all entries even if localized for correct lumping
-    regulatedNodes_ = new RegulatedNodes(atc_);
-    interscaleManager.add_set_int(regulatedNodes_,
-                                  regulatorPrefix_+"KinetostatRegulatedNodes");
-
+    regulatedNodes_ = interscaleManager.set_int(regulatorPrefix_+"KinetostatRegulatedNodes");
+    if (!regulatedNodes_) {
+      regulatedNodes_ = new RegulatedNodes(atc_);
+      interscaleManager.add_set_int(regulatedNodes_,
+                                    regulatorPrefix_+"KinetostatRegulatedNodes");
+    }
+    
     // if localized monitor nodes with applied fluxes
     if (atomicRegulator_->use_localized_lambda()) {
-      if ((kinetostat_->coupling_mode() == Kinetostat::FLUX) && (atomicRegulator_->boundary_integration_type() != NO_QUADRATURE)) {
+      if ((atomicRegulator_->coupling_mode() == Kinetostat::FLUX) && (atomicRegulator_->boundary_integration_type() != NO_QUADRATURE)) {
         // include boundary nodes
         applicationNodes_ = new FluxBoundaryNodes(atc_);
         
         boundaryNodes_ = new BoundaryNodes(atc_);
         interscaleManager.add_set_int(boundaryNodes_,
                                       regulatorPrefix_+"KinetostatBoundaryNodes");
       }
       else {
         // fluxed nodes only
         applicationNodes_ = new FluxNodes(atc_);
       }
       interscaleManager.add_set_int(applicationNodes_,
                                     regulatorPrefix_+"KinetostatApplicationNodes");
     }
     else {
       applicationNodes_ = regulatedNodes_;
     }
 
     // special set of boundary elements for boundary flux quadrature  
     if ((atomicRegulator_->boundary_integration_type() == FE_INTERPOLATION)
         && (atomicRegulator_->use_localized_lambda())) {
-      elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
-      interscaleManager.add_dense_matrix_bool(elementMask_,
-                                                   regulatorPrefix_+"BoundaryElementMask");
+      elementMask_ = interscaleManager.dense_matrix_bool(regulatorPrefix_+"BoundaryElementMask");
+      if (!elementMask_) {
+        elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
+        interscaleManager.add_dense_matrix_bool(elementMask_,
+                                                regulatorPrefix_+"BoundaryElementMask");
+      }
     }
   }
 
   //--------------------------------------------------------
   //  apply_pre_predictor:
   //    apply the kinetostat to the atoms in the
   //    pre-predictor integration phase
   //--------------------------------------------------------
   void KinetostatFlux::apply_pre_predictor(double dt)
   {
     // update filtered forces
     if (nodalGhostForce_) {
       timeFilter_->apply_pre_step1(nodalGhostForceFiltered_->set_quantity(),
                                    nodalGhostForce_->quantity(),dt);
     }
 
     KinetostatGlcFs::apply_pre_predictor(dt);
   }
  
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the kinetostat to the atoms in the
   //    post-corrector integration phase
   //--------------------------------------------------------
   void KinetostatFlux::apply_post_corrector(double dt)
   {
     // update filtered ghost force
     if (nodalGhostForce_) {
       timeFilter_->apply_post_step1(nodalGhostForceFiltered_->set_quantity(),
                                     nodalGhostForce_->quantity(),dt);
     }
     
     // compute the kinetostat equation and update lambda
     KinetostatGlcFs::apply_post_corrector(dt);
   }
 
+  //--------------------------------------------------------
+  //  add_to_momentum:
+  //            determines what if any contributions to the
+  //            finite element equations are needed for
+  //            consistency with the kinetostat
+  //--------------------------------------------------------
+  void KinetostatFlux::add_to_momentum(const DENS_MAT & nodalLambdaForce,
+                                       DENS_MAT & deltaMomentum,
+                                       double dt)
+  {
+    deltaMomentum.resize(nNodes_,nsd_);
+    const DENS_MAT & boundaryFlux(boundaryFlux_[VELOCITY].quantity());
+    for (int i = 0; i < nNodes_; i++) {
+      for (int j = 0; j < nsd_; j++) {
+        deltaMomentum(i,j) = nodalLambdaForce(i,j) + dt*boundaryFlux(i,j);
+      }
+    }
+  }
+
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the RHS of the kinetostat equations
   //            for the coupling parameter lambda
   //--------------------------------------------------------
   void KinetostatFlux::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // (a) for flux based : 
     // form rhs :  \int N_I r dV - \sum_g N_Ig^* f_g
     // sources are set in ATC transfer
     rhs.reset(nNodes_,nsd_);
     const DENS_MAT & momentumSource(momentumSource_.quantity());
     const set<int> & applicationNodes(applicationNodes_->quantity());
     set<int>::const_iterator iNode;
     for (iNode = applicationNodes.begin(); iNode != applicationNodes.end(); iNode++) {
       for (int j = 0; j < nsd_; j++) {
         rhs(*iNode,j) = momentumSource(*iNode,j);
       }
     }
 
     // add ghost forces, if needed
     if (nodalGhostForce_) {
       const DENS_MAT & nodalGhostForce(nodalGhostForce_->quantity());
       for (iNode = applicationNodes.begin(); iNode != applicationNodes.end(); iNode++) {
         for (int j = 0; j < nsd_; j++) {
           rhs(*iNode,j) -= nodalGhostForce(*iNode,j);
         }
       }
     }
   }
 
-  //--------------------------------------------------------
-  //  add_to_momentum:
-  //            determines what if any contributions to the
-  //            finite element equations are needed for
-  //            consistency with the kinetostat
-  //--------------------------------------------------------
-  void KinetostatFlux::add_to_momentum(const DENS_MAT & nodalLambdaForce,
-                                       DENS_MAT & deltaMomentum,
-                                       double dt)
-  {
-    deltaMomentum.resize(nNodes_,nsd_);
-    const DENS_MAT & boundaryFlux(boundaryFlux_[VELOCITY].quantity());
-    for (int i = 0; i < nNodes_; i++) {
-      for (int j = 0; j < nsd_; j++) {
-        deltaMomentum(i,j) = nodalLambdaForce(i,j) + dt*boundaryFlux(i,j);
-      }
-    }
-  }
-
   //--------------------------------------------------------
   //  reset_filtered_ghost_force:
   //    resets the kinetostat generated ghost force to a
   //    prescribed value
   //--------------------------------------------------------
   void KinetostatFlux::reset_filtered_ghost_force(DENS_MAT & target)
   {
     (*nodalGhostForceFiltered_) = target;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class KinetostatFluxGhost
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  KinetostatFluxGhost::KinetostatFluxGhost(Kinetostat * kinetostat,
+  KinetostatFluxGhost::KinetostatFluxGhost(AtomicRegulator * kinetostat,
                                            const string & regulatorPrefix) :
     KinetostatFlux(kinetostat,regulatorPrefix)
   {
     // flag for performing boundary flux calculation
     fieldMask_(VELOCITY,FLUX) = false;
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void KinetostatFluxGhost::construct_transfers()
   {
     KinetostatFlux::construct_transfers();
     if (!nodalGhostForce_) {
-      throw ATC_Error("StressFluxGhost::StressFluxGhost - ghost atoms must be specified");
+      throw ATC_Error("KinetostatFluxGhost::KinetostatFluxGhost - ghost atoms must be specified");
     }
   }
 
   //--------------------------------------------------------
   //  compute_boundary_flux:
   //    computes the boundary flux to be consistent with
   //    the controller
   //--------------------------------------------------------
   void KinetostatFluxGhost::compute_boundary_flux(FIELDS & fields)
   {
     // This is only used in computation of atomic sources
     boundaryFlux_[VELOCITY] = 0.;
   }
 
   //--------------------------------------------------------
   //  add_to_momentum:
   //            determines what if any contributions to the
   //            finite element equations are needed for
   //            consistency with the kinetostat
   //--------------------------------------------------------
   void KinetostatFluxGhost::add_to_momentum(const DENS_MAT & nodalLambdaForce,
                                        DENS_MAT & deltaMomentum,
                                        double dt)
   {
     deltaMomentum.resize(nNodes_,nsd_);
     const DENS_MAT & boundaryFlux(nodalGhostForce_->quantity());
     for (int i = 0; i < nNodes_; i++) {
       for (int j = 0; j < nsd_; j++) {
         deltaMomentum(i,j) = nodalLambdaForce(i,j) + dt*boundaryFlux(i,j);
       }
     }
   }
 
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the RHS of the kinetostat equations
   //            for the coupling parameter lambda
   //--------------------------------------------------------
   void KinetostatFluxGhost::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // (a) for flux based : 
     // form rhs :  \int N_I r dV - \sum_g N_Ig^* f_g
     // sources are set in ATC transfer
     rhs.reset(nNodes_,nsd_);
     const DENS_MAT & momentumSource(momentumSource_.quantity());
     const set<int> & applicationNodes(applicationNodes_->quantity());
     set<int>::const_iterator iNode;
     for (iNode = applicationNodes.begin(); iNode != applicationNodes.end(); iNode++) {
       for (int j = 0; j < nsd_; j++) {
         rhs(*iNode,j) = momentumSource(*iNode,j);
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class KinetostatFixed
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and kinetostat data
   //--------------------------------------------------------
-  KinetostatFixed::KinetostatFixed(Kinetostat * kinetostat,
+  KinetostatFixed::KinetostatFixed(AtomicRegulator * kinetostat,
                                    const string & regulatorPrefix) :
     KinetostatGlcFs(kinetostat,regulatorPrefix),
-    mdMassMatrix_(atc_->set_mass_mat_md(VELOCITY)),
-    isFirstTimestep_(true)
+    filterCoefficient_(1.)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void KinetostatFixed::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
     // determine if map is needed and set up if so
     if (this->use_local_shape_functions()) {
       lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
       interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
                                                   regulatorPrefix_+"LambdaAtomMap");
       shapeFunctionMatrix_ = new LocalLambdaCouplingMatrix(atc_,
                                                            lambdaAtomMap_,
                                                            nodeToOverlapMap_);
     }
     else {
       shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
     }
     interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
                                                  regulatorPrefix_+"LambdaCouplingMatrixMomentum");
     linearSolverType_ = AtomicRegulator::CG_SOLVE;
 
     // base class transfers
     KinetostatGlcFs::construct_transfers();
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void KinetostatFixed::initialize()
   {
     KinetostatGlcFs::initialize();
 
     // reset data to zero
     deltaFeMomentum_.reset(nNodes_,nsd_);
     deltaNodalAtomicMomentum_.reset(nNodes_,nsd_);
+
+    // initialize filtered energy
+    TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
+    if (!timeFilterManager->end_equilibrate()) {
+      nodalAtomicMomentumFiltered_ = nodalAtomicMomentum_->quantity();
+    }
+
+    // timestep factor
+    dtFactor_ = 0.5;
   }
 
   //--------------------------------------------------------
   //  halve_force:
   //    flag to halve the lambda force for improved
   //    accuracy
   //--------------------------------------------------------
   bool KinetostatFixed::halve_force()
   {
     if (isFirstTimestep_ || ((atc_->atom_to_element_map_type() == EULERIAN)
                              && (atc_->atom_to_element_map_frequency() > 1)
                              && (atc_->step() % atc_->atom_to_element_map_frequency() == 1))) {
       return true;
     }
     return false;
   }
 
   //--------------------------------------------------------
   //  construct_regulated_nodes:
   //    constructs the set of nodes being regulated
   //--------------------------------------------------------
   void KinetostatFixed::construct_regulated_nodes()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
+    regulatedNodes_ = interscaleManager.set_int(regulatorPrefix_+"RegulatedNodes");
 
-    if (!atomicRegulator_->use_localized_lambda()) {
-      regulatedNodes_ = new RegulatedNodes(atc_);
-    }
-    else if (kinetostat_->coupling_mode() == Kinetostat::FLUX) {
-      regulatedNodes_ = new FixedNodes(atc_);
-    }
-    else if (kinetostat_->coupling_mode() == Kinetostat::FIXED) {
-      // include boundary nodes
-      regulatedNodes_ = new FixedBoundaryNodes(atc_);
-    }
-    else {
-      throw ATC_Error("ThermostatFixed::construct_regulated_nodes - couldn't determine set of regulated nodes");
-    }
+    if (!regulatedNodes_) {
+      if (!atomicRegulator_->use_localized_lambda()) {
+        regulatedNodes_ = new RegulatedNodes(atc_);
+      }
+      else if (atomicRegulator_->coupling_mode() == Kinetostat::FLUX) {
+        regulatedNodes_ = new FixedNodes(atc_);
+      }
+      else if (atomicRegulator_->coupling_mode() == Kinetostat::FIXED) {
+          // include boundary nodes
+          regulatedNodes_ = new FixedBoundaryNodes(atc_);
+      }
+      else {
+        throw ATC_Error("KinetostatFixed::construct_regulated_nodes - couldn't determine set of regulated nodes");
+      }
      
-    interscaleManager.add_set_int(regulatedNodes_,
-                                  regulatorPrefix_+"RegulatedNodes");
+      interscaleManager.add_set_int(regulatedNodes_,
+                                    regulatorPrefix_+"RegulatedNodes");
+    }
 
     applicationNodes_ = regulatedNodes_;
 
     // special set of boundary elements for defining regulated atoms 
     if (atomicRegulator_->use_localized_lambda()) {
-      elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
-      interscaleManager.add_dense_matrix_bool(elementMask_,
-                                                   regulatorPrefix_+"BoundaryElementMask");
+      elementMask_ = interscaleManager.dense_matrix_bool(regulatorPrefix_+"BoundaryElementMask");
+      if (!elementMask_) {
+        elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
+        interscaleManager.add_dense_matrix_bool(elementMask_,
+                                                regulatorPrefix_+"BoundaryElementMask");
+      }
     }
   }
 
   //--------------------------------------------------------
   //  initialize_delta_nodal_atomic_momentum:
   //    initializes storage for the variable tracking
   //    the change in the nodal atomic momentum
   //    that has occured over the past timestep
   //--------------------------------------------------------
   void KinetostatFixed::initialize_delta_nodal_atomic_momentum(double dt)
   {
     // initialize delta energy
     const DENS_MAT & myNodalAtomicMomentum(nodalAtomicMomentum_->quantity());
     initialNodalAtomicMomentum_ = myNodalAtomicMomentum;
     initialNodalAtomicMomentum_ *= -1.; // initially stored as negative for efficiency
     timeFilter_->apply_pre_step1(nodalAtomicMomentumFiltered_.set_quantity(),
                                  myNodalAtomicMomentum,dt);
   }
 
   //--------------------------------------------------------
   //  compute_delta_nodal_atomic_momentum:
   //    computes the change in the nodal atomic momentum
   //    that has occured over the past timestep
   //--------------------------------------------------------
   void KinetostatFixed::compute_delta_nodal_atomic_momentum(double dt)
   {
     // set delta energy based on predicted atomic velocities
     const DENS_MAT & myNodalAtomicMomentum(nodalAtomicMomentum_->quantity());
     timeFilter_->apply_post_step1(nodalAtomicMomentumFiltered_.set_quantity(),
                                   myNodalAtomicMomentum,dt);
     deltaNodalAtomicMomentum_ = initialNodalAtomicMomentum_;
     deltaNodalAtomicMomentum_ += myNodalAtomicMomentum;
   }
 
+  //--------------------------------------------------------
+  //  compute_lambda
+  //   sets up and solves linear system for lambda
+  //--------------------------------------------------------
+  void KinetostatFixed::compute_lambda(double dt)
+  {
+    // compute predicted changes in nodal atomic momentum
+    compute_delta_nodal_atomic_momentum(dt);
+
+    // change in finite element momentum
+    deltaFeMomentum_ = initialFeMomentum_;
+    deltaFeMomentum_ += (mdMassMatrix_.quantity())*(velocity_.quantity());
+
+    // set up rhs for lambda equation
+    KinetostatGlcFs::compute_lambda(dt);
+  }
+
   //--------------------------------------------------------
   //  apply_pre_predictor:
   //    apply the kinetostat to the atoms in the
   //    pre-predictor integration phase
   //--------------------------------------------------------
   void KinetostatFixed::apply_pre_predictor(double dt)
   {
     // initialize values to be track change in finite element energy over the timestep
     initialize_delta_nodal_atomic_momentum(dt);
     initialFeMomentum_ = -1.*((mdMassMatrix_.quantity())*(velocity_.quantity())); // initially stored as negative for efficiency
 
     KinetostatGlcFs::apply_pre_predictor(dt);
   }
+
+  //--------------------------------------------------------
+  //  apply_pre_corrector:
+  //    apply the kinetostat to the atoms in the first part
+  //    of the corrector step of the Verlet algorithm
+  //--------------------------------------------------------
+  void KinetostatFixed::apply_pre_corrector(double dt)
+  {
+    // do full prediction if we just redid the shape functions
+    if (full_prediction()) {
+      _tempNodalAtomicMomentumFiltered_ = nodalAtomicMomentumFiltered_.quantity();
+    }
+
+   KinetostatGlcFs::apply_pre_corrector(dt);
+
+    if (full_prediction()) {
+      // reset temporary variables
+      nodalAtomicMomentumFiltered_ = _tempNodalAtomicMomentumFiltered_;
+    }
+  }
  
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the kinetostat to the atoms in the
   //    post-corrector integration phase
   //--------------------------------------------------------
   void KinetostatFixed::apply_post_corrector(double dt)
   {  
+    
+    bool halveForce = halve_force();
+
     KinetostatGlcFs::apply_post_corrector(dt);
 
     // update filtered momentum with lambda force
     DENS_MAT & myNodalAtomicLambdaForce(nodalAtomicLambdaForce_->set_quantity());
     timeFilter_->apply_post_step2(nodalAtomicMomentumFiltered_.set_quantity(),
                                   myNodalAtomicLambdaForce,dt);
 
-    if (halve_force()) {
+    if (halveForce) {
       // Halve lambda force due to fixed temperature constraints
       // 1) makes up for poor initial condition
       // 2) accounts for possibly large value of lambda when atomic shape function values change
       //    from eulerian mapping after more than 1 timestep
       //    avoids unstable oscillations arising from 
       //    thermostat having to correct for error introduced in lambda changing the 
       //    shape function matrices
       *lambda_ *= 0.5;
     }
-    
-    isFirstTimestep_ = false;
   }
 
   //--------------------------------------------------------
-  //  compute_kinetostat
-  //            manages the solution and application of the
-  //            kinetostat equations and variables
+  //  add_to_momentum:
+  //            determines what if any contributions to the
+  //            finite element equations are needed for
+  //            consistency with the kinetostat
   //--------------------------------------------------------
-  void KinetostatFixed::compute_lambda(double dt)
+  void KinetostatFixed::add_to_momentum(const DENS_MAT & nodalLambdaForce,
+                                       DENS_MAT & deltaMomentum,
+                                       double dt)
   {
-    // compute predicted changes in nodal atomic momentum
-    compute_delta_nodal_atomic_momentum(dt);
-
-    // change in finite element momentum
-    deltaFeMomentum_ = initialFeMomentum_;
-    deltaFeMomentum_ += (mdMassMatrix_.quantity())*(velocity_.quantity());
-
-    // set up rhs for lambda equation
-    KinetostatGlcFs::compute_lambda(dt);
+    deltaMomentum.resize(nNodes_,nsd_);
+    const set<int> & regulatedNodes(regulatedNodes_->quantity());
+    for (int i = 0; i < nNodes_; i++) {
+      if (regulatedNodes.find(i) != regulatedNodes.end()) {
+        for (int j = 0; j < nsd_; j++) {
+          deltaMomentum(i,j) = 0.;
+        }
+      }
+      else {
+        for (int j = 0; j < nsd_; j++) {
+          deltaMomentum(i,j) = nodalLambdaForce(i,j);
+        }
+      }
+    }
   }
 
   //--------------------------------------------------------
   //  set_kinetostat_rhs
   //            sets up the RHS of the kinetostat equations
   //            for the coupling parameter lambda
   //--------------------------------------------------------
   void KinetostatFixed::set_kinetostat_rhs(DENS_MAT & rhs, double dt)
   {
     // for essential bcs (fixed nodes) :
     // form rhs : (delUpsV - delUps)/dt
     const set<int> & regulatedNodes(regulatedNodes_->quantity());
     double factor = (1./dt);
     for (int i = 0; i < nNodes_; i++) {
       if (regulatedNodes.find(i) != regulatedNodes.end()) {
         for (int j = 0; j < nsd_; j++) {
           rhs(i,j) = factor*(deltaNodalAtomicMomentum_(i,j) - deltaFeMomentum_(i,j));
         }
       }
       else {
         for (int j = 0; j < nsd_; j++) {
           rhs(i,j) = 0.;
         }
       }
     }
   }
 
   //--------------------------------------------------------
-  //  add_to_momentum:
-  //            determines what if any contributions to the
-  //            finite element equations are needed for
-  //            consistency with the kinetostat
   //--------------------------------------------------------
-  void KinetostatFixed::add_to_momentum(const DENS_MAT & nodalLambdaForce,
-                                       DENS_MAT & deltaMomentum,
-                                       double dt)
+  //  Class KinetostatFluxFixed
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+ 
+  //--------------------------------------------------------
+  //  Constructor
+  //--------------------------------------------------------
+  KinetostatFluxFixed::KinetostatFluxFixed(AtomicRegulator * kinetostat,
+                                           bool constructKinetostats) :
+    RegulatorMethod(kinetostat),
+    kinetostatFlux_(NULL),
+    kinetostatFixed_(NULL),
+    kinetostatBcs_(NULL)
   {
-    deltaMomentum.resize(nNodes_,nsd_);
-    const set<int> & regulatedNodes(regulatedNodes_->quantity());
-    for (int i = 0; i < nNodes_; i++) {
-      if (regulatedNodes.find(i) != regulatedNodes.end()) {
-        for (int j = 0; j < nsd_; j++) {
-          deltaMomentum(i,j) = 0.;
-        }
+    if (constructKinetostats) {
+      if (kinetostat->coupling_mode(VELOCITY) == AtomicRegulator::GHOST_FLUX) {
+        kinetostatFlux_ = new KinetostatFluxGhost(kinetostat,regulatorPrefix_+"Flux");
       }
       else {
-        for (int j = 0; j < nsd_; j++) {
-          deltaMomentum(i,j) = nodalLambdaForce(i,j);
-        }
+        kinetostatFlux_ = new KinetostatFlux(kinetostat,regulatorPrefix_+"Flux");
+      }
+      kinetostatFixed_ = new KinetostatFixed(kinetostat,regulatorPrefix_+"Fixed");
+
+      // need to choose BC type based on coupling mode
+      if (kinetostat->coupling_mode() == AtomicRegulator::FLUX || kinetostat->coupling_mode(VELOCITY) == AtomicRegulator::GHOST_FLUX) {
+        kinetostatBcs_ = kinetostatFlux_;
+      }
+      else if (kinetostat->coupling_mode() == AtomicRegulator::FIXED) {
+        kinetostatBcs_ = kinetostatFixed_;
+      }
+      else {
+        throw ATC_Error("KinetostatFluxFixed::constructor - invalid kinetostat type provided");
       }
     }
   }
+
+  //--------------------------------------------------------
+  //  Destructor
+  //--------------------------------------------------------
+  KinetostatFluxFixed::~KinetostatFluxFixed()
+  {
+    if (kinetostatFlux_) delete kinetostatFlux_;
+    if (kinetostatFixed_) delete kinetostatFixed_;
+  }
+
+  //--------------------------------------------------------
+  //  constructor_transfers
+  //    instantiates or obtains all dependency managed data
+  //--------------------------------------------------------
+  void KinetostatFluxFixed::construct_transfers()
+  {
+    kinetostatFlux_->construct_transfers();
+    kinetostatFixed_->construct_transfers();
+  }
+
+  //--------------------------------------------------------
+  //  initialize
+  //    initializes all method data
+  //--------------------------------------------------------
+  void KinetostatFluxFixed::initialize()
+  {
+    kinetostatFlux_->initialize();
+    kinetostatFixed_->initialize();
+  }
+
+  //--------------------------------------------------------
+  //  apply_predictor:
+  //    apply the thermostat to the atoms in the first step
+  //    of the Verlet algorithm
+  //--------------------------------------------------------
+  void KinetostatFluxFixed::apply_pre_predictor(double dt)
+  {
+    kinetostatFlux_->apply_pre_predictor(dt);
+    kinetostatFixed_->apply_pre_predictor(dt);
+  }
+
+  //--------------------------------------------------------
+  //  apply_pre_corrector:
+  //    apply the thermostat to the atoms in the first part
+  //    of the corrector step of the Verlet algorithm
+  //--------------------------------------------------------
+  void KinetostatFluxFixed::apply_pre_corrector(double dt)
+  {
+    kinetostatFlux_->apply_pre_corrector(dt);
+    if (kinetostatFixed_->full_prediction()) {
+      atc_->set_fixed_nodes();
+    }
+    kinetostatFixed_->apply_pre_corrector(dt);
+  }
+
+  //--------------------------------------------------------
+  //  apply_post_corrector:
+  //    apply the thermostat to the atoms in the second part
+  //    of the corrector step of the Verlet algorithm
+  //--------------------------------------------------------
+  void KinetostatFluxFixed::apply_post_corrector(double dt)
+  {
+    kinetostatFlux_->apply_post_corrector(dt);
+    atc_->set_fixed_nodes();
+    kinetostatFixed_->apply_post_corrector(dt);
+  }
+
+  //--------------------------------------------------------
+  //  output:
+  //    adds all relevant output to outputData
+  //--------------------------------------------------------
+  void KinetostatFluxFixed::output(OUTPUT_LIST & outputData)
+  {
+    kinetostatFlux_->output(outputData);
+    kinetostatFixed_->output(outputData);
+  }
+
 };
diff --git a/lib/atc/Kinetostat.h b/lib/atc/Kinetostat.h
index 184003429..3d9b8cd5d 100644
--- a/lib/atc/Kinetostat.h
+++ b/lib/atc/Kinetostat.h
@@ -1,809 +1,882 @@
 #ifndef KINETOSTAT_H
 #define KINETOSTAT_H
 
 #include "AtomicRegulator.h"
 #include "PerAtomQuantityLibrary.h"
 #include <map>
 #include <set>
 #include <utility>
 #include <string>
 
 namespace ATC {
 
   // forward declarations
   class FundamentalAtomQuantity;
   class AtfShapeFunctionRestriction;
   template <typename T>
     class ProtectedAtomQuantity;
 
   /**
    *  @class  Kinetostat
    *  @brief  Manager class for atom-continuum control of momentum and position
    */
 
   class Kinetostat : public AtomicRegulator {
   
   public:
 
     // constructor
     Kinetostat(ATC_Coupling *atc,
                const std::string & regulatorPrefix = "");
         
     // destructor
     virtual ~Kinetostat(){};
         
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
 
     /** instantiate up the desired method(s) */
     virtual void construct_methods();
 
     // data access, intended for method objects
     /** reset the nodal force to a prescribed value */
     virtual void reset_lambda_contribution(const DENS_MAT & target);
 
   private:
 
     // DO NOT define this
     Kinetostat();
 
   };
 
   /**
    *  @class  KinetostatShapeFunction
    *  @brief  Base class for implementation of kinetostat algorithms based on FE shape functions
    */
   
   class KinetostatShapeFunction : public RegulatorShapeFunction {
   
   public:
   
-    KinetostatShapeFunction(Kinetostat *kinetostat,
+    KinetostatShapeFunction(AtomicRegulator *kinetostat,
                             const std::string & regulatorPrefix = "");
         
     virtual ~KinetostatShapeFunction(){};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
   protected:
 
     // methods
     /** set weighting factor for in matrix Nhat^T * weights * Nhat */
     virtual void set_weights();
 
     // member data
-    /** pointer to thermostat object for data */
-    Kinetostat * kinetostat_;
+    /** MD mass matrix */
+    DIAG_MAN & mdMassMatrix_;
     /** pointer to a time filtering object */
     TimeFilter * timeFilter_;
     /** stress induced by lambda */
     DENS_MAN * nodalAtomicLambdaForce_;
     /** filtered lambda force */
     DENS_MAN * lambdaForceFiltered_;
     /** atomic force induced by lambda */
     ProtectedAtomQuantity<double> * atomKinetostatForce_;
     /** lambda prolonged to the atoms */
     ProtectedAtomQuantity<double> * atomLambda_;
 
     /** pointer to atom velocities */
     FundamentalAtomQuantity * atomVelocities_;
     /** pointer to atom velocities */
     FundamentalAtomQuantity * atomMasses_;
 
     // workspace
     DENS_MAT _nodalAtomicLambdaForceOut_; // matrix for output only
 
   private:
     
     // DO NOT define this
     KinetostatShapeFunction();
 
   };
   
   /**
    *  @class  GlcKinetostat
    *  @brief  Base class for implementation of kinetostat algorithms based on Gaussian least constraints (GLC)
    */
   
   class GlcKinetostat : public KinetostatShapeFunction {
   
   public:
   
-    GlcKinetostat(Kinetostat *kinetostat);
+    GlcKinetostat(AtomicRegulator *kinetostat);
         
     virtual ~GlcKinetostat(){};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
 
   protected:
 
     // methods
     /** apply forces to atoms */
     virtual void apply_to_atoms(PerAtomQuantity<double> * quantity,
                                 const DENS_MAT & lambdaAtom,
                                 double dt=0.);
 
     /** apply any required corrections for localized kinetostats */
     virtual void apply_localization_correction(const DENS_MAT & source,
                                                DENS_MAT & nodalField,
                                                double weight = 1.){};
 
     // member data
-
-    /** MD mass matrix */
-    DIAG_MAN & mdMassMatrix_;
-
     /** nodeset corresponding to Hoover coupling */
     std::set<std::pair<int,int> > hooverNodes_;
 
     
     /** pointer to atom positions */
     FundamentalAtomQuantity * atomPositions_;
 
   private:
     
     // DO NOT define this
     GlcKinetostat();
 
   };
   
   /**
    *  @class  DisplacementGlc
    *  @brief  Enforces GLC on atomic position based on FE displacement
    */
   
   class DisplacementGlc : public GlcKinetostat {
   
   public:
   
-    DisplacementGlc(Kinetostat * kinetostat);
+    DisplacementGlc(AtomicRegulator * kinetostat);
         
     virtual ~DisplacementGlc(){};
         
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
 
     /** applies kinetostat to atoms */
     virtual void apply_post_predictor(double dt);
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
 
     /** determine if local shape function matrices are needed */
     virtual bool use_local_shape_functions() const {return (!atomicRegulator_->use_lumped_lambda_solve()) && atomicRegulator_->use_localized_lambda();};
         
   protected:
         
     // methods
     /** set weighting factor for in matrix Nhat^T * weights * Nhat */
     virtual void set_weights();
 
     /** does initial filtering operations before main computation */
     virtual void apply_pre_filtering(double dt);
     /** sets up and solves kinetostat equations */
     virtual void compute_kinetostat(double dt);
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs, double dt);
     /** computes the nodal FE force applied by the kinetostat */
     virtual void compute_nodal_lambda_force(double dt);
     /** apply any required corrections for localized kinetostats */
     virtual void apply_localization_correction(const DENS_MAT & source,
                                                DENS_MAT & nodalField,
                                                double weight = 1.);
 
     // data
     /** restricted atomic displacements at the nodes */
     DENS_MAN * nodalAtomicMassWeightedDisplacement_;
     /** clone of FE displacement field */
     DENS_MAN & nodalDisplacements_;
 
   private:
     
     // DO NOT define this
     DisplacementGlc();
   
   };
 
   /**
    *  @class  DisplacementGlcFiltered
    *  @brief  Enforces GLC on time filtered atomic position based on FE displacement
    */
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class DisplacementGlcFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class DisplacementGlcFiltered : public DisplacementGlc {
   
   public:
   
-    DisplacementGlcFiltered(Kinetostat * kinetostat);
+    DisplacementGlcFiltered(AtomicRegulator * kinetostat);
         
     virtual ~DisplacementGlcFiltered(){};
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
         
   protected:
         
     // methods
     /** does initial filtering operations before main computation */
     virtual void apply_pre_filtering(double dt);
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs, double dt);
     /** computes the nodal FE force applied by the kinetostat */
     virtual void compute_nodal_lambda_force(double dt);
 
     // data
     /** clone of FE nodal atomic displacement field */
     DENS_MAN & nodalAtomicDisplacements_;
 
   private:
     
     // DO NOT define this
     DisplacementGlcFiltered();
   
   };
 
   /**
    *  @class  VelocityGlc
    *  @brief  Enforces GLC on atomic velocity based on FE velocity
    */
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class VelocityGlc
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class VelocityGlc : public GlcKinetostat {
   
   public:
   
-    VelocityGlc(Kinetostat * kinetostat);
+    VelocityGlc(AtomicRegulator * kinetostat);
         
     virtual ~VelocityGlc(){};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
         
     /** applies kinetostat to atoms */
     virtual void apply_mid_predictor(double dt);
 
     /** applies kinetostat to atoms */
     virtual void apply_post_corrector(double dt);
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
     
     /** determine if local shape function matrices are needed */
     virtual bool use_local_shape_functions() const {return (!atomicRegulator_->use_lumped_lambda_solve()) && atomicRegulator_->use_localized_lambda();};
 
   protected:
   
     // methods
     /** set weighting factor for in matrix Nhat^T * weights * Nhat */
     virtual void set_weights();
 
     /** does initial filtering operations before main computation */
     virtual void apply_pre_filtering(double dt);
     /** sets up and solves kinetostat equations */
     virtual void compute_kinetostat(double dt);
+    /** applies kinetostat correction to atoms */
+    virtual void apply_kinetostat(double dt);
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs, double dt);
     /** computes the nodal FE force applied by the kinetostat */
     virtual void compute_nodal_lambda_force(double dt);
     /** apply any required corrections for localized kinetostats */
     virtual void apply_localization_correction(const DENS_MAT & source,
                                                DENS_MAT & nodalField,
                                                double weight = 1.);
 
     // data
     /** restricted atomic displacements at the nodes */
     DENS_MAN * nodalAtomicMomentum_;
     /** clone of FE velocity field */
     DENS_MAN & nodalVelocities_;
 
   private:
 
     // DO NOT define this
     VelocityGlc();
   
   };
 
   /**
    *  @class  VelocityGlcFiltered
    *  @brief  Enforces GLC on time filtered atomic velocity based on FE velocity
    */
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class VelocityGlcFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class VelocityGlcFiltered : public VelocityGlc {
   
   public:
   
-    VelocityGlcFiltered(Kinetostat * kinetostat);
+    VelocityGlcFiltered(AtomicRegulator * kinetostat);
         
     virtual ~VelocityGlcFiltered(){};
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
         
   protected:
 
     // methods
     /** does initial filtering operations before main computation */
     virtual void apply_pre_filtering(double dt);
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs, double dt);
     /** computes the nodal FE force applied by the kinetostat */
     virtual void compute_nodal_lambda_force(double dt);
   
     // data
     /** clone of FE nodal atomic velocity field */
     DENS_MAN & nodalAtomicVelocities_;
 
   private:
 
     // DO NOT define this
     VelocityGlcFiltered();
         
   };
 
   /**
    *  @class  StressFlux
    *  @brief  Enforces GLC on atomic forces based on FE stresses or accelerations
    */
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class StressFlux
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class StressFlux : public GlcKinetostat {
   
   public:
   
-    StressFlux(Kinetostat * kinetostat);
+    StressFlux(AtomicRegulator * kinetostat);
         
     virtual ~StressFlux();
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** applies kinetostat to atoms in the pre-predictor phase */
     virtual void apply_pre_predictor(double dt);
 
     /** applies kinetostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
 
     /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields);
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
 
     /** sets filtered ghost force to prescribed value */
     void reset_filtered_ghost_force(DENS_MAT & targetForce);
     /** returns reference to filtered ghost force */
     DENS_MAN & filtered_ghost_force() {return nodalGhostForceFiltered_;};
 
     /** determine if local shape function matrices are needed */
     virtual bool use_local_shape_functions() const {return ((!atomicRegulator_->use_lumped_lambda_solve()) && atomicRegulator_->use_localized_lambda());};
         
   protected:
 
     // data
     /** nodal force */
     DENS_MAN & nodalForce_;
     /** nodal force due to atoms */
     DENS_MAN * nodalAtomicForce_;
     /** nodal ghost force */
     AtfShapeFunctionRestriction * nodalGhostForce_;
     /** filtered ghost force */
     DENS_MAN nodalGhostForceFiltered_;
     /** reference to ATC sources coming from prescribed data, AtC coupling, and extrinsic coupling */
     DENS_MAN & momentumSource_;
 
     // methods
     /** does initial filtering operations before main computation */
     virtual void apply_pre_filtering(double dt);
     /** sets up and solves kinetostat equations */
     virtual void compute_kinetostat(double dt);
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs, double dt);
     /** computes the nodal FE force applied by the kinetostat */
     virtual void compute_nodal_lambda_force(double dt);
     /** apply forces to atoms */
     virtual void apply_to_atoms(PerAtomQuantity<double> * atomVelocities,
                                 const DENS_MAT & lambdaForce,
                                 double dt);
     /** adds in finite element rhs contributions */
     virtual void add_to_rhs(FIELDS & rhs);
 
     // workspace
     DENS_MAT _deltaVelocity_; // change in velocity during time integration
   private:
 
     // DO NOT define this
     StressFlux();
 
   };
 
   /**
    *  @class  StressFluxGhost
    *  @brief  Enforces GLC on atomic forces based on FE stresses or accelerations, using
    *          the ghost forces to prescribe the FE boundary stress
    */
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class StressFluxGhost
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class StressFluxGhost : public StressFlux {
   
   public:
   
-    StressFluxGhost(Kinetostat * kinetostat);
+    StressFluxGhost(AtomicRegulator * kinetostat);
         
     virtual ~StressFluxGhost() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** compute boundary flux, requires kinetostat input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields);
         
   protected:
 
     // methods
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs, double dt);
     /** adds in finite element rhs contributions */
     virtual void add_to_rhs(FIELDS & rhs);
 
   private:
 
     // DO NOT define this
     StressFluxGhost();
 
   };
 
   /**
    *  @class  StressFluxFiltered
    *  @brief  Enforces GLC on time filtered atomic forces based on FE stresses or accelerations
    */
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class StressFluxFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   class StressFluxFiltered : public StressFlux {
   
   public:
   
-    StressFluxFiltered(Kinetostat * kinetostat);
+    StressFluxFiltered(AtomicRegulator * kinetostat);
         
     virtual ~StressFluxFiltered(){};
 
     /** adds in finite element rhs contributions */
     virtual void add_to_rhs(FIELDS & rhs);
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
         
   protected:
 
     // data
     DENS_MAN & nodalAtomicVelocity_;
 
     // methods
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs, double dt);
     
     /** apply forces to atoms */
     virtual void apply_to_atoms(PerAtomQuantity<double> * quantity,
                                 const DENS_MAT & lambdaAtom,
                                 double dt);
 
   private:
 
     // DO NOT define this
     StressFluxFiltered();
 
   };
 
   /**
    *  @class  KinetostatGlcFs
    *  @brief  Base class for implementation of kinetostat algorithms based on Gaussian least constraints (GLC)
    *          when fractional step time integration is used
    */
   
   class KinetostatGlcFs : public KinetostatShapeFunction {
   
   public:
   
-    KinetostatGlcFs(Kinetostat *kinetostat,
+    KinetostatGlcFs(AtomicRegulator *kinetostat,
                     const std::string & regulatorPrefix = "");
         
     virtual ~KinetostatGlcFs(){};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
 
     /** applies thermostat to atoms in the predictor phase */
     virtual void apply_pre_predictor(double dt);
 
+    /** applies thermostat to atoms in the pre-corrector phase */
+    virtual void apply_pre_corrector(double dt);
+
     /** applies thermostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
     
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
 
+    /* flag for performing the full lambda prediction calculation */
+    bool full_prediction();
+
   protected:
 
     // methods
     /** determine mapping from all nodes to those to which the kinetostat applies */
     void compute_rhs_map();
 
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs,
                                     double dt) = 0;
 
     /** apply forces to atoms */
     virtual void apply_to_atoms(PerAtomQuantity<double> * atomicVelocity,
                                 const DENS_MAN * nodalAtomicEnergy,
                                 const DENS_MAT & lambdaForce,
                                 DENS_MAT & nodalAtomicLambdaPower,
                                 double dt);
 
     /** add contributions from kinetostat to FE energy */
     virtual void add_to_momentum(const DENS_MAT & nodalLambdaForce,
                                  DENS_MAT & deltaMomemtum,
                                  double dt) = 0;
 
     /* sets up and solves the linear system for lambda */
     virtual void compute_lambda(double dt);
 
-    /** sets up the transfer which is the set of nodes being regulated */
-    virtual void construct_regulated_nodes() = 0;
-
     // member data
     /** reference to AtC FE velocity */
     DENS_MAN & velocity_;
 
     /** nodal atomic momentum */
     DENS_MAN * nodalAtomicMomentum_;
 
+    /** hack to determine if first timestep has been passed */
+    bool isFirstTimestep_;
+
+    /** local version of velocity used as predicted final veloctiy */
+    PerAtomQuantity<double> * atomPredictedVelocities_;
+
+    /** predicted nodal atomic momentum */
+    AtfShapeFunctionRestriction * nodalAtomicPredictedMomentum_;
+
+    /** FE momentum change from kinetostat forces */
+    DENS_MAT deltaMomentum_;
+
     /** right-hand side data for thermostat equation */
     DENS_MAT rhs_;
 
-    /** mapping from all to regulated nodes */
-    DENS_MAT rhsMap_;
+    /** fraction of timestep over which constraint is exactly enforced */
+    double dtFactor_;
 
     // workspace
     DENS_MAT _lambdaForceOutput_; // force applied by lambda in output format
     DENS_MAT _velocityDelta_; // change in velocity when lambda force is applied
-    DENS_MAT _deltaMomentum_; // FE velocity change from kinetostat
 
   private:
     
     // DO NOT define this
     KinetostatGlcFs();
 
   };
 
   /**
    *  @class  KinetostatFlux
    *  @brief  Implementation of kinetostat algorithms based on Gaussian least constraints (GLC)
    *          which apply stresses when fractional step time integration is used
    */
   
   class KinetostatFlux : public KinetostatGlcFs {
   
   public:
   
-    KinetostatFlux(Kinetostat *kinetostat,
+    KinetostatFlux(AtomicRegulator *kinetostat,
                    const std::string & regulatorPrefix = "");
         
     virtual ~KinetostatFlux(){};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
 
     /** applies thermostat to atoms in the predictor phase */
     virtual void apply_pre_predictor(double dt);
 
     /** applies thermostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
 
     /** enables resetting of filtered ghost force */
     void reset_filtered_ghost_force(DENS_MAT & target);
 
   protected:
 
     // methods
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs,
                                     double dt);
 
     /** add contributions from kinetostat to FE energy */
     virtual void add_to_momentum(const DENS_MAT & nodalLambdaForce,
                                  DENS_MAT & deltaMomemtum,
                                  double dt);
 
     /** sets up the transfer which is the set of nodes being regulated */
     virtual void construct_regulated_nodes();
 
     // member data
     /** reference to ATC sources coming from prescribed data, AtC coupling, and extrinsic coupling */
     DENS_MAN & momentumSource_;
     
     /** force from ghost atoms restricted to nodes */
     DENS_MAN * nodalGhostForce_;
 
     /** filtered nodal ghost force */
     DENS_MAN * nodalGhostForceFiltered_;
 
   private:
     
     // DO NOT define this
     KinetostatFlux();
 
   };
 
   /**
    *  @class  KinetostatFluxGhost
    *  @brief  Implements ghost-atom boundary flux and other loads for fractional-step based kinetostats
    */
   
   class KinetostatFluxGhost : public KinetostatFlux {
   
   public:
   
-    KinetostatFluxGhost(Kinetostat *kinetostat,
+    KinetostatFluxGhost(AtomicRegulator *kinetostat,
                         const std::string & regulatorPrefix = "");
         
     virtual ~KinetostatFluxGhost(){};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** compute boundary flux */
     virtual void compute_boundary_flux(FIELDS & fields);
 
   protected:
 
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs,
                                     double dt);
 
     /** add contributions from kinetostat to FE energy */
     virtual void add_to_momentum(const DENS_MAT & nodalLambdaForce,
                                  DENS_MAT & deltaMomemtum,
                                  double dt);
 
   private:
     
     // DO NOT define this
     KinetostatFluxGhost();
 
   };
 
     /**
    *  @class  KinetostatFixed
    *  @brief  Implementation of kinetostat algorithms based on Gaussian least constraints (GLC)
    *          which perform Hoover coupling when fractional step time integration is used
    */
   
   class KinetostatFixed : public KinetostatGlcFs {
   
   public:
   
-    KinetostatFixed(Kinetostat *kinetostat,
+    KinetostatFixed(AtomicRegulator *kinetostat,
                     const std::string & regulatorPrefix = "");
         
     virtual ~KinetostatFixed(){};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
 
     /** applies thermostat to atoms in the predictor phase */
     virtual void apply_pre_predictor(double dt);
 
+    /** applies thermostat to atoms in the pre-corrector phase */
+    virtual void apply_pre_corrector(double dt);
+
     /** applies thermostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
 
+    /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
+    virtual void compute_boundary_flux(FIELDS & fields)
+      {boundaryFlux_[VELOCITY] = 0.;};
+
     /** determine if local shape function matrices are needed */
     virtual bool use_local_shape_functions() const {return atomicRegulator_->use_localized_lambda();};
 
   protected:
 
     // methods
     /** initialize data for tracking the change in nodal atomic velocity */
     virtual void initialize_delta_nodal_atomic_momentum(double dt);
 
     /** compute the change in nodal atomic velocity */
     virtual void compute_delta_nodal_atomic_momentum(double dt);
 
     /** sets up appropriate rhs for kinetostat equations */
     virtual void set_kinetostat_rhs(DENS_MAT & rhs,
                                     double dt);
 
     /** add contributions from kinetostat to FE energy */
     virtual void add_to_momentum(const DENS_MAT & nodalLambdaForce,
                                  DENS_MAT & deltaMomemtum,
                                  double dt);
 
     /* sets up and solves the linear system for lambda */
     virtual void compute_lambda(double dt);
 
     /** flag for halving the applied force to mitigate numerical errors */
     bool halve_force();
 
     /** sets up the transfer which is the set of nodes being regulated */
     virtual void construct_regulated_nodes();
 
     // member data
-    /** MD mass matrix */
-    DIAG_MAN & mdMassMatrix_;
-
     /** change in FE momentum over a timestep */
     DENS_MAT deltaFeMomentum_;
 
     /** initial FE momentum used to compute change */
     DENS_MAT initialFeMomentum_;
 
     /** change in restricted atomic FE momentum over a timestep */
     DENS_MAT deltaNodalAtomicMomentum_;
 
     /** intial restricted atomic FE momentum used to compute change */
     DENS_MAT initialNodalAtomicMomentum_;
 
     /** filtered nodal atomic momentum */
     DENS_MAN nodalAtomicMomentumFiltered_;
 
-    /** hack to determine if first timestep has been passed */
-    bool isFirstTimestep_;
+    /** coefficient to account for effect of time filtering on rhs terms */
+    double filterCoefficient_;
+
+    // workspace
+    DENS_MAT _tempNodalAtomicMomentumFiltered_; // stores filtered momentum change in atoms for persistence during predictor
 
   private:
     
     // DO NOT define this
     KinetostatFixed();
 
   };
 
+  /**
+   *  @class  KinetostatFluxFixed
+   *  @brief  Class for kinetostatting using the velocity matching constraint one one set of nodes and the flux matching constraint on another
+   */
+
+  class KinetostatFluxFixed : public RegulatorMethod {
+
+  public:
+
+    KinetostatFluxFixed(AtomicRegulator * kinetostat,
+                        bool constructThermostats = true);
+        
+    virtual ~KinetostatFluxFixed();
+
+    /** instantiate all needed data */
+    virtual void construct_transfers();
+
+    /** pre-run initialization of method data */
+    virtual void initialize();
+
+    /** applies thermostat to atoms in the predictor phase */
+    virtual void apply_pre_predictor(double dt);
+
+    /** applies thermostat to atoms in the pre-corrector phase */
+    virtual void apply_pre_corrector(double dt);
+
+    /** applies thermostat to atoms in the post-corrector phase */
+    virtual void apply_post_corrector(double dt);
+    
+    /** get data for output */
+    virtual void output(OUTPUT_LIST & outputData);
+
+    /** compute boundary flux, requires kinetostat input since it is part of the coupling scheme */
+    virtual void compute_boundary_flux(FIELDS & fields)
+      {kinetostatBcs_->compute_boundary_flux(fields);};
+
+  protected:
+
+    // data
+    /** kinetostat for imposing the fluxes */
+    KinetostatFlux * kinetostatFlux_;
+
+    /** kinetostat for imposing fixed nodes */
+    KinetostatFixed * kinetostatFixed_;
+
+    /** pointer to whichever kinetostat should compute the flux, based on coupling method */
+    KinetostatGlcFs * kinetostatBcs_;
+
+  private:
+
+    // DO NOT define this
+    KinetostatFluxFixed();
+  };
+
 }
 
 #endif
diff --git a/lib/atc/LammpsInterface.cpp b/lib/atc/LammpsInterface.cpp
index 565a3c987..78859aec6 100644
--- a/lib/atc/LammpsInterface.cpp
+++ b/lib/atc/LammpsInterface.cpp
@@ -1,1534 +1,1555 @@
 // Header file for this class
 #include "LammpsInterface.h"
 // LAMMPS includes
 #include "lammps.h"
 #include "atom.h" // x, v, f
 #include "atom_vec.h" //for insertion
 #include "domain.h" // for basing locations on regions
 #include "region.h" // region bounding box and style
 #include "force.h" // boltzman constant
 #include "group.h" // atom masks
 #include "memory.h" // grow atom information
 #include "compute.h" // computes
 #include "compute_pe_atom.h" // computes potential energy per atom
 #include "compute_stress_atom.h" // computes stress per atom
 #include "compute_centro_atom.h" // computes centrosymmetry per atom
 #include "compute_cna_atom.h" // computes common-neighbor-analysis per atom
 #include "compute_coord_atom.h" // computes coordination number per atom
 #include "compute_ke_atom.h" // computes kinetic energy per atom
 #include "modify.h" // 
 #include "neighbor.h" // neighbors
 #include "neigh_list.h" // neighbor list
 #include "update.h" // timestepping information
 #include "pair.h" // pair potentials
 #include "MANYBODY/pair_eam.h" // pair potentials
 #include "lattice.h" // lattice parameters
 #include "bond.h" // bond potentials
 #include "comm.h" //
 #include "fix.h"
 
 // ATC includes
 #include "ATC_Error.h"
 #include "MatrixLibrary.h"
 #include "Utility.h"
 using ATC_Utility::to_string;
 
 // Other include files
 #include "mpi.h"
 #include <cstring>
 #include <map>
 #include <typeinfo>
 
 using std::max;
 using std::stringstream;
 using std::copy;
 using std::map;
 using std::pair;
 using std::string;
 using std::set;
 using LAMMPS_NS::bigint;
 
 namespace ATC {
 
 const static double PI = 3.141592653589793238;
 
 const static int seed_ = 3141592;
 
 const static int MAX_GROUP_BIT = 2147483647; //4294967295; // pow(2,31)-1;
 
 double norm(double * v) {return sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); }
 
 LammpsInterface * LammpsInterface::myInstance_ = NULL;
 
 // -----------------------------------------------------------------
 //  instance()
 // -----------------------------------------------------------------
 LammpsInterface * LammpsInterface::instance()
 {
   if (myInstance_ == NULL) {
     myInstance_ = new LammpsInterface();
   }
   return myInstance_;
 }
 
 // -----------------------------------------------------------------
 //  Destroy()
 // -----------------------------------------------------------------
 void LammpsInterface::Destroy()
 {
   if (myInstance_) delete myInstance_;
   myInstance_ = NULL;
 }
 
 
 // -----------------------------------------------------------------
 //  constructor
 // -----------------------------------------------------------------
 LammpsInterface::LammpsInterface()
   : lammps_(NULL),
     fixPointer_(NULL),
     commRank_(0),
     atomPE_(NULL),
     refBoxIsSet_(false),
     random_(NULL),
     globalrandom_(NULL)
 {
 }
 
 // -----------------------------------------------------------------
 //  general interface methods
 // -----------------------------------------------------------------
 
 MPI_Comm LammpsInterface::world() const { return lammps_->world; }
 void LammpsInterface::set_fix_pointer(LAMMPS_NS::Fix * thisFix) { fixPointer_ = thisFix; }
 void LammpsInterface::forward_comm_fix() const { lammps_->comm->forward_comm_fix(fixPointer_); }
 void LammpsInterface::comm_borders() const { lammps_->comm->borders(); }
 
 #ifndef ISOLATE_FE
 void LammpsInterface::sparse_allsum(SparseMatrix<double> &toShare) const
 {
   toShare.compress();
   
   // initialize MPI information
   int nProcs;
   int myRank;
   MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
 
   int error;
 
   // get numbers of rows, columns, rowsCRS, and 
   // sizes (number of nonzero elements in matrix)
   SparseMatInfo *recInfo = new SparseMatInfo[nProcs];
   SparseMatInfo myInfo;
   myInfo.rows    = toShare.nRows();
   myInfo.cols    = toShare.nCols();
   myInfo.rowsCRS = toShare.nRowsCRS();
   myInfo.size    = toShare.size();
 
   error = MPI_Allgather(&myInfo, 4, MPI_INT,
                         recInfo, 4, MPI_INT, lammps_->world);
   if (error != MPI_SUCCESS) throw ATC_Error("error in sparse_allsum_numrows "+to_string(error));
 
   // adjust row sendcounts because recRowsCRS is off by one
   int rowCounts[nProcs];
   int sizeCounts[nProcs];
   // set up total size of receive buffers for Allgatherv calls
   int totalRowsCRS = 0;
   int totalSize = 0;
   // set up array of displacements for Allgatherv calls
   int rowOffsets[nProcs];
   rowOffsets[0] = 0;
   int sizeOffsets[nProcs];
   sizeOffsets[0] = 0;
   for (int i = 0; i < nProcs; i++) {
     // find the total number of entries to share in the mpi calls below
     rowCounts[i] = recInfo[i].rowsCRS + 1;
     sizeCounts[i] = recInfo[i].size;
     totalRowsCRS += rowCounts[i];
     totalSize += recInfo[i].size;
     // these already have their 0th slot filled in
     if (i == 0) continue;
     rowOffsets[i] = rowOffsets[i-1] + rowCounts[i-1];
     sizeOffsets[i] = sizeOffsets[i-1] + sizeCounts[i-1];
   }
 
   // get actual rows
   INDEX *rec_ia = new INDEX[totalRowsCRS];
   if (toShare.size() == 0) {
     double dummy[0];
     error = MPI_Allgatherv(dummy, 0, MPI_INT,
                            rec_ia, rowCounts, rowOffsets, MPI_INT, lammps_->world);
   }
   else
     error = MPI_Allgatherv(toShare.rows(), rowCounts[myRank], MPI_INT,
                            rec_ia, rowCounts, rowOffsets, MPI_INT, lammps_->world);
   if (error != MPI_SUCCESS)
     throw ATC_Error("error in sparse_allsum_rowarray "+to_string(error));
 
   // get actual cols
   INDEX *rec_ja = new INDEX[totalSize];
   error = MPI_Allgatherv(toShare.cols(), sizeCounts[myRank], MPI_INT,
                          rec_ja, sizeCounts, sizeOffsets, MPI_INT, lammps_->world);
   if (error != MPI_SUCCESS)
     throw ATC_Error("error in sparse_allsum_colarray "+to_string(error));
      
   // get the array of values
   double *rec_vals = new double[totalSize];
   error = MPI_Allgatherv(toShare.ptr(), sizeCounts[myRank], MPI_DOUBLE,
                          rec_vals, sizeCounts, sizeOffsets, MPI_DOUBLE, lammps_->world);
   if (error != MPI_SUCCESS)
     throw ATC_Error("error in sparse_allsum_valarray "+to_string(error));
 
   INDEX *rec_ia_proc; 
   INDEX *rec_ja_proc; 
   double *rec_vals_proc;
   for (int i = 0; i < nProcs; i++) {
     if (myRank != i) {
       // deallocated when tempMat is deleted since it wraps them
       rec_ia_proc = new INDEX[rowCounts[i]];
       rec_ja_proc = new INDEX[sizeCounts[i]];
       rec_vals_proc = new double[sizeCounts[i]];
        
       // copy the data passed with MPI into the new spots
       copy(rec_ia + rowOffsets[i], 
            rec_ia + rowOffsets[i] + rowCounts[i],
            rec_ia_proc);
       copy(rec_ja + sizeOffsets[i], 
            rec_ja + sizeOffsets[i] + sizeCounts[i],
            rec_ja_proc);
       copy(rec_vals + sizeOffsets[i], 
            rec_vals + sizeOffsets[i] + sizeCounts[i],
            rec_vals_proc);
 
       // Does anyone know why we have to declare tempMat here (as well as set it equal to
       // something) to avoid segfaults? there are still segfaults, but they happen at a much 
       // later stage of the game now (and for less benchmarks overall).
       SparseMatrix<double> tempMat =
         SparseMatrix<double>(rec_ia_proc, rec_ja_proc, rec_vals_proc, 
                              recInfo[i].size, recInfo[i].rows, 
                              recInfo[i].cols, recInfo[i].rowsCRS);
       toShare += tempMat;
     }
   }
 
   delete[] recInfo;
   delete[] rec_ia;
   delete[] rec_ja;
   delete[] rec_vals;
 }
 #endif
 
+std::string LammpsInterface::read_file(std::string filename) const
+{
+  FILE *fp = NULL;
+  if (! comm_rank()) {
+    fp = fopen(filename.c_str(),"r");
+    if (!fp) throw ATC_Error("can't open file: "+filename);
+  }
+  const int MAXLINE = 256;
+  const int CHUNK   = 1024;
+  char * buffer = new char[CHUNK*MAXLINE];
+  std::stringstream s;
+  bool eof = false;
+  while ( ! eof) {
+    eof = lammps_->comm->read_lines_from_file(fp,1,MAXLINE,buffer);
+    s << buffer;
+  }
+  delete [] buffer;
+  return s.str(); // can't copy the stream itself
+}
+
+
 // -----------------------------------------------------------------
 //  atom interface methods
 // -----------------------------------------------------------------
 string LammpsInterface::fix_id() const { return string(fixPointer_->id); }
 
 int LammpsInterface::nlocal() const { return lammps_->atom->nlocal; }
 
 int LammpsInterface::nghost() const { return lammps_->atom->nghost; }
 
 bool LammpsInterface::atoms_sorted() const
 {
   int sortfreq = lammps_->atom->sortfreq;
   if (sortfreq > 0) { return true; } 
   else              { return false;
 }
 }
 
 
 bigint LammpsInterface::natoms() const { return lammps_->atom->natoms; }
 
 int LammpsInterface::nmax() const { return lammps_->atom->nmax; }
 
 int LammpsInterface::ntypes() const { return lammps_->atom->ntypes; }
 
 double ** LammpsInterface::xatom() const { return lammps_->atom->x; }
 
 int LammpsInterface::type_to_charge(int atype) const { 
   double *q = lammps_->atom->q;
   if (! q) return 0;
   int nlocal = lammps_->atom->nlocal;
   int *type = lammps_->atom->type;
   double aq = 0.0;
   for (int i = 0; i < nlocal; i++) {
     if (type[i] == atype) {
       aq = q[i]; 
       break;
     }
   }
   double pcharge;
   MPI_Allreduce(&aq,&pcharge,1,MPI_DOUBLE,MPI_MAX,world());
   double ncharge;
   MPI_Allreduce(&aq,&ncharge,1,MPI_DOUBLE,MPI_MIN,world());
   double charge = (pcharge == 0.0) ? ncharge : pcharge;
   return charge;
 }
 
 //const double ** LammpsInterface::xatom() const { return (const double**)(lammps_->atom->x); }
 
 double ** LammpsInterface::vatom() const { return lammps_->atom->v; }
 
 double ** LammpsInterface::fatom() const { return lammps_->atom->f; }
 
 const int * LammpsInterface::atom_mask() const { return (const int*)lammps_->atom->mask; }
 
 int * LammpsInterface::atom_mask() { return lammps_->atom->mask; }
 
 int * LammpsInterface::atom_type() const { return lammps_->atom->type; }
 
 int * LammpsInterface::atom_tag() const { return lammps_->atom->tag; }
 
 int * LammpsInterface::atom_to_molecule() const { return lammps_->atom->molecule; }
 
 
 int * LammpsInterface::num_bond() const { return lammps_->atom->num_bond; }
 
 int ** LammpsInterface::bond_atom() const { return lammps_->atom->bond_atom; }
 
 int * LammpsInterface::image() const { return lammps_->atom->image; }
 
 int LammpsInterface::bond_per_atom() const { return lammps_->atom->bond_per_atom; }
 
 int LammpsInterface::newton_bond() const { return lammps_->force->newton_bond; }
 
 int LammpsInterface::local_to_global_map(int global) const { return lammps_->atom->map(global); }
 
 double * LammpsInterface::atom_mass() const { return lammps_->atom->mass; }
 
 double   LammpsInterface::atom_mass(int iType) const { return lammps_->atom->mass[iType]; }
 
 double * LammpsInterface::atom_rmass() const { return lammps_->atom->rmass; }
 
 double * LammpsInterface::atom_charge() const { return lammps_->atom->q; }
 
 double * LammpsInterface::atom_scalar(FundamentalAtomQuantity quantityType) const
 {
   if (quantityType==ATOM_MASS) {
     if (atom_mass())
       throw ATC_Error("Atom mass array requested but not defined");
     return atom_rmass();
   }
   else if (quantityType==ATOM_CHARGE) {
     double * atomCharge = atom_charge();
     if (!atomCharge)
       throw ATC_Error("Atom charge array requested but not defined");
     return atomCharge;
   }
   else
     throw ATC_Error("BAD type requested in atom_scalar");
   return NULL;
 }
 
 double ** LammpsInterface::atom_vector(FundamentalAtomQuantity quantityType) const
 {
   if (quantityType==ATOM_POSITION)
     return xatom();
   else if (quantityType==ATOM_VELOCITY)
     return vatom();
   else if (quantityType==ATOM_FORCE)
     return fatom();
   else
     throw ATC_Error("BAD type requested in atom_vector");
   return NULL;
 }
 
 int LammpsInterface::atom_quantity_ndof(FundamentalAtomQuantity quantityType) const
 {
   if (quantityType==ATOM_MASS || quantityType==ATOM_CHARGE)
     return 1;
   else if (quantityType==ATOM_POSITION || quantityType==ATOM_VELOCITY || quantityType==ATOM_FORCE)
     return dimension();
   else
     throw ATC_Error("BAD type requested in atom_quantity_ndof");
 }
 
 double LammpsInterface::atom_quantity_conversion(FundamentalAtomQuantity quantityType) const
 {
   if (quantityType==ATOM_MASS || quantityType==ATOM_CHARGE || quantityType==ATOM_POSITION || quantityType==ATOM_VELOCITY)
     return 1;
   else if ( quantityType==ATOM_FORCE)
     return ftm2v();
   else
     throw ATC_Error("BAD type requested in atom_quantity_conversion");
 }
   
 // -----------------------------------------------------------------
 //  domain interface methods
 // -----------------------------------------------------------------
 
 int LammpsInterface::dimension() const { return lammps_->domain->dimension; }
 
 int LammpsInterface::nregion() const { return lammps_->domain->nregion; }
 
 void LammpsInterface::box_bounds(double & boxxlo, double & boxxhi,
                                  double & boxylo, double & boxyhi,
                                  double & boxzlo, double &boxzhi) const 
 {
   if (lammps_->domain->triclinic == 0) {
     boxxlo = lammps_->domain->boxlo[0];
     boxxhi = lammps_->domain->boxhi[0];
     boxylo = lammps_->domain->boxlo[1];
     boxyhi = lammps_->domain->boxhi[1];
     boxzlo = lammps_->domain->boxlo[2];
     boxzhi = lammps_->domain->boxhi[2];
   }
   else {
     boxxlo = lammps_->domain->boxlo_bound[0];
     boxxhi = lammps_->domain->boxhi_bound[0];
     boxylo = lammps_->domain->boxlo_bound[1];
     boxyhi = lammps_->domain->boxhi_bound[1];
     boxzlo = lammps_->domain->boxlo_bound[2];
     boxzhi = lammps_->domain->boxhi_bound[2];
   }
 }
 
 bool LammpsInterface::in_box(double * x) const
 {
   double xlo,xhi,ylo,yhi,zlo,zhi;
   box_bounds(xlo,xhi,ylo,yhi,zlo,zhi);
   if (x[0] >= xlo && x[0] < xhi &&
       x[1] >= ylo && x[1] < yhi &&
       x[2] >= zlo && x[2] < zhi) 
   return true;
   return false;
 }
 
 bool LammpsInterface::in_my_processor_box(double * x) const
 {
   if (x[0] >= lammps_->domain->sublo[0] && x[0] < lammps_->domain->subhi[0] &&
       x[1] >= lammps_->domain->sublo[1] && x[1] < lammps_->domain->subhi[1] &&
       x[2] >= lammps_->domain->sublo[2] && x[2] < lammps_->domain->subhi[2]) 
   return true;
   if (! in_box(x)) 
     throw ATC_Error("point is in no processors box");
   return false;
 }
 
 
 void LammpsInterface::sub_bounds(double & subxlo, double & subxhi,
                                  double & subylo, double & subyhi,
                                  double & subzlo, double & subzhi) const 
 {
   if (lammps_->domain->triclinic == 0) {
     subxlo = lammps_->domain->sublo[0];
     subxhi = lammps_->domain->subhi[0];
     subylo = lammps_->domain->sublo[1];
     subyhi = lammps_->domain->subhi[1];
     subzlo = lammps_->domain->sublo[2];
     subzhi = lammps_->domain->subhi[2];
   }
   else {
     ATC_Error("Subboxes not accurate when triclinic != 0.");
   }
 }
 
 int LammpsInterface::xperiodic() const { return lammps_->domain->xperiodic; }
 
 int LammpsInterface::yperiodic() const { return lammps_->domain->yperiodic; }
 
 int LammpsInterface::zperiodic() const { return lammps_->domain->zperiodic; }
 
 int LammpsInterface::nperiodic() const 
 { 
   int nprd = 0;
   if ( lammps_->domain->xperiodic > 0 ) { nprd++ ; }
   if ( lammps_->domain->yperiodic > 0 ) { nprd++ ; }
   if ( lammps_->domain->zperiodic > 0 ) { nprd++ ; }
   return nprd;
 }
 
 // correct posistions for periodic box
 void LammpsInterface::periodicity_correction(double * x) const 
 {
   int* periodicity = lammps_->domain->periodicity; 
   if (!refBoxIsSet_) set_reference_box(); 
   for (int m = 0; m < 3; m++) {
     if ((bool) periodicity[m]) {
       if (x[m] < lower_[m] || x[m] > upper_[m]) {
         x[m] -= length_[m]*floor((x[m]-lower_[m])/length_[m]);
       }
       if (x[m] < lower_[m] || x[m] > upper_[m]) {
         throw ATC_Error("periodicity_correction: still out of box bounds");
       }
     }
   }
 }
 
 void LammpsInterface::set_reference_box(void) const 
 {
   double * hi = lammps_->domain->boxhi;
   double * lo = lammps_->domain->boxlo;
   double * len = lammps_->domain->prd;
   for (int i = 0; i < 3; i++) {
     upper_[i] = hi[i]; 
     lower_[i] = lo[i]; 
     length_[i] = len[i]; 
   }
   refBoxIsSet_ = true;
 }
 
 
 double LammpsInterface::domain_xprd() const { return lammps_->domain->xprd; }
 
 double LammpsInterface::domain_yprd() const { return lammps_->domain->yprd; }
 
 double LammpsInterface::domain_zprd() const { return lammps_->domain->zprd; }
 
 double LammpsInterface::domain_volume() const 
 {
   return (lammps_->domain->xprd)*
          (lammps_->domain->yprd)*
          (lammps_->domain->zprd);
 }
 
 double LammpsInterface::domain_xy() const { return lammps_->domain->xy; }
 
 double LammpsInterface::domain_xz() const { return lammps_->domain->xz; }
 
 double LammpsInterface::domain_yz() const { return lammps_->domain->yz; }
 
 int LammpsInterface::domain_triclinic() const { return lammps_->domain->triclinic; }
 
 void LammpsInterface::box_periodicity(int & xperiodic,
                                           int & yperiodic,
                                           int & zperiodic) const 
 {
   xperiodic = lammps_->domain->xperiodic;
   yperiodic = lammps_->domain->yperiodic;
   zperiodic = lammps_->domain->zperiodic;
 }
 
 int LammpsInterface::region_id(const char * regionName) const {
   int nregion = this->nregion();
   for (int iregion = 0; iregion < nregion; iregion++) {
     if (strcmp(regionName, region_name(iregion)) == 0) {
       return iregion;
     }
   }
   throw ATC_Error("Region has not been defined");
   return -1;
 }
 
 bool LammpsInterface::region_bounds(const char * regionName,
   double & xmin, double & xmax,
   double & ymin, double & ymax,
   double & zmin, double & zmax,
   double & xscale, double & yscale, double & zscale) const
 {
   int iRegion = region_id(regionName);
   xscale = region_xscale(iRegion);
   yscale = region_yscale(iRegion);
   zscale = region_zscale(iRegion);
   xmin = region_xlo(iRegion); 
   xmax = region_xhi(iRegion);
   ymin = region_ylo(iRegion); 
   ymax = region_yhi(iRegion);
   zmin = region_zlo(iRegion); 
   zmax = region_zhi(iRegion);
   if (strcmp(region_style(iRegion),"block")==0) { return true; }
   else                                          { return false; }
 }
 
 void LammpsInterface::minimum_image(double & dx, double & dy, double & dz) const {
   lammps_->domain->minimum_image(dx,dy,dz);
 }
 
 void LammpsInterface::closest_image(const double * const xi, const double * const xj, double * const xjImage) const {
   lammps_->domain->closest_image(xi,xj,xjImage);
 }
 
 
 // -----------------------------------------------------------------
 //  update interface methods
 // -----------------------------------------------------------------
 LammpsInterface::UnitsType LammpsInterface::units_style(void) const
 {
     if      (strcmp(lammps_->update->unit_style,"lj") == 0)    return LJ;
     else if (strcmp(lammps_->update->unit_style,"real") == 0)  return REAL;
     else if (strcmp(lammps_->update->unit_style,"metal") == 0) return METAL;
     else return UNKNOWN;
 }
 
 double LammpsInterface::convert_units(double value, UnitsType in, UnitsType out, int massExp, int lenExp, int timeExp, int engExp) const
 {
     double ps2fs = 1.e3;
     double eV2kcal = 23.069;
     if      (in==REAL) {
       if (out==METAL) {
         return value*pow(ps2fs,-timeExp)*pow(eV2kcal,-engExp);
       }
       else if (out==ATC) {
         if      (units_style()==REAL) {
           return value; 
         }
         else if (units_style()==METAL) {
           return convert_units(value, METAL, out, massExp, lenExp, timeExp)*1.0; 
         }
       }
       else throw ATC_Error("can't convert");
     }
     else if (in==METAL) {
       if (out==REAL) {
         return value*pow(ps2fs,timeExp)*pow(eV2kcal,engExp);
       }
       else if (out==ATC) {
         if      (units_style()==REAL) {
           return convert_units(value, REAL, out, massExp, lenExp, timeExp)*1.0; 
         }
         else if (units_style()==METAL) {
           return value; 
         }
       }
       else throw ATC_Error("can't convert");
     }
     else throw ATC_Error("can't convert");
     return value;
 }
 
 
 // -----------------------------------------------------------------
 //  lattice interface methods
 // -----------------------------------------------------------------
 
 double LammpsInterface::xlattice() const { return lammps_->domain->lattice->xlattice; }
 
 double LammpsInterface::ylattice() const { return lammps_->domain->lattice->ylattice; }
 
 double LammpsInterface::zlattice() const { return lammps_->domain->lattice->zlattice; }
 
 LammpsInterface::LatticeType LammpsInterface::lattice_style() const
 { 
   if (lammps_->domain->lattice) 
     return (LammpsInterface::LatticeType)lammps_->domain->lattice->style; 
   else
     throw ATC_Error("Lattice has not been defined");
 }
 
 //* retuns the number of basis vectors 
 int LammpsInterface::n_basis() const
 {
   return lammps_->domain->lattice->nbasis;
 }
 
 //* returns the basis vectors, transformed to the box coords
 void LammpsInterface::basis_vectors(double **basis) const
 {
   LAMMPS_NS::Lattice *lattice = lammps_->domain->lattice;
   int i,j;
   double origin[3] = {0.0, 0.0, 0.0};
   lattice->lattice2box(origin[0], origin[1], origin[2]);
   for (i=0; i<n_basis(); i++)
   {
     memcpy(basis[i],lattice->basis[i],3*sizeof(double));
     lattice->lattice2box(basis[i][0], basis[i][1], basis[i][2]);
     for (j=0; j<3; j++)  basis[i][j] -= origin[j];
   }
 }
 
 //* gets the (max) lattice constant
 double LammpsInterface::max_lattice_constant(void) const
 {
   double a1[3], a2[3], a3[3];
   unit_cell(a1,a2,a3);
   double a = norm(a1);
   a = max(a,norm(a2));
   a = max(a,norm(a3));
   return a;
 }
 
 //* computes a cutoff distance halfway between 1st and 2nd nearest neighbors
 double LammpsInterface::near_neighbor_cutoff(void) const
 {
   double cutoff;
   double alat = LammpsInterface::max_lattice_constant();
   LatticeType type = lattice_style();
   if (type == LammpsInterface::SC) {
     cutoff = 0.5*(1.0+sqrt(2.0))*alat; 
   } else if (type == LammpsInterface::BCC) {
     cutoff = 0.5*(0.5*sqrt(3.0)+1.0)*alat;
   } else if (type == LammpsInterface::FCC) {
     cutoff = 0.5*(1.0/sqrt(2.0)+1.0)*alat;
   } else if (type == LammpsInterface::HCP) {
     cutoff = 0.5*(1.0/sqrt(2.0)+1.0)*alat;
   } else if (type == LammpsInterface::DIAMOND) {
     cutoff = 0.5*(0.25*sqrt(3.0)+1.0/sqrt(2.0))*alat;
   } else if (type == LammpsInterface::SQ) {
     cutoff = 0.5*(1.0+sqrt(2.0))*alat; 
   } else if (type == LammpsInterface::SQ2) {
     cutoff = 0.5*(1.0/sqrt(2.0)+1.0)*alat; 
   } else if (type == LammpsInterface::HEX) {
     cutoff = 0.5*(1.0/sqrt(3.0)+1.0)*alat; 
   } else {
     throw ATC_Error("Unknown lattice type");
   }
   return cutoff;
 } 
 
 //* gets the unit cell vectors
 void LammpsInterface::unit_cell(double *a1, double *a2, double *a3) const
 {
   int i, j;
   double *a[3] = {a1,a2,a3};
   double origin[3] = {0.0,0.0,0.0};
   LAMMPS_NS::Lattice *lattice = lammps_->domain->lattice;
   // transform origin
   lattice->lattice2box(origin[0], origin[1], origin[2]);
  
   // copy reference lattice vectors
   memcpy(a[0], lattice->a1, 3*sizeof(double));
   memcpy(a[1], lattice->a2, 3*sizeof(double));
   memcpy(a[2], lattice->a3, 3*sizeof(double));
 
   for (i=0; i<3; i++)
   {
     lattice->lattice2box(a[i][0], a[i][1], a[i][2]);    
     for (j=0; j<3; j++)  a[i][j] -= origin[j];
   }
 }
 
 //* gets number of atoms in a unit cell
 int LammpsInterface::num_atoms_per_cell(void) const
 {
   int naCell = 0;
   LatticeType type = lattice_style();
   if      (type == LammpsInterface::SC)  naCell = 1;
   else if (type == LammpsInterface::BCC) naCell = 2;
   else if (type == LammpsInterface::FCC) naCell = 4;
   else if (type == LammpsInterface::DIAMOND) naCell = 8;
   else if (comm_rank()==0) {
     //{throw ATC_Error("lattice style not currently supported by ATC");}
     print_msg_once("WARNING:  Cannot get number of atoms per cell from lattice");
     naCell = 1; 
   }
   return naCell;
 }
 
 //* gets tributary volume for an atom
 double LammpsInterface::volume_per_atom(void) const
 {
   double naCell = num_atoms_per_cell();
   double volPerAtom =  
     xlattice() * ylattice() * zlattice() / naCell;
   return volPerAtom;
 }
 
 //* gets lattice basis
 void LammpsInterface::lattice(MATRIX &N, MATRIX &B) const
 {
   int nbasis = n_basis();
   double **basis = new double*[nbasis];
   N.reset(3,3);
   B.reset(3,nbasis);
   for (int i=0; i<nbasis; i++)  basis[i] = column(B,i).ptr();
   basis_vectors(basis);
   unit_cell(column(N,0).ptr(),
                                 column(N,1).ptr(),
                                 column(N,2).ptr());
   delete [] basis;
 }
 
 // -----------------------------------------------------------------
 //  force interface methods
 // -----------------------------------------------------------------
 
 double LammpsInterface::boltz() const{ return lammps_->force->boltz;      }
 
 double LammpsInterface::mvv2e() const{ return lammps_->force->mvv2e;      }     
 
 double LammpsInterface::ftm2v()const { return lammps_->force->ftm2v;      }     
 
 double LammpsInterface::nktv2p()const{ return lammps_->force->nktv2p;     }    
 
 double LammpsInterface::qqr2e() const{ return lammps_->force->qqr2e;      }     
 
 double LammpsInterface::qe2f()  const{ return lammps_->force->qe2f;       }      
 double LammpsInterface::dielectric()const{return lammps_->force->dielectric; }
 
 double LammpsInterface::qqrd2e()const{ return lammps_->force->qqrd2e;     }
 
 double LammpsInterface::qv2e()  const{ return qe2f()*ftm2v();             }
 
 double LammpsInterface::pair_force(int i, int j, double rsq, 
   double & fmag_over_rmag) const     
 { 
   int itype = (lammps_->atom->type)[i];
   int jtype = (lammps_->atom->type)[j];
   // return value is the energy
   if (rsq < (lammps_->force->pair->cutsq)[itype][jtype]) {
     return lammps_->force->pair->single(i,j,itype,jtype,
     rsq,1.0,1.0,fmag_over_rmag);
   }
   return 0.0;
 }
 double LammpsInterface::pair_force(int n, double rsq, 
   double & fmag_over_rmag) const     
 { 
   int i = bond_list_i(n);
   int j = bond_list_j(n);
   int type = bond_list_type(n);
   // return value is the energy
   return lammps_->force->bond->single(type,rsq,i,j,fmag_over_rmag);
 }
 double LammpsInterface::pair_force(
                                    map< std::pair< int,int >,int >::const_iterator itr, double rsq, 
   double & fmag_over_rmag, int nbonds) const
 { 
   int n = itr->second;
   if (n < nbonds) {
     return pair_force(n, rsq,fmag_over_rmag);
   }
   else {
     std::pair <int,int>  ij = itr->first;
     int i = ij.first;
     int j = ij.second;
     return pair_force(i,j, rsq,fmag_over_rmag);
   }
 }
 double LammpsInterface::pair_force(
   std::pair< std::pair< int,int >,int > apair, double rsq, 
   double & fmag_over_rmag, int nbonds) const
 { 
   int n = apair.second;
   if (n < nbonds) {
     return pair_force(n, rsq,fmag_over_rmag);
   }
   else {
     std::pair <int,int>  ij = apair.first;
     int i = ij.first;
     int j = ij.second;
     return pair_force(i,j, rsq,fmag_over_rmag);
   }
 }
 double LammpsInterface::bond_stiffness(int i, int j, double rsq0) const
 { 
   const double perturbation = 1.e-8;
   double rsq1 = sqrt(rsq0)+perturbation;
   rsq1 *= rsq1;
   double f0,f1;
   pair_force(i,j,rsq0,f0);
   pair_force(i,j,rsq1,f1);
   double k =  (f1-f0)/perturbation;
   return k;
 }
 
 double LammpsInterface::pair_cutoff() const
 {
   return lammps_->force->pair->cutforce;
 }
 
 void LammpsInterface::pair_reinit() const
 {
   lammps_->force->pair->reinit();
 }
 
 int LammpsInterface::single_enable() const
 {
   return lammps_->force->pair->single_enable; // all bonds have a single
 }
 
 //* insertion/deletion functions : see FixGCMC
 //* delete atom
 int LammpsInterface::delete_atom(int id) const
 {
   LAMMPS_NS::Atom * atom  = lammps_->atom;
   atom->avec->copy(atom->nlocal-1,id,1);
   atom->nlocal--;
   return atom->nlocal;
 }
 
 //* insert atom
 int LammpsInterface::insert_atom(int atype, int amask, 
   double *ax, double *av, double aq) const
 {
   LAMMPS_NS::Atom * atom  = lammps_->atom;
   atom->avec->create_atom(atype,ax);
   int m = atom->nlocal - 1;
   atom->mask[m] = amask;
   atom->v[m][0] = av[0];
   atom->v[m][1] = av[1]; 
   atom->v[m][2] = av[2]; 
   if (aq != 0) atom->q[m] = aq;
 
   int nfix = lammps_->modify->nfix;
   LAMMPS_NS::Fix **fix = lammps_->modify->fix;
   for (int j = 0; j < nfix; j++) {
     if (fix[j]->create_attribute) fix[j]->set_arrays(m);
   }
   return m;
 }
 
 int LammpsInterface::reset_ghosts(int deln) const
 {
   LAMMPS_NS::Atom * atom  = lammps_->atom;
 //ATC::LammpsInterface::instance()->print_msg("reset_ghosts del n "+to_string(deln));
   if (atom->tag_enable) {
     atom->natoms += deln;
 //ATC::LammpsInterface::instance()->print_msg("reset_ghosts natoms "+to_string(atom->natoms));
     if (deln > 0) { atom->tag_extend(); }
     if (atom->map_style) atom->map_init();
   }
   atom->nghost = 0;
   lammps_->comm->borders();
 //ATC::LammpsInterface::instance()->print_msg("reset_ghosts nghosts "+to_string(atom->nghost));
   return atom->nghost;
 }
 
 //* energy for interactions within the shortrange cutoff
 double LammpsInterface::shortrange_energy(double *coord, 
   int itype, int id, double max) const
 {
   LAMMPS_NS::Atom * atom  = lammps_->atom;
   double **x = atom->x;
   int *type = atom->type;
   int nall = atom->nlocal+ atom->nghost;
   LAMMPS_NS::Pair *pair = lammps_->force->pair;
   double **cutsq =  lammps_->force->pair->cutsq;
 
   double fpair = 0.0; // an output of single
   double factor_coul = 1.0;
   double factor_lj = 1.0;
 
   double total_energy = 0.0;
   for (int j = 0; j < nall; j++) {
     if (id == j) continue; 
     // factor_lj = special_lj[sbmask(j)];
     // factor_coul = special_coul[sbmask(j)];
     //j &= NEIGHMASK;
     double delx = coord[0] - x[j][0];
     double dely = coord[1] - x[j][1];
     double delz = coord[2] - x[j][2];
     double rsq = delx*delx + dely*dely + delz*delz;
     int jtype = type[j];
     double cut2 = cutsq[itype][jtype];
     if (rsq < cut2) {
       total_energy += pair->single(id,j,itype,jtype,rsq,factor_coul,factor_lj,fpair); //id is for charge lookup
     }
   }
   return total_energy;
 }
 double LammpsInterface::shortrange_energy(int id, double max) const
 {
   double *x = (lammps_->atom->x)[id];
   int type  = (lammps_->atom->type)[id];
   return shortrange_energy(x,type,id,max);
 }
 
 POTENTIAL LammpsInterface::potential() const 
 {
   // find pair style - FRAGILE
   const int nStyles = 4;
   string pairStyles[nStyles] = {"lj/cut",
                           "lj/cut/coul/long",
                           "lj/cut/coul/cut",
                           "lj/charmm/coul/long"};
   LAMMPS_NS::Pair *pair = NULL;
   for (int i = 0; i < nStyles; i++){ 
     pair = lammps_->force->pair_match(pairStyles[i].c_str(),1);
     if (pair != NULL) break;
   }
   return pair;
 }
 
 int LammpsInterface::type_to_groupbit(int itype) const
 {
   LAMMPS_NS::Atom * atom  = lammps_->atom;
   int groupbit = -1;
   int *type = atom->type;
   int *mask = atom->mask;
   for (int i = 0; i < nlocal(); i++) {
     if (type[i] == itype) {
       groupbit = mask[i];
       break;
     }
   }
   return int_allmax(groupbit);
 }
 
 bool LammpsInterface::epsilons(int itype, POTENTIAL pair, double * epsilon0) const 
 {
   // grab energy parameters
   char * pair_parameter = new char[8];
   strcpy(pair_parameter,"epsilon");
   int dim = 2; // a return value for extract
   double ** epsilons = (double**) ( pair->extract(pair_parameter,dim) );
   delete [] pair_parameter;
   if (epsilons == NULL) return false;
   //if (epsilons == NULL) error->all(FLERR,"Fix concentration adapted pair style parameter not supported");
   int i1,i2;
   for (int i=1; i < ntypes()+1; i++) {
     if (i < itype) { i1 = i; i2 = itype; }
     else           { i2 = i; i1 = itype; }
     epsilon0[i-1] = epsilons[i1][i2];
   }
   return true;
 }
 
 bool LammpsInterface::set_epsilons(int itype, POTENTIAL pair, double * epsilon) const
 {
   // grab energy parameters
   char * pair_parameter = new char[8];
   strcpy(pair_parameter,"epsilon");
   int dim = 2; // a return value for extract
   double ** epsilons = (double**) ( pair->extract(pair_parameter,dim) );
   delete [] pair_parameter;
   if (epsilons == NULL) return false;
   //if (epsilons == NULL) error->all(FLERR,"Fix concentration adapted pair style parameter not supported");
   // scale interactions 
   int i1,i2;
   for (int i = 1; i < ntypes()+1; i++) {
     if (i < itype) { i1 = i; i2 = itype; }
     else           { i2 = i; i1 = itype; }
     epsilons[i1][i2] = epsilon[i-1];
   }
   
   return true;
 }
 
 int LammpsInterface::set_charge(int itype, double charge) const
 {
   int nlocal = lammps_->atom->nlocal;
   int *type = lammps_->atom->type;
   double *q = lammps_->atom->q;
   int count = 0;
   for (int i = 0; i < nlocal; i++) {
     if (type[i] == itype) {
       q[i] = charge;
       count++;
     }
   }
   return count;
 }
 
 int LammpsInterface::change_type(int itype, int jtype) const
 {
   int nlocal = lammps_->atom->nlocal;
   int *type = lammps_->atom->type;
   int count = 0;
   for (int i = 0; i < nlocal; i++) {
     if (type[i] == itype) {
       type[i] = jtype;
       count++;
     }
   }
   return count;
 }
 
 int LammpsInterface::count_type(int itype) const
 {
   int nlocal = lammps_->atom->nlocal;
   int *type = lammps_->atom->type;
   int count = 0;
   for (int i = 0; i < nlocal; i++) {
     if (type[i] == itype) { count++; }
   }
   return int_allsum(count);
 }
 
 // random number generators
 RNG_POINTER LammpsInterface::random_number_generator() const {
   RNG_POINTER p = new LAMMPS_NS::RanPark(lammps_,seed_);
   return p;
 }
 double LammpsInterface::random_uniform(RNG_POINTER p) const {
   return p->uniform();
 }
 double LammpsInterface::random_normal (RNG_POINTER p) const {
   return p->gaussian();
 }
 int LammpsInterface::random_state (RNG_POINTER p) const {
   return p->state();
 }
 void LammpsInterface::set_random_state (RNG_POINTER p, int seed) const {
   return p->reset(seed);
 }
 void LammpsInterface::advance_random_generator (RNG_POINTER p, int n) const {
   advance_random_uniform(p,n);
 }
 void LammpsInterface::advance_random_uniform (RNG_POINTER p, int n) const {
   for (int i = 0; i < n; i++)  p->uniform();
 }
 void LammpsInterface::advance_random_normal (RNG_POINTER p, int n) const {
   for (int i = 0; i < n; i++)  p->gaussian();
 }
 
 //* Boltzmann's constant in M,L,T,t units
 double LammpsInterface::kBoltzmann() const  { 
   return (lammps_->force->boltz)/(lammps_->force->mvv2e);
 }
 
 //* Planck's constant 
 double LammpsInterface::hbar() const  { 
   const int UNITS_STYLE = (int) units_style();
   double hbar = 1.0; // LJ: Dimensionless
   if      (UNITS_STYLE == 2) hbar = 15.1685792814; // Real: KCal/mol-fs
   else if (UNITS_STYLE == 3) hbar = 0.000658212202469; // Metal: eV-ps
   return hbar;
 }
 
 //* Dulong-Petit heat capacity
 double LammpsInterface::heat_capacity() const  { 
   double rhoCp = dimension()*kBoltzmann()/volume_per_atom();
   return rhoCp;
 }
 
 //* reference mass density for a *unit cell*
 // all that is needed is a unit cell: volume, types, mass per type
 double LammpsInterface::mass_density(int* numPerType) const  
 { 
   const double *mass         = lammps_->atom->mass;
   if (!mass) throw ATC_Error("cannot compute a mass density: no mass");
   const int    ntypes        = lammps_->atom->ntypes;
   const int    *mass_setflag = lammps_->atom->mass_setflag;
   const int    *type         = lammps_->atom->type;
   double naCell = num_atoms_per_cell();
   double vol = volume_per_atom();
   if (numPerType) {
     double m = 0.0;
     double n = 0;
     for (int i = 0; i < ntypes; i++) {
        m += numPerType[i]*mass[i+1];
        n += numPerType[i];
     }
     if (n>naCell) throw ATC_Error("cannot compute a mass density: too many basis atoms");
     return m/n/vol;
   }
   // since basis->type map not stored only monatomic lattices are automatic
   // if not given a basis try to guess
   else {
     if (ntypes == 1) {
       if ((this->natoms()==0) && mass_setflag[1]) {
         return mass[1]/vol;
       }
       else {
         if (type)                 return mass[type[0]]/vol;
         else if (mass_setflag[1]) return mass[1]/vol;
       }
     }
   }
   throw ATC_Error("cannot compute a mass density");
   return 0.0;
 }
 
 //* permittivity of free space
 double LammpsInterface::epsilon0() const
 {
   return qe2f()/(4.*PI*qqr2e());
 }
 
 //* Coulomb's constant
 double LammpsInterface::coulomb_constant() const
 {
   return qqr2e()/qe2f();
 }
 
 //* special coulombic interactions
 double * LammpsInterface::special_coul() const
 {
   return lammps_->force->special_coul;
 }
 
 //* flag for newton 
 int LammpsInterface::newton_pair() const
 {
   return lammps_->force->newton_pair;
 }
 
 // -----------------------------------------------------------------
 //  group interface methods
 // -----------------------------------------------------------------
 
 int LammpsInterface::ngroup() const { return lammps_->group->ngroup; }
 
 int LammpsInterface::group_bit(string name) const
 { 
   return group_bit(group_index(name));
 }
 
 int LammpsInterface::group_bit(int iGroup) const
 { 
   int mybit = 0;
   mybit |= lammps_->group->bitmask[iGroup];
   if (mybit < 0 || mybit > MAX_GROUP_BIT) {
     string msg("LammpsInterface::group_bit() lammps group bit "+to_string(mybit)+" is out of range 0:"+to_string(MAX_GROUP_BIT));
     throw ATC_Error(msg);
   }
   
   return mybit;
 }
 
 int LammpsInterface::group_index(string name) const
 { 
   int igroup = lammps_->group->find(name.c_str());          
   if (igroup == -1) {
     string msg("LammpsInterface::group_index() lammps group "+name+" does not exist");
     throw ATC_Error(msg);
   }
   return igroup;
 }
 
 int LammpsInterface::group_inverse_mask(int iGroup) const
 {
   return lammps_->group->inversemask[iGroup]; 
 }
 
 char * LammpsInterface::group_name(int iGroup) const
 { 
   return lammps_->group->names[iGroup]; 
 }
 
 void LammpsInterface::group_bounds(int iGroup, double * b) const
 {
   lammps_->group->bounds(iGroup, b);
 }
 
 // -----------------------------------------------------------------
 //  memory interface methods
 // -----------------------------------------------------------------
 
 
 double * LammpsInterface::create_1d_double_array(int length, const char *name) const {
   double * myArray;
   return lammps_->memory->create(myArray, length, name);
 }
 
 double *LammpsInterface::grow_1d_double_array(double *array, 
                                               int length,
                                               const char *name) const 
 {
   return lammps_->memory->grow(array, length, name);
 }
 
 void LammpsInterface::destroy_1d_double_array(double * d) const {
   lammps_->memory->destroy(d);
 }
 
 double ** LammpsInterface::create_2d_double_array(int n1, int n2, const char *name) const {
   double ** myArray;
   return lammps_->memory->create(myArray, n1, n2, name);
 }
 
 void LammpsInterface::destroy_2d_double_array(double **d) const {
   lammps_->memory->destroy(d);
 }
 
 double **LammpsInterface::grow_2d_double_array(double **array, 
                                                int n1, 
                                                int n2, 
                                                const char *name) const 
 {
   return lammps_->memory->grow(array, n1, n2, name);
 }
 
 
 int * LammpsInterface::create_1d_int_array(int length, const char *name) const {
   int * myArray;
   return lammps_->memory->create(myArray, length, name);
 }
 
 int *LammpsInterface::grow_1d_int_array(int *array, 
                                         int length,
                                         const char *name) const 
 {
   return lammps_->memory->grow(array, length, name);
 }
 
 void LammpsInterface::destroy_1d_int_array(int * d) const {
   lammps_->memory->destroy(d);
 }
 
 int ** LammpsInterface::create_2d_int_array(int n1, int n2, const char *name) const {
   int ** myArray;
   return lammps_->memory->create(myArray, n1, n2, name);
 }
 
 void LammpsInterface::destroy_2d_int_array(int **i) const {
   lammps_->memory->destroy(i);
 }
 
 int ** LammpsInterface::grow_2d_int_array(int **array, int n1, int n2, const char *name) const {
   return lammps_->memory->grow(array, n1, n2, name);
 }
 
 // -----------------------------------------------------------------
 //  update interface methods
 // -----------------------------------------------------------------
 
 double LammpsInterface::dt() const        { return lammps_->update->dt; }
 
 bigint LammpsInterface::ntimestep() const { return lammps_->update->ntimestep; }
 
 int LammpsInterface::nsteps() const    { return lammps_->update->nsteps; }
 
 
 // -----------------------------------------------------------------
 //  neighbor list interface methods
 // -----------------------------------------------------------------
 
 int LammpsInterface::sbmask(int j) const {return j >> SBBITS & 3; }
 
 void LammpsInterface::set_list(int id, LAMMPS_NS::NeighList *ptr) { list_ = ptr; }
 
 int   LammpsInterface::neighbor_list_inum() const { return list_->inum; }
 
 int * LammpsInterface::neighbor_list_numneigh() const { return list_->numneigh; }
 
 int * LammpsInterface::neighbor_list_ilist() const { return list_->ilist; }
 
 int ** LammpsInterface::neighbor_list_firstneigh() const { return list_->firstneigh; }
 
 int   LammpsInterface::neighbor_ago() const { return lammps_->neighbor->ago; }
 
 int   LammpsInterface::reneighbor_frequency() const {return lammps_->neighbor->every; }
 
 // -----------------------------------------------------------------
 //  bond list interface methods
 // -----------------------------------------------------------------
 
 int   LammpsInterface::bond_list_length() const { return lammps_->neighbor->nbondlist; }
 int**   LammpsInterface::bond_list() const { return lammps_->neighbor->bondlist; }
 
 // -----------------------------------------------------------------
 //  region interface methods
 // -----------------------------------------------------------------
 
 char * LammpsInterface::region_name(int iRegion)  const
 {
   return lammps_->domain->regions[iRegion]->id; 
 }
 
 char * LammpsInterface::region_style(int iRegion) const
 { 
   return lammps_->domain->regions[iRegion]->style; 
 }
 
 double LammpsInterface::region_xlo(int iRegion) const
 {
   return lammps_->domain->regions[iRegion]->extent_xlo; 
 }
 
 double LammpsInterface::region_xhi(int iRegion) const
 {
   return lammps_->domain->regions[iRegion]->extent_xhi; 
 }
 
 double LammpsInterface::region_ylo(int iRegion) const
 {
   return lammps_->domain->regions[iRegion]->extent_ylo;
 }
 
 double LammpsInterface::region_yhi(int iRegion) const
 {
   return lammps_->domain->regions[iRegion]->extent_yhi;
 }
 
 double LammpsInterface::region_zlo(int iRegion) const
 {
   return lammps_->domain->regions[iRegion]->extent_zlo;
 }
 
 double LammpsInterface::region_zhi(int iRegion) const
 {
   return lammps_->domain->regions[iRegion]->extent_zhi;
 }
 
 double LammpsInterface::region_xscale(int iRegion) const
 {
   return lammps_->domain->regions[iRegion]->xscale; 
 }
 
 double LammpsInterface::region_yscale(int iRegion)  const
 {
   return lammps_->domain->regions[iRegion]->yscale;
 }
 
 double LammpsInterface::region_zscale(int iRegion)  const
 {
   return lammps_->domain->regions[iRegion]->zscale; 
 }
 
 int LammpsInterface::region_match(int iRegion, double x, double y, double z) const { 
   return lammps_->domain->regions[iRegion]->match(x,y,z);
 }
 
 // -----------------------------------------------------------------
 //  compute methods
 // -----------------------------------------------------------------
 COMPUTE_POINTER LammpsInterface::compute_pointer(string tag) const
 {
   // get the compute id
   char * name = const_cast <char*> (tag.c_str());
   int id = lammps_->modify->find_compute(name);
   if (id < 0) {
     string msg("Could not find compute "+tag);
     msg += tag;
     throw ATC_Error(msg);
   }
   // get the compute
   LAMMPS_NS::Compute* cmpt = lammps_->modify->compute[id];
   // insert it into our set, recall it won't be added if it already exists
   computePointers_.insert(cmpt);
   return cmpt;
 }
 
 void LammpsInterface::computes_addstep(int step) const
 {
   set<LAMMPS_NS::Compute * >::iterator iter;
   for (iter = computePointers_.begin(); iter != computePointers_.end(); iter++) {
     (*iter)->addstep(step);
   }
 }
 
 void LammpsInterface::compute_addstep(COMPUTE_POINTER computePointer, int step) const
 {
   LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
   cmpt->addstep(step);
 }
 
 int LammpsInterface::compute_matchstep(COMPUTE_POINTER computePointer, int step) const
 {
   LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
   return cmpt->matchstep(step);
 }
 
 void LammpsInterface::reset_invoked_flag(COMPUTE_POINTER computePointer) const
 {
   LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
   cmpt->invoked_flag = 0;
 }
 
 int LammpsInterface::compute_ncols_peratom(COMPUTE_POINTER computePointer) const
 {
   LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
   int ndof = cmpt->size_peratom_cols;
   if (ndof == 0 ) ndof = 1; 
   return ndof;
 }
 
 double*  LammpsInterface::compute_vector_peratom(COMPUTE_POINTER computePointer) const
 {
   LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
   if (!(cmpt->invoked_flag & INVOKED_PERATOM)) { 
     cmpt->compute_peratom();
     cmpt->invoked_flag |= INVOKED_PERATOM;
   }
   return cmpt->vector_atom;
 }
 
 double**  LammpsInterface::compute_array_peratom(COMPUTE_POINTER computePointer) const
 {
   LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
   if (!(cmpt->invoked_flag & INVOKED_PERATOM)) {
     cmpt->compute_peratom();
     cmpt->invoked_flag |= INVOKED_PERATOM;
   }
   return cmpt->array_atom;
 }
 
 LAMMPS_NS::Compute * LammpsInterface::const_to_active(COMPUTE_POINTER computePointer) const
 {
   LAMMPS_NS::Compute* cmpt = const_cast<LAMMPS_NS::Compute* >(computePointer);
   set<LAMMPS_NS::Compute * >::iterator cmptPtr;
   cmptPtr = computePointers_.find(cmpt);
   if (cmptPtr != computePointers_.end())
     return *cmptPtr;
   else
     throw ATC_Error("Requested bad computer pointer");
 }
 
 // -----------------------------------------------------------------
 //  compute pe/atom interface methods 
 //  - the only compute "owned" by ATC
 // -----------------------------------------------------------------
 int  LammpsInterface::create_compute_pe_peratom(void)  const
 {
   char **list = new char*[4];
   string atomPeName = compute_pe_name();
   list[0] = (char *) atomPeName.c_str();
   list[1] = (char *) "all"; 
   list[2] = (char *) "pe/atom";
   list[3] = (char *) "pair";
 
   int icompute = lammps_->modify->find_compute(list[0]);
   if (icompute < 0) {
     lammps_->modify->add_compute(4,list);
     icompute = lammps_->modify->find_compute(list[0]);
   }
   delete [] list;
   if (! atomPE_ ) {
     atomPE_ = lammps_->modify->compute[icompute];
   }
   computePointers_.insert(atomPE_);
   stringstream ss;
   ss << "peratom PE compute created with ID: " << icompute;
   ATC::LammpsInterface::instance()->print_msg_once(ss.str());
   return icompute;
 }
 
 double * LammpsInterface::compute_pe_peratom(void) const
 {
   if (atomPE_) {
     atomPE_->compute_peratom();
     return atomPE_->vector_atom;
   }
   else {
     return NULL;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void LammpsInterface::unwrap_coordinates(int iatom, double* xatom) const
 {
   double **x = lammps_->atom->x;
   int *image = lammps_->atom->image;
 
   double *h   = lammps_->domain->h;
   double xprd = lammps_->domain->xprd;
   double yprd = lammps_->domain->yprd;
   double zprd = lammps_->domain->zprd;
   int xbox,ybox,zbox;
 
   // for triclinic, need to unwrap current atom coord via h matrix
   
   if (lammps_->domain->triclinic == 0) {
     xbox = (image[iatom] & 1023) - 512;
     ybox = (image[iatom] >> 10 & 1023) - 512;
     zbox = (image[iatom] >> 20) - 512;
     xatom[0] = x[iatom][0] + xbox*xprd;
     xatom[1] = x[iatom][1] + ybox*yprd;
     xatom[2] = x[iatom][2] + zbox*zprd;
   } else {
     xbox = (image[iatom] & 1023) - 512;
     ybox = (image[iatom] >> 10 & 1023) - 512;
     zbox = (image[iatom] >> 20) - 512;
     xatom[0] = x[iatom][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox;
     xatom[1] = x[iatom][1] + h[1]*ybox + h[3]*zbox;
     xatom[2] = x[iatom][2] + h[2]*zbox;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 LAMMPS_NS::PairEAM* LammpsInterface::pair_eam() const
 {
   //if (typeid(lammps_->force->pair) == typeid(LAMMPS_NS::PairEAM)) {
   //  return lammps_->force->pair;
   //}
   LAMMPS_NS::PairEAM* pair_eam = dynamic_cast<LAMMPS_NS::PairEAM*> (lammps_->force->pair);
   if (pair_eam != NULL) {
     return pair_eam;
   }
   else {
     throw ATC_Error("LAMMPS Pair object is not of the derived class type PairEAM");
   }
 }
 
 // -----------------------------------------------------------------
 //  other methods
 // -----------------------------------------------------------------
 
 /** Return lammps pointer -- only as a last resort! */
 LAMMPS_NS::LAMMPS * LammpsInterface::lammps_pointer() const { return lammps_; }
 
 }
diff --git a/lib/atc/LammpsInterface.h b/lib/atc/LammpsInterface.h
index e306a37aa..238e6cff3 100644
--- a/lib/atc/LammpsInterface.h
+++ b/lib/atc/LammpsInterface.h
@@ -1,711 +1,735 @@
 #ifndef LAMMPS_INTERFACE_H
 #define LAMMPS_INTERFACE_H
 
 #include <iostream>
 #include <stdlib.h>
 #include <map>
 #include <iostream>
 #include <string>
 #include <sstream>
+#include <fstream>
 #include <utility>
 #include "mpi.h"
 #include "lammps.h"
+#include "comm.h"
 #include "modify.h"
 #include "memory.h"
 #include "random_park.h"
 typedef LAMMPS_NS::RanPark* RNG_POINTER;
 #include "lmptype.h"
 #include "compute.h"
 typedef const LAMMPS_NS::Compute* COMPUTE_POINTER;
 #include "update.h"
 #include "min.h"
 #include "ATC_Error.h"
 #include "ATC_TypeDefs.h"
 #include "MatrixDef.h"
 #include "MPI_Wrappers.h"
 
 typedef LAMMPS_NS::Pair* POTENTIAL;
 
 // Forward class declarations for LAMMPS_NS namespace
 namespace LAMMPS_NS {
   class LAMMPS;
   class NeighList;
   class Compute;
   class ComputePEAtom;
   class ComputeStressAtom;
   class ComputeCentroAtom;
   class ComputeCNAAtom;
   class ComputeCoordAtom;
   class ComputeKEAtom;
   class Pair;
   class PairEAM;
   class Fix;
   class RanPark;
 }
 
 namespace ATC {
 
 static const std::string atomPeNameBase_ = "atcPE";
 static const double big_ = 1.e20;
 
 /**
  *  @class LammpsInterface
  *  @brief Singleton class that handles all interfacing with the lammps code
  */
 
 class LammpsInterface {
 
  public:
 
   // Enumeration of fundamental per-atom quantities, i.e. those defined directly by Lammps
   enum FundamentalAtomQuantity {
     ATOM_MASS = 0,
     ATOM_CHARGE,
     ATOM_POSITION,
     ATOM_VELOCITY,
     ATOM_FORCE,
     NUM_FUNDAMENTAL_ATOM_QUANTITIES
   };
 
   // Enumeration for lattice type. this MUST match the enum in src/lattice.cpp
   enum LatticeType {
     NONE=0,
     SC,
     BCC,
     FCC,
     HCP,
     DIAMOND,
     SQ,
     SQ2,
     HEX,
     CUSTOM
   };
 
   // Enumeration for units type. this is internal to ATC
   enum UnitsType {
     UNKNOWN=0,
     ATC,
     LJ,
     REAL,
     METAL,
     SI
   };
 
+  // Enumeration for atom data style
+  enum AtomStyle {
+    UNKNOWN_STYLE=0,
+    ATOMIC_STYLE,
+    CHARGE_STYLE,
+    FULL_STYLE
+  };
+
   // Provides a struct for easily passing/recovering data about SparseMats
   struct SparseMatInfo { 
     INDEX rows;
     INDEX cols;
     INDEX rowsCRS;
     INDEX size;
   };
 
   /** Static instance of this class */
   static LammpsInterface * instance();
 
   /** Destroy */
   static void Destroy();
 
   /** Set lammps pointer */
   void set_lammps(LAMMPS_NS::LAMMPS * lammps) 
   { 
     lammps_ = lammps; 
     MPI_Comm_rank(lammps_->world, & commRank_);
     MPI_Comm_size(lammps_->world, & commSize_);
   }
 
   /** \name Methods that interface with lammps base class */
   /*@{*/
 // begin MPI --------------------------------------------------------------------
   MPI_Comm world() const;
 
   void broadcast(double * buf, int count = 1) const
   {
     MPI_Wrappers::broadcast(lammps_->world, buf, count);
   }
 
   void int_broadcast(int * buf, int count = 1) const
   {
     MPI_Wrappers::int_broadcast(lammps_->world, buf, count);
   }
   // send_buf is frequently a void* so MPI_IN_PLACE can be passed in
   void allsum(void * send_buf, double * rec_buf, int count = 1) const
   {
     MPI_Wrappers::allsum(lammps_->world, send_buf, rec_buf, count);
   }
 
   void int_allsum(void * send_buf, int * rec_buf, int count = 1) const
   {
     MPI_Wrappers::int_allsum(lammps_->world, send_buf, rec_buf, count);
   }
   int int_allsum(int & i) const
   {
     int j = 0;
     MPI_Wrappers::int_allsum(lammps_->world, &i, &j, 1);
     return j;
   }
   int int_scansum(int & i) const
   {
     int j = 0;
     MPI_Wrappers::int_scansum(lammps_->world, &i, &j, 1);
     return j;
   }
   int int_allmax(int & i) const
   {
     int j = 0;
     MPI_Wrappers::int_allmax(lammps_->world, &i, &j, 1);
     return j;
   }
   int int_allmin(int & i) const
   {
     int j = 0;
     MPI_Wrappers::int_allmin(lammps_->world, &i, &j, 1);
     return j;
   }
   double allmin(double & i) const
   {
     double j = 0;
     MPI_Wrappers::allmin(lammps_->world, &i, &j, 1);
     return j;
   }
   void sparse_allsum(SparseMatrix<double> &toShare) const
 #ifdef ISOLATE_FE
   {
     MPI_Wrappers::sparse_allsum(lammps_->world, toShare); 
   }
 #else
 ;
 #endif
   void allmax(double * send_buf, double * rec_buf, int count = 1)
   {
     MPI_Wrappers::allmax(lammps_->world, send_buf, rec_buf, count);
   }
   void int_allmax(int * send_buf, int * rec_buf, int count = 1) const
   {
     MPI_Wrappers::int_allmax(lammps_->world, send_buf, rec_buf, count);
   }
   void allmin(double * send_buf, double * rec_buf, int count = 1) const
   {
     MPI_Wrappers::allmin(lammps_->world, send_buf, rec_buf, count);
   }
   void int_allmin(int * send_buf, int * rec_buf, int count = 1) const
   {
     MPI_Wrappers::int_allmin(lammps_->world, send_buf, rec_buf, count);
   }
   int rank_min(double * send_buf, double * rec_buf, int count = 1) const
   {
     return MPI_Wrappers::rank_min(lammps_->world, send_buf, rec_buf, count);
   }
   void int_recv(int * recv_buf, int max_size, int iproc) const
   {
     MPI_Wrappers::int_recv(lammps_->world, recv_buf, max_size, iproc);
   }
   void recv(double * recv_buf, int max_size, int iproc) const
   {
     MPI_Wrappers::recv(lammps_->world, recv_buf, max_size, iproc);
   }
   void int_send(int * send_buf, int send_size) const
   {
     MPI_Wrappers::int_send(lammps_->world, send_buf, send_size);
   }
   void send(double * send_buf, int send_size) const
   {
     MPI_Wrappers::send(lammps_->world, send_buf, send_size);
   }
   void allgatherv(double * send_buf, int send_count,
-               double * rec_buf, int * rec_counts, int * displacements) const
+                  double * rec_buf, int * rec_counts, int * displacements) const
   {
     MPI_Wrappers::allgatherv(lammps_->world, send_buf, send_count, rec_buf,
                              rec_counts, displacements);
   }
+  void int_allgather(int send, int* recv)
+  {
+    MPI_Wrappers::int_allgather(lammps_->world,send,recv);
+  }
   void int_scatter(int * send_buf, int * rec_buf, int count = 1)
   {
     MPI_Wrappers::int_scatter(lammps_->world, send_buf, rec_buf, count);
   }
   void logical_or(void * send_buf, int * rec_buf, int count = 1) const
   {
     MPI_Wrappers::logical_or(lammps_->world, send_buf, rec_buf, count);
   }
   void barrier(void) const
   {
     MPI_Wrappers::barrier(lammps_->world);
   }
   void stop(std::string msg="") const
   {
     MPI_Wrappers::stop(lammps_->world, msg);
   }
+  std::string read_file(std::string filename) const;
+  void write_file(std::string filename, std::string contents, 
+     std::ofstream::openmode mode = std::ofstream::out) const {
+     if (! comm_rank()) {
+       std::ofstream f(filename.c_str(),mode);
+       f << contents;
+       f.close();
+     } 
+     // ignore other ranks and assume they are consistent
+  }
 // end MPI --------------------------------------------------------------------
 
   void print_debug(std::string msg="") const
   {
     std::cout << "rank " << comm_rank() << " " << msg << "\n" << std::flush; 
     barrier();
   }
 
   int comm_rank(void) const { return commRank_;}
   int comm_size(void) const { return commSize_;}
   bool rank_zero(void) const { return (commRank_==0);}
   bool serial(void) const { 
     int size = 1; MPI_Comm_size(lammps_->world,&size);
     return (size==1);
   }
 
   void print_msg(std::string msg) const
   {
     int me;
     MPI_Comm_rank(lammps_->world,&me);
     std::stringstream full_msg;
     if (serial()) {
       full_msg << " ATC: " << msg << "\n";
     } 
     else {
       full_msg << " ATC: P" << me << ", " << msg << "\n";
     }
     std::string mesg = full_msg.str();
     
     if (lammps_->screen)  fprintf(lammps_->screen, "%s",mesg.c_str());
     if (lammps_->logfile) fprintf(lammps_->logfile,"%s",mesg.c_str());
   }
 
   void print_msg_once(std::string msg,bool prefix=true, bool endline=true) const
   {
     int me;
     MPI_Comm_rank(lammps_->world,&me);
     if (me==0) {
       std::stringstream full_msg;
       if (prefix) full_msg << " ATC: ";
       full_msg << msg;
       if (endline) full_msg << "\n";
       std::string mesg = full_msg.str();
       if (lammps_->screen)  fprintf(lammps_->screen, "%s",mesg.c_str());
       if (lammps_->logfile) fprintf(lammps_->logfile,"%s",mesg.c_str());
     }
   }
 
   void all_print(double data, std::string tag ="") const
   {
     int me;
     MPI_Comm_rank(lammps_->world,&me);
     std::stringstream full_msg;
     if (serial()) {
       full_msg << " ATC: " << tag << data << "\n";
     } 
     else {
       int commSize = comm_size();
       double recv[commSize];
       MPI_Wrappers::gather(lammps_->world,data,recv);
       if (rank_zero()) {
         full_msg << " ATC:" << tag;
         for (int i = 0; i < commSize; i++) {
           full_msg << " P" << i << ": " << recv[i] ;
         }
         full_msg << "\n";
       }
     }
     if (rank_zero()) {
       std::string mesg = full_msg.str();
       if (lammps_->screen)  fprintf(lammps_->screen, "%s",mesg.c_str());
       if (lammps_->logfile) fprintf(lammps_->logfile,"%s",mesg.c_str());
     }
   }
 
   void stream_msg_once(std::string msg,bool prefix=true, bool endline=true) const
   {
     int me;
     MPI_Comm_rank(lammps_->world,&me);
     if (me==0) {
       if (prefix) std::cout << " ATC: ";
       std::cout << msg;
       if (endline) std::cout << "\n";
       std::cout << std::flush;
     }
   }
 
 
   void forward_comm_fix() const;
   void comm_borders() const;
   /*@}*/
 
   /** \name Methods that interface with Atom class */
   /*@{*/
   void set_fix_pointer(LAMMPS_NS::Fix * thisFix);
   std::string fix_id() const;
   bool atoms_sorted() const;
   LAMMPS_NS::bigint natoms() const;
   int nlocal() const;
   int nghost() const;
   int nmax() const;
   int ntypes() const;
   double ** xatom() const; 
   double ** vatom() const; 
   double ** fatom() const; 
   const int * atom_mask() const; 
   int * atom_mask();
   int * atom_type() const; 
   int * atom_tag() const; 
   int * atom_to_molecule() const;
   int * num_bond() const;
   int ** bond_atom() const;
   int * image() const;
   int bond_per_atom() const;
   int newton_bond() const;
   int local_to_global_map(int global) const;
   int type_to_charge(int t) const;
   //* Returns a pointer to the atom masses (NOT SAFE).
   double * atom_mass() const;
   //* Indexes an atomic mass by atom type (NO BOUNDS CHECK).
   double   atom_mass(int iType) const;
   double * atom_rmass() const;
   double * atom_charge() const;
   double *  atom_scalar(FundamentalAtomQuantity quantityType) const;
   double ** atom_vector(FundamentalAtomQuantity quantityType) const;
   int       atom_quantity_ndof(FundamentalAtomQuantity quantityType) const;
   double    atom_quantity_conversion(FundamentalAtomQuantity quantityType) const;
   void unwrap_coordinates(int iatom, double* xatom) const;
   /*@}*/
 
   /** \name Methods that interface with Domain class */
   /*@{*/
   int dimension() const;
   int nregion() const;
   void box_bounds(double & boxxlo, double & boxxhi,
                       double & boxylo, double & boxyhi,
                       double & boxzlo, double & boxzhi) const;
   bool in_box(double * x) const;
   bool in_my_processor_box(double * x) const;
   void sub_bounds(double & subxlo, double & subxhi,
                       double & subylo, double & subyhi,
                       double & subzlo, double & subzhi) const;
   int xperiodic() const;
   int yperiodic() const;
   int zperiodic() const;
   int nperiodic() const;
   void box_periodicity(int & xperiodic,
                            int & yperiodic,
                            int & zperiodic) const;
   void periodicity_correction(double * x) const;
   void set_reference_box(void) const; // const since called by perd_corr
   int region_id(const char * regionName) const;
   double domain_xprd() const;
   double domain_yprd() const;
   double domain_zprd() const;
   double domain_volume() const;
   double domain_xy() const;
   double domain_xz() const;
   double domain_yz() const;
   int domain_triclinic() const;
   bool region_bounds(const char * regionName,
                            double &xmin, double &xmax,
                            double &ymin, double & ymax,
                            double &zmin, double &zmax,
                            double &xscale,
                            double &yscale,
                            double &zscale) const;
   bool region_bounds(const char * regionName,
                            double &xmin, double &xmax,
                            double &ymin, double & ymax,
                            double &zmin, double &zmax) const {
     double xs,ys,zs;
     bool ifBlock = region_bounds(regionName,
       xmin,xmax,ymin,ymax,zmin,zmax,xs,ys,zs);
     xmin *= xs;
     xmax *= xs;
     ymin *= ys;
     ymax *= ys;
     zmin *= zs;
     zmax *= zs;
     return ifBlock;
   }
   /*@}*/
   void minimum_image(double & dx, double & dy, double & dz) const;
   void closest_image(const double * const xi, const double * const xj, double * const xjImage) const; 
 
 
   /** \name Methods that interface with Update class */
   UnitsType units_style() const;
   double convert_units(double value, UnitsType in, UnitsType out, int massExp, int lenExp, int timeExp, int engExp=0) const;
   //double minimize_energy() { return lammps_->update->minimize->ecurrent; }
   double minimize_energy() const { return lammps_->update->minimize->eprevious; }
   /*@}*/
   
   /** \name Methods that interface with Lattice class */
   /*@{*/
   double xlattice() const;
   double ylattice() const;
   double zlattice() const;
   LatticeType lattice_style() const;
   int n_basis() const;
   void basis_vectors(double **basis) const;
   double max_lattice_constant(void) const;
   double near_neighbor_cutoff(void) const;
   void unit_cell(double *a1, double *a2, double *a3) const;
   /** these functions are more than just simple pass throughs */
   int  num_atoms_per_cell(void) const;
   double  volume_per_atom(void) const;
   void lattice(Matrix<double> &N, Matrix<double> &B) const;
   /*@}*/
 
   /** \name Methods that interface with Force class */
   /*@{*/
   double boltz() const;
   double mvv2e() const;
   double ftm2v() const;
   double nktv2p() const;
   double qqr2e() const;
   double qe2f() const;
   double dielectric() const;
   double qqrd2e() const;
   double qv2e() const; // converts charge * voltage --> mass length^2 / time^2
   /*@}*/
 
   /** \name Methods that interface with pair class */
   /*@{*/
   // interface to "single"
   double pair_force(int i, int j, double rsq, double& fmag_over_rmag) const; // pair class
   double pair_force(int n, double rsq, double& fmag_over_rmag) const; // bond class
   double pair_force(std::map< std::pair< int,int >,int >::const_iterator itr, double rsq, double& fmag_over_rmag, int nbonds = 0) const; 
   double pair_force(std::pair< std::pair< int,int >,int > apair, double rsq, double& fmag_over_rmag, int nbonds = 0) const; 
   double pair_cutoff() const;
   void pair_reinit() const;
   int single_enable() const;
   LAMMPS_NS::PairEAM * pair_eam(void) const; 
   double bond_stiffness(int i, int j, double rsq) const;
   /*@}*/
 
   /** \name Methods for addition/deletion of atoms*/
   /*@{*/
   int delete_atom(int id) const;
   int insert_atom(int type, int mask, double* x, double* v, double q = 0) const;
   double shortrange_energy(double *x, int type, int id = -1, 
     double max = big_) const;
   int reset_ghosts(int dn) const;
   double shortrange_energy(int id, double max = big_) const;
   POTENTIAL potential(void) const;
   int type_to_groupbit(int itype) const; 
   int      change_type(int itype, int jtype) const;
   int      count_type(int itype) const;
   bool     epsilons(int type, POTENTIAL p, double * epsilons) const;
   bool set_epsilons(int type, POTENTIAL p, double * epsilons) const;
   int  set_charge(int type, double charge) const;
   /*@}*/
 
   /** \name interface to random number generator */
   /*@{*/
   RNG_POINTER random_number_generator() const;
   double random_uniform(RNG_POINTER p) const;
   double random_normal (RNG_POINTER p) const;
   int random_state (RNG_POINTER p) const;
   void set_random_state (RNG_POINTER p, int seed) const;
   void advance_random_generator (RNG_POINTER p, int n = 1) const;
   void advance_random_uniform (RNG_POINTER p, int n = 1) const;
   void advance_random_normal  (RNG_POINTER p, int n = 1) const;
   /*@}*/
 
   /** these functions are more than just simple pass throughs */
   /*@{*/
   /** Boltzmann's constant in M,L,T,t units */
   double kBoltzmann(void) const;
   /** Planck's constant (energy-time units)  */
   double hbar(void) const;
   /** Dulong-Petit heat capacity per volume in M,L,T,t units */
   double heat_capacity(void) const;
   /** mass per volume in reference configuraturation in M,L units */
   double mass_density(int* numPerType=NULL) const;
   /**  permittivity of free space, converts from LAMMPS potential units implied by the electric field units to LAMMPS charge units/LAMMPS length units (e.g., V to elemental charge/A) */
   double epsilon0(void) const;
   double coulomb_constant(void) const;
   double * special_coul() const;
   int newton_pair() const;
   double coulomb_factor(int & j) const {
     int n = nlocal() + nghost();
     double * sc =  special_coul();
     double factor_coul = 1.;
     if (j >= n) {
       factor_coul = sc[j/n];
       j %= n;
     }
     return factor_coul;
   } 
   /*@}*/
 
   /** \name Methods that interface with Group class */
   /*@{*/
   int ngroup() const;
   int group_bit(std::string name) const;
   int group_bit(int iGroup) const;
   int group_index(std::string name) const;
   int group_inverse_mask(int iGroup) const;
   char * group_name(int iGroup) const;
   void group_bounds(int iGroup, double * b) const;
   /*@}*/
 
   /** \name Methods that interface with Memory class */
   /*@{*/
   double * create_1d_double_array(int length, const char *name) const;
   double * grow_1d_double_array(double *array, int length, const char *name) const;
   void destroy_1d_double_array(double * d) const;
   double ** create_2d_double_array(int n1, int n2, const char *name) const;
   void destroy_2d_double_array(double **d) const;
   double **grow_2d_double_array(double **array, int n1, int n2, const char *name) const;
   int * create_1d_int_array(int length, const char *name) const;
   int * grow_1d_int_array(int *array, int length, const char *name) const;
   void destroy_1d_int_array(int * d) const;
   int ** create_2d_int_array(int n1, int n2, const char *name) const;
   void destroy_2d_int_array(int **i) const;
   int ** grow_2d_int_array(int **array, int n1, int n2, const char *name) const;
   template <typename T>
     T * grow_array(T *&array, int n, const char *name) const {return lammps_->memory->grow(array,n,name);};
   template <typename T>
     void destroy_array(T * array) {lammps_->memory->destroy(array);};
   template <typename T>
     T ** grow_array(T **&array, int n1, int n2, const char *name) const {return lammps_->memory->grow(array,n1,n2,name);};
   template <typename T>
     void destroy_array(T ** array) const {lammps_->memory->destroy(array);};
   /*@}*/
 
   /** \name Methods that interface with Update class */
   /*@{*/
   double dt() const;
   LAMMPS_NS::bigint ntimestep() const;
   int    nsteps() const;
   bool now(LAMMPS_NS::bigint f) { return (ntimestep() % f == 0); }
   /*@}*/
 
   /** \name Methods that interface with neighbor list */
   /*@{*/
   void neighbor_remap(int & j) const { j &= NEIGHMASK; }
   int sbmask(int j) const;
   void set_list(int id, LAMMPS_NS::NeighList *ptr) ;
   int   neighbor_list_inum() const;
   int * neighbor_list_numneigh() const;
   int * neighbor_list_ilist() const;
   int ** neighbor_list_firstneigh() const;
   int   neighbor_ago() const;
   int reneighbor_frequency() const;
   LAMMPS_NS::NeighList * neighbor_list(void) const { return list_;}
   /*@}*/
 
   /** \name Methods that interface with bond list */
   /*@{*/
   int   bond_list_length() const;
   int ** bond_list() const; // direct access
   int * bond_list(int n) const { return bond_list()[n];} 
   int   bond_list_i(int n) const    { return bond_list(n)[0];} 
   int   bond_list_j(int n) const    { return bond_list(n)[1];}
   int   bond_list_type(int n) const { return bond_list(n)[2];}
   /*@}*/
 
   /** \name Methods that interface with Region class */
   /*@{*/
   char * region_name(int iRegion) const;
   char * region_style(int iRegion) const;
   double region_xlo(int iRegion) const;
   double region_xhi(int iRegion) const;
   double region_ylo(int iRegion) const;
   double region_yhi(int iRegion) const;
   double region_zlo(int iRegion) const;
   double region_zhi(int iRegion) const;
   double region_xscale(int iRegion) const;
   double region_yscale(int iRegion) const;
   double region_zscale(int iRegion) const;
   int region_match(int iRegion, double x, double y, double z) const;
   /*@}*/
 
   /** \name Methods that interface with compute class */
   enum COMPUTE_INVOKED 
    {INVOKED_SCALAR=1,INVOKED_VECTOR=2,INVOKED_ARRAY=4,INVOKED_PERATOM=8};
   enum PER_ATOM_COMPUTE 
    {PE_ATOM,
     STRESS_ATOM,
     CENTRO_ATOM,
     CNA_ATOM,
     COORD_ATOM,
     KE_ATOM,
     NUM_PER_ATOM_COMPUTES};
   // computes owned by LAMMPS
   COMPUTE_POINTER compute_pointer(std::string tag) const;
   int      compute_ncols_peratom(COMPUTE_POINTER computePointer) const;
   double*  compute_vector_peratom(COMPUTE_POINTER computePointer) const;
   double** compute_array_peratom(COMPUTE_POINTER computePointer) const;
 
   void     computes_addstep(int step) const;
   void     compute_addstep(COMPUTE_POINTER computePointer, int step) const;
   int     compute_matchstep(COMPUTE_POINTER computePointer, int step) const;
   void     reset_invoked_flag(COMPUTE_POINTER computePointer) const;
   // computes owned by ATC
   int      create_compute_pe_peratom(void) const;
   double * compute_pe_peratom(void) const;
   std::string compute_pe_name(void) const {return atomPeNameBase_;};//  +fix_id();}; enables unique names, if desired
   void     computes_clearstep(void) const {lammps_->modify->clearstep_compute();};
   /*@}*/
  
 
 
   /** Return lammps pointer -- only as a last resort! */
   LAMMPS_NS::LAMMPS * lammps_pointer() const;
 
  protected:
   /** transfer a const compute pointer to a non-const computer pointer */
   LAMMPS_NS::Compute * const_to_active(const LAMMPS_NS::Compute* computePointer) const;
 
   LAMMPS_NS::LAMMPS * lammps_;
 
   LAMMPS_NS::Fix * fixPointer_;
 
   /** access to neighbor list */
   mutable LAMMPS_NS::NeighList *list_;
 
   /** constructor */
   LammpsInterface();
 
   /** comm rank */
   int commRank_;
 
   /** number of processes */
   int commSize_;
 
   /** compute pe/atom */
   mutable LAMMPS_NS::Compute * atomPE_;
 
   /** box info */
   mutable bool refBoxIsSet_;
   mutable double upper_[3],lower_[3],length_[3];
 
   /** registry of computer pointers */
   mutable std::set<LAMMPS_NS::Compute * > computePointers_;
 
   /** a random number generator from lammps */
   mutable LAMMPS_NS::RanPark * random_;
   mutable LAMMPS_NS::RanPark * globalrandom_;
 
  private:
 
   static LammpsInterface * myInstance_;
 
 };
 
   class HeartBeat
   {
     public:
       HeartBeat(std::string name, int freq) :
         name_(name), freq_(freq), counter_(0) {};
       ~HeartBeat(){};
       void start() const
         { ATC::LammpsInterface::instance()->stream_msg_once(name_,true,false);}
       void next() const { if (counter_++ % freq_ == 0 )
           ATC::LammpsInterface::instance()->stream_msg_once(".",false,false);}
       void finish() const
         { ATC::LammpsInterface::instance()->stream_msg_once("done",false,true);}
     protected:
       std::string name_;
       int freq_;
       mutable int counter_;
     private:
       HeartBeat();
   };
 
 
 } // end namespace ATC
 
 
 
 #endif
diff --git a/lib/atc/LinearSolver.cpp b/lib/atc/LinearSolver.cpp
index c6e1e9cf7..ea31a64a7 100644
--- a/lib/atc/LinearSolver.cpp
+++ b/lib/atc/LinearSolver.cpp
@@ -1,563 +1,564 @@
 // Header file for this class
 #include "LinearSolver.h"
 #include <sstream>
 using std::stringstream;
 using std::set;
 
 
 
 
 
 
 
 namespace ATC {
 const double  kPenalty = 1.0e4; 
 const double  kTol     = 1.0e-8;
 const int kMaxDirect   = 1000;
 
 // ====================================================================
 //  LinearSolver
 // ====================================================================
 LinearSolver::LinearSolver(
     const SPAR_MAT & A,
     const BC_SET & bcs,
     const int solverType,
     const int constraintHandlerType,
     bool parallel
 )
   : solverType_(solverType),
     constraintHandlerType_(constraintHandlerType),
     nVariables_(0),
     initialized_(false),
     initializedMatrix_(false),
     initializedInverse_(false),
     matrixModified_(false),
     allowReinitialization_(false),
     homogeneousBCs_(false),
     bcs_(&bcs),
     rhs_(NULL),
     rhsDense_(),
     b_(NULL),
     matrix_(A),
     matrixDense_(),
     matrixFreeFree_(), matrixFreeFixed_(),matrixInverse_(),
-    penalty_(0),maxIterations_(0), maxRestarts_(0), tol_(0),
+    penalty_(1),
+    maxIterations_(0), maxRestarts_(0), tol_(0),
     parallel_(parallel)
 {
   // deep copy 
   matrixCopy_ = A;
   matrixSparse_ = &matrixCopy_;
   setup();
 }
 
 LinearSolver::LinearSolver(
     const SPAR_MAT & A,
     const int solverType,
     bool parallel
 )
   : solverType_(solverType),
     constraintHandlerType_(NO_CONSTRAINTS),
     nVariables_(0),
     initialized_(false),
     initializedMatrix_(true),
     initializedInverse_(false),
     matrixModified_(false),
     allowReinitialization_(false), 
     homogeneousBCs_(false),
     bcs_(NULL), // null implies no contraints will be added later
     rhs_(NULL),
     rhsDense_(), b_(NULL),
     matrix_(A),
     matrixDense_(), 
     matrixFreeFree_(), matrixFreeFixed_(),matrixInverse_(),
-    penalty_(0),maxIterations_(0), maxRestarts_(0), tol_(0),
+    penalty_(1),
+    maxIterations_(0), maxRestarts_(0), tol_(0),
     parallel_(parallel)
 {
   // shallow copy
   matrixSparse_ = &A;
   setup(); 
 }
 
 
 // --------------------------------------------------------------------
 //  Setup
 // --------------------------------------------------------------------
 void LinearSolver::setup(void)
 {
-  penalty_ = kPenalty; // relative to matrix diagonal
   tol_     = kTol;
   nVariables_ = matrix_.nRows();
   maxIterations_=2*nVariables_;
   maxRestarts_=nVariables_;
 
 
   // switch method based on size
   if (solverType_ < 0) {
     if (nVariables_ > kMaxDirect ) {
       solverType_ = ITERATIVE_SOLVE_SYMMETRIC;
       constraintHandlerType_ = PENALIZE_CONSTRAINTS; 
     }
     else {
       solverType_ = DIRECT_SOLVE;
     }
   }
   if (constraintHandlerType_ < 0) {
     constraintHandlerType_ = PENALIZE_CONSTRAINTS;
     if (solverType_ == DIRECT_SOLVE) constraintHandlerType_ = CONDENSE_CONSTRAINTS;
   }
   if ( solverType_ == DIRECT_SOLVE && constraintHandlerType_ == CONDENSE_CONSTRAINTS ) allowReinitialization_ = true;
-  if ( solverType_ == ITERATIVE_SOLVE_SYMMETRIC && constraintHandlerType_ == CONDENSE_CONSTRAINTS ) 
-    throw ATC_Error("LinearSolver::unimplemented method");
+  if ( solverType_ == ITERATIVE_SOLVE_SYMMETRIC && constraintHandlerType_ == CONDENSE_CONSTRAINTS )  { throw ATC_Error("LinearSolver::unimplemented method"); }
 }
 
 // --------------------------------------------------------------------
 //  Initialize
 // --------------------------------------------------------------------
 void LinearSolver::allow_reinitialization(void) 
 {
   if (constraintHandlerType_ == PENALIZE_CONSTRAINTS) {
     if (matrixModified_ ) throw ATC_Error("LinearSolver: can't allow reinitialization after matrix has been modified");
     matrixOriginal_ = *matrixSparse_;
   }
   allowReinitialization_  = true;
 }
 
 void LinearSolver::initialize(const BC_SET * bcs)
 {
   if (bcs) { 
     if (! allowReinitialization_ ) throw ATC_Error("LinearSolver: reinitialization not allowed");
    //if (! bcs_ ) throw ATC_Error("LinearSolver: adding constraints after constructing without constraints is not allowed");
     // shallow --> deep copy
     if (! bcs_ ) { // constraintHandlerType_ == NO_CONSTRAINTS
       if (matrixModified_) {
         throw ATC_Error("LinearSolver: adding constraints after constructing without constraints is not allowed if matrix has been modified");
       }
       else {
         matrixCopy_ = *matrixSparse_;
         matrixSparse_ = &matrixCopy_;
         constraintHandlerType_ = -1;
         setup();
       }
     }
     bcs_ = bcs;
     initializedMatrix_ = false;
     initializedInverse_   = false;
     if (matrixModified_) {
       matrixCopy_ = matrixOriginal_;
       matrixSparse_ = &matrixCopy_;
     }
   }
   initialize_matrix();
   initialize_inverse();
   initialize_rhs();
 
   initialized_ = true;
 }
 
 // --------------------------------------------------------------------
 //  initialize_matrix
 // --------------------------------------------------------------------
 void LinearSolver::initialize_matrix(void)
 {
   if ( initializedMatrix_ ) return;
   if       (constraintHandlerType_ == PENALIZE_CONSTRAINTS) {
     add_matrix_penalty();
   }
   else if  (constraintHandlerType_ == CONDENSE_CONSTRAINTS) {
     partition_matrix(); 
   }
   initializedMatrix_ = true;
 }
 
 // --------------------------------------------------------------------
 //  initialize_inverse
 // --------------------------------------------------------------------
 void LinearSolver::initialize_inverse(void)
 {
   if ( initializedInverse_ ) return;
   if (solverType_ == ITERATIVE_SOLVE_SYMMETRIC
    || solverType_ == ITERATIVE_SOLVE ) {
     matrixDiagonal_ = matrixSparse_->diag(); // preconditioner
   }
   else { // DIRECT_SOLVE
     if (constraintHandlerType_ == CONDENSE_CONSTRAINTS) {
       if( num_unknowns() > 0 ) {
         matrixInverse_ = inv(matrixFreeFree_); 
       }
     }
     else { // NO_CONSTRAINTS || PENALIZE_CONSTRAINTS
       matrixDense_ = matrixSparse_->dense_copy(); // need dense for lapack
       matrixInverse_ = inv(matrixDense_); 
     }
   }
   initializedInverse_ = true;
 }
 
 // --------------------------------------------------------------------
 //  initialize_rhs
 // --------------------------------------------------------------------
 void LinearSolver::initialize_rhs(void)
 {
   if (! rhs_ ) return;
   if (! bcs_ ) {
     b_ = rhs_;
     return;
   }
   if      (constraintHandlerType_ == PENALIZE_CONSTRAINTS) {
     add_rhs_penalty();
   }
   else if (constraintHandlerType_ == CONDENSE_CONSTRAINTS) {
     add_rhs_influence();
   }
 }
 
 // --------------------------------------------------------------------
 // add matrix penalty
 // - change matrix for Dirichlet conditions: add penalty
 // --------------------------------------------------------------------
 void LinearSolver::add_matrix_penalty(void)
 {
+  penalty_ = kPenalty; // relative to matrix diagonal
   SPAR_MAT & A = matrixCopy_;
   penalty_ *= (A.diag()).maxabs(); 
   BC_SET::const_iterator itr;
   for (itr = bcs_->begin(); itr != bcs_->end(); itr++) {
     int i = itr->first;
     A.add(i,i,penalty_); // modifies matrix
   }
   A.compress();
   matrixModified_ = true;
 }
 
 // --------------------------------------------------------------------
 // partition matrix
 // - partition matrix based on Dirichlet constraints
 // --------------------------------------------------------------------
 void LinearSolver::partition_matrix(void)
 {
   fixedSet_.clear();
   BC_SET::const_iterator itr;
   for (itr = bcs_->begin(); itr != bcs_->end(); itr++) {
     int i = itr->first;
     fixedSet_.insert(i);
   }
   freeSet_.clear();
   freeGlobalToCondensedMap_.clear();
   int j = 0; // local index
   for (int i = 0; i < nVariables_;  i++) {
     if (fixedSet_.find(i) == fixedSet_.end() ) {
        freeSet_.insert(i);
        freeGlobalToCondensedMap_[i] = j++;
     }
   }
 
   if (matrixDense_.nRows() == 0) matrixDense_ =matrixSparse_->dense_copy();
   DENS_MAT & K = matrixDense_;
   K.row_partition(freeSet_,matrixFreeFree_,matrixFreeFixed_); 
 }
 
 // --------------------------------------------------------------------
 //  add_rhs_penalty
 // --------------------------------------------------------------------
 void LinearSolver::add_rhs_penalty()
 {
 
   // deep copy
   VECTOR & b = rhsDense_;
 
   const VECTOR & r = *rhs_;
   int size = r.nRows();
   b.reset(size);
   for (int i = 0; i < size;  i++) {
     b(i) = r(i); 
   }
 
   if ( ! homogeneousBCs_ ){
     BC_SET::const_iterator itr;
     for (itr = bcs_->begin(); itr != bcs_->end(); itr++) {
       int i = itr->first;
       double v = itr->second;
       b(i) += penalty_ * v;
     }
   }
   b_ = &rhsDense_;
 }
 
 // --------------------------------------------------------------------
 //  add_rhs_influence
 // --------------------------------------------------------------------
 void LinearSolver::add_rhs_influence()
 {
   if (! initializedMatrix_ ) partition_matrix();
 
   // rhs = rhs + K_free,fixed * x_fixed
   int nbcs = bcs_->size();
   if (nbcs == 0) { // no bcs to handle
     b_ = rhs_;
   }
   else {
     DENS_VEC & b = rhsDense_;
     if ( ! homogeneousBCs_ ){
       DENS_VEC xFixed(nbcs);
       BC_SET::const_iterator itr;
       int i = 0;
       for (itr = bcs_->begin(); itr != bcs_->end(); itr++,i++) {
         double v = itr->second;
         xFixed(i,0) = -v;
       }  
       b = matrixFreeFixed_*xFixed; // matrix and bcs have same ordering
     }
     else {
       b.reset(matrixFreeFixed_.nRows());
     }
     const VECTOR & r = *rhs_;
     set<int>::const_iterator iter;
     int i = 0;
     for (iter = freeSet_.begin(); iter != freeSet_.end(); iter++,i++) {
       b(i) += r(*iter);  
     }
     b_ = &rhsDense_;
   }
 }
 
 // --------------------------------------------------------------------
 //  set fixed values
 //  - {x_i = y_i}
 // --------------------------------------------------------------------
 void LinearSolver::set_fixed_values(VECTOR & X)
 {
   BC_SET::const_iterator itr;
   for (itr = bcs_->begin(); itr != bcs_->end(); itr++) {
     int i = itr->first;
     double v = 0;
     if ( ! homogeneousBCs_ ) v = itr->second;
     X(i) = v;
   }
 }
 
 // --------------------------------------------------------------------
 //  Eigensystem
 // --------------------------------------------------------------------
 // calls lapack
 
 void LinearSolver::eigen_system( DENS_MAT & eigenvalues, DENS_MAT & eigenvectors, const DENS_MAT * M) /* const */
 {
   initialize_matrix(); // no inverse needed
   const DENS_MAT * Kp = NULL;
   const DENS_MAT * Mp =M;
   DENS_MAT MM;
   DENS_MAT KM;
   if (constraintHandlerType_ == CONDENSE_CONSTRAINTS) { 
     Kp = &matrixFreeFree_;
     if (M) {
       DENS_MAT MfreeFixed; // not used
       M->row_partition(freeSet_,MM,MfreeFixed); 
       Mp = &MM;
     }
   }
   else { 
     if (matrixDense_.nRows() == 0) matrixDense_ =matrixSparse_->dense_copy();
     Kp = &matrixDense_;
   }
   if (!M) {
     MM.identity(Kp->nRows());
     Mp = &MM;
   }
 
   DENS_MAT eVecs, eVals;
   eVecs = eigensystem(*Kp,*Mp,eVals);
   eigenvalues.reset(nVariables_,1);
   eigenvectors.reset(nVariables_,nVariables_);
   set<int>::const_iterator itr;
 
   for (int i = 0; i < Kp->nRows(); i++) { // ordering is by energy not node
     eigenvalues(i,0) = eVals(i,0);
     int j = 0;
     for (itr = freeSet_.begin(); itr != freeSet_.end(); itr++,j++) {
       int jj = *itr;
       eigenvectors(jj,i) = eVecs(j,i); // transpose
     }
   }
 }
 
 // --------------------------------------------------------------------
 // solve
 // - solves A x = b
 // - if a "b" is provided it is used as the new rhs
 // --------------------------------------------------------------------
 
 bool LinearSolver::solve(VECTOR & x, const VECTOR & b)
 {
   SPAR_MAT * A = NULL;
 
   rhs_ = &b;
   initialized_ = false;
   initialize();
   if (num_unknowns() == 0) {
     set_fixed_values(x);
     return true;
   }
   const VECTOR & r = *b_;
   if (solverType_ == ITERATIVE_SOLVE_SYMMETRIC) {
     
     
     
     if (parallel_) {
       A = new PAR_SPAR_MAT(LammpsInterface::instance()->world(), *matrixSparse_);
     }
     else {
       A = new SPAR_MAT(*matrixSparse_);
     }
     DIAG_MAT & PC = matrixDiagonal_;
     int niter = maxIterations_;
     double tol = tol_;
     int convergence = CG(*A, x, r, PC, niter, tol);// CG changes niter, tol
     if (convergence>0) {
        stringstream ss;
        ss << "CG solve did not converge,";
        ss << " iterations: " << niter;
        ss << " residual: " << tol;
        throw ATC_Error(ss.str());
     }
   }
   else if (solverType_ == ITERATIVE_SOLVE) {
     if (parallel_) {
       A = new PAR_SPAR_MAT(LammpsInterface::instance()->world(), *matrixSparse_);
     }
     else {
       A = new SPAR_MAT(*matrixSparse_);
     }
     const DIAG_MAT & PC = matrixDiagonal_;
     int iterations = maxIterations_;
     int restarts = maxRestarts_;
     double tol = tol_;
     DENS_MAT H(maxRestarts_+1, maxRestarts_);
     DENS_VEC xx(nVariables_);
     DENS_VEC bb;
     bb = b; 
     int convergence = GMRES(*A, xx, bb, PC, H, restarts, iterations, tol);
     if (convergence>0) {
        stringstream ss;
        ss << "GMRES greens_function solve did not converge,";
        ss << " iterations: " << iterations;
        ss << " residual: " << tol;
        throw ATC_Error(ss.str());
     }
     x.copy(xx.ptr(),xx.nRows()); 
   }
   else { // DIRECT_SOLVE
     const DENS_MAT & invA = matrixInverse_;
     if (constraintHandlerType_ == CONDENSE_CONSTRAINTS) {
       DENS_MAT xx = invA*r;
       int i = 0;
       set<int>::const_iterator itr;
       for (itr = freeSet_.begin(); itr != freeSet_.end(); itr++,i++) {
         int ii = *itr;
         x(ii) = xx(i,0);
       }
       set_fixed_values(x);
     }
     else {
 
       DENS_VEC xx = invA*r;
       for (int i = 0; i < xx.nRows(); i++) {
         x(i) = xx(i);
       }
     }
   }
   delete A;
 
 
   return true;
 }
 
 // --------------------------------------------------------------------
 // greens function
 // - returns the solution to a Kronecker delta rhs b = {0 0 .. 1 .. 0 0}
 //   and with homogeneous constraints {x_i = 0}
 // --------------------------------------------------------------------
 
 void LinearSolver::greens_function(int I, VECTOR & G_I)
 {
   SPAR_MAT * A = NULL;
 
 
 
   initialize_matrix();
   initialize_inverse();
   G_I.reset(nVariables_);
   VECTOR & x = G_I;
 
   if (solverType_ == ITERATIVE_SOLVE_SYMMETRIC) {
     DENS_VEC b(nVariables_); b = 0.0; b(I) = 1.0;
     if (parallel_) {
       A = new PAR_SPAR_MAT(LammpsInterface::instance()->world(), *matrixSparse_);
     }
     else {
       A = new SPAR_MAT(*matrixSparse_);
     }
     const DIAG_MAT & PC = matrixDiagonal_;
     int niter = maxIterations_;
     double tol = tol_;
     int convergence = CG(*A, x, b, PC, niter, tol);
     if (convergence>0) {
        stringstream ss;
        ss << "CG greens_function solve did not converge,";
        ss << " iterations: " << niter;
        ss << " residual: " << tol;
        throw ATC_Error(ss.str());
     }
   }
   else if (solverType_ == ITERATIVE_SOLVE) {
     DENS_VEC b(nVariables_); b = 0.0; b(I) = 1.0;
     //  VECTOR & bb = b;
     if (parallel_) {
       A = new PAR_SPAR_MAT(LammpsInterface::instance()->world(), *matrixSparse_);
     }
     else {
       A = new SPAR_MAT(*matrixSparse_);
     }
     //  const DENS_MAT A = matrixSparse_->dense_copy();
     const DIAG_MAT & PC = matrixDiagonal_;
     int iterations = maxIterations_;
     int restarts = maxRestarts_;
     double tol = tol_;
     DENS_MAT H(maxRestarts_+1, maxRestarts_);
     DENS_VEC xx(nVariables_);
     int convergence = GMRES(*A, xx, b, PC, H, restarts, iterations, tol);
     if (convergence>0) {
        stringstream ss;
        ss << "GMRES greens_function solve did not converge,";
        ss << " iterations: " << iterations;
        ss << " residual: " << tol;
        throw ATC_Error(ss.str());
     }
     x.copy(xx.ptr(),xx.nRows()); 
   }
   else {
     const DENS_MAT & invA = matrixInverse_;
     if (constraintHandlerType_ == CONDENSE_CONSTRAINTS) {
       set<int>::const_iterator itr;
       for (itr = fixedSet_.begin(); itr != fixedSet_.end(); itr++) {
         int ii = *itr;
         x(ii) = 0;
       }
       itr = freeSet_.find(I);
       if (itr !=freeSet_.end() ) {
         int j = freeGlobalToCondensedMap_[I];
         int i = 0;
         for (itr = freeSet_.begin(); itr != freeSet_.end(); itr++,i++) {
           int ii = *itr;
           x(ii) = invA(j,i);
         }
       }
     }
     else {
       for (int i = 0; i < nVariables_; ++i) x(i) = invA(I,i);
     }
   }
   
   delete A;
 }
 
 
 } // namespace ATC
diff --git a/lib/atc/LinearSolver.h b/lib/atc/LinearSolver.h
index eb84976c3..5f456b9a1 100644
--- a/lib/atc/LinearSolver.h
+++ b/lib/atc/LinearSolver.h
@@ -1,182 +1,183 @@
 #ifndef LINEAR_SOLVER_H
 #define LINEAR_SOLVER_H
 
 // ATC includes
 #include "ATC_TypeDefs.h"
 #include "MatrixLibrary.h"
 #include "ATC_Error.h"
 
 // other includes
 #include <set>
 #include <map>
 
 #include "LammpsInterface.h"
 #include "CG.h"
 #include "GMRES.h"
 
 
 namespace ATC {
 
 /**
  *  @class LinearSolver
  *  @brief a class to solve a system of linear equations
  *  A x = b subject to a set of constraints { x_i = y_i }
  */
   
 class LinearSolver {
 
  public:
   enum LinearSolveType {
     AUTO_SOLVE=-1, 
     DIRECT_SOLVE=0,
     ITERATIVE_SOLVE,
     ITERATIVE_SOLVE_SYMMETRIC
   };
 
   enum LinearSolveConstraintHandlingType {
+    AUTO_HANDLE_CONSTRAINTS=-1, 
     NO_CONSTRAINTS=0,
     CONDENSE_CONSTRAINTS,
     PENALIZE_CONSTRAINTS
   };
 
   /** Constructor */
   LinearSolver( // does not assume that A is persistent
     const SPAR_MAT & A,  // lhs matrix "deep" copy
     const BC_SET & bcs,     // constraints
     const int solverType = AUTO_SOLVE, 
     const int bcHandlerType = -1,
     bool parallel = false
   );
   LinearSolver( // assumes A is persistent
     const SPAR_MAT & A,  // lhs matrix "shallow" copy
     const int solverType = AUTO_SOLVE,
     bool parallel = false
   );
 
   /** Destructor */
   virtual ~LinearSolver() {};
 
   /** (re)initialize 
       - if bcs are provided the lhs matrix is re-configured 
         for the new constraints 
       - if the class is to be reused with new constraints 
          allow_reinitialization must be called before first solve, etc */
   void allow_reinitialization(void); // depending on method save a copy of A
   void set_homogeneous_bcs(void) { homogeneousBCs_ = true;} // for nonlinear solver, solve for increment
   void initialize(const BC_SET * bcs = NULL);
 
   /** solve
       - solves A x = b
       - if a "b" is provided it is used as the new rhs */
   bool solve(VECTOR & x, const VECTOR & b);
 
   /** greens function 
       - returns the solution to a Kronecker delta rhs b = {0 0 .. 1 .. 0 0}
         and with homogeneous constraints {x_i = 0} */
   void greens_function(int I, VECTOR & G_I);
 
   /** eigensystem
       - returns the e-values & e-vectors for constrained system Ax + v x = 0 
       - if M is provided the eval problem : ( A + v M ) x = 0 is solved*/
   void eigen_system(DENS_MAT & eigenvalues, DENS_MAT & eigenvectors, 
    const DENS_MAT * M = NULL);
 
   /** access to penalty coefficient
       - if a penalty method is not being used this returns zero */
   double penalty_coefficient(void) const {return penalty_;};
 
   /** change iterative solver parameters */
   void set_max_iterations(const int maxIter) { 
     if (solverType_ != ITERATIVE_SOLVE && solverType_ != ITERATIVE_SOLVE_SYMMETRIC ) throw ATC_Error("inappropriate parameter set in LinearSolver");
     maxIterations_=maxIter;
   }
   void set_tolerance(const double tol) { tol_=tol;}
 
   
   /* access to number of unknowns */
   int num_unknowns(void) const 
   { 
     int nUnknowns = nVariables_;
     if (bcs_) { nUnknowns -= bcs_->size(); }
     return nUnknowns;
   }
 
 
  protected:
   /** flavors */
   int solverType_;
   int constraintHandlerType_ ;
 
   /** number of variables = number of rows of matrix */
   int nVariables_;
 
   /** initialize methods */
   bool initialized_,initializedMatrix_,initializedInverse_;
   bool matrixModified_,allowReinitialization_;
   bool homogeneousBCs_;
   void setup(void);
   void initialize_matrix(void);
   void initialize_inverse(void);
   void initialize_rhs(void);
 
   /** constraint handling methods to modify the RHS */
   void add_matrix_penalty(void); /** penalty */
   void partition_matrix(void); /** condense */
 
   /** constraint handling methods to modify the RHS */
   void add_rhs_penalty(void); /** penalty */
   void add_rhs_influence(void); /** condense */
 
   /** set fixed values */
   void set_fixed_values(VECTOR & x);
 
   /** constraints container */
   const BC_SET * bcs_; 
 
   /** rhs vector/s */
   const VECTOR * rhs_; 
   DENS_VEC rhsDense_; // modified
   const VECTOR * b_; // points to appropriate rhs
 
   /** lhs matrix */
   const SPAR_MAT & matrix_; 
   SPAR_MAT matrixCopy_; // a copy that will be modified by penalty methods
 
   SPAR_MAT matrixOriginal_; // a copy that is used for re-initialization
   const SPAR_MAT * matrixSparse_; // points to matrix_ or matrixCopy_
 
   DENS_MAT matrixDense_; // a dense copy for lapack 
 
   /** partitioned matrix - condense constraints */
   DENS_MAT matrixFreeFree_, matrixFreeFixed_;
 
   /** maps for free and fixed variables for partitioned matrix - condense */
   std::set<int> freeSet_, fixedSet_; 
   std::map<int,int> freeGlobalToCondensedMap_;
 
   /** inverse matrix matrix - direct solve */
 
   DENS_MAT matrixInverse_;
 
   /** pre-conditioner diagonal of the matrix - iterative solve */
   DIAG_MAT matrixDiagonal_;
 
   /** penalty coefficient - penalty constraints */
   double penalty_;
 
   /** max iterations - iterative solve */
   int maxIterations_;
 
   /** max restarts - GMRES solve */
   int maxRestarts_;
 
   /** tolerance - iterative solve */
   double tol_;
 
   /** run solve in parallel */
   bool parallel_;
 };
 
 } // namespace ATC
 
 #endif
diff --git a/lib/atc/MPI_Wrappers.cpp b/lib/atc/MPI_Wrappers.cpp
index d69620ecb..9468644c5 100644
--- a/lib/atc/MPI_Wrappers.cpp
+++ b/lib/atc/MPI_Wrappers.cpp
@@ -1,333 +1,342 @@
 #include "MPI_Wrappers.h"
 #include "Utility.h"
 using ATC_Utility::to_string;
 #include "ATC_Error.h"
 using ATC::ATC_Error;
 using std::cout;
 using std::string;
 #ifdef ISOLATE_FE
 #include "Matrix.h"
 using ATC_Matrix::SparseMatrix;
 #endif
 
 namespace MPI_Wrappers {
 
   int rank(MPI_Comm comm)
   {
     int rank;
     MPI_Comm_rank(comm, &rank);
     return rank;
   }
   bool rank_zero(MPI_Comm comm) { return rank(comm)==0;}
 
   int size(MPI_Comm comm)
   {
     int size;
     MPI_Comm_size(comm, &size);
     return size;
   }
   bool serial(MPI_Comm comm) { return size(comm) == 0; }
 
   void broadcast(MPI_Comm comm, double *buf, int count)
   {
     int error = MPI_Bcast(buf, count, MPI_DOUBLE, 0, comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in broadcast "+to_string(error));
   }
 
   void int_broadcast(MPI_Comm comm, int *buf, int count)
   {
     int error = MPI_Bcast(buf, count, MPI_INT, 0, comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in broadcast "+to_string(error));
   }
 
   void allsum(MPI_Comm comm, void *send_buf, double *rec_buf, int count)
   {
     int error = MPI_Allreduce(send_buf, rec_buf, count, MPI_DOUBLE, MPI_SUM,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in allsum "+to_string(error));
   }
 
   void int_allsum(MPI_Comm comm, void *send_buf, int *rec_buf, int count)
   {
     int error = MPI_Allreduce(send_buf, rec_buf, count, MPI_INT, MPI_SUM,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in int_allsum "+to_string(error));
   }
 
   void int_scansum(MPI_Comm comm, int *send_buf, int *rec_buf, int count)
   {
     int error = MPI_Scan(send_buf, rec_buf, count, MPI_INT, MPI_SUM,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in int_scansum "+to_string(error));
   }
 
 
   void allmax(MPI_Comm comm, double *send_buf, double *rec_buf, int count)
   {
     int error = MPI_Allreduce(send_buf, rec_buf, count, MPI_DOUBLE, MPI_MAX,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in allmax "+to_string(error));
   }
 
   void int_allmax(MPI_Comm comm, int *send_buf, int *rec_buf, int count)
   {
     int error = MPI_Allreduce(send_buf, rec_buf, count, MPI_INT, MPI_MAX,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in int_allmax "+to_string(error));
   }
 
   void allmin(MPI_Comm comm, double *send_buf, double *rec_buf, int count)
   {
     int error = MPI_Allreduce(send_buf, rec_buf, count, MPI_DOUBLE, MPI_MIN,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in allmax "+to_string(error));
   }
 
   void int_allmin(MPI_Comm comm, int *send_buf, int *rec_buf, int count)
   {
     int error = MPI_Allreduce(send_buf, rec_buf, count, MPI_INT, MPI_MIN,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in int_allmax "+to_string(error));
   }
 
   int rank_min(MPI_Comm comm, double *send_buf, double *rec_buf, int count)
   {
     int myRank;
     MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
     DOUBLE_RANK in[count],out[count];
     for (int i = 0; i < count; i++) {
       in[i].val = send_buf[i];
       in[i].rank = myRank;
     }
     int error = MPI_Allreduce(in, out, count, MPI_DOUBLE_INT, MPI_MINLOC,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in rank_min "+to_string(error));
     for (int i = 0; i < count; i++) {
       rec_buf[i] = out[i].val;
     }
     return out[0].rank;
   }
 
   void int_recv(MPI_Comm comm, int *recv_buf, int max_size, int iproc)
   {
     MPI_Status status;
     MPI_Request request;
     int tmp, error, recv_size;
     error = MPI_Irecv(recv_buf,max_size,MPI_INT,iproc,0,comm,&request);
     error = error && MPI_Send(&tmp,0,MPI_INT,iproc,0,comm);
     error = error && MPI_Wait(&request,&status);
     error = error && MPI_Get_count(&status,MPI_DOUBLE,&recv_size);
     if (error != MPI_SUCCESS) throw ATC_Error("error in int_recv "+to_string(error));
   }
 
   void recv(MPI_Comm comm, double *recv_buf, int max_size,int iproc)
   {
     MPI_Status status;
     MPI_Request request;
     int tmp, error, recv_size;
     error = MPI_Irecv(recv_buf,max_size,MPI_DOUBLE,iproc,0,comm,&request);
     error = error && MPI_Send(&tmp,0,MPI_INT,iproc,0,comm);
     error = error && MPI_Wait(&request,&status);
     error = error && MPI_Get_count(&status,MPI_DOUBLE,&recv_size);
     if (error != MPI_SUCCESS) throw ATC_Error("error in recv "+to_string(error));
   }
 
   void int_send(MPI_Comm comm, int *send_buf,int send_size)
   {
     MPI_Status status;
     int tmp, error;
     error = MPI_Recv(&tmp,0,MPI_INT,0,0,comm,&status);
     error = error && MPI_Rsend(send_buf,send_size,MPI_INT,0,0,comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in int_send "+to_string(error));
   }
 
   void send(MPI_Comm comm, double *send_buf,int send_size)
   {
     MPI_Status status;
     int tmp, error;
     error = MPI_Recv(&tmp,0,MPI_INT,0,0,comm,&status);
     error = error && MPI_Rsend(send_buf,send_size,MPI_DOUBLE,0,0,comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in int_send "+to_string(error));
   }
 
   void int_scatter(MPI_Comm comm, int *send_buf, int *rec_buf, int count)
   {
     int error;
     int numprocs = size(comm);
     int sizes[numprocs];
     int displacements[numprocs];
     for (int i = 0; i < numprocs; ++i) {
       sizes[i] = 1;
       displacements[i] = i;
     }
     error = MPI_Scatterv(send_buf, sizes, displacements, MPI_INT, rec_buf, count, MPI_INT, 0, comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in int_scatter "+to_string(error));
   }
 
   void allgatherv(MPI_Comm comm, double *send_buf, int send_count,
                   double *rec_buf, int *rec_counts, int *displacements)
   {
     int error = MPI_Allgatherv(send_buf, send_count, MPI_DOUBLE,
                                rec_buf, rec_counts, displacements, MPI_DOUBLE,
                                comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in allgatherv "+to_string(error));
   }
 
   void gather(MPI_Comm comm, double send, double* recv)
   {
     int send_count = 1;
     int recv_count = 1;
     int root = 0;
     int error = MPI_Gather(&send, send_count, MPI_DOUBLE,
                             recv, recv_count,  MPI_DOUBLE, root, comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in allgatherv "+to_string(error));
   }
 
+  void int_allgather(MPI_Comm comm, int send, int* recv)
+  {
+    int send_count = 1;
+    int recv_count = 1;
+    int error = MPI_Allgather(&send, send_count, MPI_INT,
+                              recv, recv_count,  MPI_INT, comm);
+    if (error != MPI_SUCCESS) throw ATC_Error("error in allgatherv "+to_string(error));
+  }
+
   void logical_or(MPI_Comm comm, void *send_buf, int *rec_buf, int count)
   {
     int error = MPI_Allreduce(send_buf, rec_buf, count, MPI_INT, MPI_LOR,
                               comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in logical_or "+to_string(error));
   }
 
   void barrier(MPI_Comm comm)
   {
     int error = MPI_Barrier(comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in barrier "+to_string(error));
   }
 
   void stop(MPI_Comm comm, string msg)
   {
     int error = MPI_Barrier(comm);
     if (error != MPI_SUCCESS) throw ATC_Error("error in barrier "+to_string(error));
     throw ATC_Error("...stopping "+msg);
   }
 
 #ifdef ISOLATE_FE
 void sparse_allsum(MPI_Comm comm,SparseMatrix<double> &toShare) const
 {
   toShare.compress();
   
   // initialize MPI information
   int nProcs = size(comm);
   int myRank = rank(comm);;
 
   int error;
 
   // get numbers of rows, columns, rowsCRS, and 
   // sizes (number of nonzero elements in matrix)
   SparseMatInfo *recInfo = new SparseMatInfo[nProcs];
   SparseMatInfo myInfo;
   myInfo.rows    = toShare.nRows();
   myInfo.cols    = toShare.nCols();
   myInfo.rowsCRS = toShare.nRowsCRS();
   myInfo.size    = toShare.size();
 
   error = MPI_Allgather(&myInfo, 4, MPI_INT,
                         recInfo, 4, MPI_INT, lammps_->world);
   if (error != MPI_SUCCESS) throw ATC_Error("error in sparse_allsum_numrows "+to_string(error));
 
   // adjust row sendcounts because recRowsCRS is off by one
   int rowCounts[nProcs];
   int sizeCounts[nProcs];
   // set up total size of receive buffers for Allgatherv calls
   int totalRowsCRS = 0;
   int totalSize = 0;
   // set up array of displacements for Allgatherv calls
   int rowOffsets[nProcs];
   rowOffsets[0] = 0;
   int sizeOffsets[nProcs];
   sizeOffsets[0] = 0;
   for (int i = 0; i < nProcs; i++) {
     // find the total number of entries to share in the mpi calls below
     rowCounts[i] = recInfo[i].rowsCRS + 1;
     sizeCounts[i] = recInfo[i].size;
     totalRowsCRS += rowCounts[i];
     totalSize += recInfo[i].size;
     // these already have their 0th slot filled in
     if (i == 0) continue;
     rowOffsets[i] = rowOffsets[i-1] + rowCounts[i-1];
     sizeOffsets[i] = sizeOffsets[i-1] + sizeCounts[i-1];
   }
 
   // get actual rows
   INDEX *rec_ia = new INDEX[totalRowsCRS];
   if (toShare.size() == 0) {
     double dummy[0];
     error = MPI_Allgatherv(dummy, 0, MPI_INT,
                            rec_ia, rowCounts, rowOffsets, MPI_INT, lammps_->world);
   }
   else
     error = MPI_Allgatherv(toShare.rows(), rowCounts[myRank], MPI_INT,
                            rec_ia, rowCounts, rowOffsets, MPI_INT, lammps_->world);
   if (error != MPI_SUCCESS)
     throw ATC_Error("error in sparse_allsum_rowarray "+to_string(error));
 
   // get actual cols
   INDEX *rec_ja = new INDEX[totalSize];
   error = MPI_Allgatherv(toShare.cols(), sizeCounts[myRank], MPI_INT,
                          rec_ja, sizeCounts, sizeOffsets, MPI_INT, lammps_->world);
   if (error != MPI_SUCCESS)
     throw ATC_Error("error in sparse_allsum_colarray "+to_string(error));
      
   // get the array of values
   double *rec_vals = new double[totalSize];
   error = MPI_Allgatherv(toShare.ptr(), sizeCounts[myRank], MPI_DOUBLE,
                          rec_vals, sizeCounts, sizeOffsets, MPI_DOUBLE, lammps_->world);
   if (error != MPI_SUCCESS)
     throw ATC_Error("error in sparse_allsum_valarray "+to_string(error));
 
   INDEX *rec_ia_proc; 
   INDEX *rec_ja_proc; 
   double *rec_vals_proc;
   for (int i = 0; i < nProcs; i++) {
     if (myRank != i) {
       // deallocated when tempMat is deleted since it wraps them
       rec_ia_proc = new INDEX[rowCounts[i]];
       rec_ja_proc = new INDEX[sizeCounts[i]];
       rec_vals_proc = new double[sizeCounts[i]];
        
       // copy the data passed with MPI into the new spots
       copy(rec_ia + rowOffsets[i], 
            rec_ia + rowOffsets[i] + rowCounts[i],
            rec_ia_proc);
       copy(rec_ja + sizeOffsets[i], 
            rec_ja + sizeOffsets[i] + sizeCounts[i],
            rec_ja_proc);
       copy(rec_vals + sizeOffsets[i], 
            rec_vals + sizeOffsets[i] + sizeCounts[i],
            rec_vals_proc);
 
       // Does anyone know why we have to declare tempMat here (as well as set it equal to
       // something) to avoid segfaults? there are still segfaults, but they happen at a much 
       // later stage of the game now (and for less benchmarks overall).
       SparseMatrix<double> tempMat =
         SparseMatrix<double>(rec_ia_proc, rec_ja_proc, rec_vals_proc, 
                              recInfo[i].size, recInfo[i].rows, 
                              recInfo[i].cols, recInfo[i].rowsCRS);
       toShare += tempMat;
     }
   }
 
   delete[] recInfo;
   delete[] rec_ia;
   delete[] rec_ja;
   delete[] rec_vals;
 }
 #endif
 
  void print_msg(MPI_Comm comm, string msg) 
   {
     if (serial(comm)) { cout << " ATC: " << msg << "\n"; }
     else { cout << " ATC: P" << rank(comm) << ", " << msg << "\n"; }
   }
 
   void print_msg_once(MPI_Comm comm, string msg, bool prefix, bool endline) 
   {
     if (rank_zero(comm)) {
       if (prefix) cout << " ATC: ";
       cout << msg;
       if (endline) cout << "\n";
     }
   }
 }
diff --git a/lib/atc/MPI_Wrappers.h b/lib/atc/MPI_Wrappers.h
index 691c9d525..37f484c6a 100644
--- a/lib/atc/MPI_Wrappers.h
+++ b/lib/atc/MPI_Wrappers.h
@@ -1,45 +1,46 @@
 #ifndef MPI_WRAPPERS_H
 #define MPI_WRAPPERS_H
 
 #include <iostream>
 #include <string>
 #include "mpi.h"
 
 namespace MPI_Wrappers {
 
   typedef struct {double val; int rank; } DOUBLE_RANK;
 
   int rank(MPI_Comm comm);
   bool rank_zero(MPI_Comm comm);
   int size(MPI_Comm comm);
   bool serial(MPI_Comm comm);
   void broadcast(MPI_Comm comm, double *buf, int count = 1);
   void int_broadcast(MPI_Comm comm, int *buf, int count = 1);
   void allsum(MPI_Comm comm, void *send_buf, double *rec_buf, int count = 1);
   void int_allsum(MPI_Comm comm, void *send_buf, int *rec_buf, int count = 1);
   void int_scansum(MPI_Comm comm, int *send_buf, int *rec_buf, int count = 1);
   void allmax(MPI_Comm comm, double *send_buf, double *rec_buf, int count = 1);
   void int_allmax(MPI_Comm comm, int *send_buf, int *rec_buf, int count = 1);
   void allmin(MPI_Comm comm, double *send_buf, double *rec_buf, int count = 1);
   void int_allmin(MPI_Comm comm, int *send_buf, int *rec_buf, int count = 1);
   int rank_min(MPI_Comm comm, double *send_buf, double *rec_buf, int count);
   void int_recv(MPI_Comm comm, int *recv_buf, int max_size,int iproc);
   void recv(MPI_Comm comm, double *recv_buf, int max_size,int iproc);
   void int_send(MPI_Comm comm, int *send_buf,int send_size);
   void send(MPI_Comm comm, double *send_buf,int send_size);
   void allgatherv(MPI_Comm comm, double *send_buf, int send_count,
                   double *rec_buf, int *rec_counts, int *displacements);
   void gather(MPI_Comm comm, double send, double * recv);
+  void int_allgather(MPI_Comm comm, int send, int* recv);
   void logical_or(MPI_Comm comm, void *send_buf, int *rec_buf, int count = 1);
   void barrier(MPI_Comm comm);
   void stop(MPI_Comm comm, std::string msg="");
   void int_scatter(MPI_Comm comm, int *send_buf, int *rec_buf, int count = 1);
 
 //  void sparse_allsum(MPI_Comm comm, SparseMatrix<double> &toShare);
 
   void print_msg(MPI_Comm comm, std::string msg);
   void print_msg_once(MPI_Comm comm,std::string msg,bool prefix=true,bool endline=true);
 
 }
 
 #endif
diff --git a/lib/atc/Material.cpp b/lib/atc/Material.cpp
index eaeb7c975..22273de2e 100644
--- a/lib/atc/Material.cpp
+++ b/lib/atc/Material.cpp
@@ -1,776 +1,964 @@
 #include "Material.h"
 #include "ATC_Transfer.h"
 #include "LammpsInterface.h"
 #include "ElectronChargeDensity.h"
 #include "ElectronHeatCapacity.h"
 #include "ElectronHeatFlux.h"
 #include "ElectronPhononExchange.h"
 #include "ElectronDragPower.h"
 #include "Stress.h"
 #include "ViscousStress.h"
 #include "BodyForce.h"
 #include "ElectronFlux.h"
 #include <sstream>
 #include <fstream>
 #include <vector>
 
 using ATC_Utility::command_line;
 using ATC_Utility::str2dbl;
 using ATC_Utility::str2int;
 using std::stringstream;
 using std::set;
 using std::fstream;
 using std::string;
 using std::vector;
 
 namespace ATC {
 
   Material::Material()
     : rhoCp_(0),
       heatCapacity_(0),
       electronHeatCapacity_(NULL),
       massDensity_(0),
       heatConductivity_(0),
       electronHeatFlux_(NULL),
       stress_(NULL),
       viscousStress_(NULL),
       bodyForce_(NULL),
       electronPhononExchange_(NULL),
       electronDragPower_(NULL),
       electronFlux_(NULL),
       permittivity_(1.),
       invEffectiveMass_(1.),
       electronEquilibriumDensity_(0),
       electronRecombinationInvTau_(0),
       electronChargeDensity_(NULL)
   {
   }
   //--------------------------------------------------------------
   //  Constructor (parser)
   //--------------------------------------------------------------
   // Example:
   // material Cu
   //   heat_capacity  constant
   //     capacity  1.0
   //   end
   //   heat_flux linear
   //     conductivity    1.0
   //   end
   //   electron_heat_flux linear
   //     conductivity  1.0
   //   end
   //   electron_heat_capacity linear
   //     capacity 1.0
   //   end
   //   electron_phonon_exchange linear
   //     coefficient   0.1
   //   end
   // end
   Material::Material(string & tag, fstream &fileId)
     : tag_(tag),
       rhoCp_(0),
       heatCapacity_(0),
       electronHeatCapacity_(NULL),
       massDensity_(0),
       heatConductivity_(0),
       electronHeatFlux_(NULL),
       stress_(NULL),
       viscousStress_(NULL),
       bodyForce_(NULL),
       electronPhononExchange_(NULL),
       electronDragPower_(NULL),
       electronFlux_(NULL),
       permittivity_(1.),
       invEffectiveMass_(1.),
       electronEquilibriumDensity_(0),
       electronRecombinationInvTau_(0),
       electronChargeDensity_(NULL)
   {
+    /*! \page man_material material
+      \section syntax
+        material <tag> <units> \n
+           <commands> \n
+        end \n
+        tag - a unique identifier for the material type which can be referenced in input decks.  Multiple materials are specified using different tag regions, terminated with an 'end', in the material file.
+        units - the LAMMPS units system the material is based on, used as a check against the actual LAMMPS units.  AtC units are consistent units using the LAMMPS length, mass, time, charge, and volts.  The only units conversion occuring within AtC are LAMMPS to AtC units and charge to volts units. 
+        \section examples
+        material Argon real
+           -------
+        end
+        \section description
+        Starts a section in which material properties can be specified.  Materials are organized by material, identified by a tag, and all associated material models are specified within its scope.  Unspecified material properties use defaults as indicated or are considered as null.  Null material properties contribute no value to integrals using them.  Material properties defined which are not part of the physics model are ignored.  Functions which are specified correspond to those implemented in the code and there is no mechanism for user-specified material models unless they are added to the main code.\n 
+        \section restrictions
+        Material models are only used for evaluating finite element integrals with for physics models they are associated with.
+        \section related
+        \section default
+        Default for all material properties is null.  The null material using the tag 'null' is the only material defined by default. \n
+      */
     linearFlux_.reset(NUM_FIELDS);
     linearFlux_ = false;
     linearSource_.reset(NUM_FIELDS);
     linearSource_ = true;
     constantDensity_.reset(NUM_FIELDS);
     constantDensity_ = false;
 
     
     rhoCp_ = ATC::LammpsInterface::instance()->heat_capacity();
     parameters_["heat_capacity"] = rhoCp_;
     heatCapacity_ = rhoCp_;
     registry_.insert("heat_capacity");
     registry_.insert("thermal_energy");
     constantDensity_(TEMPERATURE) = true;
 
     constantDensity_(DISPLACEMENT) = true;
     constantDensity_(VELOCITY) = true;
     electronDragPower_ = new ElectronDragPower(); 
 
     vector<string> line;
     while(fileId.good()) {
       command_line(fileId, line);
       if (line.size() == 0) continue;
       if (line.size() == 1) {
         if (line[0] == "end") {
           return;
         }
       }
+      /*! \page man_mat_heat_capacity material heat_capcity 
+        \section syntax
+        heat_capacity constant\n
+          capacity <value> \n
+        end \n 
+        \section description
+        Overrides use of lattice heat capacity using Dulong-Petit law for continuum regions. \n 
+        \section restrictions
+        Only valid with AtC models incorporating a phonon temperature:  thermal, two-temperature, drift-diffusion
+        \section related
+        material
+        \section default
+        If no value is given, the Dulong-Petit value for the lattice is used. \n
+      */
       if      (line[0] == "heat_capacity") { // over-ride default
         registry_. insert("heat_capacity");
         registry_. insert("thermal_energy");
         if (line[1] == "constant") {
           while(fileId.good()) {
             command_line(fileId, line);
             if (line.size() == 0) continue;
             if (line[0] == "end") break;
             double value = str2dbl(line[1]);
             if (line[0] == "capacity") {
               heatCapacity_ = value;
               parameters_["heat_capacity"] = heatCapacity_;
             }
           }
         }
       }
+      /*! \page man_mat_heat_flux material heat_flux 
+        \section syntax
+        heat_flux linear\n
+          conductivity <value> \n
+        end \n 
+        \section description
+        Specifies a heat flux proportional to the temperature gradient. \n 
+        \section restrictions
+        Only valid with AtC models incorporating a phonon temperature:  thermal, two-temperature, drift-diffusion
+        \section related
+        material
+        \section default
+        Null. \n
+      */
       else if (line[0] == "heat_flux") {
         registry_. insert("heat_flux");
         if (line[1] == "linear") {
           linearFlux_(TEMPERATURE) = true;
           while(fileId.good()) {
             command_line(fileId, line);
             if (line.size() == 0) continue;
             if (line[0] == "end") break;
             double value = str2dbl(line[1]);
             if (line[0] == "conductivity") {
               heatConductivity_ = value;
             }
           }
         }
       }
+      /*! \page man_mat_electron_heat_flux material electron_heat_flux 
+        \section syntax
+        electron_heat_flux <null|linear|power_law|thermopower>\n
+          <parameter> <value> \n
+        end \n 
+        null - no electron heat flux contributions \n
+        linear - a heat flux proportional to the temperature gradient, parameter is 'conductivity'\n
+        power_law - a heat flux proportional to the temperature gradient and ratio of electron to phonon temperatures, parameter is 'conductivity'\n
+        thermopower - same as power_law but with an addition proportional to the electron current, parameters are 'conductivity' but it also uses the Seebeck coefficient defined elsewhere
+        \section description
+        Specifies the form for the electron heat flux. \n 
+        \section restrictions
+        Only valid with AtC models incorporating an electron temperature:  two-temperature, drift-diffusion
+        \section related
+        material
+        \section default
+        Null. \n
+      */
       else if (line[0] == "electron_heat_flux") {
         registry_. insert("electron_heat_flux");
         if      (line[1] == "null") {
           linearFlux_(ELECTRON_TEMPERATURE) = true;
           if (electronHeatFlux_) delete electronHeatFlux_;
           electronHeatFlux_ = new ElectronHeatFlux();
         }
         else if      (line[1] == "linear") {
           linearFlux_(ELECTRON_TEMPERATURE) = true;
           if (electronHeatCapacity_) {
             if (electronHeatFlux_) delete electronHeatFlux_;
             electronHeatFlux_ = new ElectronHeatFluxLinear(fileId, parameters_,electronHeatCapacity_);
           }
           else {
             if (electronHeatFlux_) delete electronHeatFlux_;
             electronHeatFlux_ = new ElectronHeatFluxLinear(fileId, parameters_);
           }
         }
         else if (line[1] == "power_law") {
           if (electronHeatCapacity_) {
             if (electronHeatFlux_) delete electronHeatFlux_;
             electronHeatFlux_ = new ElectronHeatFluxPowerLaw(fileId, parameters_,electronHeatCapacity_);
           }
           else {
             if (electronHeatFlux_) delete electronHeatFlux_;
             electronHeatFlux_ = new ElectronHeatFluxPowerLaw(fileId, parameters_);
           }
         }
         else if (line[1] == "thermopower") {
           
           if (! electronFlux_) {
             throw ATC_Error( "for thermopower please define electron_flux before electron_heat_flux");
           }
           if (electronHeatFlux_) delete electronHeatFlux_;
           electronHeatFlux_ = new ElectronHeatFluxThermopower(fileId, 
             parameters_, electronFlux_);
         }
       }
+      /*! \page man_mat_electron_heat_capacity material electron_heat_capacity 
+        \section syntax
+        electron_heat_capacity <constant|linear> <no_density>\n
+          capacity <value> \n
+        end \n 
+        no_density - if this keyword is present, the electron density does not multiply the capacity\n
+        constant - a constant electron heat flux \n
+        linear - a heat flux proportional to the electron temperature\n
+        \section description
+        Specifies the form for the electron heat capacity. \n 
+        \section restrictions
+        Only valid with AtC models incorporating an electron temperature:  two-temperature, drift-diffusion
+        \section related
+        material
+        \section default
+        Null. \n
+      */
       else if (line[0] == "electron_heat_capacity") {
         registry_. insert("electron_heat_capacity");
         registry_. insert("electron_thermal_energy");
         if (line[1] == "constant") {
           if ((line.size() == 3) && (line[2] == "no_density")) {
             if (electronHeatCapacity_) delete electronHeatCapacity_;
             electronHeatCapacity_ = new ElectronHeatCapacityConstantAddDensity(fileId,
                                                                                parameters_,
                                                                                this);
           }
           else {
             constantDensity_(ELECTRON_TEMPERATURE) = true;
             if (electronHeatCapacity_) delete electronHeatCapacity_;
             electronHeatCapacity_ = new ElectronHeatCapacityConstant(fileId,
                                                                      parameters_);
           }
         }
         else if (line[1] == "linear") {
           if ((line.size() == 3) && line[2] == "no_density") {
             if (electronHeatCapacity_) delete electronHeatCapacity_;
             electronHeatCapacity_ = new ElectronHeatCapacityLinearAddDensity(fileId,
                                                                              parameters_,
                                                                              this);
           }
           else {
             if (electronHeatCapacity_) delete electronHeatCapacity_;
             electronHeatCapacity_ = new ElectronHeatCapacityLinear(fileId,
                                                                    parameters_);
           }
         }
       }
+      /*! \page man_mat_electron_phonon_exchange material electron_phonon_exchange 
+        \section syntax
+        electron_phonon_exchange <null|linear|power_law|hertel>\n
+          <parameter> <value> \n
+        end \n 
+        null - no electron heat flux contributions \n
+        linear - an energy exchange proportional to the temperature difference between the electron and phonon temperatures, parameter is 'coefficient'\n
+        power_law - same as linear, but the temperature difference is raised to a specified power, parameters are 'coefficient' and 'exponent'\n
+        hertel - exchange proportional to temperature difference to the 5th divided by the electron temperature, the coefficient is a function of the mass enhancement and Debeye temperature, parameters are 'debeye_temperature' and 'mass_enhancement'
+        \section description
+        Specifies the form for the electron/phonon heat exchange. \n 
+        \section restrictions
+        Only valid with AtC models incorporating an electron temperature:  two-temperature, drift-diffusion
+        \section related
+        material
+        \section default
+        Null. \n
+      */
       else if (line[0] == "electron_phonon_exchange") {
         registry_. insert("electron_phonon_exchange");
         if      (line[1] == "null") {
           if (electronPhononExchange_) delete electronPhononExchange_;
           electronPhononExchange_ = new ElectronPhononExchange();
         }
         else if      (line[1] == "linear") {
           if (electronPhononExchange_) delete electronPhononExchange_;
           electronPhononExchange_ = new ElectronPhononExchangeLinear(fileId,  
                                                                      parameters_);
         }
         else if (line[1] == "power_law") {
           linearSource_(TEMPERATURE) = false;
           linearSource_(ELECTRON_TEMPERATURE) = false;
           if (electronPhononExchange_) delete electronPhononExchange_;
           electronPhononExchange_ = new ElectronPhononExchangePowerLaw(fileId, 
                                                                        parameters_);
         }
         else if (line[1] == "hertel") {
           linearSource_(TEMPERATURE) = false;
           linearSource_(ELECTRON_TEMPERATURE) = false;
           if (electronPhononExchange_) delete electronPhononExchange_;
           electronPhononExchange_ = new ElectronPhononExchangeHertel(fileId,parameters_,this);
         }
       }
+      /*! \page man_mass_density material mass_density 
+        \section syntax
+        mass_density <no entry|basis|constant>\n
+          <keyword> <values> \n
+        end \n 
+        no entry - compute mass density from the lattice using the mass of the first type, no keyword or values\n
+        basis - compute mass density for the given number of atoms of each type in the lattice, no keyword, values are one integer per type specifying the number of atoms of that type in the lattice\n
+        constant - prescribed mass density, keyword = density, value = desired mass density
+        \section description
+        Specifies the mass density of the system. \n 
+        \section restrictions
+        Valid for all AtC physics models.
+        \section related
+        material
+        \section default
+        Compute from the basis. \n
+      */
       else if (line[0] == "mass_density") { // over-ride default
         registry_. insert("mass_density");
         registry_. insert("kinetic_energy");
         if (line.size() == 1 ) { // try to calculate from lattice
           massDensity_ = LammpsInterface::instance()->mass_density();
           parameters_["mass_density"] = massDensity_;
           stringstream ss;
           ss << "computed mass density : " << massDensity_ ;
           ATC::LammpsInterface::instance()->print_msg_once(ss.str());
         }
         else if (line[1] == "basis") {
           while(fileId.good()) {
             command_line(fileId, line);
             if (line.size() == 0) continue;
             if (line[0] == "end") break;
             int n = line.size();
             int* numPerType = new int[n];
             for (int i = 0; i < n; i++) {
               numPerType[i] = str2int(line[i]);
             }
             massDensity_ = LammpsInterface::instance()->mass_density(numPerType);
             delete [] numPerType;
             parameters_["mass_density"] = massDensity_;
             stringstream ss;
             ss << "computed mass density (from given basis) : " << massDensity_ ;
             ATC::LammpsInterface::instance()->print_msg_once(ss.str());
           }
         }
         else if (line[1] == "constant") {
           while(fileId.good()) {
             command_line(fileId, line);
             if (line.size() == 0) continue;
             if (line[0] == "end") break;
             double value = str2dbl(line[1]);
             if (line[0] == "density") {
               massDensity_ = value;
               parameters_["mass_density"] = massDensity_;
             }
           }
         }
       }
+      /*! \page man_mat_stress material stress
+        \section syntax
+        stress <linear|cubic|damped_cubic|cauchy_born>\n
+          <keyword> <values> \n
+        end \n 
+        null - no electron heat flux contributions \n
+        linear - a stress tensor proportional to the displacements, keywords are 'modulus' and 'poissons_ratio'\n
+        cubic - an anisotropic linear stress tensor, keywords are 'c11', 'c12', and 'c44'\n
+        damped_cubic - same as cubic, with a damping term proportional to the velocity vector, keywords are 'c11', 'c12', 'c44', and the damping parameter 'gamma'\n
+        cauchy_born - stress tensor is computed using the Cauchy-Born formalism from the lattice and given potential, keywords are 'pairstyle', 'linear' (linearizes the Cauchy-Born relationship), or 'temperature' (the temperature used to determine the Cauchy-Born stress).  The 'pairstyle' lines are followed by values of 'lj/cut', 'lj/smooth/linear', and 'eam', the latter two of which are followed on the line by the value for the cut-off radius.  The 'lj/cut' and 'lj/smooth/linear' pairstyles are followed on the next line using the keyword 'pair_coeff' followed by value of the pair-coefficients \sigma and \epsilon.
+        \section description
+        Specifies the form for the mechanical stress tensor. \n 
+        \section restrictions
+        Only valid with AtC models incorporating a mechanical stress:  elastic
+        \section related
+        material
+        \section default
+        Null. \n
+      */
       else if (line[0] == "stress") {
         registry_. insert("stress");
         registry_. insert("elastic_energy");
         if      (line[1] == "linear") {
           linearFlux_(VELOCITY) = true;
           linearFlux_(DISPLACEMENT) = true;
           if (stress_) delete stress_;
           stress_ = new StressLinearElastic(fileId);
         }
         else if (line[1] == "cubic") {
           linearFlux_(VELOCITY) = true;
           linearFlux_(DISPLACEMENT) = true;
           if (stress_) delete stress_;
           stress_ = new StressCubicElastic(fileId);
         }
         else if (line[1] == "damped_cubic") {
           linearFlux_(VELOCITY) = true;
           linearFlux_(DISPLACEMENT) = true;
           if (stress_) delete stress_;
           stress_ = new StressCubicElasticDamped(fileId);
         }
         else if (line[1] == "cauchy-born") {
           CbData cb;
           LammpsInterface *lmp = LammpsInterface::instance();
           lmp->lattice(cb.cell_vectors, cb.basis_vectors);
           cb.inv_atom_volume = 1.0 / lmp->volume_per_atom();
           cb.e2mvv           = 1.0 / lmp->mvv2e();
           cb.boltzmann       = lmp->boltz();
           cb.atom_mass       = lmp->atom_mass(1); 
           if (stress_) delete stress_;
           stress_ = new StressCauchyBorn(fileId, cb);
         }
       }
       else if (line[0] == "viscous_stress") {
         registry_.insert("viscous_stress");
         if (line[1] == "constant") {
           linearFlux_(VELOCITY) = true;
           if (viscousStress_) delete viscousStress_;
           viscousStress_ = new ViscousStressConstant(fileId);
         }
       }
+      /*! \page man_body_force material body_force 
+        \section syntax
+        body_force <electric_field|viscous>\n
+          <keyword> <values> \n
+        end \n 
+        electric_field - adds body force proportional to the electric field and charge density, no keywords or values\n
+        viscous - adds a body force proportional to the velocity vector, keyword = gamma (damping parameter) followed by its value\n
+        \section description
+        Specifies body forces acting on the system. \n 
+        \section restrictions
+        Valid for all AtC mechanical models:  elastic
+        \section related
+        material
+        \section default
+        Null. \n
+      */
       else if (line[0] == "body_force") {
         registry_. insert("body_force");
         if (line.size() > 1) {
           if      (line[1] == "electric_field") {
             if (bodyForce_) delete bodyForce_;
             bodyForce_ = new BodyForceElectricField(fileId,parameters_);
           }
           else if (line[1] == "viscous") {
             if (bodyForce_) delete bodyForce_;
             bodyForce_ = new BodyForceViscous(fileId,parameters_);
           }
           else {
             if (bodyForce_) delete bodyForce_;
             bodyForce_ = new BodyForce();
           }
         }
         else {
           if (bodyForce_) delete bodyForce_;
           bodyForce_ = new BodyForce();
         }
       }
       else if (line[0] == "electron_flux") {
         registry_. insert("electron_flux");
         if      (line[1] == "null") {
           linearFlux_(ELECTRON_DENSITY) = true;
           if (electronFlux_) delete electronFlux_;
           electronFlux_ = new ElectronFlux();
         }
         else if      (line[1] == "linear") {
           linearFlux_(ELECTRON_DENSITY) = true;
           if (electronFlux_) delete electronFlux_;
           electronFlux_ = new ElectronFluxLinear(fileId, parameters_);
         }
         else if (line[1] == "thermopower") {
           if (electronFlux_) delete electronFlux_;
           electronFlux_ = new ElectronFluxThermopower(fileId, parameters_);
         }
         else if (line[1] == "convection") {
           if (electronFlux_) delete electronFlux_;
           electronFlux_ = new ElectronFluxConvection(fileId, parameters_);
         }
       }
+      /*! \page man_electric_field material electric_field
+        \section syntax
+        electric_field linear\n
+          permittivity <value> \n
+        end \n 
+        Provide a value for the permittivity or use LAMMPS' value if no value is given.\n
+        \section description
+        Specifies the electric displacement vector to be proportional to the electric field. \n 
+        \section restrictions
+        Valid for AtC physics models using electric fields:  fem_efield, drift-diffusion
+        \section related
+        material
+        \section default
+        Use LAMMPS' permittivity. \n
+      */
       else if (line[0] == "electric_field") {
         registry_. insert("electric_field");
         registry_. insert("electric_displacement");
         if (line[1] == "linear") {
           linearFlux_(ELECTRIC_POTENTIAL) = true;
           while(fileId.good()) {
             command_line(fileId, line);
             if (line.size() == 0) continue;
             if (line[0] == "end") break;
             if (line[0] == "permittivity") {
               // if no value given use lammps dielectric constant
               if (line.size() == 1 ) {
                 permittivity_ = LammpsInterface::instance()->dielectric();
               }
               else {
                 double value = str2dbl(line[1]);
                 permittivity_ = value;
               }
               // convert relative permitivity (dielectric) to abs internal units
               stringstream ss;
-              ss << "permittivity : " << permittivity_ ;
+              ss << "permittivity: relative= " << permittivity_ ;
               permittivity_ *= LammpsInterface::instance()->epsilon0();
-              ss << " -> " << permittivity_ ;
+              ss << ", absolute= " << permittivity_ ;
+              ss << ", lattice constant= " << LammpsInterface::instance()->max_lattice_constant()  ;
+              ATC::LammpsInterface::instance()->print_msg_once(ss.str());
               LammpsInterface::UnitsType utype = LammpsInterface::instance()->units_style();
               if ( utype != LammpsInterface::REAL 
                 && utype != LammpsInterface::METAL) {
                 ATC::LammpsInterface::instance()->print_msg_once("WARNING: must use a unit system where: [Energy/force] = [Length] and [charge] = e");
               // note this is so that: perm0/e = 1 / (Epotential_units * Length)
               // our charge densities are multiples of the elemental charge
               }
               parameters_["permittivity"]    = permittivity_;
             }
           }
         }
       }
       else if (line[0] == "effective_mass") {
         registry_. insert("inv_effective_mass");
         if (line[1] == "constant") {
           linearFlux_(ELECTRON_WAVEFUNCTION) = true;
           while(fileId.good()) {
             command_line(fileId, line);
             if (line.size() == 0) continue;
             if (line[0] == "end") break;
             if (line[0] == "inv_effective_mass") {
               double value = str2dbl(line[1]);
               invEffectiveMass_ = value; // 1/m* = inv_eff_mass/m_e
               // convert to hbar^2 / 2 / m* / e
               //double hbar = LammpsInterface::instance()->hbar();
               //invEffectiveMass_ *= 0.5*hbar*hbar;
               // m_e in units [eV-ps^2/A^2] : 5.68562958414706e-32
               double scale = 3.80998192145007; // units [V A^2]
               invEffectiveMass_ *= scale;
               parameters_["inverse_effective_mass"] = invEffectiveMass_;
             }
           }
         }
       }
       else if (line[0] == "electron_drag") {
         registry_.insert("electron_drag_power");
         registry_.insert("electron_drag_coefficient");
         if      (line[1] == "null") {
           if (electronDragPower_) delete electronDragPower_;
           electronDragPower_ = new ElectronDragPower();
         }
         else if      (line[1] == "linear") {
           if (electronDragPower_) delete electronDragPower_;
           electronDragPower_ = new ElectronDragPowerLinear(fileId,  
                                                            parameters_,
                                                            this);
         }        
       }
       else if (line[0] == "electron_recombination") {
         registry_. insert("electron_recombination");
         if (line[1] == "linear") {
           while(fileId.good()) {
             command_line(fileId, line);
             if (line.size() == 0) continue;
             if (line[0] == "end") break;
             double value = str2dbl(line[1]);
             if (line[0] == "inv_relaxation_time") {
               electronRecombinationInvTau_ = value;
               parameters_["inv_relaxation_time"] = electronRecombinationInvTau_;
             }
             else if (line[0] == "equilibrium_carrier_density") {
               electronEquilibriumDensity_ = value;
               parameters_["equilibrium_carrier_density"] 
                 = electronEquilibriumDensity_;
             }
           }
         }
       }
+      /*! \page man_mat_electron_density material electron_density 
+        \section syntax
+        electron_density <null|linear|interpolation|exponential|fermi_dirac>\n
+          <keyword> <values> \n
+        end \n 
+        null - no electron density constitutive model, uses the state variable \n
+        linear - density is proportional to the electric field, keyword is 'coefficient' followed by its value\n
+        interpolation - interpolates in a look-up table contained in a file provided after the 'interpolation' word, keywords are 'scale' and 'number_of_points', followed by their values \n
+        exponential - density is based on Boltzmann statistics for the electric potential above an activation energy, keywords are 'intrinsic_concentration', 'intrinsic_energy', and reference_temperature', followed by their values\n
+        fermi_dirac - density is based on Fermi-Dirac statistics for the electric potential relative to an activation energy, keywords are 'fermi_energy', 'reference_temperature', 'band_edge', 'donor_ionization_energy', and 'donor_concentration'
+        \section description
+        Specifies the form for the electron density. \n 
+        \section restrictions
+        Only valid with AtC models incorporating an electrons:  electrostatic, two-temperature, drift-diffusion
+        \section related
+        material
+        \section default
+        Null. \n
+      */
       else if (line[0] == "electron_density") { // density is converted to charge
         registry_. insert("electron_charge_density");
         if (line[1] == "null") {
           if (electronChargeDensity_) delete electronChargeDensity_;
           electronChargeDensity_ = new ElectronChargeDensity();
         }
         else if (line[1] == "linear") {
           linearSource_(ELECTRIC_POTENTIAL) = false;
           if (electronChargeDensity_) delete electronChargeDensity_;
           electronChargeDensity_ = new ElectronChargeDensityLinear(fileId, parameters_);
         }
         else if (line[1] == "interpolation") {
           linearSource_(ELECTRIC_POTENTIAL) = false;
           if (electronChargeDensity_) delete electronChargeDensity_;
           electronChargeDensity_ = new ElectronChargeDensityInterpolation(fileId, parameters_);
         }
         else if (line[1] == "exponential") {
           linearSource_(ELECTRIC_POTENTIAL) = false;
           if (electronChargeDensity_) delete electronChargeDensity_;
           electronChargeDensity_ = new ElectronChargeDensityExponential(fileId, parameters_);
         }
         else if (line[1] == "fermi_dirac") {
           registry_. insert("band_edge_potential");  
           //linearSource_(ELECTRIC_POTENTIAL) = false;  // treated as constant
           if (electronChargeDensity_) delete electronChargeDensity_;
           electronChargeDensity_ = new ElectronChargeDensityFermiDirac(fileId, parameters_);
         }
         else {
           throw ATC_Error("unrecognized material function type: "+line[0]+" - "+line[1]);
         }
       }
       else {
         throw ATC_Error( "unrecognized material function: "+line[0]);
       }
     }
   }
   //--------------------------------------------------------------------
   Material::~Material()
   {
     if (electronDragPower_) delete electronDragPower_;
     if (electronChargeDensity_) delete electronChargeDensity_;
     if (electronHeatCapacity_) delete electronHeatCapacity_;
     if (electronHeatFlux_) delete electronHeatFlux_;
     if (electronFlux_) delete electronFlux_;
     if (stress_) delete stress_;
     if (viscousStress_) delete viscousStress_;
     if (bodyForce_) delete bodyForce_;
     if (electronPhononExchange_) delete electronPhononExchange_;
   }
 //---------------------------------------------------------------------
 void Material::initialize(){if (stress_) stress_->initialize();}
 void Material::heat_capacity(
   const FIELD_MATS & fields,
   DENS_MAT & capacity) const
 {
   const DENS_MAT & T = (fields.find(TEMPERATURE))->second;
   int nNodes  = T.nRows();
   capacity.reset(nNodes,1);
   capacity = heatCapacity_;
 };
 //---------------------------------------------------------------------
 void Material::thermal_energy(
   const FIELD_MATS &fields,
   DENS_MAT &energy) const
 {
   
   const DENS_MAT & T = (fields.find(TEMPERATURE))->second;
   energy = heatCapacity_ * T;
 };
 //---------------------------------------------------------------------
 void Material::electron_heat_capacity(
   const FIELD_MATS & fields,
   DENS_MAT & capacity) const
 {
   electronHeatCapacity_->electron_heat_capacity(fields,capacity);
 };
 //---------------------------------------------------------------------
 void Material::D_electron_heat_capacity(
   const FIELD_MATS & fields,
   const GRAD_FIELD_MATS & gradFields,
   DENS_MAT_VEC & Dcapacity) const
 {
   electronHeatCapacity_->D_electron_heat_capacity(fields,gradFields,Dcapacity);
 };
 //---------------------------------------------------------------------
 void Material::electron_thermal_energy(
   const FIELD_MATS &fields,
   DENS_MAT &energy) const
 {
   electronHeatCapacity_->electron_thermal_energy(fields,energy);
 };
 //---------------------------------------------------------------------
 void Material::mass_density(
   const FIELD_MATS &fields,
   DENS_MAT &density) const
 {
   
   int nNodes = 0;
   FIELD_MATS::const_iterator field = fields.find(MASS_DENSITY);
   if (field != fields.end()) {
     const DENS_MAT & d = field->second;
     nNodes  = d.nRows();
   }
   else {
     FIELD_MATS::const_iterator field = fields.find(VELOCITY);
     if (field != fields.end()) {
       const DENS_MAT & v = field->second;
       nNodes  = v.nRows();
     }
   }
   density.reset(nNodes,1);
   density = massDensity_;
 };
 //---------------------------------------------------------------------
 void Material::electron_mass_density(
   const FIELD_MATS &fields,
   DENS_MAT &density) const
 {
   
   
   int nNodes = 0;
   FIELD_MATS::const_iterator field = fields.find(ELECTRON_DENSITY);
   //if (field != fields.end()) {
   const DENS_MAT & d = field->second;
     nNodes  = d.nRows();
     //}
   density.reset(nNodes,1);
   inv_effective_mass(fields,density);
   density = d.div_by_element(density);
 };
 //---------------------------------------------------------------------
 void Material::kinetic_energy(
   const FIELD_MATS &fields,
   DENS_MAT &energy) const
 {
   FIELD_MATS::const_iterator field = fields.find(VELOCITY);
   if (field != fields.end()) {
     const DENS_MAT & v = field->second;
     energy = 0.5*massDensity_*v;
     energy *= v;
   }
   else {
     energy = 0.;
   }
 };
 //---------------------------------------------------------------------
 void Material::permittivity(
   const FIELD_MATS &fields,
   DENS_MAT &density) const
 {
   const DENS_MAT & phi = (fields.find(ELECTRIC_POTENTIAL))->second;
   int nNodes  = phi.nRows();
   density.reset(nNodes,1);
   density = permittivity_;
 };
 //---------------------------------------------------------------------
 void Material::band_edge_potential(
   const FIELD_MATS &fields,
   DENS_MAT &density) const
 {
   electronChargeDensity_->band_edge_potential(fields,density);
 };
 //---------------------------------------------------------------------
 void Material::inv_effective_mass(
   const FIELD_MATS &fields,
   DENS_MAT &density) const
 {
   const DENS_MAT & phi = (fields.find(ELECTRON_DENSITY))->second;
   int nNodes  = phi.nRows();
   density.reset(nNodes,1);
   density = invEffectiveMass_;
 };
 //---------------------------------------------------------------------
 void Material::heat_flux(
   const FIELD_MATS & fields,
   const GRAD_FIELD_MATS & gradFields,
   DENS_MAT_VEC & flux) const
 {
   const DENS_MAT_VEC & dT = (gradFields.find(TEMPERATURE))->second;
   flux[0] = -heatConductivity_* dT[0];
   flux[1] = -heatConductivity_* dT[1];
   flux[2] = -heatConductivity_* dT[2];
 }
 //---------------------------------------------------------------------
 void Material::electron_heat_flux(
   const FIELD_MATS & fields,
   const GRAD_FIELD_MATS & gradFields,
   DENS_MAT_VEC & flux) const
 {
   electronHeatFlux_->electron_heat_flux(fields,gradFields,flux);
 }
 //---------------------------------------------------------------------
 void Material::electron_heat_convection(
   const FIELD_MATS & fields,
   DENS_MAT_VEC & flux) const
 {
   electronHeatFlux_->electron_heat_convection(fields,flux);
 }
 //---------------------------------------------------------------------
 bool Material::electron_phonon_exchange(
   const FIELD_MATS & fields,
   DENS_MAT & flux) const
 {
   return electronPhononExchange_->electron_phonon_exchange(fields,flux);
 }
 //---------------------------------------------------------------------
 void Material::electron_drag_velocity_coefficient(
   const FIELD_MATS &fields,
   DENS_MAT & dragCoef) const
 {
   electronDragPower_->electron_drag_velocity_coefficient(fields,dragCoef);
 }
 //---------------------------------------------------------------------
 bool  Material::electron_drag_power(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &gradFields,
   DENS_MAT & power) const
 {
   return electronDragPower_->electron_drag_power(fields,gradFields,power);
 }
 //---------------------------------------------------------------------
 bool Material::electron_recombination(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &gradFields,
   DENS_MAT & recombination) const
 {
   // 1/tau (n - n0)
   const DENS_MAT & n   = (fields.find(ELECTRON_DENSITY))->second;
   recombination  = n;
   recombination -= electronEquilibriumDensity_;
   recombination *= -electronRecombinationInvTau_;
   return true; 
 }
 //---------------------------------------------------------------------
 bool Material::electron_charge_density(
   const FIELD_MATS &fields,
   DENS_MAT & density) const
 {
   return electronChargeDensity_->electron_charge_density(fields,density);
 };
 //---------------------------------------------------------------------
 void Material::D_electron_charge_density(const FieldName fieldName,
                                          const FIELD_MATS &fields,
                                          DENS_MAT & D_density) const
 {
   electronChargeDensity_->D_electron_charge_density(fieldName,fields,D_density);
 };
 //---------------------------------------------------------------------
 bool Material::body_force(
   const FIELD_MATS &fields,
   DENS_MAT & density) const
 {
   return bodyForce_->body_force(fields,density);
 };
 //---------------------------------------------------------------------
 void Material::stress(
   const FIELD_MATS & fields,
   const GRAD_FIELD_MATS & gradFields,
   DENS_MAT_VEC & stress) const
 {
   stress_->stress(fields,gradFields,stress);
 }
 //---------------------------------------------------------------------
 void Material::elastic_energy(
   const FIELD_MATS & fields,
   const GRAD_FIELD_MATS & gradFields,
   DENS_MAT & energy) const
 {
   stress_->elastic_energy(fields,gradFields,energy);
 }
 //---------------------------------------------------------------------
 void Material::viscous_stress(
   const FIELD_MATS & fields,
   const GRAD_FIELD_MATS & gradFields,
   DENS_MAT_VEC & stress) const
 {
   viscousStress_->viscous_stress(fields,gradFields,stress);
 }
 //---------------------------------------------------------------------
 void Material::viscosity(
   const FIELD_MATS &fields,
   DENS_MAT &coefs) const
 {
   viscousStress_->viscosity(fields,coefs);
 }
 //---------------------------------------------------------------------
 void Material::electron_flux(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &gradFields,
   DENS_MAT_VEC &flux) const
 {
   electronFlux_->electron_flux(fields,gradFields,flux);
 }
 //---------------------------------------------------------------------
 void Material::electric_field(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &gradFields,
   DENS_MAT_VEC &flux) const
 {
   // E = - grad \phi
   const DENS_MAT_VEC & dphi = (gradFields.find(ELECTRIC_POTENTIAL))->second;
 
   flux[0] = -1.0* dphi[0];
   flux[1] = -1.0* dphi[1];
   flux[2] = -1.0* dphi[2];
 }
 //---------------------------------------------------------------------
 void Material::electric_displacement(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &gradFields,
   DENS_MAT_VEC &flux) const
 {
   // D = - permitivity grad \phi
   const DENS_MAT_VEC & dphi = (gradFields.find(ELECTRIC_POTENTIAL))->second;
   flux[0] = -permittivity_* dphi[0];
   flux[1] = -permittivity_* dphi[1];
   flux[2] = -permittivity_* dphi[2];
 }
 //---------------------------------------------------------------------
 } // end namespace
diff --git a/lib/atc/Matrix.h b/lib/atc/Matrix.h
index 179bea52b..076ed1867 100644
--- a/lib/atc/Matrix.h
+++ b/lib/atc/Matrix.h
@@ -1,1019 +1,999 @@
 #ifndef MATRIX_H
 #define MATRIX_H
 #include "MatrixDef.h"
 
 namespace ATC_matrix {
 static const int myPrecision = 15;
 
   /**
    *  @class  Matrix
    *  @brief  Base class for linear algebra subsystem 
    */
 
 template<typename T>
 class Matrix
 {
 
 protected:
   Matrix(const Matrix &c);
 public:
   Matrix() {}
   virtual ~Matrix() {}
 
   //* stream output functions
-  void print(std::ostream &o) const { o << to_string(); }
-  void print(std::ostream &o, const std::string &name) const;
+  void print(std::ostream &o, int p=myPrecision) const { o << this->to_string(p); }
+  void print(std::ostream &o, const std::string &name, int p=myPrecision) const;
   friend std::ostream& operator<<(std::ostream &o, const Matrix<T> &m){m.print(o); return o;}
   void print() const;
-  virtual void print(const std::string &name) const;
-  virtual std::string to_string() const;
+  virtual void print(const std::string &name, int p = myPrecision) const;
+  virtual std::string to_string(int p = myPrecision) const;
 
   // element by element operations
   DenseMatrix<T> operator/(const Matrix<T>& B) const;
   DenseMatrix<T> pow(int n) const;
   DenseMatrix<T> pow(double n) const;
 
   // functions that return a copy 
   DenseMatrix<T> transpose() const;
   void row_partition(const std::set<int> & rowsIn, std::set<int> & rows, std::set<int> & colsC,
     DenseMatrix<T> & A1, DenseMatrix<T> & A2, bool complement=true) const;
   std::set<int> row_partition(const std::set<int> & rows, 
     DenseMatrix<T> & A1, DenseMatrix<T> & A2) const;
   void map(const std::set<int>& rows, const std::set<int>& cols, DenseMatrix<T> & A) const;
   void insert(const std::set<int>& rows, const std::set<int>& cols, const DenseMatrix<T> & A);
   void assemble(const std::set<int>& rows, const std::set<int>& cols, const DenseMatrix<T> & A);
 
   // matrix to scalar functions
   T sum()    const;
   T stdev()  const;
   T max()    const;
   T min()    const;
   T maxabs() const;
   T minabs() const;
   T norm()   const;
   T norm_sq()   const;
   T mean()   const;
   T dot(const Matrix<T> &r) const;
   T trace() const;
 
   // row and column operations
   T row_sum  (INDEX i=0) const { return    row(*this,i).sum();   }
   T row_mean (INDEX i=0) const { return    row(*this,i).mean();  }
   T row_norm (INDEX i=0) const { return    row(*this,i).norm();  }
   T row_min  (INDEX i=0) const { return    row(*this,i).min();  }
   T row_max  (INDEX i=0) const { return    row(*this,i).max();  }
   T row_stdev(INDEX i=0) const { return    row(*this,i).stdev(); }
   T col_sum  (INDEX i=0) const { return column(*this,i).sum();   }
   T col_mean (INDEX i=0) const { return column(*this,i).mean();  }
   T col_norm (INDEX i=0) const { return column(*this,i).norm();  }
   T col_min  (INDEX i=0) const { return column(*this,i).min();  }
   T col_max  (INDEX i=0) const { return column(*this,i).max();  }
   T col_stdev(INDEX i=0) const { return column(*this,i).stdev(); }
  
   // pure virtual functions (required to implement these) ---------------------
   //* reference index operator
   virtual T& operator()(INDEX i, INDEX j)=0;      
   //* value index operator
   virtual T  operator()(INDEX i, INDEX j)const=0; 
   //* value flat index operator
   virtual T& operator [](INDEX i)=0;              
   //* reference flat index operator
   virtual T operator [](INDEX i) const=0;         
   //* returns the # of rows
   virtual INDEX nRows() const=0;                  
   //* returns the # of columns
   virtual INDEX nCols() const=0;                  
   //* returns a pointer to the data (dangerous)
   virtual T * ptr() const=0;                  
   //* resizes the matrix, copy what fits default to OFF
   virtual void resize(INDEX nRows, INDEX nCols=1, bool copy=false)=0;
   //* resizes the matrix, zero it out default to ON
   virtual void  reset(INDEX nRows, INDEX nCols=1, bool zero=true)=0;
   //* resizes and copies data
   virtual void copy(const T * ptr, INDEX nRows, INDEX nCols=1)=0;
   //* create restart file
   virtual void write_restart(FILE *f) const=0;    
   //* writes a matlab command to recreate this in a variable named s
   virtual void matlab(std::ostream &o, const std::string &s="M") const;
   //* writes a mathematica command to recreate this in a variable named s
   virtual void mathematica(std::ostream &o, const std::string &s="M") const;
 
   // output to matlab, with variable name s
   void matlab(const std::string &s="M") const;
   // output to mathematica, with variable name s
   void mathematica(const std::string &s="M") const;
 
   Matrix<T>& operator+=(const Matrix &r);
   Matrix<T>& operator-=(const Matrix &r);
   
   Matrix<T>& operator*=(const Matrix<T>& R);
   Matrix<T>& operator/=(const Matrix<T>& R);
   Matrix<T>& operator+=(const T v);
   Matrix<T>& operator-=(const T v);
   Matrix<T>& operator*=(const T v);
   Matrix<T>& operator/=(T v);
   Matrix<T>& divide_zero_safe(const Matrix<T>& B);
 
   Matrix<T>& operator=(const T &v);
   Matrix<T>& operator=(const Matrix<T> &c); 
   virtual void set_all_elements_to(const T &v);
   //* adds a matrix scaled by factor s to this one.
   void add_scaled(const Matrix<T> &A, const T& s);
 
   //* sets all elements to zero
   Matrix& zero();
   //* sets matrix to the identity
   Matrix& identity(int nrows=0);
   //* returns the total number of elements
   virtual INDEX size() const;
   //* returns true if (i,j) is within the range of the matrix
   bool in_range(INDEX i, INDEX j) const;
   //* returns true if the matrix size is rs x cs
   bool is_size(INDEX rs, INDEX cs) const;
   //* returns true if the matrix is square and not empty
   bool is_square() const;
   //* returns true if Matrix, m, is the same size as this
   bool same_size(const Matrix &m) const;
   //* returns true if Matrix a and Matrix b are the same size
   static bool same_size(const Matrix<T> &a, const Matrix<T> &b);
   //* returns true if Matrix a rows are equal to Matrix b cols
   static bool cols_equals_rows(const Matrix<T> &a, const Matrix<T> &b);
   //* checks if memory is contiguous, only can be false for clone vector
   virtual bool memory_contiguous() const { return true; }
   //* checks if all values are within the prescribed range
   virtual bool check_range(T min, T max) const;
 
 protected:
-  virtual void _set_equal(const Matrix<T> &r);
+  virtual void _set_equal(const Matrix<T> &r) = 0;
 };
 
 //* Matrix operations 
 //@{
 //* Sets C as b*C + a*A[tranpose?]*B[transpose?] 
 template<typename T>
 void MultAB(const Matrix<T> &A, const Matrix<T> &B, DenseMatrix<T> &C, 
             bool At=0, bool Bt=0, T a=1, T b=0);
 //* performs a matrix-vector multiply
 template<typename T>
 void MultMv(const Matrix<T> &A, const Vector<T> &v, DenseVector<T> &c,
             const bool At, T a, T b);
 // returns the inverse of a double precision matrix
 DenseMatrix<double> inv(const Matrix<double>& A);
 // returns the eigensystem of a pair of double precision matrices
 DenseMatrix<double> eigensystem(const Matrix<double>& A, const Matrix<double>& B, DenseMatrix<double> & eVals, bool normalize = true);
 // returns the polar decomposition of a double precision matrix
 DenseMatrix<double>  polar_decomposition(const Matrix<double>& A, DenseMatrix<double> & rotation, DenseMatrix<double> & stretch, bool leftRotation = true);
 
 //* returns the trace of a matrix
 template<typename T> 
 T trace(const Matrix<T>& A) { return A.trace(); }
 //* computes the determinant of a square matrix
 double det(const Matrix<double>& A);
 //* Returns the maximum eigenvalue of a matrix.
 double max_eigenvalue(const Matrix<double>& A);
 //@}
 
 //-----------------------------------------------------------------------------
 // computes the sum of the difference squared of each element. 
 //-----------------------------------------------------------------------------
 template<typename T>
 double sum_difference_squared(const Matrix<T>& A, const Matrix<T> &B)
 {
   SSCK(A, B, "sum_difference_squared");
   double v=0.0;
   for (INDEX i=0; i<A.size(); i++) {
     double d = A[i]-B[i];
     v += d*d;
   }
   return v;
 }
 
 //-----------------------------------------------------------------------------
 //* Operator for Matrix-matrix product
 //-----------------------------------------------------------------------------
 template<typename T>
 DenseMatrix<T> operator*(const Matrix<T> &A, const Matrix<T> &B)
 {
   DenseMatrix<T> C(0,0,false);
   MultAB(A,B,C);
   return C;
 }
 //-----------------------------------------------------------------------------
 //* Multiply a Matrix by a scalar 
 //-----------------------------------------------------------------------------
 template<typename T>
 DenseMatrix<T> operator*(const Matrix<T> &M, const T s)
 {
   DenseMatrix<T> R(M);
   return R*=s; 
 }
 //-----------------------------------------------------------------------------
 //* Multiply a Matrix by a scalar 
 template<typename T>
 DenseMatrix<T> operator*(const T s, const Matrix<T> &M)
 {
   DenseMatrix<T> R(M);
   return R*=s; 
 }
 //-----------------------------------------------------------------------------
 //* inverse scaling operator - must always create memory
 template<typename T>
 DenseMatrix<T> operator/(const Matrix<T> &M, const T s)
 {
   DenseMatrix<T> R(M);
   return R*=(1.0/s); // for integer types this may be worthless
 }
 //-----------------------------------------------------------------------------
 //* Operator for Matrix-matrix sum
 template<typename T>
 DenseMatrix<T> operator+(const Matrix<T> &A, const Matrix<T> &B)
 {
   DenseMatrix<T> C(A);
   return C+=B;
 }
 //-----------------------------------------------------------------------------
 //* Operator for Matrix-matrix subtraction
 template<typename T>
 DenseMatrix<T> operator-(const Matrix<T> &A, const Matrix<T> &B)
 {
   DenseMatrix<T> C(A);
   return C-=B;
 }
 /******************************************************************************
 * Template definitions for class Matrix
 ******************************************************************************/
 
 //-----------------------------------------------------------------------------
 //* performs a matrix-matrix multiply with general type implementation
 template<typename T>
 void MultAB(const Matrix<T> &A, const Matrix<T> &B, DenseMatrix<T> &C, 
             const bool At, const bool Bt, T a, T b)
 {
   const INDEX sA[2] = {A.nRows(), A.nCols()};  // m is sA[At] k is sA[!At]
   const INDEX sB[2] = {B.nRows(), B.nCols()};  // k is sB[Bt] n is sB[!Bt]
 
   const INDEX M=sA[At], K=sB[Bt], N=sB[!Bt]; // M is the number of rows in A or Atrans (sA[At]),
                                     // K is the number of rows in B or Btrans (sB[Bt], sA[!At]),
                                     // N is the number of columns in B or Btrans (sB[!Bt]).
 
   GCK(A, B, sA[!At]!=K, "MultAB<T> shared index not equal size");
   if (!C.is_size(M,N))
   {
     C.resize(M,N);          // set size of C
     C.zero();
   }
   else C *= b; // Zero C
   for (INDEX p=0; p<M; p++) {
     INDEX p_times_At    = p*At;
     INDEX p_times_notAt = p*!At;
     for (INDEX q=0; q<N; q++) {
         INDEX q_times_Bt    = q*Bt;
         INDEX q_times_notBt = q*!Bt;
       for (INDEX r=0; r<K; r++) {
          INDEX ai = p_times_notAt+r*At;
          INDEX aj = p_times_At+r*!At;
          INDEX bi = r*!Bt+q_times_Bt;
          INDEX bj = r*Bt+q_times_notBt;
          T a_entry = A(ai, aj);
          T b_entry = B(bi, bj);
          T mult    = a_entry * b_entry;
          C(p,q) += mult;
       }
     }
   }
 }
 
 //-----------------------------------------------------------------------------
 //* output operator
 template<typename T>
-std::string Matrix<T>::to_string() const
+std::string Matrix<T>::to_string(int p) const
 {
   std::string s;
-  for (INDEX i=0; i<nRows(); i++)
-  {
+  for (INDEX i=0; i<nRows(); i++) {
     if (i) s += '\n';
-    for (INDEX j=0; j<nCols(); j++)
-    {
-      if (j) s+= '\t';
-      s += ATC_Utility::to_string((*this)(i,j),myPrecision)+"   ";
+    for (INDEX j=0; j<nCols(); j++) {
+      //if (j) s+= '\t';
+      s += ATC_Utility::to_string((*this)(i,j),p)+" ";
     }
   }
   return s;
 }
 //-----------------------------------------------------------------------------
 //* output operator that wraps the matrix in a nice labeled box
 template<typename T>
-void Matrix<T>::print(std::ostream &o, const std::string &name) const
+void Matrix<T>::print(std::ostream &o, const std::string &name, int p) const
 {
   o << "------- Begin "<<name<<" -----------------\n";
-  this->print(o);
+  this->print(o,p);
   o << "\n------- End "<<name<<" -------------------\n";
 }
 //-----------------------------------------------------------------------------
 //* print operator, use cout by default
 template<typename T>
 void Matrix<T>::print() const 
 {
   print(std::cout); 
 }
 //-----------------------------------------------------------------------------
 //* named print operator, use cout by default
 template<typename T>
-void Matrix<T>::print(const std::string &name) const 
+void Matrix<T>::print(const std::string &name, int p) const 
 {
-  print(std::cout, name); 
+  print(std::cout, name, p); 
 }
 //-----------------------------------------------------------------------------
 //* element by element division
 template<typename T>
 DenseMatrix<T> Matrix<T>::operator/ (const Matrix<T>& B) const
 {
   SSCK(*this, B, "Matrix<T>::Operator/");
   DenseMatrix<T> R(*this);
   R /= B;
   return R;
 }
 //-----------------------------------------------------------------------------
 //* element-wise raise to a power
 template<typename T>
 DenseMatrix<T> Matrix<T>::pow(int n) const
 {
   DenseMatrix<T> R(*this);
   int sz=this->size(); for(INDEX i=0; i<sz; i++)
   {
     double val = R[i];
     for (int k=1; k<n; k++) val *= R[i];
     for (int k=n; k<1; k++) val /= R[i];
     R[i] = val;
   }
   return R;
 }
 //-----------------------------------------------------------------------------
 //* element-wise raise to a power
 template<typename T>
 DenseMatrix<T> Matrix<T>::pow(double n) const
 {
   DenseMatrix<T> R(*this);
   int sz=this->size(); for(INDEX i=0; i<sz; i++)
   {
     double val = R[i];
     R[i] = pow(val,n);
   }
   return R;
 }
 //-----------------------------------------------------------------------------
 //* returns the transpose of this matrix (makes a copy)
 template <typename T>
 DenseMatrix<T> Matrix<T>::transpose()                                     const
 {
   DenseMatrix<T> t(this->nCols(), this->nRows());
   int szi = this->nRows();
   int szj = this->nCols(); 
   for (INDEX i = 0; i < szi; i++) 
     for (INDEX j = 0; j < szj; j++)
       t(j,i) = (*this)(i,j);
   return t;
 }
 //-----------------------------------------------------------------------------
 //* returns the transpose of a matrix (makes a copy)
 template <typename T>
 DenseMatrix<T> transpose(const Matrix<T> &A)
 {
   return A.transpose();
 }
 //-----------------------------------------------------------------------------
 //* Returns the sum of all matrix elements 
 template<typename T>
 T Matrix<T>::sum() const
 {
   if (!size())  return T(0);
   T v = (*this)[0];
   for (INDEX i=1; i<this->size(); i++) v += (*this)[i];
   return v; 
 }
 //-----------------------------------------------------------------------------
 //* Returns the standard deviation of the matrix
 template<typename T>
 T Matrix<T>::stdev() const
 {
   GCHK(this->size()<2, "Matrix::stdev() size must be > 1");
   T mean = this->mean();
   T diff = (*this)[0]-mean;
   T stdev = diff*diff;
   for (INDEX i=1; i<this->size(); i++) 
   {
     diff = (*this)[i]-mean;
     stdev += diff*diff;
   }
   return sqrt(stdev/T(this->size()-1)); 
 }
 //-----------------------------------------------------------------------------
 //* Returns the maximum of the matrix
 template<typename T>
 T Matrix<T>::max() const
 {
   GCHK(!this->size(), "Matrix::max() size must be > 0");
   T v = (*this)[0];
   for (INDEX i=1; i<this->size(); i++)   v = std::max(v, (*this)[i]);
   return v; 
 }
 //-----------------------------------------------------------------------------
 //* Returns the minimum of the matrix
 template<typename T>
 T Matrix<T>::min() const
 {
   GCHK(!this->size(), "Matrix::min() size must be > 0");
   T v = (*this)[0];
   for (INDEX i=1; i<this->size(); i++)   v = std::min(v, (*this)[i]);
   return v; 
 }
 //-----------------------------------------------------------------------------
 //* Returns the maximum absolute value of the matrix
 template<typename T>
 T Matrix<T>::maxabs() const
 {
   GCHK(!this->size(), "Matrix::maxabs() size must be > 0");
   T v = (*this)[0];
   for (INDEX i=1; i<this->size(); i++)   v = ATC_Utility::max_abs(v, (*this)[i]);
   return v; 
 }
 //-----------------------------------------------------------------------------
 //* Returns the minimum absoute value of the matrix
 template<typename T>
 T Matrix<T>::minabs() const
 {
   GCHK(!this->size(), "Matrix::minabs() size must be > 0");
   T v = (*this)[0];
   for (INDEX i=1; i<this->size(); i++)   v = ATC_Utility::min_abs(v, (*this)[i]);
   return v; 
 }
 //-----------------------------------------------------------------------------
 //* returns the L2 norm of the matrix
 template<typename T>
 T Matrix<T>::norm()                                                       const    
 {
   GCHK(!this->size(), "Matrix::norm() size must be > 0");
   return sqrt(dot(*this)); 
 }
 //-----------------------------------------------------------------------------
 //* returns the L2 norm of the matrix
 template<typename T>
 T Matrix<T>::norm_sq()                                                       const    
 {
   GCHK(!this->size(), "Matrix::norm() size must be > 0");
   return dot(*this); 
 }
 //-----------------------------------------------------------------------------
 //* returns the average of the matrix
 template<typename T>
 T Matrix<T>::mean()                                                       const    
 {
   GCHK(!this->size(), "Matrix::mean() size must be > 0");
   return sum()/T(this->size());
 }
 //-----------------------------------------------------------------------------
 //* Returns the dot product of two vectors
 template<typename T>
 T Matrix<T>::dot(const Matrix<T>& r)  const
 {
   SSCK(*this, r, "Matrix<T>::dot");
   if (!this->size()) return T(0);
   T v = r[0]*(*this)[0];
   for (INDEX i=1; i<this->size(); i++)  v += r[i]*(*this)[i];
   return v;
 }
 //-----------------------------------------------------------------------------
 // returns the sum of the matrix diagonal
 //-----------------------------------------------------------------------------
 template<typename T>
 T Matrix<T>::trace() const
 {
   const INDEX N = std::min(nRows(),nCols());
   if (!N) return T(0);
   T r = (*this)(0,0);
   for (INDEX i=0; i<N; i++)
     r += (*this)(i,i);
   return r;
 }
 //-----------------------------------------------------------------------------
 //* Adds a matrix to this one
 template<typename T>
 Matrix<T>& Matrix<T>::operator+=(const Matrix &r) 
 {
   SSCK(*this, r, "operator+= or operator +");
   int sz=this->size(); for(INDEX i=0; i<sz; i++) (*this)[i]+=r[i];
   return *this;
 }
 //-----------------------------------------------------------------------------
 // subtracts a matrix from this one
 //-----------------------------------------------------------------------------
 template<typename T>
 Matrix<T>& Matrix<T>::operator-=(const Matrix &r) 
 {
   SSCK(*this, r, "operator-= or operator -");
   int sz=this->size(); for(INDEX i=0; i<sz; i++) (*this)[i]-=r[i];
   return *this;
 }
 //-----------------------------------------------------------------------------
 // multiplies each element in this by the corresponding element in R
 //-----------------------------------------------------------------------------
 
 template<typename T>
 Matrix<T>& Matrix<T>::operator*=(const Matrix<T>& R)
 {
   if ((R.nCols()==1) && (this->nCols()>1)) { // multiply every entry in a row by the same value
     int szi = this->nRows();
     int szj = this->nCols(); 
     for (INDEX i = 0; i < szi; i++) 
       for (INDEX j = 0; j < szj; j++)
         {
           (*this)(i,j) *= R[i];
         }
   }
   else if (((R.nCols()==R.size()) && (R.nRows()==R.size())) && !((this->nCols()==this->size()) && (this->nRows()==this->size()))){ 
     int szi = this->nRows();
     int szj = this->nCols(); 
     for (INDEX i = 0; i < szi; i++) 
       for (INDEX j = 0; j < szj; j++)
       {
           (*this)(i,j) *= R[i];
     }
   } 
   else { // multiply each entry by a different value
 
     int sz = this->size();
     for (INDEX i = 0; i < sz; i++) 
       {
         (*this)[i] *= R[i]; 
       }
   }
   return *this;
 }
 //-----------------------------------------------------------------------------
 // divides each element in this by the corresponding element in R
 //-----------------------------------------------------------------------------
 template<typename T>
 Matrix<T>& Matrix<T>::operator/=(const Matrix<T>& R)
 {
   if ((R.nCols()==1) && (this->nCols()>1)) { // divide every entry in a row by the same value
     int szi = this->nRows();
     int szj = this->nCols();
     for (INDEX i = 0; i < szi; i++)
       for (INDEX j = 0; j < szj; j++)
         {
           (*this)(i,j) /= R[i];
         }
   }
   else { // divide each entry by a different value
     SSCK(*this, R, "operator/= or operator/");
     int sz = this->size();
     for(INDEX i = 0; i < sz; i++) 
       {
         GCHK(fabs(R[i])==0,"Operator/: division by zero"); 
         (*this)[i] /= R[i]; 
       }
   }
   return *this;
 }
 //-----------------------------------------------------------------------------
 // divides each element in this by the corresponding element in R unless zero
 //-----------------------------------------------------------------------------
 template<typename T>
 Matrix<T>& Matrix<T>::divide_zero_safe(const Matrix<T>& R)
 {
   if ((R.nCols()==1) && (this->nCols()>1)) { // divide every entry in a row by the same value
     int szi = this->nRows();
     int szj = this->nCols();
     for (INDEX i = 0; i < szi; i++)
       for (INDEX j = 0; j < szj; j++)
         {
           if(fabs(R[i])!=0) {
             (*this)(i,j) /= R[i];
           }
         }
   }
   else { // divide each entry by a different value
     SSCK(*this, R, "operator/= or operator/");
     int sz = this->size();
     for(INDEX i = 0; i < sz; i++) 
       {
         if(fabs(R[i])!=0) {
           (*this)[i] /= R[i]; 
         }
       }
   }
   return *this;
 }
 //-----------------------------------------------------------------------------
 // scales this matrix by a constant
 //-----------------------------------------------------------------------------
 template<typename T>
 Matrix<T>& Matrix<T>::operator*=(const T v)       
 {
   int sz=this->size(); for(INDEX i=0; i<sz; i++) (*this)[i]*=v;      
   return *this;
 }
 //-----------------------------------------------------------------------------
 // adds a constant to this matrix 
 //-----------------------------------------------------------------------------
 template<typename T>
 Matrix<T>& Matrix<T>::operator+=(const T v)       
 {
   int sz=this->size(); for(INDEX i=0; i<sz; i++) (*this)[i]+=v;      
   return *this;
 }
 //-----------------------------------------------------------------------------
 // substracts a constant to this matrix 
 //-----------------------------------------------------------------------------
 template<typename T>
 Matrix<T>& Matrix<T>::operator-=(const T v)       
 {
   int sz=this->size(); for(INDEX i=0; i<sz; i++) (*this)[i]-=v;      
   return *this;
 }
 //-----------------------------------------------------------------------------
 //* scales this matrix by the inverse of a constant
 template<typename T>
 Matrix<T>& Matrix<T>::operator/=(T v)    
 {
   return (*this)*=(1.0/v);
 }
 
 //----------------------------------------------------------------------------
 // Assigns one matrix to another
 //----------------------------------------------------------------------------
 template<typename T>
 Matrix<T>& Matrix<T>::operator=(const Matrix<T> &r)
 {
   this->_set_equal(r);
   return *this;
 }
-//----------------------------------------------------------------------------
-// general matrix assignment (for densely packed matrices)
-//----------------------------------------------------------------------------
-template<typename T>
-void Matrix<T>::_set_equal(const Matrix<T> &r)
-{
-  this->resize(r.nRows(), r.nCols());
-  const Matrix<T> *pr = &r;
-  if (const SparseMatrix<T> *ps = sparse_cast(pr)) 
-    copy_sparse_to_matrix(ps, *this);
-  
-  else if (diag_cast(pr))  // r is Diagonal?
-  {
-    this->zero();
-    for (INDEX i=0; i<r.size(); i++) (*this)(i,i) = r[i];
-  }
-  else memcpy(this->ptr(), r.ptr(), r.size()*sizeof(T));
-}
 //-----------------------------------------------------------------------------
 //* sets all elements to a constant
 template<typename T>
 inline Matrix<T>& Matrix<T>::operator=(const T &v)    
 {
   set_all_elements_to(v); 
   return *this;
 }
 //-----------------------------------------------------------------------------
 //* sets all elements to a constant
 template<typename T>
 void Matrix<T>::set_all_elements_to(const T &v)    
 {
   int sz=this->size(); for(INDEX i=0; i<sz; i++) (*this)[i] = v;
 }
 //----------------------------------------------------------------------------
 // adds a matrix scaled by factor s to this one.
 //----------------------------------------------------------------------------
 template <typename T>
 void Matrix<T>::add_scaled(const Matrix<T> &A, const T& s)
 {
     SSCK(A, *this, "Matrix::add_scaled");
     int sz=this->size(); for(INDEX i=0; i<sz; i++) (*this)[i] += A[i]*s;
 }
 //-----------------------------------------------------------------------------
 //* writes a matlab command to the console
 template<typename T>
 void Matrix<T>::matlab(const std::string &s) const 
 {
   this->matlab(std::cout, s); 
 }
 //-----------------------------------------------------------------------------
 //* Writes a matlab script defining the vector to the stream
 template<typename T>
 void Matrix<T>::matlab(std::ostream &o, const std::string &s) const
 {
   o << s <<"=zeros(" << nRows() << ","<<nCols()<<");\n";
   int szi = this->nRows();
   int szj = this->nCols(); 
   for (INDEX i = 0; i < szi; i++)
     for (INDEX j = 0; j < szj; j++) 
       o << s << "("<<i+1<<","<<j+1<<")=" << (*this)(i,j) << ";\n";
 }
 //-----------------------------------------------------------------------------
 //* writes a mathematica command to the console
 template<typename T>
 void Matrix<T>::mathematica(const std::string &s) const 
 {
   this->mathematica(std::cout, s); 
 }
 //-----------------------------------------------------------------------------
 //* Writes a mathematica script defining the vector to the stream
 template<typename T>
 void Matrix<T>::mathematica(std::ostream &o, const std::string &s) const
 {
   o << s <<" = { \n";
   o.precision(15);
   o << std::fixed;
   for(INDEX i=0; i< nRows(); i++) {
     o <<" { " << (*this)(i,0);
     for(INDEX j=1; j< nCols(); j++) o << ", " << (*this)(i,j);
     if (i+1 == nRows()) { o <<" }  \n"; }
     else                { o <<" }, \n"; }
       
   }
   o << "};\n";
   o << std::scientific;
 }
 //-----------------------------------------------------------------------------
 //* sets all matrix elements to zero
 template<typename T>
 inline Matrix<T>& Matrix<T>::zero() 
 { 
   set_all_elements_to(T(0));
   return *this;
 }
 //-----------------------------------------------------------------------------
 //* sets to identity
 template<typename T>
 inline Matrix<T>& Matrix<T>::identity(int nrows) 
 { 
   if (nrows == 0) {
     SQCK(*this, "DenseMatrix::inv(), matrix not square"); // check matrix is square
     nrows = nRows();
   }
   reset(nrows,nrows);
   for(INDEX i=0; i< nRows(); i++) (*this)(i,i) = 1;
   return *this;
 }
 //-----------------------------------------------------------------------------
 //* returns the total number of elements
 template<typename T>
 inline INDEX Matrix<T>::size() const 
 { 
   return nRows()*nCols(); 
 }
 //-----------------------------------------------------------------------------
 //* returns true if (i,j) is within the range of the matrix
 template<typename T>
 inline bool Matrix<T>::in_range(INDEX i, INDEX j) const
 { 
   return i<nRows() && j<nCols(); 
 }
 //-----------------------------------------------------------------------------
 //* returns true if the matrix size is rs x cs
 template<typename T>
 inline bool Matrix<T>::is_size(INDEX rs, INDEX cs) const
 { 
   return nRows()==rs && nCols()==cs; 
 }
 //-----------------------------------------------------------------------------
 //* returns true if the matrix is square and not empty
 template<typename T>
 inline bool Matrix<T>::is_square() const
 { 
   return nRows()==nCols() && nRows(); 
 }
 //-----------------------------------------------------------------------------
 //* returns true if Matrix, m, is the same size as this
 template<typename T>
 inline bool Matrix<T>::same_size(const Matrix<T> &m) const
 {
   return is_size(m.nRows(), m.nCols());
 }
 //-----------------------------------------------------------------------------
 //* returns true if Matrix a and Matrix b are the same size
 template<typename T>
 inline bool Matrix<T>::same_size(const Matrix<T> &a, const Matrix<T> &b)
 {
   return a.same_size(b); 
 }
 //-----------------------------------------------------------------------------
 //* returns true if Matrix a rows =  Matrix b cols
 template<typename T>
 inline bool Matrix<T>::cols_equals_rows(const Matrix<T> &a, const Matrix<T> &b)
 {
   return a.nCols() == b.nRows(); 
 }
 //-----------------------------------------------------------------------------
 //* returns true if no value is outside of the range
 template<typename T>
 inline bool Matrix<T>::check_range(T min, T max) const
 {
   for (INDEX i = 0; i < this->nRows(); i++) {
     for (INDEX j = 0; j < this->nCols(); j++) {
       T val = (*this)(i,j);
       if ( (val > max) || (val < min) ) return false;
     }
   }
   return true;
 }
 //-----------------------------------------------------------------------------
 //* Displays indexing error message and quits
 template<typename T>
 void ierror(const Matrix<T> &a, const char *FILE, int LINE, INDEX i, INDEX j)
 {
   std::cout << "Error: Matrix indexing failure ";
   std::cout << "in file: " << FILE << ", line: "<< LINE <<"\n";
   std::cout << "Tried accessing index (" << i << ", " << j <<")\n";
   std::cout << "Matrix size was "<< a.nRows() << "x" << a.nCols() << "\n";
   ERROR_FOR_BACKTRACE
   exit(EXIT_FAILURE);
 }
 //-----------------------------------------------------------------------------
 //* Displays custom message and indexing error and quits
 template<typename T>
 void ierror(const Matrix<T> &a, INDEX i, INDEX j, const std::string m)
 {
   std::cout << m << "\n";
   std::cout << "Tried accessing index (" << i << ", " << j <<")\n";
   std::cout << "Matrix size was "<< a.nRows() << "x" << a.nCols() << "\n";
   ERROR_FOR_BACKTRACE
   exit(EXIT_FAILURE);
 }
 //-----------------------------------------------------------------------------
 //* Displays matrix compatibility error message
 template<typename T>
 void merror(const Matrix<T> &a, const Matrix<T> &b, const std::string m)
 {
   std::cout << "Error: " << m << "\n";
   std::cout << "Matrix sizes were " << a.nRows() << "x" << a.nCols();
   if (&a != &b) std::cout << ", and "<< b.nRows() << "x" << b.nCols();
   std::cout << "\n";
   if (a.size() < 100) a.print("Matrix");
   ERROR_FOR_BACKTRACE
   exit(EXIT_FAILURE);
 }
 
 //-----------------------------------------------------------------------------
 //* returns upper or lower half of a partitioned matrix
 //* A1 is the on-diagonal square matrix, A2 is the off-diagonal matrix
 //* rowsIn is the rows to be placed in A1
 //* rows is the map for A1, (rows,colsC) is the map for A2
 
 template <typename T>
 void Matrix<T>::row_partition(const std::set<int> & rowsIn, 
 std::set<int> & rows, std::set<int> & colsC,
 DenseMatrix<T> & A1, DenseMatrix<T> & A2, bool complement) const
 {
   if (complement) {
     for (INDEX i = 0; i < this->nRows();  i++) {
       if (rowsIn.find(i) == rowsIn.end() ) rows.insert(i);
     }
   }
   else  rows = rowsIn;
   // complement of set "rows" in set of this.cols is "cols"
   for (INDEX i = 0; i < this->nCols();  i++) {
     if (rows.find(i) == rows.end() ) colsC.insert(i);
   }
   // degenerate cases
   if      (int(rows.size()) == this->nCols()) {
     A1 = (*this);
     A2.reset(0,0);
     return;
   }
   else if (rows.size() == 0) {
     A1.reset(0,0);
     A2 = (*this);
     return;
   }
   // non-degenerate case
   int nrows  = rows.size();
   int ncolsC = colsC.size();
   A1.reset(nrows,nrows);
   A2.reset(nrows,ncolsC);
   std::set<int>::const_iterator itrI, itrJ;
   INDEX i =0;
   for (itrI = rows.begin(); itrI != rows.end(); itrI++) {
     INDEX j = 0;
     for (itrJ = rows.begin(); itrJ != rows.end(); itrJ++) {
       A1(i,j) = (*this)(*itrI,*itrJ);
       j++;
     }
     j = 0;
     for (itrJ = colsC.begin(); itrJ != colsC.end(); itrJ++) {
       A2(i,j) = (*this)(*itrI,*itrJ);
       j++;
     }
     i++;
   }
 }
 
 template <typename T>
 std::set<int> Matrix<T>::row_partition(const std::set<int> & rows, 
 DenseMatrix<T> & A1, DenseMatrix<T> & A2) const
 {
   // complement of set "rows" in set of this.cols is "cols"
   std::set<int> colsC;
   for (INDEX i = 0; i < this->nCols();  i++) {
     if (rows.find(i) == rows.end() ) colsC.insert(i);
   }
   // degenerate cases
   if      (int(rows.size()) == this->nCols()) {
     A1 = (*this);
     A2.reset(0,0);
     return colsC;
   }
   else if (rows.size() == 0) {
     A1.reset(0,0);
     A2 = (*this);
     return colsC;
   }
   // non-degenerate case
   int nrows  = rows.size();
   int ncolsC = colsC.size();
   A1.reset(nrows,nrows);
   A2.reset(nrows,ncolsC);
   std::set<int>::const_iterator itrI, itrJ;
   INDEX i =0;
   for (itrI = rows.begin(); itrI != rows.end(); itrI++) {
     INDEX j = 0;
     for (itrJ = rows.begin(); itrJ != rows.end(); itrJ++) {
       A1(i,j) = (*this)(*itrI,*itrJ);
       j++;
     }
     j = 0;
     for (itrJ = colsC.begin(); itrJ != colsC.end(); itrJ++) {
       A2(i,j) = (*this)(*itrI,*itrJ);
       j++;
     }
     i++;
   }
   return colsC;
 }
 
 //-----------------------------------------------------------------------------
 //* returns row & column mapped matrix
 template <typename T>
 void Matrix<T>::map(const std::set<int> & rows, const std::set<int> & cols, 
 DenseMatrix<T> & A ) const
 {
   if      (rows.size() == 0 || cols.size() == 0 ) {
     A.reset(0,0);
     return;
   }
   int nrows = rows.size();
   int ncols = cols.size();
   A.reset(nrows,ncols);
   std::set<int>::const_iterator itrI, itrJ;
   INDEX i =0;
   for (itrI = rows.begin(); itrI != rows.end(); itrI++) {
     INDEX j = 0;
     for (itrJ = cols.begin(); itrJ != cols.end(); itrJ++) {
       A(i,j) = (*this)(*itrI,*itrJ);
       j++;
     }
     i++;
   }
 }
 //-----------------------------------------------------------------------------
 //* inserts elements from a smaller matrix 
 template <typename T>
 void Matrix<T>::insert(const std::set<int> & rows, const std::set<int> & cols, 
 const DenseMatrix<T> & A ) 
 {
   if      (rows.size() == 0 || cols.size() == 0 )  return;
   std::set<int>::const_iterator itrI, itrJ;
   int i =0;
   for (itrI = rows.begin(); itrI != rows.end(); itrI++) {
     int j = 0;
     for (itrJ = cols.begin(); itrJ != cols.end(); itrJ++) {
       (*this)(*itrI,*itrJ) = A(i,j);
 //std::cout << *itrI << " " << *itrJ << " : " << (*this)(*itrI,*itrJ) << "\n";
       j++;
     }
     i++;
   }
 }
 //-----------------------------------------------------------------------------
 //* assemble elements from a smaller matrix 
 template <typename T>
 void Matrix<T>::assemble(const std::set<int> & rows, const std::set<int> & cols, 
 const DenseMatrix<T> & A ) 
 {
   if      (rows.size() == 0 || cols.size() == 0 )  return;
   std::set<int>::const_iterator itrI, itrJ;
   int i =0;
   for (itrI = rows.begin(); itrI != rows.end(); itrI++) {
     int j = 0;
     for (itrJ = cols.begin(); itrJ != cols.end(); itrJ++) {
       (*this)(*itrI,*itrJ) += A(i,j);
       j++;
     }
     i++;
   }
 }
 //-----------------------------------------------------------------------------
 
 } // end namespace
 
 #endif
diff --git a/lib/atc/MeshReader.cpp b/lib/atc/MeshReader.cpp
index 0ecb8f625..a50a19584 100644
--- a/lib/atc/MeshReader.cpp
+++ b/lib/atc/MeshReader.cpp
@@ -1,223 +1,226 @@
 #include "MeshReader.h"
 #include "LammpsInterface.h"
 #include "Utility.h"
 #ifdef HAS_EXODUS
 //#include <stdio.h> 
 //#include "netcdf.h" 
 #include "exodusII.h"
 #endif
 
 using ATC_Utility::to_string;
 using std::ifstream;
 using std::istringstream;
 using std::stringstream;
 using std::map;
 using std::pair;
 using std::set;
 using std::string;
 
 namespace ATC {
   /** constructor, takes a filename */
   MeshReader::MeshReader(string filename, 
                          Array<bool> periodicity, 
                          double tol)
     : meshfile_(filename),
       periodicity_(periodicity),
       nNodes_(0),
       nElements_(0),
       coordTol_(tol)
   {
     conn_ = new Array2D<int>();
     nodeCoords_ = new DENS_MAT;
     nodeSets_ = new Array< std::pair< string,set<int> > >();
 
     size_t idx = filename.rfind('.');
     if (idx == string::npos) {
       throw ATC_Error("Given mesh file is of unknown type.");
     }
 
     string ext = filename.substr(idx+1);
     
     if      (ext == "mesh"){ read_mesh_file(); }
     else { throw ATC_Error("mesh file is of unknown type."); }
   }
 
   /** destructor */
   MeshReader::~MeshReader()
   {
+    if (conn_) delete conn_;
+    if (nodeCoords_) delete nodeCoords_;
+    if (nodeSets_) delete nodeSets_;
   }
 
   /** creates handle to new mesh object */
   FE_Mesh* MeshReader::create_mesh()
   {
     return new FE_3DMesh(elementType_,
                          nNodes_, nElements_,
                          conn_, nodeCoords_,
                          periodicity_,
                          nodeSets_);
   }
 
   int MeshReader::number_of_vertices(string str)
   {
     string temp;
     int number=0;
     for (unsigned int i=0; i < str.size(); i++) {
       if (isdigit(str[i])) {
         for (unsigned int a=i; a<str.size(); a++) {
           temp += str[a];               
         }
         break;
       }
     }
     istringstream(temp) >> number;
     return number;
   }
 
 
   /** reads .mesh format file */
   void MeshReader::read_mesh_file() {
     ifstream in;
     in.open(meshfile_.c_str(), ifstream::in);
     string header;
     while (getline(in,header)) {
       istringstream words(header);
       string section;
       words >> section;
       if (section == "Coordinates") {
         words >> nNodes_;
         nodeCoords_->reset(3, nNodes_, false);
         string line;
         for (int i = 0; i < nNodes_; ++i) {
           getline(in,line);
           istringstream coords(line);
           coords >> (*nodeCoords_)(0, i);
           coords >> (*nodeCoords_)(1, i);
           coords >> (*nodeCoords_)(2, i);
         }
         stringstream ss;
         ss << "read " << nNodes_ << " nodes";
         ATC::LammpsInterface::instance()->print_msg_once(ss.str());
       }
       else if (section == "Elements") {
         words >> nElements_;
         words >> elementType_;
         int nVerts = number_of_vertices(elementType_);
         conn_->reset(nVerts, nElements_);
         string line;
         for (int i = 0; i < nElements_; ++i) {
           getline(in,line);
           istringstream verts(line);
           for (int j = 0; j < nVerts; ++j ) {
             int node;
             verts >> node;
             (*conn_)(j,i) = node-1;
           }
         }
         stringstream ss;
         ss << "read " << nElements_ << " " << elementType_ << " elements";
         ATC::LammpsInterface::instance()->print_msg_once(ss.str());
       }
       else if (section == "Nodesets") {
         words >> nNodeSets_;
         nodeSets_->reset(nNodeSets_);
         string infoline;
         string setName;
         int nNodes;
         string line;
         for (int i = 0; i < nNodeSets_; ++i) {
           getline(in,infoline);
           istringstream info(infoline);
           info >> setName;
           info >> nNodes;
           (*nodeSets_)(i).first = setName;
           getline(in,line);
           istringstream nodes(line);
           for (int j = 0; j < nNodes; ++j ) {
             int node;
             nodes >> node;
             (*nodeSets_)(i).second.insert(node-1);
           }
         }
       }
     }
     in.close();
     if (nodeCoords_->size() == 0) {
       throw ATC_Error("Could not find mesh file, or mesh file empty.");
     }
   }
 
   /** reads .exo format file */
   void MeshReader::read_exo_file() {
 #ifndef HAS_EXODUS
     throw ATC_Error("Reading ExodusII .exo files not supported."); 
 #else
     int CPU_word_size=0,IO_word_size=0;
     float version;
     int exoid = ex_open (meshfile_.c_str(), EX_READ, 
       &CPU_word_size, &IO_word_size, &version);
     if (exoid < 0) { throw ATC_Error("couldn't open "+meshfile_); }
     int nsd,nelemblk,nfsets;
     char title[MAX_LINE_LENGTH+1];
     int error = ex_get_init (exoid, title, 
       &nsd, &nNodes_, &nElements_, &nelemblk, &nNodeSets_, &nfsets);
     if (error > 0) { throw ATC_Error("problem with init "+meshfile_+" "+title); }
     // coordinates 
     float x[nNodes_], y[nNodes_], z[nNodes_];
     error = ex_get_coord (exoid, x, y, z);
     if (error > 0) { throw ATC_Error("problem with getting coordinates "+meshfile_); }
     nodeCoords_->reset(nsd,nNodes_);
     DENS_MAT & nodes = *nodeCoords_;
     for (int i = 0; i < nNodes_; ++i) {
       nodes(0,i) = x[i];  // this is a float to double conversion 
       nodes(1,i) = y[i];  // this is a float to double conversion 
       nodes(2,i) = z[i];  // this is a float to double conversion 
     }
     ATC::LammpsInterface::instance()->print_msg_once("read "+to_string(nNodes_)+
 " nodes");
     // elements
     int blkIds[nelemblk],nblkelem[nelemblk],nnpe[nelemblk],na[nelemblk];
     error = ex_get_elem_blk_ids(exoid, blkIds);
     char etype[MAX_STR_LENGTH+1];
     string lastType;
     for (int i=0; i<nelemblk; i++){ 
       error = ex_get_elem_block (exoid, blkIds[i], etype,
         &(nblkelem[i]), &(nnpe[i]), &(na[i]));
       elementType_ = etype;
       if (i > 0 && elementType_ != lastType )
         { throw ATC_Error(meshfile_+" is composed of multiple types"); }
       lastType = etype;
     }
     int nVerts = number_of_vertices(elementType_);
     conn_->reset(nVerts, nElements_);
     int n = 0;
     for (int i=0; i<nelemblk; i++) { 
       int bconn[nnpe[i]*nblkelem[i]];
       error = ex_get_elem_conn (exoid, blkIds[i], &bconn); 
       for (int j=0; j<nblkelem[i]; j++) { 
         for (int k=0; k<nnpe[i]; k++) { 
           (*conn_)(k,n) = bconn[k+j*nnpe[i]]-1;
         }
         n++;
       }
       ATC::LammpsInterface::instance()->print_msg_once("read "+to_string(n)+" "+elementType_+" elements, block "+to_string(i+1)+"/"+to_string(nelemblk));
     }
     // nodesets
     int nsetIds[nNodeSets_];
     error = ex_get_node_set_ids (exoid, nsetIds);
     int nnodes,ndist;
     //nodeSets_ = new Array< pair< string,set<int> > >();
     nodeSets_->reset(nNodeSets_);
     for (int i=0; i<nNodeSets_; i++) { 
       (*nodeSets_)(i).first = to_string(nsetIds[i]);
       error = ex_get_node_set_param (exoid, nsetIds[i], &nnodes, &ndist);
       int nodes[nnodes];
       error = ex_get_node_set (exoid, nsetIds[i], nodes);
       for (int j=0; j<nnodes; j++) { 
         (*nodeSets_)(i).second.insert(nodes[j]-1);
       }
     }
     error = ex_close(exoid);
     if (error > 0) { throw ATC_Error("problem with closing "+meshfile_); }
 #endif
   }
 }; // end namespace ATC
diff --git a/lib/atc/OutputManager.cpp b/lib/atc/OutputManager.cpp
index 586b4294f..414c5173e 100644
--- a/lib/atc/OutputManager.cpp
+++ b/lib/atc/OutputManager.cpp
@@ -1,889 +1,890 @@
 #include <string>
 #include <fstream>
 #include <stdio.h>
 #include <sstream>
 #include "OutputManager.h"
 #include "ATC_Error.h"
 #include "LammpsInterface.h"
 
 using std::ofstream;
 using std::stringstream;
 using std::ios_base;
 using std::setw;
 using std::string;
 using std::map;
 using std::vector;
 using std::set;
 
 namespace ATC {
 
 static const int kFieldPrecison = 12;
 static const int kFieldWidth = kFieldPrecison + 6;
 
 static const int kFileNameSize = 26; // HERE <<<<
 static string tensor_component_names[9] = {"11","12","13",
                                            "21","22","23", 
                                            "31","32","33"}; 
 static string sym_tensor_component_names[6] = {"11","22","33","12","13","23"}; 
 static string vector_component_names[3] = {"_X","_Y","_Z"}; 
 static string list_component_names[26] = {"_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","_q","_r","_s","_t","_u","_v","_w","_x","_y","_z"}; 
 
 string* get_component_names(int type) { // HERE <<<<
  string* componentNames = list_component_names;
  if (type==VECTOR_OUTPUT)
    componentNames = vector_component_names;
  else if (type == SYM_TENSOR_OUTPUT)
    componentNames = sym_tensor_component_names;
  else if (type == TENSOR_OUTPUT)
    componentNames = tensor_component_names;
  return componentNames;
 }
 
              
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 OutputManager::OutputManager(string outputPrefix, set<int> & otypes)
   : initialized_(false),
     firstStep_(true),
     firstGlobalsWrite_(true),
     writeGlobalsHeader_(true),
     coordinates_(NULL),
     connectivities_(NULL),
     dataType_(POINT),
     outputPrefix_(outputPrefix),
     ensightOutput_(otypes.count(ENSIGHT)),
     textOutput_(otypes.count(GNUPLOT)),
     fullTextOutput_(otypes.count(FULL_GNUPLOT)),
     vtkOutput_(otypes.count(VTK)),
     tensorToComponents_(false), // paraview does not support tensors
-    vectorToComponents_(false)
-    
+    vectorToComponents_(false),
+    warnTooManyCols_(true)
 {}
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 OutputManager::OutputManager()
   : initialized_(false),
     firstStep_(true),
     firstGlobalsWrite_(true),
     writeGlobalsHeader_(true),
     coordinates_(NULL),
     connectivities_(NULL),
     dataType_(POINT),
     outputPrefix_("NULL"),
     ensightOutput_(true),
     textOutput_(false),
     fullTextOutput_(false),
     vtkOutput_(false),
     tensorToComponents_(false), // paraview does not support tensors
     vectorToComponents_(false)
 {}
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 OutputManager::~OutputManager() {}
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 void OutputManager::set_option(OutputOption option, bool value) {
   if      (option == OUTPUT_VECTOR_COMPONENTS) vectorToComponents_ = value;
   else if (option == OUTPUT_TENSOR_COMPONENTS) tensorToComponents_ = value;
   else throw ATC_Error("unsupported output option");
 };
 
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 void OutputManager::initialize(string outputPrefix, set<int> & otypes) 
 { 
   if (outputPrefix_ !=  outputPrefix ) { // new stream with existing object
     outputPrefix_ =  outputPrefix;
     initialized_ = false;
   }
   outputTimes_.clear();
   if (otypes.count(ENSIGHT) > 0) ensightOutput_ = true;
   else                           ensightOutput_ = false;
   if (otypes.count(GNUPLOT) > 0) textOutput_ = true;
   if (otypes.count(FULL_GNUPLOT) > 0) fullTextOutput_ = true;
   if (otypes.count(VTK) > 0) vtkOutput_ = true;
   firstStep_ = true;
   firstGlobalsWrite_ = true;
   writeGlobalsHeader_ = true;
 }
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 void OutputManager::print_custom_names() {
   map<string,vector<string> >::const_iterator itr;
   string msg = "output custom names:\n";
   for (itr = fieldNames_.begin(); itr != fieldNames_.end(); itr++) {
     string stem = itr->first;
     vector<string> names = itr->second;
     for (unsigned int i = 0; i < names.size(); i++) {
       msg+= stem+" : "+names[i]+"\n";
     }
   }
   ATC::LammpsInterface::instance()->print_msg_once(msg);
 }
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 // Dump text-based fields to disk for later restart
 void OutputManager::write_restart_file(string fileName, RESTART_LIST *data)
 {
   FILE * fp=NULL;
   fp=fopen(fileName.c_str(),"wb"); // open
   RESTART_LIST::iterator iter;
   for (iter = data->begin(); iter != data->end(); iter++) {
     const MATRIX* field_data = iter->second;
     for (int i = 0; i < field_data->nRows(); ++i) {
       for (int j = 0; j < field_data->nCols(); ++j) {
         double x = (*field_data)(i,j);
         fwrite(&x,sizeof(double),1,fp);
       }
     }
   }
   fclose(fp);
 }
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 // Read a file corresponding to a write by write_restart_file
 
 void OutputManager::read_restart_file(string fileName, RESTART_LIST *data)
 {
   FILE * fp=NULL;
   fp=fopen(fileName.c_str(),"rb"); // open
   RESTART_LIST::iterator iter;
   for (iter = data->begin(); iter != data->end(); iter++) {
     MATRIX* field_data = iter->second;
     for (int i = 0; i < field_data->nRows(); ++i) {
       for (int j = 0; j < field_data->nCols(); ++j) {
         double myVal;
         fread(&myVal,sizeof(double),1,fp);
         (*field_data)(i,j) = myVal;  
     
       }
     }
   }
   fclose(fp);
 }
 //-----------------------------------------------------------------------------
 //*
 //-----------------------------------------------------------------------------
 void OutputManager::write_globals(void) 
 {
   if ( outputPrefix_ == "NULL") return;
   string file = outputPrefix_ + ".GLOBALS";
   ofstream text;
   if ( firstGlobalsWrite_ ) text.open(file.c_str(),ios_base::out);
   else                      text.open(file.c_str(),ios_base::app);
   firstGlobalsWrite_ = false;
 
   map<string, double>::iterator iter;
   // header
   if ( firstStep_ || writeGlobalsHeader_) {
     text << "# time:1 ";
     int index = 2;
     for (iter = globalData_.begin(); iter != globalData_.end(); iter++) 
     {
       string name  = iter->first;
       string str; stringstream out; out << ":" << index++; 
       str = out.str();
       name.append(str);
       text.width(kFieldWidth); text << name << " ";
     }
     text << '\n';
   }
   writeGlobalsHeader_ = false;
   // data
   text.width(kFieldWidth); text << outputTimes_[outputTimes_.size()-1] << " ";
   for (iter = globalData_.begin(); 
        iter != globalData_.end(); iter++) {
     double value = iter->second;
     text << setw(kFieldWidth) << std::scientific << std::setprecision(kFieldPrecison) << value << " ";
   }
   text << "\n";
 }
 //-----------------------------------------------------------------------------
 //* 
 //-----------------------------------------------------------------------------
 void OutputManager::write_geometry(const MATRIX *coordinates, 
                                    const Array2D<int> *connectivities)
 {
   if ( outputPrefix_ == "NULL") throw ATC_Error( "No outputPrefix given."); 
  
   number_of_nodes_ = coordinates->nCols();
   coordinates_ = coordinates;
   connectivities_ = connectivities;
   if (ensightOutput_) write_geometry_ensight();
   if (textOutput_)    write_geometry_text();
   initialized_ = true;
 }
 //-----------------------------------------------------------------------------
 //* 
 //-----------------------------------------------------------------------------
 void OutputManager::write_geometry_ensight(void)
 {
   // geometry based on a reference configuration
   string geom_file_name = outputPrefix_ + ".geo";
 
   // open file
   FILE * fp=NULL;
   char buffer[80];
   if ( ! initialized_ ) {
     fp=fopen(geom_file_name.c_str(),"wb"); // open
     strcpy(buffer,"C Binary");
     fwrite(buffer,sizeof(char),80,fp);
   }
   else {
     fp=fopen(geom_file_name.c_str(),"ab"); // append
   }
   if (fp == NULL) {
     throw ATC_Error("can not create Ensight geometry file");
   }
 
   // write preamble
   strcpy(buffer,"BEGIN TIME STEP");
   fwrite(buffer,sizeof(char),80,fp);
   strcpy(buffer,"Ensight geometry file");
   fwrite(buffer,sizeof(char),80,fp);
   strcpy(buffer,"description");
   fwrite(buffer,sizeof(char),80,fp);
   strcpy(buffer,"node id assign");
   fwrite(buffer,sizeof(char),80,fp);
   strcpy(buffer,"element id assign");
   fwrite(buffer,sizeof(char),80,fp);
 
   // per part
   strcpy(buffer,"part");
   fwrite(buffer,sizeof(char),80,fp);
   int part_number=1;
   fwrite(&part_number,sizeof(int),1,fp);
   strcpy(buffer,"description");
   fwrite(buffer,sizeof(char),80,fp);
   const MATRIX & coordinates = *coordinates_;
   // write coordinates
   strcpy(buffer,"coordinates");
   fwrite(buffer,sizeof(char),80,fp);
   fwrite(&number_of_nodes_,sizeof(int),1,fp);
    
   int number_of_spatial_dimensions = coordinates.nRows();
   if (number_of_spatial_dimensions != 3) 
     throw ATC_Error("Ensight writer needs a 3D geometry");
 
   for (int i = 0; i < number_of_spatial_dimensions; ++i) 
   {
     for (int j = 0; j < number_of_nodes_; ++j) 
     {
       float x = (float) coordinates(i,j);
       fwrite(&x,sizeof(float),1,fp);
     }
   }
 
   // write mesh connectivities or point "connectivities"
   if (connectivities_) 
   { 
     dataType_ = MESH;
     int nodes_per_element = connectivities_->nRows();
     if      (nodes_per_element == 4) { strcpy(buffer,"tetra4"); }
     else if (nodes_per_element == 8) { strcpy(buffer,"hexa8"); }
     else if (nodes_per_element == 20) { strcpy(buffer,"hexa20"); }
     else if (nodes_per_element == 27) { strcpy(buffer,"hexa27"); }
     else 
       throw ATC_Error("Ensight writer does not recoginize element type");
     fwrite(buffer,sizeof(char),80,fp);
     int number_of_elements = connectivities_->nCols();
     fwrite(&number_of_elements,sizeof(int),1,fp);
     int number_of_nodes_per_element = connectivities_->nRows();
     for (int j = 0; j < number_of_elements; ++j) 
     {
       for (int i = 0; i < number_of_nodes_per_element; ++i) 
       {
         int inode = (*connectivities_)(i,j) +1; // 1 based numbering
         fwrite(&inode,sizeof(int),1,fp);
       }
     }
   } 
   else 
   {
     strcpy(buffer,"point");
     fwrite(buffer,sizeof(char),80,fp);
     int number_of_elements = number_of_nodes_;
     fwrite(&number_of_elements,sizeof(int),1,fp);
     for (int j = 0; j < number_of_elements; ++j)  
     {
       int inode = j +1; // 1 based numbering
       fwrite(&inode,sizeof(int),1,fp);
     }
   }
 
   // end per part
   strcpy(buffer,"END TIME STEP");
   fwrite(buffer,sizeof(char),80,fp);
   fclose(fp);
 }
 //-----------------------------------------------------------------------------
 //* 
 //-----------------------------------------------------------------------------
 void OutputManager::write_geometry_text(void)
 {
   if ( outputPrefix_ == "NULL") return;
   // geometry based on a reference configuration
   string geom_file_text = outputPrefix_ + ".XYZ";
 
   // open file
   ofstream text;
   text.open(geom_file_text.c_str(),ios_base::out);
   if (connectivities_) 
   { 
     int number_of_elements = connectivities_->nCols();
     int number_of_nodes_per_element = connectivities_->nRows();
     for (int j = 0; j < number_of_elements; ++j) 
     {
       text << "#";
       for (int i = 0; i < number_of_nodes_per_element; ++i) 
       {
         int inode = (*connectivities_)(i,j) +1; // 1 based numbering
           text << setw(6) << inode;
       }
       text << "\n";
     }
   }
 
   const MATRIX & coordinates = *coordinates_;
   int number_of_spatial_dimensions = coordinates.nRows();
   for (int j = 0; j < number_of_nodes_; ++j) 
   {
     text << setw(6) << j+1 << " ";
     for (int i = 0; i < number_of_spatial_dimensions; ++i) 
     {
       text << setw(kFieldWidth) << std::scientific << std::setprecision(kFieldPrecison) << coordinates(i,j) << " ";
     }
     text << "\n";
   }
   text << "\n";
 }
 //-----------------------------------------------------------------------------
 /** pack "soln" into data */
 //-----------------------------------------------------------------------------
 void OutputManager::write_data(double time, FIELDS *soln, OUTPUT_LIST *data, const int *node_map) 
 {
   // pack
   OUTPUT_LIST combined_data;  
   if (soln) 
   {
     FIELDS::iterator iter;
     for (iter = soln->begin(); iter != soln->end(); iter++) 
     {
       FieldName field_index = iter->first;
       MATRIX* field_data = &((iter->second).set_quantity());  
       string field_name = field_to_string(field_index);
       combined_data[field_name] = field_data;
     }
   }
   if (data) 
   {
     OUTPUT_LIST::iterator iter;
     for (iter = data->begin(); iter != data->end(); iter++) 
     {
       string field_name = iter->first;
       const MATRIX* field_data = iter->second;
       combined_data[field_name] = field_data;
     }
   }
   write_data(time, &(combined_data), node_map);
 };
 //-----------------------------------------------------------------------------
 /** write data  */
 //-----------------------------------------------------------------------------
 void OutputManager::write_data(double time, OUTPUT_LIST *data, const int *node_map)
 {
   if (! initialized_) {
     throw ATC_Error("must write geometry before data");
   }
 
   // store the time step value
   outputTimes_.push_back(time);
 
   if (ensightOutput_) {
     // write data
     OUTPUT_LIST::iterator iter;
     for (iter = data->begin(); iter != data->end(); iter++) 
     {
       string field_name = iter->first;
       const MATRIX* field_data = iter->second;
       write_data_ensight(field_name, field_data, node_map);
     }
     // write dictionary
     write_dictionary(time,data);
   }
 
   // write text dump
   if (textOutput_) {
     write_data_text(data); 
     if (firstStep_ && node_map) {
       string map_file_text = outputPrefix_ + ".MAP";
       ofstream text;
       text.open(map_file_text.c_str(),ios_base::out);
       for (int i=0; i< number_of_nodes_ ; i++) {
         text << node_map[i] << "\n";
       }
       text.close();
     }
   }
   else if (fullTextOutput_) {
     write_data_text(data,node_map); 
   }
   if (vtkOutput_) {
     write_data_vtk(data); 
   }
 
   // global variables
   if (! globalData_.empty()) write_globals();
 
   if (firstStep_) firstStep_ = false;
 }
 //-----------------------------------------------------------------------------
 /** write (ensight gold format "C" binary) data  */
 // use "ens_checker" to check binary format
 //-----------------------------------------------------------------------------
 void OutputManager::write_data_ensight(string field_name, const MATRIX *field_data, const int *node_map)
 {
   int ndof = field_data->nCols();
   int col_start = 0;
   int col_end   = ndof;
   string filenames[kFileNameSize];
   int nfiles = 1;
   filenames[0] = outputPrefix_ + "." + field_name;
   int type = data_type(ndof);
   if (use_component_names(type)){
     nfiles = ndof;
     if (nfiles > kFileNameSize) {
-      if (ATC::LammpsInterface::instance()->rank_zero()) {
+      if (warnTooManyCols_ && ATC::LammpsInterface::instance()->rank_zero()) {
+        warnTooManyCols_ = false;
         stringstream ss;
-        ss << " only writing " << kFileNameSize
+        ss << "WARNING: only writing " << kFileNameSize
            << " components of " <<  field_name << " which has " << ndof;
         ATC::LammpsInterface::instance()->print_msg(ss.str());
       }
       nfiles =  kFileNameSize;
     }
     string* component_names = get_component_names(type);
     for (int ifile = 0; ifile < nfiles; ++ifile) 
     {
       string comp_name;
       if (! custom_name(field_name,ifile,comp_name))
         comp_name = field_name + component_names[ifile];
       filenames[ifile] = outputPrefix_ + "." + comp_name;
     }
   }
 
   for (int ifile = 0; ifile < nfiles; ++ifile) 
   {
     // for vector/tensor to components
     if ( nfiles > 1 ) 
     { 
       col_start = ifile;   
       col_end   = ifile+1;   
     }
  
     // open or append data file
     string data_file_name = filenames[ifile];
     FILE * fp=NULL;
     if ( outputTimes_.size() == 1 ) {
       fp=fopen(data_file_name.c_str(),"wb"); // open
     }
     else {
       fp=fopen(data_file_name.c_str(),"ab"); // append
     }
     if (fp == NULL) {
       throw ATC_Error("can not create Ensight data file: "+data_file_name);
     }
   
     // write data
     char buffer[80];
     strcpy(buffer,"BEGIN TIME STEP");
     fwrite(buffer,sizeof(char),80,fp);
     strcpy(buffer,"field name"); 
     fwrite(buffer,sizeof(char),80,fp);
 
     // per part
     strcpy(buffer,"part");
     fwrite(buffer,sizeof(char),80,fp);
     int part_number = 1;
     fwrite(&part_number,sizeof(int),1,fp);
     strcpy(buffer,"coordinates");
     fwrite(buffer,sizeof(char),80,fp);
     if (node_map) 
     {
       for (int j = col_start; j < col_end; ++j) 
       {
         for (int i = 0; i < number_of_nodes_; ++i) 
         {
           int inode = node_map[i];
           float x = (float) (*field_data)(inode,j);
           fwrite(&x,sizeof(float),1,fp);
         }
       }
     } 
     else 
     {
       for (int j = col_start; j < col_end; ++j)  
       {
         for (int i = 0; i < field_data->nRows(); ++i) 
         {
           float x = (float) (*field_data)(i,j);
           fwrite(&x,sizeof(float),1,fp);
         }
       }
     }
     // end per part
 
     strcpy(buffer,"END TIME STEP");
     fwrite(buffer,sizeof(char),80,fp);
     fclose(fp);
   }
 }
 
 //-----------------------------------------------------------------------------
 /** write data dict for both text & full_text */
 //-----------------------------------------------------------------------------
 void OutputManager::write_text_data_header(OUTPUT_LIST *data, ofstream & text, int k)
 {
     if (data) 
     {
       OUTPUT_LIST::iterator iter;
       for (iter = data->begin(); iter != data->end(); iter++) 
       {
         string field_name = iter->first;
         int nrows = iter->second->nRows();
         if (!(nrows>0)) {
           string msg = field_name + " does not have data for output";
           throw ATC_Error(msg);
         }
         int ncols = iter->second->nCols();
         if (ncols > kFileNameSize) {
           if (ATC::LammpsInterface::instance()->rank_zero()) {
             stringstream ss;
             ss << " only writing " << kFileNameSize
                << " components of " <<  field_name << " which has " << ncols;
             ATC::LammpsInterface::instance()->print_msg(ss.str());
           }
           ncols =  kFileNameSize;
         }
         if (ncols == 1) {
           string name = field_name;
           custom_name(field_name,0,name);
           string str; stringstream out; out <<":"<<k; str = out.str();
           name.append(str);
           text.width(kFieldWidth); text << name << " ";
           k++;
         }
         else {
           for (int i = 1; i <= ncols; i++) {
             string name = field_name;
             string str; stringstream out; 
             if (! custom_name(field_name,i-1,name)) { out <<"_"<<i; }
             out <<":"<<k; str = out.str();
             name.append(str);
             text.width(kFieldWidth); text << name << " ";
             k++;
           }
         }
       }
     } else { throw ATC_Error(" data missing from output");}
     text << "\n";
 }
 
 //-----------------------------------------------------------------------------
 /** write data  in text format */
 //-----------------------------------------------------------------------------
 void OutputManager::write_data_text(OUTPUT_LIST *data)
 {
   string data_file_text = outputPrefix_ + ".DATA";
   ofstream text;
   if  (firstStep_) text.open(data_file_text.c_str(),ios_base::out);
   else text.open(data_file_text.c_str(),ios_base::app);
 
   // write data label header
   if (firstStep_) 
   {
     text.width(6); text << "# index:1" << " "; // give an ordinate for gnuplot
     text.width(10); text << " step:2" << " "; 
     write_text_data_header(data,text,3);
   }
   text << "# timestep " << outputTimes_.size() << " : "
        << outputTimes_[outputTimes_.size()-1]  << "\n";
   
   int nrows = 0;
   OUTPUT_LIST::iterator iter;
   iter = data->begin();
   if (iter == data->end()) { throw ATC_Error(" no data in output");}
   const MATRIX* field_data = iter->second;
   nrows = field_data->nRows();
 
   for (int i = 0; i < nrows; ++i) 
   {
     text.width(6); text << i << " "; // give an ordinate for gnuplot
     text.width(10); text << outputTimes_.size() << " "; 
     OUTPUT_LIST::iterator iter;
     for (iter = data->begin(); iter != data->end(); iter++) 
     {
       const MATRIX* field_data = iter->second;
       int ncols = field_data->nCols();
       if (ncols > kFileNameSize) { ncols = kFileNameSize;}
       for (int j = 0; j < ncols; ++j) 
       {
         text.width(kFieldWidth); 
         text << setw(kFieldWidth) << std::scientific << std::setprecision(kFieldPrecison) << (*field_data)(i,j) << " ";
       }
     }
     text <<"\n";
   }
   text <<"\n";
 }
 
 //-----------------------------------------------------------------------------
 /** write data  in full text format */
 //-----------------------------------------------------------------------------
 void OutputManager::write_data_text(OUTPUT_LIST *data, const int *node_map)
 {
   string data_file_text = outputPrefix_ + ".DATA";
   ofstream text;
   if  (firstStep_) text.open(data_file_text.c_str(),ios_base::out);
   else text.open(data_file_text.c_str(),ios_base::app);
 
   // write data label header
   if (firstStep_) 
   {
     text.width(6); text << "# index:1" << " "; 
     text.width(6); text << " id:2" << " "; 
     text.width(10); text << " step:3" << " "; 
     text.width(4); text << " x:4" << " "; 
     text.width(4); text << " y:5" << " "; 
     text.width(4); text << " z:6" << " "; 
     write_text_data_header(data,text,7);
 
     if (connectivities_) 
     { 
       int number_of_elements = connectivities_->nCols();
       int number_of_nodes_per_element = connectivities_->nRows();
       text << "# connectivities  number_of_elements: " << number_of_elements 
            << " nodes_per_element: " << number_of_nodes_per_element << "\n"; 
       for (int j = 0; j < number_of_elements; ++j) 
       {
         text << "#";
         for (int i = 0; i < number_of_nodes_per_element; ++i) 
         {
           int inode = (*connectivities_)(i,j) +1; // 1 based numbering
               text << setw(6) << inode;
         }
         text << "\n";
       }
     }
   }
   text << "# timestep " << outputTimes_.size() << " : "
        << outputTimes_[outputTimes_.size()-1]  << "\n";
   
   OUTPUT_LIST::iterator iter;
   iter = data->begin();
   if (iter == data->end()) { throw ATC_Error(" no data in output");}
   int nnodes = coordinates_->nCols();
 
   for (int i = 0; i < nnodes; ++i) 
   {
     int unode = i;
     if (node_map) unode = node_map[i];
     text.width(6); text << i << " "; 
     text.width(6); text << unode << " "; 
     text.width(10); text << outputTimes_.size() << " "; 
     // coordinates
     for (int j = 0; j < coordinates_->nRows(); ++j) {
       text.width(kFieldWidth); 
       text << setw(kFieldWidth) << std::scientific << std::setprecision(kFieldPrecison) << (*coordinates_)(j,i) << " ";
     }
     // data
     OUTPUT_LIST::iterator iter;
     for (iter = data->begin(); iter != data->end(); iter++) 
     {
       const MATRIX* field_data = iter->second;
       int ncols = field_data->nCols();
       if (ncols > kFileNameSize) { ncols = kFileNameSize; }
       for (int j = 0; j < ncols; ++j) 
       {
         text.width(kFieldWidth); 
         text << setw(kFieldWidth) << std::scientific << std::setprecision(kFieldPrecison) << (*field_data)(unode,j) << " ";
       }
     }
     text <<"\n";
   }
   text <<"\n";
 }
 
 //-----------------------------------------------------------------------------
 /** write data  in vtk text format */
 //-----------------------------------------------------------------------------
 void OutputManager::write_data_vtk(OUTPUT_LIST *data)
 {
   string data_file_text = outputPrefix_ + ".vtk";
   ofstream text;
   if  (firstStep_) text.open(data_file_text.c_str(),ios_base::out);
   else throw ATC_Error(" vtk format can not handle multiple steps");
   text << "# vtk DataFile Version 3.0\n";
   text << "# " << outputPrefix_ << "\n";
   text << "ASCII\n";
   text << "DATASET UNSTRUCTURED_GRID\n";
   // geometry
   int nnodes = coordinates_->nCols();
   text << "POINTS " << nnodes << " float\n";
   for (int i = 0; i < nnodes; ++i) {
     for (int j = 0; j < coordinates_->nRows(); ++j) {
       text.width(kFieldWidth); 
       text << setw(kFieldWidth) << std::scientific << std::setprecision(kFieldPrecison) << (*coordinates_)(j,i) << " ";
     }
     text << "\n";
   }
   text << "\n";
   int nelems = connectivities_->nCols();
   int nodes_per_element = connectivities_->nRows();
   text << "CELLS " << nelems << " " << nelems*(nodes_per_element+1) << "\n";
   for (int j = 0; j < nelems; ++j) {
     text << setw(6) << nodes_per_element;
     for (int i = 0; i < nodes_per_element; ++i) {
        int inode = (*connectivities_)(i,j); // 0 based numbering
        text << setw(6) << inode;
     }
     text << "\n";
   }
   text << "\n";
   int cell_type = 4 ; 
   text << "CELL_TYPES " << nelems << "\n";
   for (int j = 0; j < nelems; ++j) {
     text << cell_type << "\n";
   }
   text << "\n";
   // data
   text << "POINT_DATA " << nnodes << "\n";
   text << "\n";
   OUTPUT_LIST::iterator iter;
   for (iter = data->begin(); iter != data->end(); iter++) 
   {
     string field_name = iter->first;
     const MATRIX* field_data = iter->second;
     int ncols = field_data->nCols();
     if (ncols == 1) { 
       text << "SCALARS " << field_name << " float\n";
       text << "LOOKUP_TABLE default\n";
     }
     else {
       text << "VECTORS " << field_name << " float\n";
     }
     for (int i = 0; i < nnodes; ++i) {
       for (int j = 0; j < ncols; ++j) {
         text.width(kFieldWidth); 
         text << setw(kFieldWidth) << std::scientific << std::setprecision(kFieldPrecison) << (*field_data)(i,j) << " ";
       }
       text <<"\n";
     }
   }
   text <<"\n";
 }
 
 /** write (ensight gold : ASCII "C" format) dictionary */
 void OutputManager::write_dictionary(double time, OUTPUT_LIST *data)
 {
   // file names
   string dict_file_name = outputPrefix_ + ".case";
   string geom_file_name = outputPrefix_ + ".geo";
   
   // open file
   FILE * fp=NULL;
   if ((fp=fopen(dict_file_name.c_str(),"w")) == NULL) 
   {
     throw ATC_Error("can not create Ensight case file");
   }
 
   // write file
   fprintf(fp,"FORMAT\n");
   fprintf(fp,"type: ensight gold\n");
   fprintf(fp,"GEOMETRY\n");
   if ( dataType_ == POINT) {
     fprintf(fp,"model: 1 1 %s change_coords_only\n", geom_file_name.c_str());
   } else {
     fprintf(fp,"model: %s\n", geom_file_name.c_str());
   }
   fprintf(fp,"VARIABLE\n");
 
   // data types
   if (!data) throw ATC_Error("no data for output");
   OUTPUT_LIST::iterator iter;
   int ncols = 0;
   for (iter = data->begin(); iter != data->end(); iter++) {
     string field_name = iter->first;
     string field_file = outputPrefix_ + "." + field_name;
     const MATRIX* field_data = iter->second;
     int fieldCols = field_data->nCols();
     ncols += fieldCols;
     int type = data_type(fieldCols);
     if (use_component_names(type)){
       string* component_names = get_component_names(type);
       int ndof = fieldCols;
       if (ndof > kFileNameSize) ndof = kFileNameSize;
       for (int j = 0; j < ndof; ++j) 
       {
         string comp_name;
         if (! custom_name(field_name,j,comp_name))
         comp_name = field_name + component_names[j];
         string comp_file = outputPrefix_ + "." + comp_name;
         fprintf(fp,"scalar per node: 1 1 %s %s\n",
           comp_name.c_str(),comp_file.c_str());
       }
     }
     else if (type == VECTOR_OUTPUT) {
       fprintf(fp,"vector per node: 1 1 %s %s\n",
         field_name.c_str(),field_file.c_str());
     } 
     else if (type == SYM_TENSOR_OUTPUT) {
       fprintf(fp,"tensor symm per node: 1 1 %s %s\n",
         field_name.c_str(),field_file.c_str());
     } 
     else if (type == TENSOR_OUTPUT) {
       fprintf(fp,"tensor asymm per node: 1 1 %s %s\n",
         field_name.c_str(),field_file.c_str());
     } 
     else {
       fprintf(fp,"scalar per node: 1 1 %s %s\n",
         field_name.c_str(),field_file.c_str());
     }
   }
 
   if (!firstStep_ && ncols != nDataCols_) {
     throw ATC_Error("number of columns of data has changed: start new output");
   }
   nDataCols_ = ncols;
 
   int nsteps = outputTimes_.size();
   fprintf(fp,"TIME\n");
   fprintf(fp,"time set: 1\n");
   fprintf(fp,"number of steps: %10d\n",nsteps);
   if ( dataType_ == POINT) {
     fprintf(fp,"filename start number: 0\n");
     fprintf(fp,"filename increment: 1\n");
   }
   fprintf(fp,"time values:\n");
   for (int j = 0; j < nsteps; ++j) {
     double t = outputTimes_[j];
     fprintf(fp,"%12.5e",t);
     if ((j+1)%6 == 0) fprintf(fp,"\n");
   }
   fprintf(fp,"\n");
   fprintf(fp,"FILE\n");
   fprintf(fp,"file set: 1\n");
   fprintf(fp,"number of steps: %10d\n",nsteps);
   fclose(fp);
 };
 
 } // end ATC namespace
 
 
diff --git a/lib/atc/OutputManager.h b/lib/atc/OutputManager.h
index f63780b77..c5a901e9f 100644
--- a/lib/atc/OutputManager.h
+++ b/lib/atc/OutputManager.h
@@ -1,145 +1,147 @@
 #ifndef OUTPUT_MANAGER_H
 #define OUTPUT_MANAGER_H
 
 #include "ATC_TypeDefs.h"
 #include <map>
 #include <vector>
 #include <string>
 #include <set>
 
 
 // 1 -> scalar
 // 3 -> vector  x,y,z
 // NOT 6 -> tensor  xx,xy,xz,yy,yz,zz
 // 6 -> tensor  xx,yy,zz,xy,zx,yz
 // 9 -> tensor  xx,xy,xz,yx,yy,yz,zx,zy,zz
 
 namespace ATC {
 
   enum OutputType     { ENSIGHT=0, GNUPLOT, FULL_GNUPLOT, VTK };
   enum OutputDataType { POINT=0, MESH };
   enum OutputDataCardinality { SCALAR_OUTPUT=0, VECTOR_OUTPUT, TENSOR_OUTPUT, 
     SYM_TENSOR_OUTPUT, LIST_OUTPUT };
   enum OutputOption   { OUTPUT_VECTOR_COMPONENTS=0, OUTPUT_TENSOR_COMPONENTS};
 
   /**
    *  @class  OutputManager 
    *  @brief  Base class for handling output desired from an AtC computation 
    */
 
   class OutputManager{
 
   public:
     OutputManager(void);
     OutputManager(std::string outputPrefix, std::set<int> &otypes);
     ~OutputManager(void);
 
     /** initialize output */
     void initialize(std::string outputPrefix, std::set<int> &otypes);
 
     /** set output options */
     void set_option(OutputOption option, bool value); 
 
     // Dump text-based field info to disk for later restart
     void write_restart_file(std::string fileName, RESTART_LIST *data);
 
     // Read text-based field file written from write_restart_file
     void read_restart_file(std::string fileName, RESTART_LIST *data);
 
     /** write initial/reference geometry
         default is to write point data, 
         if connectivities are given then mesh data will be output 
         coordinates : num _total_ points/nodes X num spatial dim 
         connectivities : num elements X num nodes per element*/
     void write_geometry(const MATRIX *coordinates,
                         const Array2D<int> *connectivity=NULL);
 
     /** write data from a time step
         specify node_map to handle periodic soln & data */
     void write_data(double time, OUTPUT_LIST *data, const int *node_map=NULL);
     void write_data(double time, FIELDS *soln, OUTPUT_LIST *data, 
       const int *node_map=NULL);
 
     /** add custom names for any field */
     void add_field_names(const std::string& name, const std::vector<std::string>& list) {
       fieldNames_[name] = list; }
     /** add a scalar to a text output file */
     void add_global(const std::string& name, const double& value) {
       globalData_[name] = value; }
 
     /** delete a scalar from the output */
     void delete_global(const std::string& name) { globalData_.erase(name); }
 
     /** reset the stored output scalars */
     void reset_globals() { globalData_.clear(); writeGlobalsHeader_=true; }
 
     /** return data type: scalar, vector, tensor, list */
     int data_type(const DENS_MAT & data) const {
       return data_type(data.nCols());
     }
     int data_type(int cols) const {
       if      (cols == 1) return SCALAR_OUTPUT;
       else if (cols == 3) return VECTOR_OUTPUT;
       else if (cols == 6) return SYM_TENSOR_OUTPUT;
       else if (cols == 9) return TENSOR_OUTPUT;
       else                return LIST_OUTPUT;
     }
     bool use_component_names(int type) const {
       if ( (type==LIST_OUTPUT) ||     
        ((type==SYM_TENSOR_OUTPUT || type==TENSOR_OUTPUT) && tensorToComponents_)
       || (type==VECTOR_OUTPUT && vectorToComponents_) ) 
         return true;
       else 
         return false;
     }
     bool custom_name(const std::string field, const int index, std::string & name) const {
       std::map<std::string,std::vector<std::string> >::const_iterator itr = fieldNames_.find(field);
       if (itr == fieldNames_.end()) return false;
       std::vector<std::string>  names = itr->second;
       name = names[index];
       return true;
     }
     void print_custom_names(); 
 
   private:
 
     void write_geometry_ensight(void);
     void write_geometry_text(void);
     void write_data_ensight(std::string name, const MATRIX *data, const int *node_map);
     void write_text_data_header(OUTPUT_LIST *data, std::ofstream & text, int k);
     void write_data_text(OUTPUT_LIST *data);
     void write_data_text(OUTPUT_LIST *data, const int *node_map);
     void write_data_vtk(OUTPUT_LIST *data);
     void write_dictionary(double time, OUTPUT_LIST *data);
     void write_globals();
 
     /** status flags */
     bool initialized_, firstStep_, firstGlobalsWrite_, writeGlobalsHeader_;
 
     /** custom field names */
     std::map<std::string,std::vector<std::string> > fieldNames_;
 
     /**  pointers to mesh data */
     const MATRIX * coordinates_;
     const Array2D<int> * connectivities_;
     /** number of columns of data */
     int nDataCols_;
     /** number of nodes */ 
     int number_of_nodes_; 
     /** data type */
     int dataType_;
     /** base name for output files */
     std::string outputPrefix_;
     /** list of output timesteps */
     std::vector<double> outputTimes_;
     /** output type flags */
     bool ensightOutput_,textOutput_,fullTextOutput_,vtkOutput_;
     /** output tensor as its components */
     bool tensorToComponents_;
     /** output vector as its components */
     bool vectorToComponents_;
+    /** warn once flags */
+    bool warnTooManyCols_;
     /** global variables */
     std::map<std::string,double> globalData_;
   };
 }
 #endif
diff --git a/lib/atc/POEMSChain.h b/lib/atc/POEMSChain.h
new file mode 100644
index 000000000..7dc143a9d
--- /dev/null
+++ b/lib/atc/POEMSChain.h
@@ -0,0 +1,73 @@
+/*
+ *_________________________________________________________________________*
+ *      POEMS: PARALLELIZABLE OPEN SOURCE EFFICIENT MULTIBODY SOFTWARE     *
+ *      DESCRIPTION: SEE READ-ME                                           *
+ *      FILE NAME: PoemsChain.h                                            *
+ *      AUTHORS: See Author List                                           * 
+ *      GRANTS: See Grants List                                            *
+ *      COPYRIGHT: (C) 2005 by Authors as listed in Author's List          *
+ *      LICENSE: Please see License Agreement                              *
+ *      DOWNLOAD: Free at www.rpi.edu/~anderk5                             *
+ *      ADMINISTRATOR: Prof. Kurt Anderson                                 *
+ *                     Computational Dynamics Lab                          *
+ *                     Rensselaer Polytechnic Institute                    *
+ *                     110 8th St. Troy NY 12180                           * 
+ *      CONTACT:        anderk5@rpi.edu                                    *
+ *_________________________________________________________________________*/
+
+#ifndef POEMSCHAIN_H_
+#define POEMSCHAIN_H_
+
+#include "poemslist.h"
+
+struct ChildRingData {
+	List<int> * childRing;
+	int entranceNodeId;
+};
+
+struct POEMSChain{
+	~POEMSChain(){
+		for(int i = 0; i < childChains.GetNumElements(); i++)
+		{
+			delete childChains(i);
+		}
+	}
+	//void printTreeStructure(int tabs);
+	//void getTreeAsList(List<int> * temp);
+	List<int> listOfNodes;
+	List<POEMSChain> childChains;
+	POEMSChain * parentChain;
+	List<ChildRingData> childRings;
+	
+	
+	void printTreeStructure(int tabs){
+		for(int i = 0; i < tabs; i++)
+		{
+			cout << "\t";
+		}
+		cout << "Chain: ";
+		for(int i = 0; i < listOfNodes.GetNumElements(); i++)
+		{
+			cout << *(listOfNodes(i)) << " ";
+		}
+		cout << endl;
+		for(int i = 0; i < childChains.GetNumElements(); i++)
+		{
+			childChains(i)->printTreeStructure(tabs + 1);
+		}
+	}
+	void getTreeAsList(List<int> * temp)
+	{
+		for(int i = 0; i < listOfNodes.GetNumElements(); i++)
+		{
+			int * integer = new int;
+			*integer = *(listOfNodes(i));
+			temp->Append(integer);
+		}
+		for(int i = 0; i < childChains.GetNumElements(); i++)
+		{
+			childChains(i)->getTreeAsList(temp);
+		}
+	}
+};
+#endif
diff --git a/lib/atc/PerAtomQuantityLibrary.cpp b/lib/atc/PerAtomQuantityLibrary.cpp
index c7f57fd72..36f925245 100644
--- a/lib/atc/PerAtomQuantityLibrary.cpp
+++ b/lib/atc/PerAtomQuantityLibrary.cpp
@@ -1,2383 +1,2510 @@
 // ATC transfer headers
 #include "PerAtomQuantityLibrary.h"
 #include "ATC_Transfer.h"
 #include "FE_Engine.h"
 #include "LammpsInterface.h"
 #include <typeinfo>
 #include <sstream>
 #include <iostream>
 
 using std::map;
 using std::ifstream;
 using std::stringstream;
 using std::set;
 using std::string;
 using std::vector;
 
 using ATC_Utility::to_string;
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomToElementMap
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomToElementMap::AtomToElementMap(ATC_Method * atc,
                                      PerAtomQuantity<double> * atomPositions,
                                      AtomType atomType) :
     ProtectedAtomQuantity<int>(atc,1,atomType),
     atomPositions_(atomPositions)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomPositions_)
       atomPositions_ = interscaleManager.per_atom_quantity("AtomicCoarseGrainingPositions");
     if (!atomPositions_)
       throw ATC_Error("AtomToElementMap::AtomToElementMap - atom position quantity is undefined");
 
     atomPositions_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomToElementMap::~AtomToElementMap()
   {
     atomPositions_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomToElementMap::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<int>::reset();
       const DENS_MAT & position(atomPositions_->quantity());
       const FE_Mesh * feMesh = atc_.fe_engine()->fe_mesh();
       int nsd = atc_.nsd();
       DENS_VEC coords(nsd);
       for (int i = 0; i < quantity_.nRows(); i++) {
         for (int j = 0; j < nsd; j++) {
           coords(j) = position(i,j);
         }
         quantity_(i,0) = feMesh->map_to_element(coords);
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomInElementSet
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomInElementSet::AtomInElementSet(ATC_Method * atc,
                      PerAtomQuantity<int> * map,
                      ESET eset, int type):
   atc_(atc,INTERNAL), 
   map_(map),eset_(eset),type_(type),
   quantityToLammps_(atc_.atc_to_lammps_map())
   {
     map_->register_dependence(this);
     needReset_ = true;
     
   }
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomInElementSet::~AtomInElementSet()
   {
     map_->remove_dependence(this);
   }
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomInElementSet::reset() 
   {
     if (map_->need_reset() || needReset_) {
       list_.clear();
       INT_ARRAY map = map_->quantity();
       int * type = ATC::LammpsInterface::instance()->atom_type(); 
       ESET::const_iterator itr;
       const Array<int> & quantityToLammps = atc_.atc_to_lammps_map();
       for (int i = 0; i < map.size(); i++) {
         for (itr=eset_.begin(); itr != eset_.end(); itr++) {
           if (map(i,0) == *itr) {
             int a = quantityToLammps(i);
             if (type[a] == type_) {
               list_.push_back(ID_PAIR(i,a)); 
               break;
             }
           }
         }
       }
       needReset_ = false;
     }
   }
   //--------------------------------------------------------
   //  qauntity
   //--------------------------------------------------------
   const ID_LIST &  AtomInElementSet::quantity()
   {
     reset();
     return list_;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomVolumeUser
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomVolumeUser::AtomVolumeUser(ATC_Method * atc,
                                  map<int,double> & atomGroupVolume,
                                  AtomType atomType) :
     ProtectedAtomDiagonalMatrix<double>(atc,atomType),
     atomGroupVolume_(atomGroupVolume),
     lammpsInterface_(atc->lammps_interface()),
     atcToLammps_(atc->internal_to_atom_map())
   {
     // do nothing
   }
   
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomVolumeUser::reset() const
   {
     if (need_reset()) {
       PerAtomDiagonalMatrix<double>::reset();
       const int *mask = lammpsInterface_->atom_mask();
       quantity_ = 0.;
 
       map<int, double>::const_iterator igroup;
       for (igroup = atomGroupVolume_.begin(); igroup != atomGroupVolume_.end(); igroup++) {
         int gid = igroup->first;
         double weight = igroup->second;
         for (int i = 0; i < quantity_.nRows(); ++i) {
           if (mask[atcToLammps_(i)] & gid) {
             quantity_(i,i) = weight;
           }
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomVolumeGroup
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomVolumeGroup::AtomVolumeGroup(ATC_Method * atc,
                                    map<int,double> & atomGroupVolume,
                                    AtomType atomType) :
     AtomVolumeUser(atc,atomGroupVolume,atomType),
     atomGroupVolume_(atomGroupVolume),
     lammpsInterface_(atc->lammps_interface()),
     atcToLammps_(atc->internal_to_atom_map())
   {
     // Uses group bounding box as total volume
     // ASSUME will *only* work if atoms exactly fill the box
     int ngroup = lammpsInterface_->ngroup();
     const int *mask = lammpsInterface_->atom_mask();
     double * bounds;
       
     bounds = new double[6];
     for (int i = 0; i < ngroup; ++i) {
       lammpsInterface_->group_bounds(i, bounds);
       atomGroupVolume_[lammpsInterface_->group_bit(i)] = 
         (bounds[1]-bounds[0])*(bounds[3]-bounds[2])*(bounds[5]-bounds[4]);
     }
     delete [] bounds;
       
     INT_VECTOR localCount(ngroup);
     INT_VECTOR globalCount(ngroup);
       
     // loop over atoms
     localCount = 0;
     for (int i = 0; i < atcToLammps_.size(); ++i) {
       for (int j = 0; j < ngroup; ++j) {
         if (mask[atcToLammps_(i)] & lammpsInterface_->group_bit(j))
           localCount(j)++;
       }
     }
       
     // communication to get total atom counts per group
     lammpsInterface_->int_allsum(localCount.ptr(),
                                  globalCount.ptr(),ngroup);
     
     for (int i = 0; i < ngroup; ++i) {
       int iGroupBit = lammpsInterface_->group_bit(i); 
       if (globalCount(i) > 0)
         atomGroupVolume_[iGroupBit] /= globalCount(i);
       else
         atomGroupVolume_[iGroupBit] = 0;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomVolumeLattice
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomVolumeLattice::AtomVolumeLattice(ATC_Method * atc,
                                        AtomType atomType) :
     ProtectedAtomDiagonalMatrix<double>(atc,atomType),
     lammpsInterface_(atc->lammps_interface())
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomVolumeLattice::reset() const
   {
     if (need_reset()) {
       PerAtomDiagonalMatrix<double>::reset();
       quantity_ = lammpsInterface_->volume_per_atom();
     }
   }
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomVolumeElement
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomVolumeElement::AtomVolumeElement(ATC_Method * atc,
                                        PerAtomQuantity<int> * atomElement,
                                        AtomType atomType) :
     ProtectedAtomDiagonalMatrix<double>(atc,atomType),
     atomElement_(atomElement),
     lammpsInterface_(atc->lammps_interface()),
     feMesh_((atc->fe_engine())->fe_mesh())
   {
     if (!atomElement_) {
       InterscaleManager & interscaleManager(atc->interscale_manager());
       atomElement_ = interscaleManager.per_atom_int_quantity("AtomElement");
     }
     atomElement_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   AtomVolumeElement::~AtomVolumeElement()
   {
     atomElement_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomVolumeElement::reset() const
   {
     if (need_reset()) {
       PerAtomDiagonalMatrix<double>::reset();
       int nElts = feMesh_->num_elements();
       int nLocal = quantity_.nRows();
       _elementAtomCountLocal_.reset(nElts);
       _elementAtomCount_.resize(nElts);
       const INT_ARRAY & atomElement(atomElement_->quantity());
        _elementAtomVolume_.resize(nElts);
       
       // determine number of atoms in each element, partial sum
       for (int i = 0; i < nLocal; ++i) {
         _elementAtomCountLocal_(atomElement(i,0)) += 1;
       }
       
       // mpi to determine total atoms
       lammpsInterface_->int_allsum(_elementAtomCountLocal_.ptr(),_elementAtomCount_.ptr(),nElts);
       
       // divide element volume by total atoms to get atomic volume
       if (nLocal>0) {
         for (int i = 0; i < nElts; ++i) {
           
           double minx, maxx, miny, maxy, minz, maxz;
           feMesh_->element_coordinates(i,_nodalCoordinates_);
           minx = _nodalCoordinates_(0,0); maxx = _nodalCoordinates_(0,0);
           miny = _nodalCoordinates_(1,0); maxy = _nodalCoordinates_(1,0);
           minz = _nodalCoordinates_(2,0); maxz = _nodalCoordinates_(2,0);
           for (int j = 1; j < _nodalCoordinates_.nCols(); ++j) {
             if (_nodalCoordinates_(0,j)<minx) minx = _nodalCoordinates_(0,j);
             if (_nodalCoordinates_(0,j)>maxx) maxx = _nodalCoordinates_(0,j);
             if (_nodalCoordinates_(1,j)<miny) miny = _nodalCoordinates_(1,j);
             if (_nodalCoordinates_(1,j)>maxy) maxy = _nodalCoordinates_(1,j);
             if (_nodalCoordinates_(2,j)<minz) minz = _nodalCoordinates_(2,j);
             if (_nodalCoordinates_(2,j)>maxz) maxz = _nodalCoordinates_(2,j);
           }
           double eltVol = (maxx-minx)*(maxy-miny)*(maxz-minz);
           if (eltVol<0) eltVol *= -1.;
           _elementAtomVolume_(i) = eltVol/_elementAtomCount_(i);
         }
         
         for (int i = 0; i < nLocal; ++i)
           quantity_(i,i) = _elementAtomVolume_(atomElement(i,0));
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomVolumeRegion
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomVolumeRegion::AtomVolumeRegion(ATC_Method * atc,
                                      DENS_MAN * atomCoarseGrainingPositions,
                                      AtomType atomType) :
     ProtectedAtomDiagonalMatrix<double>(atc,atomType),
     lammpsInterface_(atc->lammps_interface())
   {
     if (!atomCoarseGrainingPositions) {
       InterscaleManager & interscaleManager(atc->interscale_manager());
       atomCoarseGrainingPositions_ = interscaleManager.per_atom_quantity("AtomicCoarseGrainingPositions");
     }
     atomCoarseGrainingPositions_->register_dependence(this);
 
     // compute volumes and atom counts in each region
     int nregion = lammpsInterface_->nregion();
     regionalAtomVolume_.resize(nregion);
     
     for (int i = 0; i < nregion; ++i) {
       regionalAtomVolume_(i) = 
         (lammpsInterface_->region_xhi(i)-lammpsInterface_->region_xlo(i))
         *(lammpsInterface_->region_yhi(i)-lammpsInterface_->region_ylo(i))
         *(lammpsInterface_->region_zhi(i)-lammpsInterface_->region_zlo(i));
     }
       
     INT_VECTOR localCount(nregion);
     INT_VECTOR globalCount(nregion);  
     // loop over atoms
     localCount = 0;
     const DENS_MAT atomicCoordinates(atomCoarseGrainingPositions->quantity());
     for (int i = 0; i < quantity_.nRows(); ++i) {
       for (int j = 0; j < nregion; ++j) {
         if (lammpsInterface_->region_match(j,
                                            atomicCoordinates(i,0),
                                            atomicCoordinates(i,1),
                                            atomicCoordinates(i,2))) {
           localCount(j)++;
         }
       }
     }
     // communication to get total atom counts per group
     lammpsInterface_->int_allsum(localCount.ptr(),
                                  globalCount.ptr(),nregion);
         
     for (int i = 0; i < nregion; ++i) {
       if (globalCount(i) > 0)
         regionalAtomVolume_(i) /= globalCount(i);
       else
         regionalAtomVolume_(i) = 0;
     }
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   AtomVolumeRegion::~AtomVolumeRegion()
   {
     atomCoarseGrainingPositions_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomVolumeRegion::reset() const
   {
     if (need_reset()) {
       PerAtomDiagonalMatrix<double>::reset();
       const DENS_MAT & atomicCoordinates(atomCoarseGrainingPositions_->quantity());  
       for (int i = 0; i < quantity_.nRows(); i++) {
         for (int iregion = 0; iregion < lammpsInterface_->nregion(); iregion++) {
           if (lammpsInterface_->region_match(iregion,
                                              atomicCoordinates(i,0),
                                              atomicCoordinates(i,0),
                                              atomicCoordinates(i,2)))
             quantity_(i,i) = regionalAtomVolume_(iregion);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomVolumeFile
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomVolumeFile::AtomVolumeFile(ATC_Method * atc,
                                  const string & atomVolumeFile,
                                  AtomType atomType) :
     ProtectedAtomDiagonalMatrix<double>(atc,atomType),
     atomVolumeFile_(atomVolumeFile),
     lammpsInterface_(atc->lammps_interface())
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomVolumeFile::reset() const
   {
     if (need_reset()) {
       PerAtomDiagonalMatrix<double>::reset();
       int nlocal = lammpsInterface_->nlocal();
       ifstream in;
       const int lineSize = 256;
       char line[lineSize];
       const char* fname = &atomVolumeFile_[0]; 
 
       // create tag to local id map for this processor
       map <int,int> tag2id;
       map <int,int>::const_iterator itr;
       const int * atom_tag = lammpsInterface_->atom_tag();
       for (int i = 0; i < nlocal; ++i) {
         tag2id[atom_tag[i]] = i;
       }
 
       // get number of atoms
       int natoms = 0;
       if (ATC::LammpsInterface::instance()->rank_zero()) {
         in.open(fname);
         string msg;
         string name = atomVolumeFile_;
         msg = "no "+name+" atomic weights file found";
         if (! in.good()) throw ATC_Error(msg);
         in.getline(line,lineSize); // header
         in.getline(line,lineSize); // blank line
         in.getline(line,lineSize); // number of atoms 
         stringstream inss (line,stringstream::in | stringstream::out);
         inss >> natoms; // number of atoms
         stringstream ss; 
         ss << " found " << natoms << " atoms in atomic weights file";
         lammpsInterface_->print_msg(ss.str());
         if (natoms != lammpsInterface_->natoms()) { 
           throw ATC_Error("Incorrect number of atomic weights read-in!");
         }
         in.getline(line,lineSize); // blank line
       }
 
       // read and assign atomic weights
       int nread = 0, tag = -1, count = 0;
       double atomic_weight;
       while (nread < natoms) {
         if (ATC::LammpsInterface::instance()->rank_zero()) {
           in.getline(line,lineSize);
           stringstream ss (line,stringstream::in | stringstream::out);
           ss >> tag >> atomic_weight; 
           nread++;
         }
         lammpsInterface_->int_broadcast(&nread);
         lammpsInterface_->int_broadcast(&tag);
         lammpsInterface_->broadcast(&atomic_weight);
         itr = tag2id.find(tag);
         if (itr != tag2id.end()) {
           int iatom = itr->second;
           quantity_(iatom,0) = atomic_weight;
           count++;
         }
       }
       if (lammpsInterface_->rank_zero()) {
         in.close();
         stringstream ss; 
         ss << " read  " << nread << " atomic weights";
         lammpsInterface_->print_msg(ss.str());
       }
       if (count != nlocal) 
         throw ATC_Error("reset "+to_string(count)+" atoms vs "+to_string(nlocal));
     }
   }
 
   // need to add capability to take in group bit (JAT, 04/02/11)
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomNumber
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   AtomNumber::AtomNumber(ATC_Method * atc, AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,1,atomType),
     atc_(atc)  
   {
   }
 
   void AtomNumber::reset() const
   {
     int nlocal = atc_->nlocal();
     quantity_.reset(nlocal,1);
     quantity_ = 1;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomTypeVector
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   AtomTypeVector::AtomTypeVector(ATC_Method * atc, 
     vector<int> typeList, AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,
     typeList.size(),
     atomType),
     atc_(atc), ntypes_(ATC::LammpsInterface::instance()->ntypes()),
     typeList_(typeList)  
   {
     if (typeList_.size() == 0) throw ATC_Error("type list is empty");
     index_.resize(ntypes_,-1); 
     for (unsigned int i = 0; i < typeList_.size(); i++) {
       index_[typeList_[i]] = i;
     }
   }
   AtomTypeVector::AtomTypeVector(ATC_Method * atc, 
     vector<int> typeList, vector<int> groupList, AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,
     typeList.size()+groupList.size(),
     atomType),
     atc_(atc), ntypes_(ATC::LammpsInterface::instance()->ntypes()),
     typeList_(typeList),
     groupList_(groupList)  
   {
     if ((typeList_.size() == 0) && (groupList_.size() == 0)) throw ATC_Error("type/group lists are empty");
     // reverse map
     index_.resize(ntypes_,-1); 
     for (unsigned int i = 0; i < typeList_.size(); i++) {
       index_[typeList_[i]-1] = i;
     }
   }
 
   void AtomTypeVector::reset() const
   {
     if (need_reset()) {
       //PerAtomQuantity<double>::reset();
       int nlocal = atc_->nlocal();
       quantity_.reset(nlocal,typeList_.size()+groupList_.size());
       const Array<int> & quantityToLammps = (PerAtomQuantity<double>::atc_).atc_to_lammps_map();
       if (typeList_.size()) { 
         int * type = ATC::LammpsInterface::instance()->atom_type(); 
         for (int i = 0; i < nlocal; i++) {
           int a = quantityToLammps(i); 
           int index = index_[type[a]-1];
           if (index > -1) quantity_(i,index) = 1;
         }
       }
       int index = typeList_.size();
       if (groupList_.size()) { 
         const int * mask = ATC::LammpsInterface::instance()->atom_mask();
         for (unsigned int j = 0; j < groupList_.size(); j++) {
           int group = groupList_[j];
           for (int i = 0; i < nlocal; i++) {
             int a = quantityToLammps(i);
             if (mask[a] & group) quantity_(i,index) = 1;
           }
           index++;
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class XrefWrapper
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   XrefWrapper::XrefWrapper(ATC_Method * atc, AtomType atomType) :
     ProtectedClonedAtomQuantity<double>(atc,atc->nsd(),atomType),
     atc_(atc)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  lammps_vector
   //--------------------------------------------------------
   double ** XrefWrapper::lammps_vector() const
   {
     return atc_->xref();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomicMassWeightedDisplacement
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   AtomicMassWeightedDisplacement::AtomicMassWeightedDisplacement(ATC_Method * atc,
     PerAtomQuantity<double> * atomPositions,
     PerAtomQuantity<double> * atomMasses,
     PerAtomQuantity<double> * atomReferencePositions,
     AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,atc->nsd(),atomType),
     atomPositions_(atomPositions),
     atomMasses_(atomMasses),
     atomReferencePositions_(atomReferencePositions)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomPositions_)
       atomPositions_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_POSITION,
                                                                        atomType);
     if (!atomMasses_)
       atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                     atomType);
     if (!atomReferencePositions_)
       atomReferencePositions_ = interscaleManager.per_atom_quantity("AtomicCoarseGrainingPositions");
 
     atomPositions_->register_dependence(this);
     atomMasses_->register_dependence(this);
     atomReferencePositions_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomicMassWeightedDisplacement::~AtomicMassWeightedDisplacement()
   {
     atomPositions_->remove_dependence(this);
     atomMasses_->remove_dependence(this);
     atomReferencePositions_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomicMassWeightedDisplacement::reset() const
   {
     if (need_reset()) { 
       PerAtomQuantity<double>::reset();
       const DENS_MAT & position(atomPositions_->quantity());
       const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & refPosition(atomReferencePositions_->quantity());
 
       // q = m * (x - xref)
       quantity_ = position;
       quantity_ -= refPosition;
       quantity_ *= mass;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomicMomentum
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   AtomicMomentum::AtomicMomentum(ATC_Method * atc,
                                  PerAtomQuantity<double> * atomVelocities,
                                  PerAtomQuantity<double> * atomMasses,
                                  AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,atc->nsd(),atomType),
     atomVelocities_(atomVelocities),
     atomMasses_(atomMasses)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomVelocities_)
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
-                                                                        atomType);
+                                                                    atomType);
     if (!atomMasses_)
       atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                     atomType);
 
     atomVelocities_->register_dependence(this);
     atomMasses_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomicMomentum::~AtomicMomentum()
   {
     atomVelocities_->remove_dependence(this);
     atomMasses_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomicMomentum::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & velocity(atomVelocities_->quantity());
 
       // q = m * v
       quantity_ = velocity;
       quantity_ *= mass;    
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class TwiceKineticEnergy
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   TwiceKineticEnergy::TwiceKineticEnergy(ATC_Method * atc,
                                          PerAtomQuantity<double> * atomVelocities,
                                          PerAtomQuantity<double> * atomMasses,
                                          AtomType atomType) :
     AtomicEnergyForTemperature(atc,atomType),
     atomVelocities_(atomVelocities),
     atomMasses_(atomMasses)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomVelocities_)
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
                                                                         atomType);
     if (!atomMasses_)
       atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                     atomType);
 
     atomVelocities_->register_dependence(this);
     atomMasses_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   TwiceKineticEnergy::~TwiceKineticEnergy()
   {
     atomVelocities_->remove_dependence(this);
     atomMasses_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void TwiceKineticEnergy::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & velocity(atomVelocities_->quantity());
       
       // q = m * (v dot v)
       for (int i = 0; i < quantity_.nRows(); i++) {
           quantity_(i,0) = velocity(i,0)*velocity(i,0);
         for (int j = 1; j < velocity.nCols(); j++) {
           quantity_(i,0) += velocity(i,j)*velocity(i,j);
         }
         quantity_(i,0) *= mass(i,0);
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class FluctuatingVelocity
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   FluctuatingVelocity::FluctuatingVelocity(ATC_Method * atc,
     PerAtomQuantity<double> * atomVelocities,
     PerAtomQuantity<double> * atomMeanVelocities,
     AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,3,atomType),
     atomVelocities_(atomVelocities),
     atomMeanVelocities_(atomMeanVelocities)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomVelocities_) {
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(
         LammpsInterface::ATOM_VELOCITY, atomType);
     }
     if (!atomMeanVelocities_) {
-      atomMeanVelocities_ = interscaleManager.per_atom_quantity("AtomicMeanVelocity");
+      atomMeanVelocities_ = interscaleManager.per_atom_quantity(field_to_prolongation_name(VELOCITY));
     }
 
     atomVelocities_->register_dependence(this);
     atomMeanVelocities_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   FluctuatingVelocity::~FluctuatingVelocity()
   {
     atomVelocities_->remove_dependence(this);
     atomMeanVelocities_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void FluctuatingVelocity::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & velocity(atomVelocities_->quantity());
       const DENS_MAT & meanVelocity(atomMeanVelocities_->quantity());
       
       // q = m * (v dot v)
       for (int i = 0; i < quantity_.nRows(); i++) {
         for (int j = 0; j < velocity.nCols(); j++) {
           quantity_(i,j) = velocity(i,j) - meanVelocity(i,j);
         }
       }
     }
   }
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ChargeVelocity
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   ChargeVelocity::ChargeVelocity(ATC_Method * atc,
     PerAtomQuantity<double> * atomVelocities,
     FundamentalAtomQuantity * atomCharge,
     AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,3,atomType),
     fluctuatingVelocities_(atomVelocities),
     atomCharge_(atomCharge)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!fluctuatingVelocities_) {
       fluctuatingVelocities_ = interscaleManager.per_atom_quantity("AtomicFluctuatingVelocity");
     }
     if (!atomCharge_) {
       atomCharge_ = interscaleManager.fundamental_atom_quantity(
         LammpsInterface::ATOM_CHARGE, atomType);
     }
     fluctuatingVelocities_->register_dependence(this);
     atomCharge_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   ChargeVelocity::~ChargeVelocity()
   {
     fluctuatingVelocities_->remove_dependence(this);
     atomCharge_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void ChargeVelocity::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & velocity(fluctuatingVelocities_->quantity());
       const DENS_MAT & charge(atomCharge_->quantity());
       for (int i = 0; i < quantity_.nRows(); i++) {
         for (int j = 0; j < velocity.nCols(); j++) {
           quantity_(i,j) = charge(i,0)*velocity(i,j);
         }
       }
     }
   }
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class SpeciesVelocity
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   SpeciesVelocity::SpeciesVelocity(ATC_Method * atc,
     PerAtomQuantity<double> * fluctuatingVelocities,
     PerAtomQuantity<double> * atomTypeVector,
     AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,3*(atomTypeVector->nCols()),atomType),
     fluctuatingVelocities_(fluctuatingVelocities),
     atomTypeVector_(atomTypeVector)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!fluctuatingVelocities_) {
       fluctuatingVelocities_ = interscaleManager.per_atom_quantity("AtomicFluctuatingVelocity");
     }
     if (!atomTypeVector_) {
       atomTypeVector_ = interscaleManager.per_atom_quantity("AtomicTypeVector");
     }
     fluctuatingVelocities_->register_dependence(this);
     atomTypeVector_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   SpeciesVelocity::~SpeciesVelocity()
   {
     fluctuatingVelocities_->remove_dependence(this);
     atomTypeVector_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void SpeciesVelocity::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & velocity(fluctuatingVelocities_->quantity());
       const DENS_MAT & tv(atomTypeVector_->quantity());
       
       for (int i = 0; i < quantity_.nRows(); i++) {
         int m = 0;
         for (int j = 0; j < velocity.nCols(); j++) {
           for (int k = 0; j < tv.nCols(); j++) {
             quantity_(i,m++) = tv(i,k)*velocity(i,j);
           }
         }
       }
     }
   }
+
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class TwiceFluctuatingKineticEnergy
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   TwiceFluctuatingKineticEnergy::TwiceFluctuatingKineticEnergy(ATC_Method * atc,
     PerAtomQuantity<double> * atomVelocities,
     PerAtomQuantity<double> * atomMasses,
     PerAtomQuantity<double> * atomMeanVelocities,
     AtomType atomType) :
     AtomicEnergyForTemperature(atc,atomType),
     atomVelocities_(atomVelocities),
     atomMasses_(atomMasses),
     atomMeanVelocities_(atomMeanVelocities)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomVelocities_) {
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
                                                                     atomType);
     }
     if (!atomMasses_) {
       atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                 atomType);
     }
     if (!atomMeanVelocities_) {
-      atomMeanVelocities_ = interscaleManager.per_atom_quantity("AtomicMeanVelocity");
+      atomMeanVelocities_ = interscaleManager.per_atom_quantity(field_to_prolongation_name(VELOCITY));
     }
 
     atomVelocities_->register_dependence(this);
     atomMasses_->register_dependence(this);
     atomMeanVelocities_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   TwiceFluctuatingKineticEnergy::~TwiceFluctuatingKineticEnergy()
   {
     atomVelocities_->remove_dependence(this);
     atomMasses_->remove_dependence(this);
     atomMeanVelocities_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void TwiceFluctuatingKineticEnergy::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & velocity(atomVelocities_->quantity());
       const DENS_MAT & meanVelocity(atomMeanVelocities_->quantity());
       
       // q = m * (v dot v)
       double vRel;
       for (int i = 0; i < quantity_.nRows(); i++) {
         vRel = velocity(i,0) - meanVelocity(i,0);
         quantity_(i,0) = vRel*vRel;
         for (int j = 1; j < velocity.nCols(); j++) {
           vRel = velocity(i,j) - meanVelocity(i,j);
           quantity_(i,0) += vRel*vRel;;
         }
         quantity_(i,0) *= mass(i,0);
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class KineticTensor
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   KineticTensor::KineticTensor(ATC_Method * atc,
      PerAtomQuantity<double> * atomVelocities,
      PerAtomQuantity<double> * atomMasses,
      AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,6,atomType),
     atomVelocities_(atomVelocities),
     atomMasses_(atomMasses)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomVelocities_) {
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
                                                                     atomType);
     }
     if (!atomMasses_) {
       atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                 atomType);
     }
 
     atomVelocities_->register_dependence(this);
     atomMasses_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   KineticTensor::~KineticTensor()
   {
     atomVelocities_->remove_dependence(this);
     atomMasses_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void KineticTensor::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & velocity(atomVelocities_->quantity());
       
       // K = m * (v \otimes v)
       for (int i = 0; i < quantity_.nRows(); i++) {
         double m = mass(i,0);
         double v[3] = {velocity(i,0),velocity(i,1),velocity(i,2)};
         quantity_(i,0) -= m*v[0]*v[0];
         quantity_(i,1) -= m*v[1]*v[1];
         quantity_(i,2) -= m*v[2]*v[2];
         quantity_(i,3) -= m*v[0]*v[1];
         quantity_(i,4) -= m*v[0]*v[2];
         quantity_(i,5) -= m*v[1]*v[2];
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class FluctuatingKineticTensor
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   FluctuatingKineticTensor::FluctuatingKineticTensor(ATC_Method * atc,
      PerAtomQuantity<double> * atomVelocities,
      PerAtomQuantity<double> * atomMasses,
      PerAtomQuantity<double> * atomMeanVelocities,
      AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,6,atomType),
     atomVelocities_(atomVelocities),
     atomMasses_(atomMasses)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomVelocities_) {
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
                                                                     atomType);
     }
     if (!atomMasses_) {
       atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                 atomType);
     }
     if (!atomMeanVelocities_) {
-      atomMeanVelocities_ = interscaleManager.per_atom_quantity("AtomicMeanVelocity");
+      atomMeanVelocities_ = interscaleManager.per_atom_quantity(field_to_prolongation_name(VELOCITY));
     }
 
     atomVelocities_->register_dependence(this);
     atomMasses_->register_dependence(this);
     atomMeanVelocities_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   FluctuatingKineticTensor::~FluctuatingKineticTensor()
   {
     atomVelocities_->remove_dependence(this);
     atomMasses_->remove_dependence(this);
     atomMeanVelocities_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void FluctuatingKineticTensor::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & velocity(atomVelocities_->quantity());
       const DENS_MAT & meanVelocity(atomMeanVelocities_->quantity());
       
       // K = m * (v \otimes v)
       for (int i = 0; i < quantity_.nRows(); i++) {
         double m = mass(i,0);
         double v[3] = {velocity(i,0)-meanVelocity(i,0),
                        velocity(i,1)-meanVelocity(i,0),
                        velocity(i,2)-meanVelocity(i,0)};
         quantity_(i,0) -= m*v[0]*v[0];
         quantity_(i,1) -= m*v[1]*v[1];
         quantity_(i,2) -= m*v[2]*v[2];
         quantity_(i,3) -= m*v[0]*v[1];
         quantity_(i,4) -= m*v[0]*v[2];
         quantity_(i,5) -= m*v[1]*v[2];
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class MixedKePeEnergy
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   MixedKePeEnergy::MixedKePeEnergy(ATC_Method * atc,
                                    double keMultiplier,
                                    double peMultiplier,
                                    PerAtomQuantity<double> * twiceKineticEnergy,
                                    PerAtomQuantity<double> * potentialEnergy,
                                    AtomType atomType) :
     AtomicEnergyForTemperature(atc,atomType),
     keMultiplier_(keMultiplier),
     peMultiplier_(peMultiplier),
     twiceKineticEnergy_(twiceKineticEnergy),
     potentialEnergy_(potentialEnergy)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!twiceKineticEnergy_) {
        twiceKineticEnergy_ = interscaleManager.per_atom_quantity("AtomicTwiceKineticEnergy");
     }
     if (!potentialEnergy_) {
       potentialEnergy_ = interscaleManager.per_atom_quantity("AtomicFluctuatingPotentialEnergy");
     }
 
     twiceKineticEnergy_->register_dependence(this);
     potentialEnergy_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   MixedKePeEnergy::~MixedKePeEnergy()
   {
     twiceKineticEnergy_->remove_dependence(this);
     potentialEnergy_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void MixedKePeEnergy::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & twoKe(twiceKineticEnergy_->quantity());
       const DENS_MAT & pe(potentialEnergy_->quantity());
 
       // q = peScale * pe + keScale * ke
       quantity_ = pe;
       quantity_ *= peMultiplier_;
       quantity_ += (keMultiplier_/2.)*twoKe;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class TotalEnergy
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   TotalEnergy::TotalEnergy(ATC_Method * atc,
                            PerAtomQuantity<double> * twiceKineticEnergy,
                            PerAtomQuantity<double> * potentialEnergy,
                            AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,atomType),
     twiceKineticEnergy_(twiceKineticEnergy),
     potentialEnergy_(potentialEnergy)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
 
     if (!twiceKineticEnergy_) {
        twiceKineticEnergy_ = interscaleManager.per_atom_quantity("AtomicTwiceKineticEnergy");
     }
     if (!potentialEnergy_) {
       potentialEnergy_ = interscaleManager.per_atom_quantity("AtomicPotentialEnergy");
     }
     twiceKineticEnergy_->register_dependence(this);
     potentialEnergy_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   TotalEnergy::~TotalEnergy()
   {
     twiceKineticEnergy_->remove_dependence(this);
     potentialEnergy_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void TotalEnergy::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & twoKe(twiceKineticEnergy_->quantity());
       const DENS_MAT & pe(potentialEnergy_->quantity());
       quantity_ = pe;
       quantity_ += (0.5)*twoKe;
     }
   }
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class FluctuatingPotentialEnergy
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   FluctuatingPotentialEnergy::FluctuatingPotentialEnergy(ATC_Method * atc,
                                                          PerAtomQuantity<double> * potentialEnergy,
                                                          PerAtomQuantity<double> * referencePotential,
                                                          AtomType atomType) :
     AtomicEnergyForTemperature(atc,atomType),
     potentialEnergy_(potentialEnergy),
     referencePotential_(referencePotential)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!potentialEnergy_) {
       potentialEnergy_ = interscaleManager.per_atom_quantity("AtomicPotentialEnergy");
     }
     if (!referencePotential_) {
        referencePotential_ = interscaleManager.per_atom_quantity("AtomicReferencePotential");
     }
     
     potentialEnergy_->register_dependence(this);
     referencePotential_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   FluctuatingPotentialEnergy::~FluctuatingPotentialEnergy()
   {
     potentialEnergy_->remove_dependence(this);
     referencePotential_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void FluctuatingPotentialEnergy::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & pe(potentialEnergy_->quantity());
       const DENS_MAT & refPe(referencePotential_->quantity());
 
       quantity_ = pe;
       quantity_ -= refPe;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class DotTwiceKineticEnergy
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   DotTwiceKineticEnergy::DotTwiceKineticEnergy(ATC_Method * atc,
                                                PerAtomQuantity<double> * atomForces,
                                                PerAtomQuantity<double> * atomVelocities,
                                                AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,1,atomType),
     atomForces_(atomForces),
     atomVelocities_(atomVelocities)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomForces_)
       atomForces_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_FORCE,
                                                                     atomType);
     if (!atomVelocities_)
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
                                                                         atomType);
 
     atomForces_->register_dependence(this);
     atomVelocities_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   DotTwiceKineticEnergy::~DotTwiceKineticEnergy()
   {
     atomForces_->remove_dependence(this);
     atomVelocities_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void DotTwiceKineticEnergy::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & velocity(atomVelocities_->quantity());
       const DENS_MAT & force(atomForces_->quantity());
 
       for (int i = 0; i < quantity_.nRows(); i++) {
         quantity_(i,0) = velocity(i,0)*force(i,0);
         for (int j = 1; j < velocity.nCols(); j++) {
           quantity_(i,0) += velocity(i,j)*force(i,j);
         }
         quantity_(i,0) *= 2.;
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class VelocitySquared
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   VelocitySquared::VelocitySquared(ATC_Method * atc,
                                    PerAtomQuantity<double> * atomVelocities,
                                    AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,1,atomType),
     atomVelocities_(atomVelocities)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomVelocities_)
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
-                                                                        atomType);
+                                                                    atomType);
     atomVelocities_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   VelocitySquared::~VelocitySquared()
   {
     atomVelocities_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void VelocitySquared::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & velocity(atomVelocities_->quantity());
 
       for (int i = 0; i < quantity_.nRows(); i++) {
         quantity_(i,0) = velocity(i,0)*velocity(i,0);
         for (int j = 1; j < velocity.nCols(); j++) {
           quantity_(i,0) += velocity(i,j)*velocity(i,j);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaSquared
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   LambdaSquared::LambdaSquared(ATC_Method * atc,
                                PerAtomQuantity<double> * atomMasses,
                                PerAtomQuantity<double> * atomVelocitiesSquared,
                                PerAtomQuantity<double> * atomLambdas,
                                AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,1,atomType),
     atomMasses_(atomMasses),
     atomVelocitiesSquared_(atomVelocitiesSquared),
     atomLambdas_(atomLambdas)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomMasses_) {
       atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                     atomType);
     }
     atomMasses_->register_dependence(this);
 
     if (!atomVelocitiesSquared) {
       atomVelocitiesSquared_ = interscaleManager.per_atom_quantity("LambdaSquared");
     }
     atomVelocitiesSquared_->register_dependence(this);
 
     if (!atomLambdas_) {
       atomLambdas_ = interscaleManager.per_atom_quantity("AtomLambdaEnergy");
     }
     atomLambdas_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   LambdaSquared::~LambdaSquared()
   {
     atomMasses_->remove_dependence(this);
     atomVelocitiesSquared_->remove_dependence(this);
     atomLambdas_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void LambdaSquared::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & velocitySquared(atomVelocitiesSquared_->quantity());
       const DENS_MAT & lambda(atomLambdas_->quantity());
 
       for (int i = 0; i < quantity_.nRows(); i++) {
         quantity_(i,0) = lambda(i,0)*lambda(i,0)*velocitySquared(i,0)/mass(i,0);
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomToType
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomToType::AtomToType(ATC_Method * atc,
                          int type,
                          AtomType atomType) :
     LargeToSmallAtomMap(atc,atomType),
     type_(type)
   {
     // DO NOTHING
     
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomToType::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<int>::reset();
       quantity_ = -1.;
       size_ = 0;
       const int * type = lammpsInterface_->atom_type();
 
       const Array<int> & quantityToLammps = atc_.atc_to_lammps_map();
       for (int i = 0; i < quantity_.nRows(); ++i) {
         int atomIdx = quantityToLammps(i);
         if (type[atomIdx] == type_) {
           quantity_(i,0) = size_;
           ++size_;
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomToGroup
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomToGroup::AtomToGroup(ATC_Method * atc,
                            int group,
                            AtomType atomType) :
     LargeToSmallAtomMap(atc,atomType),
     group_(group)
   {
     // DO NOTHING
     
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomToGroup::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<int>::reset();
       quantity_ = -1.;
       size_ = 0;
       const int * mask = lammpsInterface_->atom_mask();
 
       const Array<int> & quantityToLammps = atc_.atc_to_lammps_map();
       for (int i = 0; i < quantity_.nRows(); ++i) {
         int atomIdx = quantityToLammps(i);
         if (mask[atomIdx] & group_) {
           quantity_(i,0) = size_;
           ++size_;
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomToNodeset
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomToNodeset::AtomToNodeset(ATC_Method * atc,
                                SetDependencyManager<int> * subsetNodes,
                                PerAtomQuantity<int> * atomElement,
                                AtomType atomType) :
     LargeToSmallAtomMap(atc,atomType),
     subsetNodes_(subsetNodes),
     atomElement_(atomElement),
     feMesh_((atc->fe_engine())->fe_mesh())
   {
     if (!atomElement_) {
       atomElement_ = (atc->interscale_manager()).per_atom_int_quantity("AtomElement");
     }
     if (atomElement_) {
       atomElement_->register_dependence(this);
     }
     else {
       throw ATC_Error("PerAtomQuantityLibrary::AtomToRegulated - No AtomElement provided");
     }
 
     subsetNodes_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  quantity
   //--------------------------------------------------------
   void AtomToNodeset::reset() const
   {
     
     //so it has been commented out.
     /*
     if (need_reset()) {
       PerAtomQuantity<int>::reset();
       const INT_ARRAY & atomElement(atomElement_->quantity());
       const set<int> & subsetNodes(subsetNodes_->quantity());
       int nLocal = atomElement.nRows();
       quantity_.resize(nLocal,1);
       quantity_ = -1;
       size_ = 0;
 
       for (int i = 0; i < nLocal; ++i) {
         feMesh_->element_connectivity_unique(atomElement(i,0),_nodes_);
         for (int j = 0; j < _nodes_.size(); ++j) {
           if (subsetNodes.find(_nodes_(j)) != subsetNodes.end()) {
             quantity_(i,0) = size_;
             size_++;
             break;
           }
         }
       }
     }
     */
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomToElementset
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomToElementset::AtomToElementset(ATC_Method * atc,
                                      MatrixDependencyManager<DenseMatrix, bool> * elementMask,
                                      PerAtomQuantity<int> * atomElement,
                                      AtomType atomType) :
     LargeToSmallAtomMap(atc,atomType),
     elementMask_(elementMask),
     atomElement_(atomElement),
     feMesh_((atc->fe_engine())->fe_mesh())
   {
     if (!atomElement_) {
       atomElement_ = (atc->interscale_manager()).per_atom_int_quantity("AtomElement");
     }
     if (atomElement_) {
       atomElement_->register_dependence(this);
     }
     else {
       throw ATC_Error("PerAtomQuantityLibrary::AtomToRegulated - No AtomElement provided");
     }
 
     elementMask_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomToElementset::~AtomToElementset()
   {
     atomElement_->remove_dependence(this);
     elementMask_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  quantity
   //--------------------------------------------------------
   void AtomToElementset::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<int>::reset();
       const INT_ARRAY & atomElement(atomElement_->quantity());
       const DenseMatrix<bool> & elementMask(elementMask_->quantity());
       int nLocal = atomElement.nRows();
       quantity_.resize(nLocal,1);
       quantity_ = -1;
       size_ = 0;
 
       for (int i = 0; i < nLocal; ++i) {
         if (elementMask(atomElement(i,0),0)) {
           quantity_(i,0) = size_;
           size_++;
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class MappedAtomQuantity
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   MappedAtomQuantity::MappedAtomQuantity(ATC_Method * atc,
                                          PerAtomQuantity<double> * source,
                                          LargeToSmallAtomMap * map,
                                          AtomType atomType) :
     ProtectedMappedAtomQuantity<double>(atc,map,source->nCols(),atomType),
     source_(source),
     map_(map)
   {
     source_->register_dependence(this);
     map_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void MappedAtomQuantity::reset() const
   {
     if (needReset_) {
       ProtectedMappedAtomQuantity<double>::reset();
       const DENS_MAT & source(source_->quantity());
       const INT_ARRAY & map(map_->quantity());
       quantity_.resize(map_->size(),source.nCols());
       
       for (int i = 0; i < source.nRows(); i++) {
         int idx = map(i,0);
         if (idx > -1) {
           for (int j = 0; j < source.nCols(); j++) {
             quantity_(idx,j) = source(i,j);
           }
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class VelocitySquaredMapped
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   VelocitySquaredMapped::VelocitySquaredMapped(ATC_Method * atc,
                                                MatrixDependencyManager<DenseMatrix, int> * atomMap,
                                                PerAtomQuantity<double> * atomVelocities,
                                                AtomType atomType) :
     ProtectedMappedAtomQuantity<double>(atc,atomMap,1,atomType),
     atomVelocities_(atomVelocities)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomVelocities_)
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
                                                                         atomType);
     atomVelocities_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   VelocitySquaredMapped::~VelocitySquaredMapped()
   {
     atomVelocities_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void VelocitySquaredMapped::reset() const
   {
     if (need_reset()) {
       ProtectedMappedAtomQuantity<double>::reset();
       const DENS_MAT & velocity(atomVelocities_->quantity());
       const INT_ARRAY & atomMap(atomMap_->quantity());
 
       for (int i = 0; i < atomMap.nRows(); i++) {
         int idx = atomMap(i,0);
         if (idx > -1) {
           quantity_(idx,0) = velocity(i,0)*velocity(i,0);
           for (int j = 1; j < velocity.nCols(); j++) {
             quantity_(idx,0) += velocity(i,j)*velocity(i,j);
           }
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaSquaredMapped
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   LambdaSquaredMapped::LambdaSquaredMapped(ATC_Method * atc,
                                            MatrixDependencyManager<DenseMatrix, int> * atomMap,
                                            PerAtomQuantity<double> * atomMasses,
                                            PerAtomQuantity<double> * atomVelocitiesSquared,
                                            PerAtomQuantity<double> * atomLambdas,
                                            AtomType atomType) :
     ProtectedMappedAtomQuantity<double>(atc,atomMap,1,atomType),
     atomMasses_(atomMasses),
     atomVelocitiesSquared_(atomVelocitiesSquared),
     atomLambdas_(atomLambdas)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomMasses_) {
       atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                                     atomType);
     }
     atomMasses_->register_dependence(this);
 
     if (!atomVelocitiesSquared) {
       atomVelocitiesSquared_ = interscaleManager.per_atom_quantity("LambdaSquared");
     }
     atomVelocitiesSquared_->register_dependence(this);
 
     if (!atomLambdas_) {
       atomLambdas_ = interscaleManager.per_atom_quantity("AtomLambdaEnergy");
     }
     atomLambdas_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   LambdaSquaredMapped::~LambdaSquaredMapped()
   {
     atomMasses_->remove_dependence(this);
     atomVelocitiesSquared_->remove_dependence(this);
     atomLambdas_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void LambdaSquaredMapped::reset() const
   {
     if (need_reset()) {
       ProtectedMappedAtomQuantity<double>::reset();
       const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & velocitySquared(atomVelocitiesSquared_->quantity());
       const DENS_MAT & lambda(atomLambdas_->quantity());
       const INT_ARRAY & atomMap(atomMap_->quantity());
 
       for (int i = 0; i < atomMap.nRows(); i++) {
         int idx = atomMap(i,0);
         if (idx > -1) {
           quantity_(idx,0) = lambda(i,0)*lambda(i,0)*velocitySquared(idx,0)/mass(i,0);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class HeatCapacity
   //    computes the classical atomic heat capacity
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   HeatCapacity::HeatCapacity(ATC_Method * atc, AtomType atomType) :
     ConstantQuantity<double>(atc,1,1,atomType)
   {
     constant_ = (atc->nsd())*(lammpsInterface_->kBoltzmann());
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomicVelocityRescaleFactor
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   AtomicVelocityRescaleFactor::AtomicVelocityRescaleFactor(ATC_Method * atc,
                                                            PerAtomQuantity<double> * atomLambdas,
                                                            AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,1,atomType),
-    atomMasses_(NULL),
     atomLambdas_(atomLambdas)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
-    atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
-                                                                  atomType);
     if (!atomLambdas) {
       atomLambdas_ = interscaleManager.per_atom_quantity("AtomLambdaEnergy");
     }
-
-    atomMasses_->register_dependence(this);
     atomLambdas_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomicVelocityRescaleFactor::~AtomicVelocityRescaleFactor()
   {
-    atomMasses_->remove_dependence(this);
     atomLambdas_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomicVelocityRescaleFactor::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
-      const DENS_MAT & mass(atomMasses_->quantity());
       const DENS_MAT & lambda(atomLambdas_->quantity());
 
       for (int i = 0; i < quantity_.nRows(); i++) {
-        quantity_(i,0) = sqrt(lambda(i,0)/mass(i,0));
+        quantity_(i,0) = sqrt(lambda(i,0));
+      }
+    }
+  }
+
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class AtomicFluctuatingVelocityRescaled
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+
+  //--------------------------------------------------------
+  //  constructor
+  //--------------------------------------------------------
+  AtomicFluctuatingVelocityRescaled::AtomicFluctuatingVelocityRescaled(ATC_Method * atc,
+                                                                       PerAtomQuantity<double> * atomRescaleFactor,
+                                                                       PerAtomQuantity<double> * atomFluctuatingVelocity,
+                                                                       AtomType atomType) :
+    ProtectedAtomQuantity<double>(atc,atc->nsd(),atomType),
+    atomRescaleFactor_(atomRescaleFactor),
+    atomFluctuatingVelocity_(atomFluctuatingVelocity)
+  {
+    InterscaleManager & interscaleManager(atc->interscale_manager());
+    if (!atomRescaleFactor_) {
+      atomRescaleFactor_ = interscaleManager.per_atom_quantity("AtomVelocityRescaling");
+    }
+    if (!atomFluctuatingVelocity_) {
+      atomFluctuatingVelocity_ = interscaleManager.per_atom_quantity("AtomicFluctuatingVelocity");
+    }
+
+    atomRescaleFactor_->register_dependence(this);
+    atomFluctuatingVelocity_->register_dependence(this);
+  }
+
+  //--------------------------------------------------------
+  //  destructor
+  //--------------------------------------------------------
+  AtomicFluctuatingVelocityRescaled::~AtomicFluctuatingVelocityRescaled()
+  {
+    atomRescaleFactor_->remove_dependence(this);
+    atomFluctuatingVelocity_->remove_dependence(this);
+  }
+
+  //--------------------------------------------------------
+  //  reset
+  //--------------------------------------------------------
+  void AtomicFluctuatingVelocityRescaled::reset() const
+  {
+    if (need_reset()) {
+      PerAtomQuantity<double>::reset();
+      const DENS_MAT & factor(atomRescaleFactor_->quantity());
+      const DENS_MAT & v(atomFluctuatingVelocity_->quantity());
+
+      for (int i = 0; i < quantity_.nRows(); i++) {
+        for (int j = 0; j < quantity_.nCols(); j++) {
+          quantity_(i,j) = factor(i,0)*v(i,j);
+        }
+      }
+    }
+  }
+
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class AtomicCombinedRescaleThermostatError
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+
+  //--------------------------------------------------------
+  //  constructor
+  //--------------------------------------------------------
+  AtomicCombinedRescaleThermostatError::AtomicCombinedRescaleThermostatError(ATC_Method * atc,
+                                                                             PerAtomQuantity<double> * atomFluctuatingMomentumRescaled,
+                                                                             PerAtomQuantity<double> * atomMeanVelocity,
+                                                                             PerAtomQuantity<double> * atomStreamingVelocity,
+                                                                             PerAtomQuantity<double> * atomMass,
+                                                                             AtomType atomType) :
+    ProtectedAtomQuantity<double>(atc,1,atomType),
+    atomFluctuatingMomentumRescaled_(atomFluctuatingMomentumRescaled),
+    atomMeanVelocity_(atomMeanVelocity),
+    atomStreamingVelocity_(atomStreamingVelocity),
+    atomMass_(atomMass)
+  {
+    InterscaleManager & interscaleManager(atc->interscale_manager());
+    if (!atomFluctuatingMomentumRescaled_) {
+      atomFluctuatingMomentumRescaled_ = interscaleManager.per_atom_quantity("AtomFluctuatingMomentumRescaled");
+    }
+    if (!atomMeanVelocity_) {
+      atomMeanVelocity_ = interscaleManager.per_atom_quantity(field_to_prolongation_name(VELOCITY));
+    }
+    if (!atomStreamingVelocity_) {
+      atomStreamingVelocity_ = interscaleManager.per_atom_quantity("AtomLambdaMomentum");
+    }
+    if (!atomMass_) {
+      atomMass_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
+                                                              atomType);
+    }
+
+    atomFluctuatingMomentumRescaled_->register_dependence(this);
+    atomMeanVelocity_->register_dependence(this);
+    atomStreamingVelocity_->register_dependence(this);
+    atomMass_->register_dependence(this);
+  }
+
+  //--------------------------------------------------------
+  //  destructor
+  //--------------------------------------------------------
+  AtomicCombinedRescaleThermostatError::~AtomicCombinedRescaleThermostatError()
+  {
+    atomFluctuatingMomentumRescaled_->remove_dependence(this);
+    atomMeanVelocity_->remove_dependence(this);
+    atomStreamingVelocity_->remove_dependence(this);
+    atomMass_->remove_dependence(this);
+  }
+
+  //--------------------------------------------------------
+  //  reset
+  //--------------------------------------------------------
+  void AtomicCombinedRescaleThermostatError::reset() const
+  {
+    if (need_reset()) {
+      PerAtomQuantity<double>::reset();
+      const DENS_MAT & m(atomMass_->quantity());
+      const DENS_MAT & p(atomFluctuatingMomentumRescaled_->quantity());
+      const DENS_MAT & v(atomMeanVelocity_->quantity());
+      const DENS_MAT & s(atomStreamingVelocity_->quantity());
+
+      double diff;
+      for (int i = 0; i < quantity_.nRows(); i++) {
+        diff = s(i,0)-v(i,0);
+        quantity_(i,0) = 2.*p(i,0)*diff + m(i,0)*diff*diff;
+        for (int j = 1; j < p.nCols(); j++) {
+          diff = s(i,j)-v(i,j);
+          quantity_(i,0) += 2.*p(i,j)*diff + m(i,0)*diff*diff;
+        }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomicThermostatForce
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   AtomicThermostatForce::AtomicThermostatForce(ATC_Method * atc,
                                                PerAtomQuantity<double> * atomLambdas,
                                                PerAtomQuantity<double> * atomVelocities,
                                                AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,atc->nsd(),atomType),
     atomLambdas_(atomLambdas),
     atomVelocities_(atomVelocities)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomLambdas) {
       atomLambdas_ = interscaleManager.per_atom_quantity("AtomLambdaEnergy");
     }
     if (!atomVelocities_) {
       atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY,
                                                                     atomType);
     }
     
     atomLambdas_->register_dependence(this);
     atomVelocities_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomicThermostatForce::~AtomicThermostatForce()
   {
     atomLambdas_->remove_dependence(this);
     atomVelocities_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomicThermostatForce::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & v(atomVelocities_->quantity());
       const DENS_MAT & lambda(atomLambdas_->quantity());
       
       // force = -lambda*v
       quantity_ = v;
       quantity_ *= lambda;
       quantity_ *= -1.;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomicKinetostatForceDisplacement
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   AtomicKinetostatForceDisplacement::AtomicKinetostatForceDisplacement(ATC_Method * atc,
                                                PerAtomQuantity<double> * atomLambda,
                                                PerAtomQuantity<double> * atomMass,
                                                AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,atc->nsd(),atomType),
     atomLambda_(atomLambda),
     atomMass_(atomMass)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomLambda) {
       atomLambda_ = interscaleManager.per_atom_quantity("AtomLambdaMomentum");
     }
     if (!atomMass_) {
       atomMass_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS,
                                                               atomType);
     }
     
     atomLambda_->register_dependence(this);
     atomMass_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomicKinetostatForceDisplacement::~AtomicKinetostatForceDisplacement()
   {
     atomLambda_->remove_dependence(this);
     atomMass_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomicKinetostatForceDisplacement::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & m(atomMass_->quantity());
       const DENS_MAT & lambda(atomLambda_->quantity());
       double timeFactor = time_step_factor(0.5*atc_.dt());
       
       //force = -lambda*m*(timestep factor)
       quantity_ = lambda;
       quantity_ *= m;
       quantity_ *= -1.*timeFactor;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomicKinetostatForceStress
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   AtomicKinetostatForceStress::AtomicKinetostatForceStress(ATC_Method * atc,
                                                            PerAtomQuantity<double> * atomLambda,
                                                            AtomType atomType) :
     ProtectedAtomQuantity<double>(atc,atc->nsd(),atomType),
     atomLambda_(atomLambda)
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomLambda_) {
       atomLambda_ = interscaleManager.per_atom_quantity("AtomLambdaMomentum");
     }
     
     atomLambda_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   AtomicKinetostatForceStress::~AtomicKinetostatForceStress()
   {
     atomLambda_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void AtomicKinetostatForceStress::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & lambda(atomLambda_->quantity());
       
       // force = -lambda
       quantity_ = lambda;
       quantity_ *= -1.;
     }
   }
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class PerAtomKernelFunction
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   PerAtomKernelFunction::PerAtomKernelFunction(ATC_Method * atc,
                                                PerAtomQuantity<double> * atomPositions,
                                                AtomType atomType) :
     ProtectedAtomSparseMatrix<double>(atc,(atc->fe_engine())->num_nodes(),atc->accumulant_bandwidth(),atomType),
     atomPositions_(atomPositions),
     feEngine_(atc->fe_engine())
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomPositions_) {
       atomPositions_ = interscaleManager.per_atom_quantity("AtomicCoarseGrainingPositions");
     }
     atomPositions_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   PerAtomKernelFunction::~PerAtomKernelFunction()
   {
     atomPositions_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void PerAtomKernelFunction::reset() const
   {
     if (need_reset()) {
       PerAtomSparseMatrix<double>::reset();
       const DENS_MAT & positions(atomPositions_->quantity());
       if (positions.nRows() > 0) {
         feEngine_->evaluate_kernel_functions(positions,quantity_);
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class PerAtomShapeFunction
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   PerAtomShapeFunction::PerAtomShapeFunction(ATC_Method * atc,
                                              PerAtomQuantity<double> * atomPositions,
                                              PerAtomQuantity<int> * atomElements,
                                              AtomType atomType) :
     ProtectedAtomSparseMatrix<double>(atc,atc->num_nodes(),(atc->fe_engine())->num_nodes_per_element(),atomType),
     atomPositions_(atomPositions),
     atomElements_(atomElements),
     feEngine_(atc->fe_engine())
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomPositions_) {
       atomPositions_ = interscaleManager.per_atom_quantity("AtomicCoarseGrainingPositions");
     }
     if (!atomElements_) {
       atomElements_ = interscaleManager.per_atom_int_quantity("AtomElement");
     }
 
     atomPositions_->register_dependence(this);
     atomElements_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   PerAtomShapeFunction::~PerAtomShapeFunction()
   {
     atomPositions_->remove_dependence(this);
     atomElements_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void PerAtomShapeFunction::reset() const
   {
     if (need_reset()) {
       PerAtomSparseMatrix<double>::reset();
       const DENS_MAT & positions(atomPositions_->quantity());
       const INT_ARRAY & elements(atomElements_->quantity());
       if (positions.nRows() > 0) {
         feEngine_->evaluate_shape_functions(positions,
                                             elements,
                                             quantity_);
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LambdaCouplingMatrix
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   LambdaCouplingMatrix::LambdaCouplingMatrix(ATC_Method * atc,
                                              MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap,
                                              SPAR_MAN * shapeFunction) :
     ProtectedMappedAtomSparseMatrix<double>(atc,nodeToOverlapMap->size(),
                                             (atc->fe_engine())->num_nodes_per_element(),
                                             INTERNAL),
     shapeFunction_(shapeFunction),
     nodeToOverlapMap_(nodeToOverlapMap)
   {
     if (!shapeFunction_) {
       shapeFunction_ = (atc->interscale_manager()).per_atom_sparse_matrix("Interpolant");;
     }
     if (!nodeToOverlapMap_) {
       nodeToOverlapMap_ = (atc->interscale_manager()).dense_matrix_int("NodeToOverlapMap");
     }
     
     shapeFunction_->register_dependence(this);
     nodeToOverlapMap_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void LambdaCouplingMatrix::reset() const
   {
     if (need_reset()) {
       PerAtomSparseMatrix<double>::reset();
       int nNodeOverlap = nodeToOverlapMap_->size();
       const SPAR_MAT & shapeFunction(shapeFunction_->quantity());
       quantity_.reset(shapeFunction.nRows(),nNodeOverlap); // number of atoms X number of nodes overlapping MD region
       const INT_ARRAY nodeToOverlapMap(nodeToOverlapMap_->quantity());
     
       for (int i = 0; i < shapeFunction.size(); ++i) {
         TRIPLET<double> myTriplet = shapeFunction.triplet(i);
         int myCol = nodeToOverlapMap(myTriplet.j,0);
         if (myCol > -1) {
           quantity_.set(myTriplet.i,myCol,myTriplet.v);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class LocalLambdaCouplingMatrix
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   LocalLambdaCouplingMatrix::LocalLambdaCouplingMatrix(ATC_Method * atc,
                                                        MatrixDependencyManager<DenseMatrix, int> * lambdaAtomMap,
                                                        MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap,
                                                        SPAR_MAN * shapeFunction) :
     LambdaCouplingMatrix(atc,nodeToOverlapMap,shapeFunction),
     lambdaAtomMap_(lambdaAtomMap)
   {
     if (!lambdaAtomMap_) {
       lambdaAtomMap_ = (atc->interscale_manager()).dense_matrix_int("LambdaAtomMap");
     }
     
     lambdaAtomMap_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void LocalLambdaCouplingMatrix::reset() const
   {
     if (need_reset()) {
       PerAtomSparseMatrix<double>::reset();
       int nNodeOverlap = nodeToOverlapMap_->size();
       int nLocalLambda = lambdaAtomMap_->size();
 
       quantity_.reset(nLocalLambda,nNodeOverlap); // number of regulated atoms X number of nodes containing them
       const SPAR_MAT & shapeFunction(shapeFunction_->quantity());
       const INT_ARRAY nodeToOverlapMap(nodeToOverlapMap_->quantity());
       const INT_ARRAY lambdaAtomMap(lambdaAtomMap_->quantity());
       
       for (int i = 0; i < shapeFunction.size(); ++i) {
         TRIPLET<double> myTriplet = shapeFunction.triplet(i);
         int myRow = lambdaAtomMap(myTriplet.i,0);
         int myCol = nodeToOverlapMap(myTriplet.j,0);
         if ((myRow > -1) && (myCol > -1)) {
           quantity_.set(myRow,myCol,myTriplet.v);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class GhostCouplingMatrix
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   GhostCouplingMatrix::GhostCouplingMatrix(ATC_Method * atc,
                                            SPAR_MAN * shapeFunction,
                                            SetDependencyManager<int> * subsetNodes,
                                            MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap) :
     LambdaCouplingMatrix(atc,nodeToOverlapMap,shapeFunction),
     subsetNodes_(subsetNodes)
   {
     subsetNodes_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void GhostCouplingMatrix::reset() const
   {
     if (need_reset()) {
       PerAtomSparseMatrix<double>::reset();
       const SPAR_MAT & shapeFunction(shapeFunction_->quantity());
       const set<int> & subsetNodes(subsetNodes_->quantity());
       int nNodes = nodeToOverlapMap_->nRows();
       int nLocalGhost = shapeFunction.nRows();
       quantity_.reset(nLocalGhost,nNodes);
       const INT_ARRAY nodeToOverlapMap(nodeToOverlapMap_->quantity());
       for (int i = 0; i < shapeFunction.size(); ++i) {
         TRIPLET<double> myTriplet = shapeFunction.triplet(i);
         int myCol = myTriplet.j;
         if (nodeToOverlapMap(myCol,0) > -1) {
           quantity_.set(myTriplet.i,myCol,myTriplet.v);
         }
       }
       quantity_.compress();
       
       //int nNodes = nodeToOverlapMap_->nRows();
       _activeNodes_.reset(nNodes);
       for (int i = 0; i < nNodes; ++i) {
         if (subsetNodes.find(i) != subsetNodes.end()) {
           _activeNodes_(i) = 1.;
         }
       }
 
       //const SPAR_MAT & shapeFunction(shapeFunction_->quantity());
       //int nLocalGhost = shapeFunction.nRows();
       _weights_ = shapeFunction*_activeNodes_;
       _weightMatrix_.resize(nLocalGhost,nLocalGhost);
       for (int i = 0; i < nLocalGhost; ++i) {
         _weightMatrix_(i,i) = 1./_weights_(i);
       }
       quantity_ = _weightMatrix_*quantity_;
     }
   }
 };
diff --git a/lib/atc/PerAtomQuantityLibrary.h b/lib/atc/PerAtomQuantityLibrary.h
index e6847ef6a..dbc1f16e2 100644
--- a/lib/atc/PerAtomQuantityLibrary.h
+++ b/lib/atc/PerAtomQuantityLibrary.h
@@ -1,1727 +1,1804 @@
 // A library for defining various atomic quantities
 
 #ifndef PER_ATOM_QUANTITY_LIBRARY_H
 #define PER_ATOM_QUANTITY_LIBRARY_H
 
 #include "PerAtomQuantity.h"
 #include "FundamentalAtomicQuantity.h"
 #include <set>
 #include <map>
 #include <vector>
 #include <string>
 
 namespace ATC {
 
   // forward declarations
   class LammpsInterface;
   class FE_Mesh;
   class FE_Engine;
   template <class T> class DenseMatrixTransfer;
 
   // need to add capability to take in group bit (JAT, 04/02/11)
   /**
    *  @class  AtomNumber
    *  @brief  Class for identifying atoms based on a specified group
    */
 
   class AtomNumber : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomNumber(ATC_Method * atc, AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomNumber() {};
     
     /** reset the quantity */
     virtual void reset() const;
 
   protected:
 //  int groupBit_;
     ATC_Method * atc_;
 
   private:
 
     // do not define
     AtomNumber();
 
   };
 
   /**
    *  @class  AtomTypeVector
    *  @brief  Class for identifying atoms based on a specified group
    */
 
   class AtomTypeVector : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomTypeVector(ATC_Method * atc, std::vector<int> typeList,
       AtomType atomType = INTERNAL);
     AtomTypeVector(ATC_Method * atc, std::vector<int> typeList, std::vector<int> grpList,
       AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomTypeVector() {};
     
     /** reset the quantity */
     virtual void reset() const;
 
   protected:
     ATC_Method * atc_;
     int ntypes_;
     std::vector<int> typeList_,index_; // lammps->atc & atc->lammps
     std::vector<int> groupList_; 
 
   private:
     AtomTypeVector(); // do not define
 
   };
 
   
   //      inherited classes are used for this task because
   //      lammps changes pointer location so it can only be
   //      accessed by functions
   /**
    *  @class  XrefWrapper
    *  @brief  Class for wrapping the xref_ array
    */
   
   class XrefWrapper : public ProtectedClonedAtomQuantity<double> {
     
   public:
     
     // constructor
     XrefWrapper(ATC_Method * atc, AtomType atomType=INTERNAL);
     
     // destructor
     virtual ~XrefWrapper() {};
     
   protected:
     
     /** pointer to atc to access raw pointer */
     ATC_Method * atc_;
 
     /** gets appropriate pointer for lammps data */
     double ** lammps_vector() const;
     
   private:
 
     // do not define
     XrefWrapper();
     
   };
   
   /**
    *  @class  AtomToElementMap
    *  @brief  Class for identifying the element associated with an atom
    */
 
   class AtomToElementMap : public ProtectedAtomQuantity<int> {
 
   public:
 
     // constructor
     AtomToElementMap(ATC_Method * atc,
                      PerAtomQuantity<double> * atomPositions = NULL,
                      AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomToElementMap();
 
   protected:
 
     /** resets the data if necessary */
     virtual void reset() const;
 
     /** atomic positions */
     PerAtomQuantity<double> * atomPositions_;
 
   private:
 
     // do not define
     AtomToElementMap();
 
   };
 
   /**
    *  @class  AtomToElementMap
    *  @brief  Class list of atoms in an element set
    */
 
   class AtomInElementSet : public DependencyManager {
 
   public:
 
     // constructor
     AtomInElementSet(ATC_Method * atc,
                      PerAtomQuantity<int> * map,
                      ESET eset, int type); 
 
     // destructor
     virtual ~AtomInElementSet();
 
     // accessors
     virtual const ID_LIST & quantity(); 
     virtual ID_LIST & set_quantity() {return list_;}
     int size() {if (needReset_) reset(); return list_.size(); }
     ID_PAIR item(int i) {if (needReset_) reset(); return list_[i]; }
   protected:
 
     /** resets the data if necessary */
     virtual void reset();
 
     PaqAtcUtility atc_;
 
     /** atom to element map */
     PerAtomQuantity<int> * map_;
     ESET eset_;
     int type_;
     const Array<int> & quantityToLammps_;
     ID_LIST list_;
 
   private:
 
     // do not define
     AtomInElementSet();
 
   };
 
   /**
    *  @class  AtomVolumeUser
    *  @brief  Class for defining the volume per atom based on a user specification
    */
 
   class AtomVolumeUser : public ProtectedAtomDiagonalMatrix<double> {
 
   public:
 
     // constructor
     AtomVolumeUser(ATC_Method * atc,
                    std::map<int,double> & atomGroupVolume,
                    AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomVolumeUser() {};
 
   protected:
 
     /** resets the data if necessary */
     virtual void reset() const;
 
     /** reference to the map of atom group ids to atom volumes */
     std::map<int,double> & atomGroupVolume_;
 
     /** pointer to lammps interface */
     const LammpsInterface * lammpsInterface_;
 
     /** map from atc indices to lammps indices */
     const Array<int> & atcToLammps_;
 
   private:
 
     // do not define
     AtomVolumeUser();
 
   };
 
   /**
    *  @class  AtomVolumeGroup
    *  @brief  Class for defining the volume per atom based on the atom count in a group and its volume
    */
 
   class AtomVolumeGroup : public AtomVolumeUser {
 
   public:
 
     // constructor
     AtomVolumeGroup(ATC_Method * atc,
                     std::map<int,double> & atomGroupVolume,
                     AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomVolumeGroup() {};
 
   protected:
 
     /** map from group to group atom volume */
     std::map<int,double> atomGroupVolume_;
 
     /** pointer to lammps interface */
     const LammpsInterface * lammpsInterface_;
     
     /** reference to array mapping atc indices to lammps indices */
     const Array<int> & atcToLammps_;
 
   private:
 
     // do not define
     AtomVolumeGroup();
 
   };
 
   /**
    *  @class  AtomVolumeLattice
    *  @brief  Class for defining the volume per atom based on the lattice type and size
    */
 
   class AtomVolumeLattice : public ProtectedAtomDiagonalMatrix<double> {
 
   public:
 
     // constructor
     AtomVolumeLattice(ATC_Method * atc,
                       AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomVolumeLattice() {};
 
   protected:
 
     /** resets the data if necessary */
     virtual void reset() const;
 
     /** pointer to lammps interface */
     const LammpsInterface * lammpsInterface_;
 
   private:
 
     // do not define
     AtomVolumeLattice();
 
   };
 
   /**
    *  @class  AtomVolumeElement
    *  @brief  Class for defining the volume per atom based on the atom count per element and elemental volume
    */
 
   class AtomVolumeElement : public ProtectedAtomDiagonalMatrix<double> {
 
   public:
 
     // constructor
     AtomVolumeElement(ATC_Method * atc,
                       PerAtomQuantity<int> * atomElement = NULL,
                       AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomVolumeElement();
 
   protected:
 
     /** resets the data if necessary */
     virtual void reset() const;
 
     /** pointer to the atom to element map */
     PerAtomQuantity<int> * atomElement_;
 
     /** pointer to lammps interface */
     const LammpsInterface * lammpsInterface_;
 
     /** pointer to mesh object */
     const FE_Mesh * feMesh_;
 
     // workspace variables
     mutable INT_VECTOR _elementAtomCountLocal_;
     mutable INT_VECTOR _elementAtomCount_;
     mutable DENS_VEC _elementAtomVolume_;
     mutable DENS_MAT _nodalCoordinates_;
 
   private:
 
     // do not define
     AtomVolumeElement();
 
   };
 
   /**
    *  @class  AtomVolumeRegion
    *  @brief  Class for defining the volume per atom based on the atom count in the MD regions and their volumes.
    *          It will only be meaningful if atoms completely fill all the regions.
    */
 
   class AtomVolumeRegion : public ProtectedAtomDiagonalMatrix<double> {
 
   public:
 
     // constructor
     AtomVolumeRegion(ATC_Method * atc,
                      DENS_MAN * atomCoarseGrainingPositions = NULL,
                      AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomVolumeRegion();
 
   protected:
 
     /** resets the data if necessary */
     virtual void reset() const;
 
     /** pointer to atomic coordinates data */
     DENS_MAN * atomCoarseGrainingPositions_;
 
     /** pointer to lammps interface */
     const LammpsInterface * lammpsInterface_;
 
     /** vector from region index to volume */
     DENS_VEC regionalAtomVolume_;
 
   private:
 
     // do not define
     AtomVolumeRegion();
 
   };
 
   /**
    *  @class  AtomVolumeFile
    *  @brief  Class for defining the volume per atom based on data read in from a file
    */
 
   class AtomVolumeFile : public ProtectedAtomDiagonalMatrix<double> {
 
   public:
 
     // constructor
     AtomVolumeFile(ATC_Method * atc,
                    const std::string & atomVolumeFile,
                    AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomVolumeFile() {};
 
   protected:
 
     /** resets the data if necessary */
     virtual void reset() const;
 
     /** file name containing the atomic information */
     const std::string & atomVolumeFile_;
 
     /** pointer to lammps interface */
     const LammpsInterface * lammpsInterface_;
 
   private:
 
     // do not define
     AtomVolumeFile();
 
   };
 
   /**
    *  @class  AtomicMassWeightedDisplacement
    *  @brief  Class for computing the precursor atomic quantity m*(x - x_ref)
    */
   
   class AtomicMassWeightedDisplacement : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomicMassWeightedDisplacement(ATC_Method * atc,
                           PerAtomQuantity<double> * atomPositions = NULL,
                           PerAtomQuantity<double> * atomMasses = NULL,
                           PerAtomQuantity<double> * atomReferencePositions = NULL,
                           AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomicMassWeightedDisplacement();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic positions */
     PerAtomQuantity<double> * atomPositions_;
     
     /** atomic masses */
     PerAtomQuantity<double> * atomMasses_;
 
     /** atomic reference positions */
     PerAtomQuantity<double> * atomReferencePositions_;
 
   private:
     
     // do not define
     AtomicMassWeightedDisplacement();
 
   };
 
   /**
    *  @class  FluctuatingVelocity 
    *  @brief  Class for computing the atomic quantity v - bar{v}
    */
   
   class FluctuatingVelocity : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     FluctuatingVelocity(ATC_Method * atc,
                        PerAtomQuantity<double> * atomVelocities = NULL,
                        PerAtomQuantity<double> * atomMeanVelocities = NULL,
                        AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~FluctuatingVelocity();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
     /** atomic mean velocities */
     PerAtomQuantity<double> * atomMeanVelocities_;
   private:
     
     // do not define
     FluctuatingVelocity();
 
   };
 
   /**
    *  @class  ChargeVelcity
    *  @brief  Class for computing the atomic quantity q v'
    */
   
   class ChargeVelocity : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     ChargeVelocity(ATC_Method * atc,
                        PerAtomQuantity<double> * fluctuatingVelocities = NULL,
                        FundamentalAtomQuantity * atomCharges = NULL,
                        AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~ChargeVelocity();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * fluctuatingVelocities_;
 
     /** atomic mean velocities */
     FundamentalAtomQuantity * atomCharge_;
   private:
     
     // do not define
     ChargeVelocity();
 
   };
 
   /**
    *  @class  SpeciesVelcity
    *  @brief  Class for computing the atomic quantity m^(a) v'
    */
   
   class SpeciesVelocity : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     SpeciesVelocity(ATC_Method * atc,
                        PerAtomQuantity<double> * fluctuatingVelocities = NULL,
                        PerAtomQuantity<double> * atomTypeVector = NULL,
                        AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~SpeciesVelocity();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * fluctuatingVelocities_;
 
     /** atomic mean velocities */
     PerAtomQuantity<double> * atomTypeVector_;
   private:
     
     // do not define
     SpeciesVelocity();
 
   };
 
   /**
    *  @class  AtomicMomentum
    *  @brief  Class for computing the precursor atomic quantity m*v
    */
   
   class AtomicMomentum : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomicMomentum(ATC_Method * atc,
                    PerAtomQuantity<double> * atomVelocities = NULL,
                    PerAtomQuantity<double> * atomMasses = NULL,
                    AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomicMomentum();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
     /** atomic masses */
     PerAtomQuantity<double> * atomMasses_;
 
   private:
     
     // do not define
     AtomicMomentum();
 
   };
 
   /**
    *  @class  AtomicEnergyForTemperature 
    *  @brief  Base class for accessing quantities needed for computing temperature 
    */
   
   class AtomicEnergyForTemperature : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomicEnergyForTemperature(ATC_Method * atc,
                                AtomType atomType = INTERNAL)
       : ProtectedAtomQuantity<double>(atc, 1, atomType) {};
 
     // destructor
     virtual ~AtomicEnergyForTemperature() {};
 
     // returns coefficient which multiplies kinetic energy in temperature definition
     virtual double kinetic_energy_multiplier() const = 0;
 
   private:
     
     // do not define
     AtomicEnergyForTemperature();
 
   };
 
   /**
    *  @class  TwiceKineticEnergy 
    *  @brief  Class for computing the precursor atomic quantity m*v*v 
    *          (used when the kinetic definition of temperature is required)
    */
   
   class TwiceKineticEnergy : public AtomicEnergyForTemperature {
 
   public:
 
     // constructor
     TwiceKineticEnergy(ATC_Method * atc,
                        PerAtomQuantity<double> * atomVelocities = NULL,
                        PerAtomQuantity<double> * atomMasses = NULL,
                        AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~TwiceKineticEnergy();
 
     // returns coefficient which multiplies kinetic energy in temperature definition
     virtual double kinetic_energy_multiplier() const {return 2.;};
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
     /** atomic masses */
     PerAtomQuantity<double> * atomMasses_;
 
   private:
     
     // do not define
     TwiceKineticEnergy();
 
   };
 
   /**
    *  @class  KineticTensor 
    *  @brief  Class for computing the atomic quantity m v (x) v 
    */
   
   class KineticTensor : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     KineticTensor(ATC_Method * atc,
                        PerAtomQuantity<double> * atomVelocities = NULL,
                        PerAtomQuantity<double> * atomMasses = NULL,
                        AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~KineticTensor();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
     /** atomic masses */
     PerAtomQuantity<double> * atomMasses_;
 
   private:
     
     // do not define
     KineticTensor();
 
   };
 
 
   /**
    *  @class  FluctuatingKineticTensor 
    *  @brief  Class for computing the atomic quantity m v (x) v 
    */
   
   class FluctuatingKineticTensor : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     FluctuatingKineticTensor(ATC_Method * atc,
                        PerAtomQuantity<double> * atomVelocities = NULL,
                        PerAtomQuantity<double> * atomMasses = NULL,
                        PerAtomQuantity<double> * atomMeanVelocities = NULL,
                        AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~FluctuatingKineticTensor();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
     /** atomic masses */
     PerAtomQuantity<double> * atomMasses_;
 
     /** atomic mean velocities */
     PerAtomQuantity<double> * atomMeanVelocities_;
   private:
     
     // do not define
     FluctuatingKineticTensor();
 
   };
 
   /**
    *  @class  TwiceFluctuatingKineticEnergy 
    *  @brief  Class for computing the precursor atomic quantity m*(v-vr)*(v-vr) 
    *          (used when the kinetic definition of temperature is required)
    */
   
   class TwiceFluctuatingKineticEnergy : public AtomicEnergyForTemperature {
 
   public:
 
     // constructor
     TwiceFluctuatingKineticEnergy(ATC_Method * atc,
                                   PerAtomQuantity<double> * atomVelocities = NULL,
                                   PerAtomQuantity<double> * atomMasses = NULL,
                                   PerAtomQuantity<double> * atomMeanVelocities = NULL,
                                   AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~TwiceFluctuatingKineticEnergy();
 
     // returns coefficient which multiplies kinetic energy in temperature definition
     virtual double kinetic_energy_multiplier() const {return 2.;};
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
     /** atomic masses */
     PerAtomQuantity<double> * atomMasses_;
 
     /** atomic mean velocities */
     PerAtomQuantity<double> * atomMeanVelocities_;
 
   private:
     
     // do not define
     TwiceFluctuatingKineticEnergy();
 
   };
 
   /**
    *  @class  MixedKePeEnergy
    *  @brief  Class for computing the precursor atomic quantity for 
    *          a mixed temperature definition involving both KE and PE
    */
   
   class MixedKePeEnergy : public AtomicEnergyForTemperature {
 
   public:
 
     // constructor
     MixedKePeEnergy(ATC_Method * atc,
                     double keMultiplier,
                     double peMultiplier,
                     PerAtomQuantity<double> * twiceKineticEnergy = NULL,
                     PerAtomQuantity<double> * potentialEnergy = NULL,
                     AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~MixedKePeEnergy();
 
     // returns coefficient which multiplies kinetic energy in temperature definition
     virtual double kinetic_energy_multiplier() const {return keMultiplier_;};
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** factor multiplying kinetic energy */
     double keMultiplier_;
 
     /** factor multiplying potential energy */
     double peMultiplier_;
 
     /** twice the kinetic energy of each atom */
     PerAtomQuantity<double> * twiceKineticEnergy_;
 
     /** potential energy of each atom */
     PerAtomQuantity<double> * potentialEnergy_;
 
   private:
     
     // do not define
     MixedKePeEnergy();
 
   };
 
   /**
    *  @class  TotalEnergy
    *  @brief  Class for the atomic total energy
    */
   
   class TotalEnergy : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     TotalEnergy(ATC_Method * atc,
                 PerAtomQuantity<double> * twiceKineticEnergy = NULL,
                 PerAtomQuantity<double> * potentialEnergy = NULL,
                 AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~TotalEnergy();
 
   protected:
     /** handles resetting of data */
     virtual void reset() const;
 
     /** twice the kinetic energy of each atom */
     PerAtomQuantity<double> * twiceKineticEnergy_;
 
     /** potential energy of each atom */
     PerAtomQuantity<double> * potentialEnergy_;
 
   private:
     TotalEnergy(); // do not define
   };
 
   /**
    *  @class  FluctuatingPotentialEnergy
    *  @brief  Class for computing the precursor atomic quantity for 
    *          a configurational (PE-based) temperature
    */
   
   class FluctuatingPotentialEnergy : public AtomicEnergyForTemperature {
 
   public:
 
     // constructor
     FluctuatingPotentialEnergy(ATC_Method * atc,
                                PerAtomQuantity<double> * potentialEnergy = NULL,
                                PerAtomQuantity<double> * referencePotential = NULL,
                                AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~FluctuatingPotentialEnergy();
 
     // returns coefficient which multiplies kinetic energy in temperature definition
     virtual double kinetic_energy_multiplier() const {return 0.;;};
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** potential energy of each atom */
     PerAtomQuantity<double> * potentialEnergy_;
 
     /** twice the kinetic energy of each atom */
     PerAtomQuantity<double> * referencePotential_;
 
   private:
     
     // do not define
     FluctuatingPotentialEnergy();
 
   };
 
   /**
    *  @class  DotTwiceKineticEnergy 
    *  @brief  Class for computing the precursor atomic power 2*v*f 
    *          (used when the kinetic definition of temperature is required)
    */
  
   class DotTwiceKineticEnergy : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     DotTwiceKineticEnergy(ATC_Method * atc,
                           PerAtomQuantity<double> * atomForces = NULL,
                           PerAtomQuantity<double> * atomVelocities = NULL,
                           AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~DotTwiceKineticEnergy();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic forces */
     PerAtomQuantity<double> * atomForces_;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
   private:
     
     // do not define
     DotTwiceKineticEnergy();
 
   };
 
   /**
    *  @class  VelocitySquared
    *  @brief  Class for computing the quantity |v|^2
    *          (used for weights in the thermostat)
    */
  
   class VelocitySquared : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     VelocitySquared(ATC_Method *atc,
                     PerAtomQuantity<double> * atomVelocities = NULL,
                     AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~VelocitySquared();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
   private:
 
     // do not define
     VelocitySquared();
 
   };
 
   /**
    *  @class  LambdaSquared
    *  @brief  Class for computing the 2nd order RHS fractional step
    *          contribution to the equation for lambda, with appropriate weights
    */
  
   class LambdaSquared : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     LambdaSquared(ATC_Method *atc,
                   PerAtomQuantity<double> * atomMasses = NULL,
                   PerAtomQuantity<double> * atomVelocitiesSquared = NULL,
                   PerAtomQuantity<double> * atomLambdas = NULL,
                   AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~LambdaSquared();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic masses */
     PerAtomQuantity<double> * atomMasses_;
 
     /** atomic velocities squared */
     PerAtomQuantity<double> * atomVelocitiesSquared_;
 
     /** atomic lambdas */
     PerAtomQuantity<double> * atomLambdas_;
 
   private:
 
     // do not define
     LambdaSquared();
 
   };
 
   /**
    *  @class  LargeToSmallAtomMap
    *  @brief  mapping from a larger set of atoms to a smaller set
    *          this implementation maximizes storage but reduces execution times,
    *          including taking advantage of MPI communcation
    */
 
   class LargeToSmallAtomMap : public ProtectedAtomQuantity<int> {
 
   public:
     
     // constructor
     LargeToSmallAtomMap(ATC_Method * atc,
                         AtomType atomType = INTERNAL)
     : ProtectedAtomQuantity<int>(atc,1,atomType), size_(0) {};
     
     // destructor
     virtual ~LargeToSmallAtomMap() {};
 
     /** change map when atoms change */
     virtual void reset_nlocal() {this->set_reset();};
 
     /** get the number of elements associated with the map */
     virtual int size() const {this->quantity(); return size_;};
 
     /** sets quantity to lammps data, if needed, should be called in pre_exchange */
     virtual void prepare_exchange() {};
 
     /** sets quantity to lammps data, if needed */
     virtual void post_exchange() {this->set_reset();};
 
     /** returns how much lammps memory is used in this function */
     virtual int memory_usage() const {return 0;};
 
     /** packs up data for parallel transfer when atoms change processors */
     virtual int pack_exchange(int i, double *buffer) {return 0;};
 
     /** unpacks data after parallel transfer when atoms change processors */
     virtual int unpack_exchange(int i, double *buffer) {return 0;};
 
     /** packs up data for parallel transfer to ghost atoms on other processors */
     virtual int pack_comm(int index, double *buf, 
                           int pbc_flag, int *pbc) {return 0;};
 
     /** unpacks data after parallel transfer to ghost atoms on other processors */
     virtual int unpack_comm(int index, double *buf) {return 0;};
 
     /** returns size of per-atom communication */
     virtual int size_comm() {return 0;};
 
     /** changes size of temperary lammps storage data if transfer is being used */
     virtual void grow_lammps_array(int nmax, const std::string & tag) {};
 
     /** rearrange memory of temporary lammps storage data, called from copy_array */
     virtual void copy_lammps_array(int i, int j) {};
 
   protected:
 
     /** number of nodes in the map */
     mutable int size_;
 
   };
 
   /**
    *  @class  AtomToType
    *  @brief  mapping from all atoms to the subset of atoms of a specified type
    */
 
   class AtomToType : public LargeToSmallAtomMap {
 
   public:
     
     // constructor
     AtomToType(ATC_Method * atc,
                int type,
                AtomType atomType = INTERNAL);
     
     // destructor
     virtual ~AtomToType() {};
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** tag for type */
     int type_;
 
   private:
 
     // do not define
     AtomToType();
 
   };
 
   /**
    *  @class  AtomToGroup
    *  @brief  mapping from all atoms to the subset of atoms of a specified group
    */
 
   class AtomToGroup : public LargeToSmallAtomMap {
 
   public:
     
     // constructor
     AtomToGroup(ATC_Method * atc,
                 int group,
                 AtomType atomType = INTERNAL);
     
     // destructor
     virtual ~AtomToGroup() {};
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** tag for group */
     int group_;
 
   private:
 
     // do not define
     AtomToGroup();
 
   };
 
   /**
    *  @class  AtomToNodeset
    *  @brief  mapping from all atoms to a subset of nodes
    */
 
   class AtomToNodeset : public LargeToSmallAtomMap {
 
   public:
     
     // constructor
     AtomToNodeset(ATC_Method * atc,
                   SetDependencyManager<int> * subsetNodes,
                   PerAtomQuantity<int> * atomElement = NULL,
                   AtomType atomType = INTERNAL);
     
     // destructor
     virtual ~AtomToNodeset() {
       atomElement_->remove_dependence(this);
       subsetNodes_->remove_dependence(this);
     };
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** set of nodes which are being regulated */
     SetDependencyManager<int> * subsetNodes_;
 
     /** map from atom to element in which it resides */
     PerAtomQuantity<int> * atomElement_;
 
     /** pointer to the finite element engine */
     const FE_Mesh * feMesh_;
 
     // workspace
     mutable Array<int> _nodes_; // nodes associated with an element
 
   private:
 
     // do not define
     AtomToNodeset();
 
   };
 
   /**
    *  @class  AtomToElementset
    *  @brief  mapping from all atoms to a subset of elements
    */
 
   class AtomToElementset : public LargeToSmallAtomMap {
 
   public:
     
     // constructor
     AtomToElementset(ATC_Method * atc,
                      MatrixDependencyManager<DenseMatrix, bool> * elementMask,
                      PerAtomQuantity<int> * atomElement = NULL,
                      AtomType atomType = INTERNAL);
     
     // destructor
     virtual ~AtomToElementset();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** set of nodes which are being regulated */
     MatrixDependencyManager<DenseMatrix, bool> * elementMask_;
 
     /** map from atom to element in which it resides */
     PerAtomQuantity<int> * atomElement_;
 
     /** pointer to the finite element engine */
     const FE_Mesh * feMesh_;
 
   private:
 
     // do not define
     AtomToElementset();
 
   };
 
   /**
    *  @class  MappedAtomQuantity
    *  @brief  generic reduced mapping
    */
   
   class MappedAtomQuantity : public ProtectedMappedAtomQuantity<double> {
 
   public:
     
     // constructor
     MappedAtomQuantity(ATC_Method * atc,
                        PerAtomQuantity<double> * source,
                        LargeToSmallAtomMap * map,
                        AtomType atomType = INTERNAL);
     
     // destructor
     virtual ~MappedAtomQuantity() {
       source_->remove_dependence(this);
       map_->remove_dependence(this);
     };
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** original quantity */
     PerAtomQuantity<double> * source_;
 
     /** mapping transfer */
     LargeToSmallAtomMap * map_;
 
   private:
 
     // do not define
     MappedAtomQuantity();
 
   };
 
   /**
    *  @class  VelocitySquaredMapped
    *  @brief  Class for computing the quantity |v|^2 on a subset of atoms
    *          (used for weights in the thermostat)
    */
  
   class VelocitySquaredMapped : public ProtectedMappedAtomQuantity<double> {
 
   public:
 
     // constructor
     VelocitySquaredMapped(ATC_Method *atc,
                           MatrixDependencyManager<DenseMatrix, int> * atomMap,
                           PerAtomQuantity<double> * atomVelocities = NULL,
                           AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~VelocitySquaredMapped();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
   private:
 
     // do not define
     VelocitySquaredMapped();
 
   };
 
     /**
    *  @class  LambdaSquaredMapped
    *  @brief  Class for computing the 2nd order RHS fractional step
    *          contribution to the equation for lambda, with appropriate weights
    */
  
   class LambdaSquaredMapped : public ProtectedMappedAtomQuantity<double> {
 
   public:
 
     // constructor
     LambdaSquaredMapped(ATC_Method *atc,
                         MatrixDependencyManager<DenseMatrix, int> * atomMap,
                         PerAtomQuantity<double> * atomMasses = NULL,
                         PerAtomQuantity<double> * atomVelocitiesSquared = NULL,
                         PerAtomQuantity<double> * atomLambdas = NULL,
                         AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~LambdaSquaredMapped();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic masses */
     PerAtomQuantity<double> * atomMasses_;
 
     /** atomic velocities squared */
     PerAtomQuantity<double> * atomVelocitiesSquared_;
 
     /** atomic lambdas */
     PerAtomQuantity<double> * atomLambdas_;
 
   private:
 
     // do not define
     LambdaSquaredMapped();
 
   };
 
   /**
    *  @class  HeatCapacity 
    *  @brief  Class for the classical atomic heat capacity 
    */
   
   class HeatCapacity : public ConstantQuantity<double> {
 
   public:
 
     // constructor
     HeatCapacity(ATC_Method * atc, AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~HeatCapacity() {};
 
   protected:
 
   private:
     
     // do not define
     HeatCapacity();
 
   };
 
   /**
    *  @class  AtomicVelocityRescaleFactor 
    *  @brief  Class for computing the atomic rescaling induced by the rescaling thermostat 
    */
  
   class AtomicVelocityRescaleFactor : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomicVelocityRescaleFactor(ATC_Method * atc,
                                 PerAtomQuantity<double> * atomLambdas = NULL,
                                 AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomicVelocityRescaleFactor();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
-    /** atomic masses */
-    FundamentalAtomQuantity * atomMasses_;
-
     /** atomic lambdas */
     PerAtomQuantity<double> * atomLambdas_;
 
   private:
     
     // do not define
     AtomicVelocityRescaleFactor();
 
   };
 
+  /**
+   *  @class  AtomicFluctuatingVelocityRescaled 
+   *  @brief  Class for computing the atomic rescaling of the velocity fluctuations by the rescaling thermostat 
+   */
+ 
+  class AtomicFluctuatingVelocityRescaled : public ProtectedAtomQuantity<double> {
+
+  public:
+
+    // constructor
+    AtomicFluctuatingVelocityRescaled(ATC_Method * atc,
+                                      PerAtomQuantity<double> * atomRescaleFactor = NULL,
+                                      PerAtomQuantity<double> * atomFluctuatingVelocity = NULL,
+                                      AtomType atomType = INTERNAL);
+
+    // destructor
+    virtual ~AtomicFluctuatingVelocityRescaled();
+
+  protected:
+
+    /** handles resetting of data */
+    virtual void reset() const;
+
+    /** atomic rescaling factor */
+    PerAtomQuantity<double> * atomRescaleFactor_;
+
+    /** atomic fluctuating velocity */
+    PerAtomQuantity<double> * atomFluctuatingVelocity_;
+
+  private:
+    
+    // do not define
+    AtomicFluctuatingVelocityRescaled();
+
+  };
+
+  /**
+   *  @class  AtomicCombinedRescaleThermostatError 
+   *  @brief  Class for computing the atomic error in the rescaling thermostat when used in combination with a specified streaming velocity 
+   */
+ 
+  class AtomicCombinedRescaleThermostatError : public ProtectedAtomQuantity<double> {
+
+  public:
+
+    // constructor
+    AtomicCombinedRescaleThermostatError(ATC_Method * atc,
+                                         PerAtomQuantity<double> * atomFluctuatingMomentumRescaled = NULL,
+                                         PerAtomQuantity<double> * atomMeanVelocity = NULL,
+                                         PerAtomQuantity<double> * atomStreamingVelocity = NULL,
+                                         PerAtomQuantity<double> * atomMass = NULL,
+                                         AtomType atomType = INTERNAL);
+
+    // destructor
+    virtual ~AtomicCombinedRescaleThermostatError();
+
+  protected:
+
+    /** handles resetting of data */
+    virtual void reset() const;
+
+    /** atomic rescaled fluctuating momentum */
+    PerAtomQuantity<double> * atomFluctuatingMomentumRescaled_;
+
+    /** atomic mean (prolonged FE) velocity */
+    PerAtomQuantity<double> * atomMeanVelocity_;
+
+    /** atomic streaming velocity, as computed by rescaling kinetothermostat */
+    PerAtomQuantity<double> * atomStreamingVelocity_;
+
+    /** atomic masses */
+    PerAtomQuantity<double> * atomMass_;
+
+  private:
+    
+    // do not define
+    AtomicCombinedRescaleThermostatError();
+
+  };
+
   /**
    *  @class  AtomicThermostatForce 
    *  @brief  Class for computing the atomic force induced by the GLC-based thermostats 
    */
   
   class AtomicThermostatForce : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomicThermostatForce(ATC_Method * atc,
                           PerAtomQuantity<double> * atomLambdas = NULL,
                           PerAtomQuantity<double> * atomVelocities = NULL,
                           AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomicThermostatForce();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic lambdas */
     PerAtomQuantity<double> * atomLambdas_;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomVelocities_;
 
   private:
     
     // do not define
     AtomicThermostatForce();
 
   };
 
   /**
    *  @class  AtomicKinetostatForceDisplacement 
    *  @brief  Class for computing the atomic force induced by the GLC-based kinetostats 
    */
   
   class AtomicKinetostatForceDisplacement : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomicKinetostatForceDisplacement(ATC_Method * atc,
                                       PerAtomQuantity<double> * atomLambda = NULL,
                                       PerAtomQuantity<double> * atomMass = NULL,
                                       AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomicKinetostatForceDisplacement();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** computes the multiplication factor assocaited with the controlled quantity being an integral of the degrees of freedom */
     virtual double time_step_factor(double dt) const {return 1./dt/dt;};
 
     /** atomic lambdas */
     PerAtomQuantity<double> * atomLambda_;
 
     /** atomic velocities */
     PerAtomQuantity<double> * atomMass_;
 
   private:
     
     // do not define
     AtomicKinetostatForceDisplacement();
 
   };
 
   /**
    *  @class  AtomicKinetostatForceVelocity
    *  @brief  Class for computing the atomic force induced by the GLC-based kinetostats 
    */
   
   class AtomicKinetostatForceVelocity : public AtomicKinetostatForceDisplacement {
 
   public:
 
     // constructor
     AtomicKinetostatForceVelocity(ATC_Method * atc,
                                   PerAtomQuantity<double> * atomLambda = NULL,
                                   PerAtomQuantity<double> * atomMass = NULL,
                                   AtomType atomType = INTERNAL) :
       AtomicKinetostatForceDisplacement(atc,atomLambda,atomMass,atomType) {};
 
     // destructor
     virtual ~AtomicKinetostatForceVelocity() {};
 
   protected:
 
     /** computes the multiplication factor assocaited with the controlled quantity being an integral of the degrees of freedom */
     virtual double time_step_factor(double dt) const {return 1./dt;};
 
   private:
 
     // do not define
     AtomicKinetostatForceVelocity();
 
   };
 
   /**
    *  @class  AtomicKinetostatForceStress
    *  @brief  Class for computing the atomic force induced by the stress-based kinetostats 
    */
   
   class AtomicKinetostatForceStress : public ProtectedAtomQuantity<double> {
 
   public:
 
     // constructor
     AtomicKinetostatForceStress(ATC_Method * atc,
                                 PerAtomQuantity<double> * atomLambda = NULL,
                                 AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~AtomicKinetostatForceStress();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic lambdas */
     PerAtomQuantity<double> * atomLambda_;
 
   private:
     
     // do not define
     AtomicKinetostatForceStress();
 
   };
 
   /**
    *  @class  PerAtomKernelFunction
    *  @brief  Class for computing the kernel function at each atom location
    */
   
   class PerAtomKernelFunction : public ProtectedAtomSparseMatrix<double> {
 
   public:
 
     // constructor
     PerAtomKernelFunction(ATC_Method * atc,
                           PerAtomQuantity<double> * atomPositions = NULL,
                           AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~PerAtomKernelFunction();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic coarse-graining positions */
     PerAtomQuantity<double> * atomPositions_;
 
     /** finite element engine */
     const FE_Engine * feEngine_;
 
   private:
     
     // do not define
     PerAtomKernelFunction();
 
   };
 
   /**
    *  @class  PerAtomShapeFunction
    *  @brief  Class for computing the shape function at each atom location
    */
   
   class PerAtomShapeFunction : public ProtectedAtomSparseMatrix<double> {
 
   public:
 
     // constructor
     PerAtomShapeFunction(ATC_Method * atc,
                          PerAtomQuantity<double> * atomPositions = NULL,
                          PerAtomQuantity<int> * atomElements = NULL,
                          AtomType atomType = INTERNAL);
 
     // destructor
     virtual ~PerAtomShapeFunction();
 
   protected:
 
     /** handles resetting of data */
     virtual void reset() const;
 
     /** atomic coarse-graining positions */
     PerAtomQuantity<double> * atomPositions_;
 
     /** atom to element map */
     PerAtomQuantity<int> * atomElements_;
 
     /** finite element engine */
     const FE_Engine * feEngine_;
 
   private:
     
     // do not define
     PerAtomShapeFunction();
 
   };
 
   /**
    *  @class  LambdaCouplingMatrix
    *  @brief  constructs the coupling matrix needed to solve for lambda, i.e. N in N^T w N L = b
    */
   
   class LambdaCouplingMatrix : public ProtectedMappedAtomSparseMatrix<double> {
 
   public:
 
     // constructor
     LambdaCouplingMatrix(ATC_Method * atc,
                          MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap = NULL,
                          SPAR_MAN * shapeFunction = NULL);
     
     // destructor
     virtual ~LambdaCouplingMatrix() {
       shapeFunction_->remove_dependence(this);
       nodeToOverlapMap_->remove_dependence(this);
     };
 
   protected:
 
     /** does the actual computation of the quantity */
     virtual void reset() const;
 
     /** base shape function */
     SPAR_MAN * shapeFunction_;
 
     /** map from all nodes to regulated ones */
     MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap_;
 
   private:
 
     // do not define
     LambdaCouplingMatrix();
 
   };
 
   /**
    *  @class  LocalLambdaCouplingMatrix
    *  @brief  constructs the coupling matrix needed to solve for lambda, i.e. N in N^T w N L = b
    *          when localization is being used for the constraint
    */
   
   class LocalLambdaCouplingMatrix : public LambdaCouplingMatrix {
 
   public:
 
     // constructor
     LocalLambdaCouplingMatrix(ATC_Method * atc,
                               MatrixDependencyManager<DenseMatrix, int> * lambdaAtomMap = NULL,
                               MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap = NULL,
                               SPAR_MAN * shapeFunction = NULL);
     
     // destructor
     virtual ~LocalLambdaCouplingMatrix() {
       lambdaAtomMap_->remove_dependence(this);
     };
 
   protected:
 
     /** does the actual computation of the quantity */
     virtual void reset() const;
 
     /** map from all atoms to regulated ones */
     MatrixDependencyManager<DenseMatrix, int> * lambdaAtomMap_;
 
   private:
 
     // do not define
     LocalLambdaCouplingMatrix();
 
   };
 
   /**
    *  @class  GhostCouplingMatrix
    *  @brief  constructs the modified shape functions used to compute the total forces between ghost and internal atoms
    */
   
   class GhostCouplingMatrix : public LambdaCouplingMatrix {
 
   public:
 
     // constructor
     GhostCouplingMatrix(ATC_Method * atc,
                         SPAR_MAN * shapeFunction,
                         SetDependencyManager<int> * subsetNodes,
                         MatrixDependencyManager<DenseMatrix, int> * nodeToOverlapMap = NULL);
     
     // destructor
     virtual ~GhostCouplingMatrix() {
       subsetNodes_->remove_dependence(this);
     };
 
   protected:
 
     /** does the actual computation of the quantity */
     virtual void reset() const;
 
     /** set of nodes which are being regulated */
     SetDependencyManager<int> * subsetNodes_;
 
     // workspace
     mutable DENS_VEC _activeNodes_; // nodes which are being regulated are 1, otherwise 0
     mutable DENS_VEC _weights_; // required weighting for each shape function row to enforce partition of unity
     mutable DIAG_MAT _weightMatrix_; // diagonal with necessary scaling for partition of unity
 
   private:
 
     // do not define
     GhostCouplingMatrix();
 
   };
 
 
 }
 
 #endif
diff --git a/lib/atc/PoissonSolver.cpp b/lib/atc/PoissonSolver.cpp
index a5b4668e5..b3c077b59 100644
--- a/lib/atc/PoissonSolver.cpp
+++ b/lib/atc/PoissonSolver.cpp
@@ -1,213 +1,218 @@
 #include "PoissonSolver.h"
 #include "ATC_Coupling.h"
 #include "FE_Engine.h"
 #include "PhysicsModel.h"
 #include "PrescribedDataManager.h"
 #include "LinearSolver.h"
 #include <utility>
 #include <iostream>
 
 using std::pair;
 
 
 
 namespace ATC {
 
 // ====================================================================
 //  PoissonSolver
 // ====================================================================
 PoissonSolver::PoissonSolver(
     const FieldName fieldName,
     const PhysicsModel * physicsModel,
     const FE_Engine * feEngine,
     const PrescribedDataManager * prescribedDataMgr,
     /*const*/ ATC_Coupling * atc,
     const Array2D<bool> & rhsMask,
     const int solverType,
     bool parallel
 )
   : atc_(atc),
     feEngine_(feEngine),
     prescribedDataMgr_(prescribedDataMgr),
     physicsModel_(physicsModel),
     fieldName_(fieldName),
     rhsMask_(rhsMask),
     linear_(false),
     solver_(NULL),
     solverNL_(NULL),
     tangent_(NULL),
     solverType_(solverType),
     solverTol_(0),
     solverMaxIter_(0),
     integrationType_(FULL_DOMAIN),
     parallel_(parallel)
 {
   if (physicsModel_->has_linear_rhs(fieldName)) {
     linear_ = true;
     rhsMask_(fieldName,FLUX) = false; 
   }
 
   else {
     rhsMask_(fieldName,FLUX)   = true; 
     rhsMask_(fieldName,SOURCE) = true; 
   }
+  
   if (prescribedDataMgr_->has_robin_source(fieldName)) {
     
     
     
     rhsMask_(fieldName,ROBIN_SOURCE) = true;
   }
 }
 // --------------------------------------------------------------------
 PoissonSolver::~PoissonSolver() 
 { 
   if (tangent_) delete tangent_;
   if (solverNL_) delete solverNL_;
   if (solver_) delete solver_;
 }
 
 // --------------------------------------------------------------------
 //  Parser
 // --------------------------------------------------------------------
 
 bool PoissonSolver::modify(int narg, char **arg)
 {
   bool match = false;
   /*! \page man_poisson_solver fix_modify AtC poisson_solver 
       \section syntax
       fix_modify AtC poisson_solver mesh create <nx> <ny> <nz> <region-id> 
       <f|p> <f|p> <f|p>
       - nx ny nz = number of elements in x, y, z
       - region-id = id of region that is to be meshed
       - f p p  = perioidicity flags for x, y, z
       \section examples
       <TT> fix_modify AtC poisson_solver mesh create 10 1 1 feRegion p p p </TT>
       \section description
       Creates a uniform mesh in a rectangular region
       \section restrictions
       creates only uniform rectangular grids in a rectangular region
       \section related
       \section default
       none
   */
   int argIdx = 0;
   if (strcmp(arg[argIdx],"poisson_solver")==0) {
     argIdx++;
     if (strcmp(arg[argIdx],"mesh")==0) {
       argIdx++;
       // create a FE_Engine
 
       //feEngine_ = new FE_Engine(this); need alternate constructor?
       // send args to new engine
       // arg[0] = "mesh";
       // arg[1] = "create";
       // feEngine_->modify(narg,arg);
 
     }
   } 
   return match;
 }
 // --------------------------------------------------------------------
 //  Initialize
 // --------------------------------------------------------------------
 void PoissonSolver::initialize(void)
 {
   nNodes_ = feEngine_->num_nodes();
 
+  if (atc_->source_atomic_quadrature(fieldName_))  
+    integrationType_ = FULL_DOMAIN_ATOMIC_QUADRATURE_SOURCE;
+
   // compute penalty for Dirichlet boundaries
   if (prescribedDataMgr_->none_fixed(fieldName_))  
     throw ATC_Error("Poisson solver needs Dirichlet data");
 
   const BC_SET & bcs = (prescribedDataMgr_->bcs(fieldName_))[0];
 
   if (linear_) { // constant rhs 
     if (! solver_ ) {
       pair<FieldName,FieldName> row_col(fieldName_,fieldName_);
       Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
       rhsMask = false; rhsMask(fieldName_,FLUX) = true;
+
       if (prescribedDataMgr_->has_robin_source(fieldName_)) {
         rhsMask(fieldName_,ROBIN_SOURCE) = true;
       }
       // compute stiffness for Poisson solve
       atc_->compute_rhs_tangent(row_col, rhsMask, atc_->fields(),
         stiffness_, FULL_DOMAIN, physicsModel_);
       // create solver
-      solver_ = new LinearSolver(stiffness_,bcs,solverType_,-1,parallel_);
+      solver_ = new LinearSolver(stiffness_,bcs,solverType_,LinearSolver::AUTO_HANDLE_CONSTRAINTS,parallel_);
     }
     else {
 
     // re-initialize
     solver_->initialize(&bcs);
     }
     if (solverTol_) solver_->set_tolerance(solverTol_);
     if (solverMaxIter_) solver_->set_max_iterations(solverMaxIter_);
 
   }
   else {
 //  print_mask(rhsMask_);
     if ( solverNL_ )  delete solverNL_;
     tangent_ = new PhysicsModelTangentOperator(atc_,physicsModel_, rhsMask_, integrationType_, fieldName_); 
 
     solverNL_ = new NonLinearSolver(tangent_,&bcs,0,parallel_);
     
     if (solverTol_) solverNL_->set_residual_tolerance(solverTol_);
     if (solverMaxIter_) solverNL_->set_max_iterations(solverMaxIter_);
   }
 }
 
 // --------------------------------------------------------------------
 //  Solve
 // --------------------------------------------------------------------
 bool PoissonSolver::solve(FIELDS & fields, FIELDS & rhs)
 {
   atc_->compute_rhs_vector(rhsMask_, fields, rhs,
     integrationType_, physicsModel_);
   CLON_VEC f = column(fields[fieldName_].set_quantity(),0);
   CLON_VEC r = column(rhs[fieldName_].quantity(),0);
   bool converged = false;
   if (linear_) {converged = solver_->solve(f,r);}
   else         {converged = solverNL_->solve(f);}
 
   if (atc_->source_atomic_quadrature(fieldName_) 
     && LammpsInterface::instance()->atom_charge() ) set_charges(fields);
   return converged;
 }
 bool PoissonSolver::solve(DENS_MAT & field, const DENS_MAT & rhs) 
 {
 
   CLON_VEC f = column(field,0);
   CLON_VEC r = column(rhs,0);
   bool converged = false;
   if (linear_) {converged = solver_->solve(f,r);}
   else         {converged = solverNL_->solve(f);}
 
   if (atc_->source_atomic_quadrature(fieldName_) 
     && LammpsInterface::instance()->atom_charge() ) set_charges(atc_->fields());
   return converged;
 }
 
 // --------------------------------------------------------------------
 //  set charges on atoms
 // --------------------------------------------------------------------
 void PoissonSolver::set_charges(FIELDS & fields)
 {
   FIELD_MATS sources;
   
   atc_->compute_sources_at_atoms(rhsMask_, fields, physicsModel_,sources);
   FIELD_MATS::const_iterator nField = sources.find(fieldName_);
   if (nField != sources.end()) {
     const DENS_MAT & electronCharges = nField->second;
     double *  q = LammpsInterface::instance()->atom_charge();
     int nLocal = atc_->nlocal();
     if (nLocal > 0) {
       const Array<int> & i2a = atc_->internal_to_atom_map();
       for (int i=0; i < nLocal; i++) {
 
         int atomIdx = i2a(i);
         q[atomIdx] = -electronCharges(i,0);
       }
     }
   }
 }
 
 } // namespace ATC
diff --git a/lib/atc/PrescribedDataManager.cpp b/lib/atc/PrescribedDataManager.cpp
index 8d27f7c21..bd649c8ac 100644
--- a/lib/atc/PrescribedDataManager.cpp
+++ b/lib/atc/PrescribedDataManager.cpp
@@ -1,579 +1,623 @@
 #include "PrescribedDataManager.h"
 #include "FE_Engine.h"
 #include "ATC_Error.h"
 #include <sstream>
 #include <iostream>
 
 using std::stringstream;
 using std::make_pair;
 using std::map;
 using std::set;
 using std::pair;
 using std::string;
 using std::cout;
 
 namespace ATC {
 
 //-------------------------------------------------------------------------
 //  PrescribedDataManager
 //-------------------------------------------------------------------------
   PrescribedDataManager::PrescribedDataManager
   (FE_Engine * feEngine, 
    const map<FieldName,int> & fieldSize) :
     fieldSizes_(fieldSize), feEngine_(feEngine)
   {
     // construct & initialize internal data
     nNodes_ =  feEngine_->num_nodes();
     nElems_ =  feEngine_->num_elements();
     map<FieldName,int>::const_iterator field;
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       int thisSize = field->second;
       // nodal ics & essential bcs
       ics_[thisField].reset(nNodes_,thisSize);
       bcs_[thisField].reset(nNodes_,thisSize);
       for (int inode = 0; inode < nNodes_ ; ++inode) {
         for (int idof = 0; idof < thisSize ; ++idof) {
           ics_[thisField](inode,idof) = NULL;          
           bcs_[thisField](inode,idof) = NULL;          
         }
       }
       // compact inode, value lists
       (bcValues_[thisField]).resize(thisSize);
       // element based sources
       elementSources_[thisField].reset(nElems_,thisSize);
       for (int ielem = 0; ielem < nElems_ ; ++ielem) {
         for (int idof = 0; idof < thisSize ; ++idof) {
           elementSources_[thisField](ielem,idof) = NULL;          
         }
       }
+      // node based sources
+      nodalSources_[thisField].reset(nNodes_,thisSize);
     }
   }
 
 //-------------------------------------------------------------------------
 // ~PrescribedDataManager
 //-------------------------------------------------------------------------
   PrescribedDataManager::~PrescribedDataManager()
   {
   }
 
 //-------------------------------------------------------------------------
 // add_field
 //-------------------------------------------------------------------------
   void PrescribedDataManager::add_field(FieldName fieldName, int size)
   {
     // check to see if field exists
     if (fieldSizes_.find(fieldName) == fieldSizes_.end()) return;
 
     // construct & initialize internal data
     nNodes_ =  feEngine_->num_nodes();
     nElems_ =  feEngine_->num_elements();
   
     // nodal ics & essential bcs
     ics_[fieldName].reset(nNodes_,size);
     bcs_[fieldName].reset(nNodes_,size);
     for (int inode = 0; inode < nNodes_ ; ++inode) {
       for (int idof = 0; idof < size ; ++idof) {
         ics_[fieldName](inode,idof) = NULL;          
         bcs_[fieldName](inode,idof) = NULL;          
       }
     }
 
     // element based sources
     elementSources_[fieldName].reset(nElems_,size);
     for (int ielem = 0; ielem < nElems_ ; ++ielem) {
       for (int idof = 0; idof < size ; ++idof) {
         elementSources_[fieldName](ielem,idof) = NULL;          
       }
     }
   }
 
 //-------------------------------------------------------------------------
 // remove_field
 //-------------------------------------------------------------------------
   void PrescribedDataManager::remove_field(FieldName fieldName)
   {
     // check to see if field exists
     if (fieldSizes_.find(fieldName) == fieldSizes_.end())
       return;
     
     // delete field in maps
     fieldSizes_.erase(fieldName);
     ics_.erase(fieldName);
     bcs_.erase(fieldName);
     elementSources_.erase(fieldName);
   }
 
 //-------------------------------------------------------------------------
 //  fix_initial_field
 //-------------------------------------------------------------------------
   void PrescribedDataManager::fix_initial_field
   (const string nodesetName, 
    const FieldName thisField, 
    const int thisIndex, 
    const XT_Function * f)
   {
-    using std::set;
     set<int> nodeSet = (feEngine_->fe_mesh())->nodeset(nodesetName);
     set<int>::const_iterator iset;
     for (iset = nodeSet.begin(); iset != nodeSet.end(); iset++) {
       int inode = *iset;
       ics_[thisField](inode,thisIndex) = (XT_Function*) f; 
     }
   }
 //-------------------------------------------------------------------------
 //  fix_field
 //-------------------------------------------------------------------------
   void PrescribedDataManager::fix_field
   (const std::set<int>  nodeSet, 
    const FieldName thisField, 
    const int thisIndex, 
    const XT_Function * f)
   {
-    using std::set;
     // fix fields 
     set<int>::const_iterator iset;
     for (iset = nodeSet.begin(); iset != nodeSet.end(); iset++) {
       int inode = *iset;
       bcs_[thisField](inode,thisIndex) = (XT_Function*) f;
     }
   }
   void PrescribedDataManager::fix_field
   (const string nodesetName, 
    const FieldName thisField, 
    const int thisIndex, 
    const XT_Function * f)
   {
-    using std::set;
     set<int> nodeSet = (feEngine_->fe_mesh())->nodeset(nodesetName);
     fix_field(nodeSet,thisField,thisIndex,f);
   }
 //-------------------------------------------------------------------------
 //  unfix_field
 //-------------------------------------------------------------------------
   void PrescribedDataManager::unfix_field
   (const string nodesetName, 
    const FieldName thisField, 
    const int thisIndex)
   {
-    using std::set;
     set<int> nodeSet = (feEngine_->fe_mesh())->nodeset(nodesetName);
     set<int>::const_iterator iset;
     for (iset = nodeSet.begin(); iset != nodeSet.end(); iset++) {
       int inode = *iset;
       bcs_[thisField](inode,thisIndex) = NULL;
     }
   }
 
 //-------------------------------------------------------------------------
 //  fix_field
 //-------------------------------------------------------------------------
   void PrescribedDataManager::fix_field
   (const int nodeId, 
    const FieldName thisField, 
    const int thisIndex, 
    const XT_Function * f)
   {
     bcs_[thisField](nodeId,thisIndex) = (XT_Function*) f;
   }
 //-------------------------------------------------------------------------
 //  unfix_field
 //-------------------------------------------------------------------------
   void PrescribedDataManager::unfix_field
   (const int nodeId, 
    const FieldName thisField, 
    const int thisIndex)
   {
     bcs_[thisField](nodeId,thisIndex) = NULL;
   }
 //-------------------------------------------------------------------------
 //  fix_flux
 //-------------------------------------------------------------------------
   void PrescribedDataManager::fix_flux
   (const string facesetName, 
    const FieldName thisField, 
    const int thisIndex, 
    const XT_Function * f)
   {
     const set< pair <int,int> > * fset 
       = & ( (feEngine_->fe_mesh())->faceset(facesetName));
     set< pair<int,int> >::const_iterator iset;
     for (iset = fset->begin(); iset != fset->end(); iset++) {
       pair<int,int>  face = *iset;
       // allocate, if necessary
       Array < XT_Function * > & dof  = faceSources_[thisField][face];
       if (dof.size() == 0) {
         int ndof = (fieldSizes_.find(thisField))->second;
         dof.reset(ndof);
         for(int i = 0; i < ndof; i++)  dof(i) = NULL; 
       }
       dof(thisIndex) = (XT_Function*) f;
     }
   }
 //-------------------------------------------------------------------------
 //  unfix_flux
 //-------------------------------------------------------------------------
   void PrescribedDataManager::unfix_flux
   (const string facesetName, 
    const FieldName thisField, 
    const int thisIndex) 
   {
     const set< pair <int,int> > * fset 
       = & ( (feEngine_->fe_mesh())->faceset(facesetName));
     set< pair<int,int> >::const_iterator iset;
     for (iset = fset->begin(); iset != fset->end(); iset++) {
       pair<int,int>  face = *iset;
       Array < XT_Function * > & dof  = faceSources_[thisField][face];
       dof(thisIndex) = NULL;
     }
   }
 //-------------------------------------------------------------------------
 //  fix_robin
 //-------------------------------------------------------------------------
   void PrescribedDataManager::fix_robin
   (const string facesetName, 
    const FieldName thisField, 
    const int thisIndex, 
    const UXT_Function * f)
   {
     const set< pair <int,int> > * fset 
       = & ( (feEngine_->fe_mesh())->faceset(facesetName));
     set< pair<int,int> >::const_iterator iset;
     for (iset = fset->begin(); iset != fset->end(); iset++) {
       pair<int,int>  face = *iset;
       // allocate, if necessary
       Array < UXT_Function * > & dof  = faceSourcesRobin_[thisField][face];
       if (dof.size() == 0) {
         int ndof = (fieldSizes_.find(thisField))->second;
         dof.reset(ndof);
         for(int i = 0; i < ndof; i++)  dof(i) = NULL; 
       }
       dof(thisIndex) = (UXT_Function*) f;
     }
   }
 //-------------------------------------------------------------------------
 //  unfix_robin
 //-------------------------------------------------------------------------
   void PrescribedDataManager::unfix_robin
   (const string facesetName, 
    const FieldName thisField, 
    const int thisIndex) 
   {
     const set< pair <int,int> > * fset 
       = & ( (feEngine_->fe_mesh())->faceset(facesetName));
     set< pair<int,int> >::const_iterator iset;
     for (iset = fset->begin(); iset != fset->end(); iset++) {
       pair<int,int>  face = *iset;
       Array < UXT_Function * > & dof  = faceSourcesRobin_[thisField][face];
       dof(thisIndex) = NULL;
     }
   }
 //-------------------------------------------------------------------------
+//  fix_open
+//-------------------------------------------------------------------------
+  void PrescribedDataManager::fix_open
+  (const string facesetName, 
+   const FieldName thisField)
+  {
+    const set< pair <int,int> > * fset 
+      = & ( (feEngine_->fe_mesh())->faceset(facesetName));
+    set< pair<int,int> >::const_iterator iset;
+    for (iset = fset->begin(); iset != fset->end(); iset++) {
+      pair<int,int>  face = *iset;
+      facesOpen_[thisField].insert(face); // uniquely insert this face
+    }
+  }
+//-------------------------------------------------------------------------
+//  unfix_open
+//-------------------------------------------------------------------------
+  void PrescribedDataManager::unfix_open
+  (const string facesetName, 
+   const FieldName thisField) 
+  {
+    const set< pair <int,int> > * fset 
+      = & ( (feEngine_->fe_mesh())->faceset(facesetName));
+    set< pair<int,int> >::const_iterator iset;
+    for (iset = fset->begin(); iset != fset->end(); iset++) {
+      pair<int,int>  face = *iset;
+      facesOpen_[thisField].erase(face);
+    }
+  }
+//-------------------------------------------------------------------------
 //  fix_source
 //-------------------------------------------------------------------------
   void PrescribedDataManager::fix_source
   (const string elemsetName, 
    const FieldName thisField, 
    const int thisIndex, 
    const XT_Function *f)
   {
-    using std::set;
     set<int> elemSet = (feEngine_->fe_mesh())->elementset(elemsetName);
     set<int>::const_iterator iset;
     for (iset = elemSet.begin(); iset != elemSet.end(); iset++) {
       int ielem = *iset;
       // fix source
       elementSources_[thisField](ielem,thisIndex) = (XT_Function*) f;
     }
   }
 //-------------------------------------------------------------------------
+//  fix_source
+//-------------------------------------------------------------------------
+  void PrescribedDataManager::fix_source
+  (const FieldName thisField, 
+   const int thisIndex, 
+   const set<pair<int,double> > & s)
+  {
+    set<pair<int,double> >::const_iterator iset;
+    DENS_MAT & n(nodalSources_[thisField].set_quantity());
+    for (iset = s.begin(); iset != s.end(); iset++) {
+      pair<int,double> p = *iset;
+      int inode = p.first;
+      double v = p.second;
+      n(inode,thisIndex) = v;
+    }
+  }
+//-------------------------------------------------------------------------
 //  unfix_source
 //-------------------------------------------------------------------------
   void PrescribedDataManager::unfix_source
   (const string elemsetName, 
    const FieldName thisField, 
    const int thisIndex)
   {
-    using std::set;
     set<int> elemSet = (feEngine_->fe_mesh())->elementset(elemsetName);
     set<int>::const_iterator iset;
     for (iset = elemSet.begin(); iset != elemSet.end(); iset++) {
       int ielem = *iset;
       elementSources_[thisField](ielem,thisIndex) = NULL;
     }
   }
 //-------------------------------------------------------------------------
 //  set_initial_conditions
 //-------------------------------------------------------------------------
   void PrescribedDataManager::set_initial_conditions(const double t,  
                                                      FIELDS &fields,
                                                      FIELDS &dot_fields,
                                                      FIELDS &ddot_fields,
                                                      FIELDS &dddot_fields)
   {
     map<FieldName,int>::const_iterator field;
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       int thisSize = field->second;
       DENS_MAT & myField(fields[thisField].set_quantity());
       DENS_MAT & myDotField(dot_fields[thisField].set_quantity());
       DENS_MAT & myDDotField(ddot_fields[thisField].set_quantity());
       DENS_MAT & myDDDotField(dddot_fields[thisField].set_quantity());
       bool warn = false;
       for (int inode = 0; inode < nNodes_ ; ++inode) {
         for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
           XT_Function *f = ics_[thisField](inode,thisIndex);
           if (!f)  f = bcs_[thisField](inode,thisIndex);
           if (f) 
           {
             DENS_VEC coords(3); 
             coords = (feEngine_->fe_mesh())->nodal_coordinates(inode);
             double *x = coords.ptr();
             myField(inode,thisIndex) = f->f(x,t);
             myDotField(inode,thisIndex) = f->dfdt(x,t); 
             myDDotField(inode,thisIndex) = f->ddfdt(x,t); 
             myDDDotField(inode,thisIndex) = f->dddfdt(x,t); 
           }
           else {
             myField(inode,thisIndex) = 0;
             myDotField(inode,thisIndex) =  0;
             myDDotField(inode,thisIndex) = 0;
             myDDDotField(inode,thisIndex) = 0;
             warn = true;
           }
         }
       }
 //    if (warn &&  is_dynamic(thisField)) { need access tp physics model or return warn per field
       if (warn) {
         stringstream ss;
         ss << ("WARNING: all initial conditions for " +field_to_string(thisField)+" have not been defined and the undefined are assumed zero");
         ATC::LammpsInterface::instance()->print_msg_once(ss.str());
       }
     }
   }
 //-------------------------------------------------------------------------
 //  set_fixed_fields
 //-------------------------------------------------------------------------
   void PrescribedDataManager::set_fixed_fields(const double t, 
                                                FIELDS &fields,
                                                FIELDS &dot_fields,
                                                FIELDS &ddot_fields,
                                                FIELDS &dddot_fields)
   {
     map<FieldName,int>::const_iterator field;
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       int thisSize = field->second;
       for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
         BC_SET & bcs =  (bcValues_[thisField])[thisIndex]; 
         bcs.clear();
         for (int inode = 0; inode < nNodes_ ; ++inode) {
           XT_Function * f = bcs_[thisField](inode,thisIndex);
           if (f) {
             DENS_VEC coords(3); 
             coords = (feEngine_->fe_mesh())->nodal_coordinates(inode);
             double * x = coords.ptr();
             double val = f->f(x,t);
             
             (fields      [thisField].set_quantity())(inode,thisIndex) = val;
             (dot_fields  [thisField].set_quantity())(inode,thisIndex) = f->dfdt(x,t); 
             (ddot_fields [thisField].set_quantity())(inode,thisIndex) = f->ddfdt(x,t); 
             (dddot_fields[thisField].set_quantity())(inode,thisIndex) = f->dddfdt(x,t); 
             // compact set
             pair <int, double > bc = make_pair(inode,val);
             bcs.insert(bc);
           }
         }
       }
     }
   }
 //-------------------------------------------------------------------------
 //  set_fixed_field
 //-------------------------------------------------------------------------
   void PrescribedDataManager::set_fixed_field(
     const double t, 
     const FieldName & fieldName,
     DENS_MAT & fieldMatrix)
   {
     map<FieldName,int>::iterator fieldSizeIter = fieldSizes_.find(fieldName);
     if (fieldSizeIter == fieldSizes_.end()) {
       throw ATC_Error( "Unrecognized FieldName in PrescribedDataManager::set_fixed_field()");
     }
     int thisSize = fieldSizeIter->second;
     for (int inode = 0; inode < nNodes_ ; ++inode) {
       for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
         XT_Function * f = bcs_[fieldName](inode,thisIndex);
         if (f) {
           DENS_VEC coords(3); 
           coords = (feEngine_->fe_mesh())->nodal_coordinates(inode);
           fieldMatrix(inode,thisIndex) = f->f(coords.ptr(),t);
         }
       }
     }
   }
 //-------------------------------------------------------------------------
 //  set_fixed_dfield
 //-------------------------------------------------------------------------
   void PrescribedDataManager::set_fixed_dfield(
     const double t, 
     const FieldName & fieldName,
     DENS_MAT & dfieldMatrix)
   {
     map<FieldName,int>::iterator fieldSizeIter = fieldSizes_.find(fieldName);
     if (fieldSizeIter == fieldSizes_.end()) {
       throw ATC_Error( "Unrecognized FieldName in PrescribedDataManager::set_fixed_dfield()");
     }
     int thisSize = fieldSizeIter->second;
     for (int inode = 0; inode < nNodes_ ; ++inode) {
       for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
         XT_Function * f = bcs_[fieldName](inode,thisIndex);
         if (f) {
           DENS_VEC coords(3); 
           coords = (feEngine_->fe_mesh())->nodal_coordinates(inode);
           dfieldMatrix(inode,thisIndex) = f->dfdt(coords.ptr(),t);
         }
       }
     }
   }
 //-------------------------------------------------------------------------
 //  set_sources
 //-------------------------------------------------------------------------
   void PrescribedDataManager::set_sources
   (double t,  
    FIELDS & sources)
   {
     // zero
     Array<bool> fieldMask(NUM_FIELDS);
     fieldMask = false;
     map<FieldName,int>::const_iterator field;
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       fieldMask(thisField) = true;
       int thisSize = field->second;
       sources[thisField].reset(nNodes_,thisSize);
     }
     // compute boundary fluxes
     feEngine_->add_fluxes(fieldMask,t,faceSources_,sources);
   
     // compute internal sources
     feEngine_->add_sources(fieldMask,t,elementSources_,sources);
+    feEngine_->add_sources(fieldMask,t,nodalSources_,sources);
 
     // mask out nodes with essential bcs
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       int thisSize = field->second;
       for (int inode = 0; inode < nNodes_ ; ++inode) {
         for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
           XT_Function * f = bcs_[thisField](inode,thisIndex);
           if (f) {
             
             (sources[thisField].set_quantity())(inode,thisIndex) = 0.0;
           }
         }
       }
     }
   
   }
 
 //-------------------------------------------------------------------------
 //  print
 //-------------------------------------------------------------------------
 
   void PrescribedDataManager::print(void) 
   {
     // print and check consistency
     enum dataType {FREE=0,FIELD,SOURCE};
     Array2D < int > bcTypes;
     Array <int> conn;
     map<FieldName,int>::const_iterator field;
     XT_Function * f;
     for (field = fieldSizes_.begin(); field!=fieldSizes_.end(); field++) {
       FieldName thisField = field->first;
       int thisFieldSize = field->second;
       string fieldName = field_to_string(thisField);
       int thisSize = field->second;
       bcTypes.reset(nNodes_,thisSize);
       for (int inode = 0; inode < nNodes_ ; ++inode) {
         for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
           f = bcs_[thisField](inode,thisIndex);
           if (f) { bcTypes(inode,thisIndex) = FIELD; }
           else   { bcTypes(inode,thisIndex) = FREE; }
         }
       }
       // FIXED has higher precidence than SOURCE
       for (int ielem = 0; ielem < nElems_ ; ++ielem) {
         for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
           f = elementSources_[thisField](ielem,thisIndex);
           if (f) { 
             feEngine_->element_connectivity(ielem,conn);
             for (int i = 0; i < conn.size() ; ++i) {
               int inode = conn(i);
               if (bcTypes(inode,thisIndex) != FIELD) 
               { bcTypes(inode,thisIndex) = SOURCE; }
             }
           }
         }
       }
       map < pair<int,int>, Array < XT_Function * > > & fset 
         = faceSources_[thisField];
       map < pair<int,int>, Array < XT_Function * > > ::const_iterator iset;
       for (iset = fset.begin(); iset != fset.end(); iset++) {
         pair<int,int> face = iset->first;
         Array < XT_Function * > fs = iset->second;
         for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
           f = fs(thisIndex);
           if (f) { 
             feEngine_->face_connectivity(face,conn);
             for (int i = 0; i < conn.size() ; ++i) {
               int inode = conn(i);
               if (bcTypes(inode,thisIndex) != FIELD) 
               { bcTypes(inode,thisIndex) = SOURCE; }
             }
           }
         }
       }
       for (int inode = 0; inode < nNodes_ ; ++inode) {
         for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
           cout << "node: " << inode << " "  <<  fieldName;
           if (thisFieldSize > 1) { cout << " " << thisIndex; }
           f = ics_[thisField](inode,thisIndex);
           if (f) { cout << " IC"; }
           if      (bcTypes(inode,thisIndex) == FIELD ) {cout << " FIXED"; }
           else if (bcTypes(inode,thisIndex) == SOURCE) {cout << " SOURCE"; }
           cout << "\n";
         }
       }
     }
   }
 
 //-------------------------------------------------------------------------
 //  get_bcs  of a subset of nodes
 //-------------------------------------------------------------------------
   void PrescribedDataManager::bcs(const FieldName thisField, const set<int> nodeSet, BCS & bcs, bool local) const
   {
     bcs.clear();
     int thisSize = (fieldSizes_.find(thisField))->second;
     bcs.resize(thisSize);
     for (int thisIndex = 0; thisIndex < thisSize ; ++thisIndex) {
       set<int>::const_iterator iset;
       int i = 0;
       for (iset = nodeSet.begin(); iset != nodeSet.end(); iset++) {
         int inode = *iset;
         const BC_SET & allBCs 
           = ((bcValues_.find(thisField))->second)[thisIndex];
         BC_SET::const_iterator bset;
         for (bset = allBCs.begin(); bset != allBCs.end(); bset++) {
           int bnode = (*bset).first;
           if (inode == bnode) {
             double val = (*bset).second;
             if (local) inode = i; // use a local numbering
             pair <int, double > bc = make_pair(inode,val);
             (bcs[thisIndex]).insert(bc);
           }
         }
         i++;
       }
     }
   }
 
 } // end namespace
diff --git a/lib/atc/PrescribedDataManager.h b/lib/atc/PrescribedDataManager.h
index 1801360a8..05f553ab2 100644
--- a/lib/atc/PrescribedDataManager.h
+++ b/lib/atc/PrescribedDataManager.h
@@ -1,393 +1,413 @@
 #ifndef PRESCRIBED_DATA_MANAGER_H
 #define PRESCRIBED_DATA_MANAGER_H
 
 #include <vector>
 #include <map>
 #include <set>
 #include <string>
 #include <utility>
 
 #include "ATC_TypeDefs.h"
 #include "Function.h"
 #include "PhysicsModel.h"
 #include "FE_Element.h"
 #include "Array.h"
 #include "Array2D.h"
 #include "FE_Engine.h"
 
 
 namespace ATC {
 
   /**
    *  @class  PrescribedDataManager 
    *  @brief  Base class for managing initial conditions, essential/natural "boundary" conditions and sources 
    */
   class PrescribedDataManager {
 
   public:
 
     /** exclusive conditions: free | fixed field | flux or domain source */
     //enum Bc_Type {FREE=0,FIELD,SOURCE};
 
     PrescribedDataManager(FE_Engine * feEngine, 
                           const std::map<FieldName,int> & fieldSize);
     ~PrescribedDataManager();
 
     /** add/remove a field */
     void add_field(FieldName fieldName, int size);
     void remove_field(FieldName fieldName);
 
     /** direct access to ics */
     std::map < FieldName, Array2D < XT_Function * > > *  
       ics(void) { return & ics_; }
     const Array2D < XT_Function * > *  
       ics(FieldName fieldName) { return & ics_[fieldName]; }
     /** direct access to bcs */
 
     const std::map < FieldName, BCS > &  bcs(void) const   
     { 
       return bcValues_; 
     }
     /** */
     const BCS & bcs(const FieldName fieldName) const 
     { 
       return (bcValues_.find(fieldName))->second; 
     }
     /** */
     void bcs
       (const FieldName fieldName, const std::set<int> nodes, BCS & bcs, 
       bool local = false) const;
     /** */
     std::map < FieldName, Array2D < XT_Function * > > *  
       bc_functions(void) { return & bcs_; }
     /** */
     const Array2D < XT_Function * > *  
       bc_functions(FieldName fieldName) { return & bcs_[fieldName]; }
     /** */
     ROBIN_SURFACE_SOURCE * robin_functions(void) { return & faceSourcesRobin_; }
     bool has_robin_source(FieldName fieldName) const { 
        return ((faceSourcesRobin_.find(fieldName)->second).size() > 0) ;
     }
     /** */
     const std::map<PAIR, Array<UXT_Function*> > *
       robin_functions(FieldName fieldName) { return & faceSourcesRobin_[fieldName]; }
+    /** */
+    OPEN_SURFACE * open_faces(void) { return & facesOpen_; }
+    bool has_open_face(FieldName fieldName) const { 
+       return ((facesOpen_.find(fieldName)->second).size() > 0) ;
+    }
+    /** */
+    const std::set<PAIR> *
+      open_faces(FieldName fieldName) { return & facesOpen_[fieldName]; }
     
     /** query initial state */
     bool is_initially_fixed(const int node, 
                             const FieldName thisField,
                             const int thisIndex=0)  const
     { 
       return ((ics_.find(thisField)->second))(node,thisIndex) ? true : false ; 
     }
     /** query state */
     bool is_fixed(const int node, 
                   const FieldName thisField,
                   const int thisIndex=0)  const
     { 
       return ((bcs_.find(thisField)->second))(node,thisIndex) ? true : false ; 
     }
 
     /** */
     std::set<int> fixed_nodes(
                   const FieldName thisField,
                   const int thisIndex=0)  const
     { 
       std::set<int> fixed;
       const Array2D < XT_Function *> & bcs = bcs_.find(thisField)->second;
       for (int node = 0; node < bcs.nRows() ; node++) {
         if (bcs(node,thisIndex)) fixed.insert(node);
       }
       return fixed;
     }
     /** */
     void fixed_nodes(
                      const FieldName thisField,
                      std::set<int> & fixed,
                      const int thisIndex=0)  const
     {
       const Array2D < XT_Function *> & bcs = bcs_.find(thisField)->second;
       for (int node = 0; node < bcs.nRows() ; node++) {
         if (bcs(node,thisIndex)) fixed.insert(node);
       }
     }
     /** to determine whether a solution is needed */
     bool all_fixed(
                   const FieldName thisField,
                   const int thisIndex=-1)  const
     { 
        if (thisIndex < 0) {
          // static_casts are to iterface with std::vector without compiler warngings
          bool allFixed = (fixed_nodes(thisField,0).size() == static_cast<unsigned>(nNodes_) );
          int ndof = (fieldSizes_.find(thisField)->second);
          for (int j = 1; j < ndof; ++j) {
            allFixed = allFixed && (fixed_nodes(thisField,j).size() == static_cast<unsigned>(nNodes_));
          }
          return allFixed;
        }
        else {
          return (fixed_nodes(thisField,thisIndex).size() == static_cast<unsigned>(nNodes_) );
        }
     }
     /** a function to determine if the tangent is invertible */
     bool none_fixed(
                   const FieldName thisField,
                   const int thisIndex=0)  const
     { 
        return (fixed_nodes(thisField,thisIndex).size() == 0 )
-           && (faceSourcesRobin_.size() == 0);
+           && (faceSourcesRobin_.size() == 0)
+           && (facesOpen_.size() == 0);
     }
 
     /** */
     std::set<int> flux_face_nodes(
                   const FieldName thisField,
                   const int thisIndex=0)  const
     { 
       std::set<int> fluxes;
       //list of nodes to insert. 
       //1 for nodes to insert, 0 for nodes not to insert.
       int toInsert[nNodes_];
       for (int i = 0; i < nNodes_; ++i) toInsert[i] = 0;
 
       const std::map < std::pair <int, int>, Array < XT_Function * > > & sources = faceSources_.find(thisField)->second;
       std::map < std::pair <int, int>, Array < XT_Function * > >::const_iterator fset_iter;
       for (fset_iter = sources.begin(); fset_iter != sources.end(); fset_iter++) {
         int ielem = fset_iter->first.first;
         // if this is not our element, do not do calculations
         if (!feEngine_->fe_mesh()->is_owned_elt(ielem)) continue;
         const Array <XT_Function*> &fs = fset_iter->second;
         if (fs(thisIndex)) {
           Array<int> nodes;
           feEngine_->face_connectivity(fset_iter->first,nodes);
           for (int node = 0; node < nodes.size(); node++) {
             toInsert[nodes(node)] = 1;
           }
         }
       }
       // gather partial results
       LammpsInterface::instance()->logical_or(MPI_IN_PLACE, toInsert, nNodes_);
       // insert selected elements into fluxes
       for (int node = 0; node < nNodes_; ++node) {
         if (toInsert[node]) fluxes.insert(node);
       }
       return fluxes;
     }
 
     /** */
     void flux_face_nodes(
                   const FieldName thisField,
                   std::set<int> fluxes,
                   const int thisIndex=0)  const
     {
       //list of nodes to insert. 
       //1 for nodes to insert, 0 for nodes not to insert.
       int toInsert[nNodes_];
       for (int i = 0; i < nNodes_; ++i) toInsert[i] = 0;
 
       const std::map < std::pair <int, int>, Array < XT_Function * > > & sources = faceSources_.find(thisField)->second;
       std::map < std::pair <int, int>, Array < XT_Function * > >::const_iterator fset_iter;
       for (fset_iter = sources.begin(); fset_iter != sources.end(); fset_iter++) {
         int ielem = fset_iter->first.first;
         // if this is not our element, do not do calculations
         if (!feEngine_->fe_mesh()->is_owned_elt(ielem)) continue;
         const Array <XT_Function*> &fs = fset_iter->second;
         if (fs(thisIndex)) {
           Array<int> nodes;
           feEngine_->face_connectivity(fset_iter->first,nodes);
           for (int node = 0; node < nodes.size(); node++) {
             toInsert[nodes(node)] = 1;
           }
         }
       }
       // gather partial results
       LammpsInterface::instance()->logical_or(MPI_IN_PLACE, toInsert, nNodes_);
       // insert selected elements into fluxes
       for (int node = 0; node < nNodes_; ++node) {
         if (toInsert[node]) fluxes.insert(node);
       }
     }
 
     /** */
     std::set<int> flux_element_nodes(
                   const FieldName thisField,
                   const int thisIndex=0)  const
     { 
       std::set<int> fluxes;
       //list of nodes to insert. 
       //1 for nodes to insert, 0 for nodes not to insert.
       int toInsert[nNodes_];
       for (int i = 0; i < nNodes_; ++i) toInsert[i] = 0;
 
       const Array2D < XT_Function *> & sources = elementSources_.find(thisField)->second;
       for (int element = 0; element < sources.nRows() ; element++) {
         // if this is not our element, do not do calculations
         if (!feEngine_->fe_mesh()->is_owned_elt(element)) continue;
         if (sources(element,thisIndex)) {
           Array<int> nodes;
           feEngine_->element_connectivity(element,nodes);
           for (int node = 0; node < nodes.size(); node++) {
             toInsert[nodes(node)] = 1;
           }
         }
       }
       // gather partial results
       LammpsInterface::instance()->logical_or(MPI_IN_PLACE, toInsert, nNodes_);
       // insert selected elements into fluxes
       for (int node = 0; node < nNodes_; ++node) {
         if (toInsert[node]) fluxes.insert(node);
       }
       return fluxes;
     }
 
     /** */
     void flux_element_nodes(
                   const FieldName thisField,
                   std::set<int> fluxes,
                   const int thisIndex=0)  const
     {
       //list of nodes to insert. 
       //1 for nodes to insert, 0 for nodes not to insert.
       int toInsert[nNodes_];
       for (int i = 0; i < nNodes_; ++i) toInsert[i] = 0;
 
       const Array2D < XT_Function *> & sources = elementSources_.find(thisField)->second;
       for (int element = 0; element < sources.nRows() ; element++) {
         // if this is not our element, do not do calculations
         if (!feEngine_->fe_mesh()->is_owned_elt(element)) continue;
         if (sources(element,thisIndex)) {
           Array<int> nodes;
           feEngine_->element_connectivity(element,nodes);
           for (int node = 0; node < nodes.size(); node++) {
             toInsert[nodes(node)] = 1;
           }
         }
       }
       // gather partial results
       LammpsInterface::instance()->logical_or(MPI_IN_PLACE, toInsert, nNodes_);
       // insert selected elements into fluxes
       for (int node = 0; node < nNodes_; ++node) {
         if (toInsert[node]) fluxes.insert(node);
       }
     }
 
     /** */
     bool no_fluxes(
                    const FieldName thisField,
                    const int thisIndex=0)  const
     { 
       return ((flux_element_nodes(thisField,thisIndex).size() == 0) &&
               (flux_face_nodes(thisField,thisIndex).size() == 0));
     }
   
     /** set initial field values */
     void fix_initial_field (const std::string nodesetName, 
                             const FieldName thisField, 
                             const int thisIndex, 
                             const XT_Function * f);
     /** un/set field values at fixed nodesets */
     void fix_field (const std::set<int> nodeset, 
                     const FieldName thisField, 
                     const int thisIndex, 
                     const XT_Function * f);
     /** un/set field values at fixed nodesets */
     void fix_field (const std::string nodesetName, 
                     const FieldName thisField, 
                     const int thisIndex, 
                     const XT_Function * f);
     void unfix_field (const std::string nodesetName, 
                       const FieldName thisField, 
                       const int thisIndex); 
     /** un/set field values at fixed nodes */
     void fix_field (const int nodeId, 
                     const FieldName thisField, 
                     const int thisIndex, 
                     const XT_Function * f);
     void unfix_field (const int nodeId, 
                       const FieldName thisField, 
                       const int thisIndex); 
     /** un/set fluxes */
     void fix_flux  (const std::string facesetName,
                     const FieldName thisField, 
                     const int thisIndex, 
                     const XT_Function * f);
     void unfix_flux(const std::string facesetName,
                     const FieldName thisField, 
                     const int thisIndex);
     void fix_robin (const std::string facesetName,
                     const FieldName thisField, 
                     const int thisIndex, 
                     const UXT_Function * f);
     void unfix_robin(const std::string facesetName,
                     const FieldName thisField, 
                     const int thisIndex);
+    void fix_open  (const std::string facesetName,
+                    const FieldName thisField);
+    void unfix_open(const std::string facesetName,
+                    const FieldName thisField);
     /** un/set sources */
-    void fix_source(const std::string nodesetName,
+    void fix_source(const std::string elemsetName,
                     const FieldName thisField, 
                     const int thisIndex, 
                     const XT_Function * f);
-    void unfix_source(const std::string nodesetName,
+    void fix_source( const FieldName thisField, 
+                    const int thisIndex, 
+                    const std::set<std::pair<int,double> >  & source);
+    void unfix_source(const std::string elemsetName,
                       const FieldName thisField, 
                       const int thisIndex);
     /** get initial conditions  */
     void set_initial_conditions(const double time, 
                                 FIELDS & fields,
                                 FIELDS & dot_fields,
                                 FIELDS & ddot_fields,
                                 FIELDS & dddot_fields);
     /** get "boundary" conditions on fields */
     void set_fixed_fields(const double time, 
                           FIELDS & fields,
                           FIELDS & dot_fields,
                           FIELDS & ddot_fields,
                           FIELDS & dddot_fields);
     /** get "boundary" conditions on a single field */
     void set_fixed_field(const double time, 
                          const FieldName & fieldName,
                          DENS_MAT & fieldMatrix);
     /** get "boundary" conditions on a single time derivative field */
     void set_fixed_dfield(const double time, 
                           const FieldName & fieldName,
                           DENS_MAT & dfieldMatrix);
     /** get "sources" (flux and sources: divided by leading coef of ODE) */
     void set_sources(const double time, 
                      FIELDS & sources);
 
     /** debugging status output */
     void print(void);
 
   private:
     /** number of unique nodes */
     int nNodes_;
 
     /** number of elements */
     int nElems_;
 
     /** names and sizes of fields */
     std::map<FieldName,int> fieldSizes_;
 
     /** access to all the FE computations */
     FE_Engine * feEngine_;
 
     // node numbering & dof numbering : contiguous
     // fieldname & bc_type : types/enums
     /** ics : XT_Function * f = ics_[field](inode,idof) */
     std::map < FieldName, Array2D < XT_Function * > > ics_;
 
     /** bcs: essential bcs XT_Function * f = bcs_[field][face](idof) */
     std::map < FieldName, Array2D < XT_Function * > > bcs_;
 
     /** sources :  XT_Function * f = faceSources_[field][face](idof) */
     std::map < FieldName, std::map < std::pair <int, int>, Array < XT_Function * > > > 
       faceSources_;
     /** sources :  UXT_Function * f = faceSourcesRobin_[field][face](idof) */
     std::map < FieldName, std::map < std::pair <int, int>, Array < UXT_Function * > > > 
       faceSourcesRobin_;
+    /** sources :  facesOpen_[field][face] */
+    std::map < FieldName, std::set < std::pair <int, int> > > 
+      facesOpen_;
     /** sources :  XT_Function * f = elementSources_[field](ielem,idof) */
     std::map < FieldName, Array2D < XT_Function * > > elementSources_;
+    FIELDS nodalSources_;
 
     /** values of bcs in a compact set */
     std::map < FieldName, BCS > bcValues_;
   };
 
 }
 
 #endif
diff --git a/lib/atc/SchrodingerSolver.cpp b/lib/atc/SchrodingerSolver.cpp
index 191ddbb46..0bbfde8e2 100644
--- a/lib/atc/SchrodingerSolver.cpp
+++ b/lib/atc/SchrodingerSolver.cpp
@@ -1,559 +1,955 @@
 // ATC Headers
 #include "SchrodingerSolver.h"
 #include "ATC_Error.h"
 #include "ATC_Coupling.h"
 #include "LammpsInterface.h"
 #include "PrescribedDataManager.h"
 #include "PhysicsModel.h"
 #include "LinearSolver.h"
 #include "PoissonSolver.h"
 
+#include "Utility.h"
 
 #include <utility>
-
 using std::pair;
 using std::set;
+using std::stringstream;
+using std::min;
+using ATC_Utility::to_string;
+using ATC_Utility::sgn;
 
 const double tol = 1.e-8; 
 const double zero_tol = 1.e-12; 
 const double f_tol = 1.e-8; 
 
 namespace ATC {
 
-enum oneDconservationEnum {ONED_DENSITY=0, ONED_FLUX}; 
+enum oneDconservationEnum {ONED_DENSITY=0, ONED_FLUX, ONED_GLOBAL_FLUX}; 
+
+
+
+
 
 double fermi_dirac(const double E, const double T)
 {
   double f = 1.0;
-  if      (T > 0) f = 1.0 / ( exp(E/kBeV_/T)+1.0 );
+  if      (T > 0) f = 1.0 / ( exp(E/(kBeV_*T))+1.0 );
   else if (E > 0) f = 0;
   return f;
 };
 
 
-  //--------------------------------------------------------
+  //========================================================
   //  Schrodinger solve
-  //--------------------------------------------------------
+  //========================================================
   SchrodingerSolver::SchrodingerSolver(
     const FieldName fieldName,
     const PhysicsModel * physicsModel,
     const FE_Engine * feEngine,
     const PrescribedDataManager * prescribedDataMgr,
     /*const*/ ATC_Coupling * atc,
-    const int solverType,
     bool parallel
 )
   : atc_(atc),
     feEngine_(feEngine),
     prescribedDataMgr_(prescribedDataMgr),
     physicsModel_(physicsModel),
     fieldName_(fieldName),
-    solver_(NULL),
-    solverType_(solverType),
     nNodes_(atc->num_nodes()),
     parallel_(parallel)
   {
   }
-  SchrodingerSolver::~SchrodingerSolver()
-  {
-    if (solver_) delete solver_;
-  }
-
+  //-----------------------------------------------------
   void SchrodingerSolver::initialize()
   {
     SPAR_MAT sparseM; 
     atc_->fe_engine()->compute_mass_matrix(sparseM);
     M_ = sparseM.dense_copy();
   }
-
+  //-----------------------------------------------------
   bool SchrodingerSolver::solve(FIELDS & fields)
   {
 
 // typedef  struct{float real, imag;} COMPLEX;
     SPAR_MAT stiffness_;
     Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
     rhsMask = false;
     rhsMask(ELECTRON_WAVEFUNCTION,FLUX) = true;
     rhsMask(ELECTRON_WAVEFUNCTION,SOURCE) = true;
     pair<FieldName,FieldName> row_col(ELECTRON_WAVEFUNCTION,
                                       ELECTRON_WAVEFUNCTION);
     //set_fixed_nodes();
     atc_->fe_engine()->compute_tangent_matrix(
       rhsMask, row_col, atc_->fields(), physicsModel_,
       atc_->element_to_material_map(), stiffness_);
     DENS_MAT K(stiffness_.dense_copy());
     set<int> fixedNodes = prescribedDataMgr_->fixed_nodes(ELECTRON_WAVEFUNCTION);
     const BC_SET & bcs 
       = (prescribedDataMgr_->bcs(ELECTRON_WAVEFUNCTION))[0];
     DENS_MAT & psi   = (atc_->field(ELECTRON_WAVEFUNCTION)).set_quantity();
     DENS_MAT & eVecs = (atc_->field(ELECTRON_WAVEFUNCTIONS)).set_quantity();
     DENS_MAT & eVals = (atc_->field(ELECTRON_WAVEFUNCTION_ENERGIES)).set_quantity();
 
     if (prescribedDataMgr_->all_fixed(ELECTRON_WAVEFUNCTION)) {
       ATC::LammpsInterface::instance()->print_msg("all wavefunctions fixed");
       psi.reset(nNodes_,1);
       eVecs.reset(nNodes_,1);
       eVals.reset(nNodes_,1);
       return true;
     }
     // (1) Helmholtz solve for inhomongeneous bcs
     
     LinearSolver helmholtzSolver_(K,bcs,LinearSolver::AUTO_SOLVE,-1,parallel_);
     
     psi.reset(nNodes_,1);
     // (2) Eigenvalue solve 
     helmholtzSolver_.eigen_system(eVals,eVecs,&M_);
     return true; 
   }
 
-  //--------------------------------------------------------
+  //========================================================
   //  Schrodinger solve on slices
-  //--------------------------------------------------------
+  //========================================================
   SliceSchrodingerSolver::SliceSchrodingerSolver(
     const FieldName fieldName,
     const PhysicsModel * physicsModel,
     const FE_Engine * feEngine,
     const PrescribedDataManager * prescribedDataMgr,
     /*const*/ ATC_Coupling * atc,
     const Array< set<int> > & oneDslices,
-    const int solverType,
+    const Array< double > & oneDdxs,
     bool parallel
 )
     : SchrodingerSolver(fieldName, physicsModel, feEngine, prescribedDataMgr, 
-        atc, solverType, parallel),
-    oneDslices_(oneDslices)
-  {
-  }
-  SliceSchrodingerSolver::~SliceSchrodingerSolver()
-  {
-  }
+        atc, parallel),
+    oneDslices_(oneDslices),
+    oneDdxs_(oneDdxs)
+  {}
+  //--------------------------------------------------------
   void SliceSchrodingerSolver::initialize()
   {
     SchrodingerSolver::initialize();
   }
-
+  //--------------------------------------------------------
+  // compute charge density per slice
+  //--------------------------------------------------------
   bool SliceSchrodingerSolver::solve(FIELDS & fields)
   {
     // fields
     DENS_MAT & psi   = (atc_->field(ELECTRON_WAVEFUNCTION)).set_quantity();
     DENS_MAT & eVecs = (atc_->field(ELECTRON_WAVEFUNCTIONS)).set_quantity();
     DENS_MAT & eVals = (atc_->field(ELECTRON_WAVEFUNCTION_ENERGIES)).set_quantity();
     psi.reset(nNodes_,1);
     eVecs.reset(nNodes_,nNodes_);
     eVals.reset(nNodes_,1);
     DENS_MAT & Ef = (atc_->field(FERMI_ENERGY)).set_quantity();
     DENS_MAT & n  = (atc_->field(ELECTRON_DENSITY)).set_quantity();
     DENS_MAT & T  = (atc_->field(ELECTRON_TEMPERATURE)).set_quantity();
-
     
     // stiffness = K + V M
     SPAR_MAT stiffness_;
     Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
     rhsMask = false;
     rhsMask(ELECTRON_WAVEFUNCTION,FLUX) = true;
     rhsMask(ELECTRON_WAVEFUNCTION,SOURCE) = true;
     pair<FieldName,FieldName> row_col(ELECTRON_WAVEFUNCTION,
                                       ELECTRON_WAVEFUNCTION);
     atc_->fe_engine()->compute_tangent_matrix(
       rhsMask, row_col, atc_->fields(), physicsModel_,
       atc_->element_to_material_map(), stiffness_);
     DENS_MAT K(stiffness_.dense_copy());
 
     // Eigenvalue solve 
     DENS_MAT K1,M1;
     int nslices = oneDslices_.size();
     DENS_MAT b ;
     DENS_MAT evals1,evecs1 ;
     DENS_MAT n1 ;
     BCS bcs;
     set <int> one;
     one.insert(0);
     set <int> eindex;
     int iEVal = 0;
     for (int islice = 0; islice < nslices ; islice++) {
       set<int> & slice = oneDslices_(islice);
       int snodes = slice.size();
       prescribedDataMgr_->bcs(ELECTRON_WAVEFUNCTION,slice,bcs,true);
       const BC_SET & bc = bcs[0];
       int nfixed = bc.size();
       if (nfixed != snodes) {
+        // A: solve for e-values and wavefunctions
         K.map(slice,slice,K1);
         M_.map(slice,slice,M1);
-        LinearSolver eigensolver(K1,bc,LinearSolver::AUTO_SOLVE,-1,parallel_);
+        LinearSolver eigensolver(K1,bc,LinearSolver::AUTO_SOLVE,-1);
         // wave functions
         evals1.reset(snodes,1);
         evecs1.reset(snodes,snodes);
         eigensolver.eigen_system(evals1,evecs1,&M1);
         eindex.clear();
         for (int j = 0; j < snodes; j++) eindex.insert(iEVal++);
         eVals.insert(eindex,one,  evals1); 
         eindex.clear();
         for (int j = 0; j < snodes; j++) eindex.insert(j);
         eVecs.insert(slice,eindex,evecs1);
-        // electron density
+        // slice charge density
         n1.reset(snodes,1);
         
         set<int>::const_iterator iset;
         double aveE_f = 0;
         for (iset = slice.begin(); iset != slice.end(); iset++) { 
           int gnode = *iset; 
           aveE_f += Ef(gnode,0);
         }
         aveE_f /= snodes;
-
+//#define VERBOSE 
+#ifdef VERBOSE
+        stringstream ss;
+        ss << "   slice "+to_string(islice+1)+" E_f "+to_string(aveE_f) << "\n" 
+           << "#-----------------------------------------------\n"
+           << "#          E-Ef          f        psi          n\n"
+           << "#-----------------------------------------------\n";
+#endif
+        // B: compute charge density on slice
         int node = 0;
         for (iset = slice.begin(); iset != slice.end(); iset++) { // node
           int gnode = *iset; 
           double temp =  T(gnode,0);
-          //double E_f = Ef(gnode,0);
           for (int mode = 0; mode < snodes-nfixed; mode++) {
             double Ei = evals1(mode,0);
             double E = Ei-aveE_f;
             double f = fermi_dirac(E,temp); 
-            if (f  <  f_tol) break; // take advantage of E ordering 
             double psi1 = evecs1(node,mode); // 2nd index corresp to evals order
+#ifdef VERBOSE
+            ss << node<<":"<<mode << "  " << to_string(6,E) << " " << to_string(6,f) << " " << to_string(6,psi1) << " " << to_string(6,n1(node,0)+psi1*psi1*f) <<  "\n";
+#endif
+            if (f  <  f_tol) break; // take advantage of E ordering 
             n1(node,0) += psi1*psi1*f;
           }
           node++;
         }
+#ifdef VERBOSE
+        ATC::LammpsInterface::instance()->print_msg_once(ss.str());
+#endif
         n.insert(slice,one,  n1); // note not "assemble"
       }
     }
     return true; 
   }
 
-  //--------------------------------------------------------
+  //========================================================
   //  Schrodinger-Poisson Manager
-  //--------------------------------------------------------
+  //========================================================
   SchrodingerPoissonManager::SchrodingerPoissonManager() :
     maxConsistencyIter_(0),
     maxConstraintIter_(0),
     oneD_(false),
     oneDconserve_(ONED_FLUX),
     Ef_shift_(0.),
-    safe_dEf_(0.)
-  {
-  }
-  SchrodingerPoissonManager::~SchrodingerPoissonManager()
+    safe_dEf_(0.),
+    tol_(1.e-10),
+    mu_(1.),D_(0.)
   {
   }
-
+  //----------------------------------------------------------
   bool SchrodingerPoissonManager::modify(int narg, char **arg)
   {
     bool match = false;
     int argIndx = 0;
     if (strcmp(arg[argIndx],"self_consistency")==0) {
       argIndx++;
       maxConsistencyIter_ = atoi(arg[argIndx]);
       match = true;
     }
     else if (strcmp(arg[argIndx],"conserve")==0) {
       oneD_ = true;
       argIndx++;
-      if (strcmp(arg[argIndx],"density")==0)  oneDconserve_ = ONED_DENSITY;
-      else                                    oneDconserve_ = ONED_FLUX;
+      if (strcmp(arg[argIndx],"density")==0)   oneDconserve_ = ONED_DENSITY;
+      else if (strcmp(arg[argIndx],"flux")==0) oneDconserve_ = ONED_FLUX;
+      else                                     oneDconserve_ = ONED_GLOBAL_FLUX;
       argIndx++;
       maxConstraintIter_ = atoi(arg[argIndx]);
       match = true;
     }
     else if (strcmp(arg[argIndx],"initial_fermi_level")==0) {
       argIndx++;
       Ef_shift_ = atof(arg[argIndx]);
       match = true;
     }
     else if (strcmp(arg[argIndx],"safe_fermi_increment")==0) {
       argIndx++;
       safe_dEf_ = atof(arg[argIndx]);
       match = true;
     }
+    else if (strcmp(arg[argIndx],"relaxation")==0) {
+      argIndx++;
+      alpha_ = atof(arg[argIndx]);
+      match = true;
+    }
+    else if (strcmp(arg[argIndx],"tolerance")==0) {
+      argIndx++;
+      tol_ = atof(arg[argIndx]);
+      match = true;
+    }
+    else if (strcmp(arg[argIndx],"mobility")==0) {
+      argIndx++;
+      mu_ = atof(arg[argIndx]);
+      match = true;
+    }
+    else if (strcmp(arg[argIndx],"diffusivity")==0) {
+      argIndx++;
+      D_ = atof(arg[argIndx]);
+      match = true;
+    }
     return match;
   }
-
+  //----------------------------------------------------------------
   SchrodingerPoissonSolver * SchrodingerPoissonManager::initialize(
     /*const*/ ATC_Coupling * atc,
     SchrodingerSolver * schrodingerSolver,
     PoissonSolver * poissonSolver,
     const PhysicsModel * physicsModel
    )
   {
     SchrodingerPoissonSolver * ptr;
     if (oneD_) {
+      if (oneDconserve_ == ONED_GLOBAL_FLUX) {
+      ptr = new GlobalSliceSchrodingerPoissonSolver(atc,
+        schrodingerSolver,poissonSolver,physicsModel,maxConsistencyIter_,
+        maxConstraintIter_, oneDconserve_, Ef_shift_, alpha_, safe_dEf_, tol_,
+        mu_,D_);
+      }
+      else {
       ptr = new SliceSchrodingerPoissonSolver(atc,
         schrodingerSolver,poissonSolver,physicsModel,maxConsistencyIter_,
         maxConstraintIter_, oneDconserve_, Ef_shift_, safe_dEf_);
+      }
     }
     else {
       ptr = new SchrodingerPoissonSolver(atc,
         schrodingerSolver,poissonSolver,physicsModel,maxConsistencyIter_);
     }
     return ptr;
   }
 
-  //-------------------------------------------------------------------
+  //===================================================================
   // SchrodingerPoissonSolver
-  //-------------------------------------------------------------------
+  //===================================================================
   SchrodingerPoissonSolver::SchrodingerPoissonSolver( 
     /*const*/ ATC_Coupling * atc,
     SchrodingerSolver * schrodingerSolver,
     PoissonSolver * poissonSolver,
     const PhysicsModel * physicsModel,
     int maxConsistencyIter
   ) :
    atc_(atc),
    schrodingerSolver_(schrodingerSolver),
    poissonSolver_(poissonSolver),
    physicsModel_(physicsModel),
    maxConsistencyIter_(maxConsistencyIter),
    nNodes_(atc_->num_nodes())
   {
   }
-  SchrodingerPoissonSolver::~SchrodingerPoissonSolver(void)
-  {
-  }
+  //----------------------------------------------------------------------
 
   void SchrodingerPoissonSolver::solve(FIELDS & rhs, GRAD_FIELD_MATS & fluxes)
   {
     if ((atc_->prescribed_data_manager()->all_fixed(ELECTRON_WAVEFUNCTION))
      && (atc_->prescribed_data_manager()->all_fixed(ELECTRIC_POTENTIAL)))  {
       return;
     }
     double norm = 1.0, norm0 = 1.0; // normPrev = 1.0;
     DENS_MAT nPrev,psiPrev,phiPrev;
 
     DENS_MAT & psi = (atc_->field(ELECTRON_WAVEFUNCTIONS)).set_quantity();
     DENS_MAT & phi = (atc_->field(ELECTRIC_POTENTIAL)).set_quantity();
     DENS_MAT & E_I = (atc_->field(ELECTRON_WAVEFUNCTION_ENERGIES)).set_quantity();
     DENS_MAT & Te  = (atc_->field(ELECTRON_TEMPERATURE)).set_quantity();
     atc_->set_fixed_nodes();
     DENS_MAT Te0 = Te; // save
 
     const double tol  = 1.e-4;
-//  double Tmax = Te.max();
 
     int k = 0;
     double logRatio = 3; 
     int maxIter = (int) logRatio; 
     double base = 2.0;
 
     // temperature relaxation loop
     for (int i = 0; i < maxIter ; ++i) { 
       //double alpha = ((double) i) /( (double) maxIter-1);
       //double beta = 0.1;
       //alpha = (exp(beta*i)-1.0)/(exp(beta*(maxIter-1))-1.0);
       double alpha = pow(base,logRatio-i-1);
       // self consistency loop
       int j = 0; // for storage of last iterate
       
       for (j = 0; j < maxConsistencyIter_ ; ++j) { 
         // compute eigen-values and vectors
         atc_->set_fixed_nodes();
         Te = alpha*Te0;
         
         schrodingerSolver_->solve(atc_->fields());
 
         
         for (int l = 0; l < nNodes_; l++) {
           int count = 0;
           double T_e = Te(l,0);
           for (int m = 0; m < nNodes_; m++) {
             double f = fermi_dirac(E_I(m,0), T_e);
             if (f > tol) count++; 
           }
         }
         // compute charge density
         DENS_MAN & n = atc_->field(ELECTRON_DENSITY);
         //(n.quantity()).print("DENSITY");
         atc_->nodal_projection(ELECTRON_DENSITY,physicsModel_,n);
         atc_->set_fixed_nodes(); 
         
         
         // solve poisson eqn for electric potential
         atc_->set_fixed_nodes();
         Te = alpha*Te0;
         poissonSolver_->solve(atc_->fields(),rhs);
         
         //DENS_MAT dn = n;
         //DENS_MAT dpsi = psi;
         //DENS_MAT dphi = phi;
         if (i == 0 && j==0) {
           nPrev = n.quantity();
           psiPrev = psi;
           phiPrev = phi;
         }
         //dn -= nPrev;
         //dpsi -= psiPrev;
         //dphi -= phiPrev;
         
         norm = (n.quantity()-nPrev).norm();
         if (i == 0 && j==0) norm0 = (n.quantity()).norm();
         //normPrev = norm;
         //psi_normPrev = psi_norm;
         //phi_normPrev = phi_norm;
         nPrev = n.quantity();
         psiPrev = psi;
         phiPrev = phi;
         k++;
         if (j > 0 && norm <= tol*norm0) break;
       }
       //      Tmax_ *= 0.5;
     }
   }
   
-  //----------------------------------------------------------------------------
-  // SchrodingerPoissonSolver
-  //-------------------------------------------------------------------
+  //===================================================================
+  // SliceSchrodingerPoissonSolver
+  //===================================================================
   SliceSchrodingerPoissonSolver::SliceSchrodingerPoissonSolver( 
     /*const*/ ATC_Coupling * atc,
     SchrodingerSolver * schrodingerSolver,
     PoissonSolver * poissonSolver,
     const PhysicsModel * physicsModel,
     int maxConsistencyIter,
     int maxConstraintIter,
     int oneDconserve,
     double Ef_shift,
     double safe_dEf
   ) :
   SchrodingerPoissonSolver(atc,schrodingerSolver,poissonSolver,physicsModel,maxConsistencyIter),
-  maxConstraintIter_(maxConstraintIter),
   oneDconserve_(oneDconserve),
   oneDcoor_(0),
-  Ef_shift_(Ef_shift),
-  safe_dEf_(safe_dEf),
-  oneDslices_(((SliceSchrodingerSolver *) schrodingerSolver_)->slices())
+  oneDslices_(((SliceSchrodingerSolver *) schrodingerSolver_)->slices()),
+  oneDdxs_(((SliceSchrodingerSolver *) schrodingerSolver_)->dxs())
   {
+    Ef_shift_=Ef_shift;
+    safe_dEf_=safe_dEf;
+    maxConstraintIter_=maxConstraintIter;
     EfHistory_.reset(oneDslices_.size(),2);
   }
-  SliceSchrodingerPoissonSolver::~SliceSchrodingerPoissonSolver(void)
-  {
-  }
+  //--------------------------------------------------------------------------
   void SliceSchrodingerPoissonSolver::solve(FIELDS & rhs, GRAD_FIELD_MATS & fluxes)
   {
     const double tol = 1.e-4; // tolerance on consistency & constraint
     double norm = 1.0, norm0 = 1.0;
     DENS_MAT nPrev;
     DENS_MAT & n   = (atc_->field(ELECTRON_DENSITY)).set_quantity();
     DENS_MAT & phi = (atc_->field(ELECTRIC_POTENTIAL)).set_quantity();
 
     // fermi energy
     DENS_MAT & Ef = (atc_->field(FERMI_ENERGY)).set_quantity();
     Ef.reset(nNodes_,1);
 
     int nslices = oneDslices_.size();
     Array2D<double> nHistory(nslices,2);
 
     // target for constraint
     double target = 0.0; 
+
     set<int> & slice = oneDslices_(0); // note assume first slice is fixed
     if (oneDconserve_ == ONED_FLUX) atc_->set_sources(); 
     DENS_MAT & nSource = (atc_->source(ELECTRON_DENSITY)).set_quantity();
     for (set<int>::const_iterator iset = slice.begin(); iset != slice.end(); iset++) { 
       if (oneDconserve_ == ONED_FLUX) target  += nSource(*iset,0);
       else                            target  += n(*iset,0);
     }
     target /= slice.size(); 
+#ifdef VERBOSE
+    if (oneDconserve_ == ONED_FLUX) {
+      if (target > 0) ATC::LammpsInterface::instance()->print_msg_once(" influx target "+ to_string(target));
+      else            ATC::LammpsInterface::instance()->print_msg_once(" efflux target "+ to_string(target));
+    }
+#endif
  
-    // self consistency loop between Phi and n(psi_i)
+    // A: self consistency loop between Phi and n(psi_i)
     double error = 1.0;
     for (int i = 0; i < maxConsistencyIter_ ; ++i) { 
       atc_->set_fixed_nodes();
       if (! atc_->prescribedDataMgr_->all_fixed(ELECTRIC_POTENTIAL) ) 
         poissonSolver_->solve(atc_->fields(),rhs); 
       if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_DENSITY) )  {
         // iterate on Ef
         //if (i==0) Ef = -1.0*phi;// E ~ -|e| \Phi,  charge of electron e = 1 
-        Ef = -1.0*phi; // E ~ -|e| \Phi,  charge of electron e = 1 in eV
+        Ef = -1.0*phi; 
+        
         Ef +=Ef_shift_;
+        // B: conservation constraint
         for (int j = 0; j < maxConstraintIter_ ; ++j) {  
-
-          schrodingerSolver_->solve(atc_->fields()); 
-
+          schrodingerSolver_->solve(atc_->fields()); // n(E_f)
           atc_->set_fixed_nodes();
-          error = update_fermi_energy(target,(j==0),fluxes);
+          error = update_fermi_energy(target,(j==0),fluxes);// root finder
+#ifdef VERBOSE
+          ATC::LammpsInterface::instance()->print_msg_once(to_string(i)+":"+to_string(j)+" constraint_error "+to_string(error)+" / "+to_string(tol*target)+"\n");
+#endif
           // exit condition based on constraint satisfaction
-          if (error < tol*target) break; 
+          if (error < tol*fabs(target)) break; 
         } // loop j : flux constraint
         // error based on change in field (Cauchy convergence)
         if (i == 0) {
           norm = norm0 = n.norm();
         }
         else {
           DENS_MAT dn = n;
           dn -= nPrev;
           norm = dn.norm();
         }
         nPrev = n;
+#ifdef VERBOSE
+#if 0
+        if (i > 0) ATC::LammpsInterface::instance()->print_msg_once(to_string(i)+" density_change: "+to_string(norm)+" / "+to_string(norm0));
+        else       ATC::LammpsInterface::instance()->print_msg_once("initial norm "+to_string(norm));
+#endif
+#endif
         if (i > 0 && norm <= tol*norm0 && error < tol) break;
       }
     } // loop i : self consistency
   }
 
   //--------------------------------------------------------
   //  update fermi energy
   //--------------------------------------------------------
 
   double SliceSchrodingerPoissonSolver::update_fermi_energy
     (double target, bool first, GRAD_FIELD_MATS & fluxes)
   {
     DENS_MAT & Ef  = (atc_->field(FERMI_ENERGY)).set_quantity();
-    double safe_dEf = safe_dEf_; 
-
     DENS_MAT & n   = (atc_->field(ELECTRON_DENSITY)).set_quantity();
+    DENS_MAT & phi   = (atc_->field(ELECTRIC_POTENTIAL)).set_quantity();
     const DENS_MAT * y = &n;
     if (oneDconserve_ == ONED_FLUX) { // compute J_x
       Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX); rhsMask = false;
       rhsMask(ELECTRON_DENSITY,FLUX) = true;
+//#define WIP_REJ
       atc_->compute_flux(rhsMask,atc_->fields_,fluxes,physicsModel_);
       y = & ( fluxes[ELECTRON_DENSITY][oneDcoor_] ); 
     }
-
     BCS bcs;
     double error = 0;
     // slice
     for (int islice = 0; islice < oneDslices_.size(); islice++) {
+#ifdef VERBOSE
+      std::string cStr(" conserved ");
+      std::string Estr(" Ef");
+#endif
       set<int> & slice = oneDslices_(islice);
       int nSlice = slice.size();
-      //atc_->prescribedDataMgr_->bcs(ELECTRON_DENSITY,slice,bcs,true);
       atc_->prescribedDataMgr_->bcs(ELECTRON_WAVEFUNCTION,slice,bcs,true);
       const BC_SET & bc = bcs[0];
       int nFixed = bc.size();
-      if (nFixed == nSlice) continue;
+      if (nFixed == nSlice) continue; // skip if all fixed 
       double Y = 0.0, X = 0.0;
-double nave = 0.0;
+      double nAve = 0., phiAve = 0.;
       for (set<int>::const_iterator iset = slice.begin(); iset != slice.end(); iset++) { 
         int gnode = *iset;
         X +=   Ef(gnode,0);
         Y += (*y)(gnode,0);
-nave += n(gnode,0);
+        nAve += n(gnode,0);
+        phiAve += phi(gnode,0);
       }
       X /= nSlice;
       Y /= nSlice;
-nave /= nSlice;
-      
+      nAve /= nSlice;
+      phiAve /= nSlice;
+      // now adjust Ef for each slice 
       double dY = Y - EfHistory_(islice,0); 
       double dX = X - EfHistory_(islice,1);
-      if (fabs(dY) < zero_tol*dX) throw ATC_Error("zero increment in conserved field on slice");
       double err = target - Y; 
       if (target*Y < -zero_tol*target) {
-        //throw ATC_Error("target and quantity opposite signs");
-        ATC::LammpsInterface::instance()->print_msg_once("WARNING: target and quantity opposite signs");
+#ifdef VERBOSE
+        cStr = " opp. SIGNS";
+#else    
+        ATC::LammpsInterface::instance()->print_msg_once("WARNING: slice "+to_string(islice)+" target and quantity opposite signs "+to_string(Y));
+#endif
       }
       error += fabs(err);
-      //error = max(error,err);
-      double dEf = err / dY * dX;
+      double dEf = 0.;
       if (first) {
-        dEf = (err < 0) ? -safe_dEf : safe_dEf;
+        dEf = (err < 0) ? -safe_dEf_ : safe_dEf_;
       }
-      else if (fabs(dEf) > safe_dEf) {
-        dEf = safe_dEf * dEf / fabs(dEf);
+      else { 
+        if (fabs(dY) < zero_tol*dX) throw ATC_Error("zero increment in conserved field on slice:"+to_string(islice));
+        dEf = err / dY * dX;
+        if (fabs(dEf) > safe_dEf_) {
+          dEf = safe_dEf_* dEf / fabs(dEf);
+#ifdef VERBOSE
+          Estr = " !!";
+#else 
+          ATC::LammpsInterface::instance()->print_msg_once("WARNING: slice "+to_string(islice)+ " large Delta E_f "+to_string(dEf));
+#endif
+        }
       }
       for (set<int>::const_iterator iset = slice.begin(); iset != slice.end(); iset++) { 
         int gnode = *iset;
-        Ef(gnode,0) += dEf; 
+        Ef(gnode,0) += dEf;  
       }
       EfHistory_(islice,0) = Y;
       EfHistory_(islice,1) = X;
+      if ( std::isnan(Y) ) throw ATC_Error("target on slice is not a number");
+#ifdef VERBOSE
+      ATC::LammpsInterface::instance()->print_msg_once("   slice"+to_string(islice,2) +cStr+to_string(4,Y/target) +Estr+to_string(4,X)+" n"+to_string(5,nAve)+" phi"+to_string(4,phiAve));
+      //ATC::LammpsInterface::instance()->print_msg_once("   slice "+to_string(islice) +cStr+to_string(4,Y/target) +" E_f"+to_string(4,X)+dEstr+to_string(4,X-EfHistory_(std::max(0,islice-1),1))+" n"+to_string(4,nAve)+" phi"+to_string(4,phiAve)+"  "+to_string(nFixed)+" dn "+to_string(4,dnAve)+" dphi "+to_string(4,dphiAve));
+#endif
     } // loop slice 
     return error;
   }
 
+  //===================================================================
+  // GlobalSliceSchrodingerPoissonSolver
+  //===================================================================
+  GlobalSliceSchrodingerPoissonSolver::GlobalSliceSchrodingerPoissonSolver( 
+    /*const*/ ATC_Coupling * atc,
+    SchrodingerSolver * schrodingerSolver,
+    PoissonSolver * poissonSolver,
+    const PhysicsModel * physicsModel,
+    int maxConsistencyIter,
+    int maxConstraintIter,
+    int oneDconserve,
+    double Ef0,
+    double alpha,
+    double safe_dEf,
+    double tol, 
+    double mu, double D
+  ) :
+  SliceSchrodingerPoissonSolver(atc,schrodingerSolver,poissonSolver,physicsModel,maxConsistencyIter,maxConstraintIter,oneDconserve,0,0),
+  solver_(NULL), 
+  mobility_(mu),diffusivity_(D)
+  {
+    Ef0_ = Ef0;
+    alpha_ = alpha;
+    safe_dEf_ = safe_dEf;
+    if (safe_dEf_ < 1.e-20) throw ATC_Error("safe dE_f must be positive");
+    ATC::LammpsInterface::instance()->print_msg("mobility:"+to_string(mobility_)+" diffusivity:"+to_string(diffusivity_));
+    tol_ = tol;
+    nslices_ = oneDslices_.size();
+    sliceSize_ = (oneDslices_(0)).size();
+    nNodes_ = nslices_*sliceSize_;
+    flux_.reset(nNodes_);
+    J_.reset(nslices_);
+    //nfixed_ = 2;
+    nfixed_ = 1;
+    nfreeSlices_ = nslices_-nfixed_;
+    nLambda_ = nslices_-1;
+    lambda_.reset(nLambda_);
+    dJ_.reset(nLambda_);
+    F_.reset(nslices_);
+    Phi_.reset(nslices_);
+    n_.reset(nslices_);
+    // form stiffness, lhs dirichlet bc, rhs homogeneous neumann bc
+    //int m = nfreeSlices_;
+    int m = nLambda_;
+    DENS_MAT A(m,m);
+    for (int i = 1; i < m; ++i) {
+      A(i,i) = -2;
+      if (i>0)   A(i,i-1) = 1;
+      if (i<m-1) A(i,i+1) = 1;
+    }
+    A(0,0) = -2;
+    A(0,1) =  1;
+    A(m-1,m-1) = -2; 
+    A(m-1,m-2) =  1; 
+    //if (nfixed_ == 1) { A(m-1,m-1) = -1;  }
+    double dx = oneDdxs_(0); 
+    A *=  1./dx;
+    A.print("stiffness",4);
+    SPAR_MAT K(A);
+    K_ = K;
+    // form gradient  (account for lhs bc)
+    int n = nslices_;
+    DENS_MAT B(m,n);
+    //for (int i = 0; i < m-1; ++i) {
+    for (int i = 0; i < m; ++i) {
+      B(i,i)   =-1;
+      B(i,i+1) = 1; //B(i,i+2) = 1;
+    }
+    if (nfixed_ == 1) {
+      B(m-1,n-2) = -1;
+      B(m-1,n-1) =  1;
+    }
+    B.print("gradient",4);
+    SPAR_MAT G(B);
+    G_ = G;
+    
+    DENS_MAT C(nNodes_,nNodes_);
+    // local to ATC nodemap: k --> gnode = *iset
+    int k = 0;
+    set<int>::const_iterator iset;
+    for (int islice = 0; islice < nslices_; islice++) {
+      set<int> & slice = oneDslices_(islice);
+      for (iset = slice.begin(); iset != slice.end(); iset++) { 
+        double v = 0.5/dx;
+        if ( k < sliceSize_ || k+1 > (nslices_-1)*sliceSize_ ) v *=2.0;
+        if (islice > 0) {          C(k,k-sliceSize_) += v; }
+        else            {          C(k,k)            += v; }
+        if (islice < nslices_-1) { C(k,k+sliceSize_) -= v; }
+        else            {          C(k,k)            -= v; }
+        k++;
+      }
+    }
+    //C.print("2D gradient",4);
+    SPAR_MAT G2(C);
+    G2_ = G2;
+    solver_ = new LinearSolver(K_); // for lambda
+    rhsMask_.reset(NUM_FIELDS,NUM_FLUX); rhsMask_ = false;
+    rhsMask_(ELECTRON_DENSITY,FLUX) = true;
+
+    // report
+    if (nfixed_ ==2)
+      ATC::LammpsInterface::instance()->print_msg_once("schrodinger-poisson solver: Dirichlet INLET, Dirichlet; OUTLET");
+    else if (nfixed_ ==1)
+      ATC::LammpsInterface::instance()->print_msg_once("schrodinger-poisson solver: Dirichlet INLET, Neumann; OUTLET");
+    else 
+      ATC_Error("schrodinger-poisson solver:too many fixed");
+  }
+  GlobalSliceSchrodingerPoissonSolver::~GlobalSliceSchrodingerPoissonSolver(void)  {
+    if (solver_) delete solver_;
+  }
+  //--------------------------------------------------------------------------
+  void GlobalSliceSchrodingerPoissonSolver::solve(FIELDS & rhs, GRAD_FIELD_MATS & fluxes)
+  {
+    const DENS_MAT & phi = (atc_->fields_[ELECTRIC_POTENTIAL]).quantity();
+    const DENS_MAT & n   = (atc_->fields_[ELECTRON_DENSITY]  ).quantity();
+    DENS_MAT       & Ef  = (atc_->field(FERMI_ENERGY)).set_quantity();
+    Ef.reset(phi.nRows(),1);
+    norm_ = norm0_ = 1.0;
+    for (int i = 0; i < maxConstraintIter_ ; ++i) { 
+      atc_->set_fixed_nodes();
+      if (! atc_->prescribedDataMgr_->all_fixed(ELECTRIC_POTENTIAL) ) {
+        poissonSolver_->solve(atc_->fields(),rhs); 
+      }
+      else {
+        ATC::LammpsInterface::instance()->print_msg_once("WARNING: phi is fixed");
+      }
+      if (i == 0) { report(0); }
+      if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_DENSITY) )  {
+        update_fermi_level(); // update Ef = Ef0 +lambda
+        schrodingerSolver_->solve(atc_->fields()); // updates n(E_f)
+        //exponential_electron_density(); // surrogate
+        compute_flux(n,phi); // compute J(n,phi) & dJ_
+        solver_->solve(lambda_,dJ_); // conservation constraint
+        //lambda_.print("lambda");
+        //lambda_.print("[[J}}");
+      }
+      else {
+        ATC::LammpsInterface::instance()->print_msg_once("WARNING: rho is fixed");
+      }
+      norm_ = dJ_.norm();
+      report(i+1);
+      if (i == 0 && norm_ > tol_) norm0_ = norm_;
+      else { if (norm_ < tol_*norm0_) break; }
+    } 
+  }
+  //--------------------------------------------------------------------------
+  void GlobalSliceSchrodingerPoissonSolver::exponential_electron_density() 
+  {
+    std::cout << "******************HACK******************\n";
+
+    const DENS_MAT & phi = (atc_->fields_[ELECTRIC_POTENTIAL]).quantity();
+    DENS_MAT & n   = (atc_->fields_[ELECTRON_DENSITY]  ).set_quantity();
+    DENS_MAT       & Ef  = (atc_->field(FERMI_ENERGY)).set_quantity();
+    double T = 300;
+    double n0 = 1.e-2;
+    set<int>::const_iterator iset;
+    for (int islice = 0; islice < nslices_; islice++) {
+      set<int> & slice = oneDslices_(islice);
+      double aveE_f = 0.0;
+      for (iset = slice.begin(); iset != slice.end(); iset++) { 
+        int gnode = *iset;
+        aveE_f += Ef(gnode,0);
+      }
+      aveE_f /= slice.size();
+      for (iset = slice.begin(); iset != slice.end(); iset++) { 
+        int gnode = *iset;
+        //std::cout << phi(gnode,0)+aveE_f << "\n";
+        //n(gnode,0) = -n0*exp(-(phi(gnode,0)+aveE_f)/(kBeV_*T));
+        //n(gnode,0) = -n0*exp((-phi(gnode,0))/(kBeV_*T));
+        //n(gnode,0) = -n0*exp(aveE_f/(kBeV_*T));
+        //n(gnode,0) =  aveE_f+0.01;
+        //n(gnode,0) = aveE_f;
+        //n(gnode,0) = phi(gnode,0);
+        //n(gnode,0) = -n0*(phi(gnode,0)+aveE_f)/(kBeV_*T);
+        n(gnode,0) = -n0*(aveE_f)/(kBeV_*T);
+      }
+    }
+  }
+  //--------------------------------------------------------------------------
+  void GlobalSliceSchrodingerPoissonSolver::report(int i) 
+  {
+    const DENS_MAT & phi = (atc_->fields_[ELECTRIC_POTENTIAL]).quantity();
+    const DENS_MAT & n   = (atc_->fields_[ELECTRON_DENSITY]  ).quantity();
+    const DENS_MAT & Ef  = (atc_->field(FERMI_ENERGY)).quantity();
+    set<int>::const_iterator iset;
+    for (int islice = 0; islice < nslices_; islice++) {
+      set<int> & slice = oneDslices_(islice);
+      double Phi = 0.0;
+      double N   = 0.0;
+      double EF  = 0.0;
+      for (iset = slice.begin(); iset != slice.end(); iset++) {
+        int gnode = *iset;
+        Phi += phi(gnode,0);
+        N   +=   n(gnode,0);
+        EF  +=  Ef(gnode,0);
+      }
+      Phi /= slice.size();
+      Phi_(islice) = Phi; // average potential
+      N /= slice.size();
+      n_(islice) = N; // average electron density
+      EF /= slice.size();
+      F_(islice) = EF; // average Fermi level
+    }
+    stringstream header;
+    header << "\n";
+    header << "#----------------------------------------------------------------------\n";
+    header << "#          [[J]]     lambda        E_f        phi          n          J\n";
+    header << "#----------------------------------------------------------------------\n";
+    if (i == 0) {
+      ATC::LammpsInterface::instance()->write_file("slice.dat",header.str());
+    }
+    stringstream ss;
+    ss << "\n";
+    // first slice (fixed E_F)
+    double dJ0 = J_(1)-J_(0);
+    ss << to_string(1,2) << "*" << to_string(6,dJ0) << " " << to_string(6,0.) << " " << to_string(6,F_(0)) << " " << to_string(6,Phi_(0)) << " " << to_string(6,n_(0)) << " " << to_string(6,J_(0)) <<  "\n";
+    // interior
+    for (int j = 1; j < nslices_-1; ++j) {
+       ss << to_string(j+1,2) << " " << to_string(6,dJ_(j-1)) << " " << to_string(6,lambda_(j-1)) << " " << to_string(6,F_(j)) << " " << to_string(6,Phi_(j)) << " " << to_string(6,n_(j)) << " " << to_string(6,J_(j)) << "\n";
+    }
+    // last slice (fixed E_F)
+    double dJn = J_(nslices_-1)-J_(nslices_-2);
+    int j = nslices_-1;
+    double lambdaN = 0.;
+    std::string space = "*";
+    if (nfixed_ == 1) { 
+      lambdaN = lambda_(nslices_-2); 
+      space = " ";
+    }
+    ss << to_string(nslices_,2) << space << to_string(6,dJn) << " " << to_string(6,lambdaN) << " " << to_string(6,F_(j)) << " " << to_string(6,Phi_(j)) << " " << to_string(6,n_(j)) << " " << to_string(6,J_(j)) <<  "\n";
+    stringstream is;
+    is << "\n# iteration: " << to_string(i)+"/ "+to_string(maxConstraintIter_)+" constraint norm:"+to_string(6,norm_/norm0_) << " " << nslices_ << " slices";
+    ATC::LammpsInterface::instance()->print_msg(is.str()+header.str()+ss.str());
+    ATC::LammpsInterface::instance()->write_file("slice.dat",ss.str()+is.str()+"\n",std::ofstream::app);
+  }
+  //--------------------------------------------------------------------------
+  void GlobalSliceSchrodingerPoissonSolver::compute_flux(
+     const DENS_MAT & n, const DENS_MAT & phi)
+  {
+    DENS_VEC f(nNodes_);
+    DENS_VEC gradphi(nNodes_);
+    DENS_VEC gradn(nNodes_);
+    int k = 0;
+    set<int>::const_iterator iset;
+    // grad phi
+    for (int islice = 0; islice < nslices_; islice++) {
+      set<int> & slice = oneDslices_(islice);
+      for (iset = slice.begin(); iset != slice.end(); iset++) { 
+        int gnode = *iset;
+        f(k) = phi(gnode,0);
+        k++;
+      }
+    }
+    //f.print("phi");
+    gradphi = G2_*f;
+    //gradphi.print("grad phi");
+    k = 0;
+    // grad n
+    for (int islice = 0; islice < nslices_; islice++) {
+      set<int> & slice = oneDslices_(islice);
+      for (iset = slice.begin(); iset != slice.end(); iset++) { 
+        int gnode = *iset;
+        f(k) = n(gnode,0);
+        k++;
+      }
+    }
+    //f.print("n");
+    gradn = G2_*f;
+    ////gradn.print("grad n");
+    flux_.reset(nNodes_);
+    for (k = 0; k < nNodes_; k++) {
+      flux_(k) = -mobility_*f(k)*gradphi(k)-diffusivity_*gradn(k);
+    }
+    //flux_.print("flux");
+    // per slice flux and diference
+    k = 0;
+    for (int islice = 0; islice < nslices_; islice++) {
+      set<int> & slice = oneDslices_(islice);
+      J_(islice) = 0;
+      for (iset = slice.begin(); iset != slice.end(); iset++) { 
+        J_(islice) += flux_(k);
+        k++;
+      }
+      J_(islice) /= slice.size();
+      //std::cout << islice << "  J " << J_(islice) << "\n";
+    }
+    //J_.print("J");
+    dJ_ = G_*J_; 
+  }
+  //--------------------------------------------------------------------------
+  void GlobalSliceSchrodingerPoissonSolver::update_fermi_level() 
+  {
+
+    DENS_MAT & Ef  = (atc_->field(FERMI_ENERGY)      ).set_quantity();
+    DENS_MAT & phi = (atc_->field(ELECTRIC_POTENTIAL)).set_quantity();
+    DENS_MAT & n   = (atc_->field(ELECTRON_DENSITY)  ).set_quantity();
+    set<int>::const_iterator iset;
+    for (int islice = 0; islice < nslices_; islice++) {
+      set<int> & slice = oneDslices_(islice);
+      double Phi = 0.;
+      double N = 0.;
+      //F_(islice) = Ef0_;
+      if (islice > 0 && islice < nslices_-1) {
+        F_(islice) += alpha_*lambda_(islice-1);
+      }
+      for (iset = slice.begin(); iset != slice.end(); iset++) {
+        int gnode = *iset;
+        Phi += phi(gnode,0);
+        N += n(gnode,0);
+      }
+      Phi /= slice.size();
+      Phi_(islice) = Phi; // average potential
+      N /= slice.size();
+      n_(islice) = N; // average electron density
+      
+      //F_(j) +=  min(fabs(alpha_*lambda),safe_dEf_)*sgn(lambda);
+      for (iset = slice.begin(); iset != slice.end(); iset++) {
+        int gnode = *iset;
+        Ef(gnode,0) = F_(islice);
+      }
+    }
+    //Ef.print("Ef");
+  }
 };
diff --git a/lib/atc/SchrodingerSolver.h b/lib/atc/SchrodingerSolver.h
index e190c8eae..9b8616b45 100644
--- a/lib/atc/SchrodingerSolver.h
+++ b/lib/atc/SchrodingerSolver.h
@@ -1,204 +1,268 @@
 #ifndef SCHRODINGER_SOLVER_H
 #define SCHRODINGER_SOLVER_H
 
 // ATC includes
 #include "Array2D.h"
 #include "LinearSolver.h"
 
 // other includes
 #include <vector>
 #include <map>
 #include <set>
 
 namespace ATC {
 
 // Forward class declarations
 class ATC_Coupling;
 class FE_Engine;
 class PrescribedDataManager;
 class PhysicsModel;
 class PoissonSolver;
 
 /**
  *  @class SchrodingerSolver
  *  @brief a class to solve the (time-independent) Schrodinger equation 
  */
 class SchrodingerSolver {
 
  public:
 
   /** Constructor */
   SchrodingerSolver(
     const FieldName fieldName,
     const PhysicsModel * physicsModel,
     const FE_Engine * feEngine,
     const PrescribedDataManager * prescribedDataMgr,
     /*const*/ ATC_Coupling * atc,
-    const int solverType = ATC::LinearSolver::DIRECT_SOLVE,
-    bool parallel = false
+    bool parallel = true
   );
 
   /** Destructor */
-  virtual ~SchrodingerSolver();
+  virtual ~SchrodingerSolver(){};
 
   /** parser */
   bool modify(int narg, char **arg){ return false;}
 
   /** initialize */
   void initialize(void);
 
   /** solve */
   virtual bool solve(FIELDS & fields); 
 
 
   
 
  protected:
   
   /** Pointer to ATC */
   ATC_Coupling * atc_;
 
   /** Pointer to FE_Engine */
   const FE_Engine * feEngine_;
 
   /** Pointer to PrescribedDataManager */
   const PrescribedDataManager * prescribedDataMgr_;
 
   /** Pointer to FE_Engine */
   const PhysicsModel * physicsModel_;
 
   /** field to solve for */
   FieldName fieldName_;
 
-  /** linear solver */
-  LinearSolver * solver_;
-  int solverType_;
-
   /** number of nodes */
   int nNodes_;
 
-  /** stiffness matrix */
-
-  //SPAR_MAT stiffness_;
-
-  //SPAR_MAT massMatrix_;
+  /** mass matrix */
   DENS_MAT M_;
 
   bool parallel_;
 
 };
 
+/**
+ *  @class SchrodingerSolver
+ *  @brief a class to solve the Schrodinger equation on slices
+ */
 class SliceSchrodingerSolver : public SchrodingerSolver {
 
  public:
 
   /** Constructor */
   SliceSchrodingerSolver(
     const FieldName fieldName,
     const PhysicsModel * physicsModel,
     const FE_Engine * feEngine,
     const PrescribedDataManager * prescribedDataMgr,
     /*const*/ ATC_Coupling * atc,
     const Array< std::set<int> > & oneDslices,
-    const int solverType = ATC::LinearSolver::DIRECT_SOLVE,
-    bool parallel = false
+    const Array< double > & oneDdxs,
+    bool parallel = true
   );
 
   /** Destructor */
-  virtual ~SliceSchrodingerSolver();
+  virtual ~SliceSchrodingerSolver(){};
 
   /** parser */
   bool modify(int narg, char **arg){return false;}
 
   /** initialize */
   void initialize(void);
 
   /** solve */
   virtual bool solve(FIELDS & fields); 
 
   Array< std::set<int> > & slices(void){ return oneDslices_;} 
+  Array< double > & dxs(void){ return oneDdxs_;} 
 
  protected:
 
   Array< std::set<int> > oneDslices_;
+  Array< double > oneDdxs_;
 
 };
 
+/**
+ *  @class SchrodingerSolver
+ *  @brief a class to solve the Schrodinger-Poisson system
+ */
 class SchrodingerPoissonSolver  {
   public:
     SchrodingerPoissonSolver(
       /*const*/ ATC_Coupling * atc,
       SchrodingerSolver * schrodingerSolver,
       PoissonSolver * poissonSolver,
       const PhysicsModel * physicsModel,
       int maxConsistencyIter
     );
-    virtual ~SchrodingerPoissonSolver(void);
+    virtual ~SchrodingerPoissonSolver(void){};
     virtual void solve(
       FIELDS & rhs,
       GRAD_FIELD_MATS & fluxes
     );
   protected:
     ATC_Coupling * atc_;
     SchrodingerSolver * schrodingerSolver_;
     PoissonSolver * poissonSolver_;
     const PhysicsModel * physicsModel_;
     int maxConsistencyIter_;
+    int maxConstraintIter_;
     int nNodes_;
+    double Ef0_;
+    double Ef_shift_;
+    double safe_dEf_;
+    double tol_;
 };
 
+/**
+ *  @class SchrodingerSolver
+ *  @brief a class to solve the Schrodinger-Poisson system on slices
+ */
 class SliceSchrodingerPoissonSolver : public SchrodingerPoissonSolver  {
   public:
     SliceSchrodingerPoissonSolver(
       /*const*/ ATC_Coupling * atc,
       SchrodingerSolver * schrodingerSolver,
       PoissonSolver * poissonSolver,
       const PhysicsModel * physicsModel,
       int maxConsistencyIter,
       int maxConstraintIter,
       int oneDconserve,
       double Ef_shift,
       double safe_dEf
     );
-    virtual ~SliceSchrodingerPoissonSolver(void);
+    virtual ~SliceSchrodingerPoissonSolver(void){};
     virtual void solve(
       FIELDS & rhs,
       GRAD_FIELD_MATS & fluxes
     );
   protected:
+    int nslices_;
     double update_fermi_energy(double target, bool first, 
       GRAD_FIELD_MATS & fluxes);
-    int maxConstraintIter_;
     int oneDconserve_;
     int oneDcoor_;
-    double Ef_shift_;
-    double safe_dEf_;
     Array< std::set<int> > & oneDslices_;
+    Array< double > & oneDdxs_;
     Array2D<double> EfHistory_;
 };
 
+/**
+ *  @class SchrodingerSolver
+ *  @brief a class to solve the Schrodinger-Poisson system on slices
+ */
+class GlobalSliceSchrodingerPoissonSolver : public SliceSchrodingerPoissonSolver  {
+  public:
+    GlobalSliceSchrodingerPoissonSolver(
+      /*const*/ ATC_Coupling * atc,
+      SchrodingerSolver * schrodingerSolver,
+      PoissonSolver * poissonSolver,
+      const PhysicsModel * physicsModel,
+      int maxConsistencyIter,
+      int maxConstraintIter,
+      int oneDconserve,
+      double Ef0,
+      double alpha,
+      double safe_dEf,
+      double tol,
+      double mu, double D
+    );
+    virtual ~GlobalSliceSchrodingerPoissonSolver(void);
+    virtual void solve(
+      FIELDS & rhs,
+      GRAD_FIELD_MATS & fluxes
+    );
+  protected:
+    void compute_flux(const DENS_MAT & n, const DENS_MAT & phi);
+    void update_fermi_level();
+    void report(int i);
+    void exponential_electron_density();
+    class LinearSolver * solver_;
+    double alpha_;
+    int sliceSize_, nNodes_, nfreeSlices_, nfixed_, nLambda_;
+    SPAR_MAT K_;
+    SPAR_MAT G_,G2_; // 1D & 2D grad mats = int N gradN dv
+    DENS_VEC J_;
+    DENS_VEC flux_;
+    DENS_VEC dJ_;
+    DENS_VEC lambda_;
+    DENS_VEC F_;
+    DENS_VEC Phi_;
+    DENS_VEC n_;
+    Array2D <bool> rhsMask_;
+    double mobility_;
+    double diffusivity_;
+    double norm_, norm0_;
+};
+
+/**
+ *  @class SchrodingerSolver
+ *  @brief a manager class 
+ */
 class SchrodingerPoissonManager  {
   public:
     SchrodingerPoissonManager();
-    ~SchrodingerPoissonManager();
+    ~SchrodingerPoissonManager(){};
 
     /** parser */
     bool modify(int narg, char **arg);
 
     /** initialize */
     SchrodingerPoissonSolver * initialize(   
       /*const*/ ATC_Coupling * atc,
       SchrodingerSolver * schrodingerSolver,
       PoissonSolver * poissonSolver,
       const PhysicsModel * physicsModel
     );
   protected:
     int maxConsistencyIter_;
     int maxConstraintIter_;
     bool oneD_;
     int oneDconserve_;
     double Ef_shift_;
     double safe_dEf_;
+    double alpha_;
+    double tol_;
+    double mu_, D_;
 };
 } // namespace ATC
 #endif
diff --git a/lib/atc/SystemProcessor.h b/lib/atc/SystemProcessor.h
new file mode 100644
index 000000000..9ef511f99
--- /dev/null
+++ b/lib/atc/SystemProcessor.h
@@ -0,0 +1,283 @@
+/*
+ *_________________________________________________________________________*
+ *      POEMS: PARALLELIZABLE OPEN SOURCE EFFICIENT MULTIBODY SOFTWARE     *
+ *      DESCRIPTION: SEE READ-ME                                           *
+ *      FILE NAME: SystemProcessor.h                                       *
+ *      AUTHORS: See Author List                                           * 
+ *      GRANTS: See Grants List                                            *
+ *      COPYRIGHT: (C) 2005 by Authors as listed in Author's List          *
+ *      LICENSE: Please see License Agreement                              *
+ *      DOWNLOAD: Free at www.rpi.edu/~anderk5                             *
+ *      ADMINISTRATOR: Prof. Kurt Anderson                                 *
+ *                     Computational Dynamics Lab                          *
+ *                     Rensselaer Polytechnic Institute                    *
+ *                     110 8th St. Troy NY 12180                           * 
+ *      CONTACT:        anderk5@rpi.edu                                    *
+ *_________________________________________________________________________*/
+
+#ifndef _SYS_PROCESSOR_H_
+#define _SYS_PROCESSOR_H_
+#include "poemslist.h"
+#include "poemstree.h"
+#include "POEMSChain.h"
+
+
+struct POEMSNode {
+	List<POEMSNode> links;
+	List<bool> taken;
+	int idNumber;
+	bool visited;
+	
+	~POEMSNode(){
+		for(int i = 0; i < taken.GetNumElements(); i++)
+		{
+			delete taken(i);
+		}
+	};	
+};
+
+
+class SystemProcessor{
+private:
+	Tree nodes;
+//	List<POEMSNode> forDeletion;
+	List<POEMSChain> headsOfSystems;
+	List<List<int> > ringsInSystem;
+	POEMSNode * findSingleLink(TreeNode * aNode);
+	POEMSChain * AddNewChain(POEMSNode * currentNode);
+	bool setLinkVisited(POEMSNode * firstNode, POEMSNode * secondNode);
+public:
+	SystemProcessor(void);
+	
+	~SystemProcessor(void)	{
+		headsOfSystems.DeleteValues();
+		for(int i = 0; i < ringsInSystem.GetNumElements(); i++)
+		{
+			for(int k = 0; k < ringsInSystem(i)->GetNumElements(); i++)
+			{
+				delete (*ringsInSystem(i))(k);
+			}
+		}
+	};
+	void processArray(int** links, int numLinks);
+	List<POEMSChain> * getSystemData();
+	int getNumberOfHeadChains();
+};
+
+SystemProcessor::SystemProcessor(void){
+}
+
+void SystemProcessor::processArray(int** links, int numLinks)
+{
+	bool * false_var;					//holds the value false; needed because a constant cannot be put into a list; the list requires a
+										//reference.
+	for(int i = 0; i < numLinks; i++)	//go through all the links in the input array
+	{
+		if(!nodes.Find(links[i][0]))	//if the first node in the pair is not found in the storage tree
+		{
+			POEMSNode * newNode = new POEMSNode;	//make a new node
+//			forDeletion.Append(newNode);
+			newNode->idNumber = links[i][0];		//set its ID to the value
+			newNode->visited = false;				//set it to be unvisited
+			nodes.Insert(links[i][0], links[i][0], (void *) newNode);	//and add it to the tree storage structure
+		}
+		if(!nodes.Find(links[i][1]))				//repeat process for the other half of each link
+		{
+			POEMSNode * newNode = new POEMSNode;
+//			forDeletion.Append(newNode);
+			newNode->idNumber = links[i][1];
+			newNode->visited = false;
+			nodes.Insert(links[i][1], links[i][1], (void *) newNode);
+		}
+		POEMSNode * firstNode = (POEMSNode *)nodes.Find(links[i][0]);	//now that we are sure both nodes exist,
+		POEMSNode * secondNode = (POEMSNode *)nodes.Find(links[i][1]);	//we can get both of them out of the tree
+		firstNode->links.Append(secondNode);							//and add the link from the first to the second...
+		false_var = new bool;
+		*false_var = false;												//make a new false boolean to note that the link between these two
+		firstNode->taken.Append(false_var);								//has not already been taken, and append it to the taken list
+		secondNode->links.Append(firstNode);							//repeat process for link from second node to first
+		false_var = new bool;
+		*false_var = false;
+		secondNode->taken.Append(false_var);
+	}	
+	
+	TreeNode * temp = nodes.GetRoot();							//get the root node of the node storage tree
+	POEMSNode * currentNode;
+	do
+	{
+		currentNode = findSingleLink(temp);						//find the start of the next available chain
+		if(currentNode != NULL)
+		{
+			headsOfSystems.Append(AddNewChain(currentNode));							//and add it to the headsOfSystems list of chains
+		}
+	} 
+	while(currentNode != NULL);									//repeat this until all chains have been added		
+}
+
+POEMSChain * SystemProcessor::AddNewChain(POEMSNode * currentNode){
+	if(currentNode == NULL)	//Termination condition; if the currentNode is null, then return null
+	{
+		return NULL;
+	}
+	int * tmp;
+	POEMSNode * nextNode = NULL;	//nextNode stores the proposed next node to add to the chain.  this will be checked to make sure no backtracking is occuring before being assigned as the current node.
+	POEMSChain * newChain = new POEMSChain;	//make a new POEMSChain object.  This will be the object returned
+
+	if(currentNode->links.GetNumElements() == 0)	//if we have no links from this node, then the whole chain is only one node.  Add this node to the chain and return it; mark node as visited for future reference
+	{
+		currentNode->visited = true;
+		tmp = new int;
+		*tmp = currentNode->idNumber;
+		newChain->listOfNodes.Append(tmp);
+		return newChain;
+	}
+	while(currentNode->links.GetNumElements() <= 2)	//we go until we get to a node that branches, or both branches have already been taken both branches can already be taken if a loop with no spurs is found in the input data
+	{
+		currentNode->visited = true;
+		tmp = new int;
+		*tmp = currentNode->idNumber;
+		newChain->listOfNodes.Append(tmp);	//append the current node to the chain & mark as visited
+		//cout << "Appending node " << currentNode->idNumber << " to chain" << endl;
+		nextNode = currentNode->links.GetHeadElement()->value;	//the next node is the first or second value stored in the links array
+																//of the current node.  We get the first value...
+		if(!setLinkVisited(currentNode, nextNode))					//...and see if it points back to where we came from. If it does...
+		{														//either way, we set this link as visited
+			if(currentNode->links.GetNumElements() == 1)		//if it does, then if that is the only link to this node, we're done with the chain, so append the chain to the list and return the newly created chain
+			{
+//				headsOfSystems.Append(newChain);
+				return newChain;
+			}
+			nextNode = currentNode->links.GetHeadElement()->next->value;//follow the other link if there is one, so we go down the chain
+			if(!setLinkVisited(currentNode, nextNode))				//mark link as followed, so we know not to backtrack			
+			{
+	//			headsOfSystems.Append(newChain);
+				return newChain;								//This condition, where no branches have occurred but both links have already
+																//been taken can only occur in a loop with no spurs; add this loop to the
+																//system (currently added as a chain for consistency), and return.
+			}
+		}
+		currentNode = nextNode;									//set the current node to be the next node in the chain
+	}
+	currentNode->visited = true;
+	tmp = new int;
+	*tmp = currentNode->idNumber;
+	newChain->listOfNodes.Append(tmp);		//append the last node before branch (node shared jointly with branch chains)
+																//re-mark as visited, just to make sure
+	ListElement<POEMSNode> * tempNode = currentNode->links.GetHeadElement();	//go through all of the links, one at a time that branch
+	POEMSChain * tempChain = NULL;								//temporary variable to hold data 
+	while(tempNode != NULL)										//when we have followed all links, stop
+	{
+		if(setLinkVisited(tempNode->value, currentNode))		//dont backtrack, or create closed loops
+		{
+			tempChain = AddNewChain(tempNode->value);			//Add a new chain created out of the next node down that link
+			tempChain->parentChain = newChain;					//set the parent to be this chain
+			newChain->childChains.Append(tempChain);			//append the chain to this chain's list of child chains
+		}
+		tempNode = tempNode->next;								//go to process the next chain
+	}
+	//headsOfSystems.Append(newChain);							//append this chain to the system list		
+	return newChain;	
+}
+
+POEMSNode * SystemProcessor::findSingleLink(TreeNode * aNode)
+//This function takes the root of a search tree containing POEMSNodes and returns a POEMSNode corresponding to the start of a chain in the
+//system.  It finds a node that has not been visited before, and only has one link; this node will be used as the head of the chain.
+{
+	if(aNode == NULL)	
+	{
+		return NULL;
+	}
+	POEMSNode * returnVal =  (POEMSNode *)aNode->GetAuxData();	//get the poemsnode data out of the treenode
+	POEMSNode * detectLoneLoops = NULL;							//is used to handle a loop that has no protruding chains
+	if(returnVal->visited == false)
+	{
+		detectLoneLoops = returnVal;							//if we find any node that has not been visited yet, save it
+	}
+	if(returnVal->links.GetNumElements() == 1 && returnVal->visited == false)	//see if it has one element and hasnt been visited already
+	{
+		return returnVal;														//return the node is it meets this criteria
+	}
+	returnVal = findSingleLink(aNode->Left());									//otherwise, check the left subtree
+	if(returnVal == NULL)														//and if we find nothing...
+	{
+		returnVal = findSingleLink(aNode->Right());								//check the right subtree
+	}
+	if(returnVal == NULL)														//if we could not find any chains
+	{
+		returnVal = detectLoneLoops;											//see if we found any nodes at all that havent been processed
+	}
+	return returnVal;															//return what we find (will be NULL if no new chains are 
+																				//found)
+}
+
+bool SystemProcessor::setLinkVisited(POEMSNode * firstNode, POEMSNode * secondNode)
+//setLinkVisited sets the links between these two nodes as visited. If they are already visited, it returns false.  Otherwise, it sets
+//them as visited and returns true.  This function is used to see whether a certain path has been taken already in the graph structure.
+//If it has been, then we need to know so we dont follow it again; this prevents infinite recursion when there is a loop, and prevents
+//backtracking up a chain that has already been made.  The list of booleans denoting if a link has been visited is called 'taken' and is
+//part of the POEMSNode struct.  The list is the same size as the list of pointers to other nodes, and stores the boolean visited/unvisited
+//value for that particular link.  Because each link is represented twice, (once at each node in the link), both of the boolean values need
+//to be set in the event that the link has to be set as visited.
+{
+	//cout << "Checking link between nodes " << firstNode->idNumber << " and " << secondNode->idNumber << "... ";
+	ListElement<POEMSNode> * tmp = firstNode->links.GetHeadElement();	//get the head element of the list of pointers for node 1
+	ListElement<bool> * tmp2 = firstNode->taken.GetHeadElement();		//get the head element of the list of bool isVisited flags for node 1
+	while(tmp->value != NULL || tmp2->value != NULL)					//go through untill we reach the end of the lists
+	{
+		if(tmp->value == secondNode)							//if we find the link to the other node
+		{
+			if(*(tmp2->value) == true)							//if the link has already been visited
+			{
+				 //cout << "visited already" << endl;
+				return false;									//return false to indicate that the link has been visited before this attempt
+			}
+			else												//otherwise, visit it
+			{
+				*tmp2->value = true;
+			}
+			break;
+		}
+		tmp = tmp->next;										//go check next link
+		tmp2 = tmp2->next;
+	}
+
+	tmp = secondNode->links.GetHeadElement();			//now, if the link was unvisited, we need to go set the other node's list such that
+														//it also knows this link is being visited
+	tmp2 = secondNode->taken.GetHeadElement();
+	while(tmp->value != NULL || tmp2->value != NULL)	//go through the list
+	{
+		if(tmp->value == firstNode)						//if we find the link
+		{
+			if(*(tmp2->value) == true)					//and it has already been visited, then signal an error; this shouldnt ever happen
+			{
+				cout << "Error in parsing structure! Should never reach this condition! \n" << 
+						"Record of visited links out of synch between two adjacent nodes.\n";
+				return false;
+			}
+			else
+			{
+				*tmp2->value = true;					//set the appropriate value to true to indicate this link has been visited
+			}
+			break;
+		}
+		tmp = tmp->next;
+		tmp2 = tmp2->next;
+	}
+	//cout << "not visited" << endl;
+	return true;										//return true to indicate that this is the first time the link has been visited
+}
+
+List<POEMSChain> * SystemProcessor::getSystemData(void)	//Gets the list of POEMSChains that comprise the system.  Might eventually only
+														//return chains linked to the reference plane, but currently returns every chain
+														//in the system.
+{
+	return &headsOfSystems;
+}
+
+int SystemProcessor::getNumberOfHeadChains(void) //This function isnt implemented yet, and might be taken out entirely; this was a holdover
+												//from when I intended to return an array of chain pointers, rather than a list of chains
+												//It will probably be deleted once I finish figuring out exactly what needs to be returned
+{
+	return 0;
+}
+#endif
diff --git a/lib/atc/Thermostat.cpp b/lib/atc/Thermostat.cpp
index 110d633ac..41312bd85 100644
--- a/lib/atc/Thermostat.cpp
+++ b/lib/atc/Thermostat.cpp
@@ -1,2381 +1,2621 @@
 #include "Thermostat.h"
 #include "ATC_Coupling.h"
 #include "ATC_Error.h"
 #include "PrescribedDataManager.h"
 #include "ThermalTimeIntegrator.h"
 #include "TransferOperator.h"
 
 using namespace std;
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class Thermostat
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   Thermostat::Thermostat(ATC_Coupling * atc,
                          const string & regulatorPrefix) :
     AtomicRegulator(atc,regulatorPrefix),
     lambdaMaxIterations_(myLambdaMaxIterations)
   {
     // nothing to do
   }
 
   //--------------------------------------------------------
   //  modify:
   //    parses and adjusts thermostat state based on
   //    user input, in the style of LAMMPS user input
   //--------------------------------------------------------
   bool Thermostat::modify(int narg, char **arg)
   {
     bool foundMatch = false;
 
     int argIndex = 0;
     if (strcmp(arg[argIndex],"thermal")==0) {
       argIndex++;
     
       // thermostat type
       /*! \page man_control_thermal fix_modify AtC control thermal 
         \section syntax
         fix_modify AtC control thermal <control_type> <optional_args>
         - control_type (string) = none | rescale | hoover | flux\n
       
         fix_modify AtC control thermal rescale <frequency> \n
         - frequency (int) = time step frequency for applying velocity rescaling \n
 
         fix_modify AtC control thermal hoover \n
 
         fix_modify AtC control thermal flux <boundary_integration_type(optional)> <face_set_id(optional)>\n
         - boundary_integration_type (string) = faceset | interpolate\n
         - face_set_id (string), optional = id of boundary face set, if not specified
         (or not possible when the atomic domain does not line up with 
         mesh boundaries) defaults to an atomic-quadrature approximate 
         evaulation, does not work with interpolate\n
         \section examples
         <TT> fix_modify AtC control thermal none </TT> \n
         <TT> fix_modify AtC control thermal rescale 10 </TT> \n
         <TT> fix_modify AtC control thermal hoover </TT> \n
         <TT> fix_modify AtC control thermal flux </TT> \n
         <TT> fix_modify AtC control thermal flux faceset bndy_faces </TT> \n
         \section description
         Sets the energy exchange mechansim from the finite elements to the atoms, managed through a control algorithm.  Rescale computes a scale factor for each atom to match the finite element temperature.  Hoover is a Gaussian least-constraint isokinetic thermostat enforces that the nodal restricted atomic temperature matches the finite element temperature.  Flux is a similar mode, but rather adds energy to the atoms based on conservation of energy.  Hoover and flux allows the prescription of sources or fixed temperatures on the atoms. 
         \section restrictions
         only for be used with specific transfers :
         thermal (rescale, hoover, flux), two_temperature (flux) \n
         rescale not valid with time filtering activated
         \section related
         \section default
         none\n
         rescale frequency is 1\n
         flux boundary_integration_type is interpolate
       */
       if (strcmp(arg[argIndex],"none")==0) { // restore defaults
         regulatorTarget_ = NONE;
         couplingMode_ = UNCOUPLED;
         howOften_ = 1;
         boundaryIntegrationType_ = NO_QUADRATURE;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"rescale")==0) {
         argIndex++;
         howOften_ = atoi(arg[argIndex]);
         if (howOften_ < 1) {
           throw ATC_Error("Bad rescaling thermostat frequency");
         }
         else {
           regulatorTarget_ = FIELD;
           couplingMode_ = UNCOUPLED;
           boundaryIntegrationType_ = NO_QUADRATURE;
           foundMatch = true;
         }
       }
       else if (strcmp(arg[argIndex],"hoover")==0) {
         regulatorTarget_ = DYNAMICS;
         couplingMode_ = FIXED;
         howOften_ = 1;
         boundaryIntegrationType_ = NO_QUADRATURE;
         foundMatch = true;
       }
       else if (strcmp(arg[argIndex],"flux")==0) {
         regulatorTarget_ = DYNAMICS;
         couplingMode_ = FLUX;
         howOften_ = 1;
         argIndex++;
         
         boundaryIntegrationType_ = atc_->parse_boundary_integration(narg-argIndex,&arg[argIndex],boundaryFaceSet_);
         foundMatch = true;
       }
       // set parameters for numerical matrix solutions unique to this thermostat
       /*! \page man_control_thermal_correction_max_iterations fix_modify AtC control thermal correction_max_iterations
         \section syntax
         fix_modify AtC control thermal correction_max_iterations <max_iterations>
         - max_iterations (int) = maximum number of iterations that will be used by iterative matrix solvers\n
 
         \section examples
         <TT> fix_modify AtC control thermal correction_max_iterations 10 </TT> \n
         \section description
         Sets the maximum number of iterations to compute the 2nd order in time correction term for lambda with the fractional step method.  The method uses the same tolerance as the controller's matrix solver.
         \section restrictions
         only for use with thermal physics using the fractional step method.
         \section related
         \section default
         correction_max_iterations is 20
       */
       else if (strcmp(arg[argIndex],"correction_max_iterations")==0) {
         argIndex++;
         lambdaMaxIterations_ = atoi(arg[argIndex]);
         if (lambdaMaxIterations_ < 1) {
           throw ATC_Error("Bad correction maximum iteration count");
         }
         foundMatch = true;
       }
     }
 
     if (!foundMatch)
       foundMatch = AtomicRegulator::modify(narg,arg);
     if (foundMatch)
       needReset_ = true;
     return foundMatch;
   }
 
   //--------------------------------------------------------
   //  reset_lambda_contribution:
   //    resets the thermostat generated power to a
   //    prescribed value
   //--------------------------------------------------------
   void Thermostat::reset_lambda_contribution(const DENS_MAT & target)
   {
     DENS_MAN * lambdaPowerFiltered = regulator_data("LambdaPowerFiltered",1);
     *lambdaPowerFiltered = target;
   }
 
   //--------------------------------------------------------
   //  construct_methods:
   //    instantiations desired regulator method(s)
   
   //    dependence, but in general there is also a
   //    time integrator dependence.  In general the 
   //    precedence order is:
   //    time filter -> time integrator -> thermostat
   //    In the future this may need to be added if
   //    different types of time integrators can be
   //    specified.
   //--------------------------------------------------------
   void Thermostat::construct_methods()
   {
     // get data associated with stages 1 & 2 of ATC_Method::initialize
     AtomicRegulator::construct_methods();
 
     if (atc_->reset_methods()) {
       // eliminate existing methods
       delete_method();
 
       // update time filter
       TimeIntegrator::TimeIntegrationType myIntegrationType = (atc_->time_integrator(TEMPERATURE))->time_integration_type();
       TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
       if (timeFilterManager->need_reset() ) {
-        if (myIntegrationType == TimeIntegrator::GEAR)
-         timeFilter_ = timeFilterManager->construct(TimeFilterManager::EXPLICIT);
-        else if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP)
-         timeFilter_ = timeFilterManager->construct(TimeFilterManager::EXPLICIT_IMPLICIT);
+        if (myIntegrationType == TimeIntegrator::GEAR) {
+          timeFilter_ = timeFilterManager->construct(TimeFilterManager::EXPLICIT);
+        }
+        else if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
+          timeFilter_ = timeFilterManager->construct(TimeFilterManager::EXPLICIT_IMPLICIT);
+        }
       }
       
       if (timeFilterManager->filter_dynamics()) {
         switch (regulatorTarget_) {
         case NONE: {
           regulatorMethod_ = new RegulatorMethod(this);
           break;
         }
         case FIELD: { // error check, rescale and filtering not supported together
           throw ATC_Error("Cannot use rescaling thermostat with time filtering");
           break;
         }
         case DYNAMICS: {
           switch (couplingMode_) {
           case FIXED: {
             if (use_lumped_lambda_solve()) {
               throw ATC_Error("Thermostat:construct_methods - lumped lambda solve cannot be used with Hoover thermostats");
             }
             if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
               if (md_flux_nodes(TEMPERATURE)) {
                 if (!md_fixed_nodes(TEMPERATURE) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
                   // there are fluxes but no fixed or coupled nodes
-                  regulatorMethod_ = new ThermostatFluxFiltered(this);
+                  regulatorMethod_ = new ThermostatIntegratorFluxFiltered(this,lambdaMaxIterations_);
                 }
                 else {
                   // there are both fixed and flux nodes
-                  regulatorMethod_ = new ThermostatFluxFixedFiltered(this);
+                  regulatorMethod_ = new ThermostatFluxFixedFiltered(this,lambdaMaxIterations_);
                 }
               }
               else {
                 // there are only fixed nodes
-                regulatorMethod_ = new ThermostatFixedFiltered(this);
+                regulatorMethod_ = new ThermostatIntegratorFixedFiltered(this,lambdaMaxIterations_);
               }
             }
             else {
               regulatorMethod_ = new ThermostatHooverVerletFiltered(this);
             }
             break;
           }
           case FLUX: {
             if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
               if (use_lumped_lambda_solve()) {
                 throw ATC_Error("Thermostat:construct_methods - lumped lambda solve has been depricated for fractional step thermostats");
               }
               if (md_fixed_nodes(TEMPERATURE)) {
                 if (!md_flux_nodes(TEMPERATURE) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
                 // there are fixed nodes but no fluxes
-                regulatorMethod_ = new ThermostatFixedFiltered(this);
+                regulatorMethod_ = new ThermostatIntegratorFixedFiltered(this,lambdaMaxIterations_);
                 }
                 else {
                   // there are both fixed and flux nodes
-                  regulatorMethod_ = new ThermostatFluxFixedFiltered(this);
+                  regulatorMethod_ = new ThermostatFluxFixedFiltered(this,lambdaMaxIterations_);
                 }
               }
               else {
                 // there are only flux nodes
-                regulatorMethod_ = new ThermostatFluxFiltered(this);
+                regulatorMethod_ = new ThermostatIntegratorFluxFiltered(this,lambdaMaxIterations_);
               }
             }
             else {
               if (use_localized_lambda()) {
                 if (!((atc_->prescribed_data_manager())->no_fluxes(TEMPERATURE)) &&
                     atc_->boundary_integration_type() != NO_QUADRATURE) {
                   throw ATC_Error("Cannot use flux coupling with localized lambda");
                 }
               }
               regulatorMethod_ = new ThermostatPowerVerletFiltered(this);
             }
             break;
           }
           default:
             throw ATC_Error("Unknown coupling mode in Thermostat::initialize");
           }
           break;
         }
         default:
           throw ATC_Error("Unknown thermostat type in Thermostat::initialize");
         }
       }
       else {
         switch (regulatorTarget_) {
         case NONE: {
           regulatorMethod_ = new RegulatorMethod(this);
           break;
         }
         case FIELD: {
           if (atc_->temperature_def()==KINETIC)
             regulatorMethod_ = new ThermostatRescale(this);
           else if (atc_->temperature_def()==TOTAL)
             regulatorMethod_ = new ThermostatRescaleMixedKePe(this);
           else
             throw ATC_Error("Unknown temperature definition");
           break;
         }
         case DYNAMICS: {
           switch (couplingMode_) {
           case FIXED: {
             if (use_lumped_lambda_solve()) {
               throw ATC_Error("Thermostat:construct_methods - lumped lambda solve cannot be used with Hoover thermostats");
             }
             if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
               if (md_flux_nodes(TEMPERATURE)) {
                 if (!md_fixed_nodes(TEMPERATURE) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
                   // there are fluxes but no fixed or coupled nodes
-                  regulatorMethod_ = new ThermostatFlux(this);
+                  regulatorMethod_ = new ThermostatIntegratorFlux(this,lambdaMaxIterations_);
                 }
                 else {
                   // there are both fixed and flux nodes
-                  regulatorMethod_ = new ThermostatFluxFixed(this);
+                  regulatorMethod_ = new ThermostatFluxFixed(this,lambdaMaxIterations_);
                 }
               }
               else {
                 // there are only fixed nodes
-                regulatorMethod_ = new ThermostatFixed(this);
+                regulatorMethod_ = new ThermostatIntegratorFixed(this,lambdaMaxIterations_);
               }
             }
             else {
               regulatorMethod_ = new ThermostatHooverVerlet(this);
             }
             break;
           }
           case FLUX: {
             if (myIntegrationType == TimeIntegrator::FRACTIONAL_STEP) {
               if (use_lumped_lambda_solve()) {
                 throw ATC_Error("Thermostat:construct_methods - lumped lambda solve has been depricated for fractional step thermostats");
               }
               if (md_fixed_nodes(TEMPERATURE)) {
                 if (!md_flux_nodes(TEMPERATURE) && (boundaryIntegrationType_ == NO_QUADRATURE)) {
                   // there are fixed nodes but no fluxes
-                  regulatorMethod_ = new ThermostatFixed(this);
+                  regulatorMethod_ = new ThermostatIntegratorFixed(this,lambdaMaxIterations_);
                 }
                 else {
                   // there are both fixed and flux nodes
-                  regulatorMethod_ = new ThermostatFluxFixed(this);
+                  regulatorMethod_ = new ThermostatFluxFixed(this,lambdaMaxIterations_);
                 }
               }
               else {
                 // there are only flux nodes
-                regulatorMethod_ = new ThermostatFlux(this);
+                regulatorMethod_ = new ThermostatIntegratorFlux(this,lambdaMaxIterations_);
               }
             }
             else {
               if (use_localized_lambda()) {
                 if (!((atc_->prescribed_data_manager())->no_fluxes(TEMPERATURE)) &&
                     atc_->boundary_integration_type() != NO_QUADRATURE) {
                   throw ATC_Error("Cannot use flux coupling with localized lambda");
                 }
               }
               regulatorMethod_ = new ThermostatPowerVerlet(this);
             }
             break;
           }
           default:
             throw ATC_Error("Unknown coupling mode in Thermostat::initialize");
           }
           break;
         }
         default:
           throw ATC_Error("Unknown thermostat target in Thermostat::initialize");
         }
       }
       
       AtomicRegulator::reset_method();
     }
     else {
       set_all_data_to_used();
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatShapeFunction
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
-  ThermostatShapeFunction::ThermostatShapeFunction(Thermostat * thermostat,
+  ThermostatShapeFunction::ThermostatShapeFunction(AtomicRegulator * thermostat,
                                                    const string & regulatorPrefix) :
     RegulatorShapeFunction(thermostat,regulatorPrefix),
-    thermostat_(thermostat),
     mdMassMatrix_(atc_->set_mass_mat_md(TEMPERATURE)),
     atomVelocities_(NULL)
   {
     fieldMask_(TEMPERATURE,FLUX) = true;
-    lambda_ = thermostat_->regulator_data(regulatorPrefix_+"LambdaEnergy",1); // data associated with stage 3 in ATC_Method::initialize
+    lambda_ = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaEnergy",1); // data associated with stage 3 in ATC_Method::initialize
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatShapeFunction::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
     RegulatorShapeFunction::construct_transfers();
 
     // get atom velocity data from manager
     atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY);
 
     // construct lambda evaluated at atom locations
     atomLambdas_ = new FtaShapeFunctionProlongation(atc_,
                                                     lambda_,
                                                     interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_per_atom_quantity(atomLambdas_,regulatorPrefix_+"AtomLambdaEnergy");
   }
 
   //---------------------------------------------------------
   //  set_weights:
   //    set the diagonal weighting matrix to be the atomic
   //    temperatures
   //---------------------------------------------------------
   void ThermostatShapeFunction::set_weights()
   {
     if (this->use_local_shape_functions()) {
       VelocitySquaredMapped * myWeights = new VelocitySquaredMapped(atc_,lambdaAtomMap_);
       weights_ = myWeights;
       (atc_->interscale_manager()).add_per_atom_quantity(myWeights,
                                                          regulatorPrefix_+"AtomVelocitySquaredMapped");
     }
     else {
       VelocitySquared * myWeights = new VelocitySquared(atc_);
       weights_ = myWeights;
       (atc_->interscale_manager()).add_per_atom_quantity(myWeights,
                                                          regulatorPrefix_+"AtomVelocitySquared");
     }
   }
-  
-  
+
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatRescale
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
-  ThermostatRescale::ThermostatRescale(Thermostat * thermostat) :
+  ThermostatRescale::ThermostatRescale(AtomicRegulator * thermostat) :
     ThermostatShapeFunction(thermostat),
     nodalTemperature_(atc_->field(TEMPERATURE)),
     atomVelocityRescalings_(NULL)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatRescale::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
     // set up data for linear solver
     shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
     (atc_->interscale_manager()).add_per_atom_sparse_matrix(shapeFunctionMatrix_,
                                                             regulatorPrefix_+"LambdaCouplingMatrixEnergy");
     linearSolverType_ = AtomicRegulator::CG_SOLVE;
 
     // base class transfers
     ThermostatShapeFunction::construct_transfers();
 
     // velocity rescaling factor
     atomVelocityRescalings_ = new AtomicVelocityRescaleFactor(atc_,atomLambdas_);
     interscaleManager.add_per_atom_quantity(atomVelocityRescalings_,
                                             regulatorPrefix_+"AtomVelocityRescaling");
   }
 
+  //---------------------------------------------------------
+  //  set_weights:
+  //    set the diagonal weighting matrix to be the atomic
+  //    temperatures
+  //---------------------------------------------------------
+  void ThermostatRescale::set_weights()
+  {
+    weights_ = (atc_->interscale_manager()).per_atom_quantity("AtomicEnergyForTemperature");
+  }
+
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the thermostat in the post corrector phase
   //--------------------------------------------------------
   void ThermostatRescale::apply_post_corrector(double dt)
+  {
+    compute_thermostat(dt);
+
+    // application of rescaling lambda due
+    apply_to_atoms(atomVelocities_);
+  }
+
+  //--------------------------------------------------------
+  //  compute_thermostat
+  //            manages the solution of the
+  //            thermostat equations and variables
+  //--------------------------------------------------------
+  void ThermostatRescale::compute_thermostat(double dt)
   {
     // compute right-hand side
-    _rhs_ = mdMassMatrix_.quantity()*nodalTemperature_.quantity();
-    correct_rhs(_rhs_); // correct right-hand side for complex temperature definitions, e.g., when the potential energy is included
+    this->set_rhs(_rhs_);
     
     // solve equations
     solve_for_lambda(_rhs_,lambda_->set_quantity());
+  }
 
-    // application of rescaling lambda due
-    apply_to_atoms(atomVelocities_);
+  //--------------------------------------------------------
+  //  set_rhs:
+  //    constructs the RHS vector with the target
+  //    temperature
+  //--------------------------------------------------------
+  void ThermostatRescale::set_rhs(DENS_MAT & rhs)
+  {
+    rhs = mdMassMatrix_.quantity()*nodalTemperature_.quantity();
   }
 
   //--------------------------------------------------------
   //  apply_lambda_to_atoms:
   //    applies the velocity rescale with an existing lambda
   //    note oldAtomicQuantity and dt are not used
   //--------------------------------------------------------
   void ThermostatRescale::apply_to_atoms(PerAtomQuantity<double> * atomVelocities)
   {
     *atomVelocities *= atomVelocityRescalings_->quantity();
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void ThermostatRescale::output(OUTPUT_LIST & outputData)
   {
     DENS_MAT & lambda(lambda_->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
-      outputData["Lambda"] = &lambda;
+      outputData["LambdaEnergy"] = &lambda;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatRescaleMixedKePe
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
-  ThermostatRescaleMixedKePe::ThermostatRescaleMixedKePe(Thermostat * thermostat) :
+  ThermostatRescaleMixedKePe::ThermostatRescaleMixedKePe(AtomicRegulator * thermostat) :
     ThermostatRescale(thermostat),
     nodalAtomicFluctuatingPotentialEnergy_(NULL)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatRescaleMixedKePe::construct_transfers()
   {
     ThermostatRescale::construct_transfers();
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // get fluctuating PE at nodes
     nodalAtomicFluctuatingPotentialEnergy_ = 
       interscaleManager.dense_matrix("NodalAtomicFluctuatingPotentialEnergy");
   }
 
+  //---------------------------------------------------------
+  //  set_weights:
+  //    set the diagonal weighting matrix to be the atomic
+  //    temperatures
+  //---------------------------------------------------------
+  void ThermostatRescaleMixedKePe::set_weights()
+  {
+    weights_ = (atc_->interscale_manager()).per_atom_quantity("AtomicTwiceKineticEnergy");
+  }
+
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void ThermostatRescaleMixedKePe::initialize()
   {
     ThermostatRescale::initialize();
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // multipliers for KE and PE
     AtomicEnergyForTemperature * atomEnergyForTemperature =
       static_cast<AtomicEnergyForTemperature * >(interscaleManager.per_atom_quantity("AtomicEnergyForTemperature"));
     keMultiplier_ = atomEnergyForTemperature->kinetic_energy_multiplier();
     peMultiplier_ = 2. - keMultiplier_;
     keMultiplier_ /= 2.; // account for use of 2 X KE in matrix equation
   }
 
   //--------------------------------------------------------
-  //  correct_rhs:
+  //  set_rhs:
   //    accounts for potential energy contribution to
   //    definition of atomic temperature
   //--------------------------------------------------------
-  void ThermostatRescaleMixedKePe::correct_rhs(DENS_MAT & rhs)
+  void ThermostatRescaleMixedKePe::set_rhs(DENS_MAT & rhs)
   {
+    ThermostatRescale::set_rhs(rhs);
     rhs -=  peMultiplier_*(nodalAtomicFluctuatingPotentialEnergy_->quantity());
     rhs /= keMultiplier_;
   }
+
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class ThermostatFsSolver
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+ 
+  //--------------------------------------------------------
+  //  Constructor
+  //--------------------------------------------------------
+  ThermostatFsSolver::ThermostatFsSolver(AtomicRegulator * thermostat,
+                                         int lambdaMaxIterations,
+                                         const string & regulatorPrefix) :
+    RegulatorShapeFunction(thermostat,regulatorPrefix),
+    lambdaMaxIterations_(lambdaMaxIterations),
+    rhsLambdaSquared_(NULL),
+    dtFactor_(1.)
+  {
+    fieldMask_(TEMPERATURE,FLUX) = true;
+    lambda_ = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaEnergy",1); // data associated with stage 3 in ATC_Method::initialize
+  }
+
+  //--------------------------------------------------------
+  //  initialize
+  //    creates mapping from all nodes to those to which
+  //    the thermostat applies
+  //--------------------------------------------------------
+  void ThermostatFsSolver::initialize()
+  {
+    RegulatorShapeFunction::initialize();
+
+    rhsMap_.resize(overlapToNodeMap_->nRows(),1);
+    DENS_MAT rhsMapGlobal(nNodes_,1);
+    const set<int> & applicationNodes(applicationNodes_->quantity());
+    for (int i = 0; i < nNodes_; i++) {
+      if (applicationNodes.find(i) != applicationNodes.end()) {
+        rhsMapGlobal(i,0) = 1.;
+      }
+      else {
+        rhsMapGlobal(i,0) = 0.;
+      }
+    }
+    map_unique_to_overlap(rhsMapGlobal,rhsMap_);
+  }
+
+  //---------------------------------------------------------
+  //  set_weights:
+  //    set the diagonal weighting matrix to be the atomic
+  //    temperatures
+  //---------------------------------------------------------
+  void ThermostatFsSolver::set_weights()
+  {
+    if (this->use_local_shape_functions()) {
+      VelocitySquaredMapped * myWeights = new VelocitySquaredMapped(atc_,lambdaAtomMap_);
+      weights_ = myWeights;
+      (atc_->interscale_manager()).add_per_atom_quantity(myWeights,
+                                                         regulatorPrefix_+"AtomVelocitySquaredMapped");
+    }
+    else {
+      VelocitySquared * myWeights = new VelocitySquared(atc_);
+      weights_ = myWeights;
+      (atc_->interscale_manager()).add_per_atom_quantity(myWeights,
+                                                         regulatorPrefix_+"AtomVelocitySquared");
+    }
+  }
+
+  //--------------------------------------------------------
+  //  compute_lambda:
+  //   solves linear system for lambda, if the
+  //   bool is true it iterators to a non-linear solution
+  //--------------------------------------------------------
+  void ThermostatFsSolver::compute_lambda(const DENS_MAT & rhs,
+                                          bool iterateSolution)
+  {
+    // solve linear system for lambda guess
+    DENS_MAT & lambda(lambda_->set_quantity());
+    solve_for_lambda(rhs,lambda);
+
+    // iterate to solution
+    if (iterateSolution) {
+      iterate_lambda(rhs);
+    }
+  }
+
+  //--------------------------------------------------------
+  //  iterate_lambda:
+  //    iteratively solves the equations for lambda
+  //    for the higher order dt corrections, assuming
+  //    an initial guess for lambda
+  //--------------------------------------------------------
+  void ThermostatFsSolver::iterate_lambda(const MATRIX & rhs)
+  {
+    int nNodeOverlap = overlapToNodeMap_->nRows();
+    DENS_VEC _lambdaOverlap_(nNodeOverlap);
+    DENS_MAT & lambda(lambda_->set_quantity());
+    map_unique_to_overlap(lambda,_lambdaOverlap_);
+    double factor = 0.5*dtFactor_*atc_->dt();
+
+    _lambdaOld_.resize(nNodes_,1);
+    _rhsOverlap_.resize(nNodeOverlap,1);
+    map_unique_to_overlap(rhs,_rhsOverlap_);
+    _rhsTotal_.resize(nNodeOverlap);
+
+    // solve assuming we get initial guess for lambda
+    double error(-1.);
+    for (int i = 0; i < lambdaMaxIterations_; ++i) {
+      _lambdaOld_ = lambda;
+
+      // solve the system with the new rhs
+      const DENS_MAT & rhsLambdaSquared(rhsLambdaSquared_->quantity());
+      for (int i = 0; i < nNodeOverlap; i++) {
+        if (rhsMap_(i,0) == 1.) {
+          _rhsTotal_(i) = _rhsOverlap_(i,0) + factor*rhsLambdaSquared(i,0);
+        }
+        else {
+          _rhsTotal_(i) = 0.;
+        }
+      }
+      matrixSolver_->execute(_rhsTotal_,_lambdaOverlap_);
+
+      // check convergence
+      map_overlap_to_unique(_lambdaOverlap_,lambda);
+      lambda_->force_reset();
+      DENS_MAT difference = lambda-_lambdaOld_;
+      error = difference.col_norm()/_lambdaOld_.col_norm();
+      if (error < tolerance_)
+        break;
+    }
+    
+    if (error >= tolerance_) {
+      stringstream message;
+      message << "WARNING: Iterative solve for lambda failed to converge after " << lambdaMaxIterations_ << " iterations, final tolerance was " << error << "\n";
+      ATC::LammpsInterface::instance()->print_msg(message.str());
+    }
+  }
  
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatGlcFs
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
-  ThermostatGlcFs::ThermostatGlcFs(Thermostat * thermostat,
+  ThermostatGlcFs::ThermostatGlcFs(AtomicRegulator * thermostat,
+                                   int lambdaMaxIterations,
                                    const string & regulatorPrefix) :
-    ThermostatShapeFunction(thermostat,regulatorPrefix),
+    RegulatorMethod(thermostat,regulatorPrefix),
+    lambdaSolver_(NULL),
+    mdMassMatrix_(atc_->set_mass_mat_md(TEMPERATURE)),
+    atomVelocities_(NULL),
     temperature_(atc_->field(TEMPERATURE)),
     timeFilter_(atomicRegulator_->time_filter()),
     nodalAtomicLambdaPower_(NULL),
     lambdaPowerFiltered_(NULL),
+    atomLambdas_(NULL),
     atomThermostatForces_(NULL),
     atomMasses_(NULL),
-    rhsLambdaSquared_(NULL),
     isFirstTimestep_(true),
-    lambdaMaxIterations_(thermostat->lambda_max_iterations()),
     nodalAtomicEnergy_(NULL),
     atomPredictedVelocities_(NULL),
     nodalAtomicPredictedEnergy_(NULL),
-    firstHalfAtomForces_(NULL),
-    dtFactor_(0.)
+    firstHalfAtomForces_(NULL)
   {
     // construct/obtain data corresponding to stage 3 of ATC_Method::initialize
     nodalAtomicLambdaPower_ = thermostat->regulator_data(regulatorPrefix_+"NodalAtomicLambdaPower",1);
-    lambdaPowerFiltered_ = thermostat_->regulator_data(regulatorPrefix_+"LambdaPowerFiltered",1);
+    lambdaPowerFiltered_ = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaPowerFiltered",1);
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatGlcFs::construct_transfers()
   {
-    ThermostatShapeFunction::construct_transfers();
+    lambdaSolver_->construct_transfers();
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
+    // get atom velocity data from manager
+    atomVelocities_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_VELOCITY);
+
+    // construct lambda evaluated at atom locations
+    atomLambdas_ = interscaleManager.per_atom_quantity(regulatorPrefix_+"AtomLambdaEnergy");
+    if (!atomLambdas_) {
+      DENS_MAN * lambda = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaEnergy",1);
+      atomLambdas_ = new FtaShapeFunctionProlongation(atc_,
+                                                      lambda,
+                                                      interscaleManager.per_atom_sparse_matrix("Interpolant"));
+      interscaleManager.add_per_atom_quantity(atomLambdas_,regulatorPrefix_+"AtomLambdaEnergy");
+    }
+
     // get data from manager
     atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS),
     nodalAtomicEnergy_ = interscaleManager.dense_matrix("NodalAtomicEnergy");
     
     // thermostat forces based on lambda and the atomic velocities
     atomThermostatForces_ = new AtomicThermostatForce(atc_,atomLambdas_);
     interscaleManager.add_per_atom_quantity(atomThermostatForces_,
                                             regulatorPrefix_+"AtomThermostatForce");
 
     // predicted temperature quantities:  atom velocities, atom energies, and restricted atom energies
-    AtcAtomQuantity<double> * atomPredictedVelocities = new AtcAtomQuantity<double>(atc_,nsd_);
-    interscaleManager.add_per_atom_quantity(atomPredictedVelocities,
+    atomPredictedVelocities_ = new AtcAtomQuantity<double>(atc_,atc_->nsd());
+    // MAKE THINGS WORK WITH ONLY ONE PREDICTED VELOCITY, CHECK IT EXISTS
+    interscaleManager.add_per_atom_quantity(atomPredictedVelocities_,
                                             regulatorPrefix_+"AtomicPredictedVelocities");
-    atomPredictedVelocities_ = atomPredictedVelocities;
     AtomicEnergyForTemperature * atomPredictedEnergyForTemperature = new TwiceKineticEnergy(atc_,
-                                                                                            atomPredictedVelocities);
+                                                                                            atomPredictedVelocities_);
     interscaleManager.add_per_atom_quantity(atomPredictedEnergyForTemperature,
                                             regulatorPrefix_+"AtomicPredictedTwiceKineticEnergy");
     nodalAtomicPredictedEnergy_ = new AtfShapeFunctionRestriction(atc_,
                                                                   atomPredictedEnergyForTemperature,
                                                                   interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_dense_matrix(nodalAtomicPredictedEnergy_,
-                                            regulatorPrefix_+"NodalAtomicPredictedEnergy");
+                                       regulatorPrefix_+"NodalAtomicPredictedEnergy");
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void ThermostatGlcFs::initialize()
   {
-    ThermostatShapeFunction::initialize();
-
-    // reset data to zero
-    deltaEnergy1_.reset(nNodes_,1);
-    deltaEnergy2_.reset(nNodes_,1);
-    _lambdaPowerOutput_.reset(nNodes_,1);
+    RegulatorMethod::initialize();
     
     TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
     if (!timeFilterManager->end_equilibrate()) {
       // we should reset lambda and lambdaForce to zero in this case
       // implies an initial condition of 0 for the filtered nodal lambda power
       // initial conditions will always be needed when using time filtering
       // however, the fractional step scheme must assume the instantaneous
       // nodal lambda power is 0 initially because all quantities are in delta form
-      *lambda_ = 0.; // ensures initial lambda force is zero
+      lambdaSolver_->initialize(); // ensures initial lambda force is zero
+      lambdaSolver_->set_lambda_to_value(0.);
       *nodalAtomicLambdaPower_ = 0.; // energy change due to thermostats
       *lambdaPowerFiltered_ = 0.; // filtered energy change due to thermostats
     }
     else {
+      lambdaSolver_->initialize();
       // we can grab lambda power variables using time integrator and atc transfer in cases for equilibration
     }
 
     // sets up time filter for cases where variables temporally filtered
     if (timeFilterManager->need_reset()) {
       // the form of this integrator implies no time filters that require history data can be used
       timeFilter_->initialize(nodalAtomicLambdaPower_->quantity());
     }
 
     atomThermostatForces_->quantity(); // initialize
     atomThermostatForces_->fix_quantity();
     firstHalfAtomForces_ = atomThermostatForces_; // initialize
-
+#ifdef OBSOLETE
     compute_rhs_map();
+#endif
   }
 
   //--------------------------------------------------------
-  //  compute_rhs_map
-  //    creates mapping from all nodes to those to which
-  //    the thermostat applies
+  //  reset_atom_materials:
+  //    resets the localized atom to material map
   //--------------------------------------------------------
-  void ThermostatGlcFs::compute_rhs_map()
+  void ThermostatGlcFs::reset_atom_materials(const Array<int> & elementToMaterialMap,
+                                             const MatrixDependencyManager<DenseMatrix, int> * atomElement)
   {
-    rhsMap_.resize(overlapToNodeMap_->nRows(),1);
-    DENS_MAT rhsMapGlobal(nNodes_,1);
-    const set<int> & applicationNodes(applicationNodes_->quantity());
-    for (int i = 0; i < nNodes_; i++) {
-      if (applicationNodes.find(i) != applicationNodes.end()) {
-        rhsMapGlobal(i,0) = 1.;
-      }
-      else {
-        rhsMapGlobal(i,0) = 0.;
-      }
-    }
-    map_unique_to_overlap(rhsMapGlobal,rhsMap_);
+    lambdaSolver_->reset_atom_materials(elementToMaterialMap,
+                                        atomElement);
   }
 
   //--------------------------------------------------------
   //  apply_to_atoms:
   //     determines what if any contributions to the
   //     atomic moition is needed for
   //     consistency with the thermostat
   //     and computes the instantaneous induced power
   //--------------------------------------------------------
   void ThermostatGlcFs::apply_to_atoms(PerAtomQuantity<double> * atomicVelocity,
                                       const DENS_MAN * nodalAtomicEnergy,
                                       const DENS_MAT & lambdaForce,
                                       DENS_MAT & nodalAtomicLambdaPower,
                                       double dt)
   {
     // compute initial contributions to lambda power
     nodalAtomicLambdaPower = nodalAtomicEnergy->quantity();
     nodalAtomicLambdaPower *= -1.;
 
     // apply lambda force to atoms
     _velocityDelta_ = lambdaForce;
     _velocityDelta_ /= atomMasses_->quantity();
     _velocityDelta_ *= dt;
     (*atomicVelocity) += _velocityDelta_;
 
     // finalize lambda power
     nodalAtomicLambdaPower += nodalAtomicEnergy->quantity();
   }
 
   //--------------------------------------------------------
   //  full_prediction:
   //    flag to perform a full prediction calcalation
   //    for lambda rather than using the old value
   //--------------------------------------------------------
   bool ThermostatGlcFs::full_prediction()
   {
     if (isFirstTimestep_ || ((atc_->atom_to_element_map_type() == EULERIAN)
                              && (atc_->atom_to_element_map_frequency() > 1)
                              && (atc_->step() % atc_->atom_to_element_map_frequency() == 0 ))) {
       return true;
     }
     return false;
   }
 
   //--------------------------------------------------------
   //  apply_predictor:
   //    apply the thermostat to the atoms in the first step
   //    of the Verlet algorithm
   //--------------------------------------------------------
   void ThermostatGlcFs::apply_pre_predictor(double dt)
   {
     DENS_MAT & myLambdaPowerFiltered(lambdaPowerFiltered_->set_quantity());
     DENS_MAT & myNodalAtomicLambdaPower(nodalAtomicLambdaPower_->set_quantity());
 
     // update filtered power
     timeFilter_->apply_pre_step1(myLambdaPowerFiltered,myNodalAtomicLambdaPower,dt); // equivalent update to measure power as change in energy due to thermostat
 
     // apply lambda force to atoms and compute instantaneous lambda power for first half of time step
     this->apply_to_atoms(atomVelocities_,nodalAtomicEnergy_,
                          firstHalfAtomForces_->quantity(),
                          myNodalAtomicLambdaPower,0.5*dt);
 
     // update nodal variables for first half of time step
     this->add_to_energy(myNodalAtomicLambdaPower,deltaEnergy1_,0.5*dt);
 
     // start update of filtered lambda power
     myNodalAtomicLambdaPower = 0.; // temporary power for first part of update
     timeFilter_->apply_post_step1(myLambdaPowerFiltered,myNodalAtomicLambdaPower,dt);
   }
 
   //--------------------------------------------------------
   //  apply_pre_corrector:
   //    apply the thermostat to the atoms in the first part
   //    of the corrector step of the Verlet algorithm
   //--------------------------------------------------------
   void ThermostatGlcFs::apply_pre_corrector(double dt)
   {
     (*atomPredictedVelocities_) = atomVelocities_->quantity();
 
     // do full prediction if we just redid the shape functions
     if (full_prediction()) {
       this->compute_lambda(dt);
       
       atomThermostatForces_->unfix_quantity();  // allow update of atomic force applied by lambda
     }
 
     // apply lambda force to atoms and compute instantaneous lambda power to predict second half of time step
     DENS_MAT & myNodalAtomicLambdaPower(nodalAtomicLambdaPower_->set_quantity());
     apply_to_atoms(atomPredictedVelocities_,
                    nodalAtomicPredictedEnergy_,
                    firstHalfAtomForces_->quantity(),
                    myNodalAtomicLambdaPower,0.5*dt);
 
     if (full_prediction())
       atomThermostatForces_->fix_quantity();
     
     // update predicted nodal variables for second half of time step
     this->add_to_energy(myNodalAtomicLambdaPower,deltaEnergy2_,0.5*dt);
-    deltaEnergy1_ += deltaEnergy2_; 
+    // following manipulations performed this way for efficiency
+    deltaEnergy1_ += deltaEnergy2_;
     atc_->apply_inverse_mass_matrix(deltaEnergy1_,TEMPERATURE);
     temperature_ += deltaEnergy1_;
   }
 
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the thermostat to the atoms in the second part
   //    of the corrector step of the Verlet algorithm
   //--------------------------------------------------------
   void ThermostatGlcFs::apply_post_corrector(double dt)
   {
     // remove predicted power effects
     DENS_MAT & myTemperature(temperature_.set_quantity());
     atc_->apply_inverse_mass_matrix(deltaEnergy2_,TEMPERATURE);
     myTemperature -= deltaEnergy2_;
 
     // set up equation and update lambda
     this->compute_lambda(dt);
 
     // apply lambda force to atoms and compute instantaneous lambda power for second half of time step
     DENS_MAT & myNodalAtomicLambdaPower(nodalAtomicLambdaPower_->set_quantity());
-    atomThermostatForces_->unfix_quantity(); // allow computation of force applied by lambda
+    // allow computation of force applied by lambda using current velocities
+    atomThermostatForces_->unfix_quantity(); 
+    atomThermostatForces_->quantity();
+    atomThermostatForces_->fix_quantity();
     apply_to_atoms(atomVelocities_,nodalAtomicEnergy_,
                    atomThermostatForces_->quantity(),
                    myNodalAtomicLambdaPower,0.5*dt);
-    atomThermostatForces_->fix_quantity();
 
     // finalize filtered lambda power by adding latest contribution
     timeFilter_->apply_post_step2(lambdaPowerFiltered_->set_quantity(),
                                   myNodalAtomicLambdaPower,dt);
 
     // update nodal variables for second half of time step
     this->add_to_energy(myNodalAtomicLambdaPower,deltaEnergy2_,0.5*dt);
     atc_->apply_inverse_mass_matrix(deltaEnergy2_,TEMPERATURE);
     myTemperature += deltaEnergy2_;
     
     
     isFirstTimestep_ = false;
   }
 
   //--------------------------------------------------------
   //  compute_lambda:
   //   sets up and solves linear system for lambda, if the
   //   bool is true it iterators to a non-linear solution
   //--------------------------------------------------------
   void ThermostatGlcFs::compute_lambda(double dt,
                                        bool iterateSolution)
   {
     // set up rhs for lambda equation
-    rhs_.resize(nNodes_,1);
     this->set_thermostat_rhs(rhs_,0.5*dt);
-    
+
+    // solve system
+    lambdaSolver_->compute_lambda(rhs_,iterateSolution);
+#ifdef OBSOLETE
     // solve linear system for lambda guess
-    DENS_MAT & myLambda(lambda_->set_quantity());
-    solve_for_lambda(rhs_,myLambda);
+    DENS_MAT & lambda(lambda_->set_quantity());
+    solve_for_lambda(rhs_,lambda);
     
     // iterate to solution
     if (iterateSolution) {
       iterate_lambda(rhs_);
     }
+#endif
   }
 
   //--------------------------------------------------------
-  //  iterate_lambda:
-  //    iteratively solves the equations for lambda
-  //    for the higher order dt corrections, assuming
-  //    an initial guess for lambda
+  //  compute_boundary_flux
+  //    default computation of boundary flux based on
+  //    finite
   //--------------------------------------------------------
-  void ThermostatGlcFs::iterate_lambda(const MATRIX & rhs)
+  void ThermostatGlcFs::compute_boundary_flux(FIELDS & fields)
   {
-    int nNodeOverlap = overlapToNodeMap_->nRows();
-    DENS_VEC _lambdaOverlap_(nNodeOverlap);
-    DENS_MAT & lambda(lambda_->set_quantity());
-    map_unique_to_overlap(lambda,_lambdaOverlap_);
-    double factor = 0.5*dtFactor_*atc_->dt();
-
-    _lambdaOld_.resize(nNodes_,1);
-    _rhsOverlap_.resize(nNodeOverlap,1);
-    map_unique_to_overlap(rhs,_rhsOverlap_);
-    _rhsTotal_.resize(nNodeOverlap);
-
-    // solve assuming we get initial guess for lambda
-    double error(-1.);
-    for (int i = 0; i < lambdaMaxIterations_; ++i) {
-      _lambdaOld_ = lambda;
-
-      // solve the system with the new rhs
-      const DENS_MAT & rhsLambdaSquared(rhsLambdaSquared_->quantity());
-      for (int i = 0; i < nNodeOverlap; i++) {
-        if (rhsMap_(i,0) == 1.) {
-          _rhsTotal_(i) = _rhsOverlap_(i,0) + factor*rhsLambdaSquared(i,0);
-        }
-        else {
-          _rhsTotal_(i) = 0.;
-        }
-      }
-      matrixSolver_->execute(_rhsTotal_,_lambdaOverlap_);
-
-      // check convergence
-      map_overlap_to_unique(_lambdaOverlap_,lambda);
-      lambda_->force_reset();
-      DENS_MAT difference = lambda-_lambdaOld_;
-      error = difference.col_norm()/_lambdaOld_.col_norm();
-      if (error < tolerance_)
-        break;
-    }
     
-    if (error >= tolerance_) {
-      stringstream message;
-      message << " Iterative solve for lambda failed to converge after " << lambdaMaxIterations_ << " iterations, final tolerance was " << error << "\n";
-      ATC::LammpsInterface::instance()->print_msg(message.str());
-    }
+    lambdaSolver_->compute_boundary_flux(fields);
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void ThermostatGlcFs::output(OUTPUT_LIST & outputData)
   {
     _lambdaPowerOutput_ = nodalAtomicLambdaPower_->quantity();
     // approximate value for lambda power
     double dt =  LammpsInterface::instance()->dt();
     _lambdaPowerOutput_ *= (2./dt);
-    DENS_MAT & lambda(lambda_->set_quantity());
+    DENS_MAT & lambda((atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaEnergy",1))->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
-      outputData[regulatorPrefix_+"Lambda"] = &lambda;
+      outputData[regulatorPrefix_+"LambdaEnergy"] = &lambda;
       outputData[regulatorPrefix_+"NodalLambdaPower"] = &(_lambdaPowerOutput_);
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
-  //  Class ThermostatFlux
+  //  Class ThermostatSolverFlux
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and thermostat data
   //--------------------------------------------------------
-  ThermostatFlux::ThermostatFlux(Thermostat * thermostat,
-                                 const string & regulatorPrefix) :
-    ThermostatGlcFs(thermostat,regulatorPrefix),
-    heatSource_(atc_->atomic_source(TEMPERATURE))
+  ThermostatSolverFlux::ThermostatSolverFlux(AtomicRegulator * thermostat,
+                                             int lambdaMaxIterations,
+                                             const string & regulatorPrefix) :
+    ThermostatFsSolver(thermostat,lambdaMaxIterations,regulatorPrefix)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
-  void ThermostatFlux::construct_transfers()
+  void ThermostatSolverFlux::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
     // set up data for linear solver
     shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
     interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
                                                  regulatorPrefix_+"LambdaCouplingMatrixEnergy");
     if (elementMask_) {
       lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
       interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
                                                   regulatorPrefix_+"LambdaAtomMap");
     }
     if (atomicRegulator_->use_localized_lambda()) {
       linearSolverType_ = AtomicRegulator::RSL_SOLVE;
     }
     else {
       linearSolverType_ = AtomicRegulator::CG_SOLVE;
     }
 
     // base class transfers
-    ThermostatGlcFs::construct_transfers();
+    ThermostatFsSolver::construct_transfers();
 
     // add transfers for computation of extra RHS term accounting of O(lambda^2)
     // lambda squared followed by fractional step RHS contribution
-    PerAtomQuantity<double> * lambdaAtom(interscaleManager.per_atom_quantity(regulatorPrefix_+"AtomLambdaEnergy"));
+    atomLambdas_ = (interscaleManager.per_atom_quantity(regulatorPrefix_+"AtomLambdaEnergy"));
+    if (!atomLambdas_) {
+      atomLambdas_ = new FtaShapeFunctionProlongation(atc_,
+                                                      lambda_,
+                                                      interscaleManager.per_atom_sparse_matrix("Interpolant"));
+      interscaleManager.add_per_atom_quantity(atomLambdas_,regulatorPrefix_+"AtomLambdaEnergy");
+    }
     LambdaSquared * lambdaSquared = new LambdaSquared(atc_,
-                                                      atomMasses_,
+                                                      interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS),
                                                       weights_,
-                                                      lambdaAtom);
+                                                      atomLambdas_);
     interscaleManager.add_per_atom_quantity(lambdaSquared,
                                             regulatorPrefix_+"LambdaSquaredMapped");
     rhsLambdaSquared_ = new AtfShapeFunctionRestriction(atc_,lambdaSquared,shapeFunctionMatrix_);
     interscaleManager.add_dense_matrix(rhsLambdaSquared_,
                                             regulatorPrefix_+"RhsLambdaSquared");
   }
 
-  //--------------------------------------------------------
-  //  initialize
-  //    initializes all method data
-  //--------------------------------------------------------
-  void ThermostatFlux::initialize()
-  {
-    ThermostatGlcFs::initialize();
-
-    // timestep factor
-    dtFactor_ = 1.;
-  }
-
   //--------------------------------------------------------
   //  construct_regulated_nodes:
   //    constructs the set of nodes being regulated
   //--------------------------------------------------------
-  void ThermostatFlux::construct_regulated_nodes()
+  void ThermostatSolverFlux::construct_regulated_nodes()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // matrix requires all entries even if localized for correct lumping
-    regulatedNodes_ = new RegulatedNodes(atc_);
-    interscaleManager.add_set_int(regulatedNodes_,
-                                  regulatorPrefix_+"ThermostatRegulatedNodes");
-
+    regulatedNodes_ = interscaleManager.set_int(regulatorPrefix_+"ThermostatRegulatedNodes");
+    if (!regulatedNodes_) {
+      regulatedNodes_ = new RegulatedNodes(atc_);
+      interscaleManager.add_set_int(regulatedNodes_,
+                                    regulatorPrefix_+"ThermostatRegulatedNodes");
+    }
+    
     // if localized monitor nodes with applied fluxes
     if (atomicRegulator_->use_localized_lambda()) {
       if ((atomicRegulator_->coupling_mode() == Thermostat::FLUX) && (atomicRegulator_->boundary_integration_type() != NO_QUADRATURE)) {
         // include boundary nodes
         applicationNodes_ = new FluxBoundaryNodes(atc_);
         
         boundaryNodes_ = new BoundaryNodes(atc_);
         interscaleManager.add_set_int(boundaryNodes_,
                                       regulatorPrefix_+"ThermostatBoundaryNodes");
       }
       else {
         // fluxed nodes only
         applicationNodes_ = new FluxNodes(atc_);
       }
       interscaleManager.add_set_int(applicationNodes_,
                                     regulatorPrefix_+"ThermostatApplicationNodes");
     }
     else {
       applicationNodes_ = regulatedNodes_;
     }
 
     // special set of boundary elements for boundary flux quadrature  
     if ((atomicRegulator_->boundary_integration_type() == FE_INTERPOLATION)
         && (atomicRegulator_->use_localized_lambda())) {
-      elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
-      interscaleManager.add_dense_matrix_bool(elementMask_,
-                                                   regulatorPrefix_+"BoundaryElementMask");
+      elementMask_ = interscaleManager.dense_matrix_bool(regulatorPrefix_+"BoundaryElementMask");
+      if (!elementMask_) {
+        elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
+        interscaleManager.add_dense_matrix_bool(elementMask_,
+                                                regulatorPrefix_+"BoundaryElementMask");
+      }
     }
   }
 
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class ThermostatIntegratorFlux
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+
+  //--------------------------------------------------------
+  //  Constructor
+  //         Grab references to ATC and thermostat data
+  //--------------------------------------------------------
+  ThermostatIntegratorFlux::ThermostatIntegratorFlux(AtomicRegulator * thermostat,
+                                                     int lambdaMaxIterations,
+                                                     const string & regulatorPrefix) :
+    ThermostatGlcFs(thermostat,lambdaMaxIterations,regulatorPrefix),
+    heatSource_(atc_->atomic_source(TEMPERATURE))
+  {
+    lambdaSolver_ = new ThermostatSolverFlux(thermostat,
+                                             lambdaMaxIterations,
+                                             regulatorPrefix);
+  }
+
   //--------------------------------------------------------
   //  add_to_temperature
   //    add in contributions from lambda power and boundary
   //    flux to the FE temperature
   //--------------------------------------------------------
-  void ThermostatFlux::add_to_energy(const DENS_MAT & nodalLambdaPower,
-                                     DENS_MAT & deltaEnergy,
-                                     double dt)
+  void ThermostatIntegratorFlux::add_to_energy(const DENS_MAT & nodalLambdaPower,
+                                               DENS_MAT & deltaEnergy,
+                                               double dt)
   {
     deltaEnergy.resize(nNodes_,1);
     const DENS_MAT & myBoundaryFlux(boundaryFlux_[TEMPERATURE].quantity());
     for (int i = 0; i < nNodes_; i++) {
       deltaEnergy(i,0) = nodalLambdaPower(i,0) + dt*myBoundaryFlux(i,0);
     }
   }
 
+  //--------------------------------------------------------
+  //  initialize
+  //    initializes all method data
+  //--------------------------------------------------------
+  void ThermostatIntegratorFlux::initialize()
+  {
+    ThermostatGlcFs::initialize();
+
+    // timestep factor
+    lambdaSolver_->set_timestep_factor(1.);
+  }
+
   //--------------------------------------------------------
   //  set_thermostat_rhs:
   //    sets up the right-hand side including boundary
   //    fluxes (coupling & prescribed), heat sources, and
   //    fixed (uncoupled) nodes
   //--------------------------------------------------------
-  void ThermostatFlux::set_thermostat_rhs(DENS_MAT & rhs,
-                                          double dt)
+  void ThermostatIntegratorFlux::set_thermostat_rhs(DENS_MAT & rhs,
+                                                    double dt)
   {
     
     // only tested with flux != 0 + ess bc = 0
 
     // (a) for flux based : 
     // form rhs :  2/3kB * W_I^-1 * \int N_I r dV
     // vs  Wagner, CMAME, 2008 eq(24) RHS_I = 2/(3kB) flux_I
     // fluxes are set in ATC transfer
     const DENS_MAT & heatSource(heatSource_.quantity());
-    const set<int> & applicationNodes(applicationNodes_->quantity());
+#if true
+    const set<int> & applicationNodes((lambdaSolver_->application_nodes())->quantity());
+    rhs.resize(nNodes_,1);
     for (int i = 0; i < nNodes_; i++) {
       if (applicationNodes.find(i) != applicationNodes.end()) {
         rhs(i,0) = heatSource(i,0);
       }
       else {
         rhs(i,0) = 0.;
       }
     }
+#else
+    rhs.resize(nNodes_,1);
+    for (int i = 0; i < nNodes_; i++) {
+      rhs(i,0) = heatSource(i,0);
+    }
+#endif
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
-  //  Class ThermostatFixed
+  //  Class ThermostatSolverFixed
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and thermostat data
   //--------------------------------------------------------
-  ThermostatFixed::ThermostatFixed(Thermostat * thermostat,
-                                   const string & regulatorPrefix) :
-    ThermostatGlcFs(thermostat,regulatorPrefix),
-    atomThermostatForcesPredVel_(NULL),
-    filterCoefficient_(1.)
+  ThermostatSolverFixed::ThermostatSolverFixed(AtomicRegulator * thermostat,
+                                               int lambdaMaxIterations,
+                                               const string & regulatorPrefix) :
+    ThermostatFsSolver(thermostat,lambdaMaxIterations,regulatorPrefix)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
-  void ThermostatFixed::construct_transfers()
+  void ThermostatSolverFixed::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
     // determine if map is needed and set up if so
     if (this->use_local_shape_functions()) {
       lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
       interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
                                                   regulatorPrefix_+"LambdaAtomMap");
       shapeFunctionMatrix_ = new LocalLambdaCouplingMatrix(atc_,
                                                            lambdaAtomMap_,
                                                            nodeToOverlapMap_);
     }
     else {
       shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
     }
     interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
                                                  regulatorPrefix_+"LambdaCouplingMatrixEnergy");
     linearSolverType_ = AtomicRegulator::CG_SOLVE;
 
     // base class transfers, e.g. weights
-    ThermostatGlcFs::construct_transfers();
+    ThermostatFsSolver::construct_transfers();
 
     // add transfers for computation of extra RHS term accounting of O(lambda^2)
     // lambda squared followed by fractional step RHS contribution
-    PerAtomQuantity<double> * lambdaAtom(interscaleManager.per_atom_quantity(regulatorPrefix_+"AtomLambdaEnergy"));
+    atomLambdas_ = interscaleManager.per_atom_quantity(regulatorPrefix_+"AtomLambdaEnergy");
+    if (!atomLambdas_) {
+      atomLambdas_ = new FtaShapeFunctionProlongation(atc_,
+                                                      lambda_,
+                                                      interscaleManager.per_atom_sparse_matrix("Interpolant"));
+      interscaleManager.add_per_atom_quantity(atomLambdas_,regulatorPrefix_+"AtomLambdaEnergy");
+    }
     if (lambdaAtomMap_) {
       LambdaSquaredMapped * lambdaSquared = new LambdaSquaredMapped(atc_,
                                                                     lambdaAtomMap_,
-                                                                    atomMasses_,
+                                                                    interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS),
                                                                     weights_,
-                                                                    lambdaAtom);
+                                                                    atomLambdas_);
       interscaleManager.add_per_atom_quantity(lambdaSquared,
                                               regulatorPrefix_+"LambdaSquared");
       rhsLambdaSquared_ = new AtfShapeFunctionRestriction(atc_,lambdaSquared,shapeFunctionMatrix_);
     }
     else {
       LambdaSquared * lambdaSquared = new LambdaSquared(atc_,
-                                                        atomMasses_,
+                                                       interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS),
                                                         weights_,
-                                                        lambdaAtom);
+                                                        atomLambdas_);
       interscaleManager.add_per_atom_quantity(lambdaSquared,
                                               regulatorPrefix_+"LambdaSquaredMapped");
       rhsLambdaSquared_ = new AtfShapeFunctionRestriction(atc_,lambdaSquared,shapeFunctionMatrix_);
     }
     interscaleManager.add_dense_matrix(rhsLambdaSquared_,
-                                            regulatorPrefix_+"RhsLambdaSquared");
+                                       regulatorPrefix_+"RhsLambdaSquared");
+  }
+
+  //--------------------------------------------------------
+  //  construct_regulated_nodes:
+  //    constructs the set of nodes being regulated
+  //--------------------------------------------------------
+  void ThermostatSolverFixed::construct_regulated_nodes()
+  {
+    InterscaleManager & interscaleManager(atc_->interscale_manager());
+    regulatedNodes_ = interscaleManager.set_int(regulatorPrefix_+"ThermostatRegulatedNodes");
+
+    if (!regulatedNodes_) {
+      if (!atomicRegulator_->use_localized_lambda()) {
+        regulatedNodes_ = new RegulatedNodes(atc_);
+      }
+      else if (atomicRegulator_->coupling_mode() == AtomicRegulator::FLUX) {
+        regulatedNodes_ = new FixedNodes(atc_);
+      }
+      else if (atomicRegulator_->coupling_mode() == AtomicRegulator::FIXED) {
+          // include boundary nodes
+          regulatedNodes_ = new FixedBoundaryNodes(atc_);
+      }
+      else {
+        throw ATC_Error("ThermostatSolverFixed::construct_regulated_nodes - couldn't determine set of regulated nodes");
+      }
+     
+      interscaleManager.add_set_int(regulatedNodes_,
+                                    regulatorPrefix_+"ThermostatRegulatedNodes");
+    }
+
+    applicationNodes_ = regulatedNodes_;
+
+    // special set of boundary elements for defining regulated atoms 
+    if (atomicRegulator_->use_localized_lambda()) {
+      elementMask_ = interscaleManager.dense_matrix_bool(regulatorPrefix_+"BoundaryElementMask");
+      if (!elementMask_) {
+        elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
+        interscaleManager.add_dense_matrix_bool(elementMask_,
+                                                regulatorPrefix_+"BoundaryElementMask");
+      }
+    }
+  }
+
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+  //  Class ThermostatIntegratorFixed
+  //--------------------------------------------------------
+  //--------------------------------------------------------
+ 
+  //--------------------------------------------------------
+  //  Constructor
+  //         Grab references to ATC and thermostat data
+  //--------------------------------------------------------
+  ThermostatIntegratorFixed::ThermostatIntegratorFixed(AtomicRegulator * thermostat,
+                                                       int lambdaMaxIterations,
+                                                       const string & regulatorPrefix) :
+    ThermostatGlcFs(thermostat,lambdaMaxIterations,regulatorPrefix),
+    atomThermostatForcesPredVel_(NULL),
+    filterCoefficient_(1.)
+  {
+    lambdaSolver_ = new ThermostatSolverFixed(thermostat,
+                                              lambdaMaxIterations,
+                                              regulatorPrefix);
+  }
+
+  //--------------------------------------------------------
+  //  construct_regulated_nodes:
+  //    constructs the set of nodes being regulated
+  //--------------------------------------------------------
+  void ThermostatIntegratorFixed::construct_transfers()
+  {
+    ThermostatGlcFs::construct_transfers();
+
+    InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // predicted forces for halving update
     atomThermostatForcesPredVel_ = new AtomicThermostatForce(atc_,atomLambdas_,atomPredictedVelocities_);
     interscaleManager.add_per_atom_quantity(atomThermostatForcesPredVel_,
                                             regulatorPrefix_+"AtomThermostatForcePredictedVelocity");
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
-  void ThermostatFixed::initialize()
+  void ThermostatIntegratorFixed::initialize()
   {
     ThermostatGlcFs::initialize();
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set KE multiplier
     AtomicEnergyForTemperature * atomEnergyForTemperature =
       static_cast<AtomicEnergyForTemperature * >(interscaleManager.per_atom_quantity("AtomicEnergyForTemperature"));
     keMultiplier_ = atomEnergyForTemperature->kinetic_energy_multiplier();
 
     // reset data to zero
     deltaFeEnergy_.reset(nNodes_,1);
     deltaNodalAtomicEnergy_.reset(nNodes_,1);
 
     // initialize filtered energy
     TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
     if (!timeFilterManager->end_equilibrate()) {
       nodalAtomicEnergyFiltered_ = nodalAtomicEnergy_->quantity();
     }
 
     // timestep factor
-    dtFactor_ = 0.5;
+    lambdaSolver_->set_timestep_factor(0.5);
   }
 
   //--------------------------------------------------------
   //  halve_force:
   //    flag to halve the lambda force for improved
   //    accuracy
   //--------------------------------------------------------
-  bool ThermostatFixed::halve_force()
+  bool ThermostatIntegratorFixed::halve_force()
   {
     if (isFirstTimestep_ || ((atc_->atom_to_element_map_type() == EULERIAN)
                              && (atc_->atom_to_element_map_frequency() > 1)
                              && (atc_->step() % atc_->atom_to_element_map_frequency() == 1))) {
       return true;
     }
     return false;
   }
 
-  //--------------------------------------------------------
-  //  construct_regulated_nodes:
-  //    constructs the set of nodes being regulated
-  //--------------------------------------------------------
-  void ThermostatFixed::construct_regulated_nodes()
-  {
-    InterscaleManager & interscaleManager(atc_->interscale_manager());
-
-    if (!atomicRegulator_->use_localized_lambda()) {
-      regulatedNodes_ = new RegulatedNodes(atc_);
-    }
-    else if (thermostat_->coupling_mode() == AtomicRegulator::FLUX) {
-      regulatedNodes_ = new FixedNodes(atc_);
-    }
-    else if (thermostat_->coupling_mode() == AtomicRegulator::FIXED) {
-      // include boundary nodes
-      regulatedNodes_ = new FixedBoundaryNodes(atc_);
-    }
-    else {
-      throw ATC_Error("ThermostatFixed::construct_regulated_nodes - couldn't determine set of regulated nodes");
-    }
-     
-    interscaleManager.add_set_int(regulatedNodes_,
-                                  regulatorPrefix_+"RegulatedNodes");
-
-    applicationNodes_ = regulatedNodes_;
-
-    // special set of boundary elements for defining regulated atoms 
-    if (atomicRegulator_->use_localized_lambda()) {
-      elementMask_ = new ElementMaskNodeSet(atc_,applicationNodes_);
-      interscaleManager.add_dense_matrix_bool(elementMask_,
-                                                   regulatorPrefix_+"BoundaryElementMask");
-    }
-  }
-
   //--------------------------------------------------------
   //  initialize_delta_nodal_atomic_energy:
   //    initializes storage for the variable tracking
   //    the change in the nodal atomic energy
   //    that has occured over the past timestep
   //--------------------------------------------------------
-  void ThermostatFixed::initialize_delta_nodal_atomic_energy(double dt)
+  void ThermostatIntegratorFixed::initialize_delta_nodal_atomic_energy(double dt)
   {
     // initialize delta energy
     const DENS_MAT & myNodalAtomicEnergy(nodalAtomicEnergy_->quantity());
     initialNodalAtomicEnergy_ = myNodalAtomicEnergy;
     initialNodalAtomicEnergy_ *= -1.; // initially stored as negative for efficiency
     timeFilter_->apply_pre_step1(nodalAtomicEnergyFiltered_.set_quantity(),
                                  myNodalAtomicEnergy,dt);
   }
 
   //--------------------------------------------------------
   //  compute_delta_nodal_atomic_energy:
   //    computes the change in the nodal atomic energy
   //    that has occured over the past timestep
   //--------------------------------------------------------
-  void ThermostatFixed::compute_delta_nodal_atomic_energy(double dt)
+  void ThermostatIntegratorFixed::compute_delta_nodal_atomic_energy(double dt)
   {
     // set delta energy based on predicted atomic velocities
     const DENS_MAT & myNodalAtomicEnergy(nodalAtomicEnergy_->quantity());
     timeFilter_->apply_post_step1(nodalAtomicEnergyFiltered_.set_quantity(),
                                   myNodalAtomicEnergy,dt);
     deltaNodalAtomicEnergy_ = initialNodalAtomicEnergy_;
     deltaNodalAtomicEnergy_ += myNodalAtomicEnergy;
   }
 
   //--------------------------------------------------------
   //  compute_lambda:
-  //   sets up and solves linear system for lambda, if the
-  //   bool is true it iterators to a non-linear solution
+  //   sets up and solves linear system for lambda
   //--------------------------------------------------------
-  void ThermostatFixed::compute_lambda(double dt,
-                                       bool iterateSolution)
+  void ThermostatIntegratorFixed::compute_lambda(double dt,
+                                                 bool iterateSolution)
   {
     // compute predicted changes in nodal atomic energy
     compute_delta_nodal_atomic_energy(dt);
 
     // change in finite element energy
     deltaFeEnergy_ = initialFeEnergy_;
     deltaFeEnergy_ += (mdMassMatrix_.quantity())*(temperature_.quantity());
 
     ThermostatGlcFs::compute_lambda(dt,iterateSolution);
   }
 
   //--------------------------------------------------------
   //  apply_predictor:
   //    apply the thermostat to the atoms in the first step
   //    of the Verlet algorithm
   //--------------------------------------------------------
-  void ThermostatFixed::apply_pre_predictor(double dt)
+  void ThermostatIntegratorFixed::apply_pre_predictor(double dt)
   {
     // initialize values to be track change in finite element energy over the timestep
     initialize_delta_nodal_atomic_energy(dt);
     initialFeEnergy_ = -1.*((mdMassMatrix_.quantity())*(temperature_.quantity())); // initially stored as negative for efficiency
 
     ThermostatGlcFs::apply_pre_predictor(dt);
   }
 
   //--------------------------------------------------------
   //  apply_pre_corrector:
   //    apply the thermostat to the atoms in the first part
   //    of the corrector step of the Verlet algorithm
   //--------------------------------------------------------
-  void ThermostatFixed::apply_pre_corrector(double dt)
+  void ThermostatIntegratorFixed::apply_pre_corrector(double dt)
   {
     // do full prediction if we just redid the shape functions
     if (full_prediction()) {
       firstHalfAtomForces_ = atomThermostatForces_; // reset in case this time step needed special treatment
       _tempNodalAtomicEnergyFiltered_ = nodalAtomicEnergyFiltered_.quantity();
     }
 
     ThermostatGlcFs::apply_pre_corrector(dt);
 
     if (full_prediction()) {
       // reset temporary variables
       nodalAtomicEnergyFiltered_ = _tempNodalAtomicEnergyFiltered_;
     }
 
     if (halve_force()) {
       // save old velocities if we are doing halving calculation of lambda force
       // copy velocities over into temporary storage
       (*atomPredictedVelocities_) = atomVelocities_->quantity();
     }
   }
 
-  //--------------------------------------------------------
-  //  add_to_temperature
-  //    add in contributions from lambda power and boundary
-  //    flux to the FE temperature
-  //--------------------------------------------------------
-  void ThermostatFixed::add_to_energy(const DENS_MAT & nodalLambdaPower,
-                                      DENS_MAT & deltaEnergy,
-                                      double dt)
-  {
-    deltaEnergy.resize(nNodes_,1);
-    const set<int> & regulatedNodes(regulatedNodes_->quantity());
-    for (int i = 0; i < nNodes_; i++) {
-      if (regulatedNodes.find(i) != regulatedNodes.end()) {
-        deltaEnergy(i,0) = 0.;
-      }
-      else {
-        deltaEnergy(i,0) = nodalLambdaPower(i,0);
-      }
-    }
-  }
-
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the thermostat to the atoms in the second part
   //    of the corrector step of the Verlet algorithm
   //--------------------------------------------------------
-  void ThermostatFixed::apply_post_corrector(double dt)
+  void ThermostatIntegratorFixed::apply_post_corrector(double dt)
   {
     
     bool halveForce = halve_force();
 
     ThermostatGlcFs::apply_post_corrector(dt);
     
     // update filtered energy with lambda power
     DENS_MAT & myNodalAtomicLambdaPower(nodalAtomicLambdaPower_->set_quantity());
     timeFilter_->apply_post_step2(nodalAtomicEnergyFiltered_.set_quantity(),
                                   myNodalAtomicLambdaPower,dt);
 
     if (halveForce) {
       // Halve lambda force due to fixed temperature constraints
       // 1) makes up for poor initial condition
       // 2) accounts for possibly large value of lambda when atomic shape function values change
       //    from eulerian mapping after more than 1 timestep
       //    avoids unstable oscillations arising from 
       //    thermostat having to correct for error introduced in lambda changing the 
       //    shape function matrices
-      *lambda_ *= 0.5;
+      lambdaSolver_->scale_lambda(0.5);
       firstHalfAtomForces_ = atomThermostatForcesPredVel_;
       atomThermostatForcesPredVel_->unfix_quantity();
     }
     else {
       firstHalfAtomForces_ = atomThermostatForces_;
     }
   }
 
+  //--------------------------------------------------------
+  //  add_to_temperature
+  //    add in contributions from lambda power and boundary
+  //    flux to the FE temperature
+  //--------------------------------------------------------
+  void ThermostatIntegratorFixed::add_to_energy(const DENS_MAT & nodalLambdaPower,
+                                                DENS_MAT & deltaEnergy,
+                                                double dt)
+  {
+    deltaEnergy.resize(nNodes_,1);
+    
+    SetDependencyManager<int> * myRegulatedNodes =
+      (atc_->interscale_manager()).set_int(regulatorPrefix_+"ThermostatRegulatedNodes");
+    const set<int> & regulatedNodes(myRegulatedNodes->quantity());
+    
+    for (int i = 0; i < nNodes_; i++) {
+      if (regulatedNodes.find(i) != regulatedNodes.end()) {
+        deltaEnergy(i,0) = 0.;
+      }
+      else {
+        deltaEnergy(i,0) = nodalLambdaPower(i,0);
+      }
+    }
+  }
+
   //--------------------------------------------------------
   //  set_thermostat_rhs:
   //    sets up the right-hand side including boundary
   //    fluxes (coupling & prescribed), heat sources, and
   //    fixed (uncoupled) nodes
   //--------------------------------------------------------
-  void ThermostatFixed::set_thermostat_rhs(DENS_MAT & rhs,
-                                           double dt)
+  void ThermostatIntegratorFixed::set_thermostat_rhs(DENS_MAT & rhs,
+                                                     double dt)
   {
     // for essential bcs (fixed nodes) :
     // form rhs : (delThetaV - delTheta)/dt
-    const set<int> & regulatedNodes(regulatedNodes_->quantity());
+    SetDependencyManager<int> * myRegulatedNodes =
+      (atc_->interscale_manager()).set_int(regulatorPrefix_+"ThermostatRegulatedNodes");
+    const set<int> & regulatedNodes(myRegulatedNodes->quantity());
     double factor = (1./dt)/keMultiplier_;
+    rhs.resize(nNodes_,1);
+    
     for (int i = 0; i < nNodes_; i++) {
       if (regulatedNodes.find(i) != regulatedNodes.end()) {
         rhs(i,0) = factor*(deltaNodalAtomicEnergy_(i,0) - deltaFeEnergy_(i,0));
       }
       else {
         rhs(i,0) = 0.;
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
-  //  Class ThermostatFluxFiltered
+  //  Class ThermostatIntegratorFluxFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
   
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and thermostat data
   //--------------------------------------------------------
-  ThermostatFluxFiltered::ThermostatFluxFiltered(Thermostat * thermostat,
-                                                 const string & regulatorPrefix) :
-    ThermostatFlux(thermostat,regulatorPrefix)
+  ThermostatIntegratorFluxFiltered::ThermostatIntegratorFluxFiltered(AtomicRegulator * thermostat,
+                                                                     int lambdaMaxIterations,
+                                                                     const string & regulatorPrefix) :
+    ThermostatIntegratorFlux(thermostat,lambdaMaxIterations,regulatorPrefix)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
-  void ThermostatFluxFiltered::initialize()
+  void ThermostatIntegratorFluxFiltered::initialize()
   {
-    ThermostatFlux::initialize();
+    ThermostatIntegratorFlux::initialize();
 
     TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
     if (!timeFilterManager->end_equilibrate()) {
       // always must start as zero because of filtering scheme
       heatSourceOld_.reset(nNodes_,1);
       instantHeatSource_.reset(nNodes_,1);
       timeStepSource_.reset(nNodes_,1);
     }
   }
 
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the thermostat to the atoms in the second part
   //    of the corrector step of the Verlet algorithm
   //--------------------------------------------------------
-  void ThermostatFluxFiltered::apply_post_corrector(double dt)
+  void ThermostatIntegratorFluxFiltered::apply_post_corrector(double dt)
   {
     // compute lambda
-    ThermostatFlux::apply_post_corrector(dt);
+    ThermostatIntegratorFlux::apply_post_corrector(dt);
 
     // store data needed for filter inversion of heat flux for thermostat rhs
     instantHeatSource_ = rhs_;
     heatSourceOld_ = heatSource_.quantity();
   }
 
   //--------------------------------------------------------
   //  add_to_temperature
   //    add in contributions from lambda power and boundary
   //    flux to the FE temperature
   //--------------------------------------------------------
-  void ThermostatFluxFiltered::add_to_energy(const DENS_MAT & nodalLambdaPower,
-                                             DENS_MAT & deltaEnergy,
-                                             double dt)
+  void ThermostatIntegratorFluxFiltered::add_to_energy(const DENS_MAT & nodalLambdaPower,
+                                                       DENS_MAT & deltaEnergy,
+                                                       double dt)
   {
     deltaEnergy.reset(nNodes_,1);
     double coef = timeFilter_->unfiltered_coefficient_post_s1(2.*dt);
     const DENS_MAT & myBoundaryFlux(boundaryFlux_[TEMPERATURE].quantity());
     for (int i = 0; i < nNodes_; i++) {
       deltaEnergy(i,0) = coef*nodalLambdaPower(i,0) + dt*myBoundaryFlux(i,0);
     }
   }
 
   //--------------------------------------------------------
   //  set_thermostat_rhs:
   //    sets up the right-hand side including boundary
   //    fluxes (coupling & prescribed), heat sources, and
   //    fixed (uncoupled) nodes
   //--------------------------------------------------------
-  void ThermostatFluxFiltered::set_thermostat_rhs(DENS_MAT & rhs,
-                                                  double dt)
+  void ThermostatIntegratorFluxFiltered::set_thermostat_rhs(DENS_MAT & rhs,
+                                                            double dt)
   {
     
     // only tested with flux != 0 + ess bc = 0
 
     // (a) for flux based : 
     // form rhs :  2/3kB * W_I^-1 * \int N_I r dV
     // vs  Wagner, CMAME, 2008 eq(24) RHS_I = 2/(3kB) flux_I
     // fluxes are set in ATC transfer
 
     // invert heatSource_ to get unfiltered source
     // relevant coefficients from time filter
     
     double coefF1 = timeFilter_->filtered_coefficient_pre_s1(2.*dt);
     double coefF2 = timeFilter_->filtered_coefficient_post_s1(2.*dt);
     double coefU1 = timeFilter_->unfiltered_coefficient_pre_s1(2.*dt);
     double coefU2 = timeFilter_->unfiltered_coefficient_post_s1(2.*dt);
 
     const DENS_MAT & heatSource(heatSource_.quantity());
-    const set<int> & applicationNodes(applicationNodes_->quantity());
+    SetDependencyManager<int> * myApplicationNodes = 
+      (atc_->interscale_manager()).set_int(regulatorPrefix_+"ThermostatApplicationNodes");
+    const set<int> & applicationNodes(myApplicationNodes->quantity());
+    rhs.resize(nNodes_,1);
     for (int i = 0; i < nNodes_; i++) {
       if (applicationNodes.find(i) != applicationNodes.end()) {
         rhs(i,0) = heatSource(i,0) - coefF1*coefF2*heatSourceOld_(i,0) - coefU1*coefF2*instantHeatSource_(i,0);
         rhs(i,0) /= coefU2;
       }
       else {
         rhs(i,0) = 0.;
       }
     }
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
-  void ThermostatFluxFiltered::output(OUTPUT_LIST & outputData)
+  void ThermostatIntegratorFluxFiltered::output(OUTPUT_LIST & outputData)
   {
     _lambdaPowerOutput_ = lambdaPowerFiltered_->quantity();
     // approximate value for lambda power
     double dt =  LammpsInterface::instance()->dt();
     _lambdaPowerOutput_ *= (2./dt);
-    DENS_MAT & lambda(lambda_->set_quantity());
+    DENS_MAT & lambda((atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaEnergy",1))->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
       outputData[regulatorPrefix_+"Lambda"] = &lambda;
       outputData[regulatorPrefix_+"NodalLambdaPower"] = &(_lambdaPowerOutput_);
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
-  //  Class ThermostatFixedFiltered
+  //  Class ThermostatIntegratorFixedFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and thermostat data
   //--------------------------------------------------------
-  ThermostatFixedFiltered::ThermostatFixedFiltered(Thermostat * thermostat,
-                                                   const string & regulatorPrefix) :
-    ThermostatFixed(thermostat,regulatorPrefix)
+  ThermostatIntegratorFixedFiltered::ThermostatIntegratorFixedFiltered(AtomicRegulator * thermostat,
+                                                                       int lambdaMaxIterations,
+                                                                       const string & regulatorPrefix) :
+    ThermostatIntegratorFixed(thermostat,lambdaMaxIterations,regulatorPrefix)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  initialize_delta_nodal_atomic_energy:
   //    initializes storage for the variable tracking
   //    the change in the nodal atomic energy
   //    that has occured over the past timestep
   //--------------------------------------------------------
   
   
-  void ThermostatFixedFiltered::initialize_delta_nodal_atomic_energy(double dt)
+  void ThermostatIntegratorFixedFiltered::initialize_delta_nodal_atomic_energy(double dt)
   {
     // initialize delta energy
     DENS_MAT & myNodalAtomicEnergyFiltered(nodalAtomicEnergyFiltered_.set_quantity());
     initialNodalAtomicEnergy_ = myNodalAtomicEnergyFiltered;
     initialNodalAtomicEnergy_ *= -1.; // initially stored as negative for efficiency
     timeFilter_->apply_pre_step1(myNodalAtomicEnergyFiltered,
                                  nodalAtomicEnergy_->quantity(),dt);
   }
 
   //--------------------------------------------------------
   //  compute_delta_nodal_atomic_energy:
   //    computes the change in the nodal atomic energy
   //    that has occured over the past timestep
   //--------------------------------------------------------
-  void ThermostatFixedFiltered::compute_delta_nodal_atomic_energy(double dt)
+  void ThermostatIntegratorFixedFiltered::compute_delta_nodal_atomic_energy(double dt)
   {
     // set delta energy based on predicted atomic velocities
     DENS_MAT & myNodalAtomicEnergyFiltered(nodalAtomicEnergyFiltered_.set_quantity());
     timeFilter_->apply_post_step1(myNodalAtomicEnergyFiltered,
                                   nodalAtomicEnergy_->quantity(),dt);
     deltaNodalAtomicEnergy_ = initialNodalAtomicEnergy_;
     deltaNodalAtomicEnergy_ += myNodalAtomicEnergyFiltered;
   }
 
   //--------------------------------------------------------
   //  add_to_temperature
   //    add in contributions from lambda power and boundary
   //    flux to the FE temperature
   //--------------------------------------------------------
-  void ThermostatFixedFiltered::add_to_energy(const DENS_MAT & nodalLambdaPower,
-                                              DENS_MAT & deltaEnergy,
-                                              double dt)
+  void ThermostatIntegratorFixedFiltered::add_to_energy(const DENS_MAT & nodalLambdaPower,
+                                                        DENS_MAT & deltaEnergy,
+                                                        double dt)
   {
     deltaEnergy.resize(nNodes_,1);
-    const set<int> & regulatedNodes(regulatedNodes_->quantity());
+    SetDependencyManager<int> * myRegulatedNodes =
+      (atc_->interscale_manager()).set_int(regulatorPrefix_+"ThermostatRegulatedNodes");
+    const set<int> & regulatedNodes(myRegulatedNodes->quantity());
     double coef = timeFilter_->unfiltered_coefficient_post_s1(2.*dt);
     for (int i = 0; i < nNodes_; i++) {
       if (regulatedNodes.find(i) != regulatedNodes.end()) {
         deltaEnergy(i,0) = 0.;
       }
       else {
         deltaEnergy(i,0) = coef*nodalLambdaPower(i,0);
       }
     }
   }
   //--------------------------------------------------------
   //  set_thermostat_rhs:
   //    sets up the right-hand side for fixed
   //    (coupling & prescribed) temperature values
   //--------------------------------------------------------
-  void ThermostatFixedFiltered::set_thermostat_rhs(DENS_MAT & rhs,
-                                                   double dt)
+  void ThermostatIntegratorFixedFiltered::set_thermostat_rhs(DENS_MAT & rhs,
+                                                             double dt)
   {
-    // (b) for essential bcs (fixed nodes) :
+    // (b) for essential bcs (fixed nodes):
     // form rhs : (delThetaV - delTheta)/dt
-    const set<int> & regulatedNodes(regulatedNodes_->quantity());
+    SetDependencyManager<int> * myRegulatedNodes =
+      (atc_->interscale_manager()).set_int(regulatorPrefix_+"ThermostatRegulatedNodes");
+    const set<int> & regulatedNodes(myRegulatedNodes->quantity());
     double factor = (1./dt)/keMultiplier_;
     factor /= timeFilter_->unfiltered_coefficient_post_s1(2.*dt);
+    rhs.resize(nNodes_,1);
+    
     for (int i = 0; i < nNodes_; i++) {
       if (regulatedNodes.find(i) != regulatedNodes.end()) {
         rhs(i,0) = factor*(deltaNodalAtomicEnergy_(i,0) - deltaFeEnergy_(i,0));
       }
       else {
         rhs(i,0) = 0.;
       }
     }
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
-  void ThermostatFixedFiltered::output(OUTPUT_LIST & outputData)
+  void ThermostatIntegratorFixedFiltered::output(OUTPUT_LIST & outputData)
   {
      _lambdaPowerOutput_ = lambdaPowerFiltered_->quantity();
     // approximate value for lambda power
     double dt =  LammpsInterface::instance()->dt();
     _lambdaPowerOutput_ *= (2./dt);
-    DENS_MAT & lambda(lambda_->set_quantity());
+    DENS_MAT & lambda((atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaEnergy",1))->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
       outputData[regulatorPrefix_+"Lambda"] = &lambda;
       outputData[regulatorPrefix_+"NodalLambdaPower"] = &(_lambdaPowerOutput_);
     }
   }
 
-  
-  // have one for combined and one for lumped (lumped has two sub-thermostats)
-  // use node sets to call out fixed and fluxed locations
-  // derived off lumped lambda class that only considers certain atoms and certain nodes based on a mask
-  // move matrix solver construction to thermostats that actually do something
-  // thermostats can instantiate the type of shape function object they want in the future, for now we'll need hacks,
-  //    for now we'll have to construct them with appropriate shape function matrix
-
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatFluxFixed
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
-  ThermostatFluxFixed::ThermostatFluxFixed(Thermostat * thermostat,
+  ThermostatFluxFixed::ThermostatFluxFixed(AtomicRegulator * thermostat,
+                                           int lambdaMaxIterations,
                                            bool constructThermostats) :
     RegulatorMethod(thermostat),
     thermostatFlux_(NULL),
     thermostatFixed_(NULL),
     thermostatBcs_(NULL)
   {
     if (constructThermostats) {
-      thermostatFlux_ = new ThermostatFlux(thermostat,regulatorPrefix_+"Flux");
-      thermostatFixed_ = new ThermostatFixed(thermostat,regulatorPrefix_+"Fixed");
+      thermostatFlux_ = new ThermostatIntegratorFlux(thermostat,lambdaMaxIterations,regulatorPrefix_+"Flux");
+      thermostatFixed_ = new ThermostatIntegratorFixed(thermostat,lambdaMaxIterations,regulatorPrefix_+"Fixed");
 
       // need to choose BC type based on coupling mode
       if (thermostat->coupling_mode() == AtomicRegulator::FLUX) {
         thermostatBcs_ = thermostatFlux_;
       }
       else if (thermostat->coupling_mode() == AtomicRegulator::FIXED) {
         thermostatBcs_ = thermostatFixed_;
       }
       else {
         throw ATC_Error("ThermostatFluxFixed:create_thermostats - invalid thermostat type provided");
       }
     }
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ThermostatFluxFixed::~ThermostatFluxFixed()
   {
     if (thermostatFlux_) delete thermostatFlux_;
     if (thermostatFixed_) delete thermostatFixed_;
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatFluxFixed::construct_transfers()
   {
     thermostatFlux_->construct_transfers();
     thermostatFixed_->construct_transfers();
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void ThermostatFluxFixed::initialize()
   {
-    thermostatFlux_->initialize();
     thermostatFixed_->initialize();
+    thermostatFlux_->initialize();
   }
 
   //--------------------------------------------------------
   //  apply_predictor:
   //    apply the thermostat to the atoms in the first step
   //    of the Verlet algorithm
   //--------------------------------------------------------
   void ThermostatFluxFixed::apply_pre_predictor(double dt)
   {
     thermostatFixed_->apply_pre_predictor(dt);
     thermostatFlux_->apply_pre_predictor(dt);
   }
 
   //--------------------------------------------------------
   //  apply_pre_corrector:
   //    apply the thermostat to the atoms in the first part
   //    of the corrector step of the Verlet algorithm
   //--------------------------------------------------------
   void ThermostatFluxFixed::apply_pre_corrector(double dt)
   {
     thermostatFlux_->apply_pre_corrector(dt);
     if (thermostatFixed_->full_prediction()) {
       atc_->set_fixed_nodes();
     }
     thermostatFixed_->apply_pre_corrector(dt);
   }
 
   //--------------------------------------------------------
   //  apply_post_corrector:
   //    apply the thermostat to the atoms in the second part
   //    of the corrector step of the Verlet algorithm
   //--------------------------------------------------------
   void ThermostatFluxFixed::apply_post_corrector(double dt)
   {
     thermostatFlux_->apply_post_corrector(dt);
     atc_->set_fixed_nodes();
     thermostatFixed_->apply_post_corrector(dt);
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void ThermostatFluxFixed::output(OUTPUT_LIST & outputData)
   {
     thermostatFlux_->output(outputData);
     thermostatFixed_->output(outputData);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatFluxFixedFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
-  ThermostatFluxFixedFiltered::ThermostatFluxFixedFiltered(Thermostat * thermostat) :
-    ThermostatFluxFixed(thermostat,false)
+  ThermostatFluxFixedFiltered::ThermostatFluxFixedFiltered(AtomicRegulator * thermostat,
+                                                           int lambdaMaxIterations) :
+    ThermostatFluxFixed(thermostat,lambdaMaxIterations,false)
   {
-    thermostatFlux_ = new ThermostatFluxFiltered(thermostat,regulatorPrefix_+"Flux");
-    thermostatFixed_ = new ThermostatFixedFiltered(thermostat,regulatorPrefix_+"Fixed");
+    thermostatFlux_ = new ThermostatIntegratorFluxFiltered(thermostat,lambdaMaxIterations,regulatorPrefix_+"Flux");
+    thermostatFixed_ = new ThermostatIntegratorFixedFiltered(thermostat,lambdaMaxIterations,regulatorPrefix_+"Fixed");
 
     // need to choose BC type based on coupling mode
     if (thermostat->coupling_mode() == AtomicRegulator::FLUX) {
       thermostatBcs_ = thermostatFlux_;
     }
     else if (thermostat->coupling_mode() == AtomicRegulator::FIXED) {
       thermostatBcs_ = thermostatFixed_;
     }
     else {
       throw ATC_Error("ThermostatFluxFixed:create_thermostats - invalid thermostat type provided");
     }
   }
   //--------------------------------------------------------
   //  Class ThermostatGlc
   //--------------------------------------------------------
   //--------------------------------------------------------
  
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
-  ThermostatGlc::ThermostatGlc(Thermostat * thermostat) :
+  ThermostatGlc::ThermostatGlc(AtomicRegulator * thermostat) :
     ThermostatShapeFunction(thermostat),
     timeFilter_(atomicRegulator_->time_filter()),
     lambdaPowerFiltered_(NULL),
     atomThermostatForces_(NULL),
     prescribedDataMgr_(atc_->prescribed_data_manager()),
     atomMasses_(NULL)
   {
     // consistent with stage 3 of ATC_Method::initialize
-    lambdaPowerFiltered_= thermostat_->regulator_data(regulatorPrefix_+"LambdaPowerFiltered",1);
+    lambdaPowerFiltered_= atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaPowerFiltered",1);
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatGlc::construct_transfers()
   {
     ThermostatShapeFunction::construct_transfers();
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // get data from manager
     atomMasses_ = interscaleManager.fundamental_atom_quantity(LammpsInterface::ATOM_MASS);
 
     // thermostat forces based on lambda and the atomic velocities
     AtomicThermostatForce * atomThermostatForces = new AtomicThermostatForce(atc_);
     interscaleManager.add_per_atom_quantity(atomThermostatForces,
                                             regulatorPrefix_+"AtomThermostatForce");
     atomThermostatForces_ = atomThermostatForces;
   }
 
   //--------------------------------------------------------
   //  apply_to_atoms:
   //            determines what if any contributions to the
   //            atomic moition is needed for
   //            consistency with the thermostat
   //--------------------------------------------------------
   void ThermostatGlc::apply_to_atoms(PerAtomQuantity<double> * atomVelocities,
                                      const DENS_MAT & lambdaForce,
                                      double dt)
   {
     _velocityDelta_ = lambdaForce;
     _velocityDelta_ /= atomMasses_->quantity();
     _velocityDelta_ *= dt;
     (*atomVelocities) += _velocityDelta_;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatPowerVerlet
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and thermostat data
   //--------------------------------------------------------
-  ThermostatPowerVerlet::ThermostatPowerVerlet(Thermostat * thermostat) :
+  ThermostatPowerVerlet::ThermostatPowerVerlet(AtomicRegulator * thermostat) :
     ThermostatGlc(thermostat),
     nodalTemperatureRoc_(atc_->field_roc(TEMPERATURE)),
     heatSource_(atc_->atomic_source(TEMPERATURE)),
     nodalAtomicPower_(NULL),
     nodalAtomicLambdaPower_(NULL)
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatPowerVerlet::construct_transfers()
   {
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     // set up node mappings
     create_node_maps();
 
     // determine if mapping is needed and set up if so
     if (atomicRegulator_->use_localized_lambda()) {
         lambdaAtomMap_ = new AtomToElementset(atc_,elementMask_);
         interscaleManager.add_per_atom_int_quantity(lambdaAtomMap_,
                                                     regulatorPrefix_+"LambdaAtomMap");
     }
 
     // set up linear solver
     if (atomicRegulator_->use_lumped_lambda_solve()) {
       shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
       linearSolverType_ = AtomicRegulator::RSL_SOLVE;
     }
     else {
       if (lambdaAtomMap_) {
         shapeFunctionMatrix_ = new LocalLambdaCouplingMatrix(atc_,
                                                              lambdaAtomMap_,
                                                              nodeToOverlapMap_);
       }
       else {
         shapeFunctionMatrix_ = new LambdaCouplingMatrix(atc_,nodeToOverlapMap_);
       }
       linearSolverType_ = AtomicRegulator::CG_SOLVE;
     }
     interscaleManager.add_per_atom_sparse_matrix(shapeFunctionMatrix_,
                                                  regulatorPrefix_+"LambdaCouplingMatrixEnergy");
 
     // base class transfers, e.g. weights
     ThermostatGlc::construct_transfers();
 
     // get managed data
     nodalAtomicPower_ = interscaleManager.dense_matrix("NodalAtomicPower");
     
     // power induced by lambda
     DotTwiceKineticEnergy * atomicLambdaPower = 
       new DotTwiceKineticEnergy(atc_,atomThermostatForces_);
     interscaleManager.add_per_atom_quantity(atomicLambdaPower,
                                             regulatorPrefix_+"AtomicLambdaPower");
     
     // restriction to nodes of power induced by lambda
     nodalAtomicLambdaPower_ = new AtfShapeFunctionRestriction(atc_,
                                                               atomicLambdaPower,
                                                               interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_dense_matrix(nodalAtomicLambdaPower_,
                                             regulatorPrefix_+"NodalAtomicLambdaPower");
   }
 
   //--------------------------------------------------------
   //  initialize
   //    initializes all method data
   //--------------------------------------------------------
   void ThermostatPowerVerlet::initialize()
   {
     ThermostatGlc::initialize();
 
     // sets up time filter for cases where variables temporally filtered
     TimeFilterManager * timeFilterManager = atc_->time_filter_manager();
     if (!timeFilterManager->end_equilibrate()) {
       _nodalAtomicLambdaPowerOut_ = 0.;
       *lambdaPowerFiltered_ = 0.;
       timeFilter_->initialize(lambdaPowerFiltered_->quantity());
     }
   }
 
   //--------------------------------------------------------
   //  apply_predictor:
   //    apply the thermostat to the atoms in the first step
   //    of the Verlet algorithm
   //--------------------------------------------------------
   void ThermostatPowerVerlet::apply_pre_predictor(double dt)
   {
     atomThermostatForces_->unfix_quantity();
     compute_thermostat(0.5*dt);
 
     // apply lambda force to atoms
     const DENS_MAT & thermostatForces(atomThermostatForces_->quantity());
     atomThermostatForces_->fix_quantity();
     apply_to_atoms(atomVelocities_,thermostatForces,0.5*dt);
   }
 
   //--------------------------------------------------------
   //  apply_pre_corrector:
   //    apply the thermostat to the atoms in the first part
   //    of the corrector step of the Verlet algorithm
   //--------------------------------------------------------
   void ThermostatPowerVerlet::apply_pre_corrector(double dt)
   {
     atomThermostatForces_->unfix_quantity();
     compute_thermostat(0.5*dt);
 
     // apply lambda force to atoms
     const DENS_MAT & thermostatForces(atomThermostatForces_->quantity());
     atomThermostatForces_->fix_quantity();
     apply_to_atoms(atomVelocities_,thermostatForces,0.5*dt);
   }
 
   //--------------------------------------------------------
   //  add_to_rhs:
   //            determines what if any contributions to the
   //            finite element equations are needed for
   //            consistency with the thermostat
   //--------------------------------------------------------
   void ThermostatPowerVerlet::add_to_rhs(FIELDS & rhs)
   {
     rhs[TEMPERATURE] += nodalAtomicLambdaPower_->quantity() + boundaryFlux_[TEMPERATURE].quantity();
   }
 
   //--------------------------------------------------------
   //  set_thermostat_rhs:
   //    sets up the right-hand side including boundary
   //    fluxes (coupling & prescribed), heat sources, and
   //    fixed (uncoupled) nodes
   //--------------------------------------------------------
   void ThermostatPowerVerlet::set_thermostat_rhs(DENS_MAT & rhs_nodes)
   {
     // (a) for flux based : 
     // form rhs :  \int N_I r dV
     // vs  Wagner, CMAME, 2008 eq(24) RHS_I = 2/(3kB) flux_I
     // fluxes are set in ATC transfer
     rhs_nodes = heatSource_.quantity();
     
     // (b) for ess. bcs
     // form rhs : {sum_a (2 * N_Ia * v_ia * f_ia) - (dtheta/dt)_I}
     
     // replace rhs for prescribed nodes
     const DENS_MAT & myNodalAtomicPower(nodalAtomicPower_->quantity());
     const DIAG_MAT & myMdMassMatrix(mdMassMatrix_.quantity());
     const DENS_MAT & myNodalTemperatureRoc(nodalTemperatureRoc_.quantity());
     for (int i = 0; i < nNodes_; i++) {
       if (prescribedDataMgr_->is_fixed(i,TEMPERATURE,0)) {
         rhs_nodes(i,0) = 0.5*(myNodalAtomicPower(i,0) - myMdMassMatrix(i,i)*myNodalTemperatureRoc(i,0));
       }
     }
   }
 
   //--------------------------------------------------------
   //  compute_thermostat:
   //    sets up and solves the thermostat equations since
   //    they are the same at different parts of the time
   //    step
   //--------------------------------------------------------
   void ThermostatPowerVerlet::compute_thermostat(double dt)
   {
     // set up rhs
     set_thermostat_rhs(_rhs_);
     
     // solve linear system for lambda
     DENS_MAT & myLambda(lambda_->set_quantity());
     solve_for_lambda(_rhs_,myLambda);
 
     nodalAtomicLambdaPower_->unfix_quantity(); // enable computation of force applied by lambda
     timeFilter_->apply_pre_step1(lambdaPowerFiltered_->set_quantity(),
                                  nodalAtomicLambdaPower_->quantity(),dt);
     nodalAtomicLambdaPower_->fix_quantity();
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void ThermostatPowerVerlet::output(OUTPUT_LIST & outputData)
   {
     _nodalAtomicLambdaPowerOut_ = nodalAtomicLambdaPower_->quantity();
     DENS_MAT & lambda(lambda_->set_quantity());
     if ((atc_->lammps_interface())->rank_zero()) {
       outputData["lambda"] = &lambda;
       outputData["nodalLambdaPower"] = &(_nodalAtomicLambdaPowerOut_);
     }
   }
 
   //--------------------------------------------------------
   //  finish:
   //    final tasks after a run
   //--------------------------------------------------------
   void ThermostatPowerVerlet::finish()
   {
     _nodalAtomicLambdaPowerOut_ = nodalAtomicLambdaPower_->quantity();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatHooverVerlet
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and thermostat data
   //--------------------------------------------------------
-  ThermostatHooverVerlet::ThermostatHooverVerlet(Thermostat * thermostat) :
+  ThermostatHooverVerlet::ThermostatHooverVerlet(AtomicRegulator * thermostat) :
     ThermostatPowerVerlet(thermostat),
     lambdaHoover_(NULL),
     nodalAtomicHooverLambdaPower_(NULL)
   {
     // set up data consistent with stage 3 of ATC_Method::initialize
-    lambdaHoover_ = thermostat_->regulator_data(regulatorPrefix_+"LambdaHoover",1);
+    lambdaHoover_ = atomicRegulator_->regulator_data(regulatorPrefix_+"LambdaHoover",1);
     
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatHooverVerlet::construct_transfers()
   {
     ThermostatPowerVerlet::construct_transfers();
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
 
     FtaShapeFunctionProlongation * atomHooverLambdas = new FtaShapeFunctionProlongation(atc_,
                                                                                         lambdaHoover_,
                                                                                         interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_per_atom_quantity(atomHooverLambdas,
                                             regulatorPrefix_+"AtomHooverLambda");
     AtomicThermostatForce * atomHooverThermostatForces = new AtomicThermostatForce(atc_,atomHooverLambdas);
     interscaleManager.add_per_atom_quantity(atomHooverThermostatForces,
                                             regulatorPrefix_+"AtomHooverThermostatForce");
     SummedAtomicQuantity<double> * atomTotalThermostatForces = 
       new SummedAtomicQuantity<double>(atc_,atomThermostatForces_,atomHooverThermostatForces);
     interscaleManager.add_per_atom_quantity(atomTotalThermostatForces,
                                             regulatorPrefix_+"AtomTotalThermostatForce");
     atomThermostatForces_ = atomTotalThermostatForces;
           
     // transfers dependent on time integration method
     DotTwiceKineticEnergy * atomicHooverLambdaPower = 
       new DotTwiceKineticEnergy(atc_,atomHooverThermostatForces);
     interscaleManager.add_per_atom_quantity(atomicHooverLambdaPower,
                                             regulatorPrefix_+"AtomicHooverLambdaPower");
     
      nodalAtomicHooverLambdaPower_ = new AtfShapeFunctionRestriction(atc_,
                                                                      atomicHooverLambdaPower,
                                                                      interscaleManager.per_atom_sparse_matrix("Interpolant"));
      interscaleManager.add_dense_matrix(nodalAtomicHooverLambdaPower_,
                                              regulatorPrefix_+"NodalAtomicHooverLambdaPower");
   }
 
   //--------------------------------------------------------
   //  add_to_rhs:
   //            determines what if any contributions to the
   //            finite element equations are needed for
   //            consistency with the thermostat
   //--------------------------------------------------------
   void ThermostatHooverVerlet::add_to_rhs(FIELDS & rhs)
   {
     rhs[TEMPERATURE] += _nodalAtomicLambdaPowerOut_;
   }
 
   //--------------------------------------------------------
   //  compute_thermostat:
   //    sets up and solves the thermostat equations since
   //    they are the same at different parts of the time
   //    step
   //--------------------------------------------------------
   void ThermostatHooverVerlet::compute_thermostat(double dt)
   {
     // apply prescribed/extrinsic sources and fixed nodes
     ThermostatPowerVerlet::compute_thermostat(0.5*dt);
     _nodalAtomicLambdaPowerOut_ = nodalAtomicLambdaPower_->quantity(); // save power from lambda in power-based thermostat
     
     // set up Hoover rhs
     set_hoover_rhs(_rhs_);
     
     // solve linear system for lambda
     DENS_MAT & myLambda(lambdaHoover_->set_quantity());
     solve_for_lambda(_rhs_,myLambda);
     
     // compute force applied by lambda
     // compute nodal atomic power from Hoover coupling
     // only add in contribution to uncoupled nodes
     if (atomicRegulator_->use_localized_lambda())
       add_to_lambda_power(atomThermostatForces_->quantity(),0.5*dt);
   }
 
   //--------------------------------------------------------
   //  set_hoover_rhs:
   //    sets up the right-hand side for fixed value,
   //    i.e. Hoover coupling
   //--------------------------------------------------------
   void ThermostatHooverVerlet::set_hoover_rhs(DENS_MAT & rhs)
   {
     // form rhs : sum_a ( N_Ia * v_ia * f_ia) - 0.5*M_MD*(dtheta/dt)_I
     rhs = nodalAtomicPower_->quantity();
     rhs -= mdMassMatrix_.quantity()*nodalTemperatureRoc_.quantity();
     rhs /= 2.;
   }
 
   //--------------------------------------------------------
   //  add_to_nodal_lambda_power:
   //    determines the power exerted by the Hoover 
   //    thermostat at each FE node
   //--------------------------------------------------------
   void ThermostatHooverVerlet::add_to_lambda_power(const DENS_MAT & myLambdaForce,
                                                    double dt)
   {
     _myNodalLambdaPower_ = nodalAtomicHooverLambdaPower_->quantity();
     const INT_ARRAY & nodeToOverlapMap(nodeToOverlapMap_->quantity());
     for (int i = 0; i < nNodes_; ++i) {
       if (nodeToOverlapMap(i,0)==-1)
         _nodalAtomicLambdaPowerOut_(i,0) += _myNodalLambdaPower_(i,0);
       else
         _myNodalLambdaPower_(i,0) = 0.;
     }
     timeFilter_->apply_post_step1(lambdaPowerFiltered_->set_quantity(),_myNodalLambdaPower_,dt);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatPowerVerletFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and thermostat data
   //--------------------------------------------------------
-  ThermostatPowerVerletFiltered::ThermostatPowerVerletFiltered(Thermostat * thermostat) :
+  ThermostatPowerVerletFiltered::ThermostatPowerVerletFiltered(AtomicRegulator * thermostat) :
     ThermostatPowerVerlet(thermostat),
     nodalTemperature2Roc_(atc_->field_2roc(TEMPERATURE)),
     fieldsRoc_(atc_->fields_roc()),
     filterScale_((atc_->time_filter_manager())->filter_scale())
   {
     heatSourceRoc_.reset(nNodes_,1);
     fluxRoc_[TEMPERATURE].reset(nNodes_,1);
   }
 
   //--------------------------------------------------------
   //  compute_boundary_flux
   //    also sets time derivatives of boundary flux and
   //    heat sources
   //--------------------------------------------------------
   void ThermostatPowerVerletFiltered::compute_boundary_flux(FIELDS & fields)
   {
     ThermostatPowerVerlet::compute_boundary_flux(fields);
     
     // compute boundary flux rate of change
     fluxRoc_[TEMPERATURE] = 0.;
     atc_->compute_boundary_flux(fieldMask_,
                                 fieldsRoc_,
                                 fluxRoc_,
                                 atomMaterialGroups_,
                                 shpFcnDerivs_);
 
     
 
     // compute extrinsic model rate of change
     (atc_->extrinsic_model_manager()).set_sources(fieldsRoc_,fluxRoc_);
     heatSourceRoc_ = fluxRoc_[TEMPERATURE].quantity(); 
   }
 
   //--------------------------------------------------------
   //  add_to_rhs:
   //            determines what if any contributions to the
   //            finite element equations are needed for
   //            consistency with the thermostat
   //--------------------------------------------------------
   void ThermostatPowerVerletFiltered::add_to_rhs(FIELDS & rhs)
   {
     rhs[TEMPERATURE] += lambdaPowerFiltered_->quantity() + boundaryFlux_[TEMPERATURE].quantity();
   }
 
   //--------------------------------------------------------
   //  set_thermostat_rhs:
   //    sets up the right-hand side including boundary
   //    fluxes (coupling & prescribed), heat sources, and
   //    fixed (uncoupled) nodes
   //--------------------------------------------------------
   void ThermostatPowerVerletFiltered::set_thermostat_rhs(DENS_MAT & rhs_nodes)
   {
     // (a) for flux based : 
     // form rhs :  \int N_I r dV
     // vs  Wagner, CMAME, 2008 eq(24) RHS_I = 2/(3kB) flux_I
     // fluxes are set in ATC transfer
     rhs_nodes = heatSource_.quantity() + filterScale_*heatSourceRoc_.quantity();
 
     // (b) for ess. bcs
     // form rhs : {sum_a (N_Ia * v_ia * f_ia) - 0.5*(dtheta/dt)_I}
     const DENS_MAT & myNodalAtomicPower(nodalAtomicPower_->quantity());
     const DIAG_MAT & myMdMassMatrix(mdMassMatrix_.quantity());
     const DENS_MAT & myNodalTemperatureRoc(nodalTemperatureRoc_.quantity());
     const DENS_MAT & myNodalTemperature2Roc(nodalTemperature2Roc_.quantity());
     for (int i = 0; i < nNodes_; i++) {
       if (prescribedDataMgr_->is_fixed(i,TEMPERATURE,0)) {
         rhs_nodes(i,0) = 0.5*(myNodalAtomicPower(i,0) - myMdMassMatrix(i,i)*(myNodalTemperatureRoc(i,0)+ filterScale_*myNodalTemperature2Roc(i,0)));
       }
     }
   }
 
   //--------------------------------------------------------
   //  output:
   //    adds all relevant output to outputData
   //--------------------------------------------------------
   void ThermostatPowerVerletFiltered::output(OUTPUT_LIST & outputData)
   {
     outputData["lambda"] = &(lambda_->set_quantity());
     outputData["nodalLambdaPower"] = &(lambdaPowerFiltered_->set_quantity());
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ThermostatHooverVerletFiltered
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //         Grab references to ATC and thermostat data
   //--------------------------------------------------------
-  ThermostatHooverVerletFiltered::ThermostatHooverVerletFiltered(Thermostat * thermostat) :
+  ThermostatHooverVerletFiltered::ThermostatHooverVerletFiltered(AtomicRegulator * thermostat) :
     ThermostatPowerVerletFiltered(thermostat),
     lambdaHoover_(NULL),
     nodalAtomicHooverLambdaPower_(NULL)
   {
     // consistent with stage 3 of ATC_Method::initialize
-    lambdaHoover_ = thermostat_->regulator_data("LambdaHoover",1);
+    lambdaHoover_ = atomicRegulator_->regulator_data("LambdaHoover",1);
   }
 
   //--------------------------------------------------------
   //  constructor_transfers
   //    instantiates or obtains all dependency managed data
   //--------------------------------------------------------
   void ThermostatHooverVerletFiltered::construct_transfers()
   {
     ThermostatPowerVerletFiltered::construct_transfers();
     InterscaleManager & interscaleManager(atc_->interscale_manager());
 
     FtaShapeFunctionProlongation * atomHooverLambdas = new FtaShapeFunctionProlongation(atc_,
                                                                                         lambdaHoover_,
                                                                                         interscaleManager.per_atom_sparse_matrix("Interpolant"));
     interscaleManager.add_per_atom_quantity(atomHooverLambdas,
                                             regulatorPrefix_+"AtomHooverLambda");
     AtomicThermostatForce * atomHooverThermostatForces = new AtomicThermostatForce(atc_,atomHooverLambdas);
     interscaleManager.add_per_atom_quantity(atomHooverThermostatForces,
                                             regulatorPrefix_+"AtomHooverThermostatForce");
     SummedAtomicQuantity<double> * atomTotalThermostatForces = 
       new SummedAtomicQuantity<double>(atc_,atomThermostatForces_,atomHooverThermostatForces);
     interscaleManager.add_per_atom_quantity(atomTotalThermostatForces,
                                             regulatorPrefix_+"AtomTotalThermostatForce");
     atomThermostatForces_ = atomTotalThermostatForces;
           
     // transfers dependent on time integration method
     DotTwiceKineticEnergy * atomicHooverLambdaPower = 
       new DotTwiceKineticEnergy(atc_,atomHooverThermostatForces);
     interscaleManager.add_per_atom_quantity(atomicHooverLambdaPower,
                                             regulatorPrefix_+"AtomicHooverLambdaPower");
     
      nodalAtomicHooverLambdaPower_ = new AtfShapeFunctionRestriction(atc_,
                                                                      atomicHooverLambdaPower,
                                                                      interscaleManager.per_atom_sparse_matrix("Interpolant"));
      interscaleManager.add_dense_matrix(nodalAtomicHooverLambdaPower_,
                                              regulatorPrefix_+"NodalAtomicHooverLambdaPower");
   }
 
   //--------------------------------------------------------
   //  compute_thermostat:
   //    sets up and solves the thermostat equations since
   //    they are the same at different parts of the time
   //    step
   //--------------------------------------------------------
   void ThermostatHooverVerletFiltered::compute_thermostat(double dt)
   {
     // apply prescribed/extrinsic sources and fixed nodes
     ThermostatPowerVerletFiltered::compute_thermostat(0.5*dt);
     _nodalAtomicLambdaPowerOut_ = nodalAtomicLambdaPower_->quantity(); // save power from lambda in power-based thermostat
     
     // set up Hoover rhs
     set_hoover_rhs(_rhs_);
     
     // solve linear system for lambda
     DENS_MAT & myLambda(lambdaHoover_->set_quantity());
     solve_for_lambda(_rhs_,myLambda);
     
     
     // compute force applied by lambda
     // compute nodal atomic power from Hoover coupling
     // only add in contribution to uncoupled nodes
     if (atomicRegulator_->use_localized_lambda())
       add_to_lambda_power(atomThermostatForces_->quantity(),0.5*dt);
   }
 
   //--------------------------------------------------------
   //  set_hoover_rhs:
   //    sets up the right-hand side for fixed value,
   //    i.e. Hoover coupling
   //--------------------------------------------------------
   void ThermostatHooverVerletFiltered::set_hoover_rhs(DENS_MAT & rhs)
   {
     // form rhs : sum_a (N_Ia * v_ia * f_ia) - 0.5*M_MD*(dtheta/dt)_I
     rhs = nodalAtomicPower_->quantity();
     rhs -= mdMassMatrix_.quantity()*(nodalTemperatureRoc_.quantity() + filterScale_*nodalTemperature2Roc_.quantity());
     rhs /= 2.;
   }
 
   //--------------------------------------------------------
   //  add_to_nodal_lambda_power:
   //    determines the power exerted by the Hoover 
   //    thermostat at each FE node
   //--------------------------------------------------------
   void ThermostatHooverVerletFiltered::add_to_lambda_power(const DENS_MAT & myLambdaForce,
                                                            double dt)
   {
     _myNodalLambdaPower_ = nodalAtomicHooverLambdaPower_->quantity();
     const INT_ARRAY nodeToOverlapMap(nodeToOverlapMap_->quantity());
     for (int i = 0; i < nNodes_; ++i) {
       if (nodeToOverlapMap(i,0)==-1)
         _nodalAtomicLambdaPowerOut_(i,0) += _myNodalLambdaPower_(i,0);
       else
         _myNodalLambdaPower_(i,0) = 0.;
     }
     timeFilter_->apply_post_step1(lambdaPowerFiltered_->set_quantity(),_myNodalLambdaPower_,dt);
   }
 
   //--------------------------------------------------------
   //  add_to_rhs:
   //            determines what if any contributions to the
   //            finite element equations are needed for
   //            consistency with the thermostat
   //--------------------------------------------------------
   void ThermostatHooverVerletFiltered::add_to_rhs(FIELDS & rhs)
   {
     rhs[TEMPERATURE] += lambdaPowerFiltered_->quantity();
   }
 
 };
diff --git a/lib/atc/Thermostat.h b/lib/atc/Thermostat.h
index aa2658156..65dbba7e1 100644
--- a/lib/atc/Thermostat.h
+++ b/lib/atc/Thermostat.h
@@ -1,925 +1,1061 @@
 #ifndef THERMOSTAT_H
 #define THERMOSTAT_H
 
 #include "AtomicRegulator.h"
 #include "PerAtomQuantityLibrary.h"
 #include <map>
 #include <set>
 #include <string>
 
 namespace ATC {
 
   static const int myLambdaMaxIterations = 50;
 
   // forward declarations
   class ThermalTimeIntegrator;
   class AtfShapeFunctionRestriction;
   class FundamentalAtomQuantity;
   class PrescribedDataManager;
 
   /**
    *  @class  Thermostat
    *  @brief  Manager class for atom-continuum control of thermal energy
    */
   class Thermostat : public AtomicRegulator {
   
   public:
 
     // constructor
     Thermostat(ATC_Coupling * atc,
                const std::string & regulatorPrefix = "");
         
     // destructor
     virtual ~Thermostat(){};
         
     /** parser/modifier */
     virtual bool modify(int narg, char **arg);
 
     /** instantiate up the desired method(s) */
     virtual void construct_methods();
         
     // data access, intended for method objects
     /** reset the nodal power to a prescribed value */
     virtual void reset_lambda_contribution(const DENS_MAT & target);
 
     /** return value for the correction maximum number of iterations */
     int lambda_max_iterations() {return lambdaMaxIterations_;};
 
   protected:
 
     // data regarding fixed nodes and applied fluxes
     /** set of all fixed nodes */
     std::set<int> fixedNodes_;
     /** set of all nodes which have a flux applied */
     std::set<int> fluxNodes_;
 
     /** maximum number of iterations used in iterative solve for lambda */
     int lambdaMaxIterations_;
 
   private:
     
     // DO NOT define this
     Thermostat();
         
   };
 
   /**
    *  @class  ThermostatShapeFunction
    *  @brief  Class for thermostat algorithms using the shape function matrices
    *          (thermostats have general for of N^T w N lambda = rhs)
    */
   
   class ThermostatShapeFunction : public RegulatorShapeFunction {
 
   
   public:
   
-    ThermostatShapeFunction(Thermostat * thermostat,
+    ThermostatShapeFunction(AtomicRegulator * thermostat,
                             const std::string & regulatorPrefix = "");
         
     virtual ~ThermostatShapeFunction() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
   protected:
 
     // methods
     /** set weighting factor for in matrix Nhat^T * weights * Nhat */
     virtual void set_weights();
 
     // member data
-    /** pointer to thermostat object for data */
-    Thermostat * thermostat_;
-
     
     /** MD mass matrix */
     DIAG_MAN & mdMassMatrix_;  
 
     /** pointer to atom velocities */
     FundamentalAtomQuantity * atomVelocities_;
 
     /** workspace variables */
     DENS_VEC _weightVector_, _maskedWeightVector_;
 
   private:
 
     // DO NOT define this
     ThermostatShapeFunction();
 
   };
 
   /**
    *  @class  ThermostatRescale
    *  @brief  Enforces constraint on atomic kinetic energy based on FE temperature
    */
   
   class ThermostatRescale : public ThermostatShapeFunction {
   
   public:
+
+    friend class KinetoThermostatRescale; // since this is sometimes used as a set of member functions for friend
   
-    ThermostatRescale(Thermostat * thermostat);
+    ThermostatRescale(AtomicRegulator * thermostat);
         
     virtual ~ThermostatRescale() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
         
     /** applies thermostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
 
+    /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
+    virtual void compute_boundary_flux(FIELDS & fields)
+      {boundaryFlux_[TEMPERATURE] = 0.;};
+
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
         
   protected:
 
+    /** set weighting factor for in matrix Nhat^T * weights * Nhat */
+    virtual void set_weights();
+
+    /** sets up and solves thermostat equations */
+    virtual void compute_thermostat(double dt);
+
     /** apply solution to atomic quantities */
     void apply_to_atoms(PerAtomQuantity<double> * atomVelocities);
 
-    /** correct the RHS for complex temperature definitions */
-    virtual void correct_rhs(DENS_MAT & rhs) {};  // base class does no correction, assuming kinetic definition
+    /** construct the RHS vector */
+    virtual void set_rhs(DENS_MAT & rhs);
         
     /** FE temperature field */
     DENS_MAN & nodalTemperature_;
 
     /** construction for prolongation of lambda to atoms */
     AtomicVelocityRescaleFactor * atomVelocityRescalings_;
 
     /** workspace variables */
     DENS_MAT _rhs_;
 
   private:
 
     // DO NOT define this
     ThermostatRescale();
   
   };
 
   /**
    *  @class  ThermostatRescaleMixedKePe
    *  @brief  Enforces constraint on atomic kinetic energy based on FE temperature
    *          when the temperature is a mix of the KE and PE
    */
   
   class ThermostatRescaleMixedKePe : public ThermostatRescale {
   
   public:
   
-    ThermostatRescaleMixedKePe(Thermostat * thermostat);
+    ThermostatRescaleMixedKePe(AtomicRegulator * thermostat);
         
     virtual ~ThermostatRescaleMixedKePe() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
         
   protected:
 
-    /** correct the RHS for inclusion of the PE */
-    virtual void correct_rhs(DENS_MAT & rhs);
+    /** set weighting factor for in matrix Nhat^T * weights * Nhat */
+    virtual void set_weights();
+
+    /** construct the RHS vector */
+    virtual void set_rhs(DENS_MAT & rhs);
 
     /** nodal fluctuating potential energy */
     DENS_MAN * nodalAtomicFluctuatingPotentialEnergy_;
 
     /** fraction of temperature from KE */
     double keMultiplier_;
 
     /** fraction of temperature from PE */
     double peMultiplier_;
 
   private:
 
     // DO NOT define this
     ThermostatRescaleMixedKePe();
   
+  };
+
+    /**
+   *  @class  ThermostatFsSolver
+   *  @brief  Class for solving the linear system for lambda
+   *          (thermostats have general for of N^T w N lambda = rhs)
+   */
+  
+  class ThermostatFsSolver : public RegulatorShapeFunction {
+
+  
+  public:
+  
+    ThermostatFsSolver(AtomicRegulator * thermostat,
+                       int lambdaMaxIterations,
+                       const std::string & regulatorPrefix = "");
+        
+    virtual ~ThermostatFsSolver() {};
+
+    /** pre-run initialization of method data */
+    virtual void initialize();
+
+    /* sets up and solves the linear system for lambda */
+    virtual void compute_lambda(const DENS_MAT & rhs,
+                                bool iterateSolution = true);
+
+    /* scales lambda */
+    virtual void scale_lambda(double factor) {*lambda_ *= factor;};
+
+    /** change the time step factor */
+    virtual void set_timestep_factor(double dtFactor) {dtFactor_ = dtFactor;};
+
+  protected:
+
+    // methods  
+    /** solves the non-linear equation for lambda iteratively */
+    void iterate_lambda(const MATRIX & rhs);
+
+    /** set weighting factor for in matrix Nhat^T * weights * Nhat */
+    virtual void set_weights();
+
+    // data
+    /** mapping from all to regulated nodes */
+    DENS_MAT rhsMap_;
+
+    /** maximum number of iterations used in iterative solve for lambda */
+    int lambdaMaxIterations_;
+
+    /** pointer to the values of lambda interpolated to atoms */
+    DENS_MAN * rhsLambdaSquared_;
+
+    /** fraction of timestep over which constraint is exactly enforced */
+    double dtFactor_;
+
+    // workspace
+    DENS_MAT _lambdaOld_; // lambda from previous iteration
+    DENS_MAT _rhsOverlap_; // normal RHS vector mapped to overlap nodes
+    DENS_VEC _rhsTotal_; // normal + 2nd order RHS for the iteration loop
+    DENS_VEC _weightVector_, _maskedWeightVector_;
+
+  private:
+
+    // DO NOT define this
+    ThermostatFsSolver();
+
   };
 
   /**
    *  @class  ThermostatGlcFs
-   *  @brief  Class for thermostat algorithms based on Gaussian least constraints (GLC) for fractional step (FS) algorithsm
+   *  @brief  Class for thermostat algorithms which perform the time-integration component of the fractional step method
    */
   
-  class ThermostatGlcFs : public ThermostatShapeFunction {
+  class ThermostatGlcFs : public RegulatorMethod {
   
   public:
   
-    ThermostatGlcFs(Thermostat * thermostat,
+    ThermostatGlcFs(AtomicRegulator * thermostat,
+                    int lambdaMaxIterations,
                     const std::string & regulatorPrefix = "");
         
     virtual ~ThermostatGlcFs() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
 
     /** applies thermostat to atoms in the predictor phase */
     virtual void apply_pre_predictor(double dt);
 
     /** applies thermostat to atoms in the pre-corrector phase */
     virtual void apply_pre_corrector(double dt);
 
     /** applies thermostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
     
+    /** compute boundary flux, requires regulator input since it is part of the coupling scheme */
+    virtual void compute_boundary_flux(FIELDS & fields);
+    
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
 
     /* flag for performing the full lambda prediction calculation */
     bool full_prediction();
 
+    /** set up atom to material identification */
+    virtual void reset_atom_materials(const Array<int> & elementToMaterialMap,
+                                      const MatrixDependencyManager<DenseMatrix, int> * atomElement);
+
   protected:
 
     // methods
-    /** determine mapping from all nodes to those to which the thermostat applies */
-    void compute_rhs_map();
-
     /** sets up appropriate rhs for thermostat equations */
     virtual void set_thermostat_rhs(DENS_MAT & rhs,
                                     double dt) = 0;
 
     /** apply forces to atoms */
     virtual void apply_to_atoms(PerAtomQuantity<double> * atomicVelocity,
                                 const DENS_MAN * nodalAtomicEnergy,
                                 const DENS_MAT & lambdaForce,
                                 DENS_MAT & nodalAtomicLambdaPower,
                                 double dt);
 
     /** add contributions from thermostat to FE energy */
     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower,
                                DENS_MAT & deltaEnergy,
                                double dt) = 0;
 
     /* sets up and solves the linear system for lambda */
     virtual void compute_lambda(double dt,
                                 bool iterateSolution = true);
 
-    /** solves the non-linear equation for lambda iteratively */
-    void iterate_lambda(const MATRIX & rhs);
-
     // member data
+    /** solver for lambda linear system */
+    ThermostatFsSolver * lambdaSolver_;
+
+    
+    /** MD mass matrix */
+    DIAG_MAN & mdMassMatrix_;  
+
+    /** pointer to atom velocities */
+    FundamentalAtomQuantity * atomVelocities_;
+
     /** reference to AtC FE temperature */
     DENS_MAN & temperature_;
 
     /** pointer to a time filtering object */
     TimeFilter * timeFilter_;
 
     /** power induced by lambda */
     DENS_MAN * nodalAtomicLambdaPower_;
 
     /** filtered lambda power */
     DENS_MAN * lambdaPowerFiltered_;
 
+    /** lambda at atomic locations */
+    PerAtomQuantity<double> * atomLambdas_;
+
     /** atomic force induced by lambda */
     AtomicThermostatForce * atomThermostatForces_;
 
     /** pointer to atom masses */
     FundamentalAtomQuantity * atomMasses_;
 
-    /** pointer to the values of lambda interpolated to atoms */
-    DENS_MAN * rhsLambdaSquared_;
-
     /** hack to determine if first timestep has been passed */
     bool isFirstTimestep_;
 
-    /** maximum number of iterations used in iterative solve for lambda */
-    int lambdaMaxIterations_;
-
     /** nodal atomic energy */
     DENS_MAN * nodalAtomicEnergy_;
 
     /** local version of velocity used as predicted final veloctiy */
     PerAtomQuantity<double> * atomPredictedVelocities_;
 
     /** predicted nodal atomic energy */
     AtfShapeFunctionRestriction * nodalAtomicPredictedEnergy_;
 
     /** pointer for force applied in first time step */
     DENS_MAN * firstHalfAtomForces_;
 
     /** FE temperature change from thermostat during predictor phase in second half of timestep */
     DENS_MAT deltaEnergy1_;
 
     /** FE temperature change from thermostat during corrector phase in second half of timestep */
     DENS_MAT deltaEnergy2_;
 
     /** right-hand side data for thermostat equation */
     DENS_MAT rhs_;
 
-    /** mapping from all to regulated nodes */
-    DENS_MAT rhsMap_;
-
-    /** fraction of timestep over which constraint is exactly enforced */
-    double dtFactor_;
-
     // workspace
     DENS_MAT _lambdaPowerOutput_; // power applied by lambda in output format
     DENS_MAT _velocityDelta_; // change in velocity when lambda force is applied
     DENS_VEC _lambdaOverlap_; // lambda in MD overlapping FE nodes
-    DENS_MAT _lambdaOld_; // lambda from previous iteration
-    DENS_MAT _rhsOverlap_; // normal RHS vector mapped to overlap nodes
-    DENS_VEC _rhsTotal_; // normal + 2nd order RHS for the iteration loop
 
   private:
 
     // DO NOT define this
     ThermostatGlcFs();
 
   };
 
   /**
-   *  @class  ThermostatFlux
+   *  @class  ThermostatSolverFlux
    *  @brief  Class enforces GLC on atomic forces based on FE power when using fractional step time integration
    */
 
-  class ThermostatFlux : public ThermostatGlcFs {
+  class ThermostatSolverFlux : public ThermostatFsSolver {
   
   public:
   
-    ThermostatFlux(Thermostat * thermostat,
-                   const std::string & regulatorPrefix = "");
+    ThermostatSolverFlux(AtomicRegulator * thermostat,
+                         int lambdaMaxIterations,
+                         const std::string & regulatorPrefix = "");
         
-    virtual ~ThermostatFlux() {};
+    virtual ~ThermostatSolverFlux() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
+       
+  protected:
+
+    // methods
+    /** sets up the transfer which is the set of nodes being regulated */
+    virtual void construct_regulated_nodes();
+
+  private:
+
+    // DO NOT define this
+    ThermostatSolverFlux();
+
+  };
+
+  /**
+   *  @class  ThermostatIntegratorFlux
+   *  @brief  Class integrates GLC on atomic forces based on FE power when using fractional step time integration
+   */
+
+  class ThermostatIntegratorFlux : public ThermostatGlcFs {
+  
+  public:
+  
+    ThermostatIntegratorFlux(AtomicRegulator * thermostat,
+                             int lambdaMaxIterations,
+                             const std::string & regulatorPrefix = "");
+        
+    virtual ~ThermostatIntegratorFlux() {};
 
     /** pre-run initialization of method data */
     virtual void initialize();
        
   protected:
 
     /** sets up appropriate rhs for thermostat equations */
     virtual void set_thermostat_rhs(DENS_MAT & rhs,
                                     double dt);
 
     /** add contributions from thermostat to FE energy */
     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower,
                                DENS_MAT & deltaEnergy,
                                double dt);
 
-    /** sets up the transfer which is the set of nodes being regulated */
-    virtual void construct_regulated_nodes();
-
     // data
     /** reference to ATC sources coming from prescribed data, AtC coupling, and extrinsic coupling */
     DENS_MAN & heatSource_;
 
   private:
 
     // DO NOT define this
-    ThermostatFlux();
+    ThermostatIntegratorFlux();
 
   };
 
   /**
-   *  @class  ThermostatFixed
+   *  @class  ThermostatSolverFixed
    *  @brief  Class enforces GLC on atomic forces based on FE power when using fractional step time integration
    */
 
-  class ThermostatFixed : public ThermostatGlcFs {
+  class ThermostatSolverFixed : public ThermostatFsSolver {
   
   public:
   
-    ThermostatFixed(Thermostat * thermostat,
-                    const std::string & regulatorPrefix = "");
+    ThermostatSolverFixed(AtomicRegulator * thermostat,
+                          int lambdaMaxIterations,
+                          const std::string & regulatorPrefix = "");
+        
+    virtual ~ThermostatSolverFixed() {};
+
+    /** instantiate all needed data */
+    virtual void construct_transfers();
+       
+  protected:
+
+    // methods
+    /** sets up the transfer which is the set of nodes being regulated */
+    virtual void construct_regulated_nodes();
+
+   private:
+
+    // DO NOT define this
+    ThermostatSolverFixed();
+
+  };
+
+  /**
+   *  @class  ThermostatIntegratorFixed
+   *  @brief  Class integrates GLC on atomic forces based on FE power when using fractional step time integration
+   */
+
+  class ThermostatIntegratorFixed : public ThermostatGlcFs {
+  
+  public:
+  
+    ThermostatIntegratorFixed(AtomicRegulator * thermostat,
+                              int lambdaMaxIterations,
+                              const std::string & regulatorPrefix = "");
         
-    virtual ~ThermostatFixed() {};
+    virtual ~ThermostatIntegratorFixed() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
         
     /** applies thermostat to atoms in the predictor phase */
     virtual void apply_pre_predictor(double dt);
 
     /** applies thermostat to atoms in the pre-corrector phase */
     virtual void apply_pre_corrector(double dt);
 
     /** applies thermostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
 
     /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields)
       {boundaryFlux_[TEMPERATURE] = 0.;};
 
     /** determine if local shape function matrices are needed */
     virtual bool use_local_shape_functions() const {return atomicRegulator_->use_localized_lambda();};
         
   protected:
 
     // methods
     /** initialize data for tracking the change in nodal atomic temperature */
     virtual void initialize_delta_nodal_atomic_energy(double dt);
 
     /** compute the change in nodal atomic temperature */
     virtual void compute_delta_nodal_atomic_energy(double dt);
 
     /** sets up appropriate rhs for thermostat equations */
     virtual void set_thermostat_rhs(DENS_MAT & rhs,
                                     double dt);
 
     /** add contributions from thermostat to FE energy */
     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower,
                                DENS_MAT & deltaEnergy,
                                double dt);
 
     /* sets up and solves the linear system for lambda */
     virtual void compute_lambda(double dt,
                                 bool iterateSolution = true);
 
     /** flag for halving the applied force to mitigate numerical errors */
     bool halve_force();
 
-    /** sets up the transfer which is the set of nodes being regulated */
-    virtual void construct_regulated_nodes();
-
     // data
     /** change in FE energy over a timestep */
     DENS_MAT deltaFeEnergy_;
 
     /** initial FE energy used to compute change */
     DENS_MAT initialFeEnergy_;
 
     /** change in restricted atomic FE energy over a timestep */
     DENS_MAT deltaNodalAtomicEnergy_;
 
     /** intial restricted atomic FE energy used to compute change */
     DENS_MAT initialNodalAtomicEnergy_;
 
     /** filtered nodal atomic energy */
     DENS_MAN nodalAtomicEnergyFiltered_;
 
     /** forces depending on predicted velocities for correct updating with fixed nodes */
     AtomicThermostatForce * atomThermostatForcesPredVel_;
 
     /** coefficient to account for effect of time filtering on rhs terms */
     double filterCoefficient_;
 
     /** kinetic energy multiplier in total energy (used for temperature expression) */
     double keMultiplier_;
 
     // workspace
     DENS_MAT _tempNodalAtomicEnergyFiltered_; // stores filtered energy change in atoms for persistence during predictor
 
   private:
 
     // DO NOT define this
-    ThermostatFixed();
+    ThermostatIntegratorFixed();
 
   };
 
   /**
-   *  @class  ThermostatFluxFiltered
-   *  @brief  Class enforces GLC on atomic forces based on FE power when using fractional step time integration
+   *  @class  ThermostatIntegratorFluxFiltered
+   *  @brief  Class integrates GLC on atomic forces based on FE power when using fractional step time integration
    *          in conjunction with time filtering
    */
 
-  class ThermostatFluxFiltered : public ThermostatFlux {
+  class ThermostatIntegratorFluxFiltered : public ThermostatIntegratorFlux {
   
   public:
   
-    ThermostatFluxFiltered(Thermostat * thermostat,
-                           const std::string & regulatorPrefix = "");
+    ThermostatIntegratorFluxFiltered(AtomicRegulator * thermostat,
+                                     int lambdaMaxIterations,
+                                     const std::string & regulatorPrefix = "");
         
-    virtual ~ThermostatFluxFiltered() {};
+    virtual ~ThermostatIntegratorFluxFiltered() {};
 
     /** pre-run initialization of method data */
     virtual void initialize();
 
     /** applies thermostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
        
   protected:
 
     /** sets up appropriate rhs for thermostat equations */
     virtual void set_thermostat_rhs(DENS_MAT & rhs,
                                     double dt);
 
     /** add contributions from thermostat to FE energy */
     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower,
                                DENS_MAT & deltaEnergy,
                                double dt);
 
     // data
     /** heat source time history required to get instantaneous heat sources */
     DENS_MAT heatSourceOld_;
     DENS_MAT instantHeatSource_;
     DENS_MAT timeStepSource_;
 
   private:
 
     // DO NOT define this
-    ThermostatFluxFiltered();
+    ThermostatIntegratorFluxFiltered();
 
   };
 
   /**
-   *  @class  ThermostatFixedFiltered
+   *  @class  ThermostatIntegratorFixedFiltered
    *  @brief  Class for thermostatting using the temperature matching constraint and is compatible with
  the fractional step time-integration with time filtering
    */
   
-  class ThermostatFixedFiltered : public ThermostatFixed {
+  class ThermostatIntegratorFixedFiltered : public ThermostatIntegratorFixed {
   
   public:
   
-    ThermostatFixedFiltered(Thermostat * thermostat,
-                            const std::string & regulatorPrefix = "");
+    ThermostatIntegratorFixedFiltered(AtomicRegulator * thermostat,
+                                      int lambdaMaxIterations,
+                                      const std::string & regulatorPrefix = "");
         
-    virtual ~ThermostatFixedFiltered() {};
+    virtual ~ThermostatIntegratorFixedFiltered() {};
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
         
   protected:
 
     // methods
     /** initialize data for tracking the change in nodal atomic temperature */
     virtual void initialize_delta_nodal_atomic_energy(double dt);
 
     /** compute the change in nodal atomic temperature */
     virtual void compute_delta_nodal_atomic_energy(double dt);
 
     /** sets up appropriate rhs for thermostat equations */
     virtual void set_thermostat_rhs(DENS_MAT & rhs,
                                     double dt);
 
     /** add contributions from thermostat to temperature for uncoupled nodes */
     virtual void add_to_energy(const DENS_MAT & nodalLambdaPower,
                                DENS_MAT & deltaEnergy,
                                double dt);
 
   private:
 
     // DO NOT define this
-    ThermostatFixedFiltered();
+    ThermostatIntegratorFixedFiltered();
 
   };
 
   /**
    *  @class  ThermostatFluxFixed
    *  @brief  Class for thermostatting using the temperature matching constraint one one set of nodes and the flux matching constraint on another
    */
 
   class ThermostatFluxFixed : public RegulatorMethod {
 
   public:
 
-    ThermostatFluxFixed(Thermostat * thermostat,
+    ThermostatFluxFixed(AtomicRegulator * thermostat,
+                        int lambdaMaxIterations,
                         bool constructThermostats = true);
         
     virtual ~ThermostatFluxFixed();
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** pre-run initialization of method data */
     virtual void initialize();
 
     /** applies thermostat to atoms in the predictor phase */
     virtual void apply_pre_predictor(double dt);
 
     /** applies thermostat to atoms in the pre-corrector phase */
     virtual void apply_pre_corrector(double dt);
 
     /** applies thermostat to atoms in the post-corrector phase */
     virtual void apply_post_corrector(double dt);
     
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
 
     /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields)
       {thermostatBcs_->compute_boundary_flux(fields);};
 
   protected:
 
     // data
     /** thermostat for imposing the fluxes */
-    ThermostatFlux * thermostatFlux_;
+    ThermostatIntegratorFlux * thermostatFlux_;
 
     /** thermostat for imposing fixed nodes */
-    ThermostatFixed * thermostatFixed_;
+    ThermostatIntegratorFixed * thermostatFixed_;
 
     /** pointer to whichever thermostat should compute the flux, based on coupling method */
     ThermostatGlcFs * thermostatBcs_;
 
   private:
 
     // DO NOT define this
     ThermostatFluxFixed();
   };
 
   /**
    *  @class  ThermostatFluxFixedFiltered
    *  @brief  Class for thermostatting using the temperature matching constraint one one set of nodes and the flux matching constraint on another with time filtering
    */
 
   class ThermostatFluxFixedFiltered : public ThermostatFluxFixed {
 
   public:
 
-    ThermostatFluxFixedFiltered(Thermostat * thermostat);
+    ThermostatFluxFixedFiltered(AtomicRegulator * thermostat,
+                                int lambdaMaxIterations);
         
     virtual ~ThermostatFluxFixedFiltered(){};
 
   private:
 
     // DO NOT define this
     ThermostatFluxFixedFiltered();
 
   };
 
   /**
    *  @class  ThermostatGlc
    *  @brief  Class for thermostat algorithms based on Gaussian least constraints (GLC)
    */
   
   class ThermostatGlc : public ThermostatShapeFunction {
   
   public:
   
-    ThermostatGlc(Thermostat * thermostat);
+    ThermostatGlc(AtomicRegulator * thermostat);
         
     virtual ~ThermostatGlc() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
   protected:
 
     // methods
     /** apply forces to atoms */
     virtual void apply_to_atoms(PerAtomQuantity<double> * atomicVelocity, 
                                 const DENS_MAT & lambdaForce,
                                 double dt);
 
     // member data
     /** pointer to a time filtering object */
     TimeFilter * timeFilter_;
 
     /** filtered lambda power */
     DENS_MAN * lambdaPowerFiltered_;
 
     /** atomic force induced by lambda */
     PerAtomQuantity<double> * atomThermostatForces_;
 
     /** pointer to access prescribed data for fixed nodes */
     PrescribedDataManager * prescribedDataMgr_;
 
     /** pointer to atom masses */
     FundamentalAtomQuantity * atomMasses_;
 
     /** workspace variables */
     DENS_MAT _velocityDelta_;
 
   private:
 
     // DO NOT define this
     ThermostatGlc();
 
   };
 
   /**
    *  @class  ThermostatPowerVerlet
    *  @brief  Class for thermostatting using the heat flux matching constraint and is compatible with
  the Gear time-integration
    */
   
   class ThermostatPowerVerlet : public ThermostatGlc {
   
   public:
 
-    ThermostatPowerVerlet(Thermostat * thermostat);
+    ThermostatPowerVerlet(AtomicRegulator * thermostat);
         
     virtual ~ThermostatPowerVerlet() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
     
     /** pre-run initialization of method data */
     virtual void initialize();
         
     /** applies thermostat to atoms in the predictor phase */
     virtual void apply_pre_predictor(double dt);
 
     /** applies thermostat to atoms in the pre-corrector phase */
     virtual void apply_pre_corrector(double dt);
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
 
     /** final tasks of a run */
     virtual void finish();
 
     /** determine if local shape function matrices are needed */
     virtual bool use_local_shape_functions() const {return (!(atomicRegulator_->use_lumped_lambda_solve()) && atomicRegulator_->use_localized_lambda());};
 
   protected:
 
     /** nodal temperature rate of change */
     DENS_MAN & nodalTemperatureRoc_;
 
     /** reference to ATC sources coming from prescribed data, AtC coupling, and extrinsic coupling */
     DENS_MAN & heatSource_;
 
     /** pointer to nodal atomic power */
     DENS_MAN * nodalAtomicPower_;
 
     /** power applied to each atom by lambda force */
     AtfShapeFunctionRestriction * nodalAtomicLambdaPower_;
 
     /** workspace variables */
     DENS_MAT _rhs_;
 
     /** sets up and solves thermostat equations */
     virtual void compute_thermostat(double dt);
 
     /** sets up appropriate rhs for thermostat equations */
     virtual void set_thermostat_rhs(DENS_MAT & rhs_nodes);
 
     /** add contributions (if any) to the finite element right-hand side */
     virtual void add_to_rhs(FIELDS & rhs);
 
     // workspace
     DENS_MAT _nodalAtomicLambdaPowerOut_; // power induced by lambda in output format
 
   private:
 
     // DO NOT define this
     ThermostatPowerVerlet();
 
   };
   
   /**
    *  @class  ThermostatHooverVerlet
    *  @brief  Classfor thermostatting using the temperature matching constraint and is compatible with
  Gear time-integration 
    */
   
   class ThermostatHooverVerlet : public ThermostatPowerVerlet {
   
   public:
 
-    ThermostatHooverVerlet(Thermostat * thermostat);
+    ThermostatHooverVerlet(AtomicRegulator * thermostat);
         
     virtual ~ThermostatHooverVerlet() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
 
     /** final tasks of a run */
     virtual void finish() {};
 
     /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields)
       {boundaryFlux_[TEMPERATURE] = 0.;};
 
   protected:
 
     /** lambda coupling parameter for hoover thermostat */
     DENS_MAN * lambdaHoover_;
 
     /** workspace variables */
     DENS_MAT _myNodalLambdaPower_;
 
     /** sets up and solves thermostat equations */
     virtual void compute_thermostat(double dt);
 
     /** sets up Hoover component of the thermostat */
     void set_hoover_rhs(DENS_MAT & rhs);
 
     /** add Hoover contributions to lambda power */
     void add_to_lambda_power(const DENS_MAT & myLambdaForce,
                              double dt);
 
     /** power applied to each atom by hoover lambda force */
     AtfShapeFunctionRestriction * nodalAtomicHooverLambdaPower_;
 
     /** add contributions (if any) to the finite element right-hand side */
     virtual void add_to_rhs(FIELDS & rhs);
 
   private:
 
     // DO NOT implement this
     ThermostatHooverVerlet();
 
   };
 
   /**
    *  @class  ThermostatPowerVerletFiltered
    *  @brief  Class for thermostatting using the heat flux matching constraint and is compatible with
  Gear time-integration with time filtering
    */
   
   class ThermostatPowerVerletFiltered : public ThermostatPowerVerlet {
   
   public:
 
-    ThermostatPowerVerletFiltered(Thermostat * thermostat);
+    ThermostatPowerVerletFiltered(AtomicRegulator * thermostat);
         
     virtual ~ThermostatPowerVerletFiltered(){};
 
     /** get data for output */
     virtual void output(OUTPUT_LIST & outputData);
 
     /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields);
 
   protected:
 
     /** sets up appropriate rhs for thermostat equations */
     virtual void set_thermostat_rhs(DENS_MAT & rhs_nodes);
 
     /** add contributions (if any) to the finite element right-hand side */
     virtual void add_to_rhs(FIELDS & rhs);
 
     /** nodal temperature 2nd rate of change (i.e. second time derivative) */
     DENS_MAN & nodalTemperature2Roc_;
 
     /** reference to ATC rate of change sources coming from prescribed data, AtC coupling, and extrinsic coupling */
     DENS_MAN heatSourceRoc_;
 
     /** references to ATC field rates of changing for inverting the filtered heat sources */
     FIELDS & fieldsRoc_;
    
     /** flux rate of changes for inverting filtered fluxes */
     FIELDS fluxRoc_;
 
     /** time scale for the time filter */
     double filterScale_;
 
   private:
 
     // DO NOT define this
     ThermostatPowerVerletFiltered();
 
   };
 
   /**
    *  @class  ThermostatHooverVerletFiltered
    *  @brief  Class for thermostatting using the temperature matching constraint and is compatible with
  Gear time-integration with time filtering
    */
   
   class ThermostatHooverVerletFiltered : public ThermostatPowerVerletFiltered {
   
   public:
 
-    ThermostatHooverVerletFiltered(Thermostat * thermostat);
+    ThermostatHooverVerletFiltered(AtomicRegulator * thermostat);
         
     virtual ~ThermostatHooverVerletFiltered() {};
 
     /** instantiate all needed data */
     virtual void construct_transfers();
     
     /** final tasks of a run */
     virtual void finish() {};
     
     /** compute boundary flux, requires thermostat input since it is part of the coupling scheme */
     virtual void compute_boundary_flux(FIELDS & fields)
       {boundaryFlux_[TEMPERATURE] = 0.;};
 
   protected:
 
     /** lambda coupling parameter for hoover thermostat */
     DENS_MAN * lambdaHoover_;
 
     /** workspace variables */
     DENS_MAT _myNodalLambdaPower_;
 
     /** sets up and solves thermostat equations */
     virtual void compute_thermostat(double dt);
 
     /** sets up Hoover component of the thermostat */
     void set_hoover_rhs(DENS_MAT & rhs);
 
     /** add Hoover contributions to lambda power */
     void add_to_lambda_power(const DENS_MAT & myLambdaForce,
                              double dt);
 
     /** power applied to each atom by hoover lambda force */
     DENS_MAN * nodalAtomicHooverLambdaPower_;
 
     /** add contributions (if any) to the finite element right-hand side */
     virtual void add_to_rhs(FIELDS & rhs);
 
   private:
 
     // DO NOT implement this
     ThermostatHooverVerletFiltered();
 
   };
 
 };
 
 #endif
diff --git a/lib/atc/TimeIntegrator.h b/lib/atc/TimeIntegrator.h
index 22e4b716f..2753386d0 100644
--- a/lib/atc/TimeIntegrator.h
+++ b/lib/atc/TimeIntegrator.h
@@ -1,380 +1,382 @@
 #ifndef TIME_INTEGRATOR_H
 #define TIME_INTEGRATOR_H
 
 #include "MatrixLibrary.h"
 #include "TimeFilter.h"
 #include "ATC_TypeDefs.h"
 
 namespace ATC {
 
   // forward declarations
   class ATC_Method;
   class ATC_Coupling;
   class TimeIntegrationMethod;
 
   /**
    *  @class  AtomTimeIntegrator
    *  @brief  Base class for various time integrators for atomic quantities (replacing other lammps fixes)
    */
 
   class AtomTimeIntegrator {
   
   public:
 
     // constructor
     AtomTimeIntegrator(){};
 
     // destructor
     virtual ~AtomTimeIntegrator(){};
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers(){};
         
    /** Predictor phase, Verlet first step for velocity */
     virtual void init_integrate_velocity(double dt){};
 
     /** Predictor phase, Verlet first step for position */
     virtual void init_integrate_position(double dt){};
 
     /** Corrector phase, Verlet second step for velocity */
     virtual void final_integrate(double dt){};
 
   };
 
   /**
    *  @class  AtomTimeIntegratorType
    *  @brief  class for applying velocity-verlet based on atom type
    */
 
   class AtomTimeIntegratorType : public AtomTimeIntegrator {
   
   public:
 
     // constructor
     AtomTimeIntegratorType(ATC_Method * atc, AtomType atomType);
 
     // destructor
     virtual ~AtomTimeIntegratorType(){};
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers();
         
    /** Predictor phase, Verlet first step for velocity */
     virtual void init_integrate_velocity(double dt);
 
     /** Predictor phase, Verlet first step for position */
     virtual void init_integrate_position(double dt);
 
     /** Corrector phase, Verlet second step for velocity */
     virtual void final_integrate(double dt);
 
   protected:
 
     /** pointer to atc object */
     ATC_Method * atc_;
 
     /** atom type this is applied to */
     AtomType atomType_;
 
     /** atomic masses */
     DENS_MAN * mass_;
 
     /** atomic positions */
     DENS_MAN * position_;
 
     /** atomic velocities */
     DENS_MAN * velocity_;
 
     /** atomic forces */
     DENS_MAN * force_;
 
     // workspace
     DENS_MAT _deltaQuantity_;
 
   private:
 
     // DO NOT define this
     AtomTimeIntegratorType();
 
   };
 
   /**
    *  @class  TimeIntegrator
    *  @brief  Base class for various time integrators for FE quantities
    */
   
   class TimeIntegrator {
   
   public:
 
     /** types of time integration */
     enum TimeIntegrationType {
+      NONE=0,
       STEADY,
       VERLET,
       GEAR,
       FRACTIONAL_STEP,
       EXPLICIT,
       IMPLICIT,
-      CRANK_NICOLSON
+      CRANK_NICOLSON,
+      DIRECT
     };
       
     // constructor
     TimeIntegrator(ATC_Coupling * atc,
                    TimeIntegrationType timeIntegrationType = STEADY);
         
     // destructor
     virtual ~TimeIntegrator();
         
     /** parser/modifier */
     virtual bool modify(int narg, char **arg){return false;};
 
     /** create objects to implement requested numerical method */
     virtual void construct_methods() = 0;
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers();
 
     /** pre time integration initialization of data */
     virtual void initialize();
 
     /** flag if reset is needed */
     bool need_reset() const {return needReset_;};
         
     // time step methods, corresponding to ATC_Coupling
     /** first part of pre_initial_integrate */
     virtual void pre_initial_integrate1(double dt);
     /** second part of pre_initial_integrate */
     virtual void pre_initial_integrate2(double dt);
 
     /** first part of post_initial_integrate */
     virtual void post_initial_integrate1(double dt);
     /** second part of post_initial_integrate */
     virtual void post_initial_integrate2(double dt);
         
     /** first part of pre_final_integrate */
     virtual void pre_final_integrate1(double dt);
     /** second part of pre_final_integrate */
     virtual void pre_final_integrate2(double dt);
         
     /** first part of post_final_integrate */
     virtual void post_final_integrate1(double dt);
     /** second part of post_final_integrate */
     virtual void post_final_integrate2(double dt);
     /** third part of post_final_integrate */
     virtual void post_final_integrate3(double dt);
 
     /** checks to see if first RHS computation is needed */
     virtual bool has_final_predictor();
     /** checks to see if second RHS computation is needed */
     virtual bool has_final_corrector();
 
     /** adds any contributions from time integrator to RHS */
     virtual void add_to_rhs();
     /** post processing step prior to output */
     virtual void post_process();
     /** add output data */
     virtual void output(OUTPUT_LIST & outputData);
     /** pack persistent fields */
     virtual void pack_fields(RESTART_LIST & data);
 
     /** finalize any data */
     virtual void finish();
 
     // Member data access
     /** access to time integration type */
     TimeIntegrationType time_integration_type() const
     { return timeIntegrationType_; };
 
     /** access to ATC Transfer object */
     ATC_Coupling * atc() {return atc_;};
 
     /** access to time filter object */
     TimeFilter * time_filter() {return timeFilter_;};
 
     /** access to time filter manager object */
     TimeFilterManager * time_filter_manager() {return timeFilterManager_;};
 
     /** force the integrator to be reset */
     void force_reset() {needReset_ = true;};
 
     /** force the integrator not to be reset */
     void force_no_reset() {needReset_ = false;};
 
   protected:
 
     /** pointer to time integrator method */
     TimeIntegrationMethod * timeIntegrationMethod_;
         
     /** pointer to access ATC methods */
     ATC_Coupling * atc_;
         
     /** time filter for specific updates */
     TimeFilter * timeFilter_;
 
     /** time filter manager for getting time filtering info */
     TimeFilterManager * timeFilterManager_;
         
     /** type of integration scheme being used */
     TimeIntegrationType timeIntegrationType_;
   
     /** flat to reset data */
     bool needReset_;
 
   private:
 
     // DO NOT define this
     TimeIntegrator();
 
   };
 
   /**
    *  @class  TimeIntegrationMethod
    *  @brief  Base class for time integration methods which update FE quantities
    */
 
   class TimeIntegrationMethod {
   
   public:
   
     // constructor
     TimeIntegrationMethod(TimeIntegrator * timeIntegrator);
         
     // destructor
     virtual ~TimeIntegrationMethod(){};
 
     /** create and get necessary transfer operators */
     virtual void construct_transfers(){};
     /** pre time integration */
     virtual void initialize(){};
         
     // time step methods, corresponding to ATC_Coupling and TimeIntegrator
     /** first part of pre_initial_integrate */
     virtual void pre_initial_integrate1(double dt){};
     /** second part of pre_initial_integrate */
     virtual void pre_initial_integrate2(double dt){};
 
     /** first part of post_initial_integrate */
     virtual void post_initial_integrate1(double dt){};
     /** second part of post_initial_integrate */
     virtual void post_initial_integrate2(double dt){};
         
     /** first part of pre_final_integrate */
     virtual void pre_final_integrate1(double dt){};
     /** second part of pre_final_integrate */
     virtual void pre_final_integrate2(double dt){};
         
     /** first part of post_final_integrate */
     virtual void post_final_integrate1(double dt){};
     /** second part of post_final_integrate */
     virtual void post_final_integrate2(double dt){};
     /** third part of post_final_integrate */
     virtual void post_final_integrate3(double dt){};
 
     /** checks to see if first RHS computation is needed */
     virtual bool has_final_predictor() {return false;};
     /** checks to see if second RHS computation is needed */
     virtual bool has_final_corrector() {return false;};
 
     /** adds any contributions from time integrator to RHS */
     virtual void add_to_rhs() {};
     /** post processing step */
     virtual void post_process(){};
     /** add output data */
     virtual void output(OUTPUT_LIST & outputData){};
     /** pack persistent fields */
     virtual void pack_fields(RESTART_LIST & data){};
 
     /** finalize any states */
     virtual void finish(){};
         
   protected:
 
     /** owning time integrator */
     TimeIntegrator * timeIntegrator_;
 
     /** associated ATC transfer object */
     ATC_Coupling * atc_;
 
   private:
 
     // DO NOT define this
     TimeIntegrationMethod();
 
   };
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  time integration functions not associated
   //  with any particular class
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   inline void gear1_4_predict(MATRIX & f,
                               MATRIX & dot_f,
                               MATRIX & ddot_f,
                               const MATRIX & dddot_f,
                               double dt)
   // 4th order Gear integrator for 1rst order ODE predictor step
   {
     f      = f + dot_f*dt + ddot_f*(1./2.*dt*dt) + dddot_f*(1./6.*dt*dt*dt);
     dot_f  = dot_f + ddot_f*dt+dddot_f*(1./2.*dt*dt);
     ddot_f = ddot_f + dddot_f*dt;
   };
 
   inline void gear1_3_predict(MATRIX & f,
                               MATRIX & dot_f,
                               const MATRIX & ddot_f,
                               double dt)
   // 3rd order Gear integrator for 1rst order ODE predictor step
   {
     f      = f + dot_f*dt + ddot_f*(1./2.*dt*dt);
     dot_f  = dot_f + ddot_f*dt;
   };
 
   inline void gear1_4_correct(MATRIX & f,
                               MATRIX & dot_f,
                               MATRIX & ddot_f,
                               MATRIX & dddot_f,
                               const MATRIX & R_f,
                               double dt)
   // 4th order Gear integrator for 1rst order ODE corrector step
   {
     f       = f       + (3./8.)*R_f;
     dot_f   = dot_f   + (1./dt)*R_f;
     ddot_f  = ddot_f  + (3./2./dt/dt)*R_f;
     dddot_f = dddot_f + (1./dt/dt/dt)*R_f;
   };
 
   inline void gear1_3_correct(MATRIX & f,
                               MATRIX & dot_f,
                               MATRIX & ddot_f,
                               const MATRIX & R_f,
                               double dt)
   // 3rd order Gear integrator for 1rst order ODE corrector step
   {
     f      = f      + (5./12.)*R_f;
     dot_f  = dot_f  + (1./dt)*R_f;
     ddot_f = ddot_f + (1./dt/dt)*R_f;
   };
   
   inline void explicit_1(MATRIX & f,
                          const MATRIX & dot_f,
                          double dt)
   // 1rst order explict ODE update
   {
     f = f + dt*dot_f;
   };
 
   inline void explicit_2(MATRIX & f,
                          const MATRIX & dot_f,
                          const MATRIX & ddot_f,
                          double dt)
   // 2nd order explict ODE update
   {
     f = f + dt*dot_f + .5*dt*dt*ddot_f;
   };
 
 };
 
 #endif
 
diff --git a/lib/atc/TransferLibrary.cpp b/lib/atc/TransferLibrary.cpp
index f4cdb172a..a6bba5ca2 100644
--- a/lib/atc/TransferLibrary.cpp
+++ b/lib/atc/TransferLibrary.cpp
@@ -1,2008 +1,2008 @@
 // ATC headers
 #include "TransferLibrary.h"
 #include "ATC_Coupling.h"
 #include "PrescribedDataManager.h"
 #include "LinearSolver.h"
 #include "PerAtomQuantityLibrary.h"
 #include "KernelFunction.h"
 #include "MoleculeSet.h"
 
 //#include <typeinfo>
 #include <set>
 #include <sstream>
 #include <utility>
 #include <vector>
 
 using std::set;
 using std::map;
 using std::string;
 using std::stringstream;
 using std::pair;
 using std::vector;
 
 namespace ATC {
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class NodalAtomVolume
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   NodalAtomVolume::NodalAtomVolume(ATC_Method * atc,
                                    SPAR_MAN * shapeFunction) :
     atc_(atc),
     shapeFunction_(shapeFunction),
     lammpsInterface_(atc->lammps_interface()),
     feEngine_(atc->fe_engine()),
     tol_(1.e-10) 
   {
     shapeFunction_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void NodalAtomVolume::reset_quantity() const
   {
     // solve equation \sum_a N_Ia \sum_J N_Ja dV_J = \int_Omega N_I dV
     // form left-hand side
     int nNodes = shapeFunction_->nCols();
     SPAR_MAT lhs(nNodes,nNodes);
     atc_->compute_consistent_md_mass_matrix(shapeFunction_->quantity(),lhs);
 
     // form right-hand side
     _rhsMatrix_.resize(nNodes,nNodes);
     feEngine_->compute_lumped_mass_matrix(_rhsMatrix_);
     _rhs_.resize(nNodes);
     _rhs_.copy(_rhsMatrix_.ptr(),_rhsMatrix_.size(),1);
 
     // change entries for all entries if no atoms in shape function support
     double totalVolume = _rhs_.sum();
     double averageVolume = averaging_operation(totalVolume);
 
     _scale_.resize(nNodes);
     for (int i = 0; i < nNodes; i++) {
       if ((abs(lhs(i,i)) > 0.))  
         _scale_(i) = 1.;
       else
         _scale_(i) = 0.;
     }
     lhs.row_scale(_scale_);
     for (int i = 0; i < nNodes; i++) {
       if (_scale_(i) < 0.5) {
         lhs.set(i,i,1.);
         _rhs_(i) = averageVolume;
       }
     }
     lhs.compress();
     
     // solve equation
     LinearSolver solver(lhs, ATC::LinearSolver::ITERATIVE_SOLVE_SYMMETRIC, true);
     solver.set_max_iterations(lhs.nRows());
     solver.set_tolerance(tol_);
     quantity_.reset(nNodes,1);
     CLON_VEC tempQuantity(quantity_,CLONE_COL,0);
     solver.solve(tempQuantity,_rhs_);
   }
 
   //--------------------------------------------------------
   //  averaging_operation
   //--------------------------------------------------------
   double NodalAtomVolume::averaging_operation(const double totalVolume) const
   {
     int nLocal[1] = {shapeFunction_->nRows()};
     int nGlobal[1] = {0};
     lammpsInterface_->int_allsum(nLocal,nGlobal,1);
     return totalVolume/(double(nGlobal[0]));
   }
 
   //--------------------------------------------------------
   //  overloading operation to get number of rows
   //--------------------------------------------------------
   int NodalAtomVolume::nRows() const
   {
     return atc_->num_nodes();
   }
 
   //--------------------------------------------------------
   //  overloading operation to get number of columns
   //--------------------------------------------------------
   int NodalAtomVolume::nCols() const
   {
     return 1;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class NodalVolume
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  averaging_operation
   //--------------------------------------------------------
   double NodalVolume::averaging_operation(const double totalVolume) const
   {
     int nNodes = shapeFunction_->nCols();
     return totalVolume/nNodes;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class NodalAtomVolumeElement
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   NodalAtomVolumeElement::NodalAtomVolumeElement(ATC_Method * atc,
                                                  SPAR_MAN * shapeFunction,
                                                  PerAtomQuantity<int> * atomElement) :
     atc_(atc),
     shapeFunction_(shapeFunction),
     atomElement_(atomElement),
     feEngine_(atc->fe_engine()),
     tol_(1.e-10) 
   {
     shapeFunction_->register_dependence(this);
     if (!atomElement_) {
       InterscaleManager & interscaleManager = atc_->interscale_manager();
       atomElement_ = interscaleManager.per_atom_int_quantity("AtomElement");
     }
     atomElement_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void NodalAtomVolumeElement::reset_quantity() const
   {
     // Using analyses by G. Wagner and J. Templeton, weights ~ phi*M^{-1}*V
     //  where phi are the dimensionless shape/weighting functions, 
     //  M is the "mass" matrix M_IJ,
     //  V is the vector of nodal and element volumes
     //
     //
     // form atom-element shape functions and elemental volumes
     const FE_Mesh * feMesh = feEngine_->fe_mesh();
     int nElts = feMesh->num_elements();
     int nNodes = shapeFunction_->nCols();
     int nLocal = shapeFunction_->nRows();
 
     // form "mass" matrix M_IJ (I,J = 0, 1, ..., nNodes+nElts-1)
     int neSize = nNodes+nElts;
     const INT_ARRAY & atomElement(atomElement_->quantity());
     SPAR_MAT nodEltShpFcnMatrix(nLocal,neSize);
     const SPAR_MAT & shapeFunction(shapeFunction_->quantity());
     for(int a = 0; a < nLocal; a++) {
       for(int I = 0; I < nNodes; I++) {
         nodEltShpFcnMatrix.set(a,I,shapeFunction(a,I));
       }
       int thisCol = nNodes+atomElement(a,0);
       nodEltShpFcnMatrix.set(a,thisCol,1);
     }
       
     SPAR_MAT neMassMatrix(neSize,neSize);
     atc_->compute_consistent_md_mass_matrix(nodEltShpFcnMatrix,neMassMatrix);
       
     // form vector of nodal and elemental volumes 
     _nodeVolumesMatrix_.resize(nNodes,nNodes);
     feEngine_->compute_lumped_mass_matrix(_nodeVolumesMatrix_);
     _nodeVolumes_.resize(nNodes);
     _nodeVolumes_.copy(_nodeVolumesMatrix_.ptr(),_nodeVolumesMatrix_.size(),1);
     DENS_VEC _nodeElementVolumes_(neSize);
     for(int I = 0; I < nNodes; I++) {
       _nodeElementVolumes_(I) = _nodeVolumes_(I);
     }
     double averageEltVolume = 0.0;
     for(int E = 0; E < nElts; E++) {
       double minx, maxx, miny, maxy, minz, maxz;
       feMesh->element_coordinates(E,_nodalCoords_);
       minx = _nodalCoords_(0,0); maxx = _nodalCoords_(0,0);
       miny = _nodalCoords_(1,0); maxy = _nodalCoords_(1,0);
       minz = _nodalCoords_(2,0); maxz = _nodalCoords_(2,0);
       for (int j = 1; j < _nodalCoords_.nCols(); ++j) {
         if (_nodalCoords_(0,j)<minx) minx = _nodalCoords_(0,j);
         if (_nodalCoords_(0,j)>maxx) maxx = _nodalCoords_(0,j);
         if (_nodalCoords_(1,j)<miny) miny = _nodalCoords_(1,j);
         if (_nodalCoords_(1,j)>maxy) maxy = _nodalCoords_(1,j);
         if (_nodalCoords_(2,j)<minz) minz = _nodalCoords_(2,j);
         if (_nodalCoords_(2,j)>maxz) maxz = _nodalCoords_(2,j);
       }
       _nodeElementVolumes_(nNodes+E) = (maxx-minx)*(maxy-miny)*(maxz-minz);
       averageEltVolume += (maxx-minx)*(maxy-miny)*(maxz-minz);
     }
     averageEltVolume /= nElts;
       
     // correct entries of mass matrix if no atoms in shape function support
     double totalNodalVolume = _nodeVolumes_.sum();
     double averageNodalVolume = totalNodalVolume/nNodes;
     _scale_.resize(neSize);
     for (int i = 0; i < neSize; i++) {
       if ((abs(neMassMatrix(i,i)) > 0.)) { 
         _scale_(i) = 1.;
       } else {
         printf("No atoms are in support of node/element %i\n",i);
         _scale_(i) = 0.;
       }
     }
     neMassMatrix.row_scale(_scale_);
     for (int i = 0; i < neSize; i++) {
       if (_scale_(i) < 0.5) {
         neMassMatrix.set(i,i,1.);
         if (i < nNodes) { 
           _nodeElementVolumes_(i) = averageNodalVolume;
         } else {
           _nodeElementVolumes_(i) = averageEltVolume;
         }
       }
     }
     neMassMatrix.compress();
       
     // solve equation
     LinearSolver solver(neMassMatrix, ATC::LinearSolver::ITERATIVE_SOLVE_SYMMETRIC, true);
     solver.set_max_iterations(neMassMatrix.nRows());
     double myTol = 1.e-10; 
     solver.set_tolerance(myTol);
     quantity_.resize(neSize,0);
     CLON_VEC tempQuantity(quantity_,CLONE_COL,0);
     solver.solve(tempQuantity,_nodeElementVolumes_);
   }
 
   //--------------------------------------------------------
   //  overloading operation to get number of rows
   //--------------------------------------------------------
   int NodalAtomVolumeElement::nRows() const
   {
     return atc_->num_nodes();
   }
 
   //--------------------------------------------------------
   //  overloading operation to get number of columns
   //--------------------------------------------------------
   int NodalAtomVolumeElement::nCols() const
   {
     return 1;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomTypeElement
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomTypeElement::AtomTypeElement(ATC_Coupling * atc,
                                    PerAtomQuantity<int> * atomElement) :
     atomElement_(atomElement),
     nElts_((atc->fe_engine())->num_elements())
   {
     if (!atomElement_) {
       atomElement_ = (atc->interscale_manager()).per_atom_int_quantity("AtomElement");
     }
     atomElement_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void AtomTypeElement::reset_quantity() const
   {
     // determine which elements contain internal atoms
     quantity_.resize(nElts_,1);
     _quantityLocal_.resize(nElts_,1);
     _quantityLocal_ = 0;
     const INT_ARRAY & atomElement(atomElement_->quantity());
     for (int i = 0; i < atomElement_->nRows(); ++i) {
       _quantityLocal_(atomElement(i,0),0) = 1;
     }
     // swap contributions
     lammpsInterface_->logical_or(_quantityLocal_.ptr(),
                                  quantity_.ptr(),nElts_);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ElementMask
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ElementMask::ElementMask(ATC_Coupling * atc,
                            MatrixDependencyManager<DenseMatrix, int> * hasInternal,
                            MatrixDependencyManager<DenseMatrix, int> * hasGhost) :
     hasInternal_(hasInternal),
     hasGhost_(hasGhost),
     feEngine_(atc->fe_engine())
   {
     if (!hasInternal_) {
       hasInternal_ = (atc->interscale_manager()).dense_matrix_int("ElementHasInternal");
     }
     if (!hasGhost_) {
       hasGhost_ = (atc->interscale_manager()).dense_matrix_int("ElementHasGhost");
     }
     
     hasInternal_->register_dependence(this);
     if (hasGhost_) hasGhost_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void ElementMask::reset_quantity() const
   {
     const INT_ARRAY & hasInternal(hasInternal_->quantity());
     int nElts = hasInternal.size();
     quantity_.resize(nElts,1);
 
     if (hasGhost_) {
       const INT_ARRAY & hasGhost(hasGhost_->quantity());
       for (int i = 0; i < nElts; ++i) {
         quantity_(i,0) = !hasInternal(i,0) || hasGhost(i,0);
       }
     }
     else {
       for (int i = 0; i < nElts; ++i) {
         quantity_(i,0) = !hasInternal(i,0);
       }
     }
       
     const set<int> & nullElements = feEngine_->null_elements();
     set<int>::const_iterator iset;
     for (iset = nullElements.begin(); iset != nullElements.end(); iset++) {
       int ielem = *iset;
       quantity_(ielem,0) = false;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AtomElementMask
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AtomElementMask::AtomElementMask(ATC_Coupling * atc,
                                    MatrixDependencyManager<DenseMatrix, int> * hasAtoms) :
     hasAtoms_(hasAtoms),
     feEngine_(atc->fe_engine())
   {
     if (!hasAtoms_) {
       hasAtoms_ = (atc->interscale_manager()).dense_matrix_int("ElementHasInternal");
     }
     if (!hasAtoms_) {
       throw ATC_Error("AtomElementMask::AtomElementMask - no element has atoms transfer provided");
     }
     hasAtoms_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void AtomElementMask::reset_quantity() const
   {
     const INT_ARRAY & hasAtoms(hasAtoms_->quantity());
     int nElts = hasAtoms.size();
     quantity_.resize(nElts,1);
 
     for (int i = 0; i < nElts; ++i) {
       quantity_(i,0) = hasAtoms(i,0);
     }
 
     // this seems to cause problems because many materials end up being null
     const set<int> & nullElements = feEngine_->null_elements();
     set<int>::const_iterator iset;
     for (iset = nullElements.begin(); iset != nullElements.end(); iset++) {
       int ielem = *iset;
       quantity_(ielem,0) = false;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ElementMaskNodeSet
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ElementMaskNodeSet::ElementMaskNodeSet(ATC_Coupling * atc,
-                                         RegulatedNodes * nodeSet) :
+                                         SetDependencyManager<int> * nodeSet) :
     nodeSet_(nodeSet),
     feMesh_((atc->fe_engine())->fe_mesh())
   { 
     nodeSet_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void ElementMaskNodeSet::reset_quantity() const
   {
     quantity_.resize(feMesh_->num_elements(),1);
     quantity_ = false;
 
     // get the maximal element set corresponding to those nodes
     set<int> elementSet;
     feMesh_->nodeset_to_maximal_elementset(nodeSet_->quantity(),elementSet);
 
     set<int>::const_iterator iset;
     for (iset = elementSet.begin(); iset != elementSet.end(); iset++) {
       quantity_(*iset,0) = true;
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class NodalGeometryType
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   NodalGeometryType::NodalGeometryType(ATC_Coupling * atc,
                                        MatrixDependencyManager<DenseMatrix, int> * hasInternal,
                                        MatrixDependencyManager<DenseMatrix, int> * hasGhost) :
     hasInternal_(hasInternal),
     hasGhost_(hasGhost),
     feEngine_(atc->fe_engine()),
     nNodes_(atc->num_nodes()),
     nElts_((atc->fe_engine())->num_elements())
   {
     if (!hasInternal_) {
       hasInternal_ = (atc->interscale_manager()).dense_matrix_int("ElementHasInternal");
     }
     if (!hasGhost_) {
       hasGhost_ = (atc->interscale_manager()).dense_matrix_int("ElementHasGhost");
     }
 
     hasInternal_->register_dependence(this);
     if (hasGhost_) hasGhost_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void NodalGeometryType::reset_quantity() const
   {
     const INT_ARRAY & hasInternal(hasInternal_->quantity());
     _nodesInternal_.resize(nNodes_);
     _nodesInternal_ = 0;
     _nodesGhost_.reset(nNodes_);
     _nodesGhost_ = 0;
     Array<int> nodes;
     
     
     
     vector<int> myElems = feEngine_->fe_mesh()->owned_elts();
     if (hasGhost_) {
       const INT_ARRAY & hasGhost(hasGhost_->quantity()) ;
       // iterate through all elements owned by this processor
       
       
       for (vector<int>::iterator elemsIter = myElems.begin();
            elemsIter != myElems.end();
            ++elemsIter)
       {
         int ielem = *elemsIter;
         if (hasInternal(ielem,0) || hasGhost(ielem,0)) {
           feEngine_->element_connectivity(ielem,nodes);
           for (int j = 0; j < nodes.size(); j++) {
             if (hasInternal(ielem,0)) {
               _nodesInternal_(nodes(j)) = 1;
             }
             if (hasGhost(ielem,0)) {
               _nodesGhost_(nodes(j)) = 1;
             }
           }
         }
       }
       // sum up partial result arrays
       
       lammpsInterface_->logical_or(MPI_IN_PLACE, _nodesInternal_.ptr(), _nodesInternal_.size());
       lammpsInterface_->logical_or(MPI_IN_PLACE, _nodesGhost_.ptr(), _nodesGhost_.size());
     }
     else {
       // iterate through all elements owned by this processor
       for (vector<int>::iterator elemsIter = myElems.begin();
            elemsIter != myElems.end();
            ++elemsIter)
       {
         int ielem = *elemsIter;
         if (hasInternal(ielem,0)) {
           feEngine_->element_connectivity(ielem,nodes);
           for (int j = 0; j < nodes.size(); j++) {
             _nodesInternal_(nodes(j)) = 1;
           }
         }
       }
       // sum up partial result arrays
       lammpsInterface_->logical_or(MPI_IN_PLACE, _nodesInternal_.ptr(), _nodesInternal_.size());
     }
 
     quantity_.resize(nNodes_,1);
     for (int i = 0; i < nNodes_; i++) {
       if (_nodesInternal_(i) && _nodesGhost_(i)) {
         quantity_(i,0) = BOUNDARY;
       }
       else if (_nodesInternal_(i)) {
         quantity_(i,0) = MD_ONLY;
       }
       else {
         quantity_(i,0) = FE_ONLY;
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class NodalGeometryTypeElementSet
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   NodalGeometryTypeElementSet::NodalGeometryTypeElementSet(ATC_Coupling * atc,
                                                            MatrixDependencyManager<DenseMatrix, int> * hasInternal) :
     hasInternal_(hasInternal),
     feEngine_(atc->fe_engine()),
     nNodes_(atc->num_nodes()),
     nElts_((atc->fe_engine())->num_elements())
   {
     if (!hasInternal_) {
       hasInternal_ = (atc->interscale_manager()).dense_matrix_int("ElementHasInternal");
     }
     if (!hasInternal_) {
       throw ATC_Error("NodalGeometryTypeElementSet:  No ElementHasInternal object provided or exists");
     }
     hasInternal_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void NodalGeometryTypeElementSet::reset_quantity() const
   {
     const INT_ARRAY & hasInternal(hasInternal_->quantity());
     _nodesInternal_.resize(nNodes_);
     _nodesInternal_ = 0;
     _nodesGhost_.reset(nNodes_);
     _nodesGhost_ = 0;
     Array<int> nodes;
     
     
     
     vector<int> myElems = feEngine_->fe_mesh()->owned_elts();
     // iterate through all elements owned by this processor
     for (vector<int>::iterator elemsIter = myElems.begin();
          elemsIter != myElems.end();
          ++elemsIter)
       {
         int ielem = *elemsIter;
         if (hasInternal(ielem,0)) {
           feEngine_->element_connectivity(ielem,nodes);
           for (int j = 0; j < nodes.size(); j++) {
             _nodesInternal_(nodes(j)) = 1;
           }
         }
         else {
           feEngine_->element_connectivity(ielem,nodes);
           for (int j = 0; j < nodes.size(); j++) {
             _nodesGhost_(nodes(j)) = 1;
           }
         }
       }
     
     // sum up partial result arrays
     lammpsInterface_->logical_or(MPI_IN_PLACE, _nodesInternal_.ptr(), _nodesInternal_.size());
     lammpsInterface_->logical_or(MPI_IN_PLACE, _nodesGhost_.ptr(), _nodesGhost_.size());
 
     quantity_.resize(nNodes_,1);
     for (int i = 0; i < nNodes_; i++) {
       if (_nodesInternal_(i) && _nodesGhost_(i)) {
         quantity_(i,0) = BOUNDARY;
       }
       else if (_nodesInternal_(i)) {
         quantity_(i,0) = MD_ONLY;
       }
       else {
         quantity_(i,0) = FE_ONLY;
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class NodeToSubset
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   NodeToSubset::NodeToSubset(ATC_Method * atc,
                              SetDependencyManager<int> * subsetNodes) :
     LargeToSmallMap(),
     atc_(atc),
     subsetNodes_(subsetNodes)
   {
     subsetNodes_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void NodeToSubset::reset_quantity() const
   {
     int nNodes = atc_->num_nodes();
     const set<int> & subsetNodes(subsetNodes_->quantity());
     quantity_.resize(nNodes,1);
     size_ = 0;
 
     for (int i = 0; i < nNodes; i++) {
       if (subsetNodes.find(i) != subsetNodes.end()) {
         quantity_(i,0) = size_;
         size_++;
       }
       else {
         quantity_(i,0) = -1;
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class SubsetToNode
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   SubsetToNode::SubsetToNode(NodeToSubset * nodeToSubset) :
     nodeToSubset_(nodeToSubset)
   {
     nodeToSubset_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void SubsetToNode::reset_quantity() const
   {
     const INT_ARRAY & nodeToSubset(nodeToSubset_->quantity());
     int nNodes = nodeToSubset.nRows();
     int count = 0;
     quantity_.resize(nodeToSubset_->size(),1);
 
     for (int i = 0; i < nNodes; i++) {
       if (nodeToSubset(i,0) > -1) {
         quantity_(count,0) = i;
         count++;
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class ReducedSparseMatrix
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   ReducedSparseMatrix::ReducedSparseMatrix(ATC_Method * atc,
                                            SPAR_MAN * source,
                                            LargeToSmallAtomMap * map) :
     SparseMatrixTransfer<double>(),
     source_(source),
     map_(map)
   {
     source_->register_dependence(this);
     map_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   ReducedSparseMatrix::~ReducedSparseMatrix()
   {
     source_->remove_dependence(this);
     map_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void ReducedSparseMatrix::reset_quantity() const
   {
     const SPAR_MAT & source(source_->quantity());
     const INT_ARRAY & map(map_->quantity());
     quantity_.reset(source.nRows(),source.nCols());
 
     for (int i = 0; i < source.nRows(); i++) {
       int idx = map(i,0);
       if (idx > -1) {
         source.row(i,_row_,_index_);
         for (int j = 0; j < _row_.size(); j++) {
           quantity_.set(i,_index_(j),_row_(j));
         }
       }
     }
     quantity_.compress();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class RowMappedSparseMatrix
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void RowMappedSparseMatrix::reset_quantity() const
   {
     const SPAR_MAT & source(source_->quantity());
     const INT_ARRAY & map(map_->quantity());
     quantity_.reset(map_->size(),source.nCols());
 
     for (int i = 0; i < source.nRows(); i++) {
       int idx = map(i,0);
       if (idx > -1) {
         source.row(i,_row_,_index_);
         for (int j = 0; j < _row_.size(); j++) {
           quantity_.set(idx,_index_(j),_row_(j));
         }
       }
     }
     quantity_.compress();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class RowMappedSparseMatrixVector
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   RowMappedSparseMatrixVector::RowMappedSparseMatrixVector(ATC_Method * atc,
                                                            VectorDependencyManager<SPAR_MAT * > * source,
                                                            LargeToSmallAtomMap * map) :
     VectorTransfer<SPAR_MAT * >(),
     source_(source),
     map_(map)
   {
     source_->register_dependence(this);
     map_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   RowMappedSparseMatrixVector::~RowMappedSparseMatrixVector()
   {
     source_->remove_dependence(this);
     map_->remove_dependence(this);
     for (unsigned i = 0; i < quantity_.size(); ++i) {
       if (quantity_[i]) delete quantity_[i];
     }
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void RowMappedSparseMatrixVector::reset_quantity() const
   {
     const vector<SPAR_MAT * > & source(source_->quantity());
     const INT_ARRAY & map(map_->quantity());
 
     for (unsigned i = 0; i < quantity_.size(); ++i) {
       if (quantity_[i]) delete quantity_[i];
     }
     quantity_.resize(source.size(),NULL);
     for (unsigned i = 0; i < source.size(); i++) {
       quantity_[i] = new SPAR_MAT(map_->size(),source[i]->nCols());
     }
 
     for (unsigned i = 0; i < source.size(); i++) {
       for (int j = 0; j < source[i]->nRows(); j++) {
         int idx = map(j,0);
         if (idx > -1) {
           source[i]->row(j,_row_,_index_);
           for (int k = 0; k < _row_.size(); k++) {
             quantity_[i]->set(idx,_index_(k),_row_(k));
           }
         }
       }
     }
     for (unsigned i = 0; i < source.size(); i++) {
       quantity_[i]->compress();
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class MappedDiagonalMatrix
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   MappedDiagonalMatrix::MappedDiagonalMatrix(ATC_Method * atc,
                                              DIAG_MAN * source,
                                              LargeToSmallAtomMap * map) :
     DiagonalMatrixTransfer<double>(),
     source_(source),
     map_(map)
   {
     source_->register_dependence(this);
     map_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Destructor
   //--------------------------------------------------------
   MappedDiagonalMatrix::~MappedDiagonalMatrix()
   {
     source_->remove_dependence(this);
     map_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void MappedDiagonalMatrix::reset_quantity() const
   {
     const DIAG_MAT & source(source_->quantity());
     const INT_ARRAY & map(map_->quantity());
     quantity_.resize(map_->size(),map_->size());
 
     for (int i = 0; i < source.nRows(); i++) {
       int idx = map(i,0);
       if (idx > -1) {
         quantity_(idx,idx) = source(i,i);
       }
     }
   }
   
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class MappedQuantity
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   MappedQuantity::MappedQuantity(ATC_Method * atc,
                                  DENS_MAN * source,
                                  LargeToSmallMap * map) :
     DenseMatrixTransfer<double>(),
     source_(source),
     map_(map)
   {
     source_->register_dependence(this);
     map_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void MappedQuantity::reset_quantity() const
   {
     const DENS_MAT & source(source_->quantity());
     const INT_ARRAY & map(map_->quantity());
     quantity_.resize(map_->size(),source.nCols());
 
     for (int i = 0; i < source.nRows(); i++) {
       int idx = map(i,0);
       if (idx > -1) {
         for (int j = 0; j < source.nCols(); j++) {
           quantity_(idx,j) = source(i,j);
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class RegulatedNodes
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   RegulatedNodes::RegulatedNodes(ATC_Coupling * atc,
                                  FieldName fieldName,
                                  MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType) :
     SetTransfer<int>(),
     nodalGeometryType_(nodalGeometryType),
     atc_(atc),
     feEngine_(atc->fe_engine()),
     prescribedDataManager_(atc->prescribed_data_manager())
   {
     if (!nodalGeometryType_) {
       nodalGeometryType_ = (atc_->interscale_manager()).dense_matrix_int("NodalGeometryType");
     }
     if (nodalGeometryType_) {
       nodalGeometryType_->register_dependence(this);
     }
     else {
       throw ATC_Error("TransferLibrary::RegulatedNodes - No Nodal Geometry Type provided");
     }
 
     const map<FieldName,int> & atcFieldSizes(atc_->field_sizes());
     if (fieldName == NUM_TOTAL_FIELDS) {
       fieldSizes_ = atcFieldSizes;
     }
     else {
       map<FieldName,int>::const_iterator fs_iter = atcFieldSizes.find(fieldName);
       fieldSizes_.insert(pair<FieldName,int>(fieldName,fs_iter->second));
     }
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void RegulatedNodes::reset_quantity() const
   {
     const INT_ARRAY & nodeType(nodalGeometryType_->quantity());
     quantity_.clear();
     
     for (int i = 0; i < nodeType.size(); ++i) {
       if (nodeType(i,0) != FE_ONLY) {
         quantity_.insert(i);
       }
     }
   }
 
   //--------------------------------------------------------
   //  insert_boundary_nodes
   //--------------------------------------------------------
   void RegulatedNodes::insert_boundary_nodes() const
   {
     const INT_ARRAY & nodeType(nodalGeometryType_->quantity());
     
     for (int i = 0; i < nodeType.size(); ++i) {
       if (nodeType(i,0) == BOUNDARY) {
         quantity_.insert(i);
       }
     }
   }
 
   //--------------------------------------------------------
   //  insert_boundary_faces
   //--------------------------------------------------------
   void RegulatedNodes::insert_boundary_faces() const
   {
     const set<string> & boundaryFaceNames(atc_->boundary_face_names());
     set<string>::const_iterator iter;
     set<int>::const_iterator nodeIter;
 
     for (iter = boundaryFaceNames.begin(); iter != boundaryFaceNames.end(); iter++) {
       set<int> nodeSet;
       feEngine_->fe_mesh()->faceset_to_nodeset(*iter,nodeSet);
       for (nodeIter = nodeSet.begin(); nodeIter != nodeSet.end(); nodeIter++) {
         quantity_.insert(*nodeIter);
       }
     }
   }
 
   //--------------------------------------------------------
   //  insert_fixed_nodes
   //--------------------------------------------------------
   void RegulatedNodes::insert_fixed_nodes() const
   {
     
     const INT_ARRAY & nodeType(nodalGeometryType_->quantity());
     map<FieldName,int>::const_iterator fs_iter;
 
     for (int i = 0; i < nodeType.size(); ++i) {
       bool isFixed = false;
       for (fs_iter = fieldSizes_.begin(); fs_iter != fieldSizes_.end(); fs_iter++) {
         for (int j = 0; j < fs_iter->second; j++) {
           isFixed = prescribedDataManager_->is_fixed(i,fs_iter->first,j);
           if (isFixed) break;
         }
       }
       if (isFixed && ((nodeType(i,0)==MD_ONLY) || (nodeType(i,0)==BOUNDARY))) {
         quantity_.insert(i);
       }
     }
   }
 
   //--------------------------------------------------------
   //  insert_face_fluxes
   //--------------------------------------------------------
   void RegulatedNodes::insert_face_fluxes() const
   {
     const INT_ARRAY & nodeType(nodalGeometryType_->quantity());
     set<int>::const_iterator inode;
     map<FieldName,int>::const_iterator fs_iter;
     
     for (fs_iter = fieldSizes_.begin(); fs_iter != fieldSizes_.end(); fs_iter++) {
       for (int j = 0; j < fs_iter->second; j++) {
         set<int> faceFluxNodes = prescribedDataManager_->flux_face_nodes(fs_iter->first,j);
         for (inode = faceFluxNodes.begin(); inode != faceFluxNodes.end(); inode++) {
           if (((nodeType(*inode,0)==MD_ONLY) || (nodeType(*inode,0)==BOUNDARY))) {
             quantity_.insert(*inode);
           }
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //  insert_element_fluxes
   //--------------------------------------------------------
   void RegulatedNodes::insert_element_fluxes() const
   {
     const INT_ARRAY & nodeType(nodalGeometryType_->quantity());
     set<int>::const_iterator inode;
     map<FieldName,int>::const_iterator fs_iter;
 
     for (fs_iter = fieldSizes_.begin(); fs_iter != fieldSizes_.end(); fs_iter++) {
       for (int j = 0; j < fs_iter->second; j++) {
         set<int> elementFluxNodes = prescribedDataManager_->flux_element_nodes(fs_iter->first,j);
         for (inode = elementFluxNodes.begin(); inode != elementFluxNodes.end(); inode++) {
           if (((nodeType(*inode,0)==MD_ONLY) || (nodeType(*inode,0)==BOUNDARY))) {
             quantity_.insert(*inode);
           }
         }
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class BoundaryNodes
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void BoundaryNodes::reset_quantity() const
   {
     quantity_.clear();
 
     // a) they are a boundary node
     RegulatedNodes::insert_boundary_nodes();
 
     // b) they are in a specified boundary faceset
     RegulatedNodes::insert_boundary_faces();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class FluxNodes
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void FluxNodes::reset_quantity() const
   {
     quantity_.clear();
     
     // a) they have a fixed face flux
     RegulatedNodes::insert_face_fluxes();
 
     // b) they have a fixed element flux
     RegulatedNodes::insert_element_fluxes();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class FluxBoundaryNodes
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void FluxBoundaryNodes::reset_quantity() const
   {
     FluxNodes::reset_quantity();
 
     // a) they are a boundary node
     RegulatedNodes::insert_boundary_nodes();
 
     // b) they are in a specified boundary faceset
     RegulatedNodes::insert_boundary_faces();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AllRegulatedNodes
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void AllRegulatedNodes::reset_quantity() const
   {
     FluxBoundaryNodes::reset_quantity();
 
     // a) they are a fixed node
     RegulatedNodes::insert_fixed_nodes();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class FixedNodes
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void FixedNodes::reset_quantity() const
   {
     quantity_.clear();
     
     // a) they are a fixed node
     RegulatedNodes::insert_fixed_nodes();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class FixedBoundaryNodes
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void FixedBoundaryNodes::reset_quantity() const
   {
     FixedNodes::reset_quantity();
 
     // a) they are a boundary node
     RegulatedNodes::insert_boundary_nodes();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class DenseMatrixQuotient
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   DenseMatrixQuotient::DenseMatrixQuotient(DENS_MAN* matrixNumerator,
                                            DENS_MAN* matrixDenominator):
   matrixNumerator_(matrixNumerator),
   matrixDenominator_(matrixDenominator)
   {
     matrixNumerator_->register_dependence(this);
     matrixDenominator_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Reset_quantity
   //--------------------------------------------------------
   void DenseMatrixQuotient::reset_quantity() const
   {
       quantity_ = matrixNumerator_->quantity();
       quantity_.divide_zero_safe(matrixDenominator_->quantity());
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class DenseMatrixSum
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   DenseMatrixSum::DenseMatrixSum(DENS_MAN* matrixOne,
                                  DENS_MAN* matrixTwo):
   matrixOne_(matrixOne), matrixTwo_(matrixTwo)
   {
     matrixOne_->register_dependence(this);
     matrixTwo_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Reset_quantity
   //--------------------------------------------------------
   void DenseMatrixSum::reset_quantity() const
   {
       quantity_ = matrixOne_->quantity();
       quantity_ += (matrixTwo_->quantity());
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class DenseMatrixDelta
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   DenseMatrixDelta::DenseMatrixDelta(DENS_MAN* matrix,
                                      DENS_MAT* reference):
   matrix_(matrix), reference_(reference)
   {
     matrix_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Reset_quantity
   //--------------------------------------------------------
   void DenseMatrixDelta::reset_quantity() const
   {
       quantity_ = matrix_->quantity();
       quantity_ -= *reference_;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class PointToElementMap
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   PointToElementMap::PointToElementMap(ATC_Method * atc,
                                        MatrixDependencyManager<DenseMatrix, double> * pointPositions) :
     DenseMatrixTransfer<int>(),
     pointPositions_(pointPositions),
     feMesh_((atc->fe_engine())->fe_mesh())
   {
     pointPositions_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   PointToElementMap::~PointToElementMap()
   {
     pointPositions_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void PointToElementMap::reset_quantity() const
   {
     const DENS_MAT & position(pointPositions_->quantity());
     int nsd = position.nCols();
     int nRows = position.nRows();
     quantity_.resize(nRows,nsd);
 
     DENS_VEC coords(nsd);
     for (int i = 0; i < nRows; i++) {
       for (int j = 0; j < nsd; j++) {
         coords(j) = position(i,j);
       }
       quantity_(i,0) = feMesh_->map_to_element(coords);
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class Interpolant
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   Interpolant::Interpolant(ATC_Method * atc,
                            MatrixDependencyManager<DenseMatrix, int>* pointToElementMap,
                            DENS_MAN* pointPositions) :
     SparseMatrixTransfer<double>(),
     pointToElementMap_(pointToElementMap),
     pointPositions_(pointPositions),
     feEngine_(atc->fe_engine())
   {
     pointToElementMap_->register_dependence(this);
     pointPositions_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void Interpolant::reset_quantity() const
   {
     const DENS_MAT & positions(pointPositions_->quantity());
     const INT_ARRAY & elements(pointToElementMap_->quantity());
     if (positions.nRows() > 0) {
       feEngine_->evaluate_shape_functions(positions,
                                           elements,
                                           this->quantity_);
     }
     else {
       quantity_.resize(0,feEngine_->num_nodes());
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class InterpolantGradient
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   InterpolantGradient::InterpolantGradient(ATC_Method * atc,
                                            MatrixDependencyManager<DenseMatrix, int>* pointToElementMap,
                                            DENS_MAN* pointPositions) :
     VectorTransfer<SPAR_MAT * >(),
     pointToElementMap_(pointToElementMap),
     pointPositions_(pointPositions),
     feEngine_(atc->fe_engine())
   {
     pointToElementMap_->register_dependence(this);
     pointPositions_->register_dependence(this);
     quantity_.resize(atc->nsd(),NULL);
     for (int i = 0; i < atc->nsd(); ++i) {
       quantity_[i] = new SPAR_MAT();
     }
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   InterpolantGradient::~InterpolantGradient() {
     pointToElementMap_->remove_dependence(this);
     pointPositions_->remove_dependence(this);
     for (unsigned i = 0; i < quantity_.size(); ++i) {
       if (quantity_[i]) delete quantity_[i];
     }
   }
 
   //--------------------------------------------------------
   //  reset_quantity()
   //--------------------------------------------------------
   void InterpolantGradient::reset_quantity() const
   {
     const DENS_MAT & positions(pointPositions_->quantity());
     const INT_ARRAY & elements(pointToElementMap_->quantity());
     if (positions.nRows() > 0) {
       feEngine_->evaluate_shape_function_derivatives(positions,
                                                      elements,
                                                      this->quantity_);
     }
     else {
       for (unsigned i = 0; i < quantity_.size(); ++i) {
         (this->quantity_)[i]->resize(0,feEngine_->num_nodes());
       }
     }
   }
 
   //--------------------------------------------------------
   //  Class PerAtomShapeFunctionGradient
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   PerAtomShapeFunctionGradient::PerAtomShapeFunctionGradient(ATC_Method * atc,
                                                              MatrixDependencyManager<DenseMatrix, int>* atomToElementMap,
                                                              DENS_MAN* atomPositions,
                                                              const string & tag,
                                                              AtomType atomType) :
     VectorTransfer<SPAR_MAT * >(),
     atomToElementMap_(atomToElementMap),
     atomPositions_(atomPositions),
     feEngine_(atc->fe_engine())
   {
     InterscaleManager & interscaleManager(atc->interscale_manager());
     if (!atomToElementMap_) {
       atomToElementMap_ = interscaleManager.per_atom_int_quantity("AtomElement");
     }
     if (!atomPositions_) {
       atomPositions_ = interscaleManager.per_atom_quantity("AtomicCoarseGrainingPositions");
     }
     atomToElementMap_->register_dependence(this);
     atomPositions_->register_dependence(this);
 
     // storage container
     matrices_.resize(atc->nsd(),NULL);
     for (int i = 0; i < atc->nsd(); ++i) {
       matrices_[i] = new AtcAtomSparseMatrix<double>(atc,feEngine_->num_nodes(),
                                                      feEngine_->num_nodes_per_element(),
                                                      atomType);
       stringstream myint;
       myint << i;
       interscaleManager.add_per_atom_sparse_matrix(matrices_[i],
                                                    tag+myint.str());
       matrices_[i]->register_dependence(this);
     }
 
     quantity_.resize(atc->nsd(),NULL);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   PerAtomShapeFunctionGradient::~PerAtomShapeFunctionGradient() {
     atomToElementMap_->remove_dependence(this);
     atomPositions_->remove_dependence(this);
     for (unsigned i = 0; i < matrices_.size(); ++i) {
       matrices_[i]->remove_dependence(this);
     }
   }
 
   //--------------------------------------------------------
   //  reset_quantity()
   //--------------------------------------------------------
   void PerAtomShapeFunctionGradient::reset_quantity() const
   {
     const DENS_MAT & positions(atomPositions_->quantity());
     const INT_ARRAY & elements(atomToElementMap_->quantity());
     for (unsigned i = 0; i < quantity_.size(); ++i) {
       (this->quantity_)[i] = & matrices_[i]->set_quantity();
     }
 
     if (positions.nRows() > 0) {
       feEngine_->evaluate_shape_function_derivatives(positions,
                                                      elements,
                                                      this->quantity_);
     }
     else {
       for (unsigned i = 0; i < quantity_.size(); ++i) {
         (this->quantity_)[i]->resize(0,feEngine_->num_nodes());
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class InterpolantSmallMolecule
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   InterpolantSmallMolecule::InterpolantSmallMolecule(ATC_Method * atc,
                                                      MatrixDependencyManager<DenseMatrix, int>* moleculeToElementMap,
                                                      DENS_MAN* moleculePositions,
                                                      MoleculeSet * moleculeSet) :
     Interpolant(atc,moleculeToElementMap,moleculePositions),
     moleculeSet_(moleculeSet)
   {
     moleculeSet_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   InterpolantSmallMolecule::~InterpolantSmallMolecule()
   {
     moleculeSet_->remove_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset
   //--------------------------------------------------------
   void InterpolantSmallMolecule::reset_quantity() const
   {
     Interpolant::reset_quantity();
 
     // scale rows by fraction of molecules on this proc
     _fractions_.resize((this->quantity_).nRows());
     for (int i = 0; i < moleculeSet_->local_molecule_count(); i++)
       _fractions_(i) = moleculeSet_->local_fraction(i);
     (this->quantity_).row_scale(_fractions_);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyKernelAccumulation
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyKernelAccumulation::OnTheFlyKernelAccumulation(ATC_Method * atc,
                                                          PerAtomQuantity<double> * source,
                                                          KernelFunction* kernelFunction,
                                                          DENS_MAN* atomCoarseGrainingPositions):
     atc_(atc),
     source_(source),
     kernelFunction_(kernelFunction), 
     atomCoarseGrainingPositions_(atomCoarseGrainingPositions),
     feMesh_((atc_->fe_engine())->fe_mesh())
   {
     source_->register_dependence(this);
     atomCoarseGrainingPositions_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyKernelAccumulation::reset_quantity() const
   {
     const DENS_MAT & positions(atomCoarseGrainingPositions_->quantity());
     const DENS_MAT & source(source_->quantity());
     int nNodes = feMesh_->num_nodes_unique();
     quantity_.resize(nNodes,source.nCols());
     _quantityLocal_.reset(nNodes,source.nCols());
     
     if (source.nRows()>0) {
       DENS_VEC xI(positions.nCols()),xa(positions.nCols()),xaI(positions.nCols());
       double val;
       for (int i = 0; i < nNodes; i++) {
         xI = feMesh_->nodal_coordinates(i);
         for (int j = 0; j < positions.nRows(); j++) {
           for (int k = 0; k < positions.nCols(); ++k) {
             xa(k) = positions(j,k);
           }
           xaI = xa - xI;
           atc_->lammps_interface()->periodicity_correction(xaI.ptr());
           val = kernelFunction_->value(xaI);
           if (val > 0) {
             for (int k=0; k < source.nCols(); k++) {
               _quantityLocal_(i,k) += val*source(j,k);
             }
           }
         }
       }
     }
 
     // accumulate across processors
     int count = quantity_.nRows()*quantity_.nCols();
     lammpsInterface_->allsum(_quantityLocal_.ptr(),quantity_.ptr(),count);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyKernelAccumulationNormalized
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyKernelAccumulationNormalized::OnTheFlyKernelAccumulationNormalized(ATC_Method * atc,
                    PerAtomQuantity<double> * source,
                    KernelFunction* kernelFunction,
                    DENS_MAN* atomCoarseGrainingPositions,
                    DIAG_MAN * weights):
     OnTheFlyKernelAccumulation(atc,source,kernelFunction,atomCoarseGrainingPositions),
     weights_(weights)
   {
     weights_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyKernelAccumulationNormalized::reset_quantity() const
   {
     OnTheFlyKernelAccumulation::reset_quantity();
     quantity_ *= weights_->quantity();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyKernelAccumulationNormalizedReferenced
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyKernelAccumulationNormalizedReferenced::OnTheFlyKernelAccumulationNormalizedReferenced(ATC_Method * atc,
                 PerAtomQuantity<double> * source,
                 KernelFunction* kernelFunction,
                 DENS_MAN* atomCoarseGrainingPositions,
                 DIAG_MAN* weights,
                 DENS_MAN * reference):
     OnTheFlyKernelAccumulationNormalized(atc,source,kernelFunction,atomCoarseGrainingPositions,weights),
     reference_(reference)
   {
     reference_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyKernelAccumulationNormalizedReferenced::reset_quantity() const
   {
     OnTheFlyKernelAccumulationNormalized::reset_quantity();
     quantity_ -= reference_->quantity();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyKernelAccumulationNormalizedScaled
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyKernelAccumulationNormalizedScaled::OnTheFlyKernelAccumulationNormalizedScaled(ATC_Method * atc,
         PerAtomQuantity<double> * source,
         KernelFunction* kernelFunction,
         DENS_MAN* atomCoarseGrainingPositions,
         DIAG_MAN* weights,
         const double scale):
     OnTheFlyKernelAccumulationNormalized(atc,source,kernelFunction,atomCoarseGrainingPositions,weights),
     scale_(scale)
   {
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyKernelAccumulationNormalizedScaled::reset_quantity() const
   {
     OnTheFlyKernelAccumulationNormalized::reset_quantity();
     quantity_ *= scale_;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class AccumulantWeights
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   AccumulantWeights::AccumulantWeights(SPAR_MAN* accumulant):
     DiagonalMatrixTransfer<double>(),
     accumulant_(accumulant)
   {
     accumulant_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Reset_quantity
   //--------------------------------------------------------
   void AccumulantWeights::reset_quantity() const
   {
     const SPAR_MAT accumulant(accumulant_->quantity());
     int nNodes = accumulant.nCols();
 
     // get summation of atoms per node
     _localWeights_.reset(nNodes); _weights_.resize(nNodes);
     if (accumulant.nRows()>0) {
       _localWeights_ = (accumulant_->quantity()).col_sum();
     }
     lammpsInterface_->allsum(_localWeights_.ptr(),_weights_.ptr(),nNodes);
     
     // assign weights
     quantity_.resize(nNodes,nNodes);
     for (int i = 0; i < nNodes; i++) {
       if (_weights_(i) > 0.) {
         quantity_(i,i) = 1./_weights_(i);
       }
       else {
         quantity_(i,i) = 0.;
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyKernelWeights
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyKernelWeights::OnTheFlyKernelWeights(DENS_MAN* weights):
     DiagonalMatrixTransfer<double>(),
     weights_(weights)
   {
     weights_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  Reset_quantity
   //--------------------------------------------------------
   void OnTheFlyKernelWeights::reset_quantity() const
   {
     const DENS_MAT & weights(weights_->quantity());
     int nNodes = weights.nRows();
     
     // assign weights
     quantity_.resize(nNodes,nNodes);
     for (int i = 0; i < nNodes; i++) {
       if (weights(i,0) > 0.) {
         quantity_(i,i) = 1./weights(i,0);
       }
       else {
         quantity_(i,i) = 0.;
       }
     }
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class KernelInverseVolumes
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   KernelInverseVolumes::KernelInverseVolumes(ATC_Method * atc,
                                              KernelFunction* kernelFunction):
     kernelFunction_(kernelFunction), 
     feMesh_((atc->fe_engine())->fe_mesh())
   {
     // do nothing
   }
 
   //--------------------------------------------------------
   //  multiplication by transpose
   //--------------------------------------------------------
   void KernelInverseVolumes::reset_quantity() const
   {
     int nNodes = feMesh_->num_nodes_unique();
     quantity_.resize(nNodes,nNodes);
     quantity_ = kernelFunction_->inv_vol();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyMeshAccumulation
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyMeshAccumulation::OnTheFlyMeshAccumulation(ATC_Method * atc,
                                                      PerAtomQuantity<double> * source,
                                                      DENS_MAN* atomCoarseGrainingPositions):
     atc_(atc),
     source_(source),
     atomCoarseGrainingPositions_(atomCoarseGrainingPositions),
     feMesh_((atc_->fe_engine())->fe_mesh())
   {
     source_->register_dependence(this);
     atomCoarseGrainingPositions_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyMeshAccumulation::reset_quantity() const
   {
     const DENS_MAT & positions(atomCoarseGrainingPositions_->quantity());
     const DENS_MAT & source(source_->quantity());
     int nNodes = feMesh_->num_nodes_unique();
     int nodesPerElement = feMesh_->num_nodes_per_element();
     Array<int> node_list(nodesPerElement);
     DENS_VEC shp(nodesPerElement);
     quantity_.resize(nNodes,source.nCols());
     _quantityLocal_.reset(nNodes,source.nCols());
     DENS_VEC xj(atc_->nsd());
     
     if (source.nRows()>0) {
       for (int j = 0; j < source.nRows(); j++) {
         for (int k = 0; k < atc_->nsd(); k++) {
           xj(k) = positions(j,k);
         }
         feMesh_->shape_functions(xj,shp,node_list);
         for (int I = 0; I < nodesPerElement; I++) {
           int inode = node_list(I);
           for (int k = 0; k < source.nCols(); k++) {
             //quantity_(inode,k) += shp(I)*source(j,k);
             _quantityLocal_(inode,k) += shp(I)*source(j,k);
           }
         } 
       }
     }
     // accumulate across processors
     int count = quantity_.nRows()*quantity_.nCols();
     lammpsInterface_->allsum(_quantityLocal_.ptr(),quantity_.ptr(),count);
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyMeshAccumulationNormalized
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyMeshAccumulationNormalized::OnTheFlyMeshAccumulationNormalized(ATC_Method * atc,
                    PerAtomQuantity<double> * source,
                    DENS_MAN* atomCoarseGrainingPositions,
                    DIAG_MAN * weights):
     OnTheFlyMeshAccumulation(atc,source,atomCoarseGrainingPositions),
     weights_(weights)
   {
     weights_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyMeshAccumulationNormalized::reset_quantity() const
   {
     OnTheFlyMeshAccumulation::reset_quantity();
     quantity_ *= weights_->quantity();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyMeshAccumulationNormalizedReferenced
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyMeshAccumulationNormalizedReferenced::OnTheFlyMeshAccumulationNormalizedReferenced(ATC_Method * atc,
                 PerAtomQuantity<double> * source,
                 DENS_MAN* atomCoarseGrainingPositions,
                 DIAG_MAN* weights,
                 DENS_MAN * reference):
     OnTheFlyMeshAccumulationNormalized(atc,source,atomCoarseGrainingPositions,weights),
     reference_(reference)
   {
     reference_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyMeshAccumulationNormalizedReferenced::reset_quantity() const
   {
     OnTheFlyMeshAccumulationNormalized::reset_quantity();
     quantity_ -= reference_->quantity();
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyMeshAccumulationNormalizedScaled
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyMeshAccumulationNormalizedScaled::OnTheFlyMeshAccumulationNormalizedScaled(ATC_Method * atc,
         PerAtomQuantity<double> * source,
         DENS_MAN* atomCoarseGrainingPositions,
         DIAG_MAN* weights,
         const double scale):
     OnTheFlyMeshAccumulationNormalized(atc,source,atomCoarseGrainingPositions,weights),
     scale_(scale)
   {
   }
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyMeshAccumulationNormalizedScaled::reset_quantity() const
   {
     OnTheFlyMeshAccumulationNormalized::reset_quantity();
     quantity_ *= scale_;
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class NativeShapeFunctionGradient
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  constructor
   //--------------------------------------------------------
   NativeShapeFunctionGradient::NativeShapeFunctionGradient(ATC_Method * atc) :
     VectorTransfer<SPAR_MAT * >(),
     feEngine_(atc->fe_engine())
   {
     quantity_.resize(atc->nsd(),NULL);
     for (int i = 0; i < atc->nsd(); ++i) {
       quantity_[i] = new SPAR_MAT();
     }
   }
 
   //--------------------------------------------------------
   //  destructor
   //--------------------------------------------------------
   NativeShapeFunctionGradient::~NativeShapeFunctionGradient() {
     for (unsigned i = 0; i < quantity_.size(); ++i) {
       if (quantity_[i]) delete quantity_[i];
     }
   }
 
   //--------------------------------------------------------
   //  reset_quantity()
   //--------------------------------------------------------
   void NativeShapeFunctionGradient::reset_quantity() const
   {
     feEngine_->compute_gradient_matrix(quantity_); 
   }
 
   //--------------------------------------------------------
   //--------------------------------------------------------
   //  Class OnTheFlyShapeFunctionProlongation
   //--------------------------------------------------------
   //--------------------------------------------------------
 
   //--------------------------------------------------------
   //  Constructor
   //--------------------------------------------------------
   OnTheFlyShapeFunctionProlongation::OnTheFlyShapeFunctionProlongation(ATC_Method * atc,
                                                    DENS_MAN * source,
                                                    DENS_MAN * atomCoarseGrainingPositions):
     FeToAtomTransfer(atc,source),
     atomCoarseGrainingPositions_(atomCoarseGrainingPositions),
     feMesh_((atc->fe_engine())->fe_mesh())
   {
     atomCoarseGrainingPositions_->register_dependence(this);
   }
 
   //--------------------------------------------------------
   // destructor
   //--------------------------------------------------------
   OnTheFlyShapeFunctionProlongation::~OnTheFlyShapeFunctionProlongation() 
   {
     atomCoarseGrainingPositions_->remove_dependence(this);
   };
 
   //--------------------------------------------------------
   //  reset_quantity
   //--------------------------------------------------------
   void OnTheFlyShapeFunctionProlongation::reset() const
   {
     if (need_reset()) {
       PerAtomQuantity<double>::reset();
       const DENS_MAT & positions(atomCoarseGrainingPositions_->quantity());
       const DENS_MAT & source(source_->quantity());
       int nodesPerElement = feMesh_->num_nodes_per_element();
       Array<int> node_list(nodesPerElement);
       DENS_VEC shp(nodesPerElement);
       DENS_VEC xj(positions.nCols());
       int nLocal = positions.nRows();
       quantity_ = 0.;
       for (int j = 0; j < nLocal; j++) {
         for (int k = 0; k < source.nCols(); k++) {
           xj(k) = positions(j,k);
         }
         feMesh_->shape_functions(xj,shp,node_list);
         for (int I = 0; I < nodesPerElement; I++) {
           int inode = node_list(I);
           for (int k = 0; k < source.nCols(); k++) {
             quantity_(j,k) += shp(I)*source(inode,k);
           }
         }
       }
     }
   }
 }
diff --git a/lib/atc/TransferLibrary.h b/lib/atc/TransferLibrary.h
index 380cb6dcf..3a0f420f3 100644
--- a/lib/atc/TransferLibrary.h
+++ b/lib/atc/TransferLibrary.h
@@ -1,1724 +1,1724 @@
 // a library for the various transfer operators used in ATC
 
 #ifndef TRANSFER_LIBRARY_H
 #define TRANSFER_LIBRARY_H
 
 #include <string>
 #include <map>
 #include <vector>
 
 // ATC_Method headers
 #include "TransferOperator.h"
 
 namespace ATC {
 
   // forward declarations
   class ATC_Method;
   class ATC_Coupling;
   class FE_Engine;
   class FE_Mesh;
   class PrescribedDataManager;
   class LargeToSmallAtomMap;
   class MoleculeSet;
 
   /**
    *  @class  NodalAtomVolume
    *  @brief  Computes the nodal volumes which coarse grain the volume per atom
    */
   
   class NodalAtomVolume : public DenseMatrixTransfer<double> {
 
   public:
     
     // constructor
     NodalAtomVolume(ATC_Method * atc, SPAR_MAN * shapeFunction);
     
     // destructor
     virtual ~NodalAtomVolume() {shapeFunction_->remove_dependence(this);};
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
     /** overload function to get the number rows */
     virtual int nRows() const;
 
     /** overload function to get the number columns */
     virtual int nCols() const;
 
   protected:
 
     /** applies the needed averaging operation to get the appropriate average volume */
     virtual double averaging_operation(const double totalVolume) const;
 
     /** pointer to atc method object */
     const ATC_Method * atc_;
 
     /** shape function matrix used to base volumes on */
     SPAR_MAN * shapeFunction_;
 
     /** pointer to lammps interface */
     const LammpsInterface * lammpsInterface_;
 
     /** pointer to the FE engine */
     const FE_Engine * feEngine_;
 
     /** tolerance used in the linear solver */
     const double tol_;
 
     // workspace variables
     mutable DIAG_MAT _rhsMatrix_;
     mutable DENS_VEC _rhs_;
     mutable DENS_VEC _scale_;
 
   private:
 
     // do not define
     NodalAtomVolume();
 
   };
 
   /**
    *  @class  NodalVolume
    *  @brief  Computes the nodal volumes associated with the support of each nodal shape function
    */
   
   class NodalVolume : public NodalAtomVolume {
 
   public:
     
     // constructor
     NodalVolume(ATC_Method * atc, SPAR_MAN * shapeFunction) : NodalAtomVolume(atc,shapeFunction) {};
     
     // destructor
     virtual ~NodalVolume() {};
 
   protected:
 
     /** applies the needed averaging operation to get the appropriate average volume */
     virtual double averaging_operation(const double totalVolume) const;
 
   private:
 
     // do not define
     NodalVolume();
 
   };
 
   /**
    *  @class  NodalAtomVolumeElement
    *  @brief  Computes the nodal volumes which coarse grain the volume per atom based on element volumes
    */
   
   class NodalAtomVolumeElement : public DenseMatrixTransfer<double> {
 
   public:
     
     // constructor
     NodalAtomVolumeElement(ATC_Method * atc, SPAR_MAN * shapeFunction,
                            PerAtomQuantity<int> * atomElement=NULL);
     
     // destructor
     virtual ~NodalAtomVolumeElement() {
       shapeFunction_->remove_dependence(this);
       atomElement_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
     /** overload function to get the number rows */
     virtual int nRows() const;
 
     /** overload function to get the number columns */
     virtual int nCols() const;
 
   protected:
 
     /** pointer to atc method object */
     ATC_Method * atc_;
 
     /** shape function matrix used to base volumes on */
     SPAR_MAN * shapeFunction_;
 
     /** object containing the elements associated with each atom */
     PerAtomQuantity<int> * atomElement_;
 
     /** pointer to the FE engine */
     const FE_Engine * feEngine_;
 
     /** tolerance used in the linear solver */
     const double tol_;
 
     // workspace variables
     mutable DIAG_MAT _nodeVolumesMatrix_;
     mutable DENS_VEC _nodeVolumes_;
     mutable DENS_VEC _nodeElementVolumes_;
     mutable DENS_MAT _nodalCoords_;
     mutable DENS_VEC _scale_;
 
   private:
 
     // do not define
     NodalAtomVolumeElement();
 
   };
 
   /**
    *  @class  AtomTypeElement
    *  @brief  determines if the given atom type is in each element
    */
   class AtomTypeElement : public DenseMatrixTransfer<int> {
 
   public:
     
     // constructor
     AtomTypeElement(ATC_Coupling * atc,
                     PerAtomQuantity<int> * atomElement = NULL);
     
     // destructor
     virtual ~AtomTypeElement() {
       atomElement_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** map from atom to the element in which it resides */
     PerAtomQuantity<int> * atomElement_;
 
     /** number of element */
     int nElts_;
 
     // workspace
     mutable INT_ARRAY _quantityLocal_;
 
   private:
 
     // do not define
     AtomTypeElement();
 
   };
 
   /**
    *  @class  ElementMask
    *  @brief  determines which elements should be used for FE quadrature
    */
   class ElementMask : public DenseMatrixTransfer<bool> {
 
   public:
     
     // constructor
     ElementMask(ATC_Coupling * atc,
                 MatrixDependencyManager<DenseMatrix, int> * hasInternal = NULL,
                 MatrixDependencyManager<DenseMatrix, int> * hasGhost = NULL);
     
     // destructor
     virtual ~ElementMask() {
       hasInternal_->remove_dependence(this);
       if (hasGhost_) hasGhost_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** shape function matrix over the internal atoms used to help define the geometry */
     MatrixDependencyManager<DenseMatrix, int> * hasInternal_;
 
     /** shape function matrix over the ghost atoms used to help define the geometry */
     MatrixDependencyManager<DenseMatrix, int> * hasGhost_;
 
     /** finite element engine */
     const FE_Engine * feEngine_;
 
   private:
 
     // do not define
     ElementMask();
 
   };
 
   /**
    *  @class  AtomElementMask
    *  @brief  determines which elements should be used for FE quadrature based on presence of atoms
    */
   class AtomElementMask : public DenseMatrixTransfer<bool> {
 
   public:
     
     // constructor
     AtomElementMask(ATC_Coupling * atc,
                     MatrixDependencyManager<DenseMatrix, int> * hasAtoms = NULL);
     
     // destructor
     virtual ~AtomElementMask() {
       hasAtoms_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** shape function matrix over the atoms used to help define the geometry */
     MatrixDependencyManager<DenseMatrix, int> * hasAtoms_;
 
     /** finite element engine */
     const FE_Engine * feEngine_;
 
   private:
 
     // do not define
     AtomElementMask();
 
   };
 
   /**
    *  @class  NodalGeometryType
    *  @brief  Computes the computational geometry associated with each node with respect to the FE and MD regions
    */
   
   class NodalGeometryType : public DenseMatrixTransfer<int> {
 
   public:
     
     // constructor
     NodalGeometryType(ATC_Coupling * atc,
                       MatrixDependencyManager<DenseMatrix, int> * hasInternal = NULL,
                       MatrixDependencyManager<DenseMatrix, int> * hasGhost = NULL);
     
     // destructor
     virtual ~NodalGeometryType() {
       hasInternal_->remove_dependence(this);
       if (hasGhost_) hasGhost_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** shape function matrix over the internal atoms used to help define the geometry */
     MatrixDependencyManager<DenseMatrix, int> * hasInternal_;
 
     /** shape function matrix over the ghost atoms used to help define the geometry */
     MatrixDependencyManager<DenseMatrix, int> * hasGhost_;
 
     /** finite element engine */
     const FE_Engine * feEngine_;
 
     /** number of nodes in the mesh */
     int nNodes_;
 
     /** number of elements in the mesh */
     int nElts_;
 
     // workspace
     // ints so they can be shared through MPI
     mutable Array<int> _nodesInternal_, _nodesGhost_;
 
   private:
 
     // do not define
     NodalGeometryType();
 
   };
 
   /**
    *  @class  NodalGeometryTypeElementSet
    *  @brief  Divdes nodes into MD, FE, and boundary based on if they are connected to nodes in internal and not internal
    */
   
   class NodalGeometryTypeElementSet : public DenseMatrixTransfer<int> {
 
   public:
     
     // constructor
     NodalGeometryTypeElementSet(ATC_Coupling * atc,
                                 MatrixDependencyManager<DenseMatrix, int> * hasInternal = NULL);
     
     // destructor
     virtual ~NodalGeometryTypeElementSet() {
       hasInternal_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** shape function matrix over the internal atoms used to help define the geometry */
     MatrixDependencyManager<DenseMatrix, int> * hasInternal_;
 
     /** finite element engine */
     const FE_Engine * feEngine_;
 
     /** number of nodes in the mesh */
     int nNodes_;
 
     /** number of elements in the mesh */
     int nElts_;
 
     // workspace
     // ints so they can be shared through MPI
     mutable Array<int> _nodesInternal_, _nodesGhost_;
 
   private:
 
     // do not define
     NodalGeometryTypeElementSet();
 
   };
 
   /**
    *  @class  LargeToSmallMap
    *  @brief  mapping from a larger set to a smaller set
    */
 
   class LargeToSmallMap : public DenseMatrixTransfer<int> {
 
   public:
     
     // constructor
     LargeToSmallMap() : size_(0) {};
     
     // destructor
     virtual ~LargeToSmallMap() {};
 
     /** get the number of elements associated with the map */
     virtual int size() const {this->quantity(); return size_;};
 
   protected:
 
     /** number of nodes in the map */
     mutable int size_;
 
   };
 
   /**
    *  @class  NodeToSubset
    *  @brief  mapping from all nodes to a subset 
    */
 
   class NodeToSubset : public LargeToSmallMap {
 
   public:
     
     // constructor
     NodeToSubset(ATC_Method * atc,
                  SetDependencyManager<int> * subsetNodes);
     
     // destructor
     virtual ~NodeToSubset() {
       subsetNodes_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
     
     /** pointer to atc to get the number of nodes */
     const ATC_Method * atc_;
 
     /** map from atom to the element in which it resides */
     SetDependencyManager<int> * subsetNodes_;
 
   private:
 
     // do not define
     NodeToSubset();
 
   };
 
   /**
    *  @class  SubsetToNode
    *  @brief  mapping from a subset of nodes to all nodes 
    */
 
   class SubsetToNode : public DenseMatrixTransfer<int> {
 
   public:
     
     // constructor
     SubsetToNode(NodeToSubset * nodeToSubset);
     
     // destructor
     virtual ~SubsetToNode() {
       nodeToSubset_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** map from atom to the element in which it resides */
     NodeToSubset * nodeToSubset_;
 
   private:
 
     // do not define
     SubsetToNode();
 
   };
 
   /**
    *  @class  ReducedSparseMatrix
    *  @brief  reduction of a sparse matrix to only those columns consistent with the map
    */
   
   class ReducedSparseMatrix : public SparseMatrixTransfer<double> {
 
   public:
     
     // constructor
     ReducedSparseMatrix(ATC_Method * atc,
                           SPAR_MAN * source,
                           LargeToSmallAtomMap * map);
     
     // destructor
     virtual ~ReducedSparseMatrix();
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** original quantity */
     SPAR_MAN * source_;
 
     /** mapping transfer */
     LargeToSmallAtomMap * map_;
 
     // workspace
     mutable DenseVector<double> _row_; // vector storing the row values of a matrix
     mutable DenseVector<INDEX> _index_; // vector storing the column indices of the values
 
   private:
 
     // do not define
     ReducedSparseMatrix();
 
   };
 
   /**
    *  @class  RowMappedSparseMatrix
    *  @brief  mapping of rows from a sparse matrix to a new sparse matrix
    */
   
   class RowMappedSparseMatrix : public ReducedSparseMatrix {
 
   public:
     
     // constructor
     RowMappedSparseMatrix(ATC_Method * atc,
                           SPAR_MAN * source,
                           LargeToSmallAtomMap * map) :
                ReducedSparseMatrix(atc,source,map) {};
     
     // destructor
     virtual ~RowMappedSparseMatrix() {};
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
   private:
 
     // do not define
     RowMappedSparseMatrix();
 
   };
 
   /**
    *  @class  RowMappedSparseMatrixVector
    *  @brief  mapping of rows from a vector sparse matrices to a new vector of sparse matrices
    */
   
   class RowMappedSparseMatrixVector : public VectorTransfer<SPAR_MAT * > {
 
   public:
     
     // constructor
     RowMappedSparseMatrixVector(ATC_Method * atc,
                                 VectorDependencyManager<SPAR_MAT * > * source,
                                 LargeToSmallAtomMap * map);
     
     // destructor
     virtual ~RowMappedSparseMatrixVector();
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** original quantity */
     VectorDependencyManager<SPAR_MAT * > * source_;
 
     /** mapping transfer */
     LargeToSmallAtomMap * map_;
 
     // workspace
     mutable DenseVector<double> _row_; // vector storing the row values of a matrix
     mutable DenseVector<INDEX> _index_; // vector storing the column indices of the values
 
   private:
 
     // do not define
     RowMappedSparseMatrixVector();
 
   };
 
   /**
    *  @class  MappedDiagonalMatrix
    *  @brief  mapping of a diagonal matrix to a new diagronal matrix
    */
   
   class MappedDiagonalMatrix : public DiagonalMatrixTransfer<double> {
 
   public:
     
     // constructor
     MappedDiagonalMatrix(ATC_Method * atc,
                          DIAG_MAN * source,
                          LargeToSmallAtomMap * map);
     
     // destructor
     virtual ~MappedDiagonalMatrix();
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** original quantity */
     DIAG_MAN * source_;
 
     /** mapping transfer */
     LargeToSmallAtomMap * map_;
 
   private:
 
     // do not define
     MappedDiagonalMatrix();
 
   };
 
   /**
    *  @class  MappedQuantity
    *  @brief  generic reduced mapping
    */
   
   class MappedQuantity : public DenseMatrixTransfer<double> {
 
   public:
     
     // constructor
     MappedQuantity(ATC_Method * atc,
                    DENS_MAN * source,
                    LargeToSmallMap * map);
     
     // destructor
     virtual ~MappedQuantity() {
       source_->remove_dependence(this);
       map_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** original quantity */
     DENS_MAN * source_;
 
     /** mapping transfer */
     LargeToSmallMap * map_;
 
   private:
 
     // do not define
     MappedQuantity();
 
   };
 
   /**
    *  @class  RegulatedNodes
    *  @brief  set of all nodes being controlled by an atomic regulator
    */
 
   class RegulatedNodes : public SetTransfer<int> {
 
   public:
     
     // constructor
     RegulatedNodes(ATC_Coupling * atc,
                    FieldName fieldName = NUM_TOTAL_FIELDS,
                    MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType = NULL);
     
     // destructor
     virtual ~RegulatedNodes() {
       nodalGeometryType_->remove_dependence(this);
     };
 
   protected:
 
     /** recomputes the set of regulated nodes based on prescribed data and atom locations */
     virtual void reset_quantity() const;
 
     /** map from fields to their sizes */
     std::map<FieldName,int> fieldSizes_;
 
     /** map from atom to element in which it resides */
     MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType_;
 
     /** pointer to atc object */
     ATC_Coupling * atc_;
 
     /** pointer to the finite element engine */
     const FE_Engine * feEngine_;
 
     /** pointer to the prescribed data manager */
     const PrescribedDataManager * prescribedDataManager_;
 
     // methods
     /** adds boundary nodes */
     void insert_boundary_nodes() const;
 
     /** adds nodes associated with boundary facesets */
     void insert_boundary_faces() const;
 
     /** adds fixed nodes */
     void insert_fixed_nodes() const;
 
     /** adds nodes associated with face fluxes */
     void insert_face_fluxes() const;
 
     /** adds nodes associated with element fluxes */
     void insert_element_fluxes() const;
 
   private:
 
     // do not define
     RegulatedNodes();
 
   };
 
   /**
    *  @class  FluxNodes
    *  @brief  set of all nodes being controlled by an atomic regulator for fluxes
    */
 
   class FluxNodes : public RegulatedNodes {
 
   public:
     
     // constructor
     FluxNodes(ATC_Coupling * atc,
               FieldName fieldName = NUM_TOTAL_FIELDS,
               MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType = NULL) :
                 RegulatedNodes(atc,fieldName,nodalGeometryType) {};
     
     // destructor
     virtual ~FluxNodes() {};
 
   protected:
 
     /** recomputes the set of regulated nodes based on prescribed data and atom locations */
     virtual void reset_quantity() const;
 
   private:
 
     // do not define
     FluxNodes();
 
   };
 
   /**
    *  @class  BoundaryNodes
    *  @brief  set of all nodes associated with the FE/MD boundary
    */
 
   class BoundaryNodes : public RegulatedNodes {
 
   public:
     
     // constructor
     BoundaryNodes(ATC_Coupling * atc,
                   FieldName fieldName = NUM_TOTAL_FIELDS,
                   MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType = NULL) :
                     RegulatedNodes(atc,fieldName,nodalGeometryType) {};
     
     // destructor
     virtual ~BoundaryNodes() {};
 
   protected:
 
     /** recomputes the set of regulated nodes based on prescribed data and atom locations */
     virtual void reset_quantity() const;
 
   private:
 
     // do not define
     BoundaryNodes();
 
   };
 
   /**
    *  @class  FluxBoundaryNodes
    *  @brief  set of all nodes being controlled by an atomic regulator for fluxes
    */
 
   class FluxBoundaryNodes : public FluxNodes {
 
   public:
     
     // constructor
     FluxBoundaryNodes(ATC_Coupling * atc,
                       FieldName fieldName = NUM_TOTAL_FIELDS,
                       MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType = NULL) :
                        FluxNodes(atc,fieldName,nodalGeometryType) {};
     
     // destructor
     virtual ~FluxBoundaryNodes() {};
 
   protected:
 
     /** recomputes the set of regulated nodes based on prescribed data and atom locations */
     virtual void reset_quantity() const;
 
   private:
 
     // do not define
     FluxBoundaryNodes();
 
   };
 
     /**
    *  @class  AllRegulatedNodes
    *  @brief  set of all nodes being controlled by an atomic regulator when localization is used
    */
 
   class AllRegulatedNodes : public FluxBoundaryNodes {
 
   public:
     
     // constructor
     AllRegulatedNodes(ATC_Coupling * atc,
                       FieldName fieldName = NUM_TOTAL_FIELDS,
                       MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType = NULL) :
                         FluxBoundaryNodes(atc,fieldName,nodalGeometryType) {};
     
     // destructor
     virtual ~AllRegulatedNodes() {};
 
   protected:
 
     /** recomputes the set of regulated nodes based on prescribed data and atom locations */
     virtual void reset_quantity() const;
 
   private:
 
     // do not define
     AllRegulatedNodes();
 
   };
 
     /**
    *  @class  FixedNodes
    *  @brief  set of all nodes being controlled by an atomic regulator which are fixed
    */
 
   class FixedNodes : public RegulatedNodes {
 
   public:
     
     // constructor
     FixedNodes(ATC_Coupling * atc,
                FieldName fieldName = NUM_TOTAL_FIELDS,
                MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType = NULL) :
                  RegulatedNodes(atc,fieldName,nodalGeometryType) {};
     
     // destructor
     virtual ~FixedNodes() {};
 
   protected:
 
     /** recomputes the set of regulated nodes based on prescribed data and atom locations */
     virtual void reset_quantity() const;
 
   private:
 
     // do not define
     FixedNodes();
 
   };
 
   /**
    *  @class  FixedBoundaryNodes
    *  @brief  set of all nodes being controlled by an atomic regulator which are fixed, including for coupling
    */
 
   class FixedBoundaryNodes : public FixedNodes {
 
   public:
     
     // constructor
     FixedBoundaryNodes(ATC_Coupling * atc,
                        FieldName fieldName = NUM_TOTAL_FIELDS,
                        MatrixDependencyManager<DenseMatrix, int> * nodalGeometryType = NULL) :
                          FixedNodes(atc,fieldName,nodalGeometryType) {};
     
     // destructor
     virtual ~FixedBoundaryNodes() {};
 
   protected:
 
     /** recomputes the set of regulated nodes based on prescribed data and atom locations */
     virtual void reset_quantity() const;
 
   private:
 
     // do not define
     FixedBoundaryNodes();
 
   };
 
   /**
    *  @class  ElementMaskNodeSet
    *  @brief  determines which elements should be used for FE quadrature based on them possessing certain nodes
    */
   class ElementMaskNodeSet : public DenseMatrixTransfer<bool> {
 
   public:
     
     // constructor
     ElementMaskNodeSet(ATC_Coupling * atc,
-                       RegulatedNodes * nodeSet);
+                       SetDependencyManager<int> * nodeSet);
 
     // destructor
     virtual ~ElementMaskNodeSet() {
       nodeSet_->remove_dependence(this);
     };
 
     /** apply transfer operator */
     virtual void reset_quantity() const;
 
   protected:
 
     /** transfer determining used nodes */
-    RegulatedNodes * nodeSet_;
+    SetDependencyManager<int> * nodeSet_;
 
     /** finite element mesh */
     const FE_Mesh * feMesh_;
 
   private:
 
     // do not define
     ElementMaskNodeSet();
 
   };
 
   /**
    *  @class  PointToElementMap
    *  @brief  Class for identifying the element associated with a given point
    */
 
   class PointToElementMap : public DenseMatrixTransfer<int> {
 
   public:
 
     // constructor
     PointToElementMap(ATC_Method * atc,
                       MatrixDependencyManager<DenseMatrix, double> * pointPositions);
 
     // destructor
     virtual ~PointToElementMap();
 
   protected:
 
     /** resets the data if necessary */
     virtual void reset_quantity() const;
 
     /** point positions */
     MatrixDependencyManager<DenseMatrix, double> * pointPositions_;
 
     /** pointer to finite element mesh */
     const FE_Mesh * feMesh_;
 
   private:
 
     // do not define
     PointToElementMap();
 
   };
 
   /**
    *  @class  Interpolant
    *  @brief  constructs the spatial values of the shape functions
    */
   
   class Interpolant : public SparseMatrixTransfer<double> {
 
   public:
 
     // constructor
     Interpolant(ATC_Method * atc,
                 MatrixDependencyManager<DenseMatrix, int>* pointToElementMap,
                 DENS_MAN* pointPositions); 
     
     // destructor
     virtual ~Interpolant() {
       pointToElementMap_->remove_dependence(this);
       pointPositions_->remove_dependence(this);
     };
 
   protected:
 
     /** does the actual computation of the quantity */
     virtual void reset_quantity() const;
 
   protected:
 
     /** map from point coordinates to element */
     MatrixDependencyManager<DenseMatrix, int>* pointToElementMap_;
 
     /** coordinates used to evaluate shape functions */
     DENS_MAN* pointPositions_;
 
     /** pointer to the FE engine */
     const FE_Engine * feEngine_;
 
   private:
 
     // do not define
     Interpolant();
 
   };
 
   /**
    *  @class  InterpolantGradient
    *  @brief  constructs the spatial derivatives of the shape functions
    */
   
   class InterpolantGradient : public VectorTransfer<SPAR_MAT * > {
 
   public:
 
     // constructor
     InterpolantGradient(ATC_Method * atc,
                         MatrixDependencyManager<DenseMatrix, int>* pointToElementMap,
                         DENS_MAN* pointPositions); 
     
     // destructor
     virtual ~InterpolantGradient();
 
   protected:
 
     /** does the actual computation of the quantity */
     virtual void reset_quantity() const;
 
   protected:
 
     /** map from point coordinates to element */
     MatrixDependencyManager<DenseMatrix, int>* pointToElementMap_;
 
     /** coordinates used to evaluate shape functions */
     DENS_MAN* pointPositions_;
 
     /** pointer to the FE engine */
     const FE_Engine * feEngine_;
 
   private:
 
     // do not define
     InterpolantGradient();
 
   };
 
   /**
    *  @class  PerAtomShapeFunctionGradient
    *  @brief  constructs the spatial derivatives of the shape functions at each atom
    */
   
   class PerAtomShapeFunctionGradient : public VectorTransfer<SPAR_MAT * > {
 
   public:
 
     // constructor
     PerAtomShapeFunctionGradient(ATC_Method * atc,
                                  MatrixDependencyManager<DenseMatrix, int>* atomToElementMap = NULL,
                                  DENS_MAN* atomPositions = NULL,
                                  const std::string & tag = "AtomicShapeFunctionGradient",
                                  AtomType atomType = INTERNAL); 
     
     // destructor
     virtual ~PerAtomShapeFunctionGradient();
 
   protected:
 
     /** does the actual computation of the quantity */
     virtual void reset_quantity() const;
 
   protected:
 
     /** map from point coordinates to element */
     MatrixDependencyManager<DenseMatrix, int>* atomToElementMap_;
 
     /** coordinates used to evaluate shape functions */
     DENS_MAN* atomPositions_;
 
     /** pointer to the FE engine */
     const FE_Engine * feEngine_;
 
     /** container for dependency managers */
     std::vector<AtcAtomSparseMatrix<double> * > matrices_;
 
   private:
 
     // do not define
     PerAtomShapeFunctionGradient();
 
   };
 
   /**
    *  @class  InterpolantSmallMolecule
    *  @brief  constructs the spatial values of the shape functions for small molecules
    */
   
   class InterpolantSmallMolecule : public Interpolant {
 
   public:
 
     // constructor
     InterpolantSmallMolecule(ATC_Method * atc,
                              MatrixDependencyManager<DenseMatrix, int>* moleculeToElementMap,
                              DENS_MAN* moleculePositions,
                              MoleculeSet * moleculeSet); 
     
     // destructor
     virtual ~InterpolantSmallMolecule();
 
   protected:
 
     /** does the actual computation of the quantity */
     virtual void reset_quantity() const;
 
   protected:
 
     /** pointer to atc base class */
     MoleculeSet * moleculeSet_;
 
     // workspace
     mutable DENS_VEC _fractions_;
 
   private:
 
     // do not define
     InterpolantSmallMolecule();
 
   };
 
 
 
   /**
    *  @class  DenseMatrixQuotient
    *  @brief  quotient of two matrices
    */
 
   class DenseMatrixQuotient : public DenseMatrixTransfer<double> {
 
   public:
     
     // constructor
     DenseMatrixQuotient(DENS_MAN * matrixNumerator, DENS_MAN * matrixDenominator);
     
     // destructor
     virtual ~DenseMatrixQuotient() {
       matrixNumerator_->remove_dependence(this);
       matrixDenominator_->remove_dependence(this);
     };
 
     /** apply transfer operator  */
     virtual void reset_quantity() const;
 
     /** get number of columns */
     virtual int nCols() const {return matrixNumerator_->nCols();};
 
   protected:
   
     DENS_MAN* matrixNumerator_; 
     DENS_MAN* matrixDenominator_;
 
   private:
 
     // do not define
     DenseMatrixQuotient();
 
   };
 
   /**
    *  @class  DenseMatrixSum
    *  @brief  sum of two matrices
    */
 
   class DenseMatrixSum : public DenseMatrixTransfer<double> {
 
   public:
     
     // constructor
     DenseMatrixSum(DENS_MAN * matrixOne, DENS_MAN * matrixTwo);
     
     // destructor
     virtual ~DenseMatrixSum() {
       matrixOne_->remove_dependence(this);
       matrixTwo_->remove_dependence(this);
     };
 
     /** apply transfer operator  */
     virtual void reset_quantity() const;
 
     /** get number of columns */
     virtual int nCols() const {return matrixOne_->nCols();};
 
   protected:
   
     DENS_MAN* matrixOne_; 
     DENS_MAN* matrixTwo_;
 
   private:
 
     // do not define
     DenseMatrixSum();
 
   };
 
   /**
    *  @class  DenseMatrixDelta
    *  @brief change relative to a reference value
    */
 
   class DenseMatrixDelta : public DenseMatrixTransfer<double> {
 
   public:
     
     // constructor
     DenseMatrixDelta(DENS_MAN * current, DENS_MAT * reference);
     
     // destructor
     virtual ~DenseMatrixDelta() {
       matrix_->remove_dependence(this);
     };
 
     /** apply transfer operator  */
     virtual void reset_quantity() const;
 
   protected:
   
     DENS_MAN* matrix_; 
     DENS_MAT* reference_;
 
   private:
 
     // do not define
     DenseMatrixDelta();
 
   };
 
   /**
    *  @class  OnTheFlyKernelAccumulation
    *  @brief  implements the accumulant on the fly
    */
   
   class OnTheFlyKernelAccumulation : public DenseMatrixTransfer<double> {
 
   public:
 
     // constructor
     OnTheFlyKernelAccumulation(ATC_Method * atc,
                                PerAtomQuantity<double> * source,
                                KernelFunction* kernelFunction,
                                DENS_MAN* atomCoarseGrainingPositions); 
     
     // destructor
     virtual ~OnTheFlyKernelAccumulation() {
       source_->remove_dependence(this);
       atomCoarseGrainingPositions_->remove_dependence(this);
     };
 
     /** do nothing */
     virtual void reset_quantity() const;
 
   protected:
 
     /** pointer to atc base class */
     const ATC_Method * atc_;
 
     /** pointer to source data */
     PerAtomQuantity<double> * source_;
 
     /** map from atom coordinates to element */
     KernelFunction* kernelFunction_;
 
     /** atomic coordinates used for coarse graining operations */
     DENS_MAN* atomCoarseGrainingPositions_;
 
     /** access to mesh */
     const FE_Mesh * feMesh_;
 
     // workspace
     mutable DENS_MAT _quantityLocal_;
 
   private:
 
     // do not define
     OnTheFlyKernelAccumulation();
 
   };
 
   /**
    *  @class  OnTheFlyKernelAccumulationNormalized
    *  @brief  implements a normalized accumulant on the fly
    */
   
   class OnTheFlyKernelAccumulationNormalized : public OnTheFlyKernelAccumulation {
 
   public:
 
     // constructor
     OnTheFlyKernelAccumulationNormalized(ATC_Method * atc,
                                PerAtomQuantity<double> * source,
                                KernelFunction* kernelFunction,
                                DENS_MAN* atomCoarseGrainingPositions,
                                DIAG_MAN* weights);
     
     // destructor
     virtual ~OnTheFlyKernelAccumulationNormalized() {
       weights_->remove_dependence(this);
     };
 
     /** do nothing */
     virtual void reset_quantity() const;
 
   protected:
 
     DIAG_MAN * weights_;
 
   private:
 
     // do not define
     OnTheFlyKernelAccumulationNormalized();
 
   };
 
   /**
    *  @class  OnTheFlyKernelAccumulationNormalizedReferenced
    *  @brief  implements a normalized referenced accumulant on the fly
    */
   
   class OnTheFlyKernelAccumulationNormalizedReferenced : public OnTheFlyKernelAccumulationNormalized {
 
   public:
 
     // constructor
     OnTheFlyKernelAccumulationNormalizedReferenced(ATC_Method * atc,
                                PerAtomQuantity<double> * source,
                                KernelFunction* kernelFunction,
                                DENS_MAN* atomCoarseGrainingPositions,
                                DIAG_MAN* weights,
                                DENS_MAN * reference);
     
     // destructor
     virtual ~OnTheFlyKernelAccumulationNormalizedReferenced() {
       reference_->remove_dependence(this);
     };
 
     /** do nothing */
     virtual void reset_quantity() const;
 
   protected:
 
     /** reference value */
     DENS_MAN * reference_;
 
   private:
 
     // do not define
     OnTheFlyKernelAccumulationNormalizedReferenced();
 
   };
 
   /**
    *  @class  OnTheFlyKernelNormalizedAccumulationScaled
    *  @brief  implements a scaled accumulant on the fly
    */
   
   class OnTheFlyKernelAccumulationNormalizedScaled : public OnTheFlyKernelAccumulationNormalized {
 
   public:
 
     // constructor
     OnTheFlyKernelAccumulationNormalizedScaled(ATC_Method * atc,
                                PerAtomQuantity<double> * source,
                                KernelFunction* kernelFunction,
                                DENS_MAN* atomCoarseGrainingPositions,
                                DIAG_MAN* weights,
                                const double scale);
     
     // destructor
     virtual ~OnTheFlyKernelAccumulationNormalizedScaled() {
       atomCoarseGrainingPositions_->remove_dependence(this);
     };
 
     /** do nothing */
     virtual void reset_quantity() const;
 
   protected:
 
     const double scale_;
 
   private:
 
     // do not define
     OnTheFlyKernelAccumulationNormalizedScaled();
 
   };
 
   /**
    *  @class  AccumulantWeights
    *  @brief  weights for kernel function accumulants
    */
 
   class AccumulantWeights : public DiagonalMatrixTransfer<double> {
 
   public:
     
     // constructor
     AccumulantWeights(SPAR_MAN * accumulant);
     
     // destructor
     virtual ~AccumulantWeights() {
       accumulant_->remove_dependence(this);
     };
 
     /** apply transfer operator  */
     virtual void reset_quantity() const;
 
   protected:
   
     SPAR_MAN* accumulant_;
 
     // workspace
     mutable DENS_VEC _localWeights_;
     mutable DENS_VEC _weights_;
 
   private:
 
     // do not define
     AccumulantWeights();
 
   };
 
   /**
    *  @class  OnTheFlyKernelWeights
    *  @brief  weights for on-the-fly kernel function
    */
 
   class OnTheFlyKernelWeights : public DiagonalMatrixTransfer<double> {
 
   public:
     
     // constructor
     OnTheFlyKernelWeights(DENS_MAN * weights);
     
     // destructor
     virtual ~OnTheFlyKernelWeights() {
       weights_->remove_dependence(this);
     };
 
     /** apply transfer operator  */
     virtual void reset_quantity() const;
 
   protected:
   
     DENS_MAN* weights_;
 
   private:
 
     // do not define
     OnTheFlyKernelWeights();
 
   };
 
   /**
    *  @class  KernelInverseVolumes
    *  @brief  inverse volumes for kernel function accumulants
    */
 
   class KernelInverseVolumes : public DiagonalMatrixTransfer<double> {
 
   public:
     
     // constructor
     KernelInverseVolumes(ATC_Method * atc,
                          KernelFunction* kernelFunction);
     
     // destructor
     virtual ~KernelInverseVolumes() {};
 
     /** apply transfer operator  */
     virtual void reset_quantity() const;
 
   protected:
   
     /** kernel function being used */
     KernelFunction* kernelFunction_;
 
     /** access to mesh */
     const FE_Mesh * feMesh_;
 
   private:
 
     // do not define
     KernelInverseVolumes();
 
   };
 
   /**
    *  @class  OnTheFlyMeshAccumulation
    *  @brief  implements the mesh-based accumulant on the fly
    */
   
   class OnTheFlyMeshAccumulation : public DenseMatrixTransfer<double> {
 
   public:
 
     // constructor
     OnTheFlyMeshAccumulation(ATC_Method * atc,
                              PerAtomQuantity<double> * source,
                              DENS_MAN* atomCoarseGrainingPositions); 
     
     // destructor
     virtual ~OnTheFlyMeshAccumulation() {
       source_->remove_dependence(this);
       atomCoarseGrainingPositions_->remove_dependence(this);
     };
 
     /** do nothing */
     virtual void reset_quantity() const;
 
     /** access nCols_ */
     virtual int nCols() const { return source_->nCols(); } 
 
   protected:
 
     /** pointer to atc base class */
     const ATC_Method * atc_;
 
     /** pointer to source data */
     PerAtomQuantity<double> * source_;
 
     /** atomic coordinates used for coarse graining operations */
     DENS_MAN* atomCoarseGrainingPositions_;
 
     /** access to mesh */
     const FE_Mesh * feMesh_;
 
     // workspace
     mutable DENS_MAT _quantityLocal_;
 
   private:
 
     // do not define
     OnTheFlyMeshAccumulation();
 
   };
 
   /**
    *  @class  OnTheFlyMeshAccumulationNormalized
    *  @brief  implements a normalized mesh-based accumulant on the fly
    */
   
   class OnTheFlyMeshAccumulationNormalized : public OnTheFlyMeshAccumulation {
 
   public:
 
     // constructor
     OnTheFlyMeshAccumulationNormalized(ATC_Method * atc,
                                PerAtomQuantity<double> * source,
                                DENS_MAN* atomCoarseGrainingPositions,
                                DIAG_MAN* weights);
     
     // destructor
     virtual ~OnTheFlyMeshAccumulationNormalized() {
       weights_->remove_dependence(this);
     };
 
     /** do nothing */
     virtual void reset_quantity() const;
 
   protected:
 
     DIAG_MAN * weights_;
 
   private:
 
     // do not define
     OnTheFlyMeshAccumulationNormalized();
 
   };
 
   /**
    *  @class  OnTheFlyMeshAccumulationNormalizedReferenced
    *  @brief  implements a normalized referenced mesh-based accumulant on the fly
    */
   
   class OnTheFlyMeshAccumulationNormalizedReferenced : public OnTheFlyMeshAccumulationNormalized {
 
   public:
 
     // constructor
     OnTheFlyMeshAccumulationNormalizedReferenced(ATC_Method * atc,
                                PerAtomQuantity<double> * source,
                                DENS_MAN* atomCoarseGrainingPositions,
                                DIAG_MAN* weights,
                                DENS_MAN * reference);
     
     // destructor
     virtual ~OnTheFlyMeshAccumulationNormalizedReferenced() {
       reference_->remove_dependence(this);
     };
 
     /** do nothing */
     virtual void reset_quantity() const;
 
   protected:
 
     /** reference value */
     DENS_MAN * reference_;
 
   private:
 
     // do not define
     OnTheFlyMeshAccumulationNormalizedReferenced();
 
   };
 
   /**
    *  @class  OnTheFlyMeshAccumulationNormalizedScaled
    *  @brief  implements a scaled mesh-based accumulant on the fly
    */
   
   class OnTheFlyMeshAccumulationNormalizedScaled : public OnTheFlyMeshAccumulationNormalized {
 
   public:
 
     // constructor
     OnTheFlyMeshAccumulationNormalizedScaled(ATC_Method * atc,
                                PerAtomQuantity<double> * source,
                                DENS_MAN* atomCoarseGrainingPositions,
                                DIAG_MAN* weights,
                                const double scale);
     
     // destructor
     virtual ~OnTheFlyMeshAccumulationNormalizedScaled() {
       atomCoarseGrainingPositions_->remove_dependence(this);
     };
 
     /** do nothing */
     virtual void reset_quantity() const;
 
   protected:
 
     const double scale_;
 
   private:
 
     // do not define
     OnTheFlyMeshAccumulationNormalizedScaled();
 
   };
 
   /**
    *  @class  NativeShapeFunctionGradient
    *  @brief  constructs the spatial derivatives of the shape functions
    */
   
   class NativeShapeFunctionGradient : public VectorTransfer<SPAR_MAT * > {
 
   public:
 
     // constructor
     NativeShapeFunctionGradient(ATC_Method * atc);
     
     // destructor
     virtual ~NativeShapeFunctionGradient();
 
   protected:
 
     /** does the actual computation of the quantity */
     virtual void reset_quantity() const;
 
   protected:
 
     /** pointer to the FE engine */
     const FE_Engine * feEngine_;
 
   private:
 
     // do not define
     NativeShapeFunctionGradient();
 
   };
 
   /**
    *  @class  OnTheFlyShapeFunctionProlongation
    *  @brief  implements the interpolant on the fly
    */
   
   class OnTheFlyShapeFunctionProlongation : public FeToAtomTransfer {
 
   public:
 
     // constructor
     OnTheFlyShapeFunctionProlongation(ATC_Method * atc,
                                       DENS_MAN * source,
                                       DENS_MAN * atomCoarseGrainingPositions); 
     
     // destructor
     virtual ~OnTheFlyShapeFunctionProlongation();
 
     /** do nothing */
     virtual void reset() const;
 
   protected:
 
     /** pointer to atc base class */
     //const ATC_Method * atc_;
 
     /** pointer to source data */
     //DENS_MAN * source_;
 
     /** atomic coordinates used for coarse graining operations */
     DENS_MAN* atomCoarseGrainingPositions_;
 
     /** access to mesh */
     const FE_Mesh * feMesh_;
 
     // workspace
     //mutable DENS_MAT _quantityLocal_;
 
   private:
 
     // do not define
     OnTheFlyShapeFunctionProlongation();
 
   };
 
 }
 #endif
diff --git a/lib/atc/Utility.h b/lib/atc/Utility.h
index aa5104293..f3bbd7d1f 100644
--- a/lib/atc/Utility.h
+++ b/lib/atc/Utility.h
@@ -1,305 +1,334 @@
 #ifndef UTILITY_H
 #define UTILITY_H
 
 #include <iostream>
 #include <ctime>
 #include <limits>
 #undef near
 
 #include <vector>
 #include <fstream>
 #include <cstring>
 #include <string>
 #include <sstream>
 #include <iomanip>
 #include <algorithm>
 #include "math.h"
 
 #include "ATC_Error.h"
 
 namespace ATC_Utility
 {
   /** constants */
-  static const double Pi = 4.0*atan(1.0);
-  static const double Big = 1.e20;
-  const static double parsetol = 1.0e-10;  
-  const static double parsebig = 1.0e10;
+  static const double Pi_ = 4.0*atan(1.0);
+  static const double Big_ = 1.e20;
+  const static double parsetol_ = 1.0e-8; 
+  //const static double parsetol_ = 1.0e-10; 
+  const static double parsebig_ = 1.0e10;
 
   /** scalar triple product */
   inline double det3(double * v1, double * v2, double * v3) {
     return
      -v1[2]*v2[1]*v3[0] + v1[1]*v2[2]*v3[0] + v1[2]*v2[0]*v3[1]
      -v1[0]*v2[2]*v3[1] - v1[1]*v2[0]*v3[2] + v1[0]*v2[1]*v3[2];
   }
   inline void plane_coords(int i, int & i1, int & i2) {
     if      (i==0) { i1 = 1; i2 = 2; }
     else if (i==1) { i1 = 2; i2 = 0; }
     else if (i==2) { i1 = 0; i2 = 1; }
   }
   /** 2d cross product */
   inline double cross2(double * v1, double * v2) {
     return v1[0]*v2[1] - v1[1]*v2[0];
   }
   /** 3d cross product */
   inline void cross3(double * v1, double * v2, double * v) {
     v[0] = v1[1]*v2[2] - v1[2]*v2[1];
     v[1] = v1[2]*v2[0] - v1[0]*v2[3];
     v[2] = v1[0]*v2[1] - v1[1]*v2[0];
   }
   inline double norm3(double * v) {return sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); }
 
   inline int sgn(double x) { return (int) ((x>0) - (x<0)); }
+//  template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); }
   inline int rnd(double x) { return (int) (x+sgn(x)*0.5); }
 
   /** Compares doubles acceptably */
   inline bool dbl_geq(double dblL, double dblR, int tolMult=2)
   {
     return ( (dblL >   dblR) ||
             ((dblL <= (dblR + \
                        std::numeric_limits<double>::epsilon() * \
                        tolMult * std::max(abs(dblL), abs(dblR)))) && 
              (dblR <= (dblL + \
                        std::numeric_limits<double>::epsilon() * \
                        tolMult * std::max(abs(dblL), abs(dblR))))));
   }
 
-    
+  inline double tolerance(double x, double tol = parsetol_) {
+    return std::max(tol,tol*fabs(x));    
+  }
+  inline double nudge_up(double x)   { return x+tolerance(x); }
+  inline double nudge_down(double x) { return x-tolerance(x); }
   inline double parse_min(const char * arg) {
-    if (std::strcmp(arg,"INF") == 0)  return -parsebig;
-    else                         return atof(arg);  }   
+    if      (std::strcmp(arg,"INF") == 0)  return -parsebig_;
+    else if (std::strcmp(arg,"-INF") == 0) return -parsebig_;
+    else                                   return (atof(arg)); 
+  } 
   inline double parse_max(const char * arg) {    
-     if (std::strcmp(arg,"INF") == 0)  return parsebig;    
-     else                         return atof(arg);
+     if (std::strcmp(arg,"INF") == 0)  return parsebig_;    
+     else                              return (atof(arg));
   }   
   inline double parse_minmax(const char * arg) {
-    if      (std::strcmp(arg,"-INF") == 0)  return -parsebig;
-    else if (std::strcmp(arg,"INF") == 0)   return  parsebig;
-    else                         return atof(arg);  }   
+    if      (std::strcmp(arg,"-INF") == 0)  return -parsebig_;
+    else if (std::strcmp(arg,"INF") == 0)   return  parsebig_;
+    else                         return atof(arg);  
+  }   
   inline void split_values(double & min, double & max) {
-    double eps = std::max(parsetol,parsetol*fabs(min));    
-    min -= eps;
-    max += eps;
+    min = nudge_down(min);
+    max = nudge_up(max);
   }   
     
 
   /** Returns true if the value v is between min &  max */
   template<typename T>
   inline bool in_range(const T &v, const T &min, const T &max)
   {
     return v >= min && v <= max;
   }
   /** Returns true if the value v is between min & max within tolerance TOL */
   template<typename T>
   inline bool in_range(const T &v, const T &min, const T &max, const T &tol)
   {
     return in_range(v, min-tol, max+tol);
   }
   /** Returns the value with the larger absolute value */
   template<typename T>
   inline T max_abs(const T &a, const T &b)
   {
     return (a*a > b*b) ? a : b;
   }
   /** Returns the value with the smaller absolute value */
   template<typename T>
   inline T min_abs(const T &a, const T &b)
   {
     return (a*a < b*b) ? a : b;
   }
   /** A simple Matlab like timing function */
   inline double tictoc()
   {
     double t_new = clock() / (double) CLOCKS_PER_SEC;
     static double t = t_new;
     double dt = t_new - t;
     t = t_new;
     return dt; 
   }
   /** A simple timer */
   inline double timer()
   {
     double t_new = clock() / (double) CLOCKS_PER_SEC;
     static double t = t_new; // done once at first time the function is evoked
     double dt = t_new - t;
     return dt; 
   }
   /** Binary search between low & high for value (assumes array is sorted) */
   
   template<typename T>
   inline int search_sorted(const T* A, T value, int low, int high)
   {
     int mid;
     while (low < high)
     {
      mid = (low + high) >> 1;                 // set mid to mean of high and low, ">>" is a bit shift which divides by 2, rounding down
      if (A[mid] > value)       high = mid;  // mid was too high, reduce high
      else if (A[mid] < value)  low = mid+1;   // mid was too low, increase low
      else return mid;
     }
     return -1; // value not found in array, return -1
   }
   /** Flat search between low & high for value (assumes array is NOT sorted) */
   template<typename T>
   inline int search_unsorted(const T* A, T value, int low, int high)
   {
     for (int i=low; i<high; i++) if (A[i] == value) return i;
     return -1;
   }
   /** Regular swap */
   template<typename T>
   inline void swap(T &a, T &b)
   {
     T temp = a;
     a = b;
     b = temp;
   }
 
 
   //===================================================================
   /** A collection of string convesion/manipulation routines  */
   //===================================================================
 
 
   /** converts anything that has iostream::<< defined to a string  */
   template<typename T>
   inline std::string to_string(const T &v, int precision=0)
   {
     std::ostringstream out;
-    if (precision) out << std::setprecision(precision);
+    if (precision) {
+      out << std::setprecision(precision);
+      out << std::setw(precision+3);
+      out << std::showpoint;
+    }
     out << v;
+    out << std::noshowpoint;
     return out.str();
   }
 
+  /** formatted double to a string  */
+  inline std::string to_string(int precision, const double v)
+  {
+    char b[50];
+    sprintf(b, "%*.*f",4+precision,precision, v); 
+    std::string s(b);
+    return s;
+  }
+
   /** conversion to string */
   inline std::string true_false(const double &v)
   {
     if (v) return "TRUE";
     else   return "FALSE";
   }
 
   /** test conversion to double */
   inline bool is_numeric(const std::string &s)
   {
     double v;
     std::istringstream in(s);
     return (in >> v);
   }
 
   /** convert a string to anything that has iostream::>> defined, second arg is to disambibuate type */
   template<typename T>
   inline T str2T(const std::string &s, T v)
   {
     std::istringstream in(s);
     if (!(in >> v)) throw ATC::ATC_Error("str2T invalid string conversion");
     return v;
   }
 
   /** convert a string to a double */
   inline double str2dbl(const std::string &s) { return str2T(s, double(0.0)); }
 
   /** tests if conversion to double is possible */
   inline bool is_dbl(const std::string &s) 
   {
     char *endptr;
     strtod(s.c_str(), &endptr);
     if(endptr != NULL && *endptr == '\0') return true;
     return false;
   }
+
+  inline bool is_number(const std::string& s)
+  {
+    std::string::const_iterator it = s.begin();
+    while (it != s.end() && std::isdigit(*it)) ++it;
+    return !s.empty() && it == s.end();
+  }
   
   /** convert a string to an int */
   inline int str2int(const std::string &s)    { return str2T(s, int(4)); }
 
   //* replaces all characters in a set of characters with a character
   //* @param str input string
   //* @param *s pointer to array of characters that will be replaced
   //* @param r character to replace characters in s[] with
   static void replace_all_of(std::string &str, const char *s, const char r)
   {
      size_t found;
      found = str.find_first_of(s);
      while (found != std::string::npos)
      {
         str[found] = r;
         found = str.find_first_of(s, found+1);
      }
   }
 
   /** converts the string to lowercase */
   inline std::string& to_lower(std::string &s)
   {
     std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(tolower));
     return s;
   }
 
   /** converts the string to uppercase */
   inline std::string& to_upper(std::string &s)
   {
     std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(toupper));
     return s;
   }
   
   /** removes any whitespace from the beginning or end of string */
   static std::string& trim(std::string &s)
   {
     if (s.empty()) return s;
     size_t found = s.find_last_not_of(" \t\n");
     if (found < s.size()-1) s.erase(found+1);
     found = s.find_first_not_of(" \t\n");
     if (found != std::string::npos) s = s.substr(found);
     return s;
   }
 
   /** splits delimited string into a vector of strings */
   static void split(const std::string &s, std::vector<std::string> &ss, char del=' ')
   {
     ss.clear();
     size_t begin=0, end=0;
     while (end != std::string::npos)
     {
       begin = s.find_first_not_of(del, end);     // find beginning of fragment
       end = s.find_first_of(del,begin);
       if (begin != std::string::npos)                 // safe if end is npos-1 
         ss.push_back(s.substr(begin,end-begin)); 
     }
   } 
 
   static std::string cap(std::string & s) {
     s[0] = toupper(s[0]);
     return s;
   }
 
   /* turns Aa_Bb_Cc into aa_bb_cc */
   static std::string to_cap(const std::string &s) {
     std::vector<std::string> words;
     std::string delimiter = "_";
     split(s,words,(delimiter.c_str())[0]);
     std::string name = "";
     for (unsigned int i = 0; i < words.size(); i++) {
       name = name + cap(words[i]);
     }
     return name;
   }
   
   //* scans a string for a list of commands delimited by ', \t' with # comments
   //* @param line The input line to be parsed
   //* @cs A vector of strings parsed from the input line
   static void command_strings(std::string line, std::vector<std::string> &cs)
   {
     if (line.find('#') != std::string::npos)  line.erase(line.find("#"));
     replace_all_of(line, "\t,", ' ');
     to_lower(trim(line));
     split(line, cs);
   }
  
   //* reads a single line from a file and splits it into a vector of strings
   //* returns the number of strings in the vector
   inline int command_line(std::fstream &fid, std::vector<std::string> &cs)
   {
      std::string line;
      getline(fid, line);
      command_strings(line, cs);
      return cs.size();
   }
 }
 
 #endif
diff --git a/lib/atc/Vector.h b/lib/atc/Vector.h
index 5630b0ee1..338183d00 100644
--- a/lib/atc/Vector.h
+++ b/lib/atc/Vector.h
@@ -1,206 +1,234 @@
 #ifndef VECTOR_H
 #define VECTOR_H
 
 #include "Matrix.h"
 
 namespace ATC_matrix {
 
 ///////////////////////////////////////////////////////////////////////////////
 // forward declarations ///////////////////////////////////////////////////////
 
 //* Matrix-vector product
 //template<typename T>
 //void MultMv(const Matrix<T> &A, const Vector<T> &v, DenseVector<T> &c, 
 //            const bool At=0, T a=1, T b=0);
 
 /******************************************************************************
 * abstract class Vector
 ******************************************************************************/
 
 
 template<typename T>
 class Vector : public Matrix<T>
 {
 public:
   Vector() {}
   Vector(const Vector<T> &c); // do not implement!
   virtual ~Vector() {}
 
   std::string to_string() const;
 
   // pure virtual functions
   virtual T  operator()(INDEX i, INDEX j=0) const=0;
   virtual T& operator()(INDEX i, INDEX j=0)      =0;
   virtual T  operator[](INDEX i)            const=0;
   virtual T& operator[](INDEX i)                 =0;
   virtual INDEX nRows()                     const=0;
   virtual T* ptr()                      const=0;
   virtual void resize(INDEX nRows, INDEX nCols=1, bool copy=0)=0;
   virtual void  reset(INDEX nRows, INDEX nCols=1, bool zero=0)=0;
   virtual void copy(const T * ptr, INDEX nRows, INDEX nCols=1)=0;
   void write_restart(FILE *f)               const; // will be virtual
 
   
   // output to matlab
   using Matrix<T>::matlab;
   void matlab(std::ostream &o, const std::string &s="v") const;
 
   using Matrix<T>::operator=;
   INDEX nCols()                   const;
   bool in_range(INDEX i)          const;
   bool same_size(const Vector &m) const;
   static bool same_size(const Vector &a, const Vector &b);
 
  protected:
+  void _set_equal(const Matrix<T> &r);
   //* don't allow this
   Vector& operator=(const Vector &r);
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 //* performs a matrix-vector multiply with default naive implementation
 template<typename T>
 void MultMv(const Matrix<T> &A, const Vector<T> &v, DenseVector<T> &c, 
             const bool At, T a, T b)
 {
   const INDEX sA[2] = {A.nRows(), A.nCols()};  // m is sA[At] k is sA[!At]
   const INDEX M=sA[At], K=sA[!At];
   GCK(A, v, v.size()!=K, "MultAb<T>: matrix-vector multiply");
   if (c.size() != M)
   {
     c.resize(M);             // set size of C
     c.zero();                // do not add result to C
   }
   else c *= b;
   for (INDEX p=0; p<M; p++)
     for (INDEX r=0; r<K; r++)
        c[p] += A(p*!At+r*At, p*At+r*!At) * v[r];
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* Operator for Matrix-vector product
 template<typename T>
 DenseVector<T> operator*(const Matrix<T> &A, const Vector<T> &b)
 {
   DenseVector<T> c;
   MultMv(A, b, c, 0, 1.0, 0.0);
   return c;
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* Operator for Vector-matrix product
 template<typename T>
 DenseVector<T> operator*(const Vector<T> &a, const Matrix<T> &B)
 {
   DenseVector<T> c;
   MultMv(B, a, c, 1, 1.0, 0.0);
   return c;
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* Multiply a vector by a scalar 
 template<typename T>
 DenseVector<T> operator*(const Vector<T> &v, const T s)
 {
   DenseVector<T> r(v);
   r*=s; 
   return r;
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* Multiply a vector by a scalar - communitive
 template<typename T>
 DenseVector<T> operator*(const T s, const Vector<T> &v)
 {
   DenseVector<T> r(v);
   r*=s; 
   return r;
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* inverse scaling operator - must always create memory
 template<typename T>
 DenseMatrix<T> operator/(const Vector<T> &v, const T s)
 {
   DenseVector<T> r(v);
   r*=(1.0/s); // for integer types this may be worthless
   return ;
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* Operator for Vector-Vector sum
 template<typename T>
 DenseVector<T> operator+(const Vector<T> &a, const Vector<T> &b)
 {
   DenseVector<T> c(a);
   c+=b;
   return c;
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* Operator for Vector-Vector subtraction
 template<typename T>
 DenseVector<T> operator-(const Vector<T> &a, const Vector<T> &b)
 {
   DenseVector<T> c(a);
   c-=b;
   return c;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Template definitions ///////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 //* output operator
 template<typename T>
 std::string Vector<T>::to_string() const
 {
   std::string s;
   int sz = this->size(); 
   for (INDEX i = 0; i < sz; i++) 
     s += std::string(i?"\t":"") + ATC_Utility::to_string((*this)[i],myPrecision);
   return s;
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* Writes a matlab script defining the vector to the stream
 template<typename T>
 void Vector<T>::matlab(std::ostream &o, const std::string &s) const
 {
   o << s <<"=zeros(" << this->size() << ",1);\n";
   int sz = this->size(); 
   for (INDEX i = 0; i < sz; i++) 
     o << s << "("<<i+1<<") = " << (*this)[i] << ";\n";
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* writes the vector data to a file
 template <typename T>
 void Vector<T>::write_restart(FILE *f)                                    const
 {
   INDEX size = this->size();
   fwrite(&size, sizeof(INDEX),1,f);
   if (size) fwrite(this->ptr(), sizeof(T), this->size(), f);
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* returns the number of columns; always 1
 template<typename T>
 inline INDEX Vector<T>::nCols()                                           const
 {
   return 1; 
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* returns true if INDEX i is within the range of the vector
 template<typename T>
 bool Vector<T>::in_range(INDEX i)                                         const  
 {
   return i<this->size(); 
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* returns true if m has the same number of elements this vector
 template<typename T>
 bool Vector<T>::same_size(const Vector &m)                                const 
 {
   return this->size() == m.size(); 
 }
 ///////////////////////////////////////////////////////////////////////////////
 //* returns true if a and b have the same number of elements
 template<typename T>
 inline bool Vector<T>::same_size(const Vector &a, const Vector &b)
 {
   return a.same_size(b); 
 }
-
+//----------------------------------------------------------------------------
+// general matrix assignment (for densely packed matrices)
+//----------------------------------------------------------------------------
+template<typename T>
+void Vector<T>::_set_equal(const Matrix<T> &r)
+{
+  this->resize(r.nRows(), r.nCols());
+  const Matrix<T> *pr = &r;
+#ifdef OBSOLETE
+  if (const SparseMatrix<T> *ps = dynamic_cast<const SparseMatrix<T>*>(pr))//sparse_cast(pr)) 
+    copy_sparse_to_matrix(ps, *this);
+  
+  else if (dynamic_cast<const DiagonalMatrix<T>*>(pr))//diag_cast(pr))  // r is Diagonal?
+  {
+    this->zero();
+    for (INDEX i=0; i<r.size(); i++) (*this)(i,i) = r[i];
+  }
+  else memcpy(this->ptr(), r.ptr(), r.size()*sizeof(T));
+#else
+  const Vector<T>         *pv = dynamic_cast<const Vector<T>*>         (pr);
+  if (pv)  this->copy(pv->ptr(),pv->nRows());
+  else
+  {
+    std::cout <<"Error in general vector assignment\n";
+    exit(1);
+  }
+#endif
+}
 } // end namespace
 
 
 #endif
diff --git a/lib/atc/WeakEquationElectronContinuity.cpp b/lib/atc/WeakEquationElectronContinuity.cpp
index 67ffc581d..3b2a18b0f 100644
--- a/lib/atc/WeakEquationElectronContinuity.cpp
+++ b/lib/atc/WeakEquationElectronContinuity.cpp
@@ -1,105 +1,106 @@
 #include "WeakEquationElectronContinuity.h"
 #include "Material.h"
 #include <iostream>
 #include <fstream>
 
 namespace ATC {
 
 //==============================================================
 //  Class WeakEquationElectronContinuity
 //==============================================================
 
 //--------------------------------------------------------------
 //  Constructor
 //--------------------------------------------------------------
 WeakEquationElectronContinuity::WeakEquationElectronContinuity()
   : WeakEquation(DYNAMIC_PDE,ELECTRON_DENSITY,1)
 {}
 //--------------------------------------------------------------
 //  Destructor
 //---------------------------------------------------------------------
 WeakEquationElectronContinuity::~WeakEquationElectronContinuity(void)
 {}
 
 //---------------------------------------------------------------------
 void WeakEquationElectronContinuity::M_integrand(
   const FIELD_MATS &fields,
   const Material * material,
   DENS_MAT & density ) const
 {
   FIELD_MATS::const_iterator nField = fields.find(ELECTRON_DENSITY);
   const DENS_MAT &  n = nField->second;
   density.resize(n.nRows(),n.nCols()); 
   density = 1;
 }
 
 //---------------------------------------------------------------------
 void WeakEquationElectronContinuity::B_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT_VEC &flux) const
 {
   material->electron_flux(fields, grad_fields, flux);
 }
 
 //---------------------------------------------------------------------
 bool WeakEquationElectronContinuity::N_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT &recombination) const
 {
   return material->electron_recombination(fields, grad_fields, recombination);
 }
 
 //==============================================================
 //  Class WeakEquationElectronEquilbrium
 //==============================================================
 
 //--------------------------------------------------------------
 //  Constructor
 //--------------------------------------------------------------
 WeakEquationElectronEquilibrium::WeakEquationElectronEquilibrium()
   : WeakEquation(PROJECTION_PDE,ELECTRON_DENSITY,1)
 {}
 //--------------------------------------------------------------
 //  Destructor
 //---------------------------------------------------------------------
 WeakEquationElectronEquilibrium::~WeakEquationElectronEquilibrium(void)
 {}
 
 //---------------------------------------------------------------------
 void WeakEquationElectronEquilibrium::M_integrand(
   const FIELD_MATS &fields,
   const Material * material,
   DENS_MAT & density ) const
 {
   FIELD_MATS::const_iterator nField = fields.find(ELECTRON_DENSITY);
   const DENS_MAT &  n = nField->second;
   density.reset(n.nRows(),n.nCols()); 
   density = 1;
 }
 
 //---------------------------------------------------------------------
+
 bool WeakEquationElectronEquilibrium::N_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT &flux) const
 {
   bool flag = material->electron_charge_density(fields, flux);
   flux *= -1.; // transform from charge density to number density
   return flag;
 }
 
 //---------------------------------------------------------------------
 void WeakEquationElectronEquilibrium::B_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT_VEC &flux) const
 {
   material->electron_flux(fields, grad_fields, flux);
 }
 };
diff --git a/lib/atc/WeakEquationElectronMomentum.cpp b/lib/atc/WeakEquationElectronMomentum.cpp
index 4ae48ed70..37484f61d 100644
--- a/lib/atc/WeakEquationElectronMomentum.cpp
+++ b/lib/atc/WeakEquationElectronMomentum.cpp
@@ -1,185 +1,186 @@
 #include "WeakEquationElectronMomentum.h"
 #include "Material.h"
 #include "LammpsInterface.h"
 
 namespace ATC {
 
 //==============================================================
 //  Class WeakEquationElectronMomentum
 //==============================================================
 
 //--------------------------------------------------------------
 //  Constructor
 //--------------------------------------------------------------
 WeakEquationElectronMomentum::WeakEquationElectronMomentum()
   : WeakEquation(STATIC_PDE,ELECTRON_VELOCITY,3)
 {}
 
 //--------------------------------------------------------------
 //  Destructor
 //--------------------------------------------------------------
 WeakEquationElectronMomentum::~WeakEquationElectronMomentum()
 {}
 
 void WeakEquationElectronMomentum::convection(const FIELD_MATS &fields,
                                               const Material * material,
                                               DENS_MAT_VEC & flux) const
 {
   // set up mass density
   FIELD_MATS::const_iterator nField = fields.find(ELECTRON_DENSITY);
   const DENS_MAT & n = nField->second;
   DENS_MAT nMe(n.nRows(),n.nCols()); 
   material->inv_effective_mass(fields,nMe);
   nMe = n.div_by_element(nMe);
 
   // set up velocity and flux
   FIELD_MATS::const_iterator vField = fields.find(ELECTRON_VELOCITY);
   const DENS_MAT & velocity = vField->second;
   const CLON_VEC u(velocity,CLONE_COL,0);
   const CLON_VEC v(velocity,CLONE_COL,1);
   const CLON_VEC w(velocity,CLONE_COL,2);
   flux[0] = velocity; 
   flux[1] = velocity;
   flux[2] = velocity;
   CLON_VEC nuu(flux[0],CLONE_COL,0);
   CLON_VEC nuv(flux[1],CLONE_COL,0);
   CLON_VEC nuw(flux[2],CLONE_COL,0);
   CLON_VEC nvu(flux[0],CLONE_COL,1);
   CLON_VEC nvv(flux[1],CLONE_COL,1);
   CLON_VEC nvw(flux[2],CLONE_COL,1);
   CLON_VEC nwu(flux[0],CLONE_COL,2);
   CLON_VEC nwv(flux[1],CLONE_COL,2);
   CLON_VEC nww(flux[2],CLONE_COL,2);
   
   for (int i = 0; i < n.nRows(); i++) {
     // tensor product of velocities
     nuu(i) *= nMe(i,0)*u(i);
     nuv(i) *= nMe(i,0)*v(i);
     nuw(i) *= nMe(i,0)*w(i);
     nvu(i) *= nMe(i,0)*u(i);
     nvv(i) *= nMe(i,0)*v(i);
     nvw(i) *= nMe(i,0)*w(i);
     nwu(i) *= nMe(i,0)*u(i);
     nwv(i) *= nMe(i,0)*v(i);
     nww(i) *= nMe(i,0)*w(i);
   }
 };
 
 //---------------------------------------------------------------------
 //   compute mass density
 //---------------------------------------------------------------------
 void WeakEquationElectronMomentum::M_integrand(
   const FIELD_MATS &fields,
   const Material * material,
   DENS_MAT & density ) const
 {
   material->electron_mass_density(fields, density);
 }
 
 //--------------------------------------------------------------
 void WeakEquationElectronMomentum::B_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT_VEC &flux) const
 {
   convection(fields,material,flux);
 }
 
 //==============================================================
 //  Class WeakEquationElectronMomentumDDM
 //==============================================================
 
 //--------------------------------------------------------------
 //  Constructor
 //--------------------------------------------------------------
 WeakEquationElectronMomentumDDM::WeakEquationElectronMomentumDDM()
   : WeakEquationElectronMomentum()
 {
   DENS_MAT dummy;
   _dnCp_.reserve(nsd_);
   for (int i = 0; i < nsd_; i++)
     _dnCp_.push_back(dummy);
 
   _electricForce_.reserve(nsd_);
   for (int i = 0; i < nsd_; i++)
     _electricForce_.push_back(dummy);
 }
 
 //--------------------------------------------------------------
 //  Destructor
 //--------------------------------------------------------------
 WeakEquationElectronMomentumDDM::~WeakEquationElectronMomentumDDM()
 {}
 
 void WeakEquationElectronMomentumDDM::thermal_stress(const FIELD_MATS &fields,
                                                      const GRAD_FIELD_MATS &gradFields,
                                                      const Material * material,
                                                      DENS_MAT &flux) const
 {
   GRAD_FIELD_MATS::const_iterator dtField = gradFields.find(ELECTRON_TEMPERATURE);
   const DENS_MAT_VEC & DTe = dtField->second;
 
   CLON_VEC tsx(flux,CLONE_COL,0);
   CLON_VEC tsy(flux,CLONE_COL,1);
   CLON_VEC tsz(flux,CLONE_COL,2);
 
   // ith velocity component has thermal stress of
   // d_i n * Cp * Te
   DENS_MAT nCp(DTe[0].nRows(),DTe[0].nCols());  
   material->electron_heat_capacity(fields,nCp);
   nCp *= 2./3.;  // correction to capacity account for convection
   
   tsx += nCp.mult_by_element(DTe[0]);
   tsy += nCp.mult_by_element(DTe[1]);
   tsz += nCp.mult_by_element(DTe[2]);
   
   FIELD_MATS::const_iterator tField = fields.find(ELECTRON_TEMPERATURE);
   const DENS_MAT & Te = tField->second;
   
   material->D_electron_heat_capacity(fields,gradFields,_dnCp_);
   for (int i = 0; i < nsd_; i++)
     _dnCp_[i] *= 2./3.; // correction to capacity account for convection
   tsx += Te.mult_by_element(_dnCp_[0]);
   tsy += Te.mult_by_element(_dnCp_[1]);
   tsz += Te.mult_by_element(_dnCp_[2]);
 }
 
 //---------------------------------------------------------------------
 //   compute mass density
 //---------------------------------------------------------------------
 void WeakEquationElectronMomentumDDM::M_integrand(
   const FIELD_MATS &fields,
   const Material * material,
   DENS_MAT & density ) const
 {
   material->electron_drag_velocity_coefficient(fields, density);
 }
 
 //--------------------------------------------------------------
 bool WeakEquationElectronMomentumDDM::N_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT &flux) const
 {
   FIELD_MATS::const_iterator vField = fields.find(ELECTRON_VELOCITY);
   const DENS_MAT & velocity = vField->second;
   flux.reset(velocity.nRows(),velocity.nCols());
   thermal_stress(fields, grad_fields, material, flux);
   material->electric_displacement(fields, grad_fields, _electricForce_);
 
 
   FIELD_MATS::const_iterator nField = fields.find(ELECTRON_DENSITY);
   const DENS_MAT & n = nField->second;
+
   
   CLON_VEC tsx(flux,CLONE_COL,0);
   CLON_VEC tsy(flux,CLONE_COL,1);
   CLON_VEC tsz(flux,CLONE_COL,2);
   tsx += n.mult_by_element(_electricForce_[0]);
   tsy += n.mult_by_element(_electricForce_[1]);
   tsz += n.mult_by_element(_electricForce_[2]);
   return true;
 }
 
 }; // END namespace
diff --git a/lib/atc/WeakEquationElectronTemperature.cpp b/lib/atc/WeakEquationElectronTemperature.cpp
index 3841f619a..97a21628d 100644
--- a/lib/atc/WeakEquationElectronTemperature.cpp
+++ b/lib/atc/WeakEquationElectronTemperature.cpp
@@ -1,227 +1,230 @@
 #include "WeakEquationElectronTemperature.h"
 #include "Material.h"
 #include <iostream>
 #include <fstream>
 
 namespace ATC {
 //==============================================================
 //  Class WeakEquationElectronTemperature
 //==============================================================
 
 //--------------------------------------------------------------
 //  Constructor
 //--------------------------------------------------------------
 WeakEquationElectronTemperature::WeakEquationElectronTemperature()
   : WeakEquation(DYNAMIC_PDE,ELECTRON_TEMPERATURE,1)
 {
 }
 //--------------------------------------------------------------
 //  Destructor
 //---------------------------------------------------------------------
 WeakEquationElectronTemperature::~WeakEquationElectronTemperature(void)
 {}
 
 //---------------------------------------------------------------------
 //   compute energy
 //---------------------------------------------------------------------
 void WeakEquationElectronTemperature::E_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT & energy ) const
 {
   material->electron_thermal_energy(fields, energy);
 }
 
 //---------------------------------------------------------------------
 //   compute heat capacities
 //---------------------------------------------------------------------
 void WeakEquationElectronTemperature::M_integrand(
   const FIELD_MATS &fields,
   const Material * material,
   DENS_MAT & capacity ) const
 {
   material->electron_heat_capacity(fields, capacity);
 }
 
 //---------------------------------------------------------------------
 //   compute heat fluxes
 //---------------------------------------------------------------------
 void WeakEquationElectronTemperature::B_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT_VEC &flux) const
 {
   material->electron_heat_flux(fields, grad_fields, flux);
 }
 
 //---------------------------------------------------------------------
 //   compute exchange fluxes
 //---------------------------------------------------------------------
 bool WeakEquationElectronTemperature::N_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT &flux) const
 {
 
   DENS_MAT exchange_flux;
   bool has = material->electron_phonon_exchange(fields, exchange_flux);
   if (has) flux = -1.*exchange_flux;
   return has;
 }
 
 //==============================================================
 //  Class WeakEquationElectronJouleHeating
 //==============================================================
 
 //--------------------------------------------------------------
 //  Constructor
 //--------------------------------------------------------------
 WeakEquationElectronTemperatureJouleHeating::WeakEquationElectronTemperatureJouleHeating()
   : WeakEquationElectronTemperature()
 {
   // convert charge * voltage --> mass length^2 / time^2
   //eV2E_ = (ATC::LammpsInterface::instance()->qe2f())
   //      * (ATC::LammpsInterface::instance()->ftm2v());
   eV2E_ = ATC::LammpsInterface::instance()->qv2e();
   int nSD = 3; 
   _J_.assign(nSD, DENS_MAT()); 
   _E_.assign(nSD, DENS_MAT());
 }
 //--------------------------------------------------------------
 //  Destructor
 //---------------------------------------------------------------------
 WeakEquationElectronTemperatureJouleHeating::~WeakEquationElectronTemperatureJouleHeating(void)
 {}
 
 //---------------------------------------------------------------------
 void WeakEquationElectronTemperatureJouleHeating::E_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT &energy) const
 {
   WeakEquationElectronTemperature::E_integrand(fields, grad_fields, material, energy);
 }
 //---------------------------------------------------------------------
 void WeakEquationElectronTemperatureJouleHeating::M_integrand(
   const FIELD_MATS &fields,
   const Material * material,
   DENS_MAT &capacity) const
 {
   WeakEquationElectronTemperature::M_integrand(fields, material, capacity);
 }
 //---------------------------------------------------------------------
 void WeakEquationElectronTemperatureJouleHeating::B_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT_VEC &flux) const
 {
   WeakEquationElectronTemperature::B_integrand(fields, grad_fields, material, flux);
 }
 
 //---------------------------------------------------------------------
 bool WeakEquationElectronTemperatureJouleHeating::N_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT &flux) const
 {
+  
   // call base class to get electron_temperature terms
   WeakEquationElectronTemperature::N_integrand(fields, grad_fields, material, flux);
+  // Joule heating = -I.grad Psi = J.grad Psi \approx J.E
   DENS_MAT jouleHeating; 
-  material->electron_flux (fields, grad_fields, _J_);
+  material->electron_flux (fields, grad_fields, _J_); 
   material->electric_field(fields, grad_fields, _E_);
   jouleHeating = _J_[0].mult_by_element(_E_[0]);
   for (DENS_MAT_VEC::size_type i=1; i < _J_.size(); i++)
     jouleHeating += _J_[i].mult_by_element(_E_[i]);
   jouleHeating *= eV2E_;
-  flux += jouleHeating;
+  flux -= jouleHeating; 
   return true;
 }
 
 //==============================================================
 //  Class WeakEquationElectronConvection
 //==============================================================
 
 //--------------------------------------------------------------
 //  Constructor
 //--------------------------------------------------------------
 WeakEquationElectronTemperatureConvection::WeakEquationElectronTemperatureConvection()
-  : WeakEquationElectronTemperature()
+  : WeakEquationElectronTemperatureJouleHeating()
 {
   int nSD = 3; 
   _convectiveFlux_.assign(nSD, DENS_MAT()); 
 }
 
 //--------------------------------------------------------------
 //  Destructor
 //---------------------------------------------------------------------
 WeakEquationElectronTemperatureConvection::~WeakEquationElectronTemperatureConvection(void)
 {
   // do nothing
 }
 
 //---------------------------------------------------------------------
 void WeakEquationElectronTemperatureConvection::B_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT_VEC &flux) const
 {
   // add diffusion term
   
-  WeakEquationElectronTemperature::B_integrand(fields, grad_fields, material, flux);
+  WeakEquationElectronTemperatureJouleHeating::B_integrand(fields, grad_fields, material, flux);
   //flux[0] = 0.;
   //flux[1] = 0.;
   //flux[2] = 0.;
 
   // add convection term
   DENS_MAT_VEC convectiveFlux;
   material->electron_heat_convection(fields,_convectiveFlux_);
   flux[0] += _convectiveFlux_[0];
   flux[1] += _convectiveFlux_[1];
   flux[2] += _convectiveFlux_[2];
 }
 
 //---------------------------------------------------------------------
 bool WeakEquationElectronTemperatureConvection::N_integrand(
   const FIELD_MATS &fields,
   const GRAD_FIELD_MATS &grad_fields,
   const Material * material,
   DENS_MAT &flux) const
 {
   // call base class to get electron_temperature terms
-  WeakEquationElectronTemperature::N_integrand(fields, grad_fields, material, flux);
+  WeakEquationElectronTemperatureJouleHeating::N_integrand(fields, grad_fields, material, flux);
+#ifdef TEST
   // add exchange with kinetic energy
   DENS_MAT keExchange;
   DENS_MAT capacity;
   material->electron_heat_capacity(fields, capacity);
   capacity *= 2./3.; // correction in DDM equations
   
   
   //FIELD_MATS::const_iterator dField = fields.find(ELECTRON_DENSITY);
   FIELD_MATS::const_iterator tField = fields.find(ELECTRON_TEMPERATURE);
   //const DENS_MAT & density = dField->second;
   const DENS_MAT & temperature = tField->second;
 
   GRAD_FIELD_MATS::const_iterator velocityGradients = grad_fields.find(ELECTRON_VELOCITY);
   const DENS_MAT_VEC & dv = velocityGradients->second;
   CLON_VEC vxx(dv[0],CLONE_COL,0);
   CLON_VEC vyy(dv[1],CLONE_COL,1);
   CLON_VEC vzz(dv[2],CLONE_COL,2);
 
   keExchange = vxx + vyy + vzz;
   //keExchange *= density;
   keExchange *= temperature;
   keExchange *= capacity;
   
   flux -= keExchange;
-
+#endif
   return true;  
 }
 
 }; // end namespace
diff --git a/lib/atc/WeakEquationElectronTemperature.h b/lib/atc/WeakEquationElectronTemperature.h
index 8680de31a..1a5ecbab0 100644
--- a/lib/atc/WeakEquationElectronTemperature.h
+++ b/lib/atc/WeakEquationElectronTemperature.h
@@ -1,180 +1,180 @@
 #ifndef WEAK_EQUATION_ELECTRON_TEMPERATURE_H
 #define WEAK_EQUATION_ELECTRON_TEMPERATURE_H
 
 #include <set>
 #include <string>
 
 #include "WeakEquation.h"
 
 namespace ATC{
 
  /**
    *  @class  WeakEquationElectronTemperature
    *  @brief  Electron temperature 
    *   c T_e,t = div q_e + g(T_e-T_p) --> 
    *   int M c T_e,t = int B q_e + int N g
    */
 
 class WeakEquationElectronTemperature : public WeakEquation {
 
   public:
   
   // constructor 
   WeakEquationElectronTemperature();
 
   // destructor
   virtual ~WeakEquationElectronTemperature();
   
   /** integrand  that used to form the energy */
   virtual bool has_E_integrand(void) const {return true;}
   virtual void E_integrand(const FIELD_MATS &fields,
                            const GRAD_FIELD_MATS &grad_fields,
                            const Material * material,
                            DENS_MAT &energy ) const ;
 
   /** density that used to form the mass matrix */
   virtual bool has_M_integrand(void) const {return true;}
   virtual void M_integrand(const FIELD_MATS &fields,
                            const Material * material,
                            DENS_MAT &density ) const ;
 
   /** flux that is integrated with B = Grad N as its weight */
   virtual bool has_B_integrand(void) const {return true;}
   virtual void B_integrand(const FIELD_MATS &fields,
                            const GRAD_FIELD_MATS &grad_fields,
                            const Material * material,
                            DENS_MAT_VEC &flux) const ;
 
   /** flux that is integrated with N as its weight */
   virtual bool has_N_integrand(void) const {return true;}
   virtual bool N_integrand(const FIELD_MATS &fields, 
                            const GRAD_FIELD_MATS &grad_fields,
                            const Material * material,
                            DENS_MAT &flux) const ;
 
   /** necessary interfaces */
   virtual std::set<std::string> needs_material_functions(void) const
   {
     std::string list[4] = {"electron_thermal_energy",
                       "electron_heat_capacity",
                       "electron_phonon_exchange",
                       "electron_heat_flux"};
     std::set<std::string> needs(list,list+4);
     return needs;
   }
 
 };
 
  /**
    *  @class  WeakEquationElectronTemperatureJouleHeating
    *  @brief  Electron temperature with Joule heating
    *   c T_e,t = div q_e + g(T_e-T_p) + J.E --> 
    *   int M c T_e,t = int B q_e + int N ( g + J.E)
    */
 
 class WeakEquationElectronTemperatureJouleHeating : 
   public WeakEquationElectronTemperature  
 {
   public:
   
   // constructor 
   WeakEquationElectronTemperatureJouleHeating();
 
   // destructor
   virtual ~WeakEquationElectronTemperatureJouleHeating();
   
   /** integrand  that used to form the energy */
   virtual bool has_E_integrand(void) const {return true;}
   virtual void E_integrand(const FIELD_MATS &fields,
                            const GRAD_FIELD_MATS &grad_fields,
                            const Material * material,
                            DENS_MAT &energy ) const;
 
   /** density that used to form the mass matrix */
   virtual bool has_M_integrand(void) const {return true;}
   virtual void M_integrand(const FIELD_MATS &fields,
                            const Material * material,
                            DENS_MAT &density ) const;
 
   /** flux that is integrated with B = Grad N as its weight */
   virtual bool has_B_integrand(void) const {return true;}
   virtual void B_integrand(const FIELD_MATS &fields,
                            const GRAD_FIELD_MATS &grad_fields,
                            const Material * material,
                            DENS_MAT_VEC &flux) const;
 
   /** flux that is integrated with N as its weight */
   virtual bool has_N_integrand(void) const {return true;}
   virtual bool N_integrand(const FIELD_MATS &fields, 
                            const GRAD_FIELD_MATS &grad_fields,
                            const Material * material,
                            DENS_MAT &flux) const;
 
   /** necessary interfaces */
   virtual std::set<std::string> needs_material_functions(void) const
   {
     std::set<std::string> needs 
       = WeakEquationElectronTemperature::needs_material_functions();
     needs.insert("electric_field");
     return needs;
   }
 
 
   protected:
   
   /** conversion factor for charge * voltage --> mass length^2 / time^2 */
   double eV2E_;
 
   mutable DENS_MAT_VEC _J_, _E_;
 };
 
  /**
    *  @class  WeakEquationElectronTemperatureConvection
    *  @brief  Electron temperature with convection
    *   c ( T_e,t + grad m_e J.E T_e / e ) = div q_e + g(T_e-T_p) + c n T_e grad J.E/(n e) --> 
    *   int M c T_e,t = int B ( q_e - c m_e J.E T_e / e ) + int N ( g + c n T_e grad J.E/(n e) )
    */
 
 class WeakEquationElectronTemperatureConvection : 
-  public WeakEquationElectronTemperature  
+  public WeakEquationElectronTemperatureJouleHeating
 {
   public:
   
   // constructor 
   WeakEquationElectronTemperatureConvection();
 
   // destructor
   virtual ~WeakEquationElectronTemperatureConvection();
 
   /** flux that is integrated with B = Grad N as its weight */
   virtual bool has_B_integrand(void) const {return true;}
   virtual void B_integrand(const FIELD_MATS &fields,
                            const GRAD_FIELD_MATS &grad_fields,
                            const Material * material,
                            DENS_MAT_VEC &flux) const;
 
   /** flux that is integrated with N as its weight */
   virtual bool has_N_integrand(void) const {return true;}
   virtual bool N_integrand(const FIELD_MATS &fields, 
                            const GRAD_FIELD_MATS &grad_fields,
                            const Material * material,
                            DENS_MAT &flux) const;
 
   /** necessary interfaces */
   virtual std::set<std::string> needs_material_functions(void) const
   {
     std::set<std::string> needs 
       = WeakEquationElectronTemperature::needs_material_functions();
     needs.insert("electron_drag_power");
     return needs;
   }
 
   protected:
 
   /** workspace variable for the convective flux */
   mutable DENS_MAT_VEC _convectiveFlux_;
   
 };
 
 }; // end namespace
 #endif