/************************************************************************** * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. * * * * Author: The ALICE Off-line Project. * * Contributors are mentioned in the code where appropriate. * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ /* $Id$ */ //----------------------------------------------------------------------------- /// \class AliMillepede /// Detector independent alignment class /// /// This modified C++ version is based on a C++ translation of Millepede used /// for LHCb Vertex Detector alignment (lhcb-2005-101), available here /// http://isscvs.cern.ch/cgi-bin/cvsweb.cgi/Alignment/AlignmentTools/src/?cvsroot=lhcb /// The original millepede fortran package is available at: /// http://www.desy.de/~blobel/wwwmille.html /// /// \author Javier Castillo //----------------------------------------------------------------------------- #include #include #include #include "AliLog.h" #include "AliMillepede.h" //============================================================================= AliMillepede::AliMillepede() : TObject(), fIndexLocEq(fgkMaxGlobalPar+fgkMaxLocalPar), fDerivLocEq(fgkMaxGlobalPar+fgkMaxLocalPar), fIndexAllEqs(1000*fgkMaxGlobalPar+fgkMaxLocalPar), fDerivAllEqs(1000*fgkMaxGlobalPar+fgkMaxLocalPar), fLocEqPlace(1000), fNIndexLocEq(0), fNDerivLocEq(0), fNIndexAllEqs(0), fNDerivAllEqs(0), fNLocEqPlace(0), fNLocalEquations(0), fResCutInit(0.), fResCut(0.), fChi2CutFactor(1.0), fChi2CutRef(1.0), fIter(0), fMaxIter(10), fNStdDev(3), fNGlobalConstraints(0), fNLocalFits(0), fNLocalFitsRejected(0), fNGlobalPar(0), fNLocalPar(0) { /// Standard constructor AliInfo(" "); AliInfo(" * o o o "); AliInfo(" o o o "); AliInfo(" o ooooo o o o oo ooo oo ooo oo "); AliInfo(" o o o o o o o o o o o o o o o o "); AliInfo(" o o o o o o oooo o o oooo o o oooo "); AliInfo(" o o o o o o o ooo o o o o "); AliInfo(" o o o o o o oo o oo ooo oo ++ starts"); AliInfo(" "); } //============================================================================= AliMillepede::~AliMillepede() { /// Destructor } //============================================================================= Int_t AliMillepede::InitMille(int nGlo, int nLoc, int lNStdDev, double lResCut, double lResCutInit) { /// Initialization of millepede AliDebug(1,""); AliDebug(1,"----------------------------------------------------"); AliDebug(1,""); AliDebug(1," Entering InitMille"); AliDebug(1,""); AliDebug(1,"-----------------------------------------------------"); AliDebug(1,""); fNGlobalConstraints = 0; fNLocalFits = 0; // Total number of local fits fNLocalFitsRejected = 0; // Total number of local fits rejected fChi2CutRef = 1.0; // Reference value for Chi^2/ndof cut AliMillepede::SetNLocalEquations(0); // Number of local fits (starts at 0) fIter = 0; // By default iterations are turned off, turned on by use SetIterations fMaxIter = 10; fResCutInit = lResCutInit; fResCut = lResCut; fNGlobalPar = nGlo; // Number of global derivatives fNLocalPar = nLoc; // Number of local derivatives fNStdDev = lNStdDev; // Number of StDev for local fit chisquare cut AliDebug(1,Form("Number of global parameters : %d", fNGlobalPar)); AliDebug(1,Form("Number of local parameters : %d", fNLocalPar)); AliDebug(1,Form("Number of standard deviations : %d", fNStdDev)); if (fNGlobalPar>fgkMaxGlobalPar || fNLocalPar>fgkMaxLocalPar) { AliDebug(1,"Two many parameters !!!!!"); return 0; } // Global parameters initializations for (int i=0; i=fNGlobalPar) { return 0; } else { fInitPar[iPar] = param; } return 1; } /* ----------------------------------------------------------- PARSIG: define a constraint for a single global param param is 'encouraged' to vary within [-sigma;sigma] range ----------------------------------------------------------- iPar = the index of the global parameter in the result array (equivalent to fDeltaPar[]). sigma = value of the constraint (sigma <= 0. will mean that parameter is FIXED !!!) ----------------------------------------------------------- */ Int_t AliMillepede::SetParSigma(int iPar, double sigma) { /// Define a range [-sigma;sigma] where iPar is encourage to vary if (iPar>=fNGlobalPar) { return 0; } else { fSigmaPar[iPar] = sigma; } return 1; } /* ----------------------------------------------------------- NONLIN: set nonlinear flag for a single global param update of param durin iterations will not consider initial starting value ----------------------------------------------------------- iPar = the index of the global parameter in the result array (equivalent to fDeltaPar[]). ----------------------------------------------------------- */ Int_t AliMillepede::SetNonLinear(int iPar) { /// Set nonlinear flag for iPar if (iPar<0 || iPar>=fNGlobalPar) { return 0; } else { fIsNonLinear[iPar] = 1; } return 1; } /* ----------------------------------------------------------- INITUN: unit for iteration ----------------------------------------------------------- lChi2CutFac is used by Fitloc to define the Chi^2/ndof cut value A large cutfac value enables to take a wider range of tracks for first iterations, which might be useful if misalignments are large. As soon as cutfac differs from 0 iteration are requested. cutfac is then reduced, from one iteration to the other, and iterations are stopped when it reaches the value 1. At least one more iteration is often needed in order to remove tracks containing outliers. ----------------------------------------------------------- */ Int_t AliMillepede::SetIterations(double lChi2CutFac) { /// Number of iterations is calculated from lChi2CutFac fChi2CutFactor = TMath::Max(1.0, lChi2CutFac); AliInfo(Form("Initial cut factor is %f",fChi2CutFactor)); fIter = 1; // Initializes the iteration process return 1; } /* ----------------------------------------------------------- CONSTF: define a constraint equation in AliMillepede ----------------------------------------------------------- dercs = the row containing constraint equation derivatives (put into the final matrix) lLagMult = the lagrange multiplier value (sum of equation) ----------------------------------------------------------- */ Int_t AliMillepede::SetGlobalConstraint(double dercs[], double lLagMult) { /// Define a constraint equation if (fNGlobalConstraints>=fgkMaxGloCsts) { AliInfo("Too many constraints !!!"); return 0; } for (int i=0; i lMeas in FDERIVSTORE Then we have indices of local eq in FINDEXSTORE, and derivatives in FDERIVSTORE Second -1 ---> weight in FDERIVSTORE Then follows indices and derivatives of global eq. .... We took them and store them into matrices. As we want ONLY local params, we substract the part of the estimated value due to global params. Indeed we could have already an idea of these params, with previous alignment constants for example (set with PARGLO). Also if there are more than one iteration (FITLOC could be called by FITGLO) */ // // FIRST LOOP : local track fit // iEqTerm = 0; // fIndexLocEq.push_back(-1); if (fNIndexLocEq==fIndexLocEq.GetSize()) fIndexLocEq.Set(2*fNIndexLocEq); fIndexLocEq.AddAt(-1,fNIndexLocEq++); while (iEqTerm <= nEqTerms) { if (fIndexLocEq[iEqTerm] == -1) { if (iMeas == -1) { // First -1 : lMeas iMeas = iEqTerm; iLocFirst = iEqTerm+1; } else if (iWeight == 0) { // Second -1 : weight iWeight = iEqTerm; iLocLast = iEqTerm-1; iGloFirst = iEqTerm+1; } else { // Third -1 : end of equation; start of next iGloLast = iEqTerm-1; lMeas = fDerivLocEq[iMeas]; lWeight = fDerivLocEq[iWeight]; // AliDebug(1,Form("lMeas = %f", lMeas)); // AliDebug(1,Form("lWeight = %f", lWeight)); // Now suppress the global part (only relevant with iterations) // for (i=iGloFirst; i<=iGloLast; i++) { iIdx = fIndexLocEq[i]; // Global param indice // AliDebug(2,Form("fDeltaPar[%d] = %f", iIdx, fDeltaPar[iIdx])); // AliDebug(2,Form("Starting misalignment = %f",fInitPar[iIdx])); if (fIsNonLinear[iIdx] == 0) lMeas -= fDerivLocEq[i]*(fInitPar[iIdx]+fDeltaPar[iIdx]); // linear parameter else lMeas -= fDerivLocEq[i]*(fDeltaPar[iIdx]); // nonlinear parameter } // AliDebug(2,Form("lMeas after global stuff removal = %f", lMeas)); for (i=iLocFirst; i<=iLocLast; i++) { // Finally fill local matrix and vector iIdx = fIndexLocEq[i]; // Local param indice (the matrix line) fVecBLoc[iIdx] += lWeight*lMeas*fDerivLocEq[i]; // AliDebug(2,Form("fVecBLoc[%d] = %f", iIdx, fVecBLoc[iIdx])); for (j=iLocFirst; j<=i ; j++) { // Symmetric matrix, don't bother j>i coeffs jIdx = fIndexLocEq[j]; fMatCLoc[iIdx][jIdx] += lWeight*fDerivLocEq[i]*fDerivLocEq[j]; // AliDebug(2,Form("fMatCLoc[%d][%d] = ", iIdx, jIdx, fMatCLoc[iIdx][jIdx])); } } iMeas = -1; iWeight = 0; iEqTerm--; // end of one equation is the beginning of next } // End of "end of equation" operations } // End of loop on equation iEqTerm++; } // End of loop on all equations used in the fit // // Local params matrix is completed, now invert to solve... // Int_t nRank = AliMillepede::SpmInv(fMatCLoc, fVecBLoc, fNLocalPar); // nRank is the number of nonzero diagonal elements AliDebug(1,""); AliDebug(1," __________________________________________________"); AliDebug(1,Form(" Printout of local fit (FITLOC) with rank= %d", nRank)); AliDebug(1," Result of local fit : (index/parameter/error)"); for (i=0; i= fResCutInit && fIter <= 1) { AliDebug(2,"Rejected track !!!!!"); fNLocalFitsRejected++; fIndexLocEq.Reset(); fNIndexLocEq=0; // reset stores and go to the next track fDerivLocEq.Reset(); fNDerivLocEq=0; return 0; } if (TMath::Abs(lMeas) >= fResCut && fIter > 1) { AliDebug(2,"Rejected track !!!!!"); fNLocalFitsRejected++; fIndexLocEq.Reset(); fNIndexLocEq=0; // reset stores and go to the next track fDerivLocEq.Reset(); fNDerivLocEq=0; return 0; } lChi2 += lWeight*lMeas*lMeas ; // total chi^2 nEq++; // number of equations iMeas = -1; iWeight = 0; iEqTerm--; } // End of "end of equation" operations } // End of loop on equation iEqTerm++; } // End of loop on all equations used in the fit nDoF = nEq-nRank; lRedChi2 = 0.0; AliDebug(1,Form("Final chi square / degrees of freedom %.2f / %d",lChi2, nDoF)); if (nDoF > 0) lRedChi2 = lChi2/float(nDoF); // Chi^2/dof fNLocalFits++; if (fNStdDev != 0 && nDoF > 0 && !bSingleFit) // Chisquare cut { lChi2Cut = AliMillepede::Chi2DoFLim(fNStdDev, nDoF)*fChi2CutFactor; AliDebug(1,Form("Reject if Chisq/Ndf = %.4f > %.4f",lRedChi2,lChi2Cut)); if (lRedChi2 > lChi2Cut) // Reject the track if too much... { AliDebug(2,"Rejected track !!!!!"); fNLocalFitsRejected++; fIndexLocEq.Reset(); fNIndexLocEq=0; // reset stores and go to the next track fDerivLocEq.Reset(); fNDerivLocEq=0; return 0; } } if (bSingleFit) // Stop here if just updating the track parameters { fIndexLocEq.Reset(); fNIndexLocEq=0; // Reset store for the next track fDerivLocEq.Reset(); fNDerivLocEq=0; return 1; } // // THIRD LOOP: local operations are finished, track is accepted // We now update the global parameters (other matrices) // iEqTerm = 0; iMeas = -1; iWeight = 0; while (iEqTerm <= nEqTerms) { if (fIndexLocEq[iEqTerm] == -1) { if (iMeas == -1) { // First -1 : lMeas iMeas = iEqTerm; iLocFirst = iEqTerm+1; } else if (iWeight == 0) { // Second -1 : weight iWeight = iEqTerm; iLocLast = iEqTerm-1; iGloFirst = iEqTerm+1; } else { // Third -1 : end of equation; start of next iGloLast = iEqTerm-1; lMeas = fDerivLocEq[iMeas]; lWeight = fDerivLocEq[iWeight]; // Now suppress the global part for (i=iGloFirst; i<=iGloLast; i++) { iIdx = fIndexLocEq[i]; // Global param indice if (fIsNonLinear[iIdx] == 0) lMeas -= fDerivLocEq[i]*(fInitPar[iIdx]+fDeltaPar[iIdx]); // linear parameter else lMeas -= fDerivLocEq[i]*(fDeltaPar[iIdx]); // nonlinear parameter } for (i=iGloFirst; i<=iGloLast; i++) { iIdx = fIndexLocEq[i]; // Global param indice (the matrix line) fVecBGlo[iIdx] += lWeight*lMeas*fDerivLocEq[i]; // AliDebug(2,Form("fVecBGlo[%d] = %.6f", j, fVecBGlo[j] )); // First of all, the global/global terms (exactly like local matrix) // for (j=iGloFirst; j<=iGloLast; j++) { jIdx = fIndexLocEq[j]; fMatCGlo[iIdx][jIdx] += lWeight*fDerivLocEq[i]*fDerivLocEq[j]; // AliDebug(2,Form("fMatCGlo[%d][%d] = %.6f",iIdx,jIdx,fMatCGlo[iIdx][jIdx])); } // Now we have also rectangular matrices containing global/local terms. // iIdxIdx = fGlo2CGLRow[iIdx]; // Index of index if (iIdxIdx == -1) { // New global variable for (k=0; k 1) { for (i=0; i0) ? iEqFirst = fLocEqPlace[i-1] : iEqFirst = 0; iEqLast = fLocEqPlace[i]; AliDebug(2,Form("Track %d : ",i)); AliDebug(2,Form("Starts at %d", iEqFirst)); AliDebug(2,Form("Ends at %d",iEqLast)); if (fIndexAllEqs[iEqFirst] != -999) { // Fit is still OK fIndexLocEq.Reset(); fNIndexLocEq=0; fDerivLocEq.Reset(); fNDerivLocEq=0; for (j=iEqFirst; j=0 && iPar= rowMax[i]) rowMax[i] = TMath::Abs(matV[i][j]); // Max elemt of row i if (TMath::Abs(matV[j][i]) >= colMax[i]) colMax[i] = TMath::Abs(matV[j][i]); // Max elemt of column i } } for (Int_t i=0; iTMath::Max(TMath::Abs(vPivot),eps*diagV[j]))) { vPivot = matV[j][j]; iPivot = j; } } if (iPivot >= 0) { // pivot found nRank++; bUnUsed[iPivot] = false; // This value is used vPivot = 1.0/vPivot; matV[iPivot][iPivot] = -vPivot; // Replace pivot by its inverse for (Int_t j=0; jTMath::Max(TMath::Abs(vPivot),eps*diagV[j]))) { vPivot = matV[j][j]; iPivot = j; } } if (iPivot >= 0) { // pivot found nRank++; bUnUsed[iPivot] = false; vPivot = 1.0/vPivot; matV[iPivot][iPivot] = -vPivot; // Replace pivot by its inverse for (Int_t j=0; j 0) { lGlobalCor = TMath::Sqrt(TMath::Abs(1.0-1.0/(fMatCGlo[i][i]*fDiagCGlo[i]))); AliInfo(Form("%d\t %.6f\t %.6f\t %.6f\t %.6f\t %.6f\t %.6f", i,fInitPar[i],fInitPar[i]+fDeltaPar[i],fDeltaPar[i],fVecBGlo[i],lError,lGlobalCor)); } else { 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])); } } return 1; } /* ---------------------------------------------------------------- CHI2DOFLIM: return the limit in chi^2/nd for n sigmas stdev authorized ---------------------------------------------------------------- Only n=1, 2, and 3 are expected in input ---------------------------------------------------------------- */ double AliMillepede::Chi2DoFLim(int nSig, int nDoF) { /// return the limit in chi^2/nd for n sigmas stdev authorized int lNSig; double sn[3] = {0.47523, 1.690140, 2.782170}; double table[3][30] = {{1.0000, 1.1479, 1.1753, 1.1798, 1.1775, 1.1730, 1.1680, 1.1630, 1.1581, 1.1536, 1.1493, 1.1454, 1.1417, 1.1383, 1.1351, 1.1321, 1.1293, 1.1266, 1.1242, 1.1218, 1.1196, 1.1175, 1.1155, 1.1136, 1.1119, 1.1101, 1.1085, 1.1070, 1.1055, 1.1040}, {4.0000, 3.0900, 2.6750, 2.4290, 2.2628, 2.1415, 2.0481, 1.9736, 1.9124, 1.8610, 1.8171, 1.7791, 1.7457, 1.7161, 1.6897, 1.6658, 1.6442, 1.6246, 1.6065, 1.5899, 1.5745, 1.5603, 1.5470, 1.5346, 1.5230, 1.5120, 1.5017, 1.4920, 1.4829, 1.4742}, {9.0000, 5.9146, 4.7184, 4.0628, 3.6410, 3.3436, 3.1209, 2.9468, 2.8063, 2.6902, 2.5922, 2.5082, 2.4352, 2.3711, 2.3143, 2.2635, 2.2178, 2.1764, 2.1386, 2.1040, 2.0722, 2.0428, 2.0155, 1.9901, 1.9665, 1.9443, 1.9235, 1.9040, 1.8855, 1.8681}}; if (nDoF < 1) { return 0.0; } else { lNSig = TMath::Max(1,TMath::Min(nSig,3)); if (nDoF <= 30) { return table[lNSig-1][nDoF-1]; } else { // approximation return ((sn[lNSig-1]+TMath::Sqrt(float(2*nDoF-3)))* (sn[lNSig-1]+TMath::Sqrt(float(2*nDoF-3))))/float(2*nDoF-2); } } }