Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
/* 
 *  \class PulseFitWithFunction
 *
 *  \author: Patrick Jarry - CEA/Saclay
 */

// File PulseFitWithFunction.cxx
// ===========================================================
// ==                                                       ==
// ==     Class for a function fit method                   ==
// ==                                                       ==
// ==  Date:   July 17th 2003                               ==
// ==  Author: Patrick Jarry                                ==
// ==                                                       ==
// ==                                                       ==
// ===========================================================

#include "CalibCalorimetry/EcalLaserAnalyzer/interface/PulseFitWithFunction.h"

#include <iostream>
#include "TMath.h"

//ClassImp(PulseFitWithFunction)

// Constructor...
PulseFitWithFunction::PulseFitWithFunction() {
  fNsamples = 0;
  fNum_samp_bef_max = 0;
  fNum_samp_after_max = 0;
}

// Destructor
PulseFitWithFunction::~PulseFitWithFunction() {}

// Initialisation

void PulseFitWithFunction::init(int n_samples, int samplb, int sampla, int niter, double alfa, double beta) {
  //printf("\n");
  //printf(" =========================================================\n");
  //printf(" ==     Initialising the function fit method            ==\n");
  //printf(" ==          PulseFitWithFunction::init                 ==\n");
  //printf(" ==                                                     ==\n");

  fNsamples = n_samples;
  fAlpha_laser = alfa;
  fBeta_laser = beta;
  fAlpha_beam = 0.98;
  fBeta_beam = 2.04;
  fNb_iter = niter;
  fNum_samp_bef_max = samplb;
  fNum_samp_after_max = sampla;
  //printf(" ==  # samples used = %3d                               ==\n",fNsamples);
  //printf(" ==  #sample before max= %1d and #sample after maximum= %1d ==\n",fNum_samp_bef_max,fNum_samp_after_max);
  //printf(" ==           alpha= %5.4f       beta= %5.4f          ==\n",fAlpha_laser,fBeta_laser);
  //printf(" =========================================================\n\n");
  return;
}

// Compute the amplitude using as input the Crystaldata
double PulseFitWithFunction::doFit(double *adc) {
  double parout[4];  // amp_max ;
                     //double amp_parab , tim_parab ;
  double chi2;
  //int imax ;
  //
  // first  one has to get starting point first with parabolic fun// //
  Fit_parab(&adc[0], 3, fNsamples, parout);
  amp_parab = parout[0];
  tim_parab = parout[1];
  imax = (int)parout[2];
  amp_max = parout[3];
  //printf("amp_parab= %f tim_parab=%f amp_max=%f imax=%d\n",amp_parab,tim_parab,amp_max,imax);
  fNumber_samp_max = imax;
  //

  if (amp_parab < 1.) {
    tim_parab = (double)imax;
    amp_parab = amp_max;
  }
  //
  fValue_tim_max = tim_parab;
  fFunc_max = amp_parab;
  fTim_max = tim_parab;

  //  here to fit maximum amplitude and time of arrival ...

  chi2 = Fit_electronic(0, &adc[0], 8.);
  // adc is an array to be filled with samples
  // 0 is for Laser (1 for electron)
  // 8 is for sigma of pedestals
  // which (can be computed)

  //  double amplitude = fAmp_fitted_max ; // amplitude fitted
  // double time = fTim_fitted_max ; // time fitted

  return chi2;  // return amplitude fitted
}

//-----------------------------------------------------------------------
//----------------------------------------------------------------------

