ATLAS Offline Software
Loading...
Searching...
No Matches
LArRawChannelBuilderIterAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "GaudiKernel/SystemOfUnits.h"
11
12#include <climits>
13#include <cmath>
14#include <memory>
15
16#define MAXINT INT_MAX
17#define MAXINT2 -INT_MAX
18
19
21 ATH_CHECK(m_digitKey.initialize());
22 ATH_CHECK(m_rawChannelKey.initialize());
23 ATH_CHECK(m_pedestalKey.initialize());
24 ATH_CHECK(m_adc2MeVKey.initialize());
25 ATH_CHECK(m_ofcKey.initialize());
26 ATH_CHECK(m_shapeKey.initialize());
27 ATH_CHECK(m_cablingKey.initialize() );
30 if (m_useDBFortQ) {
31 if (m_run1DSPThresholdsKey.empty() && m_run2DSPThresholdsKey.empty()) {
32 ATH_MSG_ERROR ("useDB requested but neither Run1DSPThresholdsKey nor Run2DSPThresholdsKey initialized.");
33 return StatusCode::FAILURE;
34 }
35 }
36
37 ATH_CHECK(detStore()->retrieve(m_onlineId,"LArOnlineID"));
38
39 const std::string cutmsg = m_absECutFortQ.value() ? " fabs(E) < " : " E < ";
40 ATH_MSG_INFO("Energy cut for time and quality computation: " << cutmsg <<
41 " taken from COOL folder "<<
42 m_run1DSPThresholdsKey.key() << " (run1) " <<
43 m_run2DSPThresholdsKey.key() << " (run2) ");
44
46
47 return StatusCode::SUCCESS;
48}
49
51 return StatusCode::SUCCESS;
52}
53
54StatusCode LArRawChannelBuilderIterAlg::execute(const EventContext& ctx) const {
55
56 //Get event inputs from read handles:
58
59 //Write output via write handle
61 ATH_CHECK(outputContainer.record(std::make_unique<LArRawChannelContainer>()));
62
63 //Should we store iter results ?
64 LArOFIterResultsContainer* outputTimingContainer{nullptr};
65 if(!m_timingContKey.empty()) {
67 ATH_CHECK(timingContHandle.record(std::make_unique<LArOFIterResultsContainer>()));
68 outputTimingContainer = timingContHandle.ptr();
69 }
70 //Get Conditions input
72 const ILArPedestal* peds=*pedHdl;
73
75 const LArADC2MeV* adc2MeVs=*adc2mevHdl;
76
78 const ILArOFC* ofcs=*ofcHdl;
79
81 const ILArShape* shapes=*shapeHdl;
82
84
85 std::unique_ptr<LArDSPThresholdsFlat> run2DSPThresh;
86 const LArDSPThresholdsComplete* run1DSPThresh = nullptr;
87 if (m_useDBFortQ) {
88 if (!m_run2DSPThresholdsKey.empty()) {
90 run2DSPThresh = std::make_unique<LArDSPThresholdsFlat>(*dspThrshAttr);
91 if (ATH_UNLIKELY(!run2DSPThresh->good())) {
92 ATH_MSG_ERROR( "Failed to initialize LArDSPThresholdFlat from attribute list loaded from " << m_run2DSPThresholdsKey.key()
93 << ". Aborting." );
94 return StatusCode::FAILURE;
95 }
96 }
97 else if (!m_run1DSPThresholdsKey.empty()) {
99 run1DSPThresh = dspThresh.cptr();
100 }
101 else {
102 ATH_MSG_ERROR( "No DSP threshold configured.");
103 return StatusCode::FAILURE;
104 }
105 }
106
107 std::vector<float> signal; //Pedestal-subtracted
108
109 const float fMAXINT = static_cast<float>(MAXINT);
110 const float fMAXINT2 = static_cast<float>(MAXINT2);
111
112 //Loop over digits:
113 for (const LArDigit* digit : *inputContainer) {
114
115 const HWIdentifier id=digit->hardwareID();
116 const bool connected=(*cabling)->isOnlineConnected(id);
117
118 ATH_MSG_VERBOSE("Working on channel " << m_onlineId->channel_name(id));
119
120 const std::vector<short>& samples=digit->samples();
121 auto gain=digit->gain();
122 const float p=peds->pedestal(id,gain);
123
124
125 //The following autos will resolve either into vectors or vector-proxies
126 const auto& adc2mev=adc2MeVs->ADC2MEV(id,gain);
127
129 if (!connected) continue; //No conditions for disconencted channel, who cares?
130 ATH_MSG_ERROR("No valid pedestal for connected channel " << m_onlineId->channel_name(id)
131 << " gain " << gain);
132 return StatusCode::FAILURE;
133 }
134
135 if(ATH_UNLIKELY(adc2mev.size()<2)) {
136 if (!connected) continue; //No conditions for disconencted channel, who cares?
137 ATH_MSG_ERROR("No valid ADC2MeV for connected channel " << m_onlineId->channel_name(id)
138 << " gain " << gain);
139 return StatusCode::FAILURE;
140 }
141
142 uint16_t prov=0;
143
144 float peakval = -999.;
145 unsigned short ipeak = 0;
146 float currval = 0.;
147 const unsigned int sampsize = (unsigned int) samples.size();
148
149 signal.resize(sampsize);
150 for (unsigned int ii = 0; ii < sampsize; ++ii) {
151 if (samples[ii]==0 || samples[ii]>=m_AdcMax) { //Check for saturation
152 ATH_MSG_DEBUG("Saturation on channel 0x" <<
153 MSG::hex << id.get_compact() << MSG::dec << " ADC=" << samples[ii]);
154 if ( m_skipSaturatedCells ) {
155 ATH_MSG_DEBUG(" Skipping channel...");
156 continue;
157 }
158 prov|=0x0400;
159 }
160 currval = (float)(samples[ii] - p);
161 signal[ii]=currval;
162 if ((ii >= m_minSample)&&(ii <= m_maxSample)&&(currval > peakval)) {
163 ipeak = ii; peakval = currval;
164 }
165 }
166 ATH_MSG_DEBUG("Peak value: " << peakval << ", peak sample:" << ipeak);
167
168 int nIteration = m_nIterProp;
169 bool doIter=false;
170 if (m_minADCforIterInSigma>0) {//threshold given in terms of pedestal-rms, get pedestal
171 float vRMS=peds->pedestalRMS(id,gain);
172 if (vRMS >= (1.0+LArElecCalib::ERRORCODE)) {
173 if (peakval > (vRMS*m_minADCforIterInSigma)) doIter=true;//enough signal...
174 }
175 else { //no pedestal found, use adc threshold
176 if (peakval > m_minADCforIter) doIter=true;//enough signal...
177 }
178 } else {
179 if (peakval >= m_minADCforIter) doIter=true;//enough signal...
180 }
181
182 if (!doIter) {//No iteration, insufficient signal
183 nIteration=1;
184 ipeak = m_defaultShiftTimeSamples + 2 ;
185 }
186
187 if (ipeak > sampsize - 3) ipeak = sampsize - 3 ;
188 if (ipeak < 2) ipeak = 2;
189
190 unsigned int peak_min = ipeak - 1 ;
191 unsigned int peak_max = ipeak + 1 ;
192
193 float ADCPeak=0;
194 float time=0.;
195
196 const LArOFIterResults results = peak(signal, id, gain, m_defaultPhase, ofcs, shapes,
197 nIteration, ipeak,peak_min, peak_max );
198 if(outputTimingContainer) {
199 outputTimingContainer->push_back(results);
200 }
201 if (results.getValid()) {
202 ADCPeak = results.getAmplitude();
203 // this should be ~0 if the peak is at curr_shiftTimeSamples
204 // FIXME: this time definition still misses the tstart from the OFC to be absolutely computed
205 time = (25.*((int)(results.getPeakSample_final())
207 -(results.getDelay_final()-results.getTau()));
208
209 ATH_MSG_DEBUG("Peak and time properly retrieved with OFPeakRecoTool: ADCPeak = "
210 << ADCPeak <<", time = "<< time);
211 } else {
212 ATH_MSG_DEBUG(". OFC iteration not valid for channel 0x"<< MSG::hex <<
213 id.get_compact() << MSG::dec << " Gain = " << gain <<
214 ". Skipping channel.");
215 continue;
216 }
217
218 //Apply Ramp
219 float E=adc2mev[0]+ADCPeak*adc2mev[1];
220
221 if (E>fMAXINT) E=fMAXINT;
222 if (E<fMAXINT2) E=fMAXINT2;
223
224 if (results.getConverged()) prov |= 0x0100;
225 prov = prov & 0x3FFF;
226
227 uint16_t iquaShort=0;
228 float tau=0;
229
230
231 //uint16_t prov=0xa5; //Means all constants from DB
232
233 const float E1=m_absECutFortQ.value() ? std::fabs(E) : E;
234 float ecut(0.);
235 if (m_useDBFortQ) {
236 if (run2DSPThresh) {
237 ecut = run2DSPThresh->tQThr(id);
238 }
239 else if (run1DSPThresh) {
240 ecut = run1DSPThresh->tQThr(id);
241 }
242 else {
243 ATH_MSG_ERROR ("DSP threshold problem");
244 return StatusCode::FAILURE;
245 }
246 }
247 else {
248 ecut = m_eCutFortQ;
249 }
250
251 if (E1 > ecut) { // fill also time and quality
252 ATH_MSG_VERBOSE("Channel " << m_onlineId->channel_name(id) << " gain " <<
253 gain << " above threshold for tQ computation");
254 prov|=0x2000; // fill bit in provenance that time+quality information are available
255
256 tau=time*(Gaudi::Units::nanosecond/Gaudi::Units::picosecond); //Convert time to ps
257 if (tau>fMAXINT) tau=fMAXINT;
258 if (tau<fMAXINT2) tau=fMAXINT2;
259
260 //Get Q-factor
261
262 int iqua = (int)(results.getQuality());
263 if (iqua > 0xFFFF) iqua=0xFFFF;
264 iquaShort = static_cast<uint16_t>(iqua & 0xFFFF);
265
266 }//end if above cut
267
268
269 outputContainer->emplace_back(id,static_cast<int>(std::floor(E+0.5)),
270 static_cast<int>(std::floor(tau+0.5)),
271 iquaShort,prov,(CaloGain::CaloGain)gain);
272 }
273
274 return StatusCode::SUCCESS;
275}
276
277LArOFIterResults LArRawChannelBuilderIterAlg::peak(const std::vector<float>& samples,
278 const HWIdentifier chID, const CaloGain::CaloGain gain, const float delayIn,
279 const ILArOFC* ofcs, const ILArShape* shapes, const unsigned nIter,
280 const unsigned npeak, unsigned peak_low, unsigned peak_high) const
281{
282 const float epsilon=0.001;
283 const double samplingPeriod=1./(40.08*Gaudi::Units::megahertz);
285
286 //Fill m_result with default/input values,
287 //calculation will be done with this object
288 result.m_valid=false;
289 result.m_converged=false;
290 result.m_amplitude= 0;
291 result.m_tau = 0;
292 result.m_quality = 0;
293 result.m_delay_final = delayIn;
294 result.m_peakSample_init = npeak;
295 result.m_peakSample_final = npeak; //Assumed index of highest sample (may change in the process)
296 result.m_chid = chID;
297
298 //Set some reference to improve readablity of the code:
299 unsigned& kMax = result.m_peakSample_final; //Make reference just to have code more readable
300 float& delay = result.m_delay_final;
301 float& q=result.m_quality;
302 unsigned& delayIdx=result.m_ofcIndex;
303 //Quantities used during iteration
304 unsigned kIter=0;
305 //Computation is done as double
306 double At=0;
307 double A=0;
308
309 //Tying to avoid doing all checks for every event/channel/iteation step by assuming that
310 //the number of OFC samples is the same for all delays of a certain cell/gain.
311 //Code will segfault if not the case.
312
313 const unsigned nSamples=samples.size();
314 // force uses of high gain if required for OFC and shape
315 CaloGain::CaloGain usedGain = gain;
316 if (m_forceHighGain) {
317 if (m_onlineId->isHECchannel(chID)) usedGain = CaloGain::LARMEDIUMGAIN;
318 else usedGain = CaloGain::LARHIGHGAIN;
319 }
320
321 // Quantities depending on this cell
322 const unsigned nOFCPhase=ofcs->nTimeBins(chID,usedGain);
323 float timeOffset = ofcs->timeOffset(chID,usedGain);
324
325 // convert delay to internal OFC delay (from 0 to Nphases*timeBinWidth)
326 delay = delay-timeOffset;
327
328 float timeBinWidth;
329 float timeMax;
330 if (nOFCPhase<2) { //Only one time bin
331 delayIdx=0;
332 timeBinWidth=25.; //ns
333 timeMax=(nOFCPhase-1)*timeBinWidth;
334 } else { //Have more than one OFC bin
335 timeBinWidth=ofcs->timeBinWidth(chID,usedGain);
336 timeMax = (nOFCPhase-1)*timeBinWidth;
337 if (timeBinWidth==0.) {
338 ATH_MSG_ERROR( "timeBinWidth is zero for channel " << m_onlineId->channel_name(chID) );
339 return result;
340 }
341 //Check if initial delay isn't too big
342 if (delay>timeMax) delay=timeMax-epsilon;
343 if (delay<0.) delay=0.;
344 //Index of the in in the vector according to the delay
345 delayIdx=(unsigned)floor(0.5+delay/timeBinWidth);
346 }
347
348 //Get first set of OFC's
349 ILArOFC::OFCRef_t this_OFC_a = ofcs->OFC_a(chID,(int)usedGain,delayIdx);
350 ILArOFC::OFCRef_t this_OFC_b = ofcs->OFC_b(chID,(int)usedGain,delayIdx);
351 const unsigned ofcSize=this_OFC_a.size(); //Assumed to be the same of all delay-indices
352
353 //some sanity check on the OFCs
354 if ( ofcSize == 0 || this_OFC_b.size() == 0 ) {
355 ATH_MSG_DEBUG("OFC not found for channel " << m_onlineId->channel_name(chID));
356 return result;
357 }
358
359 if ( this_OFC_a.size() != this_OFC_b.size() ) {
360 ATH_MSG_ERROR( "OFC a (" << this_OFC_a.size() <<
361 ")and b (" << this_OFC_b.size() << ") are not the same size for channel 0x"
362 << std::hex << chID.get_compact() << std::dec );
363 return result;
364 }
365
366 //Coerce kmax, peak_high and peak_low to someting that can work
367 if (peak_low<2) peak_low=2; //By convention we expect at least 2 samples before the peak
368 if (peak_high>(nSamples+2-ofcSize)) peak_high=(nSamples+2-ofcSize);
369 if (peak_high<peak_low) {
370 ATH_MSG_WARNING( "Channel 0x" << std::hex << chID.get_compact() << std::dec
371 << "Not enough ADC samples (" << nSamples << ") to apply " << ofcSize << " OFCs." );
372 return result;
373 }
374 if(kMax<peak_low) kMax=peak_low;
375 if(kMax>peak_high) kMax=peak_high;
376
377 float amplitude_save=0.;
378 float tau_save= 99999.;
379 unsigned int kMax_save=0;
380 float delay_save=0.;
381 unsigned int delayIdx_save=0;
382
383 unsigned int mynIter = nIter;
384
385 do {
386
387 // Uncomment the following if you suspect that the ofc are corrupt for some phases:
388 /*
389 if ( this_OFC_a.size() == 0 || this_OFC_b.size() == 0 ) {
390 ATH_MSG_DEBUG( "OFC not found for channel 0x" << std::hex << chID.get_compact() << std::dec );
391 std::cout << "OFC not found for channel 0x" << std::hex << chID.get_compact() << std::dec << std::endl;
392 return result;
393 }
394
395 if ( this_OFC_a.size() != this_OFC_b.size() ) {
396 ATH_MSG_ERROR( "OFC a (" << this_OFC_a.size() <<
397 ")and b (" << this_OFC_b.size() << ") are not the same size for channel 0x"
398 << std::hex << chID.get_compact() << std::dec );
399 return result;
400 }
401 */
402
403
404 //Apply Optimal Filtering coefficients
405 A = At = 0 ;
406 for ( unsigned k=0 ; (k<ofcSize); k++ ) {
407 //for ( unsigned k=0 ; (k<ofcSize) && (kMax-2+k<nSamples); k++ ) {
408 const float& this_sample = samples[kMax-2+k];
409 A += this_OFC_a.at(k) * this_sample ;
410 At += this_OFC_b.at(k) * this_sample ;
411 }
412 //Validate the result
413 result.m_valid = true; //Doesn't mean that the result is really good, but we have something
414 if ( A == 0 ) {
415 ATH_MSG_DEBUG("Null amplitude: " << A << " for channel" << m_onlineId->channel_name(chID));
416 result.m_amplitude=0;
417 result.m_tau=0;
418 return result;
419 }
420 result.m_amplitude=A;
421 result.m_tau = At / A ;
422
423 //First iteration done, break loop if possible....
424 if (mynIter<=1) {
425 delay = delayIdx*timeBinWidth;
426 break; //No iteration requested
427 }
428
429 // Nsamples=OFCsize and only one phase available, no point to iterate
430 if (samples.size() == ofcSize && nOFCPhase<2) {
431 delay = delayIdx*timeBinWidth;
432 break;
433 }
434
435 // if we are within +-0.5*Dt of time bin, we have converged for sure
436 if (std::fabs(result.m_tau) <= (0.5*timeBinWidth)) {
437 result.m_converged=true;
438 delay = delayIdx*timeBinWidth;
439 break;
440 }
441
442 if (kIter>=mynIter) { //Max. number of iterations reached
443 delay = delayIdx*timeBinWidth;
444 if (result.m_converged) {
445 if (std::fabs(tau_save) < std::fabs(result.m_tau)) {
446 result.m_amplitude = amplitude_save;
447 result.m_tau = tau_save;
448 kMax = kMax_save;
449 delay = delay_save;
450 delayIdx = delayIdx_save;
451 }
452 }
453 if (std::fabs(result.m_tau) <= timeBinWidth) result.m_converged=true;
454 break;
455 }
456
457 // if we are within +-Dt of time bin, we consider that we have converged but we allow for one more
458 // iteration to see if we can find a smaller tau, if not we keep the previous one
459 if (std::fabs(result.m_tau) <= timeBinWidth) {
460 result.m_converged = true;
461 mynIter = kIter+1; // allow only for more iteration
462 amplitude_save = result.m_amplitude;
463 tau_save = result.m_tau;
464 kMax_save = kMax;
465 delay_save = delayIdx*timeBinWidth;
466 delayIdx_save = delayIdx;
467 }
468
469 delay = delay - result.m_tau; // moved this line up so first iteration delay results treated like subsequent
470
471 if(delay<(-0.5*timeBinWidth)) {
472 if(kMax<peak_high){
473 kMax = kMax+1 ;
474 delay=delay+samplingPeriod;
475 if( delay < 0 ) delay = 0;
476 if (delay > timeMax ) delay = timeMax-epsilon;
477 } else { // don't shift sample
478 delay = 0 ;
479 }
480 }//else if delay<0
481 else
482 if( delay>(timeMax+0.5*timeBinWidth) ) {
483 if(kMax>peak_low){
484 kMax = kMax-1 ;
485 delay=delay-samplingPeriod;
486 if (delay < 0 ) delay=0.;
487 if( delay > timeMax ) delay = timeMax-epsilon;
488 } else {
489 // don't shift sample
490 delay = timeMax-epsilon;
491 }
492 }//end if delay>nOFCPhase
493 //Prepare next iteration step:
494 kIter++;
495 delayIdx=(unsigned)floor(0.5+delay/timeBinWidth);
496 if (delayIdx>=nOFCPhase) delayIdx = nOFCPhase-1;
497 //Get next set of OFC's
498 this_OFC_a = ofcs->OFC_a(chID,(int)usedGain,delayIdx);
499 this_OFC_b = ofcs->OFC_b(chID,(int)usedGain,delayIdx);
500 }
501 while(1); // end for iteration loop
502
503 // go back to overal time
504 delay = delay + timeOffset; // sign to check
505
506 q = 0.;
507 ILArShape::ShapeRef_t thisShape = shapes->Shape(chID,(int)usedGain,delayIdx) ;
508 ILArShape::ShapeRef_t thisShapeDer;
509 if (m_useShapeDer) thisShapeDer = shapes->ShapeDer(chID,(int)usedGain,delayIdx) ;
510 if( thisShape.size() >= ofcSize ) {
511 for ( unsigned k=0 ; k<ofcSize ; k++ ) {
512 const float& this_sample = samples[kMax-2+k];
513 if (m_useShapeDer && thisShapeDer.size() >= ofcSize)
514 q += std::pow((result.m_amplitude*(thisShape[k]-result.m_tau*thisShapeDer[k]) - this_sample),2);
515 else
516 q += std::pow((result.m_amplitude*thisShape[k] - this_sample),2);
517 }
518 }
519 else {
520 ATH_MSG_DEBUG("No shape for this channel");
521 }
522
523 result.m_nIterPerf = kIter;
524 result.m_valid = true;
525 return result;
526
527}
#define MAXINT
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define ATH_UNLIKELY(x)
double delay(std::size_t d)
const ServiceHandle< StoreGateSvc > & detStore() const
virtual OFCRef_t OFC_b(const HWIdentifier &id, int gain, int tbin=0) const =0
virtual unsigned nTimeBins(const HWIdentifier &CellID, int gain) const =0
virtual OFCRef_t OFC_a(const HWIdentifier &id, int gain, int tbin=0) const =0
access to OFCs by online ID, gain, and tbin (!=0 for testbeam)
virtual float timeBinWidth(const HWIdentifier &CellID, int gain) const =0
LArVectorProxy OFCRef_t
This class defines the interface for accessing Optimal Filtering coefficients for each channel provid...
Definition ILArOFC.h:26
virtual float timeOffset(const HWIdentifier &CellID, int gain) const =0
virtual float pedestal(const HWIdentifier &id, int gain) const =0
virtual float pedestalRMS(const HWIdentifier &id, int gain) const =0
access to RMS of Pedestal index by Identifier, and gain setting
LArVectorProxy ShapeRef_t
This class defines the interface for accessing Shape (Nsample variable, Dt = 25 ns fixed) @stereotype...
Definition ILArShape.h:26
virtual ShapeRef_t Shape(const HWIdentifier &id, int gain, int tbin=0, int mode=0) const =0
virtual ShapeRef_t ShapeDer(const HWIdentifier &id, int gain, int tbin=0, int mode=0) const =0
value_type get_compact() const
Get the compact id.
const LArVectorProxy ADC2MEV(const HWIdentifier &id, int gain) const
Definition LArADC2MeV.h:32
float tQThr(const HWIdentifier chid) const
Liquid Argon digit base class.
Definition LArDigit.h:25
Gaudi::Property< unsigned short > m_minSample
Gaudi::Property< unsigned short > m_AdcMax
StatusCode execute(const EventContext &ctx) const override
SG::WriteHandleKey< LArRawChannelContainer > m_rawChannelKey
SG::ReadCondHandleKey< ILArPedestal > m_pedestalKey
Gaudi::Property< int > m_defaultShiftTimeSamples
Gaudi::Property< unsigned short > m_nIterProp
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
LArOFIterResults peak(const std::vector< float > &samples, const HWIdentifier chID, const CaloGain::CaloGain gain, const float delayIn, const ILArOFC *ofcs, const ILArShape *shapes, const unsigned nIter=0, const unsigned npeak=2, unsigned peak_low=2, unsigned peak_high=2) const
SG::ReadCondHandleKey< ILArShape > m_shapeKey
SG::ReadCondHandleKey< LArADC2MeV > m_adc2MeVKey
Gaudi::Property< bool > m_skipSaturatedCells
SG::ReadHandleKey< LArDigitContainer > m_digitKey
Gaudi::Property< unsigned short > m_minADCforIter
SG::WriteHandleKey< LArOFIterResultsContainer > m_timingContKey
Gaudi::Property< float > m_defaultPhase
SG::ReadCondHandleKey< ILArOFC > m_ofcKey
Gaudi::Property< unsigned short > m_maxSample
SG::ReadCondHandleKey< LArDSPThresholdsComplete > m_run1DSPThresholdsKey
Gaudi::Property< float > m_minADCforIterInSigma
SG::ReadCondHandleKey< AthenaAttributeList > m_run2DSPThresholdsKey
value_type at(size_t i) const
Vector indexing with bounds check.
const_pointer_type cptr()
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
@ LARMEDIUMGAIN
Definition CaloGain.h:18
@ LARHIGHGAIN
Definition CaloGain.h:18
hold the test vectors and ease the comparison