#include #include #include #include #include #include #include using namespace std; namespace RAT { void NeckCut::BeginOfRun(DS::Run& run) { fLClean = DB::Get()->GetLink("DATACLEANING",fName); fMinNhit = static_cast( fLClean->GetI("min_nhit") ); fMaxNhit = static_cast( fLClean->GetI("max_nhit") ); fMaxNeck = fLClean->GetI("max_neck"); fModeQ = fLClean->GetI("mode_q"); fPedMinQ = fLClean->GetI("ped_minq"); fPedMaxQ = fLClean->GetI("ped_maxq"); fADCMinQ = fLClean->GetI("adc_minq"); fADCMaxQ = fLClean->GetI("adc_maxq"); fModeT = fLClean->GetI("mode_t"); fTimeDiff = fLClean->GetD("time_diff"); fTacDiff = fLClean->GetD("tac_diff"); fECACal.BeginOfRun(run); } Processor::Result NeckCut::DSEvent(DS::Run&, DS::Entry& ds) { bool pass = true; // If any triggered event fails, they all fail for( size_t iEV = 0; iEV < ds.GetEVCount(); iEV++ ) if( Event(ds, ds.GetEV(iEV)) != OKTRUE ) pass = false; return pass ? OKTRUE : OKFALSE; } Processor::Result NeckCut::Event(DS::Entry&, DS::EV& ev) { fPassFlag = true; const DU::ChanHWStatus& CHS = DU::Utility::Get()->GetChanHWStatus(); double time_ave; float cqhs,cqhl,uqhs,uqhl,uqlx,ctime,utime; // skip the cut if the nhit falls outside of range if (ev.GetNhits() > fMaxNhit || ev.GetNhits() < fMinNhit){ UpdateMask(ev); return fPassFlag ? OKFALSE : OKTRUE; } // no neck hits, so return true if(ev.GetUncalPMTs().GetNeckCount() == 0){ UpdateMask(ev); return fPassFlag ? OKFALSE : OKTRUE; } // Orphan if(ev.GetTrigType() == 0){ UpdateMask(ev); return fPassFlag ? OKFALSE : OKTRUE; } // Pedestal or EXTA event if((ev.GetTrigType() & (1<= fMaxNeck){ fPassFlag = false; UpdateMask(ev); return fPassFlag ? OKFALSE : OKTRUE; } } // end loop over neck tubes for (size_t iPMT = 0; iPMT < uPMT.GetNeckCount(); iPMT++){ // If we ran any calibrations at all, get the charges const DS::PMTUncal& uneck = ev.GetUncalPMTs().GetNeckPMT(iPMT); int neckid = uneck.GetID(); // Check the neck PMTs is online if (!CHS.IsTubeOnline(neckid)) continue; uqhs = uneck.GetQHS(); uqhl = uneck.GetQHL(); uqlx = uneck.GetQLX(); utime = uneck.GetTime(); ctime = 0; // Initialize, should always get set later though // If we ran calibrations, grab the calibrated hit information if (fCalType > 0){ const DS::PMTCal& cneck = ev.GetCalPMTs().GetNeckPMT(iPMT); cqhs = cneck.GetQHS(); cqhl = cneck.GetQHL(); // If we only ran ECA we can use the calibrated time if (fCalType == 1){ ctime = cneck.GetTime(); } // If we ran PCA then re-run ECA calibration over the neck PMTs else{ fECACal.CalibrateHit(uqhs,uqhl,uqlx,utime,uneck.GetCrateCardChannelCell()); ctime = fECACal.GetTime(); } } else{ ctime = -9999; cqhs = -9999; cqhl = -9999; fModeQ = 1; // Switch to using uncalibrated charges } // If for some reason the ECA failed for this neck hit, we run in // uncalibrated mode for this event, this can happen regardless // of the level of PMT calibration run int changeMode = 0; if(abs(ctime) > 8000){ changeMode = 1; } // check if the charge was bad if ( ( fModeQ == 2 && // using calibrated charges ((cqhs < fPedMinQ || cqhs > fPedMaxQ) && (cqhl < fPedMinQ || cqhl > fPedMaxQ))) || ( fModeQ != 2 && // using uncalibrated charge in adc counts ((uqhs < fADCMinQ || uqhs > fADCMaxQ) && (uqhl < fADCMinQ || uqhl > fADCMaxQ)))){ double time_sum = 0.0; int num_tubes = 0; // If we applied ECA only the calibrated times will be OK and we can // use the neck PMTs calibrated time information, so we loop over calibrated hit. if (fModeT == 2 && fCalType == 1 && changeMode == 0){ for (size_t ipmt = 0; ipmt < ev.GetCalPMTs().GetCount(); ipmt++){ const DS::PMTCal& cpmt = ev.GetCalPMTs().GetPMT(ipmt); // If the PMT is below the equator if (DU::Utility::Get()->GetPMTInfo().GetPosition(cpmt.GetID()).Z() < 0){ float bottomtime = cpmt.GetTime(); // Check the calibrated time is in a sensible range if (abs(bottomtime) < 500){ time_sum += bottomtime; num_tubes++; } } } } // If we have PCA only or both PCA and ECA (most common), the neck tube // times will be set to invalid (99999) so we need to grab the set of // uncalibrated PMTs and re-calibrate using the ECA Cal processor else if (fModeT == 2 && (fCalType == 10 || fCalType == 11) && changeMode == 0){ for (size_t ipmt = 0; ipmt < ev.GetUncalPMTs().GetCount(); ipmt++){ const DS::PMTUncal& upmt = ev.GetUncalPMTs().GetPMT(ipmt); // If the PMT is below the equator if (DU::Utility::Get()->GetPMTInfo().GetPosition(upmt.GetID()).Z() < 0){ fECACal.CalibrateHit(upmt.GetQHS(),upmt.GetQHL(),upmt.GetQLX(),upmt.GetTime(),upmt.GetCrateCardChannelCell()); // Check that the calibration we just applied makes sense double etac = fECACal.GetTime(); if (abs(etac) < 8000){ time_sum += etac; num_tubes++; } } } } // If the user requested the raw time, or no PMT calibration was applied at all // then use the uncalibrated times else if (fModeT != 2 || fCalType == 0 || changeMode == 1){ for (size_t ipmt = 0; ipmt < ev.GetUncalPMTs().GetCount(); ipmt++){ const DS::PMTUncal& upmt = ev.GetUncalPMTs().GetPMT(ipmt); // If the PMT is below the equator if (DU::Utility::Get()->GetPMTInfo().GetPosition(upmt.GetID()).Z() < 0){ time_sum += upmt.GetTime(); num_tubes++; } } } // If there were no hits in the bottom half of the detector // do not cut the event if (num_tubes == 0){ fPassFlag = true; UpdateMask(ev); return fPassFlag ? OKFALSE : OKTRUE; } time_ave = time_sum/num_tubes; // If the neck tube came much earlier than the average hit time of hits below the equator. // then we want to tag that event as being a possible neck event. // Check the calibrated times if we've run calibration // This checks that the neck tube hits come before the average time of the hits // below the equator, which is expected for neck events if ((ctime < time_ave - fTimeDiff) && fCalType > 0 && fModeT == 2 && changeMode == 0){ fPassFlag = false; UpdateMask(ev); return fPassFlag ? OKFALSE : OKTRUE; } // Check the uncalibrated times if the user asked for it, if no PMT calibration was run, // or if the neck tube hit could not be properly calibrated for the event if ((utime > time_ave + fTacDiff) && (fModeT != 2 || fCalType == 0 || changeMode == 1)){ fPassFlag = false; UpdateMask(ev); return fPassFlag ? OKFALSE : OKTRUE; } } } // now update the mask UpdateMask(ev); return fPassFlag ? OKFALSE : OKTRUE; } } // namespace RAT