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