/**
 * \file TrkLevel2.cpp
 * \author Elena Vannuccini
 */
#include <TrkLevel2.h>
#include <iostream>
#include <math.h>
using namespace std;
//......................................
// F77 routines
//......................................
extern "C" {    
    void dotrack_(int*, double*, double*, double*, double*, int*);
    void dotrack2_(int*, double*, double*, double*, double*,double*, double*, double*,int*);
    void mini2_(int*,int*,int*); 
    void guess_();
    void gufld_(float*, float*);
    float risxeta2_(float *);
    float risxeta3_(float *);
    float risxeta4_(float *);
    float risyeta2_(float *);
}

//--------------------------------------
//
//
//--------------------------------------
TrkTrack::TrkTrack(){
//    cout << "TrkTrack::TrkTrack()" << endl;
    seqno = -1; 
    image = -1; 
    chi2  = 0;
    nstep = 0;
    for(int it1=0;it1<5;it1++){
	al[it1] = 0;
	for(int it2=0;it2<5;it2++)coval[it1][it2] = 0;
    };
    for(int ip=0;ip<6;ip++){
	xgood[ip]  = 0;
	ygood[ip]  = 0;
	xm[ip]     = 0;
	ym[ip]     = 0;
	zm[ip]     = 0;
	resx[ip]   = 0;
	resy[ip]   = 0;
	tailx[ip]   = 0;
	taily[ip]   = 0;
	xv[ip]     = 0;
	yv[ip]     = 0;
	zv[ip]     = 0;
	axv[ip]    = 0;
	ayv[ip]    = 0;
	dedx_x[ip] = 0;
	dedx_y[ip] = 0;
	multmaxx[ip] = 0; 
	multmaxy[ip] = 0;
	seedx[ip]  = 0;  
	seedy[ip]  = 0;
	xpu[ip]    = 0;   
	ypu[ip]    = 0;   

    };
    
//     TrkParams::SetTrackingMode();
//     TrkParams::SetPrecisionFactor();
//     TrkParams::SetStepMin();
    TrkParams::SetMiniDefault();
    TrkParams::SetPFA();

    int ngf = TrkParams::nGF;
    for(int i=0; i<ngf; i++){
	xGF[i] = 0.;
	yGF[i] = 0.;
    }


};
//--------------------------------------
//
//
//--------------------------------------
TrkTrack::TrkTrack(const TrkTrack& t){
    seqno = t.seqno; 
    image = t.image; 
    chi2  = t.chi2;
    nstep = t.nstep;
    for(int it1=0;it1<5;it1++){
	al[it1] = t.al[it1];
	for(int it2=0;it2<5;it2++)coval[it1][it2] = t.coval[it1][it2];
    };
    for(int ip=0;ip<6;ip++){
	xgood[ip]  = t.xgood[ip];
	ygood[ip]  = t.ygood[ip];
	xm[ip]     = t.xm[ip];
	ym[ip]     = t.ym[ip];
	zm[ip]     = t.zm[ip];
	resx[ip]   = t.resx[ip];
	resy[ip]   = t.resy[ip];
	tailx[ip]  = t.tailx[ip];
	taily[ip]  = t.taily[ip];
	xv[ip]     = t.xv[ip];
	yv[ip]     = t.yv[ip];
	zv[ip]     = t.zv[ip];
	axv[ip]    = t.axv[ip];
	ayv[ip]    = t.ayv[ip];
	dedx_x[ip] = t.dedx_x[ip];
	dedx_y[ip] = t.dedx_y[ip];
	multmaxx[ip] = t.multmaxx[ip]; 
	multmaxy[ip] = t.multmaxy[ip];
	seedx[ip]    = t.seedx[ip];  
	seedy[ip]    = t.seedy[ip];
	xpu[ip]      = t.xpu[ip];   
	ypu[ip]      = t.ypu[ip];   
    };

//     TrkParams::SetTrackingMode();
//     TrkParams::SetPrecisionFactor(); 
//     TrkParams::SetStepMin();   
    TrkParams::SetMiniDefault();
    TrkParams::SetPFA();

    int ngf = TrkParams::nGF;
    for(int i=0; i<ngf; i++){
	xGF[i] = t.xGF[i];
	yGF[i] = t.yGF[i];
    }
};
//--------------------------------------
//
//
//--------------------------------------
void TrkTrack::Copy(TrkTrack& t){

    t.seqno = seqno; 
    t.image = image; 
    t.chi2  = chi2;
    t.nstep = nstep;
    for(int it1=0;it1<5;it1++){
	t.al[it1] = al[it1];
	for(int it2=0;it2<5;it2++)t.coval[it1][it2] = coval[it1][it2];
    };
    for(int ip=0;ip<6;ip++){
	t.xgood[ip]  = xgood[ip];
	t.ygood[ip]  = ygood[ip];
	t.xm[ip]     = xm[ip];
	t.ym[ip]     = ym[ip];
	t.zm[ip]     = zm[ip];
	t.resx[ip]   = resx[ip];
	t.resy[ip]   = resy[ip];
	t.tailx[ip]  = tailx[ip];
	t.taily[ip]  = taily[ip];
	t.xv[ip]     = xv[ip];
	t.yv[ip]     = yv[ip];
	t.zv[ip]     = zv[ip];
	t.axv[ip]    = axv[ip];
	t.ayv[ip]    = ayv[ip];
	t.dedx_x[ip] = dedx_x[ip];
	t.dedx_y[ip] = dedx_y[ip];
	t.multmaxx[ip] = multmaxx[ip]; 
	t.multmaxy[ip] = multmaxy[ip];
	t.seedx[ip]    = seedx[ip];  
	t.seedy[ip]    = seedy[ip];
	t.xpu[ip]      = xpu[ip];   
	t.ypu[ip]      = ypu[ip];   
	    
    };
    int ngf = TrkParams::nGF;
    for(int i=0; i<ngf; i++){
	t.xGF[i] = xGF[i];
	t.yGF[i] = yGF[i];
    }

    
};
//--------------------------------------
//
//
//--------------------------------------
/**
 * Evaluates the trajectory in the apparatus associated to the track. 
 * It integrates the equations of motion in the magnetic field. The magnetic field should be previously loaded ( by calling  TrkLevel2::LoadField() ), otherwise an error message is returned.  
 * @param t pointer to an object of the class Trajectory, 
 * which z coordinates should be previously initialized by calling the proper constructor ( Trajectory::Trajectory(int n, float* zin) ).
 * @return error flag.
 *
 * >>> OBSOLETE !!! use TrkTrack::DoTrack2(Trajectory* t) instead
 *
 */
int TrkTrack::DoTrack(Trajectory* t){

    cout << " int TrkTrack::DoTrack(Trajectory* t) --->> OBSOLETE !!! "<<endl;
    cout << " use int TrkTrack::DoTrack2(Trajectory* t)"<<endl;

    double *dxout = new double[t->npoint];
    double *dyout = new double[t->npoint];
    double *dzin = new double[t->npoint];
    double dal[5];

    int ifail = 0;

    for (int i=0; i<5; i++)         dal[i]  = (double)al[i];
    for (int i=0; i<t->npoint; i++) dzin[i] = (double)t->z[i];

    TrkParams::Load(1);
    if( !TrkParams::IsLoaded(1) ){
	cout << "int TrkTrack::DoTrack(Trajectory* t) --- ERROR --- m.field not loaded"<<endl;
	return 0;
    }
    dotrack_(&(t->npoint),dzin,dxout,dyout,dal,&ifail);
    
    for (int i=0; i<t->npoint; i++){
	t->x[i] = (float)*(dxout+i);
	t->y[i] = (float)*(dyout+i);
    }

    delete [] dxout;
    delete [] dyout;
    delete [] dzin;

    return ifail;
};
//--------------------------------------
//
//
//--------------------------------------
/**
 * Evaluates the trajectory in the apparatus associated to the track. 
 * It integrates the equations of motion in the magnetic field. The magnetic field should be previously loaded ( by calling  TrkLevel2::LoadField() ), otherwise an error message is returned.  
 * @param t pointer to an object of the class Trajectory, 
 * which z coordinates should be previously initialized by calling the proper constructor ( Trajectory::Trajectory(int n, float* zin) ).
 * @return error flag.
 */
int TrkTrack::DoTrack2(Trajectory* t){

    double *dxout   = new double[t->npoint];
    double *dyout   = new double[t->npoint];
    double *dthxout = new double[t->npoint];
    double *dthyout = new double[t->npoint];
    double *dtlout  = new double[t->npoint];
    double *dzin    = new double[t->npoint];
    double dal[5];

    int ifail = 0;

    for (int i=0; i<5; i++)         dal[i]  = (double)al[i];
    for (int i=0; i<t->npoint; i++) dzin[i] = (double)t->z[i];

    TrkParams::Load(1);
    if( !TrkParams::IsLoaded(1) ){
	cout << "int TrkTrack::DoTrack2(Trajectory* t) --- ERROR --- m.field not loaded"<<endl;
	return 0;
    }
    dotrack2_(&(t->npoint),dzin,dxout,dyout,dthxout,dthyout,dtlout,dal,&ifail);
    
    for (int i=0; i<t->npoint; i++){
	t->x[i]   = (float)*(dxout+i);
	t->y[i]   = (float)*(dyout+i);
	t->thx[i] = (float)*(dthxout+i);
	t->thy[i] = (float)*(dthyout+i);
	t->tl[i]  = (float)*(dtlout+i);
    }

    delete [] dxout;
    delete [] dyout;
    delete [] dzin;
    delete [] dthxout;
    delete [] dthyout;
    delete [] dtlout;

    return ifail;
};
//--------------------------------------
//
//
//--------------------------------------
//float TrkTrack::BdL(){
//};
//--------------------------------------
//
//
//--------------------------------------
Float_t TrkTrack::GetRigidity(){ 
	Float_t rig=0;
	if(chi2>0)rig=1./al[4];
	if(rig<0) rig=-rig;
	return rig;
};
//
Float_t TrkTrack::GetDeflection(){
	Float_t def=0;
	if(chi2>0)def=al[4];
	return def;
};
//
/**
 * Method to retrieve the dE/dx measured on a tracker view.
 * @param ip plane (0-5)
 * @param iv view (0=x 1=y)
 */
Float_t TrkTrack::GetDEDX(int ip, int iv){
    if(iv==0 && ip>=0 && ip<6)return fabs(dedx_x[ip]);
    else if(iv==1 && ip>=0 && ip<6)return fabs(dedx_y[ip]);
    else {
	cout << "TrkTrack::GetDEDX(int ip, int iv) -- wrong input parameters "<<ip<<iv<<endl;
	return 0.;
    }
}
/**
 * Method to evaluate the dE/dx measured on a tracker plane. 
 * The two measurements on x- and y-view are averaged.
 * @param ip plane (0-5)
 */
Float_t TrkTrack::GetDEDX(int ip){
    if( (Int_t)XGood(ip)+(Int_t)YGood(ip) == 0 ) return 0; 
    return (GetDEDX(ip,0)+GetDEDX(ip,1))/((Int_t)XGood(ip)+(Int_t)YGood(ip));
};

