From 6b191dea7b94a2ba12c917b83d4119ec738e1d3c Mon Sep 17 00:00:00 2001 From: ivana Date: Wed, 22 Apr 2009 10:18:35 +0000 Subject: [PATCH] In reconstruction classes: - Improve track candidate selection by taking into account the resolution on the track parameters. - Add a flag into RecoParam to switch between track selection on their slope or on their impact parameter at vertex (default). - UPdate REcoParam in OCDB - Take into account the chamber/cluster resolution when defining the "fixed" area to quickly look for new cluster to be attached to the track. - AliMUONDigitCalibrator: Do not use digit saturation information from calibration file when using the calibration option NOGAIN. (Philippe P.) --- MUON/AliMUONDigitCalibrator.cxx | 2 +- MUON/AliMUONRecoParam.cxx | 44 +++-- MUON/AliMUONRecoParam.h | 10 +- MUON/AliMUONTrackExtrap.cxx | 5 +- MUON/AliMUONTrackParam.cxx | 1 + MUON/AliMUONTrackReconstructor.cxx | 51 ++--- MUON/AliMUONTrackReconstructorK.cxx | 105 +++++----- MUON/AliMUONVTrackReconstructor.cxx | 180 ++++++++++++++---- MUON/AliMUONVTrackReconstructor.h | 4 + MUON/runDataReconstruction.C | 4 +- .../Calib/RecoParam/Run0_999999999_v0_s0.root | Bin 4956 -> 5030 bytes 11 files changed, 260 insertions(+), 146 deletions(-) diff --git a/MUON/AliMUONDigitCalibrator.cxx b/MUON/AliMUONDigitCalibrator.cxx index aecf7077aba..a307f6c87db 100644 --- a/MUON/AliMUONDigitCalibrator.cxx +++ b/MUON/AliMUONDigitCalibrator.cxx @@ -357,7 +357,7 @@ AliMUONDigitCalibrator::CalibrateDigit(Int_t detElemId, Int_t manuId, Int_t manu { Int_t saturation(3000); - if ( gain ) + if ( gain && ( fApplyGains != fgkNoGain ) ) { saturation = gain->ValueAsInt(manuChannel,4); } diff --git a/MUON/AliMUONRecoParam.cxx b/MUON/AliMUONRecoParam.cxx index 5291eaf3316..d7840a74bb1 100644 --- a/MUON/AliMUONRecoParam.cxx +++ b/MUON/AliMUONRecoParam.cxx @@ -71,7 +71,8 @@ AliMUONRecoParam::AliMUONRecoParam() fChargeSigmaCut(4.0), fRemoveConnectedTracksInSt12(kFALSE), fMaxTriggerTracks(0), - fMaxTrackCandidates(0) + fMaxTrackCandidates(0), + fSelectTrackOnSlope(kFALSE) { /// Constructor @@ -154,8 +155,9 @@ void AliMUONRecoParam::SetLowFluxParam() fMaxBendingMomentum = 3000.; fMaxNonBendingSlope = 0.3; fMaxBendingSlope = 0.4; - fNonBendingVertexDispersion = 10.; - fBendingVertexDispersion = 10.; + fSelectTrackOnSlope = kFALSE; + fNonBendingVertexDispersion = 70.; + fBendingVertexDispersion = 70.; fMaxNonBendingDistanceToTrack = 1.; fMaxBendingDistanceToTrack = 1.; fSigmaCutForTracking = 6.; @@ -196,8 +198,9 @@ void AliMUONRecoParam::SetHighFluxParam() fMaxBendingMomentum = 3000.; fMaxNonBendingSlope = 0.3; fMaxBendingSlope = 0.4; - fNonBendingVertexDispersion = 10.; - fBendingVertexDispersion = 10.; + fSelectTrackOnSlope = kFALSE; + fNonBendingVertexDispersion = 70.; + fBendingVertexDispersion = 70.; fMaxNonBendingDistanceToTrack = 1.; fMaxBendingDistanceToTrack = 1.; fSigmaCutForTracking = 6.; @@ -236,12 +239,13 @@ void AliMUONRecoParam::SetCosmicParam() SetEventSpecie(AliRecoParam::kCosmic); fMinBendingMomentum = 1.; fMaxBendingMomentum = 10000000.; - fMaxNonBendingSlope = 0.3; - fMaxBendingSlope = 0.4; - fNonBendingVertexDispersion = 10.; - fBendingVertexDispersion = 10.; - fMaxNonBendingDistanceToTrack = 10.; - fMaxBendingDistanceToTrack = 10.; + fMaxNonBendingSlope = 0.4; + fMaxBendingSlope = 0.5; + fSelectTrackOnSlope = kTRUE; + fNonBendingVertexDispersion = 200.; + fBendingVertexDispersion = 200.; + fMaxNonBendingDistanceToTrack = 1.; + fMaxBendingDistanceToTrack = 1.; fSigmaCutForTracking = 7.; fSigmaCutForImprovement = 7.; fSigmaCutForTrigger = 8.; @@ -325,16 +329,14 @@ void AliMUONRecoParam::Print(Option_t *option) const if (fSaveFullClusterInESD) cout< %5.2f",fMinBendingMomentum)<RequestStation(7-istat)) { - fRecTracksPtr->Remove(track); - fNRecTracks--; - } else if (fNRecTracks > GetRecoParam()->GetMaxTrackCandidates()) { - AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks)); - delete segments; - return kFALSE; + if (GetRecoParam()->RequestStation(7-istat)) { + if (!clusterFound) { + fRecTracksPtr->Remove(track); + fNRecTracks--; + } else if (fNRecTracks > GetRecoParam()->GetMaxTrackCandidates()) { + AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks)); + delete segments; + return kFALSE; + } + } else { + if ((fNRecTracks + segments->GetEntriesFast() - iseg - 1) > GetRecoParam()->GetMaxTrackCandidates()) { + AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks + segments->GetEntriesFast() - iseg - 1)); + delete segments; + return kFALSE; + } } } @@ -199,8 +207,8 @@ Bool_t AliMUONTrackReconstructor::MakeMoreTrackCandidates(AliMUONVClusterStore& } // abort tracking if there are too many candidates - if (fNRecTracks > GetRecoParam()->GetMaxTrackCandidates()) { - AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks)); + if ((fNRecTracks + segments->GetEntriesFast() - iSegment - 1) > GetRecoParam()->GetMaxTrackCandidates()) { + AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks + segments->GetEntriesFast() - iSegment - 1)); delete segments; return kFALSE; } @@ -255,15 +263,11 @@ Bool_t AliMUONTrackReconstructor::FollowTracks(AliMUONVClusterStore& clusterStor Fit(*track, kFALSE, kTRUE, kTRUE); else Fit(*track, kFALSE, kFALSE, kTRUE); - // remove track with absolute bending momentum out of limits - if (AliMUONTrackExtrap::IsFieldON()) { - Double_t bendingMomentum = TMath::Abs(1. / ((AliMUONTrackParam*)track->GetTrackParamAtCluster()->First())->GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || - bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) { - fRecTracksPtr->Remove(track); - fNRecTracks--; - continue; - } + // remove tracks out of limits + if (!IsAcceptable(*((AliMUONTrackParam*)track->GetTrackParamAtCluster()->First()))) { + fRecTracksPtr->Remove(track); + fNRecTracks--; + continue; } // remove track if the normalized chi2 is too high @@ -945,6 +949,7 @@ Double_t AliMUONTrackReconstructor::TryTwoClusters(const AliMUONTrackParam &trac jacob(1,2) = 1.; // dy1/dy // first derivative at the second cluster: TMatrixD dParam(5,1); + Double_t direction[5] = {-1.,-1.,1.,1.,-1.}; for (Int_t i=0; i<5; i++) { // Skip jacobian calculation for parameters with no associated error if (kParamCov(i,i) == 0.) continue; @@ -952,7 +957,7 @@ Double_t AliMUONTrackReconstructor::TryTwoClusters(const AliMUONTrackParam &trac for (Int_t j=0; j<5; j++) { if (j==i) { dParam(j,0) = TMath::Sqrt(kParamCov(i,i)); - if (j == 4) dParam(j,0) *= TMath::Sign(1.,-paramAtCluster1Save(4,0)); // variation always in the same direction + dParam(j,0) *= TMath::Sign(1.,direction[j]*paramAtCluster1Save(j,0)); // variation always in the same direction } else dParam(j,0) = 0.; } @@ -1107,12 +1112,8 @@ Bool_t AliMUONTrackReconstructor::RecoverTrack(AliMUONTrack &trackCandidate, Ali // Calculate the track parameter covariance matrix Fit(trackCandidate, kFALSE, kFALSE, kTRUE); - // skip track with absolute bending momentum out of limits - if (AliMUONTrackExtrap::IsFieldON()) { - Double_t bendingMomentum = TMath::Abs(1. / ((AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->First())->GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || - bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) return kFALSE; - } + // skip track out of limits + if (!IsAcceptable(*((AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->First()))) return kFALSE; // Look for new cluster(s) in next station return FollowTrackInStation(trackCandidate,clusterStore,nextStation); diff --git a/MUON/AliMUONTrackReconstructorK.cxx b/MUON/AliMUONTrackReconstructorK.cxx index af722e55d7b..c5e98cb287a 100644 --- a/MUON/AliMUONTrackReconstructorK.cxx +++ b/MUON/AliMUONTrackReconstructorK.cxx @@ -116,13 +116,21 @@ Bool_t AliMUONTrackReconstructorK::MakeTrackCandidates(AliMUONVClusterStore& clu // Remove track if no cluster found on a requested station // or abort tracking if there are too many candidates - if (!clusterFound && GetRecoParam()->RequestStation(7-istat)) { - fRecTracksPtr->Remove(track); - fNRecTracks--; - } else if (fNRecTracks > GetRecoParam()->GetMaxTrackCandidates()) { - AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks)); - delete segments; - return kFALSE; + if (GetRecoParam()->RequestStation(7-istat)) { + if (!clusterFound) { + fRecTracksPtr->Remove(track); + fNRecTracks--; + } else if (fNRecTracks > GetRecoParam()->GetMaxTrackCandidates()) { + AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks)); + delete segments; + return kFALSE; + } + } else { + if ((fNRecTracks + segments->GetEntriesFast() - iSegment - 1) > GetRecoParam()->GetMaxTrackCandidates()) { + AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks + segments->GetEntriesFast() - iSegment - 1)); + delete segments; + return kFALSE; + } } } @@ -145,21 +153,17 @@ Bool_t AliMUONTrackReconstructorK::MakeTrackCandidates(AliMUONVClusterStore& clu // retrace tracks using Kalman filter RetraceTrack(*track,kTRUE); - // remove tracks with absolute bending momentum out of limits - if (GetRecoParam()->MakeTrackCandidatesFast() && AliMUONTrackExtrap::IsFieldON()) { - AliMUONTrackParam *trackParam = (AliMUONTrackParam*)track->GetTrackParamAtCluster()->First(); - Double_t bendingMomentum = TMath::Abs(1. / trackParam->GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) { - fRecTracksPtr->Remove(track); - fNRecTracks--; - } + // remove tracks out of limits + if (!IsAcceptable(*((AliMUONTrackParam*)track->GetTrackParamAtCluster()->First()))) { + fRecTracksPtr->Remove(track); + fNRecTracks--; } } // Keep only the best tracks if required if (!GetRecoParam()->TrackAllTracks()) RemoveDoubleTracks(); - else if (GetRecoParam()->MakeTrackCandidatesFast() && AliMUONTrackExtrap::IsFieldON()) fRecTracksPtr->Compress(); + else if (AliMUONTrackExtrap::IsFieldON()) fRecTracksPtr->Compress(); AliDebug(1,Form("Number of good candidates = %d",fNRecTracks)); @@ -223,8 +227,8 @@ Bool_t AliMUONTrackReconstructorK::MakeMoreTrackCandidates(AliMUONVClusterStore& } // abort tracking if there are too many candidates - if (fNRecTracks > GetRecoParam()->GetMaxTrackCandidates()) { - AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks)); + if ((fNRecTracks + segments->GetEntriesFast() - iSegment - 1) > GetRecoParam()->GetMaxTrackCandidates()) { + AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks + segments->GetEntriesFast() - iSegment - 1)); delete segments; return kFALSE; } @@ -248,13 +252,9 @@ Bool_t AliMUONTrackReconstructorK::MakeMoreTrackCandidates(AliMUONVClusterStore& RetraceTrack(*track,kTRUE); // remove tracks with absolute bending momentum out of limits - if (AliMUONTrackExtrap::IsFieldON()) { - AliMUONTrackParam *trackParam = (AliMUONTrackParam*)track->GetTrackParamAtCluster()->First(); - Double_t bendingMomentum = TMath::Abs(1. / trackParam->GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) { - fRecTracksPtr->Remove(track); - fNRecTracks--; - } + if (!IsAcceptable(*((AliMUONTrackParam*)track->GetTrackParamAtCluster()->First()))) { + fRecTracksPtr->Remove(track); + fNRecTracks--; } } @@ -471,9 +471,16 @@ Bool_t AliMUONTrackReconstructorK::FollowTracks(AliMUONVClusterStore& clusterSto } // abort tracking if there are too many candidates - if (fNRecTracks > GetRecoParam()->GetMaxTrackCandidates()) { - AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks)); - return kFALSE; + if (GetRecoParam()->RequestStation(station)) { + if (fNRecTracks > GetRecoParam()->GetMaxTrackCandidates()) { + AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks)); + return kFALSE; + } + } else { + if ((fNRecTracks + currentNRecTracks - iRecTrack - 1) > GetRecoParam()->GetMaxTrackCandidates()) { + AliError(Form("Too many track candidates (%d tracks). Abort tracking.", fNRecTracks + currentNRecTracks - iRecTrack - 1)); + return kFALSE; + } } } @@ -501,7 +508,6 @@ Bool_t AliMUONTrackReconstructorK::FollowTrackInChamber(AliMUONTrack &trackCandi /// return kTRUE if new cluster(s) have been found (otherwise return kFALSE) AliDebug(1,Form("Enter FollowTrackInChamber(1..) %d", nextChamber+1)); - Double_t bendingMomentum; Double_t chi2OfCluster; Double_t maxChi2OfCluster = 2. * GetRecoParam()->GetSigmaCutForTracking() * GetRecoParam()->GetSigmaCutForTracking(); // 2 because 2 quantities in chi2 @@ -591,12 +597,8 @@ Bool_t AliMUONTrackReconstructorK::FollowTrackInChamber(AliMUONTrack &trackCandi // Compute new track parameters including new cluster using kalman filter addChi2TrackAtCluster = RunKalmanFilter(extrapTrackParamAtCluster); - // skip track with absolute bending momentum out of limits - if (AliMUONTrackExtrap::IsFieldON()) { - bendingMomentum = TMath::Abs(1. / extrapTrackParamAtCluster.GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || - bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue; - } + // skip track out of limits + if (!IsAcceptable(extrapTrackParamAtCluster)) continue; // remember a cluster was found foundOneCluster = kTRUE; @@ -679,7 +681,6 @@ Bool_t AliMUONTrackReconstructorK::FollowTrackInStation(AliMUONTrack &trackCandi ch2 = 2*nextStation+1; } - Double_t bendingMomentum; Double_t chi2OfCluster; Double_t maxChi2OfCluster = 2. * GetRecoParam()->GetSigmaCutForTracking() * GetRecoParam()->GetSigmaCutForTracking(); // 2 because 2 quantities in chi2 @@ -782,12 +783,8 @@ Bool_t AliMUONTrackReconstructorK::FollowTrackInStation(AliMUONTrack &trackCandi // Compute new track parameters including "clusterCh2" using kalman filter addChi2TrackAtCluster2 = RunKalmanFilter(extrapTrackParamAtCluster2); - // skip track with absolute bending momentum out of limits - if (AliMUONTrackExtrap::IsFieldON()) { - bendingMomentum = TMath::Abs(1. / extrapTrackParamAtCluster2.GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || - bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue; - } + // skip track out of limits + if (!IsAcceptable(extrapTrackParamAtCluster2)) continue; // Printout for debuging if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) { @@ -840,12 +837,8 @@ Bool_t AliMUONTrackReconstructorK::FollowTrackInStation(AliMUONTrack &trackCandi // Compute new track parameters including "clusterCh1" using kalman filter addChi2TrackAtCluster1 = RunKalmanFilter(extrapTrackParamAtCluster1); - // skip track with absolute bending momentum out of limits - if (AliMUONTrackExtrap::IsFieldON()) { - bendingMomentum = TMath::Abs(1. / extrapTrackParamAtCluster1.GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || - bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue; - } + // skip track out of limits + if (!IsAcceptable(extrapTrackParamAtCluster1)) continue; // remember a second cluster was found foundSecondCluster = kTRUE; @@ -970,12 +963,8 @@ Bool_t AliMUONTrackReconstructorK::FollowTrackInStation(AliMUONTrack &trackCandi // Compute new track parameters including "clusterCh1" using kalman filter addChi2TrackAtCluster1 = RunKalmanFilter(extrapTrackParamAtCluster1); - // skip track with absolute bending momentum out of limits - if (AliMUONTrackExtrap::IsFieldON()) { - bendingMomentum = TMath::Abs(1. / extrapTrackParamAtCluster1.GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || - bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue; - } + // skip track out of limits + if (!IsAcceptable(extrapTrackParamAtCluster1)) continue; // remember a cluster was found foundOneCluster = kTRUE; @@ -1232,12 +1221,8 @@ Bool_t AliMUONTrackReconstructorK::RecoverTrack(AliMUONTrack &trackCandidate, Al // Re-calculate track parameters at the (new) first cluster RetracePartialTrack(trackCandidate,(AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->UncheckedAt(1)); - // skip track with absolute bending momentum out of limits - if (AliMUONTrackExtrap::IsFieldON()) { - Double_t bendingMomentum = TMath::Abs(1. / ((AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->First())->GetInverseBendingMomentum()); - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || - bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) return kFALSE; - } + // skip track out of limits + if (!IsAcceptable(*((AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->First()))) return kFALSE; // Look for new cluster(s) in next station return FollowTrackInStation(trackCandidate, clusterStore, nextStation); diff --git a/MUON/AliMUONVTrackReconstructor.cxx b/MUON/AliMUONVTrackReconstructor.cxx index 6c0d15da0be..797c704eae0 100644 --- a/MUON/AliMUONVTrackReconstructor.cxx +++ b/MUON/AliMUONVTrackReconstructor.cxx @@ -100,7 +100,8 @@ AliMUONVTrackReconstructor::AliMUONVTrackReconstructor(const AliMUONRecoParam* r fRecTracksPtr(0x0), fNRecTracks(0), fClusterServer(clusterServer), -fkRecoParam(recoParam) +fkRecoParam(recoParam), +fMaxMCSAngle2(0.) { /// Constructor for class AliMUONVTrackReconstructor /// WARNING: if clusterServer=0x0, no clusterization will be possible at this level @@ -110,6 +111,13 @@ fkRecoParam(recoParam) // set the magnetic field for track extrapolations AliMUONTrackExtrap::SetField(); + + // set the maximum MCS angle in chamber from the minimum acceptable momentum + AliMUONTrackParam param; + Double_t inverseBendingP = (GetRecoParam()->GetMinBendingMomentum() > 0.) ? 1./GetRecoParam()->GetMinBendingMomentum() : 1.; + param.SetInverseBendingMomentum(inverseBendingP); + fMaxMCSAngle2 = AliMUONTrackExtrap::GetMCSAngle2(param, AliMUONConstants::ChamberThicknessInX0(), 1.); + } //__________________________________________________________________________ @@ -176,17 +184,93 @@ void AliMUONVTrackReconstructor::EventReconstruct(AliMUONVClusterStore& clusterS } } - //__________________________________________________________________________ +//__________________________________________________________________________ +Bool_t AliMUONVTrackReconstructor::IsAcceptable(AliMUONTrackParam &trackParam) +{ + /// Return kTRUE if the track is within given limits on momentum/angle/origin + + const TMatrixD& kParamCov = trackParam.GetCovariances(); + Int_t chamber = trackParam.GetClusterPtr()->GetChamberId(); + Double_t z = trackParam.GetZ(); + Double_t sigmaCut = GetRecoParam()->GetSigmaCutForTracking(); + + // MCS dipersion + Double_t angleMCS2 = 0.; + if (AliMUONTrackExtrap::IsFieldON() && chamber < 6) + angleMCS2 = AliMUONTrackExtrap::GetMCSAngle2(trackParam, AliMUONConstants::ChamberThicknessInX0(), 1.); + else angleMCS2 = fMaxMCSAngle2; + Double_t impactMCS2 = 0.; + if (!GetRecoParam()->SelectOnTrackSlope()) for (Int_t iCh=0; iCh<=chamber; iCh++) + impactMCS2 += AliMUONConstants::DefaultChamberZ(chamber) * AliMUONConstants::DefaultChamberZ(chamber) * angleMCS2; + + // ------ track selection in non bending direction ------ + if (GetRecoParam()->SelectOnTrackSlope()) { + + // check if non bending slope is within tolerances + Double_t nonBendingSlopeErr = TMath::Sqrt(kParamCov(1,1) + (chamber + 1.) * angleMCS2); + if ((TMath::Abs(trackParam.GetNonBendingSlope()) - sigmaCut * nonBendingSlopeErr) > GetRecoParam()->GetMaxNonBendingSlope()) return kFALSE; + + } else { + + // or check if non bending impact parameter is within tolerances + Double_t nonBendingImpactParam = TMath::Abs(trackParam.GetNonBendingCoor() - z * trackParam.GetNonBendingSlope()); + Double_t nonBendingImpactParamErr = TMath::Sqrt(kParamCov(0,0) + z * z * kParamCov(1,1) - 2. * z * kParamCov(0,1) + impactMCS2); + if ((nonBendingImpactParam - sigmaCut * nonBendingImpactParamErr) > (3. * GetRecoParam()->GetNonBendingVertexDispersion())) return kFALSE; + + } + + // ------ track selection in bending direction ------ + if (AliMUONTrackExtrap::IsFieldON()) { // depending whether the field is ON or OFF + + // check if bending momentum is within tolerances + Double_t bendingMomentum = TMath::Abs(1. / trackParam.GetInverseBendingMomentum()); + Double_t bendingMomentumErr = TMath::Sqrt(kParamCov(4,4)) * bendingMomentum * bendingMomentum; + if (chamber < 6 && (bendingMomentum + sigmaCut * bendingMomentumErr) < GetRecoParam()->GetMinBendingMomentum()) return kFALSE; + else if ((bendingMomentum + 3. * bendingMomentumErr) < GetRecoParam()->GetMinBendingMomentum()) return kFALSE; + + } else { + + if (GetRecoParam()->SelectOnTrackSlope()) { + + // check if bending slope is within tolerances + Double_t bendingSlopeErr = TMath::Sqrt(kParamCov(3,3) + (chamber + 1.) * angleMCS2); + if ((TMath::Abs(trackParam.GetBendingSlope()) - sigmaCut * bendingSlopeErr) > GetRecoParam()->GetMaxBendingSlope()) return kFALSE; + + } else { + + // or check if bending impact parameter is within tolerances + Double_t bendingImpactParam = TMath::Abs(trackParam.GetBendingCoor() - z * trackParam.GetBendingSlope()); + Double_t bendingImpactParamErr = TMath::Sqrt(kParamCov(2,2) + z * z * kParamCov(3,3) - 2. * z * kParamCov(2,3) + impactMCS2); + if ((bendingImpactParam - sigmaCut * bendingImpactParamErr) > (3. * GetRecoParam()->GetBendingVertexDispersion())) return kFALSE; + + } + + } + + return kTRUE; + +} + +//__________________________________________________________________________ TClonesArray* AliMUONVTrackReconstructor::MakeSegmentsBetweenChambers(const AliMUONVClusterStore& clusterStore, Int_t ch1, Int_t ch2) { /// To make the list of segments from the list of clusters in the 2 given chambers. /// Return a new TClonesArray of segments. /// It is the responsibility of the user to delete it afterward. AliDebug(1,Form("Enter MakeSegmentsBetweenChambers (1..) %d-%d", ch1+1, ch2+1)); + AliCodeTimerAuto(""); AliMUONVCluster *cluster1, *cluster2; AliMUONObjectPair *segment; - Double_t nonBendingSlope = 0, bendingSlope = 0, impactParam = 0., bendingMomentum = 0.; // to avoid compilation warning + Double_t z1 = 0., z2 = 0., dZ = 0.; + Double_t nonBendingSlope = 0., nonBendingSlopeErr = 0., nonBendingImpactParam = 0., nonBendingImpactParamErr = 0.; + Double_t bendingSlope = 0., bendingSlopeErr = 0., bendingImpactParam = 0., bendingImpactParamErr = 0., bendingImpactParamErr2 = 0.; + Double_t bendingMomentum = 0., bendingMomentumErr = 0.; + Double_t bendingVertexDispersion2 = GetRecoParam()->GetBendingVertexDispersion() * GetRecoParam()->GetBendingVertexDispersion(); + Double_t impactMCS2 = 0; // maximum impact parameter dispersion**2 due to MCS in chamber + if (!GetRecoParam()->SelectOnTrackSlope() || AliMUONTrackExtrap::IsFieldON()) for (Int_t iCh=0; iCh<=ch1; iCh++) + impactMCS2 += AliMUONConstants::DefaultChamberZ(iCh) * AliMUONConstants::DefaultChamberZ(iCh) * fMaxMCSAngle2; + Double_t sigmaCut = GetRecoParam()->GetSigmaCutForTracking(); // Create iterators to loop over clusters in both chambers TIter nextInCh1(clusterStore.CreateChamberIterator(ch1,ch1)); @@ -197,41 +281,64 @@ TClonesArray* AliMUONVTrackReconstructor::MakeSegmentsBetweenChambers(const AliM // Loop over clusters in the first chamber of the station while ( ( cluster1 = static_cast(nextInCh1()) ) ) { + z1 = cluster1->GetZ(); // reset cluster iterator of chamber 2 nextInCh2.Reset(); // Loop over clusters in the second chamber of the station while ( ( cluster2 = static_cast(nextInCh2()) ) ) { + z2 = cluster2->GetZ(); + dZ = z1 - z2; - // non bending slope - nonBendingSlope = (cluster1->GetX() - cluster2->GetX()) / (cluster1->GetZ() - cluster2->GetZ()); - - // check if non bending slope is within tolerances - if (TMath::Abs(nonBendingSlope) > GetRecoParam()->GetMaxNonBendingSlope()) continue; - - // bending slope - bendingSlope = (cluster1->GetY() - cluster2->GetY()) / (cluster1->GetZ() - cluster2->GetZ()); - - // check the bending momentum of the bending slope depending if the field is ON or OFF - if (AliMUONTrackExtrap::IsFieldON()) { + // ------ track selection in non bending direction ------ + nonBendingSlope = (cluster1->GetX() - cluster2->GetX()) / dZ; + if (GetRecoParam()->SelectOnTrackSlope()) { + + // check if non bending slope is within tolerances + nonBendingSlopeErr = TMath::Sqrt((cluster1->GetErrX2() + cluster2->GetErrX2()) / dZ / dZ + (ch1 + 1.) * fMaxMCSAngle2); + if ((TMath::Abs(nonBendingSlope) - sigmaCut * nonBendingSlopeErr) > GetRecoParam()->GetMaxNonBendingSlope()) continue; + + } else { - // impact parameter - impactParam = cluster1->GetY() - cluster1->GetZ() * bendingSlope; + // or check if non bending impact parameter is within tolerances + nonBendingImpactParam = TMath::Abs(cluster1->GetX() - cluster1->GetZ() * nonBendingSlope); + nonBendingImpactParamErr = TMath::Sqrt((z1 * z1 * cluster2->GetErrX2() + z2 * z2 * cluster1->GetErrX2()) / dZ / dZ + impactMCS2); + if ((nonBendingImpactParam - sigmaCut * nonBendingImpactParamErr) > (3. * GetRecoParam()->GetNonBendingVertexDispersion())) continue; - // absolute value of bending momentum - bendingMomentum = TMath::Abs(AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(impactParam)); + } + + // ------ track selection in bending direction ------ + bendingSlope = (cluster1->GetY() - cluster2->GetY()) / dZ; + if (AliMUONTrackExtrap::IsFieldON()) { // depending whether the field is ON or OFF // check if bending momentum is within tolerances - if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() || - bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue; + bendingImpactParam = cluster1->GetY() - cluster1->GetZ() * bendingSlope; + bendingImpactParamErr2 = (z1 * z1 * cluster2->GetErrY2() + z2 * z2 * cluster1->GetErrY2()) / dZ / dZ + impactMCS2; + bendingMomentum = TMath::Abs(AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpactParam)); + bendingMomentumErr = TMath::Sqrt((bendingVertexDispersion2 + bendingImpactParamErr2) / + bendingImpactParam / bendingImpactParam + 0.01) * bendingMomentum; + if ((bendingMomentum + 3. * bendingMomentumErr) < GetRecoParam()->GetMinBendingMomentum()) continue; } else { - // check if non bending slope is within tolerances - if (TMath::Abs(bendingSlope) > GetRecoParam()->GetMaxBendingSlope()) continue; - + if (GetRecoParam()->SelectOnTrackSlope()) { + + // check if bending slope is within tolerances + bendingSlopeErr = TMath::Sqrt((cluster1->GetErrY2() + cluster2->GetErrY2()) / dZ / dZ + (ch1 + 1.) * fMaxMCSAngle2); + if ((TMath::Abs(bendingSlope) - sigmaCut * bendingSlopeErr) > GetRecoParam()->GetMaxBendingSlope()) continue; + + } else { + + // or check if bending impact parameter is within tolerances + bendingImpactParam = TMath::Abs(cluster1->GetY() - cluster1->GetZ() * bendingSlope); + bendingImpactParamErr = TMath::Sqrt((z1 * z1 * cluster2->GetErrY2() + z2 * z2 * cluster1->GetErrY2()) / dZ / dZ + impactMCS2); + if ((bendingImpactParam - sigmaCut * bendingImpactParamErr) > (3. * GetRecoParam()->GetBendingVertexDispersion())) continue; + + } + } + // make new segment segment = new ((*segments)[segments->GetLast()+1]) AliMUONObjectPair(cluster1, cluster2, kFALSE, kFALSE); @@ -469,16 +576,18 @@ void AliMUONVTrackReconstructor::AskForNewClustersInChamber(const AliMUONTrackPa AliMUONTrackParam extrapTrackParam(trackParam); AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParam, AliMUONConstants::DefaultChamberZ(chamber)); - // build the searching area using the track resolution and the maximum-distance-to-track value + // build the searching area using the track and chamber resolutions and the maximum-distance-to-track value const TMatrixD& kParamCov = extrapTrackParam.GetCovariances(); - Double_t errX2 = kParamCov(0,0) + kMaxDZ * kMaxDZ * kParamCov(1,1) + 2. * kMaxDZ * TMath::Abs(kParamCov(0,1)); - Double_t errY2 = kParamCov(2,2) + kMaxDZ * kMaxDZ * kParamCov(3,3) + 2. * kMaxDZ * TMath::Abs(kParamCov(2,3)); + Double_t errX2 = kParamCov(0,0) + kMaxDZ * kMaxDZ * kParamCov(1,1) + 2. * kMaxDZ * TMath::Abs(kParamCov(0,1)) + + GetRecoParam()->GetDefaultNonBendingReso(chamber) * GetRecoParam()->GetDefaultNonBendingReso(chamber); + Double_t errY2 = kParamCov(2,2) + kMaxDZ * kMaxDZ * kParamCov(3,3) + 2. * kMaxDZ * TMath::Abs(kParamCov(2,3)) + + GetRecoParam()->GetDefaultBendingReso(chamber) * GetRecoParam()->GetDefaultBendingReso(chamber); Double_t dX = TMath::Abs(trackParam.GetNonBendingSlope()) * kMaxDZ + GetRecoParam()->GetMaxNonBendingDistanceToTrack() + - GetRecoParam()->GetSigmaCutForTracking() * TMath::Sqrt(errX2); + GetRecoParam()->GetSigmaCutForTracking() * TMath::Sqrt(2. * errX2); Double_t dY = TMath::Abs(trackParam.GetBendingSlope()) * kMaxDZ + GetRecoParam()->GetMaxBendingDistanceToTrack() + - GetRecoParam()->GetSigmaCutForTracking() * TMath::Sqrt(errY2); + GetRecoParam()->GetSigmaCutForTracking() * TMath::Sqrt(2. * errY2); AliMpArea area(extrapTrackParam.GetNonBendingCoor(), extrapTrackParam.GetBendingCoor(), dX, dY); @@ -521,9 +630,12 @@ Double_t AliMUONVTrackReconstructor::TryOneCluster(const AliMUONTrackParam &trac const TMatrixD& kParamCov = trackParamAtCluster.GetCovariances(); Double_t sigmaX2 = kParamCov(0,0) + cluster->GetErrX2(); Double_t sigmaY2 = kParamCov(2,2) + cluster->GetErrY2(); + Double_t covXY = kParamCov(0,2); + Double_t det = sigmaX2 * sigmaY2 - covXY * covXY; // Compute chi2 - return dX * dX / sigmaX2 + dY * dY / sigmaY2; + if (det == 0.) return 1.e10; + return (dX * dX * sigmaY2 + dY * dY * sigmaX2 - 2. * dX * dY * covXY) / det; } @@ -531,7 +643,7 @@ Double_t AliMUONVTrackReconstructor::TryOneCluster(const AliMUONTrackParam &trac Bool_t AliMUONVTrackReconstructor::TryOneClusterFast(const AliMUONTrackParam &trackParam, const AliMUONVCluster* cluster) { /// Test the compatibility between the track and the cluster -/// given the track resolution + the maximum-distance-to-track value +/// given the track and cluster resolutions + the maximum-distance-to-track value /// and assuming linear propagation of the track: /// return kTRUE if they are compatibles @@ -539,12 +651,12 @@ Bool_t AliMUONVTrackReconstructor::TryOneClusterFast(const AliMUONTrackParam &tr Double_t dX = cluster->GetX() - (trackParam.GetNonBendingCoor() + trackParam.GetNonBendingSlope() * dZ); Double_t dY = cluster->GetY() - (trackParam.GetBendingCoor() + trackParam.GetBendingSlope() * dZ); const TMatrixD& kParamCov = trackParam.GetCovariances(); - Double_t errX2 = kParamCov(0,0) + dZ * dZ * kParamCov(1,1) + 2. * dZ * kParamCov(0,1); - Double_t errY2 = kParamCov(2,2) + dZ * dZ * kParamCov(3,3) + 2. * dZ * kParamCov(2,3); + Double_t errX2 = kParamCov(0,0) + dZ * dZ * kParamCov(1,1) + 2. * dZ * kParamCov(0,1) + cluster->GetErrX2(); + Double_t errY2 = kParamCov(2,2) + dZ * dZ * kParamCov(3,3) + 2. * dZ * kParamCov(2,3) + cluster->GetErrY2(); - Double_t dXmax = GetRecoParam()->GetSigmaCutForTracking() * TMath::Sqrt(errX2) + + Double_t dXmax = GetRecoParam()->GetSigmaCutForTracking() * TMath::Sqrt(2. * errX2) + GetRecoParam()->GetMaxNonBendingDistanceToTrack(); - Double_t dYmax = GetRecoParam()->GetSigmaCutForTracking() * TMath::Sqrt(errY2) + + Double_t dYmax = GetRecoParam()->GetSigmaCutForTracking() * TMath::Sqrt(2. * errY2) + GetRecoParam()->GetMaxBendingDistanceToTrack(); if (TMath::Abs(dX) > dXmax || TMath::Abs(dY) > dYmax) return kFALSE; diff --git a/MUON/AliMUONVTrackReconstructor.h b/MUON/AliMUONVTrackReconstructor.h index 4b25fe107cf..09b630d0883 100644 --- a/MUON/AliMUONVTrackReconstructor.h +++ b/MUON/AliMUONVTrackReconstructor.h @@ -64,6 +64,8 @@ class AliMUONVTrackReconstructor : public TObject { const AliMUONRecoParam* fkRecoParam; ///< reference to reco parameters + Double_t fMaxMCSAngle2; ///< maximum angle dispersion due to MCS + // Functions AliMUONVTrackReconstructor (const AliMUONVTrackReconstructor& rhs); ///< copy constructor AliMUONVTrackReconstructor& operator=(const AliMUONVTrackReconstructor& rhs); ///< assignment operator @@ -83,6 +85,8 @@ class AliMUONVTrackReconstructor : public TObject { /// Finalize the given track virtual void FinalizeTrack(AliMUONTrack &track) = 0; + Bool_t IsAcceptable(AliMUONTrackParam &trackParam); + TClonesArray* MakeSegmentsBetweenChambers(const AliMUONVClusterStore& clusterStore, Int_t ch1, Int_t ch2); void RemoveUsedSegments(TClonesArray& segments); diff --git a/MUON/runDataReconstruction.C b/MUON/runDataReconstruction.C index 87207984cb5..c8d1d4284f2 100644 --- a/MUON/runDataReconstruction.C +++ b/MUON/runDataReconstruction.C @@ -82,8 +82,8 @@ void runDataReconstruction(const char* input = "/Users/laurent/Alice/Data/Raw/09 muonRecoParam->SetCalibrationMode(caliboption.Data()); // cut on (non)bending slopes - muonRecoParam->SetMaxNonBendingSlope(0.6); - muonRecoParam->SetMaxBendingSlope(0.6); + muonRecoParam->SetMaxNonBendingSlope(0.4); + muonRecoParam->SetMaxBendingSlope(0.5); // tracking algorithm muonRecoParam->MakeMoreTrackCandidates(kTRUE); diff --git a/OCDB/MUON/Calib/RecoParam/Run0_999999999_v0_s0.root b/OCDB/MUON/Calib/RecoParam/Run0_999999999_v0_s0.root index e7ebd5c8314eba8da3b89f0846dcd8111f468224..15130b1b93b55d57d2ee181196df81bd24b3b16b 100644 GIT binary patch delta 4519 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 Y;4fG55BZOK`HRH;iz6xa6;1~I9|_`N6#xJL delta 4447 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 E08hh8=>Px# -- 2.43.0