Project
Loading...
Searching...
No Matches
RawDataManager.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
13
14#include <RtypesCore.h>
15#include <TSystem.h>
16#include <TFile.h>
17#include <TTree.h>
18#include <boost/range/distance.hpp>
19#include <boost/range/iterator_range_core.hpp>
20#include <iterator>
22#include "Framework/Logger.h"
23
24#include <set>
25#include <utility>
26#include <algorithm>
27#include <execution>
28
29using namespace o2::trd;
30
33{
34 if (a.getDetector() != b.getDetector()) {
35 return a.getDetector() < b.getDetector();
36 }
37
38 if (a.getPadRow() != b.getPadRow()) {
39 return a.getPadRow() < b.getPadRow();
40 }
41
42 if (a.getROB() != b.getROB()) {
43 return a.getROB() < b.getROB();
44 }
45
46 if (a.getMCM() != b.getMCM()) {
47 return a.getMCM() < b.getMCM();
48 }
49
50 // sort channels in descending order, to ensure ordering of pad columns
51 if (a.getChannel() != b.getChannel()) {
52 return a.getChannel() > b.getChannel();
53 }
54
55 return true;
56}
57
60{
61 // upper bits of hcid and padrow from Tracklet64 word
62 const uint64_t det_row_mask = 0x0ffde00000000000;
63
64 // lowest bit of hcid (side), MCM col and pos from Tracklet64 word
65 const uint64_t col_pos_mask = 0x00011fff00000000;
66
67 auto a_det_row = a.getTrackletWord() & det_row_mask;
68 auto b_det_row = b.getTrackletWord() & det_row_mask;
69
70 if (a_det_row != b_det_row) {
71 return a_det_row < b_det_row;
72 }
73
74 auto a_col_pos = a.getTrackletWord() & col_pos_mask;
75 auto b_col_pos = b.getTrackletWord() & col_pos_mask;
76
77 return a_col_pos < b_col_pos;
78};
79
81{
82 if (a.getDetector() != b.getDetector()) {
83 return a.getDetector() < b.getDetector();
84 }
85
86 if (a.getPadRow() != b.getPadRow()) {
87 return a.getPadRow() < b.getPadRow();
88 }
89
90 if (a.getPadCol() != b.getPadCol()) {
91 return a.getPadCol() < b.getPadCol();
92 }
93
94 return true;
95}
96
98{
99 std::stable_sort(std::begin(digits), std::end(digits), comp_digit);
100 std::stable_sort(std::begin(tracklets), std::end(tracklets), comp_tracklet);
101 std::stable_sort(std::begin(hits), std::end(hits), comp_spacepoint);
102}
103
104template <typename keyfunc>
105std::vector<RawDataSpan> RawDataSpan::iterateBy()
106{
107 // an map for keeping track which ranges correspond to which key
108 std::map<uint32_t, RawDataSpan> spanmap;
109
110 // sort digits and tracklets
111 sort();
112
113 // add all the digits to a map
114 for (auto cur = digits.begin(); cur != digits.end(); /* noop */) {
115 // calculate the key of the current (first unprocessed) digit
116 auto key = keyfunc::key(*cur);
117 // find the first digit with a different key
118 auto nxt = std::find_if(cur, digits.end(), [key](auto x) { return keyfunc::key(x) != key; });
119 // store the range cur:nxt in the map
120 spanmap[key].digits = boost::make_iterator_range(cur, nxt);
121 // continue after this range
122 cur = nxt;
123 }
124
125 // add tracklets to the map
126 for (auto cur = tracklets.begin(); cur != tracklets.end(); /* noop */) {
127 auto key = keyfunc::key(*cur);
128 auto nxt = std::find_if(cur, tracklets.end(), [key](auto x) { return keyfunc::key(x) != key; });
129 spanmap[key].tracklets = boost::make_iterator_range(cur, nxt);
130 cur = nxt;
131 }
132
133 // spanmap contains all TRD data - either digits or tracklets. Now we insert hit information into these spans. The
134 // tricky part is that space points or hits can belong to more than one MCM, i.e. they could appear in two spans.
135 // We keep the begin iterator for each key in a map
136 std::map<uint32_t, std::vector<HitPoint>::iterator> firsthit;
137 for (auto cur = hits.begin(); cur != hits.end(); ++cur) {
138 // calculate the keys for this hit
139 auto keys = keyfunc::keys(*cur);
140 // if we are not yet aware of this key, register the current hit as the first hit
141 for (auto key : keys) {
142 firsthit.insert({key, cur});
143 }
144 // remote the keys from the firsthit map that are no longer found in the hits
145 for (auto it = firsthit.cbegin(); it != firsthit.cend(); /* no increment */) {
146 if (keys.find(it->first) == keys.end()) {
147 spanmap[it->first].hits = boost::make_iterator_range(it->second, cur);
148 it = firsthit.erase(it);
149 } else {
150 ++it;
151 }
152 }
153 }
154
155 // convert the map of spans into a vector, as we do not need the access by key
156 // and longer, and having a vector makes the looping by the user easier.
157 std::vector<RawDataSpan> spans;
158 transform(spanmap.begin(), spanmap.end(), back_inserter(spans), [](auto const& pair) { return pair.second; });
159
160 return spans;
161}
162
166struct PadRowID {
168 template <typename T>
169 static uint32_t key(const T& x)
170 {
171 return 100 * x.getDetector() + x.getPadRow();
172 }
173
174 static std::set<uint32_t> keys(const o2::trd::ChamberSpacePoint& x)
175 {
176 uint32_t key = 100 * x.getDetector() + x.getPadRow();
177 return {key};
178 }
179
180 static bool match(const uint32_t key, const o2::trd::ChamberSpacePoint& x)
181 {
182 return key == 100 * x.getDetector() + x.getPadRow();
183 }
184};
185
186// instantiate the template to iterate by padrow
187template std::vector<RawDataSpan> RawDataSpan::iterateBy<PadRowID>();
188
189// non-template wrapper function to keep PadRowID within the .cxx file
190std::vector<RawDataSpan> RawDataSpan::iterateByPadRow() { return iterateBy<PadRowID>(); }
191
194struct MCM_ID {
195 template <typename T>
196 static uint32_t key(const T& x)
197 {
198 return 1000 * x.getDetector() + 8 * x.getPadRow() + 4 * (x.getROB() % 2) + x.getMCM() % 4;
199 }
200
201 static std::set<uint32_t> keys(const o2::trd::ChamberSpacePoint& x)
202 {
203 uint32_t detrow = 1000 * x.getDetector() + 8 * x.getPadRow();
204 uint32_t mcmcol = uint32_t(x.getPadCol() / float(o2::trd::constants::NCOLMCM));
205
206 // float c = x.getPadCol() - float(mcmcol * o2::trd::constants::NCOLMCM);
207 float c = x.getMCMChannel(mcmcol);
208
209 if (c >= 19.0 && mcmcol >= 1) {
210 return {detrow + mcmcol - 1, detrow + mcmcol};
211 } else if (c <= 1.0 && mcmcol <= 6) {
212 return {detrow + mcmcol, detrow + mcmcol + 1};
213 } else {
214 return {detrow + mcmcol};
215 }
216 }
217
218 static int getDetector(uint32_t k) { return k / 1000; }
219 // static int getPadRow(key) {return (key%1000) / 8;}
220 static int getMcmRowCol(uint32_t k) { return k % 1000; }
221};
222
223// template instantion and non-template wrapper function
224template std::vector<RawDataSpan> RawDataSpan::iterateBy<MCM_ID>();
225std::vector<RawDataSpan> RawDataSpan::iterateByMCM() { return iterateBy<MCM_ID>(); }
226
227// I started to implement a struct to iterate by detector, but did not finish this
228// struct DetectorID {
229// /// The static `key` method calculates a padrow ID for digits and tracklets
230// template <typename T>
231// static uint32_t key(const T& x)
232// {
233// return x.getDetector();
234// }
235
236// static std::vector<uint32_t> keys(const o2::trd::ChamberSpacePoint& x)
237// {
238// uint32_t key = x.getDetector();
239// return {key};
240// }
241
242// static bool match(const uint32_t key, const o2::trd::ChamberSpacePoint& x)
243// {
244// return key == x.getDetector();
245// }
246// };
247
248std::vector<TrackSegment> RawDataSpan::makeMCTrackSegments()
249{
250 // define a struct to keep track of the first and last MC hit of one track in one chamber
251 struct SegmentInfo {
252 // The first hit is the hit closest to the anode region, i.e. with the largest x coordinate.
253 size_t firsthit{0}; //
254 // The last hit is the hit closest to the radiator, i.e. with the smallest x coordinate.
255 size_t lasthit{0};
256 float start{-999.9}; // local x cordinate of the first hit, init value ensures any hit updates
257 float end{999.9}; // local x cordinate of the last hit, init value ensures any hit updates
258 };
259 // Keep information about found track segments in a map indexed by track ID and detector number.
260 // If the span only covers (part of) a detector, the detector information is redundant, but in
261 // the case of processing a whole event, the distinction by detector will be needed.
262 std::map<std::pair<int, int>, SegmentInfo> trackSegmentInfo;
263
264 for (int iHit = 0; iHit < hits.size(); ++iHit) {
265 auto hit = hits[iHit];
266
267 // in the following, we will look for track segments using hits in the drift region
268 if (hit.isFromDriftRegion()) {
269 // The first hit is the hit closest to the anode region, i.e. with the largest x coordinate.
270 auto id = std::make_pair(hit.getID(), hit.getDetector());
271 if (hit.getX() > trackSegmentInfo[id].start) {
272 trackSegmentInfo[id].firsthit = iHit;
273 trackSegmentInfo[id].start = hit.getX();
274 }
275 // The last hit is the hit closest to the radiator, i.e. with the smallest x coordinate.
276 if (hit.getX() < trackSegmentInfo[id].end) {
277 trackSegmentInfo[id].lasthit = iHit;
278 trackSegmentInfo[id].end = hit.getX();
279 }
280 }
281 } // hit loop
282
283 std::vector<TrackSegment> trackSegments;
284 for (auto x : trackSegmentInfo) {
285 auto trackid = x.first.first;
286 auto detector = x.first.second;
287 auto firsthit = hits[x.second.firsthit];
288 auto lasthit = hits[x.second.lasthit];
289 trackSegments.emplace_back(firsthit, lasthit, trackid);
290 }
291 return trackSegments;
292}
293
295RawDataManager::RawDataManager(std::filesystem::path dir)
296{
297
298 if (!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir)) {
299 O2ERROR("'%s' is not a directory", dir.c_str());
300 return;
301 }
302
303 // We allways need the trigger records, which are stored in trdtracklets.root.
304 // While at it, let's also set up reading the tracklets.
305 if (!std::filesystem::exists(dir / "trdtracklets.root")) {
306 O2ERROR("'tracklets.root' not found in directory '%s'", dir.c_str());
307 return;
308 }
309
310 mMainFile = new TFile((dir / "trdtracklets.root").c_str());
311 mMainFile->GetObject("o2sim", mDataTree);
312
313 // set up the branches we want to read
314 mDataTree->SetBranchAddress("Tracklet", &mTracklets);
315 mDataTree->SetBranchAddress("TrackTrg", &mTrgRecords);
316
317 if (std::filesystem::exists(dir / "trddigits.root")) {
318 mDataTree->AddFriend("o2sim", (dir / "trddigits.root").c_str());
319 mDataTree->SetBranchAddress("TRDDigit", &mDigits);
320 }
321
322 if (std::filesystem::exists(dir / "o2match_itstpc.root")) {
323 mDataTree->AddFriend("matchTPCITS", (dir / "o2match_itstpc.root").c_str());
324 mDataTree->SetBranchAddress("TPCITS", &mTracks);
325 }
326
327 // For data, we need info about time frames to match ITS and TPC tracks to trigger records.
328 if (std::filesystem::exists(dir / "o2_tfidinfo.root")) {
329 TFile fInTFID((dir / "o2_tfidinfo.root").c_str());
330 mTFIDs = (std::vector<o2::dataformats::TFIDInfo>*)fInTFID.Get("tfidinfo");
331 }
332
333 // For MC, we first read the collision context
334 if (std::filesystem::exists(dir / "collisioncontext.root")) {
335 TFile fInCollCtx((dir / "collisioncontext.root").c_str());
336 mCollisionContext = (o2::steer::DigitizationContext*)fInCollCtx.Get("DigitizationContext");
337 // mCollisionContext->printCollisionSummary();
338 }
339
340 // We create the MC TTree using event header and tracks from the kinematics file
341 if (std::filesystem::exists(dir / "o2sim_Kine.root")) {
342 mMCFile = new TFile((dir / "o2sim_Kine.root").c_str());
343 mMCFile->GetObject("o2sim", mMCTree);
344 mMCTree->SetBranchAddress("MCEventHeader.", &mMCEventHeader);
345 mMCTree->SetBranchAddress("MCTrack", &mMCTracks);
346 }
347
348 // We then add the TRD hits to the MC tree
349 if (mMCFile && std::filesystem::exists(dir / "o2sim_HitsTRD.root")) {
350 mMCTree->AddFriend("o2sim", (dir / "o2sim_HitsTRD.root").c_str());
351 mMCTree->SetBranchAddress("TRDHit", &mHits);
352 }
353}
354
356{
357 if (!mDataTree->GetEntry(mTimeFrameNo)) {
358 // loading time frame will fail at end of file
359 return false;
360 }
361
362 mEventNo = 0;
363 mTimeFrameNo++;
364
365 O2INFO("Loaded data for time frame #%d with %d TRD trigger records, %d digits and %d tracklets",
366 mTimeFrameNo, mTrgRecords->size(), mDigits->size(), mTracklets->size());
367
368 return true;
369}
370
372{
373 // get the next trigger record
374 if (mEventNo >= mTrgRecords->size()) {
375 return false;
376 }
377 mTriggerRecord = mTrgRecords->at(mEventNo);
378 O2INFO("Processing event: orbit %d bc %04d with %d digits and %d tracklets",
379 mTriggerRecord.getBCData().orbit, mTriggerRecord.getBCData().bc,
380 mTriggerRecord.getNumberOfDigits(), mTriggerRecord.getNumberOfTracklets());
381
382 if (mCollisionContext) {
383
384 // clear MC data
385 mHitPoints.clear();
386
387 for (int i = 0; i < mCollisionContext->getNCollisions(); ++i) {
388 auto evrec = mCollisionContext->getEventRecords()[i];
389 if (abs(mTriggerRecord.getBCData().differenceInBCNS(evrec)) <= 3000) {
390 // if (mMCReader) {
391 mMCTree->GetEntry(i);
392 // }
393
394 O2INFO("Loaded matching MC event #%d with time offset %f ns and %d hits",
395 i, mTriggerRecord.getBCData().differenceInBCNS(evrec), mHits->size());
396
397 // convert hits to spacepoints
399 for (auto& hit : *mHits) {
400 mHitPoints.emplace_back(ctrans->MakeSpacePoint(hit), hit.GetCharge());
401 }
402 }
403 }
404 }
405
406 mEventNo++;
407 return true;
408}
409
411{
412 RawDataSpan ev;
413
414 ev.digits = boost::make_iterator_range_n(mDigits->begin() + mTriggerRecord.getFirstDigit(), mTriggerRecord.getNumberOfDigits());
415 ev.tracklets = boost::make_iterator_range_n(mTracklets->begin() + mTriggerRecord.getFirstTracklet(), mTriggerRecord.getNumberOfTracklets());
416
417 ev.hits = boost::make_iterator_range(mHitPoints.begin(), mHitPoints.end());
418
419 auto evtime = getTriggerTime();
420
421 // if (tpctracks) {
422 // for (auto &track : *mTpcTracks) {
423 // // // auto tracktime = track.getTimeMUS().getTimeStamp();
424 // auto dtime = track.getTime0() / 5.0 - evtime;
425 // if (dtime > mMatchTimeMinTPC && dtime < mMatchTimeMaxTPC) {
426 // ev.mTpcTracks.push_back(track);
427 // }
428 // }
429 // }
430
431 if (mTracks) {
432 for (auto& track : *mTracks) {
433 // // auto tracktime = track.getTimeMUS().getTimeStamp();
434 // auto dtime = track.getTimeMUS().getTimeStamp() - evtime;
435 // if (dtime > mMatchTimeMinTPC && dtime < mMatchTimeMaxTPC) {
436 // ev.tracks.push_back(track);
437
438 // for(int ly=0; ly<6; ++ly) {
439 // auto point = extra.extrapolate(track.getParamOut(), ly);
440 // if (point.isValid()) {
441 // ev.evtrackpoints.push_back(point);
442 // }
443 // }
444 // }
445 }
446 }
447
448 // ev.trackpoints.begin() = ev.evtrackpoints.begin();
449 // ev.trackpoints.end() = ev.evtrackpoints.end();
450
451 return ev;
452}
453
455{
456 if (mTFIDs) {
457 return mTFIDs->at(mTimeFrameNo - 1);
458 } else {
460 }
461}
462
464{
465 auto tfid = getTimeFrameInfo();
466
467 if (tfid.isDummy()) {
468 return mTriggerRecord.getBCData().bc2ns() * 1e-3;
469 } else {
470 o2::InteractionRecord intrec = {0, tfid.firstTForbit};
471 return mTriggerRecord.getBCData().differenceInBCMUS(intrec);
472 }
473}
474
476{
477 std::ostringstream out;
478 if (!mMainFile) {
479 out << "RawDataManager is not connected to any files" << std::flush;
480 return out.str();
481 }
482 if (!mDataTree) {
483 out << "ERROR: main datatree not connected" << std::flush;
484 return out.str();
485 }
486 out << "Main file:" << mMainFile->GetPath() << " has " << mDataTree->GetEntries() << " time frames " << std::endl;
487 if (mDataTree->GetFriend("TRDDigit")) {
488 out << "digits" << std::endl;
489 }
490 if (mDataTree->GetFriend("TPCITS")) {
491 out << "tpc its matches" << std::endl;
492 }
493
494 if (mTFIDs) {
495 out << mTFIDs->size() << " TFIDs were read from o2_tfidinfo.root" << std::flush;
496 }
497 return out.str();
498}
499
501{
502 std::ostringstream out;
503 out << "## Time frame " << mTimeFrameNo << ": ";
504 // out << mDatareader->GetEntries() << "";
505 return out.str();
506}
507
509{
510 std::ostringstream out;
511 out << "## TF:Event " << mTimeFrameNo << ":" << mEventNo << ": "
512 // << hits->getsize() << " hits "
513 << mTriggerRecord.getNumberOfDigits() << " digits and "
514 << mTriggerRecord.getNumberOfTracklets() << " tracklets";
515 return out.str();
516}
int32_t i
#define O2ERROR(...)
Definition Logger.h:18
#define O2INFO(...)
Definition Logger.h:17
bool comp_digit(const o2::trd::Digit &a, const o2::trd::Digit &b)
comparison function to order digits by det / row / MCM / -channel
bool comp_tracklet(const o2::trd::Tracklet64 &a, const o2::trd::Tracklet64 &b)
comparison function to order tracklets by det / row / MCM / channel
bool comp_spacepoint(const ChamberSpacePoint &a, const ChamberSpacePoint &b)
uint32_t c
Definition RawData.h:2
StringRef key
std::vector< o2::InteractionTimeRecord > & getEventRecords(bool withQED=false)
static CoordinateTransformer * instance()
RawDataManager(std::filesystem::path dir=".")
The RawDataManager constructor: connects all data files and sets up trees, readers etc.
o2::dataformats::TFIDInfo getTimeFrameInfo()
access time frame info
const BCData & getBCData() const
int getFirstTracklet() const
int getNumberOfDigits() const
int getNumberOfTracklets() const
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint GLuint end
Definition glcorearb.h:469
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint start
Definition glcorearb.h:469
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLuint id
Definition glcorearb.h:650
constexpr int NCOLMCM
the number of pads per MCM
Definition Constants.h:53
static uint32_t key(const T &x)
static std::set< uint32_t > keys(const o2::trd::ChamberSpacePoint &x)
static int getMcmRowCol(uint32_t k)
static int getDetector(uint32_t k)
static uint32_t key(const T &x)
The static key method calculates a padrow ID for digits and tracklets.
static bool match(const uint32_t key, const o2::trd::ChamberSpacePoint &x)
static std::set< uint32_t > keys(const o2::trd::ChamberSpacePoint &x)
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
static double bc2ns(int bc, unsigned int orbit)
float differenceInBCMUS(const InteractionRecord &other) const
float differenceInBCNS(const InteractionRecord &other) const
std::vector< RawDataSpan > iterateByPadRow()
boost::iterator_range< std::vector< o2::trd::Tracklet64 >::iterator > tracklets
std::vector< TrackSegment > makeMCTrackSegments()
boost::iterator_range< std::vector< o2::trd::Digit >::iterator > digits
std::vector< RawDataSpan > iterateByMCM()
std::vector< RawDataSpan > iterateBy()
boost::iterator_range< std::vector< HitPoint >::iterator > hits