CMS 3D CMS Logo

HBHEPulseShapeFlag.cc
Go to the documentation of this file.
1 //---------------------------------------------------------------------------
2 #include <iostream>
3 #include <algorithm>
4 #include <fstream>
5 #include <cmath>
6 
7 //---------------------------------------------------------------------------
9 
11 
15 
16 //---------------------------------------------------------------------------
18  double TS4TS5ChargeThreshold,
19  double TS3TS4ChargeThreshold,
21  double TS5TS6ChargeThreshold,
23  double R45PlusOneRange,
24  double R45MinusOneRange,
25  unsigned int TrianglePeakTS,
26  const std::vector<double>& LinearThreshold,
27  const std::vector<double>& LinearCut,
28  const std::vector<double>& RMS8MaxThreshold,
29  const std::vector<double>& RMS8MaxCut,
30  const std::vector<double>& LeftSlopeThreshold,
31  const std::vector<double>& LeftSlopeCut,
32  const std::vector<double>& RightSlopeThreshold,
33  const std::vector<double>& RightSlopeCut,
34  const std::vector<double>& RightSlopeSmallThreshold,
35  const std::vector<double>& RightSlopeSmallCut,
36  const std::vector<double>& TS4TS5LowerThreshold,
37  const std::vector<double>& TS4TS5LowerCut,
38  const std::vector<double>& TS4TS5UpperThreshold,
39  const std::vector<double>& TS4TS5UpperCut,
40  bool UseDualFit,
41  bool TriangleIgnoreSlow,
42  bool setLegacyFlags) {
43  //
44  // The constructor that should be used
45  //
46  // Copies various thresholds and limits and parameters to the class for future use.
47  // Also calls the Initialize() function
48  //
49 
60  mSetLegacyFlags = setLegacyFlags;
61 
62  for (std::vector<double>::size_type i = 0; i < LinearThreshold.size() && i < LinearCut.size(); i++)
63  mLambdaLinearCut.push_back(std::pair<double, double>(LinearThreshold[i], LinearCut[i]));
64  sort(mLambdaLinearCut.begin(), mLambdaLinearCut.end());
65 
66  for (std::vector<double>::size_type i = 0; i < RMS8MaxThreshold.size() && i < RMS8MaxCut.size(); i++)
67  mLambdaRMS8MaxCut.push_back(std::pair<double, double>(RMS8MaxThreshold[i], RMS8MaxCut[i]));
69 
70  for (std::vector<double>::size_type i = 0; i < LeftSlopeThreshold.size() && i < LeftSlopeCut.size(); i++)
71  mLeftSlopeCut.push_back(std::pair<double, double>(LeftSlopeThreshold[i], LeftSlopeCut[i]));
72  sort(mLeftSlopeCut.begin(), mLeftSlopeCut.end());
73 
74  for (std::vector<double>::size_type i = 0; i < RightSlopeThreshold.size() && i < RightSlopeCut.size(); i++)
75  mRightSlopeCut.push_back(std::pair<double, double>(RightSlopeThreshold[i], RightSlopeCut[i]));
76  sort(mRightSlopeCut.begin(), mRightSlopeCut.end());
77 
79  mRightSlopeSmallCut.push_back(std::pair<double, double>(RightSlopeSmallThreshold[i], RightSlopeSmallCut[i]));
81 
82  for (std::vector<double>::size_type i = 0; i < TS4TS5UpperThreshold.size() && i < TS4TS5UpperCut.size(); i++)
83  mTS4TS5UpperCut.push_back(std::pair<double, double>(TS4TS5UpperThreshold[i], TS4TS5UpperCut[i]));
84  sort(mTS4TS5UpperCut.begin(), mTS4TS5UpperCut.end());
85 
86  for (std::vector<double>::size_type i = 0; i < TS4TS5LowerThreshold.size() && i < TS4TS5LowerCut.size(); i++)
87  mTS4TS5LowerCut.push_back(std::pair<double, double>(TS4TS5LowerThreshold[i], TS4TS5LowerCut[i]));
88  sort(mTS4TS5LowerCut.begin(), mTS4TS5LowerCut.end());
89 
91 
92  Initialize();
93 }
94 //---------------------------------------------------------------------------
96  // Dummy destructor - there's nothing to destruct by hand here
97 }
98 //---------------------------------------------------------------------------
100  // Dummy function in case something needs to be cleaned....but none right now
101 }
102 //---------------------------------------------------------------------------
104  //
105  // Initialization: whatever preprocess is needed
106  //
107  // 1. Get the ideal pulse shape from CMSSW
108  //
109  // Since the HcalPulseShapes class stores the ideal pulse shape in terms of 256 numbers,
110  // each representing 1ns integral of the ideal pulse, here I'm taking out the vector
111  // by calling at() function.
112  //
113  // A cumulative distribution is formed and stored to save some time doing integration to TS later on
114  //
115  // 2. Reserve space for vector
116  //
117 
118  std::vector<double> PulseShape;
119 
120  HcalPulseShapes Shapes;
121  const HcalPulseShapes::Shape& HPDShape = Shapes.hbShape();
122 
123  PulseShape.reserve(350);
124  for (int i = 0; i < 200; i++)
125  PulseShape.push_back(HPDShape.at(i));
126  PulseShape.insert(PulseShape.begin(), 150, 0); // Safety margin of a lot of zeros in the beginning
127 
128  CumulativeIdealPulse.reserve(350);
129  CumulativeIdealPulse.clear();
130  CumulativeIdealPulse.push_back(0);
131  for (unsigned int i = 1; i < PulseShape.size(); i++)
132  CumulativeIdealPulse.push_back(CumulativeIdealPulse[i - 1] + PulseShape[i]);
133 
134  // reserve space for vector
135  mCharge.reserve(10);
136 }
137 //---------------------------------------------------------------------------
139  //
140  // Perform a "triangle fit", and extract the slopes
141  //
142  // Left-hand side and right-hand side are not correlated to each other - do them separately
143  //
144 
146  result.Chi2 = 0;
147  result.LeftSlope = 0;
148  result.RightSlope = 0;
149 
150  int DigiSize = Charge.size();
151 
152  // right side, starting from TS4
153  double MinimumRightChi2 = 1000000;
154  double Numerator = 0;
155  double Denominator = 0;
156 
157  for (int iTS = mTrianglePeakTS + 2; iTS <= DigiSize; iTS++) // the place where first TS center in flat line
158  {
159  // fit a straight line to the triangle part
160  Numerator = 0;
161  Denominator = 0;
162 
163  for (int i = mTrianglePeakTS + 1; i < iTS; i++) {
164  Numerator += (i - mTrianglePeakTS) * (Charge[i] - Charge[mTrianglePeakTS]);
165  Denominator += (i - mTrianglePeakTS) * (i - mTrianglePeakTS);
166  }
167 
168  double BestSlope = 0;
169  if (Denominator != 0)
170  BestSlope = Numerator / Denominator;
171  if (BestSlope > 0)
172  BestSlope = 0;
173 
174  // check if the slope is reasonable
175  if (iTS != DigiSize) {
176  // iTS starts at mTrianglePeak+2; denominator never zero
177  if (BestSlope > -1 * Charge[mTrianglePeakTS] / (iTS - mTrianglePeakTS))
178  BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - mTrianglePeakTS);
179  if (BestSlope < -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS))
180  BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS);
181  } else {
182  // iTS starts at mTrianglePeak+2; denominator never zero
183  if (BestSlope < -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS))
184  BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS);
185  }
186 
187  // calculate partial chi2
188 
189  // The shape I'm fitting is more like a tent than a triangle.
190  // After the end of triangle edge assume a flat line
191 
192  double Chi2 = 0;
193  for (int i = mTrianglePeakTS + 1; i < iTS; i++)
194  Chi2 += (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope) *
195  (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope);
196  for (int i = iTS; i < DigiSize; i++) // Assumes fit line = 0 for iTS > fit
197  Chi2 += Charge[i] * Charge[i];
198 
199  if (Chi2 < MinimumRightChi2) {
200  MinimumRightChi2 = Chi2;
201  result.RightSlope = BestSlope;
202  }
203  } // end of right-hand side loop
204 
205  // left side
206  double MinimumLeftChi2 = 1000000;
207 
208  for (int iTS = 0; iTS < (int)mTrianglePeakTS; iTS++) // the first time after linear fit ends
209  {
210  // fit a straight line to the triangle part
211  Numerator = 0;
212  Denominator = 0;
213  for (int i = iTS; i < (int)mTrianglePeakTS; i++) {
214  Numerator = Numerator + (i - mTrianglePeakTS) * (Charge[i] - Charge[mTrianglePeakTS]);
215  Denominator = Denominator + (i - mTrianglePeakTS) * (i - mTrianglePeakTS);
216  }
217 
218  double BestSlope = 0;
219  if (Denominator != 0)
220  BestSlope = Numerator / Denominator;
221  if (BestSlope < 0)
222  BestSlope = 0;
223 
224  // check slope
225  if (iTS != 0) {
226  // iTS must be >0 and < mTrianglePeakTS; slope never 0
227  if (BestSlope > Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS))
228  BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS);
229  if (BestSlope < Charge[mTrianglePeakTS] / (mTrianglePeakTS + 1 - iTS))
230  BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS + 1 - iTS);
231  } else {
232  if (BestSlope > Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS))
233  BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS);
234  }
235 
236  // calculate minimum chi2
237  double Chi2 = 0;
238  for (int i = 0; i < iTS; i++)
239  Chi2 += Charge[i] * Charge[i];
240  for (int i = iTS; i < (int)mTrianglePeakTS; i++)
241  Chi2 += (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope) *
242  (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope);
243 
244  if (MinimumLeftChi2 > Chi2) {
245  MinimumLeftChi2 = Chi2;
246  result.LeftSlope = BestSlope;
247  }
248  } // end of left-hand side loop
249 
250  result.Chi2 = MinimumLeftChi2 + MinimumRightChi2;
251 
252  return result;
253 }
254 //---------------------------------------------------------------------------
255 double HBHEPulseShapeFlagSetter::PerformNominalFit(const std::vector<double>& Charge) {
256  //
257  // Performs a fit to the ideal pulse shape. Returns best chi2
258  //
259  // A scan over different timing offset (for the ideal pulse) is carried out,
260  // and for each offset setting a one-parameter fit is performed
261  //
262 
263  int DigiSize = Charge.size();
264 
265  double MinimumChi2 = 100000;
266 
267  double F = 0;
268 
269  double SumF2 = 0;
270  double SumTF = 0;
271  double SumT2 = 0;
272 
273  for (int i = 0; i + 250 < (int)CumulativeIdealPulse.size(); i++) {
274  if (CumulativeIdealPulse[i + 250] - CumulativeIdealPulse[i] < 1e-5)
275  continue;
276 
277  SumF2 = 0;
278  SumTF = 0;
279  SumT2 = 0;
280 
281  double ErrorTemp = 0;
282  for (int j = 0; j < DigiSize; j++) {
283  // get ideal pulse component for this time slice....
284  F = CumulativeIdealPulse[i + j * 25 + 25] - CumulativeIdealPulse[i + j * 25];
285 
286  ErrorTemp = Charge[j];
287  if (ErrorTemp < 1) // protection against small charges
288  ErrorTemp = 1;
289  // ...and increment various summations
290  SumF2 += F * F / ErrorTemp;
291  SumTF += F * Charge[j] / ErrorTemp;
292  SumT2 += fabs(Charge[j]);
293  }
294 
295  /*
296  chi2= sum((Charge[j]-aF)^2/|Charge[j]|
297  ( |Charge[j]| = assumed sigma^2 for Charge[j]; a bit wonky for Charge[j]<1 )
298  chi2 = sum(|Charge[j]|) - 2*sum(aF*Charge[j]/|Charge[j]|) +sum( a^2*F^2/|Charge[j]|)
299  chi2 minimimized when d(chi2)/da = 0:
300  a = sum(F*Charge[j])/sum(F^2)
301  ...
302  chi2= sum(|Q[j]|) - sum(Q[j]/|Q[j]|*F)*sum(Q[j]/|Q[j]|*F)/sum(F^2/|Q[j]|), where Q = Charge
303  chi2 = SumT2 - SumTF*SumTF/SumF2
304  */
305 
306  double Chi2 = SumT2 - SumTF * SumTF / SumF2;
307 
308  if (Chi2 < MinimumChi2)
309  MinimumChi2 = Chi2;
310  }
311 
312  // safety protection in case of perfect fit - don't want the log(...) to explode
313  if (MinimumChi2 < 1e-5)
314  MinimumChi2 = 1e-5;
315 
316  return MinimumChi2;
317 }
318 //---------------------------------------------------------------------------
319 double HBHEPulseShapeFlagSetter::PerformDualNominalFit(const std::vector<double>& Charge) {
320  //
321  // Perform dual nominal fit and returns the chi2
322  //
323  // In this function we do a scan over possible "distance" (number of time slices between two components)
324  // and overall offset for the two components; first coarse, then finer
325  // All the fitting is done in the DualNominalFitSingleTry function
326  //
327 
328  double OverallMinimumChi2 = 1000000;
329 
330  int AvailableDistance[] = {-100, -75, -50, 50, 75, 100};
331 
332  // loop over possible pulse distances between two components
333  bool isFirst = true;
334 
335  for (int k = 0; k < 6; k++) {
336  double SingleMinimumChi2 = 1000000;
337  int MinOffset = 0;
338 
339  // scan coarsely through different offsets and find the minimum
340  for (int i = 0; i + 250 < (int)CumulativeIdealPulse.size(); i += 10) {
341  double Chi2 = DualNominalFitSingleTry(Charge, i, AvailableDistance[k], isFirst);
342  isFirst = false;
343  if (Chi2 < SingleMinimumChi2) {
344  SingleMinimumChi2 = Chi2;
345  MinOffset = i;
346  }
347  }
348 
349  // around the minimum, scan finer for better a better minimum
350  for (int i = MinOffset - 15; i + 250 < (int)CumulativeIdealPulse.size() && i < MinOffset + 15; i++) {
351  double Chi2 = DualNominalFitSingleTry(Charge, i, AvailableDistance[k], false);
352  if (Chi2 < SingleMinimumChi2)
353  SingleMinimumChi2 = Chi2;
354  }
355 
356  // update overall minimum chi2
357  if (SingleMinimumChi2 < OverallMinimumChi2)
358  OverallMinimumChi2 = SingleMinimumChi2;
359  }
360 
361  return OverallMinimumChi2;
362 }
363 //---------------------------------------------------------------------------
365  int Offset,
366  int Distance,
367  bool newCharges) {
368  //
369  // Does a fit to dual signal pulse hypothesis given offset and distance of the two target pulses
370  //
371  // The only parameters to fit here are the two pulse heights of in-time and out-of-time components
372  // since offset is given
373  // The calculation here is based from writing down the Chi2 formula and minimize against the two parameters,
374  // ie., Chi2 = Sum{((T[i] - a1 * F1[i] - a2 * F2[i]) / (Sigma[i]))^2}, where T[i] is the input pulse shape,
375  // and F1[i], F2[i] are the two ideal pulse components
376  //
377 
378  int DigiSize = Charge.size();
379 
380  if (Offset < 0 || Offset + 250 >= (int)CumulativeIdealPulse.size())
381  return 1000000;
382  if (CumulativeIdealPulse[Offset + 250] - CumulativeIdealPulse[Offset] < 1e-5)
383  return 1000000;
384 
385  if (newCharges) {
386  f1_.resize(DigiSize);
387  f2_.resize(DigiSize);
388  errors_.resize(DigiSize);
389  for (int j = 0; j < DigiSize; j++) {
390  errors_[j] = Charge[j];
391  if (errors_[j] < 1)
392  errors_[j] = 1;
393  errors_[j] = 1.0 / errors_[j];
394  }
395  }
396 
397  double SumF1F1 = 0;
398  double SumF1F2 = 0;
399  double SumF2F2 = 0;
400  double SumTF1 = 0;
401  double SumTF2 = 0;
402 
403  unsigned int cipSize = CumulativeIdealPulse.size();
404  for (int j = 0; j < DigiSize; j++) {
405  // this is the TS value for in-time component - no problem we can do a subtraction directly
406  f1_[j] = CumulativeIdealPulse[Offset + j * 25 + 25] - CumulativeIdealPulse[Offset + j * 25];
407 
408  // However for the out-of-time component the index might go out-of-bound.
409  // Let's protect against this.
410 
411  int OffsetTemp = Offset + j * 25 + Distance;
412 
413  double C1 = 0; // lower-indexed value in the cumulative pulse shape
414  double C2 = 0; // higher-indexed value in the cumulative pulse shape
415 
416  if (OffsetTemp + 25 >= (int)cipSize)
417  C1 = CumulativeIdealPulse[cipSize - 1];
418  else if (OffsetTemp >= -25)
419  C1 = CumulativeIdealPulse[OffsetTemp + 25];
420  if (OffsetTemp >= (int)cipSize)
421  C2 = CumulativeIdealPulse[cipSize - 1];
422  else if (OffsetTemp >= 0)
423  C2 = CumulativeIdealPulse[OffsetTemp];
424  f2_[j] = C1 - C2;
425 
426  SumF1F1 += f1_[j] * f1_[j] * errors_[j];
427  SumF1F2 += f1_[j] * f2_[j] * errors_[j];
428  SumF2F2 += f2_[j] * f2_[j] * errors_[j];
429  SumTF1 += f1_[j] * Charge[j] * errors_[j];
430  SumTF2 += f2_[j] * Charge[j] * errors_[j];
431  }
432 
433  double Height = 0;
434  double Height2 = 0;
435  if (fabs(SumF1F2 * SumF1F2 - SumF1F1 * SumF2F2) > 1e-5) {
436  Height = (SumF1F2 * SumTF2 - SumF2F2 * SumTF1) / (SumF1F2 * SumF1F2 - SumF1F1 * SumF2F2);
437  Height2 = (SumF1F2 * SumTF1 - SumF1F1 * SumTF2) / (SumF1F2 * SumF1F2 - SumF1F1 * SumF2F2);
438  }
439 
440  double Chi2 = 0;
441  for (int j = 0; j < DigiSize; j++) {
442  double Residual = Height * f1_[j] + Height2 * f2_[j] - Charge[j];
443  Chi2 += Residual * Residual * errors_[j];
444  }
445 
446  // Safety protection in case of zero
447  if (Chi2 < 1e-5)
448  Chi2 = 1e-5;
449 
450  return Chi2;
451 }
452 //---------------------------------------------------------------------------
453 double HBHEPulseShapeFlagSetter::CalculateRMS8Max(const std::vector<double>& Charge) {
454  //
455  // CalculateRMS8Max
456  //
457  // returns "RMS" divided by the largest charge in the time slices
458  // "RMS" is calculated using all but the two largest time slices.
459  // The "RMS" is not quite the actual RMS (see note below), but the value is only
460  // used for determining max values, and is not quoted as the actual RMS anywhere.
461  //
462 
463  int DigiSize = Charge.size();
464 
465  if (DigiSize <= 2)
466  return 1e-5; // default statement when DigiSize is too small for useful RMS calculation
467  // Copy Charge vector again, since we are passing references around
468  std::vector<double> TempCharge = Charge;
469 
470  // Sort TempCharge vector from smallest to largest charge
471  sort(TempCharge.begin(), TempCharge.end());
472 
473  double Total = 0;
474  double Total2 = 0;
475  for (int i = 0; i < DigiSize - 2; i++) {
476  Total = Total + TempCharge[i];
477  Total2 = Total2 + TempCharge[i] * TempCharge[i];
478  }
479 
480  // This isn't quite the RMS (both Total2 and Total*Total need to be
481  // divided by an extra (DigiSize-2) within the sqrt to get the RMS.)
482  // We're only using this value for relative comparisons, though; we
483  // aren't explicitly interpreting it as the RMS. It might be nice
484  // to either change the calculation or rename the variable in the future, though.
485 
486  double RMS = sqrt(Total2 - Total * Total / (DigiSize - 2));
487 
488  double RMS8Max = RMS / TempCharge[DigiSize - 1];
489  if (RMS8Max < 1e-5) // protection against zero
490  RMS8Max = 1e-5;
491 
492  return RMS8Max;
493 }
494 //---------------------------------------------------------------------------
495 double HBHEPulseShapeFlagSetter::PerformLinearFit(const std::vector<double>& Charge) {
496  //
497  // Performs a straight-line fit over all time slices, and returns the chi2 value
498  //
499  // The calculation here is based from writing down the formula for chi2 and minimize
500  // with respect to the parameters in the fit, ie., slope and intercept of the straight line
501  // By doing two differentiation, we will get two equations, and the best parameters are determined by these
502  //
503 
504  int DigiSize = Charge.size();
505 
506  double SumTS2OverTi = 0;
507  double SumTSOverTi = 0;
508  double SumOverTi = 0;
509  double SumTiTS = 0;
510  double SumTi = 0;
511 
512  double Error2 = 0;
513  for (int i = 0; i < DigiSize; i++) {
514  Error2 = Charge[i];
515  if (Charge[i] < 1)
516  Error2 = 1;
517 
518  SumTS2OverTi += 1. * i * i / Error2;
519  SumTSOverTi += 1. * i / Error2;
520  SumOverTi += 1. / Error2;
521  SumTiTS += Charge[i] * i / Error2;
522  SumTi += Charge[i] / Error2;
523  }
524 
525  double CM1 = SumTS2OverTi; // Coefficient in front of slope in equation 1
526  double CM2 = SumTSOverTi; // Coefficient in front of slope in equation 2
527  double CD1 = SumTSOverTi; // Coefficient in front of intercept in equation 1
528  double CD2 = SumOverTi; // Coefficient in front of intercept in equation 2
529  double C1 = SumTiTS; // Constant coefficient in equation 1
530  double C2 = SumTi; // Constant coefficient in equation 2
531 
532  // Denominators always non-zero by construction
533  double Slope = (C1 * CD2 - C2 * CD1) / (CM1 * CD2 - CM2 * CD1);
534  double Intercept = (C1 * CM2 - C2 * CM1) / (CD1 * CM2 - CD2 * CM1);
535 
536  // now that the best parameters are found, calculate chi2 from those
537  double Chi2 = 0;
538  for (int i = 0; i < DigiSize; i++) {
539  double Deviation = Slope * i + Intercept - Charge[i];
540  double Error2 = Charge[i];
541  if (Charge[i] < 1)
542  Error2 = 1;
543  Chi2 += Deviation * Deviation / Error2;
544  }
545 
546  // safety protection in case of perfect fit
547  if (Chi2 < 1e-5)
548  Chi2 = 1e-5;
549 
550  return Chi2;
551 }
552 //---------------------------------------------------------------------------
554  double Discriminant,
555  std::vector<std::pair<double, double> >& Cuts,
556  int Side) {
557  //
558  // Checks whether Discriminant value passes Cuts for the specified Charge. True if pulse is good.
559  //
560  // The "Cuts" pairs are assumed to be sorted in terms of size from small to large,
561  // where each "pair" = (Charge, Discriminant)
562  // "Side" is either positive or negative, which determines whether to discard the pulse if discriminant
563  // is greater or smaller than the cut value
564  //
565 
566  if (Cuts.empty()) // safety check that there are some cuts defined
567  return true;
568 
569  if (Charge <= Cuts[0].first) // too small to cut on
570  return true;
571 
572  int IndexLargerThanCharge = -1; // find the range it is falling in
573  for (int i = 1; i < (int)Cuts.size(); i++) {
574  if (Cuts[i].first > Charge) {
575  IndexLargerThanCharge = i;
576  break;
577  }
578  }
579 
580  double limit = 1000000;
581 
582  if (IndexLargerThanCharge == -1) // if charge is greater than the last entry, assume flat line
583  limit = Cuts[Cuts.size() - 1].second;
584  else // otherwise, do a linear interpolation to find the cut position
585  {
586  double C1 = Cuts[IndexLargerThanCharge].first;
587  double C2 = Cuts[IndexLargerThanCharge - 1].first;
588  double L1 = Cuts[IndexLargerThanCharge].second;
589  double L2 = Cuts[IndexLargerThanCharge - 1].second;
590 
591  limit = (Charge - C1) / (C2 - C1) * (L2 - L1) + L1;
592  }
593 
594  if (Side > 0 && Discriminant > limit)
595  return false;
596  if (Side < 0 && Discriminant < limit)
597  return false;
598 
599  return true;
600 }
601 //---------------------------------------------------------------------------
std::vector< double > f1_
std::vector< std::pair< double, double > > mLambdaLinearCut
HBHEPulseShapeFlagSetter(double MinimumChargeThreshold, double TS4TS5ChargeThreshold, double TS3TS4ChargeThreshold, double TS3TS4UpperChargeThreshold, double TS5TS6ChargeThreshold, double TS5TS6UpperChargeThreshold, double R45PlusOneRange, double R45MinusOneRange, unsigned int TrianglePeakTS, const std::vector< double > &LinearThreshold, const std::vector< double > &LinearCut, const std::vector< double > &RMS8MaxThreshold, const std::vector< double > &RMS8MaxCut, const std::vector< double > &LeftSlopeThreshold, const std::vector< double > &LeftSlopeCut, const std::vector< double > &RightSlopeThreshold, const std::vector< double > &RightSlopeCut, const std::vector< double > &RightSlopeSmallThreshold, const std::vector< double > &RightSlopeSmallCut, const std::vector< double > &TS4TS5UpperThreshold, const std::vector< double > &TS4TS5UpperCut, const std::vector< double > &TS4TS5LowerThreshold, const std::vector< double > &TS4TS5LowerCut, bool UseDualFit, bool TriangleIgnoreSlow, bool setLegacyFlags=true)
std::vector< double > f2_
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)
T sqrt(T t)
Definition: SSEVec.h:19
std::vector< std::pair< double, double > > mRightSlopeCut
bool CheckPassFilter(double Charge, double Discriminant, std::vector< std::pair< double, double > > &Cuts, int Side)
isFirst
Definition: cuy.py:418
std::vector< double > mCharge
const Shape & hbShape() const
std::vector< std::pair< double, double > > mRightSlopeSmallCut
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:163
Definition: Chi2.h:15
std::vector< std::pair< double, double > > mTS4TS5UpperCut
float at(double time) const