/**
 * Method to evaluate the dE/dx averaged over all planes. 
 */
Float_t TrkTrack::GetDEDX(){
    Float_t dedx=0; 
    for(Int_t ip=0; ip<6; ip++)dedx+=GetDEDX(ip,0)*XGood(ip)+GetDEDX(ip,1)*YGood(ip); 
    dedx = dedx/(GetNX()+GetNY());
    return dedx;
};
/**
 * Returns 1 if the cluster on a tracker view includes bad strips 
 * (at least one bad strip among the four strip used by p.f.a.)
 * @param ip plane (0-5)
 * @param iv view (0=x 1=y)
 */
Bool_t TrkTrack::IsBad(int ip,int iv){
    if(iv==0 && ip>=0 && ip<6)return (xgood[ip]<0) ;
    else if(iv==1 && ip>=0 && ip<6)return (ygood[ip]<0) ;
    else {
	cout << "TrkTrack::IsBad(int ip, int iv) -- wrong input parameters "<<ip<<iv<<endl;
	return 0.;
    }
};
/**
 * Returns 1 if the signal on a tracker view is saturated.
 * @param ip plane (0-5)
 * @param iv view (0=x 1=y)
 */
Bool_t TrkTrack::IsSaturated(int ip,int iv){
    if(iv==0 && ip>=0 && ip<6)return (dedx_x[ip]<0) ;
    else if(iv==1 && ip>=0 && ip<6)return (dedx_y[ip]<0) ;
    else {
	cout << "TrkTrack::IsSaturated(int ip, int iv) -- wrong input parameters "<<ip<<iv<<endl;
	return 0.;
    }
};
/**
 * Returns 1 if either the x or the y signal on a tracker plane is saturated.
 * @param ip plane (0-5)
 */
Bool_t TrkTrack::IsSaturated(int ip){
    return (IsSaturated(ip,0)||IsSaturated(ip,1));
};
/**
 * Returns 1 if there is at least a saturated signal along the track.
 */
Bool_t TrkTrack::IsSaturated(){
    for(int ip=0; ip<6; ip++)for(int iv=0; iv<2; iv++)if(IsSaturated(ip,iv))return true;
    return false;
}
/**
 * Returns the track "lever-arm" on the x view, defined as the distance (in planes) between 
 * the upper and lower x measurements (the maximum value of lever-arm is 6). 
 */
Int_t TrkTrack::GetLeverArmX(){
    int first_plane = -1;
    int last_plane  = -1;
    for(Int_t ip=0; ip<6; ip++){
	if( XGood(ip) && first_plane == -1 )first_plane = ip;
	if( XGood(ip) && first_plane != -1 )last_plane = ip;
    }
    if( first_plane == -1 || last_plane == -1){
	cout<< "Int_t TrkTrack::GetLeverArmX() -- XGood(ip) always false ??? "<<endl; 
	return 0;
    }
    return (last_plane-first_plane+1);
}
/**
 * Returns the track "lever-arm" on the y view, defined as the distance (in planes) between 
 * the upper and lower y measurements (the maximum value of lever-arm is 6). 
 */
Int_t TrkTrack::GetLeverArmY(){
    int first_plane = -1;
    int last_plane  = -1;
    for(Int_t ip=0; ip<6; ip++){
	if( YGood(ip) && first_plane == -1 )first_plane = ip;
	if( YGood(ip) && first_plane != -1 )last_plane = ip;
    }
    if( first_plane == -1 || last_plane == -1){
	cout<< "Int_t TrkTrack::GetLeverArmY() -- YGood(ip) always false ??? "<<endl; 
	return 0;
    }
    return (last_plane-first_plane+1);
}
/**
 * Returns the track "lever-arm" on the x+y view, defined as the distance (in planes) between 
 * the upper and lower x,y (couple) measurements (the maximum value of lever-arm is 6). 
 */
Int_t TrkTrack::GetLeverArmXY(){
    int first_plane = -1;
    int last_plane  = -1;
    for(Int_t ip=0; ip<6; ip++){
	if( XGood(ip)*YGood(ip) && first_plane == -1 )first_plane = ip;
	if( XGood(ip)*YGood(ip) && first_plane != -1 )last_plane = ip;
    }
    if( first_plane == -1 || last_plane == -1){
	cout<< "Int_t TrkTrack::GetLeverArmXY() -- XGood(ip)*YGood(ip) always false ??? "<<endl; 
	return 0;
    }
    return (last_plane-first_plane+1);
}
/**
 * Returns the reduced chi-square of track x-projection
 */
Float_t  TrkTrack::GetChi2X(){
    float chiq=0;
    for(int ip=0; ip<6; ip++)if(XGood(ip))chiq+= pow((xv[ip]-xm[ip])/resx[ip],2.); 
    if(GetNX()>3)chiq=chiq/(GetNX()-3);
    else chiq=0;
    if(chiq==0)cout << " Float_t  TrkTrack::GetChi2X() -- WARNING -- value not defined "<<chiq<<endl;
    return chiq;
}
/**
 * Returns the reduced chi-square of track y-projection
 */
Float_t  TrkTrack::GetChi2Y(){
    float chiq=0;
    for(int ip=0; ip<6; ip++)if(YGood(ip))chiq+= pow((yv[ip]-ym[ip])/resy[ip],2.); 
    if(GetNY()>2)chiq=chiq/(GetNY()-2);
    else chiq=0;
    if(chiq==0)cout << " Float_t  TrkTrack::GetChi2Y() -- WARNING -- value not defined "<<chiq<<endl;
    return chiq;
}
/**
 * Returns the logarythm of the likeliwood-function of  track x-projection
 */
Float_t TrkTrack::GetLnLX(){
    float lnl=0;
    for(int ip=0; ip<6; ip++)
	if( XGood(ip) && tailx[ip]!=0 )
	    lnl += (tailx[ip]+1.) * log( (tailx[ip]*pow(resx[ip],2.) + pow(xv[ip]-xm[ip],2.)) / (tailx[ip]*pow(resx[ip],2)) ); 
    if(GetNX()>3)lnl=lnl/(GetNX()-3);
    else lnl=0;
    if(lnl==0){
	cout << " Float_t  TrkTrack::GetLnLX() -- WARNING -- value not defined "<<lnl<<endl;
	Dump();
    }
    return lnl;
    
}
/**
 * Returns the logarythm of the likeliwood-function of  track y-projection
 */
Float_t TrkTrack::GetLnLY(){
    float lnl=0;
    for(int ip=0; ip<6; ip++)
	if( YGood(ip) && taily[ip]!=0 )
	    lnl += (taily[ip]+1.) * log( (taily[ip]*pow(resy[ip],2.) + pow(yv[ip]-ym[ip],2.)) / (taily[ip]*pow(resy[ip],2)) ); 
    if(GetNY()>2)lnl=lnl/(GetNY()-2);
    else lnl=0;
    if(lnl==0){
	cout << " Float_t  TrkTrack::GetLnLY() -- WARNING -- value not defined "<<lnl<<endl;
	Dump();
    }
    return lnl;
    
}
/**
 * Returns the effective angle, relative to the sensor, on each plane.
 * @param ip plane (0-5)
 * @param iv view (0=x 1=y)
 */
Float_t TrkTrack::GetEffectiveAngle(int ip, int iv){

    if(ip<0 || ip>5){
	cout << "Float_t TrkTrack::GetEffectiveAngle(int "<<ip<<", int "<<iv<<") ==> wrong input"<<endl;
	return 0.;
    }

    float v[3]={xv[ip],yv[ip],zv[ip]};
    //-----------------------------------------
    // effective angle (relative to the sensor)
    //-----------------------------------------
    float axv_geo  = axv[ip];
    float muhall_h = 297.61; //cm**2/Vs
    float BY = TrkParams::GetBY(v);
    float axv_eff = 0;
    if(ip==5) axv_geo = -1*axv_geo;
    if(ip==5) BY      = -1*BY;
    axv_eff = 180.*atan( tan(axv_geo*acos(-1.)/180.) + muhall_h * BY * 0.0001)/acos(-1.);
    //-----------------------------------------
    // effective angle (relative to the sensor)
    //-----------------------------------------
    float ayv_geo = ayv[ip];
    float muhall_e = 1258.18; //cm**2/Vs
    float BX = TrkParams::GetBX(v);
    float ayv_eff = 0;
    ayv_eff = 180.*atan( tan(ayv_geo*acos(-1.)/180.) + muhall_e * BX * 0.0001)/acos(-1.);
  
    if     (iv==0)return axv_eff;
    else if(iv==1)return ayv_eff;
    else{
	cout << "Float_t TrkTrack::GetEffectiveAngle(int "<<ip<<", int "<<iv<<") ==> wrong input"<<endl;
	return 0.;
    }
  
};

//--------------------------------------
//
//
//--------------------------------------
void TrkTrack::Dump(){
    cout << endl << "========== Track " ;
    cout << endl << "seq.  n. : "<< seqno;
    cout << endl << "image n. : "<< image;
    cout << endl << "al       : "; for(int i=0; i<5; i++)cout << al[i] << " ";
    cout << endl << "chi^2    : "<< chi2;
    cout << endl << "n.step   : "<< nstep;
    cout << endl << "xgood    : "; for(int i=0; i<6; i++)cout << XGood(i) ;
    cout << endl << "ygood    : "; for(int i=0; i<6; i++)cout << YGood(i) ;
    cout << endl << "xm       : "; for(int i=0; i<6; i++)cout << xm[i] << " ";
    cout << endl << "ym       : "; for(int i=0; i<6; i++)cout << ym[i] << " ";
    cout << endl << "zm       : "; for(int i=0; i<6; i++)cout << zm[i] << " ";
    cout << endl << "xv       : "; for(int i=0; i<6; i++)cout << xv[i] << " ";
    cout << endl << "yv       : "; for(int i=0; i<6; i++)cout << yv[i] << " ";
    cout << endl << "zv       : "; for(int i=0; i<6; i++)cout << zv[i] << " ";
    cout << endl << "resx     : "; for(int i=0; i<6; i++)cout << resx[i] << " ";
    cout << endl << "resy     : "; for(int i=0; i<6; i++)cout << resy[i] << " ";
    cout << endl << "tailx    : "; for(int i=0; i<6; i++)cout << tailx[i] << " ";
    cout << endl << "taily    : "; for(int i=0; i<6; i++)cout << taily[i] << " ";
    cout << endl << "coval    : "; for(int i=0; i<5; i++)cout << coval[0][i]<<" ";
    cout << endl << "           "; for(int i=0; i<5; i++)cout << coval[1][i]<<" ";
    cout << endl << "           "; for(int i=0; i<5; i++)cout << coval[2][i]<<" ";
    cout << endl << "           "; for(int i=0; i<5; i++)cout << coval[3][i]<<" ";
    cout << endl << "           "; for(int i=0; i<5; i++)cout << coval[4][i]<<" ";
    cout << endl << "dedx_x   : "; for(int i=0; i<6; i++)cout << dedx_x[i] << " ";
    cout << endl << "dedx_y   : "; for(int i=0; i<6; i++)cout << dedx_y[i] << " ";
    cout << endl << "maxs x   : "; for(int i=0; i<6; i++)cout << GetClusterX_MaxStrip(i) << " ";
    cout << endl << "maxs y   : "; for(int i=0; i<6; i++)cout << GetClusterY_MaxStrip(i) << " ";
    cout << endl << "mult x   : "; for(int i=0; i<6; i++)cout << GetClusterX_Multiplicity(i) << " ";
    cout << endl << "mult y   : "; for(int i=0; i<6; i++)cout << GetClusterY_Multiplicity(i) << " ";
    cout << endl << "seed x   : "; for(int i=0; i<6; i++)cout << GetClusterX_Seed(i) << " ";
    cout << endl << "seed y   : "; for(int i=0; i<6; i++)cout << GetClusterY_Seed(i) << " ";
    cout << endl << "xpu      : "; for(int i=0; i<6; i++)cout << xpu[i] << " ";
    cout << endl << "ypu      : "; for(int i=0; i<6; i++)cout << ypu[i] << " ";

    cout << endl;
}
/**
 * Set the TrkTrack position measurements 
 */
