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

\brief Class for gas Cherenkov detectors

#include "THcCherenkov.h"
#include "TClonesArray.h"
#include "THaApparatus.h"
#include "THaCutList.h"
#include "THaDetMap.h"
#include "THaEvData.h"
#include "THaTrack.h"
#include "THaTrackProj.h"
#include "THcDetectorMap.h"
#include "THcGlobals.h"
#include "THcHallCSpectrometer.h"
#include "THcHitList.h"
#include "THcHodoscope.h"
#include "THcParmList.h"
#include "THcSignalHit.h"
#include "TMath.h"
#include "VarDef.h"
#include "VarType.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
using namespace std;

using std::cin;
using std::cout;
using std::endl;
using std::setprecision;
using std::setw;

//_____________________________________________________________________________
THcCherenkov::THcCherenkov(const char* name, const char* description, THaApparatus* apparatus)
    : THaNonTrackingDetector(name, description, apparatus) {
  // Normal constructor with name and description
  frAdcPedRaw       = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);
  frAdcPulseIntRaw  = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);
  frAdcPulseAmpRaw  = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);
  frAdcPulseTimeRaw = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);
  frAdcPed          = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);
  frAdcPulseInt     = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);
  frAdcPulseAmp     = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);
  frAdcPulseTime    = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);
  fAdcErrorFlag     = new TClonesArray("THcSignalHit", MaxNumCerPmt * MaxNumAdcPulse);

  fNumAdcHits         = vector<Int_t>(MaxNumCerPmt, 0.0);
  fNumGoodAdcHits     = vector<Int_t>(MaxNumCerPmt, 0.0);
  fNumTracksMatched   = vector<Int_t>(MaxNumCerPmt, 0.0);
  fNumTracksFired     = vector<Int_t>(MaxNumCerPmt, 0.0);
  fNpe                = vector<Double_t>(MaxNumCerPmt, 0.0);
  fGoodAdcPed         = vector<Double_t>(MaxNumCerPmt, 0.0);
  fGoodAdcMult        = vector<Double_t>(MaxNumCerPmt, 0.0);
  fGoodAdcHitUsed     = vector<Double_t>(MaxNumCerPmt, 0.0);
  fGoodAdcPulseInt    = vector<Double_t>(MaxNumCerPmt, 0.0);
  fGoodAdcPulseIntRaw = vector<Double_t>(MaxNumCerPmt, 0.0);
  fGoodAdcPulseAmp    = vector<Double_t>(MaxNumCerPmt, 0.0);
  fGoodAdcPulseTime   = vector<Double_t>(MaxNumCerPmt, 0.0);
  fGoodAdcTdcDiffTime = vector<Double_t>(MaxNumCerPmt, 0.0);
}

