Project
Loading...
Searching...
No Matches
Trap2CRU.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// TRD Trap2CRU class //
15// Class to take the trap output that arrives at the cru and produce //
16// the cru output. A data mapping more than a cru simulator //
18
19#include <string>
20
29#include "TFile.h"
30#include "TTree.h"
31#include <TStopwatch.h>
32#include <cassert>
33#include <fstream>
34#include <iostream>
35#include <iomanip>
36#include <array>
37#include <vector>
38#include <typeinfo>
39#include "fairlogger/Logger.h"
40
41using namespace o2::raw;
42
43namespace o2
44{
45namespace trd
46{
47
49 int32_t flpid; // hostname of flp
50 int32_t cruHWID = 0; // cru ID taken from ecs
51 int32_t HCID = 0; // hcid of first link
52};
53
54//this should probably come from ccdb or some authoritive source.
55//I doubt this is going to change very often, but ... famous last words.
56//
58 {
59 {166, 250, 0},
60 {166, 583, 0},
61 {166, 585, 0},
62 {167, 248, 0},
63 {167, 249, 0},
64 {167, 596, 0},
65 {168, 246, 0},
66 {168, 247, 0},
67 {168, 594, 0},
68 {169, 252, 0},
69 {169, 253, 0},
70 {169, 254, 0},
71 {170, 245, 0},
72 {170, 593, 0},
73 {170, 595, 0},
74 {171, 258, 0},
75 {171, 259, 0},
76 {171, 260, 0},
77 {172, 579, 0},
78 {172, 581, 0},
79 {172, 586, 0},
80 {173, 578, 0},
81 {173, 580, 0},
82 {173, 597, 0},
83 {174, 256, 0},
84 {174, 582, 0},
85 {174, 587, 0},
86 {175, 251, 0},
87 {175, 255, 0},
88 {175, 588, 0},
89 {176, 264, 0},
90 {176, 591, 0},
91 {176, 592, 0},
92 {177, 263, 0},
93 {177, 589, 0},
94 {177, 590, 0}};
95
96Trap2CRU::Trap2CRU(const std::string& outputDir, const std::string& inputdigitsfilename, const std::string& inputtrackletsfilename)
97{
98 mOutputDir = outputDir;
99 mInputDigitsFileName = inputdigitsfilename;
100 mInputTrackletsFileName = inputtrackletsfilename;
101 mCurrentDigit = 0;
102 mCurrentTracklet = 0;
103}
104
106{
107 mDigitsFile = TFile::Open(mInputDigitsFileName.data());
108 if (mDigitsFile != nullptr && !mDigitsFile->IsZombie()) {
109 mDigitsTree = (TTree*)mDigitsFile->Get("o2sim");
110 mDigitsTree->SetBranchAddress("TRDDigit", &mDigitsPtr); // the branch with the actual digits
111 } else {
112 LOG(warn) << " cant open file containing digit tree";
113 }
114 mTrackletsFile = TFile::Open(mInputTrackletsFileName.data());
115 if (mTrackletsFile != nullptr && !mTrackletsFile->IsZombie()) {
116 mTrackletsTree = (TTree*)mTrackletsFile->Get("o2sim");
117 mTrackletsTree->SetBranchAddress("Tracklet", &mTrackletsPtr); // the branch with the actual tracklets.
118 mTrackletsTree->SetBranchAddress("TrackTrg", &mTrackletTriggerRecordsPtr); // branch with trigger records for digits
119 } else {
120 LOG(fatal) << " cant open file containing tracklet tree";
121 }
122}
123
125{
126 auto sortstart = std::chrono::high_resolution_clock::now();
127 //build indexes
128 // digits first
129 mDigitsIndex.resize(mDigits.size());
130 std::iota(mDigitsIndex.begin(), mDigitsIndex.end(), 0);
131
132 for (auto& trig : mTrackletTriggerRecords) {
133 if (trig.getNumberOfTracklets() > 0) {
134 if (mVerbosity) {
135 LOG(debug) << " sorting tracklets from : " << trig.getFirstTracklet() << " till " << trig.getFirstTracklet() + trig.getNumberOfTracklets();
136 }
137 // sort to link order *NOT* hcid order ...
138 // link is defined by stack,layer,halfchamberside.
139 // tracklet data we have hcid,padrow,colum.
140 // hcid/2 = detector, detector implies stack and layer, and hcid odd/even gives side.
141 std::stable_sort(std::begin(mTracklets) + trig.getFirstTracklet(), std::begin(mTracklets) + trig.getNumberOfTracklets() + trig.getFirstTracklet(),
142 [this](auto&& t1, auto&& t2) {
143 int link1 = (!mLinkMap) ? HelperMethods::getLinkIDfromHCID(t1.getHCID()) : mLinkMap->getLink(t1.getHCID());
144 int link2 = (!mLinkMap) ? HelperMethods::getLinkIDfromHCID(t2.getHCID()) : mLinkMap->getLink(t2.getHCID());
145 if (link1 != link2) {
146 return link1 < link2;
147 }
148 if (t1.getPadRow() != t2.getPadRow()) {
149 return t1.getPadRow() < t2.getPadRow();
150 }
151 return t1.getMCM() < t2.getMCM();
152 });
153 }
154 if (trig.getNumberOfDigits() != 0) {
155 if (mVerbosity) {
156 LOG(debug) << " sorting digits from : " << trig.getFirstDigit() << " till " << trig.getFirstDigit() + trig.getNumberOfDigits();
157 }
158 std::stable_sort(mDigitsIndex.begin() + trig.getFirstDigit(), mDigitsIndex.begin() + trig.getNumberOfDigits() + trig.getFirstDigit(),
159 [this](const uint32_t i, const uint32_t j) {
160 int link1=HelperMethods::getLinkIDfromHCID(mDigits[i].getHCId());
161 int link2=HelperMethods::getLinkIDfromHCID(mDigits[j].getHCId());
162 if(link1!=link2){return link1<link2;}
163 if(mDigits[i].getROB() != mDigits[j].getROB()){return (mDigits[i].getROB() < mDigits[j].getROB());}
164 if(mDigits[i].getMCM() != mDigits[j].getMCM()){return (mDigits[i].getMCM() < mDigits[j].getMCM());}
165 return (mDigits[i].getChannel() < mDigits[j].getChannel()); });
166 }
167 }
168
169 if (mVerbosity) {
170 std::chrono::duration<double> duration = std::chrono::high_resolution_clock::now() - sortstart;
171 LOG(info) << "TRD Digit/Tracklet Sorting took " << duration.count() << " s";
172 int triggercount = 0;
173 for (auto& trig : mTrackletTriggerRecords) {
174
175 LOG(info) << "Trigger: " << triggercount << " with T " << trig.getBCData().asString();
176 LOG(info) << "Tracklets from:" << trig.getFirstTracklet() << " with " << trig.getNumberOfTracklets();
177 LOG(info) << "Digits from:" << trig.getFirstDigit() << " with " << trig.getNumberOfDigits();
178 if (trig.getNumberOfTracklets() > 0) {
179 int firsttracklet = trig.getFirstTracklet();
180 int numtracklets = trig.getNumberOfTracklets();
181 for (int trackletcount = firsttracklet; trackletcount < firsttracklet + numtracklets; ++trackletcount) {
182 LOG(info) << "Tracklet : " << trackletcount << " details : tracklethcid :" << std::dec
183 << mTracklets[trackletcount].getHCID() << " linkid:" << HelperMethods::getLinkIDfromHCID(mTracklets[trackletcount].getHCID())
184 << " linkid by map : " << ((!mLinkMap) ? -1 : (int)mLinkMap->getLink(mTracklets[trackletcount].getHCID()))
185 << " tracklet:" << mTracklets[trackletcount] << std::endl;
186 }
187 } else {
188 LOG(info) << "No Tracklets for this trigger";
189 }
190 if (trig.getNumberOfDigits() != 0) {
191 int firstdigit = trig.getFirstDigit();
192 int numdigits = trig.getNumberOfDigits();
193 for (int digitcount = firstdigit; digitcount < firstdigit + numdigits; ++digitcount) {
194 LOG(info) << "Digit indexed: " << digitcount << " digit index : " << mDigitsIndex[digitcount] << " details : hcid=" << mDigits[mDigitsIndex[digitcount]].getHCId()
195 << " calculated hcid=" << (mDigits[mDigitsIndex[digitcount]].getDetector() * 2 + (mDigits[mDigitsIndex[digitcount]].getROB() % 2))
196 << " det=" << mDigits[mDigitsIndex[digitcount]].getDetector()
197 << " mcm=" << mDigits[mDigitsIndex[digitcount]].getMCM()
198 << " rob=" << mDigits[mDigitsIndex[digitcount]].getROB()
199 << " channel=" << mDigits[mDigitsIndex[digitcount]].getChannel()
200 << " col=" << mDigits[mDigitsIndex[digitcount]].getPadRow()
201 << " pad=" << mDigits[mDigitsIndex[digitcount]].getPadCol()
202 << " adcsum=" << mDigits[mDigitsIndex[digitcount]].getADCsum()
203 << " hcid=" << mDigits[mDigitsIndex[digitcount]].getHCId();
204 }
205
206 } else {
207 LOG(error) << "No Digits for this trigger <----- this should NEVER EVER HAPPEN";
208 }
209 triggercount++;
210 }
211 LOG(info) << "end of pre sort tracklets then digits";
212 } // if verbose
213}
214
215void Trap2CRU::readTrapData()
216{
217 // set things up, read the file and then deligate to convertTrapdata to do the conversion.
218 //
219 if (mVerbosity) {
220 LOG(info) << "Trap2CRU::readTrapData";
221 }
222 // data comes in index by event (triggerrecord)
223 // first 15 links go to cru0a, second 15 links go to cru0b, 3rd 15 links go to cru1a ... first 90 links to flp0 and then repeat for 12 flp
224 // then do next event
225
226 // request the mapping from CCDB, if not yet available
227 if (!mLinkMap) {
228 LOG(info) << "Retrieving LinkToHCIDMapping for time stamp " << mTimeStamp;
229 auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance();
230 mLinkMap = ccdbmgr.getForTimeStamp<LinkToHCIDMapping>("TRD/Config/LinkToHCIDMapping", mTimeStamp);
231 }
232
233 // lets register our links
234 std::string prefix = mOutputDir;
235 if (!prefix.empty() && prefix.back() != '/') {
236 prefix += '/';
237 }
238
239 for (int link = 0; link < constants::NHALFCRU; link++) {
240 // FeeID *was* 0xFEED, now is indicates the cru Supermodule, side (A/C) and endpoint. See RawData.cxx for details.
241 int supermodule = link / 4;
242 int endpoint = link % 2;
243 int cru = link / 2;
244 int side = cru % 2; // A or C, 0 or 1 respectively:
246 LOG(info) << "FEEID;" << std::hex << mFeeID;
247 mCruID = link / 2;
248 mEndPointID = endpoint;
249
250 std::string outFileLink;
251 std::string outPrefix = "TRD_";
252 outPrefix += "alio2-cr1-flp";
253 std::string outSuffix = ".raw";
254 // filename structure of trd_cru_[CRU#]_[upper/lower].raw
255 auto flpid = trdHWMap[mCruID].flpid;
256 auto cruhwid = trdHWMap[mCruID].cruHWID;
257 if (mFilePer == "all") {
258 // single file for all links
259 outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, outSuffix);
260 } else if (mFilePer == "sm") {
261 // one file per supermodule
262 int sm = link / 4;
263 std::stringstream ss;
264 ss << std::setw(2) << std::setfill('0') << sm;
265 std::string supermodule = ss.str();
266 outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, "_sm_", supermodule, outSuffix);
267 } else if (mFilePer == "cru") {
268 // one file per CRU (both end points combined)
269 outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, std::to_string(flpid), "_cru", std::to_string(cruhwid), outSuffix);
270 } else if (mFilePer == "cruendpoint") {
271 // one file per CRU end point
272 outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, std::to_string(flpid), "_cru", std::to_string(cruhwid), "_", std::to_string(mEndPointID), outSuffix);
273 } else {
274 throw std::runtime_error("invalid option provided for file grouping");
275 }
276 LOG(info) << "registering links";
277 mWriter.registerLink(mFeeID, mCruID, mLinkID, mEndPointID, outFileLink);
278 }
279
280 openInputFiles();
281
282 if (mTrackletsTree->GetEntries() != mDigitsTree->GetEntries()) {
283 LOG(fatal) << "Entry counts in mTrackletsTree and Digits Tree dont match " << mTrackletsTree->GetEntries() << "!=" << mDigitsTree->GetEntries();
284 }
285 int nTrackletsTotal = 0;
286 int nDigitsTotal = 0;
287 int nTriggerRecordsTotal = 0;
288 int triggercount = 42; // triggercount is here so that we can span timeframes. The actual number is of no consequence,but must increase.
289 for (int entry = 0; entry < mTrackletsTree->GetEntries(); entry++) {
290 mTrackletsTree->GetEntry(entry);
291 mDigitsTree->GetEntry(entry);
292 nTrackletsTotal += mTracklets.size();
293 nDigitsTotal += mDigits.size();
294 nTriggerRecordsTotal += mTrackletTriggerRecords.size();
295 sortDataToLinks();
296 // each entry is a timeframe
297 for (auto tracklettrigger : mTrackletTriggerRecords) {
298 convertTrapData(tracklettrigger, triggercount); // tracklettrigger assumed to be authoritive
299 triggercount++;
300 }
301 }
302 LOGF(info, "In the input files there were %u tracklets and %u digits in %u trigger records", nTrackletsTotal, nDigitsTotal, nTriggerRecordsTotal);
303 LOGF(info, "Wrote %lu tracklets and %lu digits into the raw data", mTotalTrackletsWritten, mTotalDigitsWritten);
304}
305
306uint32_t Trap2CRU::buildHalfCRUHeader(HalfCRUHeader& header, const uint32_t bc, const uint32_t halfcru, bool isCalibTrigger)
307{
308 int bunchcrossing = bc;
309 int stopbits = 0x01; // do we care about this and eventtype in simulations?
310 int eventtype = isCalibTrigger ? constants::ETYPECALIBRATIONTRIGGER : constants::ETYPEPHYSICSTRIGGER;
311 int crurdhversion = 6;
312 int feeid = 0;
313 int cruid = 0;
314 int endpoint = halfcru % 2 ? 1 : 0;
315 //lets first clear it out.
316 clearHalfCRUHeader(header);
317 //this bunchcrossing is not the same as the bunchcrossing in the rdh, which is the bc coming in the parameter list to this function. See explanation in rawdata.h
318 setHalfCRUHeaderFirstWord(header, crurdhversion, bunchcrossing, stopbits, endpoint, eventtype, feeid, cruid);
319
320 return 1;
321}
322
323int Trap2CRU::buildDigitRawData(const int digitstartindex, const int digitendindex, const int mcm, const int rob, const uint32_t triggerrecordcount)
324{
325 //this is not zero suppressed.
326 int digitwordswritten = 0;
327 int digitswritten = 0;
328 // Digit
329 DigitMCMHeader header;
332 header.res = 0xc; //1100
333 header.mcm = mcm;
334 header.rob = rob;
335 header.yearflag = 1; // >10.2007
336 header.eventcount = triggerrecordcount;
337 memcpy(mRawDataPtr, (char*)&header, sizeof(DigitMCMHeader)); // uint32 -- 4 bytes.
338 // DigitMCMHeader* headerptr = (DigitMCMHeader*)mRawDataPtr;
339 // LOG(info) << "Digt Header word: 0x" << std::hex << headerptr->word;
340 mRawDataPtr += 4;
341 digitwordswritten++;
342 // we are writing zero suppressed so we need adcmask
344 memcpy(mRawDataPtr, (char*)&adcmask, sizeof(DigitMCMADCMask));
345 DigitMCMADCMask* adcmaskptr = (DigitMCMADCMask*)mRawDataPtr;
346 mRawDataPtr += 4;
347 digitwordswritten++;
348 //LOG(info) << "writing data to digit stream of " << std::hex << header.word;
349 for (int digitindex = digitstartindex; digitindex < digitendindex; ++digitindex) {
350 Digit* d = &mDigits[mDigitsIndex[digitindex]];
351 ArrayADC adcdata = d->getADC();
352 int channel = d->getChannel();
353 //set adcmask for the channel we currently have.
354 incrementADCMask(*adcmaskptr, channel); //adcmaskptr->adcmask |= 1UL << channel;
355 for (int timebin = 0; timebin < constants::TIMEBINS; timebin += 3) {
356 data.z = adcdata[timebin];
357 data.y = adcdata[timebin + 1];
358 data.x = adcdata[timebin + 2];
359 data.f = (channel % 2 == 0) ? 0x3 : 0x2; // 3 for even channel 2 for odd channel
360 memcpy(mRawDataPtr, (char*)&data, sizeof(DigitMCMData)); // uint32 -- 4 bytes.
361 mRawDataPtr += sizeof(DigitMCMData);
362 digitwordswritten++;
363 }
364 if (mVerbosity) {
365 LOG(info) << "Det " << d->getDetector() << ":" << d->getROB() << ":" << d->getMCM() << ":" << d->getChannel() << ":" << d->getADCsum() << ":" << d->getADC()[0] << ":" << d->getADC()[1] << ":" << d->getADC()[2] << "::" << d->getADC()[27] << ":" << d->getADC()[28] << ":" << d->getADC()[29];
366 }
367 digitswritten++;
368 }
369 // sanityCheckDigitMCMADCMask(*adcmaskptr, digitswritten);
370 if (digitswritten != digitendindex - digitstartindex) {
371 LOG(error) << " something wrong the number of digitswritten does not correspond to the the loop count";
372 }
373 mTotalDigitsWritten += digitswritten;
374 if (digitwordswritten != (digitswritten * 10 + 2)) {
375 LOG(error) << "something wrong with writing the digits the following should be equal " << digitwordswritten << "==" << (digitswritten * 10 + 2) << " with digitswritten=" << digitswritten;
376 LOG(error) << "digit start index distance to digit end index :" << digitendindex - digitstartindex;
377 }
378 return digitwordswritten;
379}
380
381int Trap2CRU::buildTrackletRawData(unsigned int trackletIndexStart)
382{
383 int hcid = mTracklets[trackletIndexStart].getHCID();
384 TrackletMCMHeader header; // header with common tracklet information and upper 8 bit of PID information for each tracklet
385 std::array<TrackletMCMData, 3> tracklets; // the up to three tracklet words
386
387 header.col = mTracklets[trackletIndexStart].getColumn();
388 header.padrow = mTracklets[trackletIndexStart].getPadRow();
389 header.onea = 1;
390 header.oneb = 1;
391 header.pid0 = 0xff;
392 header.pid1 = 0xff;
393 header.pid2 = 0xff;
394 int iCurrTracklet = 0;
395
396 while (hcid == mTracklets[trackletIndexStart + iCurrTracklet].getHCID() &&
397 header.col == mTracklets[trackletIndexStart + iCurrTracklet].getColumn() &&
398 header.padrow == mTracklets[trackletIndexStart + iCurrTracklet].getPadRow()) { // we are still on the same MCM
399 unsigned int trackletIndex = trackletIndexStart + iCurrTracklet;
400 auto& trackletData = tracklets[iCurrTracklet];
401 trackletData.word = 0;
402 // slope and position have the 8-th bit flipped each
403 trackletData.slope = mTracklets[trackletIndex].getSlope() ^ 0x80;
404 trackletData.pos = mTracklets[trackletIndex].getPosition() ^ 0x80;
405 trackletData.checkbit = 0;
406 int pidHeader = 0;
407 bool qDynamicRange = mTracklets[trackletIndex].getFormat() & 0x1;
408 if (qDynamicRange) {
409 // Dynamic charge range, the tracklet PID contains all 6 bits of q0 and q1
410 // TODO add scaling factor
411 LOG(warning) << "Trying to add PID information for dynamic charge range, which is not yet verified";
412 trackletData.pid = ((mTracklets[trackletIndex].getQ1() & 0x3f) << 6) | (mTracklets[trackletIndex].getQ0() & 0x3f);
413 pidHeader = mTracklets[trackletIndex].getQ2() & 0x3f;
414 } else {
415 // Fixed charge range, the tracklet PID contains all 7 bits of q0 and 5 out of 7 bits for q1
416 trackletData.pid = ((mTracklets[trackletIndex].getQ1() & 0x1f) << 7) | (mTracklets[trackletIndex].getQ0() & 0x7f);
417 pidHeader = ((mTracklets[trackletIndex].getQ2() & 0x3f) << 2) | ((mTracklets[trackletIndex].getQ1() >> 5) & 0x3);
418 }
419 if (iCurrTracklet == 0) {
420 header.pid0 = pidHeader;
421 } else if (iCurrTracklet == 1) {
422 header.pid1 = pidHeader;
423 if (header.pid0 == 0xff) {
424 LOG(error) << "Adding PID info for second tracklet, but first is marked as not available";
425 }
426 } else if (iCurrTracklet == 2) {
427 header.pid2 = pidHeader;
428 if (header.pid1 == 0xff || header.pid0 == 0xff) {
429 LOG(error) << "Adding PID info for third tracklet, but first or second is marked as not available";
430 }
431 } else {
432 LOG(fatal) << "Cannot have more than 3 tracklets for single trigger and single MCM";
433 }
434 iCurrTracklet++;
435 if (trackletIndexStart + iCurrTracklet >= mTracklets.size()) {
436 break;
437 }
438 }
439 // MCM header and MCM data are assembled, write it now
440 if (iCurrTracklet == 0) {
441 LOG(fatal) << "Not writing any tracklet. This cannot happen, there must be at least one or this function would not be called";
442 }
443 if (mVerbosity) {
445 }
446 memcpy((char*)mRawDataPtr, (char*)&header, sizeof(TrackletMCMHeader));
447 mRawDataPtr += sizeof(TrackletMCMHeader);
448 for (int i = 0; i < iCurrTracklet; ++i) {
449 if (mVerbosity) {
451 }
452 memcpy((char*)mRawDataPtr, (char*)&tracklets[i], sizeof(TrackletMCMData));
453 mRawDataPtr += sizeof(TrackletMCMData);
454 }
455 return iCurrTracklet;
456}
457
458void Trap2CRU::writeDigitEndMarkers()
459{
460 // append 0x00000000 0x00000000
461 uint32_t digitendmarker = 0;
462 memcpy(mRawDataPtr, (char*)&digitendmarker, 4);
463 mRawDataPtr += 4;
464 memcpy(mRawDataPtr, (char*)&digitendmarker, 4);
465 mRawDataPtr += 4;
466}
467
468void Trap2CRU::writeTrackletEndMarkers()
469{
470 // append 0x10001000 0x10001000
471 uint32_t trackletendmarker = constants::TRACKLETENDMARKER;
472 memcpy(mRawDataPtr, (char*)&trackletendmarker, 4);
473 mRawDataPtr += 4;
474 memcpy(mRawDataPtr, (char*)&trackletendmarker, 4);
475 mRawDataPtr += 4;
476}
477
478void Trap2CRU::writeTrackletHCHeader(int hcid, int eventcount)
479{
480 // from linkid we can get supermodule, stack, layer, side
481 unsigned int chipclock = eventcount * 42; // just has to be a constant increasing number per event for our purposes in sim to raw.
482 unsigned int format = 12;
483 TrackletHCHeader tracklethcheader;
484 constructTrackletHCHeader(tracklethcheader, hcid, chipclock, format);
485 if (mVerbosity) {
486 printTrackletHCHeader(tracklethcheader);
487 }
488 memcpy(mRawDataPtr, (char*)&tracklethcheader, sizeof(TrackletHCHeader));
489 if (mVerbosity) {
490 LOG(info) << "writing tracklethcheader of 0x" << std::hex << tracklethcheader.word;
491 }
492 mRawDataPtr += 4;
493}
494
495void Trap2CRU::writeDigitHCHeaders(const int eventcount, const uint32_t hcId)
496{
497 // The detector can in theory send up to 8 HCHeaders, but it will always send at least 2.
498 // Here, we always only send those two headers
499 int detector = hcId / 2;
500 DigitHCHeader digitheader;
501 DigitHCHeader1 digitheader1;
502 digitheader.res = 1;
503 digitheader.side = (hcId % 2) ? 1 : 0;
504 digitheader.stack = HelperMethods::getStack(detector);
505 digitheader.layer = HelperMethods::getLayer(detector);
506 digitheader.supermodule = HelperMethods::getSector(detector);
507 digitheader.numberHCW = 1; // number of additional words in th header, we are using 2 header words so 1 here.
508 digitheader.minor = 42; // my (shtm) version, not used
509 digitheader.major = 0x21; // zero suppressed and 0x1 to comply with what we see in the raw data
510 digitheader.version = 1; //new version of the header. we only have 1 version
511 digitheader1.res = 1;
512 digitheader1.ptrigcount = 1;
513 digitheader1.ptrigphase = 1;
514 digitheader1.bunchcrossing = eventcount; //NB this is not the same as the bunchcrossing the rdh. See RawData.h for explanation
515 digitheader1.numtimebins = constants::TIMEBINS;
516 memcpy(mRawDataPtr, (char*)&digitheader, sizeof(DigitHCHeader)); // 8 because we are only using the first 2 32bit words of the header, the rest are optional.
517 mRawDataPtr += sizeof(DigitHCHeader);
518 memcpy(mRawDataPtr, (char*)&digitheader1, sizeof(DigitHCHeader1)); // 8 because we are only using the first 2 32bit words of the header, the rest are optional.
519 mRawDataPtr += sizeof(DigitHCHeader1);
520}
521
522void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& triggerrecord, const int& triggercount)
523{
524 // Create the raw data for this trigger
525 // loop over half-CRUs and for each half-CRU we put
526 // 1. HalfCRUHeader
527 // 2. Tracklet data
528 // 3. Two tracklet endmarkers
529 // 4. Two digit HC headers (only for calibration events)
530 // 5. Digit data (only for calibration events)
531 // 6. Two end markers (only for calibration events)
532
533 int rawwords = 0;
534 int nLinksWithData = 0;
535 char* rawdataptratstart;
536 std::vector<char> rawdatavector(1024 * 1024 * 2); // sum of link sizes + padding in units of bytes and some space for the header (512 bytes).
537 if (mVerbosity) {
538 LOG(info) << "BUNCH CROSSING : " << triggerrecord.getBCData().bc << " with orbit : " << triggerrecord.getBCData().orbit;
539 }
540
541 uint64_t endtrackletindex = triggerrecord.getFirstTracklet() + triggerrecord.getNumberOfTracklets();
542 uint64_t enddigitindex = triggerrecord.getFirstDigit() + triggerrecord.getNumberOfDigits();
543 // with digit downscaling enabled there will be triggers with only tracklets
544 bool isCalibTrigger = triggerrecord.getNumberOfDigits() > 0 ? true : false;
545 const auto& ctpOffsets = o2::ctp::TriggerOffsetsParam::Instance();
546 auto ir = triggerrecord.getBCData();
547 ir += ctpOffsets.LM_L0;
548 if (ctpOffsets.LM_L0 < 0 && ir.toLong() <= -ctpOffsets.LM_L0) {
549 // skip this trigger
550 LOG(info) << "Skip writing IR " << triggerrecord.getBCData() << " as after applying LM_L0 shift of " << ctpOffsets.LM_L0 << " bunches the orbit would become negative";
551 mCurrentDigit = enddigitindex;
552 mCurrentTracklet = endtrackletindex;
553 return;
554 }
555 if (triggerrecord.getNumberOfTracklets() == 0 && triggerrecord.getNumberOfDigits() == 0) {
556 LOG(info) << "Skip writing trigger " << triggercount << " as there are neither digits nor tracklets";
557 return;
558 }
559
560 for (int halfcru = 0; halfcru < constants::NHALFCRU; halfcru++) {
561 int halfcruwordswritten = 0;
562 int supermodule = halfcru / 4; // 2 cru per supermodule. 72/4, as of writing
563 mEndPointID = halfcru % 2; // 2 pci end points per cru, 15 links each
564 //first cru is A second CRU is C , so an flp will be either ACA or CAC A=0 C=1
565 int cru = halfcru / 2;
566 int side = cru % 2; // first cru is A second is B, 3rd is A etc
567 mFeeID = constructTRDFeeID(supermodule, side, mEndPointID);
568 mCruID = halfcru / 2;
569 mEndPointID = halfcru % 2; // just the upper or lower half of the cru, hence %2 of the the halfcru number.
570 // 15 links per half cru or cru end point.
571 HalfCRUHeader halfcruheader;
572 //now write the cruheader at the head of all the data for this halfcru.
573 buildHalfCRUHeader(halfcruheader, ir.bc, halfcru, isCalibTrigger);
574 halfcruheader.EndPoint = mEndPointID;
575 mRawDataPtr = rawdatavector.data();
576 HalfCRUHeader* halfcruheaderptr = (HalfCRUHeader*)mRawDataPtr; // store the ptr to the halfcruheader for later adding the link lengths and possibly simulated errors.
577 mRawDataPtr += sizeof(halfcruheader);
578 halfcruwordswritten += sizeof(halfcruheader) / 4;
579 int totallinklengths = 0;
580 rawdataptratstart = mRawDataPtr; // keep track of where we started.
581 for (int halfcrulink = 0; halfcrulink < constants::NLINKSPERHALFCRU; halfcrulink++) {
582 //links run from 0 to 14, so linkid offset is halfcru*15;
583 int linkid = halfcrulink + halfcru * constants::NLINKSPERHALFCRU;
584 int hcid = (!mLinkMap) ? HelperMethods::getHCIDFromLinkID(linkid) : mLinkMap->getHCID(linkid);
585 int linkwordswritten = 0; // number of 32 bit words for this link
586 int errors = 0; // put no errors in for now.
587 uint32_t crudatasize = 0; // in 256 bit words.
588 // loop over tracklets for mcms that match
589 int nTrackletsOnLink = 0;
590 int nDigitsOnLink = 0;
591 bool haveDigitOnLink = false;
592 bool haveTrackletOnLink = false;
593 if (mCurrentTracklet < mTracklets.size() && mTracklets[mCurrentTracklet].getHCID() == hcid) {
594 haveTrackletOnLink = true;
595 }
596 if (mCurrentDigit < mDigits.size() && mDigits[mDigitsIndex[mCurrentDigit]].getHCId() == hcid) {
597 haveDigitOnLink = true;
598 }
599 if (mVerbosity) {
600 LOGF(info, "Link ID(%i), HCID(%i). Tracklets? %i, Digits? %i. Tracklet HCID(%i), mCurrentTracklet(%i), mCurrentDigit(%i)",
601 linkid, hcid, haveTrackletOnLink, haveDigitOnLink, mTracklets[mCurrentTracklet].getHCID(), mCurrentTracklet, mCurrentDigit);
602 }
603 if (haveTrackletOnLink || haveDigitOnLink) {
604 nLinksWithData++;
605 // we have some data somewhere for this link
606 if (mUseTrackletHCHeader > 0) {
607 if (haveTrackletOnLink || mUseTrackletHCHeader == 2) {
608 // write tracklethcheader if there is tracklet data or if we always want to have tracklethcheader
609 // first part of the if statement handles the mUseTrackletHCHeader==1 option
610 writeTrackletHCHeader(hcid, triggercount);
611 linkwordswritten += 1;
612 }
613 //else do nothing as we dont want/have tracklethcheader
614 }
615 while (mCurrentTracklet < endtrackletindex && mTracklets[mCurrentTracklet].getHCID() == hcid) {
616 // still on an mcm on this link
617 int tracklets = buildTrackletRawData(mCurrentTracklet); // returns # of tracklets for single MCM
618 mCurrentTracklet += tracklets;
619 nTrackletsOnLink += tracklets;
620 mTotalTrackletsWritten += tracklets;
621 linkwordswritten += tracklets + 1; // +1 to include the header
622 }
623 // write 2 tracklet end markers irrespective of there being tracklet data.
624 writeTrackletEndMarkers();
625 linkwordswritten += 2;
626
627 if (isCalibTrigger) {
628 // we write two DigitHCHeaders here
629 writeDigitHCHeaders(triggercount, hcid);
630 linkwordswritten += 2;
631 while (mCurrentDigit < enddigitindex && mDigits[mDigitsIndex[mCurrentDigit]].getHCId() == hcid) {
632 // while we are on a single mcm, copy the digits timebins to the array.
633 int digitcounter = 0;
634 int currentROB = mDigits[mDigitsIndex[mCurrentDigit]].getROB();
635 int currentMCM = mDigits[mDigitsIndex[mCurrentDigit]].getMCM();
636 int firstDigitMCM = mCurrentDigit;
637 while (mDigits[mDigitsIndex[mCurrentDigit]].getMCM() == currentMCM &&
638 mDigits[mDigitsIndex[mCurrentDigit]].getROB() == currentROB &&
639 mDigits[mDigitsIndex[mCurrentDigit]].getHCId() == hcid) {
640 mCurrentDigit++;
641 digitcounter++;
642 if (mCurrentDigit == enddigitindex) {
643 break;
644 }
645 }
646 // mcm digits are full, now write it out.
647 linkwordswritten += buildDigitRawData(firstDigitMCM, mCurrentDigit, currentMCM, currentROB, triggercount);
648 nDigitsOnLink += (mCurrentDigit - firstDigitMCM);
649 }
650
651 // write the digit end marker so long as we have any data (digits or tracklets).
652 writeDigitEndMarkers();
653 linkwordswritten += 2;
654 } // end isCalibTrigger
655
656 // pad up to a whole 256 bit word size (paddingsize is number of 32 bit words to pad)
657 int paddingsize = (linkwordswritten % 8 == 0) ? 0 : 8 - (linkwordswritten % 8);
658 int padword = constants::PADDINGWORD;
659 for (int i = 0; i < paddingsize; ++i) {
660 memcpy(mRawDataPtr, &padword, 4);
661 mRawDataPtr += 4;
662 linkwordswritten++;
663 }
664 rawwords += linkwordswritten;
665 crudatasize = linkwordswritten / 8; //convert to 256 bit alignment.
666 if ((linkwordswritten % 8) != 0) {
667 LOG(error) << "linkwordswritten is not 256 bit aligned: " << linkwordswritten << ". Padding size of= " << paddingsize;
668 }
669 //set the halfcruheader for the length of this link.
670 //but first a sanity check.
671 if (crudatasize > constants::MAXDATAPERLINK256) {
672 LOG(error) << " linksize is huge : " << crudatasize;
673 }
674 LOG(debug) << " setting halfcrulink " << halfcrulink << " linksize to : " << crudatasize << " with a linkwordswrittern=" << linkwordswritten;
675 setHalfCRUHeaderLinkSizeAndFlags(halfcruheader, halfcrulink, crudatasize, errors);
676 uint32_t bytescopied;
677 totallinklengths += crudatasize;
678 if ((mRawDataPtr - rawdataptratstart) != (totallinklengths * 32)) {
679 bytescopied = mRawDataPtr - rawdataptratstart;
680 LOGF(error, "Data size missmatch. Written words (%i), bytesCopied(%i), crudatasize(%i)", linkwordswritten, bytescopied, crudatasize);
681 }
682 LOGF(debug, "Found %i tracklets and %i digits on link %i (HCID=%i)", nTrackletsOnLink, nDigitsOnLink, linkid, hcid);
683 } else {
684 // no data on this link
685 setHalfCRUHeaderLinkSizeAndFlags(halfcruheader, halfcrulink, 0, 0);
686 if (mVerbosity) {
687 LOG(info) << "linkwordswritten is zero : " << linkwordswritten;
688 }
689 }
690 halfcruwordswritten += linkwordswritten;
691 } // end loop over all links for one half CRU
692 // write the cruhalfheader now that we know the lengths.
693 memcpy((char*)halfcruheaderptr, (char*)&halfcruheader, sizeof(halfcruheader));
694 //write halfcru data here.
695 std::vector<char> feeidpayload(halfcruwordswritten * 4);
696 memcpy(feeidpayload.data(), &rawdatavector[0], halfcruwordswritten * 4);
697 assert(halfcruwordswritten % 8 == 0);
698 mWriter.addData(mFeeID, mCruID, mLinkID, mEndPointID, ir, feeidpayload, false, triggercount);
699 if (mVerbosity) {
700 LOGF(info, "Written file for trigger %i, FeeID(%x), CruID(%i), LindID(%i), end point (%i), orbit(%i), bc(%i), payload size (%i)",
701 triggercount, mFeeID, mCruID, mLinkID, mEndPointID, ir.orbit, ir.bc, halfcruwordswritten);
702 printHalfCRUHeader(halfcruheader);
703 LOG(info) << "+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+ ====== end of writing";
704 }
705 }
706 if (mVerbosity) {
707 LOG(info) << "Raw data written for all CRUs of this trigger: " << rawwords;
708 LOG(info) << "Number of links with data for this trigger: " << nLinksWithData;
709 }
710}
711
712} // end namespace trd
713} // end namespace o2
uint16_t mcm
uint16_t rob
uint16_t digitcount
uint64_t bc
Definition RawEventData.h:5
int32_t i
Definition of the RAW Data Header.
uint32_t j
Definition RawData.h:0
uint32_t adcmask
Definition RawData.h:1
uint32_t supermodule
Definition RawData.h:3
uint32_t eventcount
Definition RawData.h:1
uint32_t side
Definition RawData.h:0
uint8_t endpoint
Definition RawData.h:0
uint32_t bunchcrossing
Definition RawData.h:3
Utility class to write detectors data to (multiple) raw data file(s) respecting CRU format.
std::ostringstream debug
static BasicCCDBManager & instance()
ADC_t getADCsum() const
Definition Digit.h:92
int getDetector() const
Definition Digit.h:79
int getChannel() const
Definition Digit.h:86
int getMCM() const
Definition Digit.h:84
ArrayADC const & getADC() const
Definition Digit.h:91
int getROB() const
Definition Digit.h:83
Trap2CRU()=default
Header for data corresponding to the same hardware trigger adapted from DataFormatsITSMFT/ROFRecord.
const BCData & getBCData() const
int getFirstTracklet() const
int getNumberOfDigits() const
int getNumberOfTracklets() const
GLuint entry
Definition glcorearb.h:5735
GLboolean * data
Definition glcorearb.h:298
GLint GLint GLsizei GLint GLenum format
Definition glcorearb.h:275
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition glcorearb.h:5034
constexpr int NHALFCRU
the number of half cru (link bundles)
Definition Constants.h:33
DigitMCMADCMask constructBlankADCMask()
Definition RawData.cxx:199
void printHalfCRUHeader(const o2::trd::HalfCRUHeader &halfcru)
Definition RawData.cxx:230
void printTrackletMCMHeader(const o2::trd::TrackletMCMHeader &mcmhead)
Definition RawData.cxx:223
void constructTrackletHCHeader(TrackletHCHeader &header, int hcid, int chipclock, int format)
Definition RawData.cxx:170
const TRDCRUMapping trdHWMap[constants::NHALFCRU/2]
Definition Trap2CRU.cxx:57
uint16_t constructTRDFeeID(int supermodule, int side, int endpoint)
Definition RawData.cxx:187
uint32_t setHalfCRUHeaderFirstWord(HalfCRUHeader &cruhead, int crurdhversion, int bunchcrossing, int stopbits, int endpoint, int eventtype, int feeid, int cruid)
Definition RawData.cxx:96
void clearHalfCRUHeader(o2::trd::HalfCRUHeader &halfcru)
Definition RawData.cxx:244
void incrementADCMask(DigitMCMADCMask &mask, int channel)
Definition RawData.cxx:323
void setHalfCRUHeaderLinkSizeAndFlags(HalfCRUHeader &cruhead, int link, int size, int errors)
Definition RawData.cxx:109
void printTrackletHCHeader(const o2::trd::TrackletHCHeader &tracklet)
Definition RawData.cxx:212
std::array< ADC_t, constants::TIMEBINS > ArrayADC
Definition Digit.h:32
void printTrackletMCMData(const o2::trd::TrackletMCMData &tracklet)
Definition RawData.cxx:218
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
Digit version of the TrackletHCHeader above, although contents are rather different.
Definition RawData.h:231
Header for half a cru, each cru has 2 output, 1 for each pciid.
Definition RawData.h:35
Header for each half chamber.
Definition RawData.h:129
Header for MCM tracklet data outuput.
Definition RawData.h:162
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
std::vector< Tracklet64 > tracklets