diff --git a/.gitignore b/.gitignore
index 2603f0df93e17739368bab554e6ccaf4a47de015..aca04a8a200f82339110d7cd4898be45a44fc409 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@ examples/*.root
 examples/*.log.*
 # This is auto generated by hodtest.C
 examples/db_cratemap.dat
+examples/report.out
 
 # Working directory
 work
diff --git a/Makefile b/Makefile
index 96eeb7a45b67149f99e50bf9be87ee8c7f041a95..0b86cf7a6e7325acd369ee1caa32f80635ca3f15 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,8 @@ SRC  =  src/THcInterface.cxx src/THcParmList.cxx src/THcAnalyzer.cxx \
 	src/THcSpacePoint.cxx src/THcDCTrack.cxx \
 	src/THcShower.cxx src/THcShowerPlane.cxx \
 	src/THcRawShowerHit.cxx \
-	src/THcAerogel.cxx src/THcAerogelHit.cxx
+	src/THcAerogel.cxx src/THcAerogelHit.cxx \
+	src/THcFormula.cxx
 
 # Name of your package. 
 # The shared library that will be built will get the name lib$(PACKAGE).so
diff --git a/SConscript.py b/SConscript.py
index e346e9aac0d0f7de3c0d8328dd9fabe985d4cf83..63f47f41a8552c57c6725a803ec2ec1416b02db4 100644
--- a/SConscript.py
+++ b/SConscript.py
@@ -17,6 +17,7 @@ hcheaders = Split("""
 	src/THcDriftChamber.h src/THcRawDCHit.h src/THcDCHit.h src/THcDCWire.h src/THcSpacePoint.h 
 	src/THcDCLookupTTDConv.h src/THcDCTimeToDistConv.h src/THcShower.h src/THcShowerPlane.h 
 	src/THcRawShowerHit.h src/THcAerogel.h src/THcAerogelHit.h src/THcGlobals.h src/THcDCTrack.h
+        src/THcFormula.h
 	src/HallC_LinkDef.h
 	""")
 pbaseenv.RootCint(roothcdict,hcheaders)
diff --git a/examples/hodtest.C b/examples/hodtest.C
index 982e284adffdc261d98dec97cbf39ec5f105b017..bac859d6ad0a95f8560874f3ba8bda6b2b138151 100644
--- a/examples/hodtest.C
+++ b/examples/hodtest.C
@@ -76,4 +76,5 @@
   //  analyzer->SetSummaryFile("summary_example.log"); // optional
   
   analyzer->Process(run);     // start the actual analysis
+  analyzer->PrintReport("report.template","report.out");
 }
diff --git a/examples/report.template b/examples/report.template
new file mode 100644
index 0000000000000000000000000000000000000000..5856b9fa3ddd981872b1450616f7bd56e24a7278
--- /dev/null
+++ b/examples/report.template
@@ -0,0 +1,34 @@
+
+           This is a report template file.
+
+It can be used to create simple run summary/statistics output files.
+
+To produce a report, put in your analysis steering script, the line 
+
+   analyzer->PrintReport(templatefilename, reportfilename); 
+
+where analyzer is your analyzer object.
+
+The template file is copied to the output file, except that anything
+inside of the braces gets evaluated.  If the braces contain a string variable,
+the value of variable replaces the braced name.  Otherwise what is
+in the braces is evaluated as an expression.  Currently the expression can be
+composed of Hall C style parameter variables, cut results (not really too usefull)
+and cut statistics.  (Number of times called and number of times passed.)
+
+For example, {100*Pedestal_event.npassed/Pedestal_event.ncalled:%.2f}% is the percentage of events that were pedestal events.
+
+Horizontal drift chamber z positions:
+Chamber 1: {hdc_zpos[0]:%6.2f} {hdc_zpos[1]:%6.2f} {hdc_zpos[2]:%6.2f} {hdc_zpos[3]:%6.2f} {hdc_zpos[4]:%6.2f} {hdc_zpos[5]:%6.2f} 
+Chamber 2: {hdc_zpos[6]:%6.2f} {hdc_zpos[7]:%6.2f} {hdc_zpos[8]:%6.2f} {hdc_zpos[9]:%6.2f} {hdc_zpos[10]:%6.2f} {hdc_zpos[11]:%6.2f} 
+
+The expression result can be formatted by putting a ":" followed by
+a c-style format after the expression.
+
+The HMS reconstruction coefficient file name is {h_recon_coeff_filename}
+The names of the HMS drift chamber planes are: {hdc_plane_names}
+
+Later, such things as hardware scalers will be added to the set of variables
+that can be used in expressions.
+
+
diff --git a/src/HallC_LinkDef.h b/src/HallC_LinkDef.h
index 53a5b40a5c2f265f7b3f326ea2590a8b1c8ad329..7a49293269021fffad2ba8283b1f6df74218a61a 100644
--- a/src/HallC_LinkDef.h
+++ b/src/HallC_LinkDef.h
@@ -33,5 +33,6 @@
 #pragma link C++ class THcRawShowerHit+;
 #pragma link C++ class THcAerogel+;
 #pragma link C++ class THcAerogelHit+;
+#pragma link C++ class THcFormula+;
 
 #endif
diff --git a/src/THcAnalyzer.cxx b/src/THcAnalyzer.cxx
index de063359287e3a9b2ff323dbf890aefe47cf0c32..d238146d4de58a6f40c9e3ff1a4c2a4cca7fe0dc 100644
--- a/src/THcAnalyzer.cxx
+++ b/src/THcAnalyzer.cxx
@@ -24,11 +24,16 @@
 #include "THcAnalyzer.h"
 #include "THaBenchmark.h"
 #include "TList.h"
+#include "THcParmList.h"
+#include "THcFormula.h"
+#include "THcGlobals.h"
+#include "TMath.h"
 
 #include <fstream>
 #include <algorithm>
 #include <iomanip>
 #include <cstring>
+#include <iostream>
 
 using namespace std;
 
@@ -52,6 +57,78 @@ THcAnalyzer::~THcAnalyzer()
 
 }
 
+//_____________________________________________________________________________
+void THcAnalyzer::PrintReport(const char* templatefile, const char* ofile)
+{
+  // Copy template to ofile, replacing {stuff} with the evaluated
+  // value of stuff.
+  ifstream ifile;
+  ifile.open(templatefile);
+
+  if(!ifile.is_open()) {
+    cout << "Error opening template file " << templatefile << endl;
+    return;
+  }
+
+  ofstream ostr(ofile);
+
+  if(!ostr.is_open()) {
+      cout << "Error opening report output file " << ofile << endl;
+  }
+
+  // In principle, we should allow braces to be escaped.  But for
+  // now we won't.  Existing template files don't seem to output
+  // any braces
+  for(string line; getline(ifile, line);) {
+    //    cout << line << endl;
+    string::size_type start;
+    while((start = line.find('{',0)) != string::npos) {
+      //      cout << start << endl;
+      string::size_type end = line.find('}',start);
+      if(end==string::npos) break; // No more expressions on the line
+      string expression=line.substr(start+1,end-start-1);
+      string::size_type formatpos = expression.find(':',0);
+      string format;
+      if(formatpos != string::npos) {
+	format=expression.substr(formatpos+1);
+	expression=expression.substr(0,formatpos);
+	//	cout << "|" << expression << "|" << format << "|" << endl;
+      }
+      // Should we first check if the expression can be simply a variable
+      // or index into variable?
+      // For now, first check if it is a string.
+      // If not, then evaluate as an expression.
+      string replacement;
+      if(const char *textstring=gHcParms->GetString(expression)) {
+	//	cout << expression << " is a string with value " << textstring << endl;
+	if(format.empty()) format = "%s";
+	replacement=Form(format.c_str(),textstring);
+      } else {
+	THcFormula* formula = new THcFormula("temp",expression.c_str(),gHcParms, gHaCuts);
+	Double_t value=formula->Eval();
+	// If the value is close to integer and no format is defined
+	// use "%.0f" to print out integer
+	if(format.empty()) {
+	  if(TMath::Abs(value-TMath::Nint(value)) < 0.0000001) {
+	    format = "%.0f";
+	  } else {
+	    format = "%f";
+	  }
+	}
+	replacement=Form(format.c_str(),value);
+      }
+      //      cout << "Replacement:" << replacement << endl;
+      line.replace(start,end-start+1,replacement);
+    }
+    ostr << line << endl;
+  }
+  ostr.close();
+  ifile.close();
+
+  return;
+}
+
+
 //_____________________________________________________________________________
 
 ClassImp(THcAnalyzer)
diff --git a/src/THcAnalyzer.h b/src/THcAnalyzer.h
index 3506ac50ef33db55e40ad69cb2a264b7c6c43b0b..e57d75e361826b42c4c310bfaaa4c76ef7c71992 100644
--- a/src/THcAnalyzer.h
+++ b/src/THcAnalyzer.h
@@ -18,6 +18,8 @@ public:
 
   void SetPedestalEvtype( Int_t evtype ) { fPedestalEvtype = evtype; }
 
+  void PrintReport( const char* templatefile, const char* ofile);
+
 protected:
 
   Int_t fPedestalEvtype;
diff --git a/src/THcFormula.cxx b/src/THcFormula.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a46b0282d208374148ac26f2e7556d00e5cc66f6
--- /dev/null
+++ b/src/THcFormula.cxx
@@ -0,0 +1,145 @@
+//*-- Author :    Stephen Wood  17-Oct-2013
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcFormula
+//
+// Tweaked THaFormula.  If cutname.scaler is used in a formula, then
+// it is evaluated as the number of times that the cut passed.
+// Use EVariableType of kUndefined to indicate cut scaler in list of
+// variables used in the formula
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "THcFormula.h"
+#include "THaVarList.h"
+#include "THaCutList.h"
+#include "THaCut.h"
+
+#include <iostream>
+
+using namespace std;
+
+static const Double_t kBig = 1e38; // Error value
+
+//_____________________________________________________________________________
+THcFormula::THcFormula(const char* name, const char* expression, 
+		       const THaVarList* vlst, const THaCutList* clst ) :
+  THaFormula()
+{
+
+  // 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 fVarList is set. 
+  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;
+
+  Compile();   // This calls our own Compile()
+}
+
+
+//_____________________________________________________________________________
+THcFormula::~THcFormula()
+{
+  // Destructor
+}
+
+//_____________________________________________________________________________
+Int_t THcFormula::DefinedCut( const TString& name )
+{
+  // Check if 'name' is a known cut. If so, enter it in the local list of 
+  // variables used in this formula.
+
+  EVariableType thistype;
+  TString realname;
+  Int_t period = name.Index('.');
+  if(period < 0) {
+    realname = name;
+    thistype = kCut;
+  } else {
+    realname = name(0,period);
+    TString attribute(name(period+1,name.Length()-period-1));
+    if(attribute.CompareTo("scaler")==0 || attribute.CompareTo("npassed")==0) {
+      thistype = (EVariableType) kCutScaler;
+    } else if (attribute.CompareTo("ncalled")==0) {
+      thistype = (EVariableType) kCutNCalled;
+    } else {
+      thistype = kUndefined;
+    }
+  }
+
+  // Cut names are obviously only valid if there is a list of existing cuts
+  if( fCutList ) {
+    const 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 )
+	  return i;
+      }
+      def->type = thistype;
+      def->code  = pcut;
+      def->index = 0;
+      fNpar = 0;
+      return fNcodes++;
+    }
+  }
+  return -1;
+}
+
+//_____________________________________________________________________________
+Double_t THcFormula::DefinedValue( Int_t i )
+{
+  // Get value of i-th variable in the formula
+  // If the i-th variable is a cut, return its last result
+  // (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( def->type ) {
+  case kVariable:
+  case kString:
+    return reinterpret_cast<const THaVar*>(ptr)->GetValue( def->index );
+    break;
+  case kCut:
+    return reinterpret_cast<const THaCut*>(ptr)->GetResult();
+    break;
+  case kCutScaler:
+    return reinterpret_cast<const THaCut*>(ptr)->GetNPassed();
+    break;
+  case kCutNCalled:
+    return reinterpret_cast<const THaCut*>(ptr)->GetNCalled();
+    break;
+  default:
+    return kBig;
+  }
+}  
+
+//_____________________________________________________________________________
+
+ClassImp(THcFormula)
diff --git a/src/THcFormula.h b/src/THcFormula.h
new file mode 100644
index 0000000000000000000000000000000000000000..13e854c1320cd6dd397834bce0202e20106442ae
--- /dev/null
+++ b/src/THcFormula.h
@@ -0,0 +1,30 @@
+#ifndef ROOT_THcFormula
+#define ROOT_THcFormula
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcFormula
+// 
+//////////////////////////////////////////////////////////////////////////
+
+#include "THaFormula.h"
+
+class THcFormula : public THaFormula {
+
+public:
+
+  THcFormula( const char* name, const char* formula, 
+	      const THaVarList*, const THaCutList* clst);
+  virtual ~THcFormula();
+
+  virtual Double_t DefinedValue( Int_t i);
+  virtual Int_t    DefinedCut( const TString& variable);
+
+protected:
+
+  enum {kCutScaler = kString+1};
+  enum {kCutNCalled = kCutScaler+1};
+  ClassDef(THcFormula,0) // Formula with cut scalers
+};
+
+#endif