Project
Loading...
Searching...
No Matches
IDCToVectorSpec.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 <iterator>
13#include <limits>
14#include <memory>
15#include <stdexcept>
16#include <vector>
17#include <string>
18#include <fstream>
19#include <algorithm>
20#include <cassert>
21#include <cmath>
22#include <fmt/format.h>
23#include <fmt/chrono.h>
24
25#include "TFile.h"
27#include "Framework/Task.h"
30#include "Framework/Logger.h"
35#include "DPLUtils/RawParser.h"
36#include "Headers/DataHeader.h"
43
44#include "DataFormatsTPC/Defs.h"
45#include "DataFormatsTPC/IDC.h"
47#include "TPCBase/Utils.h"
48#include "TPCBase/RDHUtils.h"
49#include "TPCBase/Mapper.h"
51
52using namespace o2::framework;
58
59namespace o2::tpc
60{
61
63{
64 public:
66 IDCToVectorDevice(const std::vector<uint32_t>& crus) : mCRUs(crus) {}
67
69 {
70 // set up ADC value filling
71 mWriteDebug = ic.options().get<bool>("write-debug");
72 mWriteDebugOnError = ic.options().get<bool>("write-debug-on-error");
73 mWriteRawDataOnError = ic.options().get<bool>("write-raw-data-on-error");
74 mRawDataType = ic.options().get<int>("raw-data-type");
75 o2::framework::RawParser<>::setCheckIncompleteHBF(ic.options().get<bool>("check-incomplete-hbf"));
76
77 mDebugStreamFileName = ic.options().get<std::string>("debug-file-name").data();
78 mRawOutputFileName = ic.options().get<std::string>("raw-file-name").data();
79
80 mSwapLinks = ic.options().get<bool>("swap-links");
81
82 auto pedestalFile = ic.options().get<std::string>("pedestal-url");
83 if (pedestalFile.length()) {
85 long timeStamp = o2::ccdb::getCurrentTimestamp();
86 const auto tsPos = pedestalFile.find("@");
87 std::string pedestalURL = pedestalFile.substr(0, tsPos);
88 if (pedestalURL.find("ccdb") != std::string::npos) {
89 if (pedestalURL.find("-default") != std::string::npos) {
91 }
92 LOGP(info, "Loading pedestals from ccdb: {}", pedestalURL);
93 cdb.setURL(pedestalURL);
94 if (cdb.isHostReachable()) {
95 if (tsPos != std::string::npos) {
96 timeStamp = std::stol(pedestalFile.substr(tsPos + 1));
97 LOGP(info, "Using custom time stamp {}", timeStamp);
98 }
99 auto pedestalNoise = cdb.getForTimeStamp<std::unordered_map<std::string, CalPad>>("TPC/Calib/PedestalNoise", timeStamp);
100 try {
101 if (!pedestalNoise) {
102 throw std::runtime_error("Couldn't retrieve PedestaNoise map");
103 }
104 mPedestal = std::make_unique<CalPad>(pedestalNoise->at("Pedestals"));
105 } catch (const std::exception& e) {
106 LOGP(fatal, "could not load pedestals from {} ({}), required for IDC processing", pedestalURL, e.what());
107 }
108 } else {
109 LOGP(fatal, "ccdb access to {} requested, but host is not reachable. Cannot load pedestals, required for IDC processing", pedestalURL);
110 }
111 } else {
112 LOGP(info, "Loading pedestals from file: {}", pedestalURL);
113 auto calPads = utils::readCalPads(pedestalURL, "Pedestals");
114 if (calPads.size() != 1) {
115 LOGP(fatal, "Pedestal could not be loaded from file {}, required for IDC processing", pedestalURL);
116 } else {
117 mPedestal.reset(calPads[0]);
118 }
119 }
120 } else {
121 LOGP(error, "No pedestal file set, IDCs will be without pedestal subtraction!");
122 }
123
124 initIDC();
125 }
126
128 {
129 const auto runNumber = processing_helpers::getRunNumber(pc);
130 std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; // TODO: Change to IDC when changed in DD
131 const auto& mapper = Mapper::instance();
132
133 // open files if necessary
134 if ((mWriteDebug || mWriteDebugOnError) && !mDebugStream) {
135 const auto debugFileName = fmt::format(fmt::runtime(mDebugStreamFileName), fmt::arg("run", runNumber));
136 LOGP(info, "creating debug stream {}", debugFileName);
137 mDebugStream = std::make_unique<o2::utils::TreeStreamRedirector>(debugFileName.data(), "recreate");
138 }
139
140 if (mWriteRawDataOnError && !mRawOutputFile.is_open()) {
141 std::string_view rawType = (mRawDataType < 2) ? "tf" : "raw";
142 if (mRawDataType == 4) {
143 rawType = "idc.raw";
144 }
145 const auto rawFileName = fmt::format(fmt::runtime(mRawOutputFileName), fmt::arg("run", runNumber), fmt::arg("raw_type", rawType));
146 LOGP(info, "creating raw debug file {}", rawFileName);
147 mRawOutputFile.open(rawFileName, std::ios::binary);
148 }
149
150 uint32_t heartbeatOrbit = 0;
151 uint32_t heartbeatBC = 0;
152 uint32_t tfCounter = 0;
153 bool first = true;
154 bool hasErrors = false;
155
156 CalPad* pedestals = mPedestal.get();
157
158 for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) {
159 const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
160 tfCounter = dh->tfCounter;
161 const auto subSpecification = dh->subSpecification;
162 auto payloadSize = DataRefUtils::getPayloadSize(ref);
163
164 // ---| data loop |---
165 const gsl::span<const char> raw = pc.inputs().get<gsl::span<char>>(ref);
166 try {
167 o2::framework::RawParser parser(raw.data(), raw.size());
168 size_t lastErrorCount = 0;
169
170 for (auto it = parser.begin(), end = parser.end(); it != end; ++it) {
171 const auto size = it.size();
172
173 if (parser.getNErrors() > lastErrorCount) {
174 lastErrorCount = parser.getNErrors();
175 hasErrors = true;
176 }
177
178 // skip empty packages (HBF open)
179 if (size == 0) {
180 continue;
181 }
182
183 auto rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(it.raw());
184 const auto rdhVersion = RDHUtils::getVersion(rdhPtr);
185 if (!rdhPtr || rdhVersion < 6) {
186 throw std::runtime_error(fmt::format("could not get RDH from packet, or version {} < 6", rdhVersion).data());
187 }
188
189 // ---| extract hardware information to do the processing |---
190 const auto feeId = (FEEIDType)RDHUtils::getFEEID(*rdhPtr);
191 const auto link = rdh_utils::getLink(feeId);
192 const uint32_t cruID = rdh_utils::getCRU(feeId);
193 const auto endPoint = rdh_utils::getEndPoint(feeId);
194 const auto detField = RDHUtils::getDetectorField(*rdhPtr);
195
196 // only select IDCs
197 // ToDo: cleanup once IDCs will be propagated not as RAWDATA, but IDC.
198 if ((detField != (decltype(detField))RawDataType::IDC) || (link != rdh_utils::IDCLinkID)) {
199 continue;
200 }
201 LOGP(debug, "IDC Processing firstTForbit {:9}, tfCounter {:5}, run {:6}, feeId {:6} ({:3}/{}/{:2})", dh->firstTForbit, dh->tfCounter, dh->runNumber, feeId, cruID, endPoint, link);
202
203 if (std::find(mCRUs.begin(), mCRUs.end(), cruID) == mCRUs.end()) {
204 LOGP(error, "IDC CRU {:3} not configured in CRUs, skipping", cruID);
205 continue;
206 }
207
208 const CRU cru(cruID);
209 const int sector = cru.sector();
210 const auto& partInfo = mapper.getPartitionInfo(cru.partition());
211 const int fecLinkOffsetCRU = (partInfo.getNumberOfFECs() + 1) / 2;
212 const int fecSectorOffset = partInfo.getSectorFECOffset();
213 const GlobalPadNumber regionPadOffset = Mapper::GLOBALPADOFFSET[cru.region()];
214 const GlobalPadNumber numberPads = Mapper::PADSPERREGION[cru.region()];
215 int sampaOnFEC{}, channelOnSAMPA{};
216 auto& idcVec = mIDCvectors[cruID];
217 auto& infoVec = mIDCInfos[cruID];
218
219 assert(size == sizeof(idc::Container));
220 auto data = it.data();
221 auto& idcs = *((idc::Container*)(data));
222 const uint32_t orbit = idcs.header.heartbeatOrbit;
223 const uint32_t bc = idcs.header.heartbeatBC;
224 // LOGP(info, "IDC Procssing orbit/BC: {:9}/{:4}", orbit, bc);
225
226 auto infoIt = std::find(infoVec.begin(), infoVec.end(), orbit);
227 if (!infoVec.size()) {
228 infoVec.emplace_back(orbit, bc);
229 infoIt = infoVec.end() - 1;
230 } else if (infoIt == infoVec.end()) {
231 auto& lastInfo = infoVec.back();
232 if ((orbit - lastInfo.heartbeatOrbit) != mNOrbitsIDC) {
233 LOGP(error, "received packet with invalid jump in idc orbit ({} - {} == {} != {})", orbit, lastInfo.heartbeatOrbit, int(orbit) - int(lastInfo.heartbeatOrbit), mNOrbitsIDC);
234 hasErrors = true;
235 }
236 infoVec.emplace_back(orbit, bc);
237 infoIt = infoVec.end() - 1;
238 }
239
240 // check if end poit was already processed
241 auto& lastInfo = *infoIt;
242 if (lastInfo.wasEPseen(endPoint)) {
243 LOGP(debug, "Already received another data packet for CRU {}, ep {}, orbit {}, bc {}", cruID, endPoint, orbit, bc);
244 continue;
245 }
246
247 lastInfo.setEPseen(endPoint);
248 // idc value offset in present time frame
249 const size_t idcOffset = std::distance(infoVec.begin(), infoIt);
250
251 // TODO: for debugging, remove later
252 // LOGP(info, "processing IDCs for CRU {}, ep {}, feeId {:6} ({:3}/{}/{:2}), detField: {}, orbit {}, bc {}, idcOffset {}, idcVec size {}, epSeen {:02b}", cruID, endPoint, feeId, cruID, endPoint, link, detField, orbit, bc, idcOffset, idcVec.size(), lastInfo.epSeen);
253
254 const float norm = 1. / float(mTimeStampsPerIntegrationInterval);
255 for (uint32_t iLinkTmp = 0; iLinkTmp < Mapper::LinksPerRegionPerEndpoint[cru.region()][endPoint]; ++iLinkTmp) {
256 const uint32_t iLink = mSwapLinks ? (idc::Links - iLinkTmp - 1) : iLinkTmp;
257
258 if (!idcs.hasLink(iLink)) {
259 continue;
260 }
261
262 const int fecInSector = iLinkTmp + endPoint * fecLinkOffsetCRU + fecSectorOffset;
263
264 for (uint32_t iChannel = 0; iChannel < idc::Channels; ++iChannel) {
265 auto val = idcs.getChannelValueFloat(iLink, iChannel);
266 Mapper::getSampaAndChannelOnFEC(cruID, iChannel, sampaOnFEC, channelOnSAMPA);
267 const GlobalPadNumber padInSector = mapper.globalPadNumber(fecInSector, sampaOnFEC, channelOnSAMPA);
268 if (pedestals) {
269 val -= pedestals->getValue(sector, padInSector) * mTimeStampsPerIntegrationInterval;
270 val *= norm;
271 }
272 const GlobalPadNumber padInRegion = padInSector - regionPadOffset;
273 const GlobalPadNumber vectorPosition = padInRegion + idcOffset * numberPads;
274 // TODO: for debugging, remove later
275 // auto rawVal = idcs.getChannelValue(iLink, iChannel);
276 // auto rawValF = idcs.getChannelValueFloat(iLink, iChannel);
277 // LOGP(info, "filling channel {}, link {}, fecLinkOffsetCRU {:2}, fecSectorOffset {:3}, fecInSector {:3}, idcVec[{} ({})] = {} ({} / {})", iChannel, iLink, fecLinkOffsetCRU, fecSectorOffset, fecInSector, vectorPosition, padInRegion, val, rawVal, rawValF);
278 idcVec[vectorPosition] = val;
279 }
280 }
281 }
282 } catch (const std::exception& e) {
283 // error message throtteling
284 using namespace std::literals::chrono_literals;
285 static std::unordered_map<uint32_t, size_t> nErrorPerSubspec;
286 static std::chrono::time_point<std::chrono::steady_clock> lastReport = std::chrono::steady_clock::now();
287 const auto now = std::chrono::steady_clock::now();
288 static size_t reportedErrors = 0;
289 const size_t MAXERRORS = 10;
290 const auto sleepTime = 10min;
291 ++nErrorPerSubspec[subSpecification];
292
293 if ((now - lastReport) < sleepTime) {
294 if (reportedErrors < MAXERRORS) {
295 ++reportedErrors;
296 std::string sleepInfo;
297 if (reportedErrors == MAXERRORS) {
298 sleepInfo = fmt::format(", maximum error count ({}) reached, not reporting for the next {}", MAXERRORS, sleepTime);
299 }
300 LOGP(alarm, "EXCEPTIION in processRawData: {} -> skipping part:{}/{} of spec:{}/{}/{}, size:{}, error count for subspec: {}{}", e.what(), dh->splitPayloadIndex, dh->splitPayloadParts,
301 dh->dataOrigin, dh->dataDescription, subSpecification, payloadSize, nErrorPerSubspec.at(subSpecification), sleepInfo);
302 lastReport = now;
303 }
304 } else {
305 lastReport = now;
306 reportedErrors = 0;
307 }
308 continue;
309 }
310 }
311
312 hasErrors |= snapshotIDCs(pc.outputs(), tfCounter);
313
314 if (mWriteDebug || (mWriteDebugOnError && hasErrors)) {
315 writeDebugOutput(tfCounter);
316 }
317
318 if (mWriteRawDataOnError && hasErrors) {
319 writeRawData(pc.inputs());
320 }
321
322 // clear output
323 initIDC();
324 }
325
327 {
328 LOGP(info, "closeFiles");
329
330 if (mDebugStream) {
331 // set some default aliases
332 auto& stream = (*mDebugStream) << "idcs";
333 auto& tree = stream.getTree();
334 tree.SetAlias("sector", "int(cru/10)");
335 mDebugStream->Close();
336 mDebugStream.reset(nullptr);
337 mRawOutputFile.close();
338 }
339 }
340
341 void stop() final
342 {
343 LOGP(info, "stop");
344 closeFiles();
345 }
346
348 {
349 LOGP(info, "endOfStream");
350 // ec.services().get<ControlService>().readyToQuit(QuitRequest::Me);
351 closeFiles();
352 }
353
354 private:
356 struct IDCInfo {
357 IDCInfo() = default;
358 IDCInfo(const IDCInfo&) = default;
359 IDCInfo(uint32_t orbit, uint16_t bc) : heartbeatOrbit(orbit), heartbeatBC(bc) {}
360
361 uint32_t heartbeatOrbit{0};
362 uint16_t heartbeatBC{0};
363 uint16_t epSeen{0};
364
365 bool operator==(const uint32_t orbit) const { return (heartbeatOrbit == orbit); }
366 bool operator==(const IDCInfo& inf) const { return (inf.heartbeatOrbit == heartbeatOrbit) && (inf.heartbeatBC == heartbeatBC) && (inf.epSeen == epSeen); }
367 void setEPseen(uint32_t ep) { epSeen |= uint16_t(1 << ep); }
368 bool wasEPseen(uint32_t ep) const { return epSeen & uint16_t(1 << ep); }
369 bool matches(uint32_t orbit, int16_t bc) const { return ((heartbeatOrbit == orbit) && (heartbeatBC == bc)); }
370 bool hasBothEPs() const { return epSeen == 3; }
371 };
372
373 const int mNOrbitsIDC{12};
374 const int mTimeStampsPerIntegrationInterval{(LHCMaxBunches * mNOrbitsIDC) / LHCBCPERTIMEBIN};
375 const uint32_t mMaxIDCPerTF{uint32_t(std::ceil(256.f / mNOrbitsIDC))};
376 int mRawDataType{0};
377 bool mSwapLinks{false};
378 bool mWriteDebug{false};
379 bool mWriteDebugOnError{false};
380 bool mWriteRawDataOnError{false};
381 std::vector<uint32_t> mCRUs;
382 std::unordered_map<uint32_t, std::vector<float>> mIDCvectors;
383 std::unordered_map<uint32_t, std::vector<IDCInfo>> mIDCInfos;
384 std::string mDebugStreamFileName;
385 std::unique_ptr<o2::utils::TreeStreamRedirector> mDebugStream;
386 std::unique_ptr<CalPad> mPedestal{};
387 std::ofstream mRawOutputFile;
388 std::string mRawOutputFileName;
389
390 //____________________________________________________________________________
391 bool snapshotIDCs(DataAllocator& output, uint32_t tfCounter)
392 {
393 LOGP(debug, "snapshotIDCs");
394
395 // check integrety of data between CRUs
396 size_t packetsInTF = 0;
397 std::vector<IDCInfo> const* infVecComp = nullptr;
398 std::vector<uint64_t> orbitBCInfo;
399 bool hasErrors = false;
400
401 for (const auto& [cru, infVec] : mIDCInfos) {
402 packetsInTF = std::max(infVec.size(), packetsInTF);
403 }
404
405 for (const auto& [cru, infVec] : mIDCInfos) {
406
407 for (const auto& inf : infVec) {
408 if (!inf.hasBothEPs()) {
409 LOGP(warning, "IDC CRU {:3}: data missing at ({:8}, {:4}) for one or both end points {:02b} in TF {}", cru, inf.heartbeatOrbit, inf.heartbeatBC, inf.epSeen, tfCounter);
410 hasErrors = true;
411 }
412 }
413
414 if (!infVecComp) {
415 infVecComp = &infVec;
416 std::for_each(infVec.begin(), infVec.end(), [&orbitBCInfo](const auto& inf) { orbitBCInfo.emplace_back((uint64_t(inf.heartbeatOrbit) << 32) + uint64_t(inf.heartbeatBC)); });
417 continue;
418 }
419
420 if (packetsInTF != infVec.size()) {
421 LOGP(error, "IDC CRU {:3}: number of IDC packets {} does not match max over all CRUs {} in TF {}", cru, packetsInTF, infVec.size(), tfCounter);
422 hasErrors = true;
423 }
424
425 if (!std::equal(infVecComp->begin(), infVecComp->end(), infVec.begin())) {
426 LOGP(warning, "IDC CRU {:3}: mismatch in orbit numbers", cru);
427 hasErrors = true;
428 }
429 }
430
431 // send data
432 for (auto& [cru, idcVec] : mIDCvectors) {
433 idcVec.resize(Mapper::PADSPERREGION[CRU(cru).region()] * packetsInTF);
434 const header::DataHeader::SubSpecificationType subSpec{cru << 7};
435 LOGP(debug, "Sending IDCs for CRU {} of size {}", cru, idcVec.size());
436 output.snapshot(Output{gDataOriginTPC, "IDCVECTOR", subSpec}, idcVec);
437 output.snapshot(Output{gDataOriginTPC, "IDCORBITS", subSpec}, orbitBCInfo);
438 }
439
440 return hasErrors;
441 }
442
443 //____________________________________________________________________________
444 void initIDC()
445 {
446 for (const auto cruID : mCRUs) {
447 const CRU cru(cruID);
448 const GlobalPadNumber numberPads = Mapper::PADSPERREGION[cru.region()] * mMaxIDCPerTF;
449 auto& idcVec = mIDCvectors[cruID];
450 idcVec.resize(numberPads);
451 std::fill(idcVec.begin(), idcVec.end(), -1.f);
452
453 auto& infosCRU = mIDCInfos[cruID];
454 infosCRU.clear();
455 }
456 }
457
458 //____________________________________________________________________________
459 void writeDebugOutput(uint32_t tfCounter)
460 {
461 const auto& mapper = Mapper::instance();
462
463 mDebugStream->GetFile()->cd();
464 auto& stream = (*mDebugStream) << "idcs";
465 uint32_t seen = 0;
466 static uint32_t firstOrbit = std::numeric_limits<uint32_t>::max();
467
468 for (auto cru : mCRUs) {
469 if (mIDCInfos.find(cru) == mIDCInfos.end()) {
470 continue;
471 }
472 auto& infos = mIDCInfos[cru];
473 auto& idcVec = mIDCvectors[cru];
474
475 for (int i = 0; i < infos.size(); ++i) {
476 auto& info = infos[i];
477
478 if (firstOrbit == std::numeric_limits<uint32_t>::max()) {
479 firstOrbit = info.heartbeatOrbit;
480 }
481 auto idcFirst = idcVec.begin() + i * Mapper::PADSPERREGION[cru % Mapper::NREGIONS];
482 auto idcLast = idcFirst + Mapper::PADSPERREGION[cru % Mapper::NREGIONS];
483 std::vector<float> idcs(idcFirst, idcLast);
484 std::vector<short> cpad(idcs.size());
485 std::vector<short> row(idcs.size());
486 for (int ipad = 0; ipad < idcs.size(); ++ipad) {
487 const auto& padPos = mapper.padPos(ipad + Mapper::GLOBALPADOFFSET[cru % Mapper::NREGIONS]);
488 row[ipad] = (short)padPos.getRow();
489 const short pads = (short)mapper.getNumberOfPadsInRowSector(row[ipad]);
490 cpad[ipad] = (short)padPos.getPad() - pads / 2;
491 }
492 auto idcSort = idcs;
493 std::sort(idcSort.begin(), idcSort.end());
494 const auto idcSize = idcSort.size();
495 float median = idcSize % 2 ? idcSort[idcSize / 2] : (idcSort[idcSize / 2] + idcSort[idcSize / 2 - 1]) / 2.f;
496 // outlier removal
497 auto itEnd = idcSort.end();
498 while (std::abs(*(itEnd - 1) - median) > 40) {
499 --itEnd;
500 }
501
502 float mean = 0;
503 const auto nForMean = std::distance(idcSort.begin(), itEnd);
504 if (nForMean > 0) {
505 mean = std::accumulate(idcSort.begin(), itEnd, 0.f) / float(nForMean);
506 }
507 uint32_t outliers = uint32_t(idcSort.size() - nForMean);
508
509 stream << "cru=" << cru
510 << "entry=" << i
511 << "epSeen=" << info.epSeen
512 << "tfCounter=" << tfCounter
513 << "firstOrbit=" << firstOrbit
514 << "orbit=" << info.heartbeatOrbit
515 << "bc=" << info.heartbeatBC
516 << "idcs=" << idcs
517 << "cpad=" << cpad
518 << "row=" << row
519 << "outliers=" << outliers
520 << "idc_mean=" << mean
521 << "idc_median=" << median
522 << "\n";
523 }
524 }
525 }
526
527 void writeRawData(InputRecord& inputs)
528 {
529 if (!mRawOutputFile.is_open()) {
530 return;
531 }
532
534
535 std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; // TODO: Change to IDC when changed in DD
536 for (auto const& ref : InputRecordWalker(inputs, filter)) {
537 auto dh = DataRefUtils::getHeader<header::DataHeader*>(ref);
538 // LOGP(info, "write header: {}/{}/{}, payload size: {} / {}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dh->payloadSize, ref.payloadSize);
539 if (((mRawDataType == 1) || (mRawDataType == 3)) && (dh->payloadSize == 2 * sizeof(o2::header::RAWDataHeader))) {
540 continue;
541 }
542
543 if (mRawDataType < 2) {
544 mRawOutputFile.write(ref.header, sizeof(DataHeader));
545 }
546 if (mRawDataType < 4) {
547 mRawOutputFile.write(ref.payload, ref.payloadSize);
548 }
549
550 if (mRawDataType == 4) {
551 const gsl::span<const char> raw = inputs.get<gsl::span<char>>(ref);
552 try {
553 o2::framework::RawParser parser(raw.data(), raw.size());
554 for (auto it = parser.begin(), end = parser.end(); it != end; ++it) {
555 const auto size = it.size();
556 // skip empty packages (HBF open)
557 if (size == 0) {
558 continue;
559 }
560
561 auto rdhPtr = reinterpret_cast<const o2::header::RDHAny*>(it.raw());
562 const auto rdhVersion = RDHUtils::getVersion(rdhPtr);
563 if (!rdhPtr || rdhVersion < 6) {
564 throw std::runtime_error(fmt::format("could not get RDH from packet, or version {} < 6", rdhVersion).data());
565 }
566
567 // ---| extract hardware information to do the processing |---
568 const auto feeId = (FEEIDType)RDHUtils::getFEEID(*rdhPtr);
569 const auto link = rdh_utils::getLink(feeId);
570 const auto detField = RDHUtils::getDetectorField(*rdhPtr);
571
572 // only select IDCs
573 if ((detField != (decltype(detField))RawDataType::IDC) || (link != rdh_utils::IDCLinkID)) {
574 continue;
575 }
576
577 // write out raw data
578 mRawOutputFile.write((const char*)it.raw(), RDHUtils::getMemorySize(rdhPtr));
579 }
580 } catch (...) {
581 }
582 }
583 }
584 }
585};
586
587o2::framework::DataProcessorSpec getIDCToVectorSpec(const std::string inputSpec, std::vector<uint32_t> const& crus)
588{
589 using device = o2::tpc::IDCToVectorDevice;
590
591 std::vector<OutputSpec> outputs;
592 for (const uint32_t cru : crus) {
593 const header::DataHeader::SubSpecificationType subSpec{cru << 7};
594 outputs.emplace_back(gDataOriginTPC, "IDCVECTOR", subSpec, Lifetime::Timeframe);
595 outputs.emplace_back(gDataOriginTPC, "IDCORBITS", subSpec, Lifetime::Timeframe);
596 }
597
598 return DataProcessorSpec{
599 fmt::format("tpc-idc-to-vector"),
600 select(inputSpec.data()),
601 outputs,
602 AlgorithmSpec{adaptFromTask<device>(crus)},
603 Options{
604 {"write-debug", VariantType::Bool, false, {"write a debug output tree"}},
605 {"write-debug-on-error", VariantType::Bool, false, {"write a debug output tree in case errors occurred"}},
606 {"debug-file-name", VariantType::String, "/tmp/idc_vector_debug.{run}.root", {"name of the debug output file"}},
607 {"write-raw-data-on-error", VariantType::Bool, false, {"dump raw data in case errors occurred"}},
608 {"raw-file-name", VariantType::String, "/tmp/idc_debug.{run}.{raw_type}", {"name of the raw output file"}},
609 {"raw-data-type", VariantType::Int, 0, {"Which raw data to dump: 0-full TPC with DH, 1-full TPC with DH skip empty, 2-full TPC no DH, 3-full TPC no DH skip empty, 4-IDC raw only"}},
610 {"check-incomplete-hbf", VariantType::Bool, false, {"false: don't chck; true: check and report"}},
611 {"pedestal-url", VariantType::String, "ccdb-default", {"ccdb-default: load from NameConf::getCCDBServer() OR ccdb url (must contain 'ccdb' OR pedestal file name"}},
612 {"swap-links", VariantType::Bool, false, {"swap links to circumvent bug in FW"}},
613 } // end Options
614 }; // end DataProcessorSpec
615}
616} // namespace o2::tpc
uint64_t orbit
Definition RawEventData.h:6
uint64_t bc
Definition RawEventData.h:5
int32_t i
Integrated digital currents data format definition.
A helper class to iteratate over all parts of all input routes.
Header to collect LHC related constants.
void output(const std::map< std::string, ChannelStat > &channels)
Definition rawdump.cxx:197
Definition of the Names Generator class.
Generic parser for consecutive raw pages.
std::ostringstream debug
static std::string getCCDBServer()
Definition NameConf.cxx:110
static BasicCCDBManager & instance()
A helper class to iteratate over all parts of all input routes.
The input API of the Data Processing Layer This class holds the inputs which are valid for processing...
decltype(auto) get(R binding, int part=0) const
size_t getNErrors() const
Definition RawParser.h:642
const_iterator begin() const
Definition RawParser.h:618
const_iterator end() const
Definition RawParser.h:623
static void setCheckIncompleteHBF(bool v)
Definition RawParser.h:647
unsigned char region() const
Definition CRU.h:64
const Sector sector() const
Definition CRU.h:65
unsigned char partition() const
Definition CRU.h:63
const T getValue(const int sec, const int globalPadInSector) const
Definition CalDet.h:154
IDCToVectorDevice(const std::vector< uint32_t > &crus)
void stop() final
This is invoked on stop.
void run(o2::framework::ProcessingContext &pc) final
void init(o2::framework::InitContext &ic) final
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
rdh_utils::FEEIDType FEEIDType
static constexpr unsigned int LinksPerRegionPerEndpoint[NREGIONS][NENDPOINTS]
number of links per region per end point
Definition Mapper.h:592
static constexpr unsigned int GLOBALPADOFFSET[NREGIONS]
offset of number of pads for region
Definition Mapper.h:531
static Mapper & instance(const std::string mappingDir="")
Definition Mapper.h:44
static constexpr unsigned int NREGIONS
total number of regions in one sector
Definition Mapper.h:527
static constexpr void getSampaAndChannelOnFEC(const int cruID, const size_t rawFECChannel, int &sampaOnFEC, int &channelOnSAMPA)
Definition Mapper.h:275
static constexpr unsigned int PADSPERREGION[NREGIONS]
number of pads per CRU
Definition Mapper.h:530
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLboolean * data
Definition glcorearb.h:298
GLuint GLfloat * val
Definition glcorearb.h:1582
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLuint GLuint stream
Definition glcorearb.h:1806
GLint ref
Definition glcorearb.h:291
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
double mean(std::vector< double >::const_iterator first, std::vector< double >::const_iterator last)
long getCurrentTimestamp()
returns the timestamp in long corresponding to "now"
constexpr int LHCMaxBunches
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > select(char const *matcher="")
R median(std::vector< T > v)
Definition fit.h:520
bool operator==(const DsChannelId &a, const DsChannelId &b)
Definition DsChannelId.h:65
constexpr int LHCBCPERTIMEBIN
Definition Constants.h:38
uint64_t getRunNumber(o2::framework::ProcessingContext &pc)
uint16_t FEEIDType
Definition RDHUtils.h:26
std::vector< CalPad * > readCalPads(const std::string_view fileName, const std::vector< std::string > &calPadNames)
Definition Utils.cxx:190
Global TPC definitions and constants.
Definition SimTraits.h:167
o2::framework::DataProcessorSpec getIDCToVectorSpec(const std::string inputSpec, std::vector< uint32_t > const &crus)
unsigned short GlobalPadNumber
global pad number
Definition Defs.h:129
static o2::header::DataHeader::PayloadSizeType getPayloadSize(const DataRef &ref)
the main header struct
Definition DataHeader.h:618
uint32_t SubSpecificationType
Definition DataHeader.h:620
static constexpr int getVersion()
get numeric version of the RDH
Definition RDHUtils.h:60
IDC full data container.
Definition IDC.h:107
constexpr size_t min
const int sleepTime
Definition test_Fifo.cxx:28
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
std::vector< int > row