/*************************************************/
double PulseFitWithFunction::Fit_electronic(int data, double *adc_to_fit, double sigmas_sample) {
  // fit electronic function from simulation
  // parameters fAlpha and fBeta are fixed and fit is providing
  // the maximum amplitude ( fAmp_fitted_max ) and the time of
  // the maximum amplitude ( fTim_fitted_max)
  // initialization of parameters
  double chi2 = 0;
  double d_alpha, d_beta;
  // first initialize parameters fAlpha and fBeta ( depending of beam or laser)
  fAlpha = fAlpha_laser;
  fBeta = fBeta_laser;
  if (data == 1) {
    fAlpha = fAlpha_beam;
    fBeta = fBeta_beam;
  }
  //
  fAmp_fitted_max = 0.;
  fTim_fitted_max = 0.;
  double un_sur_sigma = 1.;
  double variation_func_max = 0.;
  double variation_tim_max = 0.;
  //
  if (fValue_tim_max > 20. || fValue_tim_max < 3.) {
    fValue_tim_max = fNumber_samp_max;
  }
  int num_fit_min = (int)(fValue_tim_max - fNum_samp_bef_max);
  int num_fit_max = (int)(fValue_tim_max + fNum_samp_after_max);
  //

  if (sigmas_sample > 0.)
    un_sur_sigma = 1. / sigmas_sample;

  double func, delta;
  //          Loop on iterations
  for (int iter = 0; iter < fNb_iter; iter++) {
    //          initialization inside iteration loop !
    chi2 = 0.;
    double d11 = 0.;
    double d12 = 0.;
    double d22 = 0.;
    double z1 = 0.;
    double z2 = 0.;
    fFunc_max += variation_func_max;
    fTim_max += variation_tim_max;
    int nsamp_used = 0;
    //

    // Then we loop on samples to be fitted

    for (int i = num_fit_min; i < num_fit_max + 1; i++) {
      // calculate function to be fitted

      func = Electronic_shape((double)i);

      // then calculate derivatives of function to be fitted
      double dt = (double)i - fTim_max;
      double alpha_beta = fAlpha * fBeta;

      if (dt > -alpha_beta) {
        double dt_sur_beta = dt / fBeta;

        double variable = (double)1. + dt / alpha_beta;
        double expo = TMath::Exp(-dt_sur_beta);

        double puissance = TMath::Power(variable, fAlpha);
        d_alpha = un_sur_sigma * puissance * expo;
        d_beta = fFunc_max * d_alpha * dt_sur_beta / (alpha_beta * variable);
      } else {
        continue;
      }

      nsamp_used++;  // number of samples used inside the fit
      // compute matrix elements D (symetric --> d12 = d21 )
      d11 += d_alpha * d_alpha;
      d12 += d_alpha * d_beta;
      d22 += d_beta * d_beta;
      // compute delta
      delta = (adc_to_fit[i] - func) * un_sur_sigma;
      // compute vector elements Z
      z1 += delta * d_alpha;
      z2 += delta * d_beta;
      chi2 += delta * delta;
    }  //             end of loop on samples
    double denom = d11 * d22 - d12 * d12;
    if (denom == 0.) {
      //printf( "attention denom = 0 signal pas fitte \n") ;
      return 101;
    }
    if (nsamp_used < 3) {
      //printf( "Attention nsamp = %d ---> no function fit provided \n",nsamp_used) ;
      return 102;
    }
    // compute variations of parameters fAmp_max and fTim_max
    variation_func_max = (z1 * d22 - z2 * d12) / denom;
    variation_tim_max = (-z1 * d12 + z2 * d11) / denom;
    chi2 = chi2 / ((double)nsamp_used - 2.);
  }  //      end of loop on iterations
  // results of the fit are calculated
  fAmp_fitted_max = fFunc_max + variation_func_max;
  fTim_fitted_max = fTim_max + variation_tim_max;
  //
  return chi2;
}

//-----------------------------------------------------------------------
//----------------------------------------------------------------------

double PulseFitWithFunction::Electronic_shape(double tim) {
  // electronic function (from simulation) to fit ECAL pulse shape
  double func_electronic, dtsbeta, variable, puiss;
  double albet = fAlpha * fBeta;
  if (albet <= 0)
    return ((Double_t)0.);
  double dt = tim - fTim_max;
  if (dt > -albet) {
    dtsbeta = dt / fBeta;
    variable = 1. + dt / albet;
    puiss = TMath::Power(variable, fAlpha);
    func_electronic = fFunc_max * puiss * TMath::Exp(-dtsbeta);
  } else
    func_electronic = 0.;
  //
  return func_electronic;
}
void PulseFitWithFunction::Fit_parab(Double_t *ampl, Int_t nmin, Int_t nmax, Double_t *parout) {
  /* Now we calculate the parabolic adjustement in order to get        */
  /*    maximum and time max                                           */

  double denom, dt, amp1, amp2, amp3;
  double ampmax = 0.;
  int imax = 0;
  int k;
  /*
                                                                   */
  for (k = nmin; k < nmax; k++) {
    //printf("ampl[%d]=%f\n",k,ampl[k]);
    if (ampl[k] > ampmax) {
      ampmax = ampl[k];
      imax = k;
    }
  }
  amp1 = ampl[imax - 1];
  amp2 = ampl[imax];
  amp3 = ampl[imax + 1];
  denom = 2. * amp2 - amp1 - amp3;
  /* 	       					             */
  if (denom > 0.) {
    dt = 0.5 * (amp3 - amp1) / denom;
  } else {
    //printf("denom =%f\n",denom)  ;
    dt = 0.5;
  }
  /* 						                     */
  /* ampmax correspond au maximum d'amplitude parabolique et dt        */
  /* decalage en temps par rapport au sample maximum soit k + dt       */

  parout[0] = amp2 + (amp3 - amp1) * dt * 0.25;
  parout[1] = (double)imax + dt;
  parout[2] = (double)imax;
  parout[3] = ampmax;
  return;
}