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