Project
Loading...
Searching...
No Matches
PreClusterFinderSpec.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
16
18
19#include <iostream>
20#include <fstream>
21#include <chrono>
22#include <vector>
23#include <stdexcept>
24
25#include <gsl/span>
26
31#include "Framework/Lifetime.h"
32#include "Framework/Output.h"
33#include "Framework/Task.h"
34#include "Framework/Logger.h"
36
38#include "MCHBase/Error.h"
39#include "MCHBase/ErrorMap.h"
40#include "MCHBase/PreCluster.h"
41#include "MCHBase/SanityCheck.h"
43
44#include <iostream>
45#include <chrono>
46#include <vector>
47
48namespace o2
49{
50namespace mch
51{
52
53using namespace std;
54using namespace o2::framework;
55
61
63{
64 public:
65 //_________________________________________________________________________________________________
67 {
69 LOG(info) << "initializing preclusterizer";
70
71 mPreClusterFinder.init();
72
73 auto stop = [this]() {
74 LOG(info) << "reset precluster finder duration = " << mTimeResetPreClusterFinder.count() << " ms";
75 LOG(info) << "load digits duration = " << mTimeLoadDigits.count() << " ms";
76 LOG(info) << "discard high occupancy duration = " << mTimeDiscardHighOccupancy.count() << " ms";
77 LOG(info) << "precluster finder duration = " << mTimePreClusterFinder.count() << " ms";
78 LOG(info) << "store precluster duration = " << mTimeStorePreClusters.count() << " ms";
80 auto tStart = std::chrono::high_resolution_clock::now();
81 this->mPreClusterFinder.deinit();
82 auto tEnd = std::chrono::high_resolution_clock::now();
83 LOG(info) << "deinitializing preclusterizer in: "
84 << std::chrono::duration<double, std::milli>(tEnd - tStart).count() << " ms";
85 mErrorMap.forEach([](Error error) {
86 LOGP(warning, "{}", error.asString());
87 });
88 };
89 ic.services().get<CallbackService>().set<CallbackService::Id::Stop>(stop);
90
91 auto checkNoLeftoverDigits = ic.options().get<std::string>("check-no-leftover-digits");
92 if (checkNoLeftoverDigits == "quiet") {
93 mCheckNoLeftoverDigits = CHECK_NO_LEFTOVER_DIGITS_QUIET;
94 } else if (checkNoLeftoverDigits == "error") {
95 mCheckNoLeftoverDigits = CHECK_NO_LEFTOVER_DIGITS_ERROR;
96 } else if (checkNoLeftoverDigits == "fatal") {
97 mCheckNoLeftoverDigits = CHECK_NO_LEFTOVER_DIGITS_FATAL;
98 }
99 mDiscardHighOccDEs = ic.options().get<bool>("discard-high-occupancy-des");
100 mDiscardHighOccEvents = ic.options().get<bool>("discard-high-occupancy-events");
101 mSanityCheck = ic.options().get<bool>("sanity-check");
102 }
103
104 //_________________________________________________________________________________________________
106 {
108
109 // get the input messages with digits
110 auto digitROFs = pc.inputs().get<gsl::span<ROFRecord>>("digitrofs");
111 auto digits = pc.inputs().get<gsl::span<Digit>>("digits");
112
113 bool abort{false};
114 if (mSanityCheck) {
115 auto error = sanityCheck(digitROFs, digits);
116
117 if (!isOK(error)) {
118 if (error.nofOutOfBounds > 0) {
119 // FIXME: replace this error log with a counters' message ?
120 LOGP(error, "{}", asString(error));
121 LOGP(error, "in a TF with {} rofs and {} digits", digitROFs.size(), digits.size());
122 abort = true;
123 }
124 }
125 }
126
127 // create the output message for precluster ROFs
128 auto& preClusterROFs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"preclusterrofs"});
129
130 // count the number of digits associated with the input ROFs. This can be smaller than the
131 // total number of digits if we are processing filtered ROFs.
132 int nDigitsInRofs = 0;
133 for (const auto& digitROF : digitROFs) {
134 nDigitsInRofs += digitROF.getNEntries();
135 }
136
137 // prepare to receive new data
138 mPreClusters.clear();
139 mUsedDigits.clear();
140 auto& errorMap = mPreClusterFinder.getErrorMap();
141 errorMap.clear();
142
143 if (!abort) {
144
145 preClusterROFs.reserve(digitROFs.size());
146 mUsedDigits.reserve(digits.size());
147 int nRemovedDigits(0);
148
149 for (const auto& digitROF : digitROFs) {
150
151 // prepare to receive new data
152 auto tStart = std::chrono::high_resolution_clock::now();
153 mPreClusterFinder.reset();
154 auto tEnd = std::chrono::high_resolution_clock::now();
155 mTimeResetPreClusterFinder += tEnd - tStart;
156
157 // load the digits to get the fired pads
158 tStart = std::chrono::high_resolution_clock::now();
159 mPreClusterFinder.loadDigits(digits.subspan(digitROF.getFirstIdx(), digitROF.getNEntries()));
160 tEnd = std::chrono::high_resolution_clock::now();
161 mTimeLoadDigits += tEnd - tStart;
162
163 // discard high-occupancy (noisy) DEs and/or events
164 tStart = std::chrono::high_resolution_clock::now();
165 nRemovedDigits += mPreClusterFinder.discardHighOccupancy(mDiscardHighOccDEs, mDiscardHighOccEvents);
166 tEnd = std::chrono::high_resolution_clock::now();
167 mTimeDiscardHighOccupancy += tEnd - tStart;
168
169 // preclusterize
170 tStart = std::chrono::high_resolution_clock::now();
171 int nPreClusters = mPreClusterFinder.run();
172 tEnd = std::chrono::high_resolution_clock::now();
173 mTimePreClusterFinder += tEnd - tStart;
174
175 // get the preclusters and associated digits
176 tStart = std::chrono::high_resolution_clock::now();
177 preClusterROFs.emplace_back(digitROF.getBCData(), mPreClusters.size(), nPreClusters, digitROF.getBCWidth());
178 mPreClusterFinder.getPreClusters(mPreClusters, mUsedDigits);
179 tEnd = std::chrono::high_resolution_clock::now();
180 mTimeStorePreClusters += tEnd - tStart;
181 }
182
183 // check sizes of input and output digits vectors
184 if (nRemovedDigits + mUsedDigits.size() != nDigitsInRofs) {
185 errorMap.add(ErrorType::PreClustering_LostDigit, 0, 0, nDigitsInRofs - nRemovedDigits - mUsedDigits.size());
186 switch (mCheckNoLeftoverDigits) {
188 break;
190 static int nAlarms = 0;
191 if (nAlarms++ < 5) {
192 LOG(warning) << "some digits have been lost during the preclustering";
193 }
194 break;
196 throw runtime_error("some digits have been lost during the preclustering");
197 break;
198 };
199 }
200 }
201
202 // create the output messages for preclusters and associated digits
203 pc.outputs().snapshot(OutputRef{"preclusters"}, mPreClusters);
204 pc.outputs().snapshot(OutputRef{"preclusterdigits"}, mUsedDigits);
205
206 // create the output message for preclustering errors
207 auto& preClusterErrors = pc.outputs().make<std::vector<Error>>(OutputRef{"preclustererrors"});
208 errorMap.forEach([&preClusterErrors](Error error) {
209 preClusterErrors.emplace_back(error);
210 });
211 mErrorMap.add(errorMap);
212
213 LOGP(info, "Processed {} digit rofs with {} digits and output {} precluster rofs with {} preclusters and {} digits",
214 digitROFs.size(),
215 nDigitsInRofs,
216 preClusterROFs.size(),
217 mPreClusters.size(), mUsedDigits.size());
218 }
219
220 private:
221 PreClusterFinder mPreClusterFinder{};
222 std::vector<PreCluster> mPreClusters{};
223 std::vector<Digit> mUsedDigits{};
224 ErrorMap mErrorMap{};
225
226 int mCheckNoLeftoverDigits{CHECK_NO_LEFTOVER_DIGITS_ERROR};
227 bool mDiscardHighOccDEs = false;
228 bool mDiscardHighOccEvents = false;
229 bool mSanityCheck = false;
230 std::chrono::duration<double, std::milli> mTimeResetPreClusterFinder{};
231 std::chrono::duration<double, std::milli> mTimeLoadDigits{};
232 std::chrono::duration<double, std::milli> mTimeDiscardHighOccupancy{};
233 std::chrono::duration<double, std::milli> mTimePreClusterFinder{};
234 std::chrono::duration<double, std::milli> mTimeStorePreClusters{};
235};
236
237//_________________________________________________________________________________________________
239 std::string_view inputDigitDataDescription,
240 std::string_view inputDigitRofDataDescription)
241{
242 std::string input =
243 fmt::format("digits:MCH/{}/0;digitrofs:MCH/{}/0",
244 inputDigitDataDescription,
245 inputDigitRofDataDescription);
246 std::string helpstr = "[quiet/error/fatal] check that all digits are included in pre-clusters";
247
248 return DataProcessorSpec{
249 specName,
250 o2::framework::select(input.c_str()),
251 Outputs{OutputSpec{{"preclusterrofs"}, "MCH", "PRECLUSTERROFS", 0, Lifetime::Timeframe},
252 OutputSpec{{"preclusters"}, "MCH", "PRECLUSTERS", 0, Lifetime::Timeframe},
253 OutputSpec{{"preclusterdigits"}, "MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe},
254 OutputSpec{{"preclustererrors"}, "MCH", "PRECLUSTERERRORS", 0, Lifetime::Timeframe}},
255 AlgorithmSpec{adaptFromTask<PreClusterFinderTask>()},
256 Options{{"check-no-leftover-digits", VariantType::String, "error", {helpstr}},
257 {{"sanity-check"}, VariantType::Bool, false, {"perform some input digit sanity checks"}},
258 {"discard-high-occupancy-des", VariantType::Bool, false, {"discard DEs with occupancy > 20%"}},
259 {"discard-high-occupancy-events", VariantType::Bool, false, {"discard events with >= 5 DEs above 20% occupancy"}}}};
260}
261
262} // end namespace mch
263} // end namespace o2
definition of the MCH processing errors
Definition of the MCH precluster minimal structure.
Definition of the MCH ROFrame record.
Definition of a data processor to run the preclusterizer.
const char * specName
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
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
void forEach(ErrorFunction f) const
Definition ErrorMap.cxx:90
void add(ErrorType errorType, uint32_t id0, uint32_t id1, uint64_t n=1)
Definition ErrorMap.cxx:33
void run(framework::ProcessingContext &pc)
void init(framework::InitContext &ic)
void loadDigits(gsl::span< const Digit > digits)
int discardHighOccupancy(bool perDE, bool perEvent)
void getPreClusters(std::vector< o2::mch::PreCluster > &preClusters, std::vector< Digit > &digits)
ErrorMap & getErrorMap()
return the counting of encountered errors
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
RuntimeErrorRef runtime_error(const char *)
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > select(char const *matcher="")
std::vector< OutputSpec > Outputs
o2::framework::DataProcessorSpec getPreClusterFinderSpec(const char *specName="PreClusterFinder", std::string_view inputDigitDataDescription="F-DIGITS", std::string_view inputDigitRofDataDescription="TC-F-DIGITROFS")
std::string asString(const o2::mch::TrackMCH &t)
Definition TrackMCH.cxx:104
bool isOK(const SanityError &error)
SanityError sanityCheck(gsl::span< const ROFRecord > rofs, gsl::span< const T > items)
Definition SanityCheck.h:48
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
std::string asString() const
Definition Error.cxx:86
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits