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 return v;
160}
161
162//_________________________________________________________
163void HBFUtilsInitializer::readIRFramesVector(const std::string& fname)
164{
165 if (o2::utils::Str::beginsWith(fname, "alien://") && !gGrid && !TGrid::Connect("alien://")) {
166 LOGP(fatal, "could not open alien connection to read {}", fname);
167 }
168 std::unique_ptr<TFile> fl(TFile::Open(fname.c_str()));
169 auto vptr = (std::vector<o2::dataformats::IRFrame>*)fl->GetObjectChecked("irframes", "std::vector<o2::dataformats::IRFrame>");
170 if (!vptr) {
171 throw std::runtime_error(fmt::format("Failed to read irframes vector from {}", fname));
172 }
173 std::vector<o2::dataformats::IRFrame> v(*vptr);
174 NTFs = vptr->size();
175 LastIRFrameIndex = -1;
176 IRFrames.swap(*vptr);
177}
178
179//_________________________________________________________
180void HBFUtilsInitializer::assignDataHeaderFromTFIDInfo(const std::vector<o2::dataformats::TFIDInfo>& tfinfoVec, o2::header::DataHeader& dh, o2::framework::DataProcessingHeader& dph)
181{
182 const auto tfinf = tfinfoVec[dh.tfCounter % tfinfoVec.size()];
183 LOGP(debug, "Setting DH for {}/{} from tfCounter={} firstTForbit={} runNumber={} to tfCounter={} firstTForbit={} runNumber={}",
184 dh.dataOrigin.as<std::string>(), dh.dataDescription.as<std::string>(), dh.tfCounter, dh.firstTForbit, dh.runNumber, tfinf.tfCounter, tfinf.firstTForbit, tfinf.runNumber);
185 dh.firstTForbit = tfinf.firstTForbit;
186 dh.tfCounter = tfinf.tfCounter;
187 dh.runNumber = tfinf.runNumber;
188 dph.creation = tfinf.creation;
189}
190
191//_________________________________________________________
193{
194 const auto& hbfu = o2::raw::HBFUtils::Instance();
195 auto offset = hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).orbit;
196 dh.firstTForbit = offset + hbfu.nHBFPerTF * dh.tfCounter;
197 dh.runNumber = hbfu.runNumber;
198 dph.creation = hbfu.startTime + (dh.firstTForbit - hbfu.orbitFirst) * o2::constants::lhc::LHCOrbitMUS * 1.e-3;
199 LOGP(debug, "SETTING DH for {}/{} from tfCounter={} firstTForbit={} runNumber={}",
200 dh.dataOrigin.as<std::string>(), dh.dataDescription.as<std::string>(), dh.tfCounter, dh.firstTForbit, dh.runNumber);
201}
202
203//_________________________________________________________
205{
206 const auto& hbfu = o2::raw::HBFUtils::Instance();
207 static int64_t offset = hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).orbit;
208 dh.runNumber = hbfu.runNumber;
209 dh.firstTForbit = offset + hbfu.nHBFPerTF * dh.tfCounter; // fallback settings
210 IRFrameSel.getMin().clear(); // invalidate
211 if (LastIRFrameSplit) { // previously sent IRFrame has a continuation in the next TF
213 LastIRFrameSplit = false;
214 }
215 o2::InteractionRecord ir0Mn, ir0Mx;
216 while (++LastIRFrameIndex < NTFs) {
218 ir0Mn = hbfu.getFirstIRofTF(IRFrameSel.getMin());
219 ir0Mx = hbfu.getFirstIRofTF(IRFrameSel.getMax());
220 if (ir0Mn.orbit < offset) {
221 if (ir0Mx.orbit < offset) {
222 LOGP(warn, "IRFrame#{} ({}-{}) precedes 1st sampled TF {}, skipping",
226 hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).asString());
228 continue;
229 } else {
230 LOGP(warn, "IRFrame#{} ({}-{}) start precedes 1st sampled TF {}, overriding start", LastIRFrameIndex,
233 hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).asString());
234 ir0Mn = hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled});
235 IRFrameSel.setMin(ir0Mn);
236 }
237 }
238 if (IRFrameSel.getMax().orbit >= ir0Mn.orbit + hbfu.nHBFPerTF) {
239 ir0Mx = ir0Mn + int64_t(hbfu.nHBFPerTF) * o2::constants::lhc::LHCMaxBunches - 1;
240 LOGP(warn, "IRFrame#{} ({}-{}) is split to ({}-{}) and ({}-{})",
243 IRFrameSel.getMin().asString(), ir0Mx.asString(),
244 (ir0Mx + 1).asString(), IRFrameSel.getMax().asString());
245 IRFrameSel.setMax(ir0Mx);
246 IRFrames[LastIRFrameIndex].setMin(ir0Mx + 1);
247 LastIRFrameSplit = true;
248 }
249 break;
250 }
252 LOGP(warn, "Failed to define IRFrame");
253 } else {
254 dh.tfCounter = (ir0Mn.orbit - offset) / hbfu.nHBFPerTF;
255 dh.firstTForbit = ir0Mn.orbit;
256 if (LastIRFrameIndex == NTFs - 1 && !LastIRFrameSplit) {
258 }
259 }
260 dph.creation = hbfu.startTime + (dh.firstTForbit - hbfu.orbitFirst) * o2::constants::lhc::LHCOrbitMUS * 1.e-3;
261 LOGP(debug, "SETTING DH for {}/{} from tfCounter={} firstTForbit={} runNumber={} and IRFrame ({}-{})",
262 dh.dataOrigin.as<std::string>(), dh.dataDescription.as<std::string>(), dh.tfCounter, dh.firstTForbit, dh.runNumber,
264}
265
266//_________________________________________________________
267void HBFUtilsInitializer::addNewTimeSliceCallback(std::vector<o2::framework::CallbacksPolicy>& policies)
268{
269 policies.push_back(o2::framework::CallbacksPolicy{
270 [](o2::framework::DeviceSpec const& spec, o2::framework::ConfigContext const& context) -> bool {
271 return (!context.helpOnCommandLine() && o2f::ConfigParamsHelper::hasOption(spec.options, HBFTFInfoOpt));
272 },
274 std::string irFrames, tfInput = context.options().get<std::string>(HBFTFInfoOpt);
275 if (context.options().hasOption(HBFIRFrameOpt)) {
276 irFrames = context.options().get<std::string>(HBFIRFrameOpt);
277 }
278 uint32_t delay = context.options().hasOption(DelayOpt) && context.options().isSet(DelayOpt) ? uint32_t(1e6 * context.options().get<float>(DelayOpt)) : 0;
279 if (!tfInput.empty()) {
280 if (tfInput == HBFUSrc) { // simple linear enumeration from already updated HBFUtils
281 if (irFrames.empty()) { // push the whole TF
282 NTFs = 1;
285 static size_t tfcount = 0;
286 if (tfcount++ && delay > 0) {
287 usleep(delay);
288 }
289 });
290 } else { // linear enumeration with IRFrames selection (skimming)
291 if (!o2::utils::Str::pathExists(irFrames)) {
292 throw std::runtime_error(fmt::format("file {} does not exist", irFrames));
293 }
294 readIRFramesVector(irFrames);
298 static size_t tfcount = 0;
299 if (tfcount++ && delay > 0) {
300 usleep(delay);
301 }
302 });
303 }
304 } else if (o2::utils::Str::endsWith(tfInput, ".root")) { // read TFIDinfo from file
305 if (!o2::utils::Str::pathExists(tfInput)) {
306 throw std::runtime_error(fmt::format("file {} does not exist", tfInput));
307 }
310 assignDataHeaderFromTFIDInfo(tfidinfo, dh, dph);
311 static size_t tfcount = 0;
312 if (tfcount++ && delay > 0) {
313 usleep(delay);
314 }
315 });
316 } else { // do not modify timing info
317 // we may remove the highest bit set on the creation time?
318 }
319 }
320 }});
321}
322
323void HBFUtilsInitializer::addConfigOption(std::vector<o2f::ConfigParamSpec>& opts, const std::string& defOpt)
324{
325 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")"}});
326}
uint64_t orbit
Definition RawEventData.h:6
bool done
std::ostringstream debug
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) noexcept
Definition Bracket.h:132
void setMin(T v) noexcept
Definition Bracket.h:138
const GLdouble * v
Definition glcorearb.h:832
GLintptr offset
Definition glcorearb.h:660
constexpr int LHCMaxBunches
constexpr double LHCOrbitMUS
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
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:618
TFCounterType tfCounter
Definition DataHeader.h:679
TForbitType firstTForbit
Definition DataHeader.h:674
DataDescription dataDescription
Definition DataHeader.h:636
RunNumberType runNumber
Definition DataHeader.h:684
std::enable_if_t< std::is_same< T, std::string >::value==true, T > as() const
get the descriptor as std::string
Definition DataHeader.h:301
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)