ATLAS Offline Software
Loading...
Searching...
No Matches
TileRawChannelMonitorAlgorithm.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
8
11
13
14 ATH_MSG_DEBUG("in initialize()");
15
16 // initialize superclass
18
19 ATH_CHECK( m_digitsContainerKey.initialize() );
22 ATH_CHECK( m_emScaleKey.initialize() );
23
24 m_dac2Charge[0] = 100.* 2.0 * 4.096 / m_tileInfo->ADCmax(); // 100 pF * 2 for legacy or 200 pF for demonstrator
25 m_dac2Charge[1] = 5.2 * 2.0 * 4.096 / m_tileInfo->ADCmax(); // use the same number 5.2 pF as in TileCisDefaultCalibTool
26
27 if ((m_calibUnit >= 0) && (m_calibUnit <= 3)) {
29 }
30
34 }
35
36 ATH_MSG_INFO("Final Units: " << m_finalRawChannelUnit);
37
38 using Tile = TileCalibUtils;
39 using namespace Monitored;
40
42
45 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
46
47 m_timeGroups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelTime",
48 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
49
50 m_timeCorrGroups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelTimeCorr",
51 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
52 } else { // CIS run
53 // For 5 pF capacitor
54 m_ampOverQ5Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelAmpOverQ5",
55 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
56
57 m_time5Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelTime5",
58 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
59
60 // For 100 pF capacitor
61 m_ampOverQ100Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelAmpOverQ100",
62 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
63
64 m_time100Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelTime100",
65 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
66
68 // For 5 pF capacitor
69 m_ampVsQ5Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelAmpVsQ5",
70 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
71
72 m_timeVsTime5Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelTimeVsTime5",
73 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
74
75 // For 100 pF capacitor
76 m_ampVsQ100Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelAmpVsQ100",
77 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
78
79 m_timeVsTime100Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelTimeVsTime100",
80 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
81
82 }
83 }
84
85
87 m_dspAmpGroups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelDspAmp",
88 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
89
90 m_dspTimeGroups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelDspTime",
91 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
92
93 m_dspChi2Groups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelDspChi2",
94 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
95
96 m_dspChi2VsAmpGroups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelDspChi2VsAmp",
97 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
98
99 m_ampDiffGroups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelAmpDiff",
100 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
101
102 m_timeDiffGroups = buildToolMap<std::vector<int>>(m_tools, "TileRawChannelTimeDiff",
103 Tile::MAX_ROS - 1, Tile::MAX_DRAWER);
104 }
105
106
107 return StatusCode::SUCCESS;
108}
109
110
111StatusCode TileRawChannelMonitorAlgorithm::fillHistograms( const EventContext& ctx ) const {
112
113 using Tile = TileCalibUtils;
114
115 // In case you want to measure the execution time
116 auto timer = Monitored::Timer("TIME_execute");
117
118 if (ctx.evt() % 1000 == 0) {
119 ATH_MSG_ALWAYS(ctx.evt() << " events processed so far");
120 }
121
123 ATH_CHECK( emScale.isValid() );
124
125 SG::ReadHandle<TileDQstatus> dqStatusHandle(m_dqStatusKey, ctx);
126 ATH_CHECK( dqStatusHandle.isValid() );
127 const TileDQstatus* dqStatus = dqStatusHandle.get();
128
129 // array of CIS parameters
130 const uint32_t* cispar = dqStatus->cispar();
131
132 if (cispar[8] != 0) return StatusCode::SUCCESS;
133
134 int cap = (cispar[7] > 10) ? 0 : 1; // 100 pF or 5 pF
135 double injectionTime = cispar[5] * 0.104;
136 double chargeForNormalModule = (cispar[6] < 1024) ? cispar[6] * m_dac2Charge[cap] : 0.;
137 // Effective value of small capacitor is twice smaller for demonstrator
138 double chargeForDemonstrator = cap ? chargeForNormalModule * 0.5 : chargeForNormalModule;
139 double invChargeForNormalModule = (chargeForNormalModule != 0) ? 1.0 / chargeForNormalModule : 0.;
140 double invChargeForDemonstrator = (chargeForDemonstrator != 0) ? 1.0 / chargeForDemonstrator : 0.;
141
142 // Ignore charges below 1 pC in HG
143 // Ignore charges below 10 pC for small capacitor and below 15 pC for big capacitor in LG
144 std::array<double, 2> minChargeForNormalModule = {(cap ? 10. : 15.), 1.};
145 std::array<double, 2> minChargeForDemonstrator = {(cap ? 10. : 15.), 2.};
146
147 // Ignore charges above 11.5 pC in HG (full range is 12.5 pC)
148 // Ignore charges above 750. pC in LG (full range is 800. pC)
149 std::array<double, 2> maxChargeForNormalModule = {750., 11.5};
150 std::array<double, 2> maxChargeForDemonstrator = {750., 23.0};
151
152 const std::vector<std::vector<int>>& ampOverQCapGroups = cap ? m_ampOverQ5Groups : m_ampOverQ100Groups;
153 const std::vector<std::vector<int>>& ampVsQCapGroups = cap ? m_ampVsQ5Groups : m_ampVsQ100Groups;
154 const std::vector<std::vector<int>>& timeCapGroups = cap ? m_time5Groups : m_time100Groups;
155 const std::vector<std::vector<int>>& timeVsTimeCapGroups = cap ? m_timeVsTime5Groups : m_timeVsTime100Groups;
156
157 bool corruptedData[Tile::MAX_ROS - 1][Tile::MAX_DRAWER][Tile::MAX_GAIN][MAX_DMU]={{{{false}}}};
158
160 ATH_CHECK( digitsContainer.isValid() );
161
162 for (const TileDigitsCollection* digitsCollection : *digitsContainer) {
163 if (digitsCollection->empty() ) continue;
164
165 HWIdentifier adc_id = digitsCollection->front()->adc_HWID();
166 int ros = m_tileHWID->ros(adc_id);
167 int drawer = m_tileHWID->drawer(adc_id);
168 int partition = ros - 1;
169
170 std::vector<uint32_t> headers = digitsCollection->getFragChipHeaderWords();
171 int nDMU = headers.size();
172 if (nDMU > MAX_DMU) nDMU = MAX_DMU;
173
174 int fragId = digitsCollection->identify();
175 if (!std::binary_search(m_fragIDsToIgnoreDMUerrors.begin(), m_fragIDsToIgnoreDMUerrors.end(), fragId)) {
176 for (int dmu = 0; dmu < nDMU; ++dmu) {
177 bool isDataCorrupted = isDmuHeaderError(headers[dmu]);
178 corruptedData[partition][drawer][0][dmu] = isDataCorrupted;
179 corruptedData[partition][drawer][1][dmu] = isDataCorrupted;
180 }
181 }
182 }
183
184 int nChannels[Tile::MAX_ROS-1] = {0};
185 float partitionTimeSum[Tile::MAX_ROS-1] = {0};
186
187 //coverity[STACK_USE]
188 float offlineTime[Tile::MAX_ROS-1][Tile::MAX_DRAWER][Tile::MAX_CHAN][Tile::MAX_GAIN] = {{{{0}}}};
189 //coverity[STACK_USE]
190 float offlineAmplitude[Tile::MAX_ROS-1][Tile::MAX_DRAWER][Tile::MAX_CHAN][Tile::MAX_GAIN] = {{{{0}}}};
191
192
194 ATH_CHECK( rawChannelContainer.isValid() );
195
196 TileRawChannelUnit::UNIT rawChannelUnit = rawChannelContainer->get_unit();
197
198 for (const TileRawChannelCollection* rawChannelCollection : *rawChannelContainer) {
199 if (rawChannelCollection->empty()) continue;
200
201 HWIdentifier adc_id = rawChannelCollection->front()->adc_HWID();
202 int ros = m_tileHWID->ros(adc_id);
203 int drawer = m_tileHWID->drawer(adc_id);
204 unsigned int drawerIdx = TileCalibUtils::getDrawerIdx(ros, drawer);
205 int partition = ros - 1;
206
207 int fragId = rawChannelCollection->identify();
208 bool demonstrator = (std::binary_search(m_fragIDsDemonstrators.begin(), m_fragIDsDemonstrators.end(), fragId));
209
210 std::array<double, 2>& minCharge = demonstrator ? minChargeForDemonstrator : minChargeForNormalModule;
211 std::array<double, 2>& maxCharge = demonstrator ? maxChargeForDemonstrator : maxChargeForNormalModule;
212 double charge = demonstrator ? chargeForDemonstrator : chargeForNormalModule;
213 double invCharge = demonstrator ? invChargeForDemonstrator : invChargeForNormalModule;
214
215 for (const TileRawChannel* rawChannel : *rawChannelCollection) {
216 adc_id = rawChannel->adc_HWID();
217 int channel = m_tileHWID->channel(adc_id);
218 int adc = m_tileHWID->adc(adc_id);
219
220 if (corruptedData[partition][drawer][adc][channel / 3]) continue;
221
222 std::string channelGainSuffix = "_" + std::to_string(channel) + "_" + std::to_string(adc);
223
224 float amplitude = rawChannel->amplitude();
225 if (rawChannelUnit != m_finalRawChannelUnit) {
226 // Put everything in PicoCoulomb by default for all run types
227 // For Laser and Physcs calibrate in CesiumPicoCoulomb for all channels, but the MBTS channels,
228 // for which we keep the calibration in PicoCoulombCesium pC for consistency (no Cs calibration is possible)
230 // if EB then check that they are not MBTS channel
231 int index, pmt;
232 rawChannel->cell_ID_index(index, pmt);
233 if (index < -1) { // MBTS channel
234 amplitude = emScale->calibrateChannel(drawerIdx, channel, adc, amplitude, rawChannelUnit, TileRawChannelUnit::PicoCoulombs);
235 }
236 }
237 amplitude = emScale->calibrateChannel(drawerIdx, channel, adc, amplitude, rawChannelUnit, m_finalRawChannelUnit);
238 } // no need to calibrate
239
240 offlineAmplitude[partition][drawer][channel][adc] = amplitude;
241
242 float time = rawChannel->time();
243 offlineTime[partition][drawer][channel][adc] = time;
244
245 if (m_runTypeIsNotCIS) {
246 auto monAmplitude = Monitored::Scalar<float>("amp" + channelGainSuffix, amplitude);
247 fill(m_tools[m_ampGroups[partition][drawer]], monAmplitude);
248
249 if (time != 0) {
250 // Don't fill the time when it is exactly 0, which is a conventional value to say that it is not
251 // calculated when the difference between the max(samples) - min(samples) < threshold
252 auto monTime = Monitored::Scalar<float>("time" + channelGainSuffix, time);
253 fill(m_tools[m_timeGroups[partition][drawer]], monTime);
254 }
255
256 if (m_cabling->isDisconnected(ros, drawer, channel)
257 || amplitude < m_minAmpForCorrectedTime
258 // In EB exclude some channels (most likely single PMT) from calculating average time
259 || ((ros > 2) && (channel < 6 || channel == 12 || channel == 13 || channel == 18 || channel == 19))) {
260 continue;
261 } else {
262 partitionTimeSum[partition] += time;
263 nChannels[partition] += 1;
264 }
265
266 } else { // It's CIS run
267
268 if (m_fill2DHistograms) {
269 auto monAmplitude = Monitored::Scalar<float>("amp" + channelGainSuffix, amplitude);
270 auto monCharge = Monitored::Scalar<float>("charge" + channelGainSuffix, charge);
271 fill(m_tools[ampVsQCapGroups[partition][drawer]], monCharge, monAmplitude);
272 }
273
274 if ((minCharge[adc] < charge) && (charge < maxCharge[adc])) {
275 double ratio = amplitude * invCharge;
276 auto monRatio = Monitored::Scalar<float>("amp_ratio" + channelGainSuffix, ratio);
277 fill(m_tools[ampOverQCapGroups[partition][drawer]], monRatio);
278
279 auto monTime = Monitored::Scalar<float>("time" + channelGainSuffix, time);
280 fill(m_tools[timeCapGroups[partition][drawer]], monTime);
281
282 if (m_fill2DHistograms) {
283 auto monInjTime = Monitored::Scalar<float>("inj_time" + channelGainSuffix, injectionTime);
284 fill(m_tools[timeVsTimeCapGroups[partition][drawer]], monInjTime, monTime);
285 }
286 }
287 }
288 }
289 }
290
291 if (m_runTypeIsNotCIS) {
292 for (unsigned int partition = 0; partition < Tile::MAX_ROS - 1; ++partition) {
293 if (nChannels[partition] > 0) {
294 float averagePartitionTime = partitionTimeSum[partition] / nChannels[partition];
295 for (unsigned int drawer = 0; drawer < Tile::MAX_DRAWER; ++drawer) {
296 for (unsigned int channel = 0; channel < Tile::MAX_CHAN; ++channel) {
297 for (unsigned int gain = 0; gain < Tile::MAX_GAIN; ++gain) {
298 float time = offlineTime[partition][drawer][channel][gain];
299 if (time != 0) {
300 std::string channelGainSuffix = "_" + std::to_string(channel) + "_" + std::to_string(gain);
301 float timeCorrected = time - averagePartitionTime;
302 auto monTimeCorr = Monitored::Scalar<float>("time_corr" + channelGainSuffix, timeCorrected);
303 fill(m_tools[m_timeCorrGroups[partition][drawer]], monTimeCorr);
304 }
305 }
306 }
307 }
308 }
309 }
310 }
311
312
314
316 ATH_CHECK( dspRawChannelContainer.isValid() );
317
318 TileRawChannelUnit::UNIT dspRawChannelUnit = dspRawChannelContainer->get_unit();
319
320 for (const TileRawChannelCollection* rawChannelCollection : *dspRawChannelContainer) {
321 if (rawChannelCollection->empty() ) continue;
322
323 HWIdentifier adc_id = rawChannelCollection->front()->adc_HWID();
324 int ros = m_tileHWID->ros(adc_id);
325 int drawer = m_tileHWID->drawer(adc_id);
326 unsigned int drawerIdx = TileCalibUtils::getDrawerIdx(ros, drawer);
327 int partition = ros - 1;
328
329 for (const TileRawChannel* rawChannel : *rawChannelCollection) {
330 adc_id = rawChannel->adc_HWID();
331 int channel = m_tileHWID->channel(adc_id);
332 int adc = m_tileHWID->adc(adc_id);
333
334 if (corruptedData[partition][drawer][adc][channel / 3]) continue;
335
336 std::string channelGainSuffix = "_" + std::to_string(channel) + "_" + std::to_string(adc);
337
338 float amplitude = rawChannel->amplitude();
339 if (dspRawChannelUnit != m_finalRawChannelUnit) {
340 // Put everything in PicoCoulomb by default for all run types
341 // For Laser and Physcs calibrate in CesiumPicoCoulomb for all channels, but the MBTS channels,
342 // for which we keep the calibration in PicoCoulombCesium pC for consistency (no Cs calibration is possible)
344 // if EB then check that they are not MBTS channel
345 int index, pmt;
346 rawChannel->cell_ID_index(index, pmt);
347 if (index < -1) { // MBTS channel
348 amplitude = emScale->calibrateChannel(drawerIdx, channel, adc, amplitude, dspRawChannelUnit, TileRawChannelUnit::PicoCoulombs);
349 }
350 }
351 amplitude = emScale->calibrateChannel(drawerIdx, channel, adc, amplitude, dspRawChannelUnit, m_finalRawChannelUnit);
352 } // no need to calibrate
353
354 auto monAmplitude = Monitored::Scalar<float>("dsp_amp" + channelGainSuffix, amplitude);
355 fill(m_tools[m_dspAmpGroups[partition][drawer]], monAmplitude);
356
357 float offline_amplitude = offlineAmplitude[partition][drawer][channel][adc];
358 if (offline_amplitude > m_minOfflineAmp) {
359 float amplitudeDiff = (amplitude - offline_amplitude) / offline_amplitude;
360 auto monAmplitudeDiff = Monitored::Scalar<float>("dsp-fit_amp_diff" + channelGainSuffix, amplitudeDiff);
361 fill(m_tools[m_ampDiffGroups[partition][drawer]], monAmplitudeDiff);
362 }
363
364 float time = rawChannel->time();
365 auto monTime = Monitored::Scalar<float>("dsp_time" + channelGainSuffix, time);
366 fill(m_tools[m_dspTimeGroups[partition][drawer]], monTime);
367
368 float offline_time = offlineTime[partition][drawer][channel][adc];
369 if (offline_time != 0.) {
370 float timeDiff = time - offline_time;
371 auto monTimeDiff = Monitored::Scalar<float>("dsp-fit_time_diff" + channelGainSuffix, timeDiff);
372 fill(m_tools[m_timeDiffGroups[partition][drawer]], monTimeDiff);
373 }
374
375 float chi2 = rawChannel->quality();
376 auto monChi2 = Monitored::Scalar<float>("dsp_chi2" + channelGainSuffix, chi2);
377 fill(m_tools[m_dspChi2Groups[partition][drawer]], monChi2);
378
379 fill(m_tools[m_dspChi2VsAmpGroups[partition][drawer]], monAmplitude, monChi2);
380 }
381 }
382 }
383
384 fill("TileRawChannelMonExecuteTime", timer);
385
386 return StatusCode::SUCCESS;
387}
388
390
391 bool error = false;
393 error = true;
394 } else if (isHeaderParityError(header)) {
395 error = true;
396 } else if ((header >> 25) & 0x1) {
397 // Memory Parity Error
398 error = true;
399 } else if ((header >> 24) & 0x1) {
400 // Single Strobe Error
401 error = true;
402 } else if ((header >> 23) & 0x1) {
403 // Double Strobe Error
404 error = true;
405 }
406
407 return error;
408}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_ALWAYS(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
Handle class for reading from StoreGate.
ToolHandleArray< GenericMonitoringTool > m_tools
Array of Generic Monitoring Tools.
Declare a monitored scalar variable.
A monitored timer.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type get() const
Dereference the pointer, but don't cache anything.
bool isHeaderParityError(uint32_t header) const
SG::ReadHandleKey< TileDQstatus > m_dqStatusKey
virtual StatusCode initialize() override
initialize
const TileCablingService * m_cabling
Gaudi::Property< std::vector< int > > m_fragIDsDemonstrators
bool isHeaderFormatError(uint32_t header) const
Gaudi::Property< std::vector< int > > m_fragIDsToIgnoreDMUerrors
Static class providing several utility functions and constants.
static unsigned int getDrawerIdx(unsigned int ros, unsigned int drawer)
Returns a drawer hash.
Class that holds Data Quality fragment information and provides functions to extract the data quality...
const uint32_t * cispar() const
CIS parameters.
std::vector< std::vector< int > > m_timeCorrGroups
std::vector< std::vector< int > > m_ampGroups
SG::ReadHandleKey< TileRawChannelContainer > m_dspRawChannelContainerKey
std::vector< std::vector< int > > m_dspTimeGroups
std::vector< std::vector< int > > m_ampDiffGroups
SG::ReadCondHandleKey< TileEMScale > m_emScaleKey
Name of TileEMScale in condition store.
std::vector< std::vector< int > > m_ampVsQ100Groups
std::vector< std::vector< int > > m_ampOverQ5Groups
std::vector< std::vector< int > > m_dspChi2VsAmpGroups
std::vector< std::vector< int > > m_time100Groups
std::vector< std::vector< int > > m_dspAmpGroups
std::vector< std::vector< int > > m_dspChi2Groups
std::vector< std::vector< int > > m_timeVsTime100Groups
std::vector< std::vector< int > > m_timeDiffGroups
std::vector< std::vector< int > > m_ampOverQ100Groups
std::vector< std::vector< int > > m_timeVsTime5Groups
virtual StatusCode fillHistograms(const EventContext &ctx) const override
adds event to the monitoring histograms
virtual StatusCode initialize() override
initialize
std::vector< std::vector< int > > m_ampVsQ5Groups
std::vector< std::vector< int > > m_timeGroups
SG::ReadHandleKey< TileDigitsContainer > m_digitsContainerKey
std::vector< std::vector< int > > m_time5Groups
SG::ReadHandleKey< TileRawChannelContainer > m_rawChannelContainerKey
double chi2(TH1 *h0, TH1 *h1)
Generic monitoring tool for athena components.
std::vector< V > buildToolMap(const ToolHandleArray< GenericMonitoringTool > &tools, const std::string &baseName, int nHist)
Builds an array of indices (base case)
Definition index.py:1
void fill(H5::Group &out_file, size_t iterations)