ATLAS Offline Software
Loading...
Searching...
No Matches
LArOFPeakRecoTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "CLHEP/Matrix/Matrix.h"
7#include "CLHEP/Matrix/Vector.h"
8#include "GaudiKernel/SystemOfUnits.h"
11#include <algorithm>
12#include <cmath>
13
14
15//Changes that affect the result:
16//set the nphases, stepwith, etc..
17//set fabs(tau) <= timeBinWidth
18
20
21LArOFPeakRecoTool::LArOFPeakRecoTool(const std::string& type, const std::string& name,
22 const IInterface* parent) :
23 AthAlgTool(type, name, parent)
24 //m_nSamples(0xFFFFFFFF) //shall compare false to any possible number of samples
25{
26 declareProperty("Iterate",m_iterate=false) ;
27 declareProperty("UseShape",m_useShape=false,"Use the LArShape to compute quality factor");
28 declareProperty("UseShapeDer",m_useShapeDer=true,"Use the shape derivative in the quality factor computation");
29 declareProperty("isSuperCell",m_isSC=false,"switch to use SuperCells");
30// DelayShift = different with delay run in 25/24 ns units
31// 23 is the ad-hoc value for run 5640-5641
32 declareProperty("DelayShift",m_delayShift=23);
33 declareProperty("SamplingPeriod",m_samplingPeriod=1./(40.08*Gaudi::Units::megahertz));
34 declareProperty("forceHighGain",m_forceHighGain=false,"Force use of high gain for all shapes and OFC (default=false)");
35 declareInterface<LArOFPeakRecoTool>(this);
36}
37
39
42
44 ATH_MSG_DEBUG("initializing LArOFPeakRecoTool...");
45
46 ATH_CHECK( m_keyOFC.initialize() );
47
48 ATH_CHECK( m_keyShape.initialize(m_useShape) );
49 if (!m_useShape) {
50 ATH_MSG_WARNING( "jobOption 'UseShape' set to false. Will work without shape" );
51 }
52
53 if(!m_isSC) {
54 const LArOnlineID* laron;
55 StatusCode sc = detStore()->retrieve(laron,"LArOnlineID");
56 if (sc.isFailure()) {
57 ATH_MSG_ERROR("Unable to retrieve LArOnlineID from DetectorStore");
58 return StatusCode::FAILURE;
59 } else m_lar_on_id = static_cast<const LArOnlineID_Base*> (laron);
60 } else {
61 const LArOnline_SuperCellID* laron;
62 StatusCode sc = detStore()->retrieve(laron,"LArOnline_SuperCellID");
63 if (sc.isFailure()) {
64 ATH_MSG_ERROR("Unable to retrieve LArOnlineID from DetectorStore");
65 return StatusCode::FAILURE;
66 } else m_lar_on_id =static_cast<const LArOnlineID_Base*> (laron);
67 }
68 return StatusCode::SUCCESS;
69}
70
71
73
74LArOFIterResults LArOFPeakRecoTool::peak(const std::vector<short>& samples, HWIdentifier chID,
75 CaloGain::CaloGain gain, int delay) const {
76
77 std::vector<float> newsamples;
78 for(unsigned int i=0;i<samples.size();i++)
79 {
80 newsamples.push_back((float)samples[i]);
81 }
82 return peak(newsamples,chID,gain,delay);
83
84}
85
86
88LArOFIterResults LArOFPeakRecoTool::peak(const std::vector<float>& samples, // raw data after pedestal subtraction
89 const HWIdentifier chID, // online channel id
90 const CaloGain::CaloGain gain, // gain
91 const float delayIn, // initial delay for Shape and OFC
92 const unsigned nIter, // number of iteration
93 const unsigned npeak, // initial peak position.
94 unsigned peak_low, // lower limit for peak position
95 unsigned peak_high // upper limit for peak position
96 ) const{
97
98 const float epsilon=0.001;
100
101 //Fill m_result with default/input values,
102 //calculation will be done with this object
103 result.m_valid=false;
104 result.m_converged=false;
105 result.m_amplitude= 0;
106 result.m_tau = 0;
107 result.m_quality = 0;
108 result.m_delay_final = delayIn;
109 result.m_peakSample_init = npeak;
110 result.m_peakSample_final = npeak; //Assumed index of highest sample (may change in the process)
111 result.m_chid = chID;
112 //Set some reference to improve readablity of the code:
113 unsigned& kMax = result.m_peakSample_final; //Make reference just to have code more readable
114 float& delay = result.m_delay_final;
115 float& q=result.m_quality;
116 unsigned& delayIdx=result.m_ofcIndex;
117 //Quantities used during iteration
118 unsigned kIter=0;
119 //Computation is done as double
120 double At=0;
121 double A=0;
122
123 //Tying to avoid doing all checks for every event/channel/iteation step by assuming that
124 //the number of OFC samples is the same for all delays of a certain cell/gain.
125 //Code will segfault if not the case.
126
127 const unsigned nSamples=samples.size();
128 //if (samples.size()<5){
129 // msg() << MSG::WARNING << "Not enough ADC samples (" << nSamples << ") found for channel 0x"
130 // << std::hex << chID.get_compact() << std::dec << endmsg;
131 // return result;
132 // }
133
134 // force uses of high gain if required for OFC and shape
135 CaloGain::CaloGain usedGain = gain;
136 if (m_forceHighGain) {
137 if (m_lar_on_id->isHECchannel(chID)) usedGain = CaloGain::LARMEDIUMGAIN;
138 else usedGain = CaloGain::LARHIGHGAIN;
139 }
140
141 const ILArOFC* dd_ofc=nullptr;
142 StatusCode sc=detStore()->retrieve(dd_ofc);
143 if (sc.isFailure()){
144 ATH_MSG_ERROR("Failed to retrieve LArOFC object " );
145 return result;
146 }
147
148 // Quantities depending on this cell
149 const unsigned nOFCPhase=dd_ofc->nTimeBins(chID,usedGain);
150 float timeOffset = dd_ofc->timeOffset(chID,usedGain);
151
152 // convert delay to internal OFC delay (from 0 to Nphases*timeBinWidth)
153 delay = delay-timeOffset;
154
155 float timeBinWidth;
156 float timeMax;
157 if (nOFCPhase<2) { //Only one time bin
158 delayIdx=0;
159 timeBinWidth=25.; //ns
160 timeMax=(nOFCPhase-1)*timeBinWidth;
161 } else { //Have more than one OFC bin
162 timeBinWidth=dd_ofc->timeBinWidth(chID,usedGain);
163 timeMax = (nOFCPhase-1)*timeBinWidth;
164 if (timeBinWidth==0.) {
165 ATH_MSG_ERROR( "timeBinWidth is zero for channel " << m_lar_on_id->channel_name(chID) );
166 return result;
167 }
168 //Check if initial delay isn't too big
169 if (delay>timeMax) delay=timeMax-epsilon;
170 if (delay<0.) delay=0.;
171 //Index of the in in the vector according to the delay
172 delayIdx=(unsigned)std::floor(0.5+delay/timeBinWidth);
173 }
174
175 //Get first set of OFC's
176 ILArOFC::OFCRef_t this_OFC_a = dd_ofc->OFC_a(chID,(int)usedGain,delayIdx);
177 ILArOFC::OFCRef_t this_OFC_b = dd_ofc->OFC_b(chID,(int)usedGain,delayIdx);
178 const unsigned ofcSize=this_OFC_a.size(); //Assumed to be the same of all delay-indices
179
180 //some sanity check on the OFCs
181 if ( ofcSize == 0 || this_OFC_b.size() == 0 ) {
182 ATH_MSG_DEBUG("OFC not found for channel " << m_lar_on_id->channel_name(chID) << ", gain=" << usedGain << ", delayIdx=" << delayIdx);
183 return result;
184 }
185
186 if ( this_OFC_a.size() != this_OFC_b.size() ) {
187 ATH_MSG_ERROR( "OFC a (" << this_OFC_a.size() <<
188 ")and b (" << this_OFC_b.size() << ") are not the same size for channel 0x"
189 << std::hex << chID.get_compact() << std::dec );
190 return result;
191 }
192
193 //Coerce kmax, peak_high and peak_low to someting that can work
194 if (peak_low<2) peak_low=2; //By convention we expect at least 2 samples before the peak
195 if (peak_high>(nSamples+2-ofcSize)) peak_high=(nSamples+2-ofcSize);
196 if (peak_high<peak_low) {
197 ATH_MSG_WARNING( "Channel 0x" << std::hex << chID.get_compact() << std::dec
198 << "Not enough ADC samples (" << nSamples << ") to apply " << ofcSize << " OFCs." );
199 return result;
200 }
201 if(kMax<peak_low) kMax=peak_low;
202 if(kMax>peak_high) kMax=peak_high;
203
204 float amplitude_save=0.;
205 float tau_save= 99999.;
206 unsigned int kMax_save=0;
207 float delay_save=0.;
208 unsigned int delayIdx_save=0;
209
210 unsigned int mynIter = nIter;
211
212 do {
213
214 // Uncomment the following if you suspect that the ofc are corrupt for some phases:
215 /*
216 if ( this_OFC_a.size() == 0 || this_OFC_b.size() == 0 ) {
217 ATH_MSG_DEBUG( "OFC not found for channel 0x" << std::hex << chID.get_compact() << std::dec );
218 std::cout << "OFC not found for channel 0x" << std::hex << chID.get_compact() << std::dec << std::endl;
219 return result;
220 }
221
222 if ( this_OFC_a.size() != this_OFC_b.size() ) {
223 ATH_MSG_ERROR( "OFC a (" << this_OFC_a.size() <<
224 ")and b (" << this_OFC_b.size() << ") are not the same size for channel 0x"
225 << std::hex << chID.get_compact() << std::dec );
226 return result;
227 }
228 */
229
230
231 //Apply Optimal Filtering coefficients
232 A = At = 0 ;
233 for ( unsigned k=0 ; (k<ofcSize); k++ ) {
234 //for ( unsigned k=0 ; (k<ofcSize) && (kMax-2+k<nSamples); k++ ) {
235 const float& this_sample = samples[kMax-2+k];
236 A += this_OFC_a.at(k) * this_sample ;
237 At += this_OFC_b.at(k) * this_sample ;
238 }
239 //Validate the result
240 result.m_valid = true; //Doesn't mean that the result is really good, but we have something
241 if ( A == 0 ) {
242 ATH_MSG_DEBUG("Null amplitude: " << A << " for channel" << m_lar_on_id->channel_name(chID));
243 result.m_amplitude=0;
244 result.m_tau=0;
245 return result;
246 }
247 result.m_amplitude=A;
248 result.m_tau = At / A ;
249
250 //First iteration done, break loop if possible....
251 if (mynIter<=1) {
252 delay = delayIdx*timeBinWidth;
253 break; //No iteration requested
254 }
255
256 // Nsamples=OFCsize and only one phase available, no point to iterate
257 if (samples.size() == ofcSize && nOFCPhase<2) {
258 delay = delayIdx*timeBinWidth;
259 break;
260 }
261
262 // if we are within +-0.5*Dt of time bin, we have converged for sure
263 if (std::abs(result.m_tau) <= (0.5*timeBinWidth)) {
264 result.m_converged=true;
265 delay = delayIdx*timeBinWidth;
266 break;
267 }
268
269 if (kIter>=mynIter) { //Max. number of iterations reached
270 delay = delayIdx*timeBinWidth;
271 if (result.m_converged) {
272 if (std::abs(tau_save) < std::abs(result.m_tau)) {
273 result.m_amplitude = amplitude_save;
274 result.m_tau = tau_save;
275 kMax = kMax_save;
276 delay = delay_save;
277 delayIdx = delayIdx_save;
278 }
279 }
280 if (std::abs(result.m_tau) <= timeBinWidth) result.m_converged=true;
281 break;
282 }
283
284 // if we are within +-Dt of time bin, we consider that we have converged but we allow for one more
285 // iteration to see if we can find a smaller tau, if not we keep the previous one
286 if (std::abs(result.m_tau) <= timeBinWidth) {
287 result.m_converged = true;
288 mynIter = kIter+1; // allow only for more iteration
289 amplitude_save = result.m_amplitude;
290 tau_save = result.m_tau;
291 kMax_save = kMax;
292 delay_save = delayIdx*timeBinWidth;
293 delayIdx_save = delayIdx;
294 }
295
296 delay = delay - result.m_tau; // moved this line up so first iteration delay results treated like subsequent
297
298 if(delay<(-0.5*timeBinWidth)) {
299 if(kMax<peak_high){
300 kMax = kMax+1 ;
302 if( delay < 0 ) delay = 0;
303 if (delay > timeMax ) delay = timeMax-epsilon;
304 } else { // don't shift sample
305 delay = 0 ;
306 }
307 }//else if delay<0
308 else
309 if( delay>(timeMax+0.5*timeBinWidth) ) {
310 if(kMax>peak_low){
311 kMax = kMax-1 ;
313 if (delay < 0 ) delay=0.;
314 if( delay > timeMax ) delay = timeMax-epsilon;
315 } else {
316 // don't shift sample
317 delay = timeMax-epsilon;
318 }
319 }//end if delay>nOFCPhase
320 //Prepare next iteration step:
321 kIter++;
322 delayIdx=(unsigned)floor(0.5+delay/timeBinWidth);
323 if (delayIdx>=nOFCPhase) delayIdx = nOFCPhase-1;
324 //Get next set of OFC's
325 this_OFC_a = dd_ofc->OFC_a(chID,(int)usedGain,delayIdx);
326 this_OFC_b = dd_ofc->OFC_b(chID,(int)usedGain,delayIdx);
327 }
328 while(1); // end for iteration loop
329
330 // go back to overal time
331 delay = delay + timeOffset; // sign to check
332
333 // get shape
334 if (m_useShape){
335 const ILArShape* dd_shape=nullptr;
336 StatusCode sc=detStore()->retrieve(dd_shape);
337 if (sc.isFailure()){
338 ATH_MSG_ERROR("Failed to retrieve LArShape object with " );
339 return result;
340 }
341 q = 0.;
342 ILArShape::ShapeRef_t thisShape = dd_shape->Shape(chID,(int)usedGain,delayIdx) ;
343 ILArShape::ShapeRef_t thisShapeDer;
344 if (m_useShapeDer) thisShapeDer = dd_shape->ShapeDer(chID,(int)usedGain,delayIdx) ;
345 if( thisShape.size() >= ofcSize ) {
346 for ( unsigned k=0 ; k<ofcSize ; k++ ) {
347 const float& this_sample = samples[kMax-2+k];
348 if (m_useShapeDer && thisShapeDer.size() >= ofcSize)
349 q += std::pow((result.m_amplitude*(thisShape[k]-result.m_tau*thisShapeDer[k]) - this_sample),2);
350 else
351 q += std::pow((result.m_amplitude*thisShape[k] - this_sample),2);
352 }
353 }
354 else {
355 ATH_MSG_DEBUG("No shape for this channel");
356 }
357 }
358
359 result.m_nIterPerf = kIter;
360 result.m_valid = true;
361 return result;
362}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
double delay(std::size_t d)
static Double_t sc
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
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
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 LArOnlineID_Base * m_lar_on_id
SG::ReadCondHandleKey< ILArOFC > m_keyOFC
LArOFIterResults peak(const std::vector< short > &samples, HWIdentifier chID, CaloGain::CaloGain gain, int delay) const
SG::ReadCondHandleKey< ILArShape > m_keyShape
LArOFPeakRecoTool(const std::string &type, const std::string &name, const IInterface *parent)
virtual StatusCode initialize()
Helper for the Liquid Argon Calorimeter cell identifiers.
value_type at(size_t i) const
Vector indexing with bounds check.
@ LARMEDIUMGAIN
Definition CaloGain.h:18
@ LARHIGHGAIN
Definition CaloGain.h:18
hold the test vectors and ease the comparison