Skip to content
Snippets Groups Projects
ClusterShapes.cc 61.9 KiB
Newer Older
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
#include "DataHelper/ClusterShapes.h"
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
//#include <gsl/gsl_blas.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_eigen.h>
#include <gsl/gsl_multifit_nlin.h>
#include <gsl/gsl_sf_gamma.h>
#include <gsl/gsl_integration.h>
//#include <gsl/gsl_rng.h>
//#include <gsl/gsl_sf_pow_int.h>


// #################################################
// #####                                       #####
// #####  Additional Structures and Functions  #####
// #####                                       #####
// #################################################
//=============================================================================

struct data {
  int n;
  float* x;
  float* y;
  float* z;
  float* ex;
  float* ey;
  float* ez;
};

//=============================================================================

// Gammafunction
double G(double x) {

  return gsl_sf_gamma(x);
  
}

//=============================================================================

// inverse Gammafunction
double invG(double x) {
  
  return gsl_sf_gammainv(x);
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
    
}

//=============================================================================

// Integral needed for deriving the derivative of the Gammafunction
double Integral_G(double x, void* params) {
  double a = *(double*)params;
  double f = exp(-x) * pow(x,a-1) * log(x);
  return f;
}
    
//=============================================================================

double DinvG(double x) {

  int workspace_size = 1000;
  double abs_error = 0;
  double rel_error = 1e-6;
  double result = 0.0;
  double error = 0.0;
  
  gsl_integration_workspace* w  = gsl_integration_workspace_alloc(workspace_size);
  gsl_function F;
  F.function = &Integral_G;
  F.params = &x;
    
  /*int status=*/gsl_integration_qagiu(&F,0,abs_error,rel_error,workspace_size,w,
				 &result,&error); 
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  // debug  
  /*  
      printf ("Numeric Integration : \n");
      printf ("parameter of integration = % .18f\n", x);
      printf ("status of integration    = %d \n"   , status);
      printf ("result                   = % .18f\n", result);
      printf ("estimated error          = % .18f\n", error);
      printf ("intervals                =  %d\n\n", w->size);
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  */
  
  double G2 = pow(gsl_sf_gamma(x),2); 
  double DG = result;
  
  gsl_integration_workspace_free(w);
  
  return -DG/G2;

}

//=============================================================================

int ShapeFitFunct(const gsl_vector* par, void* d, gsl_vector* f) {

  // Used for shape fitting. Function to fit: 
  //
  // a[i](t[i],s[i]) =
  // 
  // E0 * b * 1/Gamma(a) * ( b * (t[i] - t0) )^(a-1) * exp(-b*(t[i] - t0)) * exp(-d*s[i])
  //
  // Function to minimise:
  //
  // f0[i] =  E0 * b * 1/Gamma(a) * 
  //        ( b * (t[i] - t0) )^(a-1) * exp(-b*(t[i] - t0)) * exp(-d*s[i]) - a[i]
  //


  //  float E0   = gsl_vector_get(par,0);
  float A    = gsl_vector_get(par,0);
  float B    = gsl_vector_get(par,1);
  float D    = gsl_vector_get(par,2);
  float t0   = gsl_vector_get(par,3);
  int n      = ((struct data*)d)->n;
  float* t   = ((struct data*)d)->x;
  float* s   = ((struct data*)d)->y;
  float* a   = ((struct data*)d)->z; // amplitude stored in z[i]
  float fi   = 0.0;


  for (int i(0); i < n; i++) {
    fi = /*E0 * */ B * invG(A) * pow(B*(t[i]-t0),A-1) * exp(-B*(t[i]-t0)) * exp(-D*s[i]) 
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
    gsl_vector_set(f,i,fi);
  }

  return GSL_SUCCESS;
}

//=============================================================================

