]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - STEER/AliMillePede2.cxx
Optionally the log term of Rossi parameterization for mult.scattering can be
[u/mrichter/AliRoot.git] / STEER / AliMillePede2.cxx
index aca79e251d6af6f0898082428bc23c3e495c7537..43e9ee7c9a7a957c2125faca28b5d71ec379603b 100644 (file)
+/**********************************************************************************************/
+/* General class for alignment with large number of degrees of freedom                        */
+/* Based on the original milliped2 by Volker Blobel                                           */
+/* http://www.desy.de/~blobel/mptalks.html                                                    */
+/*                                                                                            */ 
+/* Author: ruben.shahoyan@cern.ch                                                             */
+/*                                                                                            */ 
+/**********************************************************************************************/
+
 #include "AliMillePede2.h"
 #include "AliLog.h"
 #include <TStopwatch.h>
+#include <TFile.h>
+#include <TChain.h>
+#include <TMath.h>
+#include <TVectorD.h>
+#include <TArrayL.h>
+#include <TSystem.h>
+#include "AliMatrixSq.h"
+#include "AliSymMatrix.h"
+#include "AliRectMatrix.h"
+#include "AliMatrixSparse.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <fstream>
 
 using namespace std;
 
-ClassImp(AliMillePedeRecord)
-
-//_____________________________________________________________________________________________
-AliMillePedeRecord::AliMillePedeRecord() : 
-fSize(0),fIndex(0),fValue(0) {SetBufferSize(0);}
-
-//_____________________________________________________________________________________________
-AliMillePedeRecord::AliMillePedeRecord(const AliMillePedeRecord& src) : 
-  TObject(src),fSize(src.fSize),fIndex(0),fValue(0)
-{
-  fIndex = new int[GetBufferSize()];
-  memcpy(fIndex,src.fIndex,fSize*sizeof(int));
-  fValue = new double[GetBufferSize()];
-  memcpy(fValue,src.fValue,fSize*sizeof(double));
-}
 
-//_____________________________________________________________________________________________
-AliMillePedeRecord& AliMillePedeRecord::operator=(const AliMillePedeRecord& rhs)
-{
-  if (this!=&rhs) {
-    Reset();
-    for (int i=0;i<rhs.GetSize();i++) {
-      double val;
-      int    ind;
-      rhs.GetIndexValue(i,ind,val);
-      AddIndexValue(ind,val);
-    }
-  }
-  return *this;
-}
-
-//_____________________________________________________________________________________________
-AliMillePedeRecord::~AliMillePedeRecord() {delete[] fIndex; delete[] fValue;}
-
-//_____________________________________________________________________________________________
-void AliMillePedeRecord::Print(const Option_t *) const
-{
-  if (!fSize) {AliInfo("No data"); return;}
-  int cnt=0,point=0;
-  //  
-  while(cnt<fSize) {
-    //
-    double resid = fValue[cnt++];
-    double *derLoc = GetValue()+cnt;
-    int    *indLoc = GetIndex()+cnt;
-    int     nLoc = 0;
-    while(!IsWeight(cnt)) {nLoc++;cnt++;}
-    double weight = GetValue(cnt++);
-    double *derGlo = GetValue()+cnt;
-    int    *indGlo = GetIndex()+cnt;
-    int     nGlo = 0;
-    while(!IsResidual(cnt) && cnt<fSize) {nGlo++; cnt++;} 
-    //
-    printf("\n*** Point#%2d | Residual = %+.4e | Weight = %+.4e\n",point++,resid,weight);
-    printf("Locals : "); 
-    for (int i=0;i<nLoc;i++) printf("[%5d] %+.4e|",indLoc[i],derLoc[i]); printf("\n");
-    printf("Globals: "); 
-    for (int i=0;i<nGlo;i++) printf("[%5d] %+.4e|",indGlo[i],derGlo[i]); printf("\n");
-    //
-  }
-  //
-}
-
-//_____________________________________________________________________________________________
-void AliMillePedeRecord::Expand(int bfsize)
-{
-  // add extra space 
-  bfsize = TMath::Max(bfsize,GetBufferSize());
-  int *tmpI = new int[bfsize];
-  memcpy(tmpI,fIndex, fSize*sizeof(int));
-  delete fIndex;
-  fIndex = tmpI;
-  //
-  double *tmpD = new double[bfsize];
-  memcpy(tmpD,fValue, fSize*sizeof(double));
-  delete fValue;
-  fValue = tmpD;
-  //
-  SetBufferSize(bfsize);
-}
-
-//----------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------
 ClassImp(AliMillePede2)
 
-Bool_t   AliMillePede2::fgIsMatGloSparse = kFALSE;   // use faster dense matrix by default
-Int_t    AliMillePede2::fgMinResCondType = kTRUE;        // No preconditioner by default
-Double_t AliMillePede2::fgMinResTol      = 1.e-8;   // default tolerance
-Int_t    AliMillePede2::fgMinResMaxIter  = 3000;     // default max number of iterations 
+Bool_t   AliMillePede2::fgInvChol        = kTRUE;     // Invert global matrix with Cholesky solver
+Bool_t   AliMillePede2::fgWeightSigma    = kTRUE;     // weight local constraint by module statistics
+Bool_t   AliMillePede2::fgIsMatGloSparse = kFALSE;    // use faster dense matrix by default
+Int_t    AliMillePede2::fgMinResCondType = 1;         // Jacoby preconditioner by default
+Double_t AliMillePede2::fgMinResTol      = 1.e-11;    // default tolerance
+Int_t    AliMillePede2::fgMinResMaxIter  = 10000;     // default max number of iterations 
 Int_t    AliMillePede2::fgIterSol        = AliMinResSolve::kSolMinRes; // default iterative solver
-Int_t    AliMillePede2::fgNKrylovV       = 30;       // default number of Krylov vectors to keep
+Int_t    AliMillePede2::fgNKrylovV       = 240;        // default number of Krylov vectors to keep
 
 //_____________________________________________________________________________________________
 AliMillePede2::AliMillePede2() 
@@ -109,6 +53,7 @@ AliMillePede2::AliMillePede2()
   fMaxIter(10),
   fNStdDev(3),
   fNGloConstraints(0),
+  fNLagrangeConstraints(0),
   fNLocFits(0),
   fNLocFitsRejected(0),
   fNGloFix(0),
@@ -118,8 +63,10 @@ AliMillePede2::AliMillePede2()
   fChi2CutRef(1.),
   fResCutInit(100.),
   fResCut(100.),
-  fMinPntValid(0),
+  fMinPntValid(1),
 //
+  fNGroupsSet(0),
+  fParamGrID(0),
   fProcPnt(0),
   fVecBLoc(0),
   fDiagCGlo(0),
@@ -136,28 +83,44 @@ AliMillePede2::AliMillePede2()
   fMatCLoc(0),
   fMatCGlo(0),
   fMatCGloLoc(0),
-//
+  //
+  fFillIndex(0),
+  fFillValue(0),
+  //
   fDataRecFName("/tmp/mp2_data_records.root"),
   fRecord(0),
   fDataRecFile(0),  
   fTreeData(0),
+  fRecFileStatus(0),
   //
   fConstrRecFName("/tmp/mp2_constraints_records.root"),
   fTreeConstr(0),
   fConsRecFile(0),
   fCurrRecDataID(0),
-  fCurrRecConstrID(0)
+  fCurrRecConstrID(0),
+  fLocFitAdd(kTRUE),
+  fSelFirst(1),
+  fSelLast(-1),
+  fRejRunList(0),
+  fAccRunList(0)
 {}
 
 //_____________________________________________________________________________________________
 AliMillePede2::AliMillePede2(const AliMillePede2& src) : 
   TObject(src),fNLocPar(0),fNGloPar(0),fNGloSize(0),fNLocEquations(0),fIter(0),
-  fMaxIter(10),fNStdDev(3),fNGloConstraints(0),fNLocFits(0),fNLocFitsRejected(0),
+  fMaxIter(10),fNStdDev(3),fNGloConstraints(0),fNLagrangeConstraints(0),
+  fNLocFits(0),fNLocFitsRejected(0),
   fNGloFix(0),fGloSolveStatus(0),fChi2CutFactor(0),fChi2CutRef(0),fResCutInit(0),
-  fResCut(0),fMinPntValid(0),fProcPnt(0),fVecBLoc(0),fDiagCGlo(0),fVecBGlo(0),
+  fResCut(0),fMinPntValid(1),fNGroupsSet(0),fParamGrID(0),fProcPnt(0),fVecBLoc(0),fDiagCGlo(0),fVecBGlo(0),
   fInitPar(0),fDeltaPar(0),fSigmaPar(0),fIsLinear(0),fConstrUsed(0),fGlo2CGlo(0),fCGlo2Glo(0),
