Project
Loading...
Searching...
No Matches
ClustererSpec.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
13
14#include <vector>
15
21#include "ITS3Base/SpecsV2.h"
32
33using namespace o2::framework;
34
35namespace o2::its3
36{
37
39{
40 mClusterer = std::make_unique<o2::its3::Clusterer>();
41 mUseClusterDictionary = !ic.options().get<bool>("ignore-cluster-dictionary");
42 mNThreads = std::max(1, ic.options().get<int>("nthreads"));
45
46 // prepare data filter
47 for (int iLayer = 0; iLayer < (mDoStaggering ? NLayers : 1); ++iLayer) {
48 mFilter.emplace_back("digits", "IT3", "DIGITS", iLayer, Lifetime::Timeframe);
49 mFilter.emplace_back("ROframe", "IT3", "DIGITSROF", iLayer, Lifetime::Timeframe);
50 if (mUseMC) {
51 mFilter.emplace_back("labels", "IT3", "DIGITSMCTR", iLayer, Lifetime::Timeframe);
52 }
53 }
54}
55
57{
58 updateTimeDependentParams(pc);
59
60 // filter input and compose
61 std::array<gsl::span<const o2::itsmft::Digit>, NLayers> digits{};
62 std::array<gsl::span<const o2::itsmft::ROFRecord>, NLayers> rofs{};
63 std::array<gsl::span<const char>, NLayers> labelsbuffer{};
64 for (const DataRef& ref : InputRecordWalker{pc.inputs(), mFilter}) {
65 auto const* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
66 if (DataRefUtils::match(ref, {"digits", ConcreteDataTypeMatcher{"IT3", "DIGITS"}})) {
67 digits[dh->subSpecification] = pc.inputs().get<gsl::span<o2::itsmft::Digit>>(ref);
68 }
69 if (DataRefUtils::match(ref, {"ROframe", ConcreteDataTypeMatcher{"IT3", "DIGITSROF"}})) {
70 rofs[dh->subSpecification] = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>(ref);
71 }
72 if (DataRefUtils::match(ref, {"labels", ConcreteDataTypeMatcher{"IT3", "DIGITSMCTR"}})) {
73 labelsbuffer[dh->subSpecification] = pc.inputs().get<gsl::span<char>>(ref);
74 }
75 }
76
77 // query the first orbit in this TF
78 const auto firstTForbit = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
79 const o2::InteractionRecord firstIR(0, firstTForbit);
81
82 uint64_t nClusters{0};
83 TStopwatch sw;
85 for (uint32_t iLayer{0}; iLayer < (mDoStaggering ? NLayers : 1); ++iLayer) {
86 int layer = (mDoStaggering) ? iLayer : -1;
87 sw.Start();
88 LOG(info) << "Clusterer" << ((mDoStaggering) ? std::format(" on layer {}", layer) : "") << " pulled " << digits[iLayer].size() << " digits, in " << rofs[iLayer].size() << " RO frames";
89 mClusterer->setMaxROFDepthToSquash(mClusterer->getMaxROFDepthToSquash(layer));
91 reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash(layer));
92 reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking
93 reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash(layer));
94 reader.setDigits(digits[iLayer]);
95 reader.setROFRecords(rofs[iLayer]);
96 if (mUseMC) {
97 LOG(info) << "Clusterer" << ((mDoStaggering) ? std::format(" on layer {}", layer) : "") << " pulled " << labels.getNElements() << " labels ";
98 reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr);
99 }
100 reader.init();
101 std::vector<o2::itsmft::CompClusterExt> clusCompVec;
102 std::vector<o2::itsmft::ROFRecord> clusROFVec;
103 std::vector<unsigned char> clusPattVec;
104
105 std::unique_ptr<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> clusterLabels;
106 if (mUseMC) {
107 clusterLabels = std::make_unique<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>();
108 }
109 mClusterer->process(mNThreads, reader, &clusCompVec, &clusPattVec, &clusROFVec, clusterLabels.get());
110
111 // ensure that the rof output is continuous
112 size_t nROFs = clusROFVec.size();
113 const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / par.getROFLengthInBC(iLayer);
114 const int nROFsTF = nROFsPerOrbit * o2::base::GRPGeomHelper::getNHBFPerTF();
115 // It can happen that in the digitization rofs without contributing hits are skipped or there are stray ROFs
116 // We will preserve the clusters as they are but the stray ROFs will be removed (leaving their clusters unaddressed).
117 std::vector<o2::itsmft::ROFRecord> expClusRofVec(nROFsTF);
118 for (int iROF{0}; iROF < nROFsTF; ++iROF) {
119 auto& rof = expClusRofVec[iROF];
120 int orb = (iROF * par.getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches) + firstTForbit;
121 int bc = (iROF * par.getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches) + par.getROFDelayInBC(iLayer);
123 rof.setBCData(ir);
124 rof.setROFrame(iROF);
125 rof.setNEntries(0);
126 rof.setFirstEntry(-1);
127 }
128 uint32_t prevEntry{0};
129 for (const auto& rof : clusROFVec) {
130 const auto& ir = rof.getBCData();
131 if (ir < firstIR) {
132 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {}{}", ir.asString(), firstTForbit, ((mDoStaggering) ? std::format(" on layer {}", layer) : ""));
133 continue;
134 }
135 auto irToFirst = ir - firstIR;
136 if (irToFirst.toLong() - par.getROFDelayInBC(iLayer) < 0) {
137 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {} due to imposed ROF delay{}", ir.asString(), firstTForbit, ((mDoStaggering) ? std::format(" on layer {}", iLayer) : ""));
138 continue;
139 }
140 irToFirst -= par.getROFDelayInBC(iLayer);
141 const long irROF = irToFirst.toLong() / par.getROFLengthInBC(iLayer);
142 if (irROF >= nROFsTF) {
143 LOGP(warn, "Discard ROF {} exceeding TF orbit range{}", ir.asString(), ((mDoStaggering) ? std::format(" on layer {}", layer) : ""));
144 continue;
145 }
146 auto& expROF = expClusRofVec[irROF];
147 if (expROF.getNEntries() == 0) {
148 expROF.setFirstEntry(rof.getFirstEntry());
149 expROF.setNEntries(rof.getNEntries());
150 } else {
151 if (expROF.getNEntries() < rof.getNEntries()) {
152 LOGP(warn, "Repeating {} with {} clusters, prefer to already processed instance with {} clusters{}", rof.asString(), rof.getNEntries(), expROF.getNEntries(), ((mDoStaggering) ? std::format(" on layer {}", layer) : ""));
153 expROF.setFirstEntry(rof.getFirstEntry());
154 expROF.setNEntries(rof.getNEntries());
155 } else {
156 LOGP(warn, "Repeating {} with {} clusters, discard preferring already processed instance with {} clusters{}", rof.asString(), rof.getNEntries(), expROF.getNEntries(), ((mDoStaggering) ? std::format(" on layer {}", layer) : ""));
157 }
158 }
159 }
160 int prevLast{0};
161 for (auto& rof : expClusRofVec) {
162 if (rof.getFirstEntry() < 0) {
163 rof.setFirstEntry(prevLast);
164 }
165 prevLast = rof.getFirstEntry() + rof.getNEntries();
166 }
167 nROFs = expClusRofVec.size();
168 pc.outputs().snapshot(Output{"ITS", "CLUSTERSROF", iLayer}, expClusRofVec);
169
170 pc.outputs().snapshot(Output{"ITS", "COMPCLUSTERS", iLayer}, clusCompVec);
171 pc.outputs().snapshot(Output{"ITS", "PATTERNS", iLayer}, clusPattVec);
172
173 nClusters += clusCompVec.size();
174
175 if (mUseMC) {
176 pc.outputs().snapshot(Output{"ITS", "CLUSTERSMCTR", iLayer}, *clusterLabels); // at the moment requires snapshot
177 // write dummy MC2ROF vector to keep writer/readers backward compatible
178 static std::vector<o2::itsmft::MC2ROFRecord> dummyMC2ROF;
179 pc.outputs().snapshot(Output{"ITS", "CLUSTERSMC2ROF", iLayer}, dummyMC2ROF);
180 }
181 reader.reset();
182
183 sw.Stop();
184 LOG(info) << "IT3Clusterer on layer " << iLayer << " pushed " << clusCompVec.size() << " clusters, in " << nROFs << " RO frames in " << sw.RealTime() << " s";
185 }
186
187 LOG(info) << "IT3Clusterer produced " << nClusters << " clusters";
188}
189
191void ClustererDPL::updateTimeDependentParams(ProcessingContext& pc)
192{
193 static bool initOnceDone = false;
195 if (!initOnceDone) { // this params need to be queried only once
196 initOnceDone = true;
197 pc.inputs().get<TopologyDictionary*>("cldict"); // just to trigger the finaliseCCDB
200 mClusterer->setContinuousReadOut(true);
201 // settings for the fired pixel overflow masking
204 if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) {
205 LOGP(fatal, "maxBCDiffToMaskBias = {} and maxBCDiffToSquashBias = {} cannot be set at the same time. Either set masking or squashing with a BCDiff > 0", clParams.maxBCDiffToMaskBias, clParams.maxBCDiffToSquashBias);
206 }
207 mClusterer->setDropHugeClusters(clParams.dropHugeClusters);
208 auto nbc = clParams.maxBCDiffToMaskBias;
209 nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS);
210 mClusterer->setMaxBCSeparationToMask(nbc);
211 mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask);
212 // Squasher
213 int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC
214 mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias);
215 int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0.
216 if (clParams.maxSOTMUS > 0 && rofBC > 0) {
217 nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing
218 }
219 mClusterer->setMaxROFDepthToSquash(nROFsToSquash);
220 if (mClusterer->isContinuousReadOut()) { // almost tautological
221 for (int iLayer{0}; iLayer < NLayers; ++iLayer) {
222 mClusterer->addMaxBCSeparationToSquash(alpParams.getROFLengthInBC(iLayer) + clParams.getMaxBCDiffToSquashBias(iLayer));
223 mClusterer->addMaxROFDepthToSquash((clParams.getMaxBCDiffToSquashBias(iLayer) > 0) ? 2 + int(clParams.maxSOTMUS / (alpParams.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingMUS)) : 0);
224 }
225 }
226 mClusterer->print(false);
227 }
228 // we may have other params which need to be queried regularly
229}
230
233{
235 return;
236 }
237 if (matcher == ConcreteDataMatcher("IT3", "CLUSDICT", 0)) {
238 LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : "");
239 if (mUseClusterDictionary) {
240 mClusterer->setDictionary((const o2::its3::TopologyDictionary*)obj);
241 }
242 return;
243 }
244 // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level
245 if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) {
246 LOG(info) << "Alpide param updated";
248 par.printKeyValues();
249 return;
250 }
251 if (matcher == ConcreteDataMatcher("ITS", "CLUSPARAM", 0)) {
252 LOG(info) << "Cluster param updated";
254 par.printKeyValues();
255 return;
256 }
257}
258
260{
261 mClusterer->print(true);
262}
263
264DataProcessorSpec getClustererSpec(bool useMC, bool doStag)
265{
266 std::vector<InputSpec> inputs;
267 std::vector<OutputSpec> outputs;
268 for (uint32_t iLayer = 0; iLayer < (doStag ? ClustererDPL::NLayers : 1); ++iLayer) {
269 inputs.emplace_back("digits", "IT3", "DIGITS", iLayer, Lifetime::Timeframe);
270 inputs.emplace_back("ROframes", "IT3", "DIGITSROF", iLayer, Lifetime::Timeframe);
271 outputs.emplace_back("ITS", "COMPCLUSTERS", iLayer, Lifetime::Timeframe);
272 outputs.emplace_back("ITS", "PATTERNS", iLayer, Lifetime::Timeframe);
273 outputs.emplace_back("ITS", "CLUSTERSROF", iLayer, Lifetime::Timeframe);
274 if (useMC) {
275 inputs.emplace_back("labels", "IT3", "DIGITSMCTR", iLayer, Lifetime::Timeframe);
276 outputs.emplace_back("ITS", "CLUSTERSMCTR", iLayer, Lifetime::Timeframe);
277 outputs.emplace_back("ITS", "CLUSTERSMC2ROF", iLayer, Lifetime::Timeframe);
278 }
279 }
280 inputs.emplace_back("cldict", "IT3", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/ClusterDictionary"));
281 inputs.emplace_back("cluspar", "ITS", "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/ClustererParam"));
282 inputs.emplace_back("alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam"));
283 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
284 true, // GRPECS
285 false, // GRPLHCIF
286 false, // GRPMagField
287 false, // askMatLUT
289 inputs,
290 true);
291
292 return DataProcessorSpec{
293 .name = "its3-clusterer",
294 .inputs = inputs,
295 .outputs = outputs,
296 .algorithm = AlgorithmSpec{adaptFromTask<ClustererDPL>(ggRequest, useMC, doStag)},
297 .options = Options{
298 {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}},
299 {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}};
300}
301
302} // namespace o2::its3
std::vector< std::string > labels
Definition of the ITS/MFT clusterer settings.
Definition of the ITSMFT compact cluster.
A const (ready only) version of MCTruthContainer.
Definition of the ITSMFT digit.
Definition of the BuildTopologyDictionary class for ITS3.
Definition of the Alpide pixel reader for MC digits processing.
uint64_t bc
Definition RawEventData.h:5
Definition of the ITSMFT ROFrame (trigger) record.
A helper class to iteratate over all parts of all input routes.
Header to collect LHC related constants.
int nClusters
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
void snapshot(const Output &spec, T const &object)
ConfigParamRegistry const & options()
Definition InitContext.h:33
A helper class to iteratate over all parts of all input routes.
decltype(auto) get(R binding, int part=0) 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.
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
void run(ProcessingContext &pc) final
static constexpr int NLayers
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void init(InitContext &ic) final
static constexpr int MB
static constexpr int getNChips()
number of chips per barrel
static constexpr int OB
void setDigitsMCTruth(const o2::dataformats::ConstMCTruthContainerView< o2::MCCompLabel > *m)
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)
GLsizeiptr size
Definition glcorearb.h:659
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLint ref
Definition glcorearb.h:291
constexpr double LHCBunchSpacingMUS
constexpr int LHCMaxBunches
constexpr double LHCBunchSpacingNS
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
constexpr unsigned int nChips
Definition SpecsV2.h:180
framework::DataProcessorSpec getClustererSpec(bool useMC, bool doStag)
std::string asString() const
static bool match(DataRef const &ref, const char *binding)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
TStopwatch sw
std::vector< Digit > digits