Project
Loading...
Searching...
No Matches
DeadMapBuilderSpec.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
20
21namespace o2
22{
23namespace itsmft
24{
25
27// Default constructor
28ITSMFTDeadMapBuilder::ITSMFTDeadMapBuilder(std::string datasource, bool doMFT)
29 : mDataSource(datasource), mRunMFT(doMFT)
30{
31 std::string detector = doMFT ? "MFT" : "ITS";
32 mSelfName = o2::utils::Str::concat_string("ITSMFTDeadMapBuilder_", detector);
33}
34
36// Default deconstructor
38{
39 // Clear dynamic memory
40 return;
41}
42
45{
46
47 LOG(info) << "ITSMFTDeadMapBuilder init... " << mSelfName;
48
49 mTFSampling = ic.options().get<int>("tf-sampling");
50 mTFSamplingTolerance = ic.options().get<int>("tf-sampling-tolerance");
51 if (mTFSamplingTolerance > mTFSampling) {
52 LOG(warning) << "Invalid request tf-sampling-tolerance larger or equal than tf-sampling. Setting tolerance to " << mTFSampling - 1;
53 mTFSamplingTolerance = mTFSampling - 1;
54 }
55 mSampledSlidingWindowSize = ic.options().get<int>("tf-sampling-history-size");
56 mTFLength = ic.options().get<int>("tf-length");
57 mDoLocalOutput = ic.options().get<bool>("local-output");
58 mObjectName = ic.options().get<std::string>("outfile");
59 mCCDBUrl = ic.options().get<std::string>("ccdb-url");
60 if (mCCDBUrl == "none") {
61 mCCDBUrl = "";
62 }
63
64 mLocalOutputDir = ic.options().get<std::string>("output-dir");
65 mSkipStaticMap = ic.options().get<bool>("skip-static-map");
66 mNoGroupITSLanes = ic.options().get<bool>("no-group-its-lanes");
67
68 isEnded = false;
69 mTimeStart = o2::ccdb::getCurrentTimestamp();
70
71 if (mRunMFT) {
73 } else {
75 }
76
77 mSampledTFs.clear();
78 mSampledHistory.clear();
79 mDeadMapTF.clear();
80 mStaticChipStatus.clear();
81 mMapObject.clear();
82 mMapObject.setMapVersion(MAP_VERSION);
83
84 if (!mSkipStaticMap) {
85 mStaticChipStatus.resize(N_CHIPS, false);
86 }
87
88 LOG(info) << "Sampling one TF every " << mTFSampling << " with " << mTFSamplingTolerance << " TF tolerance";
89
90 return;
91}
92
94// TODO: can ChipMappingITS help here?
95std::vector<uint16_t> ITSMFTDeadMapBuilder::getChipIDsOnSameCable(uint16_t chip)
96{
97 if (mRunMFT || chip < N_CHIPS_ITSIB) {
98 return std::vector<uint16_t>{chip};
99 } else {
100 uint16_t firstchipcable = 7 * (uint16_t)((chip - N_CHIPS_ITSIB) / 7) + N_CHIPS_ITSIB;
101 std::vector<uint16_t> chipList(7);
102 std::generate(chipList.begin(), chipList.end(), [&firstchipcable]() { return firstchipcable++; });
103 return chipList;
104 }
105}
106
107bool ITSMFTDeadMapBuilder::acceptTF(long orbit)
108{
109
110 // Description of the algorithm:
111 // Return true if the TF index (calculated as orbit/TF_length) falls within any interval [k * tf_sampling, k * tf_sampling + tolerance) for some integer k, provided no other TFs have been found in the same interval.
112
113 if (mTFSamplingTolerance < 1) {
114 return ((orbit / mTFLength) % mTFSampling == 0);
115 }
116
117 if ((orbit / mTFLength) % mTFSampling > mTFSamplingTolerance) {
118 return false;
119 }
120
121 long sampling_index = orbit / mTFLength / mTFSampling;
122
123 if (mSampledTFs.find(sampling_index) == mSampledTFs.end()) {
124
125 mSampledTFs.insert(sampling_index);
126 mSampledHistory.push_back(sampling_index);
127
128 if (mSampledHistory.size() > mSampledSlidingWindowSize) {
129 long oldIndex = mSampledHistory.front();
130 mSampledHistory.pop_front();
131 mSampledTFs.erase(oldIndex);
132 }
133
134 return true;
135 }
136
137 return false;
138}
139
141
142void ITSMFTDeadMapBuilder::finalizeOutput()
143{
144
145 if (!mSkipStaticMap) {
146 std::vector<uint16_t> staticmap{};
147 int staticmap_chipcounter = 0;
148 for (uint16_t el = 0; el < mStaticChipStatus.size(); el++) {
149 if (mStaticChipStatus[el]) {
150 continue;
151 }
152 staticmap_chipcounter++;
153 bool previous_dead = (el > 0 && !mStaticChipStatus[el - 1]);
154 bool next_dead = (el < mStaticChipStatus.size() - 1 && !mStaticChipStatus[el + 1]);
155 if (!previous_dead && next_dead) {
156 staticmap.push_back(el | (uint16_t)(0x8000));
157 } else if (previous_dead && next_dead) {
158 continue;
159 } else {
160 staticmap.push_back(el);
161 }
162 }
163
164 LOG(info) << "Filling static part of the map with " << staticmap_chipcounter << " dead chips, saved into " << staticmap.size() << " words";
165
166 mMapObject.fillMap(staticmap);
167 }
168
169 if (mDoLocalOutput) {
170 std::string localoutfilename = mLocalOutputDir + "/" + mObjectName;
171 TFile outfile(localoutfilename.c_str(), "RECREATE");
172 outfile.WriteObjectAny(&mMapObject, "o2::itsmft::TimeDeadMap", "ccdb_object");
173 outfile.Close();
174 }
175 return;
176}
177
179// Main running function
181{
182
183 // Skip everything in case of garbage (potentially at EoS)
185 LOG(info) << "Skipping the processing of inputs for timeslice " << pc.services().get<o2::framework::TimingInfo>().timeslice << " (firstTForbit is " << pc.services().get<o2::framework::TimingInfo>().firstTForbit << ")";
186 return;
187 }
188
189 std::chrono::time_point<std::chrono::high_resolution_clock> start;
190 std::chrono::time_point<std::chrono::high_resolution_clock> end;
191
192 start = std::chrono::high_resolution_clock::now();
193
194 const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
195
196 if (tinfo.globalRunNumberChanged || mFirstOrbitRun == 0x0) { // new run is starting
197 mRunNumber = tinfo.runNumber;
198 mFirstOrbitRun = mFirstOrbitTF;
199 mTFCounter = 0;
200 isEnded = false;
201 }
202
203 if (isEnded) {
204 return;
205 }
206 mFirstOrbitTF = tinfo.firstTForbit;
207 mTFCounter++;
208
209 long sampled_orbit = mFirstOrbitTF - mFirstOrbitRun;
210
211 if (!acceptTF(sampled_orbit)) {
212 return;
213 }
214
215 mStepCounter++;
216 LOG(info) << "Processing step #" << mStepCounter << " out of " << mTFCounter << " good TF received. First orbit " << mFirstOrbitTF;
217
218 mDeadMapTF.clear();
219
220 std::vector<bool> ChipStatus(N_CHIPS, false);
221
222 if (mDataSource == "digits") {
223 const auto elements = pc.inputs().get<gsl::span<o2::itsmft::Digit>>("elements");
224 const auto ROFs = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("ROFs");
225 for (const auto& rof : ROFs) {
226 auto elementsInTF = rof.getROFData(elements);
227 for (const auto& el : elementsInTF) {
228 ChipStatus.at((int)el.getChipIndex()) = true;
229 }
230 }
231 } else if (mDataSource == "clusters") {
232 const auto elements = pc.inputs().get<gsl::span<o2::itsmft::CompClusterExt>>("elements");
233 const auto ROFs = pc.inputs().get<gsl::span<o2::itsmft::ROFRecord>>("ROFs");
234 for (const auto& rof : ROFs) {
235 auto elementsInTF = rof.getROFData(elements);
236 for (const auto& el : elementsInTF) {
237 ChipStatus.at((int)el.getSensorID()) = true;
238 }
239 }
240 } else if (mDataSource == "chipsstatus") {
241 const auto elements = pc.inputs().get<gsl::span<char>>("elements");
242 for (uint16_t chipID = 0; chipID < elements.size(); chipID++) {
243 if (elements[chipID]) {
244 ChipStatus.at(chipID) = true;
245 }
246 }
247 }
248
249 // Save status of single chips in static map before unmasking the full ITS lane
250 if (!mSkipStaticMap) {
251 for (size_t el = 0; el < mStaticChipStatus.size(); el++) {
252 mStaticChipStatus[el] = mStaticChipStatus[el] || ChipStatus[el];
253 }
254 }
255
256 // for ITS, if requested: declaring dead only chips belonging to lanes with no alive chips
257 if (!mRunMFT && !mNoGroupITSLanes) {
258 for (uint16_t el = N_CHIPS_ITSIB; el < ChipStatus.size(); el++) {
259 if (ChipStatus.at(el)) {
260 std::vector<uint16_t> chipincable = getChipIDsOnSameCable(el);
261 for (uint16_t el2 : chipincable) {
262 ChipStatus.at(el2) = true;
263 el = el2;
264 }
265 }
266 }
267 }
268
269 int CountDead = 0;
270
271 for (uint16_t el = 0; el < ChipStatus.size(); el++) {
272 if (ChipStatus.at(el)) {
273 continue;
274 }
275 CountDead++;
276 bool previous_dead = (el > 0 && !ChipStatus.at(el - 1));
277 bool next_dead = (el < ChipStatus.size() - 1 && !ChipStatus.at(el + 1));
278 if (!previous_dead && next_dead) {
279 mDeadMapTF.push_back(el | (uint16_t)(0x8000));
280 } else if (previous_dead && next_dead) {
281 continue;
282 } else {
283 mDeadMapTF.push_back(el);
284 }
285 }
286
287 LOG(info) << "TF contains " << CountDead << " dead chips, saved into " << mDeadMapTF.size() << " words.";
288
289 // filling the map
290 mMapObject.fillMap(mFirstOrbitTF, mDeadMapTF);
291
292 end = std::chrono::high_resolution_clock::now();
293 int difference = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
294
295 LOG(info) << "Elapsed time in TF processing: " << difference / 1000. << " ms";
296
297 if (pc.transitionState() == TransitionHandlingState::Requested && !isEnded) {
298 std::string detname = mRunMFT ? "MFT" : "ITS";
299 LOG(warning) << "Transition state requested for " << detname << " process, calling stop() and stopping the process of new data.";
300 stop();
301 }
302
303 return;
304}
305
307void ITSMFTDeadMapBuilder::PrepareOutputCcdb(EndOfStreamContext* ec, std::string ccdburl = "")
308{
309
310 // if ccdburl is specified, the object is sent to ccdb from this workflow
311
312 long tend = o2::ccdb::getCurrentTimestamp();
313
314 std::map<std::string, std::string> md = {{"map_version", MAP_VERSION}, {"runNumber", std::to_string(mRunNumber)}};
315
316 std::string path = mRunMFT ? "MFT/Calib/" : "ITS/Calib/";
317 std::string name_str = "TimeDeadMap";
318
319 o2::ccdb::CcdbObjectInfo info((path + name_str), name_str, mObjectName, md, mTimeStart - 120 * 1000, tend + 60 * 1000);
320
321 auto image = o2::ccdb::CcdbApi::createObjectImage(&mMapObject, &info);
322 info.setFileName(mObjectName);
323
324 info.setAdjustableEOV();
325
326 if (ec != nullptr) {
327
328 LOG(important) << "Sending object " << info.getPath() << "/" << info.getFileName()
329 << " to ccdb-populator, of size " << image->size() << " bytes, valid for "
330 << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp();
331
332 if (mRunMFT) {
335 } else {
338 }
339 }
340
341 else if (!ccdburl.empty()) { // send from this workflow
342
343 LOG(important) << mSelfName << " sending object " << ccdburl << "/browse/" << info.getPath() << "/" << info.getFileName()
344 << " of size " << image->size() << " bytes, valid for "
345 << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp();
346
348 mApi.init(ccdburl);
350 &image->at(0), image->size(), info.getFileName(), info.getObjectType(),
351 info.getPath(), info.getMetaData(),
352 info.getStartValidityTimestamp(), info.getEndValidityTimestamp());
354 }
355
356 else {
357
358 LOG(warning) << "PrepareOutputCcdb called with empty arguments. Doing nothing.";
359 }
360
361 return;
362}
363
365// O2 functionality allowing to do post-processing when the upstream device
366// tells that there will be no more input data
368{
369 if (!isEnded) {
370 LOG(info) << "endOfStream report: " << mSelfName;
371 finalizeOutput();
372 if (mMapObject.getEvolvingMapSize() > 0) {
373 PrepareOutputCcdb(&ec);
374 } else {
375 LOG(warning) << "Time-dependent dead map is empty and will not be forwarded as output";
376 }
377 LOG(info) << "Stop process of new data because of endOfStream";
378 isEnded = true;
379 }
380 return;
381}
382
384// DDS stop method: create local output if endOfStream not processed
386{
387 if (!isEnded) {
388 LOG(info) << "stop() report: " << mSelfName;
389 finalizeOutput();
390 if (!mCCDBUrl.empty()) {
391 std::string detname = mRunMFT ? "MFT" : "ITS";
392 LOG(warning) << "endOfStream not processed. Sending output to ccdb from the " << detname << " deadmap builder workflow.";
393 PrepareOutputCcdb(nullptr, mCCDBUrl);
394 } else {
395 LOG(alarm) << "endOfStream not processed. Nothing forwarded as output.";
396 }
397 LOG(info) << "Stop process of new data because of stop() call.";
398 isEnded = true;
399 }
400 return;
401}
402
404DataProcessorSpec getITSMFTDeadMapBuilderSpec(std::string datasource, bool doMFT)
405{
407 if (doMFT) {
409 } else {
411 }
412
413 std::vector<InputSpec> inputs;
414
415 if (datasource == "digits") {
416 inputs.emplace_back("elements", detOrig, "DIGITS", 0, Lifetime::Timeframe);
417 inputs.emplace_back("ROFs", detOrig, "DIGITSROF", 0, Lifetime::Timeframe);
418 } else if (datasource == "clusters") {
419 inputs.emplace_back("elements", detOrig, "COMPCLUSTERS", 0, Lifetime::Timeframe);
420 inputs.emplace_back("ROFs", detOrig, "CLUSTERSROF", 0, Lifetime::Timeframe);
421 } else if (datasource == "chipsstatus") {
422 inputs.emplace_back("elements", detOrig, "CHIPSSTATUS", 0, Lifetime::Timeframe);
423 } else {
424 return DataProcessorSpec{0x0}; // TODO: ADD PROTECTION
425 }
426
427 std::vector<OutputSpec> outputs;
428 outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TimeDeadMap"}, Lifetime::Sporadic);
429 outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TimeDeadMap"}, Lifetime::Sporadic);
430
431 std::string detector = doMFT ? "mft" : "its";
432 std::string objectname_default = detector + "_time_deadmap.root";
433
434 return DataProcessorSpec{
435 "itsmft-deadmap-builder_" + detector,
436 inputs,
437 outputs,
438 AlgorithmSpec{adaptFromTask<ITSMFTDeadMapBuilder>(datasource, doMFT)},
439 Options{{"tf-sampling", VariantType::Int, 350, {"Process every Nth TF. Selection according to first TF orbit."}},
440 {"tf-sampling-tolerance", VariantType::Int, 20, {"Tolerance on the tf-sampling value (sliding window size)."}},
441 {"tf-sampling-history-size", VariantType::Int, 1000, {"Do not check if new TF is contained in a window that is older than N steps."}},
442 {"tf-length", VariantType::Int, 32, {"Orbits per TF."}},
443 {"skip-static-map", VariantType::Bool, false, {"Do not fill static part of the map."}},
444 {"no-group-its-lanes", VariantType::Bool, false, {"Do not group ITS OB chips into lanes."}},
445 {"ccdb-url", VariantType::String, "", {"CCDB url. Ignored if endOfStream is processed."}},
446 {"outfile", VariantType::String, objectname_default, {"ROOT object file name."}},
447 {"local-output", VariantType::Bool, false, {"Save ROOT tree file locally."}},
448 {"output-dir", VariantType::String, "./", {"ROOT tree local output directory."}}}};
449}
450
451} // namespace itsmft
452} // namespace o2
Definition of the ITSMFT compact cluster.
Definition of the ITSMFT digit.
uint64_t orbit
Definition RawEventData.h:6
Definition of the ITSMFT time-dependend dead map.
void init(std::string const &hosts)
Definition CcdbApi.cxx:165
static std::unique_ptr< std::vector< char > > createObjectImage(const T *obj, CcdbObjectInfo *info=nullptr)
Definition CcdbApi.h:103
int storeAsBinaryFile(const char *buffer, size_t size, const std::string &fileName, const std::string &objectType, const std::string &path, const std::map< std::string, std::string > &metadata, long startValidityTimestamp, long endValidityTimestamp, std::vector< char >::size_type maxSize=0) const
Definition CcdbApi.cxx:351
void snapshot(const Output &spec, T const &object)
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
TransitionHandlingState transitionState() const
static constexpr int getNChips()
number of chips per barrel
static constexpr Int_t getNChips()
void endOfStream(EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void stop() final
This is invoked on stop.
void init(InitContext &ic) final
void run(ProcessingContext &pc) final
ITSMFTDeadMapBuilder(std::string datasource, bool doMFT)
void fillMap(unsigned long firstOrbit, const std::vector< uint16_t > &deadVect)
Definition TimeDeadMap.h:43
void setMapVersion(std::string version)
unsigned long getEvolvingMapSize() const
GLeglImageOES image
Definition glcorearb.h:4021
GLuint GLuint end
Definition glcorearb.h:469
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLuint start
Definition glcorearb.h:469
constexpr o2::header::DataOrigin gDataOriginMFT
Definition DataHeader.h:572
constexpr o2::header::DataOrigin gDataOriginITS
Definition DataHeader.h:570
long getCurrentTimestamp()
returns the timestamp in long corresponding to "now"
int adjustOverriddenEOV(CcdbApi &api, const CcdbObjectInfo &infoNew)
set EOV of overriden objects to SOV-1 of overriding one if it is allowed
std::vector< ConfigParamSpec > Options
o2::framework::DataProcessorSpec getITSMFTDeadMapBuilderSpec(std::string datasource, bool doMFT)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
static constexpr o2::header::DataOrigin gDataOriginCDBWrapper
Definition Utils.h:44
static constexpr o2::header::DataOrigin gDataOriginCDBPayload
Definition Utils.h:43
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"