]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWG3/muon/AliAnalysisTaskLinkToMC.cxx
Cleanup the code. Fix memory leak. Now inherit from AliAnalysisTaskSE (Antoine, Phili...
[u/mrichter/AliRoot.git] / PWG3 / muon / AliAnalysisTaskLinkToMC.cxx
CommitLineData
4c904d93 1/**************************************************************************
2 * This file is property of and copyright by the ALICE HLT Project *
3 * All rights reserved. *
4 * *
5 * Primary Authors: *
6 * Artur Szostak <artursz@iafrica.com> *
7 * *
8 * Permission to use, copy, modify and distribute this software and its *
9 * documentation strictly for non-commercial purposes is hereby granted *
10 * without fee, provided that the above copyright notice appears in all *
11 * copies and that both the copyright notice and this permission notice *
12 * appear in the supporting documentation. The authors make no claims *
13 * about the suitability of this software for any purpose. It is *
14 * provided "as is" without express or implied warranty. *
15 **************************************************************************/
16
27de2dfb 17/* $Id$ */
18
4c904d93 19///
20/// @file AliAnalysisTaskLinkToMC.cxx
21/// @author Artur Szostak <artursz@iafrica.com>
22/// @date 27 Oct 2008
23/// @brief Implementation of the AliAnalysisTaskLinkToMC task.
24///
25/// The AliAnalysisTaskLinkToMC connects reconstructed tracks found in the ESD
26/// to their corresponding Monte Carlo (MC) tracks via the proximity of their
27/// hit coordinates. Each ESD track is copied over to an AOD track and put into
28/// the AOD event container, but the AOD track label is filled such that the
29/// AOD track label is the same as the MC track label.
30/// If a MC track could not be found for a given ESD track then -1 is filled
31/// into the AOD track label.
32/// The corresponding MC track is found by correlating the reconstructed track
33/// clusters with the MC track references. For each cluster the closest track
34/// reference coordinate is found and a chi-squared value is computed for each
35/// X and Y dimension independently. The chi-square's are summed up and the MC
36/// track with the smallest total chi-squared is chosen as the best match to
37/// the ESD track.
38///
39/// The following cuts control the conditions under which we consider a MC track
40/// to match a given ESD track:
41/// 1) SigmaCut(Double_t value) - This is maximum distance expressed in standard
42/// deviations that is allowed between a reconstructed cluster coordinate
43/// and the MC track reference coordinate. The condition is expressed as:
44/// (x_{cluster} - x_{trackref})^2 / (sigma_{x})^2 < #sigma_{cut}
45/// This conditions is applied to each X and Y dimension respectively and
46/// cluster / track reference pairs that do not pass this cut are considered
47/// not to match.
48/// 2) MinClusters(Int_t value) - Indicates the minimum number of clusters that
49/// must be matched to a track reference from a MC track for the ESD and
50/// MC track to be considered to match.
51/// The following are absolute cuts which are used mainly as a speed optimisation
52/// so as to skip over cluster / track reference pairs that are far away from
53/// each other early.
54/// 3) HardCutLimitX(Double_t value) - The absolute maximum distance in centimetres
55/// allowed between a cluster's X coordinate and a track reference's X coordinate.
56/// If a cluster / track reference pair does not pass this condition then the
57/// pair is considered not to match.
58/// 4) HardCutLimitY(Double_t value) - Similar to HardCutLimitX but applied to the
59/// Y dimension of the cluster and track reference coordinate.
60/// 5) HardCutLimitZ(Double_t value) - Similar to HardCutLimitX but applied to the
61/// Z dimension.
62///
63/// The analysis task also optionally generates histograms which show can be used
64/// to check the quality of the correlation between ESD and MC tracks.
65/// The histograms are generated in 2D for the pT and rapidity variable,
66/// and are called:
67/// 1) findableTracksHist - Filled with the MC tracks which should in principle
68/// be findable by the reconstruction software. A findable track is defined
69/// by the IsFindable method.
70/// 2) foundTracksHistMC - Filled with the MC information for each muon track that
71/// was found in the ESD and for which we could match its corresponding MC track.
72/// 3) foundTracksHist - Filled just like the foundTracksHistMC histogram, but with
73/// the momentum information taken from the ESD track and not the corresponding
74/// MC track.
75/// 4) fakeTracksHist - Filled with all the ESD tracks for which we could not find
76/// its matching MC track and assume it is a fake track.
77/// These histograms are filled by default, but can be disabled by using the
78/// GenerateHistograms(false) method call.
79///
80
81#include "AliAnalysisTaskLinkToMC.h"
82#include "AliESDEvent.h"
83#include "AliESDMuonTrack.h"
84#include "AliESDMuonCluster.h"
85#include "AliMCEvent.h"
86#include "AliMCParticle.h"
87#include "AliAODVertex.h"
88#include "AliAODEvent.h"
89#include "AliAODTrack.h"
90#include "AliTrackReference.h"
91#include "AliStack.h"
92#include "AliLog.h"
93#include "TObjArray.h"
94#include "TCanvas.h"
95#include "TMath.h"
96#include "TMap.h"
97#include "TList.h"
98#include "TH2D.h"
99#include "TStyle.h"
100
805e576c 101ClassImp(AliAnalysisTaskLinkToMC)
4c904d93 102
103
104void AliAnalysisTaskLinkToMC::HardCutLimitX(Double_t value)
105{
106 /// Sets the absolute maximum distance in centimetres between the cluster
107 /// and track reference that is allowed in the X direction.
108
109 if (value >= 0)
110 {
111 fHardCutLimitX = value;
112 }
113 else
114 {
115 AliWarning("Setting value for fHardCutLimitX which is negative."
116 " Will set it to a positive value."
117 );
118 fHardCutLimitX = TMath::Abs(value);
119 }
120}
121
122
123void AliAnalysisTaskLinkToMC::HardCutLimitY(Double_t value)
124{
125 /// Sets the absolute maximum distance in centimetres between the cluster
126 /// and track reference that is allowed in the Y direction.
127
128 if (value >= 0)
129 {
130 fHardCutLimitY = value;
131 }
132 else
133 {
134 AliWarning("Setting value for fHardCutLimitY which is negative."
135 " Will set it to a positive value."
136 );
137 fHardCutLimitY = TMath::Abs(value);
138 }
139}
140
141
142void AliAnalysisTaskLinkToMC::HardCutLimitZ(Double_t value)
143{
144 /// Sets the absolute maximum distance in centimetres between the cluster
145 /// and track reference that is allowed in the Z direction.
146
147 if (value >= 0)
148 {
149 fHardCutLimitZ = value;
150 }
151 else
152 {
153 AliWarning("Setting value for fHardCutLimitZ which is negative."
154 " Will set it to a positive value."
155 );
156 fHardCutLimitZ = TMath::Abs(value);
157 }
158}
159
160
161Double_t AliAnalysisTaskLinkToMC::SigmaCut() const
162{
163 /// Returns the maximum sigma value to allow for each X and Y dimension
164 /// between clusters and track references.
165
166 return TMath::Sqrt(fSigmaCut2);
167}
168
169
170Bool_t AliAnalysisTaskLinkToMC::ChamberMustMatch(Int_t chamber) const
171{
172 /// Returns the flag indicating if the ESD track cluster on the given
173 /// chamber must match a corresponding track reference to be valid.
174 /// \param chamber The chamber number must be in the range 1 to 14.
175
176 if (chamber >= 1 and chamber <= 14)
177 {
178 return fChamberMustMatch[chamber-1];
179 }
180 else
181 {
182 AliError(Form("The chamber number %d is invalid. Expected a value"
183 " in the range [1..14]. Will return a value of 'false'.",
184 chamber
185 ));
186 return false;
187 }
188}
189
190
191void AliAnalysisTaskLinkToMC::ChamberMustMatch(Int_t chamber, Bool_t value)
192{
193 /// Set the flag indicating if the ESD track cluster on the given chamber
194 /// must match a corresponding track reference to be valid.
195 /// \param chamber The chamber number must be in the range 1 to 14.
196 /// \param value The new value to set to.
197
198 if (chamber >= 1 and chamber <= 14)
199 {
200 fChamberMustMatch[chamber-1] = value;
201 }
202 else
203 {
204 AliError(Form("The chamber number %d is invalid. Expected a value"
205 " in the range [1..14]. Will not set any fChamberMustMatch flag.",
206 chamber
207 ));
208 }
209}
210
211
212Bool_t AliAnalysisTaskLinkToMC::StationMustMatch(Int_t station) const
213{
214 /// Returns the flag indicating if at least one ESD track cluster on the
215 /// given station must match a corresponding track reference to be valid.
216 /// \param station The station number must be in the range 1..7. Station
217 /// 1 to 5 are the tracking stations while 6 is MT1 and 7 is MT2.
218
219 if (station >= 1 and station <= 7)
220 {
221 return fStationMustMatch[station-1];
222 }
223 else
224 {
225 AliError(Form("The station number %d is invalid. Expected a value"
226 " in the range [1..7]. Will return a value of 'false'.",
227 station
228 ));
229 return false;
230 }
231}
232
233
234void AliAnalysisTaskLinkToMC::StationMustMatch(Int_t station, Bool_t value)
235{
236 /// Sets the flag indicating if at least one ESD track cluster on the
237 /// given station must match a corresponding track reference to be valid.
238 /// \param station The station number must be in the range 1..7. Station
239 /// 1 to 5 are the tracking stations while 6 is MT1 and 7 is MT2.
240 /// \param value The new value to set to.
241
242 if (station >= 1 and station <= 7)
243 {
244 fStationMustMatch[station-1] = value;
245 }
246 else
247 {
248 AliError(Form("The station number %d is invalid. Expected a value"
249 " in the range [1..7]. Will not set any fStationMustMatch flag.",
250 station
251 ));
252 }
253}
254
255
256AliAnalysisTaskLinkToMC::AliAnalysisTaskLinkToMC() :
257 AliAnalysisTaskSE(),
258 fHistos(NULL),
259 fFindableHist(NULL),
260 fFoundHistMC(NULL),
261 fFoundHist(NULL),
262 fFakeHist(NULL),
263 fHardCutLimitX(4.), // cm
264 fHardCutLimitY(4.), // cm
265 fHardCutLimitZ(4.), // cm
266 fVarX(0.144*0.144), // cm^2
267 fVarY(0.01*0.01), // cm^2
268 fSigmaCut2(5*5), // sigma^2
269 fMinClusters(6),
270 fMinClustersInSt12(0), // no minimum requirement for stations 1 and 2.
271 fMinClustersInSt45(3), // 3 hits required on station 4 and 5 by default.
272 fMakeHists(true), // Generate histograms for monitoring by default
273 fUseZCoordinate(false) // Just use detElemId to match in the Z direction.
274{
275 /// Default constructor.
276 /// Sets input slot 0 to TChain input for ESDs, output slot 0 to TTree
277 /// for AODs and output slot 1 to TList for the list of output histograms.
278 /// The output histograms generated are to cross check the quality of the
279 /// correlation and their generation can be turned off with
280 /// AliAnalysisTaskLinkToMC::GenerateHistograms(false).
281
282 // Do not force any matching for particular chambers by default.
283 for (Int_t i = 0; i < 14; i++)
284 {
285 fChamberMustMatch[i] = false;
286 }
287 // Only force a minimum of 1 hit to be matched on stations 1, 2 and 3 by default.
288 for (Int_t i = 0; i < 3; i++)
289 {
290 fStationMustMatch[i] = true;
291 }
292 for (Int_t i = 3; i < 7; i++)
293 {
294 fStationMustMatch[i] = false;
295 }
296
297 DefineOutput(1, TList::Class());
298}
299
300
301AliAnalysisTaskLinkToMC::AliAnalysisTaskLinkToMC(const char* name) :
302 AliAnalysisTaskSE(name),
303 fHistos(NULL),
304 fFindableHist(NULL),
305 fFoundHistMC(NULL),
306 fFoundHist(NULL),
307 fFakeHist(NULL),
308 fHardCutLimitX(4.), // cm
309 fHardCutLimitY(4.), // cm
310 fHardCutLimitZ(4.), // cm
311 fVarX(0.144*0.144), // cm^2
312 fVarY(0.01*0.01), // cm^2
313 fSigmaCut2(5*5), // sigma^2
314 fMinClusters(6),
315 fMinClustersInSt12(0), // no minimum requirement for stations 1 and 2.
316 fMinClustersInSt45(3), // 3 hits required on station 4 and 5 by default.
317 fMakeHists(true), // Generate histograms for monitoring by default
318 fUseZCoordinate(false) // Just use detElemId to match in the Z direction.
319{
320 /// Constructor with a task name.
321 /// Sets input slot 0 to TChain input for ESDs, output slot 0 to TTree
322 /// for AODs and output slot 1 to TList for the list of output histograms
323 /// storing histograms generated to cross check the quility of the
324 /// correlation.
325 /// \param name The name of the task.
326
327 // Do not force any matching for particular chambers by default.
328 for (Int_t i = 0; i < 14; i++)
329 {
330 fChamberMustMatch[i] = false;
331 }
332 // Only force a minimum of 1 hit to be matched on stations 1, 2 and 3 by default.
333 for (Int_t i = 0; i < 3; i++)
334 {
335 fStationMustMatch[i] = true;
336 }
337 for (Int_t i = 3; i < 7; i++)
338 {
339 fStationMustMatch[i] = false;
340 }
341
342 DefineOutput(1, TList::Class());
343}
344
345
346void AliAnalysisTaskLinkToMC::UserCreateOutputObjects()
347{
348 /// Creates the output histograms containing findable tracks, found tracks
349 /// and fake tracks. The binning range for all histograms is 30 bins along
350 /// the pT dimension (X direction) from 0 to 20 GeV/c and 30 bins in the
351 /// rapidity dimension (Y direction) form -4 to -2.4 units.
352
353 fHistos = new TList;
354
355 char name[1024];
356 char title[1024];
357
358 Int_t nBinsX = 30;
359 Double_t minX = 0.;
360 Double_t maxX = 20.;
361 Int_t nBinsY = 30;
362 Double_t minY = -4.;
363 Double_t maxY = -2.4;
364
7bd97ad1 365 snprintf(name, 1024, "findableTracksHist");
366 snprintf(title, 1024, "Findable tracks");
4c904d93 367 fFindableHist = new TH2D(name, title, nBinsX, minX, maxX, nBinsY, minY, maxY);
368 fFindableHist->SetXTitle("p_{T} [GeV/c]");
369 fFindableHist->SetYTitle("Rapidity (Y)");
370 fHistos->Add(fFindableHist);
371
7bd97ad1 372 snprintf(name, 1024, "foundTracksHistMC");
373 snprintf(title, 1024, "Found tracks (filled with Monte Carlo kinematic information)");
4c904d93 374 fFoundHistMC = new TH2D(name, title, nBinsX, minX, maxX, nBinsY, minY, maxY);
375 fFoundHistMC->SetXTitle("p_{T} [GeV/c]");
376 fFoundHistMC->SetYTitle("Rapidity (Y)");
377 fHistos->Add(fFoundHistMC);
378
7bd97ad1 379 snprintf(name, 1024, "foundTracksHist");
380 snprintf(title, 1024, "Found tracks (filled with reconstructed kinematic information)");
4c904d93 381 fFoundHist = new TH2D(name, title, nBinsX, minX, maxX, nBinsY, minY, maxY);
382 fFoundHist->SetXTitle("p_{T} [GeV/c]");
383 fFoundHist->SetYTitle("Rapidity (Y)");
384 fHistos->Add(fFoundHist);
385
7bd97ad1 386 snprintf(name, 1024, "fakeTracksHist");
387 snprintf(title, 1024, "Fake tracks");
4c904d93 388 fFakeHist = new TH2D(name, title, nBinsX, minX, maxX, nBinsY, minY, maxY);
389 fFakeHist->SetXTitle("p_{T} [GeV/c]");
390 fFakeHist->SetYTitle("Rapidity (Y)");
391 fHistos->Add(fFakeHist);
392}
393
394
395void AliAnalysisTaskLinkToMC::UserExec(Option_t* /*option*/)
396{
397 /// This is the top level method that performs the work of the task.
398 /// It will fill the histograms for quality checking with the Monte
399 /// Carlo (MC) information if they are to be generated.
400 /// The input event is then processed which must be of type AliESDEvent.
401 /// For all the ESD muon tracks we try to find the corresponding MC
402 /// track and build a TMap for the mapping.
403 /// If the AOD output event is available then it is filled with AOD
404 /// tracks which copy the information form the ESD track and the AOD
405 /// track label is filled with the corresponding MC track label.
406 /// If a corresponding MC track could not be found then the AOD track
407 /// label is filled with -1.
408 /// Finally the checking histograms are further filled with the ESD
409 /// information based on the ESD to MC track map.
410
411 if (fMakeHists and
412 (fFindableHist == NULL or fFoundHistMC == NULL or fFoundHist == NULL or fFakeHist == NULL)
413 )
414 {
415 AliError("Histograms have not been created.");
416 return;
417 }
418
419 if (fMakeHists and MCEvent() != NULL) FillHistsFromMC();
420
421 if (InputEvent() != NULL)
422 {
423 if (InputEvent()->IsA() == AliESDEvent::Class())
424 {
425 if (MCEvent() != NULL)
426 {
427 TMap links;
428 FindLinksToMC(links);
429 if (AODEvent() != NULL) CreateAODTracks(links);
430 if (fMakeHists) FillHistsFromLinks(links);
431 }
432 else
433 {
434 AliError("To process the ESD event we must have the Monte Carlo data also.");
435 }
436 }
437 else
438 {
439 AliError(Form("The input event is of type \"%s\". Do not know how to handle it so it will be skipped.",
440 InputEvent()->ClassName()
441 ));
442 }
443 }
444
445 if (fMakeHists) PostData(1, fHistos);
446}
447
448
449void AliAnalysisTaskLinkToMC::Terminate(Option_t* /*option*/)
450{
451 /// The terminate method will draw the histograms filled by this task if
452 /// they were filled by setting appropriate flag with the
453 /// GenerateHistograms(true) method, which is the default.
454
455 if (fMakeHists)
456 {
457 gStyle->SetPalette(1);
458 new TCanvas;
459 fFindableHist->DrawCopy("colz");
460 new TCanvas;
461 fFoundHistMC->DrawCopy("colz");
462 new TCanvas;
463 fFoundHist->DrawCopy("colz");
464 new TCanvas;
465 fFakeHist->DrawCopy("colz");
466
467 AliInfo(Form("Findable tracks = %d", Int_t(fFindableHist->GetEntries()) ));
468 AliInfo(Form("Found tracks = %d", Int_t(fFoundHistMC->GetEntries()) ));
469 AliInfo(Form("Fake tracks = %d", Int_t(fFakeHist->GetEntries()) ));
470 }
471}
472
473
474bool AliAnalysisTaskLinkToMC::IsFindable(AliMCParticle* track) const
475{
476 /// This method is used to identify if a Monte Carlo (MC) track is in principle
477 /// findable in the muon spectrometer.
478 /// This means the MC track must be a muon particle and leave at least one track
479 /// reference point on either chamber in each tracking station.
480 /// \param track The MC track to check.
481 /// \returns true if the track is findable by the muon spectrometer
482 /// and false otherwise.
483 /// \note The definition of track find-ability does not affect the correlation
484 /// between ESD and MC tracks nor the generation of the AOD output tracks,
485 /// only the histogram of findable tracks is effected if it is generated at all.
486
487 // Select only muons.
488 if (TMath::Abs(track->Particle()->GetPdgCode()) != 13) return false;
489
490 // Build hit mask for chambers.
491 bool hitOnCh[14];
492 for (Int_t i = 0; i < 14; i++)
493 {
494 hitOnCh[i] = false;
495 }
496 for (Int_t i = 0; i < track->GetNumberOfTrackReferences(); i++)
497 {
498 AliTrackReference* ref = track->GetTrackReference(i);
499 if (ref->DetectorId() != AliTrackReference::kMUON) continue;
500 Int_t chamberId = ref->UserId() / 100 - 1;
501 if (0 <= chamberId and chamberId < 14)
502 {
503 hitOnCh[chamberId] = true;
504 }
505 }
506
507 // Check that enough hits are available on all tracking chambers.
508 bool hitOnSt1 = hitOnCh[0] or hitOnCh[1];
509 bool hitOnSt2 = hitOnCh[2] or hitOnCh[3];
510 bool hitOnSt3 = hitOnCh[4] or hitOnCh[5];
511 bool hitOnSt4 = hitOnCh[6] or hitOnCh[7];
512 bool hitOnSt5 = hitOnCh[8] or hitOnCh[9];
513
514 return (hitOnSt1 and hitOnSt2 and hitOnSt3 and hitOnSt4 and hitOnSt5);
515}
516
517
518void AliAnalysisTaskLinkToMC::FillHistsFromMC()
519{
520 /// Fills the histogram containing findable tracks from the MC event information.
521 /// Only MC tracks for which the IsFindable method returns true are added
522 /// to the histogram.
523
524 for (Int_t i = 0; i < MCEvent()->GetNumberOfTracks(); i++)
525 {
7aad0c47 526 AliMCParticle* mcTrack = (AliMCParticle*) MCEvent()->GetTrack(i);
4c904d93 527
528 // Select only reconstructible tracks to fill into findable hist.
529 if (IsFindable(mcTrack))
530 {
531 fFindableHist->Fill(mcTrack->Pt(), mcTrack->Y());
532 }
533 }
534}
535
536
537void AliAnalysisTaskLinkToMC::FillHistsFromLinks(TMap& links)
538{
539 /// Fills the histograms containing found tracks and fake tracks.
540 /// Found tracks are all those that have a ESD muon track in the ESD event
541 /// and for which a corresponding MC track could be found.
542 /// Fake tracks are ESD muon tracks for which no corresponding MC track
543 /// could be matched so it is considered a fake track.
544 /// \param links This contains the mapping between ESD muon tracks and
545 /// MC tracks. ESD tracks for which no MC track could be matched should
546 /// have the "value" of the key/value pair in the mapping set to NULL.
547
548 TIter itmap(links.GetTable());
549 TPair* pair = NULL;
550 while ( (pair = static_cast<TPair*>(itmap())) != NULL )
551 {
552 if (pair->Value() != NULL)
553 {
554 AliESDMuonTrack* esdTrack = static_cast<AliESDMuonTrack*>(pair->Key());
555 fFoundHist->Fill(esdTrack->Pt(), esdTrack->Y());
556
557 AliMCParticle* mcTrack = static_cast<AliMCParticle*>(pair->Value());
558 fFoundHistMC->Fill(mcTrack->Pt(), mcTrack->Y());
559 }
560 else
561 {
562 AliESDMuonTrack* esdTrack = static_cast<AliESDMuonTrack*>(pair->Key());
563 fFakeHist->Fill(esdTrack->Pt(), esdTrack->Y());
564 }
565 }
566}
567
568
569void AliAnalysisTaskLinkToMC::CreateAODTracks(TMap& links)
570{
571 /// This code is copied from AliAnalysisTaskESDMuonFilter::ConvertESDtoAOD with
572 /// modifications to fill the MC track label using the ESD to MC track mapping.
573 /// \param links This is the mapping between ESD tracks and MC tracks.
574
575 // ESD Muon Filter analysis task executed for each event
576 AliESDEvent* esd = dynamic_cast<AliESDEvent*>(InputEvent());
7bd97ad1 577 // CHECK
578 if ( ! esd ) {
579 AliError("Cannot get input event");
580 return;
581 }
4c904d93 582
583 // Define arrays for muons
584 Double_t pos[3];
585 Double_t p[3];
586 Double_t pid[10];
587
588 // has to be changed once the muon pid is provided by the ESD
805be8a6 589 for (Int_t i = 0; i < 10; pid[i++] = 0.) {}
4c904d93 590 pid[AliAODTrack::kMuon]=1.;
591
592 AliAODHeader* header = AODEvent()->GetHeader();
593 AliAODTrack *aodTrack = 0x0;
594 AliESDMuonTrack *esdMuTrack = 0x0;
595
596 // Access to the AOD container of tracks
597 TClonesArray &tracks = *(AODEvent()->GetTracks());
598 Int_t jTracks = tracks.GetEntriesFast();
599
600 // Read primary vertex from AOD event
601 AliAODVertex *primary = AODEvent()->GetPrimaryVertex();
602 if (primary != NULL) primary->Print();
603
604 // Loop on muon tracks to fill the AOD track branch
605 Int_t nMuTracks = esd->GetNumberOfMuonTracks();
606 printf("Number of Muon Tracks=%d\n",nMuTracks);
607
608 // Update number of positive and negative tracks from AOD event (M.G.)
609 Int_t nPosTracks = header->GetRefMultiplicityPos();
610 Int_t nNegTracks = header->GetRefMultiplicityNeg();
611
612 for (Int_t nMuTrack = 0; nMuTrack < nMuTracks; ++nMuTrack)
613 {
614 esdMuTrack = esd->GetMuonTrack(nMuTrack);
615
616 //if (!esdMuTrack->ContainTrackerData()) continue;
617
618 UInt_t selectInfo = 0;
619
620 p[0] = esdMuTrack->Px();
621 p[1] = esdMuTrack->Py();
622 p[2] = esdMuTrack->Pz();
623
624 pos[0] = esdMuTrack->GetNonBendingCoor();
625 pos[1] = esdMuTrack->GetBendingCoor();
626 pos[2] = esdMuTrack->GetZ();
627
628 Int_t label = -1;
629 TPair* pair = static_cast<TPair*>( links.FindObject(esdMuTrack) );
630 if (pair != NULL and pair->Value() != NULL)
631 {
632 AliMCParticle* mcTrack = static_cast<AliMCParticle*>(pair->Value());
633 label = mcTrack->GetLabel();
634 if (label == -1)
635 {
636 AliWarning("The MC track was set to -1.");
637 }
638 }
639
640 aodTrack = new(tracks[jTracks++]) AliAODTrack(
641 esdMuTrack->GetUniqueID(), // ID
642 label, // label
643 p, // momentum
644 kTRUE, // cartesian coordinate system
645 pos, // position
646 kFALSE, // isDCA
647 0x0, // covariance matrix
648 esdMuTrack->Charge(), // charge
649 0, // ITSClusterMap
650 pid, // pid
651 primary, // primary vertex
652 kFALSE, // used for vertex fit?
653 kFALSE, // used for primary vertex fit?
654 AliAODTrack::kPrimary,// track type
655 selectInfo
656 );
657
658 aodTrack->SetXYAtDCA(esdMuTrack->GetNonBendingCoorAtDCA(), esdMuTrack->GetBendingCoorAtDCA());
659 aodTrack->SetPxPyPzAtDCA(esdMuTrack->PxAtDCA(), esdMuTrack->PyAtDCA(), esdMuTrack->PzAtDCA());
660 aodTrack->ConvertAliPIDtoAODPID();
661 aodTrack->SetChi2perNDF(esdMuTrack->GetChi2() / (2.*esdMuTrack->GetNHit() - 5.));
662 aodTrack->SetChi2MatchTrigger(esdMuTrack->GetChi2MatchTrigger());
663 aodTrack->SetHitsPatternInTrigCh(esdMuTrack->GetHitsPatternInTrigCh());
664 aodTrack->SetMuonClusterMap(esdMuTrack->GetMuonClusterMap());
665 aodTrack->SetMatchTrigger(esdMuTrack->GetMatchTrigger());
666
667 if (primary != NULL) primary->AddDaughter(aodTrack);
668
669 if (esdMuTrack->Charge() > 0) nPosTracks++;
670 else nNegTracks++;
671 }
672
673 header->SetRefMultiplicity(jTracks);
674 header->SetRefMultiplicityPos(nPosTracks);
675 header->SetRefMultiplicityNeg(nNegTracks);
676
677 // Note: we do not have to call PostData for the AOD because the AliAnalysisTaskSE
678 // base class already does so just after the UserExec.
679}
680
681
682void AliAnalysisTaskLinkToMC::FindLinksToMC(TMap& links)
683{
684 /// Finds all MC tracks that correspond to their ESD tracks and creates a
685 /// mapping between the ESD tracks and MC tracks which is filled into the
686 /// 'links' TMap object.
687 /// \param links This will be filled with the ESD and MC track pairs which
688 /// have been matched. Thus, for each ESD track which is set as the TMap key,
689 /// the corresponding MC track is identified by the TMap value. If no
690 /// MC track could be matched then the MC track value is set to NULL.
691
692 // Algorithm description for connecting reconstructed ESD muon tracks to MC:
693 //
694 // Build ESD track list
695 // Build MC track list
696 // while ESD track list not empty and MC track list not empty:
697 // Find ESD/MC track pair with best compatibility.
698 // if no pair is compatible then break loop.
699 // Store found pair in return list.
700 // Remove pair from ESD and MC track list.
701 // Mark remaining tracks in ESD track list as fakes.
702 //
703 // To find ESD/MC track pair with best compatibility:
704 // bestQuality := 1e100
705 // bestESDTrack := nil
706 // bestMCTrack := nil
707 // for each ESD track:
708 // for each MC track:
709 // chi^2 / numOfClustersMatched := calculate compatibility
710 // if tracks are compatible and chi^2 / numOfClustersMatched < bestQuality then:
711 // bestQuality := chi^2 / noOfClustersMatched
712 // bestESDTrack := current ESD track
713 // bestMCTrack := current MC track
714 //
715 // To calculate compatibility (ESD track, MC track):
716 // chi^2 := 1e100
717 // numberOfClustersAssociated := 0
718 // for each cluster in ESD track:
719 // find nearest 2 track refs from MC track
720 // if 2 track refs found then find average of them into MChit
721 // else MChit := nearest ref track.
722 // k := calculate chi^2 distance between ESD cluster and MChit
723 // if k <= maxValue then:
724 // chi^2 := chi^2 + k
725 // numberOfClustersAssociated := numberOfClustersAssociated + 1
726 // else:
727 // chi^2 := chi^2 + maxAllowedChi2
728 // if numberOfClustersAssociated >= minGoodClusters then:
729 // return (compatible, chi^2)
730 // else:
731 // return (not compatible, 1e100)
732
733 AliESDEvent* esd = static_cast<AliESDEvent*>(InputEvent());
734
735 TObjArray esdTracks;
736 TObjArray mcTracks;
737 for (Int_t i = 0; i < esd->GetNumberOfMuonTracks(); i++)
738 {
739 esdTracks.Add(esd->GetMuonTrack(i));
740 }
741 for (Int_t i = 0; i < MCEvent()->GetNumberOfTracks(); i++)
742 {
743 mcTracks.Add(MCEvent()->GetTrack(i));
744 }
745
746 while (not esdTracks.IsEmpty() and not mcTracks.IsEmpty())
747 {
748 Double_t bestQuality = 1e100;
749 Int_t bestNoOfClusters = 0;
750 AliESDMuonTrack* bestEsdTrack = NULL;
751 AliMCParticle* bestMcTrack = NULL;
752 TIter itesd(&esdTracks);
753 TIter itmc(&mcTracks);
754 AliESDMuonTrack* esdTrack = NULL;
755 AliMCParticle* mcTrack = NULL;
756
757 // Find the ESD and MC track pair that matches the best.
758 while ( (esdTrack = static_cast<AliESDMuonTrack*>(itesd())) != NULL )
759 {
760 while ( (mcTrack = static_cast<AliMCParticle*>(itmc())) != NULL )
761 {
762 Double_t chi2 = 1e100;
763 bool tracksCompatible = false;
764 Int_t noOfClusters = 0;
765 CalculateTrackCompatibility(esdTrack, mcTrack, tracksCompatible, chi2, noOfClusters);
766 Double_t quality = noOfClusters > 0 ? chi2 / Double_t(noOfClusters) : 1e100;
767 if (tracksCompatible and quality < bestQuality and noOfClusters >= bestNoOfClusters)
768 {
769 bestQuality = quality;
770 bestNoOfClusters = noOfClusters;
771 bestEsdTrack = esdTrack;
772 bestMcTrack = mcTrack;
773 }
774 }
775 itmc.Reset();
776 }
777
778 // If no track pair could be matched then we are done because we
779 // will not be able to match anything more next time.
780 if (bestMcTrack == NULL) break;
781
782 links.Add(bestEsdTrack, bestMcTrack);
783
784 esdTracks.Remove(bestEsdTrack);
785 mcTracks.Remove(bestMcTrack);
786 }
787
788 // Add all remaining ESD tracks which could not be matched to any MC track
789 // to the mapping but with NULL for the MC track.
790 TIter itesd(&esdTracks);
791 AliESDMuonTrack* esdTrack = NULL;
792 while ( (esdTrack = static_cast<AliESDMuonTrack*>(itesd())) != NULL )
793 {
794 links.Add(esdTrack, NULL);
795 }
796}
797
798
799void AliAnalysisTaskLinkToMC::CalculateTrackCompatibility(
800 AliESDMuonTrack* esdTrack, AliMCParticle* mcTrack,
801 bool& tracksCompatible, Double_t& chi2, Int_t& noOfClusters
802 )
803{
804 /// Calculates the compatibility between a ESD and MC track pair.
805 /// For each cluster of the ESD track, two track references are found
806 /// which are spatially closest to it. If the distance between the cluster
807 /// and track reference is larger than the HardCutLimit*() parameters then
808 /// the track reference is not used. The average coordinate is calculated
809 /// from the two track references found and the chi-square between the cluster
810 /// and average coordinate is calculated. If only one track reference is
811 /// found then it is used for the calculation without taking an average.
812 /// If no track references are found then the cluster is not matched and
813 /// we continue to the next cluster.
814 /// If the chi-squared value for the cluster / track reference pair is
815 /// larger than that allowed by the SigmaCut() parameter then the cluster
816 /// is also considered not to be matched.
817 /// The tracks are compatible if the ESD track has a minimum number of
818 /// clusters matched with MC track references from the MC track.
819 /// [in] \param esdTrack The ESD track we are trying to match.
820 /// [in] \param mcTrack The MC track we are trying to match the ESD track to.
821 /// [out] \param tracksCompatible Filled with true if the given esdTrack
822 /// and mcTrack are compatible.
823 /// [out] \param chi2 Filled with the total chi-squared calculated for all
824 /// matched clusters.
825 /// [out] \param noOfClusters Filled with the number of clusters that were
826 /// matched to at least one track reference.
827
828 chi2 = 0;
829 noOfClusters = 0;
830 tracksCompatible = false;
831 Int_t noOfClustersSt12 = 0;
832 Int_t noOfClustersSt45 = 0;
833 bool chamberMatched[14] = {
834 false, false, false, false, false, false, false,
835 false, false, false, false, false, false, false
836 };
837 bool stationMatched[7] = {
838 false, false, false, false, false, false, false
839 };
840
841 for (Int_t i = 0; i < esdTrack->GetNClusters(); i++)
842 {
843 AliESDMuonCluster* cluster = static_cast<AliESDMuonCluster*>( esdTrack->GetClusters()[i] );
844 Double_t varX = cluster->GetErrX2();
845 Double_t varY = cluster->GetErrY2();
846 // If the variance is zero then use the default one or just 1
847 // if the default is also not set.
848 if (varX == 0) varX = fVarX != 0 ? fVarX : 1.;
849 if (varY == 0) varY = fVarY != 0 ? fVarY : 1.;
850
851 Double_t chi2A = 1e100;
852 AliTrackReference* refA = NULL;
853 Double_t chi2B = 1e100;
854 AliTrackReference* refB = NULL;
855
856 for (Int_t j = 0; j < mcTrack->GetNumberOfTrackReferences(); j++)
857 {
858 AliTrackReference* ref = mcTrack->GetTrackReference(j);
859
860 if (ref->DetectorId() != AliTrackReference::kMUON) continue;
861 if (ref->UserId() != cluster->GetDetElemId()) continue;
862
863 Double_t dx = ref->X() - cluster->GetX();
864 if (TMath::Abs(dx) > fHardCutLimitX) continue;
865 Double_t dy = ref->Y() - cluster->GetY();
866 if (TMath::Abs(dy) > fHardCutLimitY) continue;
867 if (fUseZCoordinate)
868 {
869 Double_t dz = ref->Z() - cluster->GetZ();
870 if (TMath::Abs(dz) > fHardCutLimitZ) continue;
871 }
872
873 Double_t chi2sum = dx*dx / varX + dy*dy / varY;
874 if (chi2sum < chi2A)
875 {
876 // Copy track reference A to B and set new value for A
877 chi2B = chi2A;
878 refB = refA;
879 chi2A = chi2sum;
880 refA = ref;
881 }
882 else if (chi2sum < chi2B)
883 {
884 // Track reference A still has smaller chi2 so just replace B.
885 chi2B = chi2sum;
886 refB = ref;
887 }
888 }
889
890 Double_t x = 0, y = 0;
891 if (refA != NULL and refB != NULL)
892 {
893 // Average the track references if 2 were found.
894 x = (refA->X() + refB->X()) * 0.5;
895 y = (refA->Y() + refB->Y()) * 0.5;
896 }
897 else if (refA != NULL)
898 {
899 x = refA->X();
900 y = refA->Y();
901 }
902 else
903 {
904 continue; // no track reference hit found.
905 }
906
907 Double_t dx = x - cluster->GetX();
908 Double_t dy = y - cluster->GetY();
909
910 Double_t chi2x = dx*dx / varX;
911 if (chi2x > fSigmaCut2) continue;
912 Double_t chi2y = dy*dy / varY;
913 if (chi2y > fSigmaCut2) continue;
914
915 chi2 += chi2x + chi2y;
916 noOfClusters++;
917 if (cluster->GetChamberId() >= 0 and cluster->GetChamberId() < 4)
918 {
919 noOfClustersSt12++;
920 }
921 if (cluster->GetChamberId() >= 6 and cluster->GetChamberId() < 10)
922 {
923 noOfClustersSt45++;
924 }
925
926 if (0 <= cluster->GetChamberId() and cluster->GetChamberId() < 14)
927 {
928 chamberMatched[cluster->GetChamberId()] = true;
929 stationMatched[cluster->GetChamberId()/2] = true;
930 }
931 }
932
933 // Need to check that all the chambers and stations that had to match we
934 // actually found matching track references.
935
936 bool forcedChambersMatched = true;
937 for (Int_t i = 0; i < 14; i++)
938 {
939 if (fChamberMustMatch[i] and not chamberMatched[i])
940 {
941 forcedChambersMatched = false;
942 }
943 }
944 bool forcedStationsMatched = true;
945 for (Int_t i = 0; i < 7; i++)
946 {
947 if (fStationMustMatch[i] and not stationMatched[i])
948 {
949 forcedStationsMatched = false;
950 }
951 }
952
953 if (noOfClusters >= fMinClusters and
954 noOfClustersSt12 >= fMinClustersInSt12 and
955 noOfClustersSt45 >= fMinClustersInSt45 and
956 forcedChambersMatched and forcedStationsMatched
957 )
958 {
959 tracksCompatible = true;
960 }
961}
962