Skip to content

Commit dbfdffd

Browse files
committed
Interface for integrating run-wide timeslots over many runs
1 parent 5ff1826 commit dbfdffd

File tree

5 files changed

+202
-0
lines changed

5 files changed

+202
-0
lines changed

Detectors/Calibration/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ o2_add_library(DetectorsCalibration
3030
o2_target_root_dictionary(DetectorsCalibration
3131
HEADERS include/DetectorsCalibration/TimeSlotCalibration.h
3232
include/DetectorsCalibration/TimeSlot.h
33+
include/DetectorsCalibration/TimeSlotMetaData.h
3334
include/DetectorsCalibration/Utils.h
3435
include/DetectorsCalibration/MeanVertexData.h
3536
include/DetectorsCalibration/MeanVertexCalibrator.h

Detectors/Calibration/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,40 @@ Note that in order to access the absolute time of the slot boundaries, one shoul
7676
7777
See e.g. AliceO2/Detectors/TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h, AliceO2/Detectors/TOF/calibration/testWorkflow/lhc-clockphase-workflow.cxx
7878
79+
## Calibrating over multiple runs
80+
81+
Some statistics-hungry calibrations define single time-slot which integrates data of the whole run. If there is a possibility that for the short run the slot will not accumulate enough statistics,
82+
one can save the user-defined content of the slot to a file in the dedicated partition on the calibrator node
83+
and adopt data from this file in the next run. In order to do that the calibrator class derived from the TimeSlotCalibration must:
84+
85+
* set fixed file name to write via `setSaveFileName(const std::string& n)` method. Also, the corresponding workflow should provide/parse an option to set the output directory.
86+
87+
* implement virtual method `bool saveLastSlotData(TFile& fl)` which writes content of the (last and only) slot into the provided file handler. It is up to detector to define the format of the stored data. The framework will write to the same file a
88+
TimeSlotMetaData struct describing the start/end timestamps and start/end runs for the data written.
89+
90+
* implement virtual method `bool adoptSavedData(const TimeSlotMetaData& metadata, TFile& fl)` which reads and adds saved data to the slot in the new run. Provided metadata should be used to judge if the saved data are useful.
91+
92+
* decide e.g. in the finalizeSlot method if the slot content must be saved to be accounted in the following run and call `saveLastSlot()` in that case.
93+
94+
* in the beginning of the processing, e.g. after the 1st call of the `process(..)` method (where the time-slot will be created) call `loadSavedSlot()` method, i.e.
95+
```
96+
auto data = pc.inputs().get<...>; // get input data
97+
o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mCalibrator->getCurrentTFInfo());
98+
mCalibrator->process(data);
99+
static bool firstCall = true;
100+
if (firstCall && getNSlots()) {
101+
firstCall = false;
102+
loadSavedSlot();
103+
}
104+
```
105+
Make sure the static method `o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mCalibrator->getCurrentTFInfo());` was called from the `run()` method before the `process(...)` call.
106+
107+
The slot saving and loading will be done only if `setSavedSlotAllowed(true)` was called explicitly from the calibrator device before the processing starts (e.g. in the `init()` method).
108+
Since one can have multiple instances of the calibrator device
109+
running at the same time (in staging and produnction partitions, synthetic and real runs) it is important to make sure that this method is called only for the physics run calibration.
110+
111+
In order to not pollute calibration node disk, the file will be removed in the end of `loadSavedSlot()` call.
112+
79113
## ccdb-populator-workflow
80114
81115
This is the workflow that, connected to all workflows producting calibrations with different granularities and frequencies, will update the CCDB.
@@ -103,6 +137,7 @@ then the `ObjA` will be uploaded only to the default server (`https://alice-ccdb
103137
`ObjC` will be uploaded to the `local` server only.
104138
105139
By default the ccdb-populator-workflow will not produce `fatal` on failed upload. To require it an option `--fatal-on-failure` can be used.
140+
106141
<!-- doxy
107142
* \subpage refDetectorsCalibrationtestMacros
108143
/doxy -->

Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@
1515
/// @brief Processor for the multiple time slots calibration
1616

1717
#include "DetectorsCalibration/TimeSlot.h"
18+
#include "DetectorsCalibration/TimeSlotMetaData.h"
1819
#include "DetectorsBase/TFIDInfoHelper.h"
1920
#include "DetectorsBase/GRPGeomHelper.h"
2021
#include "CommonDataFormat/TFIDInfo.h"
22+
#include <TFile.h>
23+
#include <filesystem>
2124
#include <deque>
2225
#include <gsl/gsl>
2326
#include <limits>
2427
#include <type_traits>
28+
#include <unistd.h>
2529

2630
namespace o2
2731
{
@@ -149,6 +153,32 @@ class TimeSlotCalibration
149153
static constexpr bool value = type::value;
150154
};
151155

156+
// methods for saving/reading data in the of the run in case of insufficient statistics
157+
bool getSavedSlotAllowed() const { return mSavedSlotAllowed; }
158+
void setSavedSlotAllowed(bool v) { mSavedSlotAllowed = v; }
159+
std::string getSaveFilePath() const;
160+
const std::string& getSaveFileName() const { return mSaveFileName; }
161+
void setSaveFileName(const std::string& n) { mSaveFileName = n; }
162+
void setSaveDirectory(const std::string& n) { mSaveDirectory = n; }
163+
virtual bool updateSaveMetaData();
164+
165+
// derived class using slot saving functionality must implement this method to write the
166+
// content of the slot, returning true on success
167+
virtual bool saveLastSlotData(TFile& fl)
168+
{
169+
LOG(fatal) << "This method must be implemented by derived class to write content of the slot to save";
170+
return false;
171+
}
172+
// derived class using slot saving functionality must implement this method to adopt the content of the
173+
// saved slot, returning true on success. Provided metadata should be used to judge if the saved data is useful.
174+
virtual bool adoptSavedData(const TimeSlotMetaData& metadata, TFile& fl)
175+
{
176+
LOG(fatal) << "This method must be implemented by derived class to adopt content of the saved slot";
177+
return false;
178+
}
179+
virtual bool loadSavedSlot();
180+
virtual bool saveLastSlot();
181+
152182
protected:
153183
auto& getSlots() { return mSlots; }
154184
uint32_t getRunStartOrbit() const
@@ -186,6 +216,12 @@ class TimeSlotCalibration
186216
bool mWasCheckedInfiniteSlot = false; // flag to know whether the statistics of the infinite slot was already checked
187217
bool mUpdateAtTheEndOfRunOnly = false;
188218
bool mFinalizeWhenReady = false; // if true: single bin is filled until ready, then closed and new one is added
219+
220+
std::string mSaveDirectory = ""; // directory where the file is saved
221+
std::string mSaveFileName = ""; // filename for data saves in the end of the run
222+
TimeSlotMetaData mSaveMetaData{};
223+
bool mSavedSlotAllowed = false;
224+
189225
ClassDef(TimeSlotCalibration, 1);
190226
};
191227

@@ -396,6 +432,100 @@ void TimeSlotCalibration<Input, Container>::print() const
396432
}
397433
}
398434

435+
//_________________________________________________
436+
template <typename Input, typename Container>
437+
bool TimeSlotCalibration<Input, Container>::updateSaveMetaData()
438+
{
439+
if (mSlots.empty()) {
440+
LOG(warn) << "Nothing to save, no TimeSlots defined";
441+
return false;
442+
}
443+
if (mSaveMetaData.startRun < 0) {
444+
mSaveMetaData.startRun = mCurrentTFInfo.runNumber;
445+
}
446+
mSaveMetaData.endRun = mCurrentTFInfo.runNumber;
447+
if (mSaveMetaData.startTime < 0) {
448+
mSaveMetaData.startTime = mSlots.back().getStartTimeMS();
449+
}
450+
mSaveMetaData.endTime = mSlots.back().getEndTimeMS();
451+
return true;
452+
}
453+
454+
//_________________________________________________
455+
template <typename Input, typename Container>
456+
bool TimeSlotCalibration<Input, Container>::saveLastSlot()
457+
{
458+
if (!getSavedSlotAllowed()) {
459+
LOG(info) << "Slot saving is disabled";
460+
return false;
461+
}
462+
if (!updateSaveMetaData()) {
463+
return false;
464+
}
465+
auto pth = getSaveFilePath();
466+
auto pthTmp = pth + ".part";
467+
TFile flout(pthTmp.c_str(), "recreate");
468+
if (flout.IsZombie()) {
469+
LOGP(error, "failed to open save file {}", pth);
470+
unlink(pthTmp.c_str());
471+
return false;
472+
}
473+
if (!saveLastSlotData(flout)) { // call used method to store data
474+
flout.Close();
475+
unlink(pthTmp.c_str());
476+
return false;
477+
}
478+
flout.WriteObjectAny(&mSaveMetaData, "o2::calibration::TimeSlotMetaData", "metadata");
479+
flout.Close();
480+
std::filesystem::rename(pthTmp, pth);
481+
LOGP(info, "Saved data of the last slot to {}", pth);
482+
return true;
483+
}
484+
485+
//_________________________________________________
486+
template <typename Input, typename Container>
487+
bool TimeSlotCalibration<Input, Container>::loadSavedSlot()
488+
{
489+
if (!getSavedSlotAllowed()) {
490+
LOG(info) << "Saved slot usage is disabled";
491+
return false;
492+
}
493+
auto pth = getSaveFilePath();
494+
if (!std::filesystem::exists(pth)) {
495+
LOGP(info, "No save file {} is found", pth);
496+
return false;
497+
}
498+
TFile flin(pth.c_str());
499+
if (flin.IsZombie()) {
500+
LOGP(error, "failed to open save file {}", pth);
501+
return false;
502+
}
503+
auto meta = (o2::calibration::TimeSlotMetaData*)flin.GetObjectChecked("metadata", "o2::calibration::TimeSlotMetaData");
504+
if (!meta) {
505+
LOGP(error, "Failed to read metadata from {}", pth);
506+
return false;
507+
}
508+
auto res = adoptSavedData(*meta, flin); // up to the detector to decide if data should be accepted
509+
if (res) {
510+
mSaveMetaData.startRun = meta->startRun;
511+
mSaveMetaData.startTime = meta->startTime;
512+
updateSaveMetaData();
513+
}
514+
flin.Close();
515+
unlink(pth.c_str()); // cleanup used file
516+
return true;
517+
}
518+
519+
//_________________________________________________
520+
template <typename Input, typename Container>
521+
std::string TimeSlotCalibration<Input, Container>::getSaveFilePath() const
522+
{
523+
if (mSaveFileName.empty()) {
524+
LOGP(fatal, "Save file name was not set");
525+
}
526+
return fmt::format("{}{}{}", mSaveDirectory, ((!mSaveDirectory.empty() && mSaveDirectory.back() != '/') ? "/" : ""), mSaveFileName);
527+
}
528+
399529
} // namespace calibration
400530
} // namespace o2
401531

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
#ifndef DETECTOR_CALIB_TIMESLOTMETADATA_H_
13+
#define DETECTOR_CALIB_TIMESLOTMETADATA_H_
14+
15+
/// @brief meta-data for the saved content of the timeslot
16+
17+
namespace o2
18+
{
19+
namespace calibration
20+
{
21+
struct TimeSlotMetaData {
22+
using TFType = uint32_t;
23+
24+
int startRun = -1;
25+
int endRun = -1;
26+
long startTime = -1;
27+
long endTime = -1;
28+
29+
ClassDefNV(TimeSlotMetaData, 1);
30+
};
31+
32+
} // namespace calibration
33+
} // namespace o2
34+
35+
#endif

Detectors/Calibration/src/DetectorsCalibrationLinkDef.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#pragma link off all functions;
1717

1818
#pragma link C++ class o2::calibration::MeanVertexData + ;
19+
#pragma link C++ class o2::calibration::TimeSlotMetaData + ;
1920
#pragma link C++ class o2::calibration::TimeSlot < o2::calibration::MeanVertexData> + ;
2021
#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::dataformats::PrimaryVertex, o2::calibration::MeanVertexData> + ;
2122
#pragma link C++ class o2::calibration::MeanVertexCalibrator + ;

0 commit comments

Comments
 (0)