void TrkTrack::SetMeasure(double *xmeas, double *ymeas, double *zmeas){
    for(int i=0; i<6; i++) xm[i]=*xmeas++;
    for(int i=0; i<6; i++) ym[i]=*ymeas++;
    for(int i=0; i<6; i++) zm[i]=*zmeas++;
}
/**
 * Set the TrkTrack position resolution 
 */
void TrkTrack::SetResolution(double *rx, double *ry){
    for(int i=0; i<6; i++) resx[i]=*rx++;
    for(int i=0; i<6; i++) resy[i]=*ry++;
}
/**
 * Set the TrkTrack tails position resolution 
 */
void TrkTrack::SetTail(double *tx, double *ty, double factor){
    for(int i=0; i<6; i++) tailx[i]=factor*(*tx++);
    for(int i=0; i<6; i++) taily[i]=factor*(*ty++);
}
/**
 * Set the TrkTrack Student parameter (resx,resy,tailx,taily)
 * from previous gausian fit
 *@param flag =0 standard, =1 with noise correction 
 */
void TrkTrack::SetStudentParam(int flag){
    float sx[11]={0.000128242,
		   0.000136942,
		   0.000162718,
		   0.000202644,
		   0.00025597,
		   0.000317456,
		   0.000349048,
		   0.000384638,
		   0.000457295,
		   0.000512319,
		   0.000538573};
    float tx[11]={1.79402,
		   2.04876,
		   2.88376,
		   3.3,
		   3.14084,
		   4.07686,
		   4.44736,
		   3.5179,
		   3.38697,
		   3.45739,
		   3.18627};
    float sy[11]={0.000483075,
		   0.000466925,
		   0.000431658,
		   0.000428317,
		   0.000433854,
		   0.000444044,
		   0.000482098,
		   0.000537579,
		   0.000636279,
		   0.000741998,
		   0.000864261};
    float ty[11]={0.997032,
		   1.11147,
		   1.18526,
		   1.61404,
		   2.21908,
		   3.08959,
		   4.48833,
		   4.42687,
		   4.65253,
		   4.52043,
		   4.29926};
    int index;
    float fact;
    for(int i=0; i<6; i++) {
	index = int((fabs(axv[i])+1.)/2.);
	if(index>10) index=10;
	tailx[i]=tx[index];
	if(flag==1) {
	    if(fabs(axv[i])<=10.) fact = resx[i]/risxeta2_(&(axv[i]));
	    if(fabs(axv[i])>10.&&fabs(axv[i])<=15.) fact = resx[i]/risxeta3_(&(axv[i]));
	    if(fabs(axv[i])>15.) fact = resx[i]/risxeta4_(&(axv[i]));
	} else fact = 1.;
	resx[i] = sx[index]*fact;
    }
    for(int i=0; i<6; i++) {
	index = int((fabs(ayv[i])+1.)/2.);
	if(index>10) index=10;
	taily[i]=ty[index];
	if(flag==1) fact = resy[i]/risyeta2_(&(ayv[i]));
	else fact = 1.;
	resy[i] = sy[index]*fact;
    }
}
/**
 * Set the TrkTrack good measurement 
 */
void TrkTrack::SetGood(int *xg, int *yg){

    for(int i=0; i<6; i++) xgood[i]=*xg++;
    for(int i=0; i<6; i++) ygood[i]=*yg++;
}

/**
 * Load the magnetic field
 */
void TrkTrack::LoadField(TString path){
    
//     strcpy(path_.path,path.Data());
//     path_.pathlen = path.Length();
//     path_.error   = 0;
//     readb_();

//     TrkParams::SetTrackingMode();
//     TrkParams::SetPrecisionFactor();
//     TrkParams::SetStepMin();
    TrkParams::SetMiniDefault();

    TrkParams::Set(path,1);
    TrkParams::Load(1);
    if( !TrkParams::IsLoaded(1) ){
	cout << "void TrkTrack::LoadField(TString path) --- ERROR --- m.field not loaded"<<endl;
    }

};


/**
 * Method to fill minimization-routine common
 */
void TrkTrack::FillMiniStruct(cMini2track& track){

    for(int i=0; i<6; i++){ 

// 	cout << i<<" - "<<xgood[i]<<" "<<XGood(i)<<endl;
// 	cout << i<<" - "<<ygood[i]<<" "<<YGood(i)<<endl;
	track.xgood[i]=XGood(i);
	track.ygood[i]=YGood(i);
	
	track.xm[i]=xm[i];
	track.ym[i]=ym[i];
	track.zm[i]=zm[i];
	
//      --- temporaneo ----------------------------
// 	float segment = 100.;
// 	track.xm_a[i]=xm[i];
// 	track.xm_b[i]=xm[i];
// 	track.ym_a[i]=ym[i];
// 	track.ym_b[i]=ym[i];
// 	if(       XGood(i) && !YGood(i) ){
// 	    track.ym_a[i] = track.ym_a[i]+segment;
// 	    track.ym_b[i] = track.ym_b[i]-segment;
// 	}else if( !XGood(i) && YGood(i)){
// 	    track.xm_a[i] = track.xm_a[i]+segment;
// 	    track.xm_b[i] = track.xm_b[i]-segment;
// 	}
//      --- temporaneo ----------------------------

	if( XGood(i) || YGood(i) ){
	    double segment = 2.;//cm
	    // NB: i parametri di allineamento hanno una notazione particolare!!!
	    // sensor = 0 (hybrid side), 1 
	    // ladder = 0-2 (increasing x)
	    // plane  = 0-5 (from bottom to top!!!) 
	    int is = (int)GetSensor(i); if(i==5)is=1-is;
	    int ip = 5-i;
	    int il = (int)GetLadder(i);
	    
	    double omega   = 0.; 
	    double beta    = 0.;
	    double gamma   = 0.;
	    if( 
		(is < 0 || is > 1 || ip < 0 || ip > 5 || il < 0 || il > 2) &&
		true){
		// se il piano risulta colpito, ladder e sensore devono essere 
		// assegnati correttamente
		cout << " void TrkTrack::FillMiniStruct(cMini2track&) --- WARNING --- sensor not defined, cannot read alignment parameters "<<endl;
		cout << " is ip il = "<<is<<" "<<ip<<" "<<il<<endl;
	    }else{
		omega   = alignparameters_.omega[is][il][ip];
		beta    = alignparameters_.beta[is][il][ip];
		gamma   = alignparameters_.gamma[is][il][ip];
	    }
	    
	    if(       XGood(i) && !YGood(i) ){
		track.xm_a[i] = xm[i] - omega * segment;
		track.ym_a[i] = ym[i] + segment;
//	    track.zm_a[i] = zm[i] + beta * segment;//not used yet
		track.xm_b[i] = xm[i] + omega * segment;
		track.ym_b[i] = ym[i] - segment;
//	    track.zm_b[i] = zm[i] - beta * segment;//not used yet
	    }else if( !XGood(i) && YGood(i) ){
		track.xm_a[i] = xm[i] + segment;
		track.ym_a[i] = ym[i] + omega * segment;
//	    track.zm_a[i] = zm[i] - gamma * segment;//not used yet
		track.xm_b[i] = xm[i] - segment;
		track.ym_b[i] = ym[i] - omega * segment;
//	    track.zm_b[i] = zm[i] + gamma * segment;//not used yet
	    }
	}
	
       	track.resx[i]=resx[i];
	track.resy[i]=resy[i];
	track.tailx[i]=tailx[i];
	track.taily[i]=taily[i];
    }

    for(int i=0; i<5; i++) track.al[i]=al[i]; 
    track.zini = 23.5; 
// ZINI = 23.5 !!! it should be the same parameter in all codes
    
}
/**
 * Method to set values from  minimization-routine common
 */
void TrkTrack::SetFromMiniStruct(cMini2track *track){

    for(int i=0; i<5; i++) {
	al[i]=track->al[i];
	for(int j=0; j<5; j++) coval[i][j]=track->cov[i][j];
    }
    chi2  = track->chi2;
    nstep = track->nstep;
    for(int i=0; i<6; i++){ 
	xv[i]  = track->xv[i];
	yv[i]  = track->yv[i];
	zv[i]  = track->zv[i];
	xm[i]  = track->xm[i];
	ym[i]  = track->ym[i];
	zm[i]  = track->zm[i];
	axv[i] = track->axv[i];
	ayv[i] = track->ayv[i];	
    }
    
}
/**
 * \brief Method to re-evaluate coordinates of clusters associated with a track.
 *
 * The method can be applied only after recovering level1 information 
 * (either by reprocessing single events from level0 or from  
 * the TrkLevel1 branch, if present); it calls F77 subroutines that 
 * read the level1 common and fill the minimization-routine common.
 * Some clusters can be excluded or added by means of the methods:
 *
 * TrkTrack::ResetXGood(int ip)
 * TrkTrack::ResetYGood(int ip)
 * TrkTrack::SetXGood(int ip, int cid, int is)
 * TrkTrack::SetYGood(int ip, int cid, int is)
 *
 * NB! The method TrkTrack::SetGood(int *xg, int *yg) set the plane-mask (0-1) 
 * for the minimization-routine common. It deletes the cluster information
 * (at least for the moment...) thus cannot be applied before 
 * TrkTrack::EvaluateClusterPositions().  
 *
 * Different p.f.a. can be applied by calling (once) the method:
 * 
 * TrkParams::SetPFA(0); //Set ETA p.f.a.
 *
 * @see TrkParams::SetPFA(int)
 */
