#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace RAT { DQTimeProc::DQTimeProc() : DataQualityProc("dqtimeproc") { } DQTimeProc::~DQTimeProc() { } void DQTimeProc::BeginOfRun( DS::Run& run ) { DataQualityProc::BeginOfRun( run ); fFirstEvent = true; fPreviousEventTime = 0.0; fPreviousCount10 = 0; fPreviousCount50 = 0; fPreviousGTID = 0; fNegativeDeltaTCount = 0; fNegativeDeltaGTIDCount = 0; fCount10Resets = 0; fCount50Resets = 0; fTriggerWindowDeltaTCount = 0; fRetriggerDeltaTCount = 0; f10MhzTimeCheck = true; f10MhzTimeCheckFails = 0; // Get variables from DB links, save as class members and to RATDB via JSON object fDQChecks = DB::Get()->GetLink( "DQCHECKS", "neutrino" ); fRunHeaderThresh = fDQChecks->GetD( "run_header_thresh" ); fCriteria[ "run_header_thresh" ] = fRunHeaderThresh; fClockForwardThresh = fDQChecks->GetD( "clock_forward_thresh" ); fCriteria[ "clock_forward_thresh" ] = fClockForwardThresh; fEventSeparationThresh = fDQChecks->GetD( "event_separation_thresh" ); fCriteria[ "event_separation_thresh" ] = fEventSeparationThresh; fRetriggersThresh = fDQChecks->GetD( "retriggers_thresh" ); fCriteria[ "retriggers_thresh" ] = fRetriggersThresh; fMinEventRate = fDQChecks->GetD( "min_event_rate" ); fCriteria[ "min_event_rate" ] = fMinEventRate; fMaxEventRate = fDQChecks->GetD( "max_event_rate" ); fCriteria[ "max_event_rate" ] = fMaxEventRate; // Book histograms stringstream stringRunID; stringRunID << "SNO+ Data Quality: #Deltat (event separation) - run "; stringRunID << fRunID; string baseTitle = stringRunID.str(); string title = baseTitle + " - (negative) log scale"; // negative intervals fNegativeDeltaTHist = new TH1D( "negative_delta_ts", title.c_str(), 100, 9.0, 0.0 ); NegativeLogBinsX( fNegativeDeltaTHist ); fNegativeDeltaGTIDHist = new TH1D( "negative_delta_GTID", title.c_str(), 100, 9.0, 0.0 ); NegativeLogBinsX( fNegativeDeltaGTIDHist ); fCount10ResetDeltaTHist = new TH1D( "count10_resets", title.c_str(), 100, 9.0, 0.0 ); NegativeLogBinsX( fCount10ResetDeltaTHist ); fCount50ResetDeltaTHist = new TH1D( "count50_resets", title.c_str(), 100, 9.0, 0.0 ); NegativeLogBinsX( fCount50ResetDeltaTHist ); // positive intervals title = baseTitle + " - log scale"; fPositiveDeltaTHist = new TH1D( "positive_delta_ts", title.c_str(), 100, 0.0, 9.0 ); LogBinsX( fPositiveDeltaTHist ); title = baseTitle + " - trig window detail"; fTrigWindowDeltaTHist = new TH1D( "trigger_window_detail", title.c_str(), 110, -50.0, 1050.0 ); title = baseTitle + " - 10Mhz clock count and UT differences" ; fUniversalTimeClockCountHist = new TH1I("clock UT difference",title.c_str(),100,-50,50); fNegativeDeltaTHist->SetDirectory(0); fNegativeDeltaGTIDHist->SetDirectory(0); fCount10ResetDeltaTHist->SetDirectory(0); fCount50ResetDeltaTHist->SetDirectory(0); fPositiveDeltaTHist->SetDirectory(0); fTrigWindowDeltaTHist->SetDirectory(0); fUniversalTimeClockCountHist->SetDirectory(0); } Processor::Result DQTimeProc::DSEvent( DS::Run&, DS::Entry& ds ) { for( size_t iEV = 0; iEV < ds.GetEVCount(); iEV++ ) Event(ds, ds.GetEV(iEV)); return OK; } Processor::Result DQTimeProc::Event( DS::Entry&, DS::EV& ev ) { fEventCount++; // Create RateData struct TimingData timingData; timingData.fGTID = ev.GetGTID(); // event time in nanoseconds timingData.fEventTime = ev.GetUniversalTime().GetNanoSeconds(); unsigned long int clockCount10 = ev.GetClockCount10(); unsigned long int clockCount50 = ev.GetClockCount50(); timingData.fCount50DeltaT = 0.0; if( fFirstEvent ) { fFirstEventTime = timingData.fEventTime; fFirstEvent = false; } else { if( fPreviousEventTime != 0 ) { timingData.fCount50DeltaT = 20.0 * ( clockCount50 - fPreviousCount50 ); if( timingData.fCount50DeltaT < 0.0 ) { detail << "DQTimeProc::Event: " << "calculated negative delta-t for event " << timingData.fGTID << newline; debug << " --> event time = " << timingData.fEventTime << " ns," << " (previously " << fPreviousEventTime << " ns)" << newline; fNegativeDeltaTCount++; fNegativeDeltaTHist->Fill( timingData.fCount50DeltaT ); double deltaGTID = timingData.fGTID - fPreviousGTID; double deltaCount10 = clockCount10 - fPreviousCount10; double deltaCount50 = clockCount50 - fPreviousCount50; if( deltaGTID < 0 ) // Events built out of sync { detail << " --> events built out of sync" << newline; debug << " --> GTID = " << timingData.fGTID << " (previously " << fPreviousGTID << ")" << newline; fNegativeDeltaGTIDCount++; fNegativeDeltaGTIDHist->Fill( timingData.fCount50DeltaT ); } if( ( ( deltaCount10 < 0 ) || ( deltaCount50 < 0 ) ) && !( ( deltaCount10 < 0 ) && ( deltaCount50 < 0 ) ) ) // if either deltaCount10 or deltaCount50 is negative, but not // both, then whichever is negative must have been reset { if( deltaCount10 < 0 ) // 10 MHz clock reset { detail << " --> 10 MHz clock was reset" << newline; debug << " --> 10 MHz count = " << clockCount10 << " (previously " << fPreviousCount10 << ")" << newline; fCount10Resets++; fCount10ResetDeltaTHist->Fill( timingData.fCount50DeltaT ); } if( deltaCount50 < 0 ) // 50 MHz clock reset { detail << " --> 50 MHz clock was reset" << newline; debug << " --> 50 MHz count = " << clockCount50 << " (previously " << fPreviousCount50 << ")" << newline; fCount50Resets++; fCount50ResetDeltaTHist->Fill( timingData.fCount50DeltaT ); } } } // closes if( timingData.fCount50DeltaT < 0 ) else if( ( timingData.fCount50DeltaT >= 0.0 ) && ( timingData.fCount50DeltaT < 420.0 ) ) // Delta-t is smaller than 1 trigger window + ~30 ns dead time { detail << "DQTimeProc::Event: " << "calculated delta-t = " << timingData.fCount50DeltaT << " ( > 430 ns ), for event " << timingData.fGTID << newline; fTriggerWindowDeltaTCount++; fTrigWindowDeltaTHist->Fill( timingData.fCount50DeltaT ); fPositiveDeltaTHist->Fill( timingData.fCount50DeltaT ); } else if( ( timingData.fCount50DeltaT >= 420.0 ) && ( timingData.fCount50DeltaT < 600.0 ) ) // Probably re-trigger event { detail << "DQTimeProc::Event: " << "calculated delta-t = " << timingData.fCount50DeltaT << " ( > 600 ns ), for event " << timingData.fGTID << newline; fRetriggerDeltaTCount++; fTrigWindowDeltaTHist->Fill( timingData.fCount50DeltaT ); fPositiveDeltaTHist->Fill( timingData.fCount50DeltaT ); } else // >= 600 ns --> probably standard delta-t { fPositiveDeltaTHist->Fill( timingData.fCount50DeltaT ); } } // closes if( fPreviousEventTime != 0 ) else // previous event time = 0 { detail << "DQTimeProc::Event: " << "unable to calculate delta-t for event " << timingData.fGTID << " - previous event time = 0" << newline; detail << " --> setting delta-t to zero" << newline; timingData.fCount50DeltaT = 0.0; } } // closes if( fFirstEvent ) //Comparing clock 10Mhz clock time to universal time int clockCountDifference = (int) (clockCount10 - this->DateTo10MhzClockTicks(ev.GetUniversalTime())); // Difference of 1 allowed to accomodate rounding errors when converting univ time to 10Mhz time if(clockCountDifference == 0 || clockCountDifference == 1 ){ fUniversalTimeClockCountHist->Fill(clockCountDifference); debug << "Clock count difference is: "<DateTo10MhzClockTicks(ev.GetUniversalTime()) << newline; } else{ f10MhzTimeCheck = false; f10MhzTimeCheckFails++; fUniversalTimeClockCountHist->Fill(clockCountDifference); debug << "Clock count difference is: "<DateTo10MhzClockTicks(ev.GetUniversalTime()) << newline; } // set new values fPreviousEventTime = timingData.fEventTime; fPreviousGTID = timingData.fGTID; fPreviousCount10 = clockCount10; fPreviousCount50 = clockCount50; // append to vector of records fTimingDataRecords.push_back(timingData); return OK; } void DQTimeProc::EndOfRun(DS::Run& run) { // Quick check if( fTimingDataRecords.size() != fEventCount ) { debug << "DQTimeProc::EndOfRun: " << "vector size conflict" << newline; debug << " --> size of vector fTimingDataRecords is " << fTimingDataRecords.size() << " but " << fEventCount << " events were processed" << newline; } // Check 1: Run Header Check if( fFirstEventTime <= fRunHeaderThresh ) // passes check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID()<< " passed run header check" << newline; fCheckResult = true; } else // does not pass check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " failed run header check" << newline; detail << " --> time to first event (" << fFirstEventTime << " ns) < " << fRunHeaderThresh << " ns threshold" << newline; } AddToRATDB( "run_header", fFirstEventTime ); Update( "run_header", fCheckResult ); // Check 3: Clock Forward Check double unidentifiedNegativeDeltaTs = static_cast( fNegativeDeltaTCount ); // Subtract those identified as 10 MHz oscillator resets unidentifiedNegativeDeltaTs -= fCount10Resets; // Subtract those identified as 50 MHz oscillator resets unidentifiedNegativeDeltaTs -= fCount50Resets; // Subtract those identified as events built out of sync unidentifiedNegativeDeltaTs -= fNegativeDeltaGTIDCount; double clockForwardValue = 100.0 * ( 1.0-( unidentifiedNegativeDeltaTs/static_cast( fEventCount ) ) ); if( clockForwardValue >= fClockForwardThresh ) // passes check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " passed clock forward check" << newline; fCheckResult = true; } else // does not pass check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " failed clock forward check" << newline; debug << " --> " << clockForwardValue << " % events " << "had positive (or justified negative) delta-t " << "( < " << fClockForwardThresh << " % threshold )" << newline; } AddToRATDB("10MHz_clock_resets", fCount10Resets); AddToRATDB("50MHz_clock_resets", fCount50Resets); AddToRATDB("negative_delta_GTID_count", fNegativeDeltaGTIDCount); AddToRATDB("unidentified_negative_deltaTs", unidentifiedNegativeDeltaTs); AddToRATDB( "clock_forward_value", clockForwardValue ); Update( "clock_forward", fCheckResult ); // Check 4: Event Separation Check double eventSeparationValue = 100.0 * ( static_cast( fTriggerWindowDeltaTCount ) / static_cast( fEventCount ) ); if( eventSeparationValue <= fEventSeparationThresh ) // passes check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " passed event separation check" << newline; fCheckResult = true; } else // does not pass check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " failed event separation check" << newline; debug << " --> " << eventSeparationValue << " % events " << "had delta-t within 400 ns (+30 ns dead time) trigger window " << "( > " << fEventSeparationThresh << " % threshold )" << newline; } AddToRATDB( "event_separation_value", eventSeparationValue ); Update( "event_separation", fCheckResult ); // Check 5: Retriggers Check double retriggersValue = 100.0 * ( static_cast( fRetriggerDeltaTCount ) / static_cast( fEventCount ) ); if( retriggersValue <= fRetriggersThresh ) // passes check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " passed retriggers check" << newline; fCheckResult = true; } else // does not pass check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " failed retriggers check" << newline; debug << " --> " << retriggersValue << " % events " << "had delta-t suggesting they are retriggered events " << "( > " << fRetriggersThresh << " % threshold )" << newline; } AddToRATDB( "retriggers_value", retriggersValue ); Update( "retriggers", fCheckResult ); // calculate deltaT event rate // NOT USED FOR CHECK, JUST FOR REFERENCE IN RATDB // mean time interval from histogram double meanDeltaT = fPositiveDeltaTHist->GetMean(1); // corrects for number of deltaT = N_Evts - 1 meanDeltaT += 1.0 / ( run.GetRunLength() * 1e9 ); meanDeltaT *= 1e-9; // convert to s double deltaTEventRate = 1.0 / meanDeltaT; // calculate mean event rate // USED FOR CHECK double meanEventRate = fEventCount / run.GetRunLength(); // check agreement with rough estimate double eventRateAgreement = meanEventRate - deltaTEventRate; eventRateAgreement /= deltaTEventRate; eventRateAgreement *= 100.0; // Check 6: Event Rate Check AddToRATDB( "mean_event_rate", meanEventRate ); if( ( meanEventRate >= fMinEventRate ) && ( meanEventRate <= fMaxEventRate ) ) // passes check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " passed event rate check" << newline; fCheckResult = true; } else // does not pass check { detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " failed event rate check" << newline; if( meanEventRate < fMinEventRate ) { debug << " --> events rate is too low" << newline; debug << " --> event rate (" << meanEventRate << " Hz) " << "is below " << fMinEventRate << " Hz minimum" << newline; } else if( meanEventRate > fMaxEventRate ) { debug << " --> events rate is too high" << newline; debug << " --> event rate (" << meanEventRate << " Hz) " << "is above " << fMaxEventRate << " Hz maximum" << newline; } } Update( "event_rate", fCheckResult ); AddToRATDB( "delta_t_event_rate", deltaTEventRate ); AddToRATDB( "event_rate_agreement", eventRateAgreement ); //Check 7: Compare 10Mhz clock with universal time if(f10MhzTimeCheck){ detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " passed comparrisson beween universal time and 10Mhz Clock" << newline; } else{ detail << "DQTimeProc::EndOfRun: " << "run " << GetRunID() << " failed comparrisson beween universal time and 10Mhz Clock" << newline; } Update("10Mhz_UT_comparrison",f10MhzTimeCheck); AddToRATDB("num_UT_10MhzClock_comp_fails",f10MhzTimeCheckFails); if( fOutputImages ) { Plot1DHist( fPositiveDeltaTHist, "#Deltat (ns)", "Events", true ); Plot1DHist( fTrigWindowDeltaTHist, "#Deltat (ns)" ); } WriteToRoot( fPositiveDeltaTHist, "fPositiveDeltaTHist" ); WriteToRoot( fTrigWindowDeltaTHist, "fTrigWindowDeltaTHist" ); WriteToRoot( fNegativeDeltaTHist, "fNegativeDeltaTHist" ); WriteToRoot( fNegativeDeltaGTIDHist, "fNegativeDeltaGTIDHist" ); WriteToRoot( fCount10ResetDeltaTHist, "fCount10ResetDeltaTHist" ); WriteToRoot( fCount50ResetDeltaTHist, "fCount50ResetDeltaTHist" ); WriteToRoot( fUniversalTimeClockCountHist, "fUniversalTimeClockCountHist" ); TCanvas *C1 = new TCanvas("C1"); C1->SetLogx(1); //set log scale string filename = fPositiveDeltaTHist->GetName(); filename = filename+".png"; C1->cd(); fPositiveDeltaTHist->SetXTitle("Time (ns)"); fPositiveDeltaTHist->SetYTitle("Events"); fPositiveDeltaTHist->Draw(); C1->Print( filename.c_str() ); C1->SetLogx(0); //back to linear scale filename = fTrigWindowDeltaTHist->GetName(); filename = filename+".png"; fTrigWindowDeltaTHist->SetXTitle("Time (ns)"); fTrigWindowDeltaTHist->SetYTitle("Events"); fTrigWindowDeltaTHist->Draw(); C1->Print( filename.c_str() ); delete C1; C1 = NULL; delete fPositiveDeltaTHist; fPositiveDeltaTHist = NULL; delete fTrigWindowDeltaTHist; fTrigWindowDeltaTHist = NULL; delete fNegativeDeltaTHist; fNegativeDeltaTHist = NULL; delete fNegativeDeltaGTIDHist; fNegativeDeltaGTIDHist = NULL; delete fCount10ResetDeltaTHist; fCount10ResetDeltaTHist = NULL; delete fCount50ResetDeltaTHist; fCount50ResetDeltaTHist = NULL; delete fUniversalTimeClockCountHist; fUniversalTimeClockCountHist = NULL; DataQualityProc::EndOfRun( run ); } unsigned long int DQTimeProc::DateTo10MhzClockTicks(DS::UniversalTime time){ unsigned long int secondsToClockTicks = 10000000; unsigned long int daysToClockTicks = 24*3600*secondsToClockTicks; double nanoSecondsToClockTicks = 0.01; //For last term casting as int will give lower clock count. unsigned long int clockTicks = (daysToClockTicks*time.GetDays()); clockTicks += (secondsToClockTicks*time.GetSeconds()); debug << "Nano Second clock ticks: "<