int dShapeFitFunct(const gsl_vector* par, void* d, gsl_matrix* J) {

  // Used for shape fitting
  //float E0  = gsl_vector_get(par,0);
  float A   = gsl_vector_get(par,0);
  float B   = gsl_vector_get(par,1);
  float D   = gsl_vector_get(par,2);
  float t0  = gsl_vector_get(par,3);
  int n     = ((struct data*)d)->n;
  float* t  = ((struct data*)d)->x;
  float* s  = ((struct data*)d)->y;


  // calculate Jacobi's matrix J[i][j] = dfi/dparj, but here only one dimension

  for (int i(0); i < n; i++) {

    /*    
	  gsl_matrix_set(J,i,0,B * invG(A) * pow(B*(t[i]-t0),A-1) * exp(-B*(t[i]-t0)) 
	  * exp(-D*s[i]) );
	  */
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

    gsl_matrix_set(J,i,0,( /* E0 * */ B * invG(A) * log(B*(t[i]-t0))*pow(B*(t[i]-t0),A-1) * 
			   exp(-B*(t[i]-t0)) + DinvG(A) * /* E0 * */ B * pow(B*(t[i]-t0),A-1) *
			   exp(-B*(t[i]-t0))
			   ) * exp(-D*s[i]));
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
		         
    gsl_matrix_set(J,i,1,( /* E0 * */ invG(A) * pow(B*(t[i]-t0),A-1) * exp(-B*(t[i]-t0)) +
			   /* E0 * */ invG(A) * (A-1) * B * (t[i]-t0) * pow(B*(t[i]-t0),A-2) * 
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
			   /* E0 * */ B * invG(A) * (t[i]-t0) * pow(B*(t[i]-t0),A-1) * 
			   exp(-B*(t[i]-t0)) 
			   ) * exp(-D*s[i]));
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
                         
    gsl_matrix_set(J,i,2,-/* E0 * */ B * invG(A) * s[i] * pow(B*(t[i]-t0),A-1) *
		   exp(-B*(t[i]-t0)) * exp(-D*s[i]));
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
       		         
    gsl_matrix_set(J,i,3,(-/* E0 * */ pow(B,2) * invG(A) * (A-1) * pow(B*(t[i]-t0),A-2) * 
			  exp(-B*(t[i]-t0)) +
			  /* E0 * */ pow(B,2) * invG(A) * pow(B*(t[i]-t0),A-1) * 
			  exp(-B*(t[i]-t0))
			  ) * exp(-D*s[i]));
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
 		         

  }
  
  return GSL_SUCCESS;
}

//=============================================================================

int fdfShapeFitFunct(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J) {

  //     For helix fitting
  ShapeFitFunct(par, d, f);
  dShapeFitFunct(par, d, J);

  return GSL_SUCCESS;

}

//=============================================================================

int signum(float x) {

  // computes the signum of x. Needed for the 3. parametrisation

  if ( x >= 0 ) return 1; // x == 0 is taken as positive
  else return -1;

}

//=============================================================================

int functParametrisation1(const gsl_vector* par, void* d, gsl_vector* f) {

  //     For helix fitting
  // calculate fit function f0[i] = 
  // ( (x0 + R*cos(b*z[i] + phi0)) - x[i] ) for i = 0 to n-1
  //                    and f1[i] = 
  // ( (y0 + R*sin(b*z[i] + phi0)) - y[i] ) for i = n to dim*n - 1
  // That means, minimise the two functions f0[i] and f1[i]

  float x0   = gsl_vector_get(par,0);
  float y0   = gsl_vector_get(par,1);
  float R    = gsl_vector_get(par,2);
  float b    = gsl_vector_get(par,3);
  float phi0 = gsl_vector_get(par,4);
  int n    = ((struct data*)d)->n;
  float* x = ((struct data*)d)->x;
  float* y = ((struct data*)d)->y;
  float* z = ((struct data*)d)->z;
  //float* ex = ((struct data*)d)->ex;
  //float* ey = ((struct data*)d)->ey;
  //float* ez = ((struct data*)d)->ez;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  float fi = 0.0;

  // first dimension
  for (int i(0); i < n; i++) {
    fi = (x0 + R*cos(b*z[i] + phi0)) - x[i];
    //    float err = sqrt(ex[i]*ex[i]+R*b*R*b*sin(b*z[i] + phi0)*R*b*R*b*sin(b*z[i] + phi0)*ez[i]*ez[i]);
    //    fi = fi/err;
    gsl_vector_set(f,i,fi);
  }
  // second dimension
  for (int i(0); i < n; i++) {
    fi = (y0 + R*sin(b*z[i] + phi0)) - y[i];
    //    float err = sqrt(ey[i]*ey[i]+R*b*R*b*cos(b*z[i] + phi0)*R*b*R*b*cos(b*z[i] + phi0)*ez[i]*ez[i]);
    //    fi = fi/err;  
    gsl_vector_set(f,i+n,fi);
  }

  return GSL_SUCCESS;
}

