Skip to content
Snippets Groups Projects
THcShower.cxx 37.9 KiB
Newer Older
/** \class THcShower
    \ingroup Detectors

\brief 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 ) :
  hcana::ConfigLogging<THaNonTrackingDetector>(name,description,apparatus)
  fNLayers = 0;			// No layers until we make them
  fNTotLayers = 0;
  fHasArray = 0;

  fClusterList = new THcShowerClusterList;
}

//_____________________________________________________________________________
THcShower::THcShower( ) :
  hcana::ConfigLogging<THaNonTrackingDetector>()
//_____________________________________________________________________________
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},
    {"cal_adcrefcut", &fADC_RefTimeCut, kInt, 0, 1},
  fADC_RefTimeCut = 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);
Eric Pooser's avatar
Eric Pooser committed
  // cout << "---------------------------------------------------------------\n";
  _logger->info("From THcShower::Setup: created Shower planes for {} ", GetApparatus()->GetName());
  //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";
  //}
Eric Pooser's avatar
Eric Pooser committed
  // if(fHasArray)
  //   cout << fLayerNames[fNTotLayers-1] << " has fly\'s eye configuration\n";
Eric Pooser's avatar
Eric Pooser committed
  // cout << "---------------------------------------------------------------\n";
//_____________________________________________________________________________
THaAnalysisObject::EStatus THcShower::Init( const TDatime& date )
{
  Setup(GetName(), GetTitle());
  char EngineDID[] = "xCAL";
  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.", EngineDID );
    return kInitError;
  }

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

  InitHitList(fDetMap, "THcRawShowerHit", fDetMap->GetTotNumChan()+1,
	      0, fADC_RefTimeCut);
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;
    }
  }
Eric Pooser's avatar
Eric Pooser committed
    // 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());
Eric Pooser's avatar
Eric Pooser committed
    // cout << "  New limits:" << endl;
    // cout << "    Xmin = " << fvXmin << "  Xmax = " << fvXmax << endl;
    // cout << "    Ymin = " << fvYmin << "  Ymax = " << fvYmax << endl;
Eric Pooser's avatar
Eric Pooser committed
  // cout << "---------------------------------------------------------------\n";
  // cout << "From THcShower::Init: initialized " << GetApparatus()->GetName()
  //      <<  GetName() << endl;
  // cout << "---------------------------------------------------------------\n";
  fPresentP = 0;
  THaVar* vpresent = gHaVars->Find(Form("%s.present",GetApparatus()->GetName()));
  if(vpresent) {
    fPresentP = (Bool_t *) vpresent->GetValuePointer();
  }
  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';
  CreateMissReportParms(Form("%scal",prefix));

  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,0,1},
      {"cal_fv_test", &fvTest, kInt,0,1},
      {"cal_fv_delta", &fvDelta, kDouble,0,1},
      {"cal_ADCMode", &fADCMode, kInt, 0, 1},
      {"cal_adc_tdc_offset", &fAdcTdcOffset, kDouble, 0, 1},
      {"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;
    fADCMode=kADCDynamicPedestal;
    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];
  for (UInt_t i=0; i<fNTotBlocks; i++) {
    fShPosPedLimit[i]=0.;
    fShNegPedLimit[i]=0.;
  }
  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_cor[fNTotBlocks];

  Double_t hcal_neg_cal_const[fNTotBlocks];
  Double_t hcal_neg_gain_cor[fNTotBlocks];
  fPosAdcTimeWindowMin = new Double_t [fNTotBlocks];
  fNegAdcTimeWindowMin = new Double_t [fNTotBlocks];
  fPosAdcTimeWindowMax = new Double_t [fNTotBlocks];
  fNegAdcTimeWindowMax = new Double_t [fNTotBlocks];
    {"cal_pos_cal_const", hcal_pos_cal_const, kDouble, fNTotBlocks},
    {"cal_pos_ped_limit", fShPosPedLimit, kInt,    fNTotBlocks,1},
    {"cal_pos_gain_cor",  hcal_pos_gain_cor,  kDouble, fNTotBlocks},
    {"cal_neg_cal_const", hcal_neg_cal_const, kDouble, fNTotBlocks},
    {"cal_neg_ped_limit", fShNegPedLimit, kInt,    fNTotBlocks,1},
    {"cal_neg_gain_cor",  hcal_neg_gain_cor,  kDouble, fNTotBlocks},
    {"cal_pos_AdcTimeWindowMin", fPosAdcTimeWindowMin, kDouble, static_cast<UInt_t>(fNTotBlocks),1},
    {"cal_neg_AdcTimeWindowMin", fNegAdcTimeWindowMin, kDouble, static_cast<UInt_t>(fNTotBlocks),1},
    {"cal_pos_AdcTimeWindowMax", fPosAdcTimeWindowMax, kDouble, static_cast<UInt_t>(fNTotBlocks),1},
    {"cal_neg_AdcTimeWindowMax", fNegAdcTimeWindowMax, kDouble, static_cast<UInt_t>(fNTotBlocks),1},
    {"cal_min_peds", &fShMinPeds, kInt,0,1},
    fPosAdcTimeWindowMin[ip] = -1000.;
    fNegAdcTimeWindowMin[ip] = -1000.;
    fPosAdcTimeWindowMax[ip] = 1000.;
    fNegAdcTimeWindowMax[ip] = 1000.;
  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 layer clusters",                            "fNclust" },
    { "nclusttrack", "Number of layer cluster which matched best track","fNclustTrack" },
    { "xclusttrack", "X pos of layer cluster which matched best track","fXclustTrack" },
    { "xtrack", "X pos of track which matched layer cluster", "fXTrack" },
    { "yclusttrack", "Y pos of layer cluster which matched best track","fYclustTrack" },
    { "ytrack", "Y pos of track which matched layer cluster", "fYTrack" },
    { "etot", "Total energy",                                    "fEtot" },
    { "etotnorm", "Total energy divided by Central Momentum",    "fEtotNorm" },
    { "etrack", "Track energy",                                  "fEtrack" },
    { "etracknorm", "Total energy divided by track momentum",    "fEtrackNorm" },
    { "eprtrack", "Track Preshower energy",                      "fEPRtrack" },
    { "eprtracknorm", "Preshower energy divided by track momentum", "fEPRtrackNorm" },
    { "etottracknorm", "Total energy divided by track momentum", "fETotTrackNorm" },
    { "ntracks", "Number of shower tracks",                      "fNtracks" },

  if(fHasArray) {

  RVarDef array_vars[] = {
    { "sizeclustarray", "Number of block in array cluster that matches track", "fSizeClustArray" },
    { "nclustarraytrack", "Number of cluster for Fly's eye which matched best track","fNclustArrayTrack" },
    { "nblock_high_ene", "Block number in array with highest energy which matched best track","fNblockHighEnergy" },
    { "xclustarraytrack", "X pos of cluster which matched best track","fXclustArrayTrack" },
    { "xtrackarray", "X pos of track which matched cluster", "fXTrackArray" },
    { "yclustarraytrack", "Y pos of cluster which matched best track","fYclustArrayTrack" },
    { "ytrackarray", "Y pos of track which matched cluster", "fYTrackArray" },
    { 0 }
  };

  DefineVarsFromList( array_vars, mode );
  }
  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;
}

//_____________________________________________________________________________
void THcShower::Clear(Option_t* opt)
  for(UInt_t ip=0;ip<fNLayers;ip++) {
  if(fHasArray) {
    fArray->Clear(opt);
  }

  fNhits = 0;
  fNclust = 0;
  fNclustTrack = -2;
  fXclustTrack = -1000;
  fXTrack = -1000;
  fYclustTrack = -1000;
  fYTrack = -1000;
  fNclustArrayTrack = -2;
  fXclustArrayTrack = -1000;
  fXTrackArray = -1000;
  fYclustArrayTrack = -1000;
  fYTrackArray = -1000;
  fEtot = 0.;
  fEtotNorm = 0.;
  fEPRtrack = 0.;
  fEPRtrackNorm = 0.;
  fSizeClustArray = 0;
  fNblockHighEnergy = 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
  Bool_t present = kTRUE;	// Suppress reference time warnings
  if(fPresentP) {		// if this spectrometer not part of trigger
    present = *fPresentP;
  }
  Int_t nhits = DecodeToHitList(evdata, !present);
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);
  }
  if(fHasArray) {
    nexthit = fArray->ProcessHits(fRawHitList, nexthit);
  }
  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.
  for(UInt_t ip=0;ip<fNLayers;ip++) {
    fPlanes[ip]->CoarseProcessHits();
    fEtot += fPlanes[ip]->GetEplane();
  }
  if(fHasArray) {
    fArray->CoarseProcessHits();
    fEtot += fArray->GetEarray();
  }
  THcHallCSpectrometer *app = static_cast<THcHallCSpectrometer*>(GetApparatus());
  fEtotNorm=fEtot/(app->GetPcentral());
  //
  THcShowerHitSet HitSet;
  for(UInt_t j=0; j < fNLayers; j++) {
    for (UInt_t i=0; i<fNBlocks[j]; i++) {
      if (fPlanes[j]->GetAposP(i) > 0  || fPlanes[j]->GetAnegP(i) >0) {    //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 y=-1000;
        if (fHasArray) {
	  if (Eneg>0) y = fYPos[2*j]/2 ;  
	  if (Epos>0) y = fYPos[2*j+1]/2 ;  
	  if (Epos>0 && Eneg>0) y = 0. ;  
        } else {
          y=0.;
	}
	Double_t z = fLayerZPos[j] + BlockThick[j]/2.;      //front + thick/2
	THcShowerHit* hit = new THcShowerHit(i,j,x,y,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 << " event = " << fEvent << 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 << " event = " << fEvent << "  Clustered hits. Number of clusters: " << fNclust << endl;
    UInt_t i = 0;
    for (THcShowerClusterListIt ppcl = (*fClusterList).begin();
	 ppcl != (*fClusterList).end(); ++ppcl) {
      cout << "  Cluster #" << i++
	   << "  Epr=" << clEpr(*ppcl)
	   << "  X=" << clX(*ppcl)
	   << "  Z=" << clZ(*ppcl)
	   << "  size=" << (**ppcl).size()
      Int_t j=0;
      for (THcShowerClusterIt pph=(**ppcl).begin(); pph!=(**ppcl).end();
	cout << "  hit " << j++ << ": ";
	(**pph).show();
    cout << "---------------------------------------------------------------\n";
  // Do same for Array.

  if(fHasArray) fArray->CoarseProcess(tracks);
  //  
  Int_t Ntracks = tracks.GetLast()+1;   // Number of reconstructed tracks
  Double_t save_energy=0;
 for (Int_t itrk=0; itrk<Ntracks; itrk++) {
    THaTrack* theTrack = static_cast<THaTrack*>( tracks[itrk] );
    //     save_energy = GetShEnergy(theTrack);
    save_energy = GetShEnergy(theTrack, fNLayers);
      if (fHasArray) save_energy += fArray->GetShEnergy(theTrack);
    theTrack->SetEnergy(save_energy);
  }       //over 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();

	  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 addY(Double_t x, THcShowerHit* h) {
  return x + h->hitE() * h->hitY();
}

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();
}

// Y 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 clY(THcShowerCluster* cluster) {
  Double_t Etot = accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
  return (Etot != 0. ?
	  accumulate((*cluster).begin(),(*cluster).end(),0.,addY)/Etot : -100.);
}
// 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.