]>
Commit | Line | Data |
---|---|---|
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 | ||
88cb7938 | 16 | /* $Id$ */ |
a9e2aefa | 17 | |
3831f268 | 18 | /////////////////////////////////////////////////// |
a9e2aefa | 19 | // |
3831f268 | 20 | // Reconstructed track |
21 | // in | |
22 | // ALICE | |
23 | // dimuon | |
24 | // spectrometer | |
25 | // | |
26 | /////////////////////////////////////////////////// | |
a9e2aefa | 27 | |
70479d0e | 28 | #include <Riostream.h> // for cout |
82a4bc7b | 29 | #include <stdlib.h> // for exit() |
a9e2aefa | 30 | |
31 | #include <TClonesArray.h> | |
04b5ea16 | 32 | #include <TMath.h> |
d0bfce8d | 33 | #include <TMatrixD.h> |
8429a5e4 | 34 | #include <TObjArray.h> |
956019b6 | 35 | #include <TVirtualFitter.h> |
a9e2aefa | 36 | |
37 | #include "AliMUONEventReconstructor.h" | |
38 | #include "AliMUONHitForRec.h" | |
39 | #include "AliMUONSegment.h" | |
3831f268 | 40 | #include "AliMUONTrack.h" |
a9e2aefa | 41 | #include "AliMUONTrackHit.h" |
42 | ||
04b5ea16 | 43 | // Functions to be minimized with Minuit |
a9e2aefa | 44 | void TrackChi2(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag); |
04b5ea16 | 45 | void TrackChi2MCS(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag); |
46 | ||
44f59652 | 47 | void mnvertLocal(Double_t* a, Int_t l, Int_t m, Int_t n, Int_t& ifail); |
48 | ||
04b5ea16 | 49 | Double_t MultipleScatteringAngle2(AliMUONTrackHit *TrackHit); |
a9e2aefa | 50 | |
51 | ClassImp(AliMUONTrack) // Class implementation in ROOT context | |
52 | ||
956019b6 | 53 | TVirtualFitter* AliMUONTrack::fgFitter = NULL; |
54 | ||
a9e2aefa | 55 | //__________________________________________________________________________ |
56 | AliMUONTrack::AliMUONTrack(AliMUONSegment* BegSegment, AliMUONSegment* EndSegment, AliMUONEventReconstructor* EventReconstructor) | |
57 | { | |
58 | // Constructor from two Segment's | |
59 | fEventReconstructor = EventReconstructor; // link back to EventReconstructor | |
8429a5e4 | 60 | // memory allocation for the TObjArray of pointers to reconstructed TrackHit's |
61 | fTrackHitsPtr = new TObjArray(10); | |
a9e2aefa | 62 | fNTrackHits = 0; |
63 | AddSegment(BegSegment); // add hits from BegSegment | |
64 | AddSegment(EndSegment); // add hits from EndSegment | |
65 | fTrackHitsPtr->Sort(); // sort TrackHits according to increasing Z | |
66 | SetTrackParamAtVertex(); // set track parameters at vertex | |
8429a5e4 | 67 | // set fit conditions... |
04b5ea16 | 68 | fFitMCS = 0; |
956019b6 | 69 | fFitNParam = 3; |
70 | fFitStart = 1; | |
8429a5e4 | 71 | fFitFMin = -1.0; |
a9e2aefa | 72 | return; |
73 | } | |
74 | ||
75 | //__________________________________________________________________________ | |
76 | AliMUONTrack::AliMUONTrack(AliMUONSegment* Segment, AliMUONHitForRec* HitForRec, AliMUONEventReconstructor* EventReconstructor) | |
77 | { | |
78 | // Constructor from one Segment and one HitForRec | |
79 | fEventReconstructor = EventReconstructor; // link back to EventReconstructor | |
8429a5e4 | 80 | // memory allocation for the TObjArray of pointers to reconstructed TrackHit's |
81 | fTrackHitsPtr = new TObjArray(10); | |
a9e2aefa | 82 | fNTrackHits = 0; |
83 | AddSegment(Segment); // add hits from Segment | |
84 | AddHitForRec(HitForRec); // add HitForRec | |
85 | fTrackHitsPtr->Sort(); // sort TrackHits according to increasing Z | |
86 | SetTrackParamAtVertex(); // set track parameters at vertex | |
8429a5e4 | 87 | // set fit conditions... |
04b5ea16 | 88 | fFitMCS = 0; |
956019b6 | 89 | fFitNParam = 3; |
90 | fFitStart = 1; | |
8429a5e4 | 91 | fFitFMin = -1.0; |
a9e2aefa | 92 | return; |
93 | } | |
94 | ||
8429a5e4 | 95 | //__________________________________________________________________________ |
96 | AliMUONTrack::~AliMUONTrack() | |
97 | { | |
98 | // Destructor | |
99 | if (fTrackHitsPtr) { | |
100 | delete fTrackHitsPtr; // delete the TObjArray of pointers to TrackHit's | |
101 | fTrackHitsPtr = NULL; | |
102 | } | |
103 | } | |
104 | ||
956019b6 | 105 | //__________________________________________________________________________ |
d9a3473d | 106 | AliMUONTrack::AliMUONTrack (const AliMUONTrack& MUONTrack):TObject(MUONTrack) |
a9e2aefa | 107 | { |
61adb9bd | 108 | fEventReconstructor = new AliMUONEventReconstructor(*MUONTrack.fEventReconstructor); |
c6ce342a | 109 | fTrackParamAtVertex = MUONTrack.fTrackParamAtVertex; |
61adb9bd | 110 | fTrackHitsPtr = new TObjArray(*MUONTrack.fTrackHitsPtr); |
c6ce342a | 111 | fNTrackHits = MUONTrack.fNTrackHits; |
112 | fFitMCS = MUONTrack.fFitMCS; | |
113 | fFitNParam = MUONTrack.fFitNParam; | |
114 | fFitFMin = MUONTrack.fFitFMin; | |
61adb9bd | 115 | fFitStart = MUONTrack.fFitStart; |
a9e2aefa | 116 | } |
117 | ||
956019b6 | 118 | //__________________________________________________________________________ |
61adb9bd | 119 | AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& MUONTrack) |
a9e2aefa | 120 | { |
61adb9bd | 121 | if (this == &MUONTrack) |
a9e2aefa | 122 | return *this; |
61adb9bd | 123 | |
124 | fEventReconstructor = new AliMUONEventReconstructor(*MUONTrack.fEventReconstructor); | |
125 | fTrackParamAtVertex = MUONTrack.fTrackParamAtVertex; | |
126 | fTrackHitsPtr = new TObjArray(*MUONTrack.fTrackHitsPtr); | |
127 | fNTrackHits = MUONTrack.fNTrackHits; | |
128 | fFitMCS = MUONTrack.fFitMCS; | |
129 | fFitNParam = MUONTrack.fFitNParam; | |
130 | fFitFMin = MUONTrack.fFitFMin; | |
131 | fFitStart = MUONTrack.fFitStart; | |
132 | return *this; | |
a9e2aefa | 133 | } |
134 | ||
8429a5e4 | 135 | //__________________________________________________________________________ |
136 | void AliMUONTrack::Remove() | |
137 | { | |
138 | // Remove current track from array of tracks, | |
139 | // and corresponding track hits from array of track hits. | |
140 | // Compress the TClonesArray it belongs to. | |
141 | AliMUONTrackHit *nextTrackHit; | |
142 | AliMUONEventReconstructor *eventRec = this->fEventReconstructor; | |
143 | TClonesArray *trackHitsPtr = eventRec->GetRecTrackHitsPtr(); | |
144 | // Loop over all track hits of track | |
145 | AliMUONTrackHit *trackHit = (AliMUONTrackHit*) fTrackHitsPtr->First(); | |
146 | while (trackHit) { | |
147 | nextTrackHit = (AliMUONTrackHit*) fTrackHitsPtr->After(trackHit); | |
148 | // Remove TrackHit from event TClonesArray. | |
149 | // Destructor is called, | |
150 | // hence links between HitForRec's and TrackHit's are updated | |
151 | trackHitsPtr->Remove(trackHit); | |
152 | trackHit = nextTrackHit; | |
153 | } | |
154 | // Remove the track from event TClonesArray | |
155 | // Destructor is called, | |
156 | // hence space for TObjArray of pointers to TrackHit's is freed | |
157 | eventRec->GetRecTracksPtr()->Remove(this); | |
158 | // Number of tracks decreased by 1 | |
159 | eventRec->SetNRecTracks(eventRec->GetNRecTracks() - 1); | |
160 | // Compress event TClonesArray of Track's: | |
161 | // this is essential to retrieve the TClonesArray afterwards | |
162 | eventRec->GetRecTracksPtr()->Compress(); | |
163 | // Compress event TClonesArray of TrackHit's: | |
164 | // this is probably also essential to retrieve the TClonesArray afterwards | |
165 | trackHitsPtr->Compress(); | |
166 | } | |
167 | ||
04b5ea16 | 168 | //__________________________________________________________________________ |
169 | void AliMUONTrack::SetFitMCS(Int_t FitMCS) | |
170 | { | |
956019b6 | 171 | // Set multiple Coulomb scattering option for track fit "fFitMCS" |
04b5ea16 | 172 | // from "FitMCS" argument: 0 without, 1 with |
956019b6 | 173 | if ((FitMCS == 0) || (FitMCS == 1)) fFitMCS = FitMCS; |
04b5ea16 | 174 | // better implementation with enum(with, without) ???? |
956019b6 | 175 | else { |
176 | cout << "ERROR in AliMUONTrack::SetFitMCS(FitMCS)" << endl; | |
177 | cout << "FitMCS = " << FitMCS << " is neither 0 nor 1" << endl; | |
178 | exit(0); | |
179 | } | |
180 | return; | |
181 | } | |
182 | ||
183 | //__________________________________________________________________________ | |
184 | void AliMUONTrack::SetFitNParam(Int_t FitNParam) | |
185 | { | |
186 | // Set number of parameters for track fit "fFitNParam" from "FitNParam": | |
187 | // 3 for momentum, 5 for momentum and position | |
188 | if ((FitNParam == 3) || (FitNParam == 5)) fFitNParam = FitNParam; | |
189 | else { | |
190 | cout << "ERROR in AliMUONTrack::SetFitNParam(FitNParam)" << endl; | |
191 | cout << "FitNParam = " << FitNParam << " is neither 3 nor 5" << endl; | |
192 | exit(0); | |
193 | } | |
194 | return; | |
195 | } | |
196 | ||
197 | //__________________________________________________________________________ | |
198 | void AliMUONTrack::SetFitStart(Int_t FitStart) | |
199 | { | |
200 | // Set multiple Coulomb scattering option for track fit "fFitStart" | |
201 | // from "FitStart" argument: 0 without, 1 with | |
202 | if ((FitStart == 0) || (FitStart == 1)) fFitStart = FitStart; | |
203 | // better implementation with enum(vertex, firstHit) ???? | |
204 | else { | |
205 | cout << "ERROR in AliMUONTrack::SetFitStart(FitStart)" << endl; | |
206 | cout << "FitStart = " << FitStart << " is neither 0 nor 1" << endl; | |
207 | exit(0); | |
208 | } | |
04b5ea16 | 209 | return; |
210 | } | |
211 | ||
956019b6 | 212 | //__________________________________________________________________________ |
3831f268 | 213 | AliMUONTrackParam* AliMUONTrack::GetTrackParamAtFirstHit(void) const { |
a9e2aefa | 214 | // Get pointer to TrackParamAtFirstHit |
215 | return ((AliMUONTrackHit*) (fTrackHitsPtr->First()))->GetTrackParam();} | |
a9e2aefa | 216 | |
217 | //__________________________________________________________________________ | |
3831f268 | 218 | void AliMUONTrack::RecursiveDump(void) const |
a9e2aefa | 219 | { |
220 | // Recursive dump of AliMUONTrack, i.e. with dump of TrackHit's and HitForRec's | |
221 | AliMUONTrackHit *trackHit; | |
222 | AliMUONHitForRec *hitForRec; | |
223 | cout << "Recursive dump of Track: " << this << endl; | |
224 | // Track | |
225 | this->Dump(); | |
226 | for (Int_t trackHitIndex = 0; trackHitIndex < fNTrackHits; trackHitIndex++) { | |
227 | trackHit = (AliMUONTrackHit*) ((*fTrackHitsPtr)[trackHitIndex]); | |
228 | // TrackHit | |
229 | cout << "TrackHit: " << trackHit << " (index: " << trackHitIndex << ")" << endl; | |
230 | trackHit->Dump(); | |
231 | hitForRec = trackHit->GetHitForRecPtr(); | |
232 | // HitForRec | |
233 | cout << "HitForRec: " << hitForRec << endl; | |
234 | hitForRec->Dump(); | |
235 | } | |
236 | return; | |
237 | } | |
238 | ||
8429a5e4 | 239 | //__________________________________________________________________________ |
240 | Int_t AliMUONTrack::HitsInCommon(AliMUONTrack* Track) | |
241 | { | |
242 | // Returns the number of hits in common | |
243 | // between the current track ("this") | |
244 | // and the track pointed to by "Track". | |
245 | Int_t hitsInCommon = 0; | |
246 | AliMUONTrackHit *trackHit1, *trackHit2; | |
247 | // Loop over hits of first track | |
248 | trackHit1 = (AliMUONTrackHit*) this->GetTrackHitsPtr()->First(); | |
249 | while (trackHit1) { | |
250 | // Loop over hits of second track | |
251 | trackHit2 = (AliMUONTrackHit*) Track->GetTrackHitsPtr()->First(); | |
252 | while (trackHit2) { | |
253 | // Increment "hitsInCommon" if both TrackHits point to the same HitForRec | |
254 | if ( (trackHit1->GetHitForRecPtr()) == | |
255 | (trackHit2->GetHitForRecPtr()) ) hitsInCommon++; | |
256 | trackHit2 = (AliMUONTrackHit*) Track->GetTrackHitsPtr()->After(trackHit2); | |
257 | } // trackHit2 | |
258 | trackHit1 = (AliMUONTrackHit*) this->GetTrackHitsPtr()->After(trackHit1); | |
259 | } // trackHit1 | |
260 | return hitsInCommon; | |
261 | } | |
262 | ||
a9e2aefa | 263 | //__________________________________________________________________________ |
956019b6 | 264 | void AliMUONTrack::Fit() |
a9e2aefa | 265 | { |
266 | // Fit the current track ("this"), | |
956019b6 | 267 | // with or without multiple Coulomb scattering according to "fFitMCS", |
268 | // with the number of parameters given by "fFitNParam" | |
269 | // (3 if one keeps X and Y fixed in "TrackParam", 5 if one lets them vary), | |
270 | // starting, according to "fFitStart", | |
271 | // with track parameters at vertex or at the first TrackHit. | |
272 | // "fFitMCS", "fFitNParam" and "fFitStart" have to be set before | |
273 | // by calling the corresponding Set methods. | |
a9e2aefa | 274 | Double_t arg[1], benC, errorParam, invBenP, lower, nonBenC, upper, x, y; |
956019b6 | 275 | char parName[50]; |
276 | AliMUONTrackParam *trackParam; | |
277 | // Check if Minuit is initialized... | |
278 | fgFitter = TVirtualFitter::Fitter(this); // add 3 or 5 for the maximum number of parameters ??? | |
279 | fgFitter->Clear(); // necessary ???? probably yes | |
280 | // how to reset the printout number at every fit ???? | |
281 | // is there any risk to leave it like that ???? | |
a9e2aefa | 282 | // how to go faster ???? choice of Minuit parameters like EDM ???? |
04b5ea16 | 283 | // choice of function to be minimized according to fFitMCS |
956019b6 | 284 | if (fFitMCS == 0) fgFitter->SetFCN(TrackChi2); |
285 | else fgFitter->SetFCN(TrackChi2MCS); | |
3a416225 | 286 | // Switch off printout |
d0bfce8d | 287 | arg[0] = -1; |
956019b6 | 288 | fgFitter->ExecuteCommand("SET PRINT", arg, 1); // More printing !!!! |
19dd5b2f | 289 | // No warnings |
290 | fgFitter->ExecuteCommand("SET NOW", arg, 0); | |
956019b6 | 291 | // Parameters according to "fFitStart" |
292 | // (should be a function to be used at every place where needed ????) | |
293 | if (fFitStart == 0) trackParam = &fTrackParamAtVertex; | |
294 | else trackParam = this->GetTrackParamAtFirstHit(); | |
295 | // set first 3 Minuit parameters | |
04b5ea16 | 296 | // could be tried with no limits for the search (min=max=0) ???? |
956019b6 | 297 | fgFitter->SetParameter(0, "InvBenP", |
298 | trackParam->GetInverseBendingMomentum(), | |
299 | 0.003, -0.4, 0.4); | |
300 | fgFitter->SetParameter(1, "BenS", | |
301 | trackParam->GetBendingSlope(), | |
302 | 0.001, -0.5, 0.5); | |
303 | fgFitter->SetParameter(2, "NonBenS", | |
304 | trackParam->GetNonBendingSlope(), | |
305 | 0.001, -0.5, 0.5); | |
306 | if (fFitNParam == 5) { | |
d0bfce8d | 307 | // set last 2 Minuit parameters |
308 | // mandatory limits in Bending to avoid NaN values of parameters | |
956019b6 | 309 | fgFitter->SetParameter(3, "X", |
310 | trackParam->GetNonBendingCoor(), | |
d0bfce8d | 311 | 0.03, -500.0, 500.0); |
312 | // mandatory limits in non Bending to avoid NaN values of parameters | |
956019b6 | 313 | fgFitter->SetParameter(4, "Y", |
314 | trackParam->GetBendingCoor(), | |
d0bfce8d | 315 | 0.10, -500.0, 500.0); |
a9e2aefa | 316 | } |
317 | // search without gradient calculation in the function | |
956019b6 | 318 | fgFitter->ExecuteCommand("SET NOGRADIENT", arg, 0); |
a9e2aefa | 319 | // minimization |
956019b6 | 320 | fgFitter->ExecuteCommand("MINIMIZE", arg, 0); |
a9e2aefa | 321 | // exit from Minuit |
17235410 | 322 | // fgFitter->ExecuteCommand("EXIT", arg, 0); // necessary ???? |
956019b6 | 323 | // get results into "invBenP", "benC", "nonBenC" ("x", "y") |
324 | fgFitter->GetParameter(0, parName, invBenP, errorParam, lower, upper); | |
325 | fgFitter->GetParameter(1, parName, benC, errorParam, lower, upper); | |
326 | fgFitter->GetParameter(2, parName, nonBenC, errorParam, lower, upper); | |
327 | if (fFitNParam == 5) { | |
328 | fgFitter->GetParameter(3, parName, x, errorParam, lower, upper); | |
329 | fgFitter->GetParameter(4, parName, y, errorParam, lower, upper); | |
a9e2aefa | 330 | } |
331 | // result of the fit into track parameters | |
956019b6 | 332 | trackParam->SetInverseBendingMomentum(invBenP); |
333 | trackParam->SetBendingSlope(benC); | |
334 | trackParam->SetNonBendingSlope(nonBenC); | |
335 | if (fFitNParam == 5) { | |
336 | trackParam->SetNonBendingCoor(x); | |
337 | trackParam->SetBendingCoor(y); | |
a9e2aefa | 338 | } |
8429a5e4 | 339 | // global result of the fit |
340 | Double_t fedm, errdef; | |
341 | Int_t npari, nparx; | |
342 | fgFitter->GetStats(fFitFMin, fedm, errdef, npari, nparx); | |
a9e2aefa | 343 | } |
344 | ||
345 | //__________________________________________________________________________ | |
346 | void AliMUONTrack::AddSegment(AliMUONSegment* Segment) | |
347 | { | |
8429a5e4 | 348 | // Add Segment to the track |
a9e2aefa | 349 | AddHitForRec(Segment->GetHitForRec1()); // 1st hit |
350 | AddHitForRec(Segment->GetHitForRec2()); // 2nd hit | |
351 | } | |
352 | ||
353 | //__________________________________________________________________________ | |
354 | void AliMUONTrack::AddHitForRec(AliMUONHitForRec* HitForRec) | |
355 | { | |
8429a5e4 | 356 | // Add HitForRec to the track: |
357 | // actual TrackHit into TClonesArray of TrackHit's for the event; | |
358 | // pointer to actual TrackHit in TObjArray of pointers to TrackHit's for the track | |
359 | TClonesArray *recTrackHitsPtr = this->fEventReconstructor->GetRecTrackHitsPtr(); | |
360 | Int_t eventTrackHits = this->fEventReconstructor->GetNRecTrackHits(); | |
361 | // event | |
362 | AliMUONTrackHit* trackHit = | |
363 | new ((*recTrackHitsPtr)[eventTrackHits]) AliMUONTrackHit(HitForRec); | |
364 | this->fEventReconstructor->SetNRecTrackHits(eventTrackHits + 1); | |
365 | // track | |
366 | fTrackHitsPtr->Add(trackHit); | |
a9e2aefa | 367 | fNTrackHits++; |
368 | } | |
369 | ||
370 | //__________________________________________________________________________ | |
3831f268 | 371 | void AliMUONTrack::SetTrackParamAtHit(Int_t indexHit, AliMUONTrackParam *TrackParam) const |
a9e2aefa | 372 | { |
373 | // Set track parameters at TrackHit with index "indexHit" | |
374 | // from the track parameters pointed to by "TrackParam". | |
2682e810 | 375 | //PH AliMUONTrackHit* trackHit = (AliMUONTrackHit*) ((*fTrackHitsPtr)[indexHit]); |
376 | AliMUONTrackHit* trackHit = (AliMUONTrackHit*) (fTrackHitsPtr->At(indexHit)); | |
a9e2aefa | 377 | trackHit->SetTrackParam(TrackParam); |
378 | } | |
379 | ||
380 | //__________________________________________________________________________ | |
381 | void AliMUONTrack::SetTrackParamAtVertex() | |
382 | { | |
383 | // Set track parameters at vertex. | |
384 | // TrackHit's are assumed to be only in stations(1..) 4 and 5, | |
385 | // and sorted according to increasing Z.. | |
386 | // Parameters are calculated from information in HitForRec's | |
387 | // of first and last TrackHit's. | |
388 | AliMUONTrackParam *trackParam = | |
389 | &fTrackParamAtVertex; // pointer to track parameters | |
390 | // Pointer to HitForRec of first TrackHit | |
391 | AliMUONHitForRec *firstHit = | |
392 | ((AliMUONTrackHit*) (fTrackHitsPtr->First()))->GetHitForRecPtr(); | |
393 | // Pointer to HitForRec of last TrackHit | |
394 | AliMUONHitForRec *lastHit = | |
395 | ((AliMUONTrackHit*) (fTrackHitsPtr->Last()))->GetHitForRecPtr(); | |
396 | // Z difference between first and last hits | |
397 | Double_t deltaZ = firstHit->GetZ() - lastHit->GetZ(); | |
398 | // bending slope in stations(1..) 4 and 5 | |
399 | Double_t bendingSlope = | |
400 | (firstHit->GetBendingCoor() - lastHit->GetBendingCoor()) / deltaZ; | |
401 | trackParam->SetBendingSlope(bendingSlope); | |
402 | // impact parameter | |
403 | Double_t impactParam = | |
404 | firstHit->GetBendingCoor() - bendingSlope * firstHit->GetZ(); // same if from firstHit and lastHit ???? | |
405 | // signed bending momentum | |
406 | Double_t signedBendingMomentum = | |
407 | fEventReconstructor->GetBendingMomentumFromImpactParam(impactParam); | |
408 | trackParam->SetInverseBendingMomentum(1.0 / signedBendingMomentum); | |
409 | // bending slope at vertex | |
410 | trackParam-> | |
411 | SetBendingSlope(bendingSlope + | |
412 | impactParam / fEventReconstructor->GetSimpleBPosition()); | |
413 | // non bending slope | |
414 | Double_t nonBendingSlope = | |
415 | (firstHit->GetNonBendingCoor() - lastHit->GetNonBendingCoor()) / deltaZ; | |
416 | trackParam->SetNonBendingSlope(nonBendingSlope); | |
417 | // vertex coordinates at (0,0,0) | |
418 | trackParam->SetZ(0.0); | |
419 | trackParam->SetBendingCoor(0.0); | |
420 | trackParam->SetNonBendingCoor(0.0); | |
421 | } | |
422 | ||
423 | //__________________________________________________________________________ | |
d9a3473d | 424 | void TrackChi2(Int_t &NParam, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/) |
a9e2aefa | 425 | { |
426 | // Return the "Chi2" to be minimized with Minuit for track fitting, | |
427 | // with "NParam" parameters | |
428 | // and their current values in array pointed to by "Param". | |
429 | // Assumes that the track hits are sorted according to increasing Z. | |
430 | // Track parameters at each TrackHit are updated accordingly. | |
04b5ea16 | 431 | // Multiple Coulomb scattering is not taken into account |
956019b6 | 432 | AliMUONTrack *trackBeingFitted; |
a9e2aefa | 433 | AliMUONTrackHit* hit; |
434 | AliMUONTrackParam param1; | |
435 | Int_t hitNumber; | |
436 | Double_t zHit; | |
437 | Chi2 = 0.0; // initialize Chi2 | |
438 | // copy of track parameters to be fitted | |
956019b6 | 439 | trackBeingFitted = (AliMUONTrack*) AliMUONTrack::Fitter()->GetObjectFit(); |
440 | if (trackBeingFitted->GetFitStart() == 0) | |
441 | param1 = *(trackBeingFitted->GetTrackParamAtVertex()); | |
442 | else param1 = *(trackBeingFitted->GetTrackParamAtFirstHit()); | |
a9e2aefa | 443 | // Minuit parameters to be fitted into this copy |
444 | param1.SetInverseBendingMomentum(Param[0]); | |
445 | param1.SetBendingSlope(Param[1]); | |
446 | param1.SetNonBendingSlope(Param[2]); | |
447 | if (NParam == 5) { | |
448 | param1.SetNonBendingCoor(Param[3]); | |
449 | param1.SetBendingCoor(Param[4]); | |
450 | } | |
451 | // Follow track through all planes of track hits | |
452 | for (hitNumber = 0; hitNumber < trackBeingFitted->GetNTrackHits(); hitNumber++) { | |
453 | hit = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber]; | |
454 | zHit = hit->GetHitForRecPtr()->GetZ(); | |
455 | // do something special if 2 hits with same Z ???? | |
456 | // security against infinite loop ???? | |
457 | (¶m1)->ExtrapToZ(zHit); // extrapolation | |
458 | hit->SetTrackParam(¶m1); | |
459 | // Increment Chi2 | |
460 | // done hit per hit, with hit resolution, | |
461 | // and not with point and angle like in "reco_muon.F" !!!! | |
462 | // Needs to add multiple scattering contribution ???? | |
463 | Double_t dX = | |
464 | hit->GetHitForRecPtr()->GetNonBendingCoor() - (¶m1)->GetNonBendingCoor(); | |
465 | Double_t dY = | |
466 | hit->GetHitForRecPtr()->GetBendingCoor() - (¶m1)->GetBendingCoor(); | |
467 | Chi2 = | |
468 | Chi2 + | |
469 | dX * dX / hit->GetHitForRecPtr()->GetNonBendingReso2() + | |
470 | dY * dY / hit->GetHitForRecPtr()->GetBendingReso2(); | |
471 | } | |
472 | } | |
04b5ea16 | 473 | |
474 | //__________________________________________________________________________ | |
d9a3473d | 475 | void TrackChi2MCS(Int_t &NParam, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/) |
04b5ea16 | 476 | { |
477 | // Return the "Chi2" to be minimized with Minuit for track fitting, | |
478 | // with "NParam" parameters | |
479 | // and their current values in array pointed to by "Param". | |
480 | // Assumes that the track hits are sorted according to increasing Z. | |
481 | // Track parameters at each TrackHit are updated accordingly. | |
482 | // Multiple Coulomb scattering is taken into account with covariance matrix. | |
956019b6 | 483 | AliMUONTrack *trackBeingFitted; |
04b5ea16 | 484 | AliMUONTrackParam param1; |
485 | Chi2 = 0.0; // initialize Chi2 | |
486 | // copy of track parameters to be fitted | |
956019b6 | 487 | trackBeingFitted = (AliMUONTrack*) AliMUONTrack::Fitter()->GetObjectFit(); |
488 | if (trackBeingFitted->GetFitStart() == 0) | |
489 | param1 = *(trackBeingFitted->GetTrackParamAtVertex()); | |
490 | else param1 = *(trackBeingFitted->GetTrackParamAtFirstHit()); | |
04b5ea16 | 491 | // Minuit parameters to be fitted into this copy |
492 | param1.SetInverseBendingMomentum(Param[0]); | |
493 | param1.SetBendingSlope(Param[1]); | |
494 | param1.SetNonBendingSlope(Param[2]); | |
495 | if (NParam == 5) { | |
496 | param1.SetNonBendingCoor(Param[3]); | |
497 | param1.SetBendingCoor(Param[4]); | |
498 | } | |
499 | ||
956019b6 | 500 | AliMUONTrackHit *hit; |
bbe35c23 | 501 | Int_t chCurrent, chPrev = 0, hitNumber, hitNumber1, hitNumber2, hitNumber3; |
eb9c9dab | 502 | Double_t z, z1, z2, z3; |
503 | AliMUONTrackHit *hit1, *hit2, *hit3; | |
504 | Double_t hbc1, hbc2, pbc1, pbc2; | |
505 | Double_t hnbc1, hnbc2, pnbc1, pnbc2; | |
506 | Int_t numberOfHit = trackBeingFitted->GetNTrackHits(); | |
d0bfce8d | 507 | TMatrixD *covBending = new TMatrixD(numberOfHit, numberOfHit); |
508 | TMatrixD *covNonBending = new TMatrixD(numberOfHit, numberOfHit); | |
eb9c9dab | 509 | Double_t *msa2 = new Double_t[numberOfHit]; |
04b5ea16 | 510 | |
511 | // Predicted coordinates and multiple scattering angles are first calculated | |
512 | for (hitNumber = 0; hitNumber < numberOfHit; hitNumber++) { | |
513 | hit = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber]; | |
eb9c9dab | 514 | z = hit->GetHitForRecPtr()->GetZ(); |
04b5ea16 | 515 | // do something special if 2 hits with same Z ???? |
516 | // security against infinite loop ???? | |
eb9c9dab | 517 | (¶m1)->ExtrapToZ(z); // extrapolation |
04b5ea16 | 518 | hit->SetTrackParam(¶m1); |
eb9c9dab | 519 | // square of multiple scattering angle at current hit, with one chamber |
520 | msa2[hitNumber] = MultipleScatteringAngle2(hit); | |
521 | // correction for eventual missing hits or multiple hits in a chamber, | |
522 | // according to the number of chambers | |
523 | // between the current hit and the previous one | |
524 | chCurrent = hit->GetHitForRecPtr()->GetChamberNumber(); | |
525 | if (hitNumber > 0) msa2[hitNumber] = msa2[hitNumber] * (chCurrent - chPrev); | |
526 | chPrev = chCurrent; | |
04b5ea16 | 527 | } |
528 | ||
529 | // Calculates the covariance matrix | |
eb9c9dab | 530 | for (hitNumber1 = 0; hitNumber1 < numberOfHit; hitNumber1++) { |
531 | hit1 = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber1]; | |
532 | z1 = hit1->GetHitForRecPtr()->GetZ(); | |
04b5ea16 | 533 | for (hitNumber2 = hitNumber1; hitNumber2 < numberOfHit; hitNumber2++) { |
eb9c9dab | 534 | hit2 = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber2]; |
535 | z2 = hit2->GetHitForRecPtr()->GetZ(); | |
956019b6 | 536 | // initialization to 0 (diagonal plus upper triangular part) |
537 | (*covBending)(hitNumber2, hitNumber1) = 0.0; | |
538 | // contribution from multiple scattering in bending plane: | |
539 | // loop over upstream hits | |
540 | for (hitNumber3 = 0; hitNumber3 < hitNumber1; hitNumber3++) { | |
eb9c9dab | 541 | hit3 = (AliMUONTrackHit*) |
542 | (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber3]; | |
543 | z3 = hit3->GetHitForRecPtr()->GetZ(); | |
04b5ea16 | 544 | (*covBending)(hitNumber2, hitNumber1) = |
545 | (*covBending)(hitNumber2, hitNumber1) + | |
eb9c9dab | 546 | ((z1 - z3) * (z2 - z3) * msa2[hitNumber3]); |
956019b6 | 547 | } |
548 | // equal contribution from multiple scattering in non bending plane | |
04b5ea16 | 549 | (*covNonBending)(hitNumber2, hitNumber1) = |
550 | (*covBending)(hitNumber2, hitNumber1); | |
956019b6 | 551 | if (hitNumber1 == hitNumber2) { |
552 | // Diagonal elements: add contribution from position measurements | |
553 | // in bending plane | |
554 | (*covBending)(hitNumber2, hitNumber1) = | |
eb9c9dab | 555 | (*covBending)(hitNumber2, hitNumber1) + |
556 | hit1->GetHitForRecPtr()->GetBendingReso2(); | |
956019b6 | 557 | // and in non bending plane |
04b5ea16 | 558 | (*covNonBending)(hitNumber2, hitNumber1) = |
eb9c9dab | 559 | (*covNonBending)(hitNumber2, hitNumber1) + |
560 | hit1->GetHitForRecPtr()->GetNonBendingReso2(); | |
956019b6 | 561 | } |
562 | else { | |
563 | // Non diagonal elements: symmetrization | |
564 | // for bending plane | |
565 | (*covBending)(hitNumber1, hitNumber2) = | |
566 | (*covBending)(hitNumber2, hitNumber1); | |
567 | // and non bending plane | |
568 | (*covNonBending)(hitNumber1, hitNumber2) = | |
569 | (*covNonBending)(hitNumber2, hitNumber1); | |
570 | } | |
571 | } // for (hitNumber2 = hitNumber1;... | |
572 | } // for (hitNumber1 = 0;... | |
d0bfce8d | 573 | |
44f59652 | 574 | // Inversion of covariance matrices |
575 | // with "mnvertLocal", local "mnvert" function of Minuit. | |
576 | // One cannot use directly "mnvert" since "TVirtualFitter" does not know it. | |
577 | // One will have to replace this local function by the right inversion function | |
578 | // from a specialized Root package for symmetric positive definite matrices, | |
579 | // when available!!!! | |
580 | Int_t ifailBending; | |
581 | mnvertLocal(&((*covBending)(0,0)), numberOfHit, numberOfHit, numberOfHit, | |
582 | ifailBending); | |
583 | Int_t ifailNonBending; | |
584 | mnvertLocal(&((*covNonBending)(0,0)), numberOfHit, numberOfHit, numberOfHit, | |
585 | ifailNonBending); | |
956019b6 | 586 | |
587 | // It would be worth trying to calculate the inverse of the covariance matrix | |
588 | // only once per fit, since it cannot change much in principle, | |
589 | // and it would save a lot of computing time !!!! | |
04b5ea16 | 590 | |
591 | // Calculates Chi2 | |
44f59652 | 592 | if ((ifailBending == 0) && (ifailNonBending == 0)) { |
eb9c9dab | 593 | // with Multiple Scattering if inversion correct |
594 | for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) { | |
595 | hit1 = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber1]; | |
596 | hbc1 = hit1->GetHitForRecPtr()->GetBendingCoor(); | |
597 | pbc1 = hit1->GetTrackParam()->GetBendingCoor(); | |
598 | hnbc1 = hit1->GetHitForRecPtr()->GetNonBendingCoor(); | |
599 | pnbc1 = hit1->GetTrackParam()->GetNonBendingCoor(); | |
600 | for (hitNumber2 = 0; hitNumber2 < numberOfHit; hitNumber2++) { | |
601 | hit2 = (AliMUONTrackHit*) | |
602 | (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber2]; | |
603 | hbc2 = hit2->GetHitForRecPtr()->GetBendingCoor(); | |
604 | pbc2 = hit2->GetTrackParam()->GetBendingCoor(); | |
605 | hnbc2 = hit2->GetHitForRecPtr()->GetNonBendingCoor(); | |
606 | pnbc2 = hit2->GetTrackParam()->GetNonBendingCoor(); | |
04b5ea16 | 607 | Chi2 = Chi2 + |
eb9c9dab | 608 | ((*covBending)(hitNumber2, hitNumber1) * |
609 | (hbc1 - pbc1) * (hbc2 - pbc2)) + | |
04b5ea16 | 610 | ((*covNonBending)(hitNumber2, hitNumber1) * |
eb9c9dab | 611 | (hnbc1 - pnbc1) * (hnbc2 - pnbc2)); |
04b5ea16 | 612 | } |
613 | } | |
eb9c9dab | 614 | } else { |
615 | // without Multiple Scattering if inversion impossible | |
616 | for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) { | |
617 | hit1 = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber1]; | |
618 | hbc1 = hit1->GetHitForRecPtr()->GetBendingCoor(); | |
619 | pbc1 = hit1->GetTrackParam()->GetBendingCoor(); | |
620 | hnbc1 = hit1->GetHitForRecPtr()->GetNonBendingCoor(); | |
621 | pnbc1 = hit1->GetTrackParam()->GetNonBendingCoor(); | |
622 | Chi2 = Chi2 + | |
623 | ((hbc1 - pbc1) * (hbc1 - pbc1) / | |
624 | hit1->GetHitForRecPtr()->GetBendingReso2()) + | |
625 | ((hnbc1 - pnbc1) * (hnbc1 - pnbc1) / | |
626 | hit1->GetHitForRecPtr()->GetNonBendingReso2()); | |
04b5ea16 | 627 | } |
628 | } | |
629 | ||
630 | delete covBending; | |
631 | delete covNonBending; | |
eb9c9dab | 632 | delete [] msa2; |
04b5ea16 | 633 | } |
634 | ||
635 | Double_t MultipleScatteringAngle2(AliMUONTrackHit *TrackHit) | |
636 | { | |
637 | // Returns square of multiple Coulomb scattering angle | |
638 | // at TrackHit pointed to by "TrackHit" | |
639 | Double_t slopeBending, slopeNonBending, radiationLength, inverseBendingMomentum2, inverseTotalMomentum2; | |
640 | Double_t varMultipleScatteringAngle; | |
956019b6 | 641 | AliMUONTrack *trackBeingFitted = (AliMUONTrack*) AliMUONTrack::Fitter()->GetObjectFit(); |
04b5ea16 | 642 | AliMUONTrackParam *param = TrackHit->GetTrackParam(); |
956019b6 | 643 | // Better implementation in AliMUONTrack class ???? |
04b5ea16 | 644 | slopeBending = param->GetBendingSlope(); |
645 | slopeNonBending = param->GetNonBendingSlope(); | |
646 | // thickness in radiation length for the current track, | |
647 | // taking local angle into account | |
648 | radiationLength = | |
649 | trackBeingFitted->GetEventReconstructor()->GetChamberThicknessInX0() * | |
650 | TMath::Sqrt(1.0 + | |
651 | slopeBending * slopeBending + slopeNonBending * slopeNonBending); | |
652 | inverseBendingMomentum2 = | |
653 | param->GetInverseBendingMomentum() * param->GetInverseBendingMomentum(); | |
654 | inverseTotalMomentum2 = | |
956019b6 | 655 | inverseBendingMomentum2 * (1.0 + slopeBending * slopeBending) / |
04b5ea16 | 656 | (1.0 + slopeBending *slopeBending + slopeNonBending * slopeNonBending); |
657 | varMultipleScatteringAngle = 0.0136 * (1.0 + 0.038 * TMath::Log(radiationLength)); | |
956019b6 | 658 | // The velocity is assumed to be 1 !!!! |
04b5ea16 | 659 | varMultipleScatteringAngle = inverseTotalMomentum2 * radiationLength * |
660 | varMultipleScatteringAngle * varMultipleScatteringAngle; | |
661 | return varMultipleScatteringAngle; | |
662 | } | |
44f59652 | 663 | |
664 | //______________________________________________________________________________ | |
665 | void mnvertLocal(Double_t *a, Int_t l, Int_t, Int_t n, Int_t &ifail) | |
666 | { | |
667 | //*-*-*-*-*-*-*-*-*-*-*-*Inverts a symmetric matrix*-*-*-*-*-*-*-*-*-*-*-*-* | |
668 | //*-* ========================== | |
669 | //*-* inverts a symmetric matrix. matrix is first scaled to | |
670 | //*-* have all ones on the diagonal (equivalent to change of units) | |
671 | //*-* but no pivoting is done since matrix is positive-definite. | |
672 | //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* | |
673 | ||
674 | // taken from TMinuit package of Root (l>=n) | |
675 | // fVERTs, fVERTq and fVERTpp changed to localVERTs, localVERTq and localVERTpp | |
e804eb46 | 676 | // Double_t localVERTs[n], localVERTq[n], localVERTpp[n]; |
677 | Double_t * localVERTs = new Double_t[n]; | |
678 | Double_t * localVERTq = new Double_t[n]; | |
679 | Double_t * localVERTpp = new Double_t[n]; | |
44f59652 | 680 | // fMaxint changed to localMaxint |
681 | Int_t localMaxint = n; | |
682 | ||
683 | /* System generated locals */ | |
3831f268 | 684 | Int_t aOffset; |
44f59652 | 685 | |
686 | /* Local variables */ | |
687 | Double_t si; | |
688 | Int_t i, j, k, kp1, km1; | |
689 | ||
690 | /* Parameter adjustments */ | |
3831f268 | 691 | aOffset = l + 1; |
692 | a -= aOffset; | |
44f59652 | 693 | |
694 | /* Function Body */ | |
695 | ifail = 0; | |
696 | if (n < 1) goto L100; | |
697 | if (n > localMaxint) goto L100; | |
698 | //*-*- scale matrix by sqrt of diag elements | |
699 | for (i = 1; i <= n; ++i) { | |
700 | si = a[i + i*l]; | |
701 | if (si <= 0) goto L100; | |
702 | localVERTs[i-1] = 1 / TMath::Sqrt(si); | |
703 | } | |
704 | for (i = 1; i <= n; ++i) { | |
705 | for (j = 1; j <= n; ++j) { | |
706 | a[i + j*l] = a[i + j*l]*localVERTs[i-1]*localVERTs[j-1]; | |
707 | } | |
708 | } | |
709 | //*-*- . . . start main loop . . . . | |
710 | for (i = 1; i <= n; ++i) { | |
711 | k = i; | |
712 | //*-*- preparation for elimination step1 | |
713 | if (a[k + k*l] != 0) localVERTq[k-1] = 1 / a[k + k*l]; | |
714 | else goto L100; | |
715 | localVERTpp[k-1] = 1; | |
716 | a[k + k*l] = 0; | |
717 | kp1 = k + 1; | |
718 | km1 = k - 1; | |
719 | if (km1 < 0) goto L100; | |
720 | else if (km1 == 0) goto L50; | |
721 | else goto L40; | |
722 | L40: | |
723 | for (j = 1; j <= km1; ++j) { | |
724 | localVERTpp[j-1] = a[j + k*l]; | |
725 | localVERTq[j-1] = a[j + k*l]*localVERTq[k-1]; | |
726 | a[j + k*l] = 0; | |
727 | } | |
728 | L50: | |
729 | if (k - n < 0) goto L51; | |
730 | else if (k - n == 0) goto L60; | |
731 | else goto L100; | |
732 | L51: | |
733 | for (j = kp1; j <= n; ++j) { | |
734 | localVERTpp[j-1] = a[k + j*l]; | |
735 | localVERTq[j-1] = -a[k + j*l]*localVERTq[k-1]; | |
736 | a[k + j*l] = 0; | |
737 | } | |
738 | //*-*- elimination proper | |
739 | L60: | |
740 | for (j = 1; j <= n; ++j) { | |
741 | for (k = j; k <= n; ++k) { a[j + k*l] += localVERTpp[j-1]*localVERTq[k-1]; } | |
742 | } | |
743 | } | |
744 | //*-*- elements of left diagonal and unscaling | |
745 | for (j = 1; j <= n; ++j) { | |
746 | for (k = 1; k <= j; ++k) { | |
747 | a[k + j*l] = a[k + j*l]*localVERTs[k-1]*localVERTs[j-1]; | |
748 | a[j + k*l] = a[k + j*l]; | |
749 | } | |
750 | } | |
e804eb46 | 751 | delete localVERTs; |
752 | delete localVERTq; | |
753 | delete localVERTpp; | |
44f59652 | 754 | return; |
755 | //*-*- failure return | |
756 | L100: | |
e804eb46 | 757 | delete localVERTs; |
758 | delete localVERTq; | |
759 | delete localVERTpp; | |
44f59652 | 760 | ifail = 1; |
761 | } /* mnvertLocal */ | |
762 |