CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
EcalUncalibRecHitRatioMethodAlgo.h
Go to the documentation of this file.
1 #ifndef RecoLocalCalo_EcalRecAlgos_EcalUncalibRecHitRatioMethodAlgo_HH
2 #define RecoLocalCalo_EcalRecAlgos_EcalUncalibRecHitRatioMethodAlgo_HH
3 
14 #include "Math/SVector.h"
15 #include "Math/SMatrix.h"
18 #include <vector>
19 
20 template < class C > class EcalUncalibRecHitRatioMethodAlgo {
21  public:
22  struct Ratio {
23  unsigned int index;
24  unsigned int step;
25  double value;
26  double error;
27  };
28  struct Tmax {
29  unsigned int index;
30  unsigned int step;
31  double value;
32  double error;
33  double amplitude;
34  double chi2;
35  };
37  double amplitudeMax;
38  double timeMax;
39  double timeError;
40  double chi2;
41  };
42 
44  virtual EcalUncalibratedRecHit makeRecHit(const C & dataFrame,
45  const EcalSampleMask & sampleMask,
46  const double *pedestals,
47  const double* pedestalRMSes,
48  const double *gainRatios,
49  std::vector < double >&timeFitParameters,
50  std::vector < double >&amplitudeFitParameters,
51  std::pair < double, double >&timeFitLimits);
52 
53  // more function to be able to compute
54  // amplitude and time separately
55  void init( const C &dataFrame, const EcalSampleMask &sampleMask, const double * pedestals, const double * pedestalRMSes, const double * gainRatios );
56  void computeTime(std::vector < double >&timeFitParameters, std::pair < double, double >&timeFitLimits, std::vector< double > &amplitudeFitParameters);
57  void computeAmplitude( std::vector< double > &amplitudeFitParameters );
58  CalculatedRecHit getCalculatedRecHit() { return calculatedRechit_; };
59  bool fixMGPAslew( const C &dataFrame );
60 
61  protected:
62 
65  std::vector < double > amplitudes_;
66  std::vector < double > amplitudeErrors_;
67  std::vector < Ratio > ratios_;
68  std::vector < Tmax > times_;
69  std::vector < Tmax > timesAB_;
70 
71  double pedestal_;
72  int num_;
73  double ampMaxError_;
74 
75  CalculatedRecHit calculatedRechit_;
76 };
77 
78 template <class C>
79 void EcalUncalibRecHitRatioMethodAlgo<C>::init( const C &dataFrame, const EcalSampleMask &sampleMask,
80  const double * pedestals, const double * pedestalRMSes, const double * gainRatios )
81 {
82  sampleMask_ = sampleMask;
83  theDetId_ = DetId(dataFrame.id().rawId());
84 
85  calculatedRechit_.timeMax = 5;
86  calculatedRechit_.amplitudeMax = 0;
87  calculatedRechit_.timeError = -999;
88  amplitudes_.clear();
89  amplitudes_.reserve(C::MAXSAMPLES);
90  amplitudeErrors_.clear();
91  amplitudeErrors_.reserve(C::MAXSAMPLES);
92  ratios_.clear();
93  ratios_.reserve(C::MAXSAMPLES*(C::MAXSAMPLES-1)/2);
94  times_.clear();
95  times_.reserve(C::MAXSAMPLES*(C::MAXSAMPLES-1)/2);
96  timesAB_.clear();
97  timesAB_.reserve(C::MAXSAMPLES*(C::MAXSAMPLES-1)/2);
98 
99  // to obtain gain 12 pedestal:
100  // -> if it's in gain 12, use first sample
101  // --> average it with second sample if in gain 12 and 3-sigma-noise compatible (better LF noise cancellation)
102  // -> else use pedestal from database
103  pedestal_ = 0;
104  num_ = 0;
105  if (dataFrame.sample(0).gainId() == 1 &&
106  sampleMask_.useSample(0, theDetId_ )
107  ) {
108  pedestal_ += double (dataFrame.sample(0).adc());
109  num_++;
110  }
111  if (num_!=0 &&
112  dataFrame.sample(1).gainId() == 1 &&
113  sampleMask_.useSample(1, theDetId_) &&
114  fabs(dataFrame.sample(1).adc()-dataFrame.sample(0).adc())<3*pedestalRMSes[0]) {
115  pedestal_ += double (dataFrame.sample(1).adc());
116  num_++;
117  }
118  if (num_ != 0)
119  pedestal_ /= num_;
120  else
121  pedestal_ = pedestals[0];
122 
123  // fill vector of amplitudes, pedestal subtracted and vector
124  // of amplitude uncertainties Also, find the uncertainty of a
125  // sample with max amplitude. We will use it later.
126 
127  ampMaxError_ = 0;
128  double ampMaxValue = -1000;
129 
130  // ped-subtracted and gain-renormalized samples. It is VERY
131  // IMPORTANT to have samples one clock apart which means to
132  // have vector size equal to MAXSAMPLES
133  double sample;
134  double sampleError;
135  int GainId;
136  for (int iSample = 0; iSample < C::MAXSAMPLES; iSample++) {
137 
138 
139 
140  GainId = dataFrame.sample(iSample).gainId();
141 
142 
143  // only use normally samples which are desired; if sample not to be used
144  // inflate error so won't generate ratio considered for the measurement
145  if (!sampleMask_.useSample(iSample, theDetId_ ) ) {
146  sample = 1e-9;
147  sampleError = 1e+9;
148  }
149  else if (GainId == 1) {
150  sample = double (dataFrame.sample(iSample).adc() - pedestal_);
151  sampleError = pedestalRMSes[0];
152  }
153  else if (GainId == 2 || GainId == 3){
154  sample = (double (dataFrame.sample(iSample).adc() - pedestals[GainId - 1])) *gainRatios[GainId - 1];
155  sampleError = pedestalRMSes[GainId-1]*gainRatios[GainId-1];
156  }
157  else {
158  sample = 1e-9; // GainId=0 case falls here, from saturation
159  sampleError = 1e+9; // inflate error so won't generate ratio considered for the measurement
160  }
161 
162 
163  if(sampleError>0){
164  amplitudes_.push_back(sample);
165  amplitudeErrors_.push_back(sampleError);
166  if(ampMaxValue < sample){
167  ampMaxValue = sample;
168  ampMaxError_ = sampleError;
169  }
170  }else{
171  // inflate error for useless samples
172  amplitudes_.push_back(sample);
173  amplitudeErrors_.push_back(1e+9);
174  }
175  }
176 }
177 
178 template <class C>
180 {
181 
182  // This fuction finds sample(s) preceeding gain switching and
183  // inflates errors on this sample, therefore, making this sample
184  // invisible for Ratio Method. Only gain switching DOWN is
185  // considered Only gainID=1,2,3 are considered. In case of the
186  // saturation (gainID=0), we keep "distorted" sample because it is
187  // the only chance to make time measurement; the qualilty of it will
188  // be bad anyway.
189 
190  bool result = false;
191 
192  int GainIdPrev;
193  int GainIdNext;
194  for (int iSample = 1; iSample < C::MAXSAMPLES; iSample++) {
195 
196  // only use samples which are desired
197  if (!sampleMask_.useSample(iSample, theDetId_) ) continue;
198 
199  GainIdPrev = dataFrame.sample(iSample-1).gainId();
200  GainIdNext = dataFrame.sample(iSample).gainId();
201  if( GainIdPrev>=1 && GainIdPrev<=3 &&
202  GainIdNext>=1 && GainIdNext<=3 &&
203  GainIdPrev<GainIdNext ){
204  amplitudes_[iSample-1]=1e-9;
205  amplitudeErrors_[iSample-1]=1e+9;
206  result = true;
207  }
208  }
209  return result;
210 
211 }
212 
213 template<class C>
214 void EcalUncalibRecHitRatioMethodAlgo<C>::computeTime(std::vector < double >&timeFitParameters,
215  std::pair < double, double >&timeFitLimits, std::vector < double >&amplitudeFitParameters)
216 {
218  // //
219  // RATIO METHOD FOR TIME STARTS HERE //
220  // //
222  double ampMaxAlphaBeta = 0;
223  double tMaxAlphaBeta = 5;
224  double tMaxErrorAlphaBeta = 999;
225  double tMaxRatio = 5;
226  double tMaxErrorRatio = 999;
227 
228  double sumAA = 0;
229  double sumA = 0;
230  double sum1 = 0;
231  double sum0 = 0;
232  double sumAf = 0;
233  double sumff = 0;
234  double NullChi2 = 0;
235 
236  // null hypothesis = no pulse, pedestal only
237  for(unsigned int i = 0; i < amplitudes_.size(); i++){
238  double err2 = amplitudeErrors_[i]*amplitudeErrors_[i];
239  sum0 += 1;
240  sum1 += 1/err2;
241  sumA += amplitudes_[i]/err2;
242  sumAA += amplitudes_[i]*amplitudes_[i]/err2;
243  }
244  if(sum0>0){
245  NullChi2 = (sumAA - sumA*sumA/sum1)/sum0;
246  }else{
247  // not enough samples to reconstruct the pulse
248  return;
249  }
250 
251  // Make all possible Ratio's based on any pair of samples i and j
252  // (j>i) with positive amplitudes_
253  //
254  // Ratio[k] = Amp[i]/Amp[j]
255  // where Amp[i] is pedestal subtracted ADC value in a time sample [i]
256  //
257  double alphabeta = amplitudeFitParameters[0]*amplitudeFitParameters[1];
258  double alpha = amplitudeFitParameters[0];
259  double beta = amplitudeFitParameters[1];
260 
261  for(unsigned int i = 0; i < amplitudes_.size()-1; i++){
262  for(unsigned int j = i+1; j < amplitudes_.size(); j++){
263 
264  if(amplitudes_[i]>1 && amplitudes_[j]>1){
265 
266  // ratio
267  double Rtmp = amplitudes_[i]/amplitudes_[j];
268 
269  // error^2 due to stat fluctuations of time samples
270  // (uncorrelated for both samples)
271 
272  double err1 = Rtmp*Rtmp*( (amplitudeErrors_[i]*amplitudeErrors_[i]/(amplitudes_[i]*amplitudes_[i])) + (amplitudeErrors_[j]*amplitudeErrors_[j]/(amplitudes_[j]*amplitudes_[j])) );
273 
274  // error due to fluctuations of pedestal (common to both samples)
275  double stat;
276  if(num_>0) stat = num_; // num presampeles used to compute pedestal
277  else stat = 1; // pedestal from db
278  double err2 = amplitudeErrors_[j]*(amplitudes_[i]-amplitudes_[j])/(amplitudes_[j]*amplitudes_[j])/sqrt(stat);
279 
280  //error due to integer round-down. It is relevant to low
281  //amplitudes_ in gainID=1 and negligible otherwise.
282  double err3 = 0.289/amplitudes_[j];
283 
284  double totalError = sqrt(err1 + err2*err2 +err3*err3);
285 
286 
287  // don't include useless ratios
288  if(totalError < 1.0
289  && Rtmp>0.001
290  && Rtmp<exp(double(j-i)/beta)-0.001
291  ){
292  Ratio currentRatio = { i, (j-i), Rtmp, totalError };
293  ratios_.push_back(currentRatio);
294  }
295 
296  }
297 
298  }
299  }
300 
301  // No useful ratios, return zero amplitude and no time measurement
302  if(!ratios_.size() >0)
303  return;
304 
305  // make a vector of Tmax measurements that correspond to each ratio
306  // and based on Alpha-Beta parameterization of the pulse shape
307 
308  for(unsigned int i = 0; i < ratios_.size(); i++){
309 
310  double stepOverBeta = double(ratios_[i].step)/beta;
311  double offset = double(ratios_[i].index) + alphabeta;
312 
313  double Rmin = ratios_[i].value - ratios_[i].error;
314  if(Rmin<0.001) Rmin=0.001;
315 
316  double Rmax = ratios_[i].value + ratios_[i].error;
317  double RLimit = exp(stepOverBeta)-0.001;
318  if( Rmax > RLimit ) Rmax = RLimit;
319 
320  double time1 = offset - ratios_[i].step/(exp((stepOverBeta-log(Rmin))/alpha)-1.0);
321  double time2 = offset - ratios_[i].step/(exp((stepOverBeta-log(Rmax))/alpha)-1.0);
322 
323  // this is the time measurement based on the ratios[i]
324  double tmax = 0.5 * (time1 + time2);
325  double tmaxerr = 0.5 * sqrt( (time1 - time2)*(time1 - time2) );
326 
327  // calculate chi2
328  sumAf = 0;
329  sumff = 0;
330  for(unsigned int it = 0; it < amplitudes_.size(); it++){
331  double err2 = amplitudeErrors_[it]*amplitudeErrors_[it];
332  double offset = (double(it) - tmax)/alphabeta;
333  double term1 = 1.0 + offset;
334  if(term1>1e-6){
335  double f = exp( alpha*(log(1.0+offset) - offset) );
336  sumAf += amplitudes_[it]*f/err2;
337  sumff += f*f/err2;
338  }
339  }
340 
341  double chi2 = sumAA;
342  double amp = 0;
343  if( sumff > 0 ){
344  chi2 = sumAA - sumAf*sumAf/sumff;
345  amp = sumAf/sumff;
346  }
347  chi2 /= sum0;
348 
349  // choose reasonable measurements. One might argue what is
350  // reasonable and what is not.
351  if(chi2 > 0 && tmaxerr > 0 && tmax > 0){
352  Tmax currentTmax={ ratios_[i].index, ratios_[i].step, tmax, tmaxerr, amp, chi2 };
353  timesAB_.push_back(currentTmax);
354  }
355  }
356 
357  // no reasonable time measurements!
358  if( !(timesAB_.size()> 0))
359  return;
360 
361  // find minimum chi2
362  double chi2min = 1.0e+9;
363  //double timeMinimum = 5;
364  //double errorMinimum = 999;
365  for(unsigned int i = 0; i < timesAB_.size(); i++){
366  if( timesAB_[i].chi2 <= chi2min ){
367  chi2min = timesAB_[i].chi2;
368  //timeMinimum = timesAB_[i].value;
369  //errorMinimum = timesAB_[i].error;
370  }
371  }
372 
373  // make a weighted average of tmax measurements with "small" chi2
374  // (within 1 sigma of statistical uncertainty :-)
375  double chi2Limit = chi2min + 1.0;
376  double time_max = 0;
377  double time_wgt = 0;
378  for(unsigned int i = 0; i < timesAB_.size(); i++){
379  if( timesAB_[i].chi2 < chi2Limit ){
380  double inverseSigmaSquared = 1.0/(timesAB_[i].error*timesAB_[i].error);
381  time_wgt += inverseSigmaSquared;
382  time_max += timesAB_[i].value*inverseSigmaSquared;
383  }
384  }
385 
386  tMaxAlphaBeta = time_max/time_wgt;
387  tMaxErrorAlphaBeta = 1.0/sqrt(time_wgt);
388 
389  // find amplitude and chi2
390  sumAf = 0;
391  sumff = 0;
392  for(unsigned int i = 0; i < amplitudes_.size(); i++){
393  double err2 = amplitudeErrors_[i]*amplitudeErrors_[i];
394  double offset = (double(i) - tMaxAlphaBeta)/alphabeta;
395  double term1 = 1.0 + offset;
396  if(term1>1e-6){
397  double f = exp( alpha*(log(1.0+offset) - offset) );
398  sumAf += amplitudes_[i]*f/err2;
399  sumff += f*f/err2;
400  }
401  }
402 
403  if( sumff > 0 ){
404  ampMaxAlphaBeta = sumAf/sumff;
405  double chi2AlphaBeta = (sumAA - sumAf*sumAf/sumff)/sum0;
406  if(chi2AlphaBeta > NullChi2){
407  // null hypothesis is better
408  return;
409  }
410 
411  }else{
412  // no visible pulse here
413  return;
414  }
415 
416  // if we got to this point, we have a reconstructied Tmax
417  // using RatioAlphaBeta Method. To summarize:
418  //
419  // tMaxAlphaBeta - Tmax value
420  // tMaxErrorAlphaBeta - error on Tmax, but I would not trust it
421  // ampMaxAlphaBeta - amplitude of the pulse
422  // ampMaxError_ - uncertainty of the time sample with max amplitude
423  //
424 
425 
426 
427  // Do Ratio's Method with "large" pulses
428  if( ampMaxAlphaBeta/ampMaxError_ > 5.0 ){
429 
430  // make a vector of Tmax measurements that correspond to each
431  // ratio. Each measurement have it's value and the error
432 
433  double time_max = 0;
434  double time_wgt = 0;
435 
436 
437  for (unsigned int i = 0; i < ratios_.size(); i++) {
438 
439  if(ratios_[i].step == 1
440  && ratios_[i].value >= timeFitLimits.first
441  && ratios_[i].value <= timeFitLimits.second
442  ){
443 
444  double time_max_i = ratios_[i].index;
445 
446  // calculate polynomial for Tmax
447 
448  double u = timeFitParameters[timeFitParameters.size() - 1];
449  for (int k = timeFitParameters.size() - 2; k >= 0; k--) {
450  u = u * ratios_[i].value + timeFitParameters[k];
451  }
452 
453  // calculate derivative for Tmax error
454  double du =
455  (timeFitParameters.size() -
456  1) * timeFitParameters[timeFitParameters.size() - 1];
457  for (int k = timeFitParameters.size() - 2; k >= 1; k--) {
458  du = du * ratios_[i].value + k * timeFitParameters[k];
459  }
460 
461 
462  // running sums for weighted average
463  double errorsquared =
464  ratios_[i].error * ratios_[i].error * du * du;
465  if (errorsquared > 0) {
466 
467  time_max += (time_max_i - u) / errorsquared;
468  time_wgt += 1.0 / errorsquared;
469  Tmax currentTmax =
470  { ratios_[i].index, 1, (time_max_i - u),
471  sqrt(errorsquared),0,1 };
472  times_.push_back(currentTmax);
473 
474  }
475  }
476  }
477 
478 
479  // calculate weighted average of all Tmax measurements
480  if (time_wgt > 0) {
481  tMaxRatio = time_max/time_wgt;
482  tMaxErrorRatio = 1.0/sqrt(time_wgt);
483 
484  // combine RatioAlphaBeta and Ratio Methods
485 
486  if( ampMaxAlphaBeta/ampMaxError_ > 10.0 ){
487 
488  // use pure Ratio Method
489  calculatedRechit_.timeMax = tMaxRatio;
490  calculatedRechit_.timeError = tMaxErrorRatio;
491 
492  }else{
493 
494  // combine two methods
495  calculatedRechit_.timeMax = ( tMaxAlphaBeta*(10.0-ampMaxAlphaBeta/ampMaxError_) + tMaxRatio*(ampMaxAlphaBeta/ampMaxError_ - 5.0) )/5.0;
496  calculatedRechit_.timeError = ( tMaxErrorAlphaBeta*(10.0-ampMaxAlphaBeta/ampMaxError_) + tMaxErrorRatio*(ampMaxAlphaBeta/ampMaxError_ - 5.0) )/5.0;
497 
498  }
499 
500  }else{
501 
502  // use RatioAlphaBeta Method
503  calculatedRechit_.timeMax = tMaxAlphaBeta;
504  calculatedRechit_.timeError = tMaxErrorAlphaBeta;
505 
506  }
507 
508  }else{
509 
510  // use RatioAlphaBeta Method
511  calculatedRechit_.timeMax = tMaxAlphaBeta;
512  calculatedRechit_.timeError = tMaxErrorAlphaBeta;
513 
514  }
515 }
516 
517 template<class C>
518 void EcalUncalibRecHitRatioMethodAlgo<C>::computeAmplitude( std::vector< double > &amplitudeFitParameters )
519 {
521  // //
522  // CALCULATE AMPLITUDE //
523  // //
525 
526 
527  double alpha = amplitudeFitParameters[0];
528  double beta = amplitudeFitParameters[1];
529 
530  // calculate pedestal, again
531 
532  double pedestalLimit = calculatedRechit_.timeMax - (alpha * beta) - 1.0;
533  double sumA = 0;
534  double sumF = 0;
535  double sumAF = 0;
536  double sumFF = 0;
537  double sum1 = 0;
538  for (unsigned int i = 0; i < amplitudes_.size(); i++) {
539  double err2 = amplitudeErrors_[i]*amplitudeErrors_[i];
540  double f = 0;
541  double termOne = 1 + (i - calculatedRechit_.timeMax) / (alpha * beta);
542  if (termOne > 1.e-5) f = exp(alpha * log(termOne)) * exp(-(i - calculatedRechit_.timeMax) / beta);
543 
544  // apply range of interesting samples
545 
546  if ( (i < pedestalLimit)
547  || (f > 0.6 && i <= calculatedRechit_.timeMax)
548  || (f > 0.4 && i >= calculatedRechit_.timeMax)) {
549  sum1 += 1/err2;
550  sumA += amplitudes_[i]/err2;
551  sumF += f/err2;
552  sumAF += f*amplitudes_[i]/err2;
553  sumFF += f*f/err2;
554  }
555  }
556 
557  calculatedRechit_.amplitudeMax = 0;
558  if(sum1 > 0){
559  double denom = sumFF*sum1 - sumF*sumF;
560  if(fabs(denom)>1.0e-20){
561  calculatedRechit_.amplitudeMax = (sumAF*sum1 - sumA*sumF)/denom;
562  }
563  }
564 }
565 
566 
567 
568 template < class C > EcalUncalibratedRecHit
570  const EcalSampleMask & sampleMask,
571  const double *pedestals,
572  const double *pedestalRMSes,
573  const double *gainRatios,
574  std::vector < double >&timeFitParameters,
575  std::vector < double >&amplitudeFitParameters,
576  std::pair < double, double >&timeFitLimits)
577 {
578 
579  init( dataFrame, sampleMask, pedestals, pedestalRMSes, gainRatios );
580  computeTime( timeFitParameters, timeFitLimits, amplitudeFitParameters );
581  computeAmplitude( amplitudeFitParameters );
582 
583  // 1st parameters is id
584  //
585  // 2nd parameters is amplitude. It is calculated by this method.
586  //
587  // 3rd parameter is pedestal. It is not calculated. This method
588  // relies on input parameters for pedestals and gain ratio. Return
589  // zero.
590  //
591  // 4th parameter is jitter which is a bad choice to call Tmax. It is
592  // calculated by this method (in 25 nsec clock units)
593  //
594  // GF subtract 5 so that jitter==0 corresponds to synchronous hit
595  //
596  //
597  // 5th parameter is chi2. It is possible to calculate chi2 for
598  // Tmax. It is possible to calculate chi2 for Amax. However, these
599  // values are not very useful without TmaxErr and AmaxErr. This
600  // method can return one value for chi2 but there are 4 different
601  // parameters that have useful information about the quality of Amax
602  // ans Tmax. For now we can return TmaxErr. The quality of Tmax and
603  // Amax can be judged from the magnitude of TmaxErr
604 
605  return EcalUncalibratedRecHit(dataFrame.id(),
606  calculatedRechit_.amplitudeMax,
607  pedestal_,
608  calculatedRechit_.timeMax - 5,
609  calculatedRechit_.timeError);
610 }
611 #endif
const double beta
int i
Definition: DBlmapReader.cc:9
float alpha
Definition: AMPTWrapper.h:95
void computeAmplitude(std::vector< double > &amplitudeFitParameters)
void computeTime(std::vector< double > &timeFitParameters, std::pair< double, double > &timeFitLimits, std::vector< double > &amplitudeFitParameters)
int init
Definition: HydjetWrapper.h:63
T sqrt(T t)
Definition: SSEVec.h:48
tuple result
Definition: query.py:137
int j
Definition: DBlmapReader.cc:9
double f[11][100]
virtual EcalUncalibratedRecHit makeRecHit(const C &dataFrame, const EcalSampleMask &sampleMask, const double *pedestals, const double *pedestalRMSes, const double *gainRatios, std::vector< double > &timeFitParameters, std::vector< double > &amplitudeFitParameters, std::pair< double, double > &timeFitLimits)
unsigned int offset(bool)
int k[5][pyjets_maxn]
static const double tmax[3]
Definition: DetId.h:20
const double Rmax[kNumberCalorimeter]
void init(const C &dataFrame, const EcalSampleMask &sampleMask, const double *pedestals, const double *pedestalRMSes, const double *gainRatios)
const double Rmin[kNumberCalorimeter]