-  fMatCLoc(0),fMatCGlo(0),fMatCGloLoc(0),fDataRecFName(0),fRecord(0),fDataRecFile(0),
-  fTreeData(0),fConstrRecFName(0),fTreeConstr(0),fConsRecFile(0),fCurrRecDataID(0),fCurrRecConstrID(0)
+  fMatCLoc(0),fMatCGlo(0),fMatCGloLoc(0),fFillIndex(0),fFillValue(0),
+  fDataRecFName(0),fRecord(0),fDataRecFile(0),
+  fTreeData(0),fRecFileStatus(0),fConstrRecFName(0),fTreeConstr(0),fConsRecFile(0),fCurrRecDataID(0),
+  fCurrRecConstrID(0),fLocFitAdd(kTRUE),
+  fSelFirst(1),
+  fSelLast(-1),
+  fRejRunList(0),
+  fAccRunList(0)
 {printf("Dummy\n");}
 
 //_____________________________________________________________________________________________
@@ -166,6 +129,7 @@ AliMillePede2::~AliMillePede2()
   CloseDataRecStorage();
   CloseConsRecStorage();
   //
+  delete[] fParamGrID;
   delete[] fProcPnt;
   delete[] fVecBLoc;
   delete[] fDiagCGlo;
@@ -177,11 +141,15 @@ AliMillePede2::~AliMillePede2()
   delete[] fCGlo2Glo;
   delete[] fIsLinear;
   delete[] fConstrUsed;
+  delete[] fFillIndex;
+  delete[] fFillValue;
   //
   delete fRecord;
   delete fMatCLoc;
   delete fMatCGlo;
   delete fMatCGloLoc;
+  delete fRejRunList;
+  delete fAccRunList;
 } 
 
 //_____________________________________________________________________________________________