Bool_t TrkTrack::EvaluateClusterPositions(){
    
//     cout << "void TrkTrack::GetClusterositions() "<<endl;

    bool OK=true;
    TrkParams::Load(1); if( !TrkParams::IsLoaded(1) )cout << "Bool_t TrkTrack::EvaluateClusterPositions() ---ERROR--- m.field not loaded "<<endl;
    TrkParams::Load(4); if( !TrkParams::IsLoaded(4) )cout << "Bool_t TrkTrack::EvaluateClusterPositions() ---ERROR--- p.f.a. par. not loaded "<<endl;
    TrkParams::Load(5); if( !TrkParams::IsLoaded(5) )cout << "Bool_t TrkTrack::EvaluateClusterPositions() ---ERROR--- alignment par. not loaded "<<endl;
    if(!OK)return false;

    for(int ip=0; ip<6; ip++){
//	cout << ip<<" ** "<<xm[ip]<<" / "<<ym[ip]<<endl;;
	int icx = GetClusterX_ID(ip)+1;
	int icy = GetClusterY_ID(ip)+1;
	int sensor = GetSensor(ip)+1;//<< convenzione "Paolo"
	if(ip==5 && sensor!=0)sensor=3-sensor;//<< convenzione "Elena"
	int ladder = GetLadder(ip)+1;
	float ax = axv[ip];
	float ay = ayv[ip];
	float v[3];
	v[0]=xv[ip];
	v[1]=yv[ip];
	v[2]=zv[ip];
	float bfx = 10*TrkParams::GetBX(v);//Tesla
	float bfy = 10*TrkParams::GetBY(v);//Tesla
	int ipp=ip+1;
	xyzpam_(&ipp,&icx,&icy,&ladder,&sensor,&ax,&ay,&bfx,&bfy);
	if(icx<0 || icy<0)return false;
    }
    return true;
}
/**
 * \brief Tracking method. It calls F77 mini routine.
 *
 * @param pfixed Particle momentum. If pfixed=0 the momentum 
 * is left as a free parameter, otherwise it is fixed to the input value.
 * @param fail Output flag (!=0 if the fit failed). 
 * @param iprint Flag to set debug mode ( 0 = no output; 1 = verbose; 2 = debug).
 * @param froml1 Flag to re-evaluate positions (see TrkTrack::GetClusterPositions()). 
 *
 * The option to re-evaluate positions can be used only after recovering
 * level1 information, eg. by reprocessing the single event. 
 *
 * Example:
 *
 * if( !event->GetTrkLevel0() )return false;
 * event->GetTrkLevel0()->ProcessEvent(); // re-processing level0->level1
 * int fail=0;
 * event->GetTrkLevel2()->GetTrack(0)->Fit(0.,fail,0,1);
 *
 * @see EvaluateClusterPositions()
 *
 * The fitting procedure can be varied by changing the tracking mode, 
 * the fit-precision factor, the minimum number of step, etc.
 * @see SetTrackingMode(int)
 * @see SetPrecisionFactor(double)
 * @see SetStepMin(int)
 * @see SetDeltaB(int,double)
 */
void TrkTrack::Fit(double pfixed, int& fail, int iprint, int froml1){

    bool OK=true;
    TrkParams::Load(1); if( !TrkParams::IsLoaded(1) )cout << "void TrkTrack::Fit(double,int&,int,int) ---ERROR--- m.field not loaded "<<endl;
    if(!OK)return;

    float al_ini[] = {0.,0.,0.,0.,0.};

    extern cMini2track track_;
    fail = 0;

    FillMiniStruct(track_);
        
    if(froml1!=0){
	if( !EvaluateClusterPositions() ){
	    cout << "void TrkTrack::Fit("<<pfixed<<","<<fail<<","<<iprint<<","<<froml1<<") --- ERROR evaluating cluster positions "<<endl;
	    FillMiniStruct(track_) ;
	    fail = 1;
	    return;
	}
    }else{
	FillMiniStruct(track_);	
    }
    
    // if fit variables have been reset, evaluate the initial guess
    if(al[0]==-9999.&&al[1]==-9999.&&al[2]==-9999.&&al[3]==-9999.&&al[4]==-9999.)guess_();

    // --------------------- free momentum 
    if(pfixed==0.) {
	track_.pfixed=0.; 
    }
    // --------------------- fixed momentum 
    if(pfixed!=0.) {
	al[4]=1./pfixed;     
	track_.pfixed=pfixed;
    }

    //  store temporarily the initial guess
    for(int i=0; i<5; i++) al_ini[i]=track_.al[i]; 

    //  ------------------------------------------
    //  call mini routine
    //  ------------------------------------------
    int istep=0;
    int ifail=0;
    mini2_(&istep,&ifail, &iprint);
    if(ifail!=0) {
	if(iprint)cout << "ERROR: ifail= " << ifail << endl;
	fail = 1;
    }
    //  ------------------------------------------
    
    SetFromMiniStruct(&track_);

    if(fail){
 	if(iprint)cout << " >>>> fit failed "<<endl;
 	for(int i=0; i<5; i++) al[i]=al_ini[i]; 
    }

};
/**
 * Reset the fit parameters 
 */
void TrkTrack::FitReset(){
    for(int i=0; i<5; i++) al[i]=-9999.;
    chi2=0.;
    nstep=0;
//     for(int i=0; i<6; i++) xv[i]=0.;
//     for(int i=0; i<6; i++) yv[i]=0.;
//     for(int i=0; i<6; i++) zv[i]=0.;
//     for(int i=0; i<6; i++) axv[i]=0.;
//     for(int i=0; i<6; i++) ayv[i]=0.;
    for(int i=0; i<5; i++) {
	for(int j=0; j<5; j++) coval[i][j]=0.;
    }
}
/**
 * Set the tracking mode 
 */
void TrkTrack::SetTrackingMode(int trackmode){
    extern cMini2track track_;
    track_.trackmode = trackmode;
}
/**
 * Set the factor scale for tracking precision 
 */
void TrkTrack::SetPrecisionFactor(double fact){
    extern cMini2track track_;
    track_.fact = fact;
}
/**
 * Set the minimum number of steps for tracking precision 
 */
void TrkTrack::SetStepMin(int istepmin){
    extern cMini2track track_;
    track_.istepmin = istepmin;
}
/**
 * Set deltaB parameters (id=0,1). By default they are set to zero.
 */
void TrkTrack::SetDeltaB(int id, double db){
    if(id!=0 && id!=1)cout << "void TrkTrack::SetDeltaB(int id,double db) -- wrong input parameters: "<<id<<" "<<db<<endl;
    TrkParams::SetDeltaB(id,db);
}

/**
 * Returns true if the track is inside the magnet cavity.
 * @param toll Tolerance around the nominal volume (toll>0 define an inner fiducial volume)
 */
Bool_t TrkTrack::IsInsideCavity(float toll){

//     float xmagntop, ymagntop, xmagnbottom, ymagnbottom;
//     xmagntop = xv[0] + (ZMAGNHIGH-zv[0])*tan(acos(-1.0)*axv[0]/180.);
//     ymagntop = yv[0] + (ZMAGNHIGH-zv[0])*tan(acos(-1.0)*ayv[0]/180.);
//     xmagnbottom = xv[5] + (ZMAGNLOW-zv[5])*tan(acos(-1.0)*axv[5]/180.);
//     ymagnbottom = yv[5] + (ZMAGNLOW-zv[5])*tan(acos(-1.0)*ayv[5]/180.);
//     if( xmagntop>XMAGNLOW && xmagntop<XMAGNHIGH &&
// 	ymagntop>YMAGNLOW && ymagntop<YMAGNHIGH &&
// 	xmagnbottom>XMAGNLOW && xmagnbottom<XMAGNHIGH &&
// 	ymagnbottom>YMAGNLOW && ymagnbottom<YMAGNHIGH ) return(true);
//     else return(false);

    int ngf = TrkParams::nGF;
    for(int i=0; i<ngf; i++){
	//
//	cout << endl << TrkParams::GF_element[i];
	if( 
	    TrkParams::GF_element[i].CompareTo("CUF") &&
	    TrkParams::GF_element[i].CompareTo("T2")  &&
	    TrkParams::GF_element[i].CompareTo("T3")  &&
	    TrkParams::GF_element[i].CompareTo("T4")  &&
	    TrkParams::GF_element[i].CompareTo("T5")  &&
	    TrkParams::GF_element[i].CompareTo("CLF") &&
	    true)continue;
	// apply condition only within the cavity
//	cout << " -- "<<xGF[i]<<" "<<yGF[i];
	if( 
	    xGF[i] <= TrkParams::xGF_min[i] + toll ||
	    xGF[i] >= TrkParams::xGF_max[i] - toll ||
	    yGF[i] <= TrkParams::yGF_min[i] + toll ||
	    yGF[i] >= TrkParams::yGF_max[i] - toll ||
	    false){
	    
	    return false;
	}
    }
    return true;


}
/**
 * Returns true if the track is inside the nominal acceptance, which is defined 
 * by the intersection among magnet cavity, silicon-plane sensitive area and 
 * ToF sensitive area (nominal values from the official document used to 
 * calculate the geometrical factor)
 */
Bool_t TrkTrack::IsInsideAcceptance(){

    int ngf = TrkParams::nGF;
    for(int i=0; i<ngf; i++){
	if( 
	    xGF[i] <= TrkParams::xGF_min[i] ||
	    xGF[i] >= TrkParams::xGF_max[i] ||
	    yGF[i] <= TrkParams::yGF_min[i] ||
	    yGF[i] >= TrkParams::yGF_max[i] ||
	    false)return false;
    }
    return true;

}
/**
 * Method to retrieve ID (0,1,...) of x-cluster (if any) associated to this track.
 * If no cluster is associated, ID=-1.
 * @param ip Tracker plane (0-5)
 */
Int_t TrkTrack::GetClusterX_ID(int ip){
    return ((Int_t)fabs(xgood[ip]))%10000000-1;
};
/**
 * Method to retrieve ID (0-xxx) of y-cluster (if any) associated to this track.
 * If no cluster is associated, ID=-1.
 * @param ip Tracker plane (0-5)
 */
Int_t TrkTrack::GetClusterY_ID(int ip){
    return ((Int_t)fabs(ygood[ip]))%10000000-1;
};

/**
 * Method to retrieve the ladder (0-2, increasing x) traversed by the track on this plane.
 * If no ladder is traversed (dead area) the metod retuns -1.
 * @param ip Tracker plane (0-5)
 */
Int_t TrkTrack::GetLadder(int ip){
    if(XGood(ip))return (Int_t)fabs(xgood[ip]/100000000)-1;
    if(YGood(ip))return (Int_t)fabs(ygood[ip]/100000000)-1;
    return -1;
};
/**
 * Method to retrieve the sensor (0-1, increasing y) traversed by the track on this plane.
 * If no sensor is traversed (dead area) the metod retuns -1.
 * @param ip Tracker plane (0-5)
 */
Int_t TrkTrack::GetSensor(int ip){
    if(XGood(ip))return (Int_t)((Int_t)fabs(xgood[ip]/10000000)%10)-1;
    if(YGood(ip))return (Int_t)((Int_t)fabs(ygood[ip]/10000000)%10)-1;
    return -1;
};

/**
 * \brief Method to include a x-cluster to the track.
 * @param ip Tracker plane (0-5)
 * @param clid Cluster ID (0 = no-cluster, 1,2,... otherwise )
 * @param il Ladder (0-2, increasing x, -1 if no sensitive area is hit) 
 * @param is Sensor (0-1, increasing y, -1 if no sensitive area is hit) 
 * @param bad True if the cluster contains bad strips  
 * @see Fit(double pfixed, int& fail, int iprint, int froml1)
 */
