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{
66 int lane = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId;
68 try {
69 auto v0 = o2::utils::Str::tokenize(mInputSpec, ':');
70 auto v1 = o2::utils::Str::tokenize(v0[1], '/');
71 auto v2 = o2::utils::Str::tokenize(v1[1], '?');
72 header::DataOrigin dataOrig;
74 dataOrig.runtimeInit(v1[0].c_str());
75 dataDesc.runtimeInit(v2[0].c_str());
76 Mapping map;
77 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
78 auto& dec = mDecoder.emplace_back(std::make_unique<RawPixelDecoder<Mapping>>());
79 dec->setUserDataOrigin(dataOrig);
80 dec->setUserDataDescription(dataDesc);
81 dec->init(); // is this no-op?
82
83 if (mDoStaggering) {
84 std::vector<o2::framework::InputSpec> filter;
85 for (const auto feeID : map.getLayer2FEEIDs(iLayer)) {
86 filter.emplace_back("filter", ConcreteDataMatcher{dataOrig, dataDesc, (o2::header::DataHeader::SubSpecificationType)feeID});
87 }
88 dec->setInputFilter(filter);
89 } else {
90 dec->setInputFilter({InputSpec{"filter", ConcreteDataTypeMatcher(dataOrig, dataDesc)}});
91 }
92 }
93 } catch (const std::exception& e) {
94 LOG(error) << "exception was thrown in decoder creation: " << e.what();
95 throw;
96 } catch (...) {
97 LOG(error) << "non-std::exception was thrown in decoder creation";
98 throw;
99 }
100 mApplyNoiseMap = !ic.options().get<bool>("ignore-noise-map");
101 mUseClusterDictionary = !ic.options().get<bool>("ignore-cluster-dictionary");
102 try {
103 float fr = ic.options().get<float>("rof-length-error-freq");
104 mROFErrRepIntervalMS = fr <= 0. ? -1 : long(fr * 1e3);
105 mNThreads = std::max(1, ic.options().get<int>("nthreads"));
106 mUnmutExtraLanes = ic.options().get<bool>("unmute-extra-lanes");
107 mVerbosity = ic.options().get<int>("decoder-verbosity");
108 auto dmpSz = ic.options().get<int>("stop-raw-data-dumps-after-size");
109 if (dmpSz > 0) {
110 mMaxRawDumpsSize = size_t(dmpSz) * 1024 * 1024;
111 }
112 mDumpOnError = ic.options().get<int>("raw-data-dumps");
113 if (mDumpOnError < 0) {
114 mDumpOnError = -mDumpOnError;
115 mDumpFrom1stPipeline = true;
116 }
117 if (mDumpOnError >= int(GBTLink::RawDataDumps::DUMP_NTYPES)) {
118 throw std::runtime_error(fmt::format("unknown raw data dump level {} requested", mDumpOnError));
119 }
120 auto dumpDir = ic.options().get<std::string>("raw-data-dumps-directory");
121 if (mDumpOnError != int(GBTLink::RawDataDumps::DUMP_NONE) && (!dumpDir.empty() && !o2::utils::Str::pathIsDirectory(dumpDir))) {
122 throw std::runtime_error(fmt::format("directory {} for raw data dumps does not exist", dumpDir));
123 }
124 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
125 mDecoder[iLayer]->setNThreads(mNThreads);
126 mDecoder[iLayer]->setAlwaysParseTrigger(ic.options().get<bool>("always-parse-trigger"));
127 mDecoder[iLayer]->setAllowEmptyROFs(ic.options().get<bool>("allow-empty-rofs"));
128 mDecoder[iLayer]->setRawDumpDirectory(dumpDir);
129 mDecoder[iLayer]->setFillCalibData(mDoCalibData);
130 mDecoder[iLayer]->setVerifyDecoder(mVerifyDecoder);
131 bool ignoreRampUp = !ic.options().get<bool>("accept-rof-rampup-data");
132 mDecoder[iLayer]->setSkipRampUpData(ignoreRampUp);
133 }
134 } catch (const std::exception& e) {
135 LOG(error) << "exception was thrown in decoder configuration: " << e.what();
136 throw;
137 } catch (...) {
138 LOG(error) << "non-std::exception was thrown in decoder configuration";
139 throw;
140 }
141 if (mDoCalibData) {
142 std::string warnMsg;
143 bool enforceEnsureContinuousROFinCalib = ic.options().get<bool>("enforce-continuous-rof-with-calib");
144 if (ic.options().get<bool>("enforce-continuous-rof-with-calib")) {
145 warnMsg = "Calibration data requested but the ensureContinuousROF is explicitly enforced!";
146 } else {
147 mRunEnsureContinuousROF = false;
148 warnMsg = "Calibration data requested, disabling ensureContinuousROF!";
149 }
150 if (lane == 0) {
151 LOGP(alarm, "{}", warnMsg);
152 } else {
153 LOGP(info, "{}", warnMsg);
154 }
155 }
156
157 mDisableRectifyContinuousROF = ic.options().get<bool>("disable-rectify-continuous-rof");
158 if (mDisableRectifyContinuousROF && mRunEnsureContinuousROF) {
159 std::string warnMsg = "Rectification of clusters/digits is explicitly disabled after the ensureContinuousROF!";
160 if (lane == 0) {
161 LOGP(alarm, "{}", warnMsg);
162 } else {
163 LOGP(info, "{}", warnMsg);
164 }
165 }
166
167 if (mDoClusters) {
168 mClusterer = std::make_unique<Clusterer>();
169 mClusterer->setNChips(Mapping::getNChips());
170 }
171}
172
174template <class Mapping>
176{
177 updateTimeDependentParams(pc);
178 static bool firstCall = true;
179 if (!firstCall && pc.services().get<o2::framework::TimingInfo>().globalRunNumberChanged) { // reset at the beginning of the new run
180 reset();
181 }
182 if (firstCall) {
183 firstCall = false;
184 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
185 mDecoder[iLayer]->setInstanceID(pc.services().get<const o2::framework::DeviceSpec>().inputTimesliceId);
186 mDecoder[iLayer]->setNInstances(pc.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices);
187 mDecoder[iLayer]->setVerbosity(mDecoder[iLayer]->getInstanceID() == 0 ? mVerbosity : (mUnmutExtraLanes ? mVerbosity : -1));
188 }
189 mAllowReporting &= (mDecoder[0]->getInstanceID() == 0) || mUnmutExtraLanes;
190 }
191
192 int nSlots = pc.inputs().getNofParts(0);
193 double timeCPU0 = mTimer.CpuTime(), timeReal0 = mTimer.RealTime();
194 mTimer.Start(false);
195 auto orig = Mapping::getOrigin();
196
197 // these are accumulated from each layer
198 auto& chipStatus = pc.outputs().make<std::vector<char>>(Output{orig, "CHIPSSTATUS", 0}, (size_t)Mapping::getNChips());
199 auto& linkErrors = pc.outputs().make<std::vector<GBTLinkDecodingStat>>(Output{orig, "LinkErrors", 0});
200 auto& decErrors = pc.outputs().make<std::vector<ChipError>>(Output{orig, "ChipErrors", 0});
201 auto& errMessages = pc.outputs().make<std::vector<ErrorMessage>>(Output{orig, "ErrorInfo", 0});
202 auto& physTriggers = pc.outputs().make<std::vector<PhysTrigger>>(Output{orig, "PHYSTRIG", 0});
203
204 for (uint32_t iLayer{0}; iLayer < mLayers; ++iLayer) {
205 const auto& par = AlpideParam::Instance();
206 const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / par.getROFLengthInBC(iLayer);
207 const int nROFsTF = nROFsPerOrbit * o2::base::GRPGeomHelper::getNHBFPerTF();
208 int nLayer = mDoStaggering ? iLayer : -1;
209 std::vector<o2::itsmft::CompClusterExt> clusCompVec;
210 std::vector<o2::itsmft::ROFRecord> clusROFVec;
211 std::vector<unsigned char> clusPattVec;
212 std::vector<Digit> digVec;
213 std::vector<GBTCalibData> calVec;
214 std::vector<ROFRecord> digROFVec;
215 if (mDoDigits) {
216 digVec.reserve(mEstNDig[iLayer]);
217 digROFVec.reserve(nROFsTF);
218 }
219 if (mDoClusters) {
220 clusCompVec.reserve(mEstNClus[iLayer]);
221 clusROFVec.reserve(nROFsTF);
222 clusPattVec.reserve(mEstNClusPatt[iLayer]);
223 }
224 if (mDoCalibData) {
225 calVec.reserve(mEstNCalib[iLayer]);
226 }
227
228 try {
229 mDecoder[iLayer]->startNewTF(pc.inputs());
230 mDecoder[iLayer]->setDecodeNextAuto(false);
231
232 o2::InteractionRecord lastIR{};
233 int nTriggersProcessed = mDecoder[iLayer]->getNROFsProcessed();
234 static long lastErrReportTS = 0;
235 while (mDecoder[iLayer]->decodeNextTrigger() >= 0) {
236 if ((!lastIR.isDummy() && lastIR >= mDecoder[iLayer]->getInteractionRecord()) || mFirstIR > mDecoder[iLayer]->getInteractionRecord()) {
237 const int MaxErrLog = 2;
238 static int errLocCount = 0;
239 if (errLocCount++ < MaxErrLog) {
240 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());
241 }
242 nTriggersProcessed = 0x7fffffff; // to account for a problem with event
243 continue;
244 }
245 lastIR = mDecoder[iLayer]->getInteractionRecord();
246 mDecoder[iLayer]->fillChipsStatus(chipStatus);
247 if (mDoDigits || mClusterer->getMaxROFDepthToSquash(nLayer)) { // call before clusterization, since the latter will hide the digits
248 mDecoder[iLayer]->fillDecodedDigits(digVec, digROFVec); // lot of copying involved
249 if (mDoCalibData) {
250 mDecoder[iLayer]->fillCalibData(calVec);
251 }
252 }
253 if (mDoClusters && !mClusterer->getMaxROFDepthToSquash(nLayer)) { // !!! THREADS !!!
254 mClusterer->process(mNThreads, *mDecoder[iLayer].get(), &clusCompVec, mDoPatterns ? &clusPattVec : nullptr, &clusROFVec);
255 }
256 }
257 nTriggersProcessed = mDecoder[iLayer]->getNROFsProcessed() - nTriggersProcessed - 1;
258
259 if ((nROFsTF != nTriggersProcessed) && mROFErrRepIntervalMS > 0 && mTFCounter > 1 && nTriggersProcessed > 0) {
260 long currTS = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
261 if (currTS - lastErrReportTS > mROFErrRepIntervalMS) {
262 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);
263 lastErrReportTS = currTS;
264 }
265 }
266 if (mDoClusters && mClusterer->getMaxROFDepthToSquash(nLayer)) {
267 // Digits squashing require to run on a batch of digits and uses a digit reader, cannot (?) run with decoder
268 // - Setup decoder for running on a batch of digits
270 reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash(nLayer));
271 reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking
272 reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash(nLayer));
273 reader.setDigits(digVec);
274 reader.setROFRecords(digROFVec);
275 reader.init();
276 mClusterer->setMaxROFDepthToSquash(mClusterer->getMaxROFDepthToSquash(nLayer));
277 mClusterer->process(mNThreads, reader, &clusCompVec, mDoPatterns ? &clusPattVec : nullptr, &clusROFVec);
278 }
279 } catch (const std::exception& e) {
280 static size_t nErr = 0;
282 if (++nErr < maxWarn) {
283 LOGP(alarm, "EXCEPTION {} in raw decoder{}, abandoning TF decoding {}", e.what(), ((mDoStaggering) ? std::format(" on layer {}", iLayer) : ""), nErr == maxWarn ? "(will mute further warnings)" : "");
284 }
285 }
286 if (mDoDigits) {
287 std::vector<o2::itsmft::ROFRecord> expDigRofVec;
288 if (ensureContinuousROF(digROFVec, expDigRofVec, iLayer, nROFsTF, "digits") && !mDisableRectifyContinuousROF) {
289 auto oldNDig = digVec.size();
290 rectifyDigits(expDigRofVec, digVec);
291 LOGP(warn, "Rectified {} digits out of original {} on layer {} following ensureContinuousROF", digVec.size(), oldNDig, iLayer);
292 }
293 pc.outputs().snapshot(Output{orig, "DIGITS", iLayer}, digVec);
294 pc.outputs().snapshot(Output{orig, "DIGITSROF", iLayer}, expDigRofVec);
295 mEstNDig[iLayer] = std::max(mEstNDig[iLayer], size_t(digVec.size() * 1.2));
296 if (mDoCalibData) {
297 pc.outputs().snapshot(Output{orig, "GBTCALIB", iLayer}, calVec);
298 mEstNCalib[iLayer] = std::max(mEstNCalib[iLayer], size_t(calVec.size() * 1.2));
299 }
300 LOG(debug) << mSelfName << " Decoded " << digVec.size() << " Digits in " << expDigRofVec.size() << " ROFs" << ((mDoStaggering) ? std::format(" on layer {}", iLayer) : "");
301 }
302
303 if (mDoClusters) { // we are not obliged to create vectors which are not requested, but other devices might not know the options of this one
304 std::vector<o2::itsmft::ROFRecord> expClusRofVec;
305 if (ensureContinuousROF(clusROFVec, expClusRofVec, iLayer, nROFsTF, "clusters") && !mDisableRectifyContinuousROF) {
306 auto oldNClus = clusCompVec.size(), oldNPatt = clusPattVec.size();
307 rectifyClusters(expClusRofVec, clusCompVec, clusPattVec);
308 LOGP(warn, "Rectified {} clusters and {} patterns out of original {} and {} on layer {} following ensureContinuousROF", clusCompVec.size(), clusPattVec.size(), oldNClus, oldNPatt, iLayer);
309 }
310 pc.outputs().snapshot(Output{orig, "COMPCLUSTERS", iLayer}, clusCompVec);
311 pc.outputs().snapshot(Output{orig, "PATTERNS", iLayer}, clusPattVec);
312 pc.outputs().snapshot(Output{orig, "CLUSTERSROF", iLayer}, expClusRofVec);
313 mEstNClus[iLayer] = std::max(mEstNClus[iLayer], size_t(clusCompVec.size() * 1.2));
314 mEstNClusPatt[iLayer] = std::max(mEstNClusPatt[iLayer], size_t(clusPattVec.size() * 1.2));
315 LOG(info) << mSelfName << " Built " << clusCompVec.size() << " clusters in " << expClusRofVec.size() << " ROFs" << ((mDoStaggering) ? std::format(" on layer {}", iLayer) : "");
316 }
317
318 mDecoder[iLayer]->collectDecodingErrors(linkErrors, decErrors, errMessages);
319 physTriggers.insert(physTriggers.end(), mDecoder[iLayer]->getExternalTriggers().begin(), mDecoder[iLayer]->getExternalTriggers().end());
320
321 if (mDumpOnError != int(GBTLink::RawDataDumps::DUMP_NONE) &&
322 (!mDumpFrom1stPipeline || pc.services().get<const o2::framework::DeviceSpec>().inputTimesliceId == 0)) {
323 mRawDumpedSize += mDecoder[iLayer]->produceRawDataDumps(mDumpOnError, pc.services().get<o2::framework::TimingInfo>());
324 if (mRawDumpedSize > mMaxRawDumpsSize && mMaxRawDumpsSize > 0) {
325 LOGP(info, "Max total dumped size {} MB exceeded allowed limit, disabling further dumping", mRawDumpedSize / (1024 * 1024));
327 }
328 }
329 }
330
331 mTimer.Stop();
332 auto tfID = pc.services().get<o2::framework::TimingInfo>().tfCounter;
333 LOG(debug) << mSelfName << " Total time for TF " << tfID << '(' << mTFCounter << ") : CPU: " << mTimer.CpuTime() - timeCPU0 << " Real: " << mTimer.RealTime() - timeReal0;
334 mTFCounter++;
335}
336
338template <class Mapping>
340{
341 if (mFinalizeDone) {
342 return;
343 }
344 mFinalizeDone = true;
345 LOGF(info, "%s statistics:", mSelfName);
346 LOGF(info, "%s Total STF decoding%s timing (w/o disk IO): Cpu: %.3e Real: %.3e s in %d slots", mSelfName,
347 mDoClusters ? "/clustering" : "", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1);
348 for (int iLayer{0}; iLayer < mLayers && mAllowReporting; ++iLayer) {
349 if (mDecoder[iLayer]) {
350 LOG_IF(info, mDoStaggering) << "Report for decoder of layer " << iLayer;
351 mDecoder[iLayer]->printReport();
352 }
353 }
354 if (mClusterer) {
355 mClusterer->print();
356 }
357}
358
360template <class Mapping>
361void STFDecoder<Mapping>::updateTimeDependentParams(ProcessingContext& pc)
362{
363 // we call these methods just to trigger finaliseCCDB callback
365 if (pc.services().get<o2::framework::TimingInfo>().globalRunNumberChanged) { // this params need to be queried only in the beginning of the run
366 pc.inputs().get<o2::itsmft::NoiseMap*>("noise");
367 pc.inputs().get<o2::itsmft::DPLAlpideParam<Mapping::getDetID()>*>("alppar");
368 const auto& alpParams = DPLAlpideParam<Mapping::getDetID()>::Instance();
369 alpParams.printKeyValues();
370 if (mDoClusters) {
371 mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(Mapping::getDetID()));
373 pc.inputs().get<o2::itsmft::ClustererParam<Mapping::getDetID()>*>("cluspar");
374 // settings for the fired pixel overflow masking
375 const auto& clParams = ClustererParam<Mapping::getDetID()>::Instance();
376 if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) {
377 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);
378 }
379 clParams.printKeyValues();
380 auto nbc = clParams.maxBCDiffToMaskBias;
381 nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS);
382 mClusterer->setMaxBCSeparationToMask(nbc);
383 mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask);
384 // Squasher
385 int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC
386 mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias);
387 int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0.
388 if (clParams.maxSOTMUS > 0 && rofBC > 0) {
389 nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing
390 }
391 mClusterer->setMaxROFDepthToSquash(clParams.maxBCDiffToSquashBias > 0 ? nROFsToSquash : 0);
392 if (mDoStaggering) {
393 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
394 mClusterer->addMaxBCSeparationToSquash(alpParams.getROFLengthInBC(iLayer) + clParams.getMaxBCDiffToSquashBias(iLayer));
395 mClusterer->addMaxROFDepthToSquash((clParams.getMaxBCDiffToSquashBias(iLayer) > 0) ? 2 + int(clParams.maxSOTMUS / (alpParams.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingMUS)) : 0);
396 }
397 }
398 mClusterer->print(false);
399 }
400 }
401 mFirstTFOrbit = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
402 mFirstIR = o2::InteractionRecord(0, mFirstTFOrbit);
403}
404
406template <class Mapping>
408{
409 if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
410 return;
411 }
412 if (matcher == ConcreteDataMatcher(Mapping::getOrigin(), "NOISEMAP", 0)) {
413 LOG(info) << Mapping::getName() << " noise map updated" << (!mApplyNoiseMap ? " but masking is disabled" : "");
414 if (mApplyNoiseMap) {
416 }
417 return;
418 }
419 if (matcher == ConcreteDataMatcher(Mapping::getOrigin(), "CLUSDICT", 0)) {
420 LOG(info) << Mapping::getName() << " cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : "");
421 if (mUseClusterDictionary) {
422 mClusterer->setDictionary((const TopologyDictionary*)obj);
423 }
424 return;
425 }
426 // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level
427 if (matcher == ConcreteDataMatcher(Mapping::getOrigin(), "ALPIDEPARAM", 0)) {
428 LOG(info) << "Alpide param updated";
429 return;
430 }
431}
432
434template <class Mapping>
436{
437 // reset for the new run
438 mFinalizeDone = false;
439 mTFCounter = 0;
440 mTimer.Reset();
441 for (int iLayer{0}; iLayer < mLayers; ++iLayer) {
442 if (mDecoder[iLayer]) {
443 mDecoder[iLayer]->reset();
444 }
445 }
446 if (mClusterer) {
447 mClusterer->reset();
448 }
449}
450
452template <class Mapping>
453bool STFDecoder<Mapping>::ensureContinuousROF(const std::vector<ROFRecord>& rofVec, std::vector<ROFRecord>& expROFVec, int lr, int nROFsTF, const char* name)
454{
455 if (!mRunEnsureContinuousROF) {
456 expROFVec = rofVec;
457 return false;
458 }
459 const auto& par = AlpideParam::Instance();
460 // ensure that the rof output is continuous
461 // we will preserve the digits/clusters as they are but the stray ROFs will be removed (leaving their clusters/digits unaddressed).
462 expROFVec.clear();
463 expROFVec.resize(nROFsTF);
464 for (int iROF{0}; iROF < nROFsTF; ++iROF) {
465 auto& rof = expROFVec[iROF];
466 int orb = iROF * par.getROFLengthInBC(lr) / o2::constants::lhc::LHCMaxBunches + mFirstTFOrbit;
467 int bc = iROF * par.getROFLengthInBC(lr) % o2::constants::lhc::LHCMaxBunches + par.getROFDelayInBC(lr);
469 rof.setBCData(ir);
470 rof.setROFrame(iROF);
471 rof.setNEntries(0);
472 rof.setFirstEntry(-1);
473 }
474 uint32_t prevEntry{0};
475 for (const auto& rof : rofVec) {
476 const auto& ir = rof.getBCData();
477 if (ir < mFirstIR) {
478 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {}{}", ir.asString(), mFirstTFOrbit, ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
479 continue;
480 }
481 auto irToFirst = ir - mFirstIR;
482 if (irToFirst.toLong() - par.getROFDelayInBC(lr) < 0) {
483 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {} due to imposed ROF delay{}", ir.asString(), mFirstTFOrbit, ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
484 continue;
485 }
486 irToFirst -= par.getROFDelayInBC(lr);
487 const long irROF = irToFirst.toLong() / par.getROFLengthInBC(lr);
488 if (irROF >= nROFsTF) {
489 LOGP(warn, "Discard ROF {} exceeding TF orbit range{}", ir.asString(), ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
490 continue;
491 }
492 auto& expROF = expROFVec[irROF];
493 if (expROF.getNEntries() == 0) {
494 expROF.setFirstEntry(rof.getFirstEntry());
495 expROF.setNEntries(rof.getNEntries());
496 } else {
497 if (expROF.getNEntries() < rof.getNEntries()) {
498 LOGP(warn, "Repeating {} with {} {}, prefer to already processed instance with {} {}{}", rof.asString(), rof.getNEntries(), name, expROF.getNEntries(), name, ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
499 expROF.setFirstEntry(rof.getFirstEntry());
500 expROF.setNEntries(rof.getNEntries());
501 } else {
502 LOGP(warn, "Repeating {} with {} {}, discard preferring already processed instance with {} {}{}", rof.asString(), rof.getNEntries(), name, expROF.getNEntries(), name, ((mDoStaggering) ? std::format(" on layer {}", lr) : ""));
503 }
504 }
505 }
506 int prevLast{0};
507 bool reReference = false; // in case a non-last ROF with non-0 entries is removed, ROF references need to be shifted and clusters/digits rewritten
508 for (auto& rof : expROFVec) {
509 if (rof.getFirstEntry() < 0) {
510 rof.setFirstEntry(prevLast);
511 } else if (rof.getFirstEntry() != prevLast) {
512 reReference = true; // there is jump
513 }
514 prevLast = rof.getFirstEntry() + rof.getNEntries();
515 }
516 return reReference;
517}
518
520template <class Mapping>
521void STFDecoder<Mapping>::rectifyDigits(std::vector<ROFRecord>& rofVec, std::vector<Digit>& digVec)
522{
523 // following ensureContinuousROF call some old ROFs might have been dropped, need to rebuild digits vector and rereference ROF
524 std::vector<Digit> digVecTmp;
525 digVecTmp.reserve(digVec.size());
526 auto beg0 = digVec.begin();
527 for (auto& rof : rofVec) {
528 int firstEntry = digVecTmp.size();
529 if (rof.getNEntries()) {
530 auto beg = beg0 + rof.getFirstEntry(), end = beg + rof.getNEntries();
531 std::copy(beg, end, std::back_inserter(digVecTmp));
532 }
533 rof.setFirstEntry(firstEntry);
534 }
535 digVec.swap(digVecTmp);
536}
537
539template <class Mapping>
540void STFDecoder<Mapping>::rectifyClusters(std::vector<ROFRecord>& rofVec, std::vector<CompClusterExt>& clusVec, std::vector<unsigned char>& pattVec)
541{
542 // following ensureContinuousROF call some old ROFs might have been dropped, need to rebuild clusters and patterns vectors and rereference ROF
543 std::vector<CompClusterExt> clusVecTmp;
544 clusVecTmp.reserve(clusVec.size());
545 std::vector<unsigned char> pattVecTmp;
546 pattVecTmp.reserve(pattVec.size());
547 const auto& dict = mClusterer->getDictionary();
548 auto begCl0 = clusVec.begin(), begClForPatt = begCl0;
549 auto pattIt = pattVec.begin();
550
551 auto skipToLastPattern = [&begClForPatt, &pattIt, &dict](const decltype(begCl0) tgt) {
552 while (begClForPatt < tgt) { // iterate clusters skipping their patterns until we reach targed cluster
553 const auto& clp = *begClForPatt;
554 auto pattID = clp.getPatternID();
555 if (pattID == itsmft::CompCluster::InvalidPatternID || dict.isGroup(pattID)) {
557 }
558 begClForPatt++;
559 }
560 };
561
562 for (auto& rof : rofVec) {
563 int firstEntry = clusVecTmp.size();
564 if (rof.getNEntries()) {
565 auto begClROF = begCl0 + rof.getFirstEntry(), endClROF = begClROF + rof.getNEntries(); // clusters to copy start/end here
566 if (mDoPatterns) {
567 if (begClForPatt > begClROF) { // normally should no happen unless original ROFs were not ordered
568 begClForPatt = begCl0; // start from the beginning
569 }
570 skipToLastPattern(begClROF); // iterate clusters skipping their patterns until we reach the 1st cluster to be copied
571 auto begPattToCopy = pattIt; // the 1st pattern corresponding to the needed ROF
572 skipToLastPattern(endClROF); // iterate clusters skipping their patterns until we reach the last cluster to be copied
573 std::copy(begPattToCopy, pattIt, std::back_inserter(pattVecTmp));
574 }
575 std::copy(begClROF, endClROF, std::back_inserter(clusVecTmp));
576 }
577 // copy patterns corresponding to this ROF
578 rof.setFirstEntry(firstEntry);
579 }
580 clusVec.swap(clusVecTmp);
581 pattVec.swap(pattVecTmp);
582}
583
586{
587 std::vector<OutputSpec> outputs;
588 auto inputs = o2::framework::select(inp.inputSpec.c_str());
589 uint32_t nLayers = 1;
592 } else if (inp.origin == o2::header::gDataOriginMFT && inp.doStaggering) {
594 }
595 for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) {
596 if (inp.doDigits) {
597 outputs.emplace_back(inp.origin, "DIGITS", iLayer, Lifetime::Timeframe);
598 outputs.emplace_back(inp.origin, "DIGITSROF", iLayer, Lifetime::Timeframe);
599 }
600 if (inp.doClusters) {
601 outputs.emplace_back(inp.origin, "COMPCLUSTERS", iLayer, Lifetime::Timeframe);
602 outputs.emplace_back(inp.origin, "CLUSTERSROF", iLayer, Lifetime::Timeframe);
603 // in principle, we don't need to open this input if we don't need to send real data,
604 // but other devices expecting it do not know about options of this device: problem?
605 // if (doClusters && doPatterns)
606 outputs.emplace_back(inp.origin, "PATTERNS", iLayer, Lifetime::Timeframe);
607 }
608 }
609 if (inp.doDigits && inp.doCalib) {
610 outputs.emplace_back(inp.origin, "GBTCALIB", 0, Lifetime::Timeframe);
611 }
612 outputs.emplace_back(inp.origin, "PHYSTRIG", 0, Lifetime::Timeframe);
613 outputs.emplace_back(inp.origin, "LinkErrors", 0, Lifetime::Timeframe);
614 outputs.emplace_back(inp.origin, "ChipErrors", 0, Lifetime::Timeframe);
615 outputs.emplace_back(inp.origin, "ErrorInfo", 0, Lifetime::Timeframe);
616 outputs.emplace_back(inp.origin, "CHIPSSTATUS", 0, Lifetime::Timeframe);
617
618 if (inp.askSTFDist) {
619 // request the input FLP/DISTSUBTIMEFRAME/0 that is _guaranteed_ to be present, even if none of our raw data is present.
620 inputs.emplace_back("stfDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe);
621 }
622 inputs.emplace_back("noise", inp.origin, "NOISEMAP", 0, Lifetime::Condition,
623 o2::framework::ccdbParamSpec(fmt::format("{}/Calib/NoiseMap", inp.origin.as<std::string>())));
624 inputs.emplace_back("alppar", inp.origin, "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Config/AlpideParam", inp.origin.as<std::string>())));
625 if (inp.doClusters) {
626 inputs.emplace_back("cldict", inp.origin, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/ClusterDictionary", inp.origin.as<std::string>())));
627 inputs.emplace_back("cluspar", inp.origin, "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Config/ClustererParam", inp.origin.as<std::string>())));
628 }
629
630 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
631 true, // GRPECS=true
632 false, // GRPLHCIF
633 false, // GRPMagField
634 false, // askMatLUT
636 inputs,
637 true); // query only once all objects except mag.field
638
639 return DataProcessorSpec{
640 .name = inp.deviceName,
641 .inputs = inputs,
642 .outputs = outputs,
643 .algorithm = inp.origin == o2::header::gDataOriginITS ? AlgorithmSpec{adaptFromTask<STFDecoder<ChipMappingITS>>(inp, ggRequest)} : AlgorithmSpec{adaptFromTask<STFDecoder<ChipMappingMFT>>(inp, ggRequest)},
644 .options = Options{
645 {"nthreads", VariantType::Int, 1, {"Number of decoding/clustering threads"}},
646 {"decoder-verbosity", VariantType::Int, 0, {"Verbosity level (-1: silent, 0: errors, 1: headers, 2: data, 3: raw data dump) of 1st lane"}},
647 {"always-parse-trigger", VariantType::Bool, false, {"parse trigger word even if flags continuation of old trigger"}},
648 {"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."}},
649 {"raw-data-dumps-directory", VariantType::String, "", {"Destination directory for the raw data dumps"}},
650 {"stop-raw-data-dumps-after-size", VariantType::Int, 1024, {"Stop dumping once this size in MB is accumulated. 0: no limit"}},
651 {"unmute-extra-lanes", VariantType::Bool, false, {"allow extra lanes to be as verbose as 1st one"}},
652 {"allow-empty-rofs", VariantType::Bool, false, {"record ROFs w/o any hit"}},
653 {"ignore-noise-map", VariantType::Bool, false, {"do not mask pixels flagged in the noise map"}},
654 {"enforce-continuous-rof-with-calib", VariantType::Bool, false, {"enforce ensureContinuousROF call even when calibration data is requested (not recommended)"}},
655 {"disable-rectify-continuous-rof", VariantType::Bool, false, {"do not rectify clusters and digits after ensureContinuousROF (not recommended)"}},
656 {"accept-rof-rampup-data", VariantType::Bool, false, {"do not discard data during ROF ramp up"}},
657 {"rof-length-error-freq", VariantType::Float, 60.f, {"do not report ROF length error more frequently than this value, disable if negative"}},
658 {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}}};
659}
660
661} // namespace itsmft
662} // 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)
ServiceRegistryRef services()
Definition InitContext.h:34
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)
static void skipPattern(iterator &pattIt)
static constexpr unsigned short InvalidPatternID
Definition CompCluster.h:46
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 GLuint end
Definition glcorearb.h:469
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::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)
std::vector< unsigned char > pattVec