12#ifndef DETECTOR_CALIB_TIMESLOTCALIB_H_
13#define DETECTOR_CALIB_TIMESLOTCALIB_H_
34class ProcessingContext;
39template <
typename Container>
98 LOGP(info,
"Start offset is not supported in the INFINITE_TF slot length or UpdateAtTheEndOfRunOnly or FinalizeWhenReady modes");
104 }
else if (
f > 0.95) {
110 LOGP(info,
"Imposing offset of {:4.2} x nominal slot length",
mStartOffsetFrac);
130 template <
typename... DATA>
167 template <
typename,
typename T>
170 std::integral_constant<T, false>::value,
171 "Second template parameter needs to be of function type.");
176 template <
typename C,
typename Ret,
typename... Args>
179 template <
typename T>
180 static constexpr auto check(T*)
181 ->
typename std::is_same<decltype(std::declval<T>().fill(std::declval<Args>()...)), Ret>
::type;
183 static constexpr std::false_type
check(...);
184 typedef decltype(check<C>(
nullptr)) type;
187 static constexpr bool value = type::value;
203 LOG(fatal) <<
"This method must be implemented by derived class to write content of the slot to save";
210 LOG(fatal) <<
"This method must be implemented by derived class to adopt content of the saved slot";
224 static bool suppressRunStartWarning =
false;
225 if (!suppressRunStartWarning) {
229 suppressRunStartWarning =
true;
232 suppressRunStartWarning =
true;
241 return uint32_t(orb);
280template <
typename Container>
281template <
typename... DATA>
284 if (mCurrentTFInfo.discard) {
285 LOGP(warn,
"Ignoring TF with discard flag on: Orbit {}, TFcounter {}, Run:{}, StartTime:{} CreationTime {}, ",
286 mCurrentTFInfo.firstTForbit,
287 mCurrentTFInfo.tfCounter,
288 mCurrentTFInfo.runNumber,
289 mCurrentTFInfo.startTime,
290 mCurrentTFInfo.creation);
293 static bool firstCall =
true;
300 TFType tf = mCurrentTFInfo.tfCounter;
301 uint64_t maxDelay64 = uint64_t(mSlotLength * mMaxSlotsDelay);
303 if (!mUpdateAtTheEndOfRunOnly) {
304 if (
tf < mLastClosedTF || (!mSlots.empty() && getLastSlot().getTFStart() >
tf + maxDelay64)) {
308 LOG(info) <<
"Ignoring TF " <<
tf <<
", mLastClosedTF = " << mLastClosedTF;
312 auto& slotTF = getSlotForTF(
tf);
313 using Cont_t =
typename std::remove_pointer<
decltype(slotTF.getContainer())>
::type;
315 slotTF.getContainer()->fill(mCurrentTFInfo,
data...);
317 slotTF.getContainer()->fill(
data...);
319 if (
tf > mMaxSeenTF) {
322 if (!mUpdateAtTheEndOfRunOnly) {
324 checkSlotsToFinalize(
tf, maxDelay);
331template <
typename Container>
337 if (mSlots.size() == 1 && mFinalizeWhenReady) {
338 TFType checkInterval = mCheckIntervalInfiniteSlot + mLastCheckedTFInfiniteSlot;
339 if (mWasCheckedInfiniteSlot) {
340 checkInterval = mCheckDeltaIntervalInfiniteSlot + mLastCheckedTFInfiniteSlot;
343 LOG(
debug) <<
"mMaxSeenTF = " << mMaxSeenTF <<
", mLastCheckedTFInfiniteSlot = " << mLastCheckedTFInfiniteSlot <<
", checkInterval = " << checkInterval <<
", mSlots[0].getTFStart() = " << mSlots[0].getTFStart();
345 LOG(info) <<
"End of run reached, trying to calibrate what we have, if we have enough statistics";
347 LOG(info) <<
"Calibrating as soon as we have enough statistics:";
348 LOG(info) <<
"Update interval passed (" << checkInterval <<
"), checking slot for " << mSlots[0].getTFStart() <<
" <= TF <= " <<
INFINITE_TF;
350 mLastCheckedTFInfiniteSlot =
tf;
351 if (hasEnoughData(mSlots[0])) {
352 mWasCheckedInfiniteSlot =
false;
353 mSlots[0].setTFStart(mLastClosedTF);
354 mSlots[0].setTFEnd(mMaxSeenTF);
355 LOG(info) <<
"Finalizing slot for " << mSlots[0].getTFStart() <<
" <= TF <= " << mSlots[0].getTFEnd();
356 finalizeSlot(mSlots[0]);
357 mLastClosedTF = mSlots[0].getTFEnd() <
INFINITE_TF ? (mSlots[0].getTFEnd() + 1) : mSlots[0].getTFEnd() <
INFINITE_TF;
358 mSlots.erase(mSlots.begin());
361 LOG(info) <<
"Creating new slot for " << mLastClosedTF <<
" <= TF <= " <<
INFINITE_TF;
362 auto& sl = emplaceNewSlot(
true, mLastClosedTF,
INFINITE_TF);
363 sl.setRunStartOrbit(getRunStartOrbit());
366 LOG(info) <<
"Not enough data to calibrate";
367 mWasCheckedInfiniteSlot =
true;
370 LOG(
debug) <<
"Not trying to calibrate: either not at EoS, or update interval not passed";
374 for (
auto slot = mSlots.begin(); slot != mSlots.end();) {
375 uint64_t lim64 = uint64_t(maxDelay) + slot->getTFEnd();
378 if (hasEnoughData(*slot)) {
379 LOG(
debug) <<
"Finalizing slot for " << slot->getTFStart() <<
" <= TF <= " << slot->getTFEnd();
381 }
else if ((slot + 1) != mSlots.end()) {
382 LOG(info) <<
"Merging underpopulated slot " << slot->getTFStart() <<
" <= TF <= " << slot->getTFEnd()
383 <<
" to slot " << (slot + 1)->getTFStart() <<
" <= TF <= " << (slot + 1)->getTFEnd();
384 (slot + 1)->mergeToPrevious(*slot);
386 LOG(info) <<
"Discard underpopulated slot " << slot->getTFStart() <<
" <= TF <= " << slot->getTFEnd();
389 mLastClosedTF = slot->getTFEnd() + 1;
390 LOG(info) <<
"closing slot " << slot->getTFStart() <<
" <= TF <= " << slot->getTFEnd();
391 slot = mSlots.erase(slot);
400template <
typename Container>
404 if (mSlots.empty()) {
405 LOG(warning) <<
"There are no slots defined";
408 finalizeSlot(mSlots.front());
409 mLastClosedTF = mSlots.front().getTFEnd() + 1;
410 mSlots.erase(mSlots.begin());
414template <
typename Container>
419 throw std::runtime_error(
"invalid TF");
421 if (mUpdateAtTheEndOfRunOnly) {
425 tft = int64_t(((
tf - mFirstTF + mStartOffsetTFs) / mSlotLength) * mSlotLength) + mFirstTF;
426 if (tft > mStartOffsetTFs) {
427 tft -= mStartOffsetTFs;
435template <
typename Container>
440 if (mUpdateAtTheEndOfRunOnly) {
441 if (!mSlots.empty() && mSlots.back().getTFEnd() <
tf) {
443 }
else if (mSlots.empty()) {
444 auto& sl = emplaceNewSlot(
true, mFirstTF,
tf);
445 sl.setRunStartOrbit(getRunStartOrbit());
446 sl.setStaticStartTimeMS(sl.getStartTimeMS());
448 return mSlots.back();
451 if (!mSlots.empty() && mSlots.front().getTFStart() >
tf) {
452 auto tfmn = tf2SlotMin(mSlots.front().getTFStart() - 1);
453 auto tftgt = tf2SlotMin(
tf);
454 while (tfmn >= tftgt) {
455 uint64_t tft = mSlots.front().getTFStart() - 1;
457 LOG(info) <<
"Adding new slot for " << tfmn <<
" <= TF <= " << tfmx;
458 auto& sl = emplaceNewSlot(
true, tfmn, tfmx);
459 sl.setRunStartOrbit(getRunStartOrbit());
460 sl.setStaticStartTimeMS(sl.getStartTimeMS());
464 tfmn = tf2SlotMin(mSlots.front().getTFStart() - 1);
468 for (
auto it = mSlots.begin(); it != mSlots.end(); it++) {
469 auto rel = (*it).relateToTF(
tf);
475 auto tfmn = mSlots.empty() ? tf2SlotMin(
tf) : tf2SlotMin(mSlots.back().getTFEnd() + 1);
477 uint64_t tft = uint64_t(tfmn) + mSlotLength - 1;
478 if (mSlots.empty() && mStartOffsetTFs &&
tf < mStartOffsetTFs) {
479 tft -= mStartOffsetTFs;
482 LOG(info) <<
"Adding new slot for " << tfmn <<
" <= TF <= " << tfmx;
483 auto& sl = emplaceNewSlot(
false, tfmn, tfmx);
484 sl.setRunStartOrbit(getRunStartOrbit());
485 sl.setStaticStartTimeMS(sl.getStartTimeMS());
487 }
while (
tf > mSlots.back().getTFEnd());
489 return mSlots.back();
493template <
typename Container>
496 for (
int i = 0;
i < getNSlots();
i++) {
497 LOG(info) <<
"Slot #" <<
i + 1 <<
" of " << getNSlots();
503template <
typename Container>
506 if (mSlots.empty()) {
507 LOG(warn) <<
"Nothing to save, no TimeSlots defined";
510 if (mSaveMetaData.startRun < 0) {
511 mSaveMetaData.startRun = mCurrentTFInfo.runNumber;
513 mSaveMetaData.endRun = mCurrentTFInfo.runNumber;
514 if (mSaveMetaData.startTime < 0) {
515 mSaveMetaData.startTime = mSlots.back().getStartTimeMS();
517 mSaveMetaData.endTime = mSlots.back().getEndTimeMS();
522template <
typename Container>
525 if (!getSavedSlotAllowed()) {
526 LOG(info) <<
"Slot saving is disabled";
529 if (!updateSaveMetaData()) {
533 if (!mSaveDirectory.empty() && !std::filesystem::exists(mSaveDirectory)) {
534 std::filesystem::create_directories(mSaveDirectory);
535 if (!std::filesystem::exists(mSaveDirectory)) {
536 LOGP(fatal,
"could not create output directory {}", mSaveDirectory);
538 LOGP(info,
"created calibration directory {}", mSaveDirectory);
542 auto pth = getSaveFilePath();
543 auto pthTmp = pth +
".part";
544 TFile flout(pthTmp.c_str(),
"recreate");
545 if (flout.IsZombie()) {
546 LOGP(error,
"failed to open save file {}", pth);
547 unlink(pthTmp.c_str());
550 if (!saveLastSlotData(flout)) {
552 unlink(pthTmp.c_str());
555 flout.WriteObjectAny(&mSaveMetaData,
"o2::calibration::TimeSlotMetaData",
"metadata");
557 std::filesystem::rename(pthTmp, pth);
558 LOGP(info,
"Saved data of the last slot to {}", pth);
563template <
typename Container>
566 if (!getSavedSlotAllowed()) {
567 LOG(info) <<
"Saved slot usage is disabled";
570 auto pth = getSaveFilePath();
571 if (!std::filesystem::exists(pth)) {
572 LOGP(info,
"No save file {} is found", pth);
575 TFile flin(pth.c_str());
576 if (flin.IsZombie()) {
577 LOGP(error,
"failed to open save file {}", pth);
582 LOGP(error,
"Failed to read metadata from {}", pth);
585 auto res = adoptSavedData(*meta, flin);
587 mSaveMetaData.startRun = meta->startRun;
588 mSaveMetaData.startTime = meta->startTime;
589 updateSaveMetaData();
597template <
typename Container>
600 if (mSaveFileName.empty()) {
601 LOGP(fatal,
"Save file name was not set");
603 return fmt::format(
"{}{}{}", mSaveDirectory, ((!mSaveDirectory.empty() && mSaveDirectory.back() !=
'/') ?
"/" :
""), mSaveFileName);
Helper for geometry and GRP related CCDB requests.
static int getNHBFPerTF()
static GRPGeomHelper & instance()
virtual bool adoptSavedData(const TimeSlotMetaData &metadata, TFile &fl)
static constexpr TFType INFINITE_TF
virtual bool saveLastSlotData(TFile &fl)
TFType getCheckDeltaIntervalInfiniteSlot() const
o2::calibration::TFType TFType
virtual void initOutput()=0
float getMaxSlotsDelay() const
TFType mCheckDeltaIntervalInfiniteSlot
void setFirstTF(TFType v)
virtual void checkSlotsToFinalize(TFType tf=INFINITE_TF, int maxDelay=0)
void setSaveFileName(const std::string &n)
TFType getFirstTF() const
ClassDef(TimeSlotCalibration, 1)
TFType mLastCheckedTFInfiniteSlot
const Slot & getLastSlot() const
void setCheckDeltaIntervalInfiniteSlot(TFType v)
std::string mSaveDirectory
virtual bool updateSaveMetaData()
void setStartOffsetFrac(float f)
virtual bool saveLastSlot()
const o2::dataformats::TFIDInfo & getCurrentTFInfo() const
virtual void print() const
Slot & getSlotForTF(TFType tf)
void setSlotLengthInOrbits(int n)
std::deque< Slot > mSlots
bool process(const DATA &... data)
TFType getSlotLength() const
TimeSlotCalibration()=default
o2::dataformats::TFIDInfo & getCurrentTFInfo()
virtual void finalizeOldestSlot()
const Slot & getSlot(int i) const
virtual ~TimeSlotCalibration()=default
virtual void finalizeSlot(Slot &slot)=0
uint32_t getRunStartOrbit() const
void setSaveDirectory(const std::string &n)
void setSavedSlotAllowed(bool v)
void setSlotLengthInSeconds(int s)
void setFinalizeWhenReady()
o2::dataformats::TFIDInfo mCurrentTFInfo
void setSlotLength(TFType v)
virtual bool hasEnoughData(const Slot &slot) const =0
std::string mSaveFileName
void setUpdateAtTheEndOfRunOnly()
const std::string & getSaveFileName() const
const Slot & getFirstSlot() const
TFType getCheckIntervalInfiniteSlot() const
TFType mCheckIntervalInfiniteSlot
TimeSlotMetaData mSaveMetaData
bool getSavedSlotAllowed() const
bool mUpdateAtTheEndOfRunOnly
bool mWasCheckedInfiniteSlot
TFType tf2SlotMin(TFType tf) const
virtual bool loadSavedSlot()
std::string getSaveFilePath() const
virtual Slot & emplaceNewSlot(bool front, TFType tstart, TFType tend)=0
void setCheckIntervalInfiniteSlot(TFType v)
void setMaxSlotsDelay(float v)
GLsizei const GLfloat * value
GLint GLint GLsizei GLint GLenum GLenum type
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
constexpr TFType INFINITE_TF
constexpr double LHCOrbitMUS
void check(const std::vector< std::string > &arguments, const std::vector< ConfigParamSpec > &workflowOptions, const std::vector< DeviceSpec > &deviceSpecs, CheckMatrix &matrix)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::unique_ptr< GPUReconstructionTimeframe > tf
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"