From d9dc3e4059a260368ea6028c65fb1351e4f6fc38 Mon Sep 17 00:00:00 2001
From: "Stephen A. Wood" <saw@jlab.org>
Date: Tue, 24 Apr 2012 12:10:47 -0400
Subject: [PATCH] Code to build Hall C style hit lists.  Demonstrated with
 THcHodoscope, a multiplane scintillator array.  Make a Hall C style
 spectrometer (so that default Hall A detectors are not included.)  Can read a
 Hall C data file and print out hodoscope hits where the left/right TDC/ADC
 are matched up per counter.

---
 Makefile                     |   8 +-
 podd                         |   2 +-
 src/HallC_LinkDef.h          |  10 +-
 src/THcAnalyzer.cxx          |  58 ++++++
 src/THcAnalyzer.h            |  29 +++
 src/THcCodaDecoder.cxx       |  10 -
 src/THcCodaDecoder.h         |  19 --
 src/THcCrateMap.cxx          |  46 -----
 src/THcCrateMap.h            |  41 ----
 src/THcDetectorMap.cxx       | 299 +++++++++++++++++++++++++++++
 src/THcDetectorMap.h         |  61 ++++++
 src/THcGlobals.h             |   3 +-
 src/THcHallCSpectrometer.cxx | 239 ++++++++++++++++++++++++
 src/THcHallCSpectrometer.h   |  37 ++++
 src/THcHitList.cxx           | 102 ++++++++++
 src/THcHitList.h             |  48 +++++
 src/THcHodoscope.cxx         | 353 +++++++++++++++++++++++++++++++++++
 src/THcHodoscope.h           |  88 +++++++++
 src/THcHodoscopeHit.cxx      |  80 ++++++++
 src/THcHodoscopeHit.h        |  38 ++++
 src/THcInterface.cxx         |   3 +
 src/THcRawHit.cxx            |  18 ++
 src/THcRawHit.h              |  43 +++++
 23 files changed, 1512 insertions(+), 123 deletions(-)
 create mode 100644 src/THcAnalyzer.cxx
 create mode 100644 src/THcAnalyzer.h
 delete mode 100644 src/THcCodaDecoder.cxx
 delete mode 100644 src/THcCodaDecoder.h
 delete mode 100644 src/THcCrateMap.cxx
 delete mode 100644 src/THcCrateMap.h
 create mode 100644 src/THcDetectorMap.cxx
 create mode 100644 src/THcDetectorMap.h
 create mode 100644 src/THcHallCSpectrometer.cxx
 create mode 100644 src/THcHallCSpectrometer.h
 create mode 100644 src/THcHitList.cxx
 create mode 100644 src/THcHitList.h
 create mode 100644 src/THcHodoscope.cxx
 create mode 100644 src/THcHodoscope.h
 create mode 100644 src/THcHodoscopeHit.cxx
 create mode 100644 src/THcHodoscopeHit.h
 create mode 100644 src/THcRawHit.cxx
 create mode 100644 src/THcRawHit.h

diff --git a/Makefile b/Makefile
index 30f7d0f..6fc33b4 100644
--- a/Makefile
+++ b/Makefile
@@ -8,8 +8,10 @@
 # there must be a corresponding header file (*.h).
 
 
-SRC  =  src/THcInterface.cxx src/THcParmList.cxx src/THcCrateMap.cxx \
-	src/THcCodaDecoder.cxx
+SRC  =  src/THcInterface.cxx src/THcParmList.cxx src/THcAnalyzer.cxx \
+	src/THcHodoscopeHit.cxx src/THcRawHit.cxx \
+	src/THcHitList.cxx src/THcDetectorMap.cxx src/THcHodoscope.cxx \
+	src/THcHallCSpectrometer.cxx
 
 # Name of your package. 
 # The shared library that will be built will get the name lib$(PACKAGE).so
@@ -164,7 +166,7 @@ install:	all
 	cp -p $(USERLIB) $(HOME)/cue/SRC/ana
 
 clean:
