Project
Loading...
Searching...
No Matches
DigitReaderSpec.cxx
Go to the documentation of this file.
1// Copyright 2019-2026 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
13
14#include <string>
15#include <vector>
16#include <format>
17
18#include <TTree.h>
19
22#include "Framework/Logger.h"
35#include <cassert>
36
37using namespace o2::framework;
38using namespace o2::itsmft;
39
40namespace o2
41{
42namespace itsmft
43{
44
45template <int N>
46DigitReader<N>::DigitReader(bool useMC, bool doStag, bool useCalib, bool triggerOut) : mUseMC(useMC), mDoStaggering(doStag), mUseCalib(useCalib), mTriggerOut(triggerOut), mDetNameLC(mDetName = ID.getName()), mDigTreeName("o2sim")
47{
53
54 std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower);
56 if (mDoStaggering) {
58 mDigits.resize(mLayers, nullptr);
59 mDigROFRec.resize(mLayers, nullptr);
60 mPLabels.resize(mLayers, nullptr);
61 }
62}
63
64template <int N>
66{
67 mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")),
68 ic.options().get<std::string>((mDetNameLC + "-digit-infile").c_str()));
69 if (ic.options().hasOption("ignore-irframes") && !ic.options().get<bool>("ignore-irframes")) {
70 mUseIRFrames = true;
71 }
72 connectTree(mFileName);
73}
74
75template <int N>
77{
78 const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
79 const auto& alpideParam = o2::itsmft::DPLAlpideParam<N>::Instance();
80 if (tinfo.globalRunNumberChanged && mUseIRFrames) { // new run is starting: 1st call
81 // TODO: we have to find a way define CCDBInput for IRFrames mode only using DPL fetcher
83 auto rlim = ccdb.getRunDuration(tinfo.runNumber);
84 long ts = (rlim.first + rlim.second) / 2;
85 if constexpr (N == o2::detectors::DetID::ITS) {
86 ccdb.getForTimeStamp<o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>>("ITS/Config/AlpideParam", ts);
87 mROFBiasInBC = alpideParam.roFrameBiasInBC;
88 mROFLengthInBC = alpideParam.roFrameLengthInBC;
90 } else {
91 ccdb.getForTimeStamp<o2::itsmft::DPLAlpideParam<o2::detectors::DetID::MFT>>("MFT/Config/AlpideParam", ts);
92 mROFBiasInBC = alpideParam.roFrameBiasInBC;
93 mROFLengthInBC = alpideParam.roFrameLengthInBC;
95 }
96 }
97 gsl::span<const o2::dataformats::IRFrame> irFrames{};
98 if (mUseIRFrames) {
99 irFrames = pc.inputs().get<gsl::span<o2::dataformats::IRFrame>>("driverInfo");
100 }
101
102 auto ent = mTree->GetReadEntry();
103 if (!mUseIRFrames) {
104 ent++;
105 if (ent >= mTree->GetEntries()) {
106 // A timeframe holds no collision at all whenever the interaction rate is low enough, and the
107 // digit tree then has no entry to read. Send empty output rather than dereferencing the
108 // branch addresses, which GetEntry has not filled. (This used to be an assert, which is
109 // compiled out of every production build since ENABLE_CASSERT defaults to OFF.)
110 LOG(info) << mDetName << "DigitReader has no entry to read, sending empty output";
111 for (uint32_t iLayer = 0; iLayer < mLayers; ++iLayer) {
112 pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, std::vector<o2::itsmft::ROFRecord>{});
113 pc.outputs().snapshot(Output{Origin, "DIGITS", iLayer}, std::vector<o2::itsmft::Digit>{});
114 if (mUseMC) {
115 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{Origin, "DIGITSMCTR", iLayer});
117 noLabels.flatten_to(sharedlabels);
118 pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", iLayer}, std::vector<o2::itsmft::MC2ROFRecord>{});
119 }
120 }
121 if (mUseCalib) {
122 pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, std::vector<o2::itsmft::GBTCalibData>{});
123 }
124 if (mTriggerOut) {
125 pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, std::vector<o2::itsmft::PhysTrigger>{});
126 }
127 pc.services().get<ControlService>().endOfStream();
128 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
129 return;
130 }
131 mTree->GetEntry(ent);
132 for (uint32_t iLayer = 0; iLayer < mLayers; ++iLayer) {
133 LOG(info) << mDetName << "DigitReader" << ((mDoStaggering) ? std::format(": {}", iLayer) : "") << " pushes " << mDigROFRec[iLayer]->size() << " ROFRecords, " << mDigits[iLayer]->size() << " digits at entry " << ent;
134 pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, *mDigROFRec[iLayer]);
135 pc.outputs().snapshot(Output{Origin, "DIGITS", iLayer}, *mDigits[iLayer]);
136 if (mUseMC) {
137 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{Origin, "DIGITSMCTR", iLayer});
138 mPLabels[iLayer]->copyandflatten(sharedlabels);
139 delete mPLabels[iLayer];
140 mPLabels[iLayer] = nullptr;
141 // read dummy MC2ROF vector to keep writer/readers backward compatible
142 static std::vector<o2::itsmft::MC2ROFRecord> dummyMC2ROF;
143 pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", iLayer}, dummyMC2ROF);
144 }
145 }
146 if (mUseCalib) {
147 pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, mCalib);
148 }
149 if (mTriggerOut) {
150 std::vector<o2::itsmft::PhysTrigger> dummyTrig;
151 pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig);
152 }
153 if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) {
154 pc.services().get<ControlService>().endOfStream();
155 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
156 }
157 } else { // need to select particulars IRs range, presumably from the same tree entry
158 // TODO implement for staggering
159 std::vector<o2::itsmft::Digit> digitsSel;
160 std::vector<o2::itsmft::GBTCalibData> calibSel;
161 std::vector<o2::itsmft::ROFRecord> digROFRecSel;
163
164 if (irFrames.size()) { // we assume the IRFrames are in the increasing order
165 if (ent < 0) {
166 ent++;
167 }
169 irfSel.setSelectedIRFrames(irFrames, 0, 0, -mROFBiasInBC, true);
170 const auto irMin = irfSel.getIRFrames().front().getMin(); // use processed IRframes for rough comparisons (possible shift!)
171 const auto irMax = irfSel.getIRFrames().back().getMax();
172 LOGP(info, "Selecting IRFrame {}-{}", irMin.asString(), irMax.asString());
173 while (ent < mTree->GetEntries()) {
174 // do we need to read a new entry?
175 if (ent > mTree->GetReadEntry()) {
176 if (mUseMC) {
177 delete mPLabels[0];
178 mPLabels[0] = nullptr;
179 mConstLabels[0].clear();
180 mTree->SetBranchAddress(mDigitMCTruthBranchName.c_str(), &mPLabels[0]);
181 }
182 mTree->GetEntry(ent);
183 if (mUseMC) {
184 mPLabels[0]->copyandflatten(mConstLabels[0]);
185 delete mPLabels[0];
186 mPLabels[0] = nullptr;
187 }
188 }
189 std::vector<int> rofOld2New;
190 rofOld2New.resize(mDigROFRec[0]->size(), -1);
191
192 if (mDigROFRec[0]->front().getBCData() <= irMax && (mDigROFRec[0]->back().getBCData() + mROFLengthInBC - 1) >= irMin) { // there is an overlap
193 for (int irof = 0; irof < (int)mDigROFRec[0]->size(); irof++) {
194 const auto& rof = mDigROFRec[0]->at(irof);
195 if (irfSel.check({rof.getBCData(), rof.getBCData() + mROFLengthInBC - 1}) != -1) {
196 rofOld2New[irof] = (int)digROFRecSel.size();
197 LOGP(debug, "Adding selected ROF {}", rof.getBCData().asString());
198 digROFRecSel.push_back(rof);
199 int offs = digitsSel.size();
200 digROFRecSel.back().setFirstEntry(offs);
201 std::copy(mDigits[0]->begin() + rof.getFirstEntry(), mDigits[0]->begin() + rof.getFirstEntry() + rof.getNEntries(), std::back_inserter(digitsSel));
202 for (int id = 0; id < rof.getNEntries(); id++) { // copy MC info
203 digitLabelsSel.addElements(id + offs, mConstLabels[0].getLabels(id + rof.getFirstEntry()));
204 }
205 if (mCalib.size() >= size_t((irof + 1) * mNRUs)) {
206 std::copy(mCalib.begin() + irof * mNRUs, mCalib.begin() + (irof + 1) * mNRUs, std::back_inserter(calibSel));
207 }
208 }
209 }
210 }
211 if (mDigROFRec[0]->back().getBCData() + mROFLengthInBC - 1 < irMax) { // need to check the next entry
212 ent++;
213 continue;
214 }
215 break; // push collected data
216 }
217 }
218 pc.outputs().snapshot(Output{Origin, "DIGITSROF", 0}, digROFRecSel);
219 pc.outputs().snapshot(Output{Origin, "DIGITS", 0}, digitsSel);
220 if (mUseCalib) {
221 pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, calibSel);
222 }
223 if (mTriggerOut) {
224 std::vector<o2::itsmft::PhysTrigger> dummyTrig;
225 pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig);
226 }
227 if (mUseMC) {
228 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{Origin, "DIGITSMCTR", 0});
229 digitLabelsSel.flatten_to(sharedlabels);
230 }
231
232 if (!irFrames.size() || irFrames.back().isLast()) {
233 pc.services().get<ControlService>().endOfStream();
234 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
235 }
236 }
237}
238
239template <int N>
240void DigitReader<N>::connectTree(const std::string& filename)
241{
242 mTree.reset(nullptr); // in case it was already loaded
243 mFile.reset(TFile::Open(filename.c_str()));
244 if (!mFile || mFile->IsZombie()) {
245 throw std::runtime_error(std::format("Cannot open {}", filename));
246 }
247 mTree.reset((TTree*)mFile->Get(mDigTreeName.c_str()));
248 if (!mTree) {
249 throw std::runtime_error(std::format("Tree {} not found in {}", mDigTreeName, filename));
250 }
251 for (uint32_t iLayer = 0; iLayer < mLayers; ++iLayer) {
252 setBranchAddress(mDigitROFBranchName, mDigROFRec[iLayer], iLayer);
253 setBranchAddress(mDigitBranchName, mDigits[iLayer], iLayer);
254 if (mUseMC) {
255 if (!mTree->GetBranch(getBranchName(mDigitMCTruthBranchName, iLayer).c_str())) {
256 throw std::runtime_error("MC data requested but not found in the tree");
257 }
258 if (!mPLabels[iLayer]) {
259 setBranchAddress(mDigitMCTruthBranchName, mPLabels[iLayer], iLayer);
260 }
261 }
262 }
263 if (mUseCalib) {
264 if (!mTree->GetBranch(mCalibBranchName.c_str())) {
265 throw std::runtime_error("GBT calibration data requested but not found in the tree");
266 }
267 setBranchAddress(mCalibBranchName, mCalibPtr);
268 }
269 LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries";
270}
271
272template <int N>
273std::string DigitReader<N>::getBranchName(const std::string& base, int index)
274{
275 if (mDoStaggering) {
276 return base + "_" + std::to_string(index);
277 }
278 return base;
279}
280
281template <int N>
282template <typename Ptr>
283void DigitReader<N>::setBranchAddress(const std::string& base, Ptr& addr, int layer)
284{
285 const auto name = getBranchName(base, layer);
286 if (Int_t ret = mTree->SetBranchAddress(name.c_str(), &addr); ret != 0) {
287 LOGP(fatal, "failed to set branch address for {} ret={}", name, ret);
288 }
289}
290
291namespace
292{
293template <int N>
294std::vector<OutputSpec> makeOutChannels(bool mctruth, bool doStag, bool useCalib)
295{
297 std::vector<OutputSpec> outputs;
298 int nLayers = doStag ? o2::itsmft::DPLAlpideParam<N>::getNLayers() : 1;
299 for (int iLayer = 0; iLayer < nLayers; ++iLayer) {
300 outputs.emplace_back(Origin, "DIGITS", iLayer, Lifetime::Timeframe);
301 outputs.emplace_back(Origin, "DIGITSROF", iLayer, Lifetime::Timeframe);
302 if (mctruth) {
303 outputs.emplace_back(Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe);
304 outputs.emplace_back(Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe);
305 }
306 }
307 if (useCalib) {
308 outputs.emplace_back(Origin, "GBTCALIB", 0, Lifetime::Timeframe);
309 }
310 outputs.emplace_back(Origin, "PHYSTRIG", 0, Lifetime::Timeframe);
311 return outputs;
312}
313} // namespace
314
315DataProcessorSpec getITSDigitReaderSpec(bool useMC, bool doStag, bool useCalib, bool useTriggers, std::string defname)
316{
317 return DataProcessorSpec{
318 .name = "its-digit-reader",
319 .inputs = Inputs{},
320 .outputs = makeOutChannels<o2::detectors::DetID::ITS>(useMC, doStag, useCalib),
321 .algorithm = AlgorithmSpec{adaptFromTask<ITSDigitReader>(useMC, doStag, useCalib, useTriggers)},
322 .options = Options{
323 {"its-digit-infile", VariantType::String, defname, {"Name of the input digit file"}},
324 {"input-dir", VariantType::String, "none", {"Input directory"}}}};
325}
326
327DataProcessorSpec getMFTDigitReaderSpec(bool useMC, bool doStag, bool useCalib, bool useTriggers, std::string defname)
328{
329 return DataProcessorSpec{
330 .name = "mft-digit-reader",
331 .inputs = Inputs{},
332 .outputs = makeOutChannels<o2::detectors::DetID::MFT>(useMC, doStag, useCalib),
333 .algorithm = AlgorithmSpec{adaptFromTask<MFTDigitReader>(useMC, doStag, useCalib, useTriggers)},
334 .options = Options{
335 {"mft-digit-infile", VariantType::String, defname, {"Name of the input digit file"}},
336 {"input-dir", VariantType::String, "none", {"Input directory"}}}};
337}
338
339} // namespace itsmft
340} // namespace o2
std::string getName(const TDataMember *dm, int index, int size)
A const (ready only) version of MCTruthContainer.
std::ostringstream debug
Class to check if give InteractionRecord or IRFrame is selected by the external IRFrame vector.
Class to delimit start and end IR of certain time period.
Definition of a container to keep Monte Carlo truth external to simulation objects.
Definition of the Names Generator class.
Definition Physics trigger record extracted from the ITS/MFT stream.
static BasicCCDBManager & instance()
A read-only version of MCTruthContainer allowing for storage optimisation.
A container to hold and manage MC truth information/labels.
void addElements(uint32_t dataindex, gsl::span< CompatibleLabel > elements)
size_t flatten_to(ContainerType &container) const
static constexpr ID ITS
Definition DetID.h:63
bool hasOption(const char *key) const
void snapshot(const Output &spec, T const &object)
decltype(auto) make(const Output &spec, Args... args)
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
static constexpr int getNRUs()
total number of chips
static constexpr Int_t getNRUs()
< total number of RUs
void setBranchAddress(const std::string &base, Ptr &addr, int layer=-1)
std::string getBranchName(const std::string &base, int index)
void run(ProcessingContext &pc) final
void init(InitContext &ic) final
void connectTree(const std::string &filename)
std::vector< std::vector< o2::itsmft::Digit > * > mDigits
std::string mDigitMCTruthBranchName
std::vector< o2::dataformats::IOMCTruthContainerView * > mPLabels
std::vector< std::vector< o2::itsmft::ROFRecord > * > mDigROFRec
long check(o2::dataformats::IRFrame fr, size_t bwd=0, size_t fwd=0)
void setSelectedIRFrames(const SPAN &sp, size_t bwd=0, size_t fwd=0, long shift=0, bool removeOverlaps=true)
GLsizeiptr size
Definition glcorearb.h:659
GLuint index
Definition glcorearb.h:781
GLuint const GLchar * name
Definition glcorearb.h:781
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
constexpr o2::header::DataOrigin gDataOriginMFT
Definition DataHeader.h:572
constexpr o2::header::DataOrigin gDataOriginITS
Definition DataHeader.h:570
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > Inputs
framework::DataProcessorSpec getITSDigitReaderSpec(bool useMC=true, bool doStag=false, bool useCalib=false, bool useTriggers=true, std::string defname="itsdigits.root")
framework::DataProcessorSpec getMFTDigitReaderSpec(bool useMC=true, bool doStag=false, bool useCalib=false, bool useTriggers=true, std::string defname="mftdigits.root")
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
std::string filename()
static constexpr int getNLayers()
static std::string rectifyDirectory(const std::string_view p)
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"