Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

TrackKalmanFilter.cpp

Go to the documentation of this file.
00001 // $Id: TrackKalmanFilter.cpp,v 1.1 2005/06/29 15:35:02 erodrigu Exp $
00002 //
00003 //  Implementation of the TrackKalmanFilter tool
00004 //
00005 //  Original Author: Rutger van der Eijk
00006 //  Created: 07-04-1999
00007 //  Adapted: 21-03-2002  Olivier Callot
00008 //  Adapted: 15-04-2005  Jose A. Hernando
00009 
00010 // from Gaudi
00011 #include "GaudiKernel/ToolFactory.h"
00012 
00013 // from CLHEP
00014 #include "CLHEP/Matrix/DiagMatrix.h"
00015 #include "CLHEP/Matrix/Matrix.h"
00016 #include "CLHEP/Units/PhysicalConstants.h"
00017 
00018 // from TrackEvent
00019 #include "Event/TrackKeys.h"
00020 
00021 // local
00022 #include "TrackKalmanFilter.h"
00023 
00024 static const ToolFactory<TrackKalmanFilter>  s_factory;
00025 const IToolFactory& TrackKalmanFilterFactory = s_factory;
00026 
00027 //=========================================================================
00028 // 
00029 //=========================================================================
00030 TrackKalmanFilter::TrackKalmanFilter( const std::string& type,
00031                                       const std::string& name,
00032                                       const IInterface* parent) :
00033   GaudiTool( type, name, parent)
00034 {
00035   declareInterface<ITrackFitter>( this );
00036 
00037   // Define the fixed z-positions
00038   m_zPositions.push_back(   990.0*mm );
00039   m_zPositions.push_back(  2165.0*mm );
00040   m_zPositions.push_back(  9450.0*mm );
00041   m_zPositions.push_back( 11900.0*mm );
00042 
00043   declareProperty( "Extrapolator"     , m_extrapolatorName = "TrackFirstCleverExtrapolator" );
00044   declareProperty( "Projector"        , m_projectorName = "TrackMasterProjector" );
00045   declareProperty( "ZPositions"       , m_zPositions               );
00046   declareProperty( "StatesAtMeasZPos" , m_statesAtMeasZPos = false );
00047   declareProperty( "StateAtBeamLine"  , m_stateAtBeamLine  = true  );
00048   declareProperty( "NumberFitIter"    , m_numFitIter       = 5     );
00049   declareProperty( "Chi2Outliers"     , m_chi2Outliers     = 9.0   );
00050   declareProperty( "StoreTransport"   , m_storeTransport   = true  );
00051 
00052   m_state = NULL;
00053   m_nodes.clear();
00054   m_K = HepVector(5,0);
00055 }
00056 
00057 //=========================================================================
00058 // 
00059 //=========================================================================
00060 TrackKalmanFilter::~TrackKalmanFilter() {
00061 }
00062 
00063 //=========================================================================
00064 // 
00065 //=========================================================================
00066 StatusCode TrackKalmanFilter::initialize() 
00067 {
00068   m_extrapolator = tool<ITrackExtrapolator>(m_extrapolatorName);
00069 
00070   m_projector    = tool<ITrackProjector>(m_projectorName);
00071 
00072   m_debugLevel   = msgLevel( MSG::DEBUG );
00073   
00074   return StatusCode::SUCCESS;
00075 }
00076 
00077 //=========================================================================
00078 // 
00079 //=========================================================================
00080 StatusCode TrackKalmanFilter::failure(const std::string& comment) {
00081   info() << "TrackKalmanFilter failure: " << comment << endreq;
00082   return StatusCode::FAILURE;
00083 }
00084 
00085 //=========================================================================
00086 // 
00087 //=========================================================================
00088 StatusCode TrackKalmanFilter::iniKalman(Track & track) 
00089 {
00090   // destroy the previous state if not null
00091   if (m_state != NULL) { delete m_state; m_state = 0; }
00092 
00093   // Kalman has private copy of the nodes to acelerate the computations
00094   // remember that the track owns the Nodes, so it is responsability of the
00095   // Track destructor to delete them!
00096   m_nodes.clear();
00097   debug() << "- iniKalman: getting track measurements ..." << endreq;
00098   std::vector<Measurement*>& measures = track.measurements();
00099   debug() << "- iniKalman: getting track nodes ..." << endreq;
00100   std::vector<Node*>& nodes = track.nodes();
00101   if (nodes.size() > 0) 
00102     for (std::vector<Node*>::iterator it = nodes.begin(); it != nodes.end();
00103          it++) delete *it;  
00104   nodes.clear();
00105   debug() << "- iniKalman: private nodes vector cleared ..." << endreq;
00106   // reserve some space in node vector
00107   m_nodes.reserve(measures.size());
00108   for (std::vector<Measurement*>::iterator it = measures.begin(); 
00109        it != measures.end(); it++) {
00110     Measurement& meas = *(*it);
00111     FitNode* node = new FitNode(meas);
00112     m_nodes.push_back(node);
00113     track.addToNodes(node);
00114   }
00115   debug() << "- iniKalman: private nodes vector rebuilt ..." << endreq;
00116 
00117   if ( m_debugLevel )
00118     debug() << " track nodes size \t" << m_nodes.size() << endreq;
00119 
00120   return StatusCode::SUCCESS;
00121 }
00122 
00123 //=========================================================================
00124 // Fit the track (filter and smoother)
00125 //=========================================================================
00126 StatusCode TrackKalmanFilter::fit(Track& track, const State& state)
00127 {
00128   debug() << "-> calling filter(track,state) ..." << endreq;
00129   StatusCode sc = filter(track,state);
00130   if (sc.isFailure()) return failure(" unable to filter the track");
00131 
00132   debug() << "-> calling smoother(track) ..." << endreq;
00133   sc = smoother(track);
00134   if (sc.isFailure()) return failure(" unable to smooth the track");
00135   
00136   return sc;
00137 }
00138 
00139 //=========================================================================
00140 // 
00141 //=========================================================================
00142 StatusCode TrackKalmanFilter::filter(Track& track, const State& state)
00143 {
00144   StatusCode sc = StatusCode::SUCCESS;
00145   sc = iniKalman(track);
00146   if (sc.isFailure()) return failure(" not able to create Nodes");
00147 
00148   m_state = state.clone();
00149 
00150   if ( m_debugLevel ) {
00151     debug() << " seed state at z \t " << m_state->z() << endreq
00152             << " seed state vector \t" << m_state->stateVector() << endreq    
00153             << " seed state cov \t" << m_state->covariance() << endreq
00154             << " track nodes size \t" << m_nodes.size() << endreq;
00155   }
00156 
00157   std::vector<FitNode*>::iterator iNode = m_nodes.begin();
00158   double z = (*iNode)->measurement().z();
00159 
00160   debug() << "Z-positions of seed state/meas.begin = "
00161           << state.z() << " / " << z << endreq;
00162 
00163   debug() << "- propagating the state ..." << endreq;
00164   // sc = m_extrapolator->propagate(*m_state,z,m_particleID);
00165   sc = m_extrapolator->propagate(*m_state,z);
00166   if (sc.isFailure()) 
00167     return failure(" unable to extrapolate to 1st measurement");
00168 
00169   // TODO: handle different iterations
00170   unsigned int nNodes = 0;
00171   debug() << "- looping over nodes ..." << endreq;
00172   for (iNode = m_nodes.begin(); iNode != m_nodes.end(); ++iNode) {
00173     FitNode& node = *(*iNode);
00174     debug() << "-> predict(...) for node # " << nNodes << endreq;
00175     sc = predict(node,*m_state);
00176     if (sc.isFailure()) return failure(" unable to predict at node");
00177     debug() << "-> filter(...) for node # " << nNodes++ << endreq;
00178     sc = filter(node);
00179     if (sc.isFailure()) return failure(" unable to filter node ");
00180   }  
00181 
00182   computeChiSq(track);
00183 
00184   return sc;
00185 }
00186 
00187 //=========================================================================
00188 // Predict the state to this node
00189 //=========================================================================
00190 StatusCode TrackKalmanFilter::predict(FitNode& aNode, State& aState) {
00191 
00192   Measurement& thisMeasure = aNode.measurement();
00193 
00194   // only use extrapolator in first iteration; else use stored parameters
00195   HepVector prevStateVec = aState.stateVector();
00196   HepSymMatrix prevStateCov = aState.covariance();
00197   double z = thisMeasure.z();
00198   // StatusCode sc = m_extrapolator->propagate(state,z,m_particleID);
00199   StatusCode sc = m_extrapolator->propagate(aState,z);
00200   if (sc.isFailure()) 
00201     return failure(" Unable to predit state at next measurement");
00202 
00203   const HepMatrix& F = m_extrapolator->transportMatrix();
00204   aNode.setTransportMatrix( F );
00205   aNode.setTransportVector( aState.stateVector() - F * prevStateVec );
00206   aNode.setNoiseMatrix( aState.covariance() - prevStateCov.similarity(F) );
00207 
00208   // save predicted state
00209   aNode.setPredictedState(aState);
00210 
00211   if ( m_debugLevel ) {
00212     debug() << " predicted  state at z \t" << z << endreq;
00213     debug() << " predicted  state vector  \t" << aState.stateVector() << endreq;
00214     debug() << " predicted  state cov \t" << aState.covariance() << endreq;
00215     debug() << " transport matrix \t" << aNode.transportMatrix() << endreq;
00216     debug() << " transport vector \t" << aNode.transportVector() << endreq;
00217     debug() << " noise matrix \t" << aNode.noiseMatrix() << endreq;
00218   } 
00219 
00220   return StatusCode::SUCCESS;
00221 }
00222 
00223 //=========================================================================
00224 // 
00225 //=========================================================================
00226 StatusCode TrackKalmanFilter::filter(FitNode& node) 
00227 {
00228   
00229   Measurement& meas = node.measurement();
00230   State& state      = node.state();
00231 
00232   debug() << "z-position of State = " << state.z() << endreq;
00233   debug() << "z-position of Meas  = " << meas.z() << endreq;
00234   debug() << "-> calling filter(state,meas) ..." << endreq;
00235   StatusCode sc = filter(state, meas);
00236   if (sc.isFailure()) return failure("Unable to filter the node!");
00237 
00238   debug() << "z-position of State = " << state.z() << endreq;
00239   debug() << "z-position of Meas  = " << meas.z() << endreq;
00240 
00241   double tMeasureError = meas.errMeasure();
00242   debug() << "getting info from projection ..." << endreq;
00243   double res = m_projector->residual();  // projection just made in filter(,)
00244   const HepVector& H = m_projector->projectionMatrix();
00245 
00246   // save it for later use
00247   node.setProjectionMatrix( H );
00248 
00249   double HK = dot ( H, m_K);
00250   res     *= (1 - HK);
00251   double errorRes = (1 - HK) * (tMeasureError*tMeasureError);
00252 
00253   debug() << "res/errRes = " << res << " / " << errorRes << endreq;
00254 
00255   debug() << "setting info in node ..." << endreq;
00256   node.setResidual(res);
00257   node.setErrResidual(sqrt(errorRes));
00258 
00259   // save predicted state
00260   debug() << "setting filteredState" << endreq;
00261   node.setFilteredState(state);
00262   debug() << "just set filteredState" << endreq;
00263 
00264   if ( m_debugLevel ) {
00265     debug() << " bef print" << endreq;  
00266     debug() << " filtered residual and error \t" << node.residual() << ", "
00267             <<node.errResidual() << endreq;;
00268     debug() << " aft print" << endreq;  
00269   }
00270  
00271   return StatusCode::SUCCESS;
00272 }
00273 
00274 //-----------------------------------------------------------------
00275 // Update the current track 'state' with the TrMeasurement 'measure'.
00276 // (i.e. filter the measurement into the state)
00277 //  the  measurement ch-sq is updated
00278 //-----------------------------------------------------------------
00279 StatusCode TrackKalmanFilter::filter(State& state, Measurement& meas)  {
00280   
00281   debug() << "In filter(state,meas)" << endreq;
00282   debug() << "z-position of State = " << state.z() << endreq;
00283   debug() << "z-position of Meas  = " << meas.z() << endreq;
00284   // check z position
00285   if ( fabs(meas.z() - state.z()) > 1e-6) {
00286     warning() << "z-position of State (=" << state.z() 
00287               << ") and Measurement (= " << meas.z() 
00288               << ") are not equal." << endreq;
00289   }
00290 
00291   // get reference to the state vector and cov
00292   HepVector&    tX = state.stateVector();
00293   HepSymMatrix& tC = state.covariance();
00294 
00295   debug() << "filter(state,meas): projecting ..." << endreq;
00296   // project the state into the measurement 
00297   StatusCode sc = m_projector->project(state,meas);
00298   if (sc.isFailure()) 
00299     return failure(" Not able to project a state into a measurement");
00300   debug() << "filter(state,meas): projection done" << endreq;
00301 
00302   // calculate predicted residuals
00303   double errorMeas = meas.errMeasure();
00304   double res       = m_projector->residual();
00305   double errorRes  = m_projector->errResidual();
00306   double errorRes2 = (errorRes*errorRes);
00307   const HepVector& H = m_projector->projectionMatrix();
00308 
00309   // calculate gain matrix K
00310   m_K = (tC * H)/errorRes2;
00311 
00312   // update state vector 
00313   tX += m_K * res;
00314 
00315   HepMatrix B  = HepDiagMatrix(tC.num_row(), 1) - ( m_K * H.T());
00316   tC.assign( B * tC * B.T() + ( m_K * pow(errorMeas, 2.0) * m_K.T()));
00317 
00318  if ( m_debugLevel ) {
00319     debug() << " measure and error \t" << meas.measure() << ", " 
00320             << errorMeas << endreq
00321             << " residual and error \t" << res << ", " 
00322             << errorRes << endreq
00323             << " projection matrix \t" << H << endreq
00324             << " gain matrix \t" << m_K << endreq
00325             << " filter state vector \t" << tX << endreq
00326             << " filter state covariance \t"<< tC << endreq;
00327   }
00328   
00329   return sc;
00330 }
00331 
00332 //----------------------------------------------------------------
00333 // smooth a node on a track
00334 // Input: node to be smoothed (k) + last node (k+1)
00335 // remember we are now running in the opposite direction to the filter !!
00336 // M. Needham 9/11/99
00337 //----------------------------------------------------------------
00338 StatusCode TrackKalmanFilter::smooth(FitNode& thisNode,
00339                                 const FitNode& prevNode)
00340 {
00341   debug() << "just entered smooth(node0,node1)" << endreq;  
00342   // preliminaries, first we need to invert the _predicted_ covariance
00343   // matrix at k+1
00344   const HepVector&    prevNodeX = prevNode.predictedState().stateVector();
00345   const HepSymMatrix& prevNodeC = prevNode.predictedState().covariance();
00346 
00347   debug() << "calling checkInvertMatrix ..." << endreq;  
00348   // check that the elements are not too large else dsinv will crash
00349   StatusCode sc = checkInvertMatrix(prevNodeC);
00350   if ( sc.isFailure() ) return failure(" not valid matrix in smoother"); 
00351 
00352   debug() << "inverting matrix ..." << endreq;  
00353   //invert the covariance matrix
00354   HepSymMatrix invPrevNodeC = prevNodeC;
00355   sc = invertMatrix(invPrevNodeC);
00356   if ( sc.isFailure() ) return failure(" inverting matrix in smoother");
00357   debug() << "matrix inverted ..." << endreq;  
00358 
00359   //references to _predicted_ state + cov of this node from the first step
00360   HepVector&    thisNodeX = thisNode.state().stateVector();
00361   HepSymMatrix& thisNodeC = thisNode.state().covariance();
00362 
00363   //transport
00364   const HepMatrix& F = prevNode.transportMatrix();
00365 
00366   debug() << "calculation of gain matrix A ..." << endreq;  
00367   //calculate gain matrix A
00368   HepMatrix A = thisNodeC * F.T() * invPrevNodeC;
00369 
00370   // best = smoothed state at prev Node
00371   const HepVector&    prevNodeSmoothedX = prevNode.state().stateVector();
00372   const HepSymMatrix& prevNodeSmoothedC = prevNode.state().covariance();
00373 
00374   //smooth state
00375   thisNodeX += A * (prevNodeSmoothedX - prevNodeX);
00376 
00377   // smooth covariance  matrix
00378   HepSymMatrix covDiff = prevNodeSmoothedC- prevNodeC;
00379   HepSymMatrix covUpDate = covDiff.similarity(A);
00380   thisNodeC += covUpDate;
00381 
00382   debug() << "calling checkPositiveMatrix ..." << endreq;  
00383   // check that the cov matrix is positive
00384   sc = checkPositiveMatrix(thisNodeC);
00385   if (sc.isFailure()) return Warning("non-positive Matrix in smoother");
00386   debug() << "checkPositiveMatrix done" << endreq;  
00387 
00388   // update = smooth the residuals
00389   debug() << "dims of H is" 
00390           << thisNode.projectionMatrix().num_row() << "x"
00391           << thisNode.projectionMatrix().num_col() << endreq;
00392   const HepVector& H = thisNode.projectionMatrix();
00393   debug() << "projecting ..." << endreq;
00394   sc = m_projector->project(thisNode.state(),thisNode.measurement());
00395   if (sc.isFailure()) Warning(" unable to project the smooth node");
00396   double res = m_projector->residual();
00397   thisNode.setResidual(res);
00398   double errRes = thisNode.errResidual();
00399   double errRes2 = errRes*errRes -  covUpDate.similarity(H);
00400   debug() << "errRes2 = " << errRes2 << endreq;
00401   if (errRes2 >0.) errRes = sqrt(errRes2);
00402   else return Warning( "Negative residual error in smoother!" );
00403   thisNode.setErrResidual(sqrt(errRes));
00404 
00405   if ( m_debugLevel ) {
00406     debug() << " A matrix \t" << A << endreq
00407             << " smooth state vector \t" << thisNodeX << endreq
00408             << " smooth state covariance \t"<< thisNodeC << endreq
00409             << " smooth residual, error and chi2 \t" << res << ", "
00410             << errRes << ", " << thisNode.chi2() << endreq;      
00411   }
00412 
00413   return StatusCode::SUCCESS;
00414 }
00415 
00416 //=========================================================================
00417 // 
00418 //=========================================================================
00419 StatusCode TrackKalmanFilter::smoother(Track& track) 
00420 {
00421   StatusCode sc = StatusCode::SUCCESS;
00422   // smoother loop - runs in opposite direction to filter
00423   std::vector<FitNode*>::reverse_iterator riNode = m_nodes.rbegin();
00424   FitNode* oldNode = *riNode;
00425   ++riNode;
00426 
00427   debug() << "starting loop over nodes..." << endreq;  
00428   while (riNode != m_nodes.rend()) {
00429     debug() << " call to smooth(node0,node1)..." << endreq;  
00430     sc = smooth( *(*riNode), *oldNode );
00431     if ( sc.isFailure() ) return failure("Unable to smooth node!");      
00432     oldNode = *riNode;
00433     ++riNode;
00434   }
00435 
00436   computeChiSq(track);
00437 
00438   return StatusCode::SUCCESS;
00439 }
00440 
00441 //=========================================================================
00442 // 
00443 //=========================================================================
00444 void TrackKalmanFilter::computeChiSq(Track& track) 
00445 {
00446   double chi2 = 0.;
00447   for (std::vector<FitNode*>::iterator it = m_nodes.begin();
00448        it != m_nodes.end(); it++) 
00449     chi2 += (*it)->chi2();
00450   int ndof = -(m_state->nParameters());
00451   ndof += m_nodes.size();
00452 
00453   debug() << "NDoF = " << m_nodes.size() << "-" << m_state->nParameters()
00454           << " = " << ndof << endreq;
00455 
00456   double chi2Norma = 0.;
00457   if (ndof != 0) chi2Norma = chi2 /((double) (ndof));
00458   track.setChi2PerDoF(chi2Norma);
00459   track.setNDoF(ndof);
00460 
00461   if ( m_debugLevel ) {
00462     debug() << " track ndof \t" << track.nDoF() << endreq
00463             << " track chi2, chi2/ndof \t " << track.chi2()  << ", "
00464             << track.chi2PerDoF() << endreq;
00465   }
00466   
00467 }
00468 
00469 //=========================================================================
00470 // 
00471 //=========================================================================
00472 StatusCode TrackKalmanFilter::checkInvertMatrix(const HepSymMatrix& mat) 
00473 {
00474   int nParam = (int) mat.num_row();
00475   for (int i=0; i<nParam; ++i){
00476     for (int j=0; j<nParam; ++j){
00477       if (mat[i][j] > 1e20)
00478         return Warning( "Covariance errors too big to invert!");
00479     } // j
00480   }   // i
00481   return StatusCode::SUCCESS;
00482 }
00483 
00484 //=========================================================================
00485 // 
00486 //=========================================================================
00487 StatusCode TrackKalmanFilter::checkPositiveMatrix(HepSymMatrix& mat) 
00488 {
00489   int nParam = (int) mat.num_row();
00490   for (int i=0; i<nParam; ++i){
00491     if (mat[i][i] <= 0.)
00492       return Warning( "Covariance matrix has non-positive elements!" );
00493   }
00494 
00495  return StatusCode::SUCCESS;
00496 }
00497 
00498 //=========================================================================
00499 // Invert prev node covariance matrix
00500 // What follows may seem strange - trust me it works - you
00501 // are strongly recommended NOT to change it. It turns out that
00502 // the choice of MeV, mm as units is BAD - the inversion simply fails
00503 // for numerical reasons. Therefore it is necessary to change back to G3
00504 // units, invert then go back to G4 units
00505 // M. Needham 13/6/2000
00506 // J.A. Hernando (we trust you) 15/05/05
00507 //=========================================================================
00508 StatusCode TrackKalmanFilter::invertMatrix(HepSymMatrix& invPrevNodeC){
00509 
00510   StatusCode sc = StatusCode::SUCCESS; 
00511 
00512   // G3 units
00513   cToG3(invPrevNodeC);
00514 
00515   HepSymMatrix tempMatrix = invPrevNodeC;
00516 
00517   int ifail;
00518   invPrevNodeC.invert(ifail);
00519 
00520   //G4 units
00521   cToG4(invPrevNodeC);
00522 
00523   if (ifail !=0){
00524     warning()
00525        <<"failed to invert covariance matrix, failure code " <<ifail<<endreq;
00526     sc = StatusCode::FAILURE;
00527   }
00528   return sc;
00529 }
00530 
00531 //=========================================================================
00532 //  Change some units for better matrix invertability
00533 //=========================================================================
00534 StatusCode TrackKalmanFilter::cToG3(HepSymMatrix& C){
00535 
00536   // cov matrix
00537   C[0][0] /= cm2;
00538   C[0][1] /= cm2;
00539   C[0][2] /= cm;
00540   C[0][3] /= cm;
00541   C[0][4]  = C[0][4]*GeV/cm;
00542 
00543   C[1][1] /= cm2;
00544   C[1][2] /= cm;
00545   C[1][3] /= cm;
00546   C[1][4]  = C[1][4]*GeV/cm;
00547 
00548   C[2][4]  = C[2][4]*GeV;
00549 
00550   C[3][4]  = C[3][4]*GeV;
00551 
00552   C[4][4]  = C[4][4]*GeV*GeV;
00553 
00554   return StatusCode::SUCCESS;
00555 
00556 }
00557 
00558 //=========================================================================
00559 //  Restore units after inversion. same as cToG3 !
00560 //=========================================================================
00561 StatusCode TrackKalmanFilter::cToG4(HepSymMatrix& invC){
00562 
00563   // cov matrix
00564   invC[0][0] /= cm2;
00565   invC[0][1] /= cm2;
00566   invC[0][2] /= cm;
00567   invC[0][3] /= cm;
00568   invC[0][4]  = invC[0][4]*GeV/cm;
00569 
00570   invC[1][1] /= cm2;
00571   invC[1][2] /= cm;
00572   invC[1][3] /= cm;
00573   invC[1][4]  = invC[1][4]*GeV/cm;
00574 
00575   invC[2][4]  = invC[2][4]*GeV;
00576 
00577   invC[3][4]  = invC[3][4]*GeV;
00578 
00579   invC[4][4]  = invC[4][4]*GeV*GeV;
00580 
00581   return StatusCode::SUCCESS;
00582 }
00583 
00584 //=========================================================================

Generated on Mon Jul 4 13:54:29 2005 for New Track Event Model by doxygen 1.4.1