ATLAS Offline Software
LArOFPeakRecoTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 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 
21 LArOFPeakRecoTool::LArOFPeakRecoTool(const std::string& type, const std::string& name,
22  const IInterface* 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 
41 }
42 
44  ATH_MSG_DEBUG("initializing LArOFPeakRecoTool...");
45 
47 
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 = (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 = (LArOnlineID_Base*) laron;
67  }
68  return StatusCode::SUCCESS;
69 }
70 
71 
73 
74 LArOFIterResults 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 
88 LArOFIterResults 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)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 }
LArOFPeakRecoTool::LArOFPeakRecoTool
LArOFPeakRecoTool(const std::string &type, const std::string &name, const IInterface *parent)
Definition: LArOFPeakRecoTool.cxx:21
LArOFPeakRecoTool::m_keyShape
SG::ReadCondHandleKey< ILArShape > m_keyShape
Definition: LArOFPeakRecoTool.h:69
LArOFPeakRecoTool::~LArOFPeakRecoTool
virtual ~LArOFPeakRecoTool()
Definition: LArOFPeakRecoTool.cxx:40
get_generator_info.result
result
Definition: get_generator_info.py:21
LArOFPeakRecoTool::m_useShape
bool m_useShape
Definition: LArOFPeakRecoTool.h:70
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
LArOFPeakRecoTool::peak
LArOFIterResults peak(const std::vector< short > &samples, HWIdentifier chID, CaloGain::CaloGain gain, int delay) const
Definition: LArOFPeakRecoTool.cxx:74
LArOFPeakRecoTool.h
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
CaloCondBlobAlgs_fillNoiseFromASCII.gain
gain
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:110
ILArOFC::OFC_b
virtual OFCRef_t OFC_b(const HWIdentifier &id, int gain, int tbin=0) const =0
ILArShape::ShapeDer
virtual ShapeRef_t ShapeDer(const HWIdentifier &id, int gain, int tbin=0, int mode=0) const =0
LArOFPeakRecoTool::m_samplingPeriod
float m_samplingPeriod
Definition: LArOFPeakRecoTool.h:73
Identifier::get_compact
value_type get_compact() const
Get the compact id.
HWIdentifier
Definition: HWIdentifier.h:13
LArOFPeakRecoTool::m_useShapeDer
bool m_useShapeDer
Definition: LArOFPeakRecoTool.h:71
xAOD::unsigned
unsigned
Definition: RingSetConf_v1.cxx:662
AthenaPoolTestRead.sc
sc
Definition: AthenaPoolTestRead.py:27
AthCommonDataStore< AthCommonMsg< AlgTool > >::detStore
const ServiceHandle< StoreGateSvc > & detStore() const
The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:95
dqt_zlumi_alleff_HIST.A
A
Definition: dqt_zlumi_alleff_HIST.py:110
python.SystemOfUnits.megahertz
int megahertz
Definition: SystemOfUnits.py:127
ILArOFC::timeOffset
virtual float timeOffset(const HWIdentifier &CellID, int gain) const =0
A
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
LArVectorProxy::at
value_type at(size_t i) const
Vector indexing with bounds check.
lumiFormat.i
int i
Definition: lumiFormat.py:85
LArOnlineID_Base::isHECchannel
virtual bool isHECchannel(const HWIdentifier id) const =0
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
ILArOFC::timeBinWidth
virtual float timeBinWidth(const HWIdentifier &CellID, int gain) const =0
test_pyathena.parent
parent
Definition: test_pyathena.py:15
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
LArOFPeakRecoTool::m_lar_on_id
const LArOnlineID_Base * m_lar_on_id
Definition: LArOFPeakRecoTool.h:76
delay
double delay(std::size_t d)
Definition: JetTrigTimerTest.cxx:14
ILArOFC
Definition: ILArOFC.h:14
LArOnlineID_Base
Helper for the Liquid Argon Calorimeter cell identifiers.
Definition: LArOnlineID_Base.h:105
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
SG::CondHandleKey::initialize
StatusCode initialize(bool used=true)
LArOnlineID
Definition: LArOnlineID.h:20
CaloGain::LARHIGHGAIN
@ LARHIGHGAIN
Definition: CaloGain.h:18
LArOnline_SuperCellID
Definition: LArOnline_SuperCellID.h:20
CaloGain::CaloGain
CaloGain
Definition: CaloGain.h:11
CaloGain::LARMEDIUMGAIN
@ LARMEDIUMGAIN
Definition: CaloGain.h:18
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
LArOFPeakRecoTool::m_isSC
bool m_isSC
Definition: LArOFPeakRecoTool.h:75
ILArOFC::OFC_a
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)
ILArOFC::nTimeBins
virtual unsigned nTimeBins(const HWIdentifier &CellID, int gain) const =0
extractSporadic.q
list q
Definition: extractSporadic.py:98
LArOnline_SuperCellID.h
LArDigits2NtupleDumper.nSamples
nSamples
Definition: LArDigits2NtupleDumper.py:70
LArOFPeakRecoTool::m_forceHighGain
bool m_forceHighGain
Definition: LArOFPeakRecoTool.h:74
LArOFPeakRecoTool::initialize
virtual StatusCode initialize()
Definition: LArOFPeakRecoTool.cxx:43
LArOFPeakRecoTool::m_delayShift
int m_delayShift
Definition: LArOFPeakRecoTool.h:72
AthAlgTool
Definition: AthAlgTool.h:26
LArOnlineID_Base::channel_name
std::string channel_name(const HWIdentifier id) const
Return a string corresponding to a feedthrough name given an identifier.
Definition: LArOnlineID_Base.cxx:219
ILArShape
Definition: ILArShape.h:13
LArOFPeakRecoTool::m_iterate
bool m_iterate
Definition: LArOFPeakRecoTool.h:67
fitman.k
k
Definition: fitman.py:528
LArOnlineID.h
LArVectorProxy
Proxy for accessing a range of float values like a vector.
Definition: LArVectorProxy.h:38
LArOFIterResults
Definition: LArOFIterResults.h:15
ILArShape::Shape
virtual ShapeRef_t Shape(const HWIdentifier &id, int gain, int tbin=0, int mode=0) const =0
LArOFPeakRecoTool::m_keyOFC
SG::ReadCondHandleKey< ILArOFC > m_keyOFC
Definition: LArOFPeakRecoTool.h:68