void TrkTrack::SetXGood(int ip, int clid, int il, int is, bool bad){
//    int il=0;       //ladder (temporary)
//    bool bad=false; //ladder (temporary)
    if(ip<0||ip>5||clid<0||il<-1||il>2||is<-1||is>1)
	cout << " void TrkTrack::SetXGood(int,int,int,int,bool) --> MA SEI DI COCCIO?!?!"<<endl;
    xgood[ip]=(il+1)*100000000+(is+1)*10000000+clid;
    if(bad)xgood[ip]=-xgood[ip];
};
/**
 * \brief Method to include a y-cluster to the track.
 * @param ip Tracker plane (0-5)
 * @param clid Cluster ID (0 = no-cluster, 1,2,... otherwise )
 * @param il Ladder (0-2, increasing x, -1 if no sensitive area is hit) 
 * @param is Sensor (0-1, increasing y, -1 if no sensitive area is hit) 
 * @param bad True if the cluster contains bad strips  
 * @see Fit(double pfixed, int& fail, int iprint, int froml1)
 */
void TrkTrack::SetYGood(int ip, int clid, int il, int is, bool bad){
//    int il=0;       //ladder (temporary)
//    bool bad=false; //ladder (temporary)
    if(ip<0||ip>5||clid<0||il<-1||il>2||is<-1||is>1)
	cout << " void TrkTrack::SetYGood(int,int,int,int,bool) --> MA SEI DI COCCIO?!?!"<<endl;
    ygood[ip]=(il+1)*100000000+(is+1)*10000000+clid;
    if(bad)ygood[ip]=-ygood[ip];
};

/**
 * \brief Average X
 * Average value of <xv>, evaluated from the first to the last hit x view.
 */
Float_t TrkTrack::GetXav(){
 
    int first_plane = -1;
    int last_plane  = -1;
    for(Int_t ip=0; ip<6; ip++){
	if( XGood(ip) && first_plane == -1 )first_plane = ip;
	if( XGood(ip) && first_plane != -1 )last_plane = ip;
    }
    if( first_plane == -1 || last_plane == -1){
	return -100;
    }
    if( last_plane-first_plane+1 ==0 )return -100;

    Float_t av = 0;    
    for(int ip=first_plane; ip<=last_plane; ip++)av+=xv[ip];
    
    return (av/(last_plane-first_plane+1));    
}
/**
 * \brief Average Y
 * Average value of <yv>, evaluated from the first to the last hit x view.
 */
Float_t TrkTrack::GetYav(){

    int first_plane = -1;
    int last_plane  = -1;
    for(Int_t ip=0; ip<6; ip++){
	if( XGood(ip) && first_plane == -1 )first_plane = ip;
	if( XGood(ip) && first_plane != -1 )last_plane = ip;
    }
    if( first_plane == -1 || last_plane == -1){
	return -100;
    }
    if( last_plane-first_plane+1 ==0 )return -100;

    Float_t av = 0;    
    for(int ip=first_plane; ip<=last_plane; ip++)av+=yv[ip];
 
    return (av/(last_plane-first_plane+1));    
}
/**
 * \brief Average Z
 * Average value of <zv>, evaluated from the first to the last hit x view.
 */
Float_t TrkTrack::GetZav(){

    int first_plane = -1;
    int last_plane  = -1;
    for(Int_t ip=0; ip<6; ip++){
	if( XGood(ip) && first_plane == -1 )first_plane = ip;
	if( XGood(ip) && first_plane != -1 )last_plane = ip;
    }
    if( first_plane == -1 || last_plane == -1){
	return -100;
    }
    if( last_plane-first_plane+1 ==0 )return -100;

    Float_t av = 0;    
    for(int ip=first_plane; ip<=last_plane; ip++)av+=zv[ip];
    
    return (av/(last_plane-first_plane+1));    
}

/**
 * \brief Number of column traversed
 */
Int_t TrkTrack::GetNColumns(){
    int sensors[] = {0,0,0,0,0,0};
    for(int ip=0; ip<6; ip++){
	int sensorid = GetLadder(ip)+3*GetSensor(ip);    
	if(XGood(ip)||YGood(ip))
	    if(sensorid>=0 && sensorid<6)sensors[sensorid]=1;
    }
    int nsensors=0;
    for(int is=0; is<6; is++)nsensors += sensors[is];
    return nsensors;
};
/**
 * \brief Give the maximum energy release 
 */
Float_t TrkTrack::GetDEDX_max(int ip, int iv){
    Float_t max=0;
    int pfrom = 0;
    int pto   = 6;
    int vfrom = 0;
    int vto   = 2;
    if(ip>=0&&ip<6){
	pfrom = ip;
	pto   = ip+1;
    }
    if(iv>=0&&iv<2){
	vfrom = iv;
	vto   = iv+1;
    }
    for(int i=pfrom; i<pto; i++)
	for(int j=vfrom; j<vto; j++){
	    if(j==0 && XGood(i) && GetDEDX(i,j)>max)max=GetDEDX(i,j);
	    if(j==1 && YGood(i) && GetDEDX(i,j)>max)max=GetDEDX(i,j);
	}
    return max;

};

/**
 * \brief Give the minimum energy release 
 */
Float_t TrkTrack::GetDEDX_min(int ip, int iv){
    Float_t min=100000000;
    int pfrom = 0;
    int pto   = 6;
    int vfrom = 0;
    int vto   = 2;
    if(ip>=0&&ip<6){
	pfrom = ip;
	pto   = ip+1;
    }
    if(iv>=0&&iv<2){
	vfrom = iv;
	vto   = iv+1;
    }
    for(int i=pfrom; i<pto; i++)
	for(int j=vfrom; j<vto; j++){
	    if(j==0 && XGood(i) && GetDEDX(i,j)<min)min=GetDEDX(i,j);
	    if(j==1 && YGood(i) && GetDEDX(i,j)<min)min=GetDEDX(i,j);
	}
    return min;

};

/**
 * \brief Give the maximum spatial residual  
 */
Float_t TrkTrack::GetResidual_max(int ip, int iv){
    Float_t max=0;
    int pfrom = 0;
    int pto   = 6;
    int vfrom = 0;
    int vto   = 2;
    if(ip>=0&&ip<6){
	pfrom = ip;
	pto   = ip+1;
    }
    if(iv>=0&&iv<2){
	vfrom = iv;
	vto   = iv+1;
    }
    for(int i=pfrom; i<pto; i++){
	for(int j=vfrom; j<vto; j++){
 	    if(j==0 && XGood(i) && fabs(xm[i]-xv[i])>fabs(max))max=xm[i]-xv[i];
 	    if(j==1 && YGood(i) && fabs(ym[i]-yv[i])>fabs(max))max=ym[i]-yv[i];
	}
    }
    return max;

};
/**
 * \brief Give the anerage spatial residual 
 */
Float_t TrkTrack::GetResidual_av(int ip, int iv){
    //
//Sum$((xm>-50)*(xm-xv)/resx)/sqrt(TrkTrack.GetNX()*TrkTrack.GetChi2X())<0.3

    Float_t av  = 0.;
    int     nav = 0;
    //
    int pfrom = 0;
    int pto   = 6;
    int vfrom = 0;
    int vto   = 2;
    if(ip>=0&&ip<6){
	pfrom = ip;
	pto   = ip+1;
    }
    if(iv>=0&&iv<2){ 
	vfrom = iv;
	vto   = iv+1;
    }
    for(int i=pfrom; i<pto; i++){
	for(int j=vfrom; j<vto; j++){
	    nav++;
 	    if(j==0 && XGood(i)) av += (xm[i]-xv[i])/resx[i];
 	    if(j==1 && YGood(i)) av += (ym[i]-yv[i])/resy[i];
	}
    }
    if(nav==0)return -100.;
    return av/nav;

};


/**
 * \brief Give the maximum multiplicity on the x view 
 */
Int_t TrkTrack::GetClusterX_Multiplicity_max(){
    int max=0;
    for(int ip=0; ip<6; ip++)
	if(GetClusterX_Multiplicity(ip)>max)max=GetClusterX_Multiplicity(ip);
    return max;
};
/**
 * \brief Give the minimum multiplicity on the x view 
 */
Int_t TrkTrack::GetClusterX_Multiplicity_min(){
    int min=50;
    for(int ip=0; ip<6; ip++)
	if(GetClusterX_Multiplicity(ip)<min)min=GetClusterX_Multiplicity(ip);
    return min;
};
/**
 * \brief Give the maximum multiplicity on the x view 
 */
Int_t TrkTrack::GetClusterY_Multiplicity_max(){
    int max=0;
    for(int ip=0; ip<6; ip++)
	if(GetClusterY_Multiplicity(ip)>max)max=GetClusterY_Multiplicity(ip);
    return max;
};
/**
 * \brief Give the minimum multiplicity on the x view 
 */
Int_t TrkTrack::GetClusterY_Multiplicity_min(){
    int min=50;
    for(int ip=0; ip<6; ip++)
	if(GetClusterY_Multiplicity(ip)<min)min=GetClusterY_Multiplicity(ip);
    return min;
};

/**
 * \brief Give the minimum seed on the x view 
 */
Float_t TrkTrack::GetClusterX_Seed_min(){
    Float_t min=100000;
    for(int ip=0; ip<6; ip++)
	if(XGood(ip) && GetClusterX_Seed(ip)<min)min=GetClusterX_Seed(ip);
    return min;
};
/**
 * \brief Give the minimum seed on the x view 
 */
Float_t TrkTrack::GetClusterY_Seed_min(){
    Float_t min=100000;
    for(int ip=0; ip<6; ip++)
	if(YGood(ip) && GetClusterY_Seed(ip)<min)min=GetClusterY_Seed(ip);
    return min;
};


//--------------------------------------
//
//
//--------------------------------------
void TrkTrack::Clear(){
//    cout << "TrkTrack::Clear()"<<endl;
    seqno = -1; 
    image = -1; 
    chi2  = 0;
    nstep = 0;
    for(int it1=0;it1<5;it1++){
	al[it1] = 0;
	for(int it2=0;it2<5;it2++)coval[it1][it2] = 0;
    };
    for(int ip=0;ip<6;ip++){
	xgood[ip]  = 0;
	ygood[ip]  = 0;
	xm[ip]     = 0;
	ym[ip]     = 0;
	zm[ip]     = 0;
	resx[ip]   = 0;
	resy[ip]   = 0;
	tailx[ip]  = 0;
	taily[ip]  = 0;
	xv[ip]     = 0;
	yv[ip]     = 0;
	zv[ip]     = 0;
	axv[ip]    = 0;
	ayv[ip]    = 0;
	dedx_x[ip] = 0;
	dedx_y[ip] = 0;

    };
    int ngf = TrkParams::nGF;
    for(int i=0; i<ngf; i++){
	xGF[i] = 0.;
	yGF[i] = 0.;
    }
//     if(clx)clx->Clear();
//     if(cly)cly->Clear();
//    clx.Clear();
//    cly.Clear();
};
//--------------------------------------
//
//
//--------------------------------------
void TrkTrack::Delete(){
//    cout << "TrkTrack::Delete()"<<endl;
    Clear();
//    if(clx)delete clx;
//    if(cly)delete cly;
};
//--------------------------------------
//
//
//--------------------------------------

