ATLAS Offline Software
Loading...
Searching...
No Matches
LArRawChannelBuilderAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "GaudiKernel/SystemOfUnits.h"
12#include <cmath>
13#include <memory>
14
15
17 ATH_CHECK(m_digitKey.initialize());
18 ATH_CHECK(m_rawChannelKey.initialize());
19 ATH_CHECK(m_pedestalKey.initialize());
20 ATH_CHECK(m_adc2MeVKey.initialize());
21 ATH_CHECK(m_ofcKey.initialize());
22 ATH_CHECK(m_shapeKey.initialize());
23 ATH_CHECK(m_cablingKey.initialize() );
26 if (m_useDBFortQ) {
27 if (m_run1DSPThresholdsKey.empty() && m_run2DSPThresholdsKey.empty()) {
28 ATH_MSG_ERROR ("useDB requested but neither Run1DSPThresholdsKey nor Run2DSPThresholdsKey initialized.");
29 return StatusCode::FAILURE;
30 }
31 }
32
33
34 ATH_CHECK(detStore()->retrieve(m_onlineId,"LArOnlineID"));
35
36
37 const std::string cutmsg = m_absECutFortQ.value() ? " fabs(E) < " : " E < ";
38 ATH_MSG_INFO("Energy cut for time and quality computation: " << cutmsg <<
39 " taken from COOL folder "<<
40 m_run1DSPThresholdsKey.key() << " (run1) " <<
41 m_run2DSPThresholdsKey.key() << " (run2) ");
42 return StatusCode::SUCCESS;
43}
44
46 return StatusCode::SUCCESS;
47}
48
49StatusCode LArRawChannelBuilderAlg::execute(const EventContext& ctx) const {
50
51 //Get event inputs from read handles:
53
54 //Write output via write handle
55 auto outputContainer = std::make_unique<LArRawChannelContainer>();
56
57 //Get Conditions input
59 const ILArPedestal* peds=*pedHdl;
60
62 const LArADC2MeV* adc2MeVs=*adc2mevHdl;
63
65 const ILArOFC* ofcs=*ofcHdl;
66
68 const ILArShape* shapes=*shapeHdl;
69
71
72 std::unique_ptr<LArDSPThresholdsFlat> run2DSPThresh;
73 const LArDSPThresholdsComplete* run1DSPThresh = nullptr;
74 if (m_useDBFortQ) {
75 if (!m_run2DSPThresholdsKey.empty()) {
77 run2DSPThresh = std::make_unique<LArDSPThresholdsFlat>(*dspThrshAttr);
78 if (ATH_UNLIKELY(!run2DSPThresh->good())) {
79 ATH_MSG_ERROR( "Failed to initialize LArDSPThresholdFlat from attribute list loaded from " << m_run2DSPThresholdsKey.key()
80 << ". Aborting." );
81 return StatusCode::FAILURE;
82 }
83 }
84 else if (!m_run1DSPThresholdsKey.empty()) {
86 run1DSPThresh = dspThresh.cptr();
87 }
88 else {
89 ATH_MSG_ERROR( "No DSP threshold configured.");
90 return StatusCode::FAILURE;
91 }
92 }
93
94 //Loop over digits:
95 for (const LArDigit* digit : *inputContainer) {
96
97 size_t firstSample=m_firstSample;
98
99 const HWIdentifier id=digit->hardwareID();
100 const bool connected=(*cabling)->isOnlineConnected(id);
101
102
103 ATH_MSG_VERBOSE("Working on channel " << m_onlineId->channel_name(id));
104
105 const std::vector<short>& samples=digit->samples();
106 const int gain=digit->gain();
107 const float p=peds->pedestal(id,gain);
108
109
110
111 //The following autos will resolve either into vectors or vector-proxies
112 const auto& ofca=ofcs->OFC_a(id,gain);
113 const auto& adc2mev=adc2MeVs->ADC2MEV(id,gain);
114
115 const size_t nOFC=ofca.size();
116
117 //Sanity check on input conditions data:
118 // ensure that the size of the samples vector is compatible with ofc_a size when preceeding samples are saved
119 const size_t nSamples=samples.size()-firstSample;
120 if (nSamples<nOFC) {
121 ATH_MSG_ERROR("effective sample size: "<< nSamples << ", must be >= OFC_a size: " << ofca.size());
122 return StatusCode::FAILURE;
123 }
124
125
127 if (!connected) continue; //No conditions for disconencted channel, who cares?
128 ATH_MSG_ERROR("No valid pedestal for connected channel " << m_onlineId->channel_name(id)
129 << " gain " << gain);
130 return StatusCode::FAILURE;
131 }
132
133 if(ATH_UNLIKELY(adc2mev.size()<2)) {
134 if (!connected) continue; //No conditions for disconencted channel, who cares?
135 ATH_MSG_ERROR("No valid ADC2MeV for connected channel " << m_onlineId->channel_name(id)
136 << " gain " << gain);
137 return StatusCode::FAILURE;
138 }
139
140
141 //Apply OFCs to get amplitude
142 // Evaluate sums in double-precision to get consistent results
143 // across platforms.
144 double A=0;
145 bool saturated=false;
146
147 // Check saturation AND discount pedestal
148 std::vector<float> samp_no_ped(nOFC,0.0);
149 for (size_t i=0;i<nOFC;++i) {
150 if (samples[i+firstSample]==4096 || samples[i+firstSample]==0) saturated=true;
151 samp_no_ped[i]=samples[i+firstSample]-p;
152 }
153 for (size_t i=0;i<nOFC;++i) {
154 A+=static_cast<double>(samp_no_ped[i])*ofca[i];
155 }
156
157 //Apply Ramp
158 const float E=adc2mev[0]+A*adc2mev[1];
159
160 uint16_t iquaShort=0;
161 float tau=0;
162
163
164 uint16_t prov=LArProv::DEFAULTRECO; //Means all constants from DB + OFC
165 if (saturated) prov|=LArProv::SATURATED;
166
167 const float E1=m_absECutFortQ.value() ? std::fabs(E) : E;
168 float ecut(0.);
169 if (m_useDBFortQ) {
170 if (run2DSPThresh) {
171 ecut = run2DSPThresh->tQThr(id);
172 }
173 else if (run1DSPThresh) {
174 ecut = run1DSPThresh->tQThr(id);
175 }
176 else {
177 ATH_MSG_ERROR ("DSP threshold problem");
178 return StatusCode::FAILURE;
179 }
180 }
181 else {
182 ecut = m_eCutFortQ;
183 }
184 if (E1 > ecut) {
185 ATH_MSG_VERBOSE("Channel " << m_onlineId->channel_name(id) << " gain " << gain << " above threshold for tQ computation");
186 prov|=LArProv::QTPRESENT; // fill bit in provenance that time+quality information are available
187
188 //Get time by applying OFC-b coefficients:
189 const auto& ofcb=ofcs->OFC_b(id,gain);
190 double At=0;
191 for (size_t i=0;i<nOFC;++i) {
192 At+=static_cast<double>(samp_no_ped[i])*ofcb[i];
193 }
194 //Divide A*t/A to get time
195 tau=(std::fabs(A)>0.1) ? At/A : 0.0;
196 const auto& fullShape=shapes->Shape(id,gain);
197
198 //Get Q-factor
199 //fixing HEC to move +1 in case of 4 samples and firstSample 0 (copied from old LArRawChannelBuilder)
200 const size_t nSamples=samples.size();
201 if (fullShape.size()>nSamples && nSamples==4 && m_firstSample==0) {
202 if (m_onlineId->isHECchannel(id)) {
203 firstSample=1;
204 }
205 }
206
207 if (ATH_UNLIKELY(fullShape.size()<nOFC+firstSample)) {
208 if (!connected) continue; //No conditions for disconnected channel, who cares?
209 ATH_MSG_ERROR("No valid shape for channel " << m_onlineId->channel_name(id)
210 << " gain " << gain);
211 ATH_MSG_ERROR("Got size " << fullShape.size() << ", expected at least " << nSamples+firstSample);
212 return StatusCode::FAILURE;
213 }
214
215 const float* shape=&*fullShape.begin()+firstSample;
216
217 double q=0;
218 if (m_useShapeDer) {
219 const auto& fullshapeDer=shapes->ShapeDer(id,gain);
220 if (ATH_UNLIKELY(fullshapeDer.size()<nOFC+firstSample)) {
221 ATH_MSG_ERROR("No valid shape derivative for channel " << m_onlineId->channel_name(id)
222 << " gain " << gain);
223 ATH_MSG_ERROR("Got size " << fullshapeDer.size() << ", expected at least " << nOFC+firstSample);
224 return StatusCode::FAILURE;
225 }
226
227 const float* shapeDer=&*fullshapeDer.begin()+firstSample;
228 for (size_t i=0;i<nOFC;++i) {
229 q += std::pow((A*(shape[i]-tau*shapeDer[i])-(samp_no_ped[i])),2);
230 }
231 }//end if useShapeDer
232 else {
233 //Q-factor w/o shape derivative
234 for (size_t i=0;i<nOFC;++i) {
235 q += std::pow((A*shape[i]-(samp_no_ped[i])),2);
236 }
237 }
238
239 int iqua = static_cast<int>(q);
240 if (iqua > 0xFFFF) iqua=0xFFFF;
241 iquaShort = static_cast<uint16_t>(iqua & 0xFFFF);
242
243 tau-=ofcs->timeOffset(id,gain);
244 tau*=(Gaudi::Units::nanosecond/Gaudi::Units::picosecond); //Convert time to ps
245 }//end if above cut
246
247 outputContainer->emplace_back(id,static_cast<int>(std::floor(E+0.5)),
248 static_cast<int>(std::floor(tau+0.5)),
249 iquaShort,prov,(CaloGain::CaloGain)gain);
250 }
251
252
254 ATH_CHECK(outputHandle.record(std::move(outputContainer) ) );
255
256 return StatusCode::SUCCESS;
257}
258
259
#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_UNLIKELY(x)
const ServiceHandle< StoreGateSvc > & detStore() const
virtual OFCRef_t OFC_b(const HWIdentifier &id, int gain, int tbin=0) 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 timeOffset(const HWIdentifier &CellID, int gain) const =0
virtual float pedestal(const HWIdentifier &id, int gain) const =0
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
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< int > m_firstSample
SG::ReadCondHandleKey< ILArPedestal > m_pedestalKey
SG::ReadHandleKey< LArDigitContainer > m_digitKey
Gaudi::Property< bool > m_useShapeDer
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
SG::ReadCondHandleKey< AthenaAttributeList > m_run2DSPThresholdsKey
SG::ReadCondHandleKey< LArDSPThresholdsComplete > m_run1DSPThresholdsKey
StatusCode execute(const EventContext &ctx) const override
SG::WriteHandleKey< LArRawChannelContainer > m_rawChannelKey
Gaudi::Property< bool > m_useDBFortQ
Gaudi::Property< bool > m_absECutFortQ
SG::ReadCondHandleKey< LArADC2MeV > m_adc2MeVKey
SG::ReadCondHandleKey< ILArShape > m_shapeKey
SG::ReadCondHandleKey< ILArOFC > m_ofcKey
Gaudi::Property< float > m_eCutFortQ
const_pointer_type cptr()
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
hold the test vectors and ease the comparison