Skip to content
Snippets Groups Projects
THcShower.cxx 28.2 KiB
Newer Older
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// THcShower                                                                 //
//                                                                           //
// Shower counter class, describing a generic segmented shower detector.     //
//                                                                           //
//                                                                           //
//                                                                           //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "THcShower.h"
#include "THcShowerCluster.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 "THaTrackProj.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
//  fTrackProj = new TClonesArray( "THaTrackProj", 5 );
  fNLayers = 0;			// No layers until we make them
}

//_____________________________________________________________________________
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;
  DBRequest list[]={
    {"cal_num_layers", &fNLayers, kInt},
    {"cal_layer_names", &layernamelist, kString},
    {0}
  };

  cout << "THcShower::Setup called " << GetName() << endl;

  gHcParms->LoadParmValues((DBRequest*)&list,prefix);
  cout << layernamelist << endl;
  cout << "Shower Counter: " << fNLayers << " layers" << endl;

  vector<string> layer_names = vsplit(layernamelist);
  if(layer_names.size() != (UInt_t) fNLayers) {
    cout << "ERROR: Number of layers " << fNLayers 
	 << " doesn't agree with number of layer names "
	 << layer_names.size() << endl;
    // Should quit.  Is there an official way to quit?
  }
Simon Zhamkochyan's avatar
Simon Zhamkochyan committed

  fLayerNames = new char* [fNLayers];
  for(Int_t i=0;i<fNLayers;i++) {
    fLayerNames[i] = new char[layer_names[i].length()];
    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];
Simon Zhamkochyan's avatar
Simon Zhamkochyan committed
  for(Int_t i=0;i < fNLayers;i++) {
    strcpy(desc, description);
    strcat(desc, " Plane ");
    strcat(desc, fLayerNames[i]);

    fPlanes[i] = new THcShowerPlane(fLayerNames[i], desc, i+1, this); 
    cout << "Created Shower Plane " << fLayerNames[i] << ", " << desc << endl;
  }

  cout << "THcShower::Setup Return " << GetName() << endl;
//_____________________________________________________________________________
THaAnalysisObject::EStatus THcShower::Init( const TDatime& date )
{
  static const char* const here = "Init()";

  cout << "THcShower::Init " << GetName() << endl;
  Setup(GetName(), GetTitle());

  // Should probably put this in ReadDatabase as we will know the
  // maximum number of hits after setting up the detector map

  THcHitList::InitHitList(fDetMap, "THcRawShowerHit", 100);
Simon Zhamkochyan's avatar
Simon Zhamkochyan committed
  EStatus status;
  if( (status = THaNonTrackingDetector::Init( date )) )
    return fStatus=status;

  for(Int_t ip=0;ip<fNLayers;ip++) {
    if((status = fPlanes[ip]->Init( date ))) {
      return fStatus=status;
    }
  }

  char EngineDID[] = " CAL";
  EngineDID[0] = toupper(GetApparatus()->GetName()[0]);

  if( gHcDetectorMap->FillMap(fDetMap, EngineDID) < 0 ) {
    Error( Here(here), "Error filling detectormap for %s.", 
      return kInitError;
  }

  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)

  cout << "THcShower::ReadDatabase called " << GetName() << endl;
  prefix[0]=tolower(GetApparatus()->GetName()[0]);
  prefix[1]='\0';
  {
    DBRequest list[]={
      {"cal_num_neg_columns", &fNegCols, kInt},
      {"cal_slop", &fSlop, kDouble},
      {"cal_fv_test", &fvTest, kInt},
      {"cal_fv_delta", &fvDelta, kDouble},
      {"dbg_decoded_cal", &fdbg_decoded_cal, kInt},
      {"dbg_sparsified_cal", &fdbg_sparsified_cal, kInt},
      {"dbg_clusters_cal", &fdbg_clusters_cal, kInt},
      {"dbg_tracks_cal", &fdbg_tracks_cal, kInt},
      {0}
    };
    gHcParms->LoadParmValues((DBRequest*)&list, prefix);
  }

  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 << "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},
      {"cal_d_cor", &fDcor, kDouble},
      {0}
    };
    gHcParms->LoadParmValues((DBRequest*)&list, prefix);
  }

  cout << "HMS Calorimeter coordinate correction constants:" << endl;
  cout << "    fAcor = " << fAcor << endl;
  cout << "    fBcor = " << fBcor << endl;
  cout << "    fCcor = " << fCcor << endl;
  cout << "    fDcor = " << fDcor << endl;

