Project
Loading...
Searching...
No Matches
DigitReaderSpec.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
16
18
19#include <memory>
20#include <stdexcept>
21#include <sstream>
22#include <string>
23
24#include "TFile.h"
25#include "TTree.h"
26#include "TTreeReader.h"
27#include "TTreeReaderValue.h"
28
31#include "Framework/Logger.h"
33#include "Framework/Task.h"
35#include "Framework/Variant.h"
43
44using namespace o2::framework;
45
46namespace o2
47{
48namespace mid
49{
50
52{
53 public:
54 DigitsReaderDeviceDPL(bool useMC) : mUseMC(useMC)
55 {
56 if (mUseMC) {
57 mLabels = std::make_unique<TTreeReaderValue<dataformats::MCTruthContainer<MCLabel>>>(mTreeReader, "MIDDigitMCLabels");
58 }
59 }
60
61 void init(InitContext& ic)
62 {
63 auto filename = utils::Str::concat_string(utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")),
64 ic.options().get<std::string>("mid-digit-infile"));
65
66 connectTree(filename);
67
68 if (ic.options().hasOption("ignore-irframes") && !ic.options().get<bool>("ignore-irframes")) {
69 mUseIRFrames = true;
70 }
71 }
72
74 {
75 if (mUseIRFrames) {
76 sendNextIRFrames(pc);
77 } else {
78 sendNextTF(pc);
79 }
80 }
81
82 private:
83 TTreeReader mTreeReader{};
84 TTreeReaderValue<std::vector<ROFRecord>> mRofs = {mTreeReader, "MIDROFRecords"};
85 TTreeReaderValue<std::vector<ColumnData>> mDigits = {mTreeReader, "MIDDigit"};
86 std::unique_ptr<TTreeReaderValue<dataformats::MCTruthContainer<MCLabel>>> mLabels{};
87 bool mUseMC = true;
88 bool mUseIRFrames = false;
89
90 void connectTree(std::string filename)
91 {
92 auto file = TFile::Open(filename.c_str());
93 if (!file || file->IsZombie()) {
94 throw std::invalid_argument(fmt::format("Opening file {} failed", filename));
95 }
96
97 auto tree = file->Get<TTree>("o2sim");
98 if (!tree) {
99 throw std::invalid_argument(fmt::format("Tree o2sim not found in {}", filename));
100 }
101 mTreeReader.SetTree(tree);
102 mTreeReader.Restart();
103 }
104
105 void sendNextTF(ProcessingContext& pc)
106 {
107 // A timeframe holds no collision at all whenever the interaction rate is low enough, and the
108 // digit tree then has no entry. Send empty containers and finish, rather than throwing.
109 if (mTreeReader.GetEntries() == 0) {
110 LOG(info) << "digit tree has no entry, sending empty output";
111 pc.outputs().snapshot(OutputRef{"rofs"}, std::vector<ROFRecord>{});
112 pc.outputs().snapshot(OutputRef{"digits"}, std::vector<ColumnData>{});
113 if (mUseMC) {
115 }
116 pc.services().get<ControlService>().endOfStream();
117 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
118 return;
119 }
120
121 // load the next TF and check its validity (missing branch, ...)
122 if (!mTreeReader.Next()) {
123 throw std::invalid_argument(mTreeReader.fgEntryStatusText[mTreeReader.GetEntryStatus()]);
124 }
125
126 // send the whole TF
127 pc.outputs().snapshot(OutputRef{"rofs"}, *mRofs);
128 pc.outputs().snapshot(OutputRef{"digits"}, *mDigits);
129 if (mUseMC) {
130 pc.outputs().snapshot(OutputRef{"labels"}, **mLabels);
131 }
132
133 // stop here if it was the last one
134 if (mTreeReader.GetCurrentEntry() + 1 >= mTreeReader.GetEntries()) {
135 pc.services().get<ControlService>().endOfStream();
136 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
137 }
138 }
139
140 void sendNextIRFrames(ProcessingContext& pc)
141 {
142 std::vector<ROFRecord> rofs{};
143 std::vector<ColumnData> digits{};
145
146 // get the IR frames to select
147 auto irFrames = pc.inputs().get<gsl::span<dataformats::IRFrame>>("driverInfo");
148
149 if (mTreeReader.GetEntries() == 0) {
150 // A timeframe holds no collision at all whenever the interaction rate is low enough, and the
151 // digit tree then has no entry. Nothing to select. Send empty containers.
152 LOG(info) << "digit tree has no entry, sending empty output";
153 } else if (!irFrames.empty()) {
154 utils::IRFrameSelector irfSel{};
155 irfSel.setSelectedIRFrames(irFrames, 0, 0, 0, true);
156 const auto irMin = irfSel.getIRFrames().front().getMin();
157 const auto irMax = irfSel.getIRFrames().back().getMax();
158
159 // load the first TF if not already done
160 bool loadNextTF = mTreeReader.GetCurrentEntry() < 0;
161
162 while (true) {
163 // load the next TF if requested
164 if (loadNextTF && !mTreeReader.Next()) {
165 throw std::invalid_argument(mTreeReader.fgEntryStatusText[mTreeReader.GetEntryStatus()]);
166 }
167
168 // look for selected ROFs in this TF and copy them
169 if (!mRofs->empty() && mRofs->front().interactionRecord <= irMax &&
170 mRofs->back().interactionRecord >= irMin) {
171 for (const auto& rof : *mRofs) {
172 if (irfSel.check(rof.interactionRecord) != -1) {
173 rofs.emplace_back(rof);
174 rofs.back().firstEntry = digits.size();
175 rofs.back().nEntries = rof.nEntries;
176 digits.insert(digits.end(), mDigits->begin() + rof.firstEntry, mDigits->begin() + rof.getEndIndex());
177 if (mUseMC) {
178 for (auto idig = 0; idig < rof.nEntries; ++idig) {
179 labels.addElements(labels.getIndexedSize(), (*mLabels)->getLabels(rof.firstEntry + idig));
180 }
181 }
182 }
183 }
184 }
185
186 // move to the next TF if needed and if any
187 if ((mRofs->empty() || mRofs->back().interactionRecord < irMax) &&
188 mTreeReader.GetCurrentEntry() + 1 < mTreeReader.GetEntries()) {
189 loadNextTF = true;
190 continue;
191 }
192
193 break;
194 }
195 }
196
197 // send the selected data
198 pc.outputs().snapshot(OutputRef{"rofs"}, rofs);
199 pc.outputs().snapshot(OutputRef{"digits"}, digits);
200 if (mUseMC) {
201 pc.outputs().snapshot(OutputRef{"labels"}, labels);
202 }
203
204 // stop here if they were the last IR frames to select
205 if (irFrames.empty() || irFrames.back().isLast()) {
206 pc.services().get<ControlService>().endOfStream();
207 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
208 }
209 }
210};
211
212DataProcessorSpec getDigitReaderSpec(bool useMC, const char* baseDescription)
213{
214 std::vector<OutputSpec> outputs;
215 std::stringstream ss;
216 ss << "digits:" << header::gDataOriginMID.as<std::string>() << "/" << baseDescription << "/0";
217 ss << ";rofs:" << header::gDataOriginMID.as<std::string>() << "/" << baseDescription << "ROF/0";
218 if (useMC) {
219 ss << ";labels:" << header::gDataOriginMID.as<std::string>() << "/" << baseDescription << "LABELS/0";
220 }
221 auto matchers = select(ss.str().c_str());
222 for (auto& matcher : matchers) {
223 outputs.emplace_back(DataSpecUtils::asOutputSpec(matcher));
224 }
225
226 return DataProcessorSpec{
227 "MIDDigitsReader",
228 Inputs{},
229 outputs,
230 AlgorithmSpec{adaptFromTask<DigitsReaderDeviceDPL>(useMC)},
231 Options{{"mid-digit-infile", VariantType::String, "middigits.root", {"Name of the input file"}},
232 {"input-dir", VariantType::String, "none", {"Input directory"}}}};
233}
234} // namespace mid
235} // namespace o2
std::vector< framework::ConcreteDataMatcher > matchers
std::vector< std::string > labels
Strip pattern (aka digits)
Label for MID.
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.
Data processor specs for MID digits reader device.
Definition of the MID event record.
A container to hold and manage MC truth information/labels.
bool hasOption(const char *key) const
void snapshot(const Output &spec, T const &object)
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.
void run(ProcessingContext &pc)
void setSelectedIRFrames(const SPAN &sp, size_t bwd=0, size_t fwd=0, long shift=0, bool removeOverlaps=true)
constexpr o2::header::DataOrigin gDataOriginMID
Definition DataHeader.h:573
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > select(char const *matcher="")
std::vector< InputSpec > Inputs
int32_t const char * file
framework::DataProcessorSpec getDigitReaderSpec(bool useMC, const char *baseDescription="DATAMC")
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string filename()
static OutputSpec asOutputSpec(InputSpec const &spec)
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::string rectifyDirectory(const std::string_view p)
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
std::vector< Digit > digits