@@ -201,9 +169,13 @@ Int_t AliMillePede2::InitMille(int nGlo, int nLoc, int lNStdDev,double lResCut,
     if (fgIsMatGloSparse) {fMatCGlo = new AliMatrixSparse(fNGloPar); fMatCGlo->SetSymmetric(kTRUE);}
     else                   fMatCGlo = new AliSymMatrix(fNGloPar);
     //
+    fFillIndex    = new Int_t[fNGloPar];
+    fFillValue    = new Double_t[fNGloPar];
+    //
     fMatCLoc      = new AliSymMatrix(fNLocPar);
-    fMatCGloLoc   = new TMatrixD(fNGloPar,fNLocPar);
+    fMatCGloLoc   = new AliRectMatrix(fNGloPar,fNLocPar);
     //
+    fParamGrID    = new Int_t[fNGloPar];
     fProcPnt      = new Int_t[fNGloPar];
     fVecBLoc      = new Double_t[fNLocPar];
     fDiagCGlo     = new Double_t[fNGloPar];
@@ -229,23 +201,14 @@ Int_t AliMillePede2::InitMille(int nGlo, int nLoc, int lNStdDev,double lResCut,
   memset(fProcPnt   ,0,fNGloPar*sizeof(Int_t));
   //
   for (int i=fNGloPar;i--;) {
-    fGlo2CGlo[i]=fCGlo2Glo[i] = -1;
+    fGlo2CGlo[i] = fCGlo2Glo[i] = -1;
     fIsLinear[i] = kTRUE;
+    fParamGrID[i] = -1;
   }
   //
   return 1;
 }
 
-//_____________________________________________________________________________________________
-void AliMillePede2::ResetConstraints()
-{
-  // reset constraints tree. Allows to redefine the constraints for preprocessed data 
-  CloseConsRecStorage();
-  InitConsRecStorage(kFALSE);
-  fNGloConstraints = 0;
-  AliInfo("Constraints are reset");
-}
-
 //_____________________________________________________________________________________________
 Bool_t AliMillePede2::ImposeDataRecFile(const char* fname)
 {
@@ -267,25 +230,51 @@ Bool_t AliMillePede2::InitDataRecStorage(Bool_t read)
 {
   // initialize the buffer for processed measurements records
   //
-  if (fDataRecFile) {AliInfo("Data Records File is already initialized"); return kFALSE;} 
+  if (fTreeData) {AliInfo("Data Records File is already initialized"); return kFALSE;} 
   //
   if (!fRecord) fRecord = new AliMillePedeRecord();
   //
-  fDataRecFile = TFile::Open(GetDataRecFName(),read ? "":"recreate");
-  if (!fDataRecFile) {AliInfo(Form("Failed to initialize data records file %s",GetDataRecFName())); return kFALSE;}
-  //
-  AliInfo(Form("File %s used for derivatives records",GetDataRecFName()));
-  if (read) {
-    fTreeData = (TTree*)fDataRecFile->Get("AliMillePedeRecords_Data");
-    if (!fTreeData) {AliInfo(Form("Did not find data records tree in %s",GetDataRecFName())); return kFALSE;}
-    fTreeData->SetBranchAddress("Record_Data",&fRecord);
-    AliInfo(Form("Found %d derivatives records",fTreeData->GetEntries()));
-  }
-  else {
+  if (!read) { // write mode: cannot use chain
+    fDataRecFile = TFile::Open(GetDataRecFName(),"recreate");
+    if (!fDataRecFile) {AliFatal(Form("Failed to initialize data records file %s",GetDataRecFName())); return kFALSE;}
+    AliInfo(Form("File %s used for derivatives records",GetDataRecFName()));
     fTreeData = new TTree("AliMillePedeRecords_Data","Data Records for AliMillePede2");
     fTreeData->Branch("Record_Data","AliMillePedeRecord",&fRecord,32000,99);
   }
+  else { // use chain
+    TChain* ch = new TChain("AliMillePedeRecords_Data");
+    //
+    if (fDataRecFName.EndsWith(".root")) ch->AddFile(fDataRecFName);
+    else { // assume text file with list of filenames
+      //
+      ifstream inpf(fDataRecFName.Data());
+      if (!inpf.good()) {AliInfo(Form("Failed on input records list %s\n",fDataRecFName.Data())); return kFALSE;}
+      //
+      TString recfName;
+      recfName.ReadLine(inpf);
+      while ( !(recfName.ReadLine(inpf)).eof() ) {
+       recfName = recfName.Strip(TString::kBoth,' ');
+       if (recfName.BeginsWith("//") || recfName.BeginsWith("#") || !recfName.EndsWith(".root")) {  // comment
+         AliInfo(Form("Skip %s\n",recfName.Data()));
+         continue;
+       }
+       //
+       recfName = recfName.Strip(TString::kBoth,',');
+       recfName = recfName.Strip(TString::kBoth,'"');
+       gSystem->ExpandPathName(recfName);
+       printf("Adding %s\n",recfName.Data());
+       ch->AddFile(recfName.Data());
+      }      
+    }
+    //
+    Long64_t nent = ch->GetEntries();
+    if (nent<1) { AliInfo("Obtained chain is empty"); return kFALSE;}
+    fTreeData = ch;
+    fTreeData->SetBranchAddress("Record_Data",&fRecord);
+    AliInfo(Form("Found %lld derivatives records",nent));
+  }
   fCurrRecDataID = -1;
+  fRecFileStatus = read ? 1:2;
   //
   return kTRUE;
 }
@@ -307,7 +296,7 @@ Bool_t AliMillePede2::InitConsRecStorage(Bool_t read)
     fTreeConstr = (TTree*)fConsRecFile->Get("AliMillePedeRecords_Constraints");
     if (!fTreeConstr) {AliInfo(Form("Did not find constraints records tree in %s",GetConsRecFName())); return kFALSE;}
     fTreeConstr->SetBranchAddress("Record_Constraints",&fRecord);
-    AliInfo(Form("Found %d constraints records",fTreeConstr->GetEntries()));
+    AliInfo(Form("Found %lld constraints records",fTreeConstr->GetEntries()));
     //
   }
   else {
@@ -324,16 +313,19 @@ Bool_t AliMillePede2::InitConsRecStorage(Bool_t read)
 void AliMillePede2::CloseDataRecStorage()
 {
   if (fTreeData) {
-    if (fDataRecFile->IsWritable()) {
+    if (fDataRecFile && fDataRecFile->IsWritable()) {
       fDataRecFile->cd();
       fTreeData->Write();
     }
     delete fTreeData;  
     fTreeData = 0;
-    fDataRecFile->Close();
-    delete fDataRecFile;
-    fDataRecFile = 0;
+    if (fDataRecFile) {
+      fDataRecFile->Close();
+      delete fDataRecFile;
+      fDataRecFile = 0;
+    }
   }
+  fRecFileStatus = 0;
   //
 }
 
@@ -372,10 +364,24 @@ Bool_t AliMillePede2::ReadNextRecordConstraint()
   return kTRUE;
 }
 
+//_____________________________________________________________________________________________
+void AliMillePede2::SetRecordWeight(double wgh)
+{
+  if (fRecFileStatus<2) InitDataRecStorage(); // create a buffer to store the data
+  fRecord->SetWeight(wgh);
+}
+
+//_____________________________________________________________________________________________
+void AliMillePede2::SetRecordRun(Int_t run)
+{
+  if (fRecFileStatus<2) InitDataRecStorage(); // create a buffer to store the data
+  fRecord->SetRunID(run);
+}
+
 //_____________________________________________________________________________________________
 void AliMillePede2::SetLocalEquation(double *dergb, double *derlc, double lMeas, double lSigma)
 {
-  if (!fDataRecFile || !fDataRecFile->IsWritable()) InitDataRecStorage(); // create a buffer to store the data
+  if (fRecFileStatus<2) InitDataRecStorage(); // create a buffer to store the data
   //
   // write data of single measurement
   if (lSigma<=0.0) { // If parameter is fixed, then no equation
@@ -387,12 +393,15 @@ void AliMillePede2::SetLocalEquation(double *dergb, double *derlc, double lMeas,
   fRecord->AddResidual(lMeas);
   //
   // Retrieve local param interesting indices
-  for (int i=0;i<fNLocPar;i++) if (derlc[i]!=0.0) {fRecord->AddIndexValue(i,derlc[i]); derlc[i] = 0.0;}
+  for (int i=0;i<fNLocPar;i++) if (!IsZero(derlc[i])) {fRecord->AddIndexValue(i,derlc[i]); derlc[i] = 0.0;}
   //
   fRecord->AddWeight( 1.0/lSigma/lSigma );
   //
   // Idem for global parameters
-  for (int i=0;i<fNGloPar;i++) if (dergb[i]!=0.0) {fRecord->AddIndexValue(i,dergb[i]); dergb[i] = 0.0;}
+  for (int i=0;i<fNGloPar;i++) if (!IsZero(dergb[i])) {
+    fRecord->AddIndexValue(i,dergb[i]); dergb[i] = 0.0;
+    fRecord->MarkGroup(fParamGrID[i]);
+  }
   //
 }
 
@@ -407,45 +416,49 @@ void AliMillePede2::SetLocalEquation(int *indgb, double *dergb, int ngb, int *in
     return;
   }
   //
-  if (!fDataRecFile || !fDataRecFile->IsWritable()) InitDataRecStorage(); // create a buffer to store the data
+  if (fRecFileStatus<2) InitDataRecStorage(); // create a buffer to store the data
   //
   fRecord->AddResidual(lMeas);
   //
   // Retrieve local param interesting indices
-  for (int i=0;i<nlc;i++) if (derlc[i]!=0.0) {fRecord->AddIndexValue(indlc[i],derlc[i]); derlc[i]=0.; indlc[i]=0;}
+  for (int i=0;i<nlc;i++) if (!IsZero(derlc[i])) {fRecord->AddIndexValue(indlc[i],derlc[i]); derlc[i]=0.; indlc[i]=0;}
   //
   fRecord->AddWeight( 1./lSigma/lSigma );
   //
   // Idem for global parameters
-  for (int i=0;i<ngb;i++) if (dergb[i]!=0.0) {fRecord->AddIndexValue(indgb[i],dergb[i]); dergb[i]=0.; indgb[i]=0;} 
+  for (int i=0;i<ngb;i++) if (!IsZero(dergb[i])) {fRecord->AddIndexValue(indgb[i],dergb[i]); dergb[i]=0.; indgb[i]=0;} 
   //
 }
 
+
 //_____________________________________________________________________________________________
-void AliMillePede2::SetGlobalConstraint(double *dergb, double val)
+void AliMillePede2::SetGlobalConstraint(double *dergb, double val, double sigma)
 {      
   // Define a constraint equation.
   if (!fConsRecFile || !fConsRecFile->IsWritable()) InitConsRecStorage(); // create a buffer to store the data
   //
   fRecord->Reset();
   fRecord->AddResidual(val);
-  fRecord->AddWeight(val);   // dummy
-  for (int i=0; i<fNGloPar; i++) if (dergb[i]!=0)  fRecord->AddIndexValue(i,dergb[i]);
+  fRecord->AddWeight(sigma);
+  for (int i=0; i<fNGloPar; i++) if (!IsZero(dergb[i]))  fRecord->AddIndexValue(i,dergb[i]);
   fNGloConstraints++;
+  if (IsZero(sigma)) fNLagrangeConstraints++;
+  //  printf("NewConstraint:\n"); fRecord->Print(); //RRR
   SaveRecordConstraint();
   //
 }
 
 //_____________________________________________________________________________________________
-void AliMillePede2::SetGlobalConstraint(const int *indgb, double *dergb, int ngb, double val)
+void AliMillePede2::SetGlobalConstraint(const int *indgb, double *dergb, int ngb, double val,double sigma)
 {      
   // Define a constraint equation.
   if (!fConsRecFile || !fConsRecFile->IsWritable()) InitConsRecStorage(); // create a buffer to store the data
   fRecord->Reset();
   fRecord->AddResidual(val);
-  fRecord->AddWeight(val);   // dummy
-  for (int i=0; i<ngb; i++) if (dergb[i]!=0)  fRecord->AddIndexValue(indgb[i],dergb[i]);
+  fRecord->AddWeight(sigma);   // dummy
+  for (int i=0; i<ngb; i++) if (!IsZero(dergb[i]))  fRecord->AddIndexValue(indgb[i],dergb[i]);
   fNGloConstraints++;
+  if (IsZero(sigma)) fNLagrangeConstraints++;
   SaveRecordConstraint();
   //
 }
@@ -459,16 +472,17 @@ Int_t AliMillePede2::LocalFit(double *localParams)
     localParams = (if !=0) will contain the fitted track parameters and
     related errors
   */
-  static int     nRefSize = 0;
-  static TArrayI RefLoc,RefGlo,nRefLoc,nRefGlo;
+  static int     nrefSize = 0;
+  //  static TArrayI refLoc,refGlo,nrefLoc,nrefGlo;
+  static Int_t  *refLoc=0,*refGlo=0,*nrefLoc=0,*nrefGlo=0;
   int nPoints = 0;
   //
-  AliSymMatrix    &MatCLoc    = *fMatCLoc;
-  AliMatrixSq     &MatCGlo    = *fMatCGlo;
-  TMatrixD        &MatCGloLoc = *fMatCGloLoc;
+  AliSymMatrix    &matCLoc    = *fMatCLoc;
+  AliMatrixSq     &matCGlo    = *fMatCGlo;
+  AliRectMatrix   &matCGloLoc = *fMatCGloLoc;
   //
   memset(fVecBLoc,0,fNLocPar*sizeof(double));
-  MatCLoc.Reset();     
+  matCLoc.Reset();     
   //
   int cnt=0;
   int recSz = fRecord->GetSize();
@@ -476,86 +490,96 @@ Int_t AliMillePede2::LocalFit(double *localParams)
   while(cnt<recSz) {  // Transfer the measurement records to matrices
     //
     // extract addresses of residual, weight and pointers on local and global derivatives for each point
-    if (nRefSize<=nPoints) {
-      nRefSize = 2*(nPoints+1); 
-      RefLoc.Set(nRefSize); 
-      RefGlo.Set(nRefSize);
-      nRefLoc.Set(nRefSize); 
-      nRefGlo.Set(nRefSize);
+    if (nrefSize<=nPoints) {
+      int *tmpA = 0;
+      nrefSize = 2*(nPoints+1); 
+      tmpA = refLoc;  refLoc  = new Int_t[nrefSize]; if (tmpA) memcpy(refLoc,tmpA,nPoints*sizeof(int));
+      tmpA = refGlo;  refGlo  = new Int_t[nrefSize]; if (tmpA) memcpy(refGlo,tmpA,nPoints*sizeof(int));
+      tmpA = nrefLoc; nrefLoc = new Int_t[nrefSize]; if (tmpA) memcpy(nrefLoc,tmpA,nPoints*sizeof(int));
+      tmpA = nrefGlo; nrefGlo = new Int_t[nrefSize]; if (tmpA) memcpy(nrefGlo,tmpA,nPoints*sizeof(int));
     }
     //
-    RefLoc[nPoints]  = ++cnt;
+    refLoc[nPoints]  = ++cnt;
     int nLoc = 0;
     while(!fRecord->IsWeight(cnt)) {nLoc++; cnt++;}
-    nRefLoc[nPoints] = nLoc;
+    nrefLoc[nPoints] = nLoc;
     //
-    RefGlo[nPoints]  = ++cnt;
+    refGlo[nPoints]  = ++cnt;
     int nGlo = 0;
     while(!fRecord->IsResidual(cnt) && cnt<recSz) {nGlo++; cnt++;} 
-    nRefGlo[nPoints] = nGlo;
+    nrefGlo[nPoints] = nGlo;
     //
     nPoints++;
   }
   double vl;
   //
+  double gloWgh = fRecord->GetWeight(); // global weight for this set
+  Int_t maxLocUsed = 0;
+  //
   for (int ip=nPoints;ip--;) {  // Transfer the measurement records to matrices
-    double  resid  = fRecord->GetValue( RefLoc[ip]-1 );
-    double  weight = fRecord->GetValue( RefGlo[ip]-1 );    
-    double *derLoc = fRecord->GetValue()+RefLoc[ip];
-    double *derGlo = fRecord->GetValue()+RefGlo[ip];
-    int    *indLoc = fRecord->GetIndex()+RefLoc[ip];
-    int    *indGlo = fRecord->GetIndex()+RefGlo[ip];
-    //
-    for (int i=nRefGlo[ip];i--;) {       // suppress the global part (only relevant with iterations)
+    double  resid  = fRecord->GetValue( refLoc[ip]-1 );
+    double  weight = fRecord->GetValue( refGlo[ip]-1 )*gloWgh;    
+    double *derLoc = fRecord->GetValue()+refLoc[ip];
+    double *derGlo = fRecord->GetValue()+refGlo[ip];
+    int    *indLoc = fRecord->GetIndex()+refLoc[ip];
+    int    *indGlo = fRecord->GetIndex()+refGlo[ip];
+    //
+    for (int i=nrefGlo[ip];i--;) {      // suppress the global part (only relevant with iterations)
       int iID = indGlo[i];              // Global param indice
-      if ( fSigmaPar[iID] <= 0.) continue;                                    // fixed parameter RRRCheck
+      if (fSigmaPar[iID]<=0.) continue;                                    // fixed parameter RRRCheck
       if (fIsLinear[iID]) resid -= derGlo[i]*(fInitPar[iID]+fDeltaPar[iID]);  // linear parameter
       else                resid -= derGlo[i]*fDeltaPar[iID];                  // nonlinear parameter
     }
     //
-    for (int i=nRefLoc[ip];i--;) {         // Fill local matrix and vector
-      int iID = indLoc[i];              // Local param indice (the matrix line) 
-      if ( (vl=weight*resid*derLoc[i])!=0 ) fVecBLoc[iID] += vl;
-      //                       
-      for (int j=i+1;j--;) {           // Symmetric matrix, don't bother j>i coeffs
-       int jID = indLoc[j];    
-       if ( (vl=weight*derLoc[i]*derLoc[j])!=0 ) MatCLoc(iID,jID) += vl;
-      }
-    }   
+    // Symmetric matrix, don't bother j>i coeffs
+    for (int i=nrefLoc[ip];i--;) {         // Fill local matrix and vector
+      fVecBLoc[ indLoc[i] ] += weight*resid*derLoc[i];
+      if (indLoc[i]>maxLocUsed) maxLocUsed = indLoc[i];  
+      for (int j=i+1;j--;) matCLoc(indLoc[i] ,indLoc[j]) += weight*derLoc[i]*derLoc[j];
+    }
     //
   } // end of the transfer of the measurement record to matrices
   //
+  matCLoc.SetSizeUsed(++maxLocUsed);   // data with B=0 may use less than declared nLocals 
+  //
+  /* //RRR
+  fRecord->Print("l");
+  printf("\nBefore\nLocalMatrix: "); matCLoc.Print("l");
+  printf("RHSLoc: "); for (int i=0;i<fNLocPar;i++) printf("%+e |",fVecBLoc[i]); printf("\n");
+  */
   // first try to solve by faster Cholesky decomposition, then by Gaussian elimination
-  if (!MatCLoc.SolveChol(fVecBLoc,kTRUE)) {
-    AliInfo("Failed to solve locals by Cholesky, traying Gaussian Elimination");
-    if (!MatCLoc.SolveSpmInv(fVecBLoc,kTRUE)) { 
+  if (!matCLoc.SolveChol(fVecBLoc,kTRUE)) {
+    AliInfo("Failed to solve locals by Cholesky, trying Gaussian Elimination");
+    if (!matCLoc.SolveSpmInv(fVecBLoc,kTRUE)) { 
       AliInfo("Failed to solve locals by Gaussian Elimination, skip...");
-      MatCLoc.Print("d");
+      matCLoc.Print("d");
       return 0; // failed to solve
     }
   }
   //
   // If requested, store the track params and errors
-  if (localParams) for (int i=fNLocPar; i--;) {
+  //RRR  printf("locfit: "); for (int i=0;i<fNLocPar;i++) printf("%+e |",fVecBLoc[i]); printf("\n");
+  
+  if (localParams) for (int i=maxLocUsed; i--;) {
       localParams[2*i]   = fVecBLoc[i];
-      localParams[2*i+1] = TMath::Sqrt(TMath::Abs(MatCLoc.QuerryDiag(i)));
+      localParams[2*i+1] = TMath::Sqrt(TMath::Abs(matCLoc.QueryDiag(i)));
     }
   //
   float lChi2 = 0;
   int   nEq   = 0;
   //
   for (int ip=nPoints;ip--;) {  // Calculate residuals
-    double  resid  = fRecord->GetValue( RefLoc[ip]-1 );
-    double  weight = fRecord->GetValue( RefGlo[ip]-1 );    
-    double *derLoc = fRecord->GetValue()+RefLoc[ip];
-    double *derGlo = fRecord->GetValue()+RefGlo[ip];
-    int    *indLoc = fRecord->GetIndex()+RefLoc[ip];
-    int    *indGlo = fRecord->GetIndex()+RefGlo[ip];
+    double  resid  = fRecord->GetValue( refLoc[ip]-1 );
+    double  weight = fRecord->GetValue( refGlo[ip]-1 )*gloWgh;    
+    double *derLoc = fRecord->GetValue()+refLoc[ip];
+    double *derGlo = fRecord->GetValue()+refGlo[ip];
+    int    *indLoc = fRecord->GetIndex()+refLoc[ip];
+    int    *indGlo = fRecord->GetIndex()+refGlo[ip];
     //
     // Suppress local and global contribution in residuals;
-    for (int i=nRefLoc[ip];i--;) resid -= derLoc[i]*fVecBLoc[ indLoc[i] ];     // local part 
+    for (int i=nrefLoc[ip];i--;) resid -= derLoc[i]*fVecBLoc[ indLoc[i] ];     // local part 
     //
-    for (int i=nRefGlo[ip];i--;) {                                             // global part
+    for (int i=nrefGlo[ip];i--;) {                                             // global part
       int iID = indGlo[i];
       if ( fSigmaPar[iID] <= 0.) continue;                                     // fixed parameter RRRCheck
       if (fIsLinear[iID]) resid -= derGlo[i]*(fInitPar[iID]+fDeltaPar[iID]);   // linear parameter
@@ -563,9 +587,11 @@ Int_t AliMillePede2::LocalFit(double *localParams)
     }
     //
     // reject the track if the residual is too large (outlier)
-    if ( (TMath::Abs(resid) >= fResCutInit && fIter ==1 ) ||
-        (TMath::Abs(resid) >= fResCut     && fIter > 1)) {
-      fNLocFitsRejected++;      
+    double absres = TMath::Abs(resid);
+    if ( (absres >= fResCutInit && fIter ==1 ) ||
+        (absres >= fResCut     && fIter > 1)) {
+      if (fLocFitAdd) fNLocFitsRejected++;      
+      //      printf("reject res %5ld %+e\n",fCurrRecDataID,resid);
       return 0;
     }
     // 
@@ -573,17 +599,24 @@ Int_t AliMillePede2::LocalFit(double *localParams)
     nEq++;                        // number of equations                       
   } // end of Calculate residuals
   //
-  //
-  int nDoF = nEq-fNLocPar;
+  lChi2 /= gloWgh;  
+  int nDoF = nEq-maxLocUsed;
   lChi2 = (nDoF>0) ? lChi2/nDoF : 0;  // Chi^2/dof  
   //
   if (fNStdDev != 0 && nDoF>0 && lChi2 > Chi2DoFLim(fNStdDev,nDoF)*fChi2CutFactor) { // check final chi2
-    fNLocFitsRejected++;      
+    if (fLocFitAdd) fNLocFitsRejected++;      
+    //    printf("reject chi2 %5ld: %+e\n",fCurrRecDataID, lChi2);
     return 0;
   }
   //
-  fNLocFits++;
-  fNLocEquations += nEq;
+  if (fLocFitAdd) {
+    fNLocFits++;
+    fNLocEquations += nEq;
+  }
+  else {
+    fNLocFits--;
+    fNLocEquations -= nEq;
+  }
   //
   //  local operations are finished, track is accepted 
   //  We now update the global parameters (other matrices)
@@ -591,84 +624,111 @@ Int_t AliMillePede2::LocalFit(double *localParams)
   int nGloInFit = 0;
   //
   for (int ip=nPoints;ip--;) {  // Update matrices
-    double  resid  = fRecord->GetValue( RefLoc[ip]-1 );
-    double  weight = fRecord->GetValue( RefGlo[ip]-1 );    
-    double *derLoc = fRecord->GetValue()+RefLoc[ip];
-    double *derGlo = fRecord->GetValue()+RefGlo[ip];
-    int    *indLoc = fRecord->GetIndex()+RefLoc[ip];
-    int    *indGlo = fRecord->GetIndex()+RefGlo[ip];
-    //
-    for (int i=nRefGlo[ip];i--;) {    // suppress the global part
+    double  resid  = fRecord->GetValue( refLoc[ip]-1 );
+    double  weight = fRecord->GetValue( refGlo[ip]-1 )*gloWgh;    
+    double *derLoc = fRecord->GetValue()+refLoc[ip];
+    double *derGlo = fRecord->GetValue()+refGlo[ip];
+    int    *indLoc = fRecord->GetIndex()+refLoc[ip];
+    int    *indGlo = fRecord->GetIndex()+refGlo[ip];
+    //
+    for (int i=nrefGlo[ip];i--;) {    // suppress the global part
       int iID = indGlo[i];           // Global param indice
       if ( fSigmaPar[iID] <= 0.) continue;                                         // fixed parameter RRRCheck
-      if (fIsLinear[iID] == 0)  resid -= derGlo[i]*(fInitPar[iID]+fDeltaPar[iID]); // linear parameter
-      else                      resid -= derGlo[i]*fDeltaPar[iID];                 // nonlinear parameter
+      if (fIsLinear[iID])  resid -= derGlo[i]*(fInitPar[iID]+fDeltaPar[iID]);      // linear parameter
+      else                 resid -= derGlo[i]*fDeltaPar[iID];                      // nonlinear parameter
     }
     //
-    for (int ig=nRefGlo[ip];ig--;) {
+    for (int ig=nrefGlo[ip];ig--;) {
       int iIDg = indGlo[ig];   // Global param indice (the matrix line)          
       if ( fSigmaPar[iIDg] <= 0.) continue;                                    // fixed parameter RRRCheck
-      if ( (vl = weight*resid*derGlo[ig])!=0 ) fVecBGlo[ iIDg ] += vl;
+      if (fLocFitAdd) fVecBGlo[ iIDg ] += weight*resid*derGlo[ig]; //!!!
+      else            fVecBGlo[ iIDg ] -= weight*resid*derGlo[ig]; //!!!
       //
       // First of all, the global/global terms (exactly like local matrix)
-      for (int jg=ig+1;jg--;) {        // MatCGlo is symmetric by construction  
+      int nfill = 0;
+      for (int jg=ig+1;jg--;) {        // matCGlo is symmetric by construction  
        int jIDg = indGlo[jg];
        if ( fSigmaPar[jIDg] <= 0.) continue;                                    // fixed parameter RRRCheck
-       if ( (vl = weight*derGlo[ig]*derGlo[jg])!=0 ) MatCGlo(iIDg,jIDg) += vl; 
-      } 
+       if ( !IsZero(vl = weight*derGlo[ig]*derGlo[jg]) ) {
+         fFillIndex[nfill]   = jIDg;
+         fFillValue[nfill++] = fLocFitAdd ? vl:-vl;
+       }
+      }
+      if (nfill) matCGlo.AddToRow(iIDg,fFillValue,fFillIndex,nfill);
       //
       // Now we have also rectangular matrices containing global/local terms.
       int iCIDg = fGlo2CGlo[iIDg];  // compressed Index of index          
       if (iCIDg == -1) {
-       for (int k=fNLocPar;k--;) MatCGloLoc(nGloInFit,k) = 0.0;  // reset the row
+       Double_t *rowGL = matCGloLoc(nGloInFit);
+       for (int k=maxLocUsed;k--;) rowGL[k] = 0.0;  // reset the row
        iCIDg = fGlo2CGlo[iIDg] = nGloInFit;
        fCGlo2Glo[nGloInFit++] = iIDg;
       }
       //
-      for (int il=nRefLoc[ip];il--;) {
-       int iIDl = indLoc[il];
-       if ( (vl = weight*derGlo[ig]*derLoc[il])!=0) MatCGloLoc(iCIDg,iIDl) += vl;
-      }
-      // update counter
-      fProcPnt[iIDg]++;
+      Double_t *rowGLIDg = matCGloLoc(iCIDg);
+      for (int il=nrefLoc[ip];il--;) rowGLIDg[ indLoc[il] ] += weight*derGlo[ig]*derLoc[il];
+      fProcPnt[iIDg] += fLocFitAdd ? 1:-1;       // update counter
       //
     }
   } // end of Update matrices
   //
+  /*//RRR
+  printf("After GLO\n");
+  printf("MatCLoc: "); fMatCLoc->Print("l");
+  printf("MatCGlo: "); fMatCGlo->Print("l");
+  printf("MatCGlLc:"); fMatCGloLoc->Print("l");
+  printf("BGlo: "); for (int i=0; i<fNGloPar; i++) printf("%+e |",fVecBGlo[i]); printf("\n");
+  */
   // calculate fMatCGlo -= fMatCGloLoc * fMatCLoc * fMatCGloLoc^T
   // and       fVecBGlo -= fMatCGloLoc * fVecBLoc
   //
+  //-------------------------------------------------------------- >>>
   double vll;
   for (int iCIDg=0; iCIDg<nGloInFit; iCIDg++) {
     int iIDg = fCGlo2Glo[iCIDg];
     //
     vl = 0;
-    for (int kl=0;kl<fNLocPar;kl++) if ( (vll = MatCGloLoc(iCIDg,kl))!=0) vl += vll*fVecBLoc[kl];
-    if  (vl!=0) fVecBGlo[iIDg] -= vl;
+    Double_t *rowGLIDg =  matCGloLoc(iCIDg);
+    for (int kl=0;kl<maxLocUsed;kl++) if (rowGLIDg[kl]) vl += rowGLIDg[kl]*fVecBLoc[kl];
+    if  (!IsZero(vl)) fVecBGlo[iIDg] -= fLocFitAdd ? vl : -vl;
     //
+    int nfill = 0;
     for (int jCIDg=0;jCIDg<=iCIDg; jCIDg++) {  
       int jIDg = fCGlo2Glo[jCIDg];
       //
       vl = 0;
-      for (int kl=0;kl<fNLocPar;kl++) {
+      Double_t *rowGLJDg =  matCGloLoc(jCIDg);
+      for (int kl=0;kl<maxLocUsed;kl++) {
        // diag terms
-       if ( (vll=MatCGloLoc(iCIDg,kl)*MatCGloLoc(jCIDg,kl))!=0 ) vl += MatCLoc.QuerryDiag(kl)*vll;
+       if ( (!IsZero(vll=rowGLIDg[kl]*rowGLJDg[kl])) ) vl += matCLoc.QueryDiag(kl)*vll;
        //
        // off-diag terms
        for (int ll=0;ll<kl;ll++) {
-         if ( (vll=MatCGloLoc(iCIDg,kl)*MatCGloLoc(jCIDg,ll))!=0 ) vl += MatCLoc(kl,ll)*vll;
-         if ( (vll=MatCGloLoc(iCIDg,ll)*MatCGloLoc(jCIDg,kl))!=0 ) vl += MatCLoc(kl,ll)*vll;
+         if ( !IsZero(vll=rowGLIDg[kl]*rowGLJDg[ll]) ) vl += matCLoc(kl,ll)*vll;
+         if ( !IsZero(vll=rowGLIDg[ll]*rowGLJDg[kl]) ) vl += matCLoc(kl,ll)*vll;
        }
       }
-      if (vl!=0) MatCGlo(iIDg,jIDg) -= vl; 
-      //
+      if (!IsZero(vl)) {
+       fFillIndex[nfill]   = jIDg;
+       fFillValue[nfill++] = fLocFitAdd ? -vl : vl;
+      }
     }
+    if (nfill)         matCGlo.AddToRow(iIDg,fFillValue,fFillIndex,nfill);
   }
   //
   // reset compressed index array
   //
-  for (int i=nGloInFit;i--;) { fGlo2CGlo[ fCGlo2Glo[i] ] = -1; fCGlo2Glo[i] = -1;}
+  /*//RRR
+  printf("After GLOLoc\n");
+  printf("MatCGlo: "); fMatCGlo->Print("");
+  printf("BGlo: "); for (int i=0; i<fNGloPar; i++) printf("%+e |",fVecBGlo[i]); printf("\n");
+  */
+  for (int i=nGloInFit;i--;) { 
+    fGlo2CGlo[ fCGlo2Glo[i] ] = -1;
+    fCGlo2Glo[i] = -1;
+  }
   //
+  //---------------------------------------------------- <<<
   return 1;
 }
 
@@ -687,11 +747,11 @@ Int_t AliMillePede2::GlobalFit(Double_t *par, Double_t *error, Double_t *pull)
     res = GlobalFitIteration();
     if (!res) break;
     //
-    if (fChi2CutFactor != fChi2CutRef) {    
+    if (!IsZero(fChi2CutFactor-fChi2CutRef)) {    
       fChi2CutFactor = TMath::Sqrt(fChi2CutFactor);
       if (fChi2CutFactor < 1.2*fChi2CutRef) {
        fChi2CutFactor = fChi2CutRef;
-       fIter = fMaxIter - 1;     // Last iteration
+       //RRR   fIter = fMaxIter - 1;     // Last iteration
       }
     }
     fIter++;
@@ -704,9 +764,9 @@ Int_t AliMillePede2::GlobalFit(Double_t *par, Double_t *error, Double_t *pull)
   if (par) for (int i=fNGloPar;i--;) par[i] = fInitPar[i]+fDeltaPar[i]; 
   //
   if (fGloSolveStatus==gkInvert) { // errors on params are available
-    if (error) for (int i=fNGloPar;i--;) error[i] = fProcPnt[i]>0 ? TMath::Sqrt(TMath::Abs(fMatCGlo->QuerryDiag(i))) : 0.;
-    if (pull)  for (int i=fNGloPar;i--;) pull[i]  = fProcPnt[i]>0 && (fSigmaPar[i]*fSigmaPar[i]-fMatCGlo->QuerryDiag(i))>0. && fSigmaPar[i]>0 
-                                          ? fDeltaPar[i]/TMath::Sqrt(fSigmaPar[i]*fSigmaPar[i]-fMatCGlo->QuerryDiag(i)) : 0;
+    if (error) for (int i=fNGloPar;i--;) error[i] = fProcPnt[i]>0 ? TMath::Sqrt(TMath::Abs(fMatCGlo->QueryDiag(i))) : 0.;
+    if (pull)  for (int i=fNGloPar;i--;) pull[i]  = fProcPnt[i]>0 && (fSigmaPar[i]*fSigmaPar[i]-fMatCGlo->QueryDiag(i))>0. && fSigmaPar[i]>0 
+                                          ? fDeltaPar[i]/TMath::Sqrt(fSigmaPar[i]*fSigmaPar[i]-fMatCGlo->QueryDiag(i)) : 0;
   }
   //
   return 1;
@@ -723,103 +783,234 @@ Int_t AliMillePede2::GlobalFitIteration()
     AliInfo("No data was stored, aborting iteration");
     return 0;
   }
-  TStopwatch sw; sw.Start();
+  TStopwatch sw,sws; 
+  sw.Start();
+  sws.Stop();
   //
   if (!fConstrUsed) {
     fConstrUsed = new Bool_t[fNGloConstraints];
     memset(fConstrUsed,0,fNGloConstraints*sizeof(Bool_t));
   }
   // Reset all info specific for this step
-  AliMatrixSq& MatCGlo = *fMatCGlo;
-  MatCGlo.Reset();
+  AliMatrixSq& matCGlo = *fMatCGlo;
+  matCGlo.Reset();
   memset(fProcPnt,0,fNGloPar*sizeof(Int_t));
   //
   fNGloConstraints = fTreeConstr ? fTreeConstr->GetEntries() : 0;
   //
+  // count number of Lagrange constraints: they need new row/cols to be added
+  fNLagrangeConstraints = 0;
+  for (int i=0; i<fNGloConstraints; i++) {
+    ReadRecordConstraint(i);
+    if ( IsZero(fRecord->GetValue(1)) ) fNLagrangeConstraints++; // exact constraint (no error) -> Lagrange multiplier 
+  }
+  //
   // if needed, readjust the size of the global vector (for matrices this is done automatically)
-  if (!fVecBGlo || fNGloSize!=fNGloPar+fNGloConstraints) {
+  if (!fVecBGlo || fNGloSize!=fNGloPar+fNLagrangeConstraints) {
     delete[] fVecBGlo;   // in case some constraint was added between the two manual iterations
-    fNGloSize = fNGloPar+fNGloConstraints;
+    fNGloSize = fNGloPar+fNLagrangeConstraints;
     fVecBGlo = new Double_t[fNGloSize];
   }
   memset(fVecBGlo,0,fNGloSize*sizeof(double));
   //
   fNLocFits         = 0;
   fNLocFitsRejected = 0;
-  fNLocEquations      = 0;
+  fNLocEquations    = 0;
   //
   //  Process data records and build the matrices
   Long_t ndr = fTreeData->GetEntries();
-  AliInfo(Form("Building the Global matrix from %d data records",ndr));
+  Long_t first = fSelFirst>0  ? fSelFirst : 0;
+  Long_t last  = fSelLast<1   ? ndr : (fSelLast>=ndr ? ndr : fSelLast+Long_t(1));
+  ndr = last - first;
+  //
+  AliInfo(Form("Building the Global matrix from data records %ld : %ld",first,last));
+  if (ndr<1) return 0;
+  //
+  TStopwatch swt; swt.Start();
+  fLocFitAdd = kTRUE;  // add contributions of matching tracks
   for (Long_t i=0;i<ndr;i++) {
-    ReadRecordData(i);
+    Long_t iev = i+first;
+    ReadRecordData(iev);
+    if (!IsRecordAcceptable()) continue;
     LocalFit();
+    if ( (i%int(0.2*ndr)) == 0) printf("%.1f%% of local fits done\n", double(100.*i)/ndr);
   }
+  swt.Stop();
+  printf("%ld local fits done: ", ndr);
+  /*
+  printf("MatCGlo: "); fMatCGlo->Print("l");
+  printf("BGlo: "); for (int i=0; i<fNGloPar; i++) printf("%+e |",fVecBGlo[i]); printf("\n");
+  swt.Print();
+  */
+  sw.Start(kFALSE);
   //
+  //
+  // ---------------------- Reject parameters with low statistics ------------>>
   fNGloFix = 0;
-  for (int i=fNGloPar;i--;) fDiagCGlo[i] = MatCGlo.QuerryDiag(i); // save the diagonal elements  
+  if (fMinPntValid>1 && fNGroupsSet) {
+    //
+    printf("Checking parameters with statistics < %d\n",fMinPntValid);
+    TStopwatch swsup;
+    swsup.Start();
+    // 1) build the list of parameters to fix
+    Int_t fixArrSize = 10;
+    Int_t nFixedGroups = 0;
+    TArrayI fixGroups(fixArrSize);
+    //
+    int grIDold = -2;
+    int oldStart = -1;
+    double oldMin = 1.e20;
+    double oldMax =-1.e20;
+    //
+    for (int i=fNGloPar;i--;) { // // Reset row and column of fixed params and add 1/sig^2 to free ones
+      int grID = fParamGrID[i];
+      if (grID<0) continue; // not in the group
+      //
+      if (grID!=grIDold) { // starting new group
+       if (grIDold>=0) { // decide if the group has enough statistics
+         if (oldMin<fMinPntValid && oldMax<2*fMinPntValid) { // suppress group
+           for (int iold=oldStart;iold>i;iold--) fProcPnt[iold] = 0;
+           Bool_t fnd = kFALSE;    // check if the group is already accounted
+           for (int j=nFixedGroups;j--;) if (fixGroups[j]==grIDold) {fnd=kTRUE; break;}
+           if (!fnd) {
+             if (nFixedGroups>=fixArrSize) {fixArrSize*=2; fixGroups.Set(fixArrSize);}
+             fixGroups[nFixedGroups++] = grIDold; // add group to fix
+           }
+         }       
+       }
+       grIDold = grID; // mark the start of the new group
+       oldStart = i;
+       oldMin =  1.e20;
+       oldMax = -1.e20;
+      }
+      if (oldMin>fProcPnt[i]) oldMin = fProcPnt[i];
+      if (oldMax<fProcPnt[i]) oldMax = fProcPnt[i];
+      //
+    }
+    // extra check for the last group
+    if (grIDold>=0 && oldMin<fMinPntValid && oldMax<2*fMinPntValid) { // suppress group
+      for (int iold=oldStart;iold--;) fProcPnt[iold] = 0;
+      Bool_t fnd = kFALSE;    // check if the group is already accounted
+      for (int j=nFixedGroups;j--;) if (fixGroups[j]==grIDold) {fnd=kTRUE; break;}
+      if (!fnd) {
+       if (nFixedGroups>=fixArrSize) {fixArrSize*=2; fixGroups.Set(fixArrSize);}
+       fixGroups[nFixedGroups++] = grIDold; // add group to fix
+      }
+    }
+    //
+    // 2) loop over records and add contributions of fixed groups with negative sign
+    fLocFitAdd = kFALSE;
+    //
+    for (Long_t i=0;i<ndr;i++) {
+      Long_t iev = i+first;
+      ReadRecordData(iev);
+      if (!IsRecordAcceptable()) continue;
+      Bool_t suppr = kFALSE;
+      for (int ifx=nFixedGroups;ifx--;)if (fRecord->IsGroupPresent(fixGroups[ifx])) suppr = kTRUE;
+      if (suppr) LocalFit();
+    }
+    fLocFitAdd = kTRUE;
+    //
+    if (nFixedGroups) {
+      printf("Suppressed contributions of groups with NPoints<%d :\n",fMinPntValid);
+      for (int i=0;i<nFixedGroups;i++) printf("%d ",fixGroups[i]); printf("\n");
+    }
+    swsup.Stop();
+    swsup.Print();
+  }
+  // ---------------------- Reject parameters with low statistics ------------<<
+  //
+  // add large number to diagonal of fixed params  
   //
-  //  Account for fixed parameters
   for (int i=fNGloPar;i--;) { // // Reset row and column of fixed params and add 1/sig^2 to free ones
-    if ( fSigmaPar[i] <= 0. || fProcPnt[i]<fMinPntValid) {
+    //    printf("#%3d : Nproc : %5d   grp: %d\n",i,fProcPnt[i],fParamGrID[i]);
+    if (fProcPnt[i]<1) {
       fNGloFix++; 
-      fProcPnt[i] *= -1;
       fVecBGlo[i] = 0.;
-      if (IsGlobalMatSparse()) {
-       AliVectorSparse& row = *((AliMatrixSparse*)fMatCGlo)->GetRow(i);
-       row.Clear();
-       row(i) = float(fNLocEquations);
-       for (int j=i+1;j<fNGloPar;j++) ((AliMatrixSparse*)fMatCGlo)->SetToZero(i,j);
-      }
-      else 
-       for (int j=fNGloPar;j--;) if (MatCGlo.Querry(i,j)) MatCGlo(i,j)=0;
-       MatCGlo.DiagElem(i) = float(fNLocEquations);
+      matCGlo.DiagElem(i) = 1.;//float(fNLocEquations*fNLocEquations);
+      //      matCGlo.DiagElem(i) = float(fNLocEquations*fNLocEquations);
     }
-    else MatCGlo.DiagElem(i) += 1.0/(fSigmaPar[i]*fSigmaPar[i]);
+    else matCGlo.DiagElem(i) += (fgWeightSigma ? fProcPnt[i] : 1.)/(fSigmaPar[i]*fSigmaPar[i]);
   }
   //
+  for (int i=fNGloPar;i--;) fDiagCGlo[i] = matCGlo.QueryDiag(i); // save the diagonal elements  
+  //
   // add constraint equations
   int nVar = fNGloPar;                    // Current size of global matrix     
   for (int i=0; i<fNGloConstraints; i++) {
     ReadRecordConstraint(i);
     double val   = fRecord->GetValue(0);  
+    double sig   = fRecord->GetValue(1);  
     int    *indV = fRecord->GetIndex()+2;
     double *der  = fRecord->GetValue()+2;
     int    csize = fRecord->GetSize()-2;
     //
-    // check if after suppression of fixed variables this there are non-0 derivatives
-    int NSuppressed = 0;
-    for (int j=csize;j--;)  if (fProcPnt[indV[j]]<1) NSuppressed++;
+    // check if after suppression of fixed variables there are non-0 derivatives
+    // and determine the max statistics of involved params
+    int nSuppressed = 0;
+    int maxStat = 1;
+    for (int j=csize;j--;) {
+      if (fProcPnt[indV[j]]<1) nSuppressed++; 
+      else {
+       maxStat = TMath::Max(maxStat,fProcPnt[indV[j]]);
+      }
+    }
     //
-    if (NSuppressed==csize) {
-      AliInfo(Form("Neglecting constraint %d of %d derivatives since no free parameters left",i,csize));
+    if (nSuppressed==csize) {
+      //      AliInfo(Form("Neglecting constraint %d of %d derivatives since no free parameters left",i,csize));
       //
       // was this constraint ever created ? 
-      if ( fConstrUsed[i] ) {
+      if ( sig==0 && fConstrUsed[i] ) { // this is needed only for constraints with Lagrange multiplier
        // to avoid empty row impose dummy constraint on "Lagrange multiplier"
-       MatCGlo.DiagElem(nVar) = 1.;
+       matCGlo.DiagElem(nVar) = 1.;
        fVecBGlo[nVar++] = 0;
       }
       continue;
     }
     //
-    for (int j=csize; j--;) {
-      int jID = indV[j];
-      val -= der[j]*(fInitPar[jID]+fDeltaPar[jID]);
-      if (fProcPnt[jID]<1) continue;                      // this parameter was fixed, don't put it into constraint
-      MatCGlo(nVar,jID) = float(fNLocEquations)*der[j];   // fMatCGlo is symmetric, only lower triangle is filled  
-    }
+    // account for already accumulated corrections
+    for (int j=csize; j--;) val -= der[j]*(fInitPar[ indV[j] ]+fDeltaPar[ indV[j] ]);
     //
-    if (MatCGlo.QuerryDiag(nVar)) MatCGlo.DiagElem(nVar) = 0.0;
-    fVecBGlo[nVar++] = float(fNLocEquations)*val; //RS ? should we use here fNLocFits ? 
-    fConstrUsed[i] = kTRUE;
+    if (sig > 0) {  // this is a gaussian constriant: no Lagrange multipliers are added
+      //
+      double sig2i = (fgWeightSigma ? TMath::Sqrt(maxStat) : 1.)/sig/sig;
+      for (int ir=0;ir<csize;ir++) {
+       int iID = indV[ir];
+       for (int ic=0;ic<=ir;ic++) { // matrix is symmetric
+         int jID = indV[ic];
+         double vl = der[ir]*der[ic]*sig2i;
+         if (!IsZero(vl)) matCGlo(iID,jID) += vl;
+       }
+       fVecBGlo[iID] += val*der[ir]*sig2i;
+      }
+    }
+    else {   // this is exact constriant:  Lagrange multipliers must be added
+      for (int j=csize; j--;) {
+       int jID = indV[j];
+       if (fProcPnt[jID]<1) continue;                      // this parameter was fixed, don't put it into constraint
+       matCGlo(nVar,jID) = float(fNLocEquations)*der[j];   // fMatCGlo is symmetric, only lower triangle is filled  
+      }
+      //
+      if (matCGlo.QueryDiag(nVar)) matCGlo.DiagElem(nVar) = 0.0;
+      fVecBGlo[nVar++] = float(fNLocEquations)*val; //RS ? should we use here fNLocFits ? 
+      fConstrUsed[i] = kTRUE;
+    }
   }
   //
   AliInfo(Form("Obtained %-7ld equations from %-7ld records (%-7ld rejected). Fixed %-4d globals",
               fNLocEquations,fNLocFits,fNLocFitsRejected,fNGloFix));
 
   //
+  sws.Start();
+
+  /*
+  printf("Solving:\n");
+  matCGlo.Print();
+  for (int i=0;i<fNGloSize;i++) printf("b%2d : %+e\n",i,fVecBGlo[i]);
+  */
   fGloSolveStatus = SolveGlobalMatEq();                     // obtain solution for this step
+  sws.Stop();
+  printf("Solve %d |",fIter); sws.Print();
   //
   sw.Stop();
   AliInfo(Form("Iteration#%2d %s. CPU time: %.1f",fIter,fGloSolveStatus==gkFailed ? "Failed":"Converged",sw.CpuTime()));
@@ -827,6 +1018,7 @@ Int_t AliMillePede2::GlobalFitIteration()
   //
   for (int i=fNGloPar;i--;) fDeltaPar[i] += fVecBGlo[i];    // Update global parameters values (for iterations)
   //
+  //  PrintGlobalParameters();
   return 1;
 }
 
@@ -836,33 +1028,65 @@ Int_t AliMillePede2::SolveGlobalMatEq()
   //
   // solve global matrix equation MatCGlob*X=VecBGlo and store the result in the VecBGlo
   //
+  /*
+  printf("GlobalMatrix\n");
+  fMatCGlo->Print();
+  printf("RHS\n");
+  for (int i=0;i<fNGloPar;i++) printf("%d %+e\n",i,fVecBGlo[i]);
+  */
+  //
   if (!fgIsMatGloSparse) {
     //
-    if (fNGloConstraints==0) { // pos-def systems are faster to solve by Cholesky
-      if ( ((AliSymMatrix*)fMatCGlo)->SolveChol(fVecBGlo, kTRUE) ) return gkInvert;
+    if (fNLagrangeConstraints==0) { // pos-def systems are faster to solve by Cholesky
+      if ( ((AliSymMatrix*)fMatCGlo)->SolveChol(fVecBGlo, fgInvChol) ) return fgInvChol ? gkInvert:gkNoInversion;
       else AliInfo("Solution of Global Dense System by Cholesky failed, trying Gaussian Elimiation");
     }
     //
     if (((AliSymMatrix*)fMatCGlo)->SolveSpmInv(fVecBGlo, kTRUE)) return gkInvert;
-    else AliInfo("Solution of Global Dense System by Gaussian Elimiation failed, trying iterative methods");
+    else AliInfo("Solution of Global Dense System by Gaussian Elimination failed, trying iterative methods");
   }
   // try to solve by minres
-  TVectorD SOL(fNGloSize);
+  TVectorD sol(fNGloSize);
   //
   AliMinResSolve *slv = new AliMinResSolve(fMatCGlo,fVecBGlo);
   if (!slv) return gkFailed;
   //
   Bool_t res = kFALSE;
   if      (fgIterSol == AliMinResSolve::kSolMinRes) 
-    res =  slv->SolveMinRes(SOL,fgMinResCondType,fgMinResMaxIter,fgMinResTol);
+    res =  slv->SolveMinRes(sol,fgMinResCondType,fgMinResMaxIter,fgMinResTol);
   else if (fgIterSol == AliMinResSolve::kSolFGMRes) 
-    res =  slv->SolveFGMRES(SOL,fgMinResCondType,fgMinResMaxIter,fgMinResTol,fgNKrylovV);
+    res =  slv->SolveFGMRES(sol,fgMinResCondType,fgMinResMaxIter,fgMinResTol,fgNKrylovV);
   else 
     AliInfo(Form("Undefined Iteritive Solver ID=%d, only %d are defined",fgIterSol,AliMinResSolve::kNSolvers));
   //
-  if (!res) return gkFailed;
-  for (int i=fNGloSize;i--;) fVecBGlo[i] = SOL[i];
-  return gkMinRes;
+  if (!res) {
+    const char* faildump = "fgmr_failed.dat";
+    int defout = dup(1);
+    if (defout<0) {
+      AliInfo("Failed on dup");
+      return gkFailed;
+    }
+    int slvDump = open(faildump, O_RDWR|O_CREAT, 0666);
+    if (slvDump>=0) {
+      dup2(slvDump,1);
+      //
+      printf("#Failed to solve using solver %d with PreCond: %d MaxIter: %d Tol: %e NKrylov: %d\n",
+            fgIterSol,fgMinResCondType,fgMinResMaxIter,fgMinResTol,fgNKrylovV);
+      printf("#Dump of matrix:\n");
+      fMatCGlo->Print("10");
+      printf("#Dump of RHS:\n");
+      for (int i=0;i<fNGloSize;i++) printf("%d %+.10f\n",i,fVecBGlo[i]);
+      //
+      dup2(defout,1);
+      close(slvDump);
+      close(defout);
+      printf("#Dumped failed matrix and RHS to %s\n",faildump);
+    }
+    else AliInfo("Failed on file open for matrix dumping");
+    return gkFailed;
+  }
+  for (int i=fNGloSize;i--;) fVecBGlo[i] = sol[i];
+  return gkNoInversion;
   //
 }
 
@@ -918,7 +1142,7 @@ Double_t AliMillePede2::GetParError(int iPar) const
 {
   // return error for parameter iPar
   if (fGloSolveStatus==gkInvert) {
-    double res = fMatCGlo->QuerryDiag(iPar);
+    double res = fMatCGlo->QueryDiag(iPar);
     if (res>=0) return TMath::Sqrt(res);
   } 
   return -1.;
@@ -943,7 +1167,7 @@ Int_t AliMillePede2::PrintGlobalParameters() const
     lGlobalCor = 0.0;
     //         
     double dg;
-    if (fGloSolveStatus==gkInvert && TMath::Abs( (dg=fMatCGlo->QuerryDiag(i)) *fDiagCGlo[i]) > 0) {    
+    if (fGloSolveStatus==gkInvert && TMath::Abs( (dg=fMatCGlo->QueryDiag(i)) *fDiagCGlo[i]) > 0) {    
       lGlobalCor = TMath::Sqrt(TMath::Abs(1.0-1.0/(dg*fDiagCGlo[i])));
       AliInfo(Form("%d\t %.6f\t %.6f\t %.6f\t %.6f\t %.6f\t %.6f\t %6d",
                   i,fInitPar[i],fInitPar[i]+fDeltaPar[i],fDeltaPar[i],fVecBGlo[i],lError,lGlobalCor,fProcPnt[i]));
@@ -955,3 +1179,54 @@ Int_t AliMillePede2::PrintGlobalParameters() const
   }
   return 1;
 }
+
+//_____________________________________________________________________________________________
+Bool_t AliMillePede2::IsRecordAcceptable() const
+{
+  // validate record according run lists set by the user
+  static Long_t prevRunID = kMaxInt;
+  static Bool_t prevAns   = kTRUE;
+  Long_t runID = fRecord->GetRunID();
+  if (runID!=prevRunID) {
+    int n = 0;
+    prevRunID = runID;
+    // is run to be rejected?
+    if (fRejRunList && (n=fRejRunList->GetSize())) {
+      prevAns = kTRUE;
+      for (int i=n;i--;) if (runID == (*fRejRunList)[i]) {
+         prevAns = kFALSE; 
+         printf("New Run to reject: %ld -> %d\n",runID,prevAns);
+         break;
+       }
+    }
+    else if (fAccRunList && (n=fAccRunList->GetSize())) {     // is run specifically selected
+      prevAns = kFALSE;
+      for (int i=n;i--;) if (runID == (*fAccRunList)[i]) {prevAns = kTRUE; break;}
+    }
+  }
+  //
+  return prevAns;
+  //
+}
+
+//_____________________________________________________________________________________________
+void AliMillePede2::SetRejRunList(const UInt_t *runs, Int_t nruns)
+{
+  // set the list of runs to be rejected
+  if (fRejRunList) delete fRejRunList; 
+  fRejRunList = 0;
+  if (nruns<1 || !runs) return;
+  fRejRunList = new TArrayL(nruns);
+  for (int i=0;i<nruns;i++) (*fRejRunList)[i] = runs[i];
+}
+
+//_____________________________________________________________________________________________
+void AliMillePede2::SetAccRunList(const UInt_t *runs, Int_t nruns)
+{
+  // set the list of runs to be selected
+  if (fAccRunList) delete fAccRunList;
+  fAccRunList = 0;
+  if (nruns<1 || !runs) return;
+  fAccRunList = new TArrayL(nruns);
+  for (int i=0;i<nruns;i++) (*fAccRunList)[i] = runs[i];
+}