//_____________________________________________________________________________
THcCherenkov::THcCherenkov() {
  // Constructor
  frAdcPedRaw       = NULL;
  frAdcPulseIntRaw  = NULL;
  frAdcPulseAmpRaw  = NULL;
  frAdcPed          = NULL;
  frAdcPulseInt     = NULL;
  frAdcPulseAmp     = NULL;
  frAdcPulseTime    = NULL;
//_____________________________________________________________________________
THcCherenkov::~THcCherenkov() {
  delete frAdcPedRaw;
  frAdcPedRaw = NULL;
  delete frAdcPulseIntRaw;
  frAdcPulseIntRaw = NULL;
  delete frAdcPulseAmpRaw;
  frAdcPulseAmpRaw = NULL;
  delete frAdcPulseTimeRaw;
  frAdcPulseTimeRaw = NULL;
  delete frAdcPed;
  frAdcPed = NULL;
  delete frAdcPulseInt;
  frAdcPulseInt = NULL;
  delete frAdcPulseAmp;
  frAdcPulseAmp = NULL;
  delete frAdcPulseTime;
  frAdcPulseTime = NULL;
  delete fAdcErrorFlag;
  fAdcErrorFlag = NULL;
//_____________________________________________________________________________
void THcCherenkov::InitArrays() {
  fGain     = NULL;
  fPedSum   = NULL;
  fPedSum2  = NULL;
}
//_____________________________________________________________________________
void THcCherenkov::DeleteArrays() {
  delete[] fGain;
  fGain = NULL;
  delete[] fPedSum;
  fPedSum = NULL;
  delete[] fPedSum2;
  fPedSum2 = NULL;
  delete[] fPedLimit;
  fPedLimit = NULL;
  delete[] fPedMean;
  fPedMean = NULL;
  delete[] fPedCount;
  fPedCount = NULL;
  delete[] fPed;
  fPed = NULL;
  delete[] fThresh;
  fThresh = NULL;

  delete[] fAdcTimeWindowMin;
  fAdcTimeWindowMin = 0;
  delete[] fAdcTimeWindowMax;
  fAdcTimeWindowMax = 0;
  delete[] fRegionValue;
  fRegionValue = 0;
}

//_____________________________________________________________________________
THaAnalysisObject::EStatus THcCherenkov::Init(const TDatime& date) {
Eric Pooser's avatar
Eric Pooser committed
  // cout << "THcCherenkov::Init for: " << GetName() << endl;
  string EngineDID = string(GetApparatus()->GetName()).substr(0, 1) + GetName();
  std::transform(EngineDID.begin(), EngineDID.end(), EngineDID.begin(), ::toupper);
  if (gHcDetectorMap->FillMap(fDetMap, EngineDID.c_str()) < 0) {
    static const char* const here = "Init()";
    Error(Here(here), "Error filling detectormap for %s.", EngineDID.c_str());
  if ((status = THaNonTrackingDetector::Init(date)))
    return fStatus = status;
  // Should probably put this in ReadDatabase as we will know the
  // maximum number of hits after setting up the detector map
  InitHitList(fDetMap, "THcCherenkovHit", fDetMap->GetTotNumChan() + 1, 0, fADC_RefTimeCut);
  THcHallCSpectrometer* app = dynamic_cast<THcHallCSpectrometer*>(GetApparatus());
  if (!app || !(fglHod = dynamic_cast<THcHodoscope*>(app->GetDetector("hod")))) {
    static const char* const here = "ReadDatabase()";
    Warning(Here(here), "Hodoscope \"%s\" not found. ", "hod");
  fPresentP        = 0;
  THaVar* vpresent = gHaVars->Find(Form("%s.present", GetApparatus()->GetName()));
  if (vpresent) {
    fPresentP = (Bool_t*)vpresent->GetValuePointer();
  return fStatus = kOK;
}

//_____________________________________________________________________________
Int_t THcCherenkov::ReadDatabase(const TDatime& date) {
  // This function is called by THaDetectorBase::Init() once at the beginning
  // of the analysis.

Eric Pooser's avatar
Eric Pooser committed
  // cout << "THcCherenkov::ReadDatabase for: " << GetName() << endl; // Ahmed
  string prefix = string(GetApparatus()->GetName()).substr(0, 1) + GetName();
  std::transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
  CreateMissReportParms(prefix.c_str());

  fNRegions = 4; // Defualt if not set in paramter file
  DBRequest list_1[] = {{"_tot_pmts", &fNelem, kInt}, {"_num_regions", &fNRegions, kInt}, {0}};
  gHcParms->LoadParmValues(list_1, prefix.c_str());
  _det_logger->info("Created Cherenkov detector {}.{} with {} PMTs", GetApparatus()->GetName(),
                    GetName(), fNelem);
  // cout << "Created Cherenkov detector " << GetApparatus()->GetName() << "."
  //     << GetName() << " with " << fNelem << " PMTs" << endl;
  // 6 GeV pedestal paramters
  fPedLimit         = new Int_t[fNelem];
  fGain             = new Double_t[fNelem];
  fPedMean          = new Double_t[fNelem];
  fAdcTimeWindowMin = new Double_t[fNelem];
  fAdcTimeWindowMax = new Double_t[fNelem];
  // Region parameters
  fRegionsValueMax = fNRegions * 8;
  fRegionValue     = new Double_t[fRegionsValueMax];
Mark K Jones's avatar
Mark K Jones committed
  fAdcGoodElem = new Int_t[fNelem];
  fAdcPulseAmpTest = new Double_t[fNelem];
  DBRequest list[] = {{"_ped_limit", fPedLimit, kInt, (UInt_t)fNelem, optional},
                      {"_adc_to_npe", fGain, kDouble, (UInt_t)fNelem},
                      {"_red_chi2_min", &fRedChi2Min, kDouble},
                      {"_red_chi2_max", &fRedChi2Max, kDouble},
                      {"_beta_min", &fBetaMin, kDouble},
                      {"_beta_max", &fBetaMax, kDouble},
                      {"_enorm_min", &fENormMin, kDouble},
                      {"_enorm_max", &fENormMax, kDouble},
                      {"_dp_min", &fDpMin, kDouble},
                      {"_dp_max", &fDpMax, kDouble},
                      {"_mirror_zpos", &fMirrorZPos, kDouble},
                      {"_npe_thresh", &fNpeThresh, kDouble},
                      {"_debug_adc", &fDebugAdc, kInt, 0, 1},
                      {"_adcTimeWindowMin", fAdcTimeWindowMin, kDouble, (UInt_t)fNelem, 1},
                      {"_adcTimeWindowMax", fAdcTimeWindowMax, kDouble, (UInt_t)fNelem, 1},
                      {"_adc_tdc_offset", &fAdcTdcOffset, kDouble, 0, 1},
                      {"_region", &fRegionValue[0], kDouble, (UInt_t)fRegionsValueMax},
                      {"_adcrefcut", &fADC_RefTimeCut, kInt, 0, 1},
                      {0}};
  for (Int_t i = 0; i < fNelem; i++) {
    fAdcTimeWindowMin[i] = -1000.;
    fAdcTimeWindowMax[i] = 1000.;
  fDebugAdc       = 0; // Set ADC debug parameter to false unless set in parameter file
  fAdcTdcOffset   = 0.0;
  fADC_RefTimeCut = 0;
  gHcParms->LoadParmValues((DBRequest*)&list, prefix.c_str());
Eric Pooser's avatar
Eric Pooser committed
  // if (fDebugAdc) cout << "Cherenkov ADC Debug Flag Set To TRUE" << endl;
Zafar Ahmed's avatar
Zafar Ahmed committed

Eric Pooser's avatar
Eric Pooser committed
  // cout << "Track Matching Parameters for: " << GetName() << endl;
  // for (Int_t iregion = 0; iregion < fNRegions; iregion++) {
  //   cout << "Region = " << iregion + 1 << endl;
  //   for (Int_t ivalue = 0; ivalue < 8; ivalue++)
  //     cout << fRegionValue[GetIndex(iregion, ivalue)] << "  ";
  //   cout << endl;
  // }
  // Create arrays to hold pedestal results
  InitializePedestals();

  return kOK;
}

//_____________________________________________________________________________
Int_t THcCherenkov::DefineVariables(EMode mode) {
  // Initialize global variables for histogramming and tree
Eric Pooser's avatar
Eric Pooser committed
  // cout << "THcCherenkov::DefineVariables called for: " << GetName() << endl;
  if (mode == kDefine && fIsSetup)
    return kOK;
  fIsSetup = (mode == kDefine);
  // Register variables in global list
        {"numAdcHits", "Number of ADC Hits Per PMT", "fNumAdcHits"},     // Cherenkov occupancy
        {"totNumAdcHits", "Total Number of ADC Hits", "fTotNumAdcHits"}, // Cherenkov multiplicity
        {"adcPedRaw", "Raw ADC pedestals", "frAdcPedRaw.THcSignalHit.GetData()"},
        {"adcPulseIntRaw", "Raw ADC pulse integrals", "frAdcPulseIntRaw.THcSignalHit.GetData()"},
        {"adcPulseAmpRaw", "Raw ADC pulse amplitudes", "frAdcPulseAmpRaw.THcSignalHit.GetData()"},
        {"adcPulseTimeRaw", "Raw ADC pulse times", "frAdcPulseTimeRaw.THcSignalHit.GetData()"},
        {"adcPed", "ADC pedestals", "frAdcPed.THcSignalHit.GetData()"},
        {"adcPulseInt", "ADC pulse integrals", "frAdcPulseInt.THcSignalHit.GetData()"},
        {"adcPulseAmp", "ADC pulse amplitudes", "frAdcPulseAmp.THcSignalHit.GetData()"},
        {"adcPulseTime", "ADC pulse times", "frAdcPulseTime.THcSignalHit.GetData()"},
        {0}};
    DefineVarsFromList(vars, mode);
  } // end debug statement
      {"adcCounter", "ADC counter numbers", "frAdcPulseIntRaw.THcSignalHit.GetPaddleNumber()"},
      {"adcErrorFlag", "Error Flag for When FPGA Fails", "fAdcErrorFlag.THcSignalHit.GetData()"},
      {"numGoodAdcHits", "Number of Good ADC Hits Per PMT",
       "fNumGoodAdcHits"}, // Cherenkov occupancy
      {"totNumGoodAdcHits", "Total Number of Good ADC Hits",
       "fTotNumGoodAdcHits"}, // Cherenkov multiplicity
      {"numTracksMatched", "Number of Tracks Matched Per Region", "fNumTracksMatched"},
      {"numTracksFired", "Number of Tracks that Fired Per Region", "fNumTracksFired"},
      {"totNumTracksMatched", "Total Number of Tracks Matched Per Region", "fTotNumTracksMatched"},
      {"totNumTracksFired", "Total Number of Tracks that Fired", "fTotNumTracksFired"},

      {"xAtCer", "Track X at Cherenkov mirror", "fXAtCer"},
      {"yAtCer", "Track Y at Cherenkov mirror", "fYAtCer"},

      {"npe", "Number of PEs", "fNpe"},
      {"npeSum", "Total Number of PEs", "fNpeSum"},

      {"goodAdcPed", "Good ADC pedestals", "fGoodAdcPed"},
      {"goodAdcMult", "Good ADC Multiplicity", "fGoodAdcMult"},
      {"goodAdcHitUsed", "Good ADC Hit Used", "fGoodAdcHitUsed"},
      {"goodAdcPulseInt", "Good ADC pulse integrals", "fGoodAdcPulseInt"},
      {"goodAdcPulseIntRaw", "Good ADC raw pulse integrals", "fGoodAdcPulseIntRaw"},
      {"goodAdcPulseAmp", "Good ADC pulse amplitudes", "fGoodAdcPulseAmp"},
      {"goodAdcPulseTime", "Good ADC pulse times", "fGoodAdcPulseTime"},
      {"goodAdcTdcDiffTime", "Good Hodo Start - ADC pulse times", "fGoodAdcTdcDiffTime"},
      {0}};
  return DefineVarsFromList(vars, mode);
}
//_____________________________________________________________________________

Int_t THcCherenkov::ManualInitTree(TTree* t) {
  // The most direct path to the output tree!!!
  std::string app_name = GetApparatus()->GetName();
  std::string det_name = GetName();
  // if (t) {
  //  std::string branch_name = (app_name + "_" + det_name + "_data");
  //  _det_logger->info("THcHodoscope::ManualInitTree : Adding branch, {}, to output tree",
  //  branch_name); t->Branch(branch_name.c_str(), &_basic_data, 32000, 99);
  //}
  if (t) {
    std::string branch_name = (app_name + "_" + det_name + "_waveforms");
    _det_logger->info("THcCherenkov::ManualInitTree : Adding branch, {}, to output tree",
                      branch_name);
    t->Branch(branch_name.c_str(), &_waveforms, 32000, 99);
  }
  return 0;
}
//_____________________________________________________________________________

void THcCherenkov::Clear(Option_t* opt) {
  // Clear the hit lists
  fNhits               = 0;
  fTotNumAdcHits       = 0;
  fTotNumGoodAdcHits   = 0;
  fTotNumTracksMatched = 0;
  fTotNumTracksFired   = 0;
  frAdcPedRaw->Clear();
  frAdcPulseIntRaw->Clear();
  frAdcPulseAmpRaw->Clear();
  frAdcPulseTimeRaw->Clear();
  frAdcPulseInt->Clear();
  frAdcPulseAmp->Clear();
  frAdcPulseTime->Clear();
  fAdcErrorFlag->Clear();

  for (UInt_t ielem = 0; ielem < fNumAdcHits.size(); ielem++)
    fNumAdcHits.at(ielem) = 0;
  for (UInt_t ielem = 0; ielem < fNumGoodAdcHits.size(); ielem++)
    fNumGoodAdcHits.at(ielem) = 0;
  for (UInt_t ielem = 0; ielem < fNumTracksMatched.size(); ielem++)
    fNumTracksMatched.at(ielem) = 0;
  for (UInt_t ielem = 0; ielem < fNumTracksFired.size(); ielem++)
    fNumTracksFired.at(ielem) = 0;
  for (UInt_t ielem = 0; ielem < fGoodAdcPed.size(); ielem++) {
    fGoodAdcPed.at(ielem)         = 0.0;
    fGoodAdcMult.at(ielem)        = 0.0;
    fGoodAdcHitUsed.at(ielem)     = 0.0;
    fGoodAdcPulseInt.at(ielem)    = 0.0;
    fGoodAdcPulseIntRaw.at(ielem) = 0.0;
    fGoodAdcPulseAmp.at(ielem)    = 0.0;
    fGoodAdcPulseTime.at(ielem)   = kBig;
    fGoodAdcTdcDiffTime.at(ielem) = kBig;
Whitney Armstrong's avatar
Whitney Armstrong committed
  for(auto& wf : _waveforms) {
    wf.ZeroBuffer();
  }
}

//_____________________________________________________________________________

Int_t THcCherenkov::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;
  }
  fNhits = DecodeToHitList(evdata, !present);
  if (gHaCuts->Result("Pedestal_event")) {
    AccumulatePedestals(fRawHitList);
    fAnalyzePedestals = 1; // Analyze pedestals first normal events
    return (0);
  if (fAnalyzePedestals) {
    CalculatePedestals();
    fAnalyzePedestals = 0; // Don't analyze pedestals next event
  UInt_t nrAdcHits = 0;
  _waveforms.clear();
  while (ihit < fNhits) {
    THcCherenkovHit* hit       = (THcCherenkovHit*)fRawHitList->At(ihit);
    Int_t            npmt      = hit->fCounter;
    THcRawAdcHit&    rawAdcHit = hit->GetRawAdcHitPos();
    
    _waveforms.push_back({rawAdcHit.GetSampleBuffer()});

    for (UInt_t thit = 0; thit < rawAdcHit.GetNPulses(); thit++) {
      ((THcSignalHit*)frAdcPedRaw->ConstructedAt(nrAdcHits))->Set(npmt, rawAdcHit.GetPedRaw());
      ((THcSignalHit*)frAdcPed->ConstructedAt(nrAdcHits))->Set(npmt, rawAdcHit.GetPed());
      ((THcSignalHit*)frAdcPulseIntRaw->ConstructedAt(nrAdcHits))
          ->Set(npmt, rawAdcHit.GetPulseIntRaw(thit));
      ((THcSignalHit*)frAdcPulseInt->ConstructedAt(nrAdcHits))
          ->Set(npmt, rawAdcHit.GetPulseInt(thit));
      ((THcSignalHit*)frAdcPulseAmpRaw->ConstructedAt(nrAdcHits))
          ->Set(npmt, rawAdcHit.GetPulseAmpRaw(thit));
      ((THcSignalHit*)frAdcPulseAmp->ConstructedAt(nrAdcHits))
          ->Set(npmt, rawAdcHit.GetPulseAmp(thit));
      ((THcSignalHit*)frAdcPulseTimeRaw->ConstructedAt(nrAdcHits))
          ->Set(npmt, rawAdcHit.GetPulseTimeRaw(thit));
      ((THcSignalHit*)frAdcPulseTime->ConstructedAt(nrAdcHits))
          ->Set(npmt, rawAdcHit.GetPulseTime(thit) + fAdcTdcOffset);
      if (rawAdcHit.GetPulseAmpRaw(thit) > 0)
        ((THcSignalHit*)fAdcErrorFlag->ConstructedAt(nrAdcHits))->Set(npmt, 0);
      if (rawAdcHit.GetPulseAmpRaw(thit) <= 0)
        ((THcSignalHit*)fAdcErrorFlag->ConstructedAt(nrAdcHits))->Set(npmt, 1);
      fNumAdcHits.at(npmt - 1) = npmt;
    ihit++;
  }
  return ihit;
}

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

//_____________________________________________________________________________
Int_t THcCherenkov::CoarseProcess(TClonesArray&) {
  Double_t StartTime = 0.0;
  if( fglHod ) StartTime = fglHod->GetStartTime();
Mark K Jones's avatar
Mark K Jones committed
  for(Int_t ipmt = 0; ipmt < fNelem; ipmt++) {
    fAdcPulseAmpTest[ipmt] = -1000.;
    fAdcGoodElem[ipmt]=-1;
   }
   //
  for(Int_t ielem = 0; ielem < frAdcPulseInt->GetEntries(); ielem++) {
    Int_t    npmt         = ((THcSignalHit*) frAdcPulseInt->ConstructedAt(ielem))->GetPaddleNumber() - 1;
    Double_t pulseTime    = ((THcSignalHit*) frAdcPulseTime->ConstructedAt(ielem))->GetData();
Mark K Jones's avatar
Mark K Jones committed
    Double_t pulseAmp     = ((THcSignalHit*) frAdcPulseAmp->ConstructedAt(ielem))->GetData();
   Double_t adctdcdiffTime = StartTime-pulseTime;
     Bool_t   errorFlag    = ((THcSignalHit*) fAdcErrorFlag->ConstructedAt(ielem))->GetData();
    Bool_t   pulseTimeCut = adctdcdiffTime > fAdcTimeWindowMin[npmt] && adctdcdiffTime < fAdcTimeWindowMax[npmt];
Mark K Jones's avatar
Mark K Jones committed
    if (!errorFlag && pulseTimeCut && pulseAmp > fAdcPulseAmpTest[npmt]) {
       fAdcGoodElem[npmt]=ielem;
       fAdcPulseAmpTest[npmt] = pulseAmp;
Mark K Jones's avatar
Mark K Jones committed
  }
  // Loop over the npmt
  for(Int_t npmt = 0; npmt < fNelem; npmt++) {
    Int_t ielem = fAdcGoodElem[npmt];
    if (ielem != -1) {
    Double_t pulsePed     = ((THcSignalHit*) frAdcPed->ConstructedAt(ielem))->GetData();
    Double_t pulseInt     = ((THcSignalHit*) frAdcPulseInt->ConstructedAt(ielem))->GetData();
    Double_t pulseIntRaw  = ((THcSignalHit*) frAdcPulseIntRaw->ConstructedAt(ielem))->GetData();
    Double_t pulseAmp     = ((THcSignalHit*) frAdcPulseAmp->ConstructedAt(ielem))->GetData();
    Double_t pulseTime    = ((THcSignalHit*) frAdcPulseTime->ConstructedAt(ielem))->GetData();
   Double_t adctdcdiffTime = StartTime-pulseTime;
    // By default, the last hit within the timing cut will be considered "good"
      fGoodAdcPed.at(npmt)         = pulsePed;
      fGoodAdcHitUsed.at(npmt)     = ielem + 1;
      fGoodAdcPulseInt.at(npmt)    = pulseInt;
      fGoodAdcPulseIntRaw.at(npmt) = pulseIntRaw;
      fGoodAdcPulseAmp.at(npmt)    = pulseAmp;
      fGoodAdcPulseTime.at(npmt)   = pulseTime;
      fGoodAdcTdcDiffTime.at(npmt) = adctdcdiffTime;
      fNpe.at(npmt) = fGain[npmt] * fGoodAdcPulseInt.at(npmt);
      fNpeSum += fNpe.at(npmt);

      fTotNumGoodAdcHits++;
      fNumGoodAdcHits.at(npmt) = npmt + 1;
    }
  }
  return 0;
}

//_____________________________________________________________________________
Int_t THcCherenkov::FineProcess(TClonesArray& tracks) {
  Int_t nTracks = tracks.GetLast() + 1;

  for (Int_t itrack = 0; itrack < nTracks; itrack++) {

    THaTrack* track = dynamic_cast<THaTrack*>(tracks[itrack]);
    if (track->GetIndex() != 0)
      continue; // Select the best track

    Double_t trackChi2    = track->GetChi2();
    Int_t    trackNDoF    = track->GetNDoF();
    Double_t trackRedChi2 = trackChi2 / trackNDoF;
    Double_t trackBeta    = track->GetBeta();
    Double_t trackEnergy  = track->GetEnergy();
    Double_t trackMom     = track->GetP();
    Double_t trackDp      = track->GetDp();
    Double_t trackENorm   = trackEnergy / trackMom;
    Double_t trackXfp     = track->GetX();
    Double_t trackYfp     = track->GetY();
    Double_t trackTheta   = track->GetTheta();
    Double_t trackPhi     = track->GetPhi();

    Bool_t trackRedChi2Cut = trackRedChi2 > fRedChi2Min && trackRedChi2 < fRedChi2Max;
    Bool_t trackBetaCut    = trackBeta > fBetaMin && trackBeta < fBetaMax;
    Bool_t trackENormCut   = trackENorm > fENormMin && trackENorm < fENormMax;
    Bool_t trackDpCut      = trackDp > fDpMin && trackDp < fDpMax;
    fXAtCer                = trackXfp + trackTheta * fMirrorZPos;
    fYAtCer                = trackYfp + trackPhi * fMirrorZPos;
    if (trackRedChi2Cut && trackBetaCut && trackENormCut && trackDpCut) {
      // Project the track to the Cherenkov mirror planes

      // cout << "Cherenkov Detector: " << GetName() << " has fNRegions = " << fNRegions << endl;
      // cout << "nTracks = " << nTracks << "\t" << "trackChi2 = " << trackChi2
      // 	   << "\t" << "trackNDof = " << trackNDoF << "\t" << "trackRedChi2 = " <<
      // trackRedChi2 << endl; cout << "trackBeta = " << trackBeta << "\t" << "trackEnergy = " <<
      // trackEnergy << "\t"
      // 	   << "trackMom = " << trackMom << "\t" << "trackENorm = " << trackENorm << endl;
      // cout << "trackXfp = " << trackXfp << "\t" << "trackYfp = " << trackYfp << "\t"
      // 	   << "trackTheta = " << trackTheta << "\t" << "trackPhi = " << trackPhi << endl;
      // cout << "fMirrorZPos = " << fMirrorZPos << "\t" << "fXAtCer = " << fXAtCer << "\t" <<
      // "fYAtCer = " << fYAtCer << endl; cout <<
      // "=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:" << endl;

      for (Int_t iregion = 0; iregion < fNRegions; iregion++) {

        if ((TMath::Abs(fRegionValue[GetIndex(iregion, 0)] - fXAtCer) <
             fRegionValue[GetIndex(iregion, 4)]) &&
            (TMath::Abs(fRegionValue[GetIndex(iregion, 1)] - fYAtCer) <
             fRegionValue[GetIndex(iregion, 5)]) &&
            (TMath::Abs(fRegionValue[GetIndex(iregion, 2)] - trackTheta) <
             fRegionValue[GetIndex(iregion, 6)]) &&
            (TMath::Abs(fRegionValue[GetIndex(iregion, 3)] - trackPhi) <
             fRegionValue[GetIndex(iregion, 7)])) {

          fTotNumTracksMatched++;
          fNumTracksMatched.at(iregion) = iregion + 1;

          if (fNpeSum > fNpeThresh) {
            fTotNumTracksFired++;
            fNumTracksFired.at(iregion) = iregion + 1;
          } // NPE threshold cut
        }   // Regional cuts
      }     // Loop over regions
    }       // Tracking cuts
  }         // Track loop
  return 0;
}

//_____________________________________________________________________________
void THcCherenkov::InitializePedestals() {
  fNPedestalEvents = 0;
  fMinPeds         = 500; // In engine, this is set in parameter file
  fPedSum          = new Int_t[fNelem];
  fPedSum2         = new Int_t[fNelem];
  fPedCount        = new Int_t[fNelem];
  fPed             = new Double_t[fNelem];
  fThresh          = new Double_t[fNelem];
  for (Int_t i = 0; i < fNelem; i++) {
    fPedSum[i]   = 0;
    fPedSum2[i]  = 0;
Zafar's avatar
Zafar committed
    fPedCount[i] = 0;
  }
}

//_____________________________________________________________________________
void THcCherenkov::AccumulatePedestals(TClonesArray* rawhits) {
  // Extract data from the hit list, accumulating into arrays for
  // calculating pedestals

  Int_t nrawhits = rawhits->GetLast() + 1;

  Int_t ihit = 0;
  while (ihit < nrawhits) {
    THcCherenkovHit* hit = (THcCherenkovHit*)rawhits->At(ihit);

    Int_t element = hit->fCounter - 1;
    Int_t nadc    = hit->GetRawAdcHitPos().GetPulseIntRaw();
    if (nadc <= fPedLimit[element]) {
      fPedSum[element] += nadc;
      fPedSum2[element] += nadc * nadc;
Zafar's avatar
Zafar committed
      fPedCount[element]++;
      if (fPedCount[element] == fMinPeds / 5) {
        fPedLimit[element] = 100 + fPedSum[element] / fPedCount[element];
      }
    }
    ihit++;
  }

  fNPedestalEvents++;

  return;
}

//_____________________________________________________________________________
void THcCherenkov::CalculatePedestals() {
  // Use the accumulated pedestal data to calculate pedestals
  // Later add check to see if pedestals have drifted ("Danger Will Robinson!")
  //  cout << "Plane: " << fPlaneNum << endl;
  for (Int_t i = 0; i < fNelem; i++) {
Zafar's avatar
Zafar committed
    // PMT tubes
    fPed[i]    = ((Double_t)fPedSum[i]) / TMath::Max(1, fPedCount[i]);
Zafar's avatar
Zafar committed
    fThresh[i] = fPed[i] + 15;

    // Just a copy for now, but allow the possibility that fXXXPedMean is set
    // in a parameter file and only overwritten if there is a sufficient number of
    // pedestal events.  (So that pedestals are sensible even if the pedestal events were
    // not acquired.)
    if (fMinPeds > 0) {
      if (fPedCount[i] > fMinPeds) {
        fPedMean[i] = fPed[i];
      }
    }
  }
  //  cout << " " << endl;
}

//_____________________________________________________________________________
Int_t THcCherenkov::GetIndex(Int_t nRegion, Int_t nValue) { return fNRegions * nValue + nRegion; }
//_____________________________________________________________________________
void THcCherenkov::Print(const Option_t* opt) const {
  THaNonTrackingDetector::Print(opt);
  // Print out the pedestals
  cout << endl;
  cout << "Cherenkov Pedestals" << endl;
  // Ahmed
Zafar's avatar
Zafar committed
  cout << "No.   ADC" << endl;
  for (Int_t i = 0; i < fNelem; i++)
Zafar's avatar
Zafar committed
    cout << " " << i << "    " << fPed[i] << endl;
//_____________________________________________________________________________
Double_t THcCherenkov::GetCerNPE() { return fNpeSum; }
//_____________________________________________________________________________
Int_t THcCherenkov::End(THaRunBase* run) {
  MissReport(Form("%s.%s", GetApparatus()->GetName(), GetName()));
  return 0;
}
ClassImp(THcCherenkov)
    ////////////////////////////////////////////////////////////////////////////////