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 AliMillepede
20 /// Detector independent alignment class
22 /// This modified C++ version is based on a C++ translation of Millepede used
23 /// for LHCb Vertex Detector alignment (lhcb-2005-101), available here
24 /// http://isscvs.cern.ch/cgi-bin/cvsweb.cgi/Alignment/AlignmentTools/src/?cvsroot=lhcb
25 /// The original millepede fortran package is available at:
26 /// http://www.desy.de/~blobel/wwwmille.html
28 /// \author Javier Castillo
29 //-----------------------------------------------------------------------------
36 #include "AliMillepede.h"
38 //=============================================================================
39 AliMillepede::AliMillepede(): TObject()
41 /// Standard constructor
43 fIndexLocEq.Set(fgkMaxGlobalPar+fgkMaxLocalPar);
44 fDerivLocEq.Set(fgkMaxGlobalPar+fgkMaxLocalPar);
45 fIndexAllEqs.Set(1000*fgkMaxGlobalPar+fgkMaxLocalPar);
46 fDerivAllEqs.Set(1000*fgkMaxGlobalPar+fgkMaxLocalPar);
47 fLocEqPlace.Set(1000);
52 AliInfo(" o ooooo o o o oo ooo oo ooo oo ");
53 AliInfo(" o o o o o o o o o o o o o o o o ");
54 AliInfo(" o o o o o o oooo o o oooo o o oooo ");
55 AliInfo(" o o o o o o o ooo o o o o ");
56 AliInfo(" o o o o o o oo o oo ooo oo ++ starts");
61 //=============================================================================
62 AliMillepede::~AliMillepede() {
67 //=============================================================================
68 Int_t AliMillepede::InitMille(int nGlo, int nLoc, int lNStdDev,
69 double lResCut, double lResCutInit)
71 /// Initialization of millepede
73 AliDebug(1,"----------------------------------------------------");
75 AliDebug(1," Entering InitMille");
77 AliDebug(1,"-----------------------------------------------------");
80 fNGlobalConstraints = 0;
81 fNLocalFits = 0; // Total number of local fits
82 fNLocalFitsRejected = 0; // Total number of local fits rejected
83 fChi2CutRef = 1.0; // Reference value for Chi^2/ndof cut
85 AliMillepede::SetNLocalEquations(0); // Number of local fits (starts at 0)
87 fIter = 0; // By default iterations are turned off, turned on by use SetIterations
90 fResCutInit = lResCutInit;
93 fNGlobalPar = nGlo; // Number of global derivatives
94 fNLocalPar = nLoc; // Number of local derivatives
95 fNStdDev = lNStdDev; // Number of StDev for local fit chisquare cut
97 AliDebug(1,Form("Number of global parameters : %d", fNGlobalPar));
98 AliDebug(1,Form("Number of local parameters : %d", fNLocalPar));
99 AliDebug(1,Form("Number of standard deviations : %d", fNStdDev));
101 if (fNGlobalPar>fgkMaxGlobalPar || fNLocalPar>fgkMaxLocalPar) {
102 AliDebug(1,"Two many parameters !!!!!");
106 // Global parameters initializations
107 for (int i=0; i<fNGlobalPar; i++) {
116 for (int j=0; j<fNGlobalPar;j++) {
121 // Local parameters initializations
123 for (int i=0; i<fNLocalPar; i++) {
126 for (int j=0; j<fNLocalPar;j++) {
131 // Then we fix all parameters...
133 for (int j=0; j<fNGlobalPar; j++) {
134 AliMillepede::SetParSigma(j,0.0);
137 fDerivLocEq.Reset(); fNDerivLocEq=0;
138 fIndexLocEq.Reset(); fNIndexLocEq=0;
140 fIndexAllEqs.Reset(); fNIndexAllEqs=0;
141 fDerivAllEqs.Reset(); fNDerivAllEqs=0;
142 fLocEqPlace.Reset(); fNLocEqPlace=0;
145 AliDebug(1,"----------------------------------------------------");
147 AliDebug(1," InitMille has been successfully called!");
149 AliDebug(1,"-----------------------------------------------------");
156 -----------------------------------------------------------
157 PARGLO: initialization of global parameters
158 -----------------------------------------------------------
160 param = array of starting values
162 -----------------------------------------------------------
164 Int_t AliMillepede::SetGlobalParameters(double *param)
166 /// initialization of global parameters
167 for(Int_t iPar=0; iPar<fNGlobalPar; iPar++){
168 fInitPar[iPar] = param[iPar];
175 -----------------------------------------------------------
176 PARGLO: initialization of global parameters
177 -----------------------------------------------------------
179 iPar = the index of the global parameter in the
180 result array (equivalent to fDeltaPar[]).
182 param = the starting value
184 -----------------------------------------------------------
186 Int_t AliMillepede::SetGlobalParameter(int iPar, double param)
188 /// initialization of global parameter iPar
189 if (iPar<0 || iPar>=fNGlobalPar) {
193 fInitPar[iPar] = param;
200 -----------------------------------------------------------
201 PARSIG: define a constraint for a single global param
202 param is 'encouraged' to vary within [-sigma;sigma]
204 -----------------------------------------------------------
206 iPar = the index of the global parameter in the
207 result array (equivalent to fDeltaPar[]).
209 sigma = value of the constraint (sigma <= 0. will
210 mean that parameter is FIXED !!!)
212 -----------------------------------------------------------
214 Int_t AliMillepede::SetParSigma(int iPar, double sigma)
216 /// Define a range [-sigma;sigma] where iPar is encourage to vary
217 if (iPar>=fNGlobalPar) {
221 fSigmaPar[iPar] = sigma;
229 -----------------------------------------------------------
230 NONLIN: set nonlinear flag for a single global param
231 update of param durin iterations will not
232 consider initial starting value
233 -----------------------------------------------------------
235 iPar = the index of the global parameter in the
236 result array (equivalent to fDeltaPar[]).
238 -----------------------------------------------------------
240 Int_t AliMillepede::SetNonLinear(int iPar)
242 /// Set nonlinear flag for iPar
243 if (iPar<0 || iPar>=fNGlobalPar) {
247 fIsNonLinear[iPar] = 1;
255 -----------------------------------------------------------
256 INITUN: unit for iteration
257 -----------------------------------------------------------
259 lChi2CutFac is used by Fitloc to define the Chi^2/ndof cut value
261 A large cutfac value enables to take a wider range of tracks
262 for first iterations, which might be useful if misalignments
265 As soon as cutfac differs from 0 iteration are requested.
266 cutfac is then reduced, from one iteration to the other,
267 and iterations are stopped when it reaches the value 1.
269 At least one more iteration is often needed in order to remove
270 tracks containing outliers.
272 -----------------------------------------------------------
274 Int_t AliMillepede::SetIterations(double lChi2CutFac)
276 /// Number of iterations is calculated from lChi2CutFac
277 fChi2CutFactor = TMath::Max(1.0, lChi2CutFac);
279 AliInfo(Form("Initial cut factor is %f",fChi2CutFactor));
280 fIter = 1; // Initializes the iteration process
285 -----------------------------------------------------------
286 CONSTF: define a constraint equation in AliMillepede
287 -----------------------------------------------------------
289 dercs = the row containing constraint equation
290 derivatives (put into the final matrix)
292 lLagMult = the lagrange multiplier value (sum of equation)
294 -----------------------------------------------------------
296 Int_t AliMillepede::SetGlobalConstraint(double dercs[], double lLagMult)
298 /// Define a constraint equation
299 if (fNGlobalConstraints>=fgkMaxGloCsts) {
300 AliInfo("Too many constraints !!!");
304 for (int i=0; i<fNGlobalPar; i++) {
305 fMatDerConstr[fNGlobalConstraints][i] = dercs[i];
308 fLagMult[fNGlobalConstraints] = lLagMult;
309 fNGlobalConstraints++ ;
310 AliInfo(Form("Number of constraints increased to %d",fNGlobalConstraints));
316 -----------------------------------------------------------
317 EQULOC: write ONE equation in the matrices
318 -----------------------------------------------------------
320 dergb[1..fNGlobalPar] = global parameters derivatives
321 derlc[1..fNLocalPar] = local parameters derivatives
322 rmeas = measured value
323 sigma = error on measured value (nothing to do with SetParSigma!!!)
325 -----------------------------------------------------------
327 Int_t AliMillepede::SetLocalEquation(double dergb[], double derlc[], double lMeas, double lSigma)
329 /// Write one local equation
330 if (lSigma<=0.0) { // If parameter is fixed, then no equation
331 for (int i=0; i<fNLocalPar; i++) {
334 for (int i=0; i<fNGlobalPar; i++) {
340 // Serious equation, initialize parameters
341 double lWeight = 1.0/(lSigma*lSigma);
347 for (int i=0; i<fNLocalPar; i++) { // Retrieve local param interesting indices
349 if (iLocFirst == -1) {
350 iLocFirst = i; // first index
352 iLocLast = i; // last index
355 AliDebug(2,Form("%d / %d",iLocFirst, iLocLast));
357 for (int i=0; i<fNGlobalPar; i++) { // Idem for global parameters
359 if (iGlobFirst == -1) {
360 iGlobFirst = i; // first index
362 iGlobLast = i; // last index
365 AliDebug(2,Form("%d / %d",iGlobFirst,iGlobLast));
367 if (fNIndexLocEq==fIndexLocEq.GetSize()) fIndexLocEq.Set(2*fNIndexLocEq);
368 fIndexLocEq.AddAt(-1,fNIndexLocEq++);
369 if (fNDerivLocEq==fDerivLocEq.GetSize()) fDerivLocEq.Set(2*fNDerivLocEq);
370 fDerivLocEq.AddAt(lMeas,fNDerivLocEq++);
373 for (int i=iLocFirst; i<=iLocLast; i++) { // Store interesting local parameters
375 if (fNIndexLocEq==fIndexLocEq.GetSize()) fIndexLocEq.Set(2*fNIndexLocEq);
376 fIndexLocEq.AddAt(i,fNIndexLocEq++);
377 if (fNDerivLocEq==fDerivLocEq.GetSize()) fDerivLocEq.Set(2*fNDerivLocEq);
378 fDerivLocEq.AddAt(derlc[i],fNDerivLocEq++);
383 if (fNIndexLocEq==fIndexLocEq.GetSize()) fIndexLocEq.Set(2*fNIndexLocEq);
384 fIndexLocEq.AddAt(-1,fNIndexLocEq++);
385 if (fNDerivLocEq==fDerivLocEq.GetSize()) fDerivLocEq.Set(2*fNDerivLocEq);
386 fDerivLocEq.AddAt(lWeight,fNDerivLocEq++);
388 for (int i=iGlobFirst; i<=iGlobLast; i++) { // Store interesting global parameters
390 if (fNIndexLocEq==fIndexLocEq.GetSize()) fIndexLocEq.Set(2*fNIndexLocEq);
391 fIndexLocEq.AddAt(i,fNIndexLocEq++);
392 if (fNDerivLocEq==fDerivLocEq.GetSize()) fDerivLocEq.Set(2*fNDerivLocEq);
393 fDerivLocEq.AddAt(dergb[i],fNDerivLocEq++);
398 AliDebug(2,Form("Out Equloc -- NST = %d",fNDerivLocEq));
403 -----------------------------------------------------------
404 FITLOC: perform local params fit, once all the equations
405 have been written by EquLoc
406 -----------------------------------------------------------
408 iFit = number of the fit, it is used to store
409 fit parameters and then retrieve them
410 for iterations (via FINDEXALLEQS and FDERIVALLEQS)
412 localParams = contains the fitted track parameters and
415 bSingleFit = is an option, if it is set to 1, we don't
416 perform the last loop. It is used to update
417 the track parameters without modifying global
420 -----------------------------------------------------------
422 Int_t AliMillepede::LocalFit(int iFit, double localParams[], bool bSingleFit)
424 /// Perform local parameters fit once all the local equations have been set
426 // Few initializations
429 int iIdx, jIdx, kIdx;
430 int iIdxIdx, jIdxIdx;
440 double lWeight = 0.0;
443 double lRedChi2 = 0.0;
444 double lChi2Cut = 0.0;
447 int nEqTerms = fNDerivLocEq; // Number of terms (local + global derivatives,
448 // measurement and weight) involved in this local equation
451 // Fill the track store at first pass
453 if (fIter < 2 && !bSingleFit) { // Do it only once
454 AliDebug(1,Form("Store equation no: %d", iFit));
456 for (i=0; i<nEqTerms; i++) { // Store the track parameters
457 if (fNIndexAllEqs==fIndexAllEqs.GetSize()) fIndexAllEqs.Set(2*fNIndexAllEqs);
458 fIndexAllEqs.AddAt(fIndexLocEq[i],fNIndexAllEqs++);
459 if (fNDerivAllEqs==fDerivAllEqs.GetSize()) fDerivAllEqs.Set(2*fNDerivAllEqs);
460 fDerivAllEqs.AddAt(fDerivLocEq[i],fNDerivAllEqs++);
462 if (fNLocEqPlace==fLocEqPlace.GetSize()) fLocEqPlace.Set(2*fNLocEqPlace);
463 fLocEqPlace.AddAt(fNIndexAllEqs,fNLocEqPlace++);
466 AliDebug(2,Form("FLocEqPlace size = %d",fLocEqPlace[iFit]));
467 AliDebug(2,Form("FIndexAllEqs size = %d",fNIndexAllEqs));
471 for (i=0; i<fNLocalPar; i++) { // reset local params
474 for (j=0; j<fNLocalPar; j++) {
475 fMatCLoc[i][j] = 0.0;
479 for (i=0; i<fNGlobalPar; i++) {
480 fGlo2CGLRow[i] = -1; // reset mixed params
486 LOOPS : HOW DOES IT WORKS ?
488 Now start by reading the informations stored with EquLoc.
489 Those informations are in vector FINDEXSTORE and FDERIVSTORE.
490 Each -1 in FINDEXSTORE delimits the equation parameters:
492 First -1 ---> lMeas in FDERIVSTORE
493 Then we have indices of local eq in FINDEXSTORE, and derivatives in FDERIVSTORE
494 Second -1 ---> weight in FDERIVSTORE
495 Then follows indices and derivatives of global eq.
498 We took them and store them into matrices.
500 As we want ONLY local params, we substract the part of the estimated value
501 due to global params. Indeed we could have already an idea of these params,
502 with previous alignment constants for example (set with PARGLO). Also if there
503 are more than one iteration (FITLOC could be called by FITGLO)
509 // FIRST LOOP : local track fit
513 // fIndexLocEq.push_back(-1);
514 if (fNIndexLocEq==fIndexLocEq.GetSize()) fIndexLocEq.Set(2*fNIndexLocEq);
515 fIndexLocEq.AddAt(-1,fNIndexLocEq++);
517 while (iEqTerm <= nEqTerms) {
518 if (fIndexLocEq[iEqTerm] == -1) {
519 if (iMeas == -1) { // First -1 : lMeas
521 iLocFirst = iEqTerm+1;
523 else if (iWeight == 0) { // Second -1 : weight
525 iLocLast = iEqTerm-1;
526 iGloFirst = iEqTerm+1;
528 else { // Third -1 : end of equation; start of next
529 iGloLast = iEqTerm-1;
530 lMeas = fDerivLocEq[iMeas];
531 lWeight = fDerivLocEq[iWeight];
532 // AliDebug(1,Form("lMeas = %f", lMeas));
533 // AliDebug(1,Form("lWeight = %f", lWeight));
535 // Now suppress the global part (only relevant with iterations)
537 for (i=iGloFirst; i<=iGloLast; i++) {
538 iIdx = fIndexLocEq[i]; // Global param indice
539 // AliDebug(2,Form("fDeltaPar[%d] = %f", iIdx, fDeltaPar[iIdx]));
540 // AliDebug(2,Form("Starting misalignment = %f",fInitPar[iIdx]));
541 if (fIsNonLinear[iIdx] == 0)
542 lMeas -= fDerivLocEq[i]*(fInitPar[iIdx]+fDeltaPar[iIdx]); // linear parameter
544 lMeas -= fDerivLocEq[i]*(fDeltaPar[iIdx]); // nonlinear parameter
546 // AliDebug(2,Form("lMeas after global stuff removal = %f", lMeas));
548 for (i=iLocFirst; i<=iLocLast; i++) { // Finally fill local matrix and vector
549 iIdx = fIndexLocEq[i]; // Local param indice (the matrix line)
550 fVecBLoc[iIdx] += lWeight*lMeas*fDerivLocEq[i];
551 // AliDebug(2,Form("fVecBLoc[%d] = %f", iIdx, fVecBLoc[iIdx]));
553 for (j=iLocFirst; j<=i ; j++) { // Symmetric matrix, don't bother j>i coeffs
554 jIdx = fIndexLocEq[j];
555 fMatCLoc[iIdx][jIdx] += lWeight*fDerivLocEq[i]*fDerivLocEq[j];
556 // AliDebug(2,Form("fMatCLoc[%d][%d] = ", iIdx, jIdx, fMatCLoc[iIdx][jIdx]));
561 iEqTerm--; // end of one equation is the beginning of next
562 } // End of "end of equation" operations
563 } // End of loop on equation
565 } // End of loop on all equations used in the fit
569 // Local params matrix is completed, now invert to solve...
572 Int_t nRank = AliMillepede::SpmInv(fMatCLoc, fVecBLoc, fNLocalPar);
573 // nRank is the number of nonzero diagonal elements
576 AliDebug(1," __________________________________________________");
577 AliDebug(1,Form(" Printout of local fit (FITLOC) with rank= %d", nRank));
578 AliDebug(1," Result of local fit : (index/parameter/error)");
580 for (i=0; i<fNLocalPar; i++) {
581 AliDebug(1,Form("%d / %.6f / %.6f", i, fVecBLoc[i], TMath::Sqrt(fMatCLoc[i][i])));
585 // Store the track params and errors
587 for (i=0; i<fNLocalPar; i++) {
588 localParams[2*i] = fVecBLoc[i];
589 localParams[2*i+1] = TMath::Sqrt(TMath::Abs(fMatCLoc[i][i]));
594 // SECOND LOOP : residual calculation
601 while (iEqTerm <= nEqTerms) {
602 if (fIndexLocEq[iEqTerm] == -1) {
603 if (iMeas == -1) { // First -1 : lMeas
605 iLocFirst = iEqTerm+1;
607 else if (iWeight == 0) { // Second -1 : weight
609 iLocLast = iEqTerm-1;
610 iGloFirst = iEqTerm+1;
612 else { // Third -1 : end of equation; start of next
613 iGloLast = iEqTerm-1;
614 lMeas = fDerivLocEq[iMeas];
615 lWeight = fDerivLocEq[iWeight];
617 // Print all (for debugging purposes)
619 // int nDerLoc = iLocLast-iLocFirst+1; // Number of local derivatives involved
620 // int nDerGlo = iGloLast-iGloFirst+1; // Number of global derivatives involved
623 // AliDebug(2,Form(". equation: measured value %.6f +/- %.6f", lMeas, 1.0/TMath::Sqrt(lWeight)));
624 // AliDebug(2,Form("Number of derivatives (global, local): %d, %d",nDerGlo,nDerLoc));
625 // AliDebug(2,"Global derivatives are: (index/derivative/parvalue) ");
627 // for (i=iGloFirst; i<=iGloLast; i++) {
628 // AliDebug(2,Form("%d / %.6f / %.6f",fIndexLocEq[i],fDerivLocEq[i],fInitPar[fIndexLocEq[i]]));
631 // AliDebug(2,"Local derivatives are: (index/derivative) ");
633 // for (i=(ja+1); i<jb; i++) {AliDebug(2,Form("%d / %.6f",fIndexLocEq[i], fDerivLocEq[i]));}
635 // Now suppress local and global parts to LMEAS;
637 // First the local part
638 for (i=iLocFirst; i<=iLocLast; i++) {
639 iIdx = fIndexLocEq[i];
640 lMeas -= fDerivLocEq[i]*fVecBLoc[iIdx];
642 // Then the global part
643 for (i=iGloFirst; i<=iGloLast; i++) {
644 iIdx = fIndexLocEq[i];
645 if (fIsNonLinear[iIdx] == 0)
646 lMeas -= fDerivLocEq[i]*(fInitPar[iIdx]+fDeltaPar[iIdx]); // linear parameter
648 lMeas -= fDerivLocEq[i]*(fDeltaPar[iIdx]); // nonlinear parameter
651 // lMeas contains now the residual value
652 AliDebug(2,Form("Residual value : %.6f", lMeas));
654 // reject the track if lMeas is too important (outlier)
655 if (TMath::Abs(lMeas) >= fResCutInit && fIter <= 1) {
656 AliDebug(2,"Rejected track !!!!!");
657 fNLocalFitsRejected++;
658 fIndexLocEq.Reset(); fNIndexLocEq=0; // reset stores and go to the next track
659 fDerivLocEq.Reset(); fNDerivLocEq=0;
663 if (TMath::Abs(lMeas) >= fResCut && fIter > 1) {
664 AliDebug(2,"Rejected track !!!!!");
665 fNLocalFitsRejected++;
666 fIndexLocEq.Reset(); fNIndexLocEq=0; // reset stores and go to the next track
667 fDerivLocEq.Reset(); fNDerivLocEq=0;
671 lChi2 += lWeight*lMeas*lMeas ; // total chi^2
672 nEq++; // number of equations
676 } // End of "end of equation" operations
677 } // End of loop on equation
679 } // End of loop on all equations used in the fit
684 AliDebug(1,Form("Final chi square / degrees of freedom %.2f / %d",lChi2, nDoF));
686 if (nDoF > 0) lRedChi2 = lChi2/float(nDoF); // Chi^2/dof
690 if (fNStdDev != 0 && nDoF > 0 && !bSingleFit) // Chisquare cut
692 lChi2Cut = AliMillepede::Chi2DoFLim(fNStdDev, nDoF)*fChi2CutFactor;
694 AliDebug(1,Form("Reject if Chisq/Ndf = %.4f > %.4f",lRedChi2,lChi2Cut));
696 if (lRedChi2 > lChi2Cut) // Reject the track if too much...
698 AliDebug(2,"Rejected track !!!!!");
699 fNLocalFitsRejected++;
700 fIndexLocEq.Reset(); fNIndexLocEq=0; // reset stores and go to the next track
701 fDerivLocEq.Reset(); fNDerivLocEq=0;
706 if (bSingleFit) // Stop here if just updating the track parameters
708 fIndexLocEq.Reset(); fNIndexLocEq=0; // Reset store for the next track
709 fDerivLocEq.Reset(); fNDerivLocEq=0;
714 // THIRD LOOP: local operations are finished, track is accepted
715 // We now update the global parameters (other matrices)
722 while (iEqTerm <= nEqTerms)
724 if (fIndexLocEq[iEqTerm] == -1)
726 if (iMeas == -1) { // First -1 : lMeas
728 iLocFirst = iEqTerm+1;
730 else if (iWeight == 0) { // Second -1 : weight
732 iLocLast = iEqTerm-1;
733 iGloFirst = iEqTerm+1;
735 else { // Third -1 : end of equation; start of next
736 iGloLast = iEqTerm-1;
737 lMeas = fDerivLocEq[iMeas];
738 lWeight = fDerivLocEq[iWeight];
740 // Now suppress the global part
741 for (i=iGloFirst; i<=iGloLast; i++) {
742 iIdx = fIndexLocEq[i]; // Global param indice
743 if (fIsNonLinear[iIdx] == 0)
744 lMeas -= fDerivLocEq[i]*(fInitPar[iIdx]+fDeltaPar[iIdx]); // linear parameter
746 lMeas -= fDerivLocEq[i]*(fDeltaPar[iIdx]); // nonlinear parameter
749 for (i=iGloFirst; i<=iGloLast; i++) {
750 iIdx = fIndexLocEq[i]; // Global param indice (the matrix line)
752 fVecBGlo[iIdx] += lWeight*lMeas*fDerivLocEq[i];
753 // AliDebug(2,Form("fVecBGlo[%d] = %.6f", j, fVecBGlo[j] ));
755 // First of all, the global/global terms (exactly like local matrix)
757 for (j=iGloFirst; j<=iGloLast; j++) {
758 jIdx = fIndexLocEq[j];
759 fMatCGlo[iIdx][jIdx] += lWeight*fDerivLocEq[i]*fDerivLocEq[j];
760 // AliDebug(2,Form("fMatCGlo[%d][%d] = %.6f",iIdx,jIdx,fMatCGlo[iIdx][jIdx]));
763 // Now we have also rectangular matrices containing global/local terms.
765 iIdxIdx = fGlo2CGLRow[iIdx]; // Index of index
766 if (iIdxIdx == -1) { // New global variable
767 for (k=0; k<fNLocalPar; k++) {
768 fMatCGloLoc[nGloInFit][k] = 0.0; // Initialize the row
770 fGlo2CGLRow[iIdx] = nGloInFit;
771 fCGLRow2Glo[nGloInFit] = iIdx;
776 // Now fill the rectangular matrix
777 for (k=iLocFirst; k<=iLocLast ; k++) {
778 kIdx = fIndexLocEq[k];
779 fMatCGloLoc[iIdxIdx][kIdx] += lWeight*fDerivLocEq[i]*fDerivLocEq[k];
780 // AliDebug(2,Form("fMatCGloLoc[%d][%d] = %.6f",iIdxIdx,kIdx,fMatCGloLoc[iIdxIdx][kIdx]));
786 } // End of "end of equation" operations
787 } // End of loop on equation
789 } // End of loop on all equations used in the fit
791 // Third loop is finished, now we update the correction matrices
792 AliMillepede::SpAVAt(fMatCLoc, fMatCGloLoc, fMatCGloCorr, fNLocalPar, nGloInFit);
793 AliMillepede::SpAX(fMatCGloLoc, fVecBLoc, fVecBGloCorr, fNLocalPar, nGloInFit);
795 for (iIdxIdx=0; iIdxIdx<nGloInFit; iIdxIdx++) {
796 iIdx = fCGLRow2Glo[iIdxIdx];
797 fVecBGlo[iIdx] -= fVecBGloCorr[iIdxIdx];
799 for (jIdxIdx=0; jIdxIdx<=iIdxIdx; jIdxIdx++) {
800 int jIdx = fCGLRow2Glo[jIdxIdx];
801 fMatCGlo[iIdx][jIdx] -= fMatCGloCorr[iIdxIdx][jIdxIdx];
802 fMatCGlo[jIdx][iIdx] = fMatCGlo[iIdx][jIdx];
806 fIndexLocEq.Reset(); fNIndexLocEq=0; // Reset store for the next track
807 fDerivLocEq.Reset(); fNDerivLocEq=0;
814 -----------------------------------------------------------
815 MAKEGLOBALFIT: perform global params fit, once all the 'tracks'
816 have been fitted by FitLoc
817 -----------------------------------------------------------
819 par[] = array containing the computed global
820 parameters (the misalignment constants)
822 error[] = array containing the error on global
823 parameters (estimated by AliMillepede)
825 pull[] = array containing the corresponding pulls
827 -----------------------------------------------------------
829 Int_t AliMillepede::GlobalFit(double par[], double error[], double pull[])
831 /// perform global parameters fit once all the local equations have been fitted
839 double localPars[2*fgkMaxLocalPar];
841 int nLocFitsGood = 0;
845 AliInfo("..... Making global fit .....");
847 nLocFitsTot = AliMillepede::GetNLocalEquations();
849 while (fIter < fMaxIter) // Iteration for the final loop
852 nLocFits = AliMillepede::GetNLocalEquations();
853 AliInfo(Form("...using %d local fits...",nLocFits));
855 // Start by saving the diagonal elements
857 for (i=0; i<fNGlobalPar; i++) {
858 fDiagCGlo[i] = fMatCGlo[i][i];
861 // Then we retrieve the different constraints: fixed parameter or global equation
863 nGloFix = 0; // First look at the fixed global params
865 for (i=0; i<fNGlobalPar; i++) {
866 if (fSigmaPar[i] <= 0.0) { // fixed global param
868 for (j=0; j<fNGlobalPar; j++) {
869 fMatCGlo[i][j] = 0.0; // Reset row and column
870 fMatCGlo[j][i] = 0.0;
874 fMatCGlo[i][i] += 1.0/(fSigmaPar[i]*fSigmaPar[i]);
878 nVar = fNGlobalPar; // Current number of equations
879 AliDebug(1,Form("Number of constraint equations : %d", fNGlobalConstraints));
881 for (i=0; i<fNGlobalConstraints; i++) { // Then the constraint equation
882 lConstraint = fLagMult[i];
883 for (j=0; j<fNGlobalPar; j++) {
884 fMatCGlo[nVar][j] = float(nLocFits)*fMatDerConstr[i][j];
885 fMatCGlo[j][nVar] = float(nLocFits)*fMatDerConstr[i][j];
886 lConstraint -= fMatDerConstr[i][j]*(fInitPar[j]+fDeltaPar[j]);
889 fMatCGlo[nVar][nVar] = 0.0;
890 fVecBGlo[nVar] = float(nLocFits)*lConstraint;
895 // Intended to compute the final global chisquare
897 double lFinalCor = 0.0;
900 for (i=0; i<fNGlobalPar; i++) {
901 for (j=0; j<fNGlobalPar; j++) {
902 // printf("%d, %d, %.6f %.6f %.6f\n",i,j,step[i],fMatCGlo[i][j],step[j]);
903 lFinalCor += step[i]*fMatCGlo[i][j]*step[j];
904 if (i == j && fSigmaPar[i] != 0) {
905 lFinalCor -= step[i]*step[i]/(fSigmaPar[i]*fSigmaPar[i]);
911 AliInfo(Form(" Final coeff is %.6f",lFinalCor));
912 AliInfo(Form(" Final NDOFs = %d", fNGlobalPar));
914 // The final matrix inversion
916 Int_t nRank = AliMillepede::SpmInv(fMatCGlo, fVecBGlo, nVar);
918 for (i=0; i<fNGlobalPar; i++) {
919 fDeltaPar[i] += fVecBGlo[i]; // Update global parameters values (for iterations)
920 AliDebug(1,Form("fDeltaPar[%d] = %.6f", i, fDeltaPar[i]));
921 AliDebug(1,Form("fMatCGlo[%d][%d] = %.6f", i, i, fMatCGlo[i][i]));
922 AliDebug(1,Form("err = %.6f", TMath::Sqrt(TMath::Abs(fMatCGlo[i][i]))));
924 step[i] = fVecBGlo[i];
926 if (fIter == 1) error[i] = fMatCGlo[i][i]; // Unfitted error
929 AliInfo(Form("The rank defect of the symmetric %d by %d matrix is %d (bad if non 0)",
930 nVar, nVar, nVar-nGloFix-nRank));
933 AliInfo(Form("Total : %d local fits, %d rejected.", fNLocalFits, fNLocalFitsRejected));
934 if (fIter == 0) break; // No iterations set
937 if (fIter == fMaxIter) break; // End of story
939 // Reinitialize parameters for iteration
942 fNLocalFitsRejected = 0;
944 if (fChi2CutFactor != fChi2CutRef) {
945 fChi2CutFactor = TMath::Sqrt(fChi2CutFactor);
946 if (fChi2CutFactor < 1.2*fChi2CutRef) {
947 fChi2CutFactor = fChi2CutRef;
948 fIter = fMaxIter - 1; // Last iteration
951 AliInfo(Form("Iteration %d with cut factor %.2f", fIter, fChi2CutFactor));
953 // Reset global variables
955 for (i=0; i<nVar; i++) {
957 for (j=0; j<nVar; j++) {
958 fMatCGlo[i][j] = 0.0;
963 // We start a new iteration
966 // First we read the stores for retrieving the local params
970 for (i=0; i<nLocFitsTot; i++) {
974 (i>0) ? iEqFirst = fLocEqPlace[i-1] : iEqFirst = 0;
975 iEqLast = fLocEqPlace[i];
977 AliDebug(2,Form("Track %d : ",i));
978 AliDebug(2,Form("Starts at %d", iEqFirst));
979 AliDebug(2,Form("Ends at %d",iEqLast));
981 if (fIndexAllEqs[iEqFirst] != -999) { // Fit is still OK
982 fIndexLocEq.Reset(); fNIndexLocEq=0;
983 fDerivLocEq.Reset(); fNDerivLocEq=0;
985 for (j=iEqFirst; j<iEqLast; j++) {
986 if (fNIndexLocEq==fIndexLocEq.GetSize()) fIndexLocEq.Set(2*fNIndexLocEq);
987 fIndexLocEq.AddAt(fIndexAllEqs[j],fNIndexLocEq++);
988 if (fNDerivLocEq==fDerivLocEq.GetSize()) fDerivLocEq.Set(2*fNDerivLocEq);
989 fDerivLocEq.AddAt(fDerivAllEqs[j],fNDerivLocEq++);
992 for (j=0; j<2*fNLocalPar; j++) {
996 // Int_t sc = AliMillepede::LocalFit(i,localPars,0);
997 // (sc) ? nLocFitsGood++ : fIndexAllEqs[iEqFirst] = -999;
998 AliMillepede::LocalFit(i,localPars,0);
1001 } // End of loop on fits
1003 AliMillepede::SetNLocalEquations(nLocFitsGood);
1005 } // End of iteration loop
1007 AliMillepede::PrintGlobalParameters(); // Print the final results
1009 for (j=0; j<fNGlobalPar; j++) {
1010 par[j] = fInitPar[j]+fDeltaPar[j];
1011 pull[j] = (fSigmaPar[j] <= 0.) ? 0. : fDeltaPar[j]/TMath::Sqrt(fSigmaPar[j]*fSigmaPar[j]-fMatCGlo[j][j]);
1012 error[j] = TMath::Sqrt(TMath::Abs(fMatCGlo[j][j]));
1016 AliInfo(" * o o o ");
1018 AliInfo(" o ooooo o o o oo ooo oo ooo oo ");
1019 AliInfo(" o o o o o o o o o o o o o o o o ");
1020 AliInfo(" o o o o o o oooo o o oooo o o oooo ");
1021 AliInfo(" o o o o o o o ooo o o o o ");
1022 AliInfo(" o o o o o o oo o oo ooo oo ++ ends.");
1029 -----------------------------------------------------------
1030 ERRPAR: return error for parameter iPar
1031 -----------------------------------------------------------
1033 iPar = the index of the global parameter in the
1034 result array (equivalent to fDeltaPar[]).
1036 -----------------------------------------------------------
1038 Double_t AliMillepede::GetParError(Int_t iPar) const
1040 /// return error for parameter iPar
1041 Double_t lErr = -1.;
1042 if (iPar>=0 && iPar<fNGlobalPar) {
1043 lErr = TMath::Sqrt(TMath::Abs(fMatCGlo[iPar][iPar]));
1050 -----------------------------------------------------------
1051 SPMINV: obtain solution of a system of linear equations with symmetric matrix
1052 and the inverse (using 'singular-value friendly' GAUSS pivot)
1053 -----------------------------------------------------------
1055 Solve the equation : V * X = B
1057 V is replaced by inverse matrix and B by X, the solution vector
1058 -----------------------------------------------------------
1060 int AliMillepede::SpmInv(double matV[][fgkMaxGloPC], double vecB[], int nGlo)
1062 /// Obtain solution of a system of linear equations with symmetric matrix
1063 /// and the inverse (using 'singular-value friendly' GAUSS pivot)
1068 double eps = 0.00000000000001;
1070 bool *bUnUsed = new bool[nGlo];
1071 double *diagV = new double[nGlo];
1072 double *rowMax = new double[nGlo];
1073 double *colMax = new double[nGlo];
1075 double *temp = new double[nGlo];
1077 for (Int_t i=0; i<nGlo; i++) {
1082 for (Int_t j=0; j<i; j++) {
1083 if (matV[j][i] == 0) {
1084 matV[j][i] = matV[i][j];
1089 // Small loop for matrix equilibration (gives a better conditioning)
1091 for (Int_t i=0; i<nGlo; i++) {
1092 for (Int_t j=0; j<nGlo; j++) {
1093 if (TMath::Abs(matV[i][j]) >= rowMax[i]) rowMax[i] = TMath::Abs(matV[i][j]); // Max elemt of row i
1094 if (TMath::Abs(matV[j][i]) >= colMax[i]) colMax[i] = TMath::Abs(matV[j][i]); // Max elemt of column i
1098 for (Int_t i=0; i<nGlo; i++) {
1099 if (0.0 != rowMax[i]) rowMax[i] = 1./rowMax[i]; // Max elemt of row i
1100 if (0.0 != colMax[i]) colMax[i] = 1./colMax[i]; // Max elemt of column i
1103 for (Int_t i=0; i<nGlo; i++) {
1104 for (Int_t j=0; j<nGlo; j++) {
1105 matV[i][j] = TMath::Sqrt(rowMax[i])*matV[i][j]*TMath::Sqrt(colMax[j]); // Equilibrate the V matrix
1107 diagV[i] = TMath::Abs(matV[i][i]); // save diagonal elem absolute values
1111 for (Int_t i=0; i<nGlo; i++) {
1115 for (Int_t j=0; j<nGlo; j++) { // First look for the pivot, ie max unused diagonal element
1116 if (bUnUsed[j] && (TMath::Abs(matV[j][j])>std::max(TMath::Abs(vPivot),eps*diagV[j]))) {
1117 vPivot = matV[j][j];
1122 if (iPivot >= 0) { // pivot found
1124 bUnUsed[iPivot] = false; // This value is used
1125 vPivot = 1.0/vPivot;
1126 matV[iPivot][iPivot] = -vPivot; // Replace pivot by its inverse
1128 for (Int_t j=0; j<nGlo; j++) {
1129 for (Int_t jj=0; jj<nGlo; jj++) {
1130 if (j != iPivot && jj != iPivot) {// Other elements (!!! do them first as you use old matV[k][j]'s !!!)
1131 matV[j][jj] = matV[j][jj] - vPivot*matV[j][iPivot]*matV[iPivot][jj];
1136 for (Int_t j=0; j<nGlo; j++) {
1137 if (j != iPivot) { // Pivot row or column elements
1138 matV[j][iPivot] = matV[j][iPivot]*vPivot; // Column
1139 matV[iPivot][j] = matV[iPivot][j]*vPivot; // Line
1143 else { // No more pivot value (clear those elements)
1144 for (Int_t j=0; j<nGlo; j++) {
1148 for (Int_t k=0; k<nGlo; k++) {
1154 break; // No more pivots anyway, stop here
1158 for (Int_t i=0; i<nGlo; i++) {
1159 for (Int_t j=0; j<nGlo; j++) {
1160 matV[i][j] = TMath::Sqrt(colMax[i])*matV[i][j]*TMath::Sqrt(rowMax[j]); // Correct matrix V
1164 for (Int_t j=0; j<nGlo; j++) {
1167 for (Int_t jj=0; jj<nGlo; jj++) { // Reverse matrix elements
1168 matV[j][jj] = -matV[j][jj];
1169 temp[j] += matV[j][jj]*vecB[jj];
1173 for (Int_t j=0; j<nGlo; j++) {
1174 vecB[j] = temp[j]; // The final result
1187 // Same method but for local fit, so heavily simplified
1189 int AliMillepede::SpmInv(double matV[][fgkMaxLocalPar], double vecB[], int nLoc)
1191 /// Obtain solution of a system of linear equations with symmetric matrix
1192 /// and the inverse (using 'singular-value friendly' GAUSS pivot)
1197 double eps = 0.0000000000001;
1199 bool *bUnUsed = new bool[nLoc];
1200 double *diagV = new double[nLoc];
1201 double *temp = new double[nLoc];
1203 for (Int_t i=0; i<nLoc; i++) {
1205 diagV[i] = TMath::Abs(matV[i][i]); // save diagonal elem absolute values
1206 for (Int_t j=0; j<i; j++) {
1207 matV[j][i] = matV[i][j] ;
1211 for (Int_t i=0; i<nLoc; i++) {
1215 for (Int_t j=0; j<nLoc; j++) { // First look for the pivot, ie max unused diagonal element
1216 if (bUnUsed[j] && (TMath::Abs(matV[j][j])>TMath::Max(TMath::Abs(vPivot),eps*diagV[j]))) {
1217 vPivot = matV[j][j];
1222 if (iPivot >= 0) { // pivot found
1224 bUnUsed[iPivot] = false;
1225 vPivot = 1.0/vPivot;
1226 matV[iPivot][iPivot] = -vPivot; // Replace pivot by its inverse
1228 for (Int_t j=0; j<nLoc; j++) {
1230 for (Int_t jj=0; jj<=j; jj++) {
1231 if (jj != iPivot) {// Other elements (!!! do them first as you use old matV[k][j]'s !!!)
1232 matV[j][jj] = matV[j][jj] - vPivot*matV[j][iPivot]*matV[iPivot][jj];
1233 matV[jj][j] = matV[j][jj];
1239 for (Int_t j=0; j<nLoc; j++) {
1240 if (j != iPivot) { // Pivot row or column elements
1241 matV[j][iPivot] = matV[j][iPivot]*vPivot; // Column
1242 matV[iPivot][j] = matV[j][iPivot];
1246 else { // No more pivot value (clear those elements)
1247 for (Int_t j=0; j<nLoc; j++) {
1251 for (Int_t k=0; k<j; k++) {
1258 break; // No more pivots anyway, stop here
1262 for (Int_t j=0; j<nLoc; j++) {
1264 for (Int_t jj=0; jj<nLoc; jj++) { // Reverse matrix elements
1265 matV[j][jj] = -matV[j][jj];
1266 temp[j] += matV[j][jj]*vecB[jj];
1270 for (Int_t j=0; j<nLoc; j++) {
1283 -----------------------------------------------------------
1285 -----------------------------------------------------------
1287 multiply symmetric N-by-N matrix from the left with general M-by-N
1288 matrix and from the right with the transposed of the same general
1289 matrix to form symmetric M-by-M matrix.
1292 CALL SPAVAT(V,A,W,N,M) W = A * V * A
1295 where V = symmetric N-by-N matrix
1296 A = general N-by-M matrix
1297 W = symmetric M-by-M matrix
1298 -----------------------------------------------------------
1300 Int_t AliMillepede::SpAVAt(double matV[][fgkMaxLocalPar], double matA[][fgkMaxLocalPar], double matW[][fgkMaxGlobalPar], int nLoc, int nGlo)
1302 /// multiply symmetric N-by-N matrix from the left with general M-by-N
1303 /// matrix and from the right with the transposed of the same general
1304 /// matrix to form symmetric M-by-M matrix.
1306 for (Int_t i=0; i<nGlo; i++) {
1307 for (Int_t j=0; j<=i; j++) { // Matrix w is symmetric
1308 matW[i][j] = 0.0; // Reset final matrix
1309 for (Int_t k=0; k<nLoc; k++) {
1310 matW[i][j] += matA[i][k]*matV[k][k]*matA[j][k]; // diagonal terms of v
1311 for (Int_t l=0; l<k; l++) {
1312 matW[i][j] += matA[i][k]*matV[k][l]*matA[j][l]; // Use symmetric properties
1313 matW[i][j] += matA[i][l]*matV[k][l]*matA[j][k]; // of matrix v
1317 matW[j][i] = matW[i][j]; // Matrix w is symmetric
1327 -----------------------------------------------------------
1329 -----------------------------------------------------------
1331 multiply general M-by-N matrix A and N-vector X
1333 CALL SPAX(A,X,Y,M,N) Y = A * X
1336 where A = general M-by-N matrix (A11 A12 ... A1N A21 A22 ...)
1339 -----------------------------------------------------------
1341 Int_t AliMillepede::SpAX(double matA[][fgkMaxLocalPar], double vecX[], double vecY[], int nCol, int nRow)
1343 /// multiply general M-by-N matrix A and N-vector X
1344 for (Int_t i=0; i<nRow; i++) {
1345 vecY[i] = 0.0; // Reset final vector
1346 for (Int_t j=0; j<nCol; j++) {
1347 vecY[i] += matA[i][j]*vecX[j]; // fill the vector
1356 -----------------------------------------------------------
1358 -----------------------------------------------------------
1360 Print the final results into the logfile
1362 -----------------------------------------------------------
1364 Int_t AliMillepede::PrintGlobalParameters() const
1366 /// Print the final results into the logfile
1368 double lGlobalCor =0.;
1371 AliInfo(" Result of fit for global parameters");
1372 AliInfo(" ===================================");
1373 AliInfo(" I initial final differ lastcor error gcor");
1374 AliInfo("-----------------------------------------------------------------------------------");
1376 for (int i=0; i<fNGlobalPar; i++) {
1377 lError = TMath::Sqrt(TMath::Abs(fMatCGlo[i][i]));
1378 if (fMatCGlo[i][i] < 0.0) lError = -lError;
1381 if (TMath::Abs(fMatCGlo[i][i]*fDiagCGlo[i]) > 0) {
1382 lGlobalCor = TMath::Sqrt(TMath::Abs(1.0-1.0/(fMatCGlo[i][i]*fDiagCGlo[i])));
1383 AliInfo(Form("%d\t %.6f\t %.6f\t %.6f\t %.6f\t %.6f\t %.6f",
1384 i,fInitPar[i],fInitPar[i]+fDeltaPar[i],fDeltaPar[i],fVecBGlo[i],lError,lGlobalCor));
1387 AliInfo(Form("%d\t %.6f\t %.6f\t %.6f\t %.6f\t OFF\t OFF",i,fInitPar[i],fInitPar[i]+fDeltaPar[i],fDeltaPar[i],fVecBGlo[i]));
1395 ----------------------------------------------------------------
1396 CHI2DOFLIM: return the limit in chi^2/nd for n sigmas stdev authorized
1397 ----------------------------------------------------------------
1399 Only n=1, 2, and 3 are expected in input
1400 ----------------------------------------------------------------
1402 double AliMillepede::Chi2DoFLim(int nSig, int nDoF)
1404 /// return the limit in chi^2/nd for n sigmas stdev authorized
1406 double sn[3] = {0.47523, 1.690140, 2.782170};
1407 double table[3][30] = {{1.0000, 1.1479, 1.1753, 1.1798, 1.1775, 1.1730, 1.1680, 1.1630,
1408 1.1581, 1.1536, 1.1493, 1.1454, 1.1417, 1.1383, 1.1351, 1.1321,
1409 1.1293, 1.1266, 1.1242, 1.1218, 1.1196, 1.1175, 1.1155, 1.1136,
1410 1.1119, 1.1101, 1.1085, 1.1070, 1.1055, 1.1040},
1411 {4.0000, 3.0900, 2.6750, 2.4290, 2.2628, 2.1415, 2.0481, 1.9736,
1412 1.9124, 1.8610, 1.8171, 1.7791, 1.7457, 1.7161, 1.6897, 1.6658,
1413 1.6442, 1.6246, 1.6065, 1.5899, 1.5745, 1.5603, 1.5470, 1.5346,
1414 1.5230, 1.5120, 1.5017, 1.4920, 1.4829, 1.4742},
1415 {9.0000, 5.9146, 4.7184, 4.0628, 3.6410, 3.3436, 3.1209, 2.9468,
1416 2.8063, 2.6902, 2.5922, 2.5082, 2.4352, 2.3711, 2.3143, 2.2635,
1417 2.2178, 2.1764, 2.1386, 2.1040, 2.0722, 2.0428, 2.0155, 1.9901,
1418 1.9665, 1.9443, 1.9235, 1.9040, 1.8855, 1.8681}};
1424 lNSig = TMath::Max(1,TMath::Min(nSig,3));
1427 return table[lNSig-1][nDoF-1];
1429 else { // approximation
1430 return ((sn[lNSig-1]+TMath::Sqrt(float(2*nDoF-3)))*
1431 (sn[lNSig-1]+TMath::Sqrt(float(2*nDoF-3))))/float(2*nDoF-2);