/** Implementation of the CbmKFSecondaryVertexFinder class * * @author S.Gorbunov, I.Kisel * @version 1.0 * @since 06.02.06 * */ #include "CbmKFSecondaryVertexFinder.h" #include "CbmKF.h" #include "CbmKFTrack.h" using namespace std; ClassImp(CbmKFSecondaryVertexFinder) void CbmKFSecondaryVertexFinder::Clear() { vTracks.clear(); VGuess =0; VParent = 0; MassConstraint = -1; } void CbmKFSecondaryVertexFinder::ClearTracks() { vTracks.clear(); } void CbmKFSecondaryVertexFinder::AddTrack( CbmKFTrackInterface* Track ) { vTracks.push_back(Track); } void CbmKFSecondaryVertexFinder::SetTracks( vector &vTr ) { vTracks = vTr; } void CbmKFSecondaryVertexFinder::SetApproximation( CbmKFVertexInterface *Guess ) { VGuess = Guess; } void CbmKFSecondaryVertexFinder::SetMassConstraint( Double_t MotherMass ) { MassConstraint = MotherMass; } void CbmKFSecondaryVertexFinder::SetTopoConstraint( CbmKFVertexInterface *VP ) { VParent = VP; } void CbmKFSecondaryVertexFinder::Fit() { const Int_t MaxIter=3; if( VGuess ){ r[0] = VGuess->GetRefX(); r[1] = VGuess->GetRefY(); r[2] = VGuess->GetRefZ(); }else { if( CbmKF::Instance()->vTargets.empty() ){ r[0] = r[1] = r[2] = 0.; }else{ CbmKFTube &t = CbmKF::Instance()->vTargets[0]; r[0] = r[1] = 0.; r[2] = t.z; } } for ( Int_t iteration =0; iteration::iterator tr=vTracks.begin(); tr!=vTracks.end(); ++tr ) { CbmKFTrack T( **tr ); T.Extrapolate( r0[2] ); Double_t *m = T.GetTrack(); Double_t *V = T.GetCovMatrix(); //* Fit of vertex track slopes and momentum (a,b,qp) to r0 vertex Double_t a = m[2], b = m[3], qp = m[4]; { Double_t s = V[0]*V[2] - V[1]*V[1]; s = ( s > 1.E-20 ) ?1./s :0; Double_t zetas[2] = { (r0[0]-m[0])*s, (r0[1]-m[1])*s }; a += ( V[ 3]*V[2] -V[ 4]*V[1])*zetas[0] +(-V[ 3]*V[1] +V[ 4]*V[0])*zetas[1]; b += ( V[ 6]*V[2] -V[ 7]*V[1])*zetas[0] +(-V[ 6]*V[1] +V[ 7]*V[0])*zetas[1]; qp+= (V[10]*V[2]-V[11]*V[1])*zetas[0] +(-V[10]*V[1]+V[11]*V[0])*zetas[1]; } //* convert the track to (x,y,px,py,pz,e) parameterization double mm[6], VV[21]; { double c2 = 1./(1. + a*a + b*b); double p = 1./qp; double p2 = p*p; double pz = sqrt(p2*c2); double px = a*pz; double py = b*pz; double E = sqrt( T.GetMass()*T.GetMass() + p2 ); double da = (m[2]-a); double db = (m[3]-b); double dq = (m[4]-qp); double H[3] = { -px*c2, -py*c2, -pz*p }; double HE = -p*p2/E; double dpz = H[0]*da + H[1]*db + H[2]*dq; mm[0] = m[0]; mm[1] = m[1]; mm[2] = px + da + a*dpz; mm[3] = py + db + b*dpz; mm[4] = pz + dpz; mm[5] = E + HE*dq; double cxpz = H[0]*V[ 3] + H[1]*V[ 6] + H[2]*V[10]; double cypz = H[0]*V[ 4] + H[1]*V[ 7] + H[2]*V[11]; double capz = H[0]*V[ 5] + H[1]*V[ 8] + H[2]*V[12]; double cbpz = H[0]*V[ 8] + H[1]*V[ 9] + H[2]*V[13]; double cqpz = H[0]*V[12] + H[1]*V[13] + H[2]*V[14]; double cpzpz = H[0]*H[0]*V[5] +H[1]*H[1]*V[9] + H[2]*H[2]*V[14] + 2*( H[0]*H[1]*V[8] +H[0]*H[2]*V[12] +H[1]*H[2]*V[13]); VV[ 0] = V[0]; VV[ 1] = V[1]; VV[ 2] = V[2]; VV[ 3] = V[3]*pz + a*cxpz; VV[ 4] = V[4]*pz + a*cypz; VV[ 5] = V[5]*pz*pz + 2*a*pz*capz + a*a*cpzpz; VV[ 6] = V[6]*pz+b*cxpz; VV[ 7] = V[7]*pz+b*cypz; VV[ 8] = V[8]*pz*pz + a*pz*cbpz + b*pz*capz + a*b*cpzpz; VV[ 9] = V[9]*pz*pz + 2*b*pz*cbpz + b*b*cpzpz; VV[10] = cxpz; VV[11] = cypz; VV[12] = capz*pz + a*cpzpz; VV[13] = cbpz*pz + b*cpzpz; VV[14] = cpzpz; VV[15] = HE*V[10]; VV[16] = HE*V[11]; VV[17] = HE*( V[12]*pz + a*cqpz ); VV[18] = HE*( V[13]*pz + b*cqpz ); VV[19] = HE*cqpz; VV[20] = HE*HE*V[14]; } //* Measure the state vector with the track estimate Chi2 += T.GetRefChi2(); NDF += T.GetRefNDF() - 3; //* Update the state vector with the momentum part of the track estimate r[ 3] += mm[ 2]; r[ 4] += mm[ 3]; r[ 5] += mm[ 4]; r[ 6] += mm[ 5]; C[ 9] += VV[ 5]; C[13] += VV[ 8]; C[14] += VV[ 9]; C[18] += VV[12]; C[19] += VV[13]; C[20] += VV[14]; C[24] += VV[17]; C[25] += VV[18]; C[26] += VV[19]; C[27] += VV[20]; NDF += 3; Chi2 += 0.; //* Update the state vector with the coordinate part of the track estimate //* Residual (measured - estimated) Double_t zeta[2] = { mm[0]-(r[0]-a*(r[2]-r0[2])), mm[1]-(r[1]-b*(r[2]-r0[2])) }; //* Measurement matrix H= { { 1, 0, -a, 0..0}, { 0, 1, -b,0..0} }; //* S = (H*C*H' + V )^{-1} Double_t S[3] = { VV[0] + C[0] - 2*a*C[3] + a*a*C[5], VV[1] + C[1] - b*C[3] - a*C[4] + a*b*C[5], VV[2] + C[2] - 2*b*C[4] + b*b*C[5] }; //* Invert S { Double_t s = S[0]*S[2] - S[1]*S[1]; if ( s < 1.E-20 ) continue; s = 1./s; Double_t S0 = S[0]; S[0] = s*S[2]; S[1] = -s*S[1]; S[2] = s*S0; } //* CHt = CH' - D' Double_t CHt0[7], CHt1[7]; CHt0[0]= C[ 0] -a*C[ 3]; CHt1[0]= C[ 1] -b*C[ 3]; CHt0[1]= C[ 1] -a*C[ 4]; CHt1[1]= C[ 2] -b*C[ 4]; CHt0[2]= C[ 3] -a*C[ 5]; CHt1[2]= C[ 4] -b*C[ 5]; CHt0[3]= C[ 6] -a*C[ 8] -VV[ 3]; CHt1[3]= C[ 7] -b*C[ 8] -VV[ 4]; CHt0[4]= C[10] -a*C[12] -VV[ 6]; CHt1[4]= C[11] -b*C[12] -VV[ 7]; CHt0[5]= C[15] -a*C[17] -VV[10]; CHt1[5]= C[16] -b*C[17] -VV[11]; CHt0[6]= C[21] -a*C[23] -VV[15]; CHt1[6]= C[22] -b*C[23] -VV[16]; //* Kalman gain K = CH'*S Double_t K0[7], K1[7]; for(Int_t i=0;i<7;++i){ K0[i] = CHt0[i]*S[0] + CHt1[i]*S[1]; K1[i] = CHt0[i]*S[1] + CHt1[i]*S[2]; } //* New estimation of the vertex position r += K*zeta for(Int_t i=0;i<7;++i) r[i] += K0[i]*zeta[0] + K1[i]*zeta[1]; //* New covariance matrix C -= K*(CH')' for(Int_t i=0, k=0;i<7;++i){ for(Int_t j=0;j<=i;++j,++k) C[k] -= K0[i]*CHt0[j] + K1[i]*CHt1[j]; } //* Calculate Chi^2 & NDF NDF += 2; Chi2 += zeta[0]*zeta[0]*S[0] + 2*zeta[0]*zeta[1]*S[1] + zeta[1]*zeta[1]*S[2] ; } // add tracks // Put constraints if they exist AddTopoConstraint(); AddMassConstraint(); }// iterations } void CbmKFSecondaryVertexFinder::GetVertex( CbmKFVertexInterface &vtx ) { vtx.GetRefX() = r[0]; vtx.GetRefY() = r[1]; vtx.GetRefZ() = r[2]; for( int i=0; i<6; i++) vtx.GetCovMatrix()[i] = C[i]; vtx.GetRefChi2() = Chi2; vtx.GetRefNDF() = NDF; } void CbmKFSecondaryVertexFinder::GetVertex( CbmVertex &vtx ) { CbmKFVertexInterface vi; GetVertex( vi ); vi.GetVertex(vtx); } void CbmKFSecondaryVertexFinder:: GetMotherTrack( Double_t Par[], Double_t Cov[] ) { if( !Par ) return; Double_t px=r[3], py=r[4], pz=r[5]; Double_t p = sqrt( px*px + py*py + pz*pz ); double pzi = 1/pz; double qp=1/p; Par[0] = r[0]; Par[1] = r[1]; Par[2] = px*pzi; Par[3] = py*pzi; Par[4] = qp; Par[5] = r[2]; if( !Cov ) return; double qp3=qp*qp*qp; Double_t J[5][6]; for ( Int_t i=0; i<5; i++) for (Int_t j=0;j<6;++j) J[i][j]=0.0; J[0][0] = 1; J[0][2] = -Par[2]; J[1][1] = 1; J[1][2] = -Par[3]; J[2][3] = pzi; J[2][5] = -Par[2]*pzi; J[3][4] = pzi; J[3][5] = -Par[3]*pzi; J[4][3] = -qp3*px; J[4][4] = -qp3*py; J[4][4] = -qp3*pz; Double_t JC[5][6]; for( Int_t i=0; i<5; i++) for(Int_t j=0;j<6;j++){ JC[i][j]=0; for( Int_t k=0; k<6; k++) JC[i][j]+=J[i][k]*Cij(k,j); } Int_t ii =0 ; for( Int_t i=0; i<5; i++) for(Int_t j=i;j<5;j++, ii++){ Cov[ii]=0; for( Int_t k=0; k<6; k++) Cov[ii]+=JC[i][k]*J[j][k]; } } void CbmKFSecondaryVertexFinder::GetMass( Double_t *M, Double_t *Error ) { // S = sigma^2 of m2/2 Double_t S = ( r[3]*r[3]*C[9] + r[4]*r[4]*C[14] + r[5]*r[5]*C[20] + r[6]*r[6]*C[27] + 2*( + r[3]*r[4]*C[13] + r[5]*(r[3]*C[18] + r[4]*C[19]) - r[6]*( r[3]*C[24] + r[4]*C[25] + r[5]*C[26] ) ) ); Double_t m2 = r[6]*r[6] - r[3]*r[3] - r[4]*r[4] - r[5]*r[5]; cout<<"m="<