]> git.uio.no Git - u/mrichter/AliRoot.git/blame - MUON/AliMUONTrackReconstructor.cxx
- Adding the array of slat segmentation and GetLayerSegmentation(..) method
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackReconstructor.cxx
CommitLineData
a9e2aefa 1/**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
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 **************************************************************************/
15
cc87ebcd 16/* $Id$ */
17
3831f268 18////////////////////////////////////
a9e2aefa 19//
29f1b13a 20// MUON track reconstructor in ALICE (class renamed from AliMUONEventReconstructor)
a9e2aefa 21//
22// This class contains as data:
29f1b13a 23// * the parameters for the track reconstruction
a9e2aefa 24// * a pointer to the array of hits to be reconstructed (the event)
25// * a pointer to the array of segments made with these hits inside each station
26// * a pointer to the array of reconstructed tracks
27//
28// It contains as methods, among others:
29// * MakeEventToBeReconstructed to build the array of hits to be reconstructed
30// * MakeSegments to build the segments
31// * MakeTracks to build the tracks
3831f268 32//
33////////////////////////////////////
a9e2aefa 34
ae17f568 35#include <stdlib.h>
30178c30 36#include <Riostream.h>
37#include <TDirectory.h>
38#include <TFile.h>
cc87ebcd 39#include <TMatrixD.h>
a9e2aefa 40
29f1b13a 41#include "AliMUONTrackReconstructor.h"
5e671e06 42#include "AliMUONData.h"
29fc2c86 43#include "AliMUONConstants.h"
a9e2aefa 44#include "AliMUONHitForRec.h"
276c44b7 45#include "AliMUONTriggerTrack.h"
bc4a7ff4 46#include "AliMUONTriggerCircuitNew.h"
a9e2aefa 47#include "AliMUONRawCluster.h"
276c44b7 48#include "AliMUONLocalTrigger.h"
52c9bc11 49#include "AliMUONGlobalTrigger.h"
3831f268 50#include "AliMUONSegment.h"
a9e2aefa 51#include "AliMUONTrack.h"
94de3818 52#include "AliMagF.h"
cc87ebcd 53#include "AliMUONTrackK.h"
8c343c7c 54#include "AliLog.h"
1a38e749 55#include "AliTracker.h"
de2cd600 56#include <TVirtualFitter.h>
a9e2aefa 57
a9e2aefa 58//************* Defaults parameters for reconstruction
29f1b13a 59const Double_t AliMUONTrackReconstructor::fgkDefaultMinBendingMomentum = 3.0;
7b96283c 60const Double_t AliMUONTrackReconstructor::fgkDefaultMaxBendingMomentum = 3000.0;
29f1b13a 61const Double_t AliMUONTrackReconstructor::fgkDefaultMaxChi2 = 100.0;
62const Double_t AliMUONTrackReconstructor::fgkDefaultMaxSigma2Distance = 16.0;
63const Double_t AliMUONTrackReconstructor::fgkDefaultBendingResolution = 0.01;
64const Double_t AliMUONTrackReconstructor::fgkDefaultNonBendingResolution = 0.144;
a9e2aefa 65// Simple magnetic field:
66// Value taken from macro MUONtracking.C: 0.7 T, hence 7 kG
67// Length and Position from reco_muon.F, with opposite sign:
68// Length = ZMAGEND-ZCOIL
69// Position = (ZMAGEND+ZCOIL)/2
70// to be ajusted differently from real magnetic field ????
29f1b13a 71const Double_t AliMUONTrackReconstructor::fgkDefaultSimpleBValue = 7.0;
72const Double_t AliMUONTrackReconstructor::fgkDefaultSimpleBLength = 428.0;
73const Double_t AliMUONTrackReconstructor::fgkDefaultSimpleBPosition = 1019.0;
29f1b13a 74const Double_t AliMUONTrackReconstructor::fgkDefaultEfficiency = 0.95;
a9e2aefa 75
de2cd600 76TVirtualFitter* AliMUONTrackReconstructor::fgFitter = NULL;
77
78// Functions to be minimized with Minuit
79void TrackChi2(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag);
80void TrackChi2MCS(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag);
81
82void mnvertLocal(Double_t* a, Int_t l, Int_t m, Int_t n, Int_t& ifail);
83
84Double_t MultipleScatteringAngle2(AliMUONTrackParam *param);
85
29f1b13a 86ClassImp(AliMUONTrackReconstructor) // Class implementation in ROOT context
a9e2aefa 87
3bc8b580 88//__________________________________________________________________________
cc9e7528 89AliMUONTrackReconstructor::AliMUONTrackReconstructor(AliMUONData* data)
54d7ba50 90 : TObject(),
91 fTrackMethod(1), //AZ - tracking method (1-default, 2-Kalman)
92 fMinBendingMomentum(fgkDefaultMinBendingMomentum),
93 fMaxBendingMomentum(fgkDefaultMaxBendingMomentum),
94 fMaxChi2(fgkDefaultMaxChi2),
95 fMaxSigma2Distance(fgkDefaultMaxSigma2Distance),
de2cd600 96 fRMin(0x0),
97 fRMax(0x0),
98 fSegmentMaxDistBending(0x0),
99 fSegmentMaxDistNonBending(0x0),
54d7ba50 100 fBendingResolution(fgkDefaultBendingResolution),
101 fNonBendingResolution(fgkDefaultNonBendingResolution),
de2cd600 102 fChamberThicknessInX0(AliMUONConstants::DefaultChamberThicknessInX0()),
54d7ba50 103 fSimpleBValue(fgkDefaultSimpleBValue),
104 fSimpleBLength(fgkDefaultSimpleBLength),
105 fSimpleBPosition(fgkDefaultSimpleBPosition),
54d7ba50 106 fEfficiency(fgkDefaultEfficiency),
54d7ba50 107 fHitsForRecPtr(0x0),
108 fNHitsForRec(0),
de2cd600 109 fNHitsForRecPerChamber(0x0),
110 fIndexOfFirstHitForRecPerChamber(0x0),
111 fSegmentsPtr(0x0),
112 fNSegments(0x0),
54d7ba50 113 fRecTracksPtr(0x0),
114 fNRecTracks(0),
54d7ba50 115 fMUONData(data),
58ff0bd4 116 fMuons(0),
5e671e06 117 fTriggerTrack(new AliMUONTriggerTrack()),
118 fTriggerCircuit(0x0)
a9e2aefa 119{
de2cd600 120
121 // Memory allocation
122 fRMin = new Double_t[AliMUONConstants::NTrackingCh()];
123 fRMax = new Double_t[AliMUONConstants::NTrackingCh()];
124 fSegmentMaxDistBending = new Double_t[AliMUONConstants::NTrackingSt()];
125 fSegmentMaxDistNonBending = new Double_t[AliMUONConstants::NTrackingSt()];
126 fNHitsForRecPerChamber = new Int_t[AliMUONConstants::NTrackingCh()];
127 fIndexOfFirstHitForRecPerChamber = new Int_t[AliMUONConstants::NTrackingCh()];
128
29f1b13a 129 // Constructor for class AliMUONTrackReconstructor
a9e2aefa 130 SetReconstructionParametersToDefaults();
54d7ba50 131
a9e2aefa 132 // Memory allocation for the TClonesArray of hits for reconstruction
133 // Is 10000 the right size ????
134 fHitsForRecPtr = new TClonesArray("AliMUONHitForRec", 10000);
54d7ba50 135
a9e2aefa 136 // Memory allocation for the TClonesArray's of segments in stations
137 // Is 2000 the right size ????
de2cd600 138 fSegmentsPtr = new TClonesArray*[AliMUONConstants::NTrackingSt()];
139 fNSegments = new Int_t[AliMUONConstants::NTrackingSt()];
140 for (Int_t st = 0; st < AliMUONConstants::NTrackingSt(); st++) {
a9e2aefa 141 fSegmentsPtr[st] = new TClonesArray("AliMUONSegment", 2000);
142 fNSegments[st] = 0; // really needed or GetEntriesFast sufficient ????
143 }
144 // Memory allocation for the TClonesArray of reconstructed tracks
145 // Is 10 the right size ????
146 fRecTracksPtr = new TClonesArray("AliMUONTrack", 10);
54d7ba50 147
1a38e749 148 const AliMagF* kField = AliTracker::GetFieldMap();
149 if (!kField) AliFatal("No field available");
150 // Sign of fSimpleBValue according to sign of Bx value at (50,50,-950).
a6f03ddb 151 Float_t b[3], x[3];
5b64e914 152 x[0] = 50.; x[1] = 50.; x[2] = -950.;
1a38e749 153 kField->Field(x,b);
154
155 fSimpleBValue = TMath::Sign(fSimpleBValue,(Double_t) b[0]);
5b64e914 156 fSimpleBPosition = TMath::Sign(fSimpleBPosition,(Double_t) x[2]);
a6f03ddb 157 // See how to get fSimple(BValue, BLength, BPosition)
158 // automatically calculated from the actual magnetic field ????
a9e2aefa 159
a9e2aefa 160 return;
161}
9cbdf048 162
a9e2aefa 163 //__________________________________________________________________________
29f1b13a 164AliMUONTrackReconstructor::~AliMUONTrackReconstructor(void)
a9e2aefa 165{
29f1b13a 166 // Destructor for class AliMUONTrackReconstructor
de2cd600 167 delete [] fRMin;
168 delete [] fRMax;
169 delete [] fSegmentMaxDistBending;
170 delete [] fSegmentMaxDistNonBending;
171 delete [] fNHitsForRecPerChamber;
172 delete [] fIndexOfFirstHitForRecPerChamber;
58ff0bd4 173 delete fTriggerTrack;
de2cd600 174 delete fHitsForRecPtr;
175 // Correct destruction of everything ????
176 for (Int_t st = 0; st < AliMUONConstants::NTrackingSt(); st++) delete fSegmentsPtr[st];
177 delete [] fSegmentsPtr;
178 delete [] fNSegments;
179 delete fRecTracksPtr;
a9e2aefa 180}
a9e2aefa 181 //__________________________________________________________________________
29f1b13a 182void AliMUONTrackReconstructor::SetReconstructionParametersToDefaults(void)
a9e2aefa 183{
184 // Set reconstruction parameters to default values
185 // Would be much more convenient with a structure (or class) ????
a9e2aefa 186
a9e2aefa 187 // ******** Parameters for making HitsForRec
188 // minimum radius,
189 // like in TRACKF_STAT:
190 // 2 degrees for stations 1 and 2, or ch(0...) from 0 to 3;
191 // 30 cm for stations 3 to 5, or ch(0...) from 4 to 9
190f97ea 192 for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
06c11448 193 if (ch < 4) fRMin[ch] = TMath::Abs(AliMUONConstants::DefaultChamberZ(ch)) *
a9e2aefa 194 2.0 * TMath::Pi() / 180.0;
195 else fRMin[ch] = 30.0;
d0bfce8d 196 // maximum radius at 10 degrees and Z of chamber
06c11448 197 fRMax[ch] = TMath::Abs(AliMUONConstants::DefaultChamberZ(ch)) *
d0bfce8d 198 10.0 * TMath::Pi() / 180.0;
a9e2aefa 199 }
a9e2aefa 200
201 // ******** Parameters for making segments
202 // should be parametrized ????
203 // according to interval between chambers in a station ????
204 // Maximum distance in non bending plane
205 // 5 * 0.22 just to remember the way it was made in TRACKF_STAT
206 // SIGCUT*DYMAX(IZ)
190f97ea 207 for (Int_t st = 0; st < AliMUONConstants::NTrackingCh()/2; st++)
a9e2aefa 208 fSegmentMaxDistNonBending[st] = 5. * 0.22;
860cef81 209 // Maximum distance in bending plane:
210 // values from TRACKF_STAT, corresponding to (J psi 20cm),
211 // scaled to the real distance between chambers in a station
ef21c79e 212 fSegmentMaxDistBending[0] = TMath::Abs( 1.5 *
06c11448 213 (AliMUONConstants::DefaultChamberZ(1) - AliMUONConstants::DefaultChamberZ(0)) / 20.0);
e516b01d 214 fSegmentMaxDistBending[1] = TMath::Abs( 1.5 *
06c11448 215 (AliMUONConstants::DefaultChamberZ(3) - AliMUONConstants::DefaultChamberZ(2)) / 20.0);
e516b01d 216 fSegmentMaxDistBending[2] = TMath::Abs( 3.0 *
06c11448 217 (AliMUONConstants::DefaultChamberZ(5) - AliMUONConstants::DefaultChamberZ(4)) / 20.0);
e516b01d 218 fSegmentMaxDistBending[3] = TMath::Abs( 6.0 *
06c11448 219 (AliMUONConstants::DefaultChamberZ(7) - AliMUONConstants::DefaultChamberZ(6)) / 20.0);
e516b01d 220 fSegmentMaxDistBending[4] = TMath::Abs( 6.0 *
06c11448 221 (AliMUONConstants::DefaultChamberZ(9) - AliMUONConstants::DefaultChamberZ(8)) / 20.0);
222
a9e2aefa 223 return;
224}
225
226//__________________________________________________________________________
29f1b13a 227Double_t AliMUONTrackReconstructor::GetImpactParamFromBendingMomentum(Double_t BendingMomentum) const
a9e2aefa 228{
229 // Returns impact parameter at vertex in bending plane (cm),
230 // from the signed bending momentum "BendingMomentum" in bending plane (GeV/c),
231 // using simple values for dipole magnetic field.
065bd0e1 232 // The sign of "BendingMomentum" is the sign of the charge.
a9e2aefa 233 return (-0.0003 * fSimpleBValue * fSimpleBLength * fSimpleBPosition /
234 BendingMomentum);
235}
236
237//__________________________________________________________________________
29f1b13a 238Double_t AliMUONTrackReconstructor::GetBendingMomentumFromImpactParam(Double_t ImpactParam) const
a9e2aefa 239{
240 // Returns signed bending momentum in bending plane (GeV/c),
065bd0e1 241 // the sign being the sign of the charge for particles moving forward in Z,
a9e2aefa 242 // from the impact parameter "ImpactParam" at vertex in bending plane (cm),
243 // using simple values for dipole magnetic field.
a9e2aefa 244 return (-0.0003 * fSimpleBValue * fSimpleBLength * fSimpleBPosition /
245 ImpactParam);
246}
247
a9e2aefa 248//__________________________________________________________________________
29f1b13a 249void AliMUONTrackReconstructor::EventReconstruct(void)
a9e2aefa 250{
251 // To reconstruct one event
b840996b 252 AliDebug(1,"Enter EventReconstruct");
fff097e0 253 ResetTracks(); //AZ
fff097e0 254 ResetSegments(); //AZ
255 ResetHitsForRec(); //AZ
a9e2aefa 256 MakeEventToBeReconstructed();
257 MakeSegments();
258 MakeTracks();
d837040f 259 if (fMUONData->IsTriggerTrackBranchesInTree())
260 ValidateTracksWithTrigger();
de2cd600 261
d837040f 262 // Add tracks to MUON data container
de2cd600 263 for(Int_t i=0; i<fNRecTracks; i++) {
264 AliMUONTrack * track = (AliMUONTrack*) fRecTracksPtr->At(i);
d837040f 265 fMUONData->AddRecTrack(*track);
266 }
a9e2aefa 267}
268
276c44b7 269//__________________________________________________________________________
29f1b13a 270void AliMUONTrackReconstructor::EventReconstructTrigger(void)
276c44b7 271{
272 // To reconstruct one event
b840996b 273 AliDebug(1,"Enter EventReconstructTrigger");
276c44b7 274 MakeTriggerTracks();
276c44b7 275}
276
a9e2aefa 277 //__________________________________________________________________________
29f1b13a 278void AliMUONTrackReconstructor::ResetHitsForRec(void)
a9e2aefa 279{
280 // To reset the array and the number of HitsForRec,
281 // and also the number of HitsForRec
282 // and the index of the first HitForRec per chamber
0ce28091 283 if (fHitsForRecPtr) fHitsForRecPtr->Delete();
a9e2aefa 284 fNHitsForRec = 0;
190f97ea 285 for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++)
a9e2aefa 286 fNHitsForRecPerChamber[ch] = fIndexOfFirstHitForRecPerChamber[ch] = 0;
287 return;
288}
289
290 //__________________________________________________________________________
29f1b13a 291void AliMUONTrackReconstructor::ResetSegments(void)
a9e2aefa 292{
293 // To reset the TClonesArray of segments and the number of Segments
294 // for all stations
190f97ea 295 for (Int_t st = 0; st < AliMUONConstants::NTrackingCh()/2; st++) {
a9e2aefa 296 if (fSegmentsPtr[st]) fSegmentsPtr[st]->Clear();
297 fNSegments[st] = 0;
298 }
299 return;
300}
301
302 //__________________________________________________________________________
29f1b13a 303void AliMUONTrackReconstructor::ResetTracks(void)
a9e2aefa 304{
305 // To reset the TClonesArray of reconstructed tracks
8429a5e4 306 if (fRecTracksPtr) fRecTracksPtr->Delete();
307 // Delete in order that the Track destructors are called,
308 // hence the space for the TClonesArray of pointers to TrackHit's is freed
a9e2aefa 309 fNRecTracks = 0;
310 return;
311}
312
313 //__________________________________________________________________________
29f1b13a 314void AliMUONTrackReconstructor::MakeEventToBeReconstructed(void)
a9e2aefa 315{
316 // To make the list of hits to be reconstructed,
29fc2c86 317 // either from the track ref. hits or from the raw clusters
a9e2aefa 318 // according to the parameter set for the reconstructor
1a38e749 319
b840996b 320 AliDebug(1,"Enter MakeEventToBeReconstructed");
fff097e0 321 //AZ ResetHitsForRec();
8f373020 322
323 // Reconstruction from raw clusters
324 // AliMUON *MUON = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
325 // Security on MUON ????
326 // TreeR assumed to be be "prepared" in calling function
327 // by "MUON->GetTreeR(nev)" ????
cc9e7528 328 TTree *treeR = fMUONData->TreeR();
8f373020 329
330 //AZ? fMUONData->SetTreeAddress("RC");
331 AddHitsForRecFromRawClusters(treeR);
332 // No sorting: it is done automatically in the previous function
333
b840996b 334
335 AliDebug(1,"End of MakeEventToBeReconstructed");
336 if (AliLog::GetGlobalDebugLevel() > 0) {
337 AliDebug(1, Form("NHitsForRec: %d",fNHitsForRec));
190f97ea 338 for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
b840996b 339 AliDebug(1, Form("Chamber(0...): %d",ch));
340 AliDebug(1, Form("NHitsForRec: %d", fNHitsForRecPerChamber[ch]));
341 AliDebug(1, Form("Index(first HitForRec): %d", fIndexOfFirstHitForRecPerChamber[ch]));
342 for (Int_t hit = fIndexOfFirstHitForRecPerChamber[ch];
343 hit < fIndexOfFirstHitForRecPerChamber[ch] + fNHitsForRecPerChamber[ch];
344 hit++) {
345 AliDebug(1, Form("HitForRec index(0...): %d",hit));
346 ((*fHitsForRecPtr)[hit])->Dump();
a9e2aefa 347 }
348 }
349 }
350 return;
351}
352
a9e2aefa 353 //__________________________________________________________________________
29f1b13a 354void AliMUONTrackReconstructor::SortHitsForRecWithIncreasingChamber()
a9e2aefa 355{
356 // Sort HitsForRec's in increasing order with respect to chamber number.
357 // Uses the function "Compare".
358 // Update the information for HitsForRec per chamber too.
359 Int_t ch, nhits, prevch;
360 fHitsForRecPtr->Sort();
190f97ea 361 for (ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
a9e2aefa 362 fNHitsForRecPerChamber[ch] = 0;
363 fIndexOfFirstHitForRecPerChamber[ch] = 0;
364 }
365 prevch = 0; // previous chamber
366 nhits = 0; // number of hits in current chamber
367 // Loop over HitsForRec
368 for (Int_t hit = 0; hit < fNHitsForRec; hit++) {
369 // chamber number (0...)
370 ch = ((AliMUONHitForRec*) ((*fHitsForRecPtr)[hit]))->GetChamberNumber();
371 // increment number of hits in current chamber
372 (fNHitsForRecPerChamber[ch])++;
373 // update index of first HitForRec in current chamber
374 // if chamber number different from previous one
375 if (ch != prevch) {
376 fIndexOfFirstHitForRecPerChamber[ch] = hit;
377 prevch = ch;
378 }
379 }
380 return;
381}
382
a9e2aefa 383 //__________________________________________________________________________
29f1b13a 384void AliMUONTrackReconstructor::AddHitsForRecFromRawClusters(TTree* TR)
a9e2aefa 385{
386 // To add to the list of hits for reconstruction all the raw clusters
387 // No condition added, like in Fortran TRACKF_STAT,
388 // on the radius between RMin and RMax.
389 AliMUONHitForRec *hitForRec;
390 AliMUONRawCluster *clus;
f69d51b5 391 Int_t iclus, nclus, nTRentries;
a9e2aefa 392 TClonesArray *rawclusters;
b840996b 393 AliDebug(1,"Enter AddHitsForRecFromRawClusters");
88cb7938 394
cc87ebcd 395 if (fTrackMethod != 3) { //AZ
396 fMUONData->SetTreeAddress("RC"); //AZ
397 nTRentries = Int_t(TR->GetEntries());
398 if (nTRentries != 1) {
399 AliError(Form("nTRentries = %d not equal to 1 ",nTRentries));
400 exit(0);
401 }
cc9e7528 402 fMUONData->GetRawClusters(); // only one entry
f69d51b5 403 }
52c9bc11 404
a9e2aefa 405 // Loop over tracking chambers
190f97ea 406 for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
a9e2aefa 407 // number of HitsForRec to 0 for the chamber
408 fNHitsForRecPerChamber[ch] = 0;
409 // index of first HitForRec for the chamber
410 if (ch == 0) fIndexOfFirstHitForRecPerChamber[ch] = 0;
411 else fIndexOfFirstHitForRecPerChamber[ch] = fNHitsForRec;
52c9bc11 412 rawclusters =fMUONData->RawClusters(ch);
a9e2aefa 413 nclus = (Int_t) (rawclusters->GetEntries());
414 // Loop over (cathode correlated) raw clusters
415 for (iclus = 0; iclus < nclus; iclus++) {
416 clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(iclus);
417 // new AliMUONHitForRec from raw cluster
418 // and increment number of AliMUONHitForRec's (total and in chamber)
419 hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(clus);
420 fNHitsForRec++;
421 (fNHitsForRecPerChamber[ch])++;
422 // more information into HitForRec
423 // resolution: info should be already in raw cluster and taken from it ????
fff097e0 424 //hitForRec->SetBendingReso2(fBendingResolution * fBendingResolution);
425 //hitForRec->SetNonBendingReso2(fNonBendingResolution * fNonBendingResolution);
426 hitForRec->SetBendingReso2(clus->GetErrY() * clus->GetErrY());
427 hitForRec->SetNonBendingReso2(clus->GetErrX() * clus->GetErrX());
a9e2aefa 428 // original raw cluster
429 hitForRec->SetChamberNumber(ch);
430 hitForRec->SetHitNumber(iclus);
ba5b68db 431 // Z coordinate of the raw cluster (cm)
ba12c242 432 hitForRec->SetZ(clus->GetZ(0));
80e33fc5 433
434 StdoutToAliDebug(3,
435 cout << "Chamber " << ch <<
436 " raw cluster " << iclus << " : " << endl;
437 clus->Print("full");
438 cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
439 hitForRec->Print("full");
440 );
a9e2aefa 441 } // end of cluster loop
442 } // end of chamber loop
cc87ebcd 443 SortHitsForRecWithIncreasingChamber();
a9e2aefa 444 return;
445}
446
447 //__________________________________________________________________________
29f1b13a 448void AliMUONTrackReconstructor::MakeSegments(void)
a9e2aefa 449{
450 // To make the list of segments in all stations,
451 // from the list of hits to be reconstructed
b840996b 452 AliDebug(1,"Enter MakeSegments");
fff097e0 453 //AZ ResetSegments();
a9e2aefa 454 // Loop over stations
cc87ebcd 455 Int_t nb = (fTrackMethod != 1) ? 3 : 0; //AZ
456 for (Int_t st = nb; st < AliMUONConstants::NTrackingCh()/2; st++)
80e33fc5 457 {
a9e2aefa 458 MakeSegmentsPerStation(st);
80e33fc5 459 }
460
461 StdoutToAliDebug(3,
a9e2aefa 462 cout << "end of MakeSegments" << endl;
80e33fc5 463 for (Int_t st = 0; st < AliMUONConstants::NTrackingCh()/2; st++)
464 {
465 cout << "station " << st
466 << " has " << fNSegments[st] << " segments:"
467 << endl;
468 for (Int_t seg = 0; seg < fNSegments[st]; seg++)
469 {
470 ((*fSegmentsPtr[st])[seg])->Print();
a9e2aefa 471 }
472 }
80e33fc5 473 );
a9e2aefa 474}
475
476 //__________________________________________________________________________
29f1b13a 477void AliMUONTrackReconstructor::MakeSegmentsPerStation(Int_t Station)
a9e2aefa 478{
479 // To make the list of segments in station number "Station" (0...)
480 // from the list of hits to be reconstructed.
481 // Updates "fNSegments"[Station].
482 // Segments in stations 4 and 5 are sorted
483 // according to increasing absolute value of "impact parameter"
484 AliMUONHitForRec *hit1Ptr, *hit2Ptr;
485 AliMUONSegment *segment;
486 Bool_t last2st;
487 Double_t bendingSlope, distBend, distNonBend, extBendCoor, extNonBendCoor,
d0bfce8d 488 impactParam = 0., maxImpactParam = 0., minImpactParam = 0.; // =0 to avoid compilation warnings.
b840996b 489 AliDebug(1,Form("Enter MakeSegmentsPerStation (0...) %d",Station));
a9e2aefa 490 // first and second chambers (0...) in the station
491 Int_t ch1 = 2 * Station;
492 Int_t ch2 = ch1 + 1;
493 // variable true for stations downstream of the dipole:
494 // Station(0..4) equal to 3 or 4
495 if ((Station == 3) || (Station == 4)) {
496 last2st = kTRUE;
497 // maximum impact parameter (cm) according to fMinBendingMomentum...
498 maxImpactParam =
499 TMath::Abs(GetImpactParamFromBendingMomentum(fMinBendingMomentum));
d0bfce8d 500 // minimum impact parameter (cm) according to fMaxBendingMomentum...
501 minImpactParam =
502 TMath::Abs(GetImpactParamFromBendingMomentum(fMaxBendingMomentum));
a9e2aefa 503 }
504 else last2st = kFALSE;
505 // extrapolation factor from Z of first chamber to Z of second chamber
506 // dZ to be changed to take into account fine structure of chambers ????
e516b01d 507 Double_t extrapFact;
a9e2aefa 508 // index for current segment
509 Int_t segmentIndex = 0;
510 // Loop over HitsForRec in the first chamber of the station
511 for (Int_t hit1 = fIndexOfFirstHitForRecPerChamber[ch1];
512 hit1 < fIndexOfFirstHitForRecPerChamber[ch1] + fNHitsForRecPerChamber[ch1];
513 hit1++) {
514 // pointer to the HitForRec
515 hit1Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit1]);
516 // extrapolation,
517 // on the straight line joining the HitForRec to the vertex (0,0,0),
518 // to the Z of the second chamber of the station
a9e2aefa 519 // Loop over HitsForRec in the second chamber of the station
520 for (Int_t hit2 = fIndexOfFirstHitForRecPerChamber[ch2];
521 hit2 < fIndexOfFirstHitForRecPerChamber[ch2] + fNHitsForRecPerChamber[ch2];
522 hit2++) {
523 // pointer to the HitForRec
524 hit2Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit2]);
525 // absolute values of distances, in bending and non bending planes,
526 // between the HitForRec in the second chamber
527 // and the previous extrapolation
e516b01d 528 extrapFact = hit2Ptr->GetZ()/ hit1Ptr->GetZ();
529 extBendCoor = extrapFact * hit1Ptr->GetBendingCoor();
530 extNonBendCoor = extrapFact * hit1Ptr->GetNonBendingCoor();
a9e2aefa 531 distBend = TMath::Abs(hit2Ptr->GetBendingCoor() - extBendCoor);
532 distNonBend = TMath::Abs(hit2Ptr->GetNonBendingCoor() - extNonBendCoor);
533 if (last2st) {
534 // bending slope
8999d47d 535 if ( hit1Ptr->GetZ() - hit2Ptr->GetZ() != 0.0 ) {
536 bendingSlope = (hit1Ptr->GetBendingCoor() - hit2Ptr->GetBendingCoor()) /
537 (hit1Ptr->GetZ() - hit2Ptr->GetZ());
538 // absolute value of impact parameter
539 impactParam =
540 TMath::Abs(hit1Ptr->GetBendingCoor() - hit1Ptr->GetZ() * bendingSlope);
541 }
542 else {
543 AliWarning("hit1Ptr->GetZ() = hit2Ptr->GetZ(): impactParam set to maxImpactParam");
544 impactParam = maxImpactParam;
545 }
a9e2aefa 546 }
547 // check for distances not too large,
548 // and impact parameter not too big if stations downstream of the dipole.
549 // Conditions "distBend" and "impactParam" correlated for these stations ????
550 if ((distBend < fSegmentMaxDistBending[Station]) &&
551 (distNonBend < fSegmentMaxDistNonBending[Station]) &&
d0bfce8d 552 (!last2st || (impactParam < maxImpactParam)) &&
553 (!last2st || (impactParam > minImpactParam))) {
a9e2aefa 554 // make new segment
555 segment = new ((*fSegmentsPtr[Station])[segmentIndex])
556 AliMUONSegment(hit1Ptr, hit2Ptr);
557 // update "link" to this segment from the hit in the first chamber
558 if (hit1Ptr->GetNSegments() == 0)
559 hit1Ptr->SetIndexOfFirstSegment(segmentIndex);
560 hit1Ptr->SetNSegments(hit1Ptr->GetNSegments() + 1);
b840996b 561 if (AliLog::GetGlobalDebugLevel() > 1) {
a9e2aefa 562 cout << "segmentIndex(0...): " << segmentIndex
563 << " distBend: " << distBend
564 << " distNonBend: " << distNonBend
565 << endl;
566 segment->Dump();
567 cout << "HitForRec in first chamber" << endl;
568 hit1Ptr->Dump();
569 cout << "HitForRec in second chamber" << endl;
570 hit2Ptr->Dump();
571 };
572 // increment index for current segment
573 segmentIndex++;
574 }
575 } //for (Int_t hit2
576 } // for (Int_t hit1...
577 fNSegments[Station] = segmentIndex;
578 // Sorting according to "impact parameter" if station(1..5) 4 or 5,
579 // i.e. Station(0..4) 3 or 4, using the function "Compare".
580 // After this sorting, it is impossible to use
581 // the "fNSegments" and "fIndexOfFirstSegment"
582 // of the HitForRec in the first chamber to explore all segments formed with it.
583 // Is this sorting really needed ????
584 if ((Station == 3) || (Station == 4)) (fSegmentsPtr[Station])->Sort();
b840996b 585 AliDebug(1,Form("Station: %d NSegments: %d ", Station, fNSegments[Station]));
a9e2aefa 586 return;
587}
588
589 //__________________________________________________________________________
29f1b13a 590void AliMUONTrackReconstructor::MakeTracks(void)
a9e2aefa 591{
592 // To make the tracks,
593 // from the list of segments and points in all stations
b840996b 594 AliDebug(1,"Enter MakeTracks");
8429a5e4 595 // The order may be important for the following Reset's
fff097e0 596 //AZ ResetTracks();
cc87ebcd 597 if (fTrackMethod != 1) { //AZ - Kalman filter
83dbc640 598 MakeTrackCandidatesK();
b035a148 599 if (fRecTracksPtr->GetEntriesFast() == 0) return;
83dbc640 600 // Follow tracks in stations(1..) 3, 2 and 1
601 FollowTracksK();
602 // Remove double tracks
603 RemoveDoubleTracksK();
604 // Propagate tracks to the vertex thru absorber
605 GoToVertex();
b035a148 606 // Fill AliMUONTrack data members
607 FillMUONTrack();
d837040f 608 } else {
83dbc640 609 // Look for candidates from at least 3 aligned points in stations(1..) 4 and 5
610 MakeTrackCandidates();
611 // Follow tracks in stations(1..) 3, 2 and 1
612 FollowTracks();
613 // Remove double tracks
614 RemoveDoubleTracks();
b8dc484b 615 UpdateHitForRecAtHit();
52c9bc11 616 }
a9e2aefa 617 return;
618}
619
276c44b7 620 //__________________________________________________________________________
29f1b13a 621void AliMUONTrackReconstructor::ValidateTracksWithTrigger(void)
d837040f 622{
7e6d7e07 623 // Try to match track from tracking system with trigger track
d837040f 624 AliMUONTrack *track;
de2cd600 625 AliMUONTrackParam trackParam;
626 AliMUONTriggerTrack *triggerTrack;
24ab3324 627
24ab3324 628 fMUONData->SetTreeAddress("RL");
629 fMUONData->GetRecTriggerTracks();
de2cd600 630 TClonesArray *recTriggerTracks = fMUONData->RecTriggerTracks();
631
632 Bool_t MatchTrigger;
633 Double_t distSigma[3]={1,1,0.02}; // sigma of distributions (trigger-track) X,Y,slopeY
634 Double_t distTriggerTrack[3];
635 Double_t Chi2MatchTrigger, xTrack, yTrack, ySlopeTrack, dTrigTrackMin2, dTrigTrack2 = 0.;
636
d837040f 637 track = (AliMUONTrack*) fRecTracksPtr->First();
638 while (track) {
de2cd600 639 MatchTrigger = kFALSE;
640 Chi2MatchTrigger = 0.;
641
642 trackParam = *((AliMUONTrackParam*) (track->GetTrackParamAtHit()->Last()));
643 trackParam.ExtrapToZ(AliMUONConstants::DefaultChamberZ(10)); // extrap to 1st trigger chamber
644
645 xTrack = trackParam.GetNonBendingCoor();
646 yTrack = trackParam.GetBendingCoor();
647 ySlopeTrack = trackParam.GetBendingSlope();
648 dTrigTrackMin2 = 999.;
649
650 triggerTrack = (AliMUONTriggerTrack*) recTriggerTracks->First();
651 while(triggerTrack){
652 distTriggerTrack[0] = (triggerTrack->GetX11()-xTrack)/distSigma[0];
653 distTriggerTrack[1] = (triggerTrack->GetY11()-yTrack)/distSigma[1];
654 distTriggerTrack[2] = (TMath::Tan(triggerTrack->GetThetay())-ySlopeTrack)/distSigma[2];
655 dTrigTrack2 = 0.;
656 for (Int_t iVar = 0; iVar < 3; iVar++) dTrigTrack2 += distTriggerTrack[iVar]*distTriggerTrack[iVar];
657 if (dTrigTrack2 < dTrigTrackMin2 && dTrigTrack2 < GetMaxSigma2Distance()) {
658 dTrigTrackMin2 = dTrigTrack2;
659 MatchTrigger = kTRUE;
660 Chi2MatchTrigger = dTrigTrack2/3.; // Normalized Chi2, 3 variables (X,Y,slopeY)
661 }
662 triggerTrack = (AliMUONTriggerTrack*) recTriggerTracks->After(triggerTrack);
663 }
664
665 track->SetMatchTrigger(MatchTrigger);
666 track->SetChi2MatchTrigger(Chi2MatchTrigger);
667
d837040f 668 track = (AliMUONTrack*) fRecTracksPtr->After(track);
e8765288 669 }
24ab3324 670
d837040f 671}
672
673 //__________________________________________________________________________
29f1b13a 674Bool_t AliMUONTrackReconstructor::MakeTriggerTracks(void)
276c44b7 675{
676 // To make the trigger tracks from Local Trigger
b840996b 677 AliDebug(1, "Enter MakeTriggerTracks");
276c44b7 678
679 Int_t nTRentries;
c6eddbb2 680 UChar_t gloTrigPat;
276c44b7 681 TClonesArray *localTrigger;
9131b4fe 682 TClonesArray *globalTrigger;
276c44b7 683 AliMUONLocalTrigger *locTrg;
9131b4fe 684 AliMUONGlobalTrigger *gloTrg;
bc4a7ff4 685
cc9e7528 686 TTree* treeR = fMUONData->TreeR();
5e671e06 687
30178c30 688 nTRentries = Int_t(treeR->GetEntries());
d837040f 689
30178c30 690 treeR->GetEvent(0); // only one entry
d837040f 691
692 if (!(fMUONData->IsTriggerBranchesInTree())) {
8c343c7c 693 AliWarning(Form("Trigger information is not avalaible, nTRentries = %d not equal to 1",nTRentries));
d837040f 694 return kFALSE;
276c44b7 695 }
276c44b7 696
ce3e25a8 697 fMUONData->SetTreeAddress("TC");
52c9bc11 698 fMUONData->GetTrigger();
9131b4fe 699
52c9bc11 700 // global trigger for trigger pattern
9131b4fe 701 gloTrigPat = 0;
52c9bc11 702 globalTrigger = fMUONData->GlobalTrigger();
58ff0bd4 703 gloTrg = (AliMUONGlobalTrigger*)globalTrigger->UncheckedAt(0);
704
705 if (gloTrg)
c6eddbb2 706 gloTrigPat = gloTrg->GetGlobalResponse();
58ff0bd4 707
9131b4fe 708
52c9bc11 709 // local trigger for tracking
710 localTrigger = fMUONData->LocalTrigger();
276c44b7 711 Int_t nlocals = (Int_t) (localTrigger->GetEntries());
06c11448 712
713 Float_t z11 = AliMUONConstants::DefaultChamberZ(10);
714 Float_t z21 = AliMUONConstants::DefaultChamberZ(12);
276c44b7 715
bc4a7ff4 716 Float_t y11 = 0.;
717 Int_t stripX21 = 0;
718 Float_t y21 = 0.;
719 Float_t x11 = 0.;
720
276c44b7 721 for (Int_t i=0; i<nlocals; i++) { // loop on Local Trigger
52c9bc11 722 locTrg = (AliMUONLocalTrigger*)localTrigger->UncheckedAt(i);
bc4a7ff4 723
7fead4bb 724 AliDebug(1, "AliMUONTrackReconstructor::MakeTriggerTrack using NEW trigger \n");
5e671e06 725 AliMUONTriggerCircuitNew* circuit =
726 (AliMUONTriggerCircuitNew*)fTriggerCircuit->At(locTrg->LoCircuit()-1); // -1 !!!
727
7fead4bb 728 y11 = circuit->GetY11Pos(locTrg->LoStripX());
729 stripX21 = locTrg->LoStripX()+locTrg->LoDev()+1;
730 y21 = circuit->GetY21Pos(stripX21);
731 x11 = circuit->GetX11Pos(locTrg->LoStripY());
732
58ff0bd4 733 AliDebug(1, Form(" MakeTriggerTrack %d %d %d %d %d %f %f %f \n",i,locTrg->LoCircuit(),
734 locTrg->LoStripX(),locTrg->LoStripX()+locTrg->LoDev()+1,locTrg->LoStripY(),y11, y21, x11));
7fead4bb 735
52c9bc11 736 Float_t thetax = TMath::ATan2( x11 , z11 );
737 Float_t thetay = TMath::ATan2( (y21-y11) , (z21-z11) );
bc4a7ff4 738
58ff0bd4 739 fTriggerTrack->SetX11(x11);
740 fTriggerTrack->SetY11(y11);
741 fTriggerTrack->SetThetax(thetax);
742 fTriggerTrack->SetThetay(thetay);
743 fTriggerTrack->SetGTPattern(gloTrigPat);
744
745 fMUONData->AddRecTriggerTrack(*fTriggerTrack);
276c44b7 746 } // end of loop on Local Trigger
d837040f 747 return kTRUE;
276c44b7 748}
749
de2cd600 750 //__________________________________________________________________________
751void AliMUONTrackReconstructor::MakeTrackCandidates(void)
752{
753 // To make track candidates
754 // with at least 3 aligned points in stations(1..) 4 and 5
755 // (two Segment's or one Segment and one HitForRec)
756 Int_t begStation, iBegSegment, nbCan1Seg1Hit, nbCan2Seg;
757 AliMUONSegment *begSegment;
758 AliDebug(1,"Enter MakeTrackCandidates");
759 // Loop over stations(1..) 5 and 4 for the beginning segment
760 for (begStation = 4; begStation > 2; begStation--) {
761 // Loop over segments in the beginning station
762 for (iBegSegment = 0; iBegSegment < fNSegments[begStation]; iBegSegment++) {
763 // pointer to segment
764 begSegment = (AliMUONSegment*) ((*fSegmentsPtr[begStation])[iBegSegment]);
765 AliDebug(2,Form("Look for TrackCandidate's with Segment %d in Station(0..) %d", iBegSegment, begStation));
766 // Look for track candidates with two segments,
767 // "begSegment" and all compatible segments in other station.
768 // Only for beginning station(1..) 5
769 // because candidates with 2 segments have to looked for only once.
770 if (begStation == 4)
771 nbCan2Seg = MakeTrackCandidatesWithTwoSegments(begSegment);
772 // Look for track candidates with one segment and one point,
773 // "begSegment" and all compatible HitForRec's in other station.
774 // Only if "begSegment" does not belong already to a track candidate.
775 // Is that a too strong condition ????
776 if (!(begSegment->GetInTrack()))
777 nbCan1Seg1Hit = MakeTrackCandidatesWithOneSegmentAndOnePoint(begSegment);
778 } // for (iBegSegment = 0;...
779 } // for (begStation = 4;...
780 return;
781}
782
a9e2aefa 783 //__________________________________________________________________________
29f1b13a 784Int_t AliMUONTrackReconstructor::MakeTrackCandidatesWithTwoSegments(AliMUONSegment *BegSegment)
a9e2aefa 785{
786 // To make track candidates with two segments in stations(1..) 4 and 5,
787 // the first segment being pointed to by "BegSegment".
788 // Returns the number of such track candidates.
789 Int_t endStation, iEndSegment, nbCan2Seg;
e516b01d 790 AliMUONSegment *endSegment;
791 AliMUONSegment *extrapSegment = NULL;
a9e2aefa 792 AliMUONTrack *recTrack;
793 Double_t mcsFactor;
b840996b 794 AliDebug(1,"Enter MakeTrackCandidatesWithTwoSegments");
a9e2aefa 795 // Station for the end segment
796 endStation = 7 - (BegSegment->GetHitForRec1())->GetChamberNumber() / 2;
797 // multiple scattering factor corresponding to one chamber
798 mcsFactor = 0.0136 /
799 GetBendingMomentumFromImpactParam(BegSegment->GetBendingImpact());
800 mcsFactor = fChamberThicknessInX0 * mcsFactor * mcsFactor;
801 // linear extrapolation to end station
a9e2aefa 802 // number of candidates with 2 segments to 0
803 nbCan2Seg = 0;
804 // Loop over segments in the end station
805 for (iEndSegment = 0; iEndSegment < fNSegments[endStation]; iEndSegment++) {
806 // pointer to segment
807 endSegment = (AliMUONSegment*) ((*fSegmentsPtr[endStation])[iEndSegment]);
808 // test compatibility between current segment and "extrapSegment"
04b5ea16 809 // 4 because 4 quantities in chi2
e516b01d 810 extrapSegment =
811 BegSegment->CreateSegmentFromLinearExtrapToStation(endSegment->GetZ(), mcsFactor);
a9e2aefa 812 if ((endSegment->
813 NormalizedChi2WithSegment(extrapSegment,
814 fMaxSigma2Distance)) <= 4.0) {
815 // both segments compatible:
816 // make track candidate from "begSegment" and "endSegment"
b840996b 817 AliDebug(2,Form("TrackCandidate with Segment %d in Station(0..) %d", iEndSegment, endStation));
a9e2aefa 818 // flag for both segments in one track:
819 // to be done in track constructor ????
820 BegSegment->SetInTrack(kTRUE);
821 endSegment->SetInTrack(kTRUE);
de2cd600 822 recTrack = new ((*fRecTracksPtr)[fNRecTracks]) AliMUONTrack(BegSegment, endSegment);
823 // Set track parameters at vertex from last stations 4 & 5
824 CalcTrackParamAtVertex(recTrack);
a9e2aefa 825 fNRecTracks++;
b840996b 826 if (AliLog::GetGlobalDebugLevel() > 1) recTrack->RecursiveDump();
a9e2aefa 827 // increment number of track candidates with 2 segments
828 nbCan2Seg++;
829 }
ddf8948c 830 delete extrapSegment; // should not delete HitForRec's it points to !!!!
a9e2aefa 831 } // for (iEndSegment = 0;...
a9e2aefa 832 return nbCan2Seg;
833}
834
835 //__________________________________________________________________________
29f1b13a 836Int_t AliMUONTrackReconstructor::MakeTrackCandidatesWithOneSegmentAndOnePoint(AliMUONSegment *BegSegment)
a9e2aefa 837{
838 // To make track candidates with one segment and one point
839 // in stations(1..) 4 and 5,
840 // the segment being pointed to by "BegSegment".
841 Int_t ch, ch1, ch2, endStation, iHit, iHitMax, iHitMin, nbCan1Seg1Hit;
e516b01d 842 AliMUONHitForRec *extrapHitForRec= NULL;
843 AliMUONHitForRec *hit;
a9e2aefa 844 AliMUONTrack *recTrack;
845 Double_t mcsFactor;
b840996b 846 AliDebug(1,"Enter MakeTrackCandidatesWithOneSegmentAndOnePoint");
a9e2aefa 847 // station for the end point
848 endStation = 7 - (BegSegment->GetHitForRec1())->GetChamberNumber() / 2;
849 // multiple scattering factor corresponding to one chamber
850 mcsFactor = 0.0136 /
851 GetBendingMomentumFromImpactParam(BegSegment->GetBendingImpact());
852 mcsFactor = fChamberThicknessInX0 * mcsFactor * mcsFactor;
853 // first and second chambers(0..) in the end station
854 ch1 = 2 * endStation;
855 ch2 = ch1 + 1;
856 // number of candidates to 0
857 nbCan1Seg1Hit = 0;
858 // Loop over chambers of the end station
859 for (ch = ch2; ch >= ch1; ch--) {
a9e2aefa 860 // limits for the hit index in the loop
861 iHitMin = fIndexOfFirstHitForRecPerChamber[ch];
862 iHitMax = iHitMin + fNHitsForRecPerChamber[ch];
863 // Loop over HitForRec's in the chamber
864 for (iHit = iHitMin; iHit < iHitMax; iHit++) {
865 // pointer to HitForRec
866 hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[iHit]);
867 // test compatibility between current HitForRec and "extrapHitForRec"
04b5ea16 868 // 2 because 2 quantities in chi2
e516b01d 869 // linear extrapolation to chamber
870 extrapHitForRec =
871 BegSegment->CreateHitForRecFromLinearExtrapToChamber( hit->GetZ(), mcsFactor);
a9e2aefa 872 if ((hit->
873 NormalizedChi2WithHitForRec(extrapHitForRec,
874 fMaxSigma2Distance)) <= 2.0) {
875 // both HitForRec's compatible:
876 // make track candidate from begSegment and current HitForRec
b840996b 877 AliDebug(2, Form("TrackCandidate with HitForRec %d in Chamber(0..) %d", iHit, ch));
a9e2aefa 878 // flag for beginning segments in one track:
879 // to be done in track constructor ????
880 BegSegment->SetInTrack(kTRUE);
de2cd600 881 recTrack = new ((*fRecTracksPtr)[fNRecTracks]) AliMUONTrack(BegSegment, hit);
882 // Set track parameters at vertex from last stations 4 & 5
883 CalcTrackParamAtVertex(recTrack);
a9e2aefa 884 // the right place to eliminate "double counting" ???? how ????
885 fNRecTracks++;
b840996b 886 if (AliLog::GetGlobalDebugLevel() > 1) recTrack->RecursiveDump();
a9e2aefa 887 // increment number of track candidates
888 nbCan1Seg1Hit++;
889 }
ddf8948c 890 delete extrapHitForRec;
a9e2aefa 891 } // for (iHit = iHitMin;...
a9e2aefa 892 } // for (ch = ch2;...
893 return nbCan1Seg1Hit;
894}
895
896 //__________________________________________________________________________
de2cd600 897void AliMUONTrackReconstructor::CalcTrackParamAtVertex(AliMUONTrack *Track)
a9e2aefa 898{
de2cd600 899 // Set track parameters at vertex.
900 // TrackHit's are assumed to be only in stations(1..) 4 and 5,
901 // and sorted according to increasing Z..
902 // Parameters are calculated from information in HitForRec's
903 // of first and last TrackHit's.
904 AliMUONTrackParam *trackParamVertex = Track->GetTrackParamAtVertex(); // pointer to track parameters at vertex
905 // Pointer to HitForRec attached to first TrackParamAtHit
906 AliMUONHitForRec *firstHit = ((AliMUONTrackParam*) (Track->GetTrackParamAtHit()->First()))->GetHitForRecPtr();
907 // Pointer to HitForRec attached to last TrackParamAtHit
908 AliMUONHitForRec *lastHit = ((AliMUONTrackParam*) (Track->GetTrackParamAtHit()->Last()))->GetHitForRecPtr();
909 // Z difference between first and last hits
910 Double_t deltaZ = firstHit->GetZ() - lastHit->GetZ();
911 // bending slope in stations(1..) 4 and 5
912 Double_t bendingSlope = (firstHit->GetBendingCoor() - lastHit->GetBendingCoor()) / deltaZ;
913 trackParamVertex->SetBendingSlope(bendingSlope);
914 // impact parameter
915 Double_t impactParam = firstHit->GetBendingCoor() - bendingSlope * firstHit->GetZ();
916 // signed bending momentum
917 trackParamVertex->SetInverseBendingMomentum(1.0 / GetBendingMomentumFromImpactParam(impactParam));
918 // bending slope at vertex
919 trackParamVertex->SetBendingSlope(bendingSlope + impactParam / GetSimpleBPosition());
920 // non bending slope
921 trackParamVertex->SetNonBendingSlope((firstHit->GetNonBendingCoor() - lastHit->GetNonBendingCoor()) / deltaZ);
922 // vertex coordinates at (0,0,0)
923 trackParamVertex->SetZ(0.0);
924 trackParamVertex->SetBendingCoor(0.0);
925 trackParamVertex->SetNonBendingCoor(0.0);
a9e2aefa 926}
927
928 //__________________________________________________________________________
29f1b13a 929void AliMUONTrackReconstructor::FollowTracks(void)
a9e2aefa 930{
931 // Follow tracks in stations(1..) 3, 2 and 1
04b5ea16 932 // too long: should be made more modular !!!!
e516b01d 933 AliMUONHitForRec *bestHit, *extrapHit, *hit;
934 AliMUONSegment *bestSegment, *extrapSegment, *segment;
04b5ea16 935 AliMUONTrack *track, *nextTrack;
936 AliMUONTrackParam *trackParam1, trackParam[2], trackParamVertex;
ecfa008b 937 // -1 to avoid compilation warnings
938 Int_t ch = -1, chInStation, chBestHit = -1, iHit, iSegment, station, trackIndex;
04b5ea16 939 Double_t bestChi2, chi2, dZ1, dZ2, dZ3, maxSigma2Distance, mcsFactor;
d0bfce8d 940 Double_t bendingMomentum, chi2Norm = 0.;
cc87ebcd 941
1a38e749 942
04b5ea16 943 // local maxSigma2Distance, for easy increase in testing
944 maxSigma2Distance = fMaxSigma2Distance;
b840996b 945 AliDebug(2,"Enter FollowTracks");
a9e2aefa 946 // Loop over track candidates
04b5ea16 947 track = (AliMUONTrack*) fRecTracksPtr->First();
948 trackIndex = -1;
949 while (track) {
04b5ea16 950 trackIndex++;
951 nextTrack = (AliMUONTrack*) fRecTracksPtr->After(track); // prepare next track
b840996b 952 AliDebug(2,Form("FollowTracks: track candidate(0..): %d", trackIndex));
de2cd600 953 // Fit track candidate from parameters at vertex
954 // -> with 3 parameters (X_vertex and Y_vertex are fixed)
955 // without multiple Coulomb scattering
956 Fit(track,0,0);
b840996b 957 if (AliLog::GetGlobalDebugLevel()> 2) {
a9e2aefa 958 cout << "FollowTracks: track candidate(0..): " << trackIndex
956019b6 959 << " after fit in stations(0..) 3 and 4" << endl;
a9e2aefa 960 track->RecursiveDump();
961 }
962 // Loop over stations(1..) 3, 2 and 1
04b5ea16 963 // something SPECIAL for stations 2 and 1 for majority 3 coincidence ????
964 // otherwise: majority coincidence 2 !!!!
a9e2aefa 965 for (station = 2; station >= 0; station--) {
966 // Track parameters at first track hit (smallest Z)
de2cd600 967 trackParam1 = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
a9e2aefa 968 // extrapolation to station
969 trackParam1->ExtrapToStation(station, trackParam);
79e1e601 970 extrapSegment = new AliMUONSegment(); // empty segment
a9e2aefa 971 // multiple scattering factor corresponding to one chamber
972 // and momentum in bending plane (not total)
973 mcsFactor = 0.0136 * trackParam1->GetInverseBendingMomentum();
974 mcsFactor = fChamberThicknessInX0 * mcsFactor * mcsFactor;
975 // Z difference from previous station
f93b9bd8 976 dZ1 = AliMUONConstants::DefaultChamberZ(2 * station) -
977 AliMUONConstants::DefaultChamberZ(2 * station + 2);
a9e2aefa 978 // Z difference between the two previous stations
f93b9bd8 979 dZ2 = AliMUONConstants::DefaultChamberZ(2 * station + 2) -
980 AliMUONConstants::DefaultChamberZ(2 * station + 4);
04b5ea16 981 // Z difference between the two chambers in the previous station
f93b9bd8 982 dZ3 = AliMUONConstants::DefaultChamberZ(2 * station) -
983 AliMUONConstants::DefaultChamberZ(2 * station + 1);
04b5ea16 984 extrapSegment->SetBendingCoorReso2(fBendingResolution * fBendingResolution);
de2cd600 985 extrapSegment->SetNonBendingCoorReso2(fNonBendingResolution * fNonBendingResolution);
986 extrapSegment->UpdateFromStationTrackParam(trackParam, mcsFactor, dZ1, dZ2, dZ3, station,
987 trackParam1->GetInverseBendingMomentum());
a9e2aefa 988 bestChi2 = 5.0;
989 bestSegment = NULL;
b840996b 990 if (AliLog::GetGlobalDebugLevel() > 2) {
a9e2aefa 991 cout << "FollowTracks: track candidate(0..): " << trackIndex
992 << " Look for segment in station(0..): " << station << endl;
993 }
1a38e749 994
a9e2aefa 995 // Loop over segments in station
996 for (iSegment = 0; iSegment < fNSegments[station]; iSegment++) {
997 // Look for best compatible Segment in station
998 // should consider all possibilities ????
999 // multiple scattering ????
1000 // separation in 2 functions: Segment and HitForRec ????
1001 segment = (AliMUONSegment*) ((*fSegmentsPtr[station])[iSegment]);
d0bfce8d 1002 // correction of corrected segment (fBendingCoor and fNonBendingCoor)
1003 // according to real Z value of "segment" and slopes of "extrapSegment"
de2cd600 1004 trackParam[0].ExtrapToZ(segment->GetZ());
1005 trackParam[1].ExtrapToZ(segment->GetZ()); // now same as trackParam[0] !?!?!?!?!?!
e516b01d 1006 extrapSegment->SetBendingCoor((&(trackParam[0]))->GetBendingCoor());
1007 extrapSegment->SetNonBendingCoor((&(trackParam[0]))->GetNonBendingCoor());
1008 extrapSegment->SetBendingSlope((&(trackParam[0]))->GetBendingSlope());
1009 extrapSegment->SetNonBendingSlope((&(trackParam[0]))->GetNonBendingSlope());
de2cd600 1010 chi2 = segment->NormalizedChi2WithSegment(extrapSegment, maxSigma2Distance);
a9e2aefa 1011 if (chi2 < bestChi2) {
1012 // update best Chi2 and Segment if better found
1013 bestSegment = segment;
1014 bestChi2 = chi2;
1015 }
1016 }
1017 if (bestSegment) {
1018 // best segment found: add it to track candidate
de2cd600 1019 trackParam[0].ExtrapToZ(bestSegment->GetZ());
1020 track->AddTrackParamAtHit(&(trackParam[0]),bestSegment->GetHitForRec1());
1021 trackParam[1].ExtrapToZ(bestSegment->GetZ()); // now same as trackParam[0] !?!?!?!?!?!
1022 track->AddTrackParamAtHit(&(trackParam[1]),bestSegment->GetHitForRec2());
b840996b 1023 AliDebug(3, Form("FollowTracks: track candidate(0..): %d Added segment in station(0..): %d", trackIndex, station));
1024 if (AliLog::GetGlobalDebugLevel()>2) track->RecursiveDump();
de2cd600 1025 } else {
a9e2aefa 1026 // No best segment found:
1027 // Look for best compatible HitForRec in station:
1028 // should consider all possibilities ????
1029 // multiple scattering ???? do about like for extrapSegment !!!!
79e1e601 1030 extrapHit = new AliMUONHitForRec(); // empty hit
a9e2aefa 1031 bestChi2 = 3.0;
1032 bestHit = NULL;
b840996b 1033 AliDebug(3, Form("FollowTracks: track candidate(0..): %d Segment not found, look for hit in station(0..): %d ",
1034 trackIndex, station));
1035
a9e2aefa 1036 // Loop over chambers of the station
d82671a0 1037 for (chInStation = 0; chInStation < 2; chInStation++) {
956019b6 1038 ch = 2 * station + chInStation;
de2cd600 1039 for (iHit = fIndexOfFirstHitForRecPerChamber[ch]; iHit < fIndexOfFirstHitForRecPerChamber[ch]+fNHitsForRecPerChamber[ch]; iHit++) {
a9e2aefa 1040 hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[iHit]);
e516b01d 1041 // coordinates of extrapolated hit
de2cd600 1042 trackParam[chInStation].ExtrapToZ(hit->GetZ());
1043 extrapHit->SetBendingCoor((&(trackParam[chInStation]))->GetBendingCoor());
1044 extrapHit->SetNonBendingCoor((&(trackParam[chInStation]))->GetNonBendingCoor());
e516b01d 1045 // resolutions from "extrapSegment"
1046 extrapHit->SetBendingReso2(extrapSegment->GetBendingCoorReso2());
1047 extrapHit->SetNonBendingReso2(extrapSegment->GetNonBendingCoorReso2());
1048 // Loop over hits in the chamber
a9e2aefa 1049 // condition for hit not already in segment ????
1050 chi2 = hit->NormalizedChi2WithHitForRec(extrapHit, maxSigma2Distance);
1051 if (chi2 < bestChi2) {
1052 // update best Chi2 and HitForRec if better found
1053 bestHit = hit;
1054 bestChi2 = chi2;
d82671a0 1055 chBestHit = chInStation;
a9e2aefa 1056 }
1057 }
1058 }
1059 if (bestHit) {
1060 // best hit found: add it to track candidate
de2cd600 1061 trackParam[chBestHit].ExtrapToZ(bestHit->GetZ());
1062 track->AddTrackParamAtHit(&(trackParam[chBestHit]),bestHit);
b840996b 1063 if (AliLog::GetGlobalDebugLevel() > 2) {
a9e2aefa 1064 cout << "FollowTracks: track candidate(0..): " << trackIndex
1065 << " Added hit in station(0..): " << station << endl;
1066 track->RecursiveDump();
1067 }
de2cd600 1068 } else {
8429a5e4 1069 // Remove current track candidate
1070 // and corresponding TrackHit's, ...
de2cd600 1071 fRecTracksPtr->Remove(track);
1072 fNRecTracks--;
04b5ea16 1073 delete extrapSegment;
d0bfce8d 1074 delete extrapHit;
a9e2aefa 1075 break; // stop the search for this candidate:
1076 // exit from the loop over station
1077 }
d0bfce8d 1078 delete extrapHit;
a9e2aefa 1079 }
04b5ea16 1080 delete extrapSegment;
de2cd600 1081 // Sort TrackParamAtHit according to increasing Z
1082 track->GetTrackParamAtHit()->Sort();
a9e2aefa 1083 // Update track parameters at first track hit (smallest Z)
de2cd600 1084 trackParam1 = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
d0bfce8d 1085 bendingMomentum = 0.;
1086 if (TMath::Abs(trackParam1->GetInverseBendingMomentum()) > 0.)
1087 bendingMomentum = TMath::Abs(1/(trackParam1->GetInverseBendingMomentum()));
1088 // Track removed if bendingMomentum not in window [min, max]
1089 if ((bendingMomentum < fMinBendingMomentum) || (bendingMomentum > fMaxBendingMomentum)) {
de2cd600 1090 fRecTracksPtr->Remove(track);
1091 fNRecTracks--;
d0bfce8d 1092 break; // stop the search for this candidate:
1093 // exit from the loop over station
1094 }
de2cd600 1095 // Track fit from parameters at first hit
1096 // -> with 5 parameters (momentum and position)
04b5ea16 1097 // with multiple Coulomb scattering if all stations
de2cd600 1098 if (station == 0) Fit(track,1,1);
956019b6 1099 // without multiple Coulomb scattering if not all stations
de2cd600 1100 else Fit(track,1,0);
d0bfce8d 1101 Double_t numberOfDegFree = (2.0 * track->GetNTrackHits() - 5);
1102 if (numberOfDegFree > 0) {
1103 chi2Norm = track->GetFitFMin() / numberOfDegFree;
1104 } else {
1105 chi2Norm = 1.e10;
1106 }
1107 // Track removed if normalized chi2 too high
1108 if (chi2Norm > fMaxChi2) {
de2cd600 1109 fRecTracksPtr->Remove(track);
1110 fNRecTracks--;
d0bfce8d 1111 break; // stop the search for this candidate:
1112 // exit from the loop over station
1113 }
b840996b 1114 if (AliLog::GetGlobalDebugLevel() > 2) {
a9e2aefa 1115 cout << "FollowTracks: track candidate(0..): " << trackIndex
1116 << " after fit from station(0..): " << station << " to 4" << endl;
1117 track->RecursiveDump();
1118 }
04b5ea16 1119 // Track extrapolation to the vertex through the absorber (Branson)
956019b6 1120 // after going through the first station
04b5ea16 1121 if (station == 0) {
de2cd600 1122 trackParamVertex = *((AliMUONTrackParam*) (track->GetTrackParamAtHit()->First()));
889a0215 1123 (&trackParamVertex)->ExtrapToVertex(0.,0.,0.);
04b5ea16 1124 track->SetTrackParamAtVertex(&trackParamVertex);
b840996b 1125 if (AliLog::GetGlobalDebugLevel() > 0) {
6ae236ee 1126 cout << "FollowTracks: track candidate(0..): " << trackIndex
1127 << " after extrapolation to vertex" << endl;
1128 track->RecursiveDump();
1129 }
04b5ea16 1130 }
a9e2aefa 1131 } // for (station = 2;...
04b5ea16 1132 // go really to next track
1133 track = nextTrack;
1134 } // while (track)
de2cd600 1135 // Compression of track array (necessary after Remove)
04b5ea16 1136 fRecTracksPtr->Compress();
1137 return;
1138}
1139
de2cd600 1140 //__________________________________________________________________________
1141void AliMUONTrackReconstructor::Fit(AliMUONTrack *Track, Int_t FitStart, Int_t FitMCS)
1142{
1143 // Fit the track "Track",
1144 // with or without multiple Coulomb scattering according to "FitMCS",
1145 // starting, according to "FitStart",
1146 // with track parameters at vertex or at the first TrackHit.
1147
1148 if ((FitStart != 0) && (FitStart != 1)) {
1149 cout << "ERROR in AliMUONTrackReconstructor::Fit(...)" << endl;
1150 cout << "FitStart = " << FitStart << " is neither 0 nor 1" << endl;
1151 exit(0);
1152 }
1153 if ((FitMCS != 0) && (FitMCS != 1)) {
1154 cout << "ERROR in AliMUONTrackReconstructor::Fit(...)" << endl;
1155 cout << "FitMCS = " << FitMCS << " is neither 0 nor 1" << endl;
1156 exit(0);
1157 }
1158
1159 Double_t arg[1], benC, errorParam, invBenP, lower, nonBenC, upper, x, y;
1160 char parName[50];
1161 AliMUONTrackParam *trackParam;
1162 // Check if Minuit is initialized...
1163 fgFitter = TVirtualFitter::Fitter(Track,5);
1164 fgFitter->Clear(); // necessary ???? probably yes
1165 // how to reset the printout number at every fit ????
1166 // is there any risk to leave it like that ????
1167 // how to go faster ???? choice of Minuit parameters like EDM ????
1168 // choice of function to be minimized according to fFitMCS
1169 if (FitMCS == 0) fgFitter->SetFCN(TrackChi2);
1170 else fgFitter->SetFCN(TrackChi2MCS);
1171 // Switch off printout
1172 arg[0] = -1;
1173 fgFitter->ExecuteCommand("SET PRINT", arg, 1); // More printing !!!!
1174 // No warnings
1175 fgFitter->ExecuteCommand("SET NOW", arg, 0);
1176 // Parameters according to "fFitStart"
1177 // (should be a function to be used at every place where needed ????)
1178 if (FitStart == 0) trackParam = Track->GetTrackParamAtVertex();
1179 else trackParam = (AliMUONTrackParam*) (Track->GetTrackParamAtHit()->First());
1180 // set first 3 Minuit parameters
1181 // could be tried with no limits for the search (min=max=0) ????
1182 fgFitter->SetParameter(0, "InvBenP",
1183 trackParam->GetInverseBendingMomentum(),
1184 0.003, -0.4, 0.4);
1185 fgFitter->SetParameter(1, "BenS",
1186 trackParam->GetBendingSlope(),
1187 0.001, -0.5, 0.5);
1188 fgFitter->SetParameter(2, "NonBenS",
1189 trackParam->GetNonBendingSlope(),
1190 0.001, -0.5, 0.5);
1191 if (FitStart == 1) {
1192 // set last 2 Minuit parameters when we start from first track hit
1193 // mandatory limits in Bending to avoid NaN values of parameters
1194 fgFitter->SetParameter(3, "X",
1195 trackParam->GetNonBendingCoor(),
1196 0.03, -500.0, 500.0);
1197 // mandatory limits in non Bending to avoid NaN values of parameters
1198 fgFitter->SetParameter(4, "Y",
1199 trackParam->GetBendingCoor(),
1200 0.10, -500.0, 500.0);
1201 }
1202 // search without gradient calculation in the function
1203 fgFitter->ExecuteCommand("SET NOGRADIENT", arg, 0);
1204 // minimization
1205 fgFitter->ExecuteCommand("MINIMIZE", arg, 0);
1206 // exit from Minuit
1207 // fgFitter->ExecuteCommand("EXIT", arg, 0); // necessary ????
1208 // get results into "invBenP", "benC", "nonBenC" ("x", "y")
1209 fgFitter->GetParameter(0, parName, invBenP, errorParam, lower, upper);
1210 trackParam->SetInverseBendingMomentum(invBenP);
1211 fgFitter->GetParameter(1, parName, benC, errorParam, lower, upper);
1212 trackParam->SetBendingSlope(benC);
1213 fgFitter->GetParameter(2, parName, nonBenC, errorParam, lower, upper);
1214 trackParam->SetNonBendingSlope(nonBenC);
1215 if (FitStart == 1) {
1216 fgFitter->GetParameter(3, parName, x, errorParam, lower, upper);
1217 trackParam->SetNonBendingCoor(x);
1218 fgFitter->GetParameter(4, parName, y, errorParam, lower, upper);
1219 trackParam->SetBendingCoor(y);
1220 }
1221 // global result of the fit
1222 Double_t fedm, errdef, FitFMin;
1223 Int_t npari, nparx;
1224 fgFitter->GetStats(FitFMin, fedm, errdef, npari, nparx);
1225 Track->SetFitFMin(FitFMin);
1226}
1227
1228 //__________________________________________________________________________
1229void TrackChi2(Int_t &NParam, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/)
1230{
1231 // Return the "Chi2" to be minimized with Minuit for track fitting,
1232 // with "NParam" parameters
1233 // and their current values in array pointed to by "Param".
1234 // Assumes that the track hits are sorted according to increasing Z.
1235 // Track parameters at each TrackHit are updated accordingly.
1236 // Multiple Coulomb scattering is not taken into account
1237 AliMUONTrack *trackBeingFitted;
1238 AliMUONTrackParam param1;
1239 AliMUONTrackParam* TrackParamAtHit;
1240 AliMUONHitForRec* HitForRec;
1241 Chi2 = 0.0; // initialize Chi2
1242 // copy of track parameters to be fitted
1243 trackBeingFitted = (AliMUONTrack*) AliMUONTrackReconstructor::Fitter()->GetObjectFit();
1244 // 3 parameters means fit track candidate from parameters at vertex (X_vertex and Y_vertex are fixed)
1245 if (NParam == 3) param1 = *(trackBeingFitted->GetTrackParamAtVertex());
1246 else param1 = *((AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First()));
1247 // Minuit parameters to be fitted into this copy
1248 param1.SetInverseBendingMomentum(Param[0]);
1249 param1.SetBendingSlope(Param[1]);
1250 param1.SetNonBendingSlope(Param[2]);
1251 if (NParam == 5) {
1252 param1.SetNonBendingCoor(Param[3]);
1253 param1.SetBendingCoor(Param[4]);
1254 }
1255 // Follow track through all planes of track hits
1256 TrackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First());
1257 while (TrackParamAtHit) {
1258 HitForRec = TrackParamAtHit->GetHitForRecPtr();
1259 // extrapolation to the plane of the HitForRec attached to the current TrackParamAtHit
1260 param1.ExtrapToZ(HitForRec->GetZ());
1261 // update track parameters of the current hit
1262 TrackParamAtHit->SetTrackParam(param1);
1263 // Increment Chi2
1264 // done hit per hit, with hit resolution,
1265 // and not with point and angle like in "reco_muon.F" !!!!
1266 // Needs to add multiple scattering contribution ????
1267 Double_t dX = HitForRec->GetNonBendingCoor() - param1.GetNonBendingCoor();
1268 Double_t dY = HitForRec->GetBendingCoor() - param1.GetBendingCoor();
1269 Chi2 = Chi2 + dX * dX / HitForRec->GetNonBendingReso2() + dY * dY / HitForRec->GetBendingReso2();
1270 TrackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->After(TrackParamAtHit));
1271 }
1272}
1273
1274 //__________________________________________________________________________
1275void TrackChi2MCS(Int_t &NParam, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/)
1276{
1277 // Return the "Chi2" to be minimized with Minuit for track fitting,
1278 // with "NParam" parameters
1279 // and their current values in array pointed to by "Param".
1280 // Assumes that the track hits are sorted according to increasing Z.
1281 // Track parameters at each TrackHit are updated accordingly.
1282 // Multiple Coulomb scattering is taken into account with covariance matrix.
1283 AliMUONTrack *trackBeingFitted;
1284 AliMUONTrackParam param1;
1285 AliMUONTrackParam* TrackParamAtHit;
1286 AliMUONHitForRec* HitForRec;
1287 Chi2 = 0.0; // initialize Chi2
1288 // copy of track parameters to be fitted
1289 trackBeingFitted = (AliMUONTrack*) AliMUONTrackReconstructor::Fitter()->GetObjectFit();
1290 // 3 parameters means fit track candidate from parameters at vertex (X_vertex and Y_vertex are fixed)
1291 if (NParam == 3) param1 = *(trackBeingFitted->GetTrackParamAtVertex());
1292 else param1 = *((AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First()));
1293 // Minuit parameters to be fitted into this copy
1294 param1.SetInverseBendingMomentum(Param[0]);
1295 param1.SetBendingSlope(Param[1]);
1296 param1.SetNonBendingSlope(Param[2]);
1297 if (NParam == 5) {
1298 param1.SetNonBendingCoor(Param[3]);
1299 param1.SetBendingCoor(Param[4]);
1300 }
1301
1302 Int_t chCurrent, chPrev = 0, hitNumber, hitNumber1, hitNumber2, hitNumber3;
1303 Double_t z1, z2, z3;
1304 AliMUONTrackParam *TrackParamAtHit1, *TrackParamAtHit2, *TrackParamAtHit3;
1305 AliMUONHitForRec *HitForRec1, *HitForRec2;
1306 Double_t hbc1, hbc2, pbc1, pbc2;
1307 Double_t hnbc1, hnbc2, pnbc1, pnbc2;
1308 Int_t numberOfHit = trackBeingFitted->GetNTrackHits();
1309 TMatrixD *covBending = new TMatrixD(numberOfHit, numberOfHit);
1310 TMatrixD *covNonBending = new TMatrixD(numberOfHit, numberOfHit);
1311 Double_t *msa2 = new Double_t[numberOfHit];
1312
1313 // Predicted coordinates and multiple scattering angles are first calculated
1314 for (hitNumber = 0; hitNumber < numberOfHit; hitNumber++) {
1315 TrackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber));
1316 HitForRec = TrackParamAtHit->GetHitForRecPtr();
1317 // extrapolation to the plane of the HitForRec attached to the current TrackParamAtHit
1318 param1.ExtrapToZ(HitForRec->GetZ());
1319 // update track parameters of the current hit
1320 TrackParamAtHit->SetTrackParam(param1);
1321 // square of multiple scattering angle at current hit, with one chamber
1322 msa2[hitNumber] = MultipleScatteringAngle2(&param1);
1323 // correction for eventual missing hits or multiple hits in a chamber,
1324 // according to the number of chambers
1325 // between the current hit and the previous one
1326 chCurrent = HitForRec->GetChamberNumber();
1327 if (hitNumber > 0) msa2[hitNumber] = msa2[hitNumber] * (chCurrent - chPrev);
1328 chPrev = chCurrent;
1329 }
1330
1331 // Calculates the covariance matrix
1332 for (hitNumber1 = 0; hitNumber1 < numberOfHit; hitNumber1++) {
1333 TrackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
1334 HitForRec1 = TrackParamAtHit1->GetHitForRecPtr();
1335 z1 = HitForRec1->GetZ();
1336 for (hitNumber2 = hitNumber1; hitNumber2 < numberOfHit; hitNumber2++) {
1337 TrackParamAtHit2 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber2));
1338 z2 = TrackParamAtHit2->GetHitForRecPtr()->GetZ();
1339 // initialization to 0 (diagonal plus upper triangular part)
1340 (*covBending)(hitNumber2, hitNumber1) = 0.0;
1341 // contribution from multiple scattering in bending plane:
1342 // loop over upstream hits
1343 for (hitNumber3 = 0; hitNumber3 < hitNumber1; hitNumber3++) {
1344 TrackParamAtHit3 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber3));
1345 z3 = TrackParamAtHit3->GetHitForRecPtr()->GetZ();
1346 (*covBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1) + ((z1 - z3) * (z2 - z3) * msa2[hitNumber3]);
1347 }
1348 // equal contribution from multiple scattering in non bending plane
1349 (*covNonBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1);
1350 if (hitNumber1 == hitNumber2) {
1351 // Diagonal elements: add contribution from position measurements
1352 // in bending plane
1353 (*covBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1) + HitForRec1->GetBendingReso2();
1354 // and in non bending plane
1355 (*covNonBending)(hitNumber2, hitNumber1) = (*covNonBending)(hitNumber2, hitNumber1) + HitForRec1->GetNonBendingReso2();
1356 } else {
1357 // Non diagonal elements: symmetrization
1358 // for bending plane
1359 (*covBending)(hitNumber1, hitNumber2) = (*covBending)(hitNumber2, hitNumber1);
1360 // and non bending plane
1361 (*covNonBending)(hitNumber1, hitNumber2) = (*covNonBending)(hitNumber2, hitNumber1);
1362 }
1363 } // for (hitNumber2 = hitNumber1;...
1364 } // for (hitNumber1 = 0;...
1365
1366 // Inversion of covariance matrices
1367 // with "mnvertLocal", local "mnvert" function of Minuit.
1368 // One cannot use directly "mnvert" since "TVirtualFitter" does not know it.
1369 // One will have to replace this local function by the right inversion function
1370 // from a specialized Root package for symmetric positive definite matrices,
1371 // when available!!!!
1372 Int_t ifailBending;
1373 mnvertLocal(&((*covBending)(0,0)), numberOfHit, numberOfHit, numberOfHit, ifailBending);
1374 Int_t ifailNonBending;
1375 mnvertLocal(&((*covNonBending)(0,0)), numberOfHit, numberOfHit, numberOfHit, ifailNonBending);
1376
1377 // It would be worth trying to calculate the inverse of the covariance matrix
1378 // only once per fit, since it cannot change much in principle,
1379 // and it would save a lot of computing time !!!!
1380
1381 // Calculates Chi2
1382 if ((ifailBending == 0) && (ifailNonBending == 0)) {
1383 // with Multiple Scattering if inversion correct
1384 for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) {
1385 TrackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
1386 HitForRec1 = TrackParamAtHit1->GetHitForRecPtr();
1387 hbc1 = HitForRec1->GetBendingCoor();
1388 pbc1 = TrackParamAtHit1->GetBendingCoor();
1389 hnbc1 = HitForRec1->GetNonBendingCoor();
1390 pnbc1 = TrackParamAtHit1->GetNonBendingCoor();
1391 for (hitNumber2 = 0; hitNumber2 < numberOfHit; hitNumber2++) {
1392 TrackParamAtHit2 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber2));
1393 HitForRec2 = TrackParamAtHit2->GetHitForRecPtr();
1394 hbc2 = HitForRec2->GetBendingCoor();
1395 pbc2 = TrackParamAtHit2->GetBendingCoor();
1396 hnbc2 = HitForRec2->GetNonBendingCoor();
1397 pnbc2 = TrackParamAtHit2->GetNonBendingCoor();
1398 Chi2 += ((*covBending)(hitNumber2, hitNumber1) * (hbc1 - pbc1) * (hbc2 - pbc2)) +
1399 ((*covNonBending)(hitNumber2, hitNumber1) * (hnbc1 - pnbc1) * (hnbc2 - pnbc2));
1400 }
1401 }
1402 } else {
1403 // without Multiple Scattering if inversion impossible
1404 for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) {
1405 TrackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
1406 HitForRec1 = TrackParamAtHit1->GetHitForRecPtr();
1407 hbc1 = HitForRec1->GetBendingCoor();
1408 pbc1 = TrackParamAtHit1->GetBendingCoor();
1409 hnbc1 = HitForRec1->GetNonBendingCoor();
1410 pnbc1 = TrackParamAtHit1->GetNonBendingCoor();
1411 Chi2 += ((hbc1 - pbc1) * (hbc1 - pbc1) / HitForRec1->GetBendingReso2()) +
1412 ((hnbc1 - pnbc1) * (hnbc1 - pnbc1) / HitForRec1->GetNonBendingReso2());
1413 }
1414 }
1415
1416 delete covBending;
1417 delete covNonBending;
1418 delete [] msa2;
1419}
1420
1421Double_t MultipleScatteringAngle2(AliMUONTrackParam *param)
1422{
1423 // Returns square of multiple Coulomb scattering angle
1424 // from TrackParamAtHit pointed to by "param"
1425 Double_t slopeBending, slopeNonBending, radiationLength, inverseBendingMomentum2, inverseTotalMomentum2;
1426 Double_t varMultipleScatteringAngle;
1427 // Better implementation in AliMUONTrack class ????
1428 slopeBending = param->GetBendingSlope();
1429 slopeNonBending = param->GetNonBendingSlope();
1430 // thickness in radiation length for the current track,
1431 // taking local angle into account
1432 radiationLength = AliMUONConstants::DefaultChamberThicknessInX0() *
1433 TMath::Sqrt(1.0 + slopeBending*slopeBending + slopeNonBending*slopeNonBending);
1434 inverseBendingMomentum2 = param->GetInverseBendingMomentum() * param->GetInverseBendingMomentum();
1435 inverseTotalMomentum2 = inverseBendingMomentum2 * (1.0 + slopeBending * slopeBending) /
1436 (1.0 + slopeBending *slopeBending + slopeNonBending * slopeNonBending);
1437 varMultipleScatteringAngle = 0.0136 * (1.0 + 0.038 * TMath::Log(radiationLength));
1438 // The velocity is assumed to be 1 !!!!
1439 varMultipleScatteringAngle = inverseTotalMomentum2 * radiationLength * varMultipleScatteringAngle * varMultipleScatteringAngle;
1440 return varMultipleScatteringAngle;
1441}
1442
1443//______________________________________________________________________________
1444 void mnvertLocal(Double_t *a, Int_t l, Int_t, Int_t n, Int_t &ifail)
1445{
1446//*-*-*-*-*-*-*-*-*-*-*-*Inverts a symmetric matrix*-*-*-*-*-*-*-*-*-*-*-*-*
1447//*-* ==========================
1448//*-* inverts a symmetric matrix. matrix is first scaled to
1449//*-* have all ones on the diagonal (equivalent to change of units)
1450//*-* but no pivoting is done since matrix is positive-definite.
1451//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
1452
1453 // taken from TMinuit package of Root (l>=n)
1454 // fVERTs, fVERTq and fVERTpp changed to localVERTs, localVERTq and localVERTpp
1455 // Double_t localVERTs[n], localVERTq[n], localVERTpp[n];
1456 Double_t * localVERTs = new Double_t[n];
1457 Double_t * localVERTq = new Double_t[n];
1458 Double_t * localVERTpp = new Double_t[n];
1459 // fMaxint changed to localMaxint
1460 Int_t localMaxint = n;
1461
1462 /* System generated locals */
1463 Int_t aOffset;
1464
1465 /* Local variables */
1466 Double_t si;
1467 Int_t i, j, k, kp1, km1;
1468
1469 /* Parameter adjustments */
1470 aOffset = l + 1;
1471 a -= aOffset;
1472
1473 /* Function Body */
1474 ifail = 0;
1475 if (n < 1) goto L100;
1476 if (n > localMaxint) goto L100;
1477//*-*- scale matrix by sqrt of diag elements
1478 for (i = 1; i <= n; ++i) {
1479 si = a[i + i*l];
1480 if (si <= 0) goto L100;
1481 localVERTs[i-1] = 1 / TMath::Sqrt(si);
1482 }
1483 for (i = 1; i <= n; ++i) {
1484 for (j = 1; j <= n; ++j) {
1485 a[i + j*l] = a[i + j*l]*localVERTs[i-1]*localVERTs[j-1];
1486 }
1487 }
1488//*-*- . . . start main loop . . . .
1489 for (i = 1; i <= n; ++i) {
1490 k = i;
1491//*-*- preparation for elimination step1
1492 if (a[k + k*l] != 0) localVERTq[k-1] = 1 / a[k + k*l];
1493 else goto L100;
1494 localVERTpp[k-1] = 1;
1495 a[k + k*l] = 0;
1496 kp1 = k + 1;
1497 km1 = k - 1;
1498 if (km1 < 0) goto L100;
1499 else if (km1 == 0) goto L50;
1500 else goto L40;
1501L40:
1502 for (j = 1; j <= km1; ++j) {
1503 localVERTpp[j-1] = a[j + k*l];
1504 localVERTq[j-1] = a[j + k*l]*localVERTq[k-1];
1505 a[j + k*l] = 0;
1506 }
1507L50:
1508 if (k - n < 0) goto L51;
1509 else if (k - n == 0) goto L60;
1510 else goto L100;
1511L51:
1512 for (j = kp1; j <= n; ++j) {
1513 localVERTpp[j-1] = a[k + j*l];
1514 localVERTq[j-1] = -a[k + j*l]*localVERTq[k-1];
1515 a[k + j*l] = 0;
1516 }
1517//*-*- elimination proper
1518L60:
1519 for (j = 1; j <= n; ++j) {
1520 for (k = j; k <= n; ++k) { a[j + k*l] += localVERTpp[j-1]*localVERTq[k-1]; }
1521 }
1522 }
1523//*-*- elements of left diagonal and unscaling
1524 for (j = 1; j <= n; ++j) {
1525 for (k = 1; k <= j; ++k) {
1526 a[k + j*l] = a[k + j*l]*localVERTs[k-1]*localVERTs[j-1];
1527 a[j + k*l] = a[k + j*l];
1528 }
1529 }
1530 delete [] localVERTs;
1531 delete [] localVERTq;
1532 delete [] localVERTpp;
1533 return;
1534//*-*- failure return
1535L100:
1536 delete [] localVERTs;
1537 delete [] localVERTq;
1538 delete [] localVERTpp;
1539 ifail = 1;
1540} /* mnvertLocal */
1541
04b5ea16 1542 //__________________________________________________________________________
29f1b13a 1543void AliMUONTrackReconstructor::RemoveDoubleTracks(void)
8429a5e4 1544{
1545 // To remove double tracks.
1546 // Tracks are considered identical
1547 // if they have at least half of their hits in common.
1548 // Among two identical tracks, one keeps the track with the larger number of hits
1549 // or, if these numbers are equal, the track with the minimum Chi2.
1550 AliMUONTrack *track1, *track2, *trackToRemove;
8429a5e4 1551 Int_t hitsInCommon, nHits1, nHits2;
de2cd600 1552 Bool_t removedTrack1;
1553 // Loop over first track of the pair
1554 track1 = (AliMUONTrack*) fRecTracksPtr->First();
1555 while (track1) {
1556 removedTrack1 = kFALSE;
1557 nHits1 = track1->GetNTrackHits();
1558 // Loop over second track of the pair
1559 track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
1560 while (track2) {
1561 nHits2 = track2->GetNTrackHits();
1562 // number of hits in common between two tracks
1563 hitsInCommon = track1->HitsInCommon(track2);
1564 // check for identical tracks
1565 if ((4 * hitsInCommon) >= (nHits1 + nHits2)) {
1566 // decide which track to remove
1567 if ((nHits1 > nHits2) || ((nHits1 == nHits2) && (track1->GetFitFMin() < track2->GetFitFMin()))) {
1568 // remove track2 and continue the second loop with the track next to track2
1569 trackToRemove = track2;
1570 track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
1571 fRecTracksPtr->Remove(trackToRemove);
1572 fNRecTracks--;
1573 fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
1574 } else {
1575 // else remove track1 and continue the first loop with the track next to track1
1576 trackToRemove = track1;
1577 track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
1578 fRecTracksPtr->Remove(trackToRemove);
1579 fNRecTracks--;
1580 fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
1581 removedTrack1 = kTRUE;
1582 break;
1583 }
1584 } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
1585 } // track2
1586 if (removedTrack1) continue;
1587 track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
1588 } // track1
d837040f 1589 return;
1590}
1591
b8dc484b 1592 //__________________________________________________________________________
29f1b13a 1593void AliMUONTrackReconstructor::UpdateHitForRecAtHit()
b8dc484b 1594{
de2cd600 1595 // Set cluster parameters after track fitting. Fill fHitForRecAtHit of AliMUONTrack's
b8dc484b 1596 AliMUONTrack *track;
de2cd600 1597 AliMUONTrackParam *trackParamAtHit;
b8dc484b 1598 track = (AliMUONTrack*) fRecTracksPtr->First();
1599 while (track) {
de2cd600 1600 trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
1601 while (trackParamAtHit) {
1602 track->AddHitForRecAtHit(trackParamAtHit->GetHitForRecPtr());
1603 trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->After(trackParamAtHit));
1604 }
b8dc484b 1605 track = (AliMUONTrack*) fRecTracksPtr->After(track);
de2cd600 1606 }
b8dc484b 1607 return;
1608}
1609
b035a148 1610 //__________________________________________________________________________
29f1b13a 1611void AliMUONTrackReconstructor::FillMUONTrack()
b035a148 1612{
1613 // Set track parameters at hits for Kalman track. Fill fTrackParamAtHit of AliMUONTrack's
1614 AliMUONTrackK *track;
1615 track = (AliMUONTrackK*) fRecTracksPtr->First();
1616 while (track) {
1617 track->FillMUONTrack();
1618 track = (AliMUONTrackK*) fRecTracksPtr->After(track);
1619 }
1620 return;
1621}
1622
8429a5e4 1623 //__________________________________________________________________________
29f1b13a 1624void AliMUONTrackReconstructor::EventDump(void)
04b5ea16 1625{
1626 // Dump reconstructed event (track parameters at vertex and at first hit),
1627 // and the particle parameters
1628
1629 AliMUONTrack *track;
1630 AliMUONTrackParam *trackParam, *trackParam1;
04b5ea16 1631 Double_t bendingSlope, nonBendingSlope, pYZ;
1632 Double_t pX, pY, pZ, x, y, z, c;
5e671e06 1633 Int_t trackIndex, nTrackHits;
04b5ea16 1634
b840996b 1635 AliDebug(1,"****** enter EventDump ******");
1636 AliDebug(1, Form("Number of Reconstructed tracks : %d", fNRecTracks));
1637
04b5ea16 1638 fRecTracksPtr->Compress(); // for simple loop without "Next" since no hole
1639 // Loop over reconstructed tracks
1640 for (trackIndex = 0; trackIndex < fNRecTracks; trackIndex++) {
83dbc640 1641 if (fTrackMethod != 1) continue; //AZ - skip the rest for now
b840996b 1642 AliDebug(1, Form("track number: %d", trackIndex));
04b5ea16 1643 // function for each track for modularity ????
1644 track = (AliMUONTrack*) ((*fRecTracksPtr)[trackIndex]);
1645 nTrackHits = track->GetNTrackHits();
b840996b 1646 AliDebug(1, Form("Number of track hits: %d ", nTrackHits));
04b5ea16 1647 // track parameters at Vertex
1648 trackParam = track->GetTrackParamAtVertex();
1649 x = trackParam->GetNonBendingCoor();
1650 y = trackParam->GetBendingCoor();
1651 z = trackParam->GetZ();
1652 bendingSlope = trackParam->GetBendingSlope();
1653 nonBendingSlope = trackParam->GetNonBendingSlope();
1654 pYZ = 1/TMath::Abs(trackParam->GetInverseBendingMomentum());
1655 pZ = pYZ/TMath::Sqrt(1+bendingSlope*bendingSlope);
1656 pX = pZ * nonBendingSlope;
1657 pY = pZ * bendingSlope;
1658 c = TMath::Sign(1.0, trackParam->GetInverseBendingMomentum());
b840996b 1659 AliDebug(1, Form("Track parameters at Vertex z= %f: X= %f Y= %f pX= %f pY= %f pZ= %f c= %f\n",
1660 z, x, y, pX, pY, pZ, c));
04b5ea16 1661
1662 // track parameters at first hit
de2cd600 1663 trackParam1 = (AliMUONTrackParam*) track->GetTrackParamAtHit()->First();
04b5ea16 1664 x = trackParam1->GetNonBendingCoor();
1665 y = trackParam1->GetBendingCoor();
1666 z = trackParam1->GetZ();
1667 bendingSlope = trackParam1->GetBendingSlope();
1668 nonBendingSlope = trackParam1->GetNonBendingSlope();
1669 pYZ = 1/TMath::Abs(trackParam1->GetInverseBendingMomentum());
1670 pZ = pYZ/TMath::Sqrt(1.0 + bendingSlope * bendingSlope);
1671 pX = pZ * nonBendingSlope;
1672 pY = pZ * bendingSlope;
1673 c = TMath::Sign(1.0, trackParam1->GetInverseBendingMomentum());
b840996b 1674 AliDebug(1, Form("track parameters at z= %f: X= %f Y= %f pX= %f pY= %f pZ= %f c= %f\n",
1675 z, x, y, pX, pY, pZ, c));
04b5ea16 1676 }
8f373020 1677 // informations about generated particles NO !!!!!!!!
04b5ea16 1678
88cb7938 1679// for (Int_t iPart = 0; iPart < np; iPart++) {
1680// p = gAlice->Particle(iPart);
1681// printf(" particle %d: type= %d px= %f py= %f pz= %f pdg= %d\n",
1682// iPart, p->GetPdgCode(), p->Px(), p->Py(), p->Pz(), p->GetPdgCode());
1683// }
a9e2aefa 1684 return;
1685}
1686
276c44b7 1687
1688//__________________________________________________________________________
29f1b13a 1689void AliMUONTrackReconstructor::EventDumpTrigger(void)
276c44b7 1690{
1691 // Dump reconstructed trigger event
1692 // and the particle parameters
1693
52c9bc11 1694 AliMUONTriggerTrack *triggertrack ;
1695 Int_t nTriggerTracks = fMUONData->RecTriggerTracks()->GetEntriesFast();
276c44b7 1696
b840996b 1697 AliDebug(1, "****** enter EventDumpTrigger ******");
1698 AliDebug(1, Form("Number of Reconstructed tracks : %d ", nTriggerTracks));
1699
276c44b7 1700 // Loop over reconstructed tracks
52c9bc11 1701 for (Int_t trackIndex = 0; trackIndex < nTriggerTracks; trackIndex++) {
1702 triggertrack = (AliMUONTriggerTrack*)fMUONData->RecTriggerTracks()->At(trackIndex);
276c44b7 1703 printf(" trigger track number %i x11=%f y11=%f thetax=%f thetay=%f \n",
1704 trackIndex,
1705 triggertrack->GetX11(),triggertrack->GetY11(),
1706 triggertrack->GetThetax(),triggertrack->GetThetay());
1707 }
1708}
1709
83dbc640 1710//__________________________________________________________________________
29f1b13a 1711void AliMUONTrackReconstructor::MakeTrackCandidatesK(void)
83dbc640 1712{
1713 // To make initial tracks for Kalman filter from the list of segments
1714 Int_t istat, iseg;
1715 AliMUONSegment *segment;
1716 AliMUONTrackK *trackK;
1717
b840996b 1718 AliDebug(1,"Enter MakeTrackCandidatesK");
83dbc640 1719
fff097e0 1720 AliMUONTrackK a(this, fHitsForRecPtr);
83dbc640 1721 // Loop over stations(1...) 5 and 4
1722 for (istat=4; istat>=3; istat--) {
1723 // Loop over segments in the station
1724 for (iseg=0; iseg<fNSegments[istat]; iseg++) {
1725 // Transform segments to tracks and evaluate covariance matrix
1726 segment = (AliMUONSegment*) ((*fSegmentsPtr[istat])[iseg]);
cc87ebcd 1727 trackK = new ((*fRecTracksPtr)[fNRecTracks++]) AliMUONTrackK(segment);
83dbc640 1728 } // for (iseg=0;...)
1729 } // for (istat=4;...)
1730 return;
1731}
1732
1733//__________________________________________________________________________
29f1b13a 1734void AliMUONTrackReconstructor::FollowTracksK(void)
83dbc640 1735{
1736 // Follow tracks using Kalman filter
30178c30 1737 Bool_t ok;
b035a148 1738 Int_t icand, ichamBeg = 0, ichamEnd, chamBits;
83dbc640 1739 Double_t zDipole1, zDipole2;
1740 AliMUONTrackK *trackK;
1741 AliMUONHitForRec *hit;
1742 AliMUONRawCluster *clus;
1743 TClonesArray *rawclusters;
83dbc640 1744 clus = 0; rawclusters = 0;
1745
b035a148 1746 zDipole1 = GetSimpleBPosition() + GetSimpleBLength()/2;
1747 zDipole2 = zDipole1 - GetSimpleBLength();
83dbc640 1748
1749 // Print hits
b035a148 1750 trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[0]);
8f373020 1751
b035a148 1752 if (trackK->DebugLevel() > 0) {
1753 for (Int_t i1=0; i1<fNHitsForRec; i1++) {
1754 hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[i1]);
b035a148 1755 printf(" Hit # %d %10.4f %10.4f %10.4f",
1756 hit->GetChamberNumber(), hit->GetBendingCoor(),
1757 hit->GetNonBendingCoor(), hit->GetZ());
8f373020 1758
1759 // from raw clusters
1760 rawclusters = fMUONData->RawClusters(hit->GetChamberNumber());
1761 clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->
1762 GetHitNumber());
1763 printf(" %d", clus->GetTrack(1));
1764 if (clus->GetTrack(2) != -1) printf(" %d \n", clus->GetTrack(2));
1765 else printf("\n");
1766
83dbc640 1767 }
b035a148 1768 } // if (trackK->DebugLevel() > 0)
83dbc640 1769
1770 icand = -1;
b035a148 1771 Int_t nSeeds;
1772 nSeeds = fNRecTracks; // starting number of seeds
83dbc640 1773 // Loop over track candidates
1774 while (icand < fNRecTracks-1) {
1775 icand ++;
b035a148 1776 if (trackK->DebugLevel()>0) cout << " *** Kalman track candidate No. " << icand << endl;
83dbc640 1777 trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[icand]);
b035a148 1778 if (trackK->GetRecover() < 0) continue; // failed track
83dbc640 1779
1780 // Discard candidate which will produce the double track
b035a148 1781 /*
83dbc640 1782 if (icand > 0) {
30178c30 1783 ok = CheckCandidateK(icand,nSeeds);
1784 if (!ok) {
b035a148 1785 trackK->SetRecover(-1); // mark candidate to be removed
1786 continue;
83dbc640 1787 }
1788 }
b035a148 1789 */
83dbc640 1790
30178c30 1791 ok = kTRUE;
8f373020 1792 if (trackK->GetRecover() == 0)
1793 hit = (AliMUONHitForRec*) trackK->GetTrackHits()->Last(); // last hit
1794 else
1795 hit = trackK->GetHitLastOk(); // hit where track stopped
1796
b035a148 1797 if (hit) ichamBeg = hit->GetChamberNumber();
83dbc640 1798 ichamEnd = 0;
1799 // Check propagation direction
cc87ebcd 1800 if (!hit) { ichamBeg = ichamEnd; AliFatal(" ??? "); }
b035a148 1801 else if (trackK->GetTrackDir() < 0) {
83dbc640 1802 ichamEnd = 9; // forward propagation
30178c30 1803 ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kFALSE,zDipole1,zDipole2);
1804 if (ok) {
83dbc640 1805 ichamBeg = ichamEnd;
1806 ichamEnd = 6; // backward propagation
1807 // Change weight matrix and zero fChi2 for backpropagation
1808 trackK->StartBack();
b035a148 1809 trackK->SetTrackDir(1);
30178c30 1810 ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kTRUE,zDipole1,zDipole2);
83dbc640 1811 ichamBeg = ichamEnd;
1812 ichamEnd = 0;
1813 }
1814 } else {
1815 if (trackK->GetBPFlag()) {
1816 // backpropagation
1817 ichamEnd = 6; // backward propagation
1818 // Change weight matrix and zero fChi2 for backpropagation
1819 trackK->StartBack();
30178c30 1820 ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kTRUE,zDipole1,zDipole2);
83dbc640 1821 ichamBeg = ichamEnd;
1822 ichamEnd = 0;
1823 }
1824 }
1825
30178c30 1826 if (ok) {
b035a148 1827 trackK->SetTrackDir(1);
83dbc640 1828 trackK->SetBPFlag(kFALSE);
30178c30 1829 ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kFALSE,zDipole1,zDipole2);
83dbc640 1830 }
b035a148 1831 if (!ok) { trackK->SetRecover(-1); continue; } // mark candidate to be removed
1832
1833 // Apply smoother
1834 if (trackK->GetRecover() >= 0) {
1835 ok = trackK->Smooth();
1836 if (!ok) trackK->SetRecover(-1); // mark candidate to be removed
1837 }
83dbc640 1838
1839 // Majority 3 of 4 in first 2 stations
b035a148 1840 if (!ok) continue;
83dbc640 1841 chamBits = 0;
f29ba3e1 1842 Double_t chi2max = 0;
83dbc640 1843 for (Int_t i=0; i<trackK->GetNTrackHits(); i++) {
fff097e0 1844 hit = (AliMUONHitForRec*) (*trackK->GetTrackHits())[i];
b035a148 1845 chamBits |= BIT(hit->GetChamberNumber());
f29ba3e1 1846 if (trackK->GetChi2PerPoint(i) > chi2max) chi2max = trackK->GetChi2PerPoint(i);
83dbc640 1847 }
f29ba3e1 1848 if (!((chamBits&3)==3 || (chamBits>>2&3)==3) && chi2max > 25) {
b035a148 1849 //trackK->Recover();
1850 trackK->SetRecover(-1); //mark candidate to be removed
1851 continue;
1852 }
1853 if (ok) trackK->SetTrackQuality(0); // compute "track quality"
83dbc640 1854 } // while
1855
1856 for (Int_t i=0; i<fNRecTracks; i++) {
1857 trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[i]);
1858 if (trackK->GetRecover() < 0) fRecTracksPtr->RemoveAt(i);
1859 }
1860
1861 // Compress TClonesArray
1862 fRecTracksPtr->Compress();
1863 fNRecTracks = fRecTracksPtr->GetEntriesFast();
1864 return;
1865}
1866
1867//__________________________________________________________________________
29f1b13a 1868Bool_t AliMUONTrackReconstructor::CheckCandidateK(Int_t icand, Int_t nSeeds) const
83dbc640 1869{
1870 // Discards track candidate if it will produce the double track (having
1871 // the same seed segment hits as hits of a good track found before)
1872 AliMUONTrackK *track1, *track2;
1873 AliMUONHitForRec *hit1, *hit2, *hit;
1874
1875 track1 = (AliMUONTrackK*) ((*fRecTracksPtr)[icand]);
fff097e0 1876 hit1 = (AliMUONHitForRec*) (*track1->GetTrackHits())[0]; // 1'st hit
1877 hit2 = (AliMUONHitForRec*) (*track1->GetTrackHits())[1]; // 2'nd hit
83dbc640 1878
1879 for (Int_t i=0; i<icand; i++) {
1880 track2 = (AliMUONTrackK*) ((*fRecTracksPtr)[i]);
1881 //if (track2->GetRecover() < 0) continue;
1882 if (track2->GetRecover() < 0 && icand >= nSeeds) continue;
1883
1884 if (track1->GetStartSegment() == track2->GetStartSegment()) {
1885 return kFALSE;
1886 } else {
1887 Int_t nSame = 0;
1888 for (Int_t j=0; j<track2->GetNTrackHits(); j++) {
fff097e0 1889 hit = (AliMUONHitForRec*) (*track2->GetTrackHits())[j];
83dbc640 1890 if (hit == hit1 || hit == hit2) {
1891 nSame++;
1892 if (nSame == 2) return kFALSE;
1893 }
1894 } // for (Int_t j=0;
1895 }
1896 } // for (Int_t i=0;
1897 return kTRUE;
1898}
1899
1900//__________________________________________________________________________
29f1b13a 1901void AliMUONTrackReconstructor::RemoveDoubleTracksK(void)
83dbc640 1902{
1903 // Removes double tracks (sharing more than half of their hits). Keeps
1904 // the track with higher quality
1905 AliMUONTrackK *track1, *track2, *trackToKill;
1906
1907 // Sort tracks according to their quality
1908 fRecTracksPtr->Sort();
1909
1910 // Loop over first track of the pair
1911 track1 = (AliMUONTrackK*) fRecTracksPtr->First();
b035a148 1912 Int_t debug = track1->DebugLevel();
83dbc640 1913 while (track1) {
1914 // Loop over second track of the pair
1915 track2 = (AliMUONTrackK*) fRecTracksPtr->After(track1);
1916 while (track2) {
1917 // Check whether or not to keep track2
1918 if (!track2->KeepTrack(track1)) {
b035a148 1919 if (debug >= 0) cout << " Killed track: " << 1/(*track2->GetTrackParameters())(4,0) <<
83dbc640 1920 " " << track2->GetTrackQuality() << endl;
1921 trackToKill = track2;
1922 track2 = (AliMUONTrackK*) fRecTracksPtr->After(track2);
1923 trackToKill->Kill();
1924 fRecTracksPtr->Compress();
1925 } else track2 = (AliMUONTrackK*) fRecTracksPtr->After(track2);
1926 } // track2
1927 track1 = (AliMUONTrackK*) fRecTracksPtr->After(track1);
1928 } // track1
1929
1930 fNRecTracks = fRecTracksPtr->GetEntriesFast();
b035a148 1931 if (debug >= 0) cout << " Number of Kalman tracks: " << fNRecTracks << endl;
83dbc640 1932}
1933
1934//__________________________________________________________________________
29f1b13a 1935void AliMUONTrackReconstructor::GoToVertex(void)
83dbc640 1936{
1937 // Propagates track to the vertex thru absorber
1938 // (using Branson correction for now)
1939
1940 Double_t zVertex;
1941 zVertex = 0;
1942 for (Int_t i=0; i<fNRecTracks; i++) {
1943 //((AliMUONTrackK*)(*fRecTracksPtr)[i])->Branson();
83dbc640 1944 ((AliMUONTrackK*)(*fRecTracksPtr)[i])->SetTrackQuality(1); // compute Chi2
b035a148 1945 //((AliMUONTrackK*)(*fRecTracksPtr)[i])->GoToZ(zVertex); // w/out absorber
1946 ((AliMUONTrackK*)(*fRecTracksPtr)[i])->GoToVertex(1); // with absorber
83dbc640 1947 }
1948}
b035a148 1949
1950//__________________________________________________________________________
29f1b13a 1951void AliMUONTrackReconstructor::SetTrackMethod(Int_t iTrackMethod)
b035a148 1952{
1953 // Set track method and recreate track container if necessary
1954
cc87ebcd 1955 fTrackMethod = TMath::Min (iTrackMethod, 3);
1956 fTrackMethod = TMath::Max (fTrackMethod, 1);
1957 if (fTrackMethod != 1) {
b035a148 1958 if (fRecTracksPtr) delete fRecTracksPtr;
1959 fRecTracksPtr = new TClonesArray("AliMUONTrackK", 10);
cc87ebcd 1960 if (fTrackMethod == 2) cout << " *** Tracking with the Kalman filter *** " << endl;
1961 else cout << " *** Combined cluster / track finder ***" << endl;
fff097e0 1962 } else cout << " *** Original tracking *** " << endl;
b035a148 1963
1964}