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