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 if (nROFsTF != clusROFVec.size()) {
129 // it can happen that in the digitization rofs without contributing hits are skipped
130 // however downstream consumers of the clusters cannot know apriori the time structure
131 // the cluster rofs do not account for the bias so it will start always at BC=0
132 // if we receive more cluster rofs then there supposed to be, do not throw away this data
133 // the clusterer should be blind to this!
134 const size_t nROFsLayer = std::max((size_t)nROFsTF, clusROFVec.size());
135 std::vector<o2::itsmft::ROFRecord> expClusRofVec(nROFsLayer);
136 for (int iROF{0}; iROF < nROFsLayer; ++iROF) {
137 auto& rof = expClusRofVec[iROF];
138 int orb = iROF * par.getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches + firstTForbit;
139 int bc = iROF * par.getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches;
141 rof.setBCData(ir);
142 rof.setROFrame(iROF);
143 rof.setNEntries(0);
144 rof.setFirstEntry(-1);
145 }
146 uint32_t prevEntry{0};
147 for (const auto& rof : clusROFVec) {
148 const auto& ir = rof.getBCData();
149 const auto irToFirst = ir - firstIR;
150 const int irROF = irToFirst.toLong() / par.getROFLengthInBC(iLayer);
151 auto& expROF = expClusRofVec[irROF];
152 expROF.setFirstEntry(rof.getFirstEntry());
153 expROF.setNEntries(rof.getNEntries());
154 if (expROF.getBCData() != rof.getBCData()) {
155 LOGP(fatal, "detected mismatch between expected ROF:{} and received ROF:{}", expROF.asString(), rof.asString());
156 }
157 }
158 int prevFirst{0};
159 for (auto& rof : expClusRofVec) {
160 if (rof.getFirstEntry() < 0) {
161 rof.setFirstEntry(prevFirst);
162 }
163 prevFirst = rof.getFirstEntry();
164 }
165 nROFs = expClusRofVec.size();
166 pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, expClusRofVec);
167 } else {
168 pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, clusROFVec);
169 }
170 pc.outputs().snapshot(Output{Origin, "COMPCLUSTERS", iLayer}, clusCompVec);
171 pc.outputs().snapshot(Output{Origin, "PATTERNS", iLayer}, clusPattVec);
172
173 nClusters += clusCompVec.size();
174
175 if (mUseMC) {
176 pc.outputs().snapshot(Output{Origin, "CLUSTERSMCTR", iLayer}, *clusterLabels); // at the moment requires snapshot
177 std::vector<o2::itsmft::MC2ROFRecord> clusterMC2ROframes(mc2rofs[iLayer].size());
178 for (int i = mc2rofs[iLayer].size(); i--;) {
179 clusterMC2ROframes[i] = mc2rofs[iLayer][i]; // Simply, replicate it from digits ?
180 }
181 pc.outputs().snapshot(Output{Origin, "CLUSTERSMC2ROF", iLayer}, clusterMC2ROframes);
182 }
183 reader.reset();
184
185 // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF
186 // -> consider recalculationg maxROF
187 sw.Stop();
188 LOG(info) << mDetName << "Clusterer:" << layer << " pushed " << clusCompVec.size() << " clusters, in " << nROFs << " RO frames in " << sw.RealTime() << " s";
189 }
190
191 LOG(info) << mDetName << "Clusterer produced " << nClusters << " clusters";
192}
193
195template <int N>
197{
199 static bool initOnceDone = false;
200 if (!initOnceDone) { // this params need to be queried only once
201 initOnceDone = true;
202 pc.inputs().get<TopologyDictionary*>("cldict"); // just to trigger the finaliseCCDB
204 pc.inputs().get<o2::itsmft::ClustererParam<N>*>("cluspar");
205 mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(N));
206 // settings for the fired pixel overflow masking
207 const auto& alpParams = o2::itsmft::DPLAlpideParam<N>::Instance();
208 const auto& clParams = o2::itsmft::ClustererParam<N>::Instance();
209 if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) {
210 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);
211 }
212 mClusterer->setDropHugeClusters(clParams.dropHugeClusters);
213 auto nbc = clParams.maxBCDiffToMaskBias;
214 nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS);
215 mClusterer->setMaxBCSeparationToMask(nbc);
216 mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask);
217 // Squasher
218 int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC
219 mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias);
220 int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0.
221 if (clParams.maxSOTMUS > 0 && rofBC > 0) {
222 nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing
223 }
224 mClusterer->setMaxROFDepthToSquash(nROFsToSquash);
226 if (mClusterer->isContinuousReadOut()) {
227 for (int iLayer{0}; iLayer < NLayers; ++iLayer) {
228 mClusterer->addMaxBCSeparationToSquash(alpParams.getROFLengthInBC(iLayer) + clParams.getMaxBCDiffToSquashBias(iLayer));
229 mClusterer->addMaxROFDepthToSquash((clParams.getMaxBCDiffToSquashBias(iLayer) > 0) ? 2 + int(clParams.maxSOTMUS / (alpParams.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingMUS)) : 0);
230 }
231 }
232 }
233 mClusterer->print(false);
234 }
235 // we may have other params which need to be queried regularly
236}
237
239template <int N>
241{
242 if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
243 return;
244 }
245 if (matcher == ConcreteDataMatcher(Origin, "CLUSDICT", 0)) {
246 LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : "");
247 if (mUseClusterDictionary) {
248 mClusterer->setDictionary((const TopologyDictionary*)obj);
249 }
250 return;
251 }
252 // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level
253 if (matcher == ConcreteDataMatcher(Origin, "ALPIDEPARAM", 0)) {
254 LOG(info) << "Alpide param updated";
255 const auto& par = o2::itsmft::DPLAlpideParam<N>::Instance();
256 par.printKeyValues();
257 return;
258 }
259 if (matcher == ConcreteDataMatcher(Origin, "CLUSPARAM", 0)) {
260 LOG(info) << "Cluster param updated";
261 const auto& par = o2::itsmft::ClustererParam<N>::Instance();
262 par.printKeyValues();
263 return;
264 }
265}
266
267namespace
268{
269template <int N>
270DataProcessorSpec getClustererSpec(bool useMC)
271{
273 std::vector<InputSpec> inputs;
274 constexpr uint32_t nLayers = (DPLAlpideParam<N>::supportsStaggering()) ? DPLAlpideParam<N>::getNLayers() : 1;
275 for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) {
276 inputs.emplace_back("digits", Origin, "DIGITS", iLayer, Lifetime::Timeframe);
277 inputs.emplace_back("ROframes", Origin, "DIGITSROF", iLayer, Lifetime::Timeframe);
278 if (useMC) {
279 inputs.emplace_back("labels", Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe);
280 inputs.emplace_back("MC2ROframes", Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe);
281 }
282 }
283 inputs.emplace_back("cldict", Origin, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(Origin.as<std::string>() + "/Calib/ClusterDictionary"));
284 inputs.emplace_back("cluspar", Origin, "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec(Origin.as<std::string>() + "/Config/ClustererParam"));
285 inputs.emplace_back("alppar", Origin, "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec(Origin.as<std::string>() + "/Config/AlpideParam"));
286 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
287 true, // GRPECS=true
288 false, // GRPLHCIF
289 false, // GRPMagField
290 false, // askMatLUT
292 inputs,
293 true);
294 std::vector<OutputSpec> outputs;
295 for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) {
296 outputs.emplace_back(Origin, "COMPCLUSTERS", iLayer, Lifetime::Timeframe);
297 outputs.emplace_back(Origin, "PATTERNS", iLayer, Lifetime::Timeframe);
298 outputs.emplace_back(Origin, "CLUSTERSROF", iLayer, Lifetime::Timeframe);
299 if (useMC) {
300 outputs.emplace_back(Origin, "CLUSTERSMCTR", iLayer, Lifetime::Timeframe);
301 outputs.emplace_back(Origin, "CLUSTERSMC2ROF", iLayer, Lifetime::Timeframe);
302 }
303 }
304 return DataProcessorSpec{
305 .name = (N == o2::detectors::DetID::ITS) ? "its-clusterer" : "mft-clusterer",
306 .inputs = inputs,
307 .outputs = outputs,
308 .algorithm = AlgorithmSpec{adaptFromTask<ClustererDPL<N>>(ggRequest, useMC)},
309 .options = Options{
310 {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}},
311 {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}};
312}
313} // namespace
314
316{
317 return getClustererSpec<o2::detectors::DetID::ITS>(useMC);
318}
319
321{
322 return getClustererSpec<o2::detectors::DetID::MFT>(useMC);
323}
324
325} // 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
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