diff --git a/podd b/podd
index cc0ebfe4b74446e27dc5a7040dfe2b4606b24f9e..1154ca9087e06ede79833e8ce42cc04cbb99f479 160000
--- a/podd
+++ b/podd
@@ -1 +1 @@
-Subproject commit cc0ebfe4b74446e27dc5a7040dfe2b4606b24f9e
+Subproject commit 1154ca9087e06ede79833e8ce42cc04cbb99f479
diff --git a/src/THcAerogel.cxx b/src/THcAerogel.cxx
index da2716ecd4505b8557eb492a0416635cbd58930f..610635526567a8ea260e52bf7ff57b5ac0c839b5 100644
--- a/src/THcAerogel.cxx
+++ b/src/THcAerogel.cxx
@@ -19,6 +19,7 @@
 #include "THaCutList.h"
 #include "THcParmList.h"
 #include "THcHitList.h"
+#include "THaApparatus.h"
 #include "VarDef.h"
 #include "VarType.h"
 #include "THaTrack.h"
diff --git a/src/THcCherenkov.cxx b/src/THcCherenkov.cxx
index 236db7c8be1b39244d752dde54a5c2ffd2a2570d..31a3418027ffead7028a3198e1345e62a380520d 100644
--- a/src/THcCherenkov.cxx
+++ b/src/THcCherenkov.cxx
@@ -32,6 +32,7 @@
 #include "THaCutList.h"
 #include "THcParmList.h"
 #include "THcHitList.h"
+#include "THaApparatus.h"
 #include "VarDef.h"
 #include "VarType.h"
 #include "THaTrack.h"
diff --git a/src/THcDC.cxx b/src/THcDC.cxx
index 09ab985c4182268819df4a25fd4d64ad092aa154..f1e8290bdd9c7ea80e97b3b4fe731ece363a055a 100644
--- a/src/THcDC.cxx
+++ b/src/THcDC.cxx
@@ -23,6 +23,7 @@
 #include "TClonesArray.h"
 #include "TMath.h"
 #include "TVectorD.h"
+#include "THaApparatus.h"
 
 #include <cstring>
 #include <cstdio>
diff --git a/src/THcDriftChamber.cxx b/src/THcDriftChamber.cxx
index 61f5c02c76029a2d72c04ee6863822dd009e1fdf..b9ed691797b48154cf905f7ca2d4330b3d7bed22 100644
--- a/src/THcDriftChamber.cxx
+++ b/src/THcDriftChamber.cxx
@@ -21,6 +21,7 @@
 #include "TMath.h"
 #include "TVectorD.h"
 #include "THcSpacePoint.h"
+#include "THaApparatus.h"
 
 #include "THaTrackProj.h"
 
diff --git a/src/THcDriftChamberPlane.cxx b/src/THcDriftChamberPlane.cxx
index 59516413f569d69fc356f030059fb0b0b19337cf..3df5a7bd50a2b073a5f6f7cbbe76f705cab3cbec 100644
--- a/src/THcDriftChamberPlane.cxx
+++ b/src/THcDriftChamberPlane.cxx
@@ -6,6 +6,7 @@
 //
 //////////////////////////////////////////////////////////////////////////
 
+#include "THcDC.h"
 #include "THcDriftChamberPlane.h"
 #include "THcDCWire.h"
 #include "THcDCHit.h"
@@ -14,10 +15,11 @@
 #include "THcGlobals.h"
 #include "THcParmList.h"
 #include "THcHitList.h"
-#include "THcDC.h"
+#include "THaApparatus.h"
 #include "THcHodoscope.h"
 #include "TClass.h"
 
+
 #include <cstring>
 #include <cstdio>
 #include <cstdlib>
diff --git a/src/THcFormula.cxx b/src/THcFormula.cxx
index 7740c06948fb0d75bcd6c1924e4d81c985d25c1e..114d8f6010d19e0b4d277ef390e999e033be295d 100644
--- a/src/THcFormula.cxx
+++ b/src/THcFormula.cxx
@@ -16,46 +16,64 @@
 #include "THaVarList.h"
 #include "THaCutList.h"
 #include "THaCut.h"
+#include "TMath.h"
 
 #include <iostream>
