#include #include #include using namespace RAT; TriggerClockJumpProc::TriggerClockJumpProc() : Processor("TriggerClockJumpProc"){} void TriggerClockJumpProc::BeginOfRun(DS::Run& run){ validGTID = run.GetValidGTID(); clockOnline = 1; firstClock10.resize(100); // Bigger than you'd ever need fReconstructClocks.BeginOfRun(run); gtidSync = -100; // Initialize to random harmless value } Processor::Result TriggerClockJumpProc::DSEvent(DS::Run& run, DS::Entry& ds){ subRunID = run.GetSubRunID(); for(size_t iEV = 0; iEV < ds.GetEVCount(); iEV++){ if(ds.GetEV(iEV).GetGTID() == validGTID){ clockOnline = fReconstructClocks.Check10MHzClock(ds.GetEV(iEV)); } CorrectClock(ds.GetEV(iEV)); if(!clockOnline){ fReconstructClocks.CorrectClock(ds.GetEV(iEV)); if(firstClock10[subRunID] == 0){ firstClock10[subRunID] = ds.GetEV(iEV).GetClockCount10(); } } } return OK; } void TriggerClockJumpProc::CorrectClock(DS::EV& ev){ uint64_t clock_count_50 = ev.GetClockCount50(); uint64_t clock_count_10 = ev.GetClockCount10(); int gtid = ev.GetGTID(); // First check clock information is valid ... these are orphans if(ev.GetTrigType() == 0){ return; } // Keeps track of the clock counts for each clock // for the last three events clock50.push_back(clock_count_50); clock10.push_back(clock_count_10); // GPS Sync for 10MHz clock, don't correct clock jumps // on the SYNC or the event after the SYNC if(ev.GetTrigType() & (1 << DU::TrigBits::Sync)){ gtidSync = gtid; return; } if(gtid == gtidSync + 1){ return; } /* Algorithm for identifying clock jumps in either the 10 or 50 MHz Clock: - Keep track of the previous three clock ticks, including the current one. - Take the clock count from the last event and compare it to the current clock count and the clock count from the event prior - If the clock count is less than both AND the clock count of the current event is larger than the one from two events ago, the trigger clock skipped backward in the previous event. - If the clock count is greater than both AND the clock count of the current event is larger than the one from two events ago, the trigger clock skipped foward in the previous event. - These additional complications still don't deal with situations such as: Event | Clock Ticks ------------------- 0 | 5 1 | 10 2 | 50 < ----- Did the clock skip foward here? 3 | 30 < ----- Or backward here? 4 | 85 5 | 100 - In this situation, first attempt to fix the jump foward, and if the 10MHz clock correction puts everything in a sensible order, leave it that way. Otherwise, fixing the clock jump backwards. - Always check the clocks get put in a reasonable order with the fix. */ // Wait for 3 clock counts for this run if(clock50.size() > 2 && clock10.size() > 2){ // Correct the 50MHz clock if its jumped backward if(clock50[1] < clock50[2] && clock50[1] < clock50[0] && clock50[2] > clock50[0]){ Fix50MHzClock(clock10, clock50, gtid); } // Correct the 50MHz clock if its jumped forward else if(clock50[1] > clock50[2] && clock50[1] > clock50[0] && clock50[2] > clock50[0]){ Fix50MHzClock(clock10, clock50, gtid); } // Correct the 10MHz clock if it jumped backward if(clock10[1] < clock10[2] && clock10[1] < clock10[0] && clock10[2] > clock10[0]){ Fix10MHzClock(clock10, clock50, gtid); } // Correct the 10MHz clock if its jumped forward else if(clock10[1] > clock10[2] && clock10[1] > clock10[0] && clock10[2] > clock10[0]){ Fix10MHzClock(clock10, clock50, gtid); } // Erase the oldest entry so that we keep // both these vectors at size 3 clock10.erase(clock10.begin()); clock50.erase(clock50.begin()); } } void TriggerClockJumpProc::Fix50MHzClock(std::vector clock_10, std::vector clock_50, int gtid){ // Use to 10MHz clock to correct the 50MHz clock uint64_t diff10 = clock_10[1] - clock_10[0]; // Check if the correction is sensible if(clock_50[0] + diff10*5 > clock_50[2] || clock_50[0] + diff10*5 < clock_50[0]){ detail << "Attempted to correct 50 MHz clock for GTID: " << gtid - 1 << " but put clock ticks in wrong order." << endl; gtidBadClock50.push_back(gtid - 1); } // Fix the 50MHz clock for the previous event else{ double deltaJump50 = double(clock_50[1]) - double(clock_50[0]); jump50.push_back(deltaJump50); double deltaTicks50 = diff10*5; gtidClock50.push_back(gtid - 1); delta50.push_back(deltaTicks50); } } void TriggerClockJumpProc::Fix10MHzClock(std::vector clock_10, std::vector clock_50, int gtid){ // Use to 50MHz clock to correct the 10MHz clock uint64_t diff50 = (clock_50[1] - clock_50[0]) & 0x7FFFFFFFFFF; // Deal with 43 bit rollover // Check if the correction is sensible if(clock_10[0] + diff50/5 > clock_10[2] || clock_10[0] + diff50/5 < clock_10[0]){ detail << "Attempted to correct 10 MHz clock for GTID: " << gtid - 1 << " but put clock ticks in wrong order." << endl; gtidBadClock10.push_back(gtid - 1); } // Fix the 10MHz clock for the previous event else{ double deltaJump10 = double(clock_10[1]) - double(clock_10[0]); jump10.push_back(deltaJump10); double deltaTicks10 = diff50/5; gtidClock10.push_back(gtid - 1); delta10.push_back(deltaTicks10); } } // Write trigger clock jump information to ratdb file void TriggerClockJumpProc::EndOfRun(DS::Run& run){ firstClock10.resize(subRunID+1); RAT::DBTable TCTable("TRIGGER_CLOCK_JUMPS"); TCTable.SetIndex(""); TCTable.SetI("version", 4); TCTable.SetPassNumber(-1); TCTable.SetRunRange(run.GetRunID(), run.GetRunID()); // Put dummy values in so arrays pushed to ratdb aren't empty // Makes sure all tables have the same fields if(gtidBadClock10.size() == 0){ gtidBadClock10.push_back(-1); } if(gtidBadClock50.size() == 0){ gtidBadClock50.push_back(-1); } if(gtidClock50.size() == 0){ gtidClock50.push_back(-1); delta50.push_back(-1); jump50.push_back(-1); } if(gtidClock10.size() == 0){ gtidClock10.push_back(-1); delta10.push_back(-1); jump10.push_back(-1); } // Correct the 50 MHz clock jumps TCTable.SetIArray("gtid_50MHz_jumps", gtidClock50); TCTable.SetDArray("delta_ticks_50MHz", delta50); TCTable.SetDArray("jump_50MHz", jump50); TCTable.SetIArray("gtid_bad_50MHz", gtidBadClock50); // Correct the 10 MHz clock jumps TCTable.SetIArray("gtid_10MHz_jumps", gtidClock10); TCTable.SetDArray("delta_ticks_10MHz", delta10); TCTable.SetDArray("jump_10MHz", jump10); TCTable.SetIArray("gtid_bad_10MHz", gtidBadClock10); // Whether the 10 MHz clock was working TCTable.SetI("clock_working_10MHz", clockOnline); std::vector firstClock10_bottom31; std::vector firstClock10_top; for(size_t i = 0; i < firstClock10.size(); i++){ firstClock10_bottom31.push_back((firstClock10[i] & 0x7FFFFFFF)); firstClock10_top.push_back((firstClock10[i] >> 31)); } // The first 10 MHz clock tick for each sub-file TCTable.SetIArray("first_10MHz_ticks_bottom_31_bits", firstClock10_bottom31); TCTable.SetIArray("first_10MHz_ticks_top_bits", firstClock10_top); TCTable.SaveAs("TriggerClockJumps.ratdb"); // Clear all vectors clock50.clear(); clock10.clear(); gtidClock10.clear(); gtidClock50.clear(); delta10.clear(); delta50.clear(); jump50.clear(); jump10.clear(); gtidBadClock10.clear(); gtidBadClock50.clear(); }