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