1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
16 //====================================================================================================================================================
20 // Class for the creation of the "global muon tracks" built from the tracks reconstructed in the
21 // muon spectrometer and the clusters of the Muon Forward Tracker
23 // Contact author: antonio.uras@cern.ch
25 //====================================================================================================================================================
29 #include "AliGeomManager.h"
30 #include "AliESDEvent.h"
31 #include "AliESDMuonTrack.h"
32 //#include "AliESDMuonGlobalTrack.h"
33 #include "AliMFTTrackerMU.h"
37 #include "AliMUONTrackExtrap.h"
38 #include "AliMUONTrack.h"
39 #include "AliMUONESDInterface.h"
40 #include "AliMuonForwardTrack.h"
42 ClassImp(AliMFTTrackerMU)
44 const Double_t AliMFTTrackerMU::fRadLengthSi = AliMFTConstants::fRadLengthSi;
46 //====================================================================================================================================================
48 AliMFTTrackerMU::AliMFTTrackerMU() :
54 fNPlanesMFTAnalyzed(0),
56 fScaleSigmaClusterCut(1.),
57 fNMaxMissingMFTClusters(0),
58 fGlobalTrackingDiverged(kFALSE),
62 fFinalBestCandidate(0),
66 fBransonCorrection(kFALSE)
69 //--------------------------------------------------------------------
70 // This is the AliMFTTrackerMU constructor
71 //--------------------------------------------------------------------
73 fMFT = (AliMFT*) gAlice->GetDetector("MFT");
74 fSegmentation = fMFT->GetSegmentation();
75 SetNPlanesMFT(fSegmentation->GetNPlanes());
76 AliMUONTrackExtrap::SetField(); // set the magnetic field for track extrapolations
78 for (Int_t iPlane=0; iPlane<fNPlanesMFT; iPlane++) {
79 fMFTClusterArray[iPlane] = 0;
80 fMFTClusterArrayFront[iPlane] = new TClonesArray("AliMFTCluster");
81 fMFTClusterArrayBack[iPlane] = new TClonesArray("AliMFTCluster");
82 fIsPlaneMandatory[iPlane] = kFALSE;
87 //====================================================================================================================================================
89 AliMFTTrackerMU::~AliMFTTrackerMU() {
93 for (Int_t iPlane=0; iPlane<fNPlanesMFT; iPlane++) {
94 delete fMFTClusterArray[iPlane];
95 delete fMFTClusterArrayFront[iPlane];
96 delete fMFTClusterArrayBack[iPlane];
101 //====================================================================================================================================================
103 Int_t AliMFTTrackerMU::LoadClusters(TTree *cTree) {
105 //--------------------------------------------------------------------
106 // This function loads the MFT clusters
107 //--------------------------------------------------------------------
109 if (!cTree->GetEvent()) return kFALSE;
110 for (Int_t iPlane=0; iPlane<fNPlanesMFT; iPlane++) {
111 AliDebug(1, Form("plane %02d: nClusters = %d\n", iPlane, (fMFT->GetRecPointsList(iPlane))->GetEntries()));
112 fMFTClusterArray[iPlane] = fMFT->GetRecPointsList(iPlane);
114 SeparateFrontBackClusters();
120 //====================================================================================================================================================
122 void AliMFTTrackerMU::UnloadClusters() {
124 //--------------------------------------------------------------------
125 // This function unloads MFT clusters
126 //--------------------------------------------------------------------
128 for (Int_t iPlane=0; iPlane<fNPlanesMFT; iPlane++) {
129 fMFTClusterArray[iPlane] -> Clear("C");
130 fMFTClusterArrayFront[iPlane] -> Clear("C");
131 fMFTClusterArrayBack[iPlane] -> Clear("C");
136 //====================================================================================================================================================
138 Int_t AliMFTTrackerMU::Clusters2Tracks(AliESDEvent *event) {
140 //--------------------------------------------------------------------
141 // This functions reconstructs the Muon Forward Tracks
142 // The clusters must be already loaded !
143 //--------------------------------------------------------------------
145 TTree *outputTreeMuonGlobalTracks = new TTree("AliMuonForwardTracks", "Tree of AliMuonForwardTracks");
146 TClonesArray *muonForwardTracks = new TClonesArray("AliMuonForwardTrack");
147 outputTreeMuonGlobalTracks -> Branch("tracks", &muonForwardTracks);
149 //--------------------------------------------------------------------
153 //----------- Read ESD MUON tracks -------------------
155 Int_t nTracksMUON = event->GetNumberOfMuonTracks();
157 AliInfo(Form("Number of ESD MUON tracks: %d\n", nTracksMUON));
160 while (iTrack<nTracksMUON) {
162 fNPlanesMFTAnalyzed = 0;
164 AliDebug(1, "**************************************************************************************\n");
165 AliDebug(1, Form("*************************** MUON TRACK %3d ***************************************\n", iTrack));
166 AliDebug(1, "**************************************************************************************\n");
168 fCandidateTracks -> Delete();
170 fNPlanesMFTAnalyzed = 0;
172 const AliESDMuonTrack *esdTrack = event->GetMuonTrack(iTrack);
174 AliMUONESDInterface::ESDToMUON(*esdTrack, *fMUONTrack, kFALSE);
176 // the track we are going to build, starting from fMUONTrack and adding the MFT clusters
177 AliMuonForwardTrack *track = new ((*fCandidateTracks)[0]) AliMuonForwardTrack();
178 track -> SetMUONTrack(new AliMUONTrack(*fMUONTrack));
179 track -> SetMCLabel(fMUONTrack->GetMCLabel());
180 track -> SetMatchTrigger(fMUONTrack->GetMatchTrigger());
182 //------------------------- NOW THE CYCLE OVER THE MFT PLANES STARTS ---------------------------------------
184 for (Int_t iPlane=fNPlanesMFT-1; iPlane>=0; iPlane--) { /* *** do not reverse the order of this cycle!!!
185 *** this reflects the fact that the extrapolation is performed
186 *** starting from the last MFT plane back to the origin */
188 // --------- updating the array of candidates according to the clusters available in the i-th plane ---------
190 fNPlanesMFTAnalyzed++;
192 Int_t nCandidates = fCandidateTracks->GetEntriesFast();
193 for (Int_t iCandidate=0; iCandidate<nCandidates; iCandidate++) {
194 fCurrentTrack = (AliMuonForwardTrack*) fCandidateTracks->UncheckedAt(iCandidate);
195 // if the old track is compatible with the new cluster, the track is updated and inserted as new track in the array
196 // (several new tracks can be created for one old track)
197 if (FindClusterInPlane(iPlane) == kDiverged) {
198 fGlobalTrackingDiverged = kTRUE;
202 if ((fNPlanesMFTAnalyzed-fCurrentTrack->GetNMFTClusters())>fNMaxMissingMFTClusters || fIsPlaneMandatory[iPlane]) {
203 fCandidateTracks->Remove(fCurrentTrack); // the old track is removed after the check;
206 if (fGlobalTrackingDiverged) {
207 if (fScaleSigmaClusterCut>0) fScaleSigmaClusterCut -= 0.1;
211 fCandidateTracks->Compress();
215 // -------------------------- END OF THE CYCLE OVER THE MFT PLANES --------------------------------------------
217 fGlobalTrackingDiverged = kFALSE;
218 fScaleSigmaClusterCut = 1.0;
220 AliDebug(1, "Finished cycle over planes");
224 // If we have several final tracks, we must find the best candidate:
226 Int_t nFinalTracks = fCandidateTracks->GetEntriesFast();
227 AliDebug(1, Form("nFinalTracks = %d", nFinalTracks));
229 Int_t nGoodClustersBestCandidate = 0;
230 Int_t idBestCandidate = 0;
231 Double_t bestChi2 = -1.; // variable defining the best candidate
233 for (Int_t iFinalCandidate=0; iFinalCandidate<nFinalTracks; iFinalCandidate++) {
235 AliMuonForwardTrack *finalTrack = (AliMuonForwardTrack*) fCandidateTracks->UncheckedAt(iFinalCandidate);
236 Int_t nMFTClusters = finalTrack->GetNMFTClusters();
239 for (Int_t iCluster=0; iCluster<nMFTClusters; iCluster++) {
240 AliMFTCluster *localCluster = finalTrack->GetMFTCluster(iCluster);
241 chi2 += localCluster->GetLocalChi2();
243 chi2 /= nMFTClusters;
245 // now comparing the tracks in order to find the best one
247 if (chi2<bestChi2 || bestChi2<0) {
249 idBestCandidate = iFinalCandidate;
256 AliMuonForwardTrack *newTrack = (AliMuonForwardTrack*) fCandidateTracks->UncheckedAt(idBestCandidate);
257 newTrack -> SetNWrongClustersMC(newTrack->GetNMFTClusters() - nGoodClustersBestCandidate);
259 //----------------------- Save the information to the AliESDMuonForwardTrack object
261 // AliESDMuonGlobalTrack *myESDTrack = event->NewMuonGlobalTrack();
262 // myESDTrack -> SetPxPyPz(newTrack->Px(), newTrack->Py(), newTrack->Pz());
263 // myESDTrack -> SetChi2(newTrack->GetGlobalChi2());
264 // myESDTrack -> SetCharge(newTrack->GetCharge());
265 // myESDTrack -> SetMatchTrigger(newTrack->GetMatchTrigger());
267 //---------------------------------------------------------------------------------
269 new ((*muonForwardTracks)[muonForwardTracks->GetEntries()]) AliMuonForwardTrack(*newTrack);
273 fCandidateTracks->Delete();
274 fFinalBestCandidate = NULL;
279 TFile *outputFileMuonGlobalTracks = new TFile("MuonGlobalTracks.root", "update");
280 while (outputFileMuonGlobalTracks->cd(Form("Event%d",myEventID))) myEventID++;
281 outputFileMuonGlobalTracks -> mkdir(Form("Event%d",myEventID));
282 outputFileMuonGlobalTracks -> cd(Form("Event%d",myEventID));
283 outputTreeMuonGlobalTracks -> Write();
284 outputFileMuonGlobalTracks -> Close();
290 //=========================================================================================================================================
292 void AliMFTTrackerMU::SeparateFrontBackClusters() {
294 for (Int_t iPlane=0; iPlane<fNPlanesMFT; iPlane++) {
295 fMFTClusterArrayFront[iPlane]->Delete();
296 fMFTClusterArrayBack[iPlane] ->Delete();
297 for (Int_t iCluster=0; iCluster<fMFTClusterArray[iPlane]->GetEntries(); iCluster++) {
298 AliMFTCluster *cluster = (AliMFTCluster*) fMFTClusterArray[iPlane]->At(iCluster);
299 if (TMath::Abs(cluster->GetZ())<TMath::Abs(fSegmentation->GetPlane(iPlane)->GetZCenter())) {
300 new ((*fMFTClusterArrayFront[iPlane])[fMFTClusterArrayFront[iPlane]->GetEntries()]) AliMFTCluster(*cluster);
303 new ((*fMFTClusterArrayBack[iPlane])[fMFTClusterArrayBack[iPlane]->GetEntries()]) AliMFTCluster(*cluster);
310 //==========================================================================================================================================
312 Int_t AliMFTTrackerMU::FindClusterInPlane(Int_t planeId) {
314 AliDebug(2, Form(">>>> executing AliMuonForwardTrackFinder::FindClusterInPlane(%d)\n", planeId));
316 // !!!!!!!!! coordinates and errors on the interaction vertex should be taken from the event itself (ITS) if available
318 // propagate track to plane #planeId (both to front and back active sensors)
319 // look for compatible clusters
320 // update TrackParam at found cluster (if any) using Kalman Filter
322 AliMUONTrackParam currentParamFront, currentParamBack, currentParamForResearchFront, currentParamForResearchBack;
324 if (planeId == fNPlanesMFT-1) { // last plane of the telecope
325 currentParamFront = (*((AliMUONTrackParam*)(fMUONTrack->GetTrackParamAtCluster()->First())));
326 currentParamBack = (*((AliMUONTrackParam*)(fMUONTrack->GetTrackParamAtCluster()->First())));
327 currentParamForResearchFront = currentParamFront;
328 currentParamForResearchBack = currentParamBack;
329 Double_t xExtrap = gRandom->Gaus(0,fVertexErrorX);
330 Double_t yExtrap = gRandom->Gaus(0,fVertexErrorY);
331 Double_t zExtrap = gRandom->Gaus(0,fVertexErrorZ);
332 if (fBransonCorrection) {
333 AliMUONTrackExtrap::ExtrapToVertex(¤tParamFront, xExtrap, yExtrap, zExtrap, fVertexErrorX, fVertexErrorY);
334 AliMUONTrackExtrap::ExtrapToVertex(¤tParamBack, xExtrap, yExtrap, zExtrap, fVertexErrorX, fVertexErrorY);
337 AliMUONTrackExtrap::ExtrapToVertexWithoutBranson(¤tParamFront, zExtrap);
338 AliMUONTrackExtrap::ExtrapToVertexWithoutBranson(¤tParamBack, zExtrap);
340 AliMUONTrackExtrap::ExtrapToVertex(¤tParamForResearchFront, xExtrap, yExtrap, zExtrap, fVertexErrorX, fVertexErrorY);
341 AliMUONTrackExtrap::ExtrapToVertex(¤tParamForResearchBack, xExtrap, yExtrap, zExtrap, fVertexErrorX, fVertexErrorY);
343 else { // MFT planes others than the last one: mult. scattering correction because of the upstream MFT planes is performed
344 currentParamFront = (*((AliMUONTrackParam*)(fCurrentTrack->GetTrackParamAtCluster()->First())));
345 currentParamBack = (*((AliMUONTrackParam*)(fCurrentTrack->GetTrackParamAtCluster()->First())));
346 currentParamForResearchFront = currentParamFront;
347 currentParamForResearchBack = currentParamBack;
348 AliMUONTrackExtrap::AddMCSEffect(¤tParamFront, (fSegmentation->GetPlane(planeId+1)->GetEquivalentSilicon()+
349 fSegmentation->GetPlane(planeId)->GetEquivalentSiliconBeforeFront())/fRadLengthSi,-1.);
350 AliMUONTrackExtrap::AddMCSEffect(¤tParamForResearchFront,(fSegmentation->GetPlane(planeId+1)->GetEquivalentSilicon()+
351 fSegmentation->GetPlane(planeId)->GetEquivalentSiliconBeforeFront())/fRadLengthSi,-1.);
352 AliMUONTrackExtrap::AddMCSEffect(¤tParamBack, (fSegmentation->GetPlane(planeId+1)->GetEquivalentSilicon()+
353 fSegmentation->GetPlane(planeId)->GetEquivalentSiliconBeforeBack())/fRadLengthSi,-1.);
354 AliMUONTrackExtrap::AddMCSEffect(¤tParamForResearchBack, (fSegmentation->GetPlane(planeId+1)->GetEquivalentSilicon()+
355 fSegmentation->GetPlane(planeId)->GetEquivalentSiliconBeforeBack())/fRadLengthSi,-1.);
357 // for all planes: extrapolation to the Z of the plane
358 AliMUONTrackExtrap::ExtrapToZCov(¤tParamFront, -1.*fSegmentation->GetPlane(planeId)->GetZCenterActiveFront());
359 AliMUONTrackExtrap::ExtrapToZCov(¤tParamForResearchFront, -1.*fSegmentation->GetPlane(planeId)->GetZCenterActiveFront());
360 AliMUONTrackExtrap::ExtrapToZCov(¤tParamBack, -1.*fSegmentation->GetPlane(planeId)->GetZCenterActiveBack());
361 AliMUONTrackExtrap::ExtrapToZCov(¤tParamForResearchBack, -1.*fSegmentation->GetPlane(planeId)->GetZCenterActiveBack());
363 //---------------------------------------------------------------------------------------
365 TMatrixD covFront(5,5); covFront = currentParamForResearchFront.GetCovariances();
366 TMatrixD covBack(5,5); covBack = currentParamForResearchBack.GetCovariances();
368 Double_t squaredError_X_Front = covFront(0,0);
369 Double_t squaredError_Y_Front = covFront(2,2);
370 Double_t squaredError_X_Back = covBack(0,0);
371 Double_t squaredError_Y_Back = covBack(2,2);
373 Double_t corrFact = 1.0;
375 Double_t researchRadiusFront = TMath::Sqrt(squaredError_X_Front + squaredError_Y_Front);
376 Double_t researchRadiusBack = TMath::Sqrt(squaredError_X_Back + squaredError_Y_Back);
377 if (0.5*(researchRadiusFront+researchRadiusBack)<fMinResearchRadiusAtPlane[planeId]) {
378 corrFact = fMinResearchRadiusAtPlane[planeId]/(0.5*(researchRadiusFront+researchRadiusBack));
381 //---------------------------------------------------------------------------------------
383 Double_t chi2cut = 2.*fScaleSigmaClusterCut*fScaleSigmaClusterCut*fSigmaClusterCut*fSigmaClusterCut; // depends on the number of variables (here, 2)
385 // Analyizing the clusters: FRONT ACTIVE ELEMENTS
387 Int_t nClustersFront = fMFTClusterArrayFront[planeId]->GetEntries();
388 AliDebug(2, Form("There are %3d clusters in plane %02d FRONT\n", nClustersFront, planeId));
390 for (Int_t iCluster=0; iCluster<nClustersFront; iCluster++) {
392 Bool_t isGoodChi2 = kFALSE;
394 AliMFTCluster *cluster = (AliMFTCluster*) fMFTClusterArrayFront[planeId]->At(iCluster);
395 Double_t chi2 = (1./(corrFact*corrFact)) * TryOneCluster(currentParamForResearchFront, cluster); // describes the compatibility between the track and the cluster
396 if (chi2<chi2cut) isGoodChi2 = kTRUE;
399 AliDebug(3, Form("accepting cluster: chi2=%f (cut = %f)\n", chi2, chi2cut));
400 AliMuonForwardTrack *newTrack = new ((*fCandidateTracks)[fCandidateTracks->GetEntriesFast()]) AliMuonForwardTrack(*fCurrentTrack);
401 if (fCandidateTracks->GetEntriesFast() > fMaxNCandidates) return kDiverged;
402 newTrack->AddTrackParamAtMFTCluster(currentParamFront, *cluster); // creating new track param and attaching the cluster
403 AliDebug(2, Form("After plane %02d: newTrack->GetNMFTClusters() = %d (fCurrentTrack->GetNMFTClusters() = %d)",
404 planeId, newTrack->GetNMFTClusters(), fCurrentTrack->GetNMFTClusters()));
405 newTrack->SetPlaneExists(planeId);
407 else AliDebug(3, Form("discarding cluster: chi2=%f (cut = %f)\n", chi2, chi2cut));
411 // Analyizing the clusters: BACK ACTIVE ELEMENTS
413 Int_t nClustersBack = fMFTClusterArrayBack[planeId]->GetEntries();
414 AliDebug(2, Form("There are %3d clusters in plane %02d BACK\n", nClustersBack, planeId));
416 for (Int_t iCluster=0; iCluster<nClustersBack; iCluster++) {
418 Bool_t isGoodChi2 = kFALSE;
420 AliMFTCluster *cluster = (AliMFTCluster*) fMFTClusterArrayBack[planeId]->At(iCluster);
421 Double_t chi2 = (1./(corrFact*corrFact)) * TryOneCluster(currentParamForResearchBack, cluster); // describes the compatibility between the track and the cluster
422 if (chi2<chi2cut) isGoodChi2 = kTRUE;
425 AliDebug(3,Form("accepting cluster: chi2=%f (cut = %f)\n", chi2, chi2cut));
426 AliMuonForwardTrack *newTrack = new ((*fCandidateTracks)[fCandidateTracks->GetEntriesFast()]) AliMuonForwardTrack(*fCurrentTrack);
427 if (fCandidateTracks->GetEntriesFast() > fMaxNCandidates) return kDiverged;
428 newTrack->AddTrackParamAtMFTCluster(currentParamBack, *cluster); // creating new track param and attaching the cluster
429 AliDebug(2, Form("After plane %02d: newTrack->GetNMFTClusters() = %d (fCurrentTrack->GetNMFTClusters() = %d)",
430 planeId, newTrack->GetNMFTClusters(), fCurrentTrack->GetNMFTClusters()));
431 newTrack->SetPlaneExists(planeId);
433 else AliDebug(3,Form("discarding cluster: chi2=%f (cut = %f)\n", chi2, chi2cut));
437 //---------------------------------------------------------------------------------------------
443 //==========================================================================================================================================
445 Double_t AliMFTTrackerMU::TryOneCluster(const AliMUONTrackParam &trackParam, AliMFTCluster *cluster) {
447 // Test the compatibility between the track and the cluster (using trackParam's covariance matrix):
448 // return the corresponding Chi2
449 // assume the track parameters are given at the Z of the cluster
451 // Set differences between trackParam and cluster in the bending and non bending directions
452 Double_t dX = cluster->GetX() - trackParam.GetNonBendingCoor();
453 Double_t dY = cluster->GetY() - trackParam.GetBendingCoor();
454 AliDebug(3,Form("dX = %f, dY = %f\n", dX, dY));
456 // Calculate errors and covariances
457 const TMatrixD& kParamCov = trackParam.GetCovariances();
458 Double_t sigmaX2 = kParamCov(0,0) + cluster->GetErrX2();
459 Double_t sigmaY2 = kParamCov(2,2) + cluster->GetErrY2();
460 AliDebug(3, Form("dX2 = %f, dY2 = %f\n", sigmaX2, sigmaY2));
461 Double_t covXY = kParamCov(0,2);
462 Double_t det = sigmaX2 * sigmaY2 - covXY * covXY;
465 if (det==0.) return 1.e10;
466 return (dX*dX*sigmaY2 + dY*dY*sigmaX2 - 2.*dX*dY*covXY) / det;
470 //=========================================================================================================================================