//--------------------------------------
//
//
//--------------------------------------
TrkSinglet::TrkSinglet(){
//    cout << "TrkSinglet::TrkSinglet() " << GetUniqueID()<<endl;
//     plane    = 0;
//     coord[0] = 0; 
//     coord[1] = 0;
//     sgnl     = 0;
//     multmax  = 0;
//    cls      = 0;
    Clear();
};
//--------------------------------------
//
//
//--------------------------------------
TrkSinglet::TrkSinglet(const TrkSinglet& s){
//    cout << "TrkSinglet::TrkSinglet(const TrkSinglet& s) " << GetUniqueID()<<endl;
    plane    = s.plane;
    coord[0] = s.coord[0]; 
    coord[1] = s.coord[1];
    sgnl     = s.sgnl;
    multmax  = s.multmax;
//	cls      = 0;//<<<<pointer
//    cls      = TRef(s.cls);
};
//--------------------------------------
//
//
//--------------------------------------
void TrkSinglet::Dump(){
    int i=0;
    cout << endl << "========== Singlet " ;
    cout << endl << "plane        : " << plane;
    cout << endl << "coord[2]     : "; while( i<2 && cout << coord[i] << " ") i++;
    cout << endl << "sgnl         : " << sgnl;
    cout << endl << "max.strip    : ";
    cout << endl << "multiplicity : ";
}
//--------------------------------------
//
//
//--------------------------------------
void TrkSinglet::Clear(){
//    cout << "TrkSinglet::Clear() " << GetUniqueID()<<endl;
//    cls=0;
    plane=-1;
    coord[0]=-999;
    coord[1]=-999;
    sgnl=0;
    multmax  = 0;
    
}
//--------------------------------------
//
//
//--------------------------------------
TrkLevel2::TrkLevel2(){
  //    cout <<"TrkLevel2::TrkLevel2()"<<endl;
    for(Int_t i=0; i<12 ; i++){
	good[i] = -1;
	VKmask[i] = 0;
	VKflag[i] = 0;	
    };
    Track    = 0;
    SingletX = 0;
    SingletY = 0;

}
//--------------------------------------
//
//
//--------------------------------------
void TrkLevel2::Set(){
    if(!Track)Track    = new TClonesArray("TrkTrack");
    if(!SingletX)SingletX = new TClonesArray("TrkSinglet");
    if(!SingletY)SingletY = new TClonesArray("TrkSinglet");
}
//--------------------------------------
//
//
//--------------------------------------
void TrkLevel2::Dump(){
	
	//
    cout << endl << endl << "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-";
    cout << endl << "good     : "; for(int i=0; i<12; i++) cout << hex <<" 0x"<< good[i]<<dec;
    cout << endl << "ntrk()   : " << ntrk() ;
    cout << endl << "nclsx()  : " << nclsx();
    cout << endl << "nclsy()  : " << nclsy();
    if(Track){
	TClonesArray &t  = *Track;
	for(int i=0; i<ntrk(); i++)     ((TrkTrack *)t[i])->Dump();
    }	    
//     if(SingletX){
// 	TClonesArray &sx = *SingletX;
// 	for(int i=0; i<nclsx(); i++) ((TrkSinglet *)sx[i])->Dump();
//     }
//     if(SingletY){
// 	TClonesArray &sy = *SingletY;
// 	for(int i=0; i<nclsy(); i++) ((TrkSinglet *)sy[i])->Dump();
//     }
    cout << endl;
}
/**
 * \brief Dump processing status
 */
void TrkLevel2::StatusDump(int view){
    cout << "DSP n. "<<view+1<<" status: "<<hex<<good[view]<<endl;    
};
/**
 * \brief Check event status
 *
 * Check the event status, according to a flag-mask given as input. 
 * Return true if the view passes the check.
 * 
 * @param view View number (0-11)
 * @param flagmask Mask of flags to check (eg. flagmask=0x111 no missing packet, 
 *  no crc error, no software alarm)
 *
 * @see TrkLevel2 class definition to know how the status flag is defined
 *
 */
Bool_t TrkLevel2::StatusCheck(int view, int flagmask){

    if( view<0 || view >= 12)return false;
    return !(good[view]&flagmask);

};


//--------------------------------------
//
//
//--------------------------------------
/**
 * The method returns false if the viking-chip was masked  
 * either apriori ,on the basis of the mask read from the DB, 
 * or run-by-run, on the basis of the calibration parameters)
 * @param iv Tracker view (0-11)
 * @param ivk Viking-chip number (0-23)
 */
Bool_t TrkLevel2::GetVKMask(int iv, int ivk){
    Int_t whichbit = (Int_t)pow(2,ivk);
    return (whichbit&VKmask[iv])!=0;    
}
/**
 * The method returns false if the viking-chip was masked  
 * for this event due to common-noise computation failure.
 * @param iv Tracker view (0-11)
 * @param ivk Viking-chip number (0-23)
 */
Bool_t TrkLevel2::GetVKFlag(int iv, int ivk){
    Int_t whichbit = (Int_t)pow(2,ivk);
    return (whichbit&VKflag[iv])!=0;    
}
/**
 * The method returns true if the viking-chip was masked, either
 * forced (see TrkLevel2::GetVKMask(int,int)) or 
 * for this event only (TrkLevel2::GetVKFlag(int,int)). 
 * @param iv Tracker view (0-11)
 * @param ivk Viking-chip number (0-23) 
 */
Bool_t TrkLevel2::IsMaskedVK(int iv, int ivk){
    return !(GetVKMask(iv,ivk)&&GetVKFlag(iv,ivk) ); 
};

//--------------------------------------
//
//
//--------------------------------------
/**
 * Fills a TrkLevel2 object with values from a struct cTrkLevel2 (to get data from F77 common). 
 * Ref to Level1 data (clusters) is also set. If l1==NULL no references are set.
 * (NB It make sense to set references only if events are stored in a tree that contains also the Level1 branch)
 */
void TrkLevel2::SetFromLevel2Struct(cTrkLevel2 *l2, TrkLevel1 *l1){

//    cout << "void TrkLevel2::SetFromLevel2Struct(cTrkLevel2 *l2, TrkLevel1 *l1)"<<endl;
    Clear();

//  temporary objects:
    TrkSinglet* t_singlet = new TrkSinglet();
    TrkTrack*   t_track   = new TrkTrack();

//  -----------------
//  general variables
//  -----------------
    for(Int_t i=0; i<12 ; i++){
	good[i] = l2->good[i];
	VKmask[i]=0;
	VKflag[i]=0;
	for(Int_t ii=0; ii<24 ; ii++){
	    Int_t setbit = (Int_t)pow(2,ii);
	    if( l2->vkflag[ii][i]!=-1 )VKmask[i]=VKmask[i]|setbit;
	    if( l2->vkflag[ii][i]!=0  )VKflag[i]=VKflag[i]|setbit;
	};
    };
//  --------------
//  *** TRACKS ***
//  --------------
    if(!Track) Track = new TClonesArray("TrkTrack");
    TClonesArray &t = *Track;

    for(int i=0; i<l2->ntrk; i++){
	t_track->seqno = i;// NBNBNBNB deve sempre essere = i
	t_track->image = l2->image[i]-1;
	t_track->chi2  = l2->chi2_nt[i];
	t_track->nstep = l2->nstep_nt[i];
	for(int it1=0;it1<5;it1++){
	    t_track->al[it1] = l2->al_nt[i][it1];
	    for(int it2=0;it2<5;it2++)
		t_track->coval[it1][it2] = l2->coval[i][it2][it1];
	};
	for(int ip=0;ip<6;ip++){
	    // ---------------------------------
	    // new implementation of xgood/ygood 
	    // ---------------------------------
	    t_track->xgood[ip]  = l2->cltrx[i][ip]; //cluster ID
	    t_track->ygood[ip]  = l2->cltry[i][ip]; //cluster ID
	    t_track->xgood[ip] += 10000000*l2->ls[i][ip]; // ladder+sensor
	    t_track->ygood[ip] += 10000000*l2->ls[i][ip]; // ladder+sensor
	    if(l2->xbad[i][ip]>0)t_track->xgood[ip]=-t_track->xgood[ip];
	    if(l2->ybad[i][ip]>0)t_track->ygood[ip]=-t_track->ygood[ip];
//  	    if(l2->xbad[i][ip]>0 || l2->ybad[i][ip]>0){
//   	    if(l2->dedx_x[i][ip]<0 || l2->dedx_y[i][ip]<0){
//   		cout << ip << " - "<< l2->cltrx[i][ip] << " "<<l2->cltry[i][ip]<<" "<<l2->ls[i][ip]<<endl;
//   		cout << ip << " - "<<t_track->xgood[ip]<<" "<<t_track->ygood[ip]<<endl;
//   		cout << ip << " - "<<t_track->GetClusterX_ID(ip)<<" "<<t_track->GetClusterY_ID(ip)<<" "<<t_track->GetLadder(ip)<<" "<<t_track->GetSensor(ip)<<endl;
//  		cout << ip << " - "<<t_track->BadClusterX(ip)<<" "<<t_track->BadClusterY(ip)<<endl;
//  		cout << ip << " - "<<t_track->SaturatedClusterX(ip)<<" "<<t_track->SaturatedClusterY(ip)<<endl;
//   	    }
	    t_track->xm[ip]     = l2->xm_nt[i][ip];
	    t_track->ym[ip]     = l2->ym_nt[i][ip];
	    t_track->zm[ip]     = l2->zm_nt[i][ip];
	    t_track->resx[ip]   = l2->resx_nt[i][ip];
	    t_track->resy[ip]   = l2->resy_nt[i][ip];
	    t_track->tailx[ip]  = l2->tailx[i][ip];
	    t_track->taily[ip]  = l2->taily[i][ip];
	    t_track->xv[ip]     = l2->xv_nt[i][ip];
	    t_track->yv[ip]     = l2->yv_nt[i][ip];
	    t_track->zv[ip]     = l2->zv_nt[i][ip];
	    t_track->axv[ip]    = l2->axv_nt[i][ip];
	    t_track->ayv[ip]    = l2->ayv_nt[i][ip];
	    t_track->dedx_x[ip] = l2->dedx_x[i][ip];
	    t_track->dedx_y[ip] = l2->dedx_y[i][ip];
	    t_track->multmaxx[ip] = l2->multmaxx[i][ip]; 
	    t_track->multmaxy[ip] = l2->multmaxy[i][ip];
	    t_track->seedx[ip]  = l2->seedx[i][ip];  
	    t_track->seedy[ip]  = l2->seedy[i][ip];
	    t_track->xpu[ip]    = l2->xpu[i][ip];   
	    t_track->ypu[ip]    = l2->ypu[i][ip];   
	    //-----------------------------------------------------
	    //-----------------------------------------------------
	    //-----------------------------------------------------
	    //-----------------------------------------------------
	};
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// evaluated coordinates (to define GF)
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	int    ngf = TrkParams::nGF;
	float *zgf = TrkParams::zGF;
	Trajectory tgf = Trajectory(ngf,zgf);
	tgf.DoTrack2(t_track->al);//<<<< integrate the trajectory
	for(int ip=0; ip<ngf; ip++){
	    t_track->xGF[ip] = tgf.x[ip];
	    t_track->yGF[ip] = tgf.y[ip];
	}
	
// 	if(t_track->IsSaturated())t_track->Dump();
	new(t[i]) TrkTrack(*t_track);
	t_track->Clear();
    };//end loop over track

//  ----------------
//  *** SINGLETS ***
//  ----------------
    if(!SingletX)SingletX = new TClonesArray("TrkSinglet");
    TClonesArray &sx = *SingletX;
    for(int i=0; i<l2->nclsx; i++){
	t_singlet->plane    = l2->planex[i];
	t_singlet->coord[0] = l2->xs[i][0];
	t_singlet->coord[1] = l2->xs[i][1];
	t_singlet->sgnl     = l2->signlxs[i];
	t_singlet->multmax = l2->multmaxsx[i]; 
	if(l2->sxbad[i]>0) t_singlet->multmax = -1*t_singlet->multmax;
	//-----------------------------------------------------
//	if(l1) t_singlet->cls      = l1->GetCluster(l2->clsx[i]-1);
	//-----------------------------------------------------
	new(sx[i]) TrkSinglet(*t_singlet);
	t_singlet->Clear();
    }
    if(!SingletY)SingletY = new TClonesArray("TrkSinglet");
    TClonesArray &sy = *SingletY;
    for(int i=0; i<l2->nclsy; i++){
	t_singlet->plane    = l2->planey[i];
	t_singlet->coord[0] = l2->ys[i][0];
	t_singlet->coord[1] = l2->ys[i][1];
	t_singlet->sgnl     = l2->signlys[i];
	t_singlet->multmax  = l2->multmaxsy[i]; 
	if(l2->sybad[i]>0) t_singlet->multmax = -1*t_singlet->multmax;
	//-----------------------------------------------------
//	if(l1) t_singlet->cls      = l1->GetCluster(l2->clsy[i]-1);
	//-----------------------------------------------------
	new(sy[i]) TrkSinglet(*t_singlet);
	t_singlet->Clear();
    };


	
    delete t_track;
    delete t_singlet;
}
/**
 * Fills a struct cTrkLevel2 with values from a TrkLevel2 object (to put data into a F77 common).
 */

