1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
18 // ---------------------
19 // Class AliMUONTrackK
20 // ---------------------
21 // Reconstructed track in the muon system based on the extended
22 // Kalman filter approach
23 // Author: Alexander Zinchenko, JINR Dubna
25 #include "AliMUONTrackK.h"
26 #include "AliMUONConstants.h"
28 #include "AliMUONTrackReconstructorK.h"
29 #include "AliMUONHitForRec.h"
30 #include "AliMUONObjectPair.h"
31 #include "AliMUONRawCluster.h"
32 #include "AliMUONTrackParam.h"
33 #include "AliMUONTrackExtrap.h"
34 //#include "AliMUONEventRecoCombi.h"
35 //#include "AliMUONDetElement.h"
39 #include <Riostream.h>
40 #include <TClonesArray.h>
44 ClassImp(AliMUONTrackK) // Class implementation in ROOT context
47 const Int_t AliMUONTrackK::fgkSize = 5;
48 const Int_t AliMUONTrackK::fgkNSigma = 12;
49 const Double_t AliMUONTrackK::fgkChi2max = 100;
50 const Int_t AliMUONTrackK::fgkTriesMax = 10000;
51 const Double_t AliMUONTrackK::fgkEpsilon = 0.002;
53 void mnvertLocal(Double_t* a, Int_t l, Int_t m, Int_t n, Int_t& ifail);
55 Int_t AliMUONTrackK::fgDebug = -1; //-1;
56 Int_t AliMUONTrackK::fgNOfPoints = 0;
57 AliMUONTrackReconstructorK* AliMUONTrackK::fgTrackReconstructor = NULL;
58 TClonesArray* AliMUONTrackK::fgHitForRec = NULL;
59 //AliMUONEventRecoCombi *AliMUONTrackK::fgCombi = NULL;
61 //__________________________________________________________________________
62 AliMUONTrackK::AliMUONTrackK()
89 /// Default constructor
91 fgTrackReconstructor = NULL; // pointer to event reconstructor
92 fgHitForRec = NULL; // pointer to points
93 fgNOfPoints = 0; // number of points
96 //__________________________________________________________________________
97 AliMUONTrackK::AliMUONTrackK(AliMUONTrackReconstructorK *TrackReconstructor, TClonesArray *hitForRec)
126 if (!TrackReconstructor) return;
127 fgTrackReconstructor = TrackReconstructor; // pointer to event reconstructor
128 fgHitForRec = hitForRec; // pointer to points
129 fgNOfPoints = fgHitForRec->GetEntriesFast(); // number of points
131 if (fgTrackReconstructor->GetTrackMethod() == 3)
133 AliFatal("Reimplement me!");
134 // fgCombi = AliMUONEventRecoCombi::Instance();
138 //__________________________________________________________________________
139 AliMUONTrackK::AliMUONTrackK(const AliMUONObjectPair& segment)
140 : AliMUONTrack(NULL,NULL),
141 fStartSegment(new AliMUONObjectPair(segment)),
145 fTrackHits(new TObjArray(13)),
151 fTrackPar(new TMatrixD(fgkSize,1)),
152 fTrackParNew(new TMatrixD(fgkSize,1)),
153 fCovariance(new TMatrixD(fgkSize,fgkSize)),
154 fWeight(new TMatrixD(fgkSize,fgkSize)),
155 fParExtrap(new TObjArray(15)),
156 fParFilter(new TObjArray(15)),
158 fCovExtrap(new TObjArray(15)),
159 fCovFilter(new TObjArray(15)),
160 fJacob(new TObjArray(15)),
162 fSteps(new TArrayD(15)),
163 fChi2Array(new TArrayD(13)),
166 /// Constructor from a segment
167 Double_t dX, dY, dZ, bendingSlope, bendingImpact;
168 AliMUONHitForRec *hit1, *hit2;
170 // Pointers to hits from the segment
171 hit1 = (AliMUONHitForRec*) segment.First();
172 hit2 = (AliMUONHitForRec*) segment.Second();
173 hit1->SetNTrackHits(hit1->GetNTrackHits()+1); // mark hit as being on track
174 hit2->SetNTrackHits(hit2->GetNTrackHits()+1); // mark hit as being on track
175 // check sorting in Z
176 if (TMath::Abs(hit1->GetZ()) > TMath::Abs(hit2->GetZ())) {
178 hit2 = (AliMUONHitForRec*) segment.First();
181 // Fill array of track parameters
182 if (hit1->GetChamberNumber() > 7) {
183 // last tracking station
184 (*fTrackPar)(0,0) = hit1->GetBendingCoor(); // y
185 (*fTrackPar)(1,0) = hit1->GetNonBendingCoor(); // x
186 fPosition = hit1->GetZ(); // z
187 fTrackHits->Add(hit2); // add hit 2
188 fTrackHits->Add(hit1); // add hit 1
189 //AZ(Z->-Z) fTrackDir = -1;
192 // last but one tracking station
193 (*fTrackPar)(0,0) = hit2->GetBendingCoor(); // y
194 (*fTrackPar)(1,0) = hit2->GetNonBendingCoor(); // x
195 fPosition = hit2->GetZ(); // z
196 fTrackHits->Add(hit1); // add hit 1
197 fTrackHits->Add(hit2); // add hit 2
198 //AZ(Z->-Z) fTrackDir = 1;
201 dZ = hit2->GetZ() - hit1->GetZ();
202 dY = hit2->GetBendingCoor() - hit1->GetBendingCoor();
203 dX = hit2->GetNonBendingCoor() - hit1->GetNonBendingCoor();
204 bendingSlope = (hit2->GetBendingCoor() - hit1->GetBendingCoor()) / dZ;
205 bendingImpact = hit1->GetBendingCoor() - hit1->GetZ() * bendingSlope;
206 (*fTrackPar)(2,0) = TMath::ATan2(dY,dZ); // alpha
207 if ((*fTrackPar)(2,0) < 0.) (*fTrackPar)(2,0) += 2*TMath::Pi(); // from 0 to 2*pi
208 (*fTrackPar)(3,0) = TMath::ATan2(-dX,dZ/TMath::Cos((*fTrackPar)(2,0))); // beta
209 (*fTrackPar)(2,0) -= TMath::Pi();
210 (*fTrackPar)(4,0) = 1./AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpact); // 1/Pt
211 (*fTrackPar)(4,0) *= TMath::Cos((*fTrackPar)(3,0)); // 1/p
212 // Evaluate covariance (and weight) matrix
218 //__________________________________________________________________________
220 AliMUONTrackK::SetOwnerShip()
222 /// Specify which arrays are owner of their objects.
224 fParExtrap->SetOwner(kTRUE);
225 fParFilter->SetOwner(kTRUE);
226 fCovExtrap->SetOwner(kTRUE);
227 fCovFilter->SetOwner(kTRUE);
228 fJacob->SetOwner(kTRUE);
230 fTrackHits->SetOwner(kFALSE);
233 //__________________________________________________________________________
234 AliMUONTrackK::~AliMUONTrackK()
241 //__________________________________________________________________________
243 AliMUONTrackK::Clear(Option_t* /*opt*/)
245 /// Try to release allocated memory blocks...
247 delete fStartSegment; fStartSegment = 0;
251 for (Int_t i = 0; i < fNmbTrackHits; i++)
253 AliMUONHitForRec *hit = (AliMUONHitForRec*) fTrackHits->UncheckedAt(i);
254 hit->SetNTrackHits(hit->GetNTrackHits()-1);
258 delete fTrackHits; fTrackHits = 0;
260 delete fTrackPar; fTrackPar = 0;
261 delete fTrackParNew; fTrackParNew = 0;
262 delete fCovariance; fCovariance = 0;
263 delete fWeight; fWeight = 0;
264 delete fSteps; fSteps = 0;
265 delete fChi2Array; fChi2Array = 0;
266 delete fChi2Smooth; fChi2Smooth = 0;
267 delete fParSmooth; fParSmooth = 0;
269 // Delete only matrices not shared by several tracks
270 RemoveIfUnique(fParExtrap);
271 RemoveIfUnique(fParFilter);
272 RemoveIfUnique(fCovExtrap);
273 RemoveIfUnique(fCovFilter);
274 RemoveIfUnique(fJacob);
277 //______________________________________________________________________________
279 AliMUONTrackK::RemoveIfUnique(TObjArray*& array)
281 /// Remove entries from array if they are unique (i.e. only used
282 /// by current track), and delete the array
284 if ( array == 0 ) return;
286 for (Int_t i=0; i<=array->GetLast(); ++i)
288 Int_t id = array->UncheckedAt(i)->GetUniqueID();
291 array->UncheckedAt(i)->SetUniqueID(id-1);
300 //__________________________________________________________________________
301 AliMUONTrackK & AliMUONTrackK::operator=(const AliMUONTrackK& source)
303 /// Assignment operator
306 if(&source == this) return *this;
308 // base class assignement
309 //AZ TObject::operator=(source);
310 AliMUONTrack::operator=(source);
312 delete fStartSegment; fStartSegment = 0;
313 if (source.fStartSegment) fStartSegment = new AliMUONObjectPair(*(source.fStartSegment));
315 fNmbTrackHits = source.fNmbTrackHits;
316 fChi2 = source.fChi2;
317 fPosition = source.fPosition;
318 fPositionNew = source.fPositionNew;
319 fTrackDir = source.fTrackDir;
320 fBPFlag = source.fBPFlag;
321 fRecover = source.fRecover;
322 fSkipHit = source.fSkipHit;
326 fTrackHits = new TObjArray(*source.fTrackHits);
327 //source.fTrackHits->Dump();
328 //fTrackHits->Dump();
329 for (Int_t i = 0; i < fNmbTrackHits; i++) {
330 AliMUONHitForRec *hit = (AliMUONHitForRec*) fTrackHits->UncheckedAt(i);
331 hit->SetNTrackHits(hit->GetNTrackHits()+1);
335 fTrackPar = new TMatrixD(*source.fTrackPar); // track parameters
337 fTrackParNew = new TMatrixD(*source.fTrackParNew); // track parameters
339 fCovariance = new TMatrixD(*source.fCovariance); // covariance matrix
341 fWeight = new TMatrixD(*source.fWeight); // weight matrix (inverse of covariance)
345 fParExtrap = new TObjArray(*source.fParExtrap);
347 fParFilter = new TObjArray(*source.fParFilter);
349 fCovExtrap = new TObjArray(*source.fCovExtrap);
351 fCovFilter = new TObjArray(*source.fCovFilter);
353 fJacob = new TObjArray(*source.fJacob);
355 fSteps = new TArrayD(*source.fSteps);
356 fNSteps = source.fNSteps;
359 if (source.fChi2Array) fChi2Array = new TArrayD(*source.fChi2Array);
365 for (Int_t i=0; i<fParExtrap->GetEntriesFast(); i++) {
366 fParExtrap->UncheckedAt(i)->SetUniqueID(fParExtrap->UncheckedAt(i)->GetUniqueID()+1);
367 fParFilter->UncheckedAt(i)->SetUniqueID(fParFilter->UncheckedAt(i)->GetUniqueID()+1);
368 fCovExtrap->UncheckedAt(i)->SetUniqueID(fCovExtrap->UncheckedAt(i)->GetUniqueID()+1);
369 fCovFilter->UncheckedAt(i)->SetUniqueID(fCovFilter->UncheckedAt(i)->GetUniqueID()+1);
370 fJacob->UncheckedAt(i)->SetUniqueID(fJacob->UncheckedAt(i)->GetUniqueID()+1);
375 //__________________________________________________________________________
376 void AliMUONTrackK::EvalCovariance(Double_t dZ)
378 /// Evaluate covariance (and weight) matrix for track candidate
379 Double_t sigmaB, sigmaNonB, tanA, tanB, dAdY, rad, dBdX, dBdY;
382 sigmaB = fgTrackReconstructor->GetBendingResolution(); // bending resolution
383 sigmaNonB = fgTrackReconstructor->GetNonBendingResolution(); // non-bending resolution
385 (*fWeight)(0,0) = sigmaB*sigmaB; // <yy>
387 (*fWeight)(1,1) = sigmaNonB*sigmaNonB; // <xx>
389 tanA = TMath::Tan((*fTrackPar)(2,0));
390 dAdY = 1/(1+tanA*tanA)/dZ;
391 (*fWeight)(2,2) = dAdY*dAdY*(*fWeight)(0,0)*2; // <aa>
392 (*fWeight)(0,2) = dAdY*(*fWeight)(0,0); // <ya>
393 (*fWeight)(2,0) = (*fWeight)(0,2);
395 rad = dZ/TMath::Cos((*fTrackPar)(2,0));
396 tanB = TMath::Tan((*fTrackPar)(3,0));
397 dBdX = 1/(1+tanB*tanB)/rad;
399 (*fWeight)(3,3) = dBdX*dBdX*(*fWeight)(1,1)*2; // <bb>
400 (*fWeight)(1,3) = dBdX*(*fWeight)(1,1); // <xb>
401 (*fWeight)(3,1) = (*fWeight)(1,3);
403 (*fWeight)(4,4) = ((*fTrackPar)(4,0)*0.5)*((*fTrackPar)(4,0)*0.5); // error 50%
405 // check whether the Invert method returns flag if matrix cannot be inverted,
406 // and do not calculate the Determinant in that case !!!!
407 if (fWeight->Determinant() != 0) {
408 // fWeight->Invert();
410 mnvertLocal(&((*fWeight)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
412 AliWarning(" Determinant fWeight=0:");
417 //__________________________________________________________________________
418 Bool_t AliMUONTrackK::KalmanFilter(Int_t ichamBeg, Int_t ichamEnd, Bool_t Back, Double_t zDipole1, Double_t zDipole2)
420 /// Follows track through detector stations
421 Bool_t miss, success;
422 Int_t ichamb, iFB, iMin, iMax, dChamb, ichambOK;
423 Int_t ihit, firstIndx = -1, lastIndx = -1, currIndx = -1, iz0 = -1, iz = -1;
424 Double_t zEnd, dChi2;
425 AliMUONHitForRec *hitAdd, *firstHit = NULL, *lastHit = NULL, *hit;
426 AliMUONRawCluster *clus;
427 TClonesArray *rawclusters;
428 hit = 0; clus = 0; rawclusters = 0;
430 miss = success = kTRUE;
432 //iFB = (ichamEnd == ichamBeg) ? fTrackDir : TMath::Sign(1,ichamEnd-ichamBeg);
433 iFB = (ichamEnd == ichamBeg) ? -fTrackDir : TMath::Sign(1,ichamEnd-ichamBeg);
434 iMin = TMath::Min(ichamEnd,ichamBeg);
435 iMax = TMath::Max(ichamEnd,ichamBeg);
442 if (((AliMUONHitForRec*)fTrackHits->First())->GetChamberNumber() != ichamb) currIndx = 0;
443 } else if (fRecover) {
444 hit = GetHitLastOk();
445 currIndx = fTrackHits->IndexOf(hit);
446 if (currIndx < 0) hit = (AliMUONHitForRec*) fStartSegment->First(); // for station 3
448 ichamb = hit->GetChamberNumber();
449 if (hit == fSkipHit || fRecover == 2 && currIndx >= 0) {
450 // start from the last point or outlier
451 // remove the skipped hit
452 fTrackHits->Remove(fSkipHit); // remove hit
454 fSkipHit->SetNTrackHits(fSkipHit->GetNTrackHits()-1); // unmark hit
459 ichambOK = ((AliMUONHitForRec*)((*fTrackHits)[fNmbTrackHits-1]))->GetChamberNumber();
461 if (fgTrackReconstructor->GetTrackMethod() == 3 &&
462 fSkipHit->GetHitNumber() < 0)
465 // iz0 = fgCombi->IZfromHit(fSkipHit);
468 else currIndx = fgHitForRec->IndexOf(fSkipHit);
471 fTrackHits->Compress();
473 } // if (hit == fSkipHit)
474 else if (currIndx < 0) currIndx = fTrackHits->IndexOf(hit);
475 } // else if (fRecover)
477 // Get indices of the 1'st and last hits on the track candidate
478 firstHit = (AliMUONHitForRec*) fTrackHits->First();
479 lastHit = (AliMUONHitForRec*) fTrackHits->Last();
481 if (fgTrackReconstructor->GetTrackMethod() == 3 &&
482 lastHit->GetHitNumber() < 0)
485 // iz0 = fgCombi->IZfromHit(lastHit);
488 firstIndx = fgHitForRec->IndexOf(firstHit);
489 lastIndx = fgHitForRec->IndexOf(lastHit);
490 currIndx = TMath::Abs (TMath::Max(firstIndx*iFB,lastIndx*iFB));
494 if (iz0 < 0) iz0 = iFB;
495 while (ichamb >= iMin && ichamb <= iMax) {
496 // Find the closest hit in Z, not belonging to the current plane
499 if (currIndx < fNmbTrackHits) {
500 hitAdd = (AliMUONHitForRec*) fTrackHits->UncheckedAt(currIndx);
501 zEnd = hitAdd->GetZ();
502 //AZ(z->-z) } else zEnd = -9999;
505 //AZ(Z->-Z) zEnd = -9999;
507 for (ihit=currIndx+iFB; ihit>=0 && ihit<fgNOfPoints; ihit+=iFB) {
508 hitAdd = (AliMUONHitForRec*) ((*fgHitForRec)[ihit]);
509 //if (TMath::Abs(hitAdd->GetZ()-fPosition) > 0.1) {
510 if (TMath::Abs(hitAdd->GetZ()-fPosition) > 0.5) {
511 zEnd = hitAdd->GetZ();
517 // Combined cluster / track finder
518 if (zEnd > 999 && iFB < 0 && fgTrackReconstructor->GetTrackMethod() == 3)
522 // AliMUONHitForRec hitTmp;
523 // for (iz = iz0 - iFB; iz < fgCombi->Nz(); iz++) {
524 // if (TMath::Abs(fgCombi->Z(iz)-fPosition) < 0.5) continue;
525 // Int_t *pDEatZ = fgCombi->DEatZ(iz);
526 // //cout << iz << " " << fgCombi->Z(iz) << endl;
527 // zEnd = fgCombi->Z(iz);
529 // AliMUONDetElement *detElem = fgCombi->DetElem(pDEatZ[0]);
531 // hitAdd->SetChamberNumber(detElem->Chamber());
532 // //hitAdd = (AliMUONHitForRec*) detElem->HitsForRec()->First();
533 // if (hitAdd) break;
537 if (zEnd>999 && ichamb==ichamEnd) endOfProp = 1; // end-of-propagation
539 // Check if there is a chamber without hits
540 if (zEnd>999 || TMath::Abs(hitAdd->GetChamberNumber()-ichamb) > 1) {
541 if (!Back && zEnd<999) currIndx -= iFB;
543 zEnd = AliMUONConstants::DefaultChamberZ(ichamb);
546 ichamb = hitAdd->GetChamberNumber();
550 if (ichamb<iMin || ichamb>iMax) break;
551 // Check for missing station
553 dChamb = TMath::Abs(ichamb-ichambOK);
554 //cout << dChamb << " " << ichambOK << " " << fgNOfPoints << endl;
555 Int_t dStatMiss = TMath::Abs (ichamb/2 - ichambOK/2);
556 if (zEnd > 999) dStatMiss++;
558 //if (dStatMiss == 2 && ichambOK/2 != 3 || dStatMiss > 2) { // AZ - missing st. 3
559 // missing station - abandon track
560 //cout << dChamb << " " << ichambOK << " " << fgNOfPoints << " " << 1/(*fTrackPar)(4,0) << endl;
561 if (fNmbTrackHits>2 && fRecover==0) Recover(); // try to recover track later
563 } // if (dStatMiss > 1)
565 if (endOfProp != 0) break;
567 // propagate to the found Z
569 // Check if track steps into dipole
570 //AZ(z->-z) if (fPosition>zDipole2 && zEnd<zDipole2) {
571 if (fPosition<zDipole2 && zEnd>zDipole2) {
572 //LinearPropagation(zDipole2-zBeg);
573 ParPropagation(zDipole2);
574 MSThin(1); // multiple scattering in the chamber
575 WeightPropagation(zDipole2, kTRUE); // propagate weight matrix
576 fPosition = fPositionNew;
577 *fTrackPar = *fTrackParNew;
578 //MagnetPropagation(zEnd);
579 ParPropagation(zEnd);
580 WeightPropagation(zEnd, kTRUE);
581 fPosition = fPositionNew;
583 // Check if track steps out of dipole
584 //AZ(z->-z) else if (fPosition>zDipole1 && zEnd<zDipole1) {
585 else if (fPosition<zDipole1 && zEnd>zDipole1) {
586 //MagnetPropagation(zDipole1-zBeg);
587 ParPropagation(zDipole1);
588 MSThin(1); // multiple scattering in the chamber
589 WeightPropagation(zDipole1, kTRUE);
590 fPosition = fPositionNew;
591 *fTrackPar = *fTrackParNew;
592 //LinearPropagation(zEnd-zDipole1);
593 ParPropagation(zEnd);
594 WeightPropagation(zEnd, kTRUE);
595 fPosition = fPositionNew;
597 ParPropagation(zEnd);
598 //MSThin(1); // multiple scattering in the chamber
599 if (TMath::Abs(zEnd-fPosition) > 5) MSThin(1); // multiple scattering in the chamber
600 WeightPropagation(zEnd, kTRUE);
601 fPosition = fPositionNew;
605 if (fRecover != 0 && hitAdd == fSkipHit && !miss) {
606 // recovered track - remove the hit
608 ichamb = fSkipHit->GetChamberNumber();
609 // remove the skipped hit
610 fTrackHits->Remove(fSkipHit);
612 //AZ fSkipHit->SetNTrackHits(fSkipHit->GetNTrackHits()-1); // unmark hit
615 ichambOK = ((AliMUONHitForRec*)((*fTrackHits)[fNmbTrackHits-1]))->GetChamberNumber();
616 //? if (fgTrackReconstructor->GetTrackMethod() != 3) currIndx = fgHitForRec->IndexOf(fSkipHit);
617 currIndx = fgHitForRec->IndexOf(fSkipHit);
621 // backward propagator
623 TMatrixD pointWeight(fgkSize,fgkSize);
624 TMatrixD point(fgkSize,1);
625 TMatrixD trackParTmp = point;
626 point(0,0) = hitAdd->GetBendingCoor();
627 point(1,0) = hitAdd->GetNonBendingCoor();
628 pointWeight(0,0) = 1/hitAdd->GetBendingReso2();
629 pointWeight(1,1) = 1/hitAdd->GetNonBendingReso2();
630 TryPoint(point,pointWeight,trackParTmp,dChi2);
631 *fTrackPar = trackParTmp;
632 *fWeight += pointWeight;
633 if (fTrackDir > 0) AddMatrices (this, dChi2, hitAdd);
634 fChi2 += dChi2; // Chi2
635 } else *fTrackPar = *fTrackParNew; // adjust end point to the last hit
636 if (ichamb==ichamEnd) break;
639 // forward propagator
640 if (miss || !FindPoint(ichamb, zEnd, currIndx, iFB, hitAdd, iz)) {
642 *fTrackPar = *fTrackParNew;
645 fTrackHits->Add(hitAdd); // add hit
647 hitAdd->SetNTrackHits(hitAdd->GetNTrackHits()+1); // mark hit as being on track
649 currIndx = fgHitForRec->IndexOf(hitAdd); // Check
653 if (fgDebug > 0) cout << fNmbTrackHits << " " << fChi2 << " " << 1/(*fTrackPar)(4,0) << " " << fPosition << endl;
654 if (1/TMath::Abs((*fTrackPar)(4,0)) < fgTrackReconstructor->GetMinBendingMomentum()) success = kFALSE; // p < p_min
655 if (GetRecover() < 0) success = kFALSE;
659 //__________________________________________________________________________
660 void AliMUONTrackK::ParPropagation(Double_t zEnd)
662 /// Propagation of track parameters to zEnd
664 Double_t dZ, step, distance, charge;
665 Double_t vGeant3[7], vGeant3New[7];
666 AliMUONTrackParam trackParam;
669 // First step using linear extrapolation
670 dZ = zEnd - fPosition;
671 fPositionNew = fPosition;
672 *fTrackParNew = *fTrackPar;
673 if (dZ == 0) return; //AZ ???
674 iFB = (Int_t)TMath::Sign(Double_t(1.0),dZ);
675 step = dZ/TMath::Cos((*fTrackPar)(2,0))/TMath::Cos((*fTrackPar)(3,0)); // linear estimate
676 //AZ(z->-z) charge = iFB*TMath::Sign(Double_t(1.0),(*fTrackPar)(4,0));
677 charge = -iFB*TMath::Sign(Double_t(1.0),(*fTrackPar)(4,0));
678 SetGeantParam(vGeant3,iFB);
679 //fTrackParNew->Print();
683 step = TMath::Abs(step);
684 // Propagate parameters
685 AliMUONTrackExtrap::ExtrapOneStepRungekutta(charge,step,vGeant3,vGeant3New);
686 //extrap_onestep_rungekutta(charge,step,vGeant3,vGeant3New);
687 distance = zEnd - vGeant3New[2];
688 step *= dZ/(vGeant3New[2]-fPositionNew);
690 } while (distance*iFB < 0 && TMath::Abs(distance) > fgkEpsilon);
692 GetFromGeantParam(vGeant3New,iFB);
693 //fTrackParNew->Print();
695 // Position adjustment (until within tolerance)
696 while (TMath::Abs(distance) > fgkEpsilon) {
697 dZ = zEnd - fPositionNew;
698 iFB = (Int_t)TMath::Sign(Double_t(1.0),dZ);
699 step = dZ/TMath::Cos((*fTrackParNew)(2,0))/TMath::Cos((*fTrackParNew)(3,0));
700 step = TMath::Abs(step);
701 SetGeantParam(vGeant3,iFB);
704 // Propagate parameters
705 AliMUONTrackExtrap::ExtrapOneStepRungekutta(charge,step,vGeant3,vGeant3New);
706 //extrap_onestep_rungekutta(charge,step,vGeant3,vGeant3New);
707 distance = zEnd - vGeant3New[2];
710 if (nTries > fgkTriesMax) AliError(Form(" Too many tries: %d", nTries));
711 } while (distance*iFB < 0);
713 GetFromGeantParam(vGeant3New,iFB);
715 //cout << nTries << endl;
716 //fTrackParNew->Print();
720 //__________________________________________________________________________
721 void AliMUONTrackK::WeightPropagation(Double_t zEnd, Bool_t smooth)
723 /// Propagation of the weight matrix
724 /// W = DtWD, where D is Jacobian
728 TMatrixD jacob(fgkSize,fgkSize);
731 // Save initial and propagated parameters
732 TMatrixD trackPar0 = *fTrackPar;
733 TMatrixD trackParNew0 = *fTrackParNew;
735 // Get covariance matrix
736 *fCovariance = *fWeight;
737 // check whether the Invert method returns flag if matrix cannot be inverted,
738 // and do not calculate the Determinant in that case !!!!
739 if (fCovariance->Determinant() != 0) {
741 mnvertLocal(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
742 //fCovariance->Print();
744 AliWarning(" Determinant fCovariance=0:");
747 // Loop over parameters to find change of the propagated vs initial ones
748 for (i=0; i<fgkSize; i++) {
749 dPar = TMath::Sqrt((*fCovariance)(i,i));
750 *fTrackPar = trackPar0;
751 if (i == 4) dPar *= TMath::Sign(1.,-trackPar0(4,0)); // 1/p
752 (*fTrackPar)(i,0) += dPar;
753 ParPropagation(zEnd);
754 for (j=0; j<fgkSize; j++) {
755 jacob(j,i) = ((*fTrackParNew)(j,0)-trackParNew0(j,0))/dPar;
759 //trackParNew0.Print();
760 //TMatrixD par1(jacob,TMatrixD::kMult,trackPar0); //
762 TMatrixD jacob0 = jacob;
763 if (jacob.Determinant() != 0) {
766 AliWarning(" Determinant jacob=0:");
768 TMatrixD weight1(*fWeight,TMatrixD::kMult,jacob); // WD
769 *fWeight = TMatrixD(jacob,TMatrixD::kTransposeMult,weight1); // DtWD
771 // Restore initial and propagated parameters
772 *fTrackPar = trackPar0;
773 *fTrackParNew = trackParNew0;
776 if (!smooth) return; // do not use smoother
777 if (fTrackDir < 0) return; // only for propagation towards int. point
778 TMatrixD *tmp = new TMatrixD(*fTrackParNew); // extrapolated parameters
779 fParExtrap->Add(tmp);
781 tmp = new TMatrixD(*fTrackParNew); // filtered parameters (if no measurement will be found)
782 fParFilter->Add(tmp);
784 *fCovariance = *fWeight;
785 if (fCovariance->Determinant() != 0) {
787 mnvertLocal(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
789 AliWarning(" Determinant fCovariance=0:");
791 tmp = new TMatrixD(*fCovariance); // extrapolated covariance
792 fCovExtrap->Add(tmp);
794 tmp = new TMatrixD(*fCovariance); // filtered covariance (if no measurement will be found)
795 fCovFilter->Add(tmp);
797 tmp = new TMatrixD(jacob0); // Jacobian
800 if (fSteps->fN <= fNSteps) fSteps->Set(fSteps->fN+10);
801 fSteps->AddAt(fPositionNew,fNSteps++);
802 if (fgDebug > 0) printf(" WeightPropagation %d %.3f %.3f %.3f \n", fNSteps,
803 (*fTrackParNew)(1,0), (*fTrackParNew)(0,0), fPositionNew);
807 //__________________________________________________________________________
808 Bool_t AliMUONTrackK::FindPoint(Int_t ichamb, Double_t zEnd, Int_t currIndx, Int_t iFB, AliMUONHitForRec *&hitAdd, Int_t iz)
810 /// Picks up point within a window for the chamber No ichamb
811 /// Split the track if there are more than 1 hit
812 Int_t ihit, nRecTracks;
813 Double_t windowB, windowNonB, dChi2Tmp=0, dChi2, y, x, savePosition=0;
814 TClonesArray *trackPtr;
815 AliMUONHitForRec *hit(0x0), *hitLoop;
816 AliMUONTrackK *trackK;
817 // AliMUONDetElement *detElem = NULL;
819 //sigmaB = fgTrackReconstructor->GetBendingResolution(); // bending resolution
820 //sigmaNonB = fgTrackReconstructor->GetNonBendingResolution(); // non-bending resolution
821 *fCovariance = *fWeight;
822 // check whether the Invert method returns flag if matrix cannot be inverted,
823 // and do not calculate the Determinant in that case !!!!
824 if (fCovariance->Determinant() != 0) {
826 mnvertLocal(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
828 AliWarning(" Determinant fCovariance=0:");
830 //windowB = fgkNSigma*TMath::Sqrt((*fCovariance)(0,0)+sigmaB*sigmaB);
831 //windowNonB = fgkNSigma*TMath::Sqrt((*fCovariance)(1,1)+sigmaNonB*sigmaNonB);
834 if (fgTrackReconstructor->GetTrackMethod() == 3 && iz >= 0)
837 // Combined cluster / track finder
838 // Check if extrapolated track passes thru det. elems. at iz
839 // Int_t *pDEatZ = fgCombi->DEatZ(iz);
840 // Int_t nDetElem = pDEatZ[-1];
841 // //cout << fgCombi->Z(iz) << " " << nDetElem << endl;
842 // windowB = fgkNSigma * TMath::Sqrt((*fCovariance)(0,0));
843 // windowNonB = fgkNSigma * TMath::Sqrt((*fCovariance)(1,1));
844 // if (fgkNSigma > 6) windowB = TMath::Min (windowB, 5.);
845 // windowB = TMath::Max (windowB, 2.);
846 // windowNonB = TMath::Max (windowNonB, 2.);
847 // for (Int_t i = 0; i < nDetElem; i++) {
848 // detElem = fgCombi->DetElem(pDEatZ[i]);
849 // if (detElem->Inside((*fTrackParNew)(1,0), (*fTrackParNew)(0,0), fPosition, windowNonB, windowB)) {
850 // detElem->ClusterReco((*fTrackParNew)(1,0), (*fTrackParNew)(0,0), windowNonB, windowB);
851 // hitAdd = (AliMUONHitForRec*) detElem->HitsForRec()->First();
856 // if (!ok) return ok; // outside det. elem.
860 //sigmaB = fgTrackReconstructor->GetBendingResolution(); // bending resolution
861 //sigmaNonB = fgTrackReconstructor->GetNonBendingResolution(); // non-bending resolution
862 *fCovariance = *fWeight;
863 // check whether the Invert method returns flag if matrix cannot be inverted,
864 // and do not calculate the Determinant in that case !!!!
865 if (fCovariance->Determinant() != 0) {
867 mnvertLocal(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
869 AliWarning(" Determinant fCovariance=0:");
871 //windowB = fgkNSigma*TMath::Sqrt((*fCovariance)(0,0)+sigmaB*sigmaB);
872 //windowNonB = fgkNSigma*TMath::Sqrt((*fCovariance)(1,1)+sigmaNonB*sigmaNonB);
873 // Loop over all hits and take hits from the chamber
874 TMatrixD pointWeight(fgkSize,fgkSize);
875 TMatrixD saveWeight = pointWeight;
876 TMatrixD pointWeightTmp = pointWeight;
877 TMatrixD point(fgkSize,1);
878 TMatrixD trackPar = point;
879 TMatrixD trackParTmp = point;
880 Int_t nHitsOK = 0, ihitB = currIndx, ihitE = fgNOfPoints, iDhit = iFB;
882 zLast = ((AliMUONHitForRec*)fTrackHits->Last())->GetZ();
883 // if (fgTrackReconstructor->GetTrackMethod() == 3 && detElem) {
885 // ihitE = detElem->NHitsForRec();
889 TArrayD branchChi2(20);
890 for (ihit = ihitB; ihit >= 0 && ihit < ihitE; ihit+=iDhit)
892 if (fgTrackReconstructor->GetTrackMethod() != 3 )//|| !detElem)
893 hit = (AliMUONHitForRec*) ((*fgHitForRec)[ihit]);
894 // else hit = (AliMUONHitForRec*) detElem->HitsForRec()->UncheckedAt(ihit);
895 if (hit->GetChamberNumber() == ichamb) {
896 //if (TMath::Abs(hit->GetZ()-zEnd) < 0.1) {
897 if (TMath::Abs(hit->GetZ()-zEnd) < 0.5) {
898 y = hit->GetBendingCoor();
899 x = hit->GetNonBendingCoor();
900 if (hit->GetBendingReso2() < 0) {
901 // Combined cluster / track finder
902 hit->SetBendingReso2(fgTrackReconstructor->GetBendingResolution()*
903 fgTrackReconstructor->GetBendingResolution());
904 hit->SetNonBendingReso2(fgTrackReconstructor->GetNonBendingResolution()*
905 fgTrackReconstructor->GetNonBendingResolution());
907 windowB = fgkNSigma*TMath::Sqrt((*fCovariance)(0,0)+hit->GetBendingReso2());
908 windowNonB = fgkNSigma*TMath::Sqrt((*fCovariance)(1,1)+hit->GetNonBendingReso2());
910 // windowB = TMath::Min (windowB,5.);
911 if (fgkNSigma > 6) windowB = TMath::Min (windowB,5.);
913 if (TMath::Abs(hit->GetZ()-zLast) < 50) {
914 windowB = TMath::Min (windowB,0.5);
915 windowNonB = TMath::Min (windowNonB,3.);
916 } else if (TMath::Abs(hit->GetZ()-zLast) < 200) {
917 windowB = TMath::Min (windowB,1.5);
918 windowNonB = TMath::Min (windowNonB,3.);
919 } else if (TMath::Abs(hit->GetZ()-zLast) < 350) {
920 windowB = TMath::Min (windowB,4.);
921 windowNonB = TMath::Min (windowNonB,6.);
927 if (TMath::Abs(hit->GetZ()-zLast) < 50) {
928 windowB = 5*TMath::Sqrt((*fCovariance)(0,0)+hit->GetBendingReso2());
929 windowNonB = 5*TMath::Sqrt((*fCovariance)(1,1)+hit->GetNonBendingReso2());
931 windowB = fgkNSigma*TMath::Sqrt((*fCovariance)(0,0)+hit->GetBendingReso2());
932 windowNonB = fgkNSigma*TMath::Sqrt((*fCovariance)(1,1)+hit->GetNonBendingReso2());
936 //cout << TMath::Abs((*fTrackParNew)(0,0)-y) << " " << windowB << " " << TMath::Abs((*fTrackParNew)(1,0)-x) << " " << windowNonB << " " << zEnd << endl;
937 if (TMath::Abs((*fTrackParNew)(0,0)-y) <= windowB &&
938 TMath::Abs((*fTrackParNew)(1,0)-x) <= windowNonB) {
939 //if (TMath::Abs((*fTrackParNew)(0,0)-y) <= windowB &&
940 // TMath::Abs((*fTrackParNew)(1,0)-x) <= windowNonB &&
941 // hit->GetTrackRefCharge() == 1) { // just for test
942 // Vector of measurements and covariance matrix
943 //fprintf(lun1,"%3d %3d %10.4f %10.4f \n", AliRunLoader::GetRunLoader()->GetEventNumber(), ichamb, x, y);
944 if (TMath::Abs(hit->GetZ()-zEnd) > 0.05) {
945 // Adjust position: for multiple hits in the chamber or misalignment (Z as a function of X or Y)
946 //AliWarning(Form(" *** adjust %f %f ", zEnd, hit->GetZ()));
948 *fTrackPar = *fTrackParNew;
949 ParPropagation(zEnd);
950 WeightPropagation(zEnd, kTRUE);
951 fPosition = fPositionNew;
952 *fTrackPar = *fTrackParNew;
954 *fCovariance = *fWeight;
955 if (fCovariance->Determinant() != 0) {
957 mnvertLocal(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
959 AliWarning(" Determinant fCovariance=0:" );
965 pointWeight(0,0) = 1/hit->GetBendingReso2();
966 pointWeight(1,1) = 1/hit->GetNonBendingReso2();
967 TryPoint(point,pointWeight,trackPar,dChi2);
968 if (TMath::Abs(1./(trackPar)(4,0)) < fgTrackReconstructor->GetMinBendingMomentum()) continue; // p < p_min - next hit
969 // if (TMath::Sign(1.,(trackPar)(4,0)*(*fTrackPar)(4,0)) < 0) continue; // change of sign
972 //if (nHitsOK > -1) {
974 // Save current members
975 saveWeight = *fWeight;
976 savePosition = fPosition;
977 // temporary storage for the current track
979 trackParTmp = trackPar;
980 pointWeightTmp = pointWeight;
982 if (fgDebug > 0) printf(" Added point (ch, x, y, Chi2): %d %.3f %.3f %.3f\n", ichamb, x, y, dChi2);
983 branchChi2[0] = dChi2;
985 // branching: create a new track
986 trackPtr = fgTrackReconstructor->GetRecTracksPtr();
987 nRecTracks = fgTrackReconstructor->GetNRecTracks();
988 trackK = new ((*trackPtr)[nRecTracks]) AliMUONTrackK(NULL, NULL);
990 fgTrackReconstructor->SetNRecTracks(nRecTracks+1);
991 if (fgDebug > 0) printf(" ******** New track (ch, hit, x, y, mom, Chi2, nhits, cand): %d %d %.3f %.3f %.3f %.3f %d %d\n", ichamb, hit->GetTTRTrack(), hit->GetNonBendingCoor(), hit->GetBendingCoor(), 1/(trackPar)(4,0), dChi2, fNmbTrackHits, nRecTracks);
992 trackK->fRecover = 0;
993 *(trackK->fTrackPar) = trackPar;
994 *(trackK->fWeight) += pointWeight;
995 trackK->fChi2 += dChi2;
998 *(trackK->fCovariance) = *(trackK->fWeight);
999 if (trackK->fCovariance->Determinant() != 0) {
1001 mnvertLocal(&((*(trackK->fCovariance))(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1003 cout << (*(trackK->fCovariance))(0,0) << " " << (*(trackK->fCovariance))(1,1) << " " << (*fCovariance)(0,0) << " " << (*fCovariance)(1,1) << endl;
1005 // Add filtered matrices for the smoother
1006 if (fTrackDir > 0) {
1007 if (nHitsOK > 2) { // check for position adjustment
1008 for (Int_t i=trackK->fNSteps-1; i>=0; i--) {
1009 if (TMath::Abs(hit->GetZ()-(*trackK->fSteps)[i]) > 0.1) {
1010 //if (TMath::Abs(hit->GetZ()-(trackK->fSteps)[i]) > 0.1) {
1011 RemoveMatrices(trackK);
1012 AliError(Form(" *** Position adjustment 1: %f %f", hit->GetZ(), (*trackK->fSteps)[i]));
1017 AddMatrices (trackK, dChi2, hit);
1019 // Mark hits as being on 2 tracks
1020 for (Int_t i=0; i<fNmbTrackHits; i++) {
1021 hitLoop = (AliMUONHitForRec*) ((*fTrackHits)[i]);
1022 //AZ hitLoop->SetNTrackHits(hitLoop->GetNTrackHits()+1);
1025 cout << hitLoop->GetChamberNumber() << " ";
1026 cout << hitLoop->GetBendingCoor() << " ";
1027 cout << hitLoop->GetNonBendingCoor() << " ";
1028 cout << hitLoop->GetZ() << " " << " ";
1029 cout << hitLoop->GetTTRTrack() << endl;
1030 printf(" ** %d %10.4f %10.4f %10.4f\n",
1031 hitLoop->GetChamberNumber(), hitLoop->GetBendingCoor(),
1032 hitLoop->GetNonBendingCoor(), hitLoop->GetZ());
1036 trackK->fTrackHits->Add(hit); // add hit
1037 trackK->fNmbTrackHits ++;
1038 hit->SetNTrackHits(hit->GetNTrackHits()+1); // mark hit as being on track
1041 trackK->fTrackDir = 1;
1042 trackK->fBPFlag = kTRUE;
1044 if (nHitsOK > branchChi2.GetSize()) branchChi2.Set(branchChi2.GetSize()+10);
1045 branchChi2[nHitsOK-1] = dChi2;
1049 } else break; // different chamber
1050 } // for (ihit=currIndx;
1053 *fTrackPar = trackParTmp;
1054 *fWeight = saveWeight;
1055 *fWeight += pointWeightTmp;
1056 fChi2 += dChi2Tmp; // Chi2
1057 fPosition = savePosition;
1058 // Add filtered matrices for the smoother
1059 if (fTrackDir > 0) {
1060 for (Int_t i=fNSteps-1; i>=0; i--) {
1061 if (TMath::Abs(fPosition-(*fSteps)[i]) > 0.1) {
1062 //if (TMath::Abs(fPosition-fSteps[i]) > 0.1) {
1063 RemoveMatrices(this);
1064 if (fgDebug > 0) cout << " *** Position adjustment 2 " << fPosition << " " << (*fSteps)[i] << endl;
1067 } // for (Int_t i=fNSteps-1;
1068 AddMatrices (this, dChi2Tmp, hitAdd);
1071 for (Int_t i=0; i<fNSteps; i++) cout << (*fSteps)[i] << " "; cout << endl;
1072 for (Int_t i=0; i<trackK->fNSteps; i++) cout << (*trackK->fSteps)[i] << " "; cout << endl;
1075 } // if (fTrackDir > 0)
1076 // Check for maximum number of branches - exclude excessive
1077 if (nHitsOK > 1) CheckBranches(branchChi2, nHitsOK);
1082 //__________________________________________________________________________
1083 void AliMUONTrackK::CheckBranches(TArrayD &branchChi2, Int_t nBranch)
1085 /// Check for maximum number of branches - exclude excessive
1087 Int_t nBranchMax = 5;
1088 if (nBranch <= nBranchMax) return;
1090 Double_t *chi2 = branchChi2.GetArray();
1091 Int_t *indx = new Int_t [nBranch];
1092 TMath::Sort (nBranch, chi2, indx, kFALSE);
1093 TClonesArray *trackPtr = fgTrackReconstructor->GetRecTracksPtr();
1094 Int_t nRecTracks = fgTrackReconstructor->GetNRecTracks();
1095 Int_t ibeg = nRecTracks - nBranch;
1097 // Discard excessive branches with higher Chi2 contribution
1098 for (Int_t i = nBranchMax; i < nBranch; ++i) {
1100 // Discard current track
1104 Int_t j = ibeg + indx[i];
1105 AliMUONTrackK *trackK = (AliMUONTrackK*) trackPtr->UncheckedAt(j);
1106 trackK->SetRecover(-1);
1111 //__________________________________________________________________________
1112 void AliMUONTrackK::TryPoint(TMatrixD &point, const TMatrixD &pointWeight, TMatrixD &trackParTmp, Double_t &dChi2)
1114 /// Adds a measurement point (modifies track parameters and computes
1117 // Solving linear system (W+U)p' = U(m-p) + (W+U)p
1118 TMatrixD wu = *fWeight;
1119 wu += pointWeight; // W+U
1120 trackParTmp = point;
1121 trackParTmp -= *fTrackParNew; // m-p
1122 TMatrixD right(pointWeight,TMatrixD::kMult,trackParTmp); // U(m-p)
1123 TMatrixD right1(wu,TMatrixD::kMult,*fTrackParNew); // (W+U)p
1124 right += right1; // U(m-p) + (W+U)p
1126 // check whether the Invert method returns flag if matrix cannot be inverted,
1127 // and do not calculate the Determinant in that case !!!!
1128 if (wu.Determinant() != 0) {
1130 mnvertLocal(&((wu)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1132 AliWarning(" Determinant wu=0:");
1134 trackParTmp = TMatrixD(wu,TMatrixD::kMult,right);
1136 right1 = trackParTmp;
1137 right1 -= point; // p'-m
1138 point = trackParTmp;
1139 point -= *fTrackParNew; // p'-p
1140 right = TMatrixD(*fWeight,TMatrixD::kMult,point); // W(p'-p)
1141 TMatrixD value(point,TMatrixD::kTransposeMult,right); // (p'-p)'W(p'-p)
1143 right = TMatrixD(pointWeight,TMatrixD::kMult,right1); // U(p'-m)
1144 value = TMatrixD(right1,TMatrixD::kTransposeMult,right); // (p'-m)'U(p'-m)
1145 dChi2 += value(0,0);
1149 //__________________________________________________________________________
1150 void AliMUONTrackK::MSThin(Int_t sign)
1152 /// Adds multiple scattering in a thin layer (only angles are affected)
1153 Double_t cosAlph, cosBeta, momentum, velo, path, theta0;
1155 // check whether the Invert method returns flag if matrix cannot be inverted,
1156 // and do not calculate the Determinant in that case !!!!
1157 if (fWeight->Determinant() != 0) {
1159 mnvertLocal(&((*fWeight)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1161 AliWarning(" Determinant fWeight=0:");
1164 cosAlph = TMath::Cos((*fTrackParNew)(2,0));
1165 cosBeta = TMath::Cos((*fTrackParNew)(3,0));
1166 momentum = 1/(*fTrackParNew)(4,0); // particle momentum
1167 //velo = momentum/TMath::Sqrt(momentum*momentum+muonMass*muonMass); // velocity/c for muon hypothesis
1168 velo = 1; // relativistic
1169 path = TMath::Abs(AliMUONConstants::ChamberThicknessInX0()/cosAlph/cosBeta); // path length
1170 theta0 = 0.0136/velo/momentum*TMath::Sqrt(path)*(1+0.038*TMath::Log(path)); // projected scattering angle
1172 (*fWeight)(2,2) += sign*theta0/cosBeta*theta0/cosBeta; // alpha
1173 (*fWeight)(3,3) += sign*theta0*theta0; // beta
1175 mnvertLocal(&((*fWeight)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1179 //__________________________________________________________________________
1180 void AliMUONTrackK::StartBack(void)
1182 /// Starts backpropagator
1186 for (Int_t i=0; i<fgkSize; i++) {
1187 for (Int_t j=0; j<fgkSize; j++) {
1188 if (j==i) (*fWeight)(i,i) /= 100;
1189 //if (j==i) (*fWeight)(i,i) /= fNmbTrackHits*fNmbTrackHits;
1190 else (*fWeight)(j,i) = 0;
1193 // Sort hits on track in descending order in abs(z)
1194 SortHits(0, fTrackHits);
1197 //__________________________________________________________________________
1198 void AliMUONTrackK::SortHits(Int_t iflag, TObjArray *array)
1200 /// Sort hits in Z if the seed segment is in the last but one station
1201 /// (if iflag==0 in descending order in abs(z), if !=0 - unsort)
1203 if (iflag && ((AliMUONHitForRec*)(array->UncheckedAt(0)))->GetChamberNumber() == 6) return;
1204 Double_t z = 0, zmax = TMath::Abs(((AliMUONHitForRec*)(array->UncheckedAt(0)))->GetZ());
1205 Int_t i = 1, entries = array->GetEntriesFast();
1206 for ( ; i<entries; i++) {
1208 if (((AliMUONHitForRec*)(array->UncheckedAt(i)))->GetChamberNumber() == 6) break;
1210 z = TMath::Abs(((AliMUONHitForRec*)(array->UncheckedAt(i)))->GetZ());
1211 if (z < zmax) break;
1213 if (fgDebug >= 10) cout << " " << zmax << " " << z << " " << i << endl;
1217 for (Int_t j=0; j<=(i-1)/2; j++) {
1218 TObject *hit = array->UncheckedAt(j);
1219 array->AddAt(array->UncheckedAt(i-j),j);
1220 array->AddAt(hit,i-j);
1222 if (fgDebug >= 10) {
1223 for (i=0; i<entries; i++)
1224 cout << ((AliMUONHitForRec*)(array->UncheckedAt(i)))->GetZ() << " ";
1225 cout << " - Sort" << endl;
1229 //__________________________________________________________________________
1230 void AliMUONTrackK::SetGeantParam(Double_t *VGeant3, Int_t iFB)
1232 /// Set vector of Geant3 parameters pointed to by "VGeant3"
1233 /// from track parameters
1235 VGeant3[0] = (*fTrackParNew)(1,0); // X
1236 VGeant3[1] = (*fTrackParNew)(0,0); // Y
1237 VGeant3[2] = fPositionNew; // Z
1238 VGeant3[3] = iFB*TMath::Sin((*fTrackParNew)(3,0)); // Px/Ptot
1239 VGeant3[4] = iFB*TMath::Cos((*fTrackParNew)(3,0))*TMath::Sin((*fTrackParNew)(2,0)); // Py/Ptot
1240 VGeant3[5] = iFB*TMath::Sqrt(1.0-VGeant3[3]*VGeant3[3]-VGeant3[4]*VGeant3[4]); // Pz/Ptot
1241 VGeant3[6] = 1/TMath::Abs((*fTrackParNew)(4,0)); // Ptot
1244 //__________________________________________________________________________
1245 void AliMUONTrackK::GetFromGeantParam(Double_t *VGeant3, Int_t iFB)
1247 /// Get track parameters from vector of Geant3 parameters pointed
1250 fPositionNew = VGeant3[2]; // Z
1251 (*fTrackParNew)(0,0) = VGeant3[1]; // Y
1252 (*fTrackParNew)(1,0) = VGeant3[0]; // X
1253 (*fTrackParNew)(3,0) = TMath::ASin(iFB*VGeant3[3]); // beta
1254 (*fTrackParNew)(2,0) = TMath::ASin(iFB*VGeant3[4]/TMath::Cos((*fTrackParNew)(3,0))); // alpha
1255 (*fTrackParNew)(4,0) = 1/VGeant3[6]*TMath::Sign(Double_t(1.0),(*fTrackPar)(4,0)); // 1/Ptot
1258 //__________________________________________________________________________
1259 void AliMUONTrackK::SetTrackQuality(Int_t iChi2)
1261 /// Computes "track quality" from Chi2 (if iChi2==0) or vice versa
1264 AliWarning(Form(" *** Too high Chi2: %f ", fChi2));
1267 if (iChi2 == 0) fChi2 = fNmbTrackHits + (500.-fChi2)/501;
1268 else fChi2 = 500 - (fChi2-fNmbTrackHits)*501;
1271 //__________________________________________________________________________
1272 Int_t AliMUONTrackK::Compare(const TObject* trackK) const
1274 /// "Compare" function to sort with decreasing "track quality".
1275 /// Returns +1 (0, -1) if quality of current track
1276 /// is smaller than (equal to, larger than) quality of trackK
1278 if (fChi2 < ((AliMUONTrackK*)trackK)->fChi2) return(+1);
1279 else if (fChi2 == ((AliMUONTrackK*)trackK)->fChi2) return(0);
1283 //__________________________________________________________________________
1284 Bool_t AliMUONTrackK::KeepTrack(AliMUONTrackK* track0) const
1286 /// Check whether or not to keep current track
1287 /// (keep, if it has less than half of common hits with track0)
1288 Int_t hitsInCommon, nHits0, i, j, nTrackHits2;
1289 AliMUONHitForRec *hit0, *hit1;
1292 nHits0 = track0->fNmbTrackHits;
1293 nTrackHits2 = fNmbTrackHits/2;
1295 for (i=0; i<nHits0; i++) {
1296 // Check if hit belongs to several tracks
1297 hit0 = (AliMUONHitForRec*) (*track0->fTrackHits)[i];
1298 if (hit0->GetNTrackHits() == 1) continue;
1299 for (j=0; j<fNmbTrackHits; j++) {
1300 hit1 = (AliMUONHitForRec*) (*fTrackHits)[j];
1301 if (hit1->GetNTrackHits() == 1) continue;
1304 if (hitsInCommon >= nTrackHits2) return kFALSE;
1312 //__________________________________________________________________________
1313 void AliMUONTrackK::Kill(void)
1315 /// Kill track candidate
1316 fgTrackReconstructor->GetRecTracksPtr()->Remove(this);
1319 //__________________________________________________________________________
1320 void AliMUONTrackK::FillMUONTrack(void)
1322 /// Compute track parameters at hit positions (as for AliMUONTrack)
1325 SetTrackQuality(1); // compute Chi2
1328 // Set track parameters at hits
1329 AliMUONTrackParam trackParam;
1330 SetTrackParam(&trackParam, fTrackPar, fPosition);
1331 for (Int_t i = fNmbTrackHits-1; i>=0; i--) {
1332 if ((*fChi2Smooth)[i] < 0) {
1333 // Propagate through last chambers
1334 AliMUONTrackExtrap::ExtrapToZ(&trackParam, ((AliMUONHitForRec*)((*fTrackHits)[i]))->GetZ());
1337 SetTrackParam(&trackParam, (TMatrixD*)fParSmooth->UncheckedAt(i), ((AliMUONHitForRec*)((*fTrackHits)[i]))->GetZ());
1339 AddTrackParamAtHit(&trackParam,(AliMUONHitForRec*)fTrackHits->UncheckedAt(i));
1340 // Fill array of HitForRec's
1341 AddHitForRecAtHit((AliMUONHitForRec*)fTrackHits->UncheckedAt(i));
1345 //__________________________________________________________________________
1346 void AliMUONTrackK::SetTrackParam(AliMUONTrackParam *trackParam, TMatrixD *par, Double_t z)
1348 /// Fill AliMUONTrackParam object
1350 trackParam->SetBendingCoor((*par)(0,0));
1351 trackParam->SetNonBendingCoor((*par)(1,0));
1352 trackParam->SetBendingSlope(TMath::Tan((*par)(2,0)));
1353 trackParam->SetNonBendingSlope(TMath::Tan((*par)(3,0))/TMath::Cos((*par)(2,0)));
1354 trackParam->SetInverseBendingMomentum((*par)(4,0)/TMath::Cos((*par)(3,0)));
1355 trackParam->SetZ(z);
1358 //__________________________________________________________________________
1359 void AliMUONTrackK::MSLine(Double_t dZ, Double_t x0)
1361 /// Adds multiple scattering in a thick layer for linear propagation
1363 Double_t cosAlph = TMath::Cos((*fTrackPar)(2,0));
1364 Double_t tanAlph = TMath::Tan((*fTrackPar)(2,0));
1365 Double_t cosBeta = TMath::Cos((*fTrackPar)(3,0));
1367 sinBeta = TMath::Sin((*fTrackPar)(3,0));
1368 Double_t tanBeta = TMath::Tan((*fTrackPar)(3,0));
1369 Double_t momentum = 1/(*fTrackPar)(4,0);
1370 Double_t velo = 1; // relativistic velocity
1371 Double_t step = TMath::Abs(dZ/cosAlph/cosBeta); // step length
1373 // Projected scattering angle
1374 Double_t theta0 = 0.0136/velo/momentum/TMath::Sqrt(x0)*(1+0.038*TMath::Log(step/x0));
1375 Double_t theta02 = theta0*theta0;
1376 Double_t dl2 = step*step/2*theta02;
1377 Double_t dl3 = dl2*step*2/3;
1380 Double_t dYdT = 1/cosAlph;
1381 Double_t dYdB = 0; //(*fTrackPar)(2,0)*sinBeta/cosAlph;
1382 Double_t dXdT = tanAlph*tanBeta;
1383 //Double_t dXdB = (1+(*fTrackPar)(2,0)*tanAlph*sinBeta*sinBeta)/cosBeta;
1384 Double_t dXdB = 1/cosBeta;
1385 Double_t dAdT = 1/cosBeta;
1386 Double_t dAdB = 0; //(*fTrackPar)(2,0)*tanBeta;
1388 // Get covariance matrix
1389 *fCovariance = *fWeight;
1390 if (fCovariance->Determinant() != 0) {
1391 // fCovariance->Invert();
1393 mnvertLocal(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1395 AliWarning(" Determinant fCovariance=0:" );
1398 (*fCovariance)(0,0) += dl3*(dYdT*dYdT+dYdB*dYdB); // <yy>
1399 (*fCovariance)(1,1) += dl3*(dXdT*dXdT+dXdB*dXdB); // <xx>
1400 (*fCovariance)(2,2) += theta02*step*(dAdT*dAdT+dAdB*dAdB); // <aa>
1401 (*fCovariance)(3,3) += theta02*step; // <bb>
1403 (*fCovariance)(0,1) += dl3*(dYdT*dXdT+dYdB*dXdB); // <yx>
1404 (*fCovariance)(1,0) = (*fCovariance)(0,1);
1406 (*fCovariance)(0,2) += dl2*(dYdT*dAdT+dYdB*dAdB); // <ya>
1407 (*fCovariance)(2,0) = (*fCovariance)(0,2);
1409 (*fCovariance)(0,3) += dl2*dYdB; // <yb>
1410 (*fCovariance)(3,0) = (*fCovariance)(0,3);
1412 (*fCovariance)(1,2) += dl2*(-dXdT*dAdT+dXdB*dAdB); // <xa>
1413 (*fCovariance)(2,1) = (*fCovariance)(1,2);
1415 (*fCovariance)(1,3) += dl2*dXdB; // <xb>
1416 (*fCovariance)(3,1) = (*fCovariance)(1,3);
1418 (*fCovariance)(2,3) += theta02*step*dAdB; // <ab>
1419 (*fCovariance)(3,2) = (*fCovariance)(2,3);
1421 // Get weight matrix
1422 *fWeight = *fCovariance;
1423 if (fWeight->Determinant() != 0) {
1425 mnvertLocal(&((*fWeight)(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1427 AliWarning(" Determinant fWeight=0:");
1431 //__________________________________________________________________________
1432 Bool_t AliMUONTrackK::Recover(void)
1434 /// Adds new failed track(s) which can be tried to be recovered
1436 TClonesArray *trackPtr;
1437 AliMUONTrackK *trackK;
1439 if (fgDebug > 0) cout << " ******** Enter Recover " << endl;
1440 trackPtr = fgTrackReconstructor->GetRecTracksPtr();
1442 // Remove hit with the highest chi2
1445 for (Int_t i=0; i<fNmbTrackHits; i++) {
1446 chi2 = fChi2Smooth ? (*fChi2Smooth)[i] : (*fChi2Array)[i];
1447 printf("%10.4f", chi2);
1450 for (Int_t i=0; i<fNmbTrackHits; i++) {
1451 printf("%10d", ((AliMUONHitForRec*)fTrackHits->UncheckedAt(i))->GetChamberNumber());
1455 Double_t chi2max = 0;
1457 for (Int_t i=0; i<fNmbTrackHits; i++) {
1458 chi2 = fChi2Smooth ? (*fChi2Smooth)[i] : (*fChi2Array)[i];
1459 if (chi2 < chi2max) continue;
1463 //if (chi2max < 10) return kFALSE; // !!!
1464 //if (chi2max < 25) imax = fNmbTrackHits - 1;
1465 if (chi2max < 15) imax = fNmbTrackHits - 1; // discard the last point
1466 // Check if the outlier is not from the seed segment
1467 AliMUONHitForRec *skipHit = (AliMUONHitForRec*) fTrackHits->UncheckedAt(imax);
1468 if (skipHit == (AliMUONHitForRec*) fStartSegment->First() || skipHit == (AliMUONHitForRec*) fStartSegment->Second()) {
1469 //DropBranches(fStartSegment); // drop all tracks with the same seed segment
1470 return kFALSE; // to be changed probably
1473 // Make a copy of track hit collection
1474 TObjArray *hits = new TObjArray(*fTrackHits);
1478 // Hits after the found one will be removed
1479 if (GetStation0() == 3 && skipHit->GetChamberNumber() >= 7) {
1480 SortHits(1, fTrackHits); // unsort hits
1481 imax = fTrackHits->IndexOf(skipHit);
1483 Int_t nTrackHits = fNmbTrackHits;
1484 for (Int_t i=imax+1; i<nTrackHits; i++) {
1485 AliMUONHitForRec *hit = (AliMUONHitForRec*) fTrackHits->UncheckedAt(i);
1486 fTrackHits->Remove(hit);
1487 hit->SetNTrackHits(hit->GetNTrackHits()-1); // unmark hit
1491 // Check if the track candidate doesn't exist yet
1492 if (ExistDouble()) { delete hits; return kFALSE; }
1494 //DropBranches(imax0, hits); // drop branches downstream the discarded hit
1497 nRecTracks = fgTrackReconstructor->GetNRecTracks();
1498 skipHit = (AliMUONHitForRec*) ((*fTrackHits)[fNmbTrackHits-1]);
1499 // Remove all saved steps and smoother matrices after the skipped hit
1500 RemoveMatrices(skipHit->GetZ());
1502 //AZ(z->-z) if (skipHit->GetZ() > ((AliMUONHitForRec*) fStartSegment->Second())->GetZ() || !fNSteps) {
1503 if (TMath::Abs(skipHit->GetZ()) > TMath::Abs( ((AliMUONHitForRec*) fStartSegment->Second())->GetZ()) || !fNSteps) {
1504 // Propagation toward high Z or skipped hit next to segment -
1505 // start track from segment
1506 trackK = new ((*trackPtr)[nRecTracks]) AliMUONTrackK(*fStartSegment);
1507 fgTrackReconstructor->SetNRecTracks(nRecTracks+1);
1508 trackK->fRecover = 1;
1509 trackK->fSkipHit = skipHit;
1510 trackK->fNmbTrackHits = fNmbTrackHits;
1511 delete trackK->fTrackHits; // not efficient ?
1512 trackK->fTrackHits = new TObjArray(*fTrackHits);
1513 if (fgDebug > 0) cout << nRecTracks << " " << trackK->fRecover << endl;
1517 trackK = new ((*trackPtr)[nRecTracks]) AliMUONTrackK(NULL, NULL);
1519 fgTrackReconstructor->SetNRecTracks(nRecTracks+1);
1520 //AZ(z->-z) trackK->fTrackDir = -1;
1521 trackK->fTrackDir = 1;
1522 trackK->fRecover = 1;
1523 trackK->fSkipHit = skipHit;
1524 Int_t iD = trackK->fParFilter->Last()->GetUniqueID();
1526 trackK->fParFilter->Last()->SetUniqueID(iD-1);
1527 CreateMatrix(trackK->fParFilter);
1529 *((TMatrixD*)trackK->fParFilter->Last()) = *((TMatrixD*)fParExtrap->Last());
1530 trackK->fParFilter->Last()->SetUniqueID(1);
1531 *(trackK->fTrackPar) = *((TMatrixD*)trackK->fParFilter->Last());
1532 iD = trackK->fCovFilter->Last()->GetUniqueID();
1534 trackK->fCovFilter->Last()->SetUniqueID(iD-1);
1535 CreateMatrix(trackK->fCovFilter);
1537 *((TMatrixD*)trackK->fCovFilter->Last()) = *((TMatrixD*)fCovExtrap->Last());
1538 trackK->fCovFilter->Last()->SetUniqueID(1);
1539 *(trackK->fWeight) = *((TMatrixD*)trackK->fCovFilter->Last());
1540 if (trackK->fWeight->Determinant() != 0) {
1542 mnvertLocal(&((*(trackK->fWeight))(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1544 AliWarning(" Determinant fWeight=0:");
1546 trackK->fPosition = trackK->fPositionNew = (*fSteps)[fNSteps-1];
1548 for (Int_t i=0; i<fNmbTrackHits-1; i++) trackK->fChi2 += (*fChi2Array)[i];
1549 if (fgDebug > 0) cout << nRecTracks << " " << trackK->fRecover << endl;
1553 //__________________________________________________________________________
1554 void AliMUONTrackK::AddMatrices(AliMUONTrackK *trackK, Double_t dChi2, AliMUONHitForRec *hitAdd)
1556 /// Adds matrices for the smoother and keep Chi2 for the point
1557 /// Track parameters
1558 //trackK->fParFilter->Last()->Print();
1559 Int_t iD = trackK->fParFilter->Last()->GetUniqueID();
1561 trackK->fParFilter->Last()->SetUniqueID(iD-1);
1562 CreateMatrix(trackK->fParFilter);
1565 *((TMatrixD*)(trackK->fParFilter->Last())) = *(trackK->fTrackPar);
1566 trackK->fParFilter->Last()->SetUniqueID(iD);
1568 cout << " Add matrices" << " " << fPosition << " " << dChi2 << " " << fgHitForRec->IndexOf(hitAdd) << endl;
1569 //trackK->fTrackPar->Print();
1570 //trackK->fTrackParNew->Print();
1571 trackK->fParFilter->Last()->Print();
1572 cout << " Add matrices" << endl;
1575 *(trackK->fCovariance) = *(trackK->fWeight);
1576 if (trackK->fCovariance->Determinant() != 0) {
1578 mnvertLocal(&((*(trackK->fCovariance))(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1580 AliWarning(" Determinant fCovariance=0:");
1582 iD = trackK->fCovFilter->Last()->GetUniqueID();
1584 trackK->fCovFilter->Last()->SetUniqueID(iD-1);
1585 CreateMatrix(trackK->fCovFilter);
1588 *((TMatrixD*)(trackK->fCovFilter->Last())) = *(trackK->fCovariance);
1589 trackK->fCovFilter->Last()->SetUniqueID(iD);
1591 // Save Chi2-increment for point
1592 Int_t indx = trackK->fTrackHits->IndexOf(hitAdd);
1593 if (indx < 0) indx = fNmbTrackHits;
1594 if (trackK->fChi2Array->fN <= indx) trackK->fChi2Array->Set(indx+10);
1595 trackK->fChi2Array->AddAt(dChi2,indx);
1598 //__________________________________________________________________________
1599 void AliMUONTrackK::CreateMatrix(TObjArray *objArray) const
1601 /// Create new matrix and add it to TObjArray
1603 TMatrixD *matrix = (TMatrixD*) objArray->First();
1604 TMatrixD *tmp = new TMatrixD(*matrix);
1605 objArray->AddAtAndExpand(tmp,objArray->GetLast());
1606 //cout << " !!! " << tmp << " " << tmp->GetUniqueID() << " " << tmp->GetNoElements() << endl;
1609 //__________________________________________________________________________
1610 void AliMUONTrackK::RemoveMatrices(Double_t zEnd)
1612 /// Remove matrices (and saved steps) in the smoother part with abs(z) < abs(zEnd)
1614 for (Int_t i=fNSteps-1; i>=0; i--) {
1615 if (fgDebug > 1) printf("%10.4f %10.4f \n", (*fSteps)[i], zEnd);
1616 if (TMath::Abs((*fSteps)[i]) > TMath::Abs(zEnd) - 0.01) break;
1617 RemoveMatrices(this);
1618 } // for (Int_t i=fNSteps-1;
1621 //__________________________________________________________________________
1622 void AliMUONTrackK::RemoveMatrices(AliMUONTrackK* trackK)
1624 /// Remove last saved matrices and steps in the smoother part
1627 Int_t i = trackK->fNSteps;
1630 // Delete only matrices not shared by several tracks
1631 id = trackK->fParExtrap->Last()->GetUniqueID();
1633 trackK->fParExtrap->Last()->SetUniqueID(id-1);
1634 trackK->fParExtrap->RemoveAt(i);
1636 else ((TMatrixD*)(trackK->fParExtrap->RemoveAt(i)))->Delete();
1637 id = fParFilter->Last()->GetUniqueID();
1639 trackK->fParFilter->Last()->SetUniqueID(id-1);
1640 trackK->fParFilter->RemoveAt(i);
1642 else ((TMatrixD*)(trackK->fParFilter->RemoveAt(i)))->Delete();
1643 id = trackK->fCovExtrap->Last()->GetUniqueID();
1645 trackK->fCovExtrap->Last()->SetUniqueID(id-1);
1646 trackK->fCovExtrap->RemoveAt(i);
1648 else ((TMatrixD*)(trackK->fCovExtrap->RemoveAt(i)))->Delete();
1649 id = trackK->fCovFilter->Last()->GetUniqueID();
1651 trackK->fCovFilter->Last()->SetUniqueID(id-1);
1652 trackK->fCovFilter->RemoveAt(i);
1654 else ((TMatrixD*)(trackK->fCovFilter->RemoveAt(i)))->Delete();
1655 id = trackK->fJacob->Last()->GetUniqueID();
1657 trackK->fJacob->Last()->SetUniqueID(id-1);
1658 trackK->fJacob->RemoveAt(i);
1660 else ((TMatrixD*)(trackK->fJacob->RemoveAt(i)))->Delete();
1663 //__________________________________________________________________________
1664 Bool_t AliMUONTrackK::Smooth(void)
1667 Int_t ihit = fNmbTrackHits - 1;
1668 AliMUONHitForRec *hit = (AliMUONHitForRec*) (*fTrackHits)[ihit];
1669 fChi2Smooth = new TArrayD(fNmbTrackHits);
1670 fChi2Smooth->Reset(-1);
1672 fParSmooth = new TObjArray(15);
1673 fParSmooth->SetOwner(kTRUE);
1676 cout << " ******** Enter Smooth " << endl;
1677 cout << (*fSteps)[fNSteps-1] << " " << fPosition << " " << fPositionNew << endl;
1679 for (Int_t i=fNSteps-1; i>=0; i--) cout << (*fSteps)[i] << " ";
1681 for (Int_t i=fNSteps-1; i>=0; i--) {cout << i << " " << (*fSteps)[i]; ((TMatrixD*)fParFilter->UncheckedAt(i))->Print(); ((TMatrixD*)fParExtrap->UncheckedAt(i))->Print(); ((TMatrixD*)fJacob->UncheckedAt(i))->Print();}
1683 for (Int_t i=ihit; i>=0; i--) cout << ((AliMUONHitForRec*)(*fTrackHits)[i])->GetZ() << " ";
1687 // Find last point corresponding to the last hit
1688 Int_t iLast = fNSteps - 1;
1689 for ( ; iLast>=0; iLast--) {
1690 //AZ(z->-z) if ((*fSteps)[iLast] + 0.01 > ((AliMUONHitForRec*)(*fTrackHits)[fNmbTrackHits-1])->GetZ()) break;
1691 if (TMath::Abs((*fSteps)[iLast]) + 0.01 > TMath::Abs(((AliMUONHitForRec*)(*fTrackHits)[fNmbTrackHits-1])->GetZ())) break;
1694 TMatrixD parSmooth = *((TMatrixD*)(fParFilter->UncheckedAt(iLast))); // last filtered = first smoothed
1696 TMatrixD covSmooth = *((TMatrixD*)(fCovFilter->UncheckedAt(iLast))); // last filtered = first smoothed
1697 TMatrixD tmp=covSmooth, weight=covSmooth, gain = covSmooth;
1698 TMatrixD tmpPar = *fTrackPar;
1699 //parSmooth.Print(); ((TMatrixD*)(fParExtrap->Last()))->Print();
1702 Double_t chi2max = 0;
1703 for (Int_t i=iLast+1; i>0; i--) {
1704 if (i == iLast + 1) goto L33; // temporary fix
1706 // Smoother gain matrix
1707 weight = *((TMatrixD*)(fCovExtrap->UncheckedAt(i)));
1708 if (weight.Determinant() != 0) {
1710 mnvertLocal(&(weight(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1712 AliWarning(" Determinant weight=0:");
1715 tmp = TMatrixD(*((TMatrixD*)(fJacob->UncheckedAt(i))),TMatrixD::kTransposeMult,weight);
1716 gain = TMatrixD(*((TMatrixD*)(fCovFilter->UncheckedAt(i-1))),TMatrixD::kMult,tmp);
1717 //cout << (*fSteps)[i-1] << " " << (*fSteps)[i] << endl; gain.Print();
1719 // Smoothed parameter vector
1720 //((TMatrixD*)(fParExtrap->UncheckedAt(i)))->Dump();
1721 parSmooth -= *((TMatrixD*)(fParExtrap->UncheckedAt(i)));
1722 tmpPar = *((TMatrixD*)(fParFilter->UncheckedAt(i-1)));
1723 tmpPar += TMatrixD(gain,TMatrixD::kMult,parSmooth);
1726 // Smoothed covariance
1727 covSmooth -= *((TMatrixD*)(fCovExtrap->UncheckedAt(i)));
1728 weight = TMatrixD(TMatrixD::kTransposed,gain);
1729 tmp = TMatrixD(covSmooth,TMatrixD::kMult,weight);
1730 covSmooth = *((TMatrixD*)(fCovFilter->UncheckedAt(i-1)));
1731 covSmooth += TMatrixD(gain,TMatrixD::kMult,tmp);
1733 // Check if there was a measurement at given z
1735 for ( ; ihit>=0; ihit--) {
1736 hit = (AliMUONHitForRec*) (*fTrackHits)[ihit];
1737 if (TMath::Abs(hit->GetZ()-(*fSteps)[i-1]) < 0.1) { found = kTRUE; break; }
1738 //AZ(z->-z) else if (ihit < fNmbTrackHits-1 && hit->GetZ() > (*fSteps)[i-1]) { ihit++; break; }
1739 else if (ihit < fNmbTrackHits-1 && TMath::Abs(hit->GetZ()) > TMath::Abs((*fSteps)[i-1])) { ihit++; break; }
1741 if (!found) continue; // no measurement - skip the rest
1742 else if (fgDebug > 1) cout << i << " " << ihit << " " << hit->GetZ() << endl;
1743 if (ihit == 0) continue; // the first hit - skip the rest
1746 // Smoothed residuals
1748 tmpPar(0,0) = hit->GetBendingCoor() - parSmooth(0,0); // bending coordinate
1749 tmpPar(1,0) = hit->GetNonBendingCoor() - parSmooth(1,0); // non-bending coordinate
1751 cout << hit->GetBendingCoor() << " " << parSmooth(0,0) << " " << tmpPar(0,0) << endl;
1752 cout << hit->GetNonBendingCoor() << " " << parSmooth(1,0) << " " << tmpPar(1,0) << endl;
1754 // Cov. matrix of smoothed residuals
1756 tmp(0,0) = hit->GetBendingReso2() - covSmooth(0,0);
1757 tmp(1,1) = hit->GetNonBendingReso2() - covSmooth(1,1);
1758 tmp(0,1) = tmp(1,0) = -covSmooth(0,1);
1759 tmp(2,2) = tmp(3,3) = tmp(4,4) = 1;
1761 // Calculate Chi2 of smoothed residuals
1762 if (tmp.Determinant() != 0) {
1764 mnvertLocal(&(tmp(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1766 AliWarning(" Determinant tmp=0:");
1768 TMatrixD vector(tmp,TMatrixD::kMult,tmpPar);
1769 TMatrixD chi2(tmpPar,TMatrixD::kTransposeMult,vector);
1770 if (fgDebug > 1) chi2.Print();
1771 (*fChi2Smooth)[ihit] = chi2(0,0);
1772 if (chi2(0,0) > chi2max) chi2max = chi2(0,0);
1774 if (chi2(0,0) < 0) {
1776 AliError(Form(" *** chi2 < 0: %d %d ", i, iLast));
1778 // Save smoothed parameters
1779 TMatrixD *par = new TMatrixD(parSmooth);
1780 fParSmooth->AddAtAndExpand(par, ihit);
1782 } // for (Int_t i=iLast+1;
1784 //if (chi2max > 16) {
1785 //if (chi2max > 25) {
1786 //if (chi2max > 50) {
1787 //if (chi2max > 100) {
1788 if (chi2max > fgkChi2max) {
1789 //if (Recover()) DropBranches();
1797 //__________________________________________________________________________
1798 void AliMUONTrackK::Outlier()
1800 /// Adds new track with removed hit having the highest chi2
1803 cout << " ******** Enter Outlier " << endl;
1804 for (Int_t i=0; i<fNmbTrackHits; i++) printf("%10.4f", (*fChi2Smooth)[i]);
1806 for (Int_t i=0; i<fNmbTrackHits; i++) {
1807 printf("%10d", ((AliMUONHitForRec*)fTrackHits->UncheckedAt(i))->GetChamberNumber());
1812 Double_t chi2max = 0;
1814 for (Int_t i=0; i<fNmbTrackHits; i++) {
1815 if ((*fChi2Smooth)[i] < chi2max) continue;
1816 chi2max = (*fChi2Smooth)[i];
1819 // Check if the outlier is not from the seed segment
1820 AliMUONHitForRec *hit = (AliMUONHitForRec*) fTrackHits->UncheckedAt(imax);
1821 if (hit == (AliMUONHitForRec*) fStartSegment->First() || hit == (AliMUONHitForRec*) fStartSegment->Second()) return; // to be changed probably
1823 // Check for missing station
1826 if (((AliMUONHitForRec*)fTrackHits->UncheckedAt(1))->GetChamberNumber() < 8) ok--;
1827 } else if (imax == fNmbTrackHits-1) {
1828 if (((AliMUONHitForRec*)fTrackHits->UncheckedAt(fNmbTrackHits-2))->GetChamberNumber() > 1) ok--;
1830 else if (((AliMUONHitForRec*)fTrackHits->UncheckedAt(imax-1))->GetChamberNumber()/2 - ((AliMUONHitForRec*)fTrackHits->UncheckedAt(imax+1))->GetChamberNumber()/2 > 1) ok--;
1831 if (!ok) { Recover(); return; } // try to recover track
1832 //AZ if (!ok) { if (fgDebug >= 0) cout << imax << endl; DropBranches(imax, 0); return; }
1834 // Remove saved steps and smoother matrices after the outlier
1835 RemoveMatrices(hit->GetZ());
1837 // Check for possible double track candidates
1838 //if (ExistDouble(hit)) return;
1840 TClonesArray *trackPtr = fgTrackReconstructor->GetRecTracksPtr();
1841 Int_t nRecTracks = fgTrackReconstructor->GetNRecTracks();
1843 AliMUONTrackK *trackK = 0;
1844 if (!fNSteps || GetStation0() == 3 && hit->GetChamberNumber() > 7) {
1845 // start track from segment
1846 trackK = new ((*trackPtr)[nRecTracks]) AliMUONTrackK(*fStartSegment);
1847 fgTrackReconstructor->SetNRecTracks(nRecTracks+1);
1848 trackK->fRecover = 2;
1849 trackK->fSkipHit = hit;
1850 trackK->fNmbTrackHits = fNmbTrackHits;
1852 hit = (AliMUONHitForRec*) trackK->fTrackHits->UncheckedAt(0);
1853 hit->SetNTrackHits(hit->GetNTrackHits()-1);
1854 hit = (AliMUONHitForRec*) trackK->fTrackHits->UncheckedAt(1);
1855 hit->SetNTrackHits(hit->GetNTrackHits()-1);
1856 delete trackK->fTrackHits; // not efficient ?
1857 trackK->fTrackHits = new TObjArray(*fTrackHits);
1858 for (Int_t i = 0; i < fNmbTrackHits; i++) {
1859 hit = (AliMUONHitForRec*) fTrackHits->UncheckedAt(i);
1860 hit->SetNTrackHits(hit->GetNTrackHits()+1);
1863 if (GetStation0() == 3) trackK->SortHits(1, trackK->fTrackHits);
1864 if (fgDebug > 0) cout << nRecTracks << " Outlier" << endl;
1867 trackK = new ((*trackPtr)[nRecTracks]) AliMUONTrackK(NULL, NULL);
1869 fgTrackReconstructor->SetNRecTracks(nRecTracks+1);
1870 trackK->fTrackDir = 1;
1871 trackK->fRecover = 2;
1872 trackK->fSkipHit = hit;
1873 Int_t iD = trackK->fParFilter->Last()->GetUniqueID();
1875 trackK->fParFilter->Last()->SetUniqueID(iD-1);
1876 CreateMatrix(trackK->fParFilter);
1878 *((TMatrixD*)trackK->fParFilter->Last()) = *((TMatrixD*)fParExtrap->Last());
1879 trackK->fParFilter->Last()->SetUniqueID(1);
1880 *(trackK->fTrackPar) = *((TMatrixD*)trackK->fParFilter->Last());
1881 iD = trackK->fCovFilter->Last()->GetUniqueID();
1883 trackK->fCovFilter->Last()->SetUniqueID(iD-1);
1884 CreateMatrix(trackK->fCovFilter);
1886 *((TMatrixD*)trackK->fCovFilter->Last()) = *((TMatrixD*)fCovExtrap->Last());
1887 trackK->fCovFilter->Last()->SetUniqueID(1);
1888 *(trackK->fWeight) = *((TMatrixD*)trackK->fCovFilter->Last());
1889 if (trackK->fWeight->Determinant() != 0) {
1891 mnvertLocal(&((*(trackK->fWeight))(0,0)), fgkSize,fgkSize,fgkSize,ifail);
1893 AliWarning(" Determinant fWeight=0:");
1895 trackK->fPosition = trackK->fPositionNew = (*fSteps)[fNSteps-1];
1897 for (Int_t i=0; i<fNmbTrackHits-1; i++) trackK->fChi2 += (*fChi2Array)[i];
1898 if (fgDebug > 0) cout << nRecTracks << " Outlier " << trackK->fChi2 << endl;
1901 //__________________________________________________________________________
1902 Double_t AliMUONTrackK::GetChi2PerPoint(Int_t iPoint) const
1904 /// Return Chi2 at point
1905 return fChi2Smooth ? (*fChi2Smooth)[iPoint] : (*fChi2Array)[iPoint];
1909 //__________________________________________________________________________
1910 void AliMUONTrackK::Print(FILE*) const
1912 /// Print out track information
1914 AliError("Reimplement me in order not to depend on muondata");
1917 // AliMUONHitForRec *hit = 0;
1918 // // from raw clusters
1919 // AliMUONRawCluster *clus = 0;
1920 // TClonesArray *rawclusters = 0;
1921 // for (Int_t i1=0; i1<fNmbTrackHits; i1++) {
1922 // hit = (AliMUONHitForRec*) ((*fTrackHits)[i1]);
1923 // rawclusters = fgTrackReconstructor->GetMUONData()->RawClusters(hit->GetChamberNumber());
1924 // clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->GetHitNumber());
1925 // if (TMath::Abs(clus->GetTrack(1)-1) < 2) {
1926 // if (clus->GetTrack(2)) flag = 2;
1929 // if (clus->GetTrack(2) && TMath::Abs(clus->GetTrack(2)-1) < 2) {
1936 // Int_t sig[2]={1,1}, tid[2]={0};
1937 // for (Int_t i1=0; i1<fNmbTrackHits; i1++) {
1938 // if (GetChi2PerPoint(i1) < -0.1) continue;
1939 // hit = (AliMUONHitForRec*) ((*fTrackHits)[i1]);
1940 // rawclusters = fgTrackReconstructor->GetMUONData()->RawClusters(hit->GetChamberNumber());
1941 // clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->GetHitNumber());
1942 // for (Int_t j=0; j<2; j++) {
1943 // tid[j] = clus->GetTrack(j+1) - 1;
1944 // if (clus->GetTrack(j+1) < 0) { sig[j] = 0; tid[j] = 999; }
1946 // //fprintf(lun,"%3d %3d %10.4f", AliRunLoader::GetRunLoader()->GetEventNumber(), hit->GetChamberNumber(), GetChi2PerPoint(i1));
1947 // if (!(clus->GetTrack(2))) fprintf(lun, "%3d %3d", sig[0], tid[0]); // simple cluster
1948 // else { // track overlap
1949 // fprintf(lun, "%3d %3d", TMath::Max(sig[0],sig[1]), TMath::Min(tid[0],tid[1]));
1950 // //if (tid[0] < 2) flag *= 2;
1951 // //else if (tid[1] < 2) flag *= 3;
1953 // fprintf (lun, "%3d \n", flag);
1958 //__________________________________________________________________________
1959 void AliMUONTrackK::DropBranches(Int_t imax, TObjArray *hits)
1961 /// Drop branches downstream of the skipped hit
1963 TClonesArray *trackPtr;
1964 AliMUONTrackK *trackK;
1966 trackPtr = fgTrackReconstructor->GetRecTracksPtr();
1967 nRecTracks = fgTrackReconstructor->GetNRecTracks();
1968 Int_t icand = trackPtr->IndexOf(this);
1969 if (!hits) hits = fTrackHits;
1971 // Check if the track candidate doesn't exist yet
1972 for (Int_t i=icand+1; i<nRecTracks; i++) {
1973 trackK = (AliMUONTrackK*) ((*trackPtr)[i]);
1974 if (trackK->fNmbTrackHits == 2 && trackK->GetRecover() == 0) continue;
1975 if (trackK->GetRecover() < 0) continue;
1977 if (trackK->fNmbTrackHits >= imax + 1) {
1978 for (Int_t j=0; j<=imax; j++) {
1979 //if (j != fNmbTrackHits-1 && (*trackK->fTrackHits)[j] != (*fTrackHits)[j]) break;
1980 if ((*trackK->fTrackHits)[j] != (*hits)[j]) break;
1982 if (hits != fTrackHits) {
1983 // Drop all branches downstream the hit (for Recover)
1984 trackK->SetRecover(-1);
1985 if (fgDebug >= 0 )cout << " Recover " << i << endl;
1988 // Check if the removal of the hit breaks the track
1991 if (((AliMUONHitForRec*)trackK->fTrackHits->UncheckedAt(1))->GetChamberNumber() < 8) ok--; }
1992 else if (imax == trackK->fNmbTrackHits-1) continue;
1993 // else if (imax == trackK->fNmbTrackHits-1) {
1994 //if (((AliMUONHitForRec*)trackK->fTrackHits->UncheckedAt(trackK->fNmbTrackHits-2))->GetChamberNumber() > 1) ok--;
1996 else if (((AliMUONHitForRec*)trackK->fTrackHits->UncheckedAt(imax-1))->GetChamberNumber()/2 - ((AliMUONHitForRec*)trackK->fTrackHits->UncheckedAt(imax+1))->GetChamberNumber()/2 > 1) ok--;
1997 if (!ok) trackK->SetRecover(-1);
1999 } // for (Int_t j=0;
2001 } // for (Int_t i=0;
2004 //__________________________________________________________________________
2005 void AliMUONTrackK::DropBranches(AliMUONObjectPair *segment)
2007 /// Drop all candidates with the same seed segment
2009 TClonesArray *trackPtr;
2010 AliMUONTrackK *trackK;
2011 AliMUONObjectPair *trackKSegment;
2013 trackPtr = fgTrackReconstructor->GetRecTracksPtr();
2014 nRecTracks = fgTrackReconstructor->GetNRecTracks();
2015 Int_t icand = trackPtr->IndexOf(this);
2017 for (Int_t i=icand+1; i<nRecTracks; i++) {
2018 trackK = (AliMUONTrackK*) ((*trackPtr)[i]);
2019 trackKSegment = trackK->fStartSegment;
2020 if (trackK->fNmbTrackHits == 2 && trackK->GetRecover() == 0) continue;
2021 if (trackK->GetRecover() < 0) continue;
2022 if (trackKSegment->First() == segment->First() &&
2023 trackKSegment->Second() == segment->Second()) trackK->SetRecover(-1);
2025 if (fgDebug >= 0) cout << " Drop segment " << endl;
2028 //__________________________________________________________________________
2029 AliMUONHitForRec* AliMUONTrackK::GetHitLastOk(void)
2031 /// Return the hit where track stopped
2033 if (!fNSteps) return (AliMUONHitForRec*)((*fTrackHits)[1]);
2037 //__________________________________________________________________________
2038 Int_t AliMUONTrackK::GetStation0(void)
2040 /// Return seed station number
2041 return ((AliMUONHitForRec*) fStartSegment->First())->GetChamberNumber() / 2;
2044 //__________________________________________________________________________
2045 Bool_t AliMUONTrackK::ExistDouble(AliMUONHitForRec *hit)
2047 /// Check if the track will make a double after outlier removal
2049 TClonesArray *trackPtr = fgTrackReconstructor->GetRecTracksPtr();
2050 Int_t nRecTracks = fgTrackReconstructor->GetNRecTracks();
2051 TObjArray *hitArray = new TObjArray(*fTrackHits);
2052 TObjArray *hitArray1 = new TObjArray(*hitArray);
2053 hitArray1->Remove(hit);
2054 hitArray1->Compress();
2056 Bool_t same = kFALSE;
2057 for (Int_t i=0; i<nRecTracks; i++) {
2058 AliMUONTrackK *trackK = (AliMUONTrackK*) ((*trackPtr)[i]);
2059 if (trackK->fNmbTrackHits == 2 && trackK->GetRecover() == 0) continue;
2060 if (trackK == this) continue;
2061 if (trackK->fNmbTrackHits == fNmbTrackHits || trackK->fNmbTrackHits == fNmbTrackHits-1) {
2062 TObjArray *hits = new TObjArray(*trackK->fTrackHits);
2064 if (trackK->fNmbTrackHits == fNmbTrackHits) {
2065 for (Int_t j=0; j<fNmbTrackHits; j++) {
2066 if (hits->UncheckedAt(j) != hitArray->UncheckedAt(j)) { same = kFALSE; break; }
2068 if (same) { delete hits; break; }
2069 if (trackK->fSkipHit) {
2070 TObjArray *hits1 = new TObjArray(*hits);
2071 if (hits1->Remove(trackK->fSkipHit) > 0) {
2074 for (Int_t j=0; j<fNmbTrackHits-1; j++) {
2075 if (hits1->UncheckedAt(j) != hitArray1->UncheckedAt(j)) { same = kFALSE; break; }
2077 if (same) { delete hits1; break; }
2082 // Check with removed outlier
2084 for (Int_t j=0; j<fNmbTrackHits-1; j++) {
2085 if (hits->UncheckedAt(j) != hitArray1->UncheckedAt(j)) { same = kFALSE; break; }
2087 if (same) { delete hits; break; }
2091 } // for (Int_t i=0; i<nRecTracks;
2092 delete hitArray; delete hitArray1;
2093 if (same && fgDebug >= 0) cout << " Same" << endl;
2097 //__________________________________________________________________________
2098 Bool_t AliMUONTrackK::ExistDouble(void)
2100 /// Check if the track will make a double after recovery
2102 TClonesArray *trackPtr = fgTrackReconstructor->GetRecTracksPtr();
2103 Int_t nRecTracks = fgTrackReconstructor->GetNRecTracks();
2105 TObjArray *hitArray = new TObjArray(*fTrackHits);
2106 if (GetStation0() == 3) SortHits(0, hitArray); // sort
2107 //if (GetStation0() == 3) SortHits(1, hitArray); // unsort
2109 Bool_t same = kFALSE;
2110 for (Int_t i=0; i<nRecTracks; i++) {
2111 AliMUONTrackK *trackK = (AliMUONTrackK*) ((*trackPtr)[i]);
2112 if (trackK->fNmbTrackHits == 2 && trackK->GetRecover() == 0) continue;
2113 if (trackK == this) continue;
2114 //AZ if (trackK->GetRecover() < 0) continue; //
2115 if (trackK->fNmbTrackHits >= fNmbTrackHits) {
2116 TObjArray *hits = new TObjArray(*trackK->fTrackHits);
2117 if (trackK->GetStation0() == 3) SortHits(0, hits); // sort
2118 //if (trackK->GetStation0() == 3) SortHits(1, hits); // unsort
2119 for (Int_t j=0; j<fNmbTrackHits; j++) {
2120 //cout << fNmbTrackHits << " " << i << " " << j << " " << (*hitArray)[j] << " " << (*hits)[j] << " " << trackK->fSkipHit << endl;
2121 if (j != fNmbTrackHits-1 && (*hitArray)[j] != (*hits)[j]) break;
2122 if (j == fNmbTrackHits-1) {
2123 if (trackK->fSkipHit && TMath::Abs(((AliMUONHitForRec*)((*hitArray)[j]))->GetZ()-trackK->fSkipHit->GetZ()) < 0.5) same = kTRUE;
2124 //if (trackK->fNmbTrackHits > fNmbTrackHits &&
2125 //if (trackK->fSkipHit) cout << ((AliMUONHitForRec*)((*hitArray)[j]))->GetZ() << " " << trackK->fSkipHit->GetZ() << endl;
2127 } // for (Int_t j=0;
2131 } // for (Int_t i=0;
2136 //______________________________________________________________________________
2137 void mnvertLocal(Double_t *a, Int_t l, Int_t, Int_t n, Int_t &ifail)
2139 ///*-*-*-*-*-*-*-*-*-*-*-*Inverts a symmetric matrix*-*-*-*-*-*-*-*-*-*-*-*-*
2140 ///*-* ==========================
2141 ///*-* inverts a symmetric matrix. matrix is first scaled to
2142 ///*-* have all ones on the diagonal (equivalent to change of units)
2143 ///*-* but no pivoting is done since matrix is positive-definite.
2144 ///*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
2146 // taken from TMinuit package of Root (l>=n)
2147 // fVERTs, fVERTq and fVERTpp changed to localVERTs, localVERTq and localVERTpp
2148 // Double_t localVERTs[n], localVERTq[n], localVERTpp[n];
2149 Double_t * localVERTs = new Double_t[n];
2150 Double_t * localVERTq = new Double_t[n];
2151 Double_t * localVERTpp = new Double_t[n];
2152 // fMaxint changed to localMaxint
2153 Int_t localMaxint = n;
2155 /* System generated locals */
2158 /* Local variables */
2160 Int_t i, j, k, kp1, km1;
2162 /* Parameter adjustments */
2168 if (n < 1) goto L100;
2169 if (n > localMaxint) goto L100;
2170 //*-*- scale matrix by sqrt of diag elements
2171 for (i = 1; i <= n; ++i) {
2173 if (si <= 0) goto L100;
2174 localVERTs[i-1] = 1 / TMath::Sqrt(si);
2176 for (i = 1; i <= n; ++i) {
2177 for (j = 1; j <= n; ++j) {
2178 a[i + j*l] = a[i + j*l]*localVERTs[i-1]*localVERTs[j-1];
2181 //*-*- . . . start main loop . . . .
2182 for (i = 1; i <= n; ++i) {
2184 //*-*- preparation for elimination step1
2185 if (a[k + k*l] != 0) localVERTq[k-1] = 1 / a[k + k*l];
2187 localVERTpp[k-1] = 1;
2191 if (km1 < 0) goto L100;
2192 else if (km1 == 0) goto L50;
2195 for (j = 1; j <= km1; ++j) {
2196 localVERTpp[j-1] = a[j + k*l];
2197 localVERTq[j-1] = a[j + k*l]*localVERTq[k-1];
2201 if (k - n < 0) goto L51;
2202 else if (k - n == 0) goto L60;
2205 for (j = kp1; j <= n; ++j) {
2206 localVERTpp[j-1] = a[k + j*l];
2207 localVERTq[j-1] = -a[k + j*l]*localVERTq[k-1];
2210 //*-*- elimination proper
2212 for (j = 1; j <= n; ++j) {
2213 for (k = j; k <= n; ++k) { a[j + k*l] += localVERTpp[j-1]*localVERTq[k-1]; }
2216 //*-*- elements of left diagonal and unscaling
2217 for (j = 1; j <= n; ++j) {
2218 for (k = 1; k <= j; ++k) {
2219 a[k + j*l] = a[k + j*l]*localVERTs[k-1]*localVERTs[j-1];
2220 a[j + k*l] = a[k + j*l];
2223 delete [] localVERTs;
2224 delete [] localVERTq;
2225 delete [] localVERTpp;
2227 //*-*- failure return
2229 delete [] localVERTs;
2230 delete [] localVERTq;
2231 delete [] localVERTpp;