Project
Loading...
Searching...
No Matches
RawWriter.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
12#include <set>
13
14#include <fairlogger/Logger.h>
15
16#include <fmt/core.h>
17#include <gsl/span>
18#include <TSystem.h>
21#include "EMCALBase/Geometry.h"
24
25using namespace o2::emcal;
26
28{
29 mRawWriter = std::make_unique<o2::raw::RawFileWriter>(o2::header::gDataOriginEMC, false);
30 mRawWriter->setCarryOverCallBack(this);
31
32 // initialize mappers
33 if (!mMappingHandler) {
34 mMappingHandler = std::make_unique<o2::emcal::MappingHandler>();
35 }
36
37 for (auto iddl = 0; iddl < 40; iddl++) {
38 // For EMCAL set
39 // - FEE ID = DDL ID
40 // - C-RORC and link increasing with DDL ID
41 // @TODO replace with link assignment on production FLPs,
42 // eventually storing in CCDB
43
44 // initialize containers for SRU
45 SRUDigitContainer srucont;
46 srucont.mSRUid = iddl;
47 mSRUdata.push_back(srucont);
48
49 // Skip empty links with these ddl IDs,
50 // ddl ID 21 and 39 are empty links, while 23 and 36 are connected to LEDmon only
51 if (iddl == 21 || iddl == 22 || iddl == 36 || iddl == 39) {
52 continue;
53 }
54
55 auto [crorc, link] = mGeometry->getLinkAssignment(iddl);
56 auto flpID = (iddl <= 23) ? 146 : 147;
57 std::string rawfilename = mOutputLocation;
58 switch (mFileFor) {
60 rawfilename += "/emcal.raw";
61 break;
63 rawfilename += fmt::format("/EMC_alio2-cr1-flp{:d}.raw", flpID);
64 break;
66 rawfilename += fmt::format("/EMC_alio2-cr1-flp{:d}_crorc{:d}.raw", flpID, crorc);
67 break;
69 // Pileup simulation based on DigitsWriteoutBuffer (EMCAL-681) - AliceO2 – H. Hassan
70 rawfilename += fmt::format("/EMC_alio2-cr1-flp{:d}_crorc{:d}_{:d}.raw", flpID, crorc, link);
71 break;
72 }
73 mRawWriter->registerLink(iddl, crorc, link, 0, rawfilename.data());
74 }
75}
76
77void RawWriter::digitsToRaw(gsl::span<o2::emcal::Digit> digitsbranch, gsl::span<o2::emcal::TriggerRecord> triggerbranch)
78{
79 setDigits(digitsbranch);
80 for (auto trg : triggerbranch) {
81 processTrigger(trg);
82 }
83}
84
86{
87 for (auto& srucont : mSRUdata) {
88 srucont.mChannels.clear();
89 }
90 std::vector<o2::emcal::Digit*>* bunchDigits;
91 int lasttower = -1;
92 for (auto& dig : gsl::span(mDigits.data() + trg.getFirstEntry(), trg.getNumberOfObjects())) {
93 auto tower = dig.getTower();
94 if (tower != lasttower) {
95 lasttower = tower;
96 if (tower > 20000) {
97 std::cout << "Wrong cell ID " << tower << std::endl;
98 }
99 auto onlineindices = mGeometry->getOnlineID(tower);
100 int sruID = std::get<0>(onlineindices);
101 auto towerdata = mSRUdata[sruID].mChannels.find(tower);
102 if (towerdata == mSRUdata[sruID].mChannels.end()) {
103 mSRUdata[sruID].mChannels[tower] = {std::get<1>(onlineindices), std::get<2>(onlineindices), std::vector<o2::emcal::Digit*>(mNADCSamples)};
104 bunchDigits = &(mSRUdata[sruID].mChannels[tower].mDigits);
105 memset(bunchDigits->data(), 0, sizeof(o2::emcal::Digit*) * mNADCSamples);
106 } else {
107 bunchDigits = &(towerdata->second.mDigits);
108 }
109 }
110
111 // Get time sample of the digit:
112 // Digitizer stores the time sample in ns, needs to be converted to time sample dividing
113 // by the length of the time sample
114 auto timesample = int(dig.getTimeStamp() / emcal::constants::EMCAL_TIMESAMPLE);
115 if (timesample >= mNADCSamples) {
116 LOG(error) << "Digit time sample " << timesample << " outside range [0," << mNADCSamples << "]";
117 continue;
118 }
119 (*bunchDigits)[timesample] = &dig;
120 }
121
122 // Create and fill DMA pages for each channel
123 LOG(debug) << "encode data";
124 for (auto srucont : mSRUdata) {
125
126 std::vector<char> payload; // this must be initialized per SRU, becuase pages are per SRU, therefore the payload was not reset.
127
128 if (srucont.mSRUid == 21 || srucont.mSRUid == 22 || srucont.mSRUid == 36 || srucont.mSRUid == 39) {
129 continue;
130 }
131
132 // sort found towers according to FEC inside
133 // within the FEC channels are also sorted according
134 // their local channel ID
135 std::map<int, std::map<int, int>> fecSortedTowersWithSignal;
136 auto& mappingDDL = mMappingHandler->getMappingForDDL(srucont.mSRUid);
137 for (const auto& [tower, channel] : srucont.mChannels) {
138
139 auto hwaddress = mappingDDL.getHardwareAddress(channel.mRow, channel.mCol, ChannelType_t::HIGH_GAIN);
140 auto fecInDLL = getBranchIndexFromHwAddress(hwaddress) * 10 + getFecIndexFromHwAddress(hwaddress);
141 auto channelID = getChannelIndexFromHwAddress(hwaddress);
142 auto fecFound = fecSortedTowersWithSignal.find(fecInDLL);
143 if (fecFound != fecSortedTowersWithSignal.end()) {
144 fecFound->second[channelID] = tower;
145 } else {
146 std::map<int, int> channelsInFec;
147 channelsInFec[channelID] = tower;
148 fecSortedTowersWithSignal[fecInDLL] = channelsInFec;
149 }
150 }
151
152 // encode payload for sorted channels
153 for (const auto& [fec, channelsInFec] : fecSortedTowersWithSignal) {
154 for (auto [channelID, tower] : channelsInFec) {
155 auto towerChannel = srucont.mChannels.find(tower);
156 if (towerChannel != srucont.mChannels.end()) {
157 bool saturatedBunchHG = false;
158 createPayload(towerChannel->second, ChannelType_t::HIGH_GAIN, srucont.mSRUid, payload, saturatedBunchHG);
159 if (saturatedBunchHG) {
160 createPayload(towerChannel->second, ChannelType_t::LOW_GAIN, srucont.mSRUid, payload, saturatedBunchHG);
161 }
162 } else {
163 LOG(error) << "No data found for FEC " << fec << ", channel " << channelID << "(tower " << tower << ")";
164 }
165 }
166 }
167
168 if (!payload.size()) {
169 // [EMCAL-699] No payload found in SRU
170 // Still the link is not completely ignored but a trailer with 0-payloadsize is added
171 LOG(debug) << "Payload buffer has size 0 - only write empty trailer" << std::endl;
172 }
173 LOG(debug) << "Payload buffer has size " << payload.size();
174
175 // Create RCU trailer
176 auto trailerwords = createRCUTrailer(payload.size() / sizeof(uint32_t), 100., trg.getBCData().toLong(), srucont.mSRUid);
177 for (auto word : trailerwords) {
178 payload.emplace_back(word);
179 }
180
181 // register output data
182 auto ddlid = srucont.mSRUid;
183 auto [crorc, link] = mGeometry->getLinkAssignment(ddlid);
184 LOG(debug1) << "Adding payload with size " << payload.size() << " (" << payload.size() / 4 << " ALTRO words)";
185 mRawWriter->addData(ddlid, crorc, link, 0, trg.getBCData() + o2::ctp::TriggerOffsetsParam::Instance().LM_L0, payload, false, trg.getTriggerBits());
186 }
187 LOG(debug) << "Done";
188 return true;
189}
190
191void RawWriter::createPayload(o2::emcal::ChannelData channel, o2::emcal::ChannelType_t chanType, int ddlID, std::vector<char>& payload, bool& saturatedBunch)
192{
193 // Find out hardware address of the channel
194 auto hwaddress = mMappingHandler->getMappingForDDL(ddlID).getHardwareAddress(channel.mRow, channel.mCol, chanType); // @TODO distinguish between high- and low-gain cells
195
196 std::vector<int> rawbunches;
197 int nbunches = 0;
198
199 // Creating the high gain bunch
200 for (auto& bunch : findBunches(channel.mDigits, chanType)) {
201 if (!bunch.mADCs.size()) {
202 LOG(error) << "Found bunch with without ADC entries - skipping ...";
203 continue;
204 }
205 rawbunches.push_back(bunch.mADCs.size() + 2); // add 2 words for header information
206 rawbunches.push_back(bunch.mStarttime);
207 for (auto adc : bunch.mADCs) {
208 rawbunches.push_back(adc);
209 if (adc > o2::emcal::constants::LG_SUPPRESSION_CUT) {
210 saturatedBunch = true;
211 }
212 }
213 nbunches++;
214 }
215
216 if (!rawbunches.size()) {
217 LOG(debug) << "No bunch selected";
218 return;
219 }
220 LOG(debug) << "Selected " << nbunches << " bunches";
221
222 auto encodedbunches = encodeBunchData(rawbunches);
223 auto chanhead = createChannelHeader(hwaddress, rawbunches.size(), false);
224 char* chanheadwords = reinterpret_cast<char*>(&chanhead);
225 uint32_t* testheader = reinterpret_cast<uint32_t*>(chanheadwords);
226 if ((*testheader >> 30) & 1) {
227 // header pattern found, check that the payload size is properly reflecting the number of words
228 uint32_t payloadsizeRead = ((*testheader >> 16) & 0x3FF);
229 uint32_t nwordsRead = (payloadsizeRead + 2) / 3;
230 if (encodedbunches.size() != nwordsRead) {
231 LOG(error) << "Mismatch in number of 32-bit words, encoded " << encodedbunches.size() << ", recalculated " << nwordsRead << std::endl;
232 LOG(error) << "Payload size: " << payloadsizeRead << ", number of words: " << rawbunches.size() << ", encodeed words " << encodedbunches.size() << ", calculated words " << nwordsRead << std::endl;
233 } else {
234 LOG(debug) << "Matching number of payload 32-bit words, encoded " << encodedbunches.size() << ", decoded " << nwordsRead;
235 }
236 } else {
237 LOG(error) << "Header without header bit detected ..." << std::endl;
238 }
239 for (int iword = 0; iword < sizeof(ChannelHeader) / sizeof(char); iword++) {
240 payload.emplace_back(chanheadwords[iword]);
241 }
242 char* channelwords = reinterpret_cast<char*>(encodedbunches.data());
243 for (auto iword = 0; iword < encodedbunches.size() * sizeof(int) / sizeof(char); iword++) {
244 payload.emplace_back(channelwords[iword]);
245 }
246}
247
248std::vector<AltroBunch> RawWriter::findBunches(const std::vector<o2::emcal::Digit*>& channelDigits, ChannelType_t channelType)
249{
250 std::vector<AltroBunch> result;
251 AltroBunch currentBunch;
252 bool bunchStarted = false;
253 // Digits in ALTRO bunch in time-reversed order
254 int itime;
255 for (itime = channelDigits.size() - 1; itime >= 0; itime--) {
256 auto dig = channelDigits[itime];
257 if (!dig) {
258 if (bunchStarted) {
259 // we have a bunch which is started and needs to be closed
260 // check if the ALTRO bunch has a minimum amount of ADCs
261 if (currentBunch.mADCs.size() >= mMinADCBunch) {
262 // Bunch selected, set start time and push to bunches
263 result.push_back(currentBunch);
264 currentBunch = AltroBunch();
265 bunchStarted = false;
266 }
267 }
268 continue;
269 }
270 int adc = dig->getAmplitudeADC(channelType);
271 if (adc < mPedestal) {
272 // ADC value below threshold
273 // in case we have an open bunch it needs to be stopped bunch
274 // Set the start time to the time sample of previous (passing) digit
275 if (bunchStarted) {
276 // check if the ALTRO bunch has a minimum amount of ADCs
277 if (currentBunch.mADCs.size() >= mMinADCBunch) {
278 // Bunch selected, set start time and push to bunches
279 result.push_back(currentBunch);
280 currentBunch = AltroBunch();
281 bunchStarted = false;
282 }
283 }
284 }
285 // Valid ADC value, if the bunch is closed we start a new bunch
286 if (!bunchStarted) {
287 bunchStarted = true;
288 currentBunch.mStarttime = itime;
289 }
290 currentBunch.mADCs.emplace_back(adc);
291 }
292 // if we have a last bunch set time start time to the time bin of teh previous digit
293 if (bunchStarted) {
294 if (currentBunch.mADCs.size() >= mMinADCBunch) {
295 result.push_back(currentBunch);
296 }
297 }
298 return result;
299}
300
301std::vector<int> RawWriter::encodeBunchData(const std::vector<int>& data)
302{
303 std::vector<int> encoded;
304 CaloBunchWord currentword;
305 currentword.mDataWord = 0;
306 int wordnumber = 0;
307 for (auto adc : data) {
308 if (adc > 0x3FF) {
309 LOG(error) << "Exceeding max ADC count for 10 bit ALTRO word: " << adc << " (max: 1023)" << std::endl;
310 }
311 switch (wordnumber) {
312 case 0:
313 currentword.mWord0 = adc;
314 break;
315 case 1:
316 currentword.mWord1 = adc;
317 break;
318 case 2:
319 currentword.mWord2 = adc;
320 break;
321 };
322 wordnumber++;
323 if (wordnumber == 3) {
324 // start new word;
325 encoded.push_back(currentword.mDataWord);
326 currentword.mDataWord = 0;
327 wordnumber = 0;
328 }
329 }
330 if (wordnumber) {
331 encoded.push_back(currentword.mDataWord);
332 }
333 return encoded;
334}
335
336ChannelHeader RawWriter::createChannelHeader(int hardwareAddress, int payloadSize, bool isBadChannel)
337{
338 ChannelHeader header;
339 header.mHardwareAddress = hardwareAddress;
340 header.mPayloadSize = payloadSize;
341 header.mBadChannel = isBadChannel ? 1 : 0;
342 header.mHeaderBits = 1;
343 return header;
344}
345
346std::vector<char> RawWriter::createRCUTrailer(int payloadsize, double timesample, uint64_t triggertime, int feeID)
347{
348 RCUTrailer trailer;
349 trailer.setPayloadSize(payloadsize);
350 trailer.setTimeSamplePhaseNS(triggertime, timesample);
351
352 // You can find details about these settings here https://alice.its.cern.ch/jira/browse/EMCAL-650
353 trailer.setRCUID(feeID);
354 trailer.setFirmwareVersion(2);
355 trailer.setActiveFECsA(0x0);
356 trailer.setActiveFECsB(0x1);
357 trailer.setBaselineCorrection(0);
358 trailer.setPolarity(false);
359 trailer.setNumberOfPresamples(0);
360 trailer.setNumberOfPostsamples(0);
361 trailer.setSecondBaselineCorrection(false);
362 trailer.setGlitchFilter(0);
367 // For MC we don't simulate pedestals. In order to prevent pedestal subtraction
368 // in the raw fitter we set the zero suppression to true in the RCU trailer
369 trailer.setZeroSuppression(true);
370 trailer.setSparseReadout(true);
372
373 auto trailerwords = trailer.encode();
374 std::vector<char> encoded(trailerwords.size() * sizeof(uint32_t));
375 memcpy(encoded.data(), trailerwords.data(), trailerwords.size() * sizeof(uint32_t));
376 return encoded;
377}
378
379int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data,
380 const char* ptr, int maxSize, int splitID,
381 std::vector<char>& trailer, std::vector<char>& header) const
382{
383 constexpr int TrailerSize = 9 * sizeof(uint32_t);
384 int bytesLeft = data.data() + data.size() - ptr;
385 int leftAfterSplit = bytesLeft - maxSize;
386
387 if (leftAfterSplit < TrailerSize) {
388 return std::max(0, bytesLeft - TrailerSize);
389 }
390
391 return maxSize;
392}
uint8_t channelID
Definition RawEventData.h:8
TBranch * ptr
std::ostringstream debug
EMCAL digit implementation.
Definition Digit.h:34
std::tuple< int, int, int > getOnlineID(int towerID)
Get link ID, row and column from cell ID, have a look here: https://alice.its.cern....
std::tuple< int, int > getLinkAssignment(int ddlID) const
Temporary link assignment (till final link assignment is known -.
Definition Geometry.h:522
Information stored in the RCU trailer.
Definition RCUTrailer.h:75
void setNumberOfNonZeroSuppressedPostsamples(uint16_t npostsamples)
Set the number of postsamples before zero suppression.
Definition RCUTrailer.h:304
void setPayloadSize(uint32_t size)
set the payload size in number of DDL (32-bit) words
Definition RCUTrailer.h:174
void setTimeSamplePhaseNS(uint64_t triggertime, uint64_t timesample)
Set the time sample length and L1 phase based on the trigger time.
void setNumberOfNonZeroSuppressedPresamples(uint16_t npresamples)
Set the number of presamples after zero suppression.
Definition RCUTrailer.h:308
void setSparseReadout(bool isSparse)
Set sparse readout mode.
Definition RCUTrailer.h:324
@ NBUFFERS4
4 ALTRO buffers
Definition RCUTrailer.h:118
void setNumberOfAltroBuffers(BufferMode_t bufmode)
Set the number of ALTRO buffers.
Definition RCUTrailer.h:328
void setNumberOfPretriggerSamples(uint16_t nsamples)
Set the number of pretrigger samples.
Definition RCUTrailer.h:312
void setBaselineCorrection(uint16_t baselineCorrection)
Set baseline correction method.
Definition RCUTrailer.h:280
void setSecondBaselineCorrection(bool doHave)
Specify whether second basedline correction has been applied.
Definition RCUTrailer.h:296
void setGlitchFilter(uint16_t glitchfilter)
Set the glitch filter.
Definition RCUTrailer.h:300
void setActiveFECsA(uint16_t value)
Definition RCUTrailer.h:219
void setActiveFECsB(uint16_t value)
Definition RCUTrailer.h:220
void setZeroSuppression(bool doHave)
Specify whether zero suppression has been applied.
Definition RCUTrailer.h:320
void setFirmwareVersion(uint8_t version)
Set the firmware version.
Definition RCUTrailer.h:166
std::vector< uint32_t > encode() const
Encode RCU trailer as array of DDL (32-bit) words.
void setNumberOfSamplesPerChannel(uint16_t nsamples)
Set the number of samples per channel.
Definition RCUTrailer.h:316
void setRCUID(int rcuid)
Set the ID of the RCU.
Definition RCUTrailer.h:170
void setPolarity(bool doSet)
Set the polarity.
Definition RCUTrailer.h:284
void setNumberOfPostsamples(uint16_t npostsamples)
Set the number of postsamples (after zero suppression)
Definition RCUTrailer.h:292
void setNumberOfPresamples(uint16_t npresamples)
Set the number of presamples (after zero suppression)
Definition RCUTrailer.h:288
std::vector< char > createRCUTrailer(int payloadsize, double timesample, uint64_t triggertime, int feeID)
Creating RCU trailer.
ChannelHeader createChannelHeader(int hardwareAddress, int payloadSize, bool isBadChannel)
Create channel header.
bool processTrigger(const o2::emcal::TriggerRecord &trg)
Processing digits to raw conversion for the digits from the current event.
Definition RawWriter.cxx:85
@ kSubDet
Subdetector (EMCAL/DCAL separate)
@ kFullDet
Full detector (EMCAL + DCAL)
int getChannelIndexFromHwAddress(int hwaddress)
Extracting Channel index in FEC from the hardware address.
Definition RawWriter.h:204
int getFecIndexFromHwAddress(int hwaddress)
Extracting FEC index in branch from the hardware address.
Definition RawWriter.h:200
int getBranchIndexFromHwAddress(int hwaddress)
Extracting branch index from the hardware address.
Definition RawWriter.h:196
std::vector< AltroBunch > findBunches(const std::vector< o2::emcal::Digit * > &channelDigits, ChannelType_t channelType)
Parse digits vector in channel and create ALTRO bunches.
void createPayload(o2::emcal::ChannelData channel, o2::emcal::ChannelType_t chanType, int ddlID, std::vector< char > &payload, bool &saturatedBunch)
int carryOverMethod(const header::RDHAny *rdh, const gsl::span< char > data, const char *ptr, int maxSize, int splitID, std::vector< char > &trailer, std::vector< char > &header) const
void setDigits(gsl::span< o2::emcal::Digit > digits)
Definition RawWriter.h:103
void digitsToRaw(gsl::span< o2::emcal::Digit > digits, gsl::span< o2::emcal::TriggerRecord > triggers)
Converting digits from a full timeframe to raw pages.
Definition RawWriter.cxx:77
std::vector< int > encodeBunchData(const std::vector< int > &data)
Encoding words of the ALTRO bunch into 32-bit words.
Header for data corresponding to the same hardware trigger.
uint32_t getTriggerBits() const
const BCData & getBCData() const
GLuint64EXT * result
Definition glcorearb.h:5662
GLboolean * data
Definition glcorearb.h:298
constexpr o2::header::DataOrigin gDataOriginEMC
Definition DataHeader.h:565
ChannelType_t
Type of a raw data channel.
Definition Constants.h:33
@ HIGH_GAIN
High gain channel.
Definition Constants.h:35
@ LOW_GAIN
Low gain channel.
Definition Constants.h:34
ALTRO bunch information obtained from digits.
Definition AltroHelper.h:31
std::vector< int > mADCs
ADCs belonging to the bunch.
Definition AltroHelper.h:33
int mStarttime
Start time of the bunch.
Definition AltroHelper.h:32
Structure for mapping digits to Channels within a SRU.
Definition AltroHelper.h:40
std::vector< o2::emcal::Digit * > mDigits
Digits for the channel within the current event.
Definition AltroHelper.h:43
int mRow
Row of the channel.
Definition AltroHelper.h:41
int mCol
Column of the channel.
Definition AltroHelper.h:42
Structure for organizing digits within the SRU.
Definition AltroHelper.h:48
int mSRUid
DDL of the SRU.
Definition AltroHelper.h:49
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
ArrayADC adc
Encoding of ALTRO words (32 bit consisting of 3 10-bit words)
Definition RawWriter.h:56
uint32_t mWord2
Bits 0 - 9 : Word 2.
Definition RawWriter.h:59
uint32_t mWord0
Bits 20 - 29 : Word 0.
Definition RawWriter.h:61
uint32_t mDataWord
Full data word representation.
Definition RawWriter.h:57
uint32_t mWord1
Bits 10 - 19 : Word 1.
Definition RawWriter.h:60
Bitfield encoding channel headers.
Definition RawWriter.h:43
uint32_t mPayloadSize
Bits 16 - 25: Payload size.
Definition RawWriter.h:47
uint32_t mHardwareAddress
Bits 0 - 15: Hardware address.
Definition RawWriter.h:46
uint32_t mHeaderBits
Bits 30 - 31: channel header bits (1)
Definition RawWriter.h:50
uint32_t mBadChannel
Bit 29: Bad channel status.
Definition RawWriter.h:49