void TrkLevel2::GetLevel2Struct(cTrkLevel2 *l2) const {
  
//  general variables
//    l2->good2 = good2 ;
    for(Int_t i=0; i<12 ; i++){
//	l2->crc[i] = crc[i];
		l2->good[i] = good[i];
    };
//  *** TRACKS ***

    if(Track){
	l2->ntrk              =  Track->GetEntries();    
	for(Int_t i=0;i<l2->ntrk;i++){
	    l2->image[i] = 1 + ((TrkTrack *)Track->At(i))->image;
	    l2->chi2_nt[i] =  ((TrkTrack *)Track->At(i))->chi2;
	    l2->nstep_nt[i] =  ((TrkTrack *)Track->At(i))->nstep;
	    for(int it1=0;it1<5;it1++){
		l2->al_nt[i][it1] = ((TrkTrack *)Track->At(i))->al[it1];
		for(int it2=0;it2<5;it2++)
		    l2->coval[i][it2][it1] = ((TrkTrack *)Track->At(i))->coval[it1][it2];
	    };
	    for(int ip=0;ip<6;ip++){
		l2->xgood_nt[i][ip] = ((TrkTrack *)Track->At(i))->XGood(ip);
		l2->ygood_nt[i][ip] = ((TrkTrack *)Track->At(i))->YGood(ip);
		l2->xm_nt[i][ip]    = ((TrkTrack *)Track->At(i))->xm[ip];
		l2->ym_nt[i][ip]    = ((TrkTrack *)Track->At(i))->ym[ip];
		l2->zm_nt[i][ip]    = ((TrkTrack *)Track->At(i))->zm[ip];
		l2->resx_nt[i][ip]  = ((TrkTrack *)Track->At(i))->resx[ip];
		l2->resy_nt[i][ip]  = ((TrkTrack *)Track->At(i))->resy[ip];
		l2->tailx[i][ip]  = ((TrkTrack *)Track->At(i))->tailx[ip];
		l2->taily[i][ip]  = ((TrkTrack *)Track->At(i))->taily[ip];
		l2->xv_nt[i][ip]    = ((TrkTrack *)Track->At(i))->xv[ip];
		l2->yv_nt[i][ip]    = ((TrkTrack *)Track->At(i))->yv[ip];
		l2->zv_nt[i][ip]    = ((TrkTrack *)Track->At(i))->zv[ip];
		l2->axv_nt[i][ip]   = ((TrkTrack *)Track->At(i))->axv[ip];
		l2->ayv_nt[i][ip]   = ((TrkTrack *)Track->At(i))->ayv[ip];
		l2->dedx_x[i][ip]   = ((TrkTrack *)Track->At(i))->dedx_x[ip];
		l2->dedx_y[i][ip]   = ((TrkTrack *)Track->At(i))->dedx_y[ip];
	    };
	}
    }
//  *** SINGLETS ***    
    if(SingletX){
	l2->nclsx              = SingletX->GetEntries();
	for(Int_t i=0;i<l2->nclsx;i++){
	    l2->planex[i]  = ((TrkSinglet *)SingletX->At(i))->plane;
	    l2->xs[i][0]   = ((TrkSinglet *)SingletX->At(i))->coord[0];
	    l2->xs[i][1]   = ((TrkSinglet *)SingletX->At(i))->coord[1];
	    l2->signlxs[i] = ((TrkSinglet *)SingletX->At(i))->sgnl;
	}
    }

    if(SingletY){
	l2->nclsy              = SingletY->GetEntries();
	for(Int_t i=0;i<l2->nclsy;i++){
	    l2->planey[i]  = ((TrkSinglet *)SingletY->At(i))->plane;
	    l2->ys[i][0]   = ((TrkSinglet *)SingletY->At(i))->coord[0];
	    l2->ys[i][1]   = ((TrkSinglet *)SingletY->At(i))->coord[1];
	    l2->signlys[i] = ((TrkSinglet *)SingletY->At(i))->sgnl;
	}
    }
}
//--------------------------------------
//
//
//--------------------------------------
void TrkLevel2::Clear(){
    for(Int_t i=0; i<12 ; i++){
	good[i] = -1;
	VKflag[i] = 0;
	VKmask[i] = 0;
    };
//    if(Track)Track->Clear("C");
//    if(SingletX)SingletX->Clear("C");
//    if(SingletY)SingletY->Clear("C");
    if(Track)Track->Delete();
    if(SingletX)SingletX->Delete();
    if(SingletY)SingletY->Delete();
}
// //--------------------------------------
// //
// //
// //--------------------------------------
void TrkLevel2::Delete(){
	
//    cout << "void TrkLevel2::Delete()"<<endl;
    Clear();
    if(Track)delete Track;
    if(SingletX)delete SingletX;
    if(SingletY)delete SingletY;

}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Sort physical tracks and stores them in a TObjectArray, ordering by increasing chi**2 value (in case of track image, it selects the one with lower chi**2). The total number of physical tracks is given by GetNTracks() and the it-th physical track can be retrieved by means of the method GetTrack(int it).
 * This method is overridden by PamLevel2::GetTracks(), where calorimeter and TOF information is used.
 */
