Project
Loading...
Searching...
No Matches
STFDecoderSpec.cxx
Go to the documentation of this file.
1// Copyright 2019-2026 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
15
16#include <vector>
17
37
38namespace o2
39{
40namespace itsmft
41{
42
43using namespace o2::framework;
44
46template <class Mapping>
47STFDecoder<Mapping>::STFDecoder(const STFDecoderInp& inp, std::shared_ptr<o2::base::GRPGeomRequest> gr)
48 : mDoClusters(inp.doClusters), mDoPatterns(inp.doPatterns), mDoDigits(inp.doDigits), mDoCalibData(inp.doCalib), mDoStaggering(inp.doStaggering), mAllowReporting(inp.allowReporting), mVerifyDecoder(inp.verifyDecoder), mInputSpec(inp.inputSpec), mGGCCDBRequest(gr)
49{
50 mSelfName = o2::utils::Str::concat_string(Mapping::getName(), "STFDecoder");
51 mTimer.Stop();
52 mTimer.Reset();
53 if (mDoStaggering) {
54 mLayers = Mapping::NLayers;
55 mEstNDig.resize(mLayers, 0);
56 mEstNClus.resize(mLayers, 0);
57 mEstNClusPatt.resize(mLayers, 0);
58 mEstNCalib.resize(mLayers, 0);
59 }
60}
61
63template <class Mapping>
65{
67 try {
68 auto v0 = o2::utils::Str::tokenize(mInputSpec, ':');
69 auto v1 = o2::utils::Str::tokenize(v0[1], '/');
70 auto v2 = o2::utils::Str::tokenize(v1[1], '?');
71 header::DataOrigin dataOrig;
73 dataOrig.runtimeInit(v1[0].c_str());
74 dataDesc.runtimeInit(v2[0].c_str());
75 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
76 auto& dec = mDecoder.emplace_back(std::make_unique<RawPixelDecoder<Mapping>>());
77 dec->setUserDataOrigin(dataOrig);
78 dec->setUserDataDescription(dataDesc);
79 dec->init(); // is this no-op?
80 }
81 } catch (const std::exception& e) {
82 LOG(error) << "exception was thrown in decoder creation: " << e.what();
83 throw;
84 } catch (...) {
85 LOG(error) << "non-std::exception was thrown in decoder creation";
86 throw;
87 }
88 mApplyNoiseMap = !ic.options().get<bool>("ignore-noise-map");
89 mUseClusterDictionary = !ic.options().get<bool>("ignore-cluster-dictionary");
90 try {
91 float fr = ic.options().get<float>("rof-length-error-freq");
92 mROFErrRepIntervalMS = fr <= 0. ? -1 : long(fr * 1e3);
93 mNThreads = std::max(1, ic.options().get<int>("nthreads"));
94 mUnmutExtraLanes = ic.options().get<bool>("unmute-extra-lanes");
95 mVerbosity = ic.options().get<int>("decoder-verbosity");
96 auto dmpSz = ic.options().get<int>("stop-raw-data-dumps-after-size");
97 if (dmpSz > 0) {
98 mMaxRawDumpsSize = size_t(dmpSz) * 1024 * 1024;
99 }
100 mDumpOnError = ic.options().get<int>("raw-data-dumps");
101 if (mDumpOnError < 0) {
102 mDumpOnError = -mDumpOnError;
103 mDumpFrom1stPipeline = true;
104 }
105 if (mDumpOnError >= int(GBTLink::RawDataDumps::DUMP_NTYPES)) {
106 throw std::runtime_error(fmt::format("unknown raw data dump level {} requested", mDumpOnError));
107 }
108 auto dumpDir = ic.options().get<std::string>("raw-data-dumps-directory");
109 if (mDumpOnError != int(GBTLink::RawDataDumps::DUMP_NONE) && (!dumpDir.empty() && !o2::utils::Str::pathIsDirectory(dumpDir))) {
110 throw std::runtime_error(fmt::format("directory {} for raw data dumps does not exist", dumpDir));
111 }
112 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
113 mDecoder[iLayer]->setNThreads(mNThreads);
114 mDecoder[iLayer]->setAlwaysParseTrigger(ic.options().get<bool>("always-parse-trigger"));
115 mDecoder[iLayer]->setAllowEmptyROFs(ic.options().get<bool>("allow-empty-rofs"));
116 mDecoder[iLayer]->setRawDumpDirectory(dumpDir);
117 mDecoder[iLayer]->setFillCalibData(mDoCalibData);
118 mDecoder[iLayer]->setVerifyDecoder(mVerifyDecoder);
119 bool ignoreRampUp = !ic.options().get<bool>("accept-rof-rampup-data");
120 mDecoder[iLayer]->setSkipRampUpData(ignoreRampUp);
121 }
122 } catch (const std::exception& e) {
123 LOG(error) << "exception was thrown in decoder configuration: " << e.what();
124 throw;
125 } catch (...) {
126 LOG(error) << "non-std::exception was thrown in decoder configuration";
127 throw;
128 }
129
130 if (mDoClusters) {
131 mClusterer = std::make_unique<Clusterer>();
132 mClusterer->setNChips(Mapping::getNChips());
133 }
134
135 if (mDoStaggering) {
136 Mapping map;
137 for (uint32_t iLayer{0}; iLayer < mLayers; ++iLayer) {
138 std::vector<o2::framework::InputSpec> filter;
139 for (const auto feeID : map.getLayer2FEEIDs(iLayer)) {
141 }
142 mDecoder[iLayer]->setInputFilter(filter);
143 }
144 }
145}
146
148template <class Mapping>
150{
151 updateTimeDependentParams(pc);
152 static bool firstCall = true;
153 if (!firstCall && pc.services().get<o2::framework::TimingInfo>().globalRunNumberChanged) { // reset at the beginning of the new run
154 reset();
155 }
156 if (firstCall) {
157 firstCall = false;
158 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
159 mDecoder[iLayer]->setInstanceID(pc.services().get<const o2::framework::DeviceSpec>().inputTimesliceId);
160 mDecoder[iLayer]->setNInstances(pc.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices);
161 mDecoder[iLayer]->setVerbosity(mDecoder[iLayer]->getInstanceID() == 0 ? mVerbosity : (mUnmutExtraLanes ? mVerbosity : -1));
162 }
163 mAllowReporting &= (mDecoder[0]->getInstanceID() == 0) || mUnmutExtraLanes;
164 }
165
166 int nSlots = pc.inputs().getNofParts(0);
167 double timeCPU0 = mTimer.CpuTime(), timeReal0 = mTimer.RealTime();
168 mTimer.Start(false);
169 auto orig = Mapping::getOrigin();
170
171 // these are accumulated from each layer
172 auto& chipStatus = pc.outputs().make<std::vector<char>>(Output{orig, "CHIPSSTATUS", 0}, (size_t)Mapping::getNChips());
173 auto& linkErrors = pc.outputs().make<std::vector<GBTLinkDecodingStat>>(Output{orig, "LinkErrors", 0});
174 auto& decErrors = pc.outputs().make<std::vector<ChipError>>(Output{orig, "ChipErrors", 0});
175 auto& errMessages = pc.outputs().make<std::vector<ErrorMessage>>(Output{orig, "ErrorInfo", 0});
176 auto& physTriggers = pc.outputs().make<std::vector<PhysTrigger>>(Output{orig, "PHYSTRIG", 0});
177
178 for (uint32_t iLayer{0}; iLayer < mLayers; ++iLayer) {
179 const auto& par = AlpideParam::Instance();
180 const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / par.getROFLengthInBC(iLayer);
181 const int nROFsTF = nROFsPerOrbit * o2::base::GRPGeomHelper::getNHBFPerTF();
182 int nLayer = mDoStaggering ? iLayer : -1;
183 std::vector<o2::itsmft::CompClusterExt> clusCompVec;
184 std::vector<o2::itsmft::ROFRecord> clusROFVec;
185 std::vector<unsigned char> clusPattVec;
186 std::vector<Digit> digVec;
187 std::vector<GBTCalibData> calVec;
188 std::vector<ROFRecord> digROFVec;
189 if (mDoDigits) {
190 digVec.reserve(mEstNDig[iLayer]);
191 digROFVec.reserve(nROFsTF);
192 }
193 if (mDoClusters) {
194 clusCompVec.reserve(mEstNClus[iLayer]);
195 clusROFVec.reserve(nROFsTF);
196 clusPattVec.reserve(mEstNClusPatt[iLayer]);
197 }
198 if (mDoCalibData) {
199 calVec.reserve(mEstNCalib[iLayer]);
200 }
201
202 try {
203 mDecoder[iLayer]->startNewTF(pc.inputs());
204 mDecoder[iLayer]->setDecodeNextAuto(false);
205
206 o2::InteractionRecord lastIR{};
207 int nTriggersProcessed = mDecoder[iLayer]->getNROFsProcessed();
208 static long lastErrReportTS = 0;
209 while (mDecoder[iLayer]->decodeNextTrigger() >= 0) {
210 if ((!lastIR.isDummy() && lastIR >= mDecoder[iLayer]->getInteractionRecord()) || mFirstIR > mDecoder[iLayer]->getInteractionRecord()) {
211 const int MaxErrLog = 2;
212 static int errLocCount = 0;
213 if (errLocCount++ < MaxErrLog) {
214 LOGP(warn, "Impossible ROF IR {}{}, previous was {}, TF 1st IR was {}, discarding in decoding", mDecoder[iLayer]->getInteractionRecord().asString(), ((mDoStaggering) ? std::format(" on layer {}", iLayer) : ""), lastIR.asString(), mFirstIR.asString());
215 }
216 nTriggersProcessed = 0x7fffffff; // to account for a problem with event
217 continue;
218 }
219 lastIR = mDecoder[iLayer]->getInteractionRecord();
220 mDecoder[iLayer]->fillChipsStatus(chipStatus);
221 if (mDoDigits || mClusterer->getMaxROFDepthToSquash(nLayer)) { // call before clusterization, since the latter will hide the digits
222 mDecoder[iLayer]->fillDecodedDigits(digVec, digROFVec); // lot of copying involved
223 if (mDoCalibData) {
224 mDecoder[iLayer]->fillCalibData(calVec);
225 }
226 }
227 if (mDoClusters && !mClusterer->getMaxROFDepthToSquash(nLayer)) { // !!! THREADS !!!
228 mClusterer->process(mNThreads, *mDecoder[iLayer].get(), &clusCompVec, mDoPatterns ? &clusPattVec : nullptr, &clusROFVec);
229 }
230 }
231 nTriggersProcessed = mDecoder[iLayer]->getNROFsProcessed() - nTriggersProcessed - 1;
232
233 if ((nROFsTF != nTriggersProcessed) && mROFErrRepIntervalMS > 0 && mTFCounter > 1 && nTriggersProcessed > 0) {
234 long currTS = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
235 if (currTS - lastErrReportTS > mROFErrRepIntervalMS) {
236 LOGP(critical, "Inconsistent number of ROF per TF {}{} from parameters. Received {} from readout (muting further reporting for {} ms)", nROFsTF, ((mDoStaggering) ? std::format(" on layer {}", iLayer) : ""), nTriggersProcessed, mROFErrRepIntervalMS);
237 lastErrReportTS = currTS;
238 }
239 }
240 if (mDoClusters && mClusterer->getMaxROFDepthToSquash(nLayer)) {
241 // Digits squashing require to run on a batch of digits and uses a digit reader, cannot (?) run with decoder
242 // - Setup decoder for running on a batch of digits
244 reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash(nLayer));
245 reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking
246 reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash(nLayer));
247 reader.setDigits(digVec);
248 reader.setROFRecords(digROFVec);
249 reader.init();
250 mClusterer->setMaxROFDepthToSquash(mClusterer->getMaxROFDepthToSquash(nLayer));
251 mClusterer->process(mNThreads, reader, &clusCompVec, mDoPatterns ? &clusPattVec : nullptr, &clusROFVec);
252 }
253 } catch (const std::exception& e) {
254 static size_t nErr = 0;
256 if (++nErr < maxWarn) {
257 LOGP(alarm, "EXCEPTION {} in raw decoder{}, abandoning TF decoding {}", e.what(), ((mDoStaggering) ? std::format(" on layer {}", iLayer) : ""), nErr == maxWarn ? "(will mute further warnings)" : "");
258 }
259 }
260 if (mDoDigits) {
261 pc.outputs().snapshot(Output{orig, "DIGITS", iLayer}, digVec);
262 std::vector<o2::itsmft::ROFRecord> expDigRofVec(nROFsTF);
263 ensureContinuousROF(digROFVec, expDigRofVec, iLayer, nROFsTF, "digits");
264 pc.outputs().snapshot(Output{orig, "DIGITSROF", iLayer}, digROFVec);
265 mEstNDig[iLayer] = std::max(mEstNDig[iLayer], size_t(digVec.size() * 1.2));
266 if (mDoCalibData) {
267 pc.outputs().snapshot(Output{orig, "GBTCALIB", iLayer}, calVec);
268 mEstNCalib[iLayer] = std::max(mEstNCalib[iLayer], size_t(calVec.size() * 1.2));
269 }
270 LOG(debug) << mSelfName << " Decoded " << digVec.size() << " Digits in " << digROFVec.size() << " ROFs" << ((mDoStaggering) ? std::format(" on layer {}", iLayer) : "");
271 }
272
273 if (mDoClusters) { // we are not obliged to create vectors which are not requested, but other devices might not know the options of this one
274 std::vector<o2::itsmft::ROFRecord> expClusRofVec(nROFsTF);
275 ensureContinuousROF(clusROFVec, expClusRofVec, iLayer, nROFsTF, "clusters");
276 pc.outputs().snapshot(Output{orig, "COMPCLUSTERS", iLayer}, clusCompVec);
277 pc.outputs().snapshot(Output{orig, "PATTERNS", iLayer}, clusPattVec);
278 pc.outputs().snapshot(Output{orig, "CLUSTERSROF", iLayer}, expClusRofVec);
279 mEstNClus[iLayer] = std::max(mEstNClus[iLayer], size_t(clusCompVec.size() * 1.2));
280 mEstNClusPatt[iLayer] = std::max(mEstNClusPatt[iLayer], size_t(clusPattVec.size() * 1.2));
281 LOG(info) << mSelfName << " Built " << clusCompVec.size() << " clusters in " << expClusRofVec.size() << " ROFs" << ((mDoStaggering) ? std::format(" on layer {}", iLayer) : "");
282 }
283
284 mDecoder[iLayer]->collectDecodingErrors(linkErrors, decErrors, errMessages);
285 physTriggers.insert(physTriggers.end(), mDecoder[iLayer]->getExternalTriggers().begin(), mDecoder[iLayer]->getExternalTriggers().end());
286
287 if (mDumpOnError != int(GBTLink::RawDataDumps::DUMP_NONE) &&
288 (!mDumpFrom1stPipeline || pc.services().get<const o2::framework::DeviceSpec>().inputTimesliceId == 0)) {
289 mRawDumpedSize += mDecoder[iLayer]->produceRawDataDumps(mDumpOnError, pc.services().get<o2::framework::TimingInfo>());
290 if (mRawDumpedSize > mMaxRawDumpsSize && mMaxRawDumpsSize > 0) {
291 LOGP(info, "Max total dumped size {} MB exceeded allowed limit, disabling further dumping", mRawDumpedSize / (1024 * 1024));
293 }
294 }
295 }
296
297 mTimer.Stop();
298 auto tfID = pc.services().get<o2::framework::TimingInfo>().tfCounter;
299 LOG(debug) << mSelfName << " Total time for TF " << tfID << '(' << mTFCounter << ") : CPU: " << mTimer.CpuTime() - timeCPU0 << " Real: " << mTimer.RealTime() - timeReal0;
300 mTFCounter++;
301}
302
304template <class Mapping>
306{
307 if (mFinalizeDone) {
308 return;
309 }
310 mFinalizeDone = true;
311 LOGF(info, "%s statistics:", mSelfName);
312 LOGF(info, "%s Total STF decoding%s timing (w/o disk IO): Cpu: %.3e Real: %.3e s in %d slots", mSelfName,
313 mDoClusters ? "/clustering" : "", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1);
314 for (int iLayer{0}; iLayer < mLayers && mAllowReporting; ++iLayer) {
315 if (mDecoder[iLayer]) {
316 LOG_IF(info, mDoStaggering) << "Report for decoder of layer " << iLayer;
317 mDecoder[iLayer]->printReport();
318 }
319 }
320 if (mClusterer) {
321 mClusterer->print();
322 }
323}
324
326template <class Mapping>
327void STFDecoder<Mapping>::updateTimeDependentParams(ProcessingContext& pc)
328{
329 // we call these methods just to trigger finaliseCCDB callback
331 if (pc.services().get<o2::framework::TimingInfo>().globalRunNumberChanged) { // this params need to be queried only in the beginning of the run
332 pc.inputs().get<o2::itsmft::NoiseMap*>("noise");
333 pc.inputs().get<o2::itsmft::DPLAlpideParam<Mapping::getDetID()>*>("alppar");
334 const auto& alpParams = DPLAlpideParam<Mapping::getDetID()>::Instance();
335 alpParams.printKeyValues();
336 if (mDoClusters) {
337 mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(Mapping::getDetID()));
339 pc.inputs().get<o2::itsmft::ClustererParam<Mapping::getDetID()>*>("cluspar");
340 // settings for the fired pixel overflow masking
341 const auto& clParams = ClustererParam<Mapping::getDetID()>::Instance();
342 if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) {
343 LOGP(fatal, "maxBCDiffToMaskBias = {} and maxBCDiffToMaskBias = {} cannot be set at the same time. Either set masking or squashing with a BCDiff > 0", clParams.maxBCDiffToMaskBias, clParams.maxBCDiffToSquashBias);
344 }
345 clParams.printKeyValues();
346 auto nbc = clParams.maxBCDiffToMaskBias;
347 nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS);
348 mClusterer->setMaxBCSeparationToMask(nbc);
349 mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask);
350 // Squasher
351 int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC
352 mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias);
353 int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0.
354 if (clParams.maxSOTMUS > 0 && rofBC > 0) {
355 nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing
356 }
357 mClusterer->setMaxROFDepthToSquash(clParams.maxBCDiffToSquashBias > 0 ? nROFsToSquash : 0);
358 if (mDoStaggering) {
359 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
360 mClusterer->addMaxBCSeparationToSquash(alpParams.getROFLengthInBC(iLayer) + clParams.getMaxBCDiffToSquashBias(iLayer));
361 mClusterer->addMaxROFDepthToSquash((clParams.getMaxBCDiffToSquashBias(iLayer) > 0) ? 2 + int(clParams.maxSOTMUS / (alpParams.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingMUS)) : 0);
362 }
363 }
364 mClusterer->print(false);
365 }
366 }
367 mFirstTFOrbit = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
368 mFirstIR = o2::InteractionRecord(0, mFirstTFOrbit);
369}
370
372template <class Mapping>
374{
375 if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
376 return;
377 }
378 if (matcher == ConcreteDataMatcher(Mapping::getOrigin(), "NOISEMAP", 0)) {
379 LOG(info) << Mapping::getName() << " noise map updated" << (!mApplyNoiseMap ? " but masking is disabled" : "");
380 if (mApplyNoiseMap) {
382 }
383 return;
384 }
385 if (matcher == ConcreteDataMatcher(Mapping::getOrigin(), "CLUSDICT", 0)) {
386 LOG(info) << Mapping::getName() << " cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : "");
387 if (mUseClusterDictionary) {
388 mClusterer->setDictionary((const TopologyDictionary*)obj);
389 }
390 return;
391 }
392 // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level
393 if (matcher == ConcreteDataMatcher(Mapping::getOrigin(), "ALPIDEPARAM", 0)) {
394 LOG(info) << "Alpide param updated";
395 return;
396 }
397}
398
400template <class Mapping>
402{
403 // reset for the new run
404 mFinalizeDone = false;
405 mTFCounter = 0;
406 mTimer.Reset();
407 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
408 if (mDecoder[iLayer]) {
409 mDecoder[iLayer]->reset();
410 }
411 }
412 if (mClusterer) {
413 mClusterer->reset();
414 }
415}
416
418template <class Mapping>
419void STFDecoder<Mapping>::ensureContinuousROF(const std::vector<ROFRecord>& rofVec, std::vector<ROFRecord>& expROFVec, int lr, int nROFsTF, const char* name)
420{
421 const auto& par = AlpideParam::Instance();
422 // ensure that the rof output is continuous
423 // we will preserve the digits/clusters as they are but the stray ROFs will be removed (leaving their clusters/digits unaddressed).
424 expROFVec.clear();
425 expROFVec.resize(nROFsTF);
426 for (int iROF{0}; iROF < nROFsTF; ++iROF) {
427 auto& rof = expROFVec[iROF];
428 int orb = iROF * par.getROFLengthInBC(lr) / o2::constants::lhc::LHCMaxBunches + mFirstTFOrbit;
429 int bc = iROF * par.getROFLengthInBC(lr) % o2::constants::lhc::LHCMaxBunches + par.getROFDelayInBC(lr);
431 rof.setBCData(ir);
432 rof.setROFrame(iROF);
433 rof.setNEntries(0);
434 rof.setFirstEntry(-1);
435 }
436 uint32_t prevEntry{0};
437 for (const auto& rof : rofVec) {
438 const auto& ir = rof.getBCData();
439 if (ir < mFirstIR) {
440 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {}{}", ir.asString(), mFirstTFOrbit, ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
441 continue;
442 }
443 auto irToFirst = ir - mFirstIR;
444 if (irToFirst.toLong() - par.getROFDelayInBC(lr) < 0) {
445 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {} due to imposed ROF delay{}", ir.asString(), mFirstTFOrbit, ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
446 continue;
447 }
448 irToFirst -= par.getROFDelayInBC(lr);
449 const long irROF = irToFirst.toLong() / par.getROFLengthInBC(lr);
450 if (irROF >= nROFsTF) {
451 LOGP(warn, "Discard ROF {} exceeding TF orbit range{}", ir.asString(), ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
452 continue;
453 }
454 auto& expROF = expROFVec[irROF];
455 if (expROF.getNEntries() == 0) {
456 expROF.setFirstEntry(rof.getFirstEntry());
457 expROF.setNEntries(rof.getNEntries());
458 } else {
459 if (expROF.getNEntries() < rof.getNEntries()) {
460 LOGP(warn, "Repeating {} with {} {}, prefer to already processed instance with {} {}{}", rof.asString(), rof.getNEntries(), name, expROF.getNEntries(), name, ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
461 expROF.setFirstEntry(rof.getFirstEntry());
462 expROF.setNEntries(rof.getNEntries());
463 } else {
464 LOGP(warn, "Repeating {} with {} {}, discard preferring already processed instance with {} {}{}", rof.asString(), rof.getNEntries(), name, expROF.getNEntries(), name, ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
465 }
466 }
467 }
468 int prevFirst{0};
469 for (auto& rof : expROFVec) {
470 if (rof.getFirstEntry() < 0) {
471 rof.setFirstEntry(prevFirst);
472 }
473 prevFirst = rof.getFirstEntry();
474 }
475}
476
479{
480 std::vector<OutputSpec> outputs;
481 auto inputs = o2::framework::select(inp.inputSpec.c_str());
482 uint32_t nLayers = 1;
485 } else if (inp.origin == o2::header::gDataOriginMFT && inp.doStaggering) {
487 }
488 for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) {
489 if (inp.doDigits) {
490 outputs.emplace_back(inp.origin, "DIGITS", iLayer, Lifetime::Timeframe);
491 outputs.emplace_back(inp.origin, "DIGITSROF", iLayer, Lifetime::Timeframe);
492 }
493 if (inp.doClusters) {
494 outputs.emplace_back(inp.origin, "COMPCLUSTERS", iLayer, Lifetime::Timeframe);
495 outputs.emplace_back(inp.origin, "CLUSTERSROF", iLayer, Lifetime::Timeframe);
496 // in principle, we don't need to open this input if we don't need to send real data,
497 // but other devices expecting it do not know about options of this device: problem?
498 // if (doClusters && doPatterns)
499 outputs.emplace_back(inp.origin, "PATTERNS", iLayer, Lifetime::Timeframe);
500 }
501 }
502 if (inp.doDigits && inp.doCalib) {
503 outputs.emplace_back(inp.origin, "GBTCALIB", 0, Lifetime::Timeframe);
504 }
505 outputs.emplace_back(inp.origin, "PHYSTRIG", 0, Lifetime::Timeframe);
506 outputs.emplace_back(inp.origin, "LinkErrors", 0, Lifetime::Timeframe);
507 outputs.emplace_back(inp.origin, "ChipErrors", 0, Lifetime::Timeframe);
508 outputs.emplace_back(inp.origin, "ErrorInfo", 0, Lifetime::Timeframe);
509 outputs.emplace_back(inp.origin, "CHIPSSTATUS", 0, Lifetime::Timeframe);
510
511 if (inp.askSTFDist) {
512 // request the input FLP/DISTSUBTIMEFRAME/0 that is _guaranteed_ to be present, even if none of our raw data is present.
513 inputs.emplace_back("stfDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe);
514 }
515 inputs.emplace_back("noise", inp.origin, "NOISEMAP", 0, Lifetime::Condition,
516 o2::framework::ccdbParamSpec(fmt::format("{}/Calib/NoiseMap", inp.origin.as<std::string>())));
517 inputs.emplace_back("alppar", inp.origin, "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Config/AlpideParam", inp.origin.as<std::string>())));
518 if (inp.doClusters) {
519 inputs.emplace_back("cldict", inp.origin, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/ClusterDictionary", inp.origin.as<std::string>())));
520 inputs.emplace_back("cluspar", inp.origin, "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Config/ClustererParam", inp.origin.as<std::string>())));
521 }
522
523 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
524 true, // GRPECS=true
525 false, // GRPLHCIF
526 false, // GRPMagField
527 false, // askMatLUT
529 inputs,
530 true); // query only once all objects except mag.field
531
532 return DataProcessorSpec{
533 .name = inp.deviceName,
534 .inputs = inputs,
535 .outputs = outputs,
536 .algorithm = inp.origin == o2::header::gDataOriginITS ? AlgorithmSpec{adaptFromTask<STFDecoder<ChipMappingITS>>(inp, ggRequest)} : AlgorithmSpec{adaptFromTask<STFDecoder<ChipMappingMFT>>(inp, ggRequest)},
537 .options = Options{
538 {"nthreads", VariantType::Int, 1, {"Number of decoding/clustering threads"}},
539 {"decoder-verbosity", VariantType::Int, 0, {"Verbosity level (-1: silent, 0: errors, 1: headers, 2: data, 3: raw data dump) of 1st lane"}},
540 {"always-parse-trigger", VariantType::Bool, false, {"parse trigger word even if flags continuation of old trigger"}},
541 {"raw-data-dumps", VariantType::Int, int(GBTLink::RawDataDumps::DUMP_NONE), {"Raw data dumps on error (0: none, 1: HBF for link, 2: whole TF for all links. If negative, dump only on from 1st pipeline."}},
542 {"raw-data-dumps-directory", VariantType::String, "", {"Destination directory for the raw data dumps"}},
543 {"stop-raw-data-dumps-after-size", VariantType::Int, 1024, {"Stop dumping once this size in MB is accumulated. 0: no limit"}},
544 {"unmute-extra-lanes", VariantType::Bool, false, {"allow extra lanes to be as verbose as 1st one"}},
545 {"allow-empty-rofs", VariantType::Bool, false, {"record ROFs w/o any hit"}},
546 {"ignore-noise-map", VariantType::Bool, false, {"do not mask pixels flagged in the noise map"}},
547 {"accept-rof-rampup-data", VariantType::Bool, false, {"do not discard data during ROF ramp up"}},
548 {"rof-length-error-freq", VariantType::Float, 60.f, {"do not report ROF length error more frequently than this value, disable if negative"}},
549 {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}}};
550}
551
552} // namespace itsmft
553} // namespace o2
Definition of the ITS/MFT clusterer settings.
Definition of the ITSMFT compact cluster.
std::string asString(TDataMember const &dm, char *pointer)
Definition of the ITSMFT digit.
Definition of the Alpide pixel reader for MC digits processing.
std::ostringstream debug
uint64_t bc
Definition RawEventData.h:5
Header of the AggregatedRunInfo struct.
Helper for geometry and GRP related CCDB requests.
Definition of the ITSMFT ROFrame (trigger) record.
Definition of the ITS cluster finder.
Definition of the Alpide pixel reader for raw data processing.
Device to decode ITS/MFT raw data from STF.
Checks validity of hardware address (HW) and transform it to digit AbsId index.
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
void printKeyValues(bool showProv=true, bool useLogger=false, bool withPadding=true, bool showHash=true) const final
void snapshot(const Output &spec, T const &object)
decltype(auto) make(const Output &spec, Args... args)
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
size_t getNofParts(int pos) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
static void setNoisyPixels(const NoiseMap *noise)
void setDigits(const gsl::span< const o2::itsmft::Digit > a)
void setSquashingDist(const int16_t v)
void setROFRecords(const gsl::span< const o2::itsmft::ROFRecord > a)
void setSquashingDepth(const int16_t v)
NoiseMap class for the ITS and MFT.
Definition NoiseMap.h:39
void run(ProcessingContext &pc) final
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
void init(InitContext &ic) final
GLuint const GLchar * name
Definition glcorearb.h:781
GLfloat v0
Definition glcorearb.h:811
GLfloat GLfloat v1
Definition glcorearb.h:812
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLfloat GLfloat GLfloat v2
Definition glcorearb.h:813
constexpr o2::header::DataOrigin gDataOriginMFT
Definition DataHeader.h:572
constexpr o2::header::DataDescription gDataDescriptionRawData
Definition DataHeader.h:598
constexpr o2::header::DataOrigin gDataOriginITS
Definition DataHeader.h:570
constexpr double LHCBunchSpacingMUS
constexpr int LHCMaxBunches
constexpr double LHCBunchSpacingNS
Node par(int index)
Parameters.
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > select(char const *matcher="")
auto get(const std::byte *buffer, size_t=0)
Definition DataHeader.h:454
o2::framework::DataProcessorSpec getSTFDecoderSpec(const STFDecoderInp &inp)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string asString() const
size_t maxInputTimeslices
The maximum number of time pipelining for this device.
Definition DeviceSpec.h:70
size_t inputTimesliceId
The time pipelining id of this particular device.
Definition DeviceSpec.h:68
uint32_t SubSpecificationType
Definition DataHeader.h:622
std::enable_if_t< std::is_same< T, std::string >::value==true, T > as() const
get the descriptor as std::string
Definition DataHeader.h:301
void runtimeInit(const char *string, short length=-1)
Definition DataHeader.h:261
float maxSOTMUS
max expected signal over threshold in \mus
int getMaxBCDiffToSquashBias(int layer) const noexcept
int maxBCDiffToSquashBias
squash if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable squashing
int maxRowColDiffToMask
pixel may be masked as overflow if such a neighbour in prev frame was fired
int maxBCDiffToMaskBias
mask if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable masking
static constexpr int getNLayers()
int getROFLengthInBC(int layer) const noexcept
int roFrameLengthInBC
ROF length in BC for continuous mode.
float roFrameLengthTrig
length of RO frame in ns for triggered mode
o2::header::DataOrigin origin
static bool pathIsDirectory(const std::string_view p)
static std::vector< std::string > tokenize(const std::string &src, char delim, bool trimToken=true, bool skipEmpty=true)
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)