//=============================================================================

int dfunctParametrisation1(const gsl_vector* par, void* d, gsl_matrix* J) {

  //     For helix fitting
  float R    = gsl_vector_get(par,2);
  float b    = gsl_vector_get(par,3);
  float phi0 = gsl_vector_get(par,4);

  int n    = ((struct data*)d)->n;
  float* z = ((struct data*)d)->z;
  //float* ex = ((struct data*)d)->ex;
  //float* ey = ((struct data*)d)->ey;
  //float* ez = ((struct data*)d)->ez;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed


  // calculate Jacobi's matrix J[i][j] = dfi/dparj

  // part of Jacobi's matrix corresponding to first dimension
  for (int i(0); i < n; i++) {
    //    float err = sqrt(ex[i]*ex[i]+R*b*R*b*sin(b*z[i] + phi0)*R*b*R*b*sin(b*z[i] + phi0)*ez[i]*ez[i]);
    gsl_matrix_set(J,i,0,1);
    gsl_matrix_set(J,i,1,0);
    gsl_matrix_set(J,i,2,cos(b*z[i]+phi0));
    gsl_matrix_set(J,i,3,-z[i]*R*sin(b*z[i]+phi0));
    gsl_matrix_set(J,i,4,-R*sin(b*z[i]+phi0));

  }

  // part of Jacobi's matrix corresponding to second dimension
  for (int i(0); i < n; i++) {
    //    float err = sqrt(ey[i]*ey[i]+R*b*R*b*cos(b*z[i] + phi0)*R*b*R*b*cos(b*z[i] + phi0)*ez[i]*ez[i]);
    gsl_matrix_set(J,i+n,0,0);
    gsl_matrix_set(J,i+n,1,1);
    gsl_matrix_set(J,i+n,2,sin(b*z[i]+phi0));
    gsl_matrix_set(J,i+n,3,z[i]*R*cos(b*z[i]+phi0));
    gsl_matrix_set(J,i+n,4,R*cos(b*z[i]+phi0));
    
  }
  
  return GSL_SUCCESS;
}

//=============================================================================

int fdfParametrisation1(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J) {

  //     For helix fitting
  functParametrisation1(par, d, f);
  dfunctParametrisation1(par, d, J);

  return GSL_SUCCESS;

}

//=============================================================================

int functParametrisation2(const gsl_vector* par, void* d, gsl_vector* f) {

  //     For helix fitting
  // calculate fit function f0[i] = 
  // ( (x0 + R*cos(phi)) - x[i] ) for i = 0 to n-1
  //                        f1[i] = 
  // ( (y0 + R*sin(phi)) - y[i] ) for i = n to dim*n - 1
  //                    and f2[i] =
  // ( (z0 + b*phi     ) - z[i] )
  // That means, minimise the three functions f0[i], f1[i] and f2[i]

  float x0   = gsl_vector_get(par,0);
  float y0   = gsl_vector_get(par,1);
  float z0   = gsl_vector_get(par,2);
  float R    = gsl_vector_get(par,3);
  float b    = gsl_vector_get(par,4);
  int n    = ((struct data*)d)->n;
  float* x = ((struct data*)d)->x;
  float* y = ((struct data*)d)->y;
  float* z = ((struct data*)d)->z;
  float fi = 0.0;
  float phii = 0.0;

  // first dimension
  for (int i(0); i < n; i++) {
    phii = atan2( y[i]-y0, x[i]-x0 );
    fi = (x0 + R*cos(phii)) - x[i];
    gsl_vector_set(f,i,fi);
  }
  // second dimension
  for (int i(0); i < n; i++) {
    phii = atan2( y[i]-y0, x[i]-x0 );
    fi = (y0 + R*sin(phii)) - y[i];  
    gsl_vector_set(f,i+n,fi);
  }
  // third dimension
  for (int i(0); i < n; i++) {
    phii = atan2( y[i]-y0, x[i]-x0 );
    fi = (z0 + b*phii) - z[i];  
    gsl_vector_set(f,i+2*n,fi);
  }

  return GSL_SUCCESS;
}

//=============================================================================