TRefArray *TrkLevel2::GetTracks_NFitSorted(){

    if(!Track)return 0;

    TRefArray *sorted = new TRefArray();
	
    TClonesArray &t  = *Track;
//    TClonesArray &ts = *PhysicalTrack;
    int N = ntrk();
    vector<int> m(N); for(int i=0; i<N; i++)m[i]=1;
//	int m[50]; for(int i=0; i<N; i++)m[i]=1;
	
    int indo=0;
    int indi=0;
    while(N > 0){
//    while(N != 0){
	int nfit =0;
	float chi2ref = numeric_limits<float>::max();
		
	// first loop to search maximum num. of fit points
	for(int i=0; i < ntrk(); i++){
	    if( ((TrkTrack *)t[i])->GetNtot() >= nfit && m[i]==1){
		nfit =    ((TrkTrack *)t[i])->GetNtot();
	    }
	}
	//second loop to search minimum chi2 among selected
	for(int i=0; i<ntrk(); i++){
	    Float_t chi2 = ((TrkTrack *)t[i])->chi2; 
	    if(chi2 < 0) chi2 = -chi2*1000;
	    if(    chi2 < chi2ref
		   && ((TrkTrack *)t[i])->GetNtot() == nfit 
		   && m[i]==1){
		chi2ref = ((TrkTrack *)t[i])->chi2;
		indi = i;
	    };
	};
	if( ((TrkTrack *)t[indi])->HasImage() ){
	    m[((TrkTrack *)t[indi])->image] = 0;
	    N--;
	
//	    cout << "i** "<< ((TrkTrack *)t[indi])->image << " " << nfiti <<" "<<chi2i<<endl;
	};
	sorted->Add( (TrkTrack*)t[indi] );	
		
	m[indi] = 0;
//	cout << "SORTED "<< indo << " "<< indi << " "<< N << " "<<((TrkTrack *)t[indi])->image<<" "<<chi2ref<<endl; 
	N--;	
	indo++;	
    }
    m.clear();
//    cout << "GetTracks_NFitSorted(it): Done"<< endl;

    return sorted;
//    return PhysicalTrack;
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the is-th stored track. 
 * @param it Track number, ranging from 0 to ntrk().
 * Fitted tracks ( images included ) are stored in a TObjectArray ( TrkLevel2::Track ) in the same order they are returned by the F77 fitting routine. 
 */
TrkTrack *TrkLevel2::GetStoredTrack(int is){

    if(is >= this->ntrk()){
	cout << "TrkTrack *TrkLevel2::GetStoredTrack(int) >> Track "<< is << "doen not exits! " << endl; 
	cout << "Stored tracks ntrk() = "<< this->ntrk() << endl;
	return 0;
    }
    if(!Track){
	cout << "TrkTrack *TrkLevel2::GetStoredTrack(int is) >> (TClonesArray*) Track ==0 "<<endl;
    };
    TClonesArray &t = *(Track);
    TrkTrack *track = (TrkTrack*)t[is];
    return track;
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the is-th stored X singlet. 
 * @param it Singlet number, ranging from 0 to nclsx().
 */
TrkSinglet *TrkLevel2::GetSingletX(int is){

	if(is >= this->nclsx()){
		cout << "TrkSinglet *TrkLevel2::GetSingletX(int) >> Singlet "<< is << "doen not exits! " << endl; 
		cout << "Stored x-singlets nclsx() = "<< this->nclsx() << endl;
		return 0;
	}
	if(!SingletX)return 0;
	TClonesArray &t = *(SingletX);
	TrkSinglet *singlet = (TrkSinglet*)t[is];
	return singlet;
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the is-th stored Y singlet. 
 * @param it Singlet number, ranging from 0 to nclsx().
 */
TrkSinglet *TrkLevel2::GetSingletY(int is){

	if(is >= this->nclsy()){
		cout << "TrkSinglet *TrkLevel2::GetSingletY(int) >> Singlet "<< is << "doen not exits! " << endl; 
		cout << "Stored y-singlets nclsx() = "<< this->nclsx() << endl;
		return 0;
	}
	if(!SingletY)return 0;
	TClonesArray &t = *(SingletY);
	TrkSinglet *singlet = (TrkSinglet*)t[is];
	return singlet;
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the it-th "physical" track, sorted by the method GetNTracks(). 
 * @param it Track number, ranging from 0 to GetNTracks().
 */

TrkTrack *TrkLevel2::GetTrack(int it){
    
	if(it >= this->GetNTracks()){
		cout << "TrkTrack *TrkLevel2::GetTrack(int) >> Track "<< it << "does not exits! " << endl; 
		cout << "Physical tracks GetNTracks() = "<< this->ntrk() << endl;
		return 0;
	}
	
	TRefArray *sorted = GetTracks();  //TEMPORANEO	
	if(!sorted)return 0;
	TrkTrack *track = (TrkTrack*)sorted->At(it); 
	sorted->Clear();
	delete sorted;
	return track;
}
/**
 * Give the number of "physical" tracks, sorted by the method GetTracks(). 
 */
Int_t TrkLevel2::GetNTracks(){
		
	Float_t ntot=0;
	if(!Track)return 0;
	TClonesArray &t = *Track;
	for(int i=0; i<ntrk(); i++) {	  
		if( ((TrkTrack *)t[i])->GetImageSeqNo() == -1 ) ntot+=1.;
		else ntot+=0.5;
	}
	return (Int_t)ntot;

};
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves (if present) the image of the it-th "physical" track, sorted by the method GetNTracks(). 
 * @param it Track number, ranging from 0 to GetNTracks().
 */
TrkTrack *TrkLevel2::GetTrackImage(int it){

    if(it >= this->GetNTracks()){
	cout << "TrkTrack *TrkLevel2::GetTrackImage(int) >> Track "<< it << "does not exits! " << endl; 
	cout << "Physical tracks GetNTracks() = "<< this->ntrk() << endl;
	return 0;
    }
	
    TRefArray* sorted = GetTracks(); //TEMPORANEO
    if(!sorted)return 0;
    TrkTrack *track = (TrkTrack*)sorted->At(it);
	
    if(!track->HasImage()){
	cout << "TrkTrack *TrkLevel2::GetTrackImage(int) >> Track "<< it << "does not have image! " << endl; 
	return 0;
    }
    if(!Track)return 0;
    TrkTrack *image = (TrkTrack*)(*Track)[track->image];

    sorted->Delete(); 
    delete sorted;

    return image;
    
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Loads the magnetic field. 
 * @param s Path of the magnetic-field files.
 */
void TrkLevel2::LoadField(TString path){
//
//     strcpy(path_.path,path.Data());
//     path_.pathlen = path.Length();
//     path_.error   = 0;
//     readb_();

//     TrkParams::SetTrackingMode();
//     TrkParams::SetPrecisionFactor();
//     TrkParams::SetStepMin();
    TrkParams::SetMiniDefault();

    TrkParams::Set(path,1);
    TrkParams::Load(1);
    if( !TrkParams::IsLoaded(1) ){
	cout << "void TrkLevel2::LoadField(TString path) --- ERROR --- m.field not loaded"<<endl;
    }

//
};
// /**
//  * Get BY (kGauss)
//  * @param v (x,y,z) coordinates in cm
//  */
// float TrkLevel2::GetBX(float* v){
//     float b[3];
//     gufld_(v,b);
//     return b[0]/10.;
// }
// /**
//  * Get BY (kGauss)
//  * @param v (x,y,z) coordinates in cm
//  */
// float TrkLevel2::GetBY(float* v){
//     float b[3];
//     gufld_(v,b);
//     return b[1]/10.;
// }
// /**
//  * Get BY (kGauss)
//  * @param v (x,y,z) coordinates in cm
//  */
// float TrkLevel2::GetBZ(float* v){
//     float b[3];
//     gufld_(v,b);
//     return b[2]/10.;
// }
//--------------------------------------
//
//
//--------------------------------------
/**
 * Get tracker-plane (mechanical) z-coordinate
 * @param plane_id plane index (1=TOP,2,3,4,5,6=BOTTOM)
 */
Float_t TrkLevel2::GetZTrk(Int_t plane_id){
	switch(plane_id){
		case 1: return ZTRK1;
		case 2: return ZTRK2;
		case 3: return ZTRK3;
		case 4: return ZTRK4;
		case 5: return ZTRK5;
		case 6: return ZTRK6;
		default: return 0.;
	};
};
//--------------------------------------
//
//
//--------------------------------------
/**
 * Trajectory default constructor. 
 * (By default is created with z-coordinates inside the tracking volume)
  */
Trajectory::Trajectory(){
    npoint = 10;
    x = new float[npoint];
    y = new float[npoint];
    z = new float[npoint];
    thx = new float[npoint];
    thy = new float[npoint];
    tl = new float[npoint];
    float dz = ((ZTRK1)-(ZTRK6))/(npoint-1);
    for(int i=0; i<npoint; i++){
	x[i] = 0;
	y[i] = 0;
	z[i] = (ZTRK1) - i*dz;
	thx[i] = 0;
	thy[i] = 0;
	tl[i] = 0;
    }
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Trajectory constructor.
 * (By default is created with z-coordinates inside the tracking volume)
 * \param n Number of points
 */
Trajectory::Trajectory(int n){
    if(n<=0){
	cout << "NB! Trajectory must have at least 1 point >>> created with 10 points" << endl;
	n=10;
    }
    npoint = n;
    x = new float[npoint];
    y = new float[npoint];
    z = new float[npoint];
    thx = new float[npoint];
    thy = new float[npoint];
    tl = new float[npoint];
    float dz = ((ZTRK1)-(ZTRK6))/(npoint-1);
    for(int i=0; i<npoint; i++){
    	x[i] = 0;
	y[i] = 0;
	z[i] = (ZTRK1) - i*dz;
	thx[i] = 0;
	thy[i] = 0;
	tl[i] = 0;
    }
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Trajectory constructor.
 * \param n Number of points
 * \param pz Pointer to float array, defining z coordinates
 */
Trajectory::Trajectory(int n, float* zin){
    npoint = 10;
    if(n>0)npoint = n;
    x = new float[npoint];
    y = new float[npoint];
    z = new float[npoint];
    thx = new float[npoint];
    thy = new float[npoint];
    tl = new float[npoint];
    int i=0;
    do{
	x[i] = 0;
	y[i] = 0;
	z[i] = zin[i];
	thx[i] = 0;
	thy[i] = 0;
	tl[i] = 0;
	i++;		
    }while(zin[i-1] > zin[i] && i < npoint);
    npoint=i;
    if(npoint != n)cout << "NB! Trajectory created with "<<npoint<<" points"<<endl;
}
void Trajectory::Delete(){
    
    if(x) delete [] x;
    if(y) delete [] y;
    if(z) delete [] z;
    if(thx) delete [] thx;
    if(thy) delete [] thy;
    if(tl) delete [] tl;

}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Dump the trajectory coordinates.
 */
void Trajectory::Dump(){
    cout <<endl<< "Trajectory ========== "<<endl;
    for (int i=0; i<npoint; i++){
	cout << i <<" >> " << x[i] <<" "<< y[i] <<" "<< z[i] ;
	cout <<" -- " << thx[i] <<" "<< thy[i] ;
	cout <<" -- " << tl[i] << endl;
    };
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Get trajectory length between two points
 * @param ifirst first point (default 0)
 * @param ilast last point (default npoint)
 */
float Trajectory::GetLength(int ifirst, int ilast){
    if( ifirst<0    ) ifirst = 0;
    if( ilast>=npoint) ilast  = npoint-1;
    float l=0;
    for(int i=ifirst;i<=ilast;i++){
	l=l+tl[i]; 
    };
    if(z[ilast] > ZINI)l=l-tl[ilast];
    if(z[ifirst] < ZINI)   l=l-tl[ifirst];
    
    return l;

}

/**
 * Evaluates the trajectory in the apparatus associated to the track. 
 * It integrates the equations of motion in the magnetic field. The magnetic field should be previously loaded ( by calling  TrkLevel2::LoadField() ), otherwise an error message is returned.  
 * @param t pointer to an object of the class Trajectory, 
 * which z coordinates should be previously initialized by calling the proper constructor ( Trajectory::Trajectory(int n, float* zin) ).
 * @return error flag.
 */
int Trajectory::DoTrack2(float* al){

//      double *dxout   = new double[npoint];
//      double *dyout   = new double[npoint];
//      double *dthxout = new double[npoint];
//      double *dthyout = new double[npoint];
//      double *dtlout  = new double[npoint];
//      double *dzin    = new double[npoint];
    
     double *dxout;
     double *dyout;
     double *dthxout;
     double *dthyout;
     double *dtlout;
     double *dzin;

     dxout   = (double*) malloc(npoint*sizeof(double));
     dyout   = (double*) malloc(npoint*sizeof(double));
     dthxout = (double*) malloc(npoint*sizeof(double));
     dthyout = (double*) malloc(npoint*sizeof(double));
     dtlout  = (double*) malloc(npoint*sizeof(double));
     dzin    = (double*) malloc(npoint*sizeof(double));

     double dal[5];

    int ifail = 0;

    for (int i=0; i<5; i++)      dal[i]  = (double)al[i];
    for (int i=0; i<npoint; i++) dzin[i] = (double)z[i];

    TrkParams::Load(1);
    if( !TrkParams::IsLoaded(1) ){
	cout << "int Trajectory::DoTrack2(float* al) --- ERROR --- m.field not loaded"<<endl;
	return 0;
    }
    dotrack2_(&(npoint),dzin,dxout,dyout,dthxout,dthyout,dtlout,dal,&ifail);
    
    for (int i=0; i<npoint; i++){
	x[i]   = (float)*(dxout+i);
	y[i]   = (float)*(dyout+i);
	thx[i] = (float)*(dthxout+i);
	thy[i] = (float)*(dthyout+i);
	tl[i]  = (float)*(dtlout+i);
    }

    if(dxout)  free( dxout );
    if(dyout)  free( dyout );
    if(dthxout)free( dthxout );
    if(dthyout)free( dthyout );
    if(dtlout) free( dtlout );
    if(dzin)   free( dzin );

//      delete [] dxout;
//      delete [] dyout;
//      delete [] dthxout;
//      delete [] dthyout;
//      delete [] dtlout;
//      delete [] dzin;


    return ifail;
};

ClassImp(TrkLevel2);
ClassImp(TrkSinglet);
ClassImp(TrkTrack);
ClassImp(Trajectory);