1717#include " MIDWorkflow/DigitReaderSpec.h"
1818
1919#include < memory>
20+ #include < stdexcept>
2021#include < sstream>
2122#include < string>
22- #include " DPLUtils/RootTreeReader.h"
23+
24+ #include " TFile.h"
25+ #include " TTree.h"
26+ #include " TTreeReader.h"
27+ #include " TTreeReaderValue.h"
28+
2329#include " Framework/ConfigParamRegistry.h"
2430#include " Framework/ControlService.h"
2531#include " Framework/DataSpecUtils.h"
26- #include " Framework/Logger.h"
27- #include " Framework/Output.h"
2832#include " Framework/Task.h"
2933#include " Framework/WorkflowSpec.h"
34+ #include " Framework/Variant.h"
35+ #include " CommonDataFormat/IRFrame.h"
36+ #include " CommonUtils/IRFrameSelector.h"
37+ #include " CommonUtils/StringUtils.h"
3038#include " SimulationDataFormat/MCTruthContainer.h"
3139#include " DataFormatsMID/ColumnData.h"
3240#include " DataFormatsMID/ROFRecord.h"
3341#include " DataFormatsMID/MCLabel.h"
34- #include " CommonUtils/NameConf.h"
35- #include " CommonUtils/StringUtils.h"
3642
3743using namespace o2 ::framework;
3844
@@ -44,82 +50,165 @@ namespace mid
4450class DigitsReaderDeviceDPL
4551{
4652 public:
47- DigitsReaderDeviceDPL (bool useMC, const std::vector<header::DataDescription>& descriptions)
48- : mUseMC (useMC), mDescriptions (descriptions) {}
53+ DigitsReaderDeviceDPL (bool useMC) : mUseMC (useMC)
54+ {
55+ if (mUseMC ) {
56+ mLabels = std::make_unique<TTreeReaderValue<dataformats::MCTruthContainer<MCLabel>>>(mTreeReader , " MIDDigitMCLabels" );
57+ }
58+ }
4959
5060 void init (InitContext& ic)
5161 {
5262 auto filename = utils::Str::concat_string (utils::Str::rectifyDirectory (ic.options ().get <std::string>(" input-dir" )),
5363 ic.options ().get <std::string>(" mid-digit-infile" ));
54- if (mUseMC ) {
55- mReader = std::make_unique<RootTreeReader>(" o2sim" , filename.c_str (), -1 ,
56- RootTreeReader::PublishingMode::Single,
57- RootTreeReader::BranchDefinition<std::vector<ColumnData>>{
58- Output{header::gDataOriginMID , mDescriptions [0 ], 0 , Lifetime::Timeframe}, " MIDDigit" },
59- RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{
60- Output{header::gDataOriginMID , mDescriptions [1 ], 0 , Lifetime::Timeframe}, " MIDROFRecords" },
61- RootTreeReader::BranchDefinition<dataformats::MCTruthContainer<MCLabel>>{
62- Output{header::gDataOriginMID , mDescriptions [2 ], 0 , Lifetime::Timeframe}, " MIDDigitMCLabels" },
63- &mPublishDigits );
64- } else {
65- mReader = std::make_unique<RootTreeReader>(" o2sim" , filename.c_str (), -1 ,
66- RootTreeReader::PublishingMode::Single,
67- RootTreeReader::BranchDefinition<std::vector<ColumnData>>{
68- Output{header::gDataOriginMID , mDescriptions [0 ], 0 , Lifetime::Timeframe}, " MIDDigit" },
69- RootTreeReader::BranchDefinition<std::vector<ROFRecord>>{
70- Output{header::gDataOriginMID , mDescriptions [1 ], 0 , Lifetime::Timeframe}, " MIDROFRecords" },
71- &mPublishDigits );
64+
65+ connectTree (filename);
66+
67+ if (ic.options ().hasOption (" ignore-irframes" ) && !ic.options ().get <bool >(" ignore-irframes" )) {
68+ mUseIRFrames = true ;
7269 }
7370 }
7471
7572 void run (ProcessingContext& pc)
7673 {
77- if ((++(*mReader ))(pc) == false ) {
78- pc.services ().get <ControlService>().endOfStream ();
74+ if (mUseIRFrames ) {
75+ sendNextIRFrames (pc);
76+ } else {
77+ sendNextTF (pc);
7978 }
8079 }
8180
8281 private:
83- std::unique_ptr<RootTreeReader> mReader {};
84- std::vector<header::DataDescription> mDescriptions {};
82+ TTreeReader mTreeReader {};
83+ TTreeReaderValue<std::vector<ROFRecord>> mRofs = {mTreeReader , " MIDROFRecords" };
84+ TTreeReaderValue<std::vector<ColumnData>> mDigits = {mTreeReader , " MIDDigit" };
85+ std::unique_ptr<TTreeReaderValue<dataformats::MCTruthContainer<MCLabel>>> mLabels {};
8586 bool mUseMC = true ;
87+ bool mUseIRFrames = false ;
88+
89+ void connectTree (std::string filename)
90+ {
91+ auto file = TFile::Open (filename.c_str ());
92+ if (!file || file->IsZombie ()) {
93+ throw std::invalid_argument (fmt::format (" Opening file {} failed" , filename));
94+ }
95+
96+ auto tree = file->Get <TTree>(" o2sim" );
97+ if (!tree) {
98+ throw std::invalid_argument (fmt::format (" Tree o2sim not found in {}" , filename));
99+ }
100+ mTreeReader .SetTree (tree);
101+ mTreeReader .Restart ();
102+ }
103+
104+ void sendNextTF (ProcessingContext& pc)
105+ {
106+ // load the next TF and check its validity (missing branch, ...)
107+ if (!mTreeReader .Next ()) {
108+ throw std::invalid_argument (mTreeReader .fgEntryStatusText [mTreeReader .GetEntryStatus ()]);
109+ }
86110
87- // / structure holding the function to convert and publish the digits
88- RootTreeReader::SpecialPublishHook mPublishDigits {
89- [](std::string_view name, ProcessingContext& pc, Output const & output, char * data) -> bool {
90- if (name == " MIDDigit" ) {
91- auto inputDigits = reinterpret_cast <std::vector<ColumnData>*>(data);
92- std::vector<ColumnData> digits{};
93- digits.insert (digits.end (), inputDigits->begin (), inputDigits->end ());
94- pc.outputs ().snapshot (output, digits);
95- LOG (debug) << " MIDDigitsReader pushed " << digits.size () << " digits" ;
96- return true ;
111+ // send the whole TF
112+ pc.outputs ().snapshot (OutputRef{" rofs" }, *mRofs );
113+ pc.outputs ().snapshot (OutputRef{" digits" }, *mDigits );
114+ if (mUseMC ) {
115+ pc.outputs ().snapshot (OutputRef{" labels" }, **mLabels );
116+ }
117+
118+ // stop here if it was the last one
119+ if (mTreeReader .GetCurrentEntry () + 1 >= mTreeReader .GetEntries ()) {
120+ pc.services ().get <ControlService>().endOfStream ();
121+ pc.services ().get <ControlService>().readyToQuit (QuitRequest::Me);
122+ }
123+ }
124+
125+ void sendNextIRFrames (ProcessingContext& pc)
126+ {
127+ std::vector<ROFRecord> rofs{};
128+ std::vector<ColumnData> digits{};
129+ dataformats::MCTruthContainer<MCLabel> labels{};
130+
131+ // get the IR frames to select
132+ auto irFrames = pc.inputs ().get <gsl::span<dataformats::IRFrame>>(" driverInfo" );
133+
134+ if (!irFrames.empty ()) {
135+ utils::IRFrameSelector irfSel{};
136+ irfSel.setSelectedIRFrames (irFrames, 0 , 0 , 0 , true );
137+ const auto irMin = irfSel.getIRFrames ().front ().getMin ();
138+ const auto irMax = irfSel.getIRFrames ().back ().getMax ();
139+
140+ // load the first TF if not already done
141+ bool loadNextTF = mTreeReader .GetCurrentEntry () < 0 ;
142+
143+ while (true ) {
144+ // load the next TF if requested
145+ if (loadNextTF && !mTreeReader .Next ()) {
146+ throw std::invalid_argument (mTreeReader .fgEntryStatusText [mTreeReader .GetEntryStatus ()]);
147+ }
148+
149+ // look for selected ROFs in this TF and copy them
150+ if (!mRofs ->empty () && mRofs ->front ().interactionRecord <= irMax &&
151+ mRofs ->back ().interactionRecord >= irMin) {
152+ for (const auto & rof : *mRofs ) {
153+ if (irfSel.check (rof.interactionRecord ) != -1 ) {
154+ rofs.emplace_back (rof);
155+ rofs.back ().firstEntry = digits.size ();
156+ rofs.back ().nEntries = rof.nEntries ;
157+ digits.insert (digits.end (), mDigits ->begin () + rof.firstEntry , mDigits ->begin () + rof.getEndIndex ());
158+ if (mUseMC ) {
159+ for (auto idig = 0 ; idig < rof.nEntries ; ++idig) {
160+ labels.addElements (labels.getIndexedSize (), (*mLabels )->getLabels (rof.firstEntry + idig));
161+ }
162+ }
163+ }
164+ }
165+ }
166+
167+ // move to the next TF if needed and if any
168+ if ((mRofs ->empty () || mRofs ->back ().interactionRecord < irMax) &&
169+ mTreeReader .GetCurrentEntry () + 1 < mTreeReader .GetEntries ()) {
170+ loadNextTF = true ;
171+ continue ;
172+ }
173+
174+ break ;
97175 }
98- return false ;
99- }};
176+ }
177+
178+ // send the selected data
179+ pc.outputs ().snapshot (OutputRef{" rofs" }, rofs);
180+ pc.outputs ().snapshot (OutputRef{" digits" }, digits);
181+ if (mUseMC ) {
182+ pc.outputs ().snapshot (OutputRef{" labels" }, labels);
183+ }
184+
185+ // stop here if they were the last IR frames to select
186+ if (irFrames.empty () || irFrames.back ().isLast ()) {
187+ pc.services ().get <ControlService>().endOfStream ();
188+ pc.services ().get <ControlService>().readyToQuit (QuitRequest::Me);
189+ }
190+ }
100191};
101192
102193DataProcessorSpec getDigitReaderSpec (bool useMC, const char * baseDescription)
103194{
104195 std::vector<OutputSpec> outputs;
105- std::vector<header::DataDescription> descriptions;
106196 std::stringstream ss;
107- ss << " A :" << header::gDataOriginMID .as <std::string>() << " /" << baseDescription << " /0" ;
108- ss << " ;B :" << header::gDataOriginMID .as <std::string>() << " /" << baseDescription << " ROF/0" ;
197+ ss << " digits :" << header::gDataOriginMID .as <std::string>() << " /" << baseDescription << " /0" ;
198+ ss << " ;rofs :" << header::gDataOriginMID .as <std::string>() << " /" << baseDescription << " ROF/0" ;
109199 if (useMC) {
110- ss << " ;C :" << header::gDataOriginMID .as <std::string>() << " /" << baseDescription << " LABELS/0" ;
200+ ss << " ;labels :" << header::gDataOriginMID .as <std::string>() << " /" << baseDescription << " LABELS/0" ;
111201 }
112202 auto matchers = select (ss.str ().c_str ());
113203 for (auto & matcher : matchers) {
114204 outputs.emplace_back (DataSpecUtils::asOutputSpec (matcher));
115- descriptions.emplace_back (DataSpecUtils::asConcreteDataDescription (matcher));
116205 }
117206
118207 return DataProcessorSpec{
119208 " MIDDigitsReader" ,
120209 Inputs{},
121210 outputs,
122- AlgorithmSpec{adaptFromTask<DigitsReaderDeviceDPL>(useMC, descriptions )},
211+ AlgorithmSpec{adaptFromTask<DigitsReaderDeviceDPL>(useMC)},
123212 Options{{" mid-digit-infile" , VariantType::String, " middigits.root" , {" Name of the input file" }},
124213 {" input-dir" , VariantType::String, " none" , {" Input directory" }}}};
125214}
0 commit comments