+#include <numeric>
 
 using namespace std;
 
 static const Double_t kBig = 1e38; // Error value
 
+enum EFuncCode { kLength, kSum, kMean, kStdDev, kMax, kMin,
+		 kGeoMean, kMedian, kIteration, kNumSetBits };
+
+#define ALL(c) (c).begin(), (c).end()
+
+//_____________________________________________________________________________
+static inline Int_t NumberOfSetBits( UInt_t v )
+{
+  // Count number of bits set in 32-bit integer. From
+  // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
+
+  v = v - ((v >> 1) & 0x55555555);
+  v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+  return (((v + (v >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+}
+
+//_____________________________________________________________________________
+static inline Int_t NumberOfSetBits( ULong64_t v )
+{
+  // Count number of bits in 64-bit integer
+
+  const ULong64_t mask32 = (1LL<<32)-1;
+  return NumberOfSetBits( static_cast<UInt_t>(mask32 & v) ) +
+    NumberOfSetBits( static_cast<UInt_t>(mask32 & (v>>32)) );
+}
+
 //_____________________________________________________________________________
 THcFormula::THcFormula(const char* name, const char* expression, 
 		       const THcParmList* plst, const THaVarList* vlst,
 		       const THaCutList* clst ) :
   THaFormula()
 {
+  Bool_t do_register=0;
 
-  // We have to duplicate the TFormula constructor code here because of
-  // the calls DefinedVariable.  Our version will only get called if
-  // to Compile(). Compile() only works if fParmList is set. 
   fParmList = plst;
   fVarList = vlst;
   fCutList = clst;
 
-  SetName(name);
-
-  //eliminate blanks in expression
-  Int_t nch = strlen(expression);
-  char *expr = new char[nch+1];
-  Int_t j = 0;
-  for (Int_t i=0;i<nch;i++) {
-     if (expression[i] == ' ') continue;
-     if (i > 0 && (expression[i] == '*') && (expression[i-1] == '*')) {
-        expr[j-1] = '^';
-        continue;
-     }
-     expr[j] = expression[i]; j++;
-   }
-  expr[j] = 0;
-  if (j) SetTitle(expr);
-  delete [] expr;
+  if( Init( name, expression ) != 0 ) {
+    RegisterFormula(false);
+    return;
+  }
+
+  SetBit(kNotGlobal,!do_register);
 
   Compile();   // This calls our own Compile()
+
+  if( do_register )
+    RegisterFormula();
 }
 
 //_____________________________________________________________________________
@@ -63,15 +81,10 @@ THcFormula& THcFormula::operator=( const THcFormula& rhs )
 {
   if( this != &rhs ) {
     TFormula::operator=(rhs);
-    fNcodes = rhs.fNcodes;
     fParmList = rhs.fParmList;
     fVarList = rhs.fVarList;
     fCutList = rhs.fCutList;
-    fError = rhs.fError;
-    fRegister = rhs.fRegister;
-    delete [] fVarDef;
-    fVarDef = new FVarDef_t[ kMAXCODES ];
-    memcpy( fVarDef, rhs.fVarDef, kMAXCODES*sizeof(FVarDef_t));
+    fInstance = 0;
   }
   return *this;
 }
@@ -83,7 +96,7 @@ THcFormula::~THcFormula()
 }
 
 //_____________________________________________________________________________
-Int_t THcFormula::DefinedCut( const TString& name )
+Int_t THcFormula::DefinedCut( TString& name )
 {
   // Check if 'name' is a known cut. If so, enter it in the local list of 
   // variables used in this formula.
@@ -102,26 +115,23 @@ Int_t THcFormula::DefinedCut( const TString& name )
     } else if (attribute.CompareTo("ncalled")==0) {
       thistype = (EVariableType) kCutNCalled;
     } else {
-      thistype = kUndefined;
+      thistype = kCut;
     }
   }
 
   // Cut names are obviously only valid if there is a list of existing cuts
   if( fCutList ) {
-    const THaCut* pcut = fCutList->FindCut( realname );
+    THaCut* pcut = fCutList->FindCut( realname );
     if( pcut ) {
-      if( fNcodes >= kMAXCODES ) return -1;
-      // See if this cut already used earlier in this new cut
-      FVarDef_t* def = fVarDef;
-      for( Int_t i=0; i<fNcodes; i++, def++ ) {
-	if( def->type == thistype && pcut == def->code )
+      // See if this cut already used earlier in the expression
+      for( vector<FVarDef_t>::size_type i=0; i<fVarDef.size(); ++i ) {
+	FVarDef_t& def = fVarDef[i];
+	if( def.type == thistype && pcut == def.obj )
 	  return i;
       }
-      def->type = thistype;
-      def->code  = pcut;
-      def->index = 0;
+      fVarDef.push_back( FVarDef_t(thistype,pcut,0) );
       fNpar = 0;
-      return fNcodes++;
+      return fVarDef.size()-1;
     }
   }
   return -1;
@@ -135,80 +145,201 @@ Double_t THcFormula::DefinedValue( Int_t i )
   // (calculated at the last evaluation).
   // If the variable is a string, return value of its character value
   
-#ifdef WITH_DEBUG
-  R__ASSERT( i>=0 && i<fNcodes );
-#endif
-  FVarDef_t* def = fVarDef+i;
-  const void* ptr = def->code;
-  if( !ptr ) return kBig;
-  switch( (Int_t) def->type ) {
+  typedef vector<Double_t>::size_type vsiz_t;
+  typedef vector<Double_t>::iterator  viter_t;
+
+  assert( i>=0 && i<(Int_t)fVarDef.size() );
+
+  if( IsInvalid() )
+    return 1.0;
+
+  FVarDef_t& def = fVarDef[i];
+  switch( def.type ) {
   case kVariable:
   case kString:
-    return reinterpret_cast<const THaVar*>(ptr)->GetValue( def->index );
+  case kArray:
+    {
+      const THaVar* var = static_cast<const THaVar*>(def.obj);
+      assert(var);
+      Int_t index = (def.type == kArray) ? fInstance : def.index;
+      assert(index >= 0);
+      if( index >= var->GetLen() ) {
+	SetBit(kInvalid);
+	return 1.0; // safer than kBig to prevent overflow
+      }
+      return var->GetValue( index );
+    }
     break;
   case kCut:
-    return reinterpret_cast<const THaCut*>(ptr)->GetResult();
+    {
+      const THaCut* cut = static_cast<const THaCut*>(def.obj);
+      assert(cut);
+      return cut->GetResult();
+    }
     break;
   case kCutScaler:
-    return reinterpret_cast<const THaCut*>(ptr)->GetNPassed();
+    {
+      const THaCut* cut = static_cast<const THaCut*>(def.obj);
+      assert(cut);
+      return cut->GetNPassed();
+    }
     break;
   case kCutNCalled:
-    return reinterpret_cast<const THaCut*>(ptr)->GetNCalled();
+    {
+      const THaCut* cut = static_cast<const THaCut*>(def.obj);
+      assert(cut);
+      return cut->GetNCalled();
+    }
+    break;
+  case kFunction:
+    {
+      EFuncCode code = static_cast<EFuncCode>(def.index);
+      switch( code ) {
+      case kIteration:
+	return fInstance;
+      default:
+	assert(false); // not reached
+	break;
+      }
+    }
+    break;
+  case kFormula:
+  case kVarFormula:
+    {
+      EFuncCode code = static_cast<EFuncCode>(def.index);
+      THaFormula* func = static_cast<THaFormula*>(def.obj);
+      assert(func);
+
+      vsiz_t ndata = func->GetNdata();
+      if( code == kLength )
+	return ndata;
+
+      if( ndata == 0 ) {
+	//FIXME: needs thought
+	SetBit(kInvalid);
+	return 1.0;
+      }
+      Double_t y;
+      if( code == kNumSetBits ) {
+	// Number of set bits is intended for unsigned int-type expressions
+	y = func->EvalInstance(fInstance);
+	if( y > kMaxULong64 || y < kMinLong64 ) {
+	  return 0;
+	}
+	return NumberOfSetBits( static_cast<ULong64_t>(y) );
+      }
+
+      vector<Double_t> values;
+      values.reserve(ndata);
+      for( vsiz_t i = 0; i < ndata; ++i ) {
+	values.push_back( func->EvalInstance(i) );
+      }
+      if( func->IsInvalid() ) {
+	SetBit(kInvalid);
+	return 1.0;
+      }
+      switch( code ) {
+      case kSum:
+	y = accumulate( ALL(values), static_cast<Double_t>(0.0) );
+	break;
+      case kMean:
+	y = TMath::Mean( ndata, &values[0] );
+	break;
+      case kStdDev:
+	y = TMath::RMS( ndata, &values[0] );
+	break;
+      case kMax:
+	y = *max_element( ALL(values) );
+	break;
+      case kMin:
+	y = *min_element( ALL(values) );
+	break;
+      case kGeoMean:
+	y = TMath::GeomMean( ndata, &values[0] );
+	break;
+      case kMedian:
+	y = TMath::Median( ndata, &values[0] );
+	break;
+      default:
+	assert(false); // not reached
+	break;
+      }
+      return y;
+    }
     break;
-  default:
-    return kBig;
   }
+  assert(false); // not reached
+  return kBig;
 }  
 
 
 //_____________________________________________________________________________
-Int_t THcFormula::DefinedGlobalVariable( const TString& name )
+Int_t THcFormula::DefinedGlobalVariable( TString& name )
 {
   // Check if 'name' is a known global variable. If so, enter it in the
   // local list of variables used in this formula.
 
   // No list of variables or too many variables in this formula?
-  if( (!fVarList && !fParmList) || fNcodes >= kMAXCODES )
-    return -2;
-
+  if( !fVarList && !fParmList )
+    return -1;
 
   // Parse name for array syntax
-  THaArrayString var(name);
-  if( var.IsError() )
-    return -1;
+  THaArrayString parsed_name(name);
+  if( parsed_name.IsError() ) return -1;
 
   // First check if this name is a Parameter
-  const THaVar* obj = fParmList->Find( var.GetName() );
-  if ( !obj) {  // If not, find a global variable with this name
-    obj = fVarList->Find( var.GetName() );
-    if( !obj )
+  THaVar* var = fParmList->Find( parsed_name.GetName() );
+  if ( !var) {  // If not, find a global variable with this name
+    var = fVarList->Find( parsed_name.GetName() );
+    if( !var )
       return -1;
   }
 
-  // Error if array requested but the corresponding variable is not an array
-  if( var.IsArray() && !obj->IsArray() )
-    return -2;
-
-  // Subscript(s) within bounds?
+  EVariableType type = kVariable;
   Int_t index = 0;
-  if( var.IsArray() 
-      && (index = obj->Index( var )) <0 ) return -2;
-		    
+  if( parsed_name.IsArray() ) {
+    // Requesting an array element
+    if( !var->IsArray() )
+      // Element requested but the corresponding variable is not an array
+      return -2;
+    if( var->IsVarArray() ) {
+      // Variable-size arrays are always 1-d
+      assert( var->GetNdim() == 1 );
+      if( parsed_name.GetNdim() != 1 )
+	return -2;
+      // For variable-size arrays, we allow requests for any element and
+      // check at evaluation time whether the element actually exists
+      index = parsed_name[0];
+    } else {
+      // Fixed-size arrays: check if subscript(s) within bounds?
+      //TODO: allow fixing some dimensions
+      index = var->Index( parsed_name );
+      if( index < 0 )
+	return -2;
+    }
+  } else if( var->IsArray() ) {
+    // Asking for an entire array
+    type = kArray;
+    SetBit(kArrayFormula);
+    if( var->IsVarArray() )
+      SetBit(kVarArray);
+  }
+
   // Check if this variable already used in this formula
-  FVarDef_t* def = fVarDef;
-  for( Int_t i=0; i<fNcodes; i++, def++ ) {
-    if( obj == def->code && index == def->index )
+  for( vector<FVarDef_t>::size_type i=0; i<fVarDef.size(); ++i ) {
+    FVarDef_t& def = fVarDef[i];
+    if( var == def.obj && index == def.index ) {
+      assert( type == def.type );
       return i;
+    }
   }
   // If this is a new variable, add it to the list
-  def->type = kVariable;
-  def->code = obj;
-  def->index = index;
+  fVarDef.push_back( FVarDef_t(type,var,index) );
 
   // No parameters ever for a THaFormula
   fNpar = 0;
 
-  return fNcodes++;
+  return fVarDef.size()-1;
 }
 
 
diff --git a/src/THcFormula.h b/src/THcFormula.h
index 0294ee6417a21b59cbb21a388ad301d79225eb9a..20c962ac8c19d0ba28666f5ed2b8446f5271d4f2 100644
--- a/src/THcFormula.h
+++ b/src/THcFormula.h
@@ -23,12 +23,12 @@ public:
   virtual ~THcFormula();
 
   virtual Double_t DefinedValue( Int_t i);
-  virtual Int_t    DefinedCut( const TString& variable);
-  virtual Int_t    DefinedGlobalVariable( const TString& variable);
+  virtual Int_t    DefinedCut( TString& variable);
+  virtual Int_t    DefinedGlobalVariable( TString& variable);
 
 protected:
 
-  enum {kCutScaler = kString+1};
+  enum {kCutScaler = kVarFormula+1};
   enum {kCutNCalled = kCutScaler+1};
   const THcParmList* fParmList; // Pointer to list of parameters
   ClassDef(THcFormula,0) // Formula with cut scalers
diff --git a/src/THcInterface.cxx b/src/THcInterface.cxx
index e7c1d5b2e7631c6da07be1c5fa9148e655ea5442..53c190eb61d30b0d95fb4457be075ec81b30122f 100644
--- a/src/THcInterface.cxx
+++ b/src/THcInterface.cxx
@@ -22,7 +22,7 @@
 #include "THcParmList.h"
 #include "THcDetectorMap.h"
 #include "THaCutList.h"
-#include "THaCodaDecoder.h"
+#include "CodaDecoder.h"
 #include "THaGlobals.h"
 #include "THcGlobals.h"
 #include "THaAnalyzer.h"
@@ -32,7 +32,7 @@
 
 #include "TTree.h"
 
-
+#include <iostream>
 //#include "TGXW.h"
  //#include "TVirtualX.h"
 
@@ -81,7 +81,7 @@ THcInterface::THcInterface( const char* appClassName, int* argc, char** argv,
   gHaScalers = new TList;
   gHaPhysics = new TList;
   // Use the standard CODA file decoder by default
-  gHaDecoder = THaCodaDecoder::Class();
+  gHaDecoder = Decoder::CodaDecoder::Class();
   // File-based database by default
   //  gHaDB      = new THaFileDB();
   gHaTextvars = new THaTextvars;
diff --git a/src/THcParmList.cxx b/src/THcParmList.cxx
index e6caee667ac2d9aaf70b92790fbd6acdad46678a..23ff5be3e1840bdb24c251e632bc79da77dd6285 100644
--- a/src/THcParmList.cxx
+++ b/src/THcParmList.cxx
@@ -339,8 +339,8 @@ void THcParmList::Load( const char* fname, Int_t RunNumber )
 	    if(valstr.IsFloat()) {
 	      fp[currentindex+i] = valstr.Atof();
 	    } else {
-	      THaFormula* formula = new THaFormula("temp",valstr.Data()
-						   ,this, 0);
+	      THaFormula* formula = new THaFormula
+		("temp",valstr.Data(), (Bool_t) 0, this, 0);
 	      fp[currentindex+i] = formula->Eval();
 	      delete formula;
 	    }
@@ -377,8 +377,8 @@ void THcParmList::Load( const char* fname, Int_t RunNumber )
 	    if(valstr.IsFloat()) {
 	      existingp[currentindex+i] = valstr.Atof();
 	    } else {
-	      THaFormula* formula = new THaFormula("temp",valstr.Data()
-						   ,this, 0);
+	      THaFormula* formula = new THaFormula
+		("temp",valstr.Data(), (Bool_t) 0, this, 0);
 	      existingp[currentindex+i] = formula->Eval();
 	      delete formula;
 	    }
@@ -403,8 +403,8 @@ void THcParmList::Load( const char* fname, Int_t RunNumber )
 	  if(valstr.IsFloat()) {
 	    fp[i] = valstr.Atof();
 	  } else {
-	    THaFormula* formula = new THaFormula("temp",valstr.Data()
-						 ,this, 0);
+	    THaFormula* formula = new THaFormula
+	      ("temp",valstr.Data(), (Bool_t) 0, this, 0);
 	    fp[i] = formula->Eval();
 	    delete formula;
 	  }
diff --git a/src/THcShowerPlane.cxx b/src/THcShowerPlane.cxx
index 8bd3d32e3174eeb900654d98766965c8a6a3d756..81c9f67adf9a6f1c392f97f5593e2ce6d7e77cba 100644
--- a/src/THcShowerPlane.cxx
+++ b/src/THcShowerPlane.cxx
@@ -93,7 +93,6 @@ Int_t THcShowerPlane::ReadDatabase( const TDatime& date )
 
   THcShower* fParent;
   fParent = (THcShower*) GetParent();
-
   //  Find the number of elements
   fNelem = fParent->GetNBlocks(fLayerNum-1);
 
@@ -152,7 +151,7 @@ Int_t THcShowerPlane::ReadDatabase( const TDatime& date )
   if (fParent->fdbg_init_cal) {
     cout << "---------------------------------------------------------------\n";
     cout << "Debug output from THcShowerPlane::ReadDatabase for "
-	 << GetApparatus()->GetName() << ":" << endl;
+    	 << GetParent()->GetPrefix() << ":" << endl;
 
     cout << "  Layer #" << fLayerNum << ", number of elements " << fNelem
 	 << endl;
@@ -213,7 +212,7 @@ void THcShowerPlane::Clear( Option_t* )
   if ( ((THcShower*) GetParent())->fdbg_decoded_cal ) {
     cout << "---------------------------------------------------------------\n";
     cout << "Debug output from THcShowerPlane::Clear for "
-	 << GetApparatus()->GetName() << ":" << endl;
+    	 << GetParent()->GetPrefix() << ":" << endl;
 
     cout << " Cleared ADC hits for plane " << GetName() << endl;
     cout << "---------------------------------------------------------------\n";
@@ -229,7 +228,7 @@ Int_t THcShowerPlane::Decode( const THaEvData& evdata )
   if ( ((THcShower*) GetParent())->fdbg_decoded_cal ) {
     cout << "---------------------------------------------------------------\n";
     cout << "Debug output from THcShowerPlane::Decode for "
-	 << GetApparatus()->GetName() << ":" << endl;
+      	 << GetParent()->GetPrefix() << ":" << endl;
 
     cout << " Called for plane " << GetName() << endl;
     cout << "---------------------------------------------------------------\n";
@@ -356,7 +355,7 @@ Int_t THcShowerPlane::ProcessHits(TClonesArray* rawhits, Int_t nexthit)
 
     cout << "---------------------------------------------------------------\n";
     cout << "Debug output from THcShowerPlane::ProcessHits for "
-	 << GetApparatus()->GetName() << ":" << endl;
+    	 << fParent->GetPrefix() << ":" << endl;
 
     cout << "  nrawhits =  " << nrawhits << "  nexthit =  " << nexthit << endl;
     cout << "  Sparsified hits for HMS calorimeter plane #" << fLayerNum
@@ -442,7 +441,7 @@ Int_t THcShowerPlane::AccumulatePedestals(TClonesArray* rawhits, Int_t nexthit)
 
     cout << "---------------------------------------------------------------\n";
     cout << "Debug output from THcShowerPlane::AcculatePedestals for "
-	 << GetApparatus()->GetName() << ":" << endl;
+    	 << GetParent()->GetPrefix() << ":" << endl;
 
     cout << "Processed hit list for plane " << GetName() << ":\n";
 
@@ -498,7 +497,7 @@ void THcShowerPlane::CalculatePedestals( )
 
     cout << "---------------------------------------------------------------\n";
     cout << "Debug output from THcShowerPlane::CalculatePedestals for"
-	 << GetApparatus()->GetName() << ":" << endl;
+    	 << GetParent()->GetPrefix() << ":" << endl;
 
     cout << "  ADC pedestals and thresholds for calorimeter plane "
 	 << GetName() << endl;