#include #include using namespace RAT; void CrossTalkCut::BeginOfRun(DS::Run&) { fHClean = DB::Get()->GetLink("HITCLEANING","crosstalk"); fNChannels = fHClean->GetI("number_channels"); fNearSlots = fHClean->GetI("number_of_nearby_slots"); fNearChannels = fHClean->GetI("number_of_nearby_channels"); fCalQHSHighCharge = fHClean->GetD("calQHS_high_charge"); fCalQHSLow = fHClean->GetD("calQHS_low"); fCalQHSHigh = fHClean->GetD("calQHS_high"); fCalTimeLow = fHClean->GetD("calTime_low"); fCalTimeHigh = fHClean->GetD("calTime_high"); } // Only works for ECA calibrated events void CrossTalkCut::CutCrossTalk(DS::Entry& ds) { for(size_t iEV = 0; iEV < ds.GetEVCount(); iEV++){ DS::EV& ev = ds.GetEV(iEV); // Loops through high charge hits and looks at adjacent channels. // Look at all channel types. for(size_t iPMT = 0; iPMT < ev.GetCalPMTs().GetAllCount(); iPMT++){ DS::PMTCal fHighChargePMT = ev.GetCalPMTs().GetAllPMT(iPMT); float qhs = fHighChargePMT.GetQHS(); double time = fHighChargePMT.GetTime(); // ID the HIT int crate = fHighChargePMT.GetCrate(); int card = fHighChargePMT.GetCard(); int channel = fHighChargePMT.GetChannel(); // Select high charge PMT with valid time if(qhs > fCalQHSHighCharge && time > -1000){ FlagNearbyChannels(iPMT, crate, card, channel, time, ev); } } } } // Flags crosstalk hits void CrossTalkCut::FlagNearbyChannels(size_t iPMT, int crate, int card, int channel, double time, DS::EV& ev) { // Select how many channels to loop over based on # of PMTs hit size_t nChMax = 0; if(ev.GetCalPMTs().GetAllCount() > fNChannels) nChMax = fNChannels; else nChMax = ev.GetCalPMTs().GetAllCount(); // Loop over hits for(int nCh = 1; nCh < nChMax; nCh++){ // Look back in hits if(iPMT < ev.GetCalPMTs().GetAllCount() - nCh){ DS::PMTCal fCrossTalkPMT = ev.GetCalPMTs().GetAllPMT(iPMT+nCh); double deltat = fCrossTalkPMT.GetTime() - time; if(CheckCriteria(fCrossTalkPMT, crate, card, channel, deltat)){ // This hit is likely due to cross-talk so set the flag ev.GetCalPMTs().GetAllPMT(iPMT+nCh).SetCrossTalkFlag(true); if((iPMT+nCh) < ev.GetCalPMTs().GetCount()){ // Needed to make sure inward type is separate from normal/HQE ev.GetCalPMTs().GetPMT(iPMT+nCh).SetCrossTalkFlag(true); } } } // Look foward in hits if(iPMT > nCh){ DS::PMTCal fCrossTalkPMT = ev.GetCalPMTs().GetAllPMT(iPMT-nCh); double deltat = fCrossTalkPMT.GetTime() - time; if(CheckCriteria(fCrossTalkPMT, crate, card, channel, deltat)){ // This hit is likely due to cross-talk so set the flag ev.GetCalPMTs().GetAllPMT(iPMT-nCh).SetCrossTalkFlag(true); if((iPMT-nCh) < ev.GetCalPMTs().GetCount()){ // Needed to make sure inward type is separate from normal/HQE ev.GetCalPMTs().GetPMT(iPMT-nCh).SetCrossTalkFlag(true); } } } } } // Check the charge and time of nearby channels to determine // if the hit is likely due to cross-talk bool CrossTalkCut::CheckCriteria(DS::PMTCal fCrossTalkPMT, int crate, int card, int channel, double deltat) { // Check adjacency in electronics space bool same_crate = (int(fCrossTalkPMT.GetCrate()) == crate); if(!same_crate) return false; bool neighbor_card = ((int(fCrossTalkPMT.GetCard()) > card - fNearSlots) && (int(fCrossTalkPMT.GetCard()) < card + fNearSlots)); if(!neighbor_card) return false; bool neighbor_channel = ((int(fCrossTalkPMT.GetChannel()) > channel - fNearChannels) && (int(fCrossTalkPMT.GetChannel()) < channel + fNearChannels)); if(!neighbor_channel) return false; // Check the channels is within the charge and time boundaries defines for crosstalk bool low_charge = (fCrossTalkPMT.GetQHS() > fCalQHSLow); if(!low_charge) return false; bool high_charge = (fCrossTalkPMT.GetQHS() < fCalQHSHigh); if(!high_charge) return false; bool low_time = (deltat > fCalTimeLow); if(!low_time) return false; bool high_time = (deltat < fCalTimeHigh); if(!high_time) return false; // Skip hits that have already been flagged bool dbl_count = (fCrossTalkPMT.GetCrossTalkFlag() == 0); if(!dbl_count) return false; return true; }