int dfunctParametrisation2(const gsl_vector* par, void* d, gsl_matrix* J) {

  //     For helix fitting
  float x0   = gsl_vector_get(par,0);
  float y0   = gsl_vector_get(par,1);
  float R    = gsl_vector_get(par,3);
  float b    = gsl_vector_get(par,4);
  int n    = ((struct data*)d)->n;
  float* x = ((struct data*)d)->x;
  float* y = ((struct data*)d)->y;
  float phii = 0.0;

  // calculate Jacobi's matrix J[i][j] = dfi/dparj

  // part of Jacobi's matrix corresponding to first dimension
  for (int i(0); i < n; i++) {
    
    phii = atan2( y[i]-y0, x[i]-x0 );

    gsl_matrix_set(J,i,0,1 - R*sin(phii)*
		   ( (y[i]-y0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
    gsl_matrix_set(J,i,1,R*sin(phii)*
		   ( (x[i]-x0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
    gsl_matrix_set(J,i,2,0);
    gsl_matrix_set(J,i,3,cos(phii));
    gsl_matrix_set(J,i,4,0);

  }
  
  // part of Jacobi's matrix corresponding to second dimension
  for (int i(0); i < n; i++) {

    phii = atan2( y[i]-y0, x[i]-x0 );
    
    gsl_matrix_set(J,i+n,0,R*cos(phii)*
		   ( (y[i]-y0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
    gsl_matrix_set(J,i+n,1,1 + R*cos(phii)*
		   ( (x[i]-x0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
    gsl_matrix_set(J,i+n,2,0);
    gsl_matrix_set(J,i+n,3,sin(phii));
    gsl_matrix_set(J,i+n,4,0);
    
  }

  // part of Jacobi's matrix corresponding to third dimension
  for (int i(0); i < n; i++) {

    phii = atan2( y[i]-y0, x[i]-x0 );
    
    gsl_matrix_set(J,i+2*n,0,b*
		   ( (y[i]-y0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
    gsl_matrix_set(J,i+2*n,1,b*
		   ( (x[i]-x0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
    gsl_matrix_set(J,i+2*n,2,1);
    gsl_matrix_set(J,i+2*n,3,0);
    gsl_matrix_set(J,i+2*n,4,phii);
    
  }
  
  return GSL_SUCCESS;
}

//=============================================================================

int fdfParametrisation2(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J) {

  //     For helix fitting
  functParametrisation2(par, d, f);
  dfunctParametrisation2(par, d, J);

  return GSL_SUCCESS;

}

//=============================================================================

int functParametrisation3(const gsl_vector* par, void* d, gsl_vector* f) {

  //     For helix fitting
  // calculate fit function f0[i] = 
  // ( ( ( (1/omega) - d0 )*sin(Phi0) + ( 1/fabs(omega) )*cos( ( -omega/sqrt(1+tanL^2) )*s + Phi0 +( (omega*pi)/(2*fabs(omega)) ) ) ) - x[i] ) for i = 0 to n-1
  //                        f1[i] = 
  // ( ( (-1.0)*( (1/omega) - d0 )*cos(Phi0) + ( 1/fabs(omega) )*sin( ( -omega/sqrt(1+tanL^2) )*s + Phi0 +( (omega*pi)/(2*fabs(omega)) ) ) ) - y[i] ) for i = n to dim*n - 1
  //                    and f2[i] =
  // ( ( z0 + (tanL/sqrt(1+tanL^2))*s ) - z[i] )
  // That means, minimise the three functions f0[i], f1[i] and f2[i]

  double z0    = gsl_vector_get(par,0);
  double Phi0  = gsl_vector_get(par,1);
  double omega = gsl_vector_get(par,2);
  double d0    = gsl_vector_get(par,3);
  double tanL  = gsl_vector_get(par,4);
  int n    = ((struct data*)d)->n;
  float* x = ((struct data*)d)->x;
  float* y = ((struct data*)d)->y;
  float* z = ((struct data*)d)->z;
  double phii = 0.0;
  double fi = 0.0;
  double si = 0.0;

  // first dimension
  for (int i(0); i < n; i++) {
    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
    fi = ( ( (1/omega) - d0 )*sin(Phi0) + ( 1/fabs(omega) )*cos(phii) ) - ((double)x[i]);
    gsl_vector_set(f,i,fi);
  }
  // second dimension
  for (int i(0); i < n; i++) {
    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
    fi = ( (-1.0)*( (1/omega) - d0 )*cos(Phi0) + ( 1/fabs(omega) )*sin(phii) ) - ((double)y[i]);
    gsl_vector_set(f,i+n,fi);
  }
  // third dimension
  for (int i(0); i < n; i++) {
    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
    si = (-1.0)*( (sqrt(1+pow(tanL,2)))/omega )*(phii - Phi0 - (omega*M_PI)/(2*fabs(omega)));
    fi = ( z0 + (tanL/sqrt(1+pow(tanL,2)))*si ) - ((double)z[i]);
    gsl_vector_set(f,i+2*n,fi);
  }
  
  return GSL_SUCCESS;

}

//=============================================================================

int dfunctParametrisation3(const gsl_vector* par, void* d, gsl_matrix* J) {

 
  //     For helix fitting
  // double z0    = gsl_vector_get(par,0); // not needed
  double Phi0  = gsl_vector_get(par,1);
  double omega = gsl_vector_get(par,2);
  double d0    = gsl_vector_get(par,3);
  double tanL  = gsl_vector_get(par,4);
  int n    = ((struct data*)d)->n;
  float* x = ((struct data*)d)->x;
  float* y = ((struct data*)d)->y;
  // float* z = ((struct data*)d)->z; // not needed
  double phii = 0.0;
  double si = 0.0;

  // calculate Jacobi's matrix J[i][j] = dfi/dparj

  // part of Jacobi's matrix corresponding to first dimension
  for (int i(0); i < n; i++) {
    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 ) * cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
    si = (-1.0)*( (sqrt(1+pow(tanL,2)))/omega )*(phii - Phi0 - (omega*M_PI)/(2*fabs(omega)));

    gsl_matrix_set(J,i,0,0);
    gsl_matrix_set(J,i,1,((1/omega) - d0) * cos(Phi0) - (1/fabs(omega)) * sin(phii) );
    gsl_matrix_set(J,i,2,((-1.0)*sin(Phi0))/pow(omega,2) - ( (signum(omega))/(pow(fabs(omega),2)) ) * cos(phii) - 
		   (1/fabs(omega)) * sin(phii) * ( ( ((-1.0)/sqrt(1+pow(tanL,2)))*si) + (M_PI)/(2*fabs(omega)) - (signum(omega)*omega*M_PI)/(2*pow(fabs(omega),2)) ) );
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
    gsl_matrix_set(J,i,3,(-1.0)*sin(Phi0));
    gsl_matrix_set(J,i,4,((-1.0)/fabs(omega))*sin(phii) * ( (omega*tanL*si)/sqrt(pow(1+pow(tanL,2),3)) ) );

  }
  
  // part of Jacobi's matrix corresponding to second dimension
  for (int i(0); i < n; i++) {
    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
    si = (-1.0)*( (sqrt(1+pow(tanL,2)))/omega )*(phii - Phi0 - (omega*M_PI)/(2*fabs(omega)));

    gsl_matrix_set(J,i+n,0,0);
    gsl_matrix_set(J,i+n,1,((1/omega) - d0)*sin(Phi0) + (1/fabs(omega)) * cos(phii) );
    gsl_matrix_set(J,i+n,2,cos(Phi0)/pow(omega,2) + ( (signum(omega))/(pow(fabs(omega),2)) ) * sin(phii) + 
		   (1/fabs(omega))*cos(phii) * ( ( ((-1.0)/sqrt(1+pow(tanL,2)))*si) + (M_PI)/(2*fabs(omega)) - (signum(omega)*omega*M_PI)/(2*pow(fabs(omega),2)) ) );
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
    gsl_matrix_set(J,i+n,3,cos(Phi0));
    gsl_matrix_set(J,i+n,4,(1/fabs(omega))*cos(phii) * ( (omega*tanL*si)/sqrt(pow(1+pow(tanL,2),3)) ) );
    
  }

  // part of Jacobi's matrix corresponding to third dimension
  for (int i(0); i < n; i++) {
    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
    si = (-1.0)*( (sqrt(1+pow(tanL,2)))/omega )*(phii - Phi0 - (omega*M_PI)/(2*fabs(omega)));

    gsl_matrix_set(J,i+2*n,0,1.0);
    gsl_matrix_set(J,i+2*n,1,0);
    gsl_matrix_set(J,i+2*n,2,0);
    gsl_matrix_set(J,i+2*n,3,0);
    gsl_matrix_set(J,i+2*n,4,si/sqrt(1+pow(tanL,2)) - (pow(tanL,2)*si)/sqrt(pow(1+pow(tanL,2),3)) );
    
  }
  
  return GSL_SUCCESS;

}

//=============================================================================

int fdfParametrisation3(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J) {
  
  //     For helix fitting
  functParametrisation3(par, d, f);
  dfunctParametrisation3(par, d, J);
  
  return GSL_SUCCESS;

}

//=============================================================================




// ##########################################
// #####                                #####
// #####   Constructor and Destructor   #####
// #####                                #####
// ##########################################

//=============================================================================

ClusterShapes::ClusterShapes(int nhits, float* a, float* x, float* y, float* z):

  _nHits(nhits),
  _aHit  (nhits, 0.0),
  _xHit  (nhits, 0.0),
  _yHit  (nhits, 0.0),
  _zHit  (nhits, 0.0),
  _exHit (nhits, 1.0),
  _eyHit (nhits, 1.0),
  _ezHit (nhits, 1.0),
  _xl    (nhits, 0.0),
  _xt    (nhits, 0.0),
  _t     (nhits, 0.0),
  _s     (nhits, 0.0),
  _types(nhits, 1), // all hits are assumed to be "cylindrical"

  _ifNotGravity    (1),
  _ifNotWidth      (1),
  _ifNotInertia    (1),
  _ifNotEigensystem(1)
{
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  for (int i(0); i < nhits; ++i) {
    _aHit[i] = a[i];
    _xHit[i] = x[i];
    _yHit[i] = y[i];
    _zHit[i] = z[i];
  }


}


//=============================================================================

ClusterShapes::~ClusterShapes() {

}

//=============================================================================

void ClusterShapes::setErrors(float *ex, float *ey, float *ez) {

  for (int i=0; i<_nHits; ++i) {
    _exHit[i] = ex[i];
    _eyHit[i] = ey[i];
    _ezHit[i] = ez[i];
  }	

}

void ClusterShapes::setHitTypes(int* typ) {
  for (int i=0; i<_nHits; ++i) {
    _types[i] = typ[i];

  }
  
}



// ##########################################
// #####                                #####
// #####        public methods          #####
// #####                                #####
// ##########################################

//=============================================================================

int ClusterShapes::getNumberOfHits() {
  return _nHits;
}

//=============================================================================

float ClusterShapes::getTotalAmplitude() {
  if (_ifNotGravity == 1) findGravity();
  return _totAmpl;
}

//=============================================================================

float* ClusterShapes::getCentreOfGravity() {
  if (_ifNotGravity == 1) findGravity() ;
  return &_analogGravity[0] ;
}
float* ClusterShapes::getCentreOfGravityErrors() {
  // this is a pure dummy to allow MarlinPandora development!
  if (_ifNotGravity == 1) findGravity() ;
  return &_analogGravity[0] ;
}
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

//=============================================================================

float* ClusterShapes::getEigenValInertia() {
  if (_ifNotInertia == 1) findInertia();
  return &_ValAnalogInertia[0] ;
}
float* ClusterShapes::getEigenValInertiaErrors() {
  // this is a pure dummy to allow MarlinPandora development!
  if (_ifNotInertia == 1) findInertia();
  return &_ValAnalogInertia[0] ;
}
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

//=============================================================================

float* ClusterShapes::getEigenVecInertia() {
  if (_ifNotInertia == 1) findInertia();
  return &_VecAnalogInertia[0] ;
}
float* ClusterShapes::getEigenVecInertiaErrors() {
  // this is a pure dummy to allow MarlinPandora development!
  if (_ifNotInertia == 1) findInertia();
  return &_VecAnalogInertia[0] ;
}
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

//=============================================================================

float ClusterShapes::getWidth() {
  if (_ifNotWidth == 1) findWidth();
  return _analogWidth;
}

//=============================================================================

int ClusterShapes::getEigenSytemCoordinates(float* xlong, float* xtrans) {

  float xStart[3];
  int index_xStart;


  // NOT SAVE, change to class variables !!!!!
  float X0[2]={3.50,17.57};   //in mm. //this is the exact value of tungsten and iron
  float Rm[2]={9.00,17.19};   //in mm. need to change to estimate correctly 
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);

  for (int i = 0; i < _nHits; ++i) {
    xlong[i]  = _xl[i];
    xtrans[i] = _xt[i];
  }

  return 0; // no error messages at the moment

}

//=============================================================================

int ClusterShapes::getEigenSytemCoordinates(float* xlong, float* xtrans, float* a) {

  float xStart[3];
  int index_xStart;

  // NOT SAVE, change to class variables !!!!!
  float X0[2]={3.50,17.57};   //in mm. //this is the exact value of tungsten and iron
  float Rm[2]={9.00,17.19};   //in mm. need to change to estimate correctly 
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);

  for (int i = 0; i < _nHits; ++i) {
    xlong[i]  = _xl[i];
    xtrans[i] = _xt[i];
    a[i] = _aHit[i];
  }

  return 0; // no error messages at the moment

}

//=============================================================================

int ClusterShapes::fit3DProfile(float& chi2, float& E0, float& A, float& B, float& D,
				float& xl0, float* xStart, int& index_xStart,
				float* X0, float* Rm) {
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  const int npar = 4;

  if (_ifNotEigensystem == 1){
    transformToEigensystem(xStart,index_xStart,X0,Rm);
  }
  
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  float* E = new float[_nHits];

  //doesn't fit when _nHits==0
  //std::cout << "_nhits " << _nHits << std::endl;
  if(_nHits-1 < npar){  //can't fit because number of degrees of freedom is small
    E0=0.0;

    delete[] E;
    int result = 0;  // no error handling at the moment
    return result;
  }
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  double par_init[npar];
  for (int i = 0; i < npar; ++i) par_init[i] = 0.0; // initialise

  float E0_init = 0.0;
  float A_init  = 0.0;
  float B_init  = 0.5; // empirically
  float D_init  = 0.06;    //0.5; //if Rm includes 90% of shower energy, absorption length has 63% of shower energy
  float t0_init = -10.0/X0[0]; // shift xl0_ini is assumed to be -10.0 without a reason ????
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  
  float E0_tmp = 0.0;
  //  int i_max = 0;
  //float t_max = 0.0;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  for (int i = 0; i < _nHits; ++i) {
    if (E0_tmp < _aHit[i]) {
      E0_tmp = _aHit[i]; 
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
    }
    E0_init += _aHit[i];
  }

  // first definition
  //t_max = _xl[i_max]/X0;
  //A_init = t_max*B_init + 1.0;

  // second definition
  //t_max = (1.0/3.0) * (t[_nHits-1] - t[0]);
  //A_init = t_max*B_init + 1.0;

  // third definition
  float Ec = X0[0] * 0.021/Rm[0];
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  A_init =  B_init * log(E0_init/Ec) + 0.5 * B_init + 1.0; // (+0.5 for Photons initiated showers)

  // par_init[0] = E0_init;
  E0 = E0_init;
  for (int i = 0; i < _nHits; ++i) E[i] = _aHit[i]/E0_init;
  par_init[0] = A_init; // 2.0
  par_init[1] = B_init;
  par_init[2] = D_init;
  par_init[3] = t0_init;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  // debug

  // std::cout << "E0_init : " <<  E0_init << "\t" << "A_init : " << A_init << "\t" 
  //     << "B_init : " <<  B_init << "\t" << "D_init : " << D_init << "\t" 
  //     << "xl0_init : "  << t0_init*X0 << "\t" << "X0 : " << X0 
  //     << "\t" << "t_max : " << t_max << std::endl << std::endl;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed


  double t0 = xl0/X0[0];   //probably t0 is in ecal
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  double par[npar];
  par[0] = A;
  par[1] = B;
  par[2] = D;
  par[3] = t0;

  fit3DProfileAdvanced(chi2,par_init,par,npar,&_t[0],&_s[0],E,E0);
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  A   = par[0];
  B   = par[1];
  D   = par[2];
  xl0 = par[3] * X0[0];   //probably shower start is in ecal
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  delete[] E;

  int result = 0;  // no error handling at the moment
  return result;
}

//=============================================================================

float ClusterShapes::getChi2Fit3DProfileSimple(float a, float b, float c, float d,
					       float* X0, float* Rm) {
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  float chi2 = 0.0;

  float xStart[3];
  int index_xStart;

  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);

  chi2 = calculateChi2Fit3DProfileSimple(a,b,c,d);
  
  return chi2;
  
}

//=============================================================================

float ClusterShapes::getChi2Fit3DProfileAdvanced(float E0, float a, float b, float d,
						 float t0, float* X0, float* Rm) {
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  float chi2 = 0.0;

  float xStart[3];
  int index_xStart;

  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);

  chi2 = calculateChi2Fit3DProfileAdvanced(E0,a,b,d,t0);

  return chi2;

}

//=============================================================================

int ClusterShapes::FitHelix(int max_iter, int status_out, int parametrisation,
			    float* parameter, float* dparameter, float& chi2, 
			    float& distmax, int direction) {


  // Modified by Hengne Li @ LAL
  
  double parameterdb[5];
  double dparameterdb[5];
  double chi2db;
  double distmaxdb;
  for ( int i=0; i<5; i++ ){
    parameterdb[i] = double(parameter[i]);
    dparameterdb[i] = double(dparameter[i]);
  }
  chi2db = double(chi2);
  distmaxdb = double(distmax);
  
  int returnvalue = FitHelix(max_iter,status_out,parametrisation,parameterdb,dparameterdb,chi2db,distmaxdb,direction);
  
  for ( int i=0; i<5; i++ ){
    parameter[i] = float(parameterdb[i]);
    dparameter[i] = float(dparameterdb[i]);
  }
  chi2 = float(chi2db);
  distmax = float(distmaxdb);
  
  return returnvalue ;

}

//=============================================================================

int ClusterShapes::FitHelix(int max_iter, int status_out, int parametrisation,
			    double* parameter, double* dparameter, double& chi2, 
			    double& distmax, int direction) {
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  // FIXME: version with double typed parameters needed 2006/06/10 OW
  
  if (_nHits < 3) {
    std::cout << "ClusterShapes : helix fit impossible, two few points" ;
    std::cout << std::endl;
    for (int i = 0; i < 5; ++i) {
      parameter[i] = 0.0;
      dparameter[i] = 0.0;
    }
    return 1;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  }

  // find initial parameters

  double Rmin = 1.0e+10;
  double Rmax = -1.0;
  int i1 = -1;

  // 1st loop  
  for (int i(0); i < _nHits; ++i) {
    double Rz = sqrt(_xHit[i]*_xHit[i] + _yHit[i]*_yHit[i]);
    if (Rz < Rmin) {
      Rmin = Rz;
      i1 = i;
    }
    if (Rz > Rmax) {
      Rmax = Rz;
    }
    for (int i(0); i < _nHits; ++i) std::cout << i << "  " << _xHit[i] << "  " << _yHit[i] << "  " << _zHit[i] << std::endl;
    std::cout << std::endl << Rmin << "  " <<  Rmax << "  " << i1 << std::endl;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  */





  // 2nd loop
  double Upper = Rmin + 1.1*(Rmax-Rmin);
  double Lower = Rmin + 0.9*(Rmax-Rmin);
  double dZmin  = 1.0e+20;

  int i3 = -1 ;

  for (int i(0); i < _nHits; ++i) {
    double Rz = sqrt(_xHit[i]*_xHit[i] + _yHit[i]*_yHit[i]);
    if ((Rz > Lower) && (Rz < Upper)) {
      double dZ = fabs(_zHit[i]-_zHit[i1]);
      if (dZ < dZmin) {
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
      }
    }
  }

  // debug
  //std::cout << std::endl << Upper << "  " << Lower << "  " << dZmin << "  " << i3 << std::endl;




  double z1 = std::min(_zHit[i1],_zHit[i3]);
  double z3 = std::max(_zHit[i1],_zHit[i3]);


  int i2 = -1;
  double dRmin = 1.0e+20;
  double Rref = 0.5 * ( Rmax + Rmin );

  // 3d loop

  for (int i(0); i < _nHits; ++i) {
    if (_zHit[i] >= z1 && _zHit[i] <= z3) {
      double Rz = sqrt(_xHit[i]*_xHit[i] + _yHit[i]*_yHit[i]);
      double dRz = fabs(Rz - Rref);
      if (dRz < dRmin) {
	i2 = i;
	dRmin = dRz;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
      }
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed
  }

  //int problematic = 0;
fangwx@ihep.ac.cn's avatar
fangwx@ihep.ac.cn committed

  if (i2 < 0 || i2 == i1 || i2 == i3) {