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"
34#include <cassert>
35
36using namespace o2::framework;
37using namespace o2::itsmft;
38
39namespace o2
40{
41namespace itsmft
42{
43
44template <int N>
45DigitReader<N>::DigitReader(bool useMC, bool doStag, bool useCalib, bool triggerOut) : mUseMC(useMC), mDoStaggering(doStag), mUseCalib(useCalib), mTriggerOut(triggerOut), mDetNameLC(mDetName = ID.getName()), mDigTreeName("o2sim")
46{
50
53 std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower);
54
57 mDigits.resize(mLayers, nullptr);
58 mDigROFRec.resize(mLayers, nullptr);
59 mPLabels.resize(mLayers, nullptr);
60 }
61}
62
63template <int N>
65{
66 mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")),
67 ic.options().get<std::string>((mDetNameLC + "-digit-infile").c_str()));
68 if (ic.options().hasOption("ignore-irframes") && !ic.options().get<bool>("ignore-irframes")) {
69 mUseIRFrames = true;
70 }
71 connectTree(mFileName);
72}
73
74template <int N>
76{
77 const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
78 const auto& alpideParam = o2::itsmft::DPLAlpideParam<N>::Instance();
79 if (tinfo.globalRunNumberChanged && mUseIRFrames) { // new run is starting: 1st call
80 // TODO: we have to find a way define CCDBInput for IRFrames mode only using DPL fetcher
82 auto rlim = ccdb.getRunDuration(tinfo.runNumber);
83 long ts = (rlim.first + rlim.second) / 2;
84 if constexpr (N == o2::detectors::DetID::ITS) {
85 ccdb.getForTimeStamp<o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>>("ITS/Config/AlpideParam", ts);
86 mROFBiasInBC = alpideParam.roFrameBiasInBC;
87 mROFLengthInBC = alpideParam.roFrameLengthInBC;
89 } else {
90 ccdb.getForTimeStamp<o2::itsmft::DPLAlpideParam<o2::detectors::DetID::MFT>>("MFT/Config/AlpideParam", ts);
91 mROFBiasInBC = alpideParam.roFrameBiasInBC;
92 mROFLengthInBC = alpideParam.roFrameLengthInBC;
94 }
95 }
96 gsl::span<const o2::dataformats::IRFrame> irFrames{};
97 if (mUseIRFrames) {
98 irFrames = pc.inputs().get<gsl::span<o2::dataformats::IRFrame>>("driverInfo");
99 }
100
101 auto ent = mTree->GetReadEntry();
102 if (!mUseIRFrames) {
103 ent++;
104 assert(ent < mTree->GetEntries()); // this should not happen
105 mTree->GetEntry(ent);
106 for (uint32_t iLayer = 0; iLayer < mLayers; ++iLayer) {
107 LOG(info) << mDetName << "DigitReader" << ((mDoStaggering) ? std::format(": {}", iLayer) : "") << " pushes " << mDigROFRec[iLayer]->size() << " ROFRecords, " << mDigits[iLayer]->size() << " digits at entry " << ent;
108 pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, *mDigROFRec[iLayer]);
109 pc.outputs().snapshot(Output{Origin, "DIGITS", iLayer}, *mDigits[iLayer]);
110 if (mUseMC) {
111 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{Origin, "DIGITSMCTR", iLayer});
112 mPLabels[iLayer]->copyandflatten(sharedlabels);
113 delete mPLabels[iLayer];
114 mPLabels[iLayer] = nullptr;
115 // read dummy MC2ROF vector to keep writer/readers backward compatible
116 static std::vector<o2::itsmft::MC2ROFRecord> dummyMC2ROF;
117 pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", iLayer}, dummyMC2ROF);
118 }
119 }
120 if (mUseCalib) {
121 pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, mCalib);
122 }
123 if (mTriggerOut) {
124 std::vector<o2::itsmft::PhysTrigger> dummyTrig;
125 pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig);
126 }
127 if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) {
128 pc.services().get<ControlService>().endOfStream();
129 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
130 }
131 } else { // need to select particulars IRs range, presumably from the same tree entry
132 // TODO implement for staggering
133 std::vector<o2::itsmft::Digit> digitsSel;
134 std::vector<o2::itsmft::GBTCalibData> calibSel;
135 std::vector<o2::itsmft::ROFRecord> digROFRecSel;
137
138 if (irFrames.size()) { // we assume the IRFrames are in the increasing order
139 if (ent < 0) {
140 ent++;
141 }
143 irfSel.setSelectedIRFrames(irFrames, 0, 0, -mROFBiasInBC, true);
144 const auto irMin = irfSel.getIRFrames().front().getMin(); // use processed IRframes for rough comparisons (possible shift!)
145 const auto irMax = irfSel.getIRFrames().back().getMax();
146 LOGP(info, "Selecting IRFrame {}-{}", irMin.asString(), irMax.asString());
147 while (ent < mTree->GetEntries()) {
148 // do we need to read a new entry?
149 if (ent > mTree->GetReadEntry()) {
150 if (mUseMC) {
151 delete mPLabels[0];
152 mPLabels[0] = nullptr;
153 mConstLabels[0].clear();
154 mTree->SetBranchAddress(mDigitMCTruthBranchName.c_str(), &mPLabels[0]);
155 }
156 mTree->GetEntry(ent);
157 if (mUseMC) {
158 mPLabels[0]->copyandflatten(mConstLabels[0]);
159 delete mPLabels[0];
160 mPLabels[0] = nullptr;
161 }
162 }
163 std::vector<int> rofOld2New;
164 rofOld2New.resize(mDigROFRec[0]->size(), -1);
165
166 if (mDigROFRec[0]->front().getBCData() <= irMax && (mDigROFRec[0]->back().getBCData() + mROFLengthInBC - 1) >= irMin) { // there is an overlap
167 for (int irof = 0; irof < (int)mDigROFRec[0]->size(); irof++) {
168 const auto& rof = mDigROFRec[0]->at(irof);
169 if (irfSel.check({rof.getBCData(), rof.getBCData() + mROFLengthInBC - 1}) != -1) {
170 rofOld2New[irof] = (int)digROFRecSel.size();
171 LOGP(debug, "Adding selected ROF {}", rof.getBCData().asString());
172 digROFRecSel.push_back(rof);
173 int offs = digitsSel.size();
174 digROFRecSel.back().setFirstEntry(offs);
175 std::copy(mDigits[0]->begin() + rof.getFirstEntry(), mDigits[0]->begin() + rof.getFirstEntry() + rof.getNEntries(), std::back_inserter(digitsSel));
176 for (int id = 0; id < rof.getNEntries(); id++) { // copy MC info
177 digitLabelsSel.addElements(id + offs, mConstLabels[0].getLabels(id + rof.getFirstEntry()));
178 }
179 if (mCalib.size() >= size_t((irof + 1) * mNRUs)) {
180 std::copy(mCalib.begin() + irof * mNRUs, mCalib.begin() + (irof + 1) * mNRUs, std::back_inserter(calibSel));
181 }
182 }
183 }
184 }
185 if (mDigROFRec[0]->back().getBCData() + mROFLengthInBC - 1 < irMax) { // need to check the next entry
186 ent++;
187 continue;
188 }
189 break; // push collected data
190 }
191 }
192 pc.outputs().snapshot(Output{Origin, "DIGITSROF", 0}, digROFRecSel);
193 pc.outputs().snapshot(Output{Origin, "DIGITS", 0}, digitsSel);
194 if (mUseCalib) {
195 pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, calibSel);
196 }
197 if (mTriggerOut) {
198 std::vector<o2::itsmft::PhysTrigger> dummyTrig;
199 pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig);
200 }
201 if (mUseMC) {
202 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{Origin, "DIGITSMCTR", 0});
203 digitLabelsSel.flatten_to(sharedlabels);
204 }
205
206 if (!irFrames.size() || irFrames.back().isLast()) {
207 pc.services().get<ControlService>().endOfStream();
208 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
209 }
210 }
211}
212
213template <int N>
214void DigitReader<N>::connectTree(const std::string& filename)
215{
216 mTree.reset(nullptr); // in case it was already loaded
217 mFile.reset(TFile::Open(filename.c_str()));
218 assert(mFile && !mFile->IsZombie());
219 mTree.reset((TTree*)mFile->Get(mDigTreeName.c_str()));
220 assert(mTree);
221 for (uint32_t iLayer = 0; iLayer < mLayers; ++iLayer) {
222 setBranchAddress(mDigitROFBranchName, mDigROFRec[iLayer], iLayer);
223 setBranchAddress(mDigitBranchName, mDigits[iLayer], iLayer);
224 if (mUseMC) {
225 if (!mTree->GetBranch(getBranchName(mDigitMCTruthBranchName, iLayer).c_str())) {
226 throw std::runtime_error("MC data requested but not found in the tree");
227 }
228 if (!mPLabels[iLayer]) {
229 setBranchAddress(mDigitMCTruthBranchName, mPLabels[iLayer], iLayer);
230 }
231 }
232 }
233 if (mUseCalib) {
234 if (!mTree->GetBranch(mCalibBranchName.c_str())) {
235 throw std::runtime_error("GBT calibration data requested but not found in the tree");
236 }
237 setBranchAddress(mCalibBranchName, mCalibPtr);
238 }
239 LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries";
240}
241
242template <int N>
243std::string DigitReader<N>::getBranchName(const std::string& base, int index)
244{
245 if (mDoStaggering) {
246 return base + "_" + std::to_string(index);
247 }
248 return base;
249}
250
251template <int N>
252template <typename Ptr>
253void DigitReader<N>::setBranchAddress(const std::string& base, Ptr& addr, int layer)
254{
255 const auto name = getBranchName(base, layer);
256 if (Int_t ret = mTree->SetBranchAddress(name.c_str(), &addr); ret != 0) {
257 LOGP(fatal, "failed to set branch address for {} ret={}", name, ret);
258 }
259}
260
261namespace
262{
263template <int N>
264std::vector<OutputSpec> makeOutChannels(bool mctruth, bool doStag, bool useCalib)
265{
267 std::vector<OutputSpec> outputs;
268 int nLayers = doStag ? o2::itsmft::DPLAlpideParam<N>::getNLayers() : 1;
269 for (int iLayer = 0; iLayer < nLayers; ++iLayer) {
270 outputs.emplace_back(Origin, "DIGITS", iLayer, Lifetime::Timeframe);
271 outputs.emplace_back(Origin, "DIGITSROF", iLayer, Lifetime::Timeframe);
272 if (mctruth) {
273 outputs.emplace_back(Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe);
274 outputs.emplace_back(Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe);
275 }
276 }
277 if (useCalib) {
278 outputs.emplace_back(Origin, "GBTCALIB", 0, Lifetime::Timeframe);
279 }
280 outputs.emplace_back(Origin, "PHYSTRIG", 0, Lifetime::Timeframe);
281 return outputs;
282}
283} // namespace
284
285DataProcessorSpec getITSDigitReaderSpec(bool useMC, bool doStag, bool useCalib, bool useTriggers, std::string defname)
286{
287 return DataProcessorSpec{
288 .name = "its-digit-reader",
289 .inputs = Inputs{},
290 .outputs = makeOutChannels<o2::detectors::DetID::ITS>(useMC, doStag, useCalib),
291 .algorithm = AlgorithmSpec{adaptFromTask<ITSDigitReader>(useMC, doStag, useCalib, useTriggers)},
292 .options = Options{
293 {"its-digit-infile", VariantType::String, defname, {"Name of the input digit file"}},
294 {"input-dir", VariantType::String, "none", {"Input directory"}}}};
295}
296
297DataProcessorSpec getMFTDigitReaderSpec(bool useMC, bool doStag, bool useCalib, bool useTriggers, std::string defname)
298{
299 return DataProcessorSpec{
300 .name = "mft-digit-reader",
301 .inputs = Inputs{},
302 .outputs = makeOutChannels<o2::detectors::DetID::MFT>(useMC, doStag, useCalib),
303 .algorithm = AlgorithmSpec{adaptFromTask<MFTDigitReader>(useMC, doStag, useCalib, useTriggers)},
304 .options = Options{
305 {"mft-digit-infile", VariantType::String, defname, {"Name of the input digit file"}},
306 {"input-dir", VariantType::String, "none", {"Input directory"}}}};
307}
308
309} // namespace itsmft
310} // 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 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"