LCOV - code coverage report
Current view: top level - STAT - AliNDLocalRegression.cxx (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 684 0.1 %
Date: 2016-06-14 17:26:59 Functions: 1 31 3.2 %

          Line data    Source code
       1             : /**************************************************************************
       2             :  * Copyright(c) 2006-07, ALICE Experiment at CERN, All rights reserved. *
       3             :  *                                                                        *
       4             :  * Author: The ALICE Off-line Project.                                    *
       5             :  * Contributors are mentioned in the code where appropriate.              *
       6             :  *                                                                        *
       7             :  * Permission to use, copy, modify and distribute this software and its   *
       8             :  * documentation strictly for non-commercial purposes is hereby granted   *
       9             :  * without fee, provided that the above copyright notice appears in all   *
      10             :  * copies and that both the copyright notice and this permission notice   *
      11             :  * appear in the supporting documentation. The authors make no claims     *
      12             :  * about the suitability of this software for any purpose. It is          *
      13             :  * provided "as is" without express or implied warranty.                  *
      14             :  **************************************************************************/
      15             : 
      16             : //-------------------------------------------------------------------------
      17             : //                Implementation of the AliNDLocalRegression class
      18             : //-------------------------------------------------------------------------
      19             : 
      20             : /*
      21             :   Related task: https://alice.its.cern.ch/jira/browse/ATO-193
      22             : 
      23             :   Algorithm secription - see: 
      24             :   Kernel_smoother: Local polynomial regression   
      25             :   http://en.wikipedia.org/w/index.php?title=Kernel_smoother&oldid=627785784
      26             :   
      27             : 
      28             :   Formally, the local polynomial regression is computed by solving a weighted least square problem.
      29             :   Weights are provided as a width of the gausian kernel. 
      30             :   Local fit parameters are computed on the grid defined by axis set defiend by THn.
      31             :   For example use please check UnitTest:
      32             :   .L $ALICE_ROOT/../src/STAT/test/AliNDLocalRegressionTest.C+
      33             :   //
      34             :   Init:
      35             :   AliNDLocalRegression *pfitNDIdeal=0; 
      36             :   pfitNDIdeal->SetHistogram((THn*)(hN->Clone()));
      37             :   pfitNDIdeal->SetCuts(3,0.8,1);                  // outlier rejection setting see /AliNDLocalRegressionTest.C:UnitTestGaussNoisePlusOutliers() for motivation
      38             :   pfitNDIdeal->MakeFit(treeIn, "val:err", "xyz0:xyz1","Entry$%2==1", "0.05:0.05","2:2",0.001);
      39             : 
      40             :   Usage: 
      41             : 
      42             :   Double_t xyz[2]={1,2}
      43             :   pfitNDIdeal->Eval(xyz);
      44             : 
      45             :   In TFormulas:
      46             :   pfitNDGaus0->AddVisualCorrection(pfitNDGaus0,2); 
      47             :   pfitNDGaus1->AddVisualCorrection(pfitNDGaus0,3);
      48             :   treeIn->Draw("(AliNDLocalRegression::GetCorrND(3,xyz0,xyz1)-AliNDLocalRegression::GetCorrND(2,xyz0,xyz1))/sqrt(AliNDLocalRegression::GetCorrNDError(3,xyz0,xyz1)**2+AliNDLocalRegression::GetCorrNDError(2,xyz0,xyz1)**2)>>pullsGaus01(200,-20,20)","","");
      49             : 
      50             : 
      51             :   To do:
      52             :      1.) Statistical error of the local interpolation ignores Gaussian kernel weights 
      53             :          errors are overestimated - find a proper mathematical formula to estimate statistical error of estimator
      54             :      2.) Implent regularization for smoothing  - requesting approximate smoothnes in values and derivative
      55             :      
      56             : 
      57             :   author: marian.ivanov@cern.ch
      58             : */
      59             : 
      60             : #include <TVectorD.h>
      61             : 
      62             : #include "AliNDLocalRegression.h"
      63             : #include "AliLog.h"
      64             : 
      65             : #include "THn.h"
      66             : #include "TObjString.h"
      67             : #include "TTreeStream.h"
      68             : #include "AliMathBase.h"
      69             : #include "TMatrixD.h"
      70             : #include "TRobustEstimator.h"
      71             : #include "AliMathBase.h"
      72             : #include "TStopwatch.h"
      73             : 
      74         128 : ClassImp(AliNDLocalRegression)
      75             : 
      76             : TObjArray *AliNDLocalRegression::fgVisualCorrection=0;
      77             : // instance of correction for visualization
      78             : Int_t AliNDLocalRegression::fgVerboseLevel=1000;
      79             : 
      80             : AliNDLocalRegression::AliNDLocalRegression():
      81           0 :   TNamed(),           
      82           0 :   fHistPoints(0),            // ND histogram defining regression granularity
      83           0 :   fRobustFractionLTS(0),           //   fraction of data used for the robust mean and robust rms estimator (LTS https://en.wikipedia.org/wiki/Least_trimmed_squares)
      84           0 :   fRobustRMSLTSCut(0),           //  cut on the robust RMS  |value-localmean|<fRobustRMSLTSCut*localRMS
      85           0 :   fCutType(0),                    //  type of the cut 0- no cut 1-cut localmean=median, 2-cut localmen=rosbut mean 
      86           0 :   fInputTree(0),             // input tree - object is not owner
      87           0 :   fStreamer(0),              // optional streamer 
      88           0 :   fFormulaVal(0),            // value:err  definition formula
      89           0 :   fSelection(0),             // point selector formula
      90           0 :   fFormulaVar(0),            //: separated variable   definition formula
      91           0 :   fKernelWidthFormula(0),    //: separated  - kernel width for the regression
      92           0 :   fPolDimensionFormula(0),   //: separated  - polynom for the regression
      93           0 :   fNParameters(0),           // number of local paramters to fit
      94           0 :   fLocalFitParam(0),         // local fit parameters 
      95           0 :   fLocalFitQuality(0),         // local fit quality
      96           0 :   fLocalFitCovar(0),          // local fit covariance matrix
      97           0 :   fLocalRobustStat(0),         // local robust statistic
      98           0 :   fBinIndex(0),                  //[fNParameters] working arrays current bin index
      99           0 :   fBinCenter(0),                 //[fNParameters] working current local variables - bin center
     100           0 :   fBinDelta(0),                  //[fNParameters] working current local variables - bin delta
     101           0 :   fBinWidth(0),                  //[fNParameters] working current local variables - bin delta
     102           0 :   fUseBinNorm(kFALSE)            //  switch make polynom  in units of bins (kTRUE)  or  in natural units (kFALSE)
     103           0 : {
     104           0 :   if (!fgVisualCorrection) fgVisualCorrection= new TObjArray;
     105           0 : }
     106             : 
     107             : AliNDLocalRegression::AliNDLocalRegression(const char* name, const char* title):
     108           0 :   TNamed(name,title),                           
     109           0 :  fHistPoints(0),            // ND histogram defining regression granularity
     110           0 :   fRobustFractionLTS(0),           //   fraction of data used for the robust mean and robust rms estimator (LTS https://en.wikipedia.org/wiki/Least_trimmed_squares)
     111           0 :   fRobustRMSLTSCut(0),           //  cut on the robust RMS  |value-localmean|<fRobustRMSLTSCut*localRMS
     112           0 :   fCutType(0),                    //  type of the cut 0- no cut 1-cut localmean=median, 2-cut localmen=rosbut mean 
     113           0 :   fInputTree(0),             // input tree - object is not owner
     114           0 :   fStreamer(0),              // optional streamer 
     115           0 :   fFormulaVal(0),            // value:err  definition formula
     116           0 :   fSelection(0),             // point selector formula
     117           0 :   fFormulaVar(0),            //: separated variable   definition formula
     118           0 :   fKernelWidthFormula(0),    //: separated  - kernel width for the regression
     119           0 :   fPolDimensionFormula(0),   //: separated  - polynom for the regression
     120           0 :   fNParameters(0),           // number of local paramters to fit
     121           0 :   fLocalFitParam(0),         // local fit parameters 
     122           0 :   fLocalFitQuality(0),         // local fit quality
     123           0 :   fLocalFitCovar(0),          // local fit covariance matrix
     124           0 :   fLocalRobustStat(0),         // local robust statistic
     125           0 :   fBinIndex(0),                  //[fNParameters] working arrays current bin index
     126           0 :   fBinCenter(0),                 //[fNParameters] working current local variables - bin center
     127           0 :   fBinDelta(0),                  //[fNParameters] working current local variables - bin delta
     128           0 :   fBinWidth(0),                  //[fNParameters] working current local variables - bin delta
     129           0 :   fUseBinNorm(kFALSE)            //  switch make polynom  in units of bins (kTRUE)  or  in natural units (kFALSE)
     130           0 : {
     131           0 : }
     132             : 
     133           0 : AliNDLocalRegression::~AliNDLocalRegression(){
     134             :   //
     135             :   // destructor
     136             :   //
     137           0 :   if (fHistPoints) delete fHistPoints; 
     138           0 :   if (fStreamer)   delete fStreamer;
     139             :   //  fInputTree(0),             //! input tree - object is not owner
     140           0 :   delete fFormulaVal;            // value:err  definition formula
     141           0 :   delete fSelection;             // point selector formula
     142           0 :   delete fFormulaVar;            //: separated variable   definition formula
     143           0 :   delete fKernelWidthFormula;    //: separated  - kernel width for the regression
     144           0 :   delete fPolDimensionFormula;   //: separated  - polynom for the regression
     145             :   //
     146           0 :   if (fLocalFitParam) fLocalFitParam->Delete();
     147           0 :   if (fLocalFitQuality) fLocalFitQuality->Delete();
     148           0 :   if (fLocalFitCovar) fLocalFitCovar->Delete();
     149           0 :   delete fLocalFitParam;         // local fit parameters 
     150           0 :   delete fLocalFitQuality;       // local fit quality
     151           0 :   delete fLocalFitCovar;         // local fit covariance matrix
     152             :   //
     153           0 :   delete fLocalRobustStat;
     154             :   //
     155           0 :   delete[] fBinIndex;
     156           0 :   delete[] fBinCenter;
     157           0 :   delete[] fBinDelta;
     158           0 : }
     159             : 
     160             : void AliNDLocalRegression::SetHistogram(THn* histo ){
     161             :   //
     162             :   // Setup the local regression ayout according THn hitogram binning
     163             :   //
     164           0 :   if (fHistPoints!=0){
     165           0 :     AliError("Hostogram initialized\n");
     166           0 :     return ;
     167             :   }
     168           0 :   fHistPoints=histo;
     169           0 :   fLocalFitParam = new TObjArray(fHistPoints->GetNbins());
     170           0 :   fLocalFitParam->SetOwner(kTRUE);
     171           0 :   fLocalFitQuality = new TObjArray(fHistPoints->GetNbins());
     172           0 :   fLocalFitQuality->SetOwner(kTRUE);
     173           0 :   fLocalFitCovar = new TObjArray(fHistPoints->GetNbins());
     174           0 :   fLocalFitCovar->SetOwner(kTRUE);
     175             :   
     176             :   //
     177             :   // Check histogram
     178             :   //
     179           0 :   Int_t ndim = histo->GetNdimensions();
     180             :   Bool_t isOK=kTRUE;
     181           0 :   for (Int_t idim=0; idim<ndim; idim++){
     182           0 :     TAxis * axis = histo->GetAxis(idim);
     183           0 :     if (axis->GetNbins()<2) {
     184           0 :       AliError(TString::Format("Invalid binning nbins<2 %d",  axis->GetNbins()).Data());
     185           0 :     }
     186           0 :     if (axis->GetXmin()>=axis->GetXmax()) {
     187           0 :       AliError(TString::Format("Invalid range <%f,%f", axis->GetXmin(),axis->GetXmax()).Data());
     188           0 :     }    
     189             :   }
     190             : 
     191             : 
     192           0 : }
     193             : void  AliNDLocalRegression::SetCuts(Double_t nSigma, Double_t robustFraction, Int_t estimator){
     194             :   //
     195             :   //
     196             :   //
     197           0 :   fRobustFractionLTS=robustFraction;    //  fraction of data used for the robust mean and robust rms estimator (LTS https://en.wikipedia.org/wiki/Least_trimmed_squares)
     198           0 :   fRobustRMSLTSCut=nSigma;              //  cut on the robust RMS  |value-localmean|<fRobustRMSLTSCut*localRMS
     199           0 :   fCutType=estimator;                   //  type of the cut 0- no cut 1-cut localmean=median, 2-cut localmen=rosbut mean 
     200             : 
     201           0 : }
     202             : 
     203             : Bool_t    AliNDLocalRegression::CleanCovariance(){
     204             :   //
     205             :   //  Clean covariance matrix if not needed anymore
     206             :   //
     207           0 :   if (fLocalFitCovar) delete fLocalFitCovar;
     208           0 :   fLocalFitCovar=0;
     209           0 : };
     210             : 
     211             : 
     212             : Bool_t AliNDLocalRegression::MakeFit(TTree * tree , const char* formulaVal, const char * formulaVar, const char*selection, const char * formulaKernel, const char * dimensionFormula, Double_t weightCut, Int_t entries, Bool_t useBinNorm){
     213             :   //
     214             :   //  Make a local fit in grid as specified by the input THn histogram
     215             :   //  Histogram has to be set before invocation of method
     216             :   //
     217             :   //  Output:
     218             :   //    array of fit parameters and covariance matrices  
     219             :   //  
     220             :   //  Input Parameters:
     221             :   //   tree        - input tree
     222             :   //   formulaVal  - : separated variable:error string
     223             :   //   formulaVar  - : separate varaible list
     224             :   //   selection   - selection (cut) for TTreeDraw
     225             :   //   kernelWidth - : separated list of width of kernel for local fitting
     226             :   //   dimenstionFormula - dummy for the moment
     227             :   //
     228             :   //Algorithm:
     229             :   //   1.) Check consistency of input data
     230             :   //
     231             :   //   2.) Cache input data from tree to the array of vector TVectorD
     232             :   //
     233             :   //   3.) Calculate robust local mean and robust local RMS in case outlier removal algorithm specified
     234             :   // 
     235             :   //   4.) Make local fit
     236             :   //
     237             :   //  const Double_t kEpsilon=1e-6;
     238             :   const Int_t kMaxDim=100;
     239           0 :   Int_t binRange[kMaxDim]={0};
     240           0 :   Double_t nchi2Cut=-2*TMath::Log(weightCut); // transform probability to nsigma cut 
     241           0 :   if (fHistPoints==NULL){
     242           0 :     AliError("ND histogram not initialized\n");
     243           0 :     return kFALSE;
     244             :   }
     245           0 :   if (tree==NULL || tree->GetEntries()==0){
     246           0 :     AliError("Empty tree\n");
     247           0 :     return kFALSE;
     248             :   }
     249           0 :   if (formulaVar==NULL || formulaVar==0) {
     250           0 :     AliError("Empty variable list\n");
     251           0 :     return kFALSE;
     252             :   }
     253           0 :   if (formulaKernel==NULL) {
     254           0 :     AliError("Kernel width not specified\n");
     255           0 :     return kFALSE;
     256             :   }
     257           0 :   fUseBinNorm=useBinNorm;
     258             :   //  
     259           0 :   fInputTree= tree;  // should be better TRef?
     260           0 :   fFormulaVal           = new TObjString(formulaVal);
     261           0 :   fFormulaVar           = new TObjString(formulaVar);
     262           0 :   fSelection            = new TObjString(selection);
     263           0 :   fKernelWidthFormula   = new TObjString(formulaKernel);
     264           0 :   fPolDimensionFormula  = new TObjString(dimensionFormula);
     265           0 :   TObjArray * arrayFormulaVar=fFormulaVar->String().Tokenize(":");
     266           0 :   Int_t nvarFormula = arrayFormulaVar->GetEntries();
     267           0 :   if (nvarFormula!=fHistPoints->GetNdimensions()){
     268           0 :     AliError("Histogram/points mismatch\n");
     269           0 :     return kFALSE;
     270             :   }
     271           0 :   TObjArray * arrayKernel=fKernelWidthFormula->String().Tokenize(":");
     272           0 :   Int_t nwidthFormula = arrayKernel->GetEntries();
     273           0 :   if (nvarFormula!=nwidthFormula){
     274           0 :     delete arrayKernel;
     275           0 :     delete arrayFormulaVar;
     276           0 :     AliError("Variable/Kernel mismath\n");
     277           0 :     return kFALSE;
     278             :   }
     279           0 :   fNParameters=nvarFormula;
     280             :   //
     281             :   // 2.) Load input data
     282             :   //
     283             :   //
     284           0 :   Int_t entriesVal = tree->Draw(formulaVal,selection,"goffpara",entries);
     285           0 :   if (entriesVal==0) {
     286           0 :     AliError(TString::Format("Empty point list\t%s\t%s\n",formulaVal,selection).Data());
     287           0 :     return kFALSE; 
     288             :   }
     289           0 :   if (tree->GetVal(0)==NULL || (tree->GetVal(1)==NULL)){
     290           0 :     AliError(TString::Format("Wrong selection\t%s\t%s\n",formulaVar,selection).Data());
     291           0 :     return kFALSE; 
     292             :   }
     293           0 :   TVectorD values(entriesVal,tree->GetVal(0));
     294           0 :   TVectorD errors(entriesVal,tree->GetVal(1));
     295           0 :   Double_t *pvalues = values.GetMatrixArray();
     296           0 :   Double_t *perrors = errors.GetMatrixArray();
     297             : 
     298             : 
     299             :   // 2.b) variables
     300           0 :   TObjArray pointArray(fNParameters);
     301           0 :   Int_t entriesVar = tree->Draw(formulaVar,selection,"goffpara",entries);
     302           0 :   if (entriesVal!=entriesVar) {
     303           0 :     AliError(TString::Format("Wrong selection\t%s\t%s\n",formulaVar,selection).Data());
     304           0 :     return kFALSE; 
     305             :   }
     306           0 :   for (Int_t ipar=0; ipar<fNParameters; ipar++) pointArray.AddAt(new TVectorD(entriesVar,tree->GetVal(ipar)),ipar);
     307             :   // 2.c) kernel array 
     308           0 :   TObjArray kernelArrayI2(fNParameters);
     309           0 :   Int_t entriesKernel = tree->Draw(formulaKernel,selection,"goffpara",entries);
     310           0 :   for (Int_t ipar=0; ipar<fNParameters; ipar++) {
     311           0 :     TVectorD* vdI2 = new TVectorD(entriesVar,tree->GetVal(ipar));
     312           0 :     for (int k=entriesVar;k--;) { // to speed up, precalculate inverse squared
     313           0 :       double kv = (*vdI2)[k];
     314           0 :       if (TMath::Abs(kv)<1e-12) AliFatalClassF("Kernel width=%f for entry %d of par:%d",kv,k,ipar);
     315           0 :       (*vdI2)[k] = 1./(kv*kv);
     316             :     }
     317           0 :     kernelArrayI2.AddAt(vdI2,ipar);
     318             :   }
     319             :   //
     320           0 :   Double_t *pvecVar[kMaxDim]={0};
     321           0 :   Double_t *pvecKernelI2[kMaxDim]={0};
     322           0 :   for (Int_t idim=0; idim<pointArray.GetEntries(); idim++){
     323           0 :     pvecVar[idim]=((TVectorD*)(pointArray.At(idim)))->GetMatrixArray();
     324           0 :     pvecKernelI2[idim]=((TVectorD*)(kernelArrayI2.At(idim)))->GetMatrixArray();
     325           0 :     binRange[idim]=fHistPoints->GetAxis(idim)->GetNbins();
     326             :   }
     327             :   //
     328             :   //
     329             :   //
     330           0 :   Int_t nbins = fHistPoints->GetNbins();
     331           0 :   fBinIndex   = new Int_t[fHistPoints->GetNdimensions()];
     332           0 :   fBinCenter  = new Double_t[fHistPoints->GetNdimensions()];
     333           0 :   fBinDelta   = new Double_t[fHistPoints->GetNdimensions()];
     334           0 :   fBinWidth   = new Double_t[fHistPoints->GetNdimensions()];
     335             : 
     336             :   //
     337             :   // 3.) 
     338             :   //
     339           0 :   if (fCutType>0 && fRobustRMSLTSCut>0){
     340           0 :     MakeRobustStatistic(values, errors,  pointArray, kernelArrayI2, weightCut, fRobustFractionLTS);
     341             :   }
     342             :   //
     343             : 
     344             :   // 4.) Make local fits
     345             :   //
     346             : 
     347           0 :   Double_t *binHypFit  = new Double_t[2*fHistPoints->GetNdimensions()];
     348             :   //
     349           0 :   TLinearFitter fitter(1+2*fNParameters,TString::Format("hyp%d",2*fNParameters).Data());
     350           0 :   for (Int_t ibin=0; ibin<nbins; ibin++) {
     351           0 :     fHistPoints->GetBinContent(ibin,fBinIndex); 
     352             :     Bool_t isUnderFlowBin=kFALSE;
     353             :     Bool_t isOverFlowBin=kFALSE;
     354           0 :     for (Int_t idim=0; idim<fNParameters; idim++) {      
     355           0 :       if (fBinIndex[idim]==0) isUnderFlowBin=kTRUE;
     356           0 :       if (fBinIndex[idim]>binRange[idim]) isOverFlowBin=kTRUE;      
     357           0 :       fBinCenter[idim]=fHistPoints->GetAxis(idim)->GetBinCenter(fBinIndex[idim]);
     358           0 :       fBinWidth[idim]=fHistPoints->GetAxis(idim)->GetBinWidth(fBinIndex[idim]);
     359             :     }
     360           0 :     if (isUnderFlowBin || isOverFlowBin) continue;
     361           0 :     fitter.ClearPoints();
     362             :     // add fit points    
     363           0 :     for (Int_t ipoint=0; ipoint<entriesVal; ipoint++){
     364             :       Double_t sumChi2=0;
     365           0 :       if (fCutType>0 && fRobustRMSLTSCut>0){
     366           0 :         Double_t localRMS=(*fLocalRobustStat)(ibin,2);
     367           0 :         Double_t localMean=(*fLocalRobustStat)(ibin,1);
     368           0 :         Double_t localMedian=(*fLocalRobustStat)(ibin,0);
     369           0 :         if (fCutType==1){
     370           0 :           if (TMath::Abs(pvalues[ipoint]-localMedian)>fRobustRMSLTSCut*localRMS) continue;
     371             :         }
     372           0 :         if (fCutType==2){
     373           0 :           if (TMath::Abs(pvalues[ipoint]-localMean)>fRobustRMSLTSCut*localRMS) continue;
     374             :         }
     375           0 :       }
     376           0 :       for (Int_t idim=0; idim<fNParameters; idim++){
     377             :         //TVectorD &vecVar=*((TVectorD*)(pointArray.UncheckedAt(idim)));
     378             :         //TVectorD &vecKernel=*((TVectorD*)(kernelArray.UncheckedAt(idim)));
     379           0 :         fBinDelta[idim]=pvecVar[idim][ipoint]-fBinCenter[idim];         
     380           0 :         sumChi2+= (fBinDelta[idim]*fBinDelta[idim]) * pvecKernelI2[idim][ipoint];
     381           0 :         if (sumChi2>nchi2Cut) break;//continue;
     382           0 :         if (fUseBinNorm){
     383           0 :           binHypFit[2*idim]=fBinDelta[idim]/fBinWidth[idim];
     384           0 :           binHypFit[2*idim+1]=binHypFit[2*idim]*binHypFit[2*idim];
     385           0 :         }else{
     386           0 :           binHypFit[2*idim]=fBinDelta[idim];
     387           0 :           binHypFit[2*idim+1]=fBinDelta[idim]*fBinDelta[idim];
     388             :         }
     389             :       }      
     390           0 :       if (sumChi2>nchi2Cut) continue;
     391             :       //      Double_t weight=TMath::Exp(-sumChi2*0.5);
     392             :       //      fitter.AddPoint(binHypFit,pvalues[ipoint], perrors[ipoint]/weight);
     393           0 :       Double_t weightI=TMath::Exp(sumChi2*0.5);
     394           0 :       fitter.AddPoint(binHypFit,pvalues[ipoint], perrors[ipoint]*weightI);
     395           0 :     }
     396           0 :     TVectorD * fitParam=new TVectorD(fNParameters*2+1);
     397           0 :     TVectorD * fitQuality=new TVectorD(3);
     398           0 :     TMatrixD * fitCovar=new TMatrixD(fNParameters*2+1,fNParameters*2+1);
     399           0 :     Double_t normRMS=0;
     400           0 :     Int_t nBinPoints=fitter.GetNpoints();
     401           0 :     Bool_t fitOK=kFALSE;
     402           0 :     (*fitQuality)[0]=0;
     403           0 :     (*fitQuality)[1]=0;
     404           0 :     (*fitQuality)[2]=0;
     405             : 
     406           0 :     if (fitter.GetNpoints()>fNParameters*2+2){
     407           0 :       fitOK = (fitter.Eval()==0);
     408           0 :       if (fitOK){
     409           0 :         normRMS=fitter.GetChisquare()/(fitter.GetNpoints()-fitter.GetNumberFreeParameters());
     410           0 :         fitter.GetParameters(*fitParam);
     411           0 :         fitter.GetCovarianceMatrix(*fitCovar);
     412           0 :         (*fitQuality)[0]=nBinPoints;
     413           0 :         (*fitQuality)[1]=normRMS;    
     414           0 :         (*fitQuality)[2]=ibin;          
     415           0 :         fLocalFitParam->AddAt(fitParam,ibin);
     416           0 :         fLocalFitQuality->AddAt(fitQuality,ibin);
     417           0 :         fLocalFitCovar->AddAt(fitCovar,ibin);      
     418             :       }
     419             :     }
     420           0 :     if (fStreamer){
     421           0 :       TVectorD pfBinCenter(fNParameters, fBinCenter);
     422           0 :       Double_t median=0,mean=0,rms=0;
     423           0 :       if (fLocalRobustStat){
     424           0 :         median=(*fLocalRobustStat)(ibin,0);
     425           0 :         mean=(*fLocalRobustStat)(ibin,1);
     426           0 :         rms=(*fLocalRobustStat)(ibin,2);
     427           0 :       }
     428           0 :       (*fStreamer)<<"localFit"<<
     429           0 :         "ibin="<<ibin<<                // bin index
     430           0 :         "fitOK="<<fitOK<< 
     431           0 :         "localMedian="<<median<<
     432           0 :         "localMean="<<mean<<
     433           0 :         "localRMS="<<rms<<
     434           0 :         "nBinPoints="<<nBinPoints<<    // center of the bin
     435           0 :         "binCenter.="<<&pfBinCenter<<  // 
     436           0 :         "normRMS="<<normRMS<<          
     437           0 :         "fitParam.="<<fitParam<<
     438           0 :         "fitCovar.="<<fitCovar<<
     439           0 :         "fitOK="<<fitOK<<
     440             :         "\n";
     441           0 :     }
     442           0 :     if (!fitOK) { // avoid memory leak for failed fits
     443           0 :       delete fitParam;
     444           0 :       delete fitQuality;
     445           0 :       delete fitCovar;
     446             :     }
     447           0 :   }
     448             : 
     449             :   return kTRUE;
     450           0 : }
     451             : 
     452             : 
     453             : Bool_t  AliNDLocalRegression::MakeRobustStatistic(TVectorD &values,TVectorD &errors,  TObjArray &pointArray,  TObjArray &kernelArrayI2, Double_t weightCut, Double_t robustFraction){
     454             :   //
     455             :   // Calculate robust statistic information
     456             :   // use raw array to make faster calcualtion
     457             :   const Int_t kMaxDim=100;
     458           0 :   Double_t *pvalues=values.GetMatrixArray();
     459           0 :   Double_t *pvecVar[kMaxDim]={0};
     460           0 :   Double_t *pvecKernelI2[kMaxDim]={0};
     461           0 :   for (Int_t idim=0; idim<pointArray.GetEntries(); idim++){
     462           0 :     pvecVar[idim]=((TVectorD*)(pointArray.At(idim)))->GetMatrixArray();
     463           0 :     pvecKernelI2[idim]=((TVectorD*)(kernelArrayI2.At(idim)))->GetMatrixArray();
     464             :     
     465             :   }
     466             : 
     467             : 
     468           0 :   Double_t nchi2Cut=-2*TMath::Log(weightCut); // transform probability to nsigma cut 
     469           0 :   if (robustFraction>1) robustFraction=1;
     470             : 
     471           0 :   Int_t nbins = fHistPoints->GetNbins();    // 
     472           0 :   Int_t npoints= values.GetNrows();         // number of points for fit
     473           0 :   if (fLocalRobustStat){
     474           0 :     delete fLocalRobustStat;
     475             :   }
     476           0 :   fLocalRobustStat=new TMatrixD(nbins,3);
     477             : 
     478           0 :   TVectorD valueLocal(npoints);
     479           0 :   for (Int_t ibin=0; ibin<nbins; ibin++){
     480           0 :     fHistPoints->GetBinContent(ibin,fBinIndex); // 
     481           0 :     for (Int_t idim=0; idim<fNParameters; idim++){
     482           0 :       fBinCenter[idim]=fHistPoints->GetAxis(idim)->GetBinCenter(fBinIndex[idim]);
     483           0 :       fBinWidth[idim]=fHistPoints->GetAxis(idim)->GetBinWidth(fBinIndex[idim]);
     484             :     }
     485             :     Int_t indexLocal=0;
     486           0 :     for (Int_t ipoint=0; ipoint<npoints; ipoint++){
     487             :       Double_t sumChi2=0;
     488           0 :       for (Int_t idim=0; idim<fNParameters; idim++){
     489             :         //TVectorD &vecVar=*((TVectorD*)(pointArray.UncheckedAt(idim)));
     490             :         //TVectorD &vecKernel=*((TVectorD*)(kernelArray.UncheckedAt(idim)));
     491           0 :         fBinDelta[idim]=pvecVar[idim][ipoint]-fBinCenter[idim];         
     492           0 :         sumChi2+= (fBinDelta[idim]*fBinDelta[idim]) * pvecKernelI2[idim][ipoint];
     493           0 :         if (sumChi2>nchi2Cut) break; //continue;
     494             :       }      
     495           0 :       if (sumChi2>nchi2Cut) continue;
     496           0 :       valueLocal[indexLocal]=pvalues[ipoint];
     497           0 :       indexLocal++;
     498           0 :     }
     499           0 :     Double_t median=0,meanX=0, rmsX=0;
     500           0 :     if (indexLocal*robustFraction-1>3){
     501           0 :       median=TMath::Median(indexLocal,valueLocal.GetMatrixArray());
     502           0 :       AliMathBase::EvaluateUni(indexLocal,valueLocal.GetMatrixArray(), meanX,rmsX, indexLocal*robustFraction-1);
     503             :     }
     504           0 :     (*fLocalRobustStat)(ibin,0)=median;
     505           0 :     (*fLocalRobustStat)(ibin,1)=meanX;
     506           0 :     (*fLocalRobustStat)(ibin,2)=rmsX;
     507           0 :   }
     508           0 : }
     509             : 
     510             : 
     511             : 
     512             : Double_t AliNDLocalRegression::Eval(Double_t *point ){
     513             :   //
     514             :   //
     515             :   // 
     516             :   const Double_t almost0=0.00000001;
     517             :   // backward compatibility
     518           0 :   if(!fBinWidth){
     519           0 :     fBinWidth   = new Double_t[fHistPoints->GetNdimensions()];
     520           0 :   }
     521             : 
     522           0 :   for (Int_t iDim=0; iDim<fNParameters; iDim++){
     523           0 :     if (point[iDim]<= fHistPoints->GetAxis(iDim)->GetXmin())   point[iDim]=fHistPoints->GetAxis(iDim)->GetXmin()+almost0*fHistPoints->GetAxis(iDim)->GetBinWidth(0);
     524           0 :     if (point[iDim]>= fHistPoints->GetAxis(iDim)->GetXmax())   point[iDim]=fHistPoints->GetAxis(iDim)->GetXmax()-almost0*fHistPoints->GetAxis(iDim)->GetBinWidth(0);
     525             :   }
     526             : 
     527           0 :   Int_t ibin = fHistPoints->GetBin(point);
     528             :   Bool_t rangeOK=kTRUE;
     529           0 :   if (ibin>=fLocalFitParam->GetEntriesFast() ){
     530             :     rangeOK=kFALSE;
     531           0 :   }else{
     532           0 :     if (fLocalFitParam->UncheckedAt(ibin)==NULL) {
     533             :       rangeOK=kFALSE; 
     534           0 :     }
     535             :   }
     536           0 :   if (!rangeOK) return 0;
     537             : 
     538           0 :   fHistPoints->GetBinContent(ibin,fBinIndex); 
     539           0 :   for (Int_t idim=0; idim<fNParameters; idim++){
     540           0 :     fBinCenter[idim]=fHistPoints->GetAxis(idim)->GetBinCenter(fBinIndex[idim]);
     541           0 :     fBinWidth[idim]=fHistPoints->GetAxis(idim)->GetBinWidth(fBinIndex[idim]);
     542             :   } 
     543           0 :   TVectorD &vecParam = *((TVectorD*)fLocalFitParam->At(ibin));
     544           0 :   Double_t value=vecParam[0];
     545           0 :   if (!rangeOK) return value;
     546           0 :   if (fUseBinNorm) {
     547           0 :     for (Int_t ipar=0; ipar<fNParameters; ipar++){
     548           0 :       Double_t delta=(point[ipar]-fBinCenter[ipar])/fBinWidth[ipar];
     549           0 :       value+=(vecParam[1+2*ipar]+vecParam[1+2*ipar+1]*delta)*delta;
     550             :     }
     551           0 :   } else {
     552           0 :     for (Int_t ipar=0; ipar<fNParameters; ipar++){
     553           0 :       Double_t delta=(point[ipar]-fBinCenter[ipar]);
     554           0 :       value+=(vecParam[1+2*ipar]+vecParam[1+2*ipar+1]*delta)*delta;
     555             :     }
     556             :   }
     557           0 :   return value;
     558           0 : }
     559             : 
     560             : Double_t AliNDLocalRegression::EvalError(Double_t *point ){
     561             :   //
     562             :   //
     563             :   // 
     564           0 :   if (fLocalFitCovar==NULL) {
     565           0 :     ::Error("AliNDLocalRegression::EvalError", "Covariance matrix not available");
     566           0 :     return 0 ;
     567             :   }
     568           0 :   for (Int_t iDim=0; iDim<fNParameters; iDim++){
     569           0 :     if (point[iDim]< fHistPoints->GetAxis(iDim)->GetXmin())   point[iDim]=fHistPoints->GetAxis(iDim)->GetXmin();
     570           0 :     if (point[iDim]> fHistPoints->GetAxis(iDim)->GetXmax())   point[iDim]=fHistPoints->GetAxis(iDim)->GetXmax();
     571             :   }
     572             : 
     573           0 :   Int_t ibin = fHistPoints->GetBin(point); 
     574           0 :   if (fLocalFitParam->At(ibin)==NULL) return 0;
     575           0 :   fHistPoints->GetBinContent(ibin,fBinIndex); 
     576           0 :   for (Int_t idim=0; idim<fNParameters; idim++){
     577           0 :     fBinCenter[idim]=fHistPoints->GetAxis(idim)->GetBinCenter(fBinIndex[idim]);
     578             :   } 
     579           0 :   TMatrixD &vecCovar = *((TMatrixD*)fLocalFitCovar->At(ibin));
     580             :   //TVectorD &vecQuality = *((TVectorD*)fLocalFitQuality->At(ibin));
     581           0 :   Double_t value=TMath::Sqrt(vecCovar(0,0));  // fill covariance to be used 
     582             :   return value;
     583           0 : }
     584             : 
     585             : Bool_t AliNDLocalRegression::Derivative(Double_t *point, Double_t *d)
     586             : {
     587             :   // fill d by partial derivatives
     588             :   //
     589             :   const Double_t almost0=0.00000001;
     590           0 :   for (Int_t iDim=0; iDim<fNParameters; iDim++){
     591           0 :     const TAxis* ax = fHistPoints->GetAxis(iDim);
     592           0 :     if      (point[iDim]<=ax->GetXmin()) point[iDim] = ax->GetXmin()+almost0*ax->GetBinWidth(0);
     593           0 :     else if (point[iDim]>=ax->GetXmax()) point[iDim] = ax->GetXmax()-almost0*ax->GetBinWidth(0);
     594             :   }
     595             : 
     596           0 :   Int_t ibin = fHistPoints->GetBin(point);
     597           0 :   if (ibin>=fLocalFitParam->GetEntriesFast() ||
     598           0 :       !fLocalFitParam->UncheckedAt(ibin) ) return kFALSE;
     599             :   //
     600           0 :   fHistPoints->GetBinContent(ibin,fBinIndex); 
     601           0 :   for (Int_t idim=0; idim<fNParameters; idim++){
     602           0 :     const TAxis* ax = fHistPoints->GetAxis(idim);
     603           0 :     fBinCenter[idim] = ax->GetBinCenter(fBinIndex[idim]);
     604           0 :     fBinWidth[idim] = ax->GetBinWidth(fBinIndex[idim]);
     605             :   } 
     606           0 :   TVectorD &vecParam = *((TVectorD*)fLocalFitParam->At(ibin));
     607             : 
     608           0 :   if (fUseBinNorm){
     609           0 :     for (Int_t ipar=0; ipar<fNParameters; ipar++){
     610           0 :       Double_t delta=(point[ipar]-fBinCenter[ipar])/fBinWidth[ipar];
     611           0 :       d[ipar] = vecParam[1+2*ipar] + 2.0*vecParam[1+2*ipar+1]*delta;
     612             :     }
     613           0 :   }else{
     614           0 :     for (Int_t ipar=0; ipar<fNParameters; ipar++){
     615           0 :       Double_t delta=(point[ipar]-fBinCenter[ipar]);
     616           0 :       d[ipar] = vecParam[1+2*ipar] + 2.0*vecParam[1+2*ipar+1]*delta;
     617             :     }
     618             :   }
     619             :   return kTRUE;
     620           0 : }
     621             : 
     622             : Bool_t AliNDLocalRegression::EvalAndDerivative(Double_t *point, Double_t &val, Double_t *d)
     623             : {
     624             :   // fill d by partial derivatives and calculate value in one go
     625             :   //
     626             :   const Double_t almost0=0.00000001;
     627           0 :   for (Int_t iDim=0; iDim<fNParameters; iDim++){
     628           0 :     const TAxis* ax = fHistPoints->GetAxis(iDim);
     629           0 :     if      (point[iDim]<=ax->GetXmin()) point[iDim] = ax->GetXmin()+almost0*ax->GetBinWidth(0);
     630           0 :     else if (point[iDim]>=ax->GetXmax()) point[iDim] = ax->GetXmax()-almost0*ax->GetBinWidth(0);
     631             :   }
     632           0 :   val = 0;
     633           0 :   Int_t ibin = fHistPoints->GetBin(point);
     634           0 :   if (ibin>=fLocalFitParam->GetEntriesFast() ||
     635           0 :       !fLocalFitParam->UncheckedAt(ibin) ) return kFALSE;
     636             :   //
     637           0 :   fHistPoints->GetBinContent(ibin,fBinIndex); 
     638           0 :   for (Int_t idim=0; idim<fNParameters; idim++){
     639           0 :     const TAxis* ax = fHistPoints->GetAxis(idim);
     640           0 :     fBinCenter[idim] = ax->GetBinCenter(fBinIndex[idim]);
     641           0 :     fBinWidth[idim] = ax->GetBinWidth(fBinIndex[idim]);
     642             :   } 
     643           0 :   TVectorD &vecParam = *((TVectorD*)fLocalFitParam->At(ibin));
     644             :   
     645           0 :   val = vecParam[0];
     646           0 :   if (fUseBinNorm){
     647           0 :     for (Int_t ipar=0; ipar<fNParameters; ipar++){
     648           0 :       Double_t delta=(point[ipar]-fBinCenter[ipar])/fBinWidth[ipar];
     649           0 :       d[ipar] = vecParam[1+2*ipar] + 2.0*vecParam[1+2*ipar+1]*delta;
     650           0 :       val += (vecParam[1+2*ipar]+vecParam[1+2*ipar+1]*delta)*delta;
     651             :     }
     652           0 :   } else {
     653           0 :     for (Int_t ipar=0; ipar<fNParameters; ipar++){
     654           0 :       Double_t delta=(point[ipar]-fBinCenter[ipar]);
     655           0 :       d[ipar] = vecParam[1+2*ipar] + 2.0*vecParam[1+2*ipar+1]*delta;
     656           0 :       val += (vecParam[1+2*ipar]+vecParam[1+2*ipar+1]*delta)*delta;
     657             :     }
     658             :   }
     659             :   return kTRUE;
     660           0 : }
     661             : 
     662             : 
     663             : Int_t  AliNDLocalRegression::GetVisualCorrectionIndex(const char *corName){
     664             :   //
     665           0 :   return TMath::Hash(corName)%1000000;
     666             : }
     667             : 
     668             :     
     669             : void AliNDLocalRegression::AddVisualCorrection(AliNDLocalRegression* corr, Int_t position){
     670             :   /// make correction available for visualization using
     671             :   /// TFormula, TFX and TTree::Draw
     672             :   /// important in order to check corrections and also compute dervied variables
     673             :   /// e.g correction partial derivatives
     674             :   ///
     675             :   /// NOTE - class is not owner of correction
     676           0 :   if (position==0) {
     677           0 :     position=GetVisualCorrectionIndex(corr->GetName());
     678           0 :   }
     679             :   
     680           0 :   if (!fgVisualCorrection) fgVisualCorrection=new TObjArray(1000000);
     681           0 :   if (position>=fgVisualCorrection->GetEntriesFast())
     682           0 :     fgVisualCorrection->Expand((position+10)*2);
     683           0 :   if (fgVisualCorrection->At(position)!=NULL){
     684           0 :     ::Error("AliNDLocalRegression::AddVisualCorrection","Correction %d already defined Old: %s New: %s",position,fgVisualCorrection->At(position)->GetName(), corr->GetName());
     685           0 :   }
     686           0 :   fgVisualCorrection->AddAt(corr, position);
     687           0 : }
     688             : 
     689             : AliNDLocalRegression* AliNDLocalRegression::GetVisualCorrection(Int_t position) {
     690             :   /// Get visula correction registered at index=position  
     691           0 :   return fgVisualCorrection? (AliNDLocalRegression*)fgVisualCorrection->At(position):0;
     692             : }
     693             : 
     694             : Double_t AliNDLocalRegression::GetCorrND(Double_t index, Double_t par0){
     695             :   //
     696             :   //
     697           0 :   AliNDLocalRegression *corr = (AliNDLocalRegression*)fgVisualCorrection->At(index);
     698           0 :   if (!corr) return 0;
     699           0 :   return corr->Eval(&par0);
     700           0 : }
     701             : 
     702             : Double_t AliNDLocalRegression::GetCorrNDError(Double_t index, Double_t par0){
     703             :   //
     704             :   //
     705           0 :   AliNDLocalRegression *corr = (AliNDLocalRegression*)fgVisualCorrection->At(index);
     706           0 :   if (!corr) return 0;
     707           0 :   return corr->EvalError(&par0);
     708           0 : }
     709             : 
     710             : Double_t AliNDLocalRegression::GetCorrND(Double_t index, Double_t par0, Double_t par1){
     711             :   //
     712             :   //
     713           0 :   AliNDLocalRegression *corr = (AliNDLocalRegression*)fgVisualCorrection->At(index);
     714           0 :   if (!corr) return 0;
     715           0 :   Double_t par[2]={par0,par1};
     716           0 :   return corr->Eval(par);
     717           0 : }
     718             : Double_t AliNDLocalRegression::GetCorrNDError(Double_t index, Double_t par0, Double_t par1){
     719             :   //
     720             :   //
     721           0 :   AliNDLocalRegression *corr = (AliNDLocalRegression*)fgVisualCorrection->At(index);
     722           0 :   if (!corr) return 0;
     723           0 :   Double_t par[2]={par0,par1};
     724           0 :   return corr->EvalError(par);
     725           0 : }
     726             : 
     727             : Double_t AliNDLocalRegression::GetCorrND(Double_t index, Double_t par0, Double_t par1, Double_t par2){
     728             :   //
     729             :   //
     730           0 :   AliNDLocalRegression *corr = (AliNDLocalRegression*)fgVisualCorrection->At(index);
     731           0 :   if (!corr) return 0;
     732           0 :   Double_t par[3]={par0,par1,par2};
     733           0 :   return corr->Eval(par);
     734           0 : }
     735             : 
     736             : Double_t AliNDLocalRegression::GetCorrNDError(Double_t index, Double_t par0, Double_t par1, Double_t par2){
     737             :   //
     738             :   //
     739           0 :   AliNDLocalRegression *corr = (AliNDLocalRegression*)fgVisualCorrection->At(index);
     740           0 :   if (!corr) return 0;
     741           0 :   Double_t par[3]={par0,par1,par2};
     742           0 :   return corr->EvalError(par);
     743           0 : }
     744             : 
     745             : 
     746             : 
     747             : Double_t AliNDLocalRegression::GetCorrND(Double_t index, Double_t par0, Double_t par1, Double_t par2, Double_t par3){
     748             :   //
     749             :   //
     750           0 :   AliNDLocalRegression *corr = (AliNDLocalRegression*)fgVisualCorrection->At(index);
     751           0 :   if (!corr) return 0;
     752           0 :   Double_t par[4]={par0,par1,par2,par3};
     753           0 :   return corr->Eval(par);
     754           0 : }
     755             : 
     756             : Double_t AliNDLocalRegression::GetCorrNDError(Double_t index, Double_t par0, Double_t par1, Double_t par2, Double_t par3){
     757             :   //
     758             :   //
     759           0 :   AliNDLocalRegression *corr = (AliNDLocalRegression*)fgVisualCorrection->At(index);
     760           0 :   if (!corr) return 0;
     761           0 :   Double_t par[4]={par0,par1,par2,par3};
     762           0 :   return corr->EvalError(par);
     763           0 : }
     764             : 
     765             : 
     766             : 
     767             : 
     768             : Bool_t AliNDLocalRegression::AddWeekConstrainsAtBoundaries(Int_t nDims, Int_t *indexes, Double_t *relWeight, TTreeSRedirector* pcstream, Bool_t useCommon){
     769             :    //
     770             :   // Adding week constrain AtBoundaries
     771             :   //
     772             :   //  Technique similar to "Kalman update" of measurement used at boundaries - https://en.wikipedia.org/wiki/Kalman_filter
     773             :   // 
     774             :   // 1.) Make backup of original parameters
     775             :   // 2.) Book Kalman matrices
     776             :   // 3.) Loop over all measurements bins and update mesurements -adding boundary measurements as additional measurement
     777             :   //     relWeight vector specify relative weight of such measurement  (err_i=sigma_i*refWeight_i) - not yet implemented
     778             :   // 4.) replace original parameters with constrained parameters
     779             :   //     procedure can be repeated 
     780             :   /*
     781             :     Input parameters example:
     782             :     nDims=2;
     783             :     Int_t indexes[2]={0,1};
     784             :     Double_t relWeight0[6]={1,1,1,1,1,1};
     785             :     Double_t relWeight1[6]={1,1,10,1,1,10};
     786             :     pcstream=new TTreeSRedirector("constrainStream.root","recreate");
     787             :     
     788             :     AliNDLocalRegression * regression0 = ( AliNDLocalRegression *)AliNDLocalRegression::GetVisualCorrections()->FindObject("pfitNDGaus0");
     789             :     AliNDLocalRegression * regression1 = ( AliNDLocalRegression *)AliNDLocalRegression::GetVisualCorrections()->FindObject("pfitNDGaus1");
     790             : 
     791             :     regressionUpdate0 = (AliNDLocalRegression *)regression0->Clone();
     792             :     regressionUpdate1 = (AliNDLocalRegression *)regression1->Clone();
     793             :     AddWeekConstrainsAtBoundaries( regressionUpdate0, nDims, indexes,relWeight0, pcstream);
     794             :     AddWeekConstrainsAtBoundaries( regressionUpdate0, nDims, indexes,relWeight0, pcstream);
     795             :     AddWeekConstrainsAtBoundaries( regressionUpdate0, nDims, indexes,relWeight0, pcstream);
     796             :     AddWeekConstrainsAtBoundaries( regressionUpdate0, nDims, indexes,relWeight0, pcstream);
     797             :     AddWeekConstrainsAtBoundaries( regressionUpdate1, nDims, indexes,relWeight1, pcstream);
     798             :     AddWeekConstrainsAtBoundaries( regressionUpdate1, nDims, indexes,relWeight1, pcstream);
     799             :     AddWeekConstrainsAtBoundaries( regressionUpdate1, nDims, indexes,relWeight1, pcstream);
     800             :     AddWeekConstrainsAtBoundaries( regressionUpdate1, nDims, indexes,relWeight1, pcstream);
     801             : 
     802             :     regressionUpdate0->SetName("pfitNDGaus0_Updated");
     803             :     regressionUpdate1->SetName("pfitNDGaus1_Updated");
     804             :     AliNDLocalRegression::AddVisualCorrection(regressionUpdate0);
     805             :     AliNDLocalRegression::AddVisualCorrection(regressionUpdate1);
     806             :     treeIn->SetAlias( regressionUpdate0->GetName(), TString::Format("AliNDLocalRegression::GetCorrND(%d,xyz0,xyz1+0)", regressionUpdate0->GetVisualCorrectionIndex()).Data());
     807             :      treeIn->SetAlias( regressionUpdate1->GetName(), TString::Format("AliNDLocalRegression::GetCorrND(%d,xyz0,xyz1+0)", regressionUpdate1->GetVisualCorrectionIndex()).Data());
     808             :     delete pcstream;
     809             : 
     810             : 
     811             :     TFile *f = TFile::Open("constrainStream.root")
     812             :    */
     813             :   const Double_t kScale=0.5;
     814             :   const Double_t singularity_tolerance = 1e-200;
     815           0 :   if (fLocalFitCovar==NULL) {
     816           0 :     ::Error("AliNDLocalRegression::EvalError", "Covariance matrix not available");
     817           0 :     return 0 ;
     818             :   }
     819             :   //
     820             :   // 1.)  Make backup of original parameters
     821             :   //
     822           0 :   const TObjArray *vecParamOrig    = fLocalFitParam;
     823             :   const TObjArray *vecCovarOrig    = fLocalFitCovar;
     824           0 :   TObjArray *vecParamUpdated = new TObjArray(fHistPoints->GetNbins());
     825           0 :   TObjArray *vecCovarUpdated = new TObjArray(fHistPoints->GetNbins());
     826             :   // 
     827             :   // 2.) Book local varaibles and Kalman matrices
     828             :   //  
     829           0 :   Int_t nParams= 1+2*fNParameters;
     830           0 :   Int_t nMeas= nDims*6; // update each dimension specified 2 ends 2 measurements (value and first derivative)
     831             :   
     832           0 :   TMatrixD matWeight(nParams,nParams);       // weight matrix for side param
     833           0 :   TMatrixD matCovarSide(nParams,nParams);    // reweighted covariance matrix for side parameters
     834             : 
     835           0 :   TMatrixD vecXk(nParams,1);           // X vector - parameter of the local fit at bin
     836           0 :   TMatrixD covXk(nParams,nParams);     // X covariance 
     837           0 :   TMatrixD matHk(nMeas,nParams);       // vector to mesurement (values at boundary of bin)
     838           0 :   TMatrixD measR(nMeas,nMeas);         // measurement error at boundary as provided by bin in local neigberhood 
     839           0 :   TMatrixD vecZk(nMeas,1);             // measurement at boundary 
     840             :   //
     841           0 :   TMatrixD measRBin(nMeas,nMeas);              // measurement error bin
     842           0 :   TMatrixD vecZkBin(nMeas,1);                  // measurement bin
     843           0 :   TMatrixD matrixTransformBin(nMeas, nParams);  // vector to measurement to calculate error matrix current bin
     844             :   //
     845           0 :   TMatrixD vecZkSide(3,1);                // measurement side
     846           0 :   TMatrixD matrixTransformSide(3,nParams);// vector to measurement to calculate error matrix side bin
     847             : 
     848             :   //
     849           0 :   TMatrixD vecYk(nMeas,1);          // Innovation or measurement residual
     850           0 :   TMatrixD matHkT(nParams,nMeas);
     851           0 :   TMatrixD matSk(nMeas,nMeas);    // Innovation (or residual) covariance
     852           0 :   TMatrixD matKk(nParams,nMeas);    // Optimal Kalman gain
     853           0 :   TMatrixD mat1(nParams,nParams);     // update covariance matrix
     854           0 :   TMatrixD covXk2(nParams,nParams);   // 
     855           0 :   TMatrixD covOut(nParams,nParams);   //
     856           0 :   mat1.UnitMatrix();
     857             :   //
     858             :   // 3.) Loop over all measurements bins and update mesurements -adding boundary measurements as additional measurement
     859             :   //     relWeight vector specify relative weight of such measurement  (err_i=sigma_i*refWeight_i
     860           0 :   const THn* his = GetHistogram();
     861           0 :   Int_t binIndex[999]={0};
     862           0 :   Int_t binIndexSide[999]={0};
     863           0 :   Int_t nbinsAxis[999]={0};
     864           0 :   Double_t binCenter[999]={0};
     865           0 :   Double_t binWidth[999]={0};
     866             : 
     867           0 :   if (relWeight!=NULL) for (Int_t iParam=0; iParam<nParams; iParam++){
     868             :     Int_t index=0;
     869           0 :     if (iParam<3)  index=iParam;
     870           0 :     if (iParam>=3) {
     871           0 :       Int_t dim=(iParam-3)/2;
     872           0 :       Int_t deriv=1+(iParam-3)%2;
     873           0 :       index=3*dim+deriv;
     874           0 :     }
     875           0 :     matWeight(iParam,iParam)=relWeight[index];
     876           0 :   }
     877             : 
     878             : 
     879           0 :   for (Int_t iDim=0; iDim<nDims; iDim++){nbinsAxis[iDim]=his->GetAxis(iDim)->GetNbins();}  
     880             :   //  Int_t nBins=fHistPoints->GetNbins();
     881           0 :   Int_t nBins=fLocalFitParam->GetSize();
     882           0 :   for (Int_t iBin=0; iBin<nBins; iBin++){   // loop over bins
     883           0 :     if (iBin%fgVerboseLevel==0) printf("%d\n",iBin);
     884             :     //
     885           0 :     his->GetBinContent(iBin,binIndex);
     886           0 :     for (Int_t iDim=0; iDim<nDims; iDim++) { // fill common info for bin of interest
     887           0 :       binCenter[iDim]= his->GetAxis(iDim)->GetBinCenter(binIndex[iDim]);
     888           0 :       binWidth[iDim] = his->GetAxis(iDim)->GetBinWidth(binIndex[iDim]);
     889             :     }
     890           0 :     if (fLocalFitParam->UncheckedAt(iBin)==NULL) continue;
     891           0 :     Double_t *vecParam0 = ((TVectorD*)(fLocalFitParam->UncheckedAt(iBin)))->GetMatrixArray();
     892           0 :     TMatrixD   matParam0(nParams,1, vecParam0);
     893           0 :     TMatrixD & matCovar0=*(((TMatrixD*)(fLocalFitCovar->UncheckedAt(iBin))));
     894           0 :     measR.Zero();
     895           0 :     vecZk.Zero();
     896           0 :     measRBin.Zero();
     897           0 :     vecZkBin.Zero();    
     898           0 :     matrixTransformBin.Zero();
     899           0 :     covXk=matCovar0;
     900           0 :     vecXk=matParam0;
     901             :     //
     902             :     //  neiborhood loop
     903           0 :     Int_t constCounter=0;
     904           0 :     Int_t constCounterDim[100]={0};
     905           0 :     for (Int_t iDim=0; iDim<nDims; iDim++){         // loop in n dim
     906           0 :       constCounterDim[iDim]=0;  // number of constraints per dimension
     907           0 :       for (Int_t iSide=-1; iSide<=1; iSide+=2){     // left right loop
     908           0 :         for (Int_t jDim=0; jDim<nDims; jDim++) binIndexSide[jDim]= binIndex[jDim];
     909           0 :         vecZkSide.Zero();
     910           0 :         matrixTransformSide.Zero();
     911             :         //
     912           0 :         binIndexSide[iDim]+=iSide;      
     913           0 :         if (binIndexSide[iDim]<0) binIndexSide[iDim]=0;
     914           0 :         if (binIndexSide[iDim]>his->GetAxis(iDim)->GetNbins())  binIndexSide[iDim]=his->GetAxis(iDim)->GetNbins();
     915           0 :         Bool_t isConst=binIndexSide[iDim]>0 &&binIndexSide[iDim]<=his->GetAxis(iDim)->GetNbins() && (fLocalFitParam)->UncheckedAt(his->GetBin(binIndexSide))!=NULL; 
     916           0 :         Int_t binSide=his->GetBin(binIndexSide);
     917           0 :         if (binSide>=nBins ) binIndexSide[iDim]=binIndex[iDim];
     918           0 :         if ((fLocalFitParam)->UncheckedAt(his->GetBin(binIndexSide))==NULL) binIndexSide[iDim]=binIndex[iDim];
     919           0 :         if (isConst)  {
     920           0 :           constCounter++;
     921           0 :           constCounterDim[iDim]++;
     922           0 :         }
     923           0 :         Double_t localCenter=his->GetAxis(iDim)->GetBinCenter(binIndex[iDim]);
     924           0 :         Double_t sideCenter= his->GetAxis(iDim)->GetBinCenter(binIndexSide[iDim]);
     925           0 :         Double_t position=   (iSide<0) ? his->GetAxis(iDim)->GetBinLowEdge(binIndex[iDim]) :  his->GetAxis(iDim)->GetBinUpEdge(binIndex[iDim]);
     926           0 :         Double_t* vecParamSide  = ((TVectorD*)(fLocalFitParam)->UncheckedAt(his->GetBin(binIndexSide)))->GetMatrixArray();
     927           0 :         TMatrixD   matParamSide(nParams,1, vecParamSide);
     928           0 :         if (relWeight==NULL){
     929           0 :           matCovarSide=*((TMatrixD*)(fLocalFitCovar->UncheckedAt(his->GetBin(binIndexSide))));
     930             :         }
     931           0 :         if (relWeight!=NULL){
     932           0 :           matCovarSide=TMatrixD( matWeight,TMatrixD::kMult,*((TMatrixD*)(fLocalFitCovar->UncheckedAt(his->GetBin(binIndexSide)))));
     933           0 :           matCovarSide*=matWeight;
     934             :         }
     935           0 :         if (!isConst) matCovarSide*=1000;
     936             :         //
     937           0 :         Double_t deltaLocal=(position-localCenter);
     938           0 :         Double_t deltaSide=(position-sideCenter);
     939           0 :         if (fUseBinNorm){
     940           0 :            deltaLocal/=fBinWidth[iDim];
     941           0 :            deltaSide/=fBinWidth[iDim];
     942           0 :         }
     943             :         //
     944           0 :         matrixTransformSide(0,0)=1;        matrixTransformSide(0,1+2*iDim)=deltaSide;      matrixTransformSide(0,1+2*iDim+1)=deltaSide*deltaSide;
     945           0 :         matrixTransformSide(1,1+2*iDim)=1;   matrixTransformSide(1,1+2*iDim+1)=2*deltaSide;
     946           0 :         matrixTransformSide(2,1+2*iDim+1)=2;
     947             :         //
     948           0 :         Int_t iMeas0=6*iDim+3*(iSide+1)/2;
     949           0 :         matrixTransformBin(iMeas0+0,0)=1;        matrixTransformBin(iMeas0+0,1+2*iDim)=deltaLocal;      matrixTransformBin(iMeas0+0,1+2*iDim+1)=deltaSide*deltaLocal;
     950           0 :         matrixTransformBin(iMeas0+1,1+2*iDim)=1;   matrixTransformBin(iMeas0+1,1+2*iDim+1)=2*deltaLocal;
     951           0 :         matrixTransformBin(iMeas0+2,1+2*iDim+1)=2;
     952             :         //
     953           0 :         for (Int_t iconst=0; iconst<3; iconst++){
     954           0 :           Int_t iMeas=iMeas0+iconst;
     955             :           Double_t localMeasurement=0;
     956             :           Double_t sideMeasurement=0;
     957           0 :           if (iconst==0){ // measurement - derivative 0
     958           0 :             localMeasurement=vecParam0[0]+deltaLocal*(vecParam0[1+2*iDim]+vecParam0[2+2*iDim]*deltaLocal);
     959           0 :             sideMeasurement=vecParamSide[0]+deltaSide*(vecParamSide[1+2*iDim]+vecParamSide[2+2*iDim]*deltaSide);
     960           0 :           }
     961           0 :           if (iconst==1){ // measurement -derivative 1
     962           0 :             localMeasurement=(vecParam0[1+2*iDim]+2*vecParam0[2+2*iDim]*deltaLocal);
     963           0 :             sideMeasurement=(vecParamSide[1+2*iDim]+2*vecParamSide[2+2*iDim]*deltaSide);
     964           0 :           }
     965           0 :           if (iconst==2){
     966           0 :             localMeasurement=2*vecParam0[2+2*iDim];
     967           0 :             sideMeasurement=2*vecParamSide[2+2*iDim];
     968           0 :           }
     969           0 :           vecZkSide(iconst,0)=sideMeasurement;
     970           0 :           vecZk(iMeas,0)=sideMeasurement;
     971           0 :           if (!isConst) vecZk(iMeas,0)=localMeasurement;
     972           0 :           vecZkBin(iMeas,0)=localMeasurement;
     973             :         }
     974           0 :         TMatrixD measRSide0(matrixTransformSide,TMatrixD::kMult,matCovarSide);   //     (iconst,iconst)  = (iconst,nParam)*(nParams,nParams)*(nParams,iconst
     975           0 :         TMatrixD matrixTransformSideT(TMatrixD::kTransposed ,matrixTransformSide);
     976           0 :         TMatrixD measRSide(measRSide0,TMatrixD::kMult,matrixTransformSideT);
     977             :         // update measutement Covariance matrix for given side
     978           0 :         for (Int_t iconst=0; iconst<3; iconst++)
     979           0 :           for (Int_t jconst=0; jconst<3; jconst++){
     980           0 :             measR(iMeas0+iconst,iMeas0+jconst)=measRSide(iconst,jconst);
     981             :           }
     982           0 :         if (pcstream){
     983           0 :           TMatrixD vecZkSideCheck(matrixTransformSide,TMatrixD::kMult,matParamSide);   //     (iconst,1)       = (iConst,nParam)*(nParams,1)    
     984             :           //
     985           0 :           (*pcstream)<<"checkSide"<<  // check agreement in 1D
     986           0 :             "iBin="<<iBin<<
     987           0 :             "iDim="<<iDim<<
     988           0 :             "iSide="<<iSide<<
     989           0 :             "vecZkSide.="<<&vecZkSide<<
     990           0 :             "vecZkSideCheck.="<<&vecZkSideCheck<<
     991           0 :             "measRSide.="<<&measRSide<<         
     992           0 :             "vecZk.="<<&vecZk<<
     993           0 :             "vecZkBin.="<<&vecZkBin<<     
     994             :             "\n";
     995           0 :         }       
     996           0 :       }
     997             :     }
     998             :     //
     999             :     //
    1000           0 :     TMatrixD measRBin0(matrixTransformBin,TMatrixD::kMult,matCovar0);   //     (iconst,iconst)  = (iconst,nParam)*(nParams,nParams)*(nParams,iconst
    1001           0 :     TMatrixD matrixTransformBinT(TMatrixD::kTransposed ,matrixTransformBin);
    1002           0 :     TMatrixD measRBin(measRBin0,TMatrixD::kMult,matrixTransformBinT);
    1003             :     //
    1004             :     // make Kalman Update of state vector with side mesurement
    1005             :     //
    1006           0 :     matHk=matrixTransformBin;
    1007           0 :     matHkT= matrixTransformBinT;
    1008             :     //
    1009           0 :     vecYk = vecZk-matHk*vecXk;                 // Innovation or measurement residual
    1010           0 :     if (useCommon) vecYk*=0.5;                 // in case we are using middle point use only half of delta
    1011           0 :     matSk = (matHk*(covXk*matHkT))+measR;      // Innovation (or residual) covariance
    1012           0 :     Double_t determinant=0;
    1013             :     Int_t constCounter2=0;
    1014           0 :     for (Int_t kDim=0; kDim<nDims; kDim++) if (constCounterDim[kDim]>0) constCounter2++;
    1015           0 :     if (constCounter2==nDims){
    1016           0 :       determinant= matSk.Determinant();
    1017           0 :     }
    1018           0 :     if (TMath::Abs(determinant)<singularity_tolerance ) {
    1019           0 :       vecParamUpdated->AddAt(new TVectorD(*((TVectorD*)(fLocalFitParam->UncheckedAt(iBin)))),iBin); 
    1020           0 :       vecCovarUpdated->AddAt(new TMatrixD(*((TMatrixD*)(fLocalFitCovar->UncheckedAt(iBin)))),iBin);
    1021           0 :       AliDebug(1,TString::Format("Update matrix not possible matSk.Determinant() too small, skipping bin %d",iBin).Data());
    1022             :     }else{
    1023           0 :       matSk.Invert();
    1024           0 :       matKk = (covXk*matHkT)*matSk;              //  Optimal Kalman gain
    1025           0 :       vecXk += matKk*vecYk;                      //  updated vector 
    1026           0 :       covXk2 = (mat1-(matKk*matHk));
    1027           0 :       covOut =  covXk2*covXk; 
    1028             :       //
    1029           0 :       vecParamUpdated->AddAt(new TVectorD(nParams,vecXk.GetMatrixArray()), iBin); 
    1030           0 :       vecCovarUpdated->AddAt(new TMatrixD(covOut), iBin); 
    1031             :     }
    1032           0 :     if (pcstream){
    1033           0 :       TMatrixD vecZkBinCheck(matrixTransformBin,TMatrixD::kMult,matParam0); 
    1034           0 :       TVectorD vecPos(nDims,binCenter);
    1035           0 :       TVectorD *vecXk0= (TVectorD*)(fLocalFitParam->UncheckedAt(iBin));
    1036           0 :       TMatrixD vecYkUpdated=(vecZk-matHk*vecXk);
    1037             :       //
    1038           0 :        (*pcstream)<<"checkBin"<<       // check agreement in all sides
    1039           0 :          "iBin="<<iBin<<               // bin index
    1040           0 :          "vecPos.="<<&vecPos<<         // bin position
    1041           0 :          "determinant="<<determinant<<  // determinant
    1042           0 :          "constCounter="<<constCounter<<
    1043           0 :          "constCounter2="<<constCounter<< 
    1044             :          //
    1045           0 :          "vecXk0.="<<vecXk0<<          // original parameter vector
    1046           0 :          "vecXk.="<<&vecXk<<           // parameter vector at bin after update
    1047           0 :          "covXk.="<<&covXk<<           // covaraince matrix before update
    1048           0 :          "covOut.="<<&covOut<<           // covaraince matrix after update
    1049           0 :          "vecZk.="<<&vecZk<<           // measurement vector - values according side measurement
    1050           0 :          "vecZkBin.="<<&vecZkBin<<     // expected vector according parameters for bin
    1051           0 :          "vecZkBinCheck.="<<&vecZkBinCheck<<   // expected vector according parameters at bin centers - crosscheck tracsrormation matrix
    1052           0 :          "measRBin.="<<&measRBin<<     // expected error of extrapolation
    1053           0 :          "measR.="<<&measR<<           // error of the side measurement
    1054             :          // tmporary data
    1055           0 :          "vecYk.="<<&vecYk<<           // delta vector (nparams)
    1056           0 :          "matSk.="<<&matSk<<           // inovation covariance (nMeas,nMeas)
    1057           0 :          "matKk.="<<&matKk<<          // optimal Kalman gain  (nParams,nMeas) 
    1058           0 :          "covXk2.="<<&covXk2<<         
    1059             :          //
    1060           0 :          "vecYkUpdated.="<<&vecYkUpdated<< // diff after kalman update
    1061             :          "\n";
    1062           0 :     }
    1063           0 :   } 
    1064             :   //
    1065             :   // 4.) replace original parameters with constrained parameters
    1066             :   //
    1067           0 :   fLocalFitParam= vecParamUpdated;
    1068           0 :   fLocalFitCovar= vecCovarUpdated;  
    1069             :   return 0;
    1070           0 : }
    1071             : 
    1072             : void AliNDLocalRegression::DumpToTree(Int_t nDiv,  TTreeStream & stream){
    1073             :   //
    1074             :   //
    1075             :   //
    1076             :   const Int_t kMaxDim=100;
    1077           0 :   Int_t nBins=fHistPoints->GetNbins();
    1078             :   
    1079           0 :   TVectorD binLowEdge(fNParameters);
    1080           0 :   TVectorD binLocal(fNParameters);
    1081           0 :   TVectorF binIndexF(fNParameters);
    1082           0 :   Double_t *pbinLowEdge= binLowEdge.GetMatrixArray();
    1083             :   //
    1084           0 :   for (Int_t iBin=0; iBin<nBins; iBin++){   // loop over bins
    1085           0 :     if (iBin%fgVerboseLevel==0) printf("%d\n",iBin);
    1086           0 :     fHistPoints->GetBinContent(iBin,fBinIndex);
    1087           0 :     for (Int_t iDim=0; iDim<fNParameters; iDim++) { // fill common info for bin of interest
    1088           0 :       binIndexF[iDim]=fBinIndex[iDim];
    1089           0 :       fBinCenter[iDim]= fHistPoints->GetAxis(iDim)->GetBinCenter(fBinIndex[iDim]);
    1090           0 :       binLowEdge[iDim]= fHistPoints->GetAxis(iDim)->GetBinLowEdge(fBinIndex[iDim]);
    1091           0 :       fBinDelta[iDim] = fHistPoints->GetAxis(iDim)->GetBinWidth(fBinIndex[iDim]);
    1092             :     }
    1093             :     
    1094           0 :     for (Int_t iDim=0; iDim<fNParameters; iDim++){
    1095           0 :       for (Int_t jDim=0; jDim<fNParameters; jDim++) binLocal[jDim]=fBinCenter[jDim];
    1096           0 :       for (Int_t iDiv=0; iDiv<nDiv; iDiv++){
    1097           0 :         binLocal[iDim]=binLowEdge[iDim]+(fBinDelta[iDim]*(iDiv-1.))/Double_t(nDiv);
    1098           0 :         Double_t value2= Eval(binLocal.GetMatrixArray());
    1099           0 :         binLocal[iDim]=binLowEdge[iDim]+(fBinDelta[iDim]*Double_t(iDiv))/Double_t(nDiv);
    1100           0 :         Double_t value=Eval(binLocal.GetMatrixArray());
    1101           0 :         Double_t derivative=nDiv*(value-value2)/fBinDelta[iDim];
    1102           0 :         stream<<
    1103           0 :           "pos.="<<&binLocal<<          // position vector
    1104           0 :           "iBin="<<iBin<<               // bin index
    1105           0 :           "iDim="<<iDim<<               // scan bin index
    1106           0 :           "iDiv="<<iDiv<<               // division index
    1107           0 :           "binIndexF.="<<&binIndexF<<   // bin index
    1108           0 :           "value="<<value<<             // value at 
    1109           0 :           "derivative="<<derivative<<   // numerical derivative
    1110             :           "\n";
    1111           0 :       }
    1112             :     }
    1113             :   }
    1114           0 : }
    1115             : 
    1116             : 
    1117             : Double_t AliNDLocalRegression::EvalGraphKernel(TGraph * gr, Double_t evalTime, Double_t kernelWidth, Int_t sigmaCut, Bool_t evalLog, Int_t pol, TVectorD *param, TMatrixD *covar){
    1118             :   ///
    1119             :   ///
    1120             :   ///   Interpolate graph using local regression with kernel width  
    1121             :   ///    
    1122             :   Int_t kMinEntries=4;
    1123           0 :   Int_t npoints=gr->GetN();
    1124           0 :   Int_t index0= TMath::BinarySearch(npoints, gr->GetX(), evalTime-sigmaCut*kernelWidth);
    1125           0 :   Int_t index1= TMath::BinarySearch(npoints, gr->GetX(), evalTime+sigmaCut*kernelWidth);
    1126           0 :   if (index1-index0 < kMinEntries) {
    1127           0 :     Int_t index= TMath::BinarySearch(npoints, gr->GetX(), evalTime);
    1128           0 :     index0=index-kMinEntries/2;
    1129           0 :     index1=index+kMinEntries/2;
    1130           0 :   }
    1131           0 :   if (index0<0) index0=0;
    1132           0 :   if (index1>=npoints) index1=npoints-1;
    1133           0 :   TLinearFitter fitter(pol+1, TString::Format("pol%d",pol));
    1134           0 :   Double_t mkernel2=1./(kernelWidth*kernelWidth);
    1135           0 :   for (Int_t ipoint=index0; ipoint<=index1; ipoint++){
    1136           0 :     Double_t x=gr->GetX()[ipoint]-evalTime;
    1137           0 :     Double_t y=gr->GetY()[ipoint];
    1138           0 :     if (evalLog==kFALSE){
    1139           0 :       fitter.AddPoint(&x, gr->GetY()[ipoint], TMath::Exp(x*x*mkernel2));
    1140             :     }else{
    1141           0 :       if (y>0) fitter.AddPoint(&x, TMath::Log(y) , TMath::Exp(x*x*mkernel2));
    1142             :     }
    1143           0 :   }
    1144           0 :   Int_t hasFailed=(fitter.GetNpoints()>kMinEntries)? fitter.Eval():1;
    1145           0 :   if (hasFailed) return 0;
    1146             :   
    1147           0 :   if (param){
    1148           0 :     fitter.GetParameters(*param);
    1149             :   }
    1150           0 :   if (covar) fitter.GetCovarianceMatrix(*covar);  
    1151           0 :   return (evalLog==0) ? fitter.GetParameter(0) : TMath::Exp(fitter.GetParameter(0));
    1152           0 : }
    1153             : 
    1154             : 

Generated by: LCOV version 1.11