Skip to content
Snippets Groups Projects
THcShower.cxx 32 KiB
Newer Older
  • Learn to ignore specific revisions
  • /** \class THcShower
        \ingroup Detectors
    
    Shower counter class, describing a generic segmented shower detector.     //
    
    */
    
    #include "THcHallCSpectrometer.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 "THaTrackProj.h"
    
    #include "TMath.h"
    
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    
    
    using namespace std;
    
    //_____________________________________________________________________________
    THcShower::THcShower( const char* name, const char* description,
    				  THaApparatus* apparatus ) :
      THaNonTrackingDetector(name,description,apparatus)
    {
      // Constructor
    
      fNLayers = 0;			// No layers until we make them
    
      fNTotLayers = 0;
      fHasArray = 0;
    
    
      fClusterList = new THcShowerClusterList;
    
    }
    
    //_____________________________________________________________________________
    THcShower::THcShower( ) :
      THaNonTrackingDetector()
    {
      // Constructor
    }
    
    
    //_____________________________________________________________________________
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
    void THcShower::Setup(const char* name, const char* description)
    {
    
      char prefix[2];
    
      prefix[0] = tolower(GetApparatus()->GetName()[0]);
      prefix[1] = '\0';
    
    
      string layernamelist;
    
      fHasArray = 0;		// Flag for presence of fly's eye array
    
      DBRequest list[]={
        {"cal_num_layers", &fNLayers, kInt},
        {"cal_layer_names", &layernamelist, kString},
    
        {"cal_array",&fHasArray, kInt,0, 1}, 
    
        {0}
      };
    
      gHcParms->LoadParmValues((DBRequest*)&list,prefix);
    
      fNTotLayers = (fNLayers+(fHasArray!=0?1:0));
    
      vector<string> layer_names = vsplit(layernamelist);
    
      if(layer_names.size() != fNTotLayers) {
        cout << "THcShower::Setup ERROR: Number of layers " << fNTotLayers 
    
    	 << " doesn't agree with number of layer names "
    	 << layer_names.size() << endl;
    
        // Should quit.  Is there an official way to quit?
      }
    
      fLayerNames = new char* [fNTotLayers];
      for(UInt_t i=0;i<fNTotLayers;i++) {
    
        fLayerNames[i] = new char[layer_names[i].length()+1];
    
        strcpy(fLayerNames[i], layer_names[i].c_str());
      }
      
      char *desc = new char[strlen(description)+100];
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
      fPlanes = new THcShowerPlane* [fNLayers];
    
      for(UInt_t i=0;i < fNLayers;i++) {
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
        strcpy(desc, description);
        strcat(desc, " Plane ");
        strcat(desc, fLayerNames[i]);
    
        fPlanes[i] = new THcShowerPlane(fLayerNames[i], desc, i+1, this); 
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
      }
    
      if(fHasArray) {
        strcpy(desc, description);
        strcat(desc, " Array ");
        strcat(desc, fLayerNames[fNTotLayers-1]);
    
    
        fArray = new THcShowerArray(fLayerNames[fNTotLayers-1], desc, fNTotLayers,
    				this);
    
      cout << "---------------------------------------------------------------\n";
    
      cout << "From THcShower::Setup: created Shower planes for "
           << GetApparatus()->GetName() << ": ";
    
    
      for(UInt_t i=0;i < fNTotLayers;i++) {
    
        cout << fLayerNames[i];
    
        i < fNTotLayers-1 ? cout << ", " : cout << ".\n";
    
    
      if(fHasArray)
        cout << fLayerNames[fNTotLayers-1] << " has fly\'s eye configuration\n";
    
    
      cout << "---------------------------------------------------------------\n";
    
    
    //_____________________________________________________________________________
    THaAnalysisObject::EStatus THcShower::Init( const TDatime& date )
    {
    
      Setup(GetName(), GetTitle());
    
    
      // Should probably put this in ReadDatabase as we will know the
      // maximum number of hits after setting up the detector map
    
    
      InitHitList(fDetMap, "THcRawShowerHit", 100);
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
      EStatus status;
      if( (status = THaNonTrackingDetector::Init( date )) )
        return fStatus=status;
    
    
      for(UInt_t ip=0;ip<fNLayers;ip++) {
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
        if((status = fPlanes[ip]->Init( date ))) {
          return fStatus=status;
        }
      }
    
      if(fHasArray) {
        if((status = fArray->Init( date ))) {
          return fStatus = status;
        }
      }
    
    
      char EngineDID[] = " CAL";
      EngineDID[0] = toupper(GetApparatus()->GetName()[0]);
    
      if( gHcDetectorMap->FillMap(fDetMap, EngineDID) < 0 ) {
    
        static const char* const here = "Init()";
    
        Error( Here(here), "Error filling detectormap for %s.", 
    
      if(fHasArray) {
        cout << "THcShower::Init: adjustment of fiducial volume limits to the fly's eye part." << endl;
        cout << "  Old limits:" << endl;
        cout << "    Xmin = " << fvXmin << "  Xmax = " << fvXmax << endl;
        cout << "    Ymin = " << fvYmin << "  Ymax = " << fvYmax << endl;
        fvXmin = TMath::Max(fvXmin, fArray->fvXmin());
        fvXmax = TMath::Min(fvXmax, fArray->fvXmax());
        fvYmin = TMath::Max(fvYmin, fArray->fvYmin());
        fvYmax = TMath::Min(fvYmax, fArray->fvYmax());
        cout << "  New limits:" << endl;
        cout << "    Xmin = " << fvXmin << "  Xmax = " << fvXmax << endl;
        cout << "    Ymin = " << fvYmin << "  Ymax = " << fvYmax << endl;
      }
    
      cout << "---------------------------------------------------------------\n";
    
      cout << "From THcShower::Init: initialized " << GetApparatus()->GetName()
           <<  GetName() << endl;
    
      cout << "---------------------------------------------------------------\n";
    
    
      return fStatus = kOK;
    }
    
    //_____________________________________________________________________________
    Int_t THcShower::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.
    
      // 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)
    
    
      prefix[0]=tolower(GetApparatus()->GetName()[0]);
      prefix[1]='\0';
    
      fNegCols = fNLayers;		// If not defined assume tube on each end
                                    // for every layer
    
          {"cal_num_neg_columns", &fNegCols, kInt, 0, 1},
    
          {"cal_slop", &fSlop, kDouble},
    
          {"cal_fv_test", &fvTest, kInt,0,1},
    
          {"cal_fv_delta", &fvDelta, kDouble},
    
          {"dbg_raw_cal", &fdbg_raw_cal, kInt, 0, 1},
          {"dbg_decoded_cal", &fdbg_decoded_cal, kInt, 0, 1},
          {"dbg_sparsified_cal", &fdbg_sparsified_cal, kInt, 0, 1},
          {"dbg_clusters_cal", &fdbg_clusters_cal, kInt, 0, 1},
          {"dbg_tracks_cal", &fdbg_tracks_cal, kInt, 0, 1},
          {"dbg_init_cal", &fdbg_init_cal, kInt, 0, 1},
    
        fvTest = 0;			// Default if not defined
    
        fdbg_raw_cal = 0;		// Debugging off by default
        fdbg_decoded_cal = 0;
        fdbg_sparsified_cal = 0;
        fdbg_clusters_cal = 0;
        fdbg_tracks_cal = 0;
        fdbg_init_cal = 0;
    
    
        gHcParms->LoadParmValues((DBRequest*)&list, prefix);
      }
    
    
      // Debug output.
    
        cout << "---------------------------------------------------------------\n";
    
        cout << "Debug output from THcShower::ReadDatabase for "
    	 << GetApparatus()->GetName() << endl;
    
    
        cout << "  Number of neg. columns      = " << fNegCols << endl;
        cout << "  Slop parameter              = " << fSlop << endl;
        cout << "  Fiducial volume test flag   = " << fvTest << endl;
        cout << "  Fiducial volume excl. width = " << fvDelta << endl;
        cout << "  Initialize debug flag       = " << fdbg_init_cal  << endl;
        cout << "  Raw hit debug flag          = " << fdbg_raw_cal  << endl;
        cout << "  Decode debug flag           = " << fdbg_decoded_cal  << endl;
        cout << "  Sparsify debug flag         = " << fdbg_sparsified_cal  << endl;
        cout << "  Cluster debug flag          = " << fdbg_clusters_cal  << endl;
        cout << "  Tracking debug flag         = " << fdbg_tracks_cal  << endl;
    
      {
        DBRequest list[]={
          {"cal_a_cor", &fAcor, kDouble},
          {"cal_b_cor", &fBcor, kDouble},
    
          {"cal_c_cor", fCcor, kDouble, 2},
          {"cal_d_cor", fDcor, kDouble, 2},
    
          {0}
        };
        gHcParms->LoadParmValues((DBRequest*)&list, prefix);
      }
    
    
      // Debug output.
    
        cout << "  Coordinate correction constants:\n";
    
        cout << "    fAcor = " << fAcor << endl;
        cout << "    fBcor = " << fBcor << endl;
    
        cout << "    fCcor = " << fCcor[0] << ", " << fCcor[1] << endl;
        cout << "    fDcor = " << fDcor[0] << ", " << fDcor[1] << endl;
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
      BlockThick = new Double_t [fNLayers];
    
      fNBlocks = new UInt_t [fNLayers];
    
      fLayerZPos = new Double_t [fNLayers];
      fYPos = new Double_t [2*fNLayers];
    
      for(UInt_t i=0;i<fNLayers;i++) {
    
        DBRequest list[]={
          {Form("cal_%s_thick",fLayerNames[i]), &BlockThick[i], kDouble},
          {Form("cal_%s_nr",fLayerNames[i]), &fNBlocks[i], kInt},
    
          {Form("cal_%s_zpos",fLayerNames[i]), &fLayerZPos[i], kDouble},
          {Form("cal_%s_right",fLayerNames[i]), &fYPos[2*i], kDouble},
          {Form("cal_%s_left",fLayerNames[i]), &fYPos[2*i+1], kDouble},
    
          {0}
        };
        gHcParms->LoadParmValues((DBRequest*)&list, prefix);
    
      //Caution! Z positions (fronts) are off in hcal.param! Correct later on.
    
    
      for(UInt_t i=0;i<fNLayers;i++) {
    
        fXPos[i] = new Double_t [fNBlocks[i]];
    
          {Form("cal_%s_top",fLayerNames[i]),fXPos[i], kDouble, fNBlocks[i]},
    
          {0}
        };
        gHcParms->LoadParmValues((DBRequest*)&list, prefix);
    
      // Debug output.
    
        for(UInt_t i=0;i<fNLayers;i++) {
    
          cout << "  Plane " << fLayerNames[i] << ":" << endl;
    
          cout << "    Block thickness: " << BlockThick[i] << endl;
          cout << "    NBlocks        : " << fNBlocks[i] << endl;
    
          cout << "    Z Position     : " << fLayerZPos[i] << endl;
          cout << "    Y Positions    : " << fYPos[2*i] << ", " << fYPos[2*i+1]
    
    	   <<endl;
          cout << "    X Positions    :";
    
          for(UInt_t j=0; j<fNBlocks[i]; j++) {
    
      // Fiducial volume limits, based on Plane 1 positions.
      //
    
    
      fvXmin = fXPos[0][0] + fvDelta;
      fvXmax = fXPos[0][fNBlocks[0]-1] + BlockThick[0] - fvDelta;
      fvYmin = fYPos[0] + fvDelta;
      fvYmax = fYPos[1] - fvDelta;
    
      // Debug output.
    
        cout << "  Fiducial volume limits:" << endl;
        cout << "    Xmin = " << fvXmin << "  Xmax = " << fvXmax << endl;
        cout << "    Ymin = " << fvYmin << "  Ymax = " << fvYmax << endl;
    
      //Calibration related parameters (from h(s)cal.param).
    
      fNTotBlocks=0;              //total number of blocks in the layers
      for (UInt_t i=0; i<fNLayers; i++) fNTotBlocks += fNBlocks[i];
    
      // Debug output.
    
        cout << "  Total number of blocks in the layers of calorimeter: " << dec
    	 << fNTotBlocks << endl;
    
    
      //Pedestal limits from hcal.param.
    
      fShPosPedLimit = new Int_t [fNTotBlocks];
      fShNegPedLimit = new Int_t [fNTotBlocks];
    
      fPosGain = new Double_t [fNTotBlocks];
      fNegGain = new Double_t [fNTotBlocks];
    
    
      //Read in parameters from hcal.param
    
      Double_t hcal_pos_cal_const[fNTotBlocks];
      //  Double_t hcal_pos_gain_ini[fNTotBlocks];     not used
      //  Double_t hcal_pos_gain_cur[fNTotBlocks];     not used
      //  Int_t    hcal_pos_ped_limit[fNTotBlocks];    not used
      Double_t hcal_pos_gain_cor[fNTotBlocks];
    
      Double_t hcal_neg_cal_const[fNTotBlocks];
      //  Double_t hcal_neg_gain_ini[fNTotBlocks];     not used
      //  Double_t hcal_neg_gain_cur[fNTotBlocks];     not used
      //  Int_t    hcal_neg_ped_limit[fNTotBlocks];    not used
      Double_t hcal_neg_gain_cor[fNTotBlocks];
    
        {"cal_pos_cal_const", hcal_pos_cal_const, kDouble, fNTotBlocks},
        //    {"cal_pos_gain_ini",  hcal_pos_gain_ini,  kDouble, fNTotBlocks},
        //    {"cal_pos_gain_cur",  hcal_pos_gain_cur,  kDouble, fNTotBlocks},
        {"cal_pos_ped_limit", fShPosPedLimit, kInt,    fNTotBlocks},
        {"cal_pos_gain_cor",  hcal_pos_gain_cor,  kDouble, fNTotBlocks},
        {"cal_neg_cal_const", hcal_neg_cal_const, kDouble, fNTotBlocks},
        //    {"cal_neg_gain_ini",  hcal_neg_gain_ini,  kDouble, fNTotBlocks},
        //    {"cal_neg_gain_cur",  hcal_neg_gain_cur,  kDouble, fNTotBlocks},
        {"cal_neg_ped_limit", fShNegPedLimit, kInt,    fNTotBlocks},
        {"cal_neg_gain_cor",  hcal_neg_gain_cor,  kDouble, fNTotBlocks},
    
        {"cal_min_peds", &fShMinPeds, kInt},
    
        {0}
      };
      gHcParms->LoadParmValues((DBRequest*)&list, prefix);
    
    
      // Debug output.
    
        cout << "  hcal_pos_cal_const:" << endl;
    
        for (UInt_t j=0; j<fNLayers; j++) {
    
          for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
    	cout << hcal_pos_cal_const[j*fNBlocks[j]+i] << " ";
          };
          cout <<  endl;
    
        cout << "  fShPosPedLimit:" << endl;
    
        for (UInt_t j=0; j<fNLayers; j++) {
    
          for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
    	cout << fShPosPedLimit[j*fNBlocks[j]+i] << " ";
          };
          cout <<  endl;
    
        cout << "  hcal_pos_gain_cor:" << endl;
    
        for (UInt_t j=0; j<fNLayers; j++) {
    
          for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
    	cout << hcal_pos_gain_cor[j*fNBlocks[j]+i] << " ";
          };
          cout <<  endl;
    
        cout << "  hcal_neg_cal_const:" << endl;
    
        for (UInt_t j=0; j<fNLayers; j++) {
    
          for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
    	cout << hcal_neg_cal_const[j*fNBlocks[j]+i] << " ";
          };
          cout <<  endl;
    
        cout << "  fShNegPedLimit:" << endl;
    
        for (UInt_t j=0; j<fNLayers; j++) {
    
          for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
    	cout << fShNegPedLimit[j*fNBlocks[j]+i] << " ";
          };
          cout <<  endl;
    
        cout << "  hcal_neg_gain_cor:" << endl;
    
        for (UInt_t j=0; j<fNLayers; j++) {
    
          for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
    	cout << hcal_neg_gain_cor[j*fNBlocks[j]+i] << " ";
          };
          cout <<  endl;
    
      // Calibration constants (GeV / ADC channel).
    
      for (UInt_t i=0; i<fNTotBlocks; i++) {
    
        fPosGain[i] = hcal_pos_cal_const[i] *  hcal_pos_gain_cor[i];
        fNegGain[i] = hcal_neg_cal_const[i] *  hcal_neg_gain_cor[i];
    
      // Debug output.
    
        cout << "  fPosGain:" << endl;
    
        for (UInt_t j=0; j<fNLayers; j++) {
    
          for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
    	cout << fPosGain[j*fNBlocks[j]+i] << " ";
          };
          cout <<  endl;
    
        cout << "  fNegGain:" << endl;
    
        for (UInt_t j=0; j<fNLayers; j++) {
    
          for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
    	cout << fNegGain[j*fNBlocks[j]+i] << " ";
          };
          cout <<  endl;
    
      // Origin of the calorimeter, at the centre of the face of the detector,
      // or at the centre of the front of the 1-st layer.
    
      Double_t xOrig = (fXPos[0][0] + fXPos[0][fNBlocks[0]-1])/2 + BlockThick[0]/2;
      Double_t yOrig = (fYPos[0] + fYPos[1])/2;
      Double_t zOrig = fLayerZPos[0];
    
    
      fOrigin.SetXYZ(xOrig, yOrig, zOrig);
    
    
      // Debug output.
    
        cout << "  Origin of the Calorimeter:" << endl;
        cout << "    Xorig = " << GetOrigin().X() << endl;
        cout << "    Yorig = " << GetOrigin().Y() << endl;
        cout << "    Zorig = " << GetOrigin().Z() << endl;
        cout << "---------------------------------------------------------------\n";
    
    
      // Detector axes. Assume no rotation.
      //
      DefineAxes(0.);
    
    
      fIsInit = true;
    
      return kOK;
    }
    
    
    //_____________________________________________________________________________
    Int_t THcShower::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[] = {
    
        { "nhits", "Number of hits",                                 "fNhits" },
        { "nclust", "Number of clusters",                            "fNclust" },
    
        { "etot", "Total energy",                                    "fEtot" },
    
        { "etotnorm", "Total energy divided by Central Momentum",    "fEtotNorm" },
        { "etrack", "Track energy",                                  "fEtrack" },
    
        { "ntracks", "Number of shower tracks",                      "fNtracks" },
    
      return DefineVarsFromList( vars, mode );
    
    }
    
    //_____________________________________________________________________________
    THcShower::~THcShower()
    {
      // Destructor. Remove variables from global list.
    
      if( fIsSetup )
        RemoveVariables();
      if( fIsInit )
        DeleteArrays();
      if (fTrackProj) {
        fTrackProj->Clear();
        delete fTrackProj; fTrackProj = 0;
      }
    }
    
    //_____________________________________________________________________________
    void THcShower::DeleteArrays()
    {
      // Delete member arrays. Used by destructor.
    
      delete [] BlockThick;  BlockThick = NULL;
      delete [] fNBlocks;  fNBlocks = NULL;
    
      delete [] fLayerZPos;  fLayerZPos = NULL;
      delete [] fXPos;  fXPos = NULL;
      delete [] fZPos;  fZPos = NULL;
    
    }
    
    //_____________________________________________________________________________
    inline 
    
    void THcShower::Clear(Option_t* opt)
    
      for(UInt_t ip=0;ip<fNLayers;ip++) {
    
      if(fHasArray) {
        fArray->Clear(opt);
      }
    
    
      fNhits = 0;
      fNclust = 0;
    
      fEtot = 0.;
      fEtotNorm = 0.;
    
      // Purge cluster list
    
      for (THcShowerClusterListIt i=fClusterList->begin(); i!=fClusterList->end();
           ++i) {
        delete *i;
        *i = 0;
      }
      fClusterList->clear();
    
    }
    
    //_____________________________________________________________________________
    Int_t THcShower::Decode( const THaEvData& evdata )
    {
    
      // Get the Hall C style hitlist (fRawHitList) for this event
    
    Zafar's avatar
    Zafar committed
      fEvent = evdata.GetEvNum();
    
    
      if(gHaCuts->Result("Pedestal_event")) {
    
        for(UInt_t ip=0;ip<fNLayers;ip++) {
    
          nexthit = fPlanes[ip]->AccumulatePedestals(fRawHitList, nexthit);
        }
    
        if(fHasArray) {
          nexthit = fArray->AccumulatePedestals(fRawHitList, nexthit);
        }
    
        fAnalyzePedestals = 1;	// Analyze pedestals first normal events
        return(0);
      }
    
    
      if(fAnalyzePedestals) {
    
        for(UInt_t ip=0;ip<fNLayers;ip++) {
    
          fPlanes[ip]->CalculatePedestals();
        }
    
        if(fHasArray) {
          fArray->CalculatePedestals();
        }
    
        fAnalyzePedestals = 0;	// Don't analyze pedestals next event
      }
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
      Int_t nexthit = 0;
    
      for(UInt_t ip=0;ip<fNLayers;ip++) {
    
    Simon Zhamkochyan's avatar
    Simon Zhamkochyan committed
        nexthit = fPlanes[ip]->ProcessHits(fRawHitList, nexthit);
    
        fEtot += fPlanes[ip]->GetEplane();
    
      if(fHasArray) {
        nexthit = fArray->ProcessHits(fRawHitList, nexthit);
    
        fEtot += fArray->GetEarray();
    
      THcHallCSpectrometer *app = static_cast<THcHallCSpectrometer*>(GetApparatus());
      fEtotNorm=fEtot/(app->GetPcentral());
     
    
      return nhits;
    }
    
    //_____________________________________________________________________________
    
    Int_t THcShower::CoarseProcess( TClonesArray& tracks)
    
    {
      // Calculation of coordinates of particle track cross point with shower
      // plane in the detector coordinate system. For this, parameters of track 
      // reconstructed in THaVDC::CoarseTrack() are used.
      //
      // Apply corrections and reconstruct the complete hits.
      
    
      // Clustering of hits.
      //
    
      // Fill set of unclustered hits.
    
      THcShowerHitSet HitSet;
    
      for(UInt_t j=0; j < fNLayers; j++) {
    
        for (UInt_t i=0; i<fNBlocks[j]; i++) {
    
          //May be should be done this way.
          //
    
          //      Double_t Edep = fPlanes[j]->GetEmean(i);
    
          //      if (Edep > 0.) {                                 //hit
    
          //	Double_t x = fYPos[j][i] + BlockThick[j]/2.;    //top + thick/2
          //	Double_t z = fLayerZPos[j] + BlockThick[j]/2.;//front + thick/2
    
          //      	THcShowerHit* hit = new THcShowerHit(i,j,x,z,Edep);
    
    
          //ENGINE way.
          //
          if (fPlanes[j]->GetApos(i) - fPlanes[j]->GetPosPed(i) >
    	  fPlanes[j]->GetPosThr(i) - fPlanes[j]->GetPosPed(i) ||
    	  fPlanes[j]->GetAneg(i) - fPlanes[j]->GetNegPed(i) >
    	  fPlanes[j]->GetNegThr(i) - fPlanes[j]->GetNegPed(i)) {    //hit
    
    	Double_t Edep = fPlanes[j]->GetEmean(i);
    
    	Double_t Epos = fPlanes[j]->GetEpos(i);
    	Double_t Eneg = fPlanes[j]->GetEneg(i);
    
    	Double_t x = fXPos[j][i] + BlockThick[j]/2.;        //top + thick/2
    	Double_t z = fLayerZPos[j] + BlockThick[j]/2.;      //front + thick/2
    
    	THcShowerHit* hit = new THcShowerHit(i,j,x,z,Edep,Epos,Eneg);
    
    	HitSet.insert(hit);   //<set> version
    
      fNhits = HitSet.size();
    
      //Debug output, print out hits before clustering.
    
    
      if (fdbg_clusters_cal) {
    
        cout << "---------------------------------------------------------------\n";
    
        cout << "Debug output from THcShower::CoarseProcess for "
    	 << GetApparatus()->GetName() << endl;
    
    
        cout << "  List of unclustered hits. Total hits:     " << fNhits << endl;
    
        THcShowerHitIt it = HitSet.begin();    //<set> version
    
        for (Int_t i=0; i!=fNhits; i++) {
    
          cout << "  hit " << i << ": ";
    
      // Fill list of clusters.
    
      ClusterHits(HitSet, fClusterList);
    
      fNclust = (*fClusterList).size();   //number of clusters
    
      //Debug output, print out the cluster list.
    
      if (fdbg_clusters_cal) {
    
    
        cout << "  Clustered hits. Number of clusters: " << fNclust << endl;
    
        UInt_t i = 0;
        for (THcShowerClusterListIt ppcl = (*fClusterList).begin();
    	 ppcl != (*fClusterList).end(); ppcl++) {
    
          cout << "  Cluster #" << i++
    	   <<":  E=" << clE(*ppcl) 
    	   << "  Epr=" << clEpr(*ppcl)
    	   << "  X=" << clX(*ppcl)
    	   << "  Z=" << clZ(*ppcl)
    	   << "  size=" << (**ppcl).size()
    
          Int_t j=0;
          for (THcShowerClusterIt pph=(**ppcl).begin(); pph!=(**ppcl).end();
    	   pph++) {
    	cout << "  hit " << j++ << ": ";
    	(**pph).show();
    
        cout << "---------------------------------------------------------------\n";
    
      // Do same for Array.
    
    
      if(fHasArray) fArray->CoarseProcess(tracks);
    
    
    //-----------------------------------------------------------------------------
    
    
    void THcShower::ClusterHits(THcShowerHitSet& HitSet,
    			    THcShowerClusterList* ClusterList) {
    
    
      // Collect hits from the HitSet into the clusters. The resultant clusters
    
      // of hits are saved in the ClusterList.
    
    
      while (HitSet.size() != 0) {
    
        THcShowerCluster* cluster = new THcShowerCluster;
    
        THcShowerHitIt it = HitSet.end();
        (*cluster).insert(*(--it));   //Move the last hit from the hit list
        HitSet.erase(it);             //into the 1st cluster
    
        bool clustered = true;
    
        while (clustered) {                   //Proceed while a hit is clustered
    
          clustered = false;
    
          for (THcShowerHitIt i=HitSet.begin(); i!=HitSet.end(); ++i) {
    
    	for (THcShowerClusterIt k=(*cluster).begin(); k!=(*cluster).end();
    	     k++) {
    
    	  if ((**i).isNeighbour(*k)) {
    
    	    (*cluster).insert(*i);      //If the hit #i is neighbouring a hit
    	    HitSet.erase(i);            //in the cluster, then move it
    	                                //into the cluster.
    	    clustered = true;
    	  }
    
    	  if (clustered) break;
    	}                               //k
    
    	if (clustered) break;
          }                                 //i
    
        }                                   //while clustered
    
    
        ClusterList->push_back(cluster);   //Put the cluster in the cluster list
    
    
      }                                     //While hit_list not exhausted
    
    };
    
    //-----------------------------------------------------------------------------
    
    
    // Various helper functions to accumulate hit related quantities.
    
    
    Double_t addE(Double_t x, THcShowerHit* h) {
      return x + h->hitE();
    }
    
    Double_t addX(Double_t x, THcShowerHit* h) {
      return x + h->hitE() * h->hitX();
    }
    
    Double_t addZ(Double_t x, THcShowerHit* h) {
      return x + h->hitE() * h->hitZ();
    }
    
    Double_t addEpr(Double_t x, THcShowerHit* h) {
      return h->hitColumn() == 0 ? x + h->hitE() : x;
    }
    
    Double_t addEpos(Double_t x, THcShowerHit* h) {
      return x + h->hitEpos();
    }
    
    Double_t addEneg(Double_t x, THcShowerHit* h) {
      return x + h->hitEneg();
    }
    
    // X coordinate of center of gravity of cluster, calculated as hit energy
    
    // weighted average. Put X out of the calorimeter (-100 cm), if there is no
    
    // energy deposition in the cluster.
    //
    Double_t clX(THcShowerCluster* cluster) {
      Double_t Etot = accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
      return (Etot != 0. ?
    
    	  accumulate((*cluster).begin(),(*cluster).end(),0.,addX)/Etot : -100.);
    
    }
    
    // Z coordinate of center of gravity of cluster, calculated as a hit energy
    // weighted average. Put Z out of the calorimeter (0 cm), if there is no energy
    // deposition in the cluster.
    //
    Double_t clZ(THcShowerCluster* cluster) {
      Double_t Etot = accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
      return (Etot != 0. ?
    	  accumulate((*cluster).begin(),(*cluster).end(),0.,addZ)/Etot : 0.);
    }
    
    //Energy depostion in a cluster
    //
    Double_t clE(THcShowerCluster* cluster) {
        return accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
    }
    
    //Energy deposition in the Preshower (1st plane) for a cluster
    //
    Double_t clEpr(THcShowerCluster* cluster) {
        return accumulate((*cluster).begin(),(*cluster).end(),0.,addEpr);
    }
    
    //Cluster energy deposition in plane iplane=0,..,3:
    // side=0 -- from positive PMTs only;
    // side=1 -- from negative PMTs only;
    // side=2 -- from postive and negative PMTs.
    //
    
    Double_t clEplane(THcShowerCluster* cluster, Int_t iplane, Int_t side) {
    
      if (side!=0&&side!=1&&side!=2) {
        cout << "*** Wrong Side in clEplane:" << side << " ***" << endl;
        return -1;
      }
    
      THcShowerHitSet pcluster;
      for (THcShowerHitIt it=(*cluster).begin(); it!=(*cluster).end(); ++it) {
        if ((*it)->hitColumn() == iplane) pcluster.insert(*it);
      }
    
      Double_t Eplane;
      switch (side) {
      case 0 :
        Eplane = accumulate(pcluster.begin(),pcluster.end(),0.,addEpos);
        break;
      case 1 :
        Eplane = accumulate(pcluster.begin(),pcluster.end(),0.,addEneg);
        break;
      case 2 :
        Eplane = accumulate(pcluster.begin(),pcluster.end(),0.,addE);
        break;
      default :
        Eplane = 0. ;
      }
    
      return Eplane;
    }
    
    //-----------------------------------------------------------------------------
    
    
    Int_t THcShower::MatchCluster(THaTrack* Track,
    
      // Match a cluster to a given track. Return the cluster number,
      // and track coordinates at the front of calorimeter.
    
      // Track interception with face of the calorimeter. The coordinates are
      // in the calorimeter's local system.
    
      fOrigin = fPlanes[0]->GetOrigin();
    
      CalcTrackIntercept(Track, pathl, XTrFront, YTrFront);
    
    
      // Transform coordiantes to the spectrometer's coordinate system.
    
      XTrFront += GetOrigin().X();
      YTrFront += GetOrigin().Y();
    
      Bool_t inFidVol = true;            // In Fiducial Volume flag
    
      // Re-evaluate Fid. Volume Flag if fid. volume test is requested
    
        // Track coordinates at the back of the detector.
    
        // Origin at the front of the last layer.
    
        fOrigin = fPlanes[fNLayers-1]->GetOrigin();
    
        Double_t XTrBack = kBig;
        Double_t YTrBack = kBig;
    
        CalcTrackIntercept(Track, pathl, XTrBack, YTrBack);
    
        XTrBack += GetOrigin().X();   // from local coord. system
        YTrBack += GetOrigin().Y();   // to the spectrometer system
    
        inFidVol = (XTrFront <= fvXmax) && (XTrFront >= fvXmin) &&
                   (YTrFront <= fvYmax) && (YTrFront >= fvYmin) &&
                   (XTrBack <= fvXmax) && (XTrBack >= fvXmin) &&
                   (YTrBack <= fvYmax) && (YTrBack >= fvYmin);
    
      Int_t mclust = -1;    // The match cluster #, initialize with a bogus value.
      Double_t deltaX = kBig;   // Track to cluster distance
    
      if (inFidVol) {
    
        // Since hits and clusters are in reverse order (with respect to Engine),
        // search backwards to be consistent with Engine.
        //
        for (Int_t i=fNclust-1; i>-1; i--) {
    
          THcShowerCluster* cluster = *(fClusterList->begin()+i);
    
          Double_t dx = TMath::Abs( clX(cluster) - XTrFront );
    
    
          if (dx <= (0.5*BlockThick[0] + fSlop)) {
    
    	fNtracks++;  // number of shower tracks (Consistent with engine)
    
      //Debug output.
    
      if (fdbg_tracks_cal) {
        cout << "---------------------------------------------------------------\n";
    
        cout << "Debug output from THcShower::MatchCluster for "
    	 << GetApparatus()->GetName() << endl;
    
    
        cout << "  Track at DC:"
    	 << "  X = " << Track->GetX()
    	 << "  Y = " << Track->GetY()
    	 << "  Theta = " << Track->GetTheta()
    	 << "  Phi = " << Track->GetPhi()
    	 << endl;
        cout << "  Track at the front of Calorimeter:"
    	 << "  X = " << XTrFront
    	 << "  Y = " << YTrFront
    	 << "  Pathl = " << pathl
    	 << endl;
        if (fvTest) 
          cout << "  Fiducial volume test: inFidVol = " << inFidVol << endl;
    
        cout << "  Matched cluster #" << mclust << ",  delatX= " << deltaX 
    
        cout << "---------------------------------------------------------------\n";
      }
    
    //_____________________________________________________________________________
    Float_t THcShower::GetShEnergy(THaTrack* Track) {
    
      // Get total energy deposited in the cluster matched to the given
      // spectrometer Track.
    
      // Track coordinates at front of the calorimeter, initialize out of
      // acceptance.
    
      Double_t Xtr = -100.;
      Double_t Ytr = -100.;