-		rm -f *.o *~ $(USERLIB) $(USERDICT).*
+		rm -f src/*.o *~ $(USERLIB) $(USERDICT).*
 
 realclean:	clean
 		rm -f *.d
diff --git a/podd b/podd
index 9a47be4..fe3e746 160000
--- a/podd
+++ b/podd
@@ -1 +1 @@
-Subproject commit 9a47be4dc77822bd7af642d1b3ca962f09cf89f6
+Subproject commit fe3e7463fe6e531dd790cf5ea103a368e4b17b7a
diff --git a/src/HallC_LinkDef.h b/src/HallC_LinkDef.h
index e6da1aa..c743ba4 100644
--- a/src/HallC_LinkDef.h
+++ b/src/HallC_LinkDef.h
@@ -5,10 +5,16 @@
 #pragma link off all functions;
 
 #pragma link C++ global gHcParms;
+#pragma link C++ global gHcDetectorMap;
 
 #pragma link C++ class THcInterface+;
 #pragma link C++ class THcParmList+;
-#pragma link C++ class THcCrateMap+;
-#pragma link C++ class THcCodaDecoder+;
+#pragma link C++ class THcAnalyzer+;
+#pragma link C++ class THcRawHit+;
+#pragma link C++ class THcHodoscopeHit+;
+#pragma link C++ class THcHitList+;
+#pragma link C++ class THcHodoscope+;
+#pragma link C++ class THcDetectorMap+;
+#pragma link C++ class THcHallCSpectrometer+;
 
 #endif
diff --git a/src/THcAnalyzer.cxx b/src/THcAnalyzer.cxx
new file mode 100644
index 0000000..de06335
--- /dev/null
+++ b/src/THcAnalyzer.cxx
@@ -0,0 +1,58 @@
+//*-- Author :    Stephen Wood  13-March-2012
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcAnalyzer
+//
+// THcAnalyzer is the base class for a "Hall C analyzer" class.
+// An analyzer defines the basic actions to perform during analysis.
+// THcAnalyzer is the default analyzer that is used if no user class is
+// defined.  It performs a standard analysis consisting of
+//
+//   1. Decoding/Calibrating
+//   2. Track Reconstruction
+//   3. Physics variable processing
+//
+// At the end of each step, testing and histogramming are done for
+// the appropriate block defined in the global test/histogram lists.
+//
+// Hall C has their own analyzer class because some things are bound to
+// be different.
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "THcAnalyzer.h"
+#include "THaBenchmark.h"
+#include "TList.h"
+
+#include <fstream>
+#include <algorithm>
+#include <iomanip>
+#include <cstring>
+
+using namespace std;
+
+
+// Pointer to single instance of this object
+//THcAnalyzer* THcAnalyzer::fgAnalyzer = 0;
+
+//FIXME: 
+// do we need to "close" scalers/EPICS analysis if we reach the event limit?
+
+//_____________________________________________________________________________
+THcAnalyzer::THcAnalyzer()
+{
+
+}
+
+//_____________________________________________________________________________
+THcAnalyzer::~THcAnalyzer()
+{
+  // Destructor. 
+
+}
+
+//_____________________________________________________________________________
+
+ClassImp(THcAnalyzer)
+
diff --git a/src/THcAnalyzer.h b/src/THcAnalyzer.h
new file mode 100644
index 0000000..172d125
--- /dev/null
+++ b/src/THcAnalyzer.h
@@ -0,0 +1,29 @@
+#ifndef ROOT_THcAnalyzer
+#define ROOT_THcAnalyzer
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcAnalyzer
+// 
+//////////////////////////////////////////////////////////////////////////
+
+#include "THaAnalyzer.h"
+
+class THcAnalyzer : public THaAnalyzer {
+
+public:
+
+  THcAnalyzer();
+  virtual ~THcAnalyzer();
+
+protected:
+    
+private:
+  //  THcAnalyzer( const THcAnalyzer& );
+  //  THcAnalyzer& operator=( const THcAnalyzer& );
+  
+  ClassDef(THcAnalyzer,0)  //Hall C Analyzer Standard Event Loop
+
+};
+
+#endif
diff --git a/src/THcCodaDecoder.cxx b/src/THcCodaDecoder.cxx
deleted file mode 100644
index 2146945..0000000
--- a/src/THcCodaDecoder.cxx
+++ /dev/null
@@ -1,10 +0,0 @@
-//
-// THcCodaDecoder
-//
-// author  Stephen Wood (saw@jlab.org)
-
-#include "THcCodaDecoder.h"
-
-using namespace std;
-
-ClassImp(THcCodaDecoder)
diff --git a/src/THcCodaDecoder.h b/src/THcCodaDecoder.h
deleted file mode 100644
index d94d749..0000000
--- a/src/THcCodaDecoder.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef THcCodaDecoder_
-#define THcCodaDecoder_
-
-// Hall C version of decoder
-
-#include "THaCodaDecoder.h"
-
-class THcCodaDecoder : public THaCodaDecoder {
-
- public:
-
- private:
-
- protected:
-  ClassDef(THcCodaDecoder,0) // Hall C Coda Decoder
-
-};
-#endif
-
diff --git a/src/THcCrateMap.cxx b/src/THcCrateMap.cxx
deleted file mode 100644
index 2546770..0000000
--- a/src/THcCrateMap.cxx
+++ /dev/null
@@ -1,46 +0,0 @@
-/////////////////////////////////////////////////////////////////////
-//
-//  THcCrateMap
-//  Layout, or "map", of DAQ Crates.
-//
-//  THaCrateMap contains info on how the DAQ crates
-//  are arranged in Hall A, i.e whether slots are
-//  fastbus or vme, what the module types are, and
-//  what header info to expect.  Probably nobody needs
-//  to know about this except the author, and at present
-//  an object of this class is a private member of the decoder.
-//
-//  author  Robert Michaels (rom@jlab.org)
-//  author  Stephen Wood (saw@jlab.org)
-//
-/////////////////////////////////////////////////////////////////////
-
-
-#include "THcCrateMap.h"
-
-#include "TError.h"
-
-using namespace std;
-
-THcCrateMap::THcCrateMap( const char* db_filename )
-{
-  // Need to do something different since we are going to read
-  // a Hall C style map file.
-
-  // Construct uninitialized crate map. The argument is the name of
-  // the database file to use for initialization
-
-  if( !db_filename || !*db_filename ) {
-    ::Warning( "THcCrateMap", "Undefined database file name, "
-	       "using default \"db_cratemap.dat\"" );
-    db_filename = "cratemap";
-  }
-  // Why does this give an error?  Can't I use a private
-  // member of the class I inherit from?
-  fMapfileName = db_filename;
-
-}
-
-
-
-ClassImp(THcCrateMap)
diff --git a/src/THcCrateMap.h b/src/THcCrateMap.h
deleted file mode 100644
index e286323..0000000
--- a/src/THcCrateMap.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef THcCrateMap_
-#define THcCrateMap_
-
-/////////////////////////////////////////////////////////////////////
-//
-//  THcCrateMap
-//  Layout, or "map", of DAQ Crates.
-//
-//  Inheriting from THaCrateMap
-//
-//  THcCrateMap contains info on how the DAQ crates
-//  are arranged in Hall A, i.e whether slots are
-//  fastbus or vme, what the module types are, and
-//  what header info to expect.  Probably nobody needs
-//  to know about this except the author, and at present
-//  an object of this class is a private member of the decoder.
-//
-//  author  Robert Michaels (rom@jlab.org)
-//  author  Stephen Wood (saw@jlab.org)
-//
-/////////////////////////////////////////////////////////////////////
-
-
-#include "THaCrateMap.h"
-
-class THcCrateMap : public THaCrateMap {
-
- public:
-
-  THcCrateMap( const char* db = "cratemap" );    // Construct uninitialized
-
- private:
-
-  TString fMapfileName;
-
- protected:
-  ClassDef(THcCrateMap,0) // Crate map
-
-
-};     
-#endif
diff --git a/src/THcDetectorMap.cxx b/src/THcDetectorMap.cxx
new file mode 100644
index 0000000..5a9214f
--- /dev/null
+++ b/src/THcDetectorMap.cxx
@@ -0,0 +1,299 @@
+//*-- Author: Stephen Wood
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcDetectorMap
+//
+// Class to read and hold Hall C style detector map
+//
+// Will need method to retrieve all map entries for a given
+// detector id.
+//
+// Not sure we will keep this class, but still need the parsing of the map file
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "THcDetectorMap.h"
+
+#include "TObjArray.h"
+#include "TObjString.h"
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+
+using namespace std;
+
+ClassImp(THcDetectorMap)
+
+inline static bool IsComment( const string& s, string::size_type pos )
+{
+  return ( pos != string::npos && pos < s.length() &&
+	   (s[pos] == '!') );
+}
+
+//_____________________________________________________________________________
+THcDetectorMap::THcDetectorMap() : fNchans(0)
+{
+}
+
+//_____________________________________________________________________________
+THcDetectorMap::~THcDetectorMap()
+{
+}
+
+bool THcDetectorMap::compare(const ChaninMod *first, const ChaninMod *second) {
+  // This one not used, but we get a link error if we don't include
+  // a compare method
+      return((first->channel < second->channel)? true: false);
+}
+struct Functor
+{
+  bool operator() (const THcDetectorMap::ChaninMod &first, const THcDetectorMap::ChaninMod &second)
+  { return((first.channel < second.channel)? true: false);}
+};
+//_____________________________________________________________________________
+Int_t THcDetectorMap::FillMap(THaDetMap *detmap, const char *detectorname)
+// Should probably return a status
+{
+  list<ModChanList>::iterator imod;
+  list<ChaninMod>::iterator ichan;
+  ChaninMod Achan;
+  ModChanList Amod;
+
+  // Translate detector name into and ID
+  // For now just long if then else.  Could get it from the comments
+  // at the beginning of the map file.
+  Int_t did;
+  if(strcasecmp(detectorname,"HDC")==0) {
+    did = 1;
+  } else if (strcasecmp(detectorname,"HSCIN")==0) {
+    did = 2;
+  } else if (strcasecmp(detectorname,"HCER")==0) {
+    did = 3;
+  } else if (strcasecmp(detectorname,"HCAL")==0) {
+    did = 4;
+  } else if (strcasecmp(detectorname,"HMISC")==0) {
+    did = 5;
+  } else if (strcasecmp(detectorname,"GMISC")==0) {
+    did = 6;
+  } else if (strcasecmp(detectorname,"HAERO")==0) {
+    did = 7;
+  } else {
+    did = 0;
+  }
+  // Start SHMS with S?  What about SOS?
+
+  mlist.clear();
+  //  cout << "fNchans=" << fNchans << endl;
+  for(Int_t ich=0;ich<fNchans;ich++) {
+    if(fTable[ich].did == did) {
+      Int_t roc=fTable[ich].roc;
+      Int_t slot=fTable[ich].slot;
+      Int_t model=fTable[ich].model;
+      //      cout << "ROC=" << fTable[ich].roc << "  SLOT=" << fTable[ich].slot
+      //	   << " CHANNEL=" << fTable[ich].channel << endl;
+      Achan.channel = fTable[ich].channel;
+      Achan.plane = fTable[ich].plane;
+      Achan.counter = fTable[ich].counter;
+      Achan.signal = fTable[ich].signal;
+      for(imod=mlist.begin(); imod!= mlist.end(); ++imod) {
+	if((*imod).roc == roc && (*imod).slot == slot) {
+	  //	  cout << "Pushing chan " << Achan.channel << " to " << roc
+	  //	       << " " << slot << endl;
+	  (*imod).clist.push_back(Achan);
+	  break;
+	}
+      }
+      if(imod == mlist.end()) {
+	Amod.roc = roc;
+	Amod.slot = slot;
+	Amod.model = model;
+	Amod.clist.clear();
+	Amod.clist.push_back(Achan);
+	mlist.push_back(Amod);
+	// 	cout << "New module  " << Achan.channel << " to " << roc
+	//	     << " " << slot << endl;
+      }
+    }
+  }
+  if(mlist.size() <= 0) {
+    return(-1);
+  }
+  Functor f;
+  for(imod=mlist.begin(); imod!= mlist.end(); ++imod) {
+    //    cout << "Slot " << (*imod).slot << endl;
+    list<ChaninMod> *clistp = &((*imod).clist);
+    clistp->sort(f);//Sort by channel
+  }
+  // Copy the information to the Hall A style detector map
+  // grouping consecutive channels that are all the same plane
+  // and signal type
+  for(imod=mlist.begin(); imod!= mlist.end(); ++imod) {
+    UShort_t roc = (*imod).roc;
+    UShort_t slot = (*imod).slot;
+    UInt_t model=(*imod).model;
+    //    cout << "Slot " << slot << endl;
+    list<ChaninMod> *clistp = &((*imod).clist);
+    Int_t first_chan = -1;
+    Int_t last_chan = -1;
+    Int_t last_plane = -1;
+    Int_t last_signal = -1;
+    Int_t first_counter = -1;
+    Int_t last_counter = -1;
+    for(ichan=clistp->begin(); ichan!=clistp->end(); ++ichan) {
+      Int_t this_chan = (*ichan).channel;
+      Int_t this_counter = (*ichan).counter;
+      Int_t this_signal = (*ichan).signal;
+      Int_t this_plane = (*ichan).plane;
+      if(last_chan+1!=this_chan || last_counter+1 != this_counter 
+	 || last_plane != this_plane || last_signal!=this_signal) {
+	if(last_chan >= 0) {
+	  if(ichan != clistp->begin()) {
+	    //	    cout << "AddModule " << slot << " " << first_chan << 
+	    //  " " << last_chan << " " << first_counter << endl;
+	    detmap->AddModule((UShort_t)roc, (UShort_t)slot,
+			      (UShort_t)first_chan, (UShort_t)last_chan, 
+			      (UInt_t) first_counter, model, (Int_t) 0,
+			      (Int_t) -1, (UInt_t)last_plane, (UInt_t)last_signal);
+	  }
+	}
+	first_chan = this_chan;
+	first_counter = this_counter;
+      }
+      last_chan = this_chan;
+      last_counter = this_counter;
+      last_plane = this_plane;
+      last_signal = this_signal;
+      //      cout << "  Channel " << (*ichan).channel << " " <<
+      //	(*ichan).plane << " " <<  (*ichan).counter << endl;
+    }
+    detmap->AddModule((UShort_t)roc, (UShort_t)slot,
+		      (UShort_t)first_chan, (UShort_t)last_chan, 
+		      (UInt_t) first_counter, model, (Int_t) 0,
+		      (Int_t) -1, (UInt_t)last_plane, (UInt_t)last_signal);
+  }
+  
+  return(0);
+}
+
+void THcDetectorMap::Load(const char *fname)
+{
+  static const char* const here = "THcDetectorMap::Load";
+  static const char* const whtspc = " \t";
+
+  ifstream ifile;
+
+  ifile.open(fname);
+  if(!ifile.is_open()) {
+    Error(here, "error opening detector map file %s",fname);
+    return;			// Need a success/failure argument?
+  }
+  string line;
+
+  Int_t roc=0;
+  Int_t nsubadd=0;
+  Int_t mask=0;
+  Int_t bsub=0;
+  Int_t detector=0;
+  Int_t slot=0;
+  Int_t model=0;
+
+  fNchans = 0;
+
+  string::size_type start, pos=0;
+
+  char varname[100];
+
+  while(getline(ifile,line)) {
+    // BLank line or comment
+    if(line.empty()
+       || (start = line.find_first_not_of( whtspc )) == string::npos
+       || IsComment(line, start) )
+      continue;
+
+    //    cout << "MAPA: " << line << endl;
+
+    // Remove comment from line
+    while ((pos = line.find_first_of("!", pos+1)) != string::npos) {
+      if(IsComment(line, pos)) {
+	line.erase(pos);
+	break;
+      }
+    }
+
+    // Get rid of all white space
+    while((pos=line.find_first_of(whtspc)) != string::npos) {
+      line.erase(pos,1);
+    }
+
+    //    cout << "MAPB: " << line << endl;
+
+  // Decide if line is ROC/NSUBADD/MASK/BSUB/DETECTOR/SLOT = something
+  // or chan, plane, counter[, signal]
+
+  
+    if((pos=line.find_first_of("=")) != string::npos) { // Setting parameter
+      strcpy(varname, (line.substr(0,pos)).c_str());
+      Int_t valuestartpos = pos+1;
+      Int_t value = atoi(line.substr(valuestartpos).c_str());
+      // Some if statements
+      if(strcasecmp(varname,"detector")==0) {
+	detector = value;
+      } else if (strcasecmp(varname,"roc")==0) {
+	roc = value;
+      } else if (strcasecmp(varname,"nsubadd")==0) {
+	nsubadd = value;
+      } else if (strcasecmp(varname,"mask")==0) {
+	mask = value;
+      } else if (strcasecmp(varname,"bsub")==0) {
+	bsub = value;
+      } else if (strcasecmp(varname,"slot")==0) {
+	slot = value;
+      }
+      if(nsubadd == 96) {
+	model = 1877;
+      } else if (nsubadd == 64) {
+	if(bsub == 16) {
+	  model = 1872;
+	} else if(bsub == 17) {
+	  model = 1881;
+	} else {
+	  model = 0;
+	}
+      } else {
+	model = 0;
+      }
+    } else {			// Assume channel definition
+      TString values(line.c_str());
+      TObjArray *vararr = values.Tokenize(",");
+      Int_t nvals = vararr->GetLast()+1;
+      if(nvals<3 || nvals>4) {
+	if(nvals > 1) {	// Silent for help, noecho, nodebug, override
+	  cout << "Map file: Invalid value count: " << line << endl;
+	}
+	continue;
+      }
+      Int_t channel = ((TObjString*)vararr->At(0))->GetString().Atoi();
+      Int_t plane = ((TObjString*)vararr->At(1))->GetString().Atoi();
+      Int_t counter = ((TObjString*)vararr->At(2))->GetString().Atoi();
+      Int_t signal = 0;
+      if(nvals==4) {
+	signal= ((TObjString*)vararr->At(3))->GetString().Atoi();
+      }
+
+      fTable[fNchans].roc=roc;
+      fTable[fNchans].slot=slot;
+      fTable[fNchans].channel=channel;
+      fTable[fNchans].did=detector;
+      fTable[fNchans].plane=plane;
+      fTable[fNchans].counter=counter;
+      fTable[fNchans].signal=signal;
+      fTable[fNchans].model=model;
+
+      fNchans++;
+    }
+  }
+
+}
+
diff --git a/src/THcDetectorMap.h b/src/THcDetectorMap.h
new file mode 100644
index 0000000..d78df90
--- /dev/null
+++ b/src/THcDetectorMap.h
@@ -0,0 +1,61 @@
+#ifndef ROOT_THcDetectorMap
+#define ROOT_THcDetectorMap
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcDetectorMap
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "TObject.h"
+#include "THaDetMap.h"
+#include <list>
+
+class THcDetectorMap : public TObject {
+
+ public:
+  THcDetectorMap();
+  virtual ~THcDetectorMap();
+  
+  virtual void Load(const char *fname);
+  virtual Int_t FillMap(THaDetMap* detmap, const char* detectorname);
+
+  Int_t fNchans;  // Number of hardware channels
+
+  struct Channel { // Mapping for one hardware channel
+    Int_t roc;
+    Int_t slot;
+    Int_t channel;
+    Int_t did;
+    Int_t plane;
+    Int_t counter;
+    Int_t signal;
+    Int_t model;
+  };
+  Channel fTable[10000]; // Big ugly cache of the map file
+
+  struct ChaninMod {
+    Int_t channel;
+    Int_t plane;
+    Int_t counter;
+    Int_t signal;
+  };
+  struct ModChanList {
+    Int_t roc;
+    Int_t slot;
+    Int_t model;
+    std::list<ChaninMod> clist;
+      
+  };
+  std::list<ModChanList> mlist;
+
+  bool compare(const ChaninMod *first, const ChaninMod *second);
+
+ protected:
+
+  ClassDef(THcDetectorMap,0);
+};
+#endif
+
+  
+  
diff --git a/src/THcGlobals.h b/src/THcGlobals.h
index 39b40da..c18bf53 100644
--- a/src/THcGlobals.h
+++ b/src/THcGlobals.h
@@ -6,8 +6,9 @@
 #include "DllImport.h"
 #endif
 
-// Global Analyzer variables. Defined in THaInterface implementation file.
+// Global Analyzer variables. Defined in THcInterface implementation file.
 
 R__EXTERN class THcParmList*  gHcParms;      //List of global symbolic variables
+R__EXTERN class THcDetectorMap*  gHcDetectorMap;   //Cached map file
 
 #endif
diff --git a/src/THcHallCSpectrometer.cxx b/src/THcHallCSpectrometer.cxx
new file mode 100644
index 0000000..53c141c
--- /dev/null
+++ b/src/THcHallCSpectrometer.cxx
@@ -0,0 +1,239 @@
+//*-- Author :    Stephen Wood 20-Apr-2012
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcHallCSpectrometer
+//
+// A standard Hall C spectrometer.
+// Contains no standard detectors,
+//  May add hodoscope
+//
+// The usual name of this object is either "H", "S", or "P"
+// for HMS, SOS, or suPerHMS respectively
+//
+// Defines the functions FindVertices() and TrackCalc(), which are common
+// to both the LeftHRS and the RightHRS.
+//
+// Special configurations of the HRS (e.g. more detectors, different 
+// detectors) can be supported in on e of three ways:
+//
+//   1. Use the AddDetector() method to include a new detector
+//      in this apparatus.  The detector will be decoded properly,
+//      and its variables will be available for cuts and histograms.
+//      Its processing methods will also be called by the generic Reconstruct()
+//      algorithm implemented in THaSpectrometer::Reconstruct() and should
+//      be correctly handled if the detector class follows the standard 
+//      interface design.
+//
+//   2. Write a derived class that creates the detector in the
+//      constructor.  Write a new Reconstruct() method or extend the existing
+//      one if necessary.
+//
+//   3. Write a new class inheriting from THaSpectrometer, using this
+//      class as an example.  This is appropriate if your HRS 
+//      configuration has fewer or different detectors than the 
+//      standard HRS. (It might not be sensible to provide a RemoveDetector() 
+//      method since Reconstruct() relies on the presence of the 
+//      standard detectors to some extent.)
+//
+//  For timing calculations, S1 is treated as the scintillator at the
+//  'reference distance', corresponding to the pathlength correction
+//  matrix.
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "THcHallCSpectrometer.h"
+#include "THaTrackingDetector.h"
+#include "THaTrack.h"
+#include "THaTrackProj.h"
+#include "THaTriggerTime.h"
+#include "TMath.h"
+#include "TList.h"
+
+#include "TList.h"
+#include "TMath.h"
+
+#ifdef WITH_DEBUG
+#include <iostream>
+#endif
+
+using namespace std;
+
+//_____________________________________________________________________________
+THcHallCSpectrometer::THcHallCSpectrometer( const char* name, const char* description ) :
+  THaSpectrometer( name, description )
+{
+  // Constructor. Defines the standard detectors for the HRS.
+  //  AddDetector( new THaTriggerTime("trg","Trigger-based time offset"));
+
+  //sc_ref = static_cast<THaScintillator*>(GetDetector("s1"));
+
+  SetTrSorting(kFALSE);
+}
+
+//_____________________________________________________________________________
+THcHallCSpectrometer::~THcHallCSpectrometer()
+{
+  // Destructor
+}
+
+//_____________________________________________________________________________
+Bool_t THcHallCSpectrometer::SetTrSorting( Bool_t set )
+{
+  if( set )
+    fProperties |= kSortTracks;
+  else
+    fProperties &= ~kSortTracks;
+
+  return set;
+}
+
+//_____________________________________________________________________________
+Bool_t THcHallCSpectrometer::GetTrSorting() const
+{
+  return ((fProperties & kSortTracks) != 0);
+}
+ 
+//_____________________________________________________________________________
+Int_t THcHallCSpectrometer::FindVertices( TClonesArray& tracks )
+{
+  // Reconstruct target coordinates for all tracks found in the focal plane.
+
+  TIter nextTrack( fTrackingDetectors );
+
+  nextTrack.Reset();
+  while( THaTrackingDetector* theTrackDetector =
+	 static_cast<THaTrackingDetector*>( nextTrack() )) {
+#ifdef WITH_DEBUG
+    if( fDebug>1 ) cout << "Call FineTrack() for " 
+			<< theTrackDetector->GetName() << "... ";
+#endif
+    theTrackDetector->FindVertices( tracks );
+#ifdef WITH_DEBUG
+    if( fDebug>1 ) cout << "done.\n";
+#endif
+  }
+
+  // If enabled, sort the tracks by chi2/ndof
+  if( GetTrSorting() )
+    fTracks->Sort();
+  
+  // Find the "Golden Track". 
+  if( GetNTracks() > 0 ) {
+    // Select first track in the array. If there is more than one track
+    // and track sorting is enabled, then this is the best fit track
+    // (smallest chi2/ndof).  Otherwise, it is the track with the best
+    // geometrical match (smallest residuals) between the U/V clusters
+    // in the upper and lower VDCs (old behavior).
+    // 
+    // Chi2/dof is a well-defined quantity, and the track selected in this
+    // way is immediately physically meaningful. The geometrical match
+    // criterion is mathematically less well defined and not usually used
+    // in track reconstruction. Hence, chi2 sortiing is preferable, albeit
+    // obviously slower.
+
+    fGoldenTrack = static_cast<THaTrack*>( fTracks->At(0) );
+    fTrkIfo      = *fGoldenTrack;
+    fTrk         = fGoldenTrack;
+  } else
+    fGoldenTrack = NULL;
+
+  return 0;
+}
+
+//_____________________________________________________________________________
+Int_t THcHallCSpectrometer::TrackCalc()
+{
+  // Additioal track calculations. At present, we only calculate beta here.
+
+  return TrackTimes( fTracks );
+}
+
+//_____________________________________________________________________________
+Int_t THcHallCSpectrometer::TrackTimes( TClonesArray* Tracks ) {
+  // Do the actual track-timing (beta) calculation.
+  // Use multiple scintillators to average together and get "best" time at S1.
+  //
+  // To be useful, a meaningful timing resolution should be assigned
+  // to each Scintillator object (part of the database).
+  
+  if ( !Tracks ) return -1;
+  
+  THaTrack *track=0;
+  Int_t ntrack = GetNTracks();
+
+  // linear regression to:  t = t0 + pathl/(beta*c)
+  //   where t0 is the time of the track at the reference plane (sc_ref).
+  //   t0 and beta are solved for.
+  //
+#if 0
+  for ( Int_t i=0; i < ntrack; i++ ) {
+    track = static_cast<THaTrack*>(Tracks->At(i));
+    THaTrackProj* tr_ref = static_cast<THaTrackProj*>
+      (sc_ref->GetTrackHits()->At(i));
+    
+    Double_t pathlref = tr_ref->GetPathLen();
+    
+    Double_t wgt_sum=0.,wx2=0.,wx=0.,wxy=0.,wy=0.;
+    Int_t ncnt=0;
+    
+    // linear regression to get beta and time at ref.
+    TIter nextSc( fNonTrackingDetectors );
+    THaNonTrackingDetector *det;
+    while ( ( det = static_cast<THaNonTrackingDetector*>(nextSc()) ) ) {
+      THaScintillator *sc = dynamic_cast<THaScintillator*>(det);
+      if ( !sc ) continue;
+
+      const THaTrackProj *trh = static_cast<THaTrackProj*>(sc->GetTrackHits()->At(i));
+      
+      Int_t pad = trh->GetChannel();
+      if (pad<0) continue;
+      Double_t pathl = (trh->GetPathLen()-pathlref);
+      Double_t time = (sc->GetTimes())[pad];
+      Double_t wgt = (sc->GetTuncer())[pad];
+      
+      if (pathl>.5*kBig || time>.5*kBig) continue;
+      if (wgt>0) wgt = 1./(wgt*wgt);
+      else continue;
+      
+      wgt_sum += wgt;
+      wx2 += wgt*pathl*pathl;
+      wx  += wgt*pathl;
+      wxy += wgt*pathl*time;
+      wy  += wgt*time;
+      ncnt++;
+    }
+
+    Double_t beta = kBig;
+    Double_t dbeta = kBig;
+    Double_t time = kBig;
+    Double_t dt = kBig;
+    
+    Double_t delta = wgt_sum*wx2-wx*wx;
+    
+    if (delta != 0.) {
+      time = (wx2*wy-wx*wxy)/delta;
+      dt = TMath::Sqrt(wx2/delta);
+      Double_t invbeta = (wgt_sum*wxy-wx*wy)/delta;
+      if (invbeta != 0.) {
+#if ROOT_VERSION_CODE >= ROOT_VERSION(3,4,0)
+	Double_t c = TMath::C();
+#else
+	Double_t c = 2.99792458e8;
+#endif
+	beta = 1./(c*invbeta);
+	dbeta = TMath::Sqrt(wgt_sum/delta)/(c*invbeta*invbeta);
+      }
+    } 
+
+    track->SetBeta(beta);
+    track->SetdBeta(dbeta);
+    track->SetTime(time);
+    track->SetdTime(dt);
+  }
+#endif  
+  return 0;
+}
+
+//_____________________________________________________________________________
+ClassImp(THcHallCSpectrometer)
diff --git a/src/THcHallCSpectrometer.h b/src/THcHallCSpectrometer.h
new file mode 100644
index 0000000..f560bbf
--- /dev/null
+++ b/src/THcHallCSpectrometer.h
@@ -0,0 +1,37 @@
+#ifndef ROOT_THcHallCSpectrometer
+#define ROOT_THcHallCSpectrometer
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcHallCSpectrometer
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "THaSpectrometer.h"
+
+//class THaScintillator;
+
+class THcHallCSpectrometer : public THaSpectrometer {
+  
+public:
+  THcHallCSpectrometer( const char* name, const char* description );
+  virtual ~THcHallCSpectrometer();
+
+  virtual Int_t   FindVertices( TClonesArray& tracks );
+  virtual Int_t   TrackCalc();
+  virtual Int_t   TrackTimes( TClonesArray* tracks );
+
+  Bool_t SetTrSorting( Bool_t set = kFALSE );
+  Bool_t GetTrSorting() const;
+  
+protected:
+  //  THaScintillator *sc_ref;  // calculate time track hits this plane
+
+  // Flag for fProperties indicating that tracks are to be sorted by chi2
+  static const UInt_t kSortTracks = BIT(16);
+
+  ClassDef(THcHallCSpectrometer,0) //A Hall A High Resolution Spectrometer
+};
+
+#endif
+
diff --git a/src/THcHitList.cxx b/src/THcHitList.cxx
new file mode 100644
index 0000000..9a1303b
--- /dev/null
+++ b/src/THcHitList.cxx
@@ -0,0 +1,102 @@
+//*-- Author :    Stephen Wood 30-March-2012
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcHitList
+//
+// Add hitlist to the Hall A detector base
+// May not need to inherit from THaDetectorBase since we may end up
+// replacing most of the methods
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "THcHitList.h"
+
+using namespace std;
+
+THcHitList::THcHitList()
+{
+  // Normal constructor.
+
+  fRawHitList = NULL;
+
+}
+
+THcHitList::~THcHitList() {
+  // Destructor
+}
+
+void THcHitList::InitHitList(THaDetMap* detmap,
+				  const char *hitclass, Int_t maxhits) {
+  // Probably called by ReadDatabase
+
+  fRawHitList = new TClonesArray(hitclass, maxhits);
+  fRawHitClass = fRawHitList->GetClass();
+  fNMaxRawHits = maxhits;
+  fNRawHits = 0;
+  for(Int_t i=0;i<maxhits;i++) {
+    fRawHitList->ConstructedAt(i);
+  }
+  
+  fdMap = detmap;
+}
+
+Int_t THcHitList::DecodeToHitList( const THaEvData& evdata ) {
+  THcRawHit* rawhit;
+  // cout << " Clearing TClonesArray " << endl;
+  fRawHitList->Clear("C");
+  fNRawHits = 0;
+
+  for ( Int_t i=0; i < fdMap->GetSize(); i++ ) {
+    THaDetMap::Module* d = fdMap->GetModule(i);
+
+    // Loop over all channels that have a hit.
+    //    cout << "Crate/Slot: " << d->crate << "/" << d->slot << endl;
+    for ( Int_t j=0; j < evdata.GetNumChan( d->crate, d->slot); j++) {
+      
+      Int_t chan = evdata.GetNextChan( d->crate, d->slot, j );
+      if( chan < d->lo || chan > d->hi ) continue;     // Not one of my channels
+      
+      // Need to convert crate, slot, chan into plane, counter, signal
+      // Search hitlist for this plane,counter,signal
+      Int_t plane = d->plane;
+      Int_t signal = d->signal;
+      Int_t counter = d->reverse ? d->first + d->hi - chan : d->first + chan - d->lo;
+      //cout << d->crate << " " << d->slot << " " << chan << " " << plane << " "
+      // << counter << " " << signal << endl;
+      // Search hit list for plane and counter
+      // We could do sorting 
+      Int_t thishit = 0;
+      while(thishit < fNRawHits) {
+	rawhit = (THcRawHit*) (*fRawHitList)[thishit];
+	if (plane == rawhit->fPlane
+	    && counter == rawhit->fCounter) {
+	  // cout << "Found as " << thishit << "/" << fNRawHits << endl;
+	  break;
+	}
+	thishit++;
+      }
+
+      if(thishit == fNRawHits) {
+	rawhit = (THcRawHit*) (*fRawHitList)[thishit];
+	fNRawHits++;
+	rawhit->fPlane = plane;
+	rawhit->fCounter = counter;
+      }
+	
+      // Get the data from this channel
+      // Allow for multiple hits
+      Int_t nMHits = evdata.GetNumHits(d->crate, d->slot, chan);
+      for (Int_t mhit = 0; mhit < nMHits; mhit++) {
+	Int_t data = evdata.GetData( d->crate, d->slot, chan, mhit);
+	// cout << "Signal " << signal << "=" << data << endl;
+	rawhit->SetData(signal,data);
+      }
+    }
+  }
+  fRawHitList->Sort(fNRawHits);
+
+  return fNRawHits;		// Does anything care what is returned
+}
+
+ClassImp(THcHitList)
diff --git a/src/THcHitList.h b/src/THcHitList.h
new file mode 100644
index 0000000..be90264
--- /dev/null
+++ b/src/THcHitList.h
@@ -0,0 +1,48 @@
+#ifndef ROOT_THcHitList
+#define ROOT_THcHitList
+
+#include "THcRawHit.h"
+#include "THaDetMap.h"
+#include "THaEvData.h"
+#include "TClonesArray.h"
+#include "TObject.h"
+
+
+using namespace std;
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THcHitList
+//
+//////////////////////////////////////////////////////////////////////////
+
+//class THaDetMap;
+
+class THcHitList {
+
+ public:
+
+  virtual ~THcHitList();
+
+  THcHitList();
+
+  virtual Int_t DecodeToHitList( const THaEvData& );
+  void          InitHitList(THaDetMap* detmap,
+			    const char *hitclass, Int_t maxhits);
+
+  // This is a list of pointers to hit objects
+  // Instead should we have a list of the actual objects so that we are
+  // no delting and creating objects all the time.
+  //
+  Int_t         fNRawHits;
+  Int_t         fNMaxRawHits;
+  TClonesArray* fRawHitList; // List of raw hits
+  TClass* fRawHitClass;		  // Class of raw hit object to use
+
+  THaDetMap*    fdMap;
+
+ protected:
+
+  ClassDef(THcHitList,0)
+};
+#endif
diff --git a/src/THcHodoscope.cxx b/src/THcHodoscope.cxx
new file mode 100644
index 0000000..ede9289
--- /dev/null
+++ b/src/THcHodoscope.cxx
@@ -0,0 +1,353 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// THcHodoscope                                                              //
+//                                                                           //
+// Class for a generic hodoscope consisting of multiple                      //
+// planes with multiple paddles with phototubes on both ends.                //
+// This differs from Hall A scintillator class in that it is the whole       //
+// hodoscope array, not just one plane.                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "THcHodoscope.h"
+#include "THaEvData.h"
+#include "THaDetMap.h"
+#include "THcDetectorMap.h"
+#include "THcGlobals.h"
+#include "THcParmList.h"
+#include "VarDef.h"
+#include "VarType.h"
+#include "THaTrack.h"
+#include "TClonesArray.h"
+#include "TMath.h"
+
+#include "THaTrackProj.h"
+
+#include <cstring>
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+
+using namespace std;
+
+//_____________________________________________________________________________
+THcHodoscope::THcHodoscope( const char* name, const char* description,
+				  THaApparatus* apparatus ) :
+  THaNonTrackingDetector(name,description,apparatus)
+{
+  // Constructor
+
+  fTrackProj = new TClonesArray( "THaTrackProj", 5 );
+}
+
+//_____________________________________________________________________________
+THcHodoscope::THcHodoscope( ) :
+  THaNonTrackingDetector()
+{
+  // Constructor
+}
+
+//_____________________________________________________________________________
+THaAnalysisObject::EStatus THcHodoscope::Init( const TDatime& date )
+{
+  static const char* const here = "Init()";
+
+  if( THaNonTrackingDetector::Init( date ) )
+    return fStatus;
+
+  // Replace with what we need for Hall C
+  //  const DataDest tmp[NDEST] = {
+  //    { &fRTNhit, &fRANhit, fRT, fRT_c, fRA, fRA_p, fRA_c, fROff, fRPed, fRGain },
+  //    { &fLTNhit, &fLANhit, fLT, fLT_c, fLA, fLA_p, fLA_c, fLOff, fLPed, fLGain }
+  //  };
+  //  memcpy( fDataDest, tmp, NDEST*sizeof(DataDest) );
+
+  // Should probably put this in ReadDatabase as we will know the
+  // maximum number of hits after setting up the detector map
+
+  THcHitList::InitHitList(fDetMap, "THcHodoscopeHit", 100);
+
+  // Will need to determine which apparatus it belongs to and use the
+  // appropriate detector ID in the FillMap call
+  if( gHcDetectorMap->FillMap(fDetMap, "HSCIN") < 0 ) {
+    Error( Here(here), "Error filling detectormap for %s.", 
+	     "detectorname");
+      return kInitError;
+  }
+
+  return fStatus = kOK;
+}
+
+//_____________________________________________________________________________
+Int_t THcHodoscope::ReadDatabase( const TDatime& date )
+{
+  // Read this detector's parameters from the database file 'fi'.
+  // This function is called by THaDetectorBase::Init() once at the
+  // beginning of the analysis.
+  // 'date' contains the date/time of the run being analyzed.
+
+  //  static const char* const here = "ReadDatabase()";
+
+  // Read data from database 
+  // Pull values from the THcParmList instead of reading a database
+  // file like Hall A does.
+
+  //  DBRequest list[] = {
+  //    { "TDC_offsetsL", fLOff, kDouble, fNelem },
+  //    { "TDC_offsetsR", fROff, kDouble, fNelem },
+  //    { "ADC_pedsL", fLPed, kDouble, fNelem },
+  //    { "ADC_pedsR", fRPed, kDouble, fNelem },
+  //    { "ADC_coefL", fLGain, kDouble, fNelem },
+  //    { "ADC_coefR", fRGain, kDouble, fNelem },
+  //    { "TDC_res",   &fTdc2T },
+  //    { "TransSpd",  &fCn },
+  //    { "AdcMIP",    &fAdcMIP },
+  //    { "NTWalk",    &fNTWalkPar, kInt },
+  //    { "Timewalk",  fTWalkPar, kDouble, 2*fNelem },
+  //    { "ReTimeOff", fTrigOff, kDouble, fNelem },
+  //    { "AvgRes",    &fResolution },
+  //    { "Atten",     &fAttenuation },
+  //    { 0 }
+  //  };
+
+  // We will probably want to add some kind of method to gHcParms to allow
+  // bulk retrieval of parameters of interest.
+
+  // Will need to determine which spectrometer in order to construct
+  // the parameter names (e.g. hscin_1x_nr vs. sscin_1x_nr)
+
+  fNPlanes = 4;			// Hardwire for now
+
+  fNPaddle = new Int_t [4];
+
+  fNPaddle[0] = *(Int_t *)gHcParms->Find("hscin_1x_nr")->GetValuePointer();
+  fNPaddle[1] = *(Int_t *)gHcParms->Find("hscin_1y_nr")->GetValuePointer();
+  fNPaddle[2] = *(Int_t *)gHcParms->Find("hscin_2x_nr")->GetValuePointer();
+  fNPaddle[3] = *(Int_t *)gHcParms->Find("hscin_2y_nr")->GetValuePointer();
+
+  fSpacing = new Double_t [4];
+  fSpacing[0] = gHcParms->Find("hscin_1x_spacing")->GetValue(0);
+  fSpacing[1] = gHcParms->Find("hscin_1y_spacing")->GetValue(0);
+  fSpacing[2] = gHcParms->Find("hscin_2x_spacing")->GetValue(0);
+  fSpacing[3] = gHcParms->Find("hscin_2y_spacing")->GetValue(0);
+
+  fCenter = new Double_t* [4];
+  Double_t* p;
+  Int_t iplane;
+
+  iplane = 0;
+  p = (Double_t *)gHcParms->Find("hscin_1x_center")->GetValuePointer();
+  fCenter[iplane] = new Double_t [fNPaddle[iplane]];
+  // Print out some parameters just to demonstrate that it works
+  cout << iplane;
+  for(Int_t i=0;i<fNPaddle[iplane];i++) {
+    fCenter[iplane][i] = p[i];
+    cout << " " << fCenter[iplane][i];
+  }
+  cout << endl;
+
+  iplane = 1;
+  p = (Double_t *)gHcParms->Find("hscin_1y_center")->GetValuePointer();
+  fCenter[iplane] = new Double_t [fNPaddle[iplane]];
+  cout << iplane;
+  for(Int_t i=0;i<fNPaddle[iplane];i++) {
+    fCenter[iplane][i] = p[i];
+    cout << " " << fCenter[iplane][i];
+  }
+  cout << endl;
+
+  iplane = 2;
+  p = (Double_t *)gHcParms->Find("hscin_2x_center")->GetValuePointer();
+  fCenter[iplane] = new Double_t [fNPaddle[iplane]];
+  cout << iplane;
+  for(Int_t i=0;i<fNPaddle[iplane];i++) {
+    fCenter[iplane][i] = p[i];
+    cout << " " << fCenter[iplane][i];
+  }
+  cout << endl;
+
+  iplane = 3;
+  p = (Double_t *)gHcParms->Find("hscin_2y_center")->GetValuePointer();
+  fCenter[iplane] = new Double_t [fNPaddle[iplane]];
+  cout << iplane;
+  for(Int_t i=0;i<fNPaddle[iplane];i++) {
+    fCenter[iplane][i] = p[i];
+    cout << " " << fCenter[iplane][i];
+  }
+  cout << endl;
+
+  fIsInit = true;
+
+  return kOK;
+}
+
+//_____________________________________________________________________________
+Int_t THcHodoscope::DefineVariables( EMode mode )
+{
+  // Initialize global variables and lookup table for decoder
+
+  if( mode == kDefine && fIsSetup ) return kOK;
+  fIsSetup = ( mode == kDefine );
+
+  // Register variables in global list
+
+  //  RVarDef vars[] = {
+  //    { "nlthit", "Number of Left paddles TDC times",  "fLTNhit" },
+  //    { "nrthit", "Number of Right paddles TDC times", "fRTNhit" },
+  //    { "nlahit", "Number of Left paddles ADCs amps",  "fLANhit" },
+  //    { "nrahit", "Number of Right paddles ADCs amps", "fRANhit" },
+  //    { "lt",     "TDC values left side",              "fLT" },
+  //    { "lt_c",   "Corrected times left side",         "fLT_c" },
+  //    { "rt",     "TDC values right side",             "fRT" },
+  //    { "rt_c",   "Corrected times right side",        "fRT_c" },
+  //    { "la",     "ADC values left side",              "fLA" },
+  //    { "la_p",   "Corrected ADC values left side",    "fLA_p" },
+  //    { "la_c",   "Corrected ADC values left side",    "fLA_c" },
+  //    { "ra",     "ADC values right side",             "fRA" },
+  //    { "ra_p",   "Corrected ADC values right side",   "fRA_p" },
+  //    { "ra_c",   "Corrected ADC values right side",   "fRA_c" },
+  //    { "nthit",  "Number of paddles with l&r TDCs",   "fNhit" },
+  //    { "t_pads", "Paddles with l&r coincidence TDCs", "fHitPad" },
+  //    { "y_t",    "y-position from timing (m)",        "fYt" },
+  //    { "y_adc",  "y-position from amplitudes (m)",    "fYa" },
+  //    { "time",   "Time of hit at plane (s)",          "fTime" },
+  //    { "dtime",  "Est. uncertainty of time (s)",      "fdTime" },
+  //    { "dedx",   "dEdX-like deposited in paddle",     "fAmpl" },
+  //    { "troff",  "Trigger offset for paddles",        "fTrigOff"},
+  //    { "trn",    "Number of tracks for hits",         "GetNTracks()" },
+  //    { "trx",    "x-position of track in det plane",  "fTrackProj.THaTrackProj.fX" },
+  //    { "try",    "y-position of track in det plane",  "fTrackProj.THaTrackProj.fY" },
+  //    { "trpath", "TRCS pathlen of track to det plane","fTrackProj.THaTrackProj.fPathl" },
+  //    { "trdx",   "track deviation in x-position (m)", "fTrackProj.THaTrackProj.fdX" },
+  //    { "trpad",  "paddle-hit associated with track",  "fTrackProj.THaTrackProj.fChannel" },
+  //    { 0 }
+  //  };
+  //  return DefineVarsFromList( vars, mode );
+  return kOK;
+}
+
+//_____________________________________________________________________________
+THcHodoscope::~THcHodoscope()
+{
+  // Destructor. Remove variables from global list.
+
+  if( fIsSetup )
+    RemoveVariables();
+  if( fIsInit )
+    DeleteArrays();
+  if (fTrackProj) {
+    fTrackProj->Clear();
+    delete fTrackProj; fTrackProj = 0;
+  }
+}
+
+//_____________________________________________________________________________
+void THcHodoscope::DeleteArrays()
+{
+  // Delete member arrays. Used by destructor.
+
+  delete [] fNPaddle;  fNPaddle = NULL;
+  delete [] fSpacing;  fSpacing = NULL;
+  delete [] fCenter;   fCenter = NULL; // This 2D. What is correct way to delete?
+
+  //  delete [] fRA_c;    fRA_c    = NULL;
+  //  delete [] fRA_p;    fRA_p    = NULL;
+  //  delete [] fRA;      fRA      = NULL;
+  //  delete [] fLA_c;    fLA_c    = NULL;
+  //  delete [] fLA_p;    fLA_p    = NULL;
+  //  delete [] fLA;      fLA      = NULL;
+  //  delete [] fRT_c;    fRT_c    = NULL;
+  //  delete [] fRT;      fRT      = NULL;
+  //  delete [] fLT_c;    fLT_c    = NULL;
+  //  delete [] fLT;      fLT      = NULL;
+  
+  //  delete [] fRGain;   fRGain   = NULL;
+  //  delete [] fLGain;   fLGain   = NULL;
+  //  delete [] fRPed;    fRPed    = NULL;
+  //  delete [] fLPed;    fLPed    = NULL;
+  //  delete [] fROff;    fROff    = NULL;
+  //  delete [] fLOff;    fLOff    = NULL;
+  //  delete [] fTWalkPar; fTWalkPar = NULL;
+  //  delete [] fTrigOff; fTrigOff = NULL;
+
+  //  delete [] fHitPad;  fHitPad  = NULL;
+  //  delete [] fTime;    fTime    = NULL;
+  //  delete [] fdTime;   fdTime   = NULL;
+  //  delete [] fYt;      fYt      = NULL;
+  //  delete [] fYa;      fYa      = NULL;
+}
+
+//_____________________________________________________________________________
+inline 
+void THcHodoscope::ClearEvent()
+{
+  // Reset per-event data.
+
+  fTrackProj->Clear();
+}
+
+//_____________________________________________________________________________
+Int_t THcHodoscope::Decode( const THaEvData& evdata )
+{
+
+  // Get the Hall C style hitlist (fRawHitList) for this event
+  Int_t nhits = THcHitList::DecodeToHitList(evdata);
+
+  // fRawHitList is TClones array of THcHodoscopeHit objects
+  for(Int_t ihit = 0; ihit < fNRawHits ; ihit++) {
+    THcHodoscopeHit* hit = (THcHodoscopeHit *) fRawHitList->At(ihit);
+    cout << ihit << " : " << hit->fPlane << ":" << hit->fCounter << " : "
+	 << hit->fADC_pos << " " << hit->fADC_neg << " "  <<  hit->fTDC_pos
+	 << " " <<  hit->fTDC_neg << endl;
+  }
+  cout << endl;
+
+  return nhits;
+}
+
+//_____________________________________________________________________________
+Int_t THcHodoscope::ApplyCorrections( void )
+{
+  return(0);
+}
+
+//_____________________________________________________________________________
+Double_t THcHodoscope::TimeWalkCorrection(const Int_t& paddle,
+					     const ESide side)
+{
+  return(0.0);
+}
+
+//_____________________________________________________________________________
+Int_t THcHodoscope::CoarseProcess( TClonesArray& /* tracks */ )
+{
+  // Calculation of coordinates of particle track cross point with scint
+  // plane in the detector coordinate system. For this, parameters of track 
+  // reconstructed in THaVDC::CoarseTrack() are used.
+  //
+  // Apply corrections and reconstruct the complete hits.
+  //
+  //  static const Double_t sqrt2 = TMath::Sqrt(2.);
+  
+  ApplyCorrections();
+
+  return 0;
+}
+
+//_____________________________________________________________________________
+Int_t THcHodoscope::FineProcess( TClonesArray& tracks )
+{
+  // Reconstruct coordinates of particle track cross point with scintillator
+  // plane, and copy the data into the following local data structure:
+  //
+  // Units of measurements are meters.
+
+  // Calculation of coordinates of particle track cross point with scint
+  // plane in the detector coordinate system. For this, parameters of track 
+  // reconstructed in THaVDC::FineTrack() are used.
+
+  return 0;
+}
+
+ClassImp(THcHodoscope)
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/THcHodoscope.h b/src/THcHodoscope.h
new file mode 100644
index 0000000..31760f5
--- /dev/null
+++ b/src/THcHodoscope.h
@@ -0,0 +1,88 @@
+#ifndef ROOT_THcHodoscope
+#define ROOT_THcHodoscope
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// THcHodoscope                                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "TClonesArray.h"
+#include "THaNonTrackingDetector.h"
+#include "THcHitList.h"
+#include "THcHodoscopeHit.h"
+
+class THaScCalib;
+
+class THcHodoscope : public THaNonTrackingDetector, public THcHitList {
+
+public:
+  THcHodoscope( const char* name, const char* description = "",
+		   THaApparatus* a = NULL );
+  virtual ~THcHodoscope();
+
+  virtual Int_t      Decode( const THaEvData& );
+  virtual EStatus    Init( const TDatime& run_time );
+  virtual Int_t      CoarseProcess( TClonesArray& tracks );
+  virtual Int_t      FineProcess( TClonesArray& tracks );
+  
+  virtual Int_t      ApplyCorrections( void );
+
+  //  Int_t GetNHits() const { return fNhit; }
+  
+  Int_t GetNTracks() const { return fTrackProj->GetLast()+1; }
+  const TClonesArray* GetTrackHits() const { return fTrackProj; }
+  
+  friend class THaScCalib;
+
+  THcHodoscope();  // for ROOT I/O
+protected:
+
+  // Calibration
+
+  // Per-event data
+
+
+  // Potential Hall C parameters.  Mostly here for demonstration
+  Int_t fNPlanes;
+  Int_t* fNPaddle;		// Number of paddles per plane
+  Double_t* fSpacing;		// Paddle spacing in cm
+  Double_t** fCenter;           // Center position of each paddle
+
+
+
+  TClonesArray*  fTrackProj;  // projection of track onto scintillator plane
+                              // and estimated match to TOF paddle
+  // Useful derived quantities
+  // double tan_angle, sin_angle, cos_angle;
+  
+  //  static const char NDEST = 2;
+  //  struct DataDest {
+  //    Int_t*    nthit;
+  //    Int_t*    nahit;
+  //    Double_t*  tdc;
+  //    Double_t*  tdc_c;
+  //    Double_t*  adc;
+  //    Double_t*  adc_p;
+  //    Double_t*  adc_c;
+  //    Double_t*  offset;
+  //    Double_t*  ped;
+  //    Double_t*  gain;
+  //  } fDataDest[NDEST];     // Lookup table for decoder
+
+  void           ClearEvent();
+  void           DeleteArrays();
+  virtual Int_t  ReadDatabase( const TDatime& date );
+  virtual Int_t  DefineVariables( EMode mode = kDefine );
+
+  enum ESide { kLeft = 0, kRight = 1 };
+  
+  virtual  Double_t TimeWalkCorrection(const Int_t& paddle,
+					   const ESide side);
+
+  ClassDef(THcHodoscope,0)   // Generic hodoscope class
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/THcHodoscopeHit.cxx b/src/THcHodoscopeHit.cxx
new file mode 100644
index 0000000..1a34c8b
--- /dev/null
+++ b/src/THcHodoscopeHit.cxx
@@ -0,0 +1,80 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// THcHodoscopeHit                                                           //
+//                                                                           //
+// Class representing a single raw hit for a hodoscope paddle                //
+//                                                                           //
+// Contains plane, counter and pos/neg adc and tdc values                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "THcHodoscopeHit.h"
+
+using namespace std;
+
+
+void THcHodoscopeHit::SetData(Int_t signal, Int_t data) {
+  if(signal==0) {
+    fADC_pos = data;
+  } else if (signal==1) {
+    fADC_neg = data;
+  } else if(signal==2) {
+    fTDC_pos = data;
+  } else if (signal==3) {
+    fTDC_neg = data;
+  }
+}
+
+Int_t THcHodoscopeHit::GetData(Int_t signal) {
+  if(signal==0) {
+    return(fADC_pos);
+  } else if (signal==1) {
+    return(fADC_neg);
+  } else if(signal==2) {
+    return(fTDC_pos);
+  } else if (signal==3) {
+    return(fTDC_neg);
+  }
+  return(-1); // Actually should throw exception
+}
+
+Int_t THcHodoscopeHit::Compare(const TObject* obj) const
+{
+  // Compare to sort by plane and counter
+
+  const THcHodoscopeHit* hit = dynamic_cast<const THcHodoscopeHit*>(obj);
+
+  if(!hit) return -1;
+  Int_t p1 = fPlane;
+  Int_t p2 = hit->fPlane;
+  if(p1 < p2) return -1;
+  else if(p1 > p2) return 1;
+  else {
+    Int_t c1 = fCounter;
+    Int_t c2 = hit->fCounter;
+    if(c1 < c2) return -1;
+    else if (c1 == c2) return 0;
+    else return 1;
+  }
+}
+//_____________________________________________________________________________
+THcHodoscopeHit& THcHodoscopeHit::operator=( const THcHodoscopeHit& rhs )
+{
+  // Assignment operator.
+
+  THcRawHit::operator=(rhs);
+  if ( this != &rhs ) {
+    fPlane = rhs.fPlane;
+    fCounter = rhs.fCounter;
+    fADC_pos = rhs.fADC_pos;
+    fADC_neg = rhs.fADC_neg;
+    fTDC_pos = rhs.fTDC_pos;
+    fTDC_neg = rhs.fTDC_neg;
+  }
+  return *this;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+ClassImp(THcHodoscopeHit)
+
diff --git a/src/THcHodoscopeHit.h b/src/THcHodoscopeHit.h
new file mode 100644
index 0000000..f8ce97b
--- /dev/null
+++ b/src/THcHodoscopeHit.h
@@ -0,0 +1,38 @@
+#ifndef ROOT_THcHodoscopeHit
+#define ROOT_THcHodoscopeHit
+
+#include "THcRawHit.h"
+
+class THcHodoscopeHit : public THcRawHit {
+
+ public:
+
+ THcHodoscopeHit(Int_t plane=0, Int_t counter=0) : THcRawHit(plane, counter), 
+    fADC_pos(-1), fADC_neg(-1),
+    fTDC_pos(-1), fTDC_neg(-1) {
+  }
+  THcHodoscopeHit& operator=( const THcHodoscopeHit& );
+  virtual ~THcHodoscopeHit() {}
+
+  virtual void Clear( Option_t* opt="" )
+    { fADC_pos = -1; fADC_neg = -1; fTDC_pos = -1; fTDC_neg = -1; }
+
+  void SetData(Int_t signal, Int_t data);
+  Int_t GetData(Int_t signal);
+
+  virtual Bool_t  IsSortable () const {return kTRUE; }
+  virtual Int_t   Compare(const TObject* obj) const;
+
+  Int_t fADC_pos;
+  Int_t fADC_neg;
+  Int_t fTDC_pos;
+  Int_t fTDC_neg;
+
+ protected:
+
+ private:
+
+  ClassDef(THcHodoscopeHit, 0);	// Hodoscope hit class
+};  
+
+#endif
diff --git a/src/THcInterface.cxx b/src/THcInterface.cxx
index 023c2ab..887c578 100644
--- a/src/THcInterface.cxx
+++ b/src/THcInterface.cxx
@@ -20,6 +20,7 @@
 #include "TInterpreter.h"
 #include "THaVarList.h"
 #include "THcParmList.h"
+#include "THcDetectorMap.h"
 #include "THaCutList.h"
 #include "THaCodaDecoder.h"
 #include "THaGlobals.h"
@@ -48,6 +49,7 @@ THaDB*       gHaDB       = NULL;  // Database system to use
 THaTextvars* gHaTextvars = NULL;  // Text variable definitions
 
 THcParmList* gHcParms     = NULL;  // List of symbolic analyzer variables
+THcDetectorMap* gHcDetectorMap = NULL; // Global (Hall C style) detector map
 
 THcInterface* THcInterface::fgAint = NULL;  // Pointer to this interface
 
@@ -161,6 +163,7 @@ THcInterface::~THcInterface()
     delete gHaCuts;         gHaCuts=0;
 
     delete gHcParms;        gHcParms=0;
+    delete gHcDetectorMap;   gHcDetectorMap=0;
 
     fgAint = NULL;
   }
diff --git a/src/THcRawHit.cxx b/src/THcRawHit.cxx
new file mode 100644
index 0000000..daa5138
--- /dev/null
+++ b/src/THcRawHit.cxx
@@ -0,0 +1,18 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// THcRawHit                                                                 //
+//                                                                           //
+// Abstract class for a single raw hit                                       //
+//                                                                           //
+// Contains plane, counter and at least one data value                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "THcRawHit.h"
+
+//THcRawHit::~THcRawHit()
+//{}
+
+ClassImp(THcRawHit)
+
+//_____________________________________________________________________________
diff --git a/src/THcRawHit.h b/src/THcRawHit.h
new file mode 100644
index 0000000..921939e
--- /dev/null
+++ b/src/THcRawHit.h
@@ -0,0 +1,43 @@
+#ifndef ROOT_THcRawHit
+#define ROOT_THcRawHit
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// THcRawHit                                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+#include "TObject.h"
+
+class THcRawHit : public TObject {
+
+public:
+ THcRawHit(Int_t plane=0, Int_t counter=0) :
+  fPlane(plane), fCounter(counter) {};
+ THcRawHit( const THcRawHit& rhs ) : TObject(rhs) {}
+  THcRawHit& operator=( const THcRawHit& rhs )
+    { TObject::operator=(rhs); return *this; };
+
+  virtual ~THcRawHit() {}
+
+  // This line causes problem
+  //  virtual void Clear( Option_t* opt="" )=0;
+
+  //  virtual Bool_t  operator==( const THcRawHit& ) = 0;
+  //  virtual Bool_t  operator!=( const THcRawHit& ) = 0;
+
+  virtual void SetData(Int_t signal, Int_t data) {};
+  virtual Int_t GetData(Int_t signal) {return 0;};
+
+  // Derived objects must be sortable and supply Compare method
+  virtual Bool_t  IsSortable () const {return kFALSE; }
+  virtual Int_t   Compare(const TObject* obj) const {return 0;}
+
+  Int_t fPlane;
+  Int_t fCounter;
+
+ private:
+
+  ClassDef(THcRawHit,0)      // Track ID abstract base class
+};
+
+#endif
-- 
GitLab