#include #include #include using namespace RAT; ReconstructClocks::ReconstructClocks() : Processor("ReconstructClocks"){} void ReconstructClocks::BeginOfRun(DS::Run& run){ correct10MHzClock = 0; correct50MHzClock = 0; eventCount = 0; clockOnline = 1; foundRunStart = 0; // Get run date uint64_t dateTime = run.GetDate(); // Run start time uint64_t startTime = run.GetTime(); // First valid GTID validGTID = run.GetValidGTID(); // Convert the time in the run header to an integer theTime = ConvertTimeToInt(dateTime, startTime); TZERO = 14610*24*3600; // TZero is Jan 1. 2010 UTC currentTime = 0; runStartTime = (theTime - TZERO)*10000000; DBLinkPtr fDBClockReconstruction = DB::Get()->GetLink("CLOCK_RECONSTRUCTION"); // Allow run header to be 5s different than 10MHz clock count timeAllowed = fDBClockReconstruction->GetD("time_allowed"); // From the database get the information about the trigger clock jumps DBLinkPtr fDBTriggerClockJumps = DB::Get()->GetLink("TRIGGER_CLOCK_JUMPS"); fClock10SubRun_bottom31.resize(0); fClock10SubRun_top.resize(0); try{ fGTID50MHz = fDBTriggerClockJumps->GetIArray("gtid_50MHz_jumps"); fDeltaTicks50MHz = fDBTriggerClockJumps->GetDArray("delta_ticks_50MHz"); } catch(DBNotFoundError &e){ detail << "Caught DB Error loading 50MHz clock info." << endl; correct50MHzClock = 1; } try{ fBadGTID50MHz = fDBTriggerClockJumps->GetIArray("gtid_bad_50MHz"); } catch(DBNotFoundError &e){ detail << "Could not find bad 50MHz field" << endl; } try{ fBadGTID10MHz = fDBTriggerClockJumps->GetIArray("gtid_bad_10MHz"); } catch(DBNotFoundError &e){ detail << "Could not find bad 10MHz field" << endl; } try{ fGTID10MHz = fDBTriggerClockJumps->GetIArray("gtid_10MHz_jumps"); fDeltaTicks10MHz = fDBTriggerClockJumps->GetDArray("delta_ticks_10MHz"); } catch(DBNotFoundError &e){ detail << "Caught DB Error loading 10MHz clock info." << endl; correct10MHzClock = 1; } try{ fClock10SubRun_bottom31 = fDBTriggerClockJumps->GetIArray("first_10MHz_ticks_bottom_31_bits"); fClock10SubRun_top = fDBTriggerClockJumps->GetIArray("first_10MHz_ticks_top_bits"); } catch(DBNotFoundError &e){ detail << "Caught DB Error loading first 10 MHz ticks." << endl; } try{ clockOnline = fDBTriggerClockJumps->GetI("clock_working_10MHz"); } catch(DBNotFoundError &e){ detail << "Caught DB Error loading clock working." << endl; } } time_t ReconstructClocks::ConvertTimeToInt(uint64_t dateTime, uint64_t startTime){ // Convert the start and date time in run header information // These conversions come from the way the date and time are // set in the mtc server int year = (dateTime >> 24) + 1852; int month = ((dateTime >> 16) & 0xFF) + 1; int day = (dateTime >> 8) & 0xFF; int isDST = dateTime & 0xFF; int hour = (startTime >> 24); int minute = (startTime >> 16) & 0xFF; int second = (startTime >> 8) & 0xFF; // Convert the time to UTC to compare against the 10 MHz Clock struct tm tms; tms.tm_year = year - 1900; tms.tm_mon = month - 1; tms.tm_mday = day; tms.tm_hour = hour; tms.tm_min = minute; tms.tm_sec = second; // timegm interprets input structure as UTC time_t t = timegm(&tms); // conversion to compare to clock, keep track of daylight savings if(isDST){ t += 4*3600; } else{ t += 5*3600; } return t; } Processor::Result ReconstructClocks::DSEvent(DS::Run& run, DS::Entry& ds){ subRunID = run.GetSubRunID(); // Once we get to the first valid GTID check the 10MHz clock is working. for(size_t iEV = 0; iEV < ds.GetEVCount(); iEV++){ if(ds.GetEV(iEV).GetGTID() == validGTID){ foundRunStart = 1; clockOnline = Check10MHzClock(ds.GetEV(iEV)); } if(foundRunStart || subRunID > 0){ CorrectClock(ds.GetEV(iEV)); } } return OK; } int ReconstructClocks::Check10MHzClock(DS::EV& ev){ clockOnline = 1; currentTime = TZERO + ev.GetClockCount10()/10000000; // If the times are different by more than the allowed time than // assume the 10MHz clock is not working. int64_t dt = (abs(int64_t(currentTime) - int64_t(theTime))); detail << "10MHz clock is " << dt << " seconds different than the SBC time." << endl; if(dt > timeAllowed){ warn << "10MHz clock not within " << timeAllowed << "s of time in run header." << endl; warn << "Using 50MHz clock to correct the 10MHz clock." << endl; clockOnline = 0; } return clockOnline; } void ReconstructClocks::CorrectClock(DS::EV& ev){ // Skip orphans if(ev.GetTrigType() == 0){ return; } // If the 10MHz clock is working, fix the trigger clock jumps if(clockOnline){ // Correct the trigger clock jumps on the 50MHz Clock if(correct50MHzClock == 0){ // Loop over all GTIDs in the clock jumps vector, don't assume they are in order for(size_t i = 0; i < fGTID50MHz.size(); i++){ if(ev.GetGTID() == fGTID50MHz[i]){ detail << "Fixed 50MHz clock for GTID " << fGTID50MHz[i] << endl; uint64_t fixedClock = clock50.back() + uint64_t(fDeltaTicks50MHz[i]); ev.SetClockCount50(fixedClock); } } } // Correct the trigger clock jumps on the 10MHz Clock if(correct10MHzClock == 0){ // Loop over all GTIDs in the clock jumps vector, don't assume they are in order for(size_t i = 0; i < fGTID10MHz.size(); i++){ if(ev.GetGTID() == fGTID10MHz[i]){ detail << "Fixed 10MHz clock for GTID " << fGTID10MHz[i] << endl; uint64_t fixedClock = clock10.back() + uint64_t(fDeltaTicks10MHz[i]); ev.SetClockCount10(fixedClock); } } } } // If the 10MHz clock is not working, reconstruct it from the 50MHz clock else{ // After the first event, use the 50MHz clock if(eventCount > 0){ int clockSkipped = 0; // We've already found all the 50MHz clock jumps, so use that information for(size_t i = 0; i < fGTID50MHz.size(); i++){ // If the 50MHz clock skipped, set both clock to their previous values if(ev.GetGTID() == fGTID50MHz[i]){ ev.SetClockCount10(clock10.back()); ev.SetClockCount50(clock50.back()); clockSkipped = 1; } } // We've found events where both clocks had bad clock ticks for(size_t i = 0; i < fBadGTID50MHz.size(); i++){ // Don't fix these events either if(ev.GetGTID() == fBadGTID50MHz[i]){ ev.SetClockCount10(clock10.back()); ev.SetClockCount50(clock50.back()); clockSkipped = 1; } } // Another check that we aren't incorrectly correcting the 10MHz clock if(((int64_t(ev.GetClockCount50()) - int64_t(clock50.back())) & 0x7FFFFFFFFFF) < 0){ ev.SetClockCount10(clock10.back()); ev.SetClockCount50(clock50.back()); clockSkipped = 1; } // Another check that we aren't incorrectly correcting the 10MHz clock else if((((int64_t(ev.GetClockCount50()) - int64_t(clock50.back())) & 0x7FFFFFFFFFF)*20.0/1e9) > 10.0){ ev.SetClockCount10(clock10.back()); ev.SetClockCount50(clock50.back()); clockSkipped = 1; } // If the 50MHz clock did not skip, correct the 10MHz clock if(!clockSkipped){ // Handle 43-bit rollover on 50MHz clock uint64_t deltaTicks50 = (ev.GetClockCount50() - clock50.back()) & 0x7FFFFFFFFFF; uint64_t fixedClock = clock10.back() + deltaTicks50/5; ev.SetClockCount10(fixedClock); } } // For the first event use the run header information to correct the clock // This relies on the fact that the input zdab files come in order and start // with the first one else if(eventCount == 0 && subRunID == 0){ detail << "Using the SBC Clock to correct the 10 MHz clock for the first event." << endl; ev.SetClockCount10(uint64_t((theTime - TZERO)*10000000)); } else{ if(fClock10SubRun_bottom31.size() > 0){ warn << "Using the SBC Clock and the 50 MHz clock to correct the 10 MHz clock for the first event." << endl; uint64_t fClock10SubRun = fClock10SubRun_bottom31[subRunID] + (uint64_t(fClock10SubRun_top[subRunID]) << 31); ev.SetClockCount10(fClock10SubRun); } else{ warn << "Could not correct 10 MHz clock for this run." << endl; } } // set UT from the fixed 10MHz clock uint64_t total = ev.GetClockCount10() * 100; uint64_t ns = total % 1000000000; uint64_t s = total / 1000000000; uint64_t d = s / 86400; s -= (86400 * d); ev.SetUniversalTime(RAT::DS::UniversalTime(d, s, ns)); } // Store the corrected clock information clock50.push_back(ev.GetClockCount50()); clock10.push_back(ev.GetClockCount10()); if(clockOnline){ // If four clock ticks on the 10MHz clock are the same, // the 10MHz clock probably stopped working during the run if(clock10.back() == clock10[clock10.size()-2] && clock10.back() == clock10[clock10.size()-3] && clock10.back() == clock10[clock10.size()-4]){ warn << "Four conescutive 10MHz clock ticks are the same, assuming 10MHz clock stopped working" << endl; clockOnline = 0; } } eventCount++; }