Project
Loading...
Searching...
No Matches
HBFUtilsInitializer.cxx
Go to the documentation of this file.
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// @brief Aux.class initialize HBFUtils
13// @author ruben.shahoyan@cern.ch
14
15#include "Headers/DataHeader.h"
28#include "Framework/Logger.h"
30#include <gsl/span>
31#include <TFile.h>
32#include <TGrid.h>
33
34using namespace o2::raw;
35namespace o2f = o2::framework;
36
41
45std::vector<o2::dataformats::IRFrame> HBFUtilsInitializer::IRFrames = {};
47
48//_________________________________________________________
50{
51 bool upstream = false; // timing info will be provided from upstream readers-driver, just subscribe to it
52 std::string rootFileInput{};
53 std::string hbfuInput{};
54
55 auto updateHBFUtils = [&configcontext, &upstream, &hbfuInput, &rootFileInput]() {
56 static bool done = false;
57 if (!done) {
58 bool helpasked = configcontext.helpOnCommandLine(); // if help is asked, don't take for granted that the ini file is there, don't produce an error if it is not!
59 auto conf = configcontext.options().isSet(HBFConfOpt) ? configcontext.options().get<std::string>(HBFConfOpt) : "";
60 if (!conf.empty()) {
61 int nopts = 0;
62 auto vopts = o2::utils::Str::tokenize(conf, ',');
63 for (const auto& optStr : vopts) {
64 if (optStr == UpstreamOpt) {
65 upstream = true;
66 continue;
67 }
68 HBFOpt opt = getOptType(optStr, !helpasked); // do not throw on unknown opt if help-opt was given
69 nopts++;
70 if ((opt == HBFOpt::INI || opt == HBFOpt::JSON) && !helpasked) {
71 o2::conf::ConfigurableParam::updateFromFile(optStr, "HBFUtils", true); // update only those values which were not touched yet (provenance == kCODE)
72 const auto& hbfu = o2::raw::HBFUtils::Instance();
73 hbfu.checkConsistency();
74 hbfuInput = optStr;
75 } else if (opt == HBFOpt::HBFUTILS) {
76 const auto& hbfu = o2::raw::HBFUtils::Instance();
77 hbfu.checkConsistency();
78 hbfuInput = optStr;
79 } else if (opt == HBFOpt::ROOT) {
80 rootFileInput = optStr;
81 }
82 }
83 if (!nopts && !helpasked) {
84 LOGP(fatal, "No source was provided for timing input of --hbfutils-config");
85 }
86 }
87 done = true;
88 /* RSS
89 if (upstream) {
90 if (rootFileInput.empty()) {
91 throw std::runtime_error(fmt::format("invalid option {}: upstream can be used only with root file providing TFIDInfo or IRFrames", conf));
92 }
93 }
94 */
95 }
96 };
97
98 if (configcontext.options().hasOption("disable-root-input") && configcontext.options().get<bool>("disable-root-input")) {
99 return; // we apply HBFUtilsInitializer only in case of root readers
100 }
101 const auto& hbfu = o2::raw::HBFUtils::Instance();
102 for (auto& spec : wf) {
103 if (spec.inputs.empty()) {
104 updateHBFUtils();
105 if (!upstream || spec.name == ReaderDriverDevice) {
106 if (!hbfuInput.empty()) { // MC timing coming from the HBFUtils configurable
107 o2f::ConfigParamsHelper::addOptionIfMissing(spec.options, o2f::ConfigParamSpec{HBFTFInfoOpt, o2f::VariantType::String, HBFUSrc, {"HBFUtils input"}});
108 if (!rootFileInput.empty() && spec.name == ReaderDriverDevice) { // this is IRFrame file passed to reader driver
109 o2f::ConfigParamsHelper::addOptionIfMissing(spec.options, o2f::ConfigParamSpec{HBFIRFrameOpt, o2f::VariantType::String, rootFileInput, {"root file with selected IR-frames"}});
110 }
111 } else {
112 o2f::ConfigParamsHelper::addOptionIfMissing(spec.options, o2f::ConfigParamSpec{HBFTFInfoOpt, o2f::VariantType::String, rootFileInput, {"root file with per-TF info"}});
113 }
114 o2f::ConfigParamsHelper::addOptionIfMissing(spec.options, o2f::ConfigParamSpec{DelayOpt, o2f::VariantType::Float, 0.f, {"delay in seconds between consecutive TFs sending"}});
115 } else { // subsribe to upstream timing info from readers-driver
116 spec.inputs.emplace_back(o2f::InputSpec{"driverInfo", "GLO", "READER_DRIVER", 0, o2f::Lifetime::Timeframe});
117 if (!hbfuInput.empty() && !rootFileInput.empty()) { // flag that the READER_DRIVER is not dummy but contains IRFrames
118 o2f::ConfigParamsHelper::addOptionIfMissing(spec.options, o2f::ConfigParamSpec{IgnoreIRFramesOpt, o2f::VariantType::Bool, false, {"ignore IR-frames info"}});
119 }
120 }
121 }
122 }
123}
124
125//_________________________________________________________
126HBFUtilsInitializer::HBFOpt HBFUtilsInitializer::getOptType(const std::string& optString, bool throwOnFailure)
127{
128 // return type of the file provided via HBFConfOpt
129 HBFOpt opt = HBFOpt::NONE;
130 if (!optString.empty()) {
131 if (o2::utils::Str::endsWith(optString, ".ini")) {
132 opt = HBFOpt::INI;
133 } else if (o2::utils::Str::endsWith(optString, ".json")) {
134 opt = HBFOpt::JSON;
135 } else if (o2::utils::Str::endsWith(optString, ".root")) {
136 opt = HBFOpt::ROOT;
137 } else if (optString == HBFUSrc) {
138 opt = HBFOpt::HBFUTILS;
139 } else if (optString != "none" && throwOnFailure) {
140 throw std::runtime_error(fmt::format("invalid option {} for {}", optString, HBFConfOpt));
141 }
142 }
143 return opt;
144}
145
146//_________________________________________________________
147std::vector<o2::dataformats::TFIDInfo> HBFUtilsInitializer::readTFIDInfoVector(const std::string& fname)
148{
149 if (o2::utils::Str::beginsWith(fname, "alien://") && !gGrid && !TGrid::Connect("alien://")) {
150 LOGP(fatal, "could not open alien connection to read {}", fname);
151 }
152 std::unique_ptr<TFile> fl(TFile::Open(fname.c_str()));
153 auto vptr = (std::vector<o2::dataformats::TFIDInfo>*)fl->GetObjectChecked("tfidinfo", "std::vector<o2::dataformats::TFIDInfo>");
154 if (!vptr) {
155 throw std::runtime_error(fmt::format("Failed to read tfidinfo vector from {}", fname));
156 }
157 std::vector<o2::dataformats::TFIDInfo> v(*vptr);
158 NTFs = v.size();
159 if (!NTFs) {
160 throw std::runtime_error(fmt::format("tfidinfo vector from {} has 0 size", fname));
161 }
162 return v;
163}
164
165//_________________________________________________________
166void HBFUtilsInitializer::readIRFramesVector(const std::string& fname)
167{
168 if (o2::utils::Str::beginsWith(fname, "alien://") && !gGrid && !TGrid::Connect("alien://")) {
169 LOGP(fatal, "could not open alien connection to read {}", fname);
170 }
171 std::unique_ptr<TFile> fl(TFile::Open(fname.c_str()));
172 auto vptr = (std::vector<o2::dataformats::IRFrame>*)fl->GetObjectChecked("irframes", "std::vector<o2::dataformats::IRFrame>");
173 if (!vptr) {
174 throw std::runtime_error(fmt::format("Failed to read irframes vector from {}", fname));
175 }
176 std::vector<o2::dataformats::IRFrame> v(*vptr);
177 NTFs = vptr->size();
178 LastIRFrameIndex = -1;
179 IRFrames.swap(*vptr);
180}
181
182//_________________________________________________________
183void HBFUtilsInitializer::assignDataHeaderFromTFIDInfo(const std::vector<o2::dataformats::TFIDInfo>& tfinfoVec, o2::header::DataHeader& dh, o2::framework::DataProcessingHeader& dph)
184{
185 const auto tfinf = tfinfoVec[dh.tfCounter % tfinfoVec.size()];
186 LOGP(debug, "Setting DH for {}/{} from tfCounter={} firstTForbit={} runNumber={} to tfCounter={} firstTForbit={} runNumber={}",
187 dh.dataOrigin.as<std::string>(), dh.dataDescription.as<std::string>(), dh.tfCounter, dh.firstTForbit, dh.runNumber, tfinf.tfCounter, tfinf.firstTForbit, tfinf.runNumber);
188 dh.firstTForbit = tfinf.firstTForbit;
189 dh.tfCounter = tfinf.tfCounter;
190 dh.runNumber = tfinf.runNumber;
191 dph.creation = tfinf.creation;
192}
193
194//_________________________________________________________
196{
197 const auto& hbfu = o2::raw::HBFUtils::Instance();
198 auto offset = hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).orbit;
199 dh.firstTForbit = offset + hbfu.nHBFPerTF * dh.tfCounter;
200 dh.tfCounter++; // tfCounter provided by the timer starts from 0, we want it to start from 1.
201 dh.runNumber = hbfu.runNumber;
202 dph.creation = hbfu.startTime + (dh.firstTForbit - hbfu.orbitFirst) * o2::constants::lhc::LHCOrbitMUS * 1.e-3;
203 LOGP(debug, "SETTING DH for {}/{} from tfCounter={} firstTForbit={} runNumber={}",
204 dh.dataOrigin.as<std::string>(), dh.dataDescription.as<std::string>(), dh.tfCounter, dh.firstTForbit, dh.runNumber);
205}
206
207//_________________________________________________________
209{
210 const auto& hbfu = o2::raw::HBFUtils::Instance();
211 static int64_t offset = hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).orbit;
212 dh.runNumber = hbfu.runNumber;
213 dh.firstTForbit = offset + hbfu.nHBFPerTF * dh.tfCounter; // fallback settings
214 dh.tfCounter++; // tfCounter provided by the timer starts from 0, we want it to start from 1.
215
216 IRFrameSel.getMin().clear(); // invalidate
217 if (LastIRFrameSplit) { // previously sent IRFrame has a continuation in the next TF
219 LastIRFrameSplit = false;
220 }
221 o2::InteractionRecord ir0Mn, ir0Mx;
222 while (++LastIRFrameIndex < NTFs) {
224 ir0Mn = hbfu.getFirstIRofTF(IRFrameSel.getMin());
225 ir0Mx = hbfu.getFirstIRofTF(IRFrameSel.getMax());
226 if (ir0Mn.orbit < offset) {
227 if (ir0Mx.orbit < offset) {
228 LOGP(warn, "IRFrame#{} ({}-{}) precedes 1st sampled TF {}, skipping",
232 hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).asString());
234 continue;
235 } else {
236 LOGP(warn, "IRFrame#{} ({}-{}) start precedes 1st sampled TF {}, overriding start", LastIRFrameIndex,
239 hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).asString());
240 ir0Mn = hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled});
241 IRFrameSel.setMin(ir0Mn);
242 }
243 }
244 if (IRFrameSel.getMax().orbit >= ir0Mn.orbit + hbfu.nHBFPerTF) {
245 ir0Mx = ir0Mn + int64_t(hbfu.nHBFPerTF) * o2::constants::lhc::LHCMaxBunches - 1;
246 LOGP(warn, "IRFrame#{} ({}-{}) is split to ({}-{}) and ({}-{})",
249 IRFrameSel.getMin().asString(), ir0Mx.asString(),
250 (ir0Mx + 1).asString(), IRFrameSel.getMax().asString());
251 IRFrameSel.setMax(ir0Mx);
252 IRFrames[LastIRFrameIndex].setMin(ir0Mx + 1);
253 LastIRFrameSplit = true;
254 }
255 break;
256 }
258 LOGP(warn, "Failed to define IRFrame");
259 } else {
260 dh.tfCounter = 1u + (ir0Mn.orbit - offset) / hbfu.nHBFPerTF;
261 dh.firstTForbit = ir0Mn.orbit;
262 if (LastIRFrameIndex == NTFs - 1 && !LastIRFrameSplit) {
264 }
265 }
266 dph.creation = hbfu.startTime + (dh.firstTForbit - hbfu.orbitFirst) * o2::constants::lhc::LHCOrbitMUS * 1.e-3;
267 LOGP(debug, "SETTING DH for {}/{} from tfCounter={} firstTForbit={} runNumber={} and IRFrame ({}-{})",
268 dh.dataOrigin.as<std::string>(), dh.dataDescription.as<std::string>(), dh.tfCounter, dh.firstTForbit, dh.runNumber,
270}
271
272//_________________________________________________________
273void HBFUtilsInitializer::addNewTimeSliceCallback(std::vector<o2::framework::CallbacksPolicy>& policies)
274{
275 policies.push_back(o2::framework::CallbacksPolicy{
276 [](o2::framework::DeviceSpec const& spec, o2::framework::ConfigContext const& context) -> bool {
277 return (!context.helpOnCommandLine() && o2f::ConfigParamsHelper::hasOption(spec.options, HBFTFInfoOpt));
278 },
280 std::string irFrames, tfInput = context.options().get<std::string>(HBFTFInfoOpt);
281 if (context.options().hasOption(HBFIRFrameOpt)) {
282 irFrames = context.options().get<std::string>(HBFIRFrameOpt);
283 }
284 uint32_t delay = context.options().hasOption(DelayOpt) && context.options().isSet(DelayOpt) ? uint32_t(1e6 * context.options().get<float>(DelayOpt)) : 0;
285 if (!tfInput.empty()) {
286 if (tfInput == HBFUSrc) { // simple linear enumeration from already updated HBFUtils
287 if (irFrames.empty()) { // push the whole TF
288 NTFs = 1;
291 static size_t tfcount = 0;
292 if (tfcount++ && delay > 0) {
293 usleep(delay);
294 }
295 });
296 } else { // linear enumeration with IRFrames selection (skimming)
297 if (!o2::utils::Str::pathExists(irFrames)) {
298 throw std::runtime_error(fmt::format("file {} does not exist", irFrames));
299 }
300 readIRFramesVector(irFrames);
304 static size_t tfcount = 0;
305 if (tfcount++ && delay > 0) {
306 usleep(delay);
307 }
308 });
309 }
310 } else if (o2::utils::Str::endsWith(tfInput, ".root")) { // read TFIDinfo from file
311 if (!o2::utils::Str::pathExists(tfInput)) {
312 throw std::runtime_error(fmt::format("file {} does not exist", tfInput));
313 }
316 assignDataHeaderFromTFIDInfo(tfidinfo, dh, dph);
317 static size_t tfcount = 0;
318 if (tfcount++ && delay > 0) {
319 usleep(delay);
320 }
321 });
322 } else { // do not modify timing info
323 // we may remove the highest bit set on the creation time?
324 }
325 }
326 }});
327}
328
329void HBFUtilsInitializer::addConfigOption(std::vector<o2f::ConfigParamSpec>& opts, const std::string& defOpt)
330{
331 o2f::ConfigParamsHelper::addOptionIfMissing(opts, o2f::ConfigParamSpec{HBFConfOpt, o2f::VariantType::String, defOpt, {R"(ConfigurableParam ini file or "hbfutils" for HBFUtils, root file with per-TF info (augmented with ,upstream if reader-driver is used) or "none")"}});
332}
std::ostringstream debug
uint64_t orbit
Definition RawEventData.h:6
unsigned int uint32_t
bool done
static void updateFromFile(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
ConfigParamRegistry & options() const
bool hasOption(const char *key) const
void setMax(T v) GPUnoexcept()
Definition Bracket.h:134
void setMin(T v) GPUnoexcept()
Definition Bracket.h:140
const GLdouble * v
Definition glcorearb.h:832
GLintptr offset
Definition glcorearb.h:660
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< DataProcessorSpec > WorkflowSpec
uint32_t orbit
LHC orbit.
std::string asString() const
void setLast(bool v=true)
Definition IRFrame.h:37
std::vector< ConfigParamSpec > options
Definition DeviceSpec.h:57
the main header struct
Definition DataHeader.h:623
TFCounterType tfCounter
Definition DataHeader.h:684
TForbitType firstTForbit
Definition DataHeader.h:679
DataDescription dataDescription
Definition DataHeader.h:641
RunNumberType runNumber
Definition DataHeader.h:689
T as() const
get the descriptor as std::string
Definition DataHeader.h:304
static std::vector< o2::dataformats::IRFrame > IRFrames
static void assignDataHeaderFromHBFUtilWithIRFrames(o2::header::DataHeader &dh, o2::framework::DataProcessingHeader &dph)
static constexpr char HBFConfOpt[]
static void readIRFramesVector(const std::string &fname)
static constexpr char HBFUSrc[]
static constexpr char DelayOpt[]
static constexpr char UpstreamOpt[]
static void assignDataHeaderFromTFIDInfo(const std::vector< o2::dataformats::TFIDInfo > &tfinfoVec, o2::header::DataHeader &dh, o2::framework::DataProcessingHeader &dph)
HBFUtilsInitializer(const o2::framework::ConfigContext &configcontext, o2::framework::WorkflowSpec &wf)
static HBFOpt getOptType(const std::string &optString, bool throwOnFailure=true)
static constexpr char ReaderDriverDevice[]
static constexpr char HBFIRFrameOpt[]
static void addNewTimeSliceCallback(std::vector< o2::framework::CallbacksPolicy > &policies)
static std::vector< o2::dataformats::TFIDInfo > readTFIDInfoVector(const std::string &fname)
static void assignDataHeaderFromHBFUtils(o2::header::DataHeader &dh, o2::framework::DataProcessingHeader &dph)
static void addConfigOption(std::vector< o2::framework::ConfigParamSpec > &opts, const std::string &defOpt=std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE))
static o2::dataformats::IRFrame IRFrameSel
static constexpr char HBFTFInfoOpt[]
static bool pathExists(const std::string_view p)
static bool beginsWith(const std::string &s, const std::string &start)
static std::vector< std::string > tokenize(const std::string &src, char delim, bool trimToken=true, bool skipEmpty=true)
static bool endsWith(const std::string &s, const std::string &ending)