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 <string>
22#include <vector>
23
24#include <fmt/format.h>
25
26#include <gsl/span>
27
28#include <TFile.h>
29#include <TTree.h>
30#include <TTreeReader.h>
31#include <TTreeReaderValue.h>
32
40#include "Framework/Logger.h"
42#include "Framework/Task.h"
47
48using namespace o2::framework;
49
50namespace o2
51{
52namespace mch
53{
54
56{
57 public:
58 DigitsReaderDeviceDPL(bool useMC) : mUseMC(useMC)
59 {
60 if (mUseMC) {
61 mLabels = std::make_unique<TTreeReaderValue<dataformats::MCTruthContainer<MCCompLabel>>>(mTreeReader, "MCHMCLabels");
62 }
63 }
64
65 void init(InitContext& ic)
66 {
67 auto fileName = utils::Str::concat_string(utils::Str::rectifyDirectory(ic.options().get<std::string>("input-dir")),
68 ic.options().get<std::string>("mch-digit-infile"));
69 connectTree(fileName);
70
71 if (ic.options().hasOption("ignore-irframes") && !ic.options().get<bool>("ignore-irframes")) {
72 mUseIRFrames = true;
73 }
74
75 mTimeOffset = ic.options().get<bool>("no-time-offset") ? 0 : DigitFilterParam::Instance().timeOffset;
76 }
77
79 {
80 if (mUseIRFrames) {
81 sendNextIRFrames(pc);
82 } else {
83 sendNextTF(pc);
84 }
85 }
86
87 private:
88 TTreeReader mTreeReader{};
89 TTreeReaderValue<std::vector<ROFRecord>> mRofs = {mTreeReader, "MCHROFRecords"};
90 TTreeReaderValue<std::vector<Digit>> mDigits = {mTreeReader, "MCHDigit"};
91 std::unique_ptr<TTreeReaderValue<dataformats::MCTruthContainer<MCCompLabel>>> mLabels{};
92 bool mUseMC = true;
93 bool mUseIRFrames = false;
94 int mTimeOffset = 0;
95
96 void connectTree(std::string fileName)
97 {
98 auto file = TFile::Open(fileName.c_str());
99 if (!file || file->IsZombie()) {
100 throw std::invalid_argument(fmt::format("Opening file {} failed", fileName));
101 }
102
103 auto tree = file->Get<TTree>("o2sim");
104 if (!tree) {
105 throw std::invalid_argument(fmt::format("Tree o2sim not found in {}", fileName));
106 }
107 mTreeReader.SetTree(tree);
108 mTreeReader.Restart();
109 }
110
111 void sendNextTF(ProcessingContext& pc)
112 {
113 // A timeframe holds no collision at all whenever the interaction rate is low enough, and the
114 // digit tree then has no entry. Send empty containers and finish, rather than throwing.
115 if (mTreeReader.GetEntries() == 0) {
116 LOG(info) << "digit tree has no entry, sending empty output";
117 pc.outputs().snapshot(OutputRef{"rofs"}, std::vector<ROFRecord>{});
118 pc.outputs().snapshot(OutputRef{"digits"}, std::vector<Digit>{});
119 if (mUseMC) {
121 }
122 pc.services().get<ControlService>().endOfStream();
123 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
124 return;
125 }
126
127 // load the next TF and check its validity (missing branch, ...)
128 if (!mTreeReader.Next()) {
129 throw std::invalid_argument(mTreeReader.fgEntryStatusText[mTreeReader.GetEntryStatus()]);
130 }
131
132 // send the whole TF
133 pc.outputs().snapshot(OutputRef{"rofs"}, *mRofs);
134 pc.outputs().snapshot(OutputRef{"digits"}, *mDigits);
135 if (mUseMC) {
136 pc.outputs().snapshot(OutputRef{"labels"}, **mLabels);
137 }
138
139 // stop here if it was the last one
140 if (mTreeReader.GetCurrentEntry() + 1 >= mTreeReader.GetEntries()) {
141 pc.services().get<ControlService>().endOfStream();
142 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
143 }
144 }
145
146 void sendNextIRFrames(ProcessingContext& pc)
147 {
148 std::vector<ROFRecord> rofs{};
149 std::vector<Digit> digits{};
151
152 // get the IR frames to select
153 auto irFrames = pc.inputs().get<gsl::span<dataformats::IRFrame>>("driverInfo");
154
155 if (!irFrames.empty()) {
156 utils::IRFrameSelector irfSel{};
157 irfSel.setSelectedIRFrames(irFrames, 0, 0, -mTimeOffset, true);
158 const auto irMin = irfSel.getIRFrames().front().getMin();
159 const auto irMax = irfSel.getIRFrames().back().getMax();
160
161 // load the first TF if not already done
162 bool loadNextTF = mTreeReader.GetCurrentEntry() < 0;
163
164 while (true) {
165 // load the next TF if requested
166 if (loadNextTF && !mTreeReader.Next()) {
167 throw std::invalid_argument(mTreeReader.fgEntryStatusText[mTreeReader.GetEntryStatus()]);
168 }
169
170 // look for selected ROFs in this TF and copy them
171 if (!mRofs->empty() && mRofs->front().getBCData() <= irMax &&
172 mRofs->back().getBCData() + mRofs->back().getBCWidth() - 1 >= irMin) {
173 for (const auto& rof : *mRofs) {
174 if (irfSel.check({rof.getBCData(), rof.getBCData() + rof.getBCWidth() - 1}) != -1) {
175 rofs.emplace_back(rof);
176 rofs.back().setDataRef(digits.size(), rof.getNEntries());
177 digits.insert(digits.end(), mDigits->begin() + rof.getFirstIdx(), mDigits->begin() + rof.getFirstIdx() + rof.getNEntries());
178 if (mUseMC) {
179 for (auto i = 0; i < rof.getNEntries(); ++i) {
180 labels.addElements(labels.getIndexedSize(), (*mLabels)->getLabels(rof.getFirstIdx() + i));
181 }
182 }
183 }
184 }
185 }
186
187 // move to the next TF if needed and if any
188 if ((mRofs->empty() || mRofs->back().getBCData() + mRofs->back().getBCWidth() - 1 < irMax) &&
189 mTreeReader.GetCurrentEntry() + 1 < mTreeReader.GetEntries()) {
190 loadNextTF = true;
191 continue;
192 }
193
194 break;
195 }
196 }
197
198 // send the selected data
199 pc.outputs().snapshot(OutputRef{"rofs"}, rofs);
200 pc.outputs().snapshot(OutputRef{"digits"}, digits);
201 if (mUseMC) {
202 pc.outputs().snapshot(OutputRef{"labels"}, labels);
203 }
204
205 // stop here if they were the last IR frames to select
206 if (irFrames.empty() || irFrames.back().isLast()) {
207 pc.services().get<ControlService>().endOfStream();
208 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
209 }
210 }
211};
212
213DataProcessorSpec getDigitReaderSpec(bool useMC, std::string_view specName,
214 std::string_view outputDigitDataDescription,
215 std::string_view outputDigitRofDataDescription,
216 std::string_view outputDigitLabelDataDescription)
217{
218 std::string output = fmt::format("digits:MCH/{}/0;rofs:MCH/{}/0", outputDigitDataDescription, outputDigitRofDataDescription);
219 if (useMC) {
220 output += fmt::format(";labels:MCH/{}/0", outputDigitLabelDataDescription);
221 }
222
223 std::vector<OutputSpec> outputs;
224 auto matchers = select(output.c_str());
225 for (auto& matcher : matchers) {
226 outputs.emplace_back(DataSpecUtils::asOutputSpec(matcher));
227 }
228
229 return DataProcessorSpec{
230 std::string(specName),
231 Inputs{},
232 outputs,
233 AlgorithmSpec{adaptFromTask<DigitsReaderDeviceDPL>(useMC)},
234 Options{{"mch-digit-infile", VariantType::String, "mchdigits.root", {"Name of the input file"}},
235 {"input-dir", VariantType::String, "none", {"Input directory"}},
236 {"no-time-offset", VariantType::Bool, false, {"no time offset between IRFrames and digits"}}}};
237}
238} // namespace mch
239} // namespace o2
std::vector< framework::ConcreteDataMatcher > matchers
std::vector< std::string > labels
int32_t i
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.
void output(const std::map< std::string, ChannelStat > &channels)
Definition rawdump.cxx:197
Definition of a container to keep Monte Carlo truth external to simulation objects.
Definition of the MCH ROFrame record.
const char * specName
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)
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, std::string_view specName="mch-digit-reader", std::string_view outputDigitDataDescription="DIGITS", std::string_view outputDigitRofDataDescription="DIGITROFS", std::string_view outputDigitLabelDataDescription="DIGITLABELS")
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
static OutputSpec asOutputSpec(InputSpec const &spec)
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