CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
HBHEPulseShapeFlag.cc
Go to the documentation of this file.
1 //---------------------------------------------------------------------------
2 #include <string>
3 #include <vector>
4 #include <iostream>
5 #include <algorithm>
6 #include <fstream>
7 #include <cmath>
8 
9 //---------------------------------------------------------------------------
12 
14 
18 
22 //---------------------------------------------------------------------------
24 {
25  //
26  // Argumentless constructor; should not be used
27  //
28  // If arguments not properly specified for the constructor, I don't think
29  // we'd trust the flagging algorithm.
30  // Set the minimum charge threshold large enough so that nothing will be flagged.
31  //
32 
33  mMinimumChargeThreshold = 99999999;
34  mTS4TS5ChargeThreshold = 99999999;
35 }
36 //---------------------------------------------------------------------------
38  double TS4TS5ChargeThreshold,
39  unsigned int TrianglePeakTS,
40  const std::vector<double>& LinearThreshold,
41  const std::vector<double>& LinearCut,
42  const std::vector<double>& RMS8MaxThreshold,
43  const std::vector<double>& RMS8MaxCut,
44  const std::vector<double>& LeftSlopeThreshold,
45  const std::vector<double>& LeftSlopeCut,
46  const std::vector<double>& RightSlopeThreshold,
47  const std::vector<double>& RightSlopeCut,
48  const std::vector<double>& RightSlopeSmallThreshold,
49  const std::vector<double>& RightSlopeSmallCut,
50  const std::vector<double>& TS4TS5LowerThreshold,
51  const std::vector<double>& TS4TS5LowerCut,
52  const std::vector<double>& TS4TS5UpperThreshold,
53  const std::vector<double>& TS4TS5UpperCut,
54  bool UseDualFit,
55  bool TriangleIgnoreSlow)
56 {
57  //
58  // The constructor that should be used
59  //
60  // Copies various thresholds and limits and parameters to the class for future use.
61  // Also calls the Initialize() function
62  //
63 
64  mMinimumChargeThreshold = MinimumChargeThreshold;
65  mTS4TS5ChargeThreshold = TS4TS5ChargeThreshold;
66  mTrianglePeakTS = TrianglePeakTS;
67  mTriangleIgnoreSlow = TriangleIgnoreSlow;
68 
69  for(std::vector<double>::size_type i = 0; i < LinearThreshold.size() && i < LinearCut.size(); i++)
70  mLambdaLinearCut.push_back(std::pair<double, double>(LinearThreshold[i], LinearCut[i]));
71  sort(mLambdaLinearCut.begin(), mLambdaLinearCut.end());
72 
73  for(std::vector<double>::size_type i = 0; i < RMS8MaxThreshold.size() && i < RMS8MaxCut.size(); i++)
74  mLambdaRMS8MaxCut.push_back(std::pair<double, double>(RMS8MaxThreshold[i], RMS8MaxCut[i]));
76 
77  for(std::vector<double>::size_type i = 0; i < LeftSlopeThreshold.size() && i < LeftSlopeCut.size(); i++)
78  mLeftSlopeCut.push_back(std::pair<double, double>(LeftSlopeThreshold[i], LeftSlopeCut[i]));
79  sort(mLeftSlopeCut.begin(), mLeftSlopeCut.end());
80 
81  for(std::vector<double>::size_type i = 0; i < RightSlopeThreshold.size() && i < RightSlopeCut.size(); i++)
82  mRightSlopeCut.push_back(std::pair<double, double>(RightSlopeThreshold[i], RightSlopeCut[i]));
83  sort(mRightSlopeCut.begin(), mRightSlopeCut.end());
84 
85  for(std::vector<double>::size_type i = 0; i < RightSlopeSmallThreshold.size() && i < RightSlopeSmallCut.size(); i++)
86  mRightSlopeSmallCut.push_back(std::pair<double, double>(RightSlopeSmallThreshold[i], RightSlopeSmallCut[i]));
88 
89  for(std::vector<double>::size_type i = 0; i < TS4TS5UpperThreshold.size() && i < TS4TS5UpperCut.size(); i++)
90  mTS4TS5UpperCut.push_back(std::pair<double, double>(TS4TS5UpperThreshold[i], TS4TS5UpperCut[i]));
91  sort(mTS4TS5UpperCut.begin(), mTS4TS5UpperCut.end());
92 
93  for(std::vector<double>::size_type i = 0; i < TS4TS5LowerThreshold.size() && i < TS4TS5LowerCut.size(); i++)
94  mTS4TS5LowerCut.push_back(std::pair<double, double>(TS4TS5LowerThreshold[i], TS4TS5LowerCut[i]));
95  sort(mTS4TS5LowerCut.begin(), mTS4TS5LowerCut.end());
96 
97  mUseDualFit = UseDualFit;
98 
99  Initialize();
100 }
101 //---------------------------------------------------------------------------
103 {
104  // Dummy destructor - there's nothing to destruct by hand here
105 }
106 //---------------------------------------------------------------------------
108 {
109  // Dummy function in case something needs to be cleaned....but none right now
110 }
111 //---------------------------------------------------------------------------
113  const HBHEDataFrame &digi,
114  const HcalCoder &coder,
115  const HcalCalibrations &calib)
116 {
117  //
118  // Decide if a digi/pulse is good or bad using fit-based discriminants
119  //
120  // SetPulseShapeFlags determines the total charge in the digi.
121  // If the charge is above the minimum threshold, the code then
122  // runs the flag-setting algorithms to determine whether the
123  // flags should be set.
124  //
125 
126  // hack to exclude ieta=28/29 for the moment...
127  int abseta = hbhe.id().ietaAbs();
128  if(abseta == 28 || abseta == 29) return;
129 
130  CaloSamples Tool;
131  coder.adc2fC(digi, Tool);
132 
133  // mCharge.clear(); // mCharge is a vector of (pedestal-subtracted) Charge values vs. time slice
134  mCharge.resize(digi.size());
135 
136  double TotalCharge = 0;
137 
138  for(int i = 0; i < digi.size(); ++i)
139  {
140  mCharge[i] = Tool[i] - calib.pedestal(digi.sample(i).capid());
141  TotalCharge += mCharge[i];
142  }
143 
144  // No flagging if TotalCharge is less than threshold
145  if(TotalCharge < mMinimumChargeThreshold)
146  return;
147 
148  double NominalChi2 = 0;
149  if (mUseDualFit == true)
150  NominalChi2=PerformDualNominalFit(mCharge);
151  else
152  NominalChi2=PerformNominalFit(mCharge);
153 
154  double LinearChi2 = PerformLinearFit(mCharge);
155 
156  double RMS8Max = CalculateRMS8Max(mCharge);
157  TriangleFitResult TriangleResult = PerformTriangleFit(mCharge);
158 
159  // Set the HBHEFlatNoise and HBHESpikeNoise flags
160  if(CheckPassFilter(TotalCharge, log(LinearChi2) - log(NominalChi2), mLambdaLinearCut, -1) == false)
162  if(CheckPassFilter(TotalCharge, log(RMS8Max) * 2 - log(NominalChi2), mLambdaRMS8MaxCut, -1) == false)
164 
165  // Set the HBHETriangleNoise flag
166  if ((int)mCharge.size() >= mTrianglePeakTS) // can't compute flag if peak TS isn't present; revise this at some point?
167  {
168  // initial values
169  double TS4Left = 1000;
170  double TS4Right = 1000;
171 
172  // Use 'if' statements to protect against slopes that are either 0 or very small
173  if (TriangleResult.LeftSlope > 1e-5)
174  TS4Left = mCharge[mTrianglePeakTS] / TriangleResult.LeftSlope;
175  if (TriangleResult.RightSlope < -1e-5)
176  TS4Right = mCharge[mTrianglePeakTS] / -TriangleResult.RightSlope;
177 
178  if(TS4Left > 1000 || TS4Left < -1000)
179  TS4Left = 1000;
180  if(TS4Right > 1000 || TS4Right < -1000)
181  TS4Right = 1000;
182 
183  if(mTriangleIgnoreSlow == false) // the slow-rising and slow-dropping edges won't be useful in 50ns/75ns
184  {
185  if(CheckPassFilter(mCharge[mTrianglePeakTS], TS4Left, mLeftSlopeCut, 1) == false)
187  else if(CheckPassFilter(mCharge[mTrianglePeakTS], TS4Right, mRightSlopeCut, 1) == false)
189  }
190 
191  // fast-dropping ones should be checked in any case
192  if(CheckPassFilter(mCharge[mTrianglePeakTS], TS4Right, mRightSlopeSmallCut, -1) == false)
194  }
195 
196  if(mCharge[4] + mCharge[5] > mTS4TS5ChargeThreshold && mTS4TS5ChargeThreshold>0) // silly protection against negative charge values
197  {
198  double TS4TS5 = (mCharge[4] - mCharge[5]) / (mCharge[4] + mCharge[5]);
199  if(CheckPassFilter(mCharge[4] + mCharge[5], TS4TS5, mTS4TS5UpperCut, 1) == false)
201  if(CheckPassFilter(mCharge[4] + mCharge[5], TS4TS5, mTS4TS5LowerCut, -1) == false)
203  }
204 }
205 //---------------------------------------------------------------------------
207 {
208  //
209  // Initialization: whatever preprocess is needed
210  //
211  // 1. Get the ideal pulse shape from CMSSW
212  //
213  // Since the HcalPulseShapes class stores the ideal pulse shape in terms of 256 numbers,
214  // each representing 1ns integral of the ideal pulse, here I'm taking out the vector
215  // by calling at() function.
216  //
217  // A cumulative distribution is formed and stored to save some time doing integration to TS later on
218  //
219  // 2. Reserve space for vector
220  //
221 
222  std::vector<double> PulseShape;
223 
224  HcalPulseShapes Shapes;
225  HcalPulseShapes::Shape HPDShape = Shapes.hbShape();
226 
227  PulseShape.reserve(350);
228  for(int i = 0; i < 200; i++)
229  PulseShape.push_back(HPDShape.at(i));
230  PulseShape.insert(PulseShape.begin(), 150, 0); // Safety margin of a lot of zeros in the beginning
231 
232  CumulativeIdealPulse.reserve(350);
233  CumulativeIdealPulse.clear();
234  CumulativeIdealPulse.push_back(0);
235  for(unsigned int i = 1; i < PulseShape.size(); i++)
236  CumulativeIdealPulse.push_back(CumulativeIdealPulse[i-1] + PulseShape[i]);
237 
238  // reserve space for vector
239  mCharge.reserve(10);
240 }
241 //---------------------------------------------------------------------------
243 {
244  //
245  // Perform a "triangle fit", and extract the slopes
246  //
247  // Left-hand side and right-hand side are not correlated to each other - do them separately
248  //
249 
251  result.Chi2 = 0;
252  result.LeftSlope = 0;
253  result.RightSlope = 0;
254 
255  int DigiSize = Charge.size();
256 
257  // right side, starting from TS4
258  double MinimumRightChi2 = 1000000;
259  double Numerator = 0;
260  double Denominator = 0;
261 
262  for(int iTS = mTrianglePeakTS + 2; iTS <= DigiSize; iTS++) // the place where first TS center in flat line
263  {
264  // fit a straight line to the triangle part
265  Numerator = 0;
266  Denominator = 0;
267 
268  for(int i = mTrianglePeakTS + 1; i < iTS; i++)
269  {
270  Numerator += (i - mTrianglePeakTS) * (Charge[i] - Charge[mTrianglePeakTS]);
271  Denominator += (i - mTrianglePeakTS) * (i - mTrianglePeakTS);
272  }
273 
274  double BestSlope = 0;
275  if (Denominator!=0) BestSlope = Numerator / Denominator;
276  if(BestSlope > 0)
277  BestSlope = 0;
278 
279  // check if the slope is reasonable
280  if(iTS != DigiSize)
281  {
282  // iTS starts at mTrianglePeak+2; denominator never zero
283  if(BestSlope > -1 * Charge[mTrianglePeakTS] / (iTS - mTrianglePeakTS))
284  BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - mTrianglePeakTS);
285  if(BestSlope < -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS))
286  BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS);
287  }
288  else
289  {
290  // iTS starts at mTrianglePeak+2; denominator never zero
291  if(BestSlope < -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS))
292  BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS);
293  }
294 
295  // calculate partial chi2
296 
297  // The shape I'm fitting is more like a tent than a triangle.
298  // After the end of triangle edge assume a flat line
299 
300  double Chi2 = 0;
301  for(int i = mTrianglePeakTS + 1; i < iTS; i++)
302  Chi2 += (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope)
303  * (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope);
304  for(int i = iTS; i < DigiSize; i++) // Assumes fit line = 0 for iTS > fit
305  Chi2 += Charge[i] * Charge[i];
306 
307  if(Chi2 < MinimumRightChi2)
308  {
309  MinimumRightChi2 = Chi2;
310  result.RightSlope = BestSlope;
311  }
312  } // end of right-hand side loop
313 
314  // left side
315  double MinimumLeftChi2 = 1000000;
316 
317  for(int iTS = 0; iTS < (int)mTrianglePeakTS; iTS++) // the first time after linear fit ends
318  {
319  // fit a straight line to the triangle part
320  Numerator = 0;
321  Denominator = 0;
322  for(int i = iTS; i < (int)mTrianglePeakTS; i++)
323  {
324  Numerator = Numerator + (i - mTrianglePeakTS) * (Charge[i] - Charge[mTrianglePeakTS]);
325  Denominator = Denominator + (i - mTrianglePeakTS) * (i - mTrianglePeakTS);
326  }
327 
328  double BestSlope = 0;
329  if (Denominator!=0) BestSlope = Numerator / Denominator;
330  if (BestSlope < 0)
331  BestSlope = 0;
332 
333  // check slope
334  if(iTS != 0)
335  {
336  // iTS must be >0 and < mTrianglePeakTS; slope never 0
337  if(BestSlope > Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS))
338  BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS);
339  if(BestSlope < Charge[mTrianglePeakTS] / (mTrianglePeakTS + 1 - iTS))
340  BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS + 1 - iTS);
341  }
342  else
343  {
344  if(BestSlope > Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS))
345  BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS);
346  }
347 
348  // calculate minimum chi2
349  double Chi2 = 0;
350  for(int i = 0; i < iTS; i++)
351  Chi2 += Charge[i] * Charge[i];
352  for(int i = iTS; i < (int)mTrianglePeakTS; i++)
353  Chi2 += (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope)
354  * (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope);
355 
356  if(MinimumLeftChi2 > Chi2)
357  {
358  MinimumLeftChi2 = Chi2;
359  result.LeftSlope = BestSlope;
360  }
361  } // end of left-hand side loop
362 
363  result.Chi2 = MinimumLeftChi2 + MinimumRightChi2;
364 
365  return result;
366 }
367 //---------------------------------------------------------------------------
368 double HBHEPulseShapeFlagSetter::PerformNominalFit(const std::vector<double> &Charge)
369 {
370  //
371  // Performs a fit to the ideal pulse shape. Returns best chi2
372  //
373  // A scan over different timing offset (for the ideal pulse) is carried out,
374  // and for each offset setting a one-parameter fit is performed
375  //
376 
377  int DigiSize = Charge.size();
378 
379  double MinimumChi2 = 100000;
380 
381  double F = 0;
382 
383  double SumF2 = 0;
384  double SumTF = 0;
385  double SumT2 = 0;
386 
387  for(int i = 0; i + 250 < (int)CumulativeIdealPulse.size(); i++)
388  {
390  continue;
391 
392  SumF2 = 0;
393  SumTF = 0;
394  SumT2 = 0;
395 
396  double ErrorTemp=0;
397  for(int j = 0; j < DigiSize; j++)
398  {
399  // get ideal pulse component for this time slice....
400  F = CumulativeIdealPulse[i+j*25+25] - CumulativeIdealPulse[i+j*25];
401 
402  ErrorTemp=Charge[j];
403  if (ErrorTemp<1) // protection against small charges
404  ErrorTemp=1;
405  // ...and increment various summations
406  SumF2 += F * F / ErrorTemp;
407  SumTF += F * Charge[j] / ErrorTemp;
408  SumT2 += fabs(Charge[j]);
409  }
410 
411  /*
412  chi2= sum((Charge[j]-aF)^2/|Charge[j]|
413  ( |Charge[j]| = assumed sigma^2 for Charge[j]; a bit wonky for Charge[j]<1 )
414  chi2 = sum(|Charge[j]|) - 2*sum(aF*Charge[j]/|Charge[j]|) +sum( a^2*F^2/|Charge[j]|)
415  chi2 minimimized when d(chi2)/da = 0:
416  a = sum(F*Charge[j])/sum(F^2)
417  ...
418  chi2= sum(|Q[j]|) - sum(Q[j]/|Q[j]|*F)*sum(Q[j]/|Q[j]|*F)/sum(F^2/|Q[j]|), where Q = Charge
419  chi2 = SumT2 - SumTF*SumTF/SumF2
420  */
421 
422  double Chi2 = SumT2 - SumTF * SumTF / SumF2;
423 
424  if(Chi2 < MinimumChi2)
425  MinimumChi2 = Chi2;
426  }
427 
428  // safety protection in case of perfect fit - don't want the log(...) to explode
429  if(MinimumChi2 < 1e-5)
430  MinimumChi2 = 1e-5;
431 
432  return MinimumChi2;
433 }
434 //---------------------------------------------------------------------------
435 double HBHEPulseShapeFlagSetter::PerformDualNominalFit(const std::vector<double> &Charge)
436 {
437  //
438  // Perform dual nominal fit and returns the chi2
439  //
440  // In this function we do a scan over possible "distance" (number of time slices between two components)
441  // and overall offset for the two components; first coarse, then finer
442  // All the fitting is done in the DualNominalFitSingleTry function
443  //
444 
445  double OverallMinimumChi2 = 1000000;
446 
447  int AvailableDistance[] = {-100, -75, -50, 50, 75, 100};
448 
449  // loop over possible pulse distances between two components
450  bool isFirst=true;
451 
452  for(int k = 0; k < 6; k++)
453  {
454  double SingleMinimumChi2 = 1000000;
455  int MinOffset = 0;
456 
457  // scan coarsely through different offsets and find the minimum
458  for(int i = 0; i + 250 < (int)CumulativeIdealPulse.size(); i += 10)
459  {
460  double Chi2 = DualNominalFitSingleTry(Charge, i, AvailableDistance[k],isFirst);
461  isFirst=false;
462  if(Chi2 < SingleMinimumChi2)
463  {
464  SingleMinimumChi2 = Chi2;
465  MinOffset = i;
466  }
467  }
468 
469  // around the minimum, scan finer for better a better minimum
470  for(int i = MinOffset - 15; i + 250 < (int)CumulativeIdealPulse.size() && i < MinOffset + 15; i++)
471  {
472  double Chi2 = DualNominalFitSingleTry(Charge, i, AvailableDistance[k],false);
473  if(Chi2 < SingleMinimumChi2)
474  SingleMinimumChi2 = Chi2;
475  }
476 
477  // update overall minimum chi2
478  if(SingleMinimumChi2 < OverallMinimumChi2)
479  OverallMinimumChi2 = SingleMinimumChi2;
480  }
481 
482  return OverallMinimumChi2;
483 }
484 //---------------------------------------------------------------------------
485 double HBHEPulseShapeFlagSetter::DualNominalFitSingleTry(const std::vector<double> &Charge, int Offset, int Distance, bool newCharges)
486 {
487  //
488  // Does a fit to dual signal pulse hypothesis given offset and distance of the two target pulses
489  //
490  // The only parameters to fit here are the two pulse heights of in-time and out-of-time components
491  // since offset is given
492  // The calculation here is based from writing down the Chi2 formula and minimize against the two parameters,
493  // ie., Chi2 = Sum{((T[i] - a1 * F1[i] - a2 * F2[i]) / (Sigma[i]))^2}, where T[i] is the input pulse shape,
494  // and F1[i], F2[i] are the two ideal pulse components
495  //
496 
497  int DigiSize = Charge.size();
498 
499  if(Offset < 0 || Offset + 250 >= (int)CumulativeIdealPulse.size())
500  return 1000000;
501  if(CumulativeIdealPulse[Offset+250] - CumulativeIdealPulse[Offset] < 1e-5)
502  return 1000000;
503 
504  if ( newCharges) {
505  f1_.resize(DigiSize);
506  f2_.resize(DigiSize);
507  errors_.resize(DigiSize);
508  for(int j = 0; j < DigiSize; j++)
509  {
510  errors_[j] = Charge[j];
511  if(errors_[j] < 1)
512  errors_[j] = 1;
513  errors_[j]=1.0/errors_[j];
514  }
515  }
516 
517  double SumF1F1 = 0;
518  double SumF1F2 = 0;
519  double SumF2F2 = 0;
520  double SumTF1 = 0;
521  double SumTF2 = 0;
522 
523  unsigned int cipSize=CumulativeIdealPulse.size();
524  for(int j = 0; j < DigiSize; j++)
525  {
526  // this is the TS value for in-time component - no problem we can do a subtraction directly
527  f1_[j] = CumulativeIdealPulse[Offset+j*25+25] - CumulativeIdealPulse[Offset+j*25];
528 
529  // However for the out-of-time component the index might go out-of-bound.
530  // Let's protect against this.
531 
532  int OffsetTemp = Offset + j * 25 + Distance;
533 
534  double C1 = 0; // lower-indexed value in the cumulative pulse shape
535  double C2 = 0; // higher-indexed value in the cumulative pulse shape
536 
537 
538  if(OffsetTemp + 25 >= (int)cipSize)
539  C1 = CumulativeIdealPulse[cipSize-1];
540  else
541  if( OffsetTemp >= -25)
542  C1 = CumulativeIdealPulse[OffsetTemp+25];
543  if(OffsetTemp >= (int)cipSize)
544  C2 = CumulativeIdealPulse[cipSize-1];
545  else
546  if( OffsetTemp >= 0)
547  C2 = CumulativeIdealPulse[OffsetTemp];
548  f2_[j] = C1 - C2;
549 
550  SumF1F1 += f1_[j] * f1_[j] * errors_[j];
551  SumF1F2 += f1_[j] * f2_[j] * errors_[j];
552  SumF2F2 += f2_[j] * f2_[j] * errors_[j];
553  SumTF1 += f1_[j] * Charge[j] * errors_[j];
554  SumTF2 += f2_[j] * Charge[j] * errors_[j];
555  }
556 
557  double Height = 0;
558  double Height2 = 0;
559  if (fabs(SumF1F2*SumF1F2-SumF1F1*SumF2F2)>1e-5)
560  {
561  Height = (SumF1F2 * SumTF2 - SumF2F2 * SumTF1) / (SumF1F2 * SumF1F2 - SumF1F1 * SumF2F2);
562  Height2 = (SumF1F2 * SumTF1 - SumF1F1 * SumTF2) / (SumF1F2 * SumF1F2 - SumF1F1 * SumF2F2);
563  }
564 
565  double Chi2 = 0;
566  for(int j = 0; j < DigiSize; j++)
567  {
568  double Residual = Height * f1_[j] + Height2 * f2_[j] - Charge[j];
569  Chi2 += Residual * Residual *errors_[j];
570  }
571 
572  // Safety protection in case of zero
573  if(Chi2 < 1e-5)
574  Chi2 = 1e-5;
575 
576  return Chi2;
577 }
578 //---------------------------------------------------------------------------
579 double HBHEPulseShapeFlagSetter::CalculateRMS8Max(const std::vector<double> &Charge)
580 {
581  //
582  // CalculateRMS8Max
583  //
584  // returns "RMS" divided by the largest charge in the time slices
585  // "RMS" is calculated using all but the two largest time slices.
586  // The "RMS" is not quite the actual RMS (see note below), but the value is only
587  // used for determining max values, and is not quoted as the actual RMS anywhere.
588  //
589 
590  int DigiSize = Charge.size();
591 
592  if (DigiSize<=2) return 1e-5; // default statement when DigiSize is too small for useful RMS calculation
593  // Copy Charge vector again, since we are passing references around
594  std::vector<double> TempCharge = Charge;
595 
596  // Sort TempCharge vector from smallest to largest charge
597  sort(TempCharge.begin(), TempCharge.end());
598 
599  double Total = 0;
600  double Total2 = 0;
601  for(int i = 0; i < DigiSize - 2; i++)
602  {
603  Total = Total + TempCharge[i];
604  Total2 = Total2 + TempCharge[i] * TempCharge[i];
605  }
606 
607  // This isn't quite the RMS (both Total2 and Total*Total need to be
608  // divided by an extra (DigiSize-2) within the sqrt to get the RMS.)
609  // We're only using this value for relative comparisons, though; we
610  // aren't explicitly interpreting it as the RMS. It might be nice
611  // to either change the calculation or rename the variable in the future, though.
612 
613  double RMS = sqrt(Total2 - Total * Total / (DigiSize - 2));
614 
615  double RMS8Max = RMS / TempCharge[DigiSize-1];
616  if(RMS8Max < 1e-5) // protection against zero
617  RMS8Max = 1e-5;
618 
619  return RMS / TempCharge[DigiSize-1];
620 }
621 //---------------------------------------------------------------------------
622 double HBHEPulseShapeFlagSetter::PerformLinearFit(const std::vector<double> &Charge)
623 {
624  //
625  // Performs a straight-line fit over all time slices, and returns the chi2 value
626  //
627  // The calculation here is based from writing down the formula for chi2 and minimize
628  // with respect to the parameters in the fit, ie., slope and intercept of the straight line
629  // By doing two differentiation, we will get two equations, and the best parameters are determined by these
630  //
631 
632  int DigiSize = Charge.size();
633 
634  double SumTS2OverTi = 0;
635  double SumTSOverTi = 0;
636  double SumOverTi = 0;
637  double SumTiTS = 0;
638  double SumTi = 0;
639 
640  double Error2 = 0;
641  for(int i = 0; i < DigiSize; i++)
642  {
643  Error2 = Charge[i];
644  if(Charge[i] < 1)
645  Error2 = 1;
646 
647  SumTS2OverTi += 1.* i * i / Error2;
648  SumTSOverTi += 1.* i / Error2;
649  SumOverTi += 1. / Error2;
650  SumTiTS += Charge[i] * i / Error2;
651  SumTi += Charge[i] / Error2;
652  }
653 
654  double CM1 = SumTS2OverTi; // Coefficient in front of slope in equation 1
655  double CM2 = SumTSOverTi; // Coefficient in front of slope in equation 2
656  double CD1 = SumTSOverTi; // Coefficient in front of intercept in equation 1
657  double CD2 = SumOverTi; // Coefficient in front of intercept in equation 2
658  double C1 = SumTiTS; // Constant coefficient in equation 1
659  double C2 = SumTi; // Constant coefficient in equation 2
660 
661  // Denominators always non-zero by construction
662  double Slope = (C1 * CD2 - C2 * CD1) / (CM1 * CD2 - CM2 * CD1);
663  double Intercept = (C1 * CM2 - C2 * CM1) / (CD1 * CM2 - CD2 * CM1);
664 
665  // now that the best parameters are found, calculate chi2 from those
666  double Chi2 = 0;
667  for(int i = 0; i < DigiSize; i++)
668  {
669  double Deviation = Slope * i + Intercept - Charge[i];
670  double Error2 = Charge[i];
671  if(Charge[i] < 1)
672  Error2 = 1;
673  Chi2 += Deviation * Deviation / Error2;
674  }
675 
676  // safety protection in case of perfect fit
677  if(Chi2 < 1e-5)
678  Chi2 = 1e-5;
679 
680  return Chi2;
681 }
682 //---------------------------------------------------------------------------
684  double Discriminant,
685  std::vector<std::pair<double, double> > &Cuts,
686  int Side)
687 {
688  //
689  // Checks whether Discriminant value passes Cuts for the specified Charge. True if pulse is good.
690  //
691  // The "Cuts" pairs are assumed to be sorted in terms of size from small to large,
692  // where each "pair" = (Charge, Discriminant)
693  // "Side" is either positive or negative, which determines whether to discard the pulse if discriminant
694  // is greater or smaller than the cut value
695  //
696 
697  if(Cuts.size() == 0) // safety check that there are some cuts defined
698  return true;
699 
700  if(Charge <= Cuts[0].first) // too small to cut on
701  return true;
702 
703  int IndexLargerThanCharge = -1; // find the range it is falling in
704  for(int i = 1; i < (int)Cuts.size(); i++)
705  {
706  if(Cuts[i].first > Charge)
707  {
708  IndexLargerThanCharge = i;
709  break;
710  }
711  }
712 
713  double limit = 1000000;
714 
715  if(IndexLargerThanCharge == -1) // if charge is greater than the last entry, assume flat line
716  limit = Cuts[Cuts.size()-1].second;
717  else // otherwise, do a linear interpolation to find the cut position
718  {
719  double C1 = Cuts[IndexLargerThanCharge].first;
720  double C2 = Cuts[IndexLargerThanCharge-1].first;
721  double L1 = Cuts[IndexLargerThanCharge].second;
722  double L2 = Cuts[IndexLargerThanCharge-1].second;
723 
724  limit = (Charge - C1) / (C2 - C1) * (L2 - L1) + L1;
725  }
726 
727  if(Side > 0 && Discriminant > limit)
728  return false;
729  if(Side < 0 && Discriminant < limit)
730  return false;
731 
732  return true;
733 }
734 //---------------------------------------------------------------------------
735 
736 
int i
Definition: DBlmapReader.cc:9
std::vector< double > f1_
std::vector< std::pair< double, double > > mLambdaLinearCut
float at(double time) const
std::vector< double > f2_
int size() const
total number of samples in the digi
Definition: HBHEDataFrame.h:26
HcalDetId id() const
get the id
Definition: HBHERecHit.h:23
void setFlagField(uint32_t value, int base, int width=1)
Definition: CaloRecHit.cc:20
isFirst
Definition: cuy.py:417
double pedestal(int fCapId) const
get pedestal for capid=0..3
double CalculateRMS8Max(const std::vector< double > &Charge)
std::vector< std::pair< double, double > > mTS4TS5LowerCut
double PerformNominalFit(const std::vector< double > &Charge)
double DualNominalFitSingleTry(const std::vector< double > &Charge, int Offset, int Distance, bool newCharges=true)
double PerformDualNominalFit(const std::vector< double > &Charge)
uint16_t size_type
double PerformLinearFit(const std::vector< double > &Charge)
std::vector< std::pair< double, double > > mLeftSlopeCut
TriangleFitResult PerformTriangleFit(const std::vector< double > &Charge)
MVATrainerComputer * calib
Definition: MVATrainer.cc:64
T sqrt(T t)
Definition: SSEVec.h:48
std::vector< std::pair< double, double > > mRightSlopeCut
tuple result
Definition: query.py:137
int j
Definition: DBlmapReader.cc:9
bool CheckPassFilter(double Charge, double Discriminant, std::vector< std::pair< double, double > > &Cuts, int Side)
int ietaAbs() const
get the absolute value of the cell ieta
Definition: HcalDetId.h:49
std::vector< double > mCharge
std::vector< std::pair< double, double > > mRightSlopeSmallCut
int capid() const
get the Capacitor id
Definition: HcalQIESample.h:26
const HcalQIESample & sample(int i) const
access a sample
Definition: HBHEDataFrame.h:39
const Shape & hbShape() const
virtual void adc2fC(const HBHEDataFrame &df, CaloSamples &lf) const =0
void SetPulseShapeFlags(HBHERecHit &hbhe, const HBHEDataFrame &digi, const HcalCoder &coder, const HcalCalibrations &calib)
std::vector< double > errors_
std::vector< double > CumulativeIdealPulse
std::vector< std::pair< double, double > > mLambdaRMS8MaxCut
static uInt32 F(BLOWFISH_CTX *ctx, uInt32 x)
Definition: blowfish.cc:281
Definition: Chi2.h:17
std::vector< std::pair< double, double > > mTS4TS5UpperCut