1 #include "AliMillePede2.h"
3 #include <TStopwatch.h>
7 ClassImp(AliMillePedeRecord)
9 //_____________________________________________________________________________________________
10 AliMillePedeRecord::AliMillePedeRecord() :
11 fSize(0),fIndex(0),fValue(0) {SetBufferSize(0);}
13 //_____________________________________________________________________________________________
14 AliMillePedeRecord::AliMillePedeRecord(const AliMillePedeRecord& src) :
15 TObject(src),fSize(src.fSize),fIndex(0),fValue(0)
17 fIndex = new int[GetBufferSize()];
18 memcpy(fIndex,src.fIndex,fSize*sizeof(int));
19 fValue = new double[GetBufferSize()];
20 memcpy(fValue,src.fValue,fSize*sizeof(double));
23 //_____________________________________________________________________________________________
24 AliMillePedeRecord& AliMillePedeRecord::operator=(const AliMillePedeRecord& rhs)
28 for (int i=0;i<rhs.GetSize();i++) {
31 rhs.GetIndexValue(i,ind,val);
32 AddIndexValue(ind,val);
38 //_____________________________________________________________________________________________
39 AliMillePedeRecord::~AliMillePedeRecord() {delete[] fIndex; delete[] fValue;}
41 //_____________________________________________________________________________________________
42 void AliMillePedeRecord::Print(const Option_t *) const
44 if (!fSize) {AliInfo("No data"); return;}
49 double resid = fValue[cnt++];
50 double *derLoc = GetValue()+cnt;
51 int *indLoc = GetIndex()+cnt;
53 while(!IsWeight(cnt)) {nLoc++;cnt++;}
54 double weight = GetValue(cnt++);
55 double *derGlo = GetValue()+cnt;
56 int *indGlo = GetIndex()+cnt;
58 while(!IsResidual(cnt) && cnt<fSize) {nGlo++; cnt++;}
60 printf("\n*** Point#%2d | Residual = %+.4e | Weight = %+.4e\n",point++,resid,weight);
62 for (int i=0;i<nLoc;i++) printf("[%5d] %+.4e|",indLoc[i],derLoc[i]); printf("\n");
64 for (int i=0;i<nGlo;i++) printf("[%5d] %+.4e|",indGlo[i],derGlo[i]); printf("\n");
70 //_____________________________________________________________________________________________
71 void AliMillePedeRecord::Expand(int bfsize)
74 bfsize = TMath::Max(bfsize,GetBufferSize());
75 int *tmpI = new int[bfsize];
76 memcpy(tmpI,fIndex, fSize*sizeof(int));
80 double *tmpD = new double[bfsize];
81 memcpy(tmpD,fValue, fSize*sizeof(double));
85 SetBufferSize(bfsize);
88 //----------------------------------------------------------------------------------------------
89 //----------------------------------------------------------------------------------------------
90 //----------------------------------------------------------------------------------------------
91 //----------------------------------------------------------------------------------------------
92 ClassImp(AliMillePede2)
94 Bool_t AliMillePede2::fgIsMatGloSparse = kFALSE; // use faster dense matrix by default
95 Int_t AliMillePede2::fgMinResCondType = kTRUE; // No preconditioner by default
96 Double_t AliMillePede2::fgMinResTol = 1.e-8; // default tolerance
97 Int_t AliMillePede2::fgMinResMaxIter = 3000; // default max number of iterations
98 Int_t AliMillePede2::fgIterSol = AliMinResSolve::kSolMinRes; // default iterative solver
99 Int_t AliMillePede2::fgNKrylovV = 30; // default number of Krylov vectors to keep
101 //_____________________________________________________________________________________________
102 AliMillePede2::AliMillePede2()
113 fNLocFitsRejected(0),
115 fGloSolveStatus(gkFailed),
140 fDataRecFName("/tmp/mp2_data_records.root"),
145 fConstrRecFName("/tmp/mp2_constraints_records.root"),
152 //_____________________________________________________________________________________________
153 AliMillePede2::AliMillePede2(const AliMillePede2& src) :
154 TObject(src),fNLocPar(0),fNGloPar(0),fNGloSize(0),fNLocEquations(0),fIter(0),
155 fMaxIter(10),fNStdDev(3),fNGloConstraints(0),fNLocFits(0),fNLocFitsRejected(0),
156 fNGloFix(0),fGloSolveStatus(0),fChi2CutFactor(0),fChi2CutRef(0),fResCutInit(0),
157 fResCut(0),fMinPntValid(0),fProcPnt(0),fVecBLoc(0),fDiagCGlo(0),fVecBGlo(0),
158 fInitPar(0),fDeltaPar(0),fSigmaPar(0),fIsLinear(0),fConstrUsed(0),fGlo2CGlo(0),fCGlo2Glo(0),
159 fMatCLoc(0),fMatCGlo(0),fMatCGloLoc(0),fDataRecFName(0),fRecord(0),fDataRecFile(0),
160 fTreeData(0),fConstrRecFName(0),fTreeConstr(0),fConsRecFile(0),fCurrRecDataID(0),fCurrRecConstrID(0)
163 //_____________________________________________________________________________________________
164 AliMillePede2::~AliMillePede2()
166 CloseDataRecStorage();
167 CloseConsRecStorage();
179 delete[] fConstrUsed;
187 //_____________________________________________________________________________________________
188 Int_t AliMillePede2::InitMille(int nGlo, int nLoc, int lNStdDev,double lResCut, double lResCutInit)
191 if (nLoc>0) fNLocPar = nLoc;
192 if (nGlo>0) fNGloPar = nGlo;
193 if (lResCutInit>0) fResCutInit = lResCutInit;
194 if (lResCut>0) fResCut = lResCut;
195 if (lNStdDev>0) fNStdDev = lNStdDev;
197 fNGloSize = fNGloPar;
201 if (fgIsMatGloSparse) {fMatCGlo = new AliMatrixSparse(fNGloPar); fMatCGlo->SetSymmetric(kTRUE);}
202 else fMatCGlo = new AliSymMatrix(fNGloPar);
204 fMatCLoc = new AliSymMatrix(fNLocPar);
205 fMatCGloLoc = new TMatrixD(fNGloPar,fNLocPar);
207 fProcPnt = new Int_t[fNGloPar];
208 fVecBLoc = new Double_t[fNLocPar];
209 fDiagCGlo = new Double_t[fNGloPar];
211 fInitPar = new Double_t[fNGloPar];
212 fDeltaPar = new Double_t[fNGloPar];
213 fSigmaPar = new Double_t[fNGloPar];
214 fIsLinear = new Bool_t[fNGloPar];
216 fGlo2CGlo = new Int_t[fNGloPar];
217 fCGlo2Glo = new Int_t[fNGloPar];
220 AliInfo(Form("Failed to allocate the memory for %d global and %d local parameters",fNGloPar,fNLocPar));
224 memset(fVecBLoc ,0,fNLocPar*sizeof(Double_t));
225 memset(fDiagCGlo ,0,fNGloPar*sizeof(Double_t));
226 memset(fInitPar ,0,fNGloPar*sizeof(Double_t));
227 memset(fDeltaPar ,0,fNGloPar*sizeof(Double_t));
228 memset(fSigmaPar ,0,fNGloPar*sizeof(Double_t));
229 memset(fProcPnt ,0,fNGloPar*sizeof(Int_t));
231 for (int i=fNGloPar;i--;) {
232 fGlo2CGlo[i]=fCGlo2Glo[i] = -1;
233 fIsLinear[i] = kTRUE;
239 //_____________________________________________________________________________________________
240 void AliMillePede2::ResetConstraints()
242 // reset constraints tree. Allows to redefine the constraints for preprocessed data
243 CloseConsRecStorage();
244 InitConsRecStorage(kFALSE);
245 fNGloConstraints = 0;
246 AliInfo("Constraints are reset");
249 //_____________________________________________________________________________________________
250 Bool_t AliMillePede2::ImposeDataRecFile(const char* fname)
252 CloseDataRecStorage();
253 SetDataRecFName(fname);
254 return InitDataRecStorage(kTRUE); // open in read mode
257 //_____________________________________________________________________________________________
258 Bool_t AliMillePede2::ImposeConsRecFile(const char* fname)
260 CloseConsRecStorage();
261 SetConsRecFName(fname);
262 return InitConsRecStorage(kTRUE); // open in read mode
265 //_____________________________________________________________________________________________
266 Bool_t AliMillePede2::InitDataRecStorage(Bool_t read)
268 // initialize the buffer for processed measurements records
270 if (fDataRecFile) {AliInfo("Data Records File is already initialized"); return kFALSE;}
272 if (!fRecord) fRecord = new AliMillePedeRecord();
274 fDataRecFile = TFile::Open(GetDataRecFName(),read ? "":"recreate");
275 if (!fDataRecFile) {AliInfo(Form("Failed to initialize data records file %s",GetDataRecFName())); return kFALSE;}
277 AliInfo(Form("File %s used for derivatives records",GetDataRecFName()));
279 fTreeData = (TTree*)fDataRecFile->Get("AliMillePedeRecords_Data");
280 if (!fTreeData) {AliInfo(Form("Did not find data records tree in %s",GetDataRecFName())); return kFALSE;}
281 fTreeData->SetBranchAddress("Record_Data",&fRecord);
282 AliInfo(Form("Found %d derivatives records",fTreeData->GetEntries()));
285 fTreeData = new TTree("AliMillePedeRecords_Data","Data Records for AliMillePede2");
286 fTreeData->Branch("Record_Data","AliMillePedeRecord",&fRecord,32000,99);
293 //_____________________________________________________________________________________________
294 Bool_t AliMillePede2::InitConsRecStorage(Bool_t read)
296 // initialize the buffer for processed measurements records
298 if (fConsRecFile) {AliInfo("Constraints Records File is already initialized"); return kFALSE;}
300 if (!fRecord) fRecord = new AliMillePedeRecord();
302 fConsRecFile = TFile::Open(GetConsRecFName(),read ? "":"recreate");
303 if (!fConsRecFile) {AliInfo(Form("Failed to initialize constraints records file %s",GetConsRecFName())); return kFALSE;}
305 AliInfo(Form("File %s used for constraints records",GetConsRecFName()));
307 fTreeConstr = (TTree*)fConsRecFile->Get("AliMillePedeRecords_Constraints");
308 if (!fTreeConstr) {AliInfo(Form("Did not find constraints records tree in %s",GetConsRecFName())); return kFALSE;}
309 fTreeConstr->SetBranchAddress("Record_Constraints",&fRecord);
310 AliInfo(Form("Found %d constraints records",fTreeConstr->GetEntries()));
315 fTreeConstr = new TTree("AliMillePedeRecords_Constraints","Constraints Records for AliMillePede2");
316 fTreeConstr->Branch("Record_Constraints","AliMillePedeRecord",&fRecord,32000,99);
318 fCurrRecConstrID = -1;
323 //_____________________________________________________________________________________________
324 void AliMillePede2::CloseDataRecStorage()
327 if (fDataRecFile->IsWritable()) {
333 fDataRecFile->Close();
340 //_____________________________________________________________________________________________
341 void AliMillePede2::CloseConsRecStorage()
344 if (fConsRecFile->IsWritable()) {
346 fTreeConstr->Write();
350 fConsRecFile->Close();
357 //_____________________________________________________________________________________________
358 Bool_t AliMillePede2::ReadNextRecordData()
360 // read next data record (if any)
361 if (!fTreeData || ++fCurrRecDataID >= fTreeData->GetEntries()) { fCurrRecDataID--; return kFALSE;}
362 fTreeData->GetEntry(fCurrRecDataID);
366 //_____________________________________________________________________________________________
367 Bool_t AliMillePede2::ReadNextRecordConstraint()
369 // read next constraint record (if any)
370 if (!fTreeConstr || ++fCurrRecConstrID >= fTreeConstr->GetEntries()) { fCurrRecConstrID--; return kFALSE;}
371 fTreeConstr->GetEntry(fCurrRecConstrID);
375 //_____________________________________________________________________________________________
376 void AliMillePede2::SetLocalEquation(double *dergb, double *derlc, double lMeas, double lSigma)
378 if (!fDataRecFile || !fDataRecFile->IsWritable()) InitDataRecStorage(); // create a buffer to store the data
380 // write data of single measurement
381 if (lSigma<=0.0) { // If parameter is fixed, then no equation
382 for (int i=fNLocPar; i--;) derlc[i] = 0.0;
383 for (int i=fNGloPar; i--;) dergb[i] = 0.0;
387 fRecord->AddResidual(lMeas);
389 // Retrieve local param interesting indices
390 for (int i=0;i<fNLocPar;i++) if (derlc[i]!=0.0) {fRecord->AddIndexValue(i,derlc[i]); derlc[i] = 0.0;}
392 fRecord->AddWeight( 1.0/lSigma/lSigma );
394 // Idem for global parameters
395 for (int i=0;i<fNGloPar;i++) if (dergb[i]!=0.0) {fRecord->AddIndexValue(i,dergb[i]); dergb[i] = 0.0;}
399 //_____________________________________________________________________________________________
400 void AliMillePede2::SetLocalEquation(int *indgb, double *dergb, int ngb, int *indlc,
401 double *derlc,int nlc,double lMeas,double lSigma)
403 // write data of single measurement
404 if (lSigma<=0.0) { // If parameter is fixed, then no equation
405 for (int i=nlc;i--;) derlc[i] = 0.0;
406 for (int i=ngb;i--;) dergb[i] = 0.0;
410 if (!fDataRecFile || !fDataRecFile->IsWritable()) InitDataRecStorage(); // create a buffer to store the data
412 fRecord->AddResidual(lMeas);
414 // Retrieve local param interesting indices
415 for (int i=0;i<nlc;i++) if (derlc[i]!=0.0) {fRecord->AddIndexValue(indlc[i],derlc[i]); derlc[i]=0.; indlc[i]=0;}
417 fRecord->AddWeight( 1./lSigma/lSigma );
419 // Idem for global parameters
420 for (int i=0;i<ngb;i++) if (dergb[i]!=0.0) {fRecord->AddIndexValue(indgb[i],dergb[i]); dergb[i]=0.; indgb[i]=0;}
424 //_____________________________________________________________________________________________
425 void AliMillePede2::SetGlobalConstraint(double *dergb, double val)
427 // Define a constraint equation.
428 if (!fConsRecFile || !fConsRecFile->IsWritable()) InitConsRecStorage(); // create a buffer to store the data
431 fRecord->AddResidual(val);
432 fRecord->AddWeight(val); // dummy
433 for (int i=0; i<fNGloPar; i++) if (dergb[i]!=0) fRecord->AddIndexValue(i,dergb[i]);
435 SaveRecordConstraint();
439 //_____________________________________________________________________________________________
440 void AliMillePede2::SetGlobalConstraint(const int *indgb, double *dergb, int ngb, double val)
442 // Define a constraint equation.
443 if (!fConsRecFile || !fConsRecFile->IsWritable()) InitConsRecStorage(); // create a buffer to store the data
445 fRecord->AddResidual(val);
446 fRecord->AddWeight(val); // dummy
447 for (int i=0; i<ngb; i++) if (dergb[i]!=0) fRecord->AddIndexValue(indgb[i],dergb[i]);
449 SaveRecordConstraint();
453 //_____________________________________________________________________________________________
454 Int_t AliMillePede2::LocalFit(double *localParams)
457 Perform local parameters fit once all the local equations have been set
458 -----------------------------------------------------------
459 localParams = (if !=0) will contain the fitted track parameters and
462 static int nRefSize = 0;
463 static TArrayI RefLoc,RefGlo,nRefLoc,nRefGlo;
466 AliSymMatrix &MatCLoc = *fMatCLoc;
467 AliMatrixSq &MatCGlo = *fMatCGlo;
468 TMatrixD &MatCGloLoc = *fMatCGloLoc;
470 memset(fVecBLoc,0,fNLocPar*sizeof(double));
474 int recSz = fRecord->GetSize();
476 while(cnt<recSz) { // Transfer the measurement records to matrices
478 // extract addresses of residual, weight and pointers on local and global derivatives for each point
479 if (nRefSize<=nPoints) {
480 nRefSize = 2*(nPoints+1);
481 RefLoc.Set(nRefSize);
482 RefGlo.Set(nRefSize);
483 nRefLoc.Set(nRefSize);
484 nRefGlo.Set(nRefSize);
487 RefLoc[nPoints] = ++cnt;
489 while(!fRecord->IsWeight(cnt)) {nLoc++; cnt++;}
490 nRefLoc[nPoints] = nLoc;
492 RefGlo[nPoints] = ++cnt;
494 while(!fRecord->IsResidual(cnt) && cnt<recSz) {nGlo++; cnt++;}
495 nRefGlo[nPoints] = nGlo;
501 for (int ip=nPoints;ip--;) { // Transfer the measurement records to matrices
502 double resid = fRecord->GetValue( RefLoc[ip]-1 );
503 double weight = fRecord->GetValue( RefGlo[ip]-1 );
504 double *derLoc = fRecord->GetValue()+RefLoc[ip];
505 double *derGlo = fRecord->GetValue()+RefGlo[ip];
506 int *indLoc = fRecord->GetIndex()+RefLoc[ip];
507 int *indGlo = fRecord->GetIndex()+RefGlo[ip];
509 for (int i=nRefGlo[ip];i--;) { // suppress the global part (only relevant with iterations)
510 int iID = indGlo[i]; // Global param indice
511 if ( fSigmaPar[iID] <= 0.) continue; // fixed parameter RRRCheck
512 if (fIsLinear[iID]) resid -= derGlo[i]*(fInitPar[iID]+fDeltaPar[iID]); // linear parameter
513 else resid -= derGlo[i]*fDeltaPar[iID]; // nonlinear parameter
516 for (int i=nRefLoc[ip];i--;) { // Fill local matrix and vector
517 int iID = indLoc[i]; // Local param indice (the matrix line)
518 if ( (vl=weight*resid*derLoc[i])!=0 ) fVecBLoc[iID] += vl;
520 for (int j=i+1;j--;) { // Symmetric matrix, don't bother j>i coeffs
522 if ( (vl=weight*derLoc[i]*derLoc[j])!=0 ) MatCLoc(iID,jID) += vl;
526 } // end of the transfer of the measurement record to matrices
528 // first try to solve by faster Cholesky decomposition, then by Gaussian elimination
529 if (!MatCLoc.SolveChol(fVecBLoc,kTRUE)) {
530 AliInfo("Failed to solve locals by Cholesky, traying Gaussian Elimination");
531 if (!MatCLoc.SolveSpmInv(fVecBLoc,kTRUE)) {
532 AliInfo("Failed to solve locals by Gaussian Elimination, skip...");
534 return 0; // failed to solve
538 // If requested, store the track params and errors
539 if (localParams) for (int i=fNLocPar; i--;) {
540 localParams[2*i] = fVecBLoc[i];
541 localParams[2*i+1] = TMath::Sqrt(TMath::Abs(MatCLoc.QuerryDiag(i)));
547 for (int ip=nPoints;ip--;) { // Calculate residuals
548 double resid = fRecord->GetValue( RefLoc[ip]-1 );
549 double weight = fRecord->GetValue( RefGlo[ip]-1 );
550 double *derLoc = fRecord->GetValue()+RefLoc[ip];
551 double *derGlo = fRecord->GetValue()+RefGlo[ip];
552 int *indLoc = fRecord->GetIndex()+RefLoc[ip];
553 int *indGlo = fRecord->GetIndex()+RefGlo[ip];
555 // Suppress local and global contribution in residuals;
556 for (int i=nRefLoc[ip];i--;) resid -= derLoc[i]*fVecBLoc[ indLoc[i] ]; // local part
558 for (int i=nRefGlo[ip];i--;) { // global part
560 if ( fSigmaPar[iID] <= 0.) continue; // fixed parameter RRRCheck
561 if (fIsLinear[iID]) resid -= derGlo[i]*(fInitPar[iID]+fDeltaPar[iID]); // linear parameter
562 else resid -= derGlo[i]*fDeltaPar[iID]; // nonlinear parameter
565 // reject the track if the residual is too large (outlier)
566 if ( (TMath::Abs(resid) >= fResCutInit && fIter ==1 ) ||
567 (TMath::Abs(resid) >= fResCut && fIter > 1)) {
572 lChi2 += weight*resid*resid ; // total chi^2
573 nEq++; // number of equations
574 } // end of Calculate residuals
577 int nDoF = nEq-fNLocPar;
578 lChi2 = (nDoF>0) ? lChi2/nDoF : 0; // Chi^2/dof
580 if (fNStdDev != 0 && nDoF>0 && lChi2 > Chi2DoFLim(fNStdDev,nDoF)*fChi2CutFactor) { // check final chi2
586 fNLocEquations += nEq;
588 // local operations are finished, track is accepted
589 // We now update the global parameters (other matrices)
593 for (int ip=nPoints;ip--;) { // Update matrices
594 double resid = fRecord->GetValue( RefLoc[ip]-1 );
595 double weight = fRecord->GetValue( RefGlo[ip]-1 );
596 double *derLoc = fRecord->GetValue()+RefLoc[ip];
597 double *derGlo = fRecord->GetValue()+RefGlo[ip];
598 int *indLoc = fRecord->GetIndex()+RefLoc[ip];
599 int *indGlo = fRecord->GetIndex()+RefGlo[ip];
601 for (int i=nRefGlo[ip];i--;) { // suppress the global part
602 int iID = indGlo[i]; // Global param indice
603 if ( fSigmaPar[iID] <= 0.) continue; // fixed parameter RRRCheck
604 if (fIsLinear[iID] == 0) resid -= derGlo[i]*(fInitPar[iID]+fDeltaPar[iID]); // linear parameter
605 else resid -= derGlo[i]*fDeltaPar[iID]; // nonlinear parameter
608 for (int ig=nRefGlo[ip];ig--;) {
609 int iIDg = indGlo[ig]; // Global param indice (the matrix line)
610 if ( fSigmaPar[iIDg] <= 0.) continue; // fixed parameter RRRCheck
611 if ( (vl = weight*resid*derGlo[ig])!=0 ) fVecBGlo[ iIDg ] += vl;
613 // First of all, the global/global terms (exactly like local matrix)
614 for (int jg=ig+1;jg--;) { // MatCGlo is symmetric by construction
615 int jIDg = indGlo[jg];
616 if ( fSigmaPar[jIDg] <= 0.) continue; // fixed parameter RRRCheck
617 if ( (vl = weight*derGlo[ig]*derGlo[jg])!=0 ) MatCGlo(iIDg,jIDg) += vl;
620 // Now we have also rectangular matrices containing global/local terms.
621 int iCIDg = fGlo2CGlo[iIDg]; // compressed Index of index
623 for (int k=fNLocPar;k--;) MatCGloLoc(nGloInFit,k) = 0.0; // reset the row
624 iCIDg = fGlo2CGlo[iIDg] = nGloInFit;
625 fCGlo2Glo[nGloInFit++] = iIDg;
628 for (int il=nRefLoc[ip];il--;) {
629 int iIDl = indLoc[il];
630 if ( (vl = weight*derGlo[ig]*derLoc[il])!=0) MatCGloLoc(iCIDg,iIDl) += vl;
636 } // end of Update matrices
638 // calculate fMatCGlo -= fMatCGloLoc * fMatCLoc * fMatCGloLoc^T
639 // and fVecBGlo -= fMatCGloLoc * fVecBLoc
642 for (int iCIDg=0; iCIDg<nGloInFit; iCIDg++) {
643 int iIDg = fCGlo2Glo[iCIDg];
646 for (int kl=0;kl<fNLocPar;kl++) if ( (vll = MatCGloLoc(iCIDg,kl))!=0) vl += vll*fVecBLoc[kl];
647 if (vl!=0) fVecBGlo[iIDg] -= vl;
649 for (int jCIDg=0;jCIDg<=iCIDg; jCIDg++) {
650 int jIDg = fCGlo2Glo[jCIDg];
653 for (int kl=0;kl<fNLocPar;kl++) {
655 if ( (vll=MatCGloLoc(iCIDg,kl)*MatCGloLoc(jCIDg,kl))!=0 ) vl += MatCLoc.QuerryDiag(kl)*vll;
658 for (int ll=0;ll<kl;ll++) {
659 if ( (vll=MatCGloLoc(iCIDg,kl)*MatCGloLoc(jCIDg,ll))!=0 ) vl += MatCLoc(kl,ll)*vll;
660 if ( (vll=MatCGloLoc(iCIDg,ll)*MatCGloLoc(jCIDg,kl))!=0 ) vl += MatCLoc(kl,ll)*vll;
663 if (vl!=0) MatCGlo(iIDg,jIDg) -= vl;
668 // reset compressed index array
670 for (int i=nGloInFit;i--;) { fGlo2CGlo[ fCGlo2Glo[i] ] = -1; fCGlo2Glo[i] = -1;}
675 //_____________________________________________________________________________________________
676 Int_t AliMillePede2::GlobalFit(Double_t *par, Double_t *error, Double_t *pull)
678 // performs a requested number of global iterations
681 TStopwatch sw; sw.Start();
684 AliInfo("Starting Global fit.");
685 while (fIter<=fMaxIter) {
687 res = GlobalFitIteration();
690 if (fChi2CutFactor != fChi2CutRef) {
691 fChi2CutFactor = TMath::Sqrt(fChi2CutFactor);
692 if (fChi2CutFactor < 1.2*fChi2CutRef) {
693 fChi2CutFactor = fChi2CutRef;
694 fIter = fMaxIter - 1; // Last iteration
701 AliInfo(Form("Global fit %s, CPU time: %.1f",res ? "Converged":"Failed",sw.CpuTime()));
704 if (par) for (int i=fNGloPar;i--;) par[i] = fInitPar[i]+fDeltaPar[i];
706 if (fGloSolveStatus==gkInvert) { // errors on params are available
707 if (error) for (int i=fNGloPar;i--;) error[i] = fProcPnt[i]>0 ? TMath::Sqrt(TMath::Abs(fMatCGlo->QuerryDiag(i))) : 0.;
708 if (pull) for (int i=fNGloPar;i--;) pull[i] = fProcPnt[i]>0 && (fSigmaPar[i]*fSigmaPar[i]-fMatCGlo->QuerryDiag(i))>0. && fSigmaPar[i]>0
709 ? fDeltaPar[i]/TMath::Sqrt(fSigmaPar[i]*fSigmaPar[i]-fMatCGlo->QuerryDiag(i)) : 0;
715 //_____________________________________________________________________________________________
716 Int_t AliMillePede2::GlobalFitIteration()
718 // perform global parameters fit once all the local equations have been fitted
720 AliInfo(Form("Global Fit Iteration#%2d (Local Fit Chi^2 cut factor: %.2f)",fIter,fChi2CutFactor));
722 if (!fNGloPar || !fTreeData) {
723 AliInfo("No data was stored, aborting iteration");
726 TStopwatch sw; sw.Start();
729 fConstrUsed = new Bool_t[fNGloConstraints];
730 memset(fConstrUsed,0,fNGloConstraints*sizeof(Bool_t));
732 // Reset all info specific for this step
733 AliMatrixSq& MatCGlo = *fMatCGlo;
735 memset(fProcPnt,0,fNGloPar*sizeof(Int_t));
737 fNGloConstraints = fTreeConstr ? fTreeConstr->GetEntries() : 0;
739 // if needed, readjust the size of the global vector (for matrices this is done automatically)
740 if (!fVecBGlo || fNGloSize!=fNGloPar+fNGloConstraints) {
741 delete[] fVecBGlo; // in case some constraint was added between the two manual iterations
742 fNGloSize = fNGloPar+fNGloConstraints;
743 fVecBGlo = new Double_t[fNGloSize];
745 memset(fVecBGlo,0,fNGloSize*sizeof(double));
748 fNLocFitsRejected = 0;
751 // Process data records and build the matrices
752 Long_t ndr = fTreeData->GetEntries();
753 AliInfo(Form("Building the Global matrix from %d data records",ndr));
754 for (Long_t i=0;i<ndr;i++) {
760 for (int i=fNGloPar;i--;) fDiagCGlo[i] = MatCGlo.QuerryDiag(i); // save the diagonal elements
762 // Account for fixed parameters
763 for (int i=fNGloPar;i--;) { // // Reset row and column of fixed params and add 1/sig^2 to free ones
764 if ( fSigmaPar[i] <= 0. || fProcPnt[i]<fMinPntValid) {
768 if (IsGlobalMatSparse()) {
769 AliVectorSparse& row = *((AliMatrixSparse*)fMatCGlo)->GetRow(i);
771 row(i) = float(fNLocEquations);
772 for (int j=i+1;j<fNGloPar;j++) ((AliMatrixSparse*)fMatCGlo)->SetToZero(i,j);
775 for (int j=fNGloPar;j--;) if (MatCGlo.Querry(i,j)) MatCGlo(i,j)=0;
776 MatCGlo.DiagElem(i) = float(fNLocEquations);
778 else MatCGlo.DiagElem(i) += 1.0/(fSigmaPar[i]*fSigmaPar[i]);
781 // add constraint equations
782 int nVar = fNGloPar; // Current size of global matrix
783 for (int i=0; i<fNGloConstraints; i++) {
784 ReadRecordConstraint(i);
785 double val = fRecord->GetValue(0);
786 int *indV = fRecord->GetIndex()+2;
787 double *der = fRecord->GetValue()+2;
788 int csize = fRecord->GetSize()-2;
790 // check if after suppression of fixed variables this there are non-0 derivatives
792 for (int j=csize;j--;) if (fProcPnt[indV[j]]<1) NSuppressed++;
794 if (NSuppressed==csize) {
795 AliInfo(Form("Neglecting constraint %d of %d derivatives since no free parameters left",i,csize));
797 // was this constraint ever created ?
798 if ( fConstrUsed[i] ) {
799 // to avoid empty row impose dummy constraint on "Lagrange multiplier"
800 MatCGlo.DiagElem(nVar) = 1.;
801 fVecBGlo[nVar++] = 0;
806 for (int j=csize; j--;) {
808 val -= der[j]*(fInitPar[jID]+fDeltaPar[jID]);
809 if (fProcPnt[jID]<1) continue; // this parameter was fixed, don't put it into constraint
810 MatCGlo(nVar,jID) = float(fNLocEquations)*der[j]; // fMatCGlo is symmetric, only lower triangle is filled
813 if (MatCGlo.QuerryDiag(nVar)) MatCGlo.DiagElem(nVar) = 0.0;
814 fVecBGlo[nVar++] = float(fNLocEquations)*val; //RS ? should we use here fNLocFits ?
815 fConstrUsed[i] = kTRUE;
818 AliInfo(Form("Obtained %-7ld equations from %-7ld records (%-7ld rejected). Fixed %-4d globals",
819 fNLocEquations,fNLocFits,fNLocFitsRejected,fNGloFix));
822 fGloSolveStatus = SolveGlobalMatEq(); // obtain solution for this step
825 AliInfo(Form("Iteration#%2d %s. CPU time: %.1f",fIter,fGloSolveStatus==gkFailed ? "Failed":"Converged",sw.CpuTime()));
826 if (fGloSolveStatus==gkFailed) return 0;
828 for (int i=fNGloPar;i--;) fDeltaPar[i] += fVecBGlo[i]; // Update global parameters values (for iterations)
833 //_____________________________________________________________________________________________
834 Int_t AliMillePede2::SolveGlobalMatEq()
837 // solve global matrix equation MatCGlob*X=VecBGlo and store the result in the VecBGlo
839 if (!fgIsMatGloSparse) {
841 if (fNGloConstraints==0) { // pos-def systems are faster to solve by Cholesky
842 if ( ((AliSymMatrix*)fMatCGlo)->SolveChol(fVecBGlo, kTRUE) ) return gkInvert;
843 else AliInfo("Solution of Global Dense System by Cholesky failed, trying Gaussian Elimiation");
846 if (((AliSymMatrix*)fMatCGlo)->SolveSpmInv(fVecBGlo, kTRUE)) return gkInvert;
847 else AliInfo("Solution of Global Dense System by Gaussian Elimiation failed, trying iterative methods");
849 // try to solve by minres
850 TVectorD SOL(fNGloSize);
852 AliMinResSolve *slv = new AliMinResSolve(fMatCGlo,fVecBGlo);
853 if (!slv) return gkFailed;
856 if (fgIterSol == AliMinResSolve::kSolMinRes)
857 res = slv->SolveMinRes(SOL,fgMinResCondType,fgMinResMaxIter,fgMinResTol);
858 else if (fgIterSol == AliMinResSolve::kSolFGMRes)
859 res = slv->SolveFGMRES(SOL,fgMinResCondType,fgMinResMaxIter,fgMinResTol,fgNKrylovV);
861 AliInfo(Form("Undefined Iteritive Solver ID=%d, only %d are defined",fgIterSol,AliMinResSolve::kNSolvers));
863 if (!res) return gkFailed;
864 for (int i=fNGloSize;i--;) fVecBGlo[i] = SOL[i];
869 //_____________________________________________________________________________________________
870 Float_t AliMillePede2::Chi2DoFLim(int nSig, int nDoF) const
872 /// return the limit in chi^2/nd for n sigmas stdev authorized
873 // Only n=1, 2, and 3 are expected in input
875 float sn[3] = {0.47523, 1.690140, 2.782170};
876 float table[3][30] = {{1.0000, 1.1479, 1.1753, 1.1798, 1.1775, 1.1730, 1.1680, 1.1630,
877 1.1581, 1.1536, 1.1493, 1.1454, 1.1417, 1.1383, 1.1351, 1.1321,
878 1.1293, 1.1266, 1.1242, 1.1218, 1.1196, 1.1175, 1.1155, 1.1136,
879 1.1119, 1.1101, 1.1085, 1.1070, 1.1055, 1.1040},
880 {4.0000, 3.0900, 2.6750, 2.4290, 2.2628, 2.1415, 2.0481, 1.9736,
881 1.9124, 1.8610, 1.8171, 1.7791, 1.7457, 1.7161, 1.6897, 1.6658,
882 1.6442, 1.6246, 1.6065, 1.5899, 1.5745, 1.5603, 1.5470, 1.5346,
883 1.5230, 1.5120, 1.5017, 1.4920, 1.4829, 1.4742},
884 {9.0000, 5.9146, 4.7184, 4.0628, 3.6410, 3.3436, 3.1209, 2.9468,
885 2.8063, 2.6902, 2.5922, 2.5082, 2.4352, 2.3711, 2.3143, 2.2635,
886 2.2178, 2.1764, 2.1386, 2.1040, 2.0722, 2.0428, 2.0155, 1.9901,
887 1.9665, 1.9443, 1.9235, 1.9040, 1.8855, 1.8681}};
893 lNSig = TMath::Max(1,TMath::Min(nSig,3));
896 return table[lNSig-1][nDoF-1];
898 else { // approximation
899 return ((sn[lNSig-1]+TMath::Sqrt(float(2*nDoF-3)))*
900 (sn[lNSig-1]+TMath::Sqrt(float(2*nDoF-3))))/float(2*nDoF-2);
905 //_____________________________________________________________________________________________
906 Int_t AliMillePede2::SetIterations(double lChi2CutFac)
908 // Number of iterations is calculated from lChi2CutFac
909 fChi2CutFactor = TMath::Max(1.0, lChi2CutFac);
911 AliInfo(Form("Initial cut factor is %f",fChi2CutFactor));
912 fIter = 1; // Initializes the iteration process
916 //_____________________________________________________________________________________________
917 Double_t AliMillePede2::GetParError(int iPar) const
919 // return error for parameter iPar
920 if (fGloSolveStatus==gkInvert) {
921 double res = fMatCGlo->QuerryDiag(iPar);
922 if (res>=0) return TMath::Sqrt(res);
928 //_____________________________________________________________________________________________
929 Int_t AliMillePede2::PrintGlobalParameters() const
931 /// Print the final results into the logfile
933 double lGlobalCor =0.;
936 AliInfo(" Result of fit for global parameters");
937 AliInfo(" ===================================");
938 AliInfo(" I initial final differ lastcor error gcor Npnt");
939 AliInfo("----------------------------------------------------------------------------------------------");
941 for (int i=0; i<fNGloPar; i++) {
942 lError = GetParError(i);
946 if (fGloSolveStatus==gkInvert && TMath::Abs( (dg=fMatCGlo->QuerryDiag(i)) *fDiagCGlo[i]) > 0) {
947 lGlobalCor = TMath::Sqrt(TMath::Abs(1.0-1.0/(dg*fDiagCGlo[i])));
948 AliInfo(Form("%d\t %.6f\t %.6f\t %.6f\t %.6f\t %.6f\t %.6f\t %6d",
949 i,fInitPar[i],fInitPar[i]+fDeltaPar[i],fDeltaPar[i],fVecBGlo[i],lError,lGlobalCor,fProcPnt[i]));
952 AliInfo(Form("%d\t %.6f\t %.6f\t %.6f\t %.6f\t OFF\t OFF\t %6d",i,fInitPar[i],fInitPar[i]+fDeltaPar[i],
953 fDeltaPar[i],fVecBGlo[i],fProcPnt[i]));