Simon Zhamkochyan's avatar
Simon Zhamkochyan committed
  BlockThick = new Double_t [fNLayers];
  fNBlocks = new Int_t [fNLayers];
Simon Zhamkochyan's avatar
Simon Zhamkochyan committed
  fNLayerZPos = new Double_t [fNLayers];
  YPos = new Double_t [2*fNLayers];
  for(Int_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]), &fNLayerZPos[i], kDouble},
      {Form("cal_%s_right",fLayerNames[i]), &YPos[2*i], kDouble},
      {Form("cal_%s_left",fLayerNames[i]), &YPos[2*i+1], kDouble},
      {0}
    };
    gHcParms->LoadParmValues((DBRequest*)&list, prefix);
  //Caution! Z positions (fronts) are off in hcal.param! Correct later on.

  XPos = new Double_t* [fNLayers];
  for(Int_t i=0;i<fNLayers;i++) {
    XPos[i] = new Double_t [fNBlocks[i]];
      {Form("cal_%s_top",fLayerNames[i]),XPos[i], kDouble, fNBlocks[i]},
      {0}
    };
    gHcParms->LoadParmValues((DBRequest*)&list, prefix);
  for(Int_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     : " << fNLayerZPos[i] << endl;
    cout << "    Y Positions    : " << YPos[2*i] << ", " << YPos[2*i+1] <<endl;
    cout << "    X Positions    :";
    for(Int_t j=0; j<fNBlocks[i]; j++) {
      cout << " " << XPos[i][j];
  // Fiducial volume limits, based on Plane 1 positions.
  //

  fvXmin = XPos[0][0] + fvDelta;
  fvXmax = XPos[0][fNBlocks[0]-1] + BlockThick[0] - fvDelta;
  fvYmin = YPos[0] + fvDelta;
  fvYmax = YPos[1] - fvDelta;

  cout << "Fiducial volume limits:" << endl;
  cout << "   Xmin = " << fvXmin << "  Xmax = " << fvXmax << endl;
  cout << "   Ymin = " << fvYmin << "  Ymax = " << fvYmax << endl;

  //Calibration related parameters (from hcal.param).

  fNtotBlocks=0;              //total number of blocks
  for (Int_t i=0; i<fNLayers; i++) fNtotBlocks += fNBlocks[i];

  cout << "Total number of blocks in the calorimeter: " << 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];
  //  Double_t hcal_pos_gain_cur[fNtotBlocks];
  //  Int_t    hcal_pos_ped_limit[fNtotBlocks];
  Double_t hcal_pos_gain_cor[fNtotBlocks];

  Double_t hcal_neg_cal_const[fNtotBlocks];
  //  Double_t hcal_neg_gain_ini[fNtotBlocks];
  //  Double_t hcal_neg_gain_cur[fNtotBlocks];
  //  Int_t    hcal_neg_ped_limit[fNtotBlocks];
  Double_t hcal_neg_gain_cor[fNtotBlocks];

  DBRequest list[]={
    {"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);

  //+++

  cout << "hcal_pos_cal_const:" << endl;
  for (Int_t j=0; j<fNLayers; j++) {
    for (Int_t i=0; i<fNBlocks[j]; i++) {
      cout << hcal_pos_cal_const[j*fNBlocks[j]+i] << " ";
    };
    cout <<  endl;
  };

  //  cout << "hcal_pos_gain_ini:" << endl;
  //  for (Int_t j=0; j<fNLayers; j++) {
  //    for (Int_t i=0; i<fNBlocks[j]; i++) {
  //      cout << hcal_pos_gain_ini[j*fNBlocks[j]+i] << " ";
  //    };
  //    cout <<  endl;
  //  };

  //  cout << "hcal_pos_gain_cur:" << endl;
  //  for (Int_t j=0; j<fNLayers; j++) {
  //    for (Int_t i=0; i<fNBlocks[j]; i++) {
  //      cout << hcal_pos_gain_cur[j*fNBlocks[j]+i] << " ";
  //    };
  //    cout <<  endl;
  //  };

  for (Int_t j=0; j<fNLayers; j++) {
    for (Int_t i=0; i<fNBlocks[j]; i++) {
      cout << fShPosPedLimit[j*fNBlocks[j]+i] << " ";
    };
    cout <<  endl;
  };

  cout << "hcal_pos_gain_cor:" << endl;
  for (Int_t j=0; j<fNLayers; j++) {
    for (Int_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 (Int_t j=0; j<fNLayers; j++) {
    for (Int_t i=0; i<fNBlocks[j]; i++) {
      cout << hcal_neg_cal_const[j*fNBlocks[j]+i] << " ";
    };
    cout <<  endl;
  };

  //  cout << "hcal_neg_gain_ini:" << endl;
  //  for (Int_t j=0; j<fNLayers; j++) {
  //    for (Int_t i=0; i<fNBlocks[j]; i++) {
  //      cout << hcal_neg_gain_ini[j*fNBlocks[j]+i] << " ";
  //    };
  //  //    cout <<  endl;
  //  };

  //  cout << "hcal_neg_gain_cur:" << endl;
  //  for (Int_t j=0; j<fNLayers; j++) {
  //    for (Int_t i=0; i<fNBlocks[j]; i++) {
  //      cout << hcal_neg_gain_cur[j*fNBlocks[j]+i] << " ";
  //    };
  //    cout <<  endl;
  //  };

  for (Int_t j=0; j<fNLayers; j++) {
    for (Int_t i=0; i<fNBlocks[j]; i++) {
      cout << fShNegPedLimit[j*fNBlocks[j]+i] << " ";
    };
    cout <<  endl;
  };

  cout << "hcal_neg_gain_cor:" << endl;
  for (Int_t j=0; j<fNLayers; j++) {
    for (Int_t i=0; i<fNBlocks[j]; i++) {
      cout << hcal_neg_gain_cor[j*fNBlocks[j]+i] << " ";
    };
    cout <<  endl;
  };

  //Calibration constants in GeV per ADC channel.

  for (Int_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];
  cout << "fPosGain:" << endl;
  for (Int_t j=0; j<fNLayers; j++) {
    for (Int_t i=0; i<fNBlocks[j]; i++) {
      cout << fPosGain[j*fNBlocks[j]+i] << " ";
  cout << "fNegGain:" << endl;
  for (Int_t j=0; j<fNLayers; j++) {
    for (Int_t i=0; i<fNBlocks[j]; i++) {
      cout << fNegGain[j*fNBlocks[j]+i] << " ";
  // Corrdiante corrected track energies per plane

  fTREpl_cor     = new Double_t [fNLayers];
  fTREpl_pos_cor = new Double_t [fNLayers];
  fTREpl_neg_cor = new Double_t [fNLayers];

  // Origin of the calorimeter, at tha middle of the face of the detector,
  // or at the middle of the front plane of the 1-st layer.
  //
  Double_t xOrig = (XPos[0][0] + XPos[0][fNBlocks[0]-1])/2 + BlockThick[0]/2;
  Double_t yOrig = (YPos[0] + YPos[1])/2;
  Double_t zOrig = fNLayerZPos[0];

  //  cout << "Origin of the Calorimeter to be set:" << endl;
  //  cout << "       Xorig = " << xOrig << endl;
  //  cout << "       Yorig = " << yOrig << endl;
  //  cout << "       Zorig = " << zOrig << endl;
  // << endl;

  fOrigin.SetXYZ(xOrig, yOrig, zOrig);

  cout << "Origin of the Calorimeter:" << endl;
  cout << "       Xorig = " << GetOrigin().X() << endl;
  cout << "       Yorig = " << GetOrigin().Y() << endl;
  cout << "       Zorig = " << GetOrigin().Z() << endl;
  cout << endl;

  // 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 );

Simon Zhamkochyan's avatar
Simon Zhamkochyan committed
  cout << "THcShower::DefineVariables called " << GetName() << endl;

  RVarDef vars[] = {
    { "nhits",  "Number of hits",                     "fNhits" },
 //   { "a",      "Raw ADC amplitudes",                 "fA" },
 //   { "a_p",    "Ped-subtracted ADC amplitudes",      "fA_p" },
 //   { "a_c",    "Calibrated ADC amplitudes",          "fA_c" },
 //   { "asum_p", "Sum of ped-subtracted ADCs",         "fAsum_p" },
 //   { "asum_c", "Sum of calibrated ADCs",             "fAsum_c" },
    { "nclust", "Number of clusters",                 "fNclust" },
    { "emax",   "Energy of largest cluster",    "fE" },
    { "eprmax",   "Preshower Energy of largest cluster",    "fEpr" },
    { "xmax",      "x-position (cm) of largest cluster", "fX" },
 //   { "z",      "z-position (cm) of largest cluster", "fZ" },
    { "mult",   "Multiplicity of largest cluster",    "fMult" },
 //   { "nblk",   "Numbers of blocks in main cluster",  "fNblk" },
 //   { "eblk",   "Energies of blocks in main cluster", "fEblk" },
    { "trx",    "track x-position in det plane (1st track)",      "fTRX" },
    { "try",    "track y-position in det plane (1st track)",      "fTRY" },
    { "tre",    "track energy in the calorimeter (1st track)",    "fTRE" },
    { "trepr",  "track energy in the preshower (1st track)",      "fTREpr" },
    { "trecor",    "Y-corrected track Edep (1st track)", "fTRE_cor" },
    { "treprcor",  "Y-corrected track Epr (1st track)", "fTREpr_cor" },
    { "treplcor", "Y-corrected track Edep for planes", "fTREpl_cor" },
    { 0 }
  };
  return DefineVarsFromList( vars, mode );

  /*
  for (Int_t i=0; i<fNLayers; i++) {
    RVarDef vars[] = {
      { Form("treplcor%d",i+1),
	Form("Y-corrected track Edep for plane %d",i+1),
	Form("fTREpl_cor[%d]",i) },
      { 0 }
    };
    return DefineVarsFromList( vars, mode );
  };
  */

  //{ "treplposcor","Y-corrected track pos. Edep per plane", "fTREpl_pos_cor"},
  //{ "treplnegcor","Y-corrected track neg. Edep per plane", "fTREpl_neg_cor"},

  return kOK;
}

//_____________________________________________________________________________
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 [] fNLayerZPos;  fNLayerZPos = NULL;
  delete [] XPos;  XPos = NULL;
  delete [] ZPos;  ZPos = NULL;
  //delete [] fSpacing;  fSpacing = NULL;
  //delete [] fCenter;   fCenter = NULL; // This 2D. What is correct way to delete?
}

//_____________________________________________________________________________
inline 
void THcShower::Clear(Option_t* opt)
  for(Int_t ip=0;ip<fNLayers;ip++) {
    fPlanes[ip]->Clear(opt);
  }

  fNhits = 0;
  fNclust = 0;
  fMult = 0;
  fE = 0.;
  fEpr = 0.;
  fX = -75.;    //out of acceptance
  fTRX = -75.;  //out of acceptance
  fTRY = -40.;  //out of acceptance
  fTRE = -0.;
  fTREpr = -0.;
  fTRE_cor = -0.;
  fTREpr_cor = -0.;
  for(Int_t ip=0;ip<fNLayers;ip++) {
    fTREpl_cor[ip] = -0.;
    fTREpl_pos_cor[ip] = -0.;
    fTREpl_neg_cor[ip] = -0.;
  }
}

//_____________________________________________________________________________
Int_t THcShower::Decode( const THaEvData& evdata )
{
  // Get the Hall C style hitlist (fRawHitList) for this event
  Int_t nhits = THcHitList::DecodeToHitList(evdata);
  if(gHaCuts->Result("Pedestal_event")) {
    Int_t nexthit = 0;
    for(Int_t ip=0;ip<fNLayers;ip++) {
      nexthit = fPlanes[ip]->AccumulatePedestals(fRawHitList, nexthit);
      if (fdbg_decoded_cal) {
	cout << "THcShower::Decode: nexthit = " << nexthit << endl;
      }
    }
    fAnalyzePedestals = 1;	// Analyze pedestals first normal events
    return(0);
  }

  if(fAnalyzePedestals) {
    for(Int_t ip=0;ip<fNLayers;ip++) {
      fPlanes[ip]->CalculatePedestals();
    }
    fAnalyzePedestals = 0;	// Don't analyze pedestals next event
  }
Simon Zhamkochyan's avatar
Simon Zhamkochyan committed
  Int_t nexthit = 0;
  for(Int_t ip=0;ip<fNLayers;ip++) {
    nexthit = fPlanes[ip]->ProcessHits(fRawHitList, nexthit);
  }
  //   fRawHitList is TClones array of THcRawShowerHit objects

  //  if (fdbg_decoded_cal) {
  //    cout << "THcShower::Decode: Shower raw hit list:" << endl;
  //    for(Int_t ihit = 0; ihit < fNRawHits ; ihit++) {
  //      THcRawShowerHit* hit = (THcRawShowerHit *) fRawHitList->At(ihit);
  //      cout << ihit << " : " << hit->fPlane << ":" << hit->fCounter << " : "
  //	   << hit->fADC_pos << " " << hit->fADC_neg << " "  << endl;
  //    }
  //    cout << endl;
  return nhits;
}

//_____________________________________________________________________________
Int_t THcShower::ApplyCorrections( void )
{
  return(0);
}

//_____________________________________________________________________________
//Double_t THcShower::TimeWalkCorrection(const Int_t& paddle,
//					     const ESide side)
//{
//  return(0.0);
//}

//_____________________________________________________________________________
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.
  //
  //  static const Double_t sqrt2 = TMath::Sqrt(2.);
  
  cout << "THcShower::CoarseProcess called ---------------------------" <<endl;

  //  ApplyCorrections();

  //
  // Clustering of hits.
  //

  THcShowerHitList HitList;                    //list of unclustered hits

  for(Int_t j=0; j < fNLayers; j++) {

   //cout << "Plane " << j << "  Eplane = " << fPlanes[j]->GetEplane() << endl;
    for (Int_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 = YPos[j][i] + BlockThick[j]/2.;        //top + thick/2
      //	Double_t z = fNLayerZPos[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]->GetPosThr(i) ||
      //	  fPlanes[j]->GetAneg(i)> fPlanes[j]->GetNegThr(i)) {    //hit
      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 = XPos[j][i] + BlockThick[j]/2.;        //top + thick/2
	Double_t z = fNLayerZPos[j] + BlockThick[j]/2.;    //front + thick/2
	THcShowerHit* hit = new THcShowerHit(i,j,x,z,Edep,Epos,Eneg);
	//cout << "Hit: Edep = " << Edep << " X = " << x << " Z = " << z <<
	//	  " Block " << i << " Layer " << j << endl;
      };

    }
  }

  //Print out hits before clustering.
  //
  fNhits = HitList.size();

  if (fdbg_clusters_cal) {
    cout << "Total hits:     " << fNhits << endl;
    for (Int_t i=0; i!=fNhits; i++) {
      cout << "unclustered hit " << i << ": ";
      (*(HitList.begin()+i))->show();
    }
  }

  THcShowerClusterList* ClusterList = new THcShowerClusterList;
  ClusterList->ClusterHits(HitList);

  fNclust = (*ClusterList).NbClusters();

  //Print out the cluster list.
  //
  if (fdbg_clusters_cal) cout << "Cluster_list size: " << fNclust << endl;
    for (Int_t i=0; i!=fNclust; i++) {
      THcShowerCluster* cluster = (*ClusterList).ListedCluster(i);
      cout << "Cluster #" << i 
	   <<":  E=" << (*cluster).clE() 
	   << "  Epr=" << (*cluster).clEpr()
	   << "  X=" << (*cluster).clX()
	   << "  Z=" << (*cluster).clZ()
	   << "  size=" << (*cluster).clSize()
	   << endl;

      for (UInt_t j=0; j!=(*cluster).clSize(); j++) {
	THcShowerHit* hit = (*cluster).ClusteredHit(j);
	cout << "  hit #" << j << ":  "; (*hit).show();
      }

  
  //The largest cluster.
  //

  if (fNclust != 0) {

    THcShowerCluster* MaxCluster =  (*ClusterList).ListedCluster(0);
    fE = (*MaxCluster).clE();

    for (Int_t i=1; i<fNclust; i++) {


      THcShowerCluster* cluster = (*ClusterList).ListedCluster(i);

	MaxCluster = cluster;
      }
    }

    fMult = (*MaxCluster).clSize();
    fEpr = (*MaxCluster).clEpr();
    fX = (*MaxCluster).clX();
  if (fdbg_clusters_cal)
    cout << "Max.cluster: fEpr = " << fEpr << " fE = " << fE << " fX = " << fX
	 << endl;
  // Track-to-cluster  matching.
  //

  Int_t Ntracks = tracks.GetLast()+1;   // Number of reconstructed tracks

  if (fdbg_tracks_cal) {
    cout << endl;
    cout << "Number of reconstructed tracks = " << Ntracks << endl;
  }
  for (Int_t itrk=0; itrk<Ntracks; itrk++) {
    THaTrack* theTrack = static_cast<THaTrack*>( tracks[itrk] );
    if (fdbg_tracks_cal) {
      cout << "   Track " << itrk << ": "
	   << "  X = " << theTrack->GetX()
	   << "  Y = " << theTrack->GetY()
	   << "  Theta = " << theTrack->GetTheta()
	   << "  Phi = " << theTrack->GetPhi()
	   << endl;
    }
    Double_t Xtr = -75.;
    Double_t Ytr = -40.;

    Int_t mclust = MatchCluster(theTrack, ClusterList, Xtr, Ytr);

	THcShowerCluster* cluster = (*ClusterList).ListedCluster(mclust);
	fTRE = (*cluster).clE();
	fTREpr = (*cluster).clEpr();
	fTRE_cor = 0.;

	for (Int_t ip=0; ip<fNLayers; ip++) {

	  Float_t corpos = 1.;
	  Float_t corneg = 1.;
	  if (ip < fNegCols) {
	    corpos = Ycor(Ytr,0);
	    corneg = Ycor(Ytr,1);
	  }
	  else {
	    corpos = Ycor(Ytr);
	    corneg = 0.;
	  }

	  if (fdbg_tracks_cal) {
	    cout << "   Plane " << ip << "  Ytr = " << Ytr 
		 << "  corpos = " << corpos 
		 << "  corneg = " << corneg << endl;
	  }

	  fTREpl_pos_cor[ip] = (*cluster).clEplane(ip,0) * corpos;
	  fTREpl_neg_cor[ip] = (*cluster).clEplane(ip,1) * corneg;;
	  fTREpl_cor[ip] = fTREpl_pos_cor[ip] + fTREpl_neg_cor[ip];

	  if (fdbg_tracks_cal) {
	    cout << "   fTREpl_pos_cor = " << fTREpl_pos_cor[ip]
		 << "   fTREpl_neg_cor = " << fTREpl_neg_cor[ip] << endl;
	  }

	  fTRE_cor += fTREpl_cor[ip];

	}   //over planes

	fTREpr_cor = fTREpl_cor[0];

	if (fdbg_tracks_cal)
	  cout << "   fTREpr = " << fTREpr 
	       << "   fTREpr_cor = " << fTREpr_cor << endl;

      }   //mclust>=0

    }     //itrk==0

  }       //over tracks
  if (fdbg_tracks_cal)
    cout << "1st track cluster:  fTRX = " << fTRX << "  fTRY = " << fTRY 
	 << endl;
  if (fdbg_clusters_cal)
  cout << "THcShower::CoarseProcess return ---------------------------" <<endl;
//-----------------------------------------------------------------------------

Int_t THcShower::MatchCluster(THaTrack* Track,
			      THcShowerClusterList* ClusterList,
			      Double_t& XTrFront, Double_t& YTrFront)
{
  // Match a cluster to a given track.

  if (fdbg_tracks_cal) {
    cout << "THcShower::MatchCluster: Track at DC:"
	 << "  X = " << Track->GetX()
	 << "  Y = " << Track->GetY()
	 << "  Theta = " << Track->GetTheta()
	 << "  Phi = " << Track->GetPhi()
	 << endl;
  }
  // 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();
  if (fdbg_tracks_cal)
    cout << "  Track at the front of Calorimeter:"
	 << "  X = " << XTrFront
	 << "  Y = " << YTrFront
	 << "  Pathl = " << pathl
	 << endl;
    fOrigin = fPlanes[fNLayers-1]->GetOrigin();
    Double_t XTrBack = kBig;
    Double_t YTrBack = kBig;
    CalcTrackIntercept(Track, pathl, XTrBack, YTrBack);
    XTrBack += GetOrigin().X();
    YTrBack += GetOrigin().Y();
    if (fdbg_tracks_cal)
      cout << "  Track at the back of Calorimeter:"
	   << "  X = " << XTrBack
	   << "  Y = " << YTrBack
	   << "  Pathl = " << pathl
	   << endl;
    inFidVol = (XTrFront < fvXmax) && (XTrFront > fvXmin) &&
               (YTrFront < fvYmax) && (YTrFront > fvYmin) &&
               (XTrBack < fvXmax) && (XTrBack > fvXmin) &&
               (YTrBack < fvYmax) && (YTrBack > fvYmin);
    if (fdbg_tracks_cal) 
      cout << "  Fiducial volume test: inFidVol = " << inFidVol << endl;
  Int_t mclust = -1;    // The match cluster #, initialize with a bogus value.
  Double_t deltaX = kBig;   // Track to cluster distance

  if (inFidVol) {
    for (Int_t i=0; i<fNclust; i++) {

      THcShowerCluster* cluster = (*ClusterList).ListedCluster(i);

      Double_t dx = TMath::Abs( (*cluster).clX() - XTrFront );

      if (dx <= (0.5*BlockThick[0] + fSlop)) {

	if (dx <= deltaX) {
	  mclust = i;
	  deltaX = dx;
	}
  if (fdbg_tracks_cal)
    cout << "MatchCluster: mclust= " << mclust << "  delatX= " << deltaX 
	 << endl;
//_____________________________________________________________________________
Int_t THcShower::FineProcess( TClonesArray& tracks )
{
  // Reconstruct coordinates of particle track cross point with shower
  // 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 shower
  // plane in the detector coordinate system. For this, parameters of track 
  // reconstructed in THaVDC::FineTrack() are used.

  return 0;
}

ClassImp(THcShower)
////////////////////////////////////////////////////////////////////////////////