Project
Loading...
Searching...
No Matches
rawReaderPadRootify.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
14
15#include <bitset>
16#include <iostream>
17#include <boost/program_options.hpp>
18#include <gsl/span>
19#include <fairlogger/Logger.h>
20
21#include <TFile.h>
22#include <TTree.h>
23
29#include "Headers/RDHAny.h"
30
31namespace bpo = boost::program_options;
32
33// Data for tree
35 static constexpr int NASICS = 20;
36 static constexpr int NCHANNELS = 72;
37 static constexpr int WINDUR = 20;
38 static constexpr int NTRIGGER = 8;
39
40 int mBCid;
41 int mOrbit;
61
62 TTree* mTree = nullptr;
63
64 void connectTree(TTree* padtree)
65 {
66 mTree = padtree;
67 mTree->Branch("ORBIT", &mOrbit, "ORBIT/I");
68 mTree->Branch("BCID", &mBCid, "BCID/I");
69 mTree->Branch("HEAD0", &mHeader0, "HEAD0[20]/I");
70 mTree->Branch("FOURBIT0", &mFOURBIT0, "FOURBIT0[20]/I");
71 mTree->Branch("BCID0", &mBCID0, "BCID0[20]/I");
72 mTree->Branch("WADD0", &mWADD0, "WADD0[20]/I");
73 mTree->Branch("TRAILER0", &mTrailer0, "TRAILER0[20]/I");
74 mTree->Branch("HEAD1", &mHeader1, "HEAD1[20]/I");
75 mTree->Branch("FOURBIT1", &mFOURBIT1, "FOURBIT1[20]/I");
76 mTree->Branch("BCID1", &mBCID1, "BCID1[20]/I");
77 mTree->Branch("WADD1", &mWADD1, "WADD1[20]/I");
78 mTree->Branch("TRAILER1", &mTrailer1, "TRAILER1[20]/I");
79 mTree->Branch("ASIC", &mASICNum, "ASICNum[20]/I");
80 mTree->Branch("ADC", &mADC, "ADC[20][72]/I");
81 mTree->Branch("TOA", &mTOA, "TOA[20][72]/I");
82 mTree->Branch("TOT", &mTOT, "TOT[20][72]/I");
83 mTree->Branch("CALIB0", &mCalib0, "CALIB0[20]/I");
84 mTree->Branch("CALIB1", &mCalib1, "CALIB1[20]/I");
85 mTree->Branch("TRIGHEADER0", &mTriggerhead0, "TRIGHEADER0[20][20]/I");
86 mTree->Branch("TRIGHEADER1", &mTriggerhead1, "TRIGHEADER1[20][20]/I");
87 mTree->Branch("TRIGDATA", &mTriggerdata, "TRIGDATA[20][8][20]/I");
88 }
89
90 void reset()
91 {
92 mBCid = 0;
93 mOrbit = 0;
94 memset(mHeader0, 0, sizeof(int) * 20);
95 memset(mFOURBIT0, 0, sizeof(int) * 20);
96 memset(mBCID0, 0, sizeof(int) * 20);
97 memset(mWADD0, 0, sizeof(int) * 20);
98 memset(mTrailer0, 0, sizeof(int) * 20);
99 memset(mHeader1, 0, sizeof(int) * 20);
100 memset(mFOURBIT1, 0, sizeof(int) * 20);
101 memset(mBCID1, 0, sizeof(int) * 20);
102 memset(mWADD1, 0, sizeof(int) * 20);
103 memset(mTrailer1, 0, sizeof(int) * 20);
104 memset(mASICNum, 0, sizeof(int) * 20);
105 memset(mADC, 0, sizeof(int) * 20 * 72);
106 memset(mTOA, 0, sizeof(int) * 20 * 72);
107 memset(mTOT, 0, sizeof(int) * 20 * 72);
108 memset(mCalib0, 0, sizeof(int) * 20);
109 memset(mCalib1, 0, sizeof(int) * 20);
110 memset(mTriggerhead0, 0, sizeof(int) * 20 * 20);
111 memset(mTriggerhead1, 0, sizeof(int) * 20 * 20);
112 memset(mTriggerdata, 0, sizeof(int) * 20 * 8 * 20);
113 }
114
116 {
117 mBCid = ir.bc;
118 mOrbit = ir.orbit;
119 }
120
122 {
123 for (int iasic = 0; iasic < NASICS; iasic++) {
124 auto& asicdata = data.getDataForASIC(iasic);
125 auto& asicraw = asicdata.getASIC();
126 mASICNum[iasic] = iasic;
127 mHeader0[iasic] = asicraw.getFirstHeader().mHeader;
128 mFOURBIT0[iasic] = asicraw.getFirstHeader().mFourbit;
129 mBCID0[iasic] = asicraw.getFirstHeader().mBCID;
130 mWADD0[iasic] = asicraw.getFirstHeader().mWADD;
131 mTrailer0[iasic] = asicraw.getFirstHeader().mTrailer;
132 mHeader1[iasic] = asicraw.getSecondHeader().mHeader;
133 mFOURBIT1[iasic] = asicraw.getSecondHeader().mFourbit;
134 mBCID1[iasic] = asicraw.getSecondHeader().mBCID;
135 mWADD1[iasic] = asicraw.getSecondHeader().mWADD;
136 mTrailer1[iasic] = asicraw.getSecondHeader().mTrailer;
137 mCalib0[iasic] = asicraw.getFirstCalib().mADC;
138 mCalib1[iasic] = asicraw.getSecondCalib().mADC;
139 for (auto ichannel = 0; ichannel < NCHANNELS; ichannel++) {
140 mADC[iasic][ichannel] = asicraw.getChannel(ichannel).getADC();
141 mTOT[iasic][ichannel] = asicraw.getChannel(ichannel).getTOT();
142 mTOA[iasic][ichannel] = asicraw.getChannel(ichannel).getTOA();
143 }
144 auto triggerdata = asicdata.getTriggerWords();
145 for (auto iwin = 0; iwin < WINDUR; iwin++) {
146 mTriggerhead0[iasic][iwin] = triggerdata[iwin].mHeader0;
147 mTriggerhead1[iasic][iwin] = triggerdata[iwin].mHeader1;
148 mTriggerdata[iasic][0][iwin] = triggerdata[iwin].mTrigger0;
149 mTriggerdata[iasic][1][iwin] = triggerdata[iwin].mTrigger1;
150 mTriggerdata[iasic][2][iwin] = triggerdata[iwin].mTrigger2;
151 mTriggerdata[iasic][3][iwin] = triggerdata[iwin].mTrigger3;
152 mTriggerdata[iasic][4][iwin] = triggerdata[iwin].mTrigger4;
153 mTriggerdata[iasic][5][iwin] = triggerdata[iwin].mTrigger5;
154 mTriggerdata[iasic][6][iwin] = triggerdata[iwin].mTrigger6;
155 mTriggerdata[iasic][7][iwin] = triggerdata[iwin].mTrigger7;
156 }
157 }
158 }
159
160 void fillTree()
161 {
162 mTree->Fill();
163 }
164};
165
166int convertPadData(gsl::span<const char> padrawdata, const o2::InteractionRecord& currentir, PadTreeData& rootified)
167{
168 auto payloadsizeGBT = padrawdata.size() * sizeof(char) / sizeof(o2::focal::PadGBTWord);
169 auto gbtdata = gsl::span<const o2::focal::PadGBTWord>(reinterpret_cast<const o2::focal::PadGBTWord*>(padrawdata.data()), payloadsizeGBT);
170 o2::focal::PadDecoder decoder;
171
172 constexpr std::size_t EVENTSIZEPADGBT = 1180;
173 int nevents = gbtdata.size() / EVENTSIZEPADGBT;
174 for (int iev = 0; iev < nevents; iev++) {
175 decoder.reset();
176 rootified.reset();
177 decoder.decodeEvent(gbtdata.subspan(iev * EVENTSIZEPADGBT, EVENTSIZEPADGBT));
178 rootified.setInteractionRecord(currentir);
179 rootified.fill(decoder.getData());
180 rootified.fillTree();
181 }
182 return nevents;
183}
184
185int main(int argc, char** argv)
186{
187 bpo::variables_map vm;
188 bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) +
189 " <cmds/options>\n"
190 " Tool will decode the DDLx data for EMCAL 0\n"
191 "Commands / Options");
192 bpo::options_description opt_hidden("");
193 bpo::options_description opt_all;
194 bpo::positional_options_description opt_pos;
195
196 try {
197 auto add_option = opt_general.add_options();
198 add_option("help,h", "Print this help message");
199 add_option("verbose,v", bpo::value<uint32_t>()->default_value(0), "Select verbosity level [0 = no output]");
200 add_option("version", "Print version information");
201 add_option("input-file,i", bpo::value<std::string>()->required(), "Specifies input file. Multiple files can be parsed separated by ,");
202 add_option("output-file,o", bpo::value<std::string>()->default_value("FOCALPadData.root"), "Output file for rootified data");
203 add_option("readout,r", bpo::value<std::string>()->default_value("RORC"), "Readout mode (RORC or CRU)");
204 add_option("debug,d", bpo::value<uint32_t>()->default_value(0), "Select debug output level [0 = no debug output]");
205
206 opt_all.add(opt_general).add(opt_hidden);
207 bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm);
208
209 if (vm.count("help") || argc == 1) {
210 std::cout << opt_general << std::endl;
211 exit(0);
212 }
213
214 if (vm.count("version")) {
215 // std::cout << GitInfo();
216 exit(0);
217 }
218
219 bpo::notify(vm);
220 } catch (bpo::error& e) {
221 std::cerr << "ERROR: " << e.what() << std::endl
222 << std::endl;
223 std::cerr << opt_general << std::endl;
224 exit(1);
225 } catch (std::exception& e) {
226 std::cerr << e.what() << ", application will now exit" << std::endl;
227 exit(2);
228 }
229
230 auto rawfilename = vm["input-file"].as<std::string>();
231 auto rootfilename = vm["output-file"].as<std::string>();
232 auto readoutmode = vm["readout"].as<std::string>();
233
234 std::vector<std::string> inputfiles;
235 if (rawfilename.find(",") != std::string::npos) {
236 // Multiple input file mode
237 std::stringstream parser(rawfilename);
238 std::string buffer;
239 while (std::getline(parser, buffer, ',')) {
240 LOG(info) << "Adding " << buffer;
241 inputfiles.push_back(buffer);
242 }
243 LOG(info) << "Found " << inputfiles.size() << " input files to process";
244 } else {
245 // Processing just a single input file
246 LOG(info) << "Adding " << rawfilename;
247 inputfiles.push_back(rawfilename);
248 }
249
251 if (readoutmode != "RORC" && readoutmode != "CRU") {
252 LOG(error) << "Unknown readout mode - select RORC or CRU";
253 exit(3);
254 } else if (readoutmode == "RORC") {
255 LOG(info) << "Reconstructing in C-RORC mode";
257 } else {
258 LOG(info) << "Reconstructing in CRU mode";
260 }
261
265 reader.setDefaultReadoutCardType(readout);
266 for (auto rawfile : inputfiles) {
267 LOG(debug) << "Adding " << rawfile << " to raw reader";
268 reader.addFile(rawfile);
269 }
270 reader.init();
271
272 std::unique_ptr<TFile> rootfilewriter(TFile::Open(rootfilename.data(), "RECREATE"));
273 rootfilewriter->cd();
274 TTree* padtree = new TTree("PadData", "PadData");
275 PadTreeData rootified;
276 rootified.connectTree(padtree);
277
278 int nHBFprocessed = 0, nTFprocessed = 0, nEventsProcessed = 0;
279 std::map<int, int> nEvnetsHBF;
280 while (1) {
281 int tfID = reader.getNextTFToRead();
282 if (tfID >= reader.getNTimeFrames()) {
283 LOG(info) << "nothing left to read after " << tfID << " TFs read";
284 break;
285 }
286 std::vector<char> rawtf; // where to put extracted data
287 for (int il = 0; il < reader.getNLinks(); il++) {
288 auto& link = reader.getLink(il);
289
290 auto sz = link.getNextTFSize(); // size in bytes needed for the next TF of this link
291 rawtf.resize(sz);
292 link.readNextTF(rawtf.data());
293 gsl::span<char> dataBuffer(rawtf);
294
295 // Parse
296 std::vector<char> hbfbuffer;
297 int currentpos = 0;
298 o2::InteractionRecord currentir;
299 while (currentpos < dataBuffer.size()) {
300 auto rdh = reinterpret_cast<const o2::header::RDHAny*>(dataBuffer.data() + currentpos);
302 if (o2::raw::RDHUtils::getMemorySize(rdh) == o2::raw::RDHUtils::getHeaderSize(rdh)) {
303 auto trigger = o2::raw::RDHUtils::getTriggerType(rdh);
304 if (trigger & o2::trigger::SOT || trigger & o2::trigger::HB) {
305 if (o2::raw::RDHUtils::getStop(rdh)) {
306 LOG(debug) << "Stop bit received - processing payload";
307 auto nevents = convertPadData(hbfbuffer, currentir, rootified);
308 hbfbuffer.clear();
309 nHBFprocessed++;
310 nEventsProcessed += nevents;
311 auto found = nEvnetsHBF.find(nevents);
312 if (found == nEvnetsHBF.end()) {
313 nEvnetsHBF[nevents] = 1;
314 } else {
315 found->second++;
316 }
317 } else {
318 LOG(debug) << "New HBF or Timeframe";
319 hbfbuffer.clear();
320 currentir.bc = o2::raw::RDHUtils::getTriggerBC(rdh);
321 currentir.orbit = o2::raw::RDHUtils::getTriggerOrbit(rdh);
322 }
323 } else {
324 LOG(error) << "Found unknown trigger" << std::bitset<32>(trigger);
325 }
326 currentpos += o2::raw::RDHUtils::getOffsetToNext(rdh);
327 continue;
328 }
329 if (o2::raw::RDHUtils::getStop(rdh)) {
330 LOG(error) << "Unexpected stop";
331 }
332
333 // non-0 payload size:
334 auto payloadsize = o2::raw::RDHUtils::getMemorySize(rdh) - o2::raw::RDHUtils::getHeaderSize(rdh);
335 int endpoint = static_cast<int>(o2::raw::RDHUtils::getEndPointID(rdh));
336 LOG(debug) << "Next RDH: ";
337 LOG(debug) << "Found endpoint " << endpoint;
338 LOG(debug) << "Found trigger BC: " << o2::raw::RDHUtils::getTriggerBC(rdh);
339 LOG(debug) << "Found trigger Oribt: " << o2::raw::RDHUtils::getTriggerOrbit(rdh);
340 LOG(debug) << "Found payload size: " << payloadsize;
341 LOG(debug) << "Found offset to next: " << o2::raw::RDHUtils::getOffsetToNext(rdh);
342 LOG(debug) << "Stop bit: " << (o2::raw::RDHUtils::getStop(rdh) ? "yes" : "no");
343 LOG(debug) << "Number of GBT words: " << (payloadsize * sizeof(char) / sizeof(o2::focal::PadGBTWord));
344 auto page_payload = dataBuffer.subspan(currentpos + o2::raw::RDHUtils::getHeaderSize(rdh), payloadsize);
345 std::copy(page_payload.begin(), page_payload.end(), std::back_inserter(hbfbuffer));
346 currentpos += o2::raw::RDHUtils::getOffsetToNext(rdh);
347 }
348 }
349 reader.setNextTFToRead(++tfID);
350 nTFprocessed++;
351 }
352 rootfilewriter->Write();
353 LOG(info) << "Processed " << nTFprocessed << " timeframes, " << nHBFprocessed << " HBFs";
354 LOG(info) << "Analyzed " << nEventsProcessed << " events:";
355 LOG(info) << "=============================================================";
356 for (auto& [nevents, nHBF] : nEvnetsHBF) {
357 LOG(info) << " " << nevents << " event(s)/HBF: " << nHBF << " HBFs ...";
358 }
359}
Definition of the 32 Central Trigger System (CTS) Trigger Types defined in https://twiki....
uint8_t endpoint
Definition RawData.h:0
Reader for (multiple) raw data files.
std::ostringstream debug
const PadData & getData() const
Definition PadDecoder.h:37
void decodeEvent(gsl::span< const PadGBTWord > padpayload)
uint32_t getNextTFToRead() const
void setNextTFToRead(uint32_t tf)
void setDefaultDataDescription(const std::string &desc)
void setDefaultDataOrigin(const std::string &orig)
uint32_t getNTimeFrames() const
const LinkData & getLink(int i) const
void setDefaultReadoutCardType(ReadoutCardType t=CRU)
bool addFile(const std::string &sname, o2::header::DataOrigin origin, o2::header::DataDescription desc, ReadoutCardType t=CRU)
GLuint buffer
Definition glcorearb.h:655
GLboolean * data
Definition glcorearb.h:298
constexpr o2::header::DataOrigin gDataOriginFOC
Definition DataHeader.h:583
constexpr o2::header::DataDescription gDataDescriptionRawData
Definition DataHeader.h:597
constexpr uint32_t SOT
Definition Triggers.h:33
constexpr uint32_t HB
Definition Triggers.h:27
int convertPadData(gsl::span< const char > padrawdata, const o2::InteractionRecord &currentir, PadTreeData &rootified)
int mTriggerdata[NASICS][NTRIGGER][WINDUR]
int mTrailer0[NASICS]
int mTriggerhead0[NASICS][WINDUR]
static constexpr int NCHANNELS
int mFOURBIT0[NASICS]
int mADC[NASICS][NCHANNELS]
int mTOA[NASICS][NCHANNELS]
int mTriggerhead1[NASICS][WINDUR]
int mTrailer1[NASICS]
void setInteractionRecord(const o2::InteractionRecord &ir)
static constexpr int NTRIGGER
void connectTree(TTree *padtree)
static constexpr int WINDUR
int mTOT[NASICS][NCHANNELS]
void fill(const o2::focal::PadData &data)
int mFOURBIT1[NASICS]
static constexpr int NASICS
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
static void printRDH(const RDHv4 &rdh)
Definition RDHUtils.cxx:26
#define main
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)