ATLAS Offline Software
Loading...
Searching...
No Matches
BipolarFit.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3*/
4
6// A programme to determine the parameters of
7// a bipolar pulse by chi2 minimization
8//
9// http://knikolop.home.cern.ch/knikolop/csc/bipolarfit.c
10//
11// for the function of the bipolar pulse look
12// http://positron.ps.uci.edu/~schernau/ROD/SIT/results/cluster1.html
13//
14// Konstantinos Nikolopoulos
15// 23/5/2007
16//
17// This is temporary
18
19// this version : 27/7/2007
21#include "BipolarFit.h"
22#include <stdio.h>
23#include <iostream>
25{
26 m_n=12.;
27 m_powcachez = -9999.;
28 m_powcachezn= -9999.;
29 m_zmax= m_n+1 - std::sqrt(m_n+1.0);
31 m_tsampling = 25.;
32
33}
34
37
38 double
40{
41 if(std::abs(m_powcachez-z)<1.e-4)
42 return m_powcachezn;
43
44 double zpower = z*z*z;
45 zpower *= zpower;
46 zpower *= zpower;
47
48 m_powcachez = z;
49 m_powcachezn= zpower;
50 return zpower;
51}
52
53 double
54BipolarFit::FindInitValues(double*x,double *initValues,int *maxsample)
55{
56 // find maximum sample imax:
57 double peakingTime=-99.; // interpolated peaking time in samples
58 double amplitude=-99.; // interpolated amplitude
59 double amin, amax;
60 int imax = 0;
61 const int numSample=4;
62 amax = x[0];
63 amin = x[0];
64 for(int j=1; j<numSample; j++)
65 {
66 if(amax<x[j])
67 {
68 amax = x[j];
69 imax = j;
70 }
71 if(amin>x[j])
72 amin = x[j];
73 }
74
75 // calculate peak and amplitude:
76 (*maxsample)=imax;
77 if((imax==0) || (imax==numSample-1)) // no interpolation possible
78 {
79 peakingTime = imax;
80 amplitude = amax;
81 }
82 else // do parabolic interpolation
83 {
84 double a, b, c; // coeffients of parabola y=a*x*x+b*x+c
85 a = 0.5*(x[imax+1]+x[imax-1]-2.0*x[imax]);
86 b = 0.5*(x[imax+1]-x[imax-1]);
87 c = x[imax];
88
89 peakingTime = -0.5*b/a;
90 amplitude = a*peakingTime*peakingTime + b*peakingTime + c;
91 peakingTime += imax; // it was relative to imax
92 }
93
94 initValues[0] = amplitude;
95 initValues[1] = peakingTime - m_zmax*initValues[2]/m_tsampling;
96 return x[imax];
97}
98
99 double
100BipolarFit::bipolar(double *x, double *parm) // the bipolar pulse function
101{
102 // the bipolar pulse function is
103 //
104 // z = (x-parm[0])*m_tsampling/parm[3]
105 // m_zmax = m_n+1 - sqrt(m_n+1)
106 // aa = exp(m_n*log(m_zmax))*(1-m_zmax/(m_n+1))*exp(-m_zmax)
107 // parm[0]*exp(m_n*log(z))*(1-z/(m_n+1))*exp(-z)/aa
108 //
109 // for timing reasons instead of x (ie # of sample)
110 // the z is given
111 double z = x[0];
112
113
114 //const double m_tsampling = 25.;// nsec
115 //z=(x[0]-parm[1])*m_tsampling/(parm[2]);
116 if(z<0.)
117 return 0.;
118
119 return parm[0]*FindPow(z)*(1-z/(m_n+1))*std::exp(-z)/m_bipolarNormalization;
120}
121
122 void
123BipolarFit::Derivative(double A[][3],double fp[][1], double p0[][1],int imeas, int*meas)
124{
125 //calculate the derivatives and the 0th order approximation
126 //around the ADC samplings
127 double norm = p0[0][0];
128 //double parm[3]={1.,p0[1][0],p0[2][0]};
129 for(int i=0;i<imeas;i++)
130 {
131 int ii = meas[i];
132 double z = (ii-p0[1][0])*m_tsampling/p0[2][0];
133 double repquant = 0.;
134 double dFdzNormalized = 0.;
135 if(z>0.)
136 {
137 repquant = FindPow(z)*std::exp(-z)/m_bipolarNormalization;
138 dFdzNormalized= repquant*(m_n/z+z/13.-2.);
139 }
140
141 A[ii][0] = repquant*(1.-z/13.);
142 //A[ii][0] = bipolar(&z,parm);
143 fp[ii][0] = norm * A[ii][0];
144
145 //double normOverZmax = norm/m_bipolarNormalization;
146 double commonpart = norm* dFdzNormalized;//(z,parm);
147 A[ii][1] = commonpart * (-m_tsampling/p0[2][0]);
148 A[ii][2] = commonpart * (-z/p0[2][0]);
149 }
150 // end of derivative/zeroth order calculations
151}
152
153//void BipolarFit::InvertMatrix(HepMatrix& matrix,const int dim,int*correspdim)
154void BipolarFit::InvertMatrix(double matrix[][3],const int dim,int*correspdim)
155{
156 // invert 2x2 or 3x3 symmetric matrix
157 if(dim==2)
158 {
159 int ii=correspdim[0];
160 int jj=correspdim[1];
161 double determinant= -matrix[jj][ii]*matrix[ii][jj] +matrix[ii][ii]*matrix[jj][jj];
162 double i00 = matrix[ii][ii];
163 matrix[ii][ii] = matrix[jj][jj]/determinant;
164 matrix[jj][jj] = i00/determinant;
165 matrix[ii][jj] = -matrix[ii][jj]/determinant;
166 matrix[jj][ii] = matrix[ii][jj];
167
168 }
169 else if(dim==3)
170 {
171 double sm12 = matrix[0][1]*matrix[0][1];
172 double sm13 = matrix[0][2]*matrix[0][2];
173 double sm23 = matrix[1][2]*matrix[1][2];
174 double determinant = matrix[0][0]*matrix[1][1]*matrix[2][2]
175 -matrix[0][0]*sm23-sm12*matrix[2][2]
176 +2.*matrix[0][1]*matrix[0][2]*matrix[1][2]
177 -matrix[1][1]*sm13;
178
179 double i00 = matrix[1][1]*matrix[2][2]-sm23;
180 double i11 = matrix[0][0]*matrix[2][2]-sm13;
181 double i22 = matrix[0][0]*matrix[1][1]-sm12;
182
183 matrix[1][0] = (matrix[0][2]*matrix[1][2]-matrix[2][2]*matrix[0][1])/determinant;
184 matrix[2][0] = (matrix[0][1]*matrix[1][2]-matrix[0][2]*matrix[1][1])/determinant;
185 matrix[2][1] = (matrix[0][1]*matrix[0][2]-matrix[0][0]*matrix[1][2])/determinant;
186 matrix[0][1] = matrix[1][0];
187 matrix[0][2] = matrix[2][0];
188 matrix[1][2] = matrix[2][1];
189 matrix[0][0] = i00/determinant;
190 matrix[1][1] = i11/determinant;
191 matrix[2][2] = i22/determinant;
192
193 }
194 else
195 {
196 //int ierr;
197 //matrix.invert(ierr);
198 printf("this is not a 2x2 or 3x3 matrix\n");
199 }
200}
201
202 int
203BipolarFit::Fit(double *x,const double ex,const double pedestal, const double predefinedwidth,double *result,double * ,double *chi2)
204{
234
235 // initial parameter estimates using parabola interpolation
236 double initValues[3]={0.};
237 int imax = -1;
238 initValues[2]=predefinedwidth;
239 double samplemax = FindInitValues(x,initValues,&imax);
240 result[0] = initValues[0];
241 result[1] = initValues[1];
242 result[2] = initValues[2];
243
244 // do not fit noise
245 if(samplemax < 5.*ex)
246 return 7;
247
248 bool onesaturated = false;
249 if(imax==0)
250 {
251 if(x[imax+1]<0. && x[imax+2]<0.)
252 return 8;
253 }
254 else if(imax==3)
255 {
256 // don't fit too late pulses
257 if(initValues[1]+m_zmax*initValues[2]/m_tsampling>2.75)
258 return 9;
259 }
260 else
261 {
262 if(x[imax-1]<0. && (x[imax+1]<2. || -x[imax-1]-x[imax]>0.))
263 return 8;
264 if(x[imax]+pedestal>4000.)
265 {
266 if(x[imax-1]+pedestal>4000. || x[imax+1]+pedestal>4000.)
267 return 6;
268 else
269 {
270 onesaturated=true;
271 }
272 }
273 }
274 //always fix width and fit two parameters
275 bool fitpar[3] = {true,true,false};
276 bool usemeas[4] = {true,true,true,true};
277 if(initValues[1]+m_zmax*initValues[2]/m_tsampling<2.0)
278 {
279 fitpar[2] = false;
280 usemeas[3]= false;
281 }
282 //if(initValues[1]>0.)
283 //{
284 // usemeas[0]= false;
285 // fitpar[2] = false;
286 //}
287
288 if(onesaturated)
289 {
290 usemeas[imax]= false;
291 fitpar[2] = false;
292 }
293 int imeas =0;
294 int meas[4] = {0};
295 for(int i=0;i<4;i++)
296 if(usemeas[i])
297 {
298 meas[imeas]=i;
299 imeas++;
300 }
301 int ipar =0;
302 int par[3] = {0};
303 for(int i=0;i<3;i++)
304 if(fitpar[i])
305 {
306 par[ipar]=i;
307 ipar++;
308 }
309
310 int FitStatus = TheFitter(x,ex,initValues,imeas,meas,ipar,par,chi2,result);
311 // the parabola interpolated estimate is most of the time a lower bound (for high pulses)!
312 if(result[0]> 10.*ex && result[0]<0.90*initValues[0])
313 {
314 result[0] = initValues[0];
315 return 10;
316 }
317
318 if(onesaturated)
319 return 5;
320
321
322 return FitStatus;
323}
324
325 void
327{
328 double Determinant = W[0][3]*W[0][3]*W[1][2]*W[1][2] - 2.*W[0][2]*W[0][3]*W[1][2]*W[1][3]
329 +W[0][2]*W[0][2]*W[1][3]*W[1][3]-W[0][3]*W[0][3]*W[1][1]*W[2][2] + 2.*W[0][1]*W[0][3]*W[1][3]*W[2][2] - W[0][0]*W[1][3]*W[1][3]*W[2][2]+2.*W[0][2]*W[0][3]*W[1][1]*W[2][3]
330 - 2.*W[0][1]*W[0][3]*W[1][2]*W[2][3] - 2.*W[0][1]*W[0][2]*W[1][3]*W[2][3]+2.*W[0][0]*W[1][2]*W[1][3]*W[2][3]+W[0][1]*W[0][1]*W[2][3]*W[2][3]-W[0][0]*W[1][1]*W[2][3]*W[2][3]-W[0][2]*W[0][2]*W[1][1]*W[3][3]+2.*W[0][1]*W[0][2]*W[1][2]*W[3][3]-W[0][0]*W[1][2]*W[1][2]*W[3][3]-W[0][1]*W[0][1]*W[2][2]*W[3][3]+W[0][0]*W[1][1]*W[2][2]*W[3][3];
331
332 W[0][1] = W[3][0]*W[3][1]*W[2][2]-W[3][0]*W[2][1]*W[3][2] - W[2][0]*W[3][1]*W[3][2]+W[1][0]*W[3][2]*W[3][2]+W[2][0]*W[2][1]*W[3][3]-W[1][0]*W[2][2]*W[3][3];
333 W[0][2] = -W[3][0]*W[2][1]*W[3][1]+W[2][0]*W[3][1]*W[3][1]+W[3][0]*W[1][1]*W[3][2]-W[1][0]*W[3][1]*W[3][2]-W[2][0]*W[1][1]*W[3][3]+W[1][0]*W[2][1]*W[3][3];
334 W[0][3] = W[3][0]*W[2][1]*W[2][1]-W[2][0]*W[2][1]*W[3][1]-W[3][0]*W[1][1]*W[2][2]+W[1][0]*W[3][1]*W[2][2]+W[2][0]*W[1][1]*W[3][2]-W[1][0]*W[2][1]*W[3][2];
335 W[1][2] = W[3][0]*W[3][0]*W[2][1]-W[2][0]*W[3][0]*W[3][1]-W[1][0]*W[3][0]*W[3][2]+W[0][0]*W[3][1]*W[3][2]+W[1][0]*W[2][0]*W[3][3]-W[0][0]*W[2][1]*W[3][3];
336
337 W[1][3] = -W[2][0]*W[3][0]*W[2][1]+W[2][0]*W[2][0]*W[3][1]+W[1][0]*W[3][0]*W[2][2]-W[0][0]*W[3][1]*W[2][2]-W[1][0]*W[2][0]*W[3][2]+W[0][0]*W[2][1]*W[3][2];
338 W[2][3] = W[2][0]*W[3][0]*W[1][1]-W[1][0]*W[3][0]*W[2][1]-W[1][0]*W[2][0]*W[3][1]+W[0][0]*W[2][1]*W[3][1]+W[1][0]*W[1][0]*W[3][2]-W[0][0]*W[1][1]*W[3][2];
339
340 double W00 = -W[3][1]*W[3][1]*W[2][2]+2.*W[2][1]*W[3][1]*W[3][2]-W[1][1]*W[3][2]*W[3][2]-W[2][1]*W[2][1]*W[3][3]+W[1][1]*W[2][2]*W[3][3];
341 double W11 = -W[3][0]*W[3][0]*W[2][2]+2.*W[2][0]*W[3][0]*W[3][2]-W[0][0]*W[3][2]*W[3][2]-W[2][0]*W[2][0]*W[3][3]+W[0][0]*W[2][2]*W[3][3];
342 double W22 = -W[3][0]*W[3][0]*W[1][1]+2.*W[1][0]*W[3][0]*W[3][1]-W[0][0]*W[3][1]*W[3][1]-W[1][0]*W[1][0]*W[3][3]+W[0][0]*W[1][1]*W[3][3];
343 double W33 = -W[2][0]*W[2][0]*W[1][1]+2.*W[1][0]*W[2][0]*W[2][1]-W[0][0]*W[2][1]*W[2][1]-W[1][0]*W[1][0]*W[2][2]+W[0][0]*W[1][1]*W[2][2];
344
345 for(int i=0;i<3;i++)
346 {
347 for(int j=1;j<4;j++)
348 {
349 if(i>=j)
350 continue;
351 W[i][j] = W[i][j]/Determinant;
352 W[j][i] = W[i][j];
353 }
354 }
355 W[0][0] = W00/Determinant;
356 W[1][1] = W11/Determinant;
357 W[2][2] = W22/Determinant;
358 W[3][3] = W33/Determinant;
359}
360
361 int
362BipolarFit::TheFitter(double*x,const double ex,double *initValues, int imeas, int *meas, int ipar, int *par,double *chi2,double *result)
363{
364 // maximum iterations
365 const int maxIter = 7;
366 // tolerances
367 double fitTolerance0 = 0.10;
368 double fitTolerance1 = 0.01;
369 //HepMatrix p0(3,1,0); // the matrix of the initial fit parameters
370 double p0[3][1]={{0.}};
371 for(int j=0;j<3;j++)
372 p0[j][0] = initValues[j];
373
374 //HepMatrix m(4,1,0); // the matrix of ADC measurements (samples: 0,1,2,3)
375 double m[4][1]={{0.}};
376 //HepMatrix W(4,4,0); // the error matrix of the ADC measurements
377 double W[4][4]={{0.}};
378 for(int i=0;i<4;i++)
379 {
380 m[i][0] = x[i];
381 W[i][i] = ex*ex;
382 }
383 // covariances
384 W[0][1] = 0.03*ex*ex;
385 W[0][2] = -0.411*ex*ex;
386 W[0][3] = -0.188*ex*ex;
387 W[1][2] = 0.0275*ex*ex;
388 W[1][3] = -0.4303*ex*ex;
389 W[2][3] = 0.*ex*ex;
390 W[1][0] = W[0][1];
391 W[2][0] = W[0][2];
392 W[3][0] = W[0][3];
393 W[2][1] = W[1][2];
394 W[3][1] = W[1][3];
395 W[3][2] = W[2][3];
396
397 //WW.invert(ierr);
399
400 // Taylor expansion of the bipolar pulse model around the
401 // samplings : F(x) = F(p0) + A *(p-p0) + higher.order
402 //HepMatrix fp(4,1,0); // the matrix of 0th order approximation
403 double fp[4][1]={{0.}};
404 //HepMatrix A(4,3,0); // the matrix of derivatives
405 double A[4][3]={{0.}};
406 // remarks :
407 // if the pulse peaks in the last sampling fit with a constant shaping time
408 // if the pulse peaks in the first sampling fit without using the last sampling
409 // (too large contribution to the chi2
410 int counter=0;
411 bool converged=false;
412 double amplitudeChangeOld = 0.;
413 bool diverganceCandidate = false;
414 //HepMatrix weight(3,3,1); // weight matrix allocated once
415 // the non-fitted parts are taken care appropriately
416 // at least if the fitting parameters or measurements
417 // don't change during the fitting procedure
418 double weight[3][3]={{0.}};
419 weight[0][0]=1.;
420 weight[1][1]=1.;
421 weight[2][2]=1.;
422
423 //HepMatrix residFactor(3,4,0); // residFactor allocated once
424 double residFactor[3][4]={{0.}};
425 while(!converged && counter<maxIter) // fit loop
426 {
427 Derivative(A,fp,p0,imeas,meas);// calculate the matrix of derivatives and 0th order approximation
428 // matrix multiplication
429 // the weight matrix is symmetric
430 // weight= A.T()*W*A;//.assign(A.T()*W*A);
431
432 double helpmatrix[4][3]={{0.}};
433 for(int i=0;i<imeas;i++)
434 {
435 int ii=meas[i];
436 for(int j=0;j<ipar;j++)
437 {
438 int jj=par[j];
439 for(int k=0;k<imeas;k++)
440 {
441 int kk=meas[k];
442 helpmatrix[ii][jj] += W[ii][kk]*A[kk][jj];
443 }
444 }
445 }
446 for(int i=0;i<ipar;i++)
447 {
448 int ii=par[i];
449 for(int j=i;j<ipar;j++)
450 {
451 int jj=par[j];
452 weight[ii][jj] = 0.;
453 for(int k=0;k<imeas;k++)
454 {
455 int kk=meas[k];
456 weight[ii][jj] += A[kk][ii]*helpmatrix[kk][jj];//A[kk][ii]*A[kk][jj];
457 }
458 //weight[ii][jj]*=W[0][0];
459 weight[jj][ii] =weight[ii][jj];
460 }
461 }
462 //weight.invert(ierr); // inversion of weight matrix
463 // hand-made inversion of 2x2 or 3x3 symmetric matrix
464 InvertMatrix(weight,ipar,par);
465
466 //calculate W*(A.T()*W)
467 //residFactor = weight*(A.T()*W);
468 double helpmatrix2[3][4]={{0.}};
469 for(int i=0;i<ipar;i++)
470 {
471 int ii=par[i];
472 for(int j=0;j<imeas;j++)
473 {
474 int jj=meas[j];
475 for(int k=0;k<imeas;k++)
476 {
477 int kk=meas[k];
478 helpmatrix2[ii][jj] += A[kk][ii] * W[kk][jj];
479 }
480 }
481 }
482
483 for(int i=0;i<ipar;i++)
484 {
485 int ii = par[i];
486 for(int j=0;j<imeas;j++)
487 {
488 int jj=meas[j];
489 residFactor[ii][jj]=0.;
490 for(int k=0;k<ipar;k++)
491 {
492 int kk=par[k];
493 residFactor[ii][jj] += weight[ii][kk]*helpmatrix2[kk][jj];
494 }
495 //residFactor[ii][jj]*=W[0][0];
496 }
497 }
498
499 double paramDiff[3] = {0.};
500 for(int i=0;i<ipar;i++)
501 {
502 int ii=par[i];
503 //estimation of new parameters
504 //paramDiff[i][0] += (weight*(A.T()*W)*(m-fp))[i][0];
505 for(int j=0;j<imeas;j++)
506 {
507 int jj = meas[j];
508 paramDiff[ii] += residFactor[ii][jj]*(m[jj][0]-fp[jj][0]);
509 }
510 p0[ii][0] += paramDiff[ii];
511 }
512 // if the parameters are going nuts keep them sensible
513 if(p0[1][0]>1. || p0[1][0]<-3.)
514 p0[1][0] = initValues[1];
515
516 double amplitudeChangeNew = std::abs(paramDiff[0]);
517 if(std::abs(paramDiff[0])<fitTolerance0 && std::abs(paramDiff[1])<fitTolerance1)
518 {
519 converged = true;
520 // calculate chi2
521 double residual[4]= {0.};
522 for(int i=0;i<imeas;i++)
523 {
524 int ii=meas[i];
525 residual[i] = m[ii][0]-fp[ii][0];
526 }
527
528 double tmpChi2 = 0.;
529 double helpmatrixchi2[4][1]={{0.}};
530 for(int i=0;i<imeas;i++)
531 {
532 int ii=meas[i];
533 for(int k=0;k<imeas;k++)
534 {
535 int kk=meas[k];
536 helpmatrixchi2[ii][0] += W[ii][kk]*residual[kk];
537 }
538 }
539 for(int k=0;k<imeas;k++)
540 {
541 int kk=meas[k];
542 tmpChi2 += residual[kk]*helpmatrixchi2[kk][0];
543 }
544 (*chi2) = tmpChi2;
545 }
546 else if(counter>4 && (amplitudeChangeNew>4.*amplitudeChangeOld))
547 {
548 if(diverganceCandidate)
549 {
550 //diverging fit
551 //return parabola interpolation
552 printf("Diverging fit\n");
553 return 4;
554 }
555 else
556 diverganceCandidate = true;
557 }
558 if(p0[0][0]<0.)
559 {
560 //negative amplitude
561 //fit diverged
562 // return parabola
563 return 4;
564 }
565 //if after a couple of iterations the amplitude is low
566 // reduce the tolerances (or the maximum iterations)
567 // low amplitude pulses tend to oscillate and exhaust all iterations
568 if(p0[0][0]<20.)
569 {
570 fitTolerance0 = 0.1;
571 fitTolerance1 = 0.05;
572 }
573 amplitudeChangeOld = amplitudeChangeNew;
574 counter++;
575 }
576 result[0]=p0[0][0];
577 result[1]=m_zmax*p0[2][0]/m_tsampling+p0[1][0];
578 result[2]=p0[2][0];
579
580 if(counter==maxIter)
581 return 3;
582 return 0;
583}
static Double_t a
int imax(int i, int j)
#define x
#define z
double m_powcachez
Definition BipolarFit.h:42
double m_tsampling
Definition BipolarFit.h:46
double FindInitValues(double *x, double *initValues, int *maxsample)
int Fit(double *x, const double ex, const double pedestal, const double predefinedwidth, double *result, double *errors, double *chi2)
double m_zmax
Definition BipolarFit.h:44
void InvertSymmetric4x4(double W[][4])
void InvertMatrix(double matrix[][3], const int dim, int *)
double m_bipolarNormalization
Definition BipolarFit.h:45
double m_n
Definition BipolarFit.h:41
void Derivative(double A[][3], double fp[][1], double p0[][1], int imeas, int *meas)
double m_powcachezn
Definition BipolarFit.h:43
int TheFitter(double *x, const double ex, double *initValues, int imeas, int *meas, int ipar, int *par, double *chi2, double *result)
double bipolar(double *, double *)
double FindPow(double z)
double chi2(TH1 *h0, TH1 *h1)
hold the test vectors and ease the comparison