ATLAS Offline Software
Loading...
Searching...
No Matches
LArRawChannelMonAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
6
10#include "CLHEP/Units/SystemOfUnits.h"
12#include "Identifier/Identifier.h"
14#include "Identifier/Range.h"
20#include "AthenaKernel/Units.h"
23#include "GaudiKernel/ThreadLocalContext.h"
24
25#include <algorithm>
26#include <cmath>
27#include <stdexcept>
28#include <complex>
29
30using namespace std::complex_literals;
31
32namespace {
33
34enum : int8_t {
35 EMBA,
36 EMBC,
37 EMECA,
38 EMECC,
39 HECA,
40 HECC,
41 FCALA,
42 FCALC,
43 NDETECTORS,
44 UNDEF = -1
45};
46
47constexpr unsigned numberOfSlotsPerFeedthrough(int8_t det) {
48 bool b{det == ::EMBA || det == ::EMBC};
49 return b ? 14 : 15;
50}
51
52constexpr std::array<int8_t, 8> partitions() {
53 return {::EMBA, ::EMBC, ::EMECA, ::EMECC,
55}
56
57} // namespace
58
59
61 ISvcLocator *pSvcLocator)
62 : AthMonitorAlgorithm(name, pSvcLocator) {
63 using T = decltype(m_det_to_nchannels);
64 static_assert(std::tuple_size_v<T> >= ::NDETECTORS);
65 using U = decltype(m_monitoring_tool_index);
66 static_assert(std::tuple_size_v<U> >= ::NDETECTORS);
67}
68
69
71
72
74{
75 ATH_MSG_DEBUG("===> start " << name() << "::initialize <=== ");
76
77 ATH_CHECK(m_larFlagKey.initialize());
79 ATH_CHECK(detStore()->retrieve(m_lar_online_id_ptr, "LArOnlineID"));
80 ATH_CHECK(m_bcContKey.initialize());
81 ATH_CHECK(m_bcMask.buildBitMask(m_problemsToMask, msg()));
82 ATH_CHECK(m_atlasReady_tools.retrieve());
83 ATH_CHECK(m_noiseKey.initialize());
84 ATH_CHECK(m_cablingKey.initialize());
85
86 auto get_detector = [&](auto hwid) {
87 const bool sideA = m_lar_online_id_ptr->pos_neg(hwid);
88 if (m_lar_online_id_ptr->isEMBchannel(hwid))
89 return sideA ? ::EMBA : ::EMBC;
90 else if (m_lar_online_id_ptr->isEMECchannel(hwid))
91 return sideA ? ::EMECA : ::EMECC;
92 else if (m_lar_online_id_ptr->isHECchannel(hwid))
93 return sideA ? ::HECA : ::HECC;
94 else if (m_lar_online_id_ptr->isFCALchannel(hwid))
95 return sideA ? ::FCALA : ::FCALC;
96 return ::UNDEF; };
97
98 // Create FEB hash -> Detector map
99 std::size_t feb_hash_max = m_lar_online_id_ptr->febHashMax();
100 m_feb_hash_to_detector.resize(feb_hash_max, ::UNDEF);
101 auto end_feb = m_lar_online_id_ptr->feb_end();
102 for (auto itr = m_lar_online_id_ptr->feb_begin(); itr != end_feb; ++itr) {
103 IdentifierHash feb_hash = m_lar_online_id_ptr->feb_Hash(*itr);
104 auto det = get_detector(*itr);
105 if (feb_hash < m_feb_hash_to_detector.size()) {
106 m_feb_hash_to_detector.at(feb_hash) = det;
107 } else {
108 ATH_MSG_WARNING("FEB hash out of range, ignored.");
109 }
110 }
111
112 // Count number of channels in each detector ---
113 std::fill(m_det_to_nchannels.begin(), m_det_to_nchannels.end(), 0);
114 auto citr = m_lar_online_id_ptr->channel_begin();
115 auto citr_end = m_lar_online_id_ptr->channel_end();
116 for (; citr != citr_end; ++citr) {
117 // TODO: skip unconnected/masked channels, but these may depend on IOV...
118 auto det = get_detector(*citr);
119 if (det != ::UNDEF)
120 m_det_to_nchannels[det] += 1;
121 }
122
123 std::vector<std::string> det2str(::NDETECTORS);
124 det2str[::EMBA] = "EMBA";
125 det2str[::EMBC] = "EMBC";
126 det2str[::EMECA] = "EMECA";
127 det2str[::EMECC] = "EMECC";
128 det2str[::HECA] = "HECA";
129 det2str[::HECC] = "HECC";
130 det2str[::FCALA] = "FCalA";
131 det2str[::FCALC] = "FCalC";
132
133 if (msgLvl(MSG::DEBUG)) {
134 ATH_MSG_DEBUG("Number of channels in detectors: ");
135 for (int8_t det : partitions()) {
136 auto n = m_det_to_nchannels[det];
137 ATH_MSG_DEBUG(det2str[det] << " has " << n << "channels ");
138 }
139 }
140
142
143 auto toolmap = Monitored::buildToolMap<int>(
144 m_tools, "LArRawChannelMon", det2str);
145 for (int8_t det : partitions()) {
146 m_monitoring_tool_index[det] = toolmap.at(det2str[det]);
147 }
148
149 ATH_MSG_DEBUG("===> end " << name() << "::initialize, "
150 "will now initialize base class <=== ");
152}
153
154
155StatusCode LArRawChannelMonAlg::fillHistograms(const EventContext &ctx) const
156{
157 ATH_MSG_DEBUG("===> start " << name() << "::fillHistograms() <=== ");
158
159 // Retrieve raw channels
162 if (!raw_channels.isValid()) {
163 ATH_MSG_WARNING("Cannot retrieve LArRawChannelContainer with key: "
165 return StatusCode::SUCCESS;
166 }
167
168 const bool is_atlas_ready = std::all_of(
169 m_atlasReady_tools.begin(),
170 m_atlasReady_tools.end(),
171 [](auto &f) { return f->accept(); });
172
174 int bcid{0}, lumi_block{0};
175 bool larNoisyROAlg_flag{false};
176 bool larNoisyROAlgInTimeW_flag{false};
177 bool larNoisyROAlg_W_flag{false};
178 bool noisy_event{false};
179 if (event_info.isValid()) {
180 auto checkEventFlag = [&](auto bitinfo, const char *txt) {
181 bool flag = event_info->isEventFlagBitSet(
182 xAOD::EventInfo::LAr, bitinfo);
183 if (flag) ATH_MSG_DEBUG(" !!! Noisy event found " << txt << " !!!");
184 return flag; };
185 larNoisyROAlg_flag = checkEventFlag(
186 LArEventBitInfo::BADFEBS, "from LArNoisyROAlg");
187 larNoisyROAlg_W_flag = checkEventFlag(
188 LArEventBitInfo::BADFEBS_W, "from LArNoisyROAlg_W");
189 larNoisyROAlgInTimeW_flag = checkEventFlag(
190 3, "by LArNoisyROAlg in Time window of 500ms");
191 bcid = event_info->bcid();
192 lumi_block = event_info->lumiBlock();
193
194 const auto &tags = event_info->streamTags();
195 auto inSet = [&](auto &x){ return m_noise_streams_set.count(x.name()); };
196 noisy_event = m_noise_streams_set.empty()
197 || std::any_of(tags.begin(), tags.end(), inSet);
198 } else {
199 ATH_MSG_DEBUG("Cannot retrieve EventInfo");
200 }
201
202 std::array<uint32_t, ::NDETECTORS> det_n_noisy_channels{};
203 std::array<uint32_t, ::NDETECTORS> det_n_noisy_channels_Neg{};
204 std::array<uint32_t, ::NDETECTORS> det_n_badQ_channels{};
205 using wsum_t = std::complex<double>;
206 wsum_t event_mean_time{};
207 std::array<wsum_t, ::NDETECTORS> mean_detector_times;
208 std::vector<wsum_t> mean_feb_times(m_feb_hash_to_detector.size(), 0.);
209 std::array<double, ::NDETECTORS> per_detector_total_energy{};
210 int8_t lastdet{::UNDEF};
211 ToolHandle<GenericMonitoringTool> monitoring{nullptr};
215 ATH_CHECK(noiseH.isValid());
216 ATH_CHECK(bcContH.isValid());
217 ATH_CHECK(cablingH.isValid());
218
219 Monitored::Scalar<int> dqm_superslot{"S", -1};
220 Monitored::Scalar<int> dqm_channel{"C", -1};
221 Monitored::Scalar<float> dqm_posn{"posn", 0};
222 Monitored::Scalar<float> dqm_negn{"negn", 0};
223 Monitored::Scalar<float> dqm_qual{"Q4k", 0};
224 Monitored::Scalar<float> dqm_energy{"E", 0};
225 Monitored::Scalar<int> dqm_gain{"G", 0};
226 Monitored::Scalar<bool> dqmf_occ{"occ", false};
227 Monitored::Scalar<bool> dqmf_sig{"sig", false};
228
229 for (const LArRawChannel &chan : *raw_channels) {
230 HWIdentifier hardware_id{chan.hardwareID()};
231 Identifier offline_id{0};
232 HWIdentifier feb_id{0};
233 IdentifierHash feb_hash{0};
234 int channel{-1};
235 int slot_number{-1}, feedthrough_number{-1};
236 int8_t det{::UNDEF};
237 float energy, time, noise, significance;
238 int gain{-1};
239 bool bad_quality;
240
241 // Skip unconnected channels
242 if (!cablingH->isOnlineConnected(hardware_id)) continue;
243 // Skip masked channels
244 if (m_bcMask.cellShouldBeMasked(*bcContH, hardware_id)) continue;
245
246 // Monitor properly reconstructed channels only:
247 // - provenance&0x00ff == 0x00a5:
248 // raw channels from OFC iteration, all calib constants found in DB
249 // - provenance&0x1000 == 0x1000:
250 // raw channels from DSP. If no constant loaded in DSP, energy==0
252 && !LArProv::test(chan.provenance(), LArProv::DEFAULTRECO)
253 && !LArProv::test(chan.provenance(), LArProv::DSPCALC)) continue;
254
255 try {
256 feb_id = m_lar_online_id_ptr->feb_Id(hardware_id);
257 feb_hash = m_lar_online_id_ptr->feb_Hash(feb_id);
258 det = m_feb_hash_to_detector.at(feb_hash);
259 if (det != lastdet) {
260 if (det >= 0 && det < ::NDETECTORS) {
261 monitoring = m_tools[m_monitoring_tool_index[det]];
262 } else {
263 monitoring = nullptr;
264 }
265 lastdet = det;
266 }
267
268 slot_number = m_lar_online_id_ptr->slot(hardware_id);
269 feedthrough_number = m_lar_online_id_ptr->feedthrough(hardware_id);
270 channel = m_lar_online_id_ptr->channel(hardware_id);
271 energy = chan.energy() * Athena::Units::MeV; // fixed in MeV by DSP
272 time = chan.time() * Athena::Units::picosecond; // fixed in ps by DSP
273 gain = chan.gain();
274 noise = noiseH->getNoise(offline_id, gain);
275 significance = energy / noise;
276 bad_quality = (energy > 0.1 * Athena::Units::MeV)
277 && (chan.quality() > m_quality_threshold);
278 }
279 catch (const LArOnlID_Exception &) {
280 continue; // skip this channel
281 }
282 catch (const std::out_of_range &err) {
283 ATH_MSG_WARNING("FEB hash out of range. Detector undefined"
284 << err.what());
285 continue; // skip this channel
286 }
287 catch (const LArID_Exception &) {
288 ATH_MSG_WARNING("channel offline id undefined ... skipping");
289 continue; // skip this channel
290 }
291
292 // Fill per-detector histograms ---
293 if (m_monitor_detectors && monitoring) {
294 bool noisy_pos{significance > m_pos_noise_thresholds[det]};
295 bool noisy_neg{-significance > m_neg_noise_thresholds[det]};
296 per_detector_total_energy[det] += energy;
297 det_n_noisy_channels[det] += noisy_pos;
298 det_n_noisy_channels_Neg[det] += noisy_neg;
299 det_n_badQ_channels[det] += bad_quality;
300 dqm_superslot = feedthrough_number * ::numberOfSlotsPerFeedthrough(det)
301 + slot_number;
302 dqm_channel = channel;
303 dqmf_occ = noisy_event && (energy > m_occupancy_thresholds[det]);
304 dqmf_sig = noisy_event && (energy > m_signal_thresholds[det])
305 && is_atlas_ready && !larNoisyROAlgInTimeW_flag;
306 dqm_energy = energy;
307 dqm_gain = gain;
308 dqm_posn = 100 * (noisy_event && !larNoisyROAlgInTimeW_flag
309 && noisy_pos && is_atlas_ready);
310 dqm_negn = 100 * (noisy_event && !larNoisyROAlgInTimeW_flag
311 && noisy_neg && is_atlas_ready);
312 dqm_qual = 100 * (bad_quality && is_atlas_ready
313 && !larNoisyROAlgInTimeW_flag);
314 fill(monitoring, dqm_superslot, dqm_channel,
315 dqmf_occ, dqmf_sig, dqm_energy, dqm_gain,
316 dqm_posn, dqm_negn, dqm_qual);
317
318 if (m_monitor_time && significance > m_time_threshold) {
319 // The time resolution is \sigma_t = \frac{a}{E/\sigma_{E}} \oplus b
320 // where a and b depend on the channel position (partition + layer);
321 // in practice a = 30ns and b = 1ns are assumed.
322 if (significance != 0.) {
323 double weight = 1. + 900. / std::pow(significance, 2);
324 // <t> = ( \sum w*t ) / ( \sum w )
325 // -> num. & den. are accumulated separately using a complex variable
326 wsum_t datapoint{weight * (double(time) + 1i)};
327 event_mean_time += datapoint;
328 mean_detector_times[det] += datapoint;
329 mean_feb_times[feb_hash] += datapoint;
330 }
331 }
332 }
333 }
334
335 Monitored::Scalar<int> dqm_lb{"lb", lumi_block};
336 Monitored::Scalar<int> dqm_bcid{"bc", bcid};
337 Monitored::Scalar<int> dqm_qnChan{"nQ4k", 0};
338 Monitored::Scalar<float> dqm_percent_noisy{"%noisy", 0};
339 Monitored::Scalar<float> dqm_percent_neg_noisy{"%noisy_neg", 0};
340 Monitored::Scalar<bool> dqmf_burst{"burst", false};
341 Monitored::Scalar<bool> dqmf_burst_timevetoed{"burst_quietW", false};
342 Monitored::Scalar<float> dqm_total_energy{"detE", 0};
343 Monitored::Scalar<bool> dqmf_qburst{"qburst", false};
344 Monitored::Scalar<bool> dqmf_noNoisyRO{"quiet", !larNoisyROAlg_flag};
345 Monitored::Scalar<bool> dqmf_noNoisyRO_W{"quietW", !larNoisyROAlg_W_flag};
346 Monitored::Scalar<bool> dqmf_noNoisyRO_ITW{
347 "quietITW", !larNoisyROAlgInTimeW_flag};
348 for (int8_t det : ::partitions()) {
349 float scaling = 100.f / m_det_to_nchannels[det];
350 float percent_noisy = scaling * det_n_noisy_channels[det];
351 float percent_bad_quality = scaling * det_n_badQ_channels[det];
352 dqmf_burst = percent_noisy > m_noise_burst_percent_thresholds[det];
353 dqmf_burst_timevetoed = dqmf_burst && !larNoisyROAlgInTimeW_flag;
354 dqm_percent_noisy = percent_noisy;
355 dqm_percent_neg_noisy = scaling * det_n_noisy_channels_Neg[det];
356 dqm_qnChan = det_n_badQ_channels[det];
357 dqmf_qburst = percent_bad_quality > m_noise_burst_percent_thresholds[det];
358 dqm_total_energy = per_detector_total_energy[det];
359
360 if (m_monitor_burst) {
361 fill(m_tools[m_monitoring_tool_index[det]], dqm_lb, dqm_bcid,
362 dqm_percent_noisy, dqm_percent_neg_noisy,
363 dqmf_noNoisyRO, dqmf_noNoisyRO_W, dqmf_noNoisyRO_ITW,
364 dqmf_burst, dqmf_burst_timevetoed, dqmf_qburst,
365 dqm_qnChan);
366 }
367 if (m_monitor_signal) {
368 fill(m_tools[m_monitoring_tool_index[det]], dqm_lb, dqm_bcid,
369 dqmf_noNoisyRO_W, dqm_total_energy);
370 }
371 }
372
373 Monitored::Scalar<float> dqm_time{"T", 0};
375 // sum w*t and sum w are accumulated respectively in Re(z) and Im(z)
376 double t{event_mean_time.real() / event_mean_time.imag()};
377 for (uint32_t h = 0; h < mean_feb_times.size(); ++h) {
378 wsum_t w{mean_feb_times[h]};
379 if (w.imag() == 0.) continue;
380 int8_t det = m_feb_hash_to_detector.at(h);
381 double t_feb = w.real() / w.imag();
382 dqm_time = (t_feb - t) / Athena::Units::nanosecond;
383 fill(m_tools[m_monitoring_tool_index[det]], dqm_time);
384 }
385 }
386
387 return StatusCode::SUCCESS;
388}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Definition of CaloDetDescrManager.
Wrapper to avoid constant divisions when using units.
#define x
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
virtual StatusCode initialize() override
initialize
SG::ReadHandle< xAOD::EventInfo > GetEventInfo(const EventContext &) const
Return a ReadHandle for an EventInfo object (get run/event numbers, etc.)
AthMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
ToolHandleArray< GenericMonitoringTool > m_tools
Array of Generic Monitoring Tools.
This is a "hash" representation of an Identifier.
Exception class for LAr Identifiers.
Exception class for LAr online Identifiers.
SG::ReadHandleKey< LArRawChannelContainer > m_LArRawChannel_container_key
Gaudi::Property< std::vector< int > > m_pos_noise_thresholds
virtual StatusCode initialize() override
initialize
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
const LArOnlineID * m_lar_online_id_ptr
Gaudi::Property< short > m_time_threshold
ToolHandleArray< IDQFilterTool > m_atlasReady_tools
Gaudi::Property< bool > m_db_and_ofc_only
LArRawChannelMonAlg(const std::string &, ISvcLocator *)
SG::ReadCondHandleKey< CaloNoise > m_noiseKey
Gaudi::Property< bool > m_monitor_signal
std::vector< int8_t > m_feb_hash_to_detector
std::array< uint32_t, 8 > m_det_to_nchannels
Gaudi::Property< bool > m_monitor_burst
Gaudi::Property< std::vector< std::string > > m_problemsToMask
Gaudi::Property< unsigned short > m_quality_threshold
std::set< std::string > m_noise_streams_set
SG::ReadCondHandleKey< LArBadChannelCont > m_bcContKey
Gaudi::Property< bool > m_monitor_time
Gaudi::Property< std::vector< std::string > > m_noise_streams
SG::ReadDecorHandleKey< xAOD::EventInfo > m_larFlagKey
virtual StatusCode fillHistograms(const EventContext &ctx) const override
adds event to the monitoring histograms
std::array< int, 8 > m_monitoring_tool_index
Gaudi::Property< std::vector< double > > m_occupancy_thresholds
Gaudi::Property< bool > m_monitor_detectors
Gaudi::Property< std::vector< double > > m_noise_burst_percent_thresholds
Gaudi::Property< std::vector< int > > m_neg_noise_thresholds
Gaudi::Property< std::vector< double > > m_signal_thresholds
LArBadChannelMask m_bcMask
Liquid Argon ROD output object base class.
Declare a monitored scalar variable.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
@ LAr
The LAr calorimeter.
std::vector< std::string > tags
Definition hcg.cxx:105
dict partitions
Definition DeMoScan.py:65
bool test(const uint16_t prov, const LArProvenance check)
std::vector< V > buildToolMap(const ToolHandleArray< GenericMonitoringTool > &tools, const std::string &baseName, int nHist)
Builds an array of indices (base case)
void fill(H5::Group &out_file, size_t iterations)