Project
Loading...
Searching...
No Matches
DigitFilteringSpec.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
18#include "Framework/Logger.h"
20#include "Framework/Task.h"
22#include "MCHBase/SanityCheck.h"
23#include "MCHStatus/StatusMap.h"
28#include <fmt/format.h>
29#include <functional>
30#include <iostream>
31#include <string>
32#include <vector>
33
34using namespace o2::dataformats;
35using namespace o2::framework;
36
37namespace o2::mch
38{
40{
41 public:
42 DigitFilteringTask(bool useMC, bool useStatusMap) : mUseMC{useMC}, mUseStatusMap{useStatusMap} {}
43
44 void init(InitContext& ic)
45 {
46 mSanityCheck = DigitFilterParam::Instance().sanityCheck;
47 mMinADC = DigitFilterParam::Instance().minADC;
48 mRejectBackground = DigitFilterParam::Instance().rejectBackground;
49 mStatusMask = DigitFilterParam::Instance().statusMask;
50 mTimeCalib = DigitFilterParam::Instance().timeOffset;
51 auto stop = [this]() {
52 LOG(info) << "digit filtering duration = "
53 << std::chrono::duration<double, std::milli>(mElapsedTime).count() << " ms";
54 };
55 ic.services().get<CallbackService>().set<CallbackService::Id::Stop>(stop);
56 }
57
58 void shiftDigitsTime(gsl::span<ROFRecord> rofs, gsl::span<Digit> digits)
59 {
60 for (auto i = 0; i < rofs.size(); i++) {
61 ROFRecord& rof = rofs[i];
62 rof.getBCData() += mTimeCalib;
63 }
64
65 for (auto i = 0; i < digits.size(); i++) {
66 Digit& d = digits[i];
67 d.setTime(d.getTime() + mTimeCalib);
68 }
69 }
70
72 {
73 StatusMap defaultStatusMap;
74
75 // get input
76 auto iRofs = pc.inputs().get<gsl::span<ROFRecord>>("rofs");
77 auto iDigits = pc.inputs().get<gsl::span<Digit>>("digits");
78 auto iLabels = mUseMC ? pc.inputs().get<MCTruthContainer<MCCompLabel>*>("labels") : nullptr;
79 auto statusMap = mUseStatusMap && pc.inputs().isValid("statusmap") ? pc.inputs().get<StatusMap*>("statusmap") : nullptr;
80
81 bool abort{false};
82
83 auto tStart = std::chrono::high_resolution_clock::now();
84
85 if (mSanityCheck) {
86 LOGP(info, "performing sanity checks");
87 auto error = sanityCheck(iRofs, iDigits);
88
89 if (!isOK(error)) {
90 if (error.nofOutOfBounds > 0) {
91 LOGP(error, "{}", asString(error));
92 LOGP(error, "in a TF with {} rofs and {} digits", iRofs.size(), iDigits.size());
93 abort = true;
94 }
95 }
96 }
97
98 // create the output messages
99 auto& oRofs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"rofs"});
100 auto& oDigits = pc.outputs().make<std::vector<Digit>>(OutputRef{"digits"});
101 auto oLabels = mUseMC ? &pc.outputs().make<MCTruthContainer<MCCompLabel>>(OutputRef{"labels"}) : nullptr;
102
103 if (!abort) {
104 bool selectSignal = false;
105
106 mIsGoodDigit = createDigitFilter(mMinADC,
107 mRejectBackground,
108 selectSignal,
109 statusMap ? *statusMap : defaultStatusMap,
110 mStatusMask);
111 // at digit filtering stage it is important to keep the 3rd parameter
112 // (selectSignal) to false in the call above : the idea is to not cut
113 // too much on the tails of the charge distributions otherwise
114 // the clustering resolution will suffer.
115 // That's why we only apply the "reject background" filter, which
116 // is a loose background cut that does not penalize the signal
117 int cursor{0};
118 for (const auto& irof : iRofs) {
119 const auto digits = iDigits.subspan(irof.getFirstIdx(), irof.getNEntries());
120
121 // filter the digits from the current ROF
122 for (auto i = 0; i < digits.size(); i++) {
123 const auto& d = digits[i];
124 if (mIsGoodDigit(d)) {
125 oDigits.emplace_back(d);
126 if (iLabels) {
127 oLabels->addElements(oLabels->getIndexedSize(), iLabels->getLabels(i + irof.getFirstIdx()));
128 }
129 }
130 }
131 int nofGoodDigits = oDigits.size() - cursor;
132 if (nofGoodDigits > 0) {
133 // we create an ouput ROF only if at least one digit from
134 // the input ROF passed the filtering
135 oRofs.emplace_back(ROFRecord(irof.getBCData(),
136 cursor,
137 nofGoodDigits,
138 irof.getBCWidth()));
139 cursor += nofGoodDigits;
140 }
141 }
142 }
143
144 auto labelMsg = mUseMC ? fmt::format("| {} labels (out of {})", oLabels->getNElements(), iLabels->getNElements()) : "";
145
146 LOGP(info, "Kept after filtering : {} rofs (out of {}) | {} digits (out of {}) {}",
147 oRofs.size(), iRofs.size(),
148 oDigits.size(), iDigits.size(),
149 labelMsg);
150
151 if (mTimeCalib != 0) {
152 shiftDigitsTime(oRofs, oDigits);
153 }
154
155 if (abort) {
156 LOGP(error, "Sanity check failed");
157 }
158 auto tEnd = std::chrono::high_resolution_clock::now();
159 mElapsedTime += tEnd - tStart;
160 }
161
162 private:
163 bool mRejectBackground{false};
164 bool mSanityCheck{false};
165 bool mUseMC{false};
166 bool mUseStatusMap{false};
167 int mMinADC{1};
168 int32_t mTimeCalib{0};
169 uint32_t mStatusMask{0};
170 DigitFilter mIsGoodDigit;
171 std::chrono::duration<double> mElapsedTime{};
172};
173
176 std::string_view specName,
177 std::string_view inputDigitDataDescription,
178 std::string_view outputDigitDataDescription,
179 std::string_view inputDigitRofDataDescription,
180 std::string_view outputDigitRofDataDescription,
181 std::string_view inputDigitLabelDataDescription,
182 std::string_view outputDigitLabelDataDescription)
183
184{
185 std::string input =
186 fmt::format("digits:MCH/{}/0;rofs:MCH/{}/0",
187 inputDigitDataDescription,
188 inputDigitRofDataDescription);
189 if (useMC) {
190 input += fmt::format(";labels:MCH/{}/0", inputDigitLabelDataDescription);
191 }
192
193 bool useStatusMap = DigitFilterParam::Instance().statusMask != 0;
194
195 if (useStatusMap) {
196 input += ";statusmap:MCH/STATUSMAP/0";
197 }
198
199 std::string output =
200 fmt::format("digits:MCH/{}/0;rofs:MCH/{}/0",
201 outputDigitDataDescription,
202 outputDigitRofDataDescription);
203 if (useMC) {
204 output += fmt::format(";labels:MCH/{}/0", outputDigitLabelDataDescription);
205 }
206
207 std::vector<OutputSpec> outputs;
208 auto matchers = select(output.c_str());
209 for (auto& matcher : matchers) {
210 outputs.emplace_back(DataSpecUtils::asOutputSpec(matcher));
211 }
212
213 return DataProcessorSpec{
214 specName.data(),
215 Inputs{select(input.c_str())},
216 outputs,
217 AlgorithmSpec{adaptFromTask<DigitFilteringTask>(useMC, useStatusMap)},
218 Options{}};
219}
220} // namespace o2::mch
int32_t i
void output(const std::map< std::string, ChannelStat > &channels)
Definition rawdump.cxx:197
Definition of a container to keep Monte Carlo truth external to simulation objects.
Definition of the MCH ROFrame record.
const char * specName
A container to hold and manage MC truth information/labels.
decltype(auto) make(const Output &spec, Args... args)
ServiceRegistryRef services()
Definition InitContext.h:34
bool isValid(std::string const &s) const
Helper method to be used to check if a given part of the InputRecord is present.
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 run(ProcessingContext &pc)
DigitFilteringTask(bool useMC, bool useStatusMap)
void shiftDigitsTime(gsl::span< ROFRecord > rofs, gsl::span< Digit > digits)
MCH digit implementation.
Definition Digit.h:31
int32_t getTime() const
Definition Digit.h:44
void setTime(int32_t t)
Definition Digit.h:43
const BCData & getBCData() const
get the interaction record
Definition ROFRecord.h:46
Definition of a container to keep/associate and arbitrary number of labels associated to an index wit...
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > select(char const *matcher="")
std::vector< InputSpec > Inputs
o2::framework::DataProcessorSpec getDigitFilteringSpec(bool useMC, std::string_view specName="mch-digit-filtering", std::string_view inputDigitDataDescription="DIGITS", std::string_view outputDigitDataDescription="F-DIGITS", std::string_view inputDigitRofDataDescription="DIGITROFS", std::string_view outputDigitRofDataDescription="F-DIGITROFS", std::string_view inputDigitLabelDataDescription="DIGITLABELS", std::string_view outputDigitLabelDataDescription="F-DIGITLABELS")
std::string asString(const o2::mch::TrackMCH &t)
Definition TrackMCH.cxx:104
std::function< bool(const Digit &)> DigitFilter
Definition DigitFilter.h:21
DigitFilter createDigitFilter(uint32_t minADC, bool rejectBackground, bool selectSignal, const StatusMap &statusMap={}, uint32_t statusMask=0)
bool isOK(const SanityError &error)
SanityError sanityCheck(gsl::span< const ROFRecord > rofs, gsl::span< const T > items)
Definition SanityCheck.h:48
static OutputSpec asOutputSpec(InputSpec const &spec)
uint32_t statusMask
mask to reject digits based on the statusmap (0 = no rejection)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits