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
36
37namespace o2::itsmft
38{
39
40template <int N>
42{
43 mClusterer = std::make_unique<o2::itsmft::Clusterer>();
45 mUseClusterDictionary = !ic.options().get<bool>("ignore-cluster-dictionary");
47 mNThreads = std::max(1, ic.options().get<int>("nthreads"));
48 mDetName = Origin.as<std::string>();
49
50 // prepare data filter
51 for (int iLayer = 0; iLayer < NLayers; ++iLayer) {
52 mFilter.emplace_back("digits", Origin, "DIGITS", iLayer, Lifetime::Timeframe);
53 mFilter.emplace_back("ROframe", Origin, "DIGITSROF", iLayer, Lifetime::Timeframe);
54 if (mUseMC) {
55 mFilter.emplace_back("labels", Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe);
56 mFilter.emplace_back("MC2ROframes", Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe);
57 }
58 }
59}
60
61template <int N>
63{
64 updateTimeDependentParams(pc);
65
66 // filter input and compose
67 std::array<gsl::span<const o2::itsmft::Digit>, NLayers> digits;
68 std::array<gsl::span<const o2::itsmft::ROFRecord>, NLayers> rofs;
69 std::array<gsl::span<const char>, NLayers> labelsbuffer;
70 std::array<gsl::span<const o2::itsmft::MC2ROFRecord>, NLayers> mc2rofs;
71 for (const DataRef& ref : InputRecordWalker{pc.inputs(), mFilter}) {
72 auto const* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
73 if (DataRefUtils::match(ref, {"digits", ConcreteDataTypeMatcher{Origin, "DIGITS"}})) {
74 digits[dh->subSpecification] = pc.inputs().get<gsl::span<o2::itsmft::Digit>>(ref);
75 }
76 if (DataRefUtils::match(ref, {"ROframe", ConcreteDataTypeMatcher{Origin, "DIGITSROF"}})) {
77 rofs[dh->subSpecification] = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>(ref);
78 }
79 if (DataRefUtils::match(ref, {"labels", ConcreteDataTypeMatcher{Origin, "DIGITSMCTR"}})) {
80 labelsbuffer[dh->subSpecification] = pc.inputs().get<gsl::span<char>>(ref);
81 }
82 if (DataRefUtils::match(ref, {"MC2ROframes", ConcreteDataTypeMatcher{Origin, "DIGITSMC2ROF"}})) {
83 mc2rofs[dh->subSpecification] = pc.inputs().get<gsl::span<o2::itsmft::MC2ROFRecord>>(ref);
84 }
85 }
86
87 // query the first orbit in this TF
88 const auto firstTForbit = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
89 const o2::InteractionRecord firstIR(0, firstTForbit);
90 const auto& par = DPLAlpideParam<N>::Instance();
91
92 // process received inputs
93 uint64_t nClusters{0};
94 TStopwatch sw;
96 for (uint32_t iLayer{0}; iLayer < NLayers; ++iLayer) {
97 int layer = (DPLAlpideParam<N>::supportsStaggering()) ? iLayer : -1;
98 sw.Start();
99 LOG(info) << mDetName << "Clusterer:" << layer << " pulled " << digits[iLayer].size() << " digits, in " << rofs[iLayer].size() << " RO frames";
100
101 mClusterer->setMaxROFDepthToSquash(mClusterer->getMaxROFDepthToSquash(layer));
103 reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash(layer));
104 reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking
105 reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash(layer));
106 reader.setDigits(digits[iLayer]);
107 reader.setROFRecords(rofs[iLayer]);
108 if (mUseMC) {
109 reader.setMC2ROFRecords(mc2rofs[iLayer]);
110 LOG(info) << mDetName << "Clusterer:" << layer << " pulled " << labels.getNElements() << " labels ";
111 reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr);
112 }
113 reader.init();
114 std::vector<o2::itsmft::CompClusterExt> clusCompVec;
115 std::vector<o2::itsmft::ROFRecord> clusROFVec;
116 std::vector<unsigned char> clusPattVec;
117
118 std::unique_ptr<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> clusterLabels;
119 if (mUseMC) {
120 clusterLabels = std::make_unique<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>();
121 }
122 mClusterer->process(mNThreads, reader, &clusCompVec, &clusPattVec, &clusROFVec, clusterLabels.get());
123
124 // ensure that the rof output is continuous
125 size_t nROFs = clusROFVec.size();
126 const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / par.getROFLengthInBC(iLayer);
127 const int nROFsTF = nROFsPerOrbit * o2::base::GRPGeomHelper::getNHBFPerTF();
128 // It can happen that in the digitization rofs without contributing hits are skipped or there are stray ROFs
129 // We will preserve the clusters as they are but the stray ROFs will be removed (leaving their clusters unaddressed).
130 std::vector<o2::itsmft::ROFRecord> expClusRofVec(nROFsTF);
131 for (int iROF{0}; iROF < nROFsTF; ++iROF) {
132 auto& rof = expClusRofVec[iROF];
133 int orb = iROF * par.getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches + firstTForbit;
134 int bc = iROF * par.getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches;
136 rof.setBCData(ir);
137 rof.setROFrame(iROF);
138 rof.setNEntries(0);
139 rof.setFirstEntry(-1);
140 }
141 uint32_t prevEntry{0};
142 for (const auto& rof : clusROFVec) {
143 const auto& ir = rof.getBCData();
144 if (ir < firstIR) {
145 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {}, layer:{}", ir.asString(), firstTForbit, iLayer);
146 continue;
147 }
148 const auto irToFirst = ir - firstIR;
149 const long irROF = irToFirst.toLong() / par.getROFLengthInBC(iLayer);
150 if (irROF >= nROFsTF) {
151 LOGP(warn, "Discard ROF {} exceding TF orbit range, layer:{}", ir.asString(), iLayer);
152 continue;
153 }
154 auto& expROF = expClusRofVec[irROF];
155 if (expROF.getNEntries() == 0) {
156 expROF.setFirstEntry(rof.getFirstEntry());
157 expROF.setNEntries(rof.getNEntries());
158 } else {
159 if (expROF.getNEntries() < rof.getNEntries()) {
160 LOGP(warn, "Repeating ROF {} with {} clusters, prefer to already processed instance with {} clusters", rof.asString(), rof.getNEntries(), expROF.getNEntries());
161 expROF.setFirstEntry(rof.getFirstEntry());
162 expROF.setNEntries(rof.getNEntries());
163 } else {
164 LOGP(warn, "Repeating ROF {} with {} clusters, discard preferring already processed instance with {} clusters", rof.asString(), rof.getNEntries(), expROF.getNEntries());
165 }
166 }
167 }
168 int prevLast{0};
169 for (auto& rof : expClusRofVec) {
170 if (rof.getFirstEntry() < 0) {
171 rof.setFirstEntry(prevLast);
172 }
173 prevLast = rof.getFirstEntry() + rof.getNEntries();
174 }
175 nROFs = expClusRofVec.size();
176 pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, expClusRofVec);
177
178 pc.outputs().snapshot(Output{Origin, "COMPCLUSTERS", iLayer}, clusCompVec);
179 pc.outputs().snapshot(Output{Origin, "PATTERNS", iLayer}, clusPattVec);
180
181 nClusters += clusCompVec.size();
182
183 if (mUseMC) {
184 pc.outputs().snapshot(Output{Origin, "CLUSTERSMCTR", iLayer}, *clusterLabels); // at the moment requires snapshot
185 std::vector<o2::itsmft::MC2ROFRecord> clusterMC2ROframes(mc2rofs[iLayer].size());
186 for (int i = mc2rofs[iLayer].size(); i--;) {
187 clusterMC2ROframes[i] = mc2rofs[iLayer][i]; // Simply, replicate it from digits ?
188 }
189 pc.outputs().snapshot(Output{Origin, "CLUSTERSMC2ROF", iLayer}, clusterMC2ROframes);
190 }
191 reader.reset();
192
193 // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF
194 // -> consider recalculationg maxROF
195 sw.Stop();
196 LOG(info) << mDetName << "Clusterer:" << layer << " pushed " << clusCompVec.size() << " clusters, in " << nROFs << " RO frames in " << sw.RealTime() << " s";
197 }
198
199 LOG(info) << mDetName << "Clusterer produced " << nClusters << " clusters";
200}
201
203template <int N>
205{
207 static bool initOnceDone = false;
208 if (!initOnceDone) { // this params need to be queried only once
209 initOnceDone = true;
210 pc.inputs().get<TopologyDictionary*>("cldict"); // just to trigger the finaliseCCDB
212 pc.inputs().get<o2::itsmft::ClustererParam<N>*>("cluspar");
213 mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(N));
214 // settings for the fired pixel overflow masking
215 const auto& alpParams = o2::itsmft::DPLAlpideParam<N>::Instance();
216 const auto& clParams = o2::itsmft::ClustererParam<N>::Instance();
217 if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) {
218 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);
219 }
220 mClusterer->setDropHugeClusters(clParams.dropHugeClusters);
221 auto nbc = clParams.maxBCDiffToMaskBias;
222 nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS);
223 mClusterer->setMaxBCSeparationToMask(nbc);
224 mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask);
225 // Squasher
226 int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC
227 mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias);
228 int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0.
229 if (clParams.maxSOTMUS > 0 && rofBC > 0) {
230 nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing
231 }
232 mClusterer->setMaxROFDepthToSquash(nROFsToSquash);
234 if (mClusterer->isContinuousReadOut()) {
235 for (int iLayer{0}; iLayer < NLayers; ++iLayer) {
236 mClusterer->addMaxBCSeparationToSquash(alpParams.getROFLengthInBC(iLayer) + clParams.getMaxBCDiffToSquashBias(iLayer));
237 mClusterer->addMaxROFDepthToSquash((clParams.getMaxBCDiffToSquashBias(iLayer) > 0) ? 2 + int(clParams.maxSOTMUS / (alpParams.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingMUS)) : 0);
238 }
239 }
240 }
241 mClusterer->print(false);
242 }
243 // we may have other params which need to be queried regularly
244}
245
247template <int N>
249{
250 if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
251 return;
252 }
253 if (matcher == ConcreteDataMatcher(Origin, "CLUSDICT", 0)) {
254 LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : "");
255 if (mUseClusterDictionary) {
256 mClusterer->setDictionary((const TopologyDictionary*)obj);
257 }
258 return;
259 }
260 // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level
261 if (matcher == ConcreteDataMatcher(Origin, "ALPIDEPARAM", 0)) {
262 LOG(info) << "Alpide param updated";
263 const auto& par = o2::itsmft::DPLAlpideParam<N>::Instance();
264 par.printKeyValues();
265 return;
266 }
267 if (matcher == ConcreteDataMatcher(Origin, "CLUSPARAM", 0)) {
268 LOG(info) << "Cluster param updated";
269 const auto& par = o2::itsmft::ClustererParam<N>::Instance();
270 par.printKeyValues();
271 return;
272 }
273}
274
275namespace
276{
277template <int N>
278DataProcessorSpec getClustererSpec(bool useMC)
279{
281 std::vector<InputSpec> inputs;
282 constexpr uint32_t nLayers = (DPLAlpideParam<N>::supportsStaggering()) ? DPLAlpideParam<N>::getNLayers() : 1;
283 for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) {
284 inputs.emplace_back("digits", Origin, "DIGITS", iLayer, Lifetime::Timeframe);
285 inputs.emplace_back("ROframes", Origin, "DIGITSROF", iLayer, Lifetime::Timeframe);
286 if (useMC) {
287 inputs.emplace_back("labels", Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe);
288 inputs.emplace_back("MC2ROframes", Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe);
289 }
290 }
291 inputs.emplace_back("cldict", Origin, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(Origin.as<std::string>() + "/Calib/ClusterDictionary"));
292 inputs.emplace_back("cluspar", Origin, "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec(Origin.as<std::string>() + "/Config/ClustererParam"));
293 inputs.emplace_back("alppar", Origin, "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec(Origin.as<std::string>() + "/Config/AlpideParam"));
294 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
295 true, // GRPECS=true
296 false, // GRPLHCIF
297 false, // GRPMagField
298 false, // askMatLUT
300 inputs,
301 true);
302 std::vector<OutputSpec> outputs;
303 for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) {
304 outputs.emplace_back(Origin, "COMPCLUSTERS", iLayer, Lifetime::Timeframe);
305 outputs.emplace_back(Origin, "PATTERNS", iLayer, Lifetime::Timeframe);
306 outputs.emplace_back(Origin, "CLUSTERSROF", iLayer, Lifetime::Timeframe);
307 if (useMC) {
308 outputs.emplace_back(Origin, "CLUSTERSMCTR", iLayer, Lifetime::Timeframe);
309 outputs.emplace_back(Origin, "CLUSTERSMC2ROF", iLayer, Lifetime::Timeframe);
310 }
311 }
312 return DataProcessorSpec{
313 .name = (N == o2::detectors::DetID::ITS) ? "its-clusterer" : "mft-clusterer",
314 .inputs = inputs,
315 .outputs = outputs,
316 .algorithm = AlgorithmSpec{adaptFromTask<ClustererDPL<N>>(ggRequest, useMC)},
317 .options = Options{
318 {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}},
319 {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}};
320}
321} // namespace
322
324{
325 return getClustererSpec<o2::detectors::DetID::ITS>(useMC);
326}
327
329{
330 return getClustererSpec<o2::detectors::DetID::MFT>(useMC);
331}
332
333} // namespace o2::itsmft
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 ClusterTopology class.
Definition of the Names Generator class.
Definition of the GeometryManager class.
Definition of the Alpide pixel reader for MC digits processing.
uint64_t bc
Definition RawEventData.h:5
int32_t i
Header of the General Run Parameters object.
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)
static constexpr ID ITS
Definition DetID.h:63
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.
static constexpr int getNChips()
number of chips per barrel
static constexpr Int_t getNChips()
void init(InitContext &ic) final
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
void run(ProcessingContext &pc) final
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 setMC2ROFRecords(const gsl::span< const o2::itsmft::MC2ROFRecord > a)
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 o2::header::DataOrigin gDataOriginMFT
Definition DataHeader.h:572
constexpr o2::header::DataOrigin gDataOriginITS
Definition DataHeader.h:570
Origins::iterator Origin
constexpr double LHCBunchSpacingMUS
constexpr int LHCMaxBunches
constexpr double LHCBunchSpacingNS
AlgorithmSpec adaptFromTask(Args &&... args)
Definition Task.h:59
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
framework::DataProcessorSpec getMFTClustererSpec(bool useMC)
framework::DataProcessorSpec getITSClustererSpec(bool useMC)
constexpr int nLayers
Definition Specs.h:45
std::string asString() const
static bool match(DataRef const &ref, const char *binding)
static constexpr int getNLayers()
static constexpr bool supportsStaggering() noexcept
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
TStopwatch sw
std::vector< Digit > digits