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