diff --git a/hist/CMakeLists.txt b/hist/CMakeLists.txt
index 455ed789fe17d7c2f42f916e3c373a6e4707c866..d9547d3a58c8792b1ed41a8723342a246dfd7d67 100644
--- a/hist/CMakeLists.txt
+++ b/hist/CMakeLists.txt
@@ -2,6 +2,7 @@ Add_Subdirectory(hist)             # special CMakeLists.txt
 Add_Subdirectory(histpainter)      # special CMakeLists.txt
 Add_Subdirectory(spectrum)
 Add_Subdirectory(spectrumpainter)  # special CMakeLists.txt
+Add_Subdirectory(unfold)
 If(CMAKE_Fortran_COMPILER)
   Add_Subdirectory(hbook)
 EndIf(CMAKE_Fortran_COMPILER)
diff --git a/hist/hist/inc/LinkDef.h b/hist/hist/inc/LinkDef.h
index dfef00e18774cb7fd13c583bd509c855fd75a6e2..5a0d4ee81e8f92a261d0ce40660298824a4b19e5 100644
--- a/hist/hist/inc/LinkDef.h
+++ b/hist/hist/inc/LinkDef.h
@@ -160,10 +160,6 @@
 #pragma link C++ class TVirtualGraphPainter+;
 #pragma link C++ class TVirtualFitter+;
 #pragma link C++ class TBackCompFitter+;
-#pragma link C++ class TUnfold+;
-#pragma link C++ class TUnfoldSys+;
-#pragma link C++ class TUnfoldBinning+;
-#pragma link C++ class TUnfoldDensity+;
 #pragma link C++ class TSVDUnfold+;
 #pragma link C++ class TEfficiency+;
 #pragma link C++ class TKDE+;
diff --git a/hist/hist/src/TUnfoldBinning.cxx b/hist/hist/src/TUnfoldBinning.cxx
deleted file mode 100644
index 120337f0446e9552519b66ff6e573320758d8d75..0000000000000000000000000000000000000000
--- a/hist/hist/src/TUnfoldBinning.cxx
+++ /dev/null
@@ -1,1748 +0,0 @@
-// Author: Stefan Schmitt
-// DESY, 10/08/11
-
-//  Version 17.1, in parallel to changes in TUnfold
-//
-//  History:
-//    Version 17.0, initial version, numbered in parallel to TUnfold
-
-/** \class TUnfoldBinning
-    \ingroup Hist
-  This class serves as a container of analysis bins
-  analysis bins are specified by defining the axes of a distribution.
-  It is also possible to have unconnected analysis bins without axis.
-  Multiple TUnfoldBinning objects may be arranged in a tree,
-  such that a full tree structure of histograms and bins is supported
-
-  If you use this software, please consider the following citation
-       S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]
-
-  More documentation and updates are available on
-      http://www.desy.de/~sschmitt
-
-  Functionality
-
-  The class gives access to all analysis bins numbered in sequence.
-  Such a sequence of bins may be stored in a 1-dimension histogram.
-  Correlations between two TUnfoldBinning objects may be stored in
-  a 2-dimensional histogram. This type of ordering is required for
-  the TUnfold class.
-
-  In addition, it is possible to have root histograms, using the
-  axes as defined with the distributions. Underflow/overflow bins
-  can be included or excluded when mapping bins on root histograms.
-  In addition, it is possible to collapse one of more axes when going
-  from a N-dimensional distribution to a root histogram.
-*/
-
-/*
- This file is part of TUnfold.
-
- TUnfold is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- TUnfold is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with TUnfold.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "TUnfoldBinning.h"
-#include <TVectorD.h>
-#include <TAxis.h>
-#include <TString.h>
-#include <iostream>
-#include <fstream>
-#include <TMath.h>
-#include <TF1.h>
-#include <TH1D.h>
-#include <TH2D.h>
-#include <TH3D.h>
-#include <TList.h>
-#include <TIterator.h>
-
-// #define DEBUG
-
-using namespace std;
-
-ClassImp(TUnfoldBinning)
-
-/********************* setup **************************/
-
-void TUnfoldBinning::Initialize(Int_t nBins)
-{
-   // initialize variables
-   parentNode=0;
-   childNode=0;
-   nextNode=0;
-   prevNode=0;
-   fAxisList=new TObjArray();
-   fAxisLabelList=new TObjArray();
-   fAxisList->SetOwner();
-   fAxisLabelList->SetOwner();
-   fHasUnderflow=0;
-   fHasOverflow=0;
-   fDistributionSize=nBins;
-   fBinFactorFunction=0;
-   fBinFactorConstant=1.0;
-}
-
-Int_t TUnfoldBinning::UpdateFirstLastBin(Bool_t startWithRootNode)
-{
-   // update fFirstBin and fLastBin members of this node and its children
-   //   startWithRootNode: if true, start the update with the root node
-   if(startWithRootNode) {
-      return GetRootNode()->UpdateFirstLastBin(kFALSE);
-   }
-   if(GetPrevNode()) {
-      // if this is not the first node in a sequence,
-      // start with the end bin of the previous node
-      fFirstBin=GetPrevNode()->GetEndBin();
-   } else if(GetParentNode()) {
-      // if this is the first node in a sequence but has a parent,
-      // start with the end bin of the parent's distribution
-      fFirstBin=GetParentNode()->GetStartBin()+
-      GetParentNode()->GetDistributionNumberOfBins();
-   } else {
-      // if this is the top level node, the first bin number is 1
-      fFirstBin=1;
-      //  ... unless the top level node is the only node
-      //  ... with dimension=1
-      //  ... and there are no child nodes
-      //  ... and there is an underflow bin
-      if((!GetChildNode())&&(GetDistributionDimension()==1)&&
-         (fHasUnderflow==1)) {
-         fFirstBin=0;
-      }
-   }
-   fLastBin=fFirstBin+fDistributionSize;
-   // now update count for all children
-   for(TUnfoldBinning *node=childNode;node;node=node->nextNode) {
-      fLastBin=node->UpdateFirstLastBin(kFALSE);
-   }
-   return fLastBin;
-}
-
-TUnfoldBinning::TUnfoldBinning
-(const char *name,Int_t nBins,const char *binNames)
-: TNamed(name ? name : "",name ? name : "")
-{
-   // initialize a node with bins but without axis
-   //   name: name of the node
-   //   nBin: number of extra bins (could be zero)
-   //   binNames: (optionally) names of the bins sepatared by ';'
-   Initialize(nBins);
-   if(binNames) {
-      TString nameString(binNames);
-      delete fAxisLabelList;
-      fAxisLabelList=nameString.Tokenize(";");
-   }
-   UpdateFirstLastBin();
-}
-
-TUnfoldBinning::TUnfoldBinning
-(const TAxis &axis,Int_t includeUnderflow,Int_t includeOverflow)
-: TNamed(axis.GetName(),axis.GetTitle())
-{
-   // create binning containing a distribution with one axis
-   //     axis: the axis to represent
-   //     includeUnderflow: include underflow bin
-   //     includeOverflow: include overflow bin
-   Initialize(0);
-   AddAxis(axis,includeUnderflow,includeOverflow);
-   UpdateFirstLastBin();
-}
-
-TUnfoldBinning::~TUnfoldBinning(void)
-{
-   // delete all children
-   if(childNode) delete childNode;
-   // remove this node from the tree
-   if(GetParentNode() && (GetParentNode()->GetChildNode()==this)) {
-      parentNode->childNode=nextNode;
-   }
-   if(GetPrevNode()) prevNode->nextNode=nextNode;
-   if(GetNextNode()) nextNode->prevNode=prevNode;
-   delete fAxisList;
-   delete fAxisLabelList;
-}
-
-TUnfoldBinning *TUnfoldBinning::AddBinning
-(const char *name,Int_t nBins,const char *binNames)
-{
-   // add a binning as last daughter to this tree
-   //   name: name of the node
-   //   nBin: number of bins not belonging to a distribution (usually zero)
-   //   binNames: (optionally) names of these bins sepatared by ';'
-   return AddBinning(new TUnfoldBinning(name,nBins,binNames));
-}
-
-TUnfoldBinning *TUnfoldBinning::AddBinning(TUnfoldBinning *binning)
-{
-   // add a binning as last daughter to this tree
-   //   binning: pointer to the new binning
-   // return value: if succeeded, return "binning"
-   //               otherwise return 0
-   TUnfoldBinning *r=0;
-   if(binning->GetParentNode()) {
-      Error("binning \"%s\" already has parent \"%s\", can not be added to %s",
-            (char *)binning->GetName(),
-            (char *)binning->GetParentNode()->GetName(),
-            (char *)GetName());
-   } else if(binning->GetPrevNode()) {
-      Error("binning \"%s\" has previous node \"%s\", can not be added to %s",
-            (char *)binning->GetName(),
-            (char *)binning->GetPrevNode()->GetName(),
-            (char *)GetName());
-   } else if(binning->GetNextNode()) {
-      Error("binning \"%s\" has next node \"%s\", can not be added to %s",
-            (char *)binning->GetName(),
-            (char *)binning->GetNextNode()->GetName(),
-            (char *)GetName());
-   } else {
-      r=binning;
-      binning->parentNode=this;
-      if(childNode) {
-         TUnfoldBinning *child=childNode;
-         // find last child
-         while(child->nextNode) {
-            child=child->nextNode;
-         }
-         // add as last child
-         child->nextNode=r;
-         r->prevNode=child;
-      } else {
-         childNode=r;
-      }
-      UpdateFirstLastBin();
-      r=binning;
-   }
-   return r;
-}
-
-Bool_t TUnfoldBinning::AddAxis
-(const char *name,Int_t nBin,Double_t xMin,Double_t xMax,
- Bool_t hasUnderflow,Bool_t hasOverflow)
-{
-   // add an axis with equidistant bins to the distribution
-   //    name: name of the axis
-   //    nBin: number of bins
-   //    xMin: lower edge of the first bin
-   //    xMax: upper edge of the last bin
-   //    hasUnderflow: decide whether the axis has an underflow bin
-   //    hasOverflow: decide whether the axis has an overflow bin
-   // return: true if the axis has been added
-   Bool_t r=kFALSE;
-   if(nBin<=0) {
-      Fatal("AddAxis","number of bins %d is not positive",
-            nBin);
-   } else if((!TMath::Finite(xMin))||(!TMath::Finite(xMax))||
-             (xMin>=xMax)) {
-      Fatal("AddAxis","xmin=%f required to be smaller than xmax=%f",
-            xMin,xMax);
-   } else {
-      Double_t *binBorders=new Double_t[nBin+1];
-      Double_t x=xMin;
-      Double_t dx=(xMax-xMin)/nBin;
-      for(Int_t i=0;i<=nBin;i++) {
-         binBorders[i]=x+i*dx;
-      }
-      r=AddAxis(name,nBin,binBorders,hasUnderflow,hasOverflow);
-      delete [] binBorders;
-   }
-   return r;
-}
-
-Bool_t TUnfoldBinning::AddAxis
-(const TAxis &axis,Bool_t hasUnderflow,Bool_t hasOverflow)
-{
-   // add an axis to the distribution
-   //    axis: the axis
-   //    hasUnderflow: decide whether the underflow bin should be included
-   //    hasOverflow: decide whether the overflow bin should be included
-   // return: true if the axis has been added
-   //
-   // Note: axis labels are not imported
-   Int_t nBin=axis.GetNbins();
-   Double_t *binBorders=new Double_t[nBin+1];
-   for(Int_t i=0;i<nBin;i++) {
-      binBorders[i]=axis.GetBinLowEdge(i+1);
-   }
-   binBorders[nBin]=axis.GetBinUpEdge(nBin);
-   Bool_t r=AddAxis(axis.GetTitle(),nBin,binBorders,hasUnderflow,hasOverflow);
-   delete [] binBorders;
-   return r;
-}
-
-Bool_t TUnfoldBinning::AddAxis
-(const char *name,Int_t nBin,const Double_t *binBorders,
- Bool_t hasUnderflow,Bool_t hasOverflow)
-{
-   // add an axis with the specified bin borders to the distribution
-   //    name: name of the axis
-   //    nBin: number of bins
-   //    binBorders: array of bin borders, with nBin+1 elements
-   //    hasUnderflow: decide whether the axis has an underflow bin
-   //    hasOverflow: decide whether the axis has an overflow bin
-   Bool_t r=kFALSE;
-   if(HasUnconnectedBins()) {
-      Fatal("AddAxis","node already has %d bins without axis",
-            GetDistributionNumberOfBins());
-   } else if(nBin<=0) {
-      Fatal("AddAxis","number of bins %d is not positive",
-            nBin);
-   } else {
-      TVectorD *bins=new TVectorD(nBin+1);
-      r=kTRUE;
-      for(Int_t i=0;i<=nBin;i++) {
-         (*bins)(i)=binBorders[i];
-         if(!TMath::Finite((*bins)(i))) {
-            Fatal("AddAxis","bin border %d is not finite",i);
-            r=kFALSE;
-         } else if((i>0)&&((*bins)(i)<=(*bins)(i-1))) {
-            Fatal("AddAxis","bins not in order x[%d]=%f <= %f=x[%d]",
-                  i,(*bins)(i),(*bins)(i-1),i-1);
-            r=kFALSE;
-         }
-      }
-      if(r) {
-         Int_t axis=fAxisList->GetEntriesFast();
-         Int_t bitMask=1<<axis;
-         Int_t nBinUO=nBin;
-         if(hasUnderflow) {
-            fHasUnderflow |= bitMask;
-            nBinUO++;
-         } else {
-            fHasUnderflow &= ~bitMask;
-         }
-         if(hasOverflow) {
-            fHasOverflow |= bitMask;
-            nBinUO++;
-         } else {
-            fHasOverflow &= ~bitMask;
-         }
-         fAxisList->AddLast(bins);
-         fAxisLabelList->AddLast(new TObjString(name));
-         if(!fDistributionSize) fDistributionSize=1;
-         fDistributionSize *= nBinUO;
-         UpdateFirstLastBin();
-      }
-   }
-   return r;
-}
-
-void TUnfoldBinning::PrintStream(ostream &out,Int_t indent) const
-{
-   // print some information about this binning tree
-   //    out: stream to write to
-   //    indent: initial indentation (sub-trees have indent+1)
-   for(Int_t i=0;i<indent;i++) out<<"  ";
-   out<<"TUnfoldBinning \""<<GetName()<<"\" has ";
-   Int_t nBin=GetEndBin()-GetStartBin();
-   if(nBin==1) {
-      out<<"1 bin";
-   } else {
-      out<<nBin<<" bins";
-   }
-   out<<" ["
-   <<GetStartBin()<<","<<GetEndBin()<<"] nTH1x="
-   <<GetTH1xNumberOfBins()
-   <<"\n";
-   if(GetDistributionNumberOfBins()) {
-      for(Int_t i=0;i<indent;i++) out<<"  ";
-      out<<" distribution: "<<GetDistributionNumberOfBins()<<" bins\n";
-      if(fAxisList->GetEntriesFast()) {
-         /* for(Int_t i=0;i<indent;i++) out<<"  ";
-          out<<" axes:\n"; */
-         for(Int_t axis=0;axis<GetDistributionDimension();axis++) {
-            for(Int_t i=0;i<indent;i++) out<<"  ";
-            out<<"  \""
-            <<GetDistributionAxisLabel(axis)
-            <<"\" nbin="<<GetDistributionBinning(axis)->GetNrows()-1;
-            if(fHasUnderflow & (1<<axis)) out<<" plus underflow";
-            if(fHasOverflow & (1<<axis)) out<<" plus overflow";
-            out<<"\n";
-         }
-      } else {
-         for(Int_t i=0;i<indent;i++) out<<"  ";
-         out<<" no axis\n";
-         for(Int_t i=0;i<indent;i++) out<<"  ";
-         out<<" names: ";
-         for(Int_t ibin=0;(ibin<GetDistributionNumberOfBins())&&
-             (ibin<fAxisLabelList->GetEntriesFast());ibin++) {
-            if(ibin) out<<";";
-            if(GetDistributionAxisLabel(ibin)) {
-               out<<GetDistributionAxisLabel(ibin);
-            }
-         }
-         out<<"\n";
-      }
-   }
-   TUnfoldBinning const *child=GetChildNode();
-   if(child) {
-      while(child) {
-         child->PrintStream(out,indent+1);
-         child=child->GetNextNode();
-      }
-   }
-}
-
-/********************* Navigation **********************/
-
-TUnfoldBinning const *TUnfoldBinning::FindNode(char const *name) const
-{
-   // parse the tree and return a node with the given name
-   //   name: the name of the node to find
-   TUnfoldBinning const *r=0;
-   if((!name)||(!TString(GetName()).CompareTo(name))) {
-      r=this;
-   }
-   for(TUnfoldBinning const *child=GetChildNode();
-       (!r) && child;child=child->GetNextNode()) {
-      r=child->FindNode(name);
-   }
-   return r;
-}
-
-TUnfoldBinning *TUnfoldBinning::GetRootNode(void)
-{
-   // return root node
-   TUnfoldBinning *node=this;
-   while(node->GetParentNode()) node=node->parentNode;
-   return node;
-}
-
-TUnfoldBinning const *TUnfoldBinning::GetRootNode(void) const
-{
-   // return root node
-   TUnfoldBinning const *node=this;
-   while(node->GetParentNode()) node=node->GetParentNode();
-   return node;
-}
-
-/********************* Create THxx histograms **********/
-
-TString TUnfoldBinning::BuildHistogramTitle
-(const char *histogramName,const char *histogramTitle,Int_t const *axisList)
-const
-{
-   // build a title
-   // input:
-   //   histogramTitle : if this is non-zero, use that title
-   //  otherwise:
-   //   title=histogramName[;x[;y[;z]]]
-   //   ?Axis : -2 stop adding text to the title
-   //           -1 add name of this node
-   //          >=0 use name of the corresponding axis
-   TString r;
-   if(histogramTitle) {
-      r=histogramTitle;
-   } else {
-      r=histogramName;
-      Int_t iEnd;
-      for(iEnd=2;iEnd>0;iEnd--) {
-         if(axisList[iEnd]>=0) break;
-      }
-      for(Int_t i=0;i<=iEnd;i++) {
-         r += ";";
-         if(axisList[i]<0) {
-            r += GetName();
-         } else {
-            r += GetNonemptyNode()->GetDistributionAxisLabel(axisList[i]);
-         }
-      }
-   }
-   return r;
-}
-
-TString TUnfoldBinning::BuildHistogramTitle2D
-(const char *histogramName,const char *histogramTitle,
- Int_t xAxis,const TUnfoldBinning *yAxisBinning,Int_t yAxis) const
-{
-   // build a title
-   // input:
-   //   histogramTitle : if this is non-zero, use that title
-   //  otherwise:
-   //   title=histogramName;x;y
-   //   xAxis : -1 no title for this axis
-   //          >=0 use name of the corresponding axis
-   TString r;
-   if(histogramTitle) {
-      r=histogramTitle;
-   } else {
-      r=histogramName;
-      r += ";";
-      if(xAxis==-1) {
-         r += GetName();
-      } else if(xAxis>=0) {
-         r += GetNonemptyNode()->GetDistributionAxisLabel(xAxis);
-      }
-      r+= ";";
-      if(yAxis==-1) {
-         r += yAxisBinning->GetName();
-      } else if(yAxis>=0) {
-         r += yAxisBinning->GetNonemptyNode()->GetDistributionAxisLabel(yAxis);
-      }
-
-   }
-   return r;
-}
-
-Int_t TUnfoldBinning::GetTH1xNumberOfBins
-(Bool_t originalAxisBinning,const char *axisSteering) const
-{
-   // return the number of histogram bins required when storing
-   // this binning in a one-dimensional histogram
-   //     originalAxisBinning : try to preserve the axis binning,
-   //                           if this binning is 1-dimensional then the
-   //                           underflow/overflow are stored in the
-   //                           corresponding bins of the TH1 and
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //  return: number of bins of the TH1 (underflow/overflow are not counted)
-   Int_t axisBins[3],axisList[3];
-   GetTHxxBinning(originalAxisBinning ? 1 : 0,axisBins,axisList,
-                  axisSteering);
-   return axisBins[0];
-}
-
-TH1 *TUnfoldBinning::CreateHistogram
-(const char *histogramName,Bool_t originalAxisBinning,Int_t **binMap,
- const char *histogramTitle,const char *axisSteering) const
-{
-   // create a THxx histogram capable to hold the bins of this binning
-   // scheme and its children
-   //  input:
-   //     histogramName: name of the histogram which is created
-   //     originalAxisBinning : try to preserve the axis binning
-   //                           if this parameter is true, the resulting
-   //                           histogram has bin widths and histogram
-   //                           dimension (TH1D, TH2D, TH3D)
-   //                           in parallel to the binning scheme
-   //                           (if possible)
-   //     binMap : mapping of global bins to histogram bins
-   //               see method CreateBinMap()
-   //               if(binMap==0), no binMap is created
-   //     histogramTitle: if this is non-zero, it is taken as histogram title
-   //                     otherwise, the title is created automatically
-   //     axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   // returns: a new histogram (TH1D, TH2D or TH3D)
-   Int_t nBin[3],axisList[3];
-   Int_t nDim=GetTHxxBinning(originalAxisBinning ? 3 : 0,nBin,axisList,
-                             axisSteering);
-   const TUnfoldBinning *neNode=GetNonemptyNode();
-   TString title=BuildHistogramTitle(histogramName,histogramTitle,axisList);
-   TH1 *r=0;
-   if(nDim>0) {
-      const TVectorD *axisBinsX=
-      neNode->GetDistributionBinning(axisList[0]);
-      if(nDim>1) {
-         const TVectorD *axisBinsY=
-         neNode->GetDistributionBinning(axisList[1]);
-         if(nDim>2) {
-            const TVectorD *axisBinsZ=
-            neNode->GetDistributionBinning(axisList[2]);
-            r=new TH3D(histogramName,title,
-                       nBin[0],axisBinsX->GetMatrixArray(),
-                       nBin[1],axisBinsY->GetMatrixArray(),
-                       nBin[2],axisBinsZ->GetMatrixArray());
-         } else {
-            r=new TH2D(histogramName,title,
-                       nBin[0],axisBinsX->GetMatrixArray(),
-                       nBin[1],axisBinsY->GetMatrixArray());
-         }
-      } else {
-         r=new TH1D(histogramName,title,nBin[0],axisBinsX->GetMatrixArray());
-      }
-   } else {
-      if(originalAxisBinning) {
-         Warning("CreateHistogram",
-                 "Original binning can not be represented as THxx");
-      }
-      r=new TH1D(histogramName,title,nBin[0],0.5,nBin[0]+0.5);
-      nDim=0;
-   }
-   if(binMap) {
-      *binMap=CreateBinMap(r,nDim,axisList,axisSteering);
-   }
-   return r;
-}
-
-TH2D *TUnfoldBinning::CreateErrorMatrixHistogram
-(const char *histogramName,Bool_t originalAxisBinning,Int_t **binMap,
- const char *histogramTitle,const char *axisSteering) const
-{
-   // create a TH2D histogram capable to hold an error matrix
-   // coresponding to the bins of this binning scheme and its children
-   //  input:
-   //     histogramName: name of the histogram which is created
-   //     originalAxisBinning : try to preserve the axis binning
-   //                           if this parameter is true, the resulting
-   //                           histogram has bin widths
-   //                           in parallel to this binning scheme
-   //                           (if possible)
-   //     binMap : mapping of global bins to histogram bins
-   //               see method CreateBinMap()
-   //               if(binMap==0), no binMap is created
-   //     histogramTitle: if this is non-zero, it is taken as histogram title
-   //                     otherwise, the title is created automatically
-   //     axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   // returns: a new TH2D
-
-   Int_t nBin[3],axisList[3];
-   Int_t nDim=GetTHxxBinning(originalAxisBinning ? 1 : 0,nBin,axisList,
-                             axisSteering);
-   TString title=BuildHistogramTitle(histogramName,histogramTitle,axisList);
-   TH2D *r=0;
-   if(nDim==1) {
-      const TVectorD *axisBinsX=(TVectorD const *)
-      GetNonemptyNode()->fAxisList->At(axisList[0]);
-      r=new TH2D(histogramName,title,nBin[0],axisBinsX->GetMatrixArray(),
-                 nBin[0],axisBinsX->GetMatrixArray());
-   } else {
-      if(originalAxisBinning) {
-         Info("CreateErrorMatrixHistogram",
-              "Original binning can not be represented on one axis");
-      }
-      r=new TH2D(histogramName,title,nBin[0],0.5,nBin[0]+0.5,
-                 nBin[0],0.5,nBin[0]+0.5);
-      nDim=0;
-   }
-   if(binMap) {
-      *binMap=CreateBinMap(r,nDim,axisList,axisSteering);
-   }
-   return r;
-}
-
-TH2D *TUnfoldBinning::CreateHistogramOfMigrations
-(TUnfoldBinning const *xAxis,TUnfoldBinning const *yAxis,
- char const *histogramName,Bool_t originalXAxisBinning,
- Bool_t originalYAxisBinning,char const *histogramTitle)
-{
-   // create a TH2D histogram capable to hold the bins of the two
-   // input binning schemes on the x and y axes, respectively
-   //  input:
-   //     histogramName: name of the histogram which is created
-   //     xAxis: binning scheme for the x axis
-   //     yAxis: binning scheme for the y axis
-   //     originalXAxisBinning: preserve x-axis bin widths if possible
-   //     originalXAxisBinning: preserve y-axis bin widths if possible
-   //     histogramTitle: if this is non-zero, it is taken as histogram title
-   //                     otherwise, the title is created automatically
-   // returns: a new TH2D
-
-   Int_t nBinX[3],axisListX[3];
-   Int_t nDimX=
-   xAxis->GetTHxxBinning(originalXAxisBinning ? 1 : 0,nBinX,axisListX,0);
-   Int_t nBinY[3],axisListY[3];
-   Int_t nDimY=
-   yAxis->GetTHxxBinning(originalYAxisBinning ? 1 : 0,nBinY,axisListY,0);
-   TString title=xAxis->BuildHistogramTitle2D
-   (histogramName,histogramTitle,axisListX[0],yAxis,axisListY[0]);
-   if(nDimX==1) {
-      const TVectorD *axisBinsX=(TVectorD const *)
-      xAxis->fAxisList->At(axisListX[0]);
-      if(nDimY==1) {
-         const TVectorD *axisBinsY=(TVectorD const *)
-         yAxis->fAxisList->At(axisListY[0]);
-         return new TH2D(histogramName,title,
-                         nBinX[0],axisBinsX->GetMatrixArray(),
-                         nBinY[0],axisBinsY->GetMatrixArray());
-      } else {
-         return new TH2D(histogramName,title,
-                         nBinX[0],axisBinsX->GetMatrixArray(),
-                         nBinY[0],0.5,0.5+nBinY[0]);
-      }
-   } else {
-      if(nDimY==1) {
-         const TVectorD *axisBinsY=(TVectorD const *)
-         yAxis->fAxisList->At(axisListY[0]);
-         return new TH2D(histogramName,title,
-                         nBinX[0],0.5,0.5+nBinX[0],
-                         nBinY[0],axisBinsY->GetMatrixArray());
-      } else {
-         return new TH2D(histogramName,title,
-                         nBinX[0],0.5,0.5+nBinX[0],
-                         nBinY[0],0.5,0.5+nBinY[0]);
-      }
-   }
-}
-
-Int_t TUnfoldBinning::GetTHxxBinning
-(Int_t maxDim,Int_t *axisBins,Int_t *axisList,
- const char *axisSteering) const
-{
-   // calculate properties of a THxx histogram to store this binning
-   // input:
-   //   maxDim : maximum dimension of the THxx (0 or 1..3)
-   //              maxDim==0 is used to indicate that the histogram should be
-   //              1-dimensional with all bins mapped on one axis,
-   //               bin centers equal to bin numbers
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   // output;
-   //   axisBins[0..2] : number of bins on the THxx axes [0]:x [1]:y [2]:z
-   //   axisList[0..2] : TUnfoldBinning axis number corresponding to TH1 axis
-   //                        [0]:x [1]:y [2]:z
-   // return value :  1-3: dimension of THxx
-   //                 0 : use 1-dim THxx, binning structure is not preserved
-   for(Int_t i=0;i<3;i++) {
-      axisBins[i]=0;
-      axisList[i]=-1;
-   }
-   const TUnfoldBinning *theNode=GetNonemptyNode();
-   if(theNode) {
-      return theNode->GetTHxxBinningSingleNode
-      (maxDim,axisBins,axisList,axisSteering);
-   } else {
-      axisBins[0]=GetTHxxBinsRecursive(axisSteering);
-      return 0;
-   }
-}
-
-const TUnfoldBinning *TUnfoldBinning::GetNonemptyNode(void) const
-{
-   // get the node which has non-empty distributions
-   // if there is none or if there are many, return zero
-   const TUnfoldBinning *r=GetDistributionNumberOfBins()>0 ? this : 0;
-   for(TUnfoldBinning const *child=GetChildNode();child;
-       child=child->GetNextNode()) {
-      const TUnfoldBinning *c=child->GetNonemptyNode();
-      if(!r) {
-         // new candidate found
-         r=c;
-      } else {
-         if(c) {
-            // multiple nodes found
-            r=0;
-            break;
-         }
-      }
-   }
-   return r;
-}
-
-Int_t TUnfoldBinning::GetTHxxBinningSingleNode
-(Int_t maxDim,Int_t *axisBins,Int_t *axisList,const char *axisSteering) const
-{
-   // get the properties of a histogram capable to hold the distribution
-   // of this node
-   // input:
-   //   maxDim : maximum dimension of the THxx (0 or 1..3)
-   //              maxDim==0 is used to indicate that the histogram should be
-   //              1-dimensional with all bins mapped on one axis
-   //   axisSteering :
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   input/output:
-   //    axisBins[0..2] : cumulated number of bins on the THxx axes
-   //                         [0]:x [1]:y [2]:z
-   //    axisList[0..2] : TUnfoldBinning axis number corresponding to TH1 axis
-   //                         [0]:x [1]:y [2]:z
-   // return value :  1-3: dimension of THxx
-   //                 0 : use 1-dim THxx, binning structure is not preserved
-
-
-   // decode axisSteering
-   //   isOptionGiven[0] ('C'): bit vector which axes to collapse
-   //   isOptionGiven[1] ('U'): bit vector to discarde underflow bins
-   //   isOptionGiven[2] ('U'): bit vector to discarde overflow bins
-   Int_t isOptionGiven[3] = { 0 };
-   DecodeAxisSteering(axisSteering,"CUO",isOptionGiven);
-   // count number of axes after projecting
-   Int_t numDimension=GetDistributionDimension();
-   Int_t r=0;
-   for(Int_t i=0;i<numDimension;i++) {
-      if(isOptionGiven[0] & (1<<i)) continue;
-      r++;
-   }
-   if((r>0)&&(r<=maxDim)) {
-      // 0<r<=maxDim
-      //
-      // -> preserve the original binning
-      //    axisList[] and axisBins[] are overwritten
-      r=0;
-      for(Int_t i=0;i<numDimension;i++) {
-         if(isOptionGiven[0] & (1<<i)) continue;
-         axisList[r]=i;
-         axisBins[r]=GetDistributionBinning(i)->GetNrows()-1;
-         r++;
-      }
-   } else {
-      // map everything on one axis
-      //  axisBins[0] is the number of bins
-      if(HasUnconnectedBins() || (GetDistributionNumberOfBins()<=0)) {
-         axisBins[0] = GetDistributionNumberOfBins();
-      } else {
-         Int_t nBin=1;
-         for(Int_t i=0;i<numDimension;i++) {
-            Int_t mask=(1<<i);
-            if(isOptionGiven[0] & mask) continue;
-            Int_t nBinI=GetDistributionBinning(i)->GetNrows()-1;
-            if((fHasUnderflow & mask)&& !(isOptionGiven[1] & mask)) nBinI++;
-            if((fHasOverflow & mask)&& !(isOptionGiven[2] & mask)) nBinI++;
-            nBin *= nBinI;
-         }
-         axisBins[0] = nBin;
-      }
-      r=0;
-   }
-   return r;
-}
-
-Int_t TUnfoldBinning::GetTHxxBinsRecursive(const char *axisSteering) const
-{
-   // input:
-   //   axisSteering :
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   // output:
-   //   binMap[] : map global bin numbers to histogram bins
-   // return value :  number of bins
-
-   Int_t r=0;
-   for(TUnfoldBinning const *child=GetChildNode();child;
-       child=child->GetNextNode()) {
-      r +=child->GetTHxxBinsRecursive(axisSteering);
-   }
-   // here: process distribution of this node
-   Int_t axisBins[3] = {0}, axisList[3] = {0};
-   GetTHxxBinningSingleNode(0,axisBins,axisList,axisSteering);
-   r += axisBins[0];
-   return r;
-}
-
-Int_t *TUnfoldBinning::CreateBinMap
-(const TH1 *hist,Int_t nDim,const Int_t *axisList,const char *axisSteering)
-const
-{
-   // create mapping from global bin number to a histogram for this node
-   // global bins are the bins of the root node binning scheme
-   // when projecting them on a TH1 histogram "hRootNode" without special
-   // axis steering and without attempting to preserve the axis binnings
-   //
-   // The bin map is an array of size hRootNode->GetNbinsX()+2
-   // For each bin of the "hRootNode" histogram it holds the target bin in
-   // "hist" or the number -1 if the corresponding "hRootNode" bin is not
-   // represented in "hist"
-   //
-   // input
-   //   hist : the histogram (to calculate root bin numbers)
-   //   nDim : target dimension of the TUnfoldBinning
-   //          if(nDim==0) all bins are mapped linearly
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //
-   // input used only if nDim>0:
-   //    axisList : for each THxx axis give the TUnfoldBinning axis number
-   //
-   // return value:
-   //   an new array which holds the bin mapping
-   //    r[0] : to which THxx bin to map global bin number 0
-   //    r[1] : to which THxx bin to map global bin number 1
-   //      ...
-   //    r[nmax]
-   //  where nmax=GetRootNode()->GetEndBin()+1
-   Int_t nMax=GetRootNode()->GetEndBin()+1;
-   Int_t *r=new Int_t[nMax];
-   for(Int_t i=0;i<nMax;i++) {
-      r[i]=-1;
-   }
-   Int_t startBin=GetRootNode()->GetStartBin();
-   if(nDim>0) {
-      const TUnfoldBinning *nonemptyNode=GetNonemptyNode();
-      if(nonemptyNode) {
-         FillBinMapSingleNode(hist,startBin,nDim,axisList,axisSteering,r);
-      } else {
-         Fatal("CreateBinMap","called with nDim=%d but GetNonemptyNode()=0",
-               nDim);
-      }
-   } else {
-      FillBinMapRecursive(startBin,axisSteering,r);
-   }
-   return r;
-}
-
-Int_t TUnfoldBinning::FillBinMapRecursive
-(Int_t startBin,const char *axisSteering,Int_t *binMap) const
-{
-   // fill bin map recursively
-   // input
-   //   startBin : first histogram bin
-   //   axisSteering : specify how to project the axes
-   //   binMap : the bin mapping which is to be filled
-   //
-   // the positions
-   //       binMap[GetStartBin()]
-   //         ..
-   //       binMap[GetEndBin()-1]
-   // are filled
-   //
-   Int_t nbin=0;
-   nbin = FillBinMapSingleNode(0,startBin,0,0,axisSteering,binMap);
-   for(TUnfoldBinning const *child=GetChildNode();child;
-       child=child->GetNextNode()) {
-      nbin += child->FillBinMapRecursive(startBin+nbin,axisSteering,binMap);
-   }
-   return nbin;
-}
-
-Int_t TUnfoldBinning::FillBinMapSingleNode
-(const TH1 *hist,Int_t startBin,Int_t nDim,const Int_t *axisList,
- const char *axisSteering,Int_t *binMap) const
-{
-   // fill bin map for a single node
-   //  input:
-   //     hist: the histogram represeinthing this node (used if nDim>0)
-   //     startBin: start bin in the bin map
-   //     nDim:
-   //        0: bins are mapped in linear order, ignore hist and axisList
-   //        nDim=hist->GetDimension():
-   //           bins are mapped to "hist" bin numbers
-   //           the corresponding TUnfoldBinning axes are taken from axisList[]
-   //        nDim=1 and hist->GetDimension()>1:
-   //           bins are mapped to th x-axis of "hist"
-   //           the corresponding TUnfoldBinning axis is taken from axisList[0]
-   //     axisList[]:
-   //           TUnfoldBinning axis numbers corresponding to the
-   //           x[0], y[1], z[2] axes of "hist"
-   //     axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //     binMap: the bin map to fill
-   // return value:
-   //     the number of bins mapped
-   //     (only relevant if nDim==0)
-   // first, decode axisSteering
-   //   isOptionGiven[0] ('C'): bit vector which axes to collapse
-   //   isOptionGiven[1] ('U'): bit vector to discarde underflow bins
-   //   isOptionGiven[2] ('U'): bit vector to discarde overflow bins
-   Int_t isOptionGiven[3] = {0};
-   DecodeAxisSteering(axisSteering,"CUO",isOptionGiven);
-   Int_t axisBins[MAXDIM] = {0};
-   Int_t dimension=GetDistributionDimension();
-   Int_t axisNbin[MAXDIM] = {0};
-   for(Int_t i=0;i<dimension;i++) {
-      const TVectorD *binning=GetDistributionBinning(i);
-      axisNbin[i]=binning->GetNrows()-1;
-   };
-   for(Int_t i=0;i<GetDistributionNumberOfBins();i++) {
-      Int_t globalBin=GetStartBin()+i;
-      const TUnfoldBinning *dest=ToAxisBins(globalBin,axisBins);
-      if(dest!=this) {
-         if(!dest) {
-            Fatal("FillBinMapSingleNode",
-                  "bin %d outside binning scheme",
-                  globalBin);
-         } else {
-            Fatal("FillBinMapSingleNode",
-                  "bin %d located in %s %d-%d rather than %s %d=%d",
-                  i,(const char *)dest->GetName(),
-                  dest->GetStartBin(),dest->GetEndBin(),
-                  (const char *)GetName(),GetStartBin(),GetEndBin());
-         }
-      }
-      // check whether this bin has to be skipped (underflow/overflow excluded)
-      Bool_t skip=kFALSE;
-      for(Int_t axis=0;axis<dimension;axis++) {
-         Int_t mask=(1<<axis);
-         if(((axisBins[axis]<0)&&(isOptionGiven[1] & mask))||
-            ((axisBins[axis]>=axisNbin[axis])&&(isOptionGiven[2] & mask)))
-            skip=kTRUE;
-      }
-      if(skip) continue;
-
-      if(nDim>0) {
-         // get bin number from THxx function(s)
-         if(nDim==hist->GetDimension()) {
-            Int_t ibin[3];
-            ibin[0]=ibin[1]=ibin[2]=0;
-            for(Int_t hdim=0;hdim<nDim;hdim++) {
-               Int_t axis=axisList[hdim];
-               ibin[hdim]=axisBins[axis]+1;
-            }
-            binMap[globalBin]=hist->GetBin(ibin[0],ibin[1],ibin[2]);
-         } else if(nDim==1) {
-            // histogram has more dimensions than the binning scheme
-            // and the binning scheme has one axis only
-            // -> use the first valid axis only
-            for(Int_t ii=0;ii<hist->GetDimension();ii++) {
-               if(axisList[ii]>=0) {
-                  binMap[globalBin]=axisBins[axisList[ii]]+1;
-                  break;
-               }
-            }
-         } else {
-            Fatal("FillBinMapSingleNode","unexpected bin mapping %d %d",nDim,
-                  hist->GetDimension());
-         }
-      } else {
-         // order all bins in sequence
-         // calculation in parallel to ToGlobalBin()
-         // but take care of
-         //   startBin,collapseAxis,discardeUnderflow,discardeOverflow
-         if(dimension>0) {
-            Int_t r=0;
-            for(Int_t axis=dimension-1;axis>=0;axis--) {
-               Int_t mask=(1<<axis);
-               if(isOptionGiven[0] & mask) {
-                  // bins on this axis are integrated over
-                  continue;
-               }
-               Int_t iBin=axisBins[axis];
-               Int_t nMax=axisNbin[axis];
-               if((fHasUnderflow & ~isOptionGiven[1]) & mask) {
-                  nMax +=1;
-                  iBin +=1;
-               }
-               if((fHasOverflow & ~isOptionGiven[2]) & mask) {
-                  nMax += 1;
-               }
-               r = r*nMax +iBin;
-            }
-            binMap[globalBin] = startBin + r;
-         } else {
-            binMap[globalBin] = startBin + axisBins[0];
-         }
-      }
-   }
-   Int_t nbin;
-   if(dimension>0) {
-      nbin=1;
-      for(Int_t axis=dimension-1;axis>=0;axis--) {
-         Int_t mask=(1<<axis);
-         if(isOptionGiven[0] & mask) {
-            // bins on this axis are integrated over
-            continue;
-         }
-         Int_t nMax=axisNbin[axis];
-         if((fHasUnderflow & ~isOptionGiven[1]) & mask) {
-            nMax +=1;
-         }
-         if((fHasOverflow & ~isOptionGiven[2]) & mask) {
-            nMax += 1;
-         }
-         nbin = nbin*nMax;
-      }
-   } else {
-      nbin=GetDistributionNumberOfBins();
-   }
-   return nbin;
-}
-
-TH1 *TUnfoldBinning::ExtractHistogram
-(const char *histogramName,const TH1 *globalBins,
- const TH2 *globalBinsEmatrix,Bool_t originalAxisBinning,
- const char *axisSteering) const
-{
-   // extract a distribution from the given set of global bins
-   // input:
-   //    histogramName : name of the histogram which ic created
-   //    globalBins : histogram with all bins
-   //    globalBinsEmatrix : corresponding error matrix
-   //                 if this pointer is zero, only diagonal errors
-   //                 are considered
-   //    originalAxisBinning :  extract  histogram with proper binning
-   //                          (if possible)
-   //    axisSteering
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   Int_t *binMap=0;
-   TH1 *r=CreateHistogram(histogramName,originalAxisBinning,&binMap,0,
-                          axisSteering);
-   TUnfoldBinning const *root=GetRootNode();
-   Int_t nMax=0;
-   for(Int_t iSrc=root->GetStartBin();iSrc<root->GetEndBin();iSrc++) {
-      if(binMap[iSrc]>nMax) nMax=binMap[iSrc];
-   }
-   TVectorD eSquared(nMax+1);
-   for(Int_t iSrc=root->GetStartBin();iSrc<root->GetEndBin();iSrc++) {
-      Int_t iDest=binMap[iSrc];
-      if(iDest>=0) {
-         Double_t c=r->GetBinContent(iDest);
-         r->SetBinContent(iDest,c+globalBins->GetBinContent(iSrc));
-         if(!globalBinsEmatrix) {
-            eSquared(iDest) += TMath::Power(globalBins->GetBinError(iSrc),2.);
-         } else {
-            for(Int_t jSrc=root->GetStartBin();jSrc<root->GetEndBin();jSrc++) {
-               if(binMap[jSrc]==iDest) {
-                  eSquared(iDest) +=
-                  TMath::Power(globalBins->GetBinError(jSrc),2.);
-               }
-            }
-         }
-      }
-   }
-   for(Int_t i=0;i<nMax;i++) {
-      Double_t e2=eSquared(i);
-      if(e2>0.0) {
-         r->SetBinError(i,TMath::Sqrt(e2));
-      }
-   }
-   delete [] binMap;
-
-   return r;
-}
-
-/********************* Calculate global bin number ******/
-
-Int_t TUnfoldBinning::GetGlobalBinNumber(Double_t x) const
-{
-   // locate bin on a one-dimensional distribution
-   // input
-   //    x: coordinate to locate
-   if(GetDistributionDimension()!=1) {
-      Fatal("GetBinNumber",
-            "called with 1 argument for %d dimensional distribution",
-            GetDistributionDimension());
-   }
-   return GetGlobalBinNumber(&x);
-}
-
-Int_t TUnfoldBinning::GetGlobalBinNumber(Double_t x,Double_t y) const
-{
-   // locate bin on a two-dimensional distribution
-   // input
-   //    x,y: coordinates to locate
-   if(GetDistributionDimension()!=2) {
-      Fatal("GetBinNumber",
-            "called with 2 arguments for %d dimensional distribution",
-            GetDistributionDimension());
-   }
-   Double_t xx[2];
-   xx[0]=x;
-   xx[1]=y;
-   return GetGlobalBinNumber(xx);
-}
-
-Int_t TUnfoldBinning::GetGlobalBinNumber
-(Double_t x,Double_t y,Double_t z) const
-{
-   // locate bin on a three-dimensional distribution
-   // input
-   //    x,y,z: coordinates to locate
-   if(GetDistributionDimension()!=3) {
-      Fatal("GetBinNumber",
-            "called with 3 arguments for %d dimensional distribution",
-            GetDistributionDimension());
-   }
-   Double_t xx[3];
-   xx[0]=x;
-   xx[1]=y;
-   xx[2]=z;
-   return GetGlobalBinNumber(xx);
-}
-
-Int_t TUnfoldBinning::GetGlobalBinNumber
-(Double_t x0,Double_t x1,Double_t x2,Double_t x3) const
-{
-   // locate bin on a four-dimensional distribution
-   // input
-   //    x0,x1,x2,x3: coordinates to locate
-   if(GetDistributionDimension()!=4) {
-      Fatal("GetBinNumber",
-            "called with 4 arguments for %d dimensional distribution",
-            GetDistributionDimension());
-   }
-   Double_t xx[4];
-   xx[0]=x0;
-   xx[1]=x1;
-   xx[2]=x2;
-   xx[3]=x3;
-   return GetGlobalBinNumber(xx);
-}
-
-Int_t TUnfoldBinning::GetGlobalBinNumber(const Double_t *x) const
-{
-   // locate bin on a n-dimensional distribution
-   // input
-   //    x[]: coordinates to locate
-   if(!GetDistributionDimension()) {
-      Fatal("GetBinNumber",
-            "no axes are defined for node %s",
-            (char const *)GetName());
-   }
-   Int_t iAxisBins[MAXDIM] = {0};
-   for(Int_t dim=0;dim<GetDistributionDimension();dim++) {
-      TVectorD const *bins=(TVectorD const *) fAxisList->At(dim);
-      Int_t i0=0;
-      Int_t i1=bins->GetNrows()-1;
-      Int_t iBin= 0;
-      if(x[dim]<(*bins)[i0]) {
-         iBin += i0-1;
-         // underflow
-      } else if(x[dim]>=(*bins)[i1]) {
-         // overflow
-         iBin += i1;
-      } else {
-         while(i1-i0>1) {
-            Int_t i2=(i0+i1)/2;
-            if(x[dim]<(*bins)[i2]) {
-               i1=i2;
-            } else {
-               i0=i2;
-            }
-         }
-         iBin += i0;
-      }
-      iAxisBins[dim]=iBin;
-   }
-   Int_t r=ToGlobalBin(iAxisBins);
-   if(r<0) r=0;
-   return r;
-}
-
-/********************* access by global bin number ******/
-
-TString TUnfoldBinning::GetBinName(Int_t iBin) const
-{
-   // get the name of a bin in the given tree
-   //    iBin: bin number
-   Int_t axisBins[MAXDIM] = {0};
-   TString r=TString::Format("#%d",iBin);
-   TUnfoldBinning const *distribution=ToAxisBins(iBin,axisBins);
-   if(distribution) {
-      r +=" (";
-      r += distribution->GetName();
-      Int_t dimension=distribution->GetDistributionDimension();
-      if(dimension>0) {
-         TString axisString;
-         for(Int_t axis=0;axis<dimension;axis++) {
-            TString thisAxisString=
-            distribution->GetDistributionAxisLabel(axis);
-            TVectorD const *bins=distribution->GetDistributionBinning(axis);
-            Int_t i=axisBins[axis];
-            if(i<0) thisAxisString += "[ufl]";
-            else if(i>=bins->GetNrows()-1) thisAxisString += "[ofl]";
-            else {
-               thisAxisString +=
-               TString::Format("[%.3g,%.3g]",(*bins)[i],(*bins)[i+1]);
-            }
-            axisString = ":"+thisAxisString+axisString;
-         }
-         r += axisString;
-      } else {
-         // extra bins
-         Int_t i=axisBins[0];
-         if((i>=0)&&(i<distribution->fAxisLabelList->GetEntriesFast())) {
-            r += distribution->GetDistributionAxisLabel(i);
-         } else {
-            r += TString::Format(" %d",i);
-         }
-      }
-      r +=")";
-   }
-   return r;
-}
-
-Double_t TUnfoldBinning::GetBinSize(Int_t iBin) const
-{
-   // get N-dimensional bin size
-   // input:
-   //    iBin : global bin number
-   //    includeUO : include underflow/overflow bins or not
-   Int_t axisBins[MAXDIM] = {0};
-   TUnfoldBinning const *distribution=ToAxisBins(iBin,axisBins);
-   Double_t r=0.0;
-   if(distribution) {
-      if(distribution->GetDistributionDimension()>0) r=1.0;
-      for(Int_t axis=0;axis<distribution->GetDistributionDimension();axis++) {
-         TVectorD const *bins=distribution->GetDistributionBinning(axis);
-         Int_t pos=axisBins[axis];
-         if(pos<0) {
-            r *= distribution->GetDistributionUnderflowBinWidth(axis);
-         } else if(pos>=bins->GetNrows()-1) {
-            r *= distribution->GetDistributionOverflowBinWidth(axis);
-         } else {
-            r *= (*bins)(pos+1)-(*bins)(pos);
-         }
-         if(r<=0.) break;
-      }
-   }
-   return r;
-}
-
-Double_t TUnfoldBinning::GetBinFactor(Int_t iBin) const
-{
-   // return user factor for a bin
-   //    iBin : global bin number
-   Int_t axisBins[MAXDIM] = {0};
-   TUnfoldBinning const *distribution=ToAxisBins(iBin,axisBins);
-   Double_t r=distribution->fBinFactorConstant;
-   if((r!=0.0) && distribution->fBinFactorFunction) {
-      Double_t x[MAXDIM];
-      Int_t dimension=distribution->GetDistributionDimension();
-      if(dimension>0) {
-         for(Int_t  axis=0;axis<dimension;axis++) {
-            x[axis]=distribution->GetDistributionBinCenter
-            (axis,axisBins[axis]);
-         }
-         r *= distribution->fBinFactorFunction->EvalPar
-         (x,distribution->fBinFactorFunction->GetParameters());
-      } else {
-         x[0]=axisBins[0];
-         r *= distribution->fBinFactorFunction->Eval(x[0]);
-      }
-
-   }
-   return r;
-}
-
-void TUnfoldBinning::GetBinNeighbours
-(Int_t bin,Int_t axis,Int_t *prev,Double_t *distPrev,
- Int_t *next,Double_t *distNext) const
-{
-   // get neighbour bins along the specified axis
-   // input:
-   //    bin,axis : bin number and axis number
-   // output:
-   //    prev: bin number of previous bin (or -1 if not existing)
-   //    distPrev: distance to previous bin
-   //    next: bin number of next bin (or -1 if not existing)
-   //    distNext: distance to next bin
-   Int_t axisBins[MAXDIM] = {0};
-   TUnfoldBinning const *distribution=ToAxisBins(bin,axisBins);
-   Int_t dimension=distribution->GetDistributionDimension();
-   *prev=-1;
-   *next=-1;
-   *distPrev=0.;
-   *distNext=0.;
-   if((axis>=0)&&(axis<dimension)) {
-      //TVectorD const *bins=distribution->GetDistributionBinning(axis);
-      //Int_t nBin=bins->GetNrows()-1;
-      Int_t centerBin= axisBins[axis];
-      axisBins[axis] =centerBin-1;
-      *prev=ToGlobalBin(axisBins);
-      if(*prev>=0) {
-         *distPrev=distribution->GetDistributionBinCenter(axis,axisBins[axis])-
-         distribution->GetDistributionBinCenter(axis,centerBin);
-      }
-      axisBins[axis] =centerBin+1;
-      *next=ToGlobalBin(axisBins);
-      if(*next>=0) {
-         *distNext=distribution->GetDistributionBinCenter(axis,axisBins[axis])-
-         distribution->GetDistributionBinCenter(axis,centerBin);
-      }
-   }
-}
-
-void TUnfoldBinning::GetBinUnderflowOverflowStatus
-(Int_t iBin,Int_t *uStatus,Int_t *oStatus) const
-{
-   // return bit map indicating underflow and overflow status
-   //  iBin: global bin number
-   // output
-   //  uStatus: bin map indicating whether the bin is in underflow
-   //  oStatus: bin map indicating whether the bin is in overflow
-   Int_t axisBins[MAXDIM] = {0};
-   TUnfoldBinning const *distribution=ToAxisBins(iBin,axisBins);
-   Int_t dimension=distribution->GetDistributionDimension();
-   *uStatus=0;
-   *oStatus=0;
-   for(Int_t axis=0;axis<dimension;axis++) {
-      TVectorD const *bins=distribution->GetDistributionBinning(axis);
-      Int_t nBin=bins->GetNrows()-1;
-      if(axisBins[axis]<0) *uStatus |= (1<<axis);
-      if(axisBins[axis]>=nBin) *oStatus |= (1<<axis);
-   }
-}
-
-/********************* access by bin number, given a projection mode ******/
-const TUnfoldBinning *TUnfoldBinning::GetBinLocation
-(Int_t binTHxx,const char *axisSteering,Int_t axisBins[MAXDIM]) const
-{
-   // locate the node corresponding to
-   //   a given THxx bin for a given projection mode
-   // input:
-   //    binTHxx : bin in histogram
-   //    axisSteering :
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   // output:
-   //    axisBins[]
-   //      for each axis of the identified binning node give the bin number
-   //            -1 underflow bin
-   //            >=0 inside distribution or overflow bin
-   //        special bin numbers
-   //            -2 : axis collapsed
-   //            -3 : axis collapsed and underflow bin excluded
-   //            -4 : axis collapsed and overflow bin excluded
-   //            -5 : axis collapsed and underflow+overflow bin excluded
-   // return value:
-   //    the binning node or 0 if not found
-   Int_t offset=binTHxx-GetStartBin();
-   return GetBinLocationRecursive(offset,axisSteering,axisBins);
-}
-
-const TUnfoldBinning *TUnfoldBinning::GetBinLocationRecursive
-(Int_t &offset,const char *axisSteering,Int_t axisBins[MAXDIM]) const
-{
-   // recursively locate the node corresponding to
-   //   a given THxx bin for a given projection mode
-   // input:
-   //    offset : start bin of this nodes in the histogram
-   //    axisSteering :
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   // output:
-   //    axisBins[]
-   //      for each axis of the identified binning node give the bin number
-   //            -1 underflow bin
-   //            >=0 inside distribution or overflow bin
-   //        special bin numbers
-   //            -2 : axis collapsed
-   //            -3 : axis collapsed and underflow bin excluded
-   //            -4 : axis collapsed and overflow bin excluded
-   //            -5 : axis collapsed and underflow+overflow bin excluded
-   // return value:
-   //    the binning node or 0 if not found
-
-   // decode axisSteering
-   //   isOptionGiven[0] ('C'): bit vector which axes to collapse
-   //   isOptionGiven[1] ('U'): bit vector to discarde underflow bins
-   //   isOptionGiven[2] ('U'): bit vector to discarde overflow bins
-   Int_t isOptionGiven[3] = { 0 };
-   DecodeAxisSteering(axisSteering,"CUO",isOptionGiven);
-   const TUnfoldBinning *r=0;
-   if(offset>=0) {
-      if(GetDistributionDimension()>0) {
-         Int_t nBinsTotal=1;
-         Int_t i=offset;
-         for(Int_t axis=0;axis<GetDistributionDimension();axis++) {
-            Int_t mask=1<<axis;
-            if(isOptionGiven[0] & mask) {
-               axisBins[axis]=-2;
-               if((isOptionGiven[1] & mask)&&
-                  (fHasUnderflow & mask)) axisBins[axis] -= 1;
-               if((isOptionGiven[2] & mask)&&
-                  (fHasOverflow & mask)) axisBins[axis] -= 2;
-            } else {
-               Int_t nBin=GetDistributionBinning(axis)->GetNrows()-1;
-               axisBins[axis]=0;
-               if((fHasUnderflow & mask) && !(isOptionGiven[1] & mask)) {
-                  nBin++;
-                  axisBins[axis]=-1;
-               }
-               if((fHasOverflow & mask) && !(isOptionGiven[2] & mask)) {
-                  nBin++;
-               }
-               axisBins[axis] += i % nBin;
-               i /= nBin;
-               nBinsTotal *= nBin;
-            }
-         }
-         offset -= nBinsTotal;
-         if(offset<0) {
-            r=this;
-         }
-      } else {
-         axisBins[0]=offset;
-         offset -= GetDistributionNumberOfBins();
-         if(offset<0) r=this;
-      }
-   }
-   if(!r) {
-      for(TUnfoldBinning const *child=GetChildNode();child;
-          child=child->GetNextNode()) {
-         r=child->GetBinLocationRecursive(offset,axisSteering,axisBins);
-         if(r) break;
-      }
-   }
-   return r;
-}
-
-Bool_t TUnfoldBinning::HasUnconnectedBins(void) const
-{
-   // check whether there are bins but no axis
-   return (!GetDistributionDimension())&&(GetDistributionNumberOfBins()>0);
-}
-
-Double_t TUnfoldBinning::GetDistributionAverageBinSize
-(Int_t axis,Bool_t includeUnderflow,Bool_t includeOverflow) const
-{
-   // get average bin size of the specified axis
-   //   axis : axis number
-   //   includeUnderflow : include underflow bin
-   //   includeOverflow : include overflow bin
-   Double_t r=0.0;
-   if((axis>=0)&&(axis<GetDistributionDimension())) {
-      TVectorD const *bins=GetDistributionBinning(axis);
-      Double_t d=(*bins)[bins->GetNrows()-1]-(*bins)[0];
-      Double_t nBins=bins->GetNrows()-1;
-      if(includeUnderflow && (fHasUnderflow & (1<<axis))) {
-         Double_t w=GetDistributionUnderflowBinWidth(axis);
-         if(w>0) {
-            nBins++;
-            d += w;
-         }
-      }
-      if(includeOverflow && (fHasOverflow & (1<<axis))) {
-         Double_t w=GetDistributionOverflowBinWidth(axis);
-         if(w>0.0) {
-            nBins++;
-            d += w;
-         }
-      }
-      if(nBins>0) {
-         r=d/nBins;
-      }
-   } else {
-      Error("GetDistributionAverageBinSize","axis %d does not exist",axis);
-   }
-   return r;
-}
-
-Double_t TUnfoldBinning::GetDistributionUnderflowBinWidth(Int_t axis) const
-{
-   // return width of the underflow bin
-   //   axis: axis number
-   TVectorD const *bins=GetDistributionBinning(axis);
-   return (*bins)[1]-(*bins)[0];
-}
-
-Double_t TUnfoldBinning::GetDistributionOverflowBinWidth(Int_t axis) const
-{
-   // return width of the underflow bin
-   //   axis: axis number
-   TVectorD const *bins=GetDistributionBinning(axis);
-   return (*bins)[bins->GetNrows()-1]-(*bins)[bins->GetNrows()-2];
-}
-
-Double_t TUnfoldBinning::GetDistributionBinCenter
-(Int_t axis,Int_t bin) const
-{
-   // position of the bin center
-   // input
-   //   axis : axis number
-   //   bin : bin number on the axis
-   TVectorD const *bins=GetDistributionBinning(axis);
-   Double_t r=0.0;
-   if(bin<0) {
-      // underflow bin
-      r=(*bins)[0]-0.5*GetDistributionUnderflowBinWidth(axis);
-   } else if(bin>=bins->GetNrows()-1) {
-      // overflow bin
-      r=(*bins)[bins->GetNrows()-1]+0.5*GetDistributionOverflowBinWidth(axis);
-   } else {
-      r=0.5*((*bins)[bin+1]+(*bins)[bin]);
-   }
-   return r;
-}
-
-Int_t TUnfoldBinning::ToGlobalBin(Int_t const *axisBins) const
-{
-   // get global bin number, given axis bin numbers
-   //   axisBins[]: bin numbers on each axis
-   // return: global bin nmber or -1 if not inside distribution
-   Int_t dimension=GetDistributionDimension();
-   Int_t r=0;
-   if(dimension>0) {
-      for(Int_t axis=dimension-1;axis>=0;axis--) {
-         Int_t nMax=GetDistributionBinning(axis)->GetNrows()-1;
-         Int_t i=axisBins[axis];
-         if(fHasUnderflow & (1<<axis)) {
-            nMax +=1;
-            i +=1;
-         }
-         if(fHasOverflow & (1<<axis)) nMax +=1;
-         if((i>=0)&&(i<nMax)) {
-            r = r*nMax +i;
-         } else {
-            r=-1;
-            break;
-         }
-      }
-      if(r>=0) {
-         r += GetStartBin();
-      }
-   } else {
-      if((axisBins[0]>=0)&&(axisBins[0]<GetDistributionNumberOfBins()))
-         r=GetStartBin()+axisBins[0];
-   }
-   return r;
-}
-
-TUnfoldBinning const *TUnfoldBinning::ToAxisBins
-(Int_t globalBin,Int_t *axisBins) const
-{
-   // return distribution in which the bin is located
-   // and bin numbers on the corresponding axes
-   // input
-   //   globalBin : global bin number
-   // output
-   //   if(GetDistributionDimension()>0)
-   //     axisBin[] : bin number on the individual axes
-   //                 bin numbers are starting with -1 (underflow)
-   //   else
-   //     axisBin[0] : bin number, counted from zero
-   // return value
-   //   the distribution in which the globalBin is located
-   //   or 0 if the globalBin is outside the tree
-   TUnfoldBinning const *r=0;
-   if((globalBin>=GetStartBin())&&(globalBin<GetEndBin())) {
-      TUnfoldBinning const *node;
-      for(node=GetChildNode();node && !r; node=node->GetNextNode()) {
-         r=node->ToAxisBins(globalBin,axisBins);
-      }
-      if(!r) {
-         r=this;
-         Int_t i=globalBin-GetStartBin();
-         Int_t dimension=GetDistributionDimension();
-         if(dimension>0) {
-            for(int axis=0;axis<dimension;axis++) {
-               Int_t nMax=GetDistributionBinning(axis)->GetNrows()-1;
-               axisBins[axis]=0;
-               if(fHasUnderflow & (1<<axis)) {
-                  axisBins[axis] =-1;
-                  nMax += 1;
-               }
-               if(fHasOverflow & (1<<axis)) nMax +=1;
-               axisBins[axis] += i % nMax;
-               i /= nMax;
-            }
-         } else {
-            axisBins[0]=i;
-         }
-      }
-   }
-   return r;
-}
-
-void TUnfoldBinning::DecodeAxisSteering
-(const char *axisSteering,const char *options,Int_t *isOptionGiven) const
-{
-   // decode axis steering
-   // input
-   //   axisSteering: the steering to decode
-   //   options: the allowed options to extract
-   // output
-   //   isOptionGiven[] : array of decoded steering options
-   //            the dimension of isOptionGiven[] has to match the number of
-   //            characters in "option"
-   //
-   // the axis steering is given in the form
-   //   steering1;steering2;...;steeringN
-   // all parts of the steering, sepatared by ';' are parsed
-   // each part must have the form
-   //   axisName[optionlist]
-   // where:
-   //   axisName : the name of the axis for which the optionlist is relevant
-   //               if the name is the character '*', all axes are matched
-   //   optionlist : for each option the corresonding character
-   //
-   // example:
-   //   imagine this node has two axes, named "xgen" and "ygen"
-   //  then
-   //   DecodeAxisSteering("*[u];xgen[c]","cuo",options);
-   //  will set the "U" option for all axes and the "C" option for the "xgen"
-   //  axis, so:
-   //    options[0]=0x1; // option 'c' is true for axis 0 (bit #0 is set)
-   //    options[1]=0x3; // option 'u' is true for both axes (bit #0,#1 are set)
-   //    options[2]=0x0; // option 'o' is not given (no bits are set)
-   Int_t nOpt=TString(options).Length();
-   for(Int_t i=0;i<nOpt;i++) isOptionGiven[i]=0;
-   if(axisSteering) {
-      TObjArray *patterns=TString(axisSteering).Tokenize(";");
-      Int_t nPattern=patterns->GetEntries();
-      Int_t nAxis=fAxisLabelList->GetEntries();
-      for(Int_t i=0;i<nPattern;i++) {
-         TString const &pattern=((TObjString * const)patterns->At(i))
-         ->GetString();
-         Int_t bracketBegin=pattern.Last('[');
-         Int_t len=pattern.Length();
-         if((bracketBegin>0)&&(pattern[len-1]==']')) {
-            TString axisId=pattern(0,bracketBegin);
-            Int_t mask=0;
-            if((axisId[0]=='*')&&(axisId.Length()==1)) {
-               // turn all bins on
-               mask=(1<<nAxis)-1;
-            } else {
-               // if axis is there, turn its bit on
-               for(Int_t j=0;j<nAxis;j++) {
-                  if(!axisId.CompareTo(GetDistributionAxisLabel(j))) {
-                     mask|= (1<<j);
-                  }
-               }
-            }
-            for(Int_t o=0;o<nOpt;o++) {
-               if(pattern.Last(options[o])>bracketBegin) {
-                  isOptionGiven[o] |= mask;
-               }
-            }
-         } else {
-            Error("DecodeAxisSteering",
-                  "steering \"%s\" does not end with [options]",
-                  (const char *)pattern);
-         }
-      }
-   }
-}
-
diff --git a/hist/unfold/CMakeLists.txt b/hist/unfold/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fc719703cbb8a6b9680fcfb483c6ecccaa4ecce9
--- /dev/null
+++ b/hist/unfold/CMakeLists.txt
@@ -0,0 +1,7 @@
+############################################################################
+# CMakeLists.txt file for building ROOT hist/unfold package
+############################################################################
+
+set(libname Unfold)
+
+ROOT_STANDARD_LIBRARY_PACKAGE(Unfold DEPENDENCIES Hist XMLParser Matrix DICTIONARY_OPTIONS "-writeEmptyRootPCM")
\ No newline at end of file
diff --git a/hist/unfold/Module.mk b/hist/unfold/Module.mk
new file mode 100644
index 0000000000000000000000000000000000000000..173fbe1053ebc5a2460e3980aec000d49f7ff20f
--- /dev/null
+++ b/hist/unfold/Module.mk
@@ -0,0 +1,75 @@
+# Module.mk for unfold module
+# Copyright (c) 2000 Rene Brun and Fons Rademakers
+#
+# Author: Olivier Couet, 23/11/2016
+
+MODNAME      := unfold
+MODDIR       := $(ROOT_SRCDIR)/hist/$(MODNAME)
+MODDIRS      := $(MODDIR)/src
+MODDIRI      := $(MODDIR)/inc
+
+UNFOLDDIR  := $(MODDIR)
+UNFOLDDIRS := $(UNFOLDDIR)/src
+UNFOLDDIRI := $(UNFOLDDIR)/inc
+
+##### libSpectrum #####
+UNFOLDL    := $(MODDIRI)/LinkDef.h
+UNFOLDDS   := $(call stripsrc,$(MODDIRS)/G__Spectrum.cxx)
+UNFOLDDO   := $(UNFOLDDS:.cxx=.o)
+UNFOLDDH   := $(UNFOLDDS:.cxx=.h)
+
+UNFOLDH    := $(filter-out $(MODDIRI)/LinkDef%,$(wildcard $(MODDIRI)/*.h))
+UNFOLDS    := $(filter-out $(MODDIRS)/G__%,$(wildcard $(MODDIRS)/*.cxx))
+UNFOLDO    := $(call stripsrc,$(UNFOLDS:.cxx=.o))
+
+UNFOLDDEP  := $(UNFOLDO:.o=.d) $(UNFOLDDO:.o=.d)
+
+UNFOLDLIB  := $(LPATH)/libSpectrum.$(SOEXT)
+UNFOLDMAP  := $(UNFOLDLIB:.$(SOEXT)=.rootmap)
+
+# used in the main Makefile
+ALLHDRS      += $(patsubst $(MODDIRI)/%.h,include/%.h,$(UNFOLDH))
+ALLLIBS      += $(UNFOLDLIB)
+ALLMAPS      += $(UNFOLDMAP)
+
+# include all dependency files
+INCLUDEFILES += $(UNFOLDDEP)
+
+##### local rules #####
+.PHONY:         all-$(MODNAME) clean-$(MODNAME) distclean-$(MODNAME)
+
+include/%.h:    $(UNFOLDDIRI)/%.h
+		cp $< $@
+
+$(UNFOLDLIB): $(UNFOLDO) $(UNFOLDDO) $(ORDER_) $(MAINLIBS) \
+                $(UNFOLDLIBDEP)
+		@$(MAKELIB) $(PLATFORM) $(LD) "$(LDFLAGS)" \
+		   "$(SOFLAGS)" libSpectrum.$(SOEXT) $@ \
+		   "$(UNFOLDO) $(UNFOLDDO)" \
+		   "$(UNFOLDLIBEXTRA)"
+
+$(call pcmrule,UNFOLD)
+	$(noop)
+
+$(UNFOLDDS):  $(UNFOLDH) $(UNFOLDL) $(ROOTCLINGEXE) $(call pcmdep,UNFOLD)
+		$(MAKEDIR)
+		@echo "Generating dictionary $@..."
+		$(ROOTCLINGSTAGE2) -f $@ $(call dictModule,UNFOLD) -c -writeEmptyRootPCM $(UNFOLDH) $(UNFOLDL)
+
+$(UNFOLDMAP): $(UNFOLDH) $(UNFOLDL) $(ROOTCLINGEXE) $(call pcmdep,UNFOLD)
+		$(MAKEDIR)
+		@echo "Generating rootmap $@..."
+		$(ROOTCLINGSTAGE2) -r $(UNFOLDDS) $(call dictModule,UNFOLD) -c $(UNFOLDH) $(UNFOLDL)
+
+all-$(MODNAME): $(UNFOLDLIB)
+
+clean-$(MODNAME):
+		@rm -f $(UNFOLDO) $(UNFOLDDO)
+
+clean::         clean-$(MODNAME)
+
+distclean-$(MODNAME): clean-$(MODNAME)
+		@rm -f $(UNFOLDDEP) $(UNFOLDLIB) $(UNFOLDMAP) \
+		   $(UNFOLDDS) $(UNFOLDDH)
+
+distclean::     distclean-$(MODNAME)
diff --git a/hist/unfold/doc/index.md b/hist/unfold/doc/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..c119ced298f0e7958a6fd728be683d2d96527aeb
--- /dev/null
+++ b/hist/unfold/doc/index.md
@@ -0,0 +1,7 @@
+\defgroup Unfold TUnfold classes
+\ingroup Hist
+
+An algorithm to unfold distributions from detector to truth level.
+
+\author Stefan Schmitt DESY
+
diff --git a/hist/unfold/inc/LinkDef.h b/hist/unfold/inc/LinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca6e63144f457d87afa20abcb3cb6dbc77561aeb
--- /dev/null
+++ b/hist/unfold/inc/LinkDef.h
@@ -0,0 +1,23 @@
+/* @(#)root/unfold:$Id$ */
+
+/*************************************************************************
+ * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
+ * All rights reserved.                                                  *
+ *                                                                       *
+ * For the licensing terms see $ROOTSYS/LICENSE.                         *
+ * For the list of contributors see $ROOTSYS/README/CREDITS.             *
+ *************************************************************************/
+
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class TUnfold+;
+#pragma link C++ class TUnfoldSys+;
+#pragma link C++ class TUnfoldBinning+;
+#pragma link C++ class TUnfoldDensity+;
+#pragma link C++ class TUnfoldBinningXML+;
+
+#endif
diff --git a/hist/hist/inc/TUnfold.h b/hist/unfold/inc/TUnfold.h
similarity index 60%
rename from hist/hist/inc/TUnfold.h
rename to hist/unfold/inc/TUnfold.h
index 24af3a3faad373aa0e4ec5546072569da4a9d019..8c8a91c4755999fc81f46a6e1f3662551dba1ab0 100644
--- a/hist/hist/inc/TUnfold.h
+++ b/hist/unfold/inc/TUnfold.h
@@ -1,9 +1,14 @@
 // Author: Stefan Schmitt
 // DESY, 13/10/08
 
-//  Version 17.1, bug fixes in GetFoldedOutput, GetOutput
+//  Version 17.6,  updated doxygen-style comments, add one argument for scanLCurve
 //
 //  History:
+//    Version 17.5, fix memory leak and other bugs
+//    Version 17.4, in parallel to changes in TUnfoldBinning
+//    Version 17.3, in parallel to changes in TUnfoldBinning
+//    Version 17.2, in parallel to changes in TUnfoldBinning
+//    Version 17.1, bug fixes in GetFoldedOutput, GetOutput
 //    Version 17.0, error matrix with SetInput, store fL not fLSquared
 //    Version 16.2, in parallel to bug-fix in TUnfoldSys
 //    Version 16.1, in parallel to bug-fix in TUnfold.C
@@ -60,7 +65,7 @@
 //  matrices with large dimensions.                                     //
 //                                                                      //
 //  Thus the algorithm should not used for large dimensions of x and y  //
-//    dim(x) should not exceed O(100)                                   //
+//    dim(x) should not exceed O(100)                                   //    
 //    dim(y) should not exceed O(500)                                   //
 //                                                                      //
 //////////////////////////////////////////////////////////////////////////
@@ -92,7 +97,7 @@
 #include <TObjArray.h>
 #include <TString.h>
 
-#define TUnfold_VERSION "V17.1"
+#define TUnfold_VERSION "V17.6"
 #define TUnfold_CLASS_VERSION 17
 
 
@@ -100,51 +105,110 @@ class TUnfold : public TObject {
  private:
    void InitTUnfold(void);     // initialize all data members
  public:
+
+   /// type of extra constraint
    enum EConstraint {
-      kEConstraintNone =0, // use no extra constraint
-      kEConstraintArea =1  // enforce preservation of the area
+
+      /// use no extra constraint
+      kEConstraintNone =0,
+
+      /// enforce preservation of the area
+      kEConstraintArea =1
+   };
+
+   /// choice of regularisation scheme
+   enum ERegMode {
+
+      /// no regularisation, or defined later by RegularizeXXX() methods
+      kRegModeNone = 0,
+
+      /// regularise the amplitude of the output distribution
+      kRegModeSize = 1,
+
+      /// regularize the 1st derivative of the output distribution
+      kRegModeDerivative = 2,
+
+      /// regularize the 2nd derivative of the output distribution
+      kRegModeCurvature = 3,
+
+
+      /// mixed regularisation pattern
+      kRegModeMixed = 4
    };
-   enum ERegMode {              // regularisation scheme
-      kRegModeNone = 0,         // no regularisation
-      kRegModeSize = 1,         // regularise the size of the output
-      kRegModeDerivative = 2,   // regularize the 1st derivative of the output
-      kRegModeCurvature = 3,    // regularize the 2nd derivative of the output
-      kRegModeMixed = 4         // mixed regularisation pattern
+
+   /// arrangement of axes for the response matrix (TH2 histogram)
+   enum EHistMap {
+
+      /// truth level on x-axis of the response matrix
+      kHistMapOutputHoriz = 0,
+
+      /// truth level on y-axis of the response matrix
+      kHistMapOutputVert = 1
    };
+
  protected:
-   TMatrixDSparse * fA;         // Input: matrix
-   TMatrixDSparse *fL;          // Input: regularisation conditions
-   TMatrixDSparse *fVyy;        // Input: covariance matrix for y
-   TMatrixD *fY;                // Input: y
-   TMatrixD *fX0;               // Input: x0
-   Double_t fTauSquared;        // Input: regularisation parameter
-   Double_t fBiasScale;         // Input: scale factor for the bias
-   TArrayI fXToHist;            // Input: matrix indices -> histogram bins
-   TArrayI fHistToX;            // Input: histogram bins -> matrix indices
-   TArrayD fSumOverY;           // Input: sum of all columns
-   EConstraint fConstraint;     // Input: type of constraint to use
-   ERegMode fRegMode;           // Input: type of regularisation
+   /// response matrix A
+   TMatrixDSparse * fA;
+   /// regularisation conditions L
+   TMatrixDSparse *fL;
+   /// input (measured) data y
+   TMatrixD *fY;
+   /// covariance matrix Vyy corresponding to y
+   TMatrixDSparse *fVyy;
+   /// scale factor for the bias
+   Double_t fBiasScale;
+   /// bias vector x0
+   TMatrixD *fX0;
+   /// regularisation parameter tau squared
+   Double_t fTauSquared;
+   /// mapping of matrix indices to histogram bins
+   TArrayI fXToHist;
+   /// mapping of histogram bins to matrix indices
+   TArrayI fHistToX;
+   /// truth vector calculated from the non-normalized response matrix
+   TArrayD fSumOverY;
+   /// type of constraint to use for the unfolding
+   EConstraint fConstraint;
+   /// type of regularisation
+   ERegMode fRegMode;
  private:
-   Int_t fIgnoredBins;          // number of input bins which are dropped because they have error=0
-   Double_t fEpsMatrix;         // machine accuracy for eingenvalue analysis
-   TMatrixD *fX;                // Result: x
-   TMatrixDSparse *fVyyInv;     // Result: inverse of covariance matrix on y
-   TMatrixDSparse *fVxx;        // Result: covariance matrix on x
-   TMatrixDSparse *fVxxInv;     // Result: inverse of covariance matrix on x
-   TMatrixDSparse *fAx;         // Result: Ax
-   Double_t fChi2A;             // Result: chi**2 contribution from (y-Ax)V(y-Ax)
-   Double_t fLXsquared;         // Result: chi**2 contribution from (x-s*x0)Lsquared(x-s*x0)
-   Double_t fRhoMax;            // Result: maximum global correlation
-   Double_t fRhoAvg;            // Result: average global correlation
-   Int_t fNdf;                  // Result: number of degrees of freedom
-   TMatrixDSparse *fDXDAM[2];   // Result: part of derivative dx_k/dA_ij
-   TMatrixDSparse *fDXDAZ[2];   // Result: part of derivative dx_k/dA_ij
-   TMatrixDSparse *fDXDtauSquared;     // Result: derivative dx/dtau
-   TMatrixDSparse *fDXDY;       // Result: derivative dx/dy
-   TMatrixDSparse *fEinv;       // Result: matrix E^(-1)
-   TMatrixDSparse *fE;          // Result: matrix E
+   /// number of input bins which are dropped because they have error=0
+   Int_t fIgnoredBins;
+   /// machine accuracy used to determine matrix rank after eigenvalue analysis
+   Double_t fEpsMatrix;
+   /// unfolding result x
+   TMatrixD *fX;
+   /// covariance matrix Vxx
+   TMatrixDSparse *fVxx;
+   /// inverse of covariance matrix Vxx<sup>-1</sub>
+   TMatrixDSparse *fVxxInv;
+   /// inverse of the input covariance matrix Vyy<sup>-1</sub>
+   TMatrixDSparse *fVyyInv;
+   /// result x folded back A*x
+   TMatrixDSparse *fAx;
+   /// chi**2 contribution from (y-Ax)Vyy<sup>-1</sub>(y-Ax)
+   Double_t fChi2A;
+   /// chi**2 contribution from (x-s*x0)<sup>T</sub>L<sup>T</sub>L(x-s*x0)
+   Double_t fLXsquared;
+   /// maximum global correlation coefficient
+   Double_t fRhoMax;
+   /// average global correlation coefficient
+   Double_t fRhoAvg;
+   /// number of degrees of freedom
+   Int_t fNdf;
+   /// matrix contribution to the of derivative dx_k/dA_ij
+   TMatrixDSparse *fDXDAM[2];
+   /// vector contribution to the of derivative dx_k/dA_ij
+   TMatrixDSparse *fDXDAZ[2];
+   /// derivative of the result wrt tau squared
+   TMatrixDSparse *fDXDtauSquared;
+   /// derivative of the result wrt dx/dy
+   TMatrixDSparse *fDXDY;
+   /// matrix E^(-1)
+   TMatrixDSparse *fEinv;
+   /// matrix E
+   TMatrixDSparse *fE;
  protected:
-   TUnfold(void);              // for derived classes
    // Int_t IsNotSymmetric(TMatrixDSparse const &m) const;
    virtual Double_t DoUnfold(void);     // the unfolding algorithm
    virtual void ClearResults(void);     // clear all results
@@ -159,91 +223,120 @@ class TUnfold : public TObject {
    TMatrixDSparse *InvertMSparseSymmPos(const TMatrixDSparse *A,Int_t *rank) const; // invert symmetric (semi-)positive sparse matrix
    void AddMSparse(TMatrixDSparse *dest,Double_t f,const TMatrixDSparse *src) const; // replacement for dest += f*src
    TMatrixDSparse *CreateSparseMatrix(Int_t nrow,Int_t ncol,Int_t nele,Int_t *row,Int_t *col,Double_t *data) const; // create a TMatrixDSparse from an array
+   /// returns internal number of output (truth) matrix rows
    inline Int_t GetNx(void) const {
       return fA->GetNcols();
-   } // number of non-zero output bins
+   }
+   /// converts truth histogram bin number to matrix row
+   inline Int_t GetRowFromBin(int ix) const { return fHistToX[ix]; }
+   /// converts matrix row to truth histogram bin number
+   inline Int_t GetBinFromRow(int ix) const { return fXToHist[ix]; }
+   /// returns the number of measurement bins
    inline Int_t GetNy(void) const {
       return fA->GetNrows();
-   } // number of input bins
+   }
+   /// vector of the unfolding result
+   inline const TMatrixD *GetX(void) const { return fX; }
+   /// covariance matrix of the result
+   inline const TMatrixDSparse *GetVxx(void) const { return fVxx; }
+   /// inverse of covariance matrix of the result
+   inline const TMatrixDSparse *GetVxxInv(void) const { return fVxxInv; }
+   /// vector of folded-back result
+   inline const TMatrixDSparse *GetAx(void) const { return fAx; }
+   /// matrix of derivatives dx/dy
+   inline const TMatrixDSparse *GetDXDY(void) const { return fDXDY; }
+   /// matrix contributions of the derivative dx/dA
+   inline const TMatrixDSparse *GetDXDAM(int i) const { return fDXDAM[i]; }
+   /// vector contributions of the derivative dx/dA
+   inline const TMatrixDSparse *GetDXDAZ(int i) const { return fDXDAZ[i]; }
+   /// matrix E<sup>-1</sup>, using internal bin counting
+   inline const TMatrixDSparse *GetEinv(void) const { return fEinv; }
+   /// matrix E, using internal bin counting
+   inline const TMatrixDSparse *GetE(void) const { return fE; }
+   /// inverse of covariance matrix of the data y
+   inline const TMatrixDSparse *GetVyyInv(void) const { return fVyyInv; }
+
    void ErrorMatrixToHist(TH2 *ematrix,const TMatrixDSparse *emat,const Int_t *binMap,Bool_t doClear) const; // return an error matrix as histogram
    Double_t GetRhoIFromMatrix(TH1 *rhoi,const TMatrixDSparse *eOrig,const Int_t *binMap,TH2 *invEmat) const; // return global correlation coefficients
-   inline const TMatrixDSparse *GetDXDY(void) const { return fDXDY; } // access derivative dx/dy
-   inline const TMatrixDSparse *GetDXDAM(int i) const { return fDXDAM[i]; } // access matrix parts of the derivative dx/dA
-   inline const TMatrixDSparse *GetDXDAZ(int i) const { return fDXDAZ[i]; } // access vector parts of the derivative dx/dA
-   inline const TMatrixDSparse *GetDXDtauSquared(void) const { return fDXDtauSquared; } // get derivative dx/dtauSquared
-   inline const TMatrixDSparse *GetAx(void) const { return fAx; } // get vector Ax
-   inline const TMatrixDSparse *GetEinv(void) const { return fEinv; } // get matrix E^-1
-   inline const TMatrixDSparse *GetE(void) const { return fE; } // get matrix E
-   inline const TMatrixDSparse *GetVxx(void) const { return fVxx; } // get covariance matrix of x
-   inline const TMatrixDSparse *GetVxxInv(void) const { return fVxxInv; } // get inverse of covariance matrix of x
-   inline const TMatrixDSparse *GetVyyInv(void) const { return fVyyInv; } // get inverse of covariance matrix of y
-   inline const TMatrixD *GetX(void) const { return fX; } // get result vector x
-   inline Int_t GetRowFromBin(int ix) const { return fHistToX[ix]; } // convert histogram bin number to matrix row
-   inline Int_t GetBinFromRow(int ix) const { return fXToHist[ix]; } // convert matrix row to histogram bin number
-   static void DeleteMatrix(TMatrixD **m); // delete and invalidate pointer
-   static void DeleteMatrix(TMatrixDSparse **m); // delete and invalidate pointer
+   /// vector of derivative dx/dtauSquared, using internal bin counting
+   inline const TMatrixDSparse *GetDXDtauSquared(void) const { return fDXDtauSquared; }
+   /// delete matrix and invalidate pointer
+   static void DeleteMatrix(TMatrixD **m);
+   /// delete sparse matrix and invalidate pointer
+   static void DeleteMatrix(TMatrixDSparse **m);
+
    Bool_t AddRegularisationCondition(Int_t i0,Double_t f0,Int_t i1=-1,Double_t f1=0.,Int_t i2=-1,Double_t f2=0.); // add regularisation condition for a triplet of output bins
    Bool_t AddRegularisationCondition(Int_t nEle,const Int_t *indices,const Double_t *rowData); // add a regularisation condition
 public:
-   enum EHistMap {              // mapping between unfolding matrix and TH2 axes
-      kHistMapOutputHoriz = 0,  // map unfolding output to x-axis of TH2 matrix
-      kHistMapOutputVert = 1    // map unfolding output to y-axis of TH2 matrix
-   };
-
+   static const char*GetTUnfoldVersion(void);
+   // Set up response matrix and regularisation scheme
    TUnfold(const TH2 *hist_A, EHistMap histmap,
            ERegMode regmode = kRegModeSize,
-           EConstraint constraint=kEConstraintArea);      // constructor
-   virtual ~TUnfold(void);    // delete data members
-   static const char*GetTUnfoldVersion(void);
-   void SetBias(const TH1 *bias);       // set alternative bias
-   void SetConstraint(EConstraint constraint); // set type of constraint for the next unfolding
-   Int_t RegularizeSize(int bin, Double_t scale = 1.0);   // regularise the size of one output bin
-   Int_t RegularizeDerivative(int left_bin, int right_bin, Double_t scale = 1.0); // regularize difference of two output bins (1st derivative)
-   Int_t RegularizeCurvature(int left_bin, int center_bin, int right_bin, Double_t scale_left = 1.0, Double_t scale_right = 1.0);  // regularize curvature of three output bins (2nd derivative)
-   Int_t RegularizeBins(int start, int step, int nbin, ERegMode regmode);        // regularize a 1-dimensional curve
-   Int_t RegularizeBins2D(int start_bin, int step1, int nbin1, int step2, int nbin2, ERegMode regmode);  // regularize a 2-dimensional grid
-   Double_t DoUnfold(Double_t tau,
-                     const TH1 *hist_y, Double_t scaleBias=0.0);  // do the unfolding
-   virtual Int_t SetInput(const TH1 *hist_y, Double_t scaleBias=0.0,Double_t oneOverZeroError=0.0,const TH2 *hist_vyy=0,const TH2 *hist_vyy_inv=0); // define input distribution
-   virtual Double_t DoUnfold(Double_t tau); // Unfold with given choice of tau
+           EConstraint constraint=kEConstraintArea);
+   // for root streamer and derived classes
+   TUnfold(void);
+   virtual ~TUnfold(void);
+   // define input distribution
+   virtual Int_t SetInput(const TH1 *hist_y, Double_t scaleBias=0.0,Double_t oneOverZeroError=0.0,const TH2 *hist_vyy=0,const TH2 *hist_vyy_inv=0);
+   // Unfold with given choice of tau and input 
+   virtual Double_t DoUnfold(Double_t tau);
+   Double_t DoUnfold(Double_t tau,const TH1 *hist_y, Double_t scaleBias=0.0);
+   // scan the L curve using successive calls to DoUnfold(Double_t) at various tau
    virtual Int_t ScanLcurve(Int_t nPoint,Double_t tauMin,
                             Double_t tauMax,TGraph **lCurve,
-                            TSpline **logTauX=0,TSpline **logTauY=0); // scan the L curve using successive calls to DoUnfold(Double_t) at various tau
-   void GetProbabilityMatrix(TH2 *A,EHistMap histmap) const; // get the matrix A of probabilities
-   void GetNormalisationVector(TH1 *s,const Int_t *binMap=0) const; // get the vector of normalisation factors, equivalent to the initial bias vector
-
-   void GetOutput(TH1 *output,const Int_t *binMap=0) const; // get output distribution, arbitrary bin mapping
+			    TSpline **logTauX=0,TSpline **logTauY=0,
+                            TSpline **logTauCurvature=0);
 
-   void GetBias(TH1 *bias,const Int_t *binMap=0) const; // get bias (includind biasScale)
-
-   void GetFoldedOutput(TH1 *folded,const Int_t *binMap=0) const; // get unfolding result folded back through the matrix
+   // access unfolding results
+   Double_t GetTau(void) const;
+   void GetOutput(TH1 *output,const Int_t *binMap=0) const;
+   void GetEmatrix(TH2 *ematrix,const Int_t *binMap=0) const;
+   void GetRhoIJ(TH2 *rhoij,const Int_t *binMap=0) const;
+   Double_t GetRhoI(TH1 *rhoi,const Int_t *binMap=0,TH2 *invEmat=0) const;
+   void GetFoldedOutput(TH1 *folded,const Int_t *binMap=0) const;
 
+   // access input parameters
+   void GetProbabilityMatrix(TH2 *A,EHistMap histmap) const;
+   void GetNormalisationVector(TH1 *s,const Int_t *binMap=0) const; // get the vector of normalisation factors, equivalent to the initial bias vector
    void GetInput(TH1 *inputData,const Int_t *binMap=0) const; // get input data
-
-   void GetRhoIJ(TH2 *rhoij,const Int_t *binMap=0) const; // get correlation coefficients, arbitrary bin mapping
-
-   void GetEmatrix(TH2 *ematrix,const Int_t *binMap=0) const; // get error matrix, arbitrary bin mapping
-
-   Double_t GetRhoI(TH1 *rhoi,const Int_t *binMap=0,TH2 *invEmat=0) const; // get global correlation coefficients, arbitrary bin mapping
-
-   void GetLsquared(TH2 *lsquared) const; // get regularisation conditions squared
-
-   inline Int_t GetNr(void) const { return fL->GetNrows(); } // number of regularisation conditions
+   void GetInputInverseEmatrix(TH2 *ematrix);   // get input data inverse of error matrix
+   void GetBias(TH1 *bias,const Int_t *binMap=0) const; // get bias (includind biasScale)
+   Int_t GetNr(void) const; // number of regularisation conditions
    void GetL(TH2 *l) const; // get matrix of regularisation conditions
+   void GetLsquared(TH2 *lsquared) const;
 
-   void GetInputInverseEmatrix(TH2 *ematrix);   // get input data inverse of error matrix
+   // access various properties of the result
+   /// get maximum global correlation determined in recent unfolding
+   inline Double_t GetRhoMax(void) const { return fRhoMax; }
+   /// get average global correlation determined in recent unfolding
+   inline Double_t GetRhoAvg(void) const { return fRhoAvg; }
+   /// get &chi;<sup>2</sup><sub>A</sub> contribution determined in recent unfolding
+   inline Double_t GetChi2A(void) const { return fChi2A; }
 
-   Double_t GetTau(void) const;  // get regularisation parameter
-   inline Double_t GetRhoMax(void) const { return fRhoMax; } // get maximum global correlation
-   inline Double_t GetRhoAvg(void) const { return fRhoAvg; }  // get average global correlation
-   inline Double_t GetChi2A(void) const { return fChi2A; }  // get chi**2 contribution from A
-   Double_t GetChi2L(void) const;        // get chi**2 contribution from L
+   Double_t GetChi2L(void) const; // get &chi;<sup>2</sup><sub>L</sub> contribution determined in recent unfolding
    virtual Double_t GetLcurveX(void) const;        // get value on x axis of L curve
    virtual Double_t GetLcurveY(void) const;        // get value on y axis of L curve
-   inline Int_t GetNdf(void) const { return fNdf; }   // get number of degrees of freedom
+   /// get number of degrees of freedom determined in recent unfolding
+   ///
+   /// This returns the number of valid measurements minus the number
+   /// of unfolded truth bins. If the area constraint is active, one
+   /// further degree of freedom is subtracted
+   inline Int_t GetNdf(void) const { return fNdf; }
    Int_t GetNpar(void) const;  // get number of parameters
 
-   inline Double_t GetEpsMatrix(void) const { return  fEpsMatrix; } // get accuracy for eingenvalue analysis
+   // advanced features
+   void SetBias(const TH1 *bias);       // set alternative bias
+   void SetConstraint(EConstraint constraint); // set type of constraint for the next unfolding
+   Int_t RegularizeSize(int bin, Double_t scale = 1.0);   // regularise the size of one output bin
+   Int_t RegularizeDerivative(int left_bin, int right_bin, Double_t scale = 1.0); // regularize difference of two output bins (1st derivative)
+   Int_t RegularizeCurvature(int left_bin, int center_bin, int right_bin, Double_t scale_left = 1.0, Double_t scale_right = 1.0);  // regularize curvature of three output bins (2nd derivative)
+   Int_t RegularizeBins(int start, int step, int nbin, ERegMode regmode);        // regularize a 1-dimensional curve
+   Int_t RegularizeBins2D(int start_bin, int step1, int nbin1, int step2, int nbin2, ERegMode regmode);  // regularize a 2-dimensional grid
+   /// get numerical accuracy for Eigenvalue analysis when inverting
+   /// matrices with rank problems
+   inline Double_t GetEpsMatrix(void) const { return  fEpsMatrix; } 
+   /// set numerical accuracy for Eigenvalue analysis when inverting
+   /// matrices with rank problems
    void SetEpsMatrix(Double_t eps); // set accuracy for eigenvalue analysis
 
    ClassDef(TUnfold, TUnfold_CLASS_VERSION) //Unfolding with support for L-curve analysis
diff --git a/hist/hist/inc/TUnfoldBinning.h b/hist/unfold/inc/TUnfoldBinning.h
similarity index 64%
rename from hist/hist/inc/TUnfoldBinning.h
rename to hist/unfold/inc/TUnfoldBinning.h
index 2ec68b718f51275f840e731af35f69ded3dbb03a..2384ab90762aa3f9087c83147547239783fc7d8c 100644
--- a/hist/hist/inc/TUnfoldBinning.h
+++ b/hist/unfold/inc/TUnfoldBinning.h
@@ -1,9 +1,13 @@
 // Author: Stefan Schmitt
 // DESY, 10/08/11
 
-//  Version 17.1, in parallel to TUnfold
+//  Version 17.5, in parallel to changes in TUnfold
 //
 //  History:
+//    Version 17.4, bug fix with error handling
+//    Version 17.3, bug fix with underflow/overflow bins
+//    Version 17.2, new option isPeriodic
+//    Version 17.1, in parallel to TUnfold
 //    Version 17.0, initial version, numbered in parallel to TUnfold
 
 #ifndef ROOT_TUnfoldBinning
@@ -42,31 +46,48 @@
 #include <TNamed.h>
 #include <TObjArray.h>
 #include <TObjString.h>
-
-class TAxis;
-class TF1;
+#include <TAxis.h>
+#include <TF1.h>
 
 
 class TUnfoldBinning : public TNamed {
  protected:
-   TUnfoldBinning *parentNode; // mother node
-   TUnfoldBinning *childNode; // first daughter node
-   TUnfoldBinning *nextNode; // next sister
-   TUnfoldBinning *prevNode; // previous sister
-   TObjArray *fAxisList; // for each axis the bin borders (TVectorD)
-   TObjArray *fAxisLabelList; // for each axis its name (TObjString)
-   Int_t fHasUnderflow,fHasOverflow; // bit fields indicating whether there are underflow/overflow bins on the axes
-   Int_t fDistributionSize; // number of bins in this node's distribution
-   Int_t fFirstBin; // global bin number of the first bin
-   Int_t fLastBin; // global bin number of the last(+1) bin
-   TF1 *fBinFactorFunction; // function to calculate user factor from bin centres (default function is a constant)
-   Double_t fBinFactorConstant; // scale factor on user factor
+   /// mother node
+   TUnfoldBinning *parentNode;
+   /// first daughter node
+   TUnfoldBinning *childNode;
+   /// next sister
+   TUnfoldBinning *nextNode;
+   /// previous sister
+   TUnfoldBinning *prevNode;
+   /// for each axis the bin borders (TVectorD)
+   TObjArray *fAxisList;
+   /// for each axis its name (TObjString), or names of unconnected bins
+   TObjArray *fAxisLabelList;
+   /// bit fields indicating whether there are underflow bins on the axes
+   Int_t fHasUnderflow;
+   /// bit fields indicating whether there are overflow bins on the axes
+   Int_t fHasOverflow;
+   /// number of bins in this node's distribution
+   Int_t fDistributionSize;
+   /// global bin number of the first bin
+   Int_t fFirstBin;
+   /// global bin number of the last(+1) bin, including daughters
+   Int_t fLastBin;
+   /// function to calculate a scale factor from bin centres (may be a TF1 or a TVectorD
+   TObject *fBinFactorFunction;
+   /// common scale factor for all bins of this node
+   Double_t fBinFactorConstant;
  public:
    /********************* setup **************************/
-
+   enum {
+      /// maximum numner of axes per distribution
+      MAXDIM=32
+   };
    TUnfoldBinning(const char *name=0,Int_t nBins=0,const char *binNames=0); // create a new root node with a given number of unconnected bins
    TUnfoldBinning(const TAxis &axis,Int_t includeUnderflow,Int_t includeOverflow); // create a binning scheme with one axis
-   TUnfoldBinning *AddBinning(TUnfoldBinning *binning); // add a new node to the TUnfoldBinning tree
+   TUnfoldBinning *AddBinning
+      (TUnfoldBinning *binning); // add a new node to the TUnfoldBinning tree
    TUnfoldBinning *AddBinning(const char *name,Int_t nBins=0,const char *binNames=0); // add a new node to the TUnfoldBinning tree
    Bool_t AddAxis(const char *name,Int_t nBins,const Double_t *binBorders,
                 Bool_t hasUnderflow,Bool_t hasOverflow); // add an axis (variable bins) to the distribution associated with this node
@@ -74,16 +95,21 @@ class TUnfoldBinning : public TNamed {
                 Bool_t hasUnderflow,Bool_t hasOverflow); // add an axis (equidistant bins) to the distribution associated with this node
    Bool_t AddAxis(const TAxis &axis,Bool_t includeUnderflow,Bool_t includeOverflow); // add an axis (from TAxis instance) to the distribution associated with this node
    virtual ~TUnfoldBinning(void);
-   void PrintStream(std::ostream &out,Int_t indent=0) const;
-   inline void SetBinFactorFunction(Double_t normalisation,TF1 *userFunc=0) {
-      fBinFactorConstant=normalisation; fBinFactorFunction=userFunc; }// define function to calculate bin factor
+   void PrintStream(std::ostream &out,Int_t indent=0,int debug=0) const;
+   void SetBinFactorFunction(Double_t normalisation,TF1 *userFunc=0); // define function to calculate bin factor. Note: the function is not owned by this class
 
    /********************* Navigation **********************/
-   inline TUnfoldBinning const *GetChildNode(void) const { return childNode; } // first daughter
-   inline TUnfoldBinning const *GetPrevNode(void) const { return prevNode; } // previoous sister
-   inline TUnfoldBinning const *GetNextNode(void) const { return nextNode; } // next sister
-   inline TUnfoldBinning const *GetParentNode(void) const { return parentNode; } // mother
+   /// first daughter node
+   inline TUnfoldBinning const *GetChildNode(void) const { return childNode; }
+   /// previous sister node
+   inline TUnfoldBinning const *GetPrevNode(void) const { return prevNode; }
+   /// next sister node
+   inline TUnfoldBinning const *GetNextNode(void) const { return nextNode; }
+   /// mother node
+   inline TUnfoldBinning const *GetParentNode(void) const { return parentNode; }
    TUnfoldBinning const *FindNode(char const *name) const; // find node by name
+   /// return root node of the binnig scheme
+   TUnfoldBinning const *GetRootNode(void) const;
 
    /********************* Create THxx histograms **********/
    Int_t GetTH1xNumberOfBins(Bool_t originalAxisBinning=kTRUE,const char *axisSteering=0) const; // get number of bins of a one-dimensional histogram TH1
@@ -96,49 +122,66 @@ class TUnfoldBinning : public TNamed {
                                            Bool_t originalYAxisBinning=kFALSE,
                                            char const *histogramTitle=0); // create 2D histogram with one binning on the x axis and the other binning on the y axis
    TH1 *ExtractHistogram(const char *histogramName,const TH1 *globalBins,const TH2 *globalBinsEmatrix=0,Bool_t originalAxisBinning=kTRUE,const char *axisSteering=0) const; // extract a distribution from the given set of global bins
+   /********************* Create and manipulate bin map ****/
+   Int_t *CreateEmptyBinMap(void) const; // create empty bin map
+   void SetBinMapEntry(Int_t *binMap,Int_t globalBin,Int_t destBin) const; // change mapping for a given global bin
+   Int_t FillBinMap1D(Int_t *binMap,const char *axisSteering,
+                      Int_t firstBinX) const; // map bins from this distribution to destHist
    /********************* Calculate global bin number ******/
    Int_t GetGlobalBinNumber(Double_t x) const; // get bin number 1-dim distribution
    Int_t GetGlobalBinNumber(Double_t x,Double_t y) const; // get bin number 2-dim distribution
    Int_t GetGlobalBinNumber(Double_t x,Double_t y,Double_t z) const; // get bin number 3-dim distribution
-   Int_t GetGlobalBinNumber(Double_t x0,Double_t x1,Double_t x2,Double_t x3) const; // get bin number for given variables, up to four-dimensional binning
-   Int_t GetGlobalBinNumber(const Double_t *x) const; // get bin number, up to 32 dimenstional binning
-   inline Int_t GetStartBin(void) const { return fFirstBin; } // first bin of this node
-   inline Int_t GetEndBin(void) const { return fLastBin; } // last+1 bin of this node (includes children)
+   Int_t GetGlobalBinNumber(Double_t x0,Double_t x1,Double_t x2,Double_t x3) const; // get bin number four-dimensional binning
+   Int_t GetGlobalBinNumber(Double_t x0,Double_t x1,Double_t x2,Double_t x3,Double_t x4) const; // get bin number five-dimensional binning
+   Int_t GetGlobalBinNumber(Double_t x0,Double_t x1,Double_t x2,Double_t x3,Double_t x4,Double_t x5) const; // get bin number six-dimensional binning
+   Int_t GetGlobalBinNumber(const Double_t *x,Int_t *isBelow=0,Int_t *isAbove=0) const; // get bin number, up to 32 dimensional binning 
+   /// first bin of this node
+   inline Int_t GetStartBin(void) const { return fFirstBin; }
+   /// last+1 bin of this node (includes children)
+   inline Int_t GetEndBin(void) const { return fLastBin; }
+   virtual Bool_t IsBinFactorGlobal(void) const; // check whether global or local bin factor must be used
+   Double_t GetGlobalFactor(void) const; // return global factor
 
     /********************* access by global bin number ******/
    TString GetBinName(Int_t iBin) const; // return bin name
    Double_t GetBinSize(Int_t iBin) const; // return bin size (in N dimensions)
    virtual Double_t GetBinFactor(Int_t iBin) const; // return user factor
    void GetBinUnderflowOverflowStatus(Int_t iBin,Int_t *uStatus,Int_t *oStatus) const; // return bit map indicating underflow and overflow status
-   void GetBinNeighbours(Int_t globalBin,Int_t axis,
-                         Int_t *prev,Double_t *distPrev,
-                         Int_t *next,Double_t *distNext) const; // get neighbour bins along an axis
-   /********************* access by bin number, given an axis steering ******/
-   enum { MAXDIM=32 };
-   const TUnfoldBinning *GetBinLocation(Int_t binTHxx,const char *axisSteering,
-                                  Int_t axisBins[MAXDIM]) const; //  locate a given THxx bin for a given axis steering
-   void DecodeAxisSteering(const char *axisSteering,const char *options,
-                           Int_t *isOptionGiven) const; // decode axis steering options
+   Int_t GetBinNeighbours(Int_t globalBin,Int_t axis,
+                          Int_t *prev,Double_t *distPrev,
+                          Int_t *next,Double_t *distNext,
+                          Bool_t isPeriodic=kFALSE) const; // get neighbour bins along an axis
    /********************** access distribution properties *************/
-   inline Int_t GetDistributionNumberOfBins(void) const { return fDistributionSize; } // number of bins in the distribution possibly including under/overflow
-   inline Int_t GetDistributionDimension(void) const {  return fAxisList->GetEntriesFast(); } // query dimension of this node's distribution
+   /// number of bins in the distribution possibly including under/overflow
+   inline Int_t GetDistributionNumberOfBins(void) const { return fDistributionSize; }
+   /// query dimension of this node's distribution
+   inline Int_t GetDistributionDimension(void) const {  return fAxisList->GetEntriesFast(); }
    virtual Double_t GetDistributionAverageBinSize(Int_t axis,Bool_t includeUnderflow, Bool_t includeOverflow) const; // get average bin size
+   /// get vector of bin borders for one axis
    inline TVectorD const *GetDistributionBinning(Int_t axis) const {
-      return (TVectorD const *)fAxisList->At(axis); } // get bin borders for some axis
+      return (TVectorD const *)fAxisList->At(axis); }
+   /// get name of an axis
    inline TString GetDistributionAxisLabel(Int_t axis) const {
-      return ((TObjString * const)fAxisLabelList->At(axis))->GetString(); }// get name of this axis
+      return ((TObjString * const)fAxisLabelList->At(axis))->GetString(); }
 
    virtual Double_t GetDistributionUnderflowBinWidth(Int_t axis) const; // width of underflow bin on the given axis
    virtual Double_t GetDistributionOverflowBinWidth(Int_t axis) const; // width of overflow bin on the given axis
    virtual Double_t GetDistributionBinCenter(Int_t axis,Int_t bin) const; // position of bin center on the given axis
+   Bool_t HasUnconnectedBins(void) const; // check whether this node has bins without axis
+   const TObjString *GetUnconnectedBinName(Int_t bin) const; // return bin name (if any)
+   /// check whether an axis has an underflow bin
+   Bool_t HasUnderflow(int axis) const { return fHasUnderflow & (1<<axis); }
+   /// check whether the axis has an overflow bin
+   Bool_t HasOverflow(int axis) const { return fHasOverflow & (1<<axis); }
+   void DecodeAxisSteering(const char *axisSteering,const char *options,
+			     Int_t *isOptionGiven) const; // decode axis steering options
  protected:
-   TUnfoldBinning *GetRootNode(void); // return root node
-   TUnfoldBinning const *GetRootNode(void) const; // return root node
+   /// return root node
+   TUnfoldBinning *GetRootNode(void);
    void Initialize(Int_t nBins);
    Int_t UpdateFirstLastBin(Bool_t startWithRootNode=kTRUE); // update fFirstBin and fLastBin
-   Bool_t HasUnconnectedBins(void) const; // check whether this node has bins without axis
    TUnfoldBinning const *ToAxisBins(Int_t globalBin,Int_t *axisBins) const; // return distribution in which the bin is located
-   Int_t ToGlobalBin(Int_t const *axisBins) const; // return -1 if not inside distribution
+   Int_t ToGlobalBin(Int_t const *axisBins,Int_t *isBelow=0,Int_t *isAbove=0) const; // return -1 if not inside distribution
    TString BuildHistogramTitle(const char *histogramName,const char *histogramTitle,
                                Int_t const *axisList) const; // construct histogram title
    TString BuildHistogramTitle2D(const char *histogramName,const char *histogramTitle,
@@ -146,13 +189,12 @@ class TUnfoldBinning : public TNamed {
    Int_t GetTHxxBinning(Int_t maxDim,Int_t *axisBins,Int_t *axisList,const char *axisSteering) const; // get binning information for creating a THxx
    Int_t GetTHxxBinningSingleNode(Int_t maxDim,Int_t *axisBins,Int_t *axisList,const char *axisSteering) const; // get binning information for creating a THxx
    Int_t GetTHxxBinsRecursive(const char *axisSteering) const; // get binning information for creating a THxx
-   const TUnfoldBinning *GetBinLocationRecursive(Int_t &offset,const char *axisSteering,
-                                  Int_t axisBins[MAXDIM]) const; //  locate a THxx bin offset for a given axis steering
    const TUnfoldBinning *GetNonemptyNode(void) const; // get the only nodes with non-empty distributions if there are multiple nodes, return 0
    Int_t *CreateBinMap(const TH1 *hist,Int_t nDim,const Int_t *axisList,const char *axisSteering) const; // create mapping from global bins to a histogram
    Int_t FillBinMapRecursive(Int_t startBin,const char *axisSteering,
                             Int_t *binMap) const; // fill bin map recursively
    Int_t FillBinMapSingleNode(const TH1 *hist,Int_t startBin,Int_t nDim,const Int_t *axisList,const char *axisSteering,Int_t *binMap) const; // fill bin map for a single node
+   void SetBinFactor(Double_t normalisation,TObject *factors); // define function to calculate bin factor. Note: the object is owned by this class, unless it is a function
 
    ClassDef(TUnfoldBinning, TUnfold_CLASS_VERSION) //Complex binning schemes for TUnfoldDensity
 };
diff --git a/hist/unfold/inc/TUnfoldBinningXML.h b/hist/unfold/inc/TUnfoldBinningXML.h
new file mode 100644
index 0000000000000000000000000000000000000000..e843258dee9f5dd684a683822a896eac21aa1468
--- /dev/null
+++ b/hist/unfold/inc/TUnfoldBinningXML.h
@@ -0,0 +1,75 @@
+// Author: Stefan Schmitt
+// DESY, 10/08/11
+
+//  Version 17.5, in parallel to changes in TUnfold
+//
+//  History:
+//    Version 17.4, in parallel to changes in TUnfoldBinning
+//    Version 17.3, support for repeated bins with the same width
+//    Version 17.2, XML interface for class TUnfoldBinning
+
+#ifndef ROOT_TUnfoldBinningXML
+#define ROOT_TUnfoldBinningXML
+
+
+//////////////////////////////////////////////////////////////////////////
+//                                                                      //
+//                                                                      //
+//  TUnfoldBinningXML, an auxillary class to read and write             //
+//  complex binning schemes in XML                                      //
+//                                                                      //
+//  Citation: S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]        //
+//                                                                      //
+//////////////////////////////////////////////////////////////////////////
+
+/*
+  This file is part of TUnfold.
+
+  TUnfold is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  TUnfold is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with TUnfold.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "TUnfoldBinning.h"
+#include <iostream>
+#include <TNamed.h>
+#include <TObjArray.h>
+#include <TObjString.h>
+#include <TXMLNode.h>
+#include <TXMLDocument.h>
+#include <iostream>
+
+class TXMLNode;
+class TXMLDocument;
+
+
+class TUnfoldBinningXML : public TUnfoldBinning {
+ public:
+   /********************** XML interface to read binning schemes *************/
+static TUnfoldBinningXML *ImportXML(const TXMLDocument *document,const char *name); // import binning scheme
+   static Int_t ExportXML(const TUnfoldBinning &binning,std::ostream &out,Bool_t writeHeader,Bool_t writeFooter,Int_t indent=0); // append binning scheme to file
+   Int_t ExportXML(const char *fileName) const; // export this binning scheme
+   static void WriteDTD(const char *fileName="tunfoldbinning.dtd"); // write DTD file
+   static void WriteDTD(std::ostream &out); // write DTD to stream
+
+   /// construct a new binning scheme, for use with the root streamer
+   TUnfoldBinningXML (const char *name=0,Int_t nBins=0,const char *binNames=0) 
+      : TUnfoldBinning (name,nBins,binNames) { }
+ protected:
+   static TUnfoldBinningXML *ImportXMLNode(TXMLNode *node); // import the given node as binning scheme
+   void AddAxisXML(TXMLNode *node); // import axis information
+protected:
+
+   ClassDef(TUnfoldBinningXML, TUnfold_CLASS_VERSION) //Complex binning schemes for TUnfoldDensity
+};
+
+#endif
diff --git a/hist/hist/inc/TUnfoldDensity.h b/hist/unfold/inc/TUnfoldDensity.h
similarity index 57%
rename from hist/hist/inc/TUnfoldDensity.h
rename to hist/unfold/inc/TUnfoldDensity.h
index 7ffcb5b3a6967eed6b1e3e572cb6579eec3fbed8..d93981377b1a62405434c4c2c930c84506c36339 100644
--- a/hist/hist/inc/TUnfoldDensity.h
+++ b/hist/unfold/inc/TUnfoldDensity.h
@@ -1,10 +1,14 @@
 // Author: Stefan Schmitt
 // DESY, 11/08/11
 
-//  Version 17.1, add scan type RhoSquare
+//  Version 17.5, bug fix in TUnfold also corrects GetEmatrixSysUncorr()
 //
 //  History:
-//     Version 17.0, support for density regularisation and complex binning schemes
+//    Version 17.4, in parallel to changes in TUnfoldBinning
+//    Version 17.3, in parallel to changes in TUnfoldBinning
+//    Version 17.2, in parallel to changes in TUnfoldBinning
+//    Version 17.1, add scan type RhoSquare
+//    Version 17.0, support for density regularisation and complex binning schemes
 
 #ifndef ROOT_TUnfoldDensity
 #define ROOT_TUnfoldDensity
@@ -43,25 +47,33 @@
 
 class TUnfoldDensity : public TUnfoldSys {
  protected:
-   const TUnfoldBinning * fConstOutputBins; // binning scheme for the output
-   const TUnfoldBinning * fConstInputBins; // binning scheme for the input
-   TUnfoldBinning *fOwnedOutputBins; // output binning scheme if owner
-   TUnfoldBinning *fOwnedInputBins; // input binning scheme if owner
-   TUnfoldBinning *fRegularisationConditions; // binning scheme for the regularisation conditions
+   /// binning scheme for the output (truth level)
+   const TUnfoldBinning * fConstOutputBins;
+   /// binning scheme for the input (detector level)
+   const TUnfoldBinning * fConstInputBins;
+   /// pointer to output binning scheme if owned by this class
+   TUnfoldBinning *fOwnedOutputBins;
+   /// pointer to input binning scheme if owned by this class
+   TUnfoldBinning *fOwnedInputBins;
+   /// binning scheme for the regularisation conditions
+   TUnfoldBinning *fRegularisationConditions;
 
  public:
+   /// choice of regularisation scale factors to cinstruct the matrix L
    enum EDensityMode {
-     kDensityModeeNone=0,
-     kDensityModeBinWidth=1,
-     kDensityModeUser=2,
-     kDensityModeBinWidthAndUser=3
+      /// no scale factors, matrix L is similar to unity matrix
+      kDensityModeNone=0,
+      /// scale factors from multidimensional bin width
+      kDensityModeBinWidth=1,
+      /// scale factors from user function in TUnfoldBinning
+      kDensityModeUser=2,
+      /// scale factors from multidimensional bin width and  user function
+      kDensityModeBinWidthAndUser=3
    };
  protected:
 
    virtual TString GetOutputBinName(Int_t iBinX) const; // name a bin
 
-   TUnfoldDensity(void); // constructor for derived classes, do nothing
-
    Double_t GetDensityFactor(EDensityMode densityMode,Int_t iBin) const; // density correction factor for this bin
    void RegularizeDistributionRecursive
      (const TUnfoldBinning *binning,ERegMode regmode,
@@ -72,29 +84,37 @@ class TUnfoldDensity : public TUnfoldSys {
       EDensityMode densityMode,const char *axisSteering); // regularize the distribution of one binning node
 
  public:
+   TUnfoldDensity(void); // constructor for derived classes, do nothing
+
    TUnfoldDensity(const TH2 *hist_A, EHistMap histmap,
-                  ERegMode regmode = kRegModeCurvature,
-                  EConstraint constraint=kEConstraintArea,
-                  EDensityMode densityMode=kDensityModeBinWidthAndUser,
-                  const TUnfoldBinning *outputBins=0,
-                  const TUnfoldBinning *inputBins=0,
-                  const char *regularisationDistribution=0,
-                  const char *regularisationAxisSteering="*[UOB]"); // constructor for using the histogram classes. Default regularisation is on the curvature of the bin-width normalized density, excluding underflow and overflow bins
+		     ERegMode regmode = kRegModeCurvature,
+		     EConstraint constraint=kEConstraintArea,
+		     EDensityMode densityMode=kDensityModeBinWidthAndUser,
+		     const TUnfoldBinning *outputBins=0,
+		     const TUnfoldBinning *inputBins=0,
+		     const char *regularisationDistribution=0,
+		     const char *regularisationAxisSteering="*[UOB]"); // constructor for using the histogram classes. Default regularisation is on the curvature of the bin-width normalized density, excluding underflow and overflow bins
 
    virtual ~ TUnfoldDensity(void); // delete data members
 
    void RegularizeDistribution(ERegMode regmode,EDensityMode densityMode,
-                               const char *distribution,
-                               const char *axisSteering); // regularize distribution(s) of the output binning scheme
-
-
-   enum EScanTauMode { // scan mode of correlation scan
-      kEScanTauRhoAvg =0, // average global correlation coefficient (from TUnfold::GetRhoI())
-      kEScanTauRhoMax =1, // maximum global correlation coefficient (from TUnfold::GetRhoI())
-      kEScanTauRhoAvgSys =2, // average global correlation coefficient (from TUnfoldSys::GetRhoItotal())
-      kEScanTauRhoMaxSys =3,  // maximum global correlation coefficient (from TUnfoldSys::GetRhoItotal())
-      kEScanTauRhoSquareAvg =4, // average global correlation coefficient squared (from TUnfold::GetRhoI())
-      kEScanTauRhoSquareAvgSys =5 // average global correlation coefficient squared (from TUnfoldSys::GetRhoItotal())
+			       const char *distribution,
+			       const char *axisSteering); // regularize distribution(s) of the output binning scheme
+
+   /// scan mode for correlation scan
+   enum EScanTauMode {
+      /// average global correlation coefficient (from TUnfold::GetRhoI())
+      kEScanTauRhoAvg =0,
+      /// maximum global correlation coefficient (from TUnfold::GetRhoI())
+      kEScanTauRhoMax =1,
+       /// average global correlation coefficient (from TUnfoldSys::GetRhoItotal())
+      kEScanTauRhoAvgSys =2,
+      /// maximum global correlation coefficient (from TUnfoldSys::GetRhoItotal())
+      kEScanTauRhoMaxSys =3,
+      /// average global correlation coefficient squared (from TUnfold::GetRhoI())
+      kEScanTauRhoSquareAvg =4,
+      /// average global correlation coefficient squared (from TUnfoldSys::GetRhoItotal())
+      kEScanTauRhoSquareAvgSys =5
    };
 
    virtual Int_t ScanTau(Int_t nPoint,Double_t tauMin,Double_t tauMax,
@@ -104,10 +124,10 @@ class TUnfoldDensity : public TUnfoldSys {
 
    TH1 *GetOutput(const char *histogramName,
                   const char *histogramTitle=0,const char *distributionName=0,
-                  const char *projectionMode=0,Bool_t useAxisBinning=kTRUE) const;  // get unfolding result
+		  const char *projectionMode=0,Bool_t useAxisBinning=kTRUE) const;  // get unfolding result
    TH1 *GetBias(const char *histogramName,
                 const char *histogramTitle=0,const char *distributionName=0,
-                const char *projectionMode=0,Bool_t useAxisBinning=kTRUE) const;      // get bias
+		const char *projectionMode=0,Bool_t useAxisBinning=kTRUE) const;      // get bias
    TH1 *GetFoldedOutput(const char *histogramName,
                         const char *histogramTitle=0,
                         const char *distributionName=0,
@@ -116,8 +136,7 @@ class TUnfoldDensity : public TUnfoldSys {
    TH1 *GetBackground(const char *histogramName,const char *bgrSource=0,
                       const char *histogramTitle=0,
                       const char *distributionName=0,
-                      const char *projectionMode=0,Bool_t useAxisBinning=kTRUE,Int_t includeError=3,
-                      Bool_t clearHist=kTRUE) const; // get background source
+                      const char *projectionMode=0,Bool_t useAxisBinning=kTRUE,Int_t includeError=3) const; // get background source
    TH1 *GetInput(const char *histogramName,const char *histogramTitle=0,
                  const char *distributionName=0,
                  const char *projectionMode=0,Bool_t useAxisBinning=kTRUE) const;     // get unfolding input
@@ -125,57 +144,58 @@ class TUnfoldDensity : public TUnfoldSys {
                           const char *histogramName,
                           const char *histogramTitle=0,
                           const char *distributionName=0,
-                          const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get systematic shifts from one systematic source
+			  const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get systematic shifts from one systematic source
    TH1 *GetDeltaSysBackgroundScale(const char *bgrSource,
                                    const char *histogramName,
                                    const char *histogramTitle=0,
                                    const char *distributionName=0,
-                                   const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get correlated uncertainty induced by the scale uncertainty of a background source
+				   const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get correlated uncertainty induced by the scale uncertainty of a background source
    TH1 *GetDeltaSysTau(const char *histogramName,
                        const char *histogramTitle=0,
                        const char *distributionName=0,
-                       const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get correlated uncertainty from varying tau
+		       const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get correlated uncertainty from varying tau
    TH2 *GetEmatrixSysUncorr(const char *histogramName,
-                            const char *histogramTitle=0,
-                            const char *distributionName=0,
-                            const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get error matrix contribution from uncorrelated errors on the matrix A
+			    const char *histogramTitle=0,
+			    const char *distributionName=0,
+			    const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get error matrix contribution from uncorrelated errors on the matrix A
    TH2 *GetEmatrixSysBackgroundUncorr(const char *bgrSource,
-                                      const char *histogramName,
-                                      const char *histogramTitle=0,
-                                      const char *distributionName=0,
-                                      const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get error matrix from uncorrelated error of one background source
+				      const char *histogramName,
+				      const char *histogramTitle=0,
+				      const char *distributionName=0,
+				      const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get error matrix from uncorrelated error of one background source
    TH2 *GetEmatrixInput(const char *histogramName,
                         const char *histogramTitle=0,
-                        const char *distributionName=0,
-                        const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get error contribution from input vector
+			const char *distributionName=0,
+			const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get error contribution from input vector
    TH2 *GetEmatrixTotal(const char *histogramName,
-                        const char *histogramTitle=0,
-                        const char *distributionName=0,
-                        const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get total error including systematic,statistical,background,tau errors
+			const char *histogramTitle=0,
+			const char *distributionName=0,
+			const char *projectionMode=0,Bool_t useAxisBinning=kTRUE); // get total error including systematic,statistical,background,tau errors
    TH1 *GetRhoIstatbgr(const char *histogramName,const char *histogramTitle=0,
                      const char *distributionName=0,
-                       const char *projectionMode=0,Bool_t useAxisBinning=kTRUE,
+		     const char *projectionMode=0,Bool_t useAxisBinning=kTRUE,
                      TH2 **ematInv=0);      // get global correlation coefficients, stat+bgr errors only (from TUnfold)
    TH1 *GetRhoItotal(const char *histogramName,const char *histogramTitle=0,
                      const char *distributionName=0,
-                     const char *projectionMode=0,Bool_t useAxisBinning=kTRUE,
+		     const char *projectionMode=0,Bool_t useAxisBinning=kTRUE,
                      TH2 **ematInv=0);      // get global correlation coefficients, including systematic errors (from TUnfoldSys)
    TH2 *GetRhoIJtotal(const char *histogramName,
-                      const char *histogramTitle=0,
-                      const char *distributionName=0,
-                      const char *projectionMode=0,Bool_t useAxisBinning=kTRUE);     // get correlation coefficients
+		      const char *histogramTitle=0,
+		      const char *distributionName=0,
+		      const char *projectionMode=0,Bool_t useAxisBinning=kTRUE);     // get correlation coefficients
    TH2 *GetL(const char *histogramName,
              const char *histogramTitle=0,
              Bool_t useAxisBinning=kTRUE); // get regularisation matrix
-   TH1 *GetLxMinusBias(const char *histogramName,const char *histogramTitle=0); // get vector L(x-bias) of regularisation conditions
+   TH1 *GetLxMinusBias(const char *histogramName,const char *histogramTitle=0); // get vector L(x-bias) of regularisation conditions 
 
    TH2 *GetProbabilityMatrix(const char *histogramName,
-                             const char *histogramTitle=0,Bool_t useAxisBinning=kTRUE) const; // get matrix of probabilities
+                           const char *histogramTitle=0,Bool_t useAxisBinning=kTRUE) const; // get matrix of probabilities
 
    const TUnfoldBinning *GetInputBinning(const char *distributionName=0) const; // find binning scheme for input bins
    const TUnfoldBinning *GetOutputBinning(const char *distributionName=0) const; // find binning scheme for output bins
-TUnfoldBinning *GetLBinning(void) const { return fRegularisationConditions; } // binning scheme for regularisation conditions (matrix L)
-   ClassDef(TUnfoldDensity, TUnfold_CLASS_VERSION) //Unfolding with densisty regularisation
+   /// return binning scheme for regularisation conditions (matrix L)
+TUnfoldBinning *GetLBinning(void) const { return fRegularisationConditions; }
+   ClassDef(TUnfoldDensity, TUnfold_CLASS_VERSION) //Unfolding with density regularisation
 };
 
 #endif
diff --git a/hist/hist/inc/TUnfoldSys.h b/hist/unfold/inc/TUnfoldSys.h
similarity index 71%
rename from hist/hist/inc/TUnfoldSys.h
rename to hist/unfold/inc/TUnfoldSys.h
index 75e0344d5d513ef8eb191a8f8d88e2ed5b807220..9943efb94b74ab95804fa5a45344abd5c4a1a007 100644
--- a/hist/hist/inc/TUnfoldSys.h
+++ b/hist/unfold/inc/TUnfoldSys.h
@@ -1,16 +1,20 @@
 // Author: Stefan Schmitt
 // DESY, 23/01/09
 
-//  Version 17.1, bug fix with background uncertainty
+//  Version 17.5, bug fixes in TUnfold fix problem with GetEmatrixSysUncorr
 //
 //  History:
-//     Version 17.0, possibility to specify an error matrix with SetInput
-//     Version 16.2, bug-fix with the calculation of background errors
-//     Version 16.1, parallel to changes in TUnfold
-//     Version 16.0, parallel to changes in TUnfold
-//     Version 15, fix bugs with uncorr. uncertainties, add backgnd subtraction
-//     Version 14, with changes in TUnfoldSys.cxx
-//     Version 13, support for systematic errors
+//    Version 17.4, in parallel to changes in TUnfoldBinning
+//    Version 17.3, in parallel to changes in TUnfoldBinning
+//    Version 17.2, add methods to find back systematic and background sources
+//    Version 17.1, bug fix with background uncertainty
+//    Version 17.0, possibility to specify an error matrix with SetInput
+//    Version 16.2, bug-fix with the calculation of background errors
+//    Version 16.1, parallel to changes in TUnfold
+//    Version 16.0, parallel to changes in TUnfold
+//    Version 15, fix bugs with uncorr. uncertainties, add backgnd subtraction
+//    Version 14, with changes in TUnfoldSys.cxx
+//    Version 13, support for systematic errors
 
 #ifndef ROOT_TUnfoldSys
 #define ROOT_TUnfoldSys
@@ -43,32 +47,46 @@
   along with TUnfold.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <TMap.h>
+#include <TSortedList.h>
 #include "TUnfold.h"
 
-class TMap;
-
 
 class TUnfoldSys : public TUnfold {
  private:
    void InitTUnfoldSys(void);     // initialize all data members
  protected:
-   TMatrixDSparse *fDAinRelSq;  // Input: normalized errors from input matrix
-   TMatrixD* fDAinColRelSq;     // Input: normalized column err.sq. (inp.matr.)
-   TMatrixD* fAoutside;         // Input: underflow/overflow bins
-   TMap *fSysIn;                // Input: correlated errors
-   TMap *fBgrIn;                // Input: size of background sources
-   TMap *fBgrErrUncorrInSq;     // Input: uncorr error squared from bgr sources
-   TMap *fBgrErrScaleIn;        // Input: background sources correlated error
-   Double_t fDtau;              // Input: error on tau
-   TMatrixD *fYData;            // Input: fY prior to bgr subtraction
-   TMatrixDSparse *fVyyData;    // Input: error on fY prior to bgr subtraction
-   TMatrixDSparse *fEmatUncorrX;      // Result: syst.error from fDA2 on fX
-   TMatrixDSparse *fEmatUncorrAx;     // Result: syst.error from fDA2 on fAx
-   TMap *fDeltaCorrX;           // Result: syst.shift from fSysIn on fX
-   TMap *fDeltaCorrAx;          // Result: syst.shift from fSysIn on fAx
-   TMatrixDSparse *fDeltaSysTau; // Result: systematic shift from tau
+   /// Input: normalized errors from input matrix
+   TMatrixDSparse *fDAinRelSq;
+   /// Input: normalized column err.sq. (inp.matr.)
+   TMatrixD* fDAinColRelSq;
+   /// Input: underflow/overflow bins
+   TMatrixD* fAoutside;
+   /// Input: correlated errors
+   TMap *fSysIn;
+   /// Input: size of background sources
+   TMap *fBgrIn;
+   /// Input: uncorr error squared from bgr sources
+   TMap *fBgrErrUncorrInSq;
+   /// Input: background sources correlated error
+   TMap *fBgrErrScaleIn;
+   /// Input: error on tau
+   Double_t fDtau;
+   /// Input: fY prior to bgr subtraction
+   TMatrixD *fYData;
+   /// Input: error on fY prior to bgr subtraction
+   TMatrixDSparse *fVyyData;
+   /// Result: syst.error from fDA2 on fX
+   TMatrixDSparse *fEmatUncorrX;
+   /// Result: syst.error from fDA2 on fAx
+   TMatrixDSparse *fEmatUncorrAx;
+   /// Result: syst.shift from fSysIn on fX
+   TMap *fDeltaCorrX;
+   /// Result: syst.shift from fSysIn on fAx
+   TMap *fDeltaCorrAx;
+   /// Result: systematic shift from tau
+   TMatrixDSparse *fDeltaSysTau;
  protected:
-   TUnfoldSys(void);            // for derived classes
    virtual void ClearResults(void);     // clear all results
    virtual void PrepareSysError(void); // common calculations for syst.errors
    virtual TMatrixDSparse *PrepareUncorrEmat(const TMatrixDSparse *m1,const TMatrixDSparse *m2); // calculate uncorrelated error matrix
@@ -80,36 +98,43 @@ class TUnfoldSys : public TUnfold {
    TMatrixDSparse *GetSummedErrorMatrixYY(void);
    TMatrixDSparse *GetSummedErrorMatrixXX(void);
  public:
-   enum ESysErrMode { // meaning of the argument to AddSysError()
-     kSysErrModeMatrix=0, // matrix is an alternative to the default matrix, the errors are the difference to the original matrix
-     kSysErrModeShift=1, // matrix gives the absolute shifts
-     kSysErrModeRelative=2 // matrix gives the relative shifts
+   /// type of matrix specified with AddSysError()
+   enum ESysErrMode { 
+      /// matrix is an alternative to the default matrix, the errors are the difference to the original matrix
+     kSysErrModeMatrix=0,
+     /// matrix gives the absolute shifts
+     kSysErrModeShift=1,
+     /// matrix gives the relative shifts
+     kSysErrModeRelative=2
    };
    TUnfoldSys(const TH2 *hist_A, EHistMap histmap, ERegMode regmode = kRegModeSize,
              EConstraint constraint=kEConstraintArea);      // constructor
+   TUnfoldSys(void);            // for derived classes
    virtual ~ TUnfoldSys(void);    // delete data members
    void AddSysError(const TH2 *sysError,const char *name, EHistMap histmap,
                     ESysErrMode mode); // add a systematic error source
-   Bool_t GetDeltaSysSource(TH1 *hist_delta,const char *source,
-                          const Int_t *binMap=0); // get systematic shifts from one systematic source
    void SubtractBackground(const TH1 *hist_bgr,const char *name,
                            Double_t scale=1.0,
                            Double_t scale_error=0.0); // subtract background prior to unfolding
-   void GetBackground(TH1 *bgr,const char *bgrSource=0,const Int_t *binMap=0,Int_t includeError=3,Bool_t clearHist=kTRUE) const; // get background as histogram
    virtual Int_t SetInput(const TH1 *hist_y,Double_t scaleBias=0.0,Double_t oneOverZeroError=0.0,const TH2 *hist_vyy=0,const TH2 *hist_vyy_inv=0); // define input consistently in case of background subtraction
-   Bool_t GetDeltaSysBackgroundScale(TH1 *delta,const char *source,
-                                const Int_t *binMap=0); // get correlated uncertainty induced by the scale uncertainty of a background source
    void SetTauError(Double_t delta_tau); // set uncertainty on tau
-   Bool_t GetDeltaSysTau(TH1 *delta,const Int_t *binMap=0); // get correlated uncertainty from varying tau
-   void GetEmatrixSysUncorr(TH2 *ematrix,const Int_t *binMap=0,Bool_t clearEmat=kTRUE); // get error matrix contribution from uncorrelated errors on the matrix A
-   void GetEmatrixSysSource(TH2 *ematrix,const char *source,
-                            const Int_t *binMap=0,Bool_t clearEmat=kTRUE); // get error matrix from one systematic source
+   TSortedList *GetBgrSources(void) const; // get names of background sources
+   TSortedList *GetSysSources(void) const; // get names of systematic sources
+   void GetBackground(TH1 *bgr,const char *bgrSource=0,const Int_t *binMap=0,Int_t includeError=3,Bool_t clearHist=kTRUE) const; // get background as histogram
    void GetEmatrixSysBackgroundUncorr(TH2 *ematrix,const char *source,
                                    const Int_t *binMap=0,Bool_t clearEmat=kTRUE); // get error matrix from uncorrelated error of one background source
    void GetEmatrixSysBackgroundScale(TH2 *ematrix,const char *source,
                                   const Int_t *binMap=0,Bool_t clearEmat=kTRUE); // get error matrix from the scale error of one background source
+   Bool_t GetDeltaSysBackgroundScale(TH1 *delta,const char *source,
+                                const Int_t *binMap=0); // get correlated uncertainty induced by the scale uncertainty of a background source
+   void GetEmatrixSysUncorr(TH2 *ematrix,const Int_t *binMap=0,Bool_t clearEmat=kTRUE); // get error matrix contribution from uncorrelated errors on the matrix A
+   void GetEmatrixSysSource(TH2 *ematrix,const char *source,
+                            const Int_t *binMap=0,Bool_t clearEmat=kTRUE); // get error matrix from one systematic source
+   Bool_t GetDeltaSysSource(TH1 *hist_delta,const char *source,
+                          const Int_t *binMap=0); // get systematic shifts from one systematic source
    void GetEmatrixSysTau(TH2 *ematrix,
                       const Int_t *binMap=0,Bool_t clearEmat=kTRUE); // get error matrix from tau variation
+   Bool_t GetDeltaSysTau(TH1 *delta,const Int_t *binMap=0); // get correlated uncertainty from varying tau
    void GetEmatrixInput(TH2 *ematrix,const Int_t *binMap=0,Bool_t clearEmat=kTRUE); // get error contribution from input vector
    void GetEmatrixTotal(TH2 *ematrix,const Int_t *binMap=0); // get total error including systematic,statistical,background,tau errors
    void GetRhoItotal(TH1 *rhoi,const Int_t *binMap=0,TH2 *invEmat=0); // get global correlation coefficients including systematic,statistical,background,tau errors
diff --git a/hist/hist/src/TUnfold.cxx b/hist/unfold/src/TUnfold.cxx
similarity index 57%
rename from hist/hist/src/TUnfold.cxx
rename to hist/unfold/src/TUnfold.cxx
index e497e73adb5324d3953c24f66a34962c25ef98d7..75dce1ed0a1821d3f0a3c005d8390fe09b6733e7 100644
--- a/hist/hist/src/TUnfold.cxx
+++ b/hist/unfold/src/TUnfold.cxx
@@ -1,265 +1,117 @@
-// Author: Stefan Schmitt
-// DESY, 13/10/08
-
-//  Version 17.1, bug fixes in GetFoldedOutput, GetOutput
-//
-//  History:
-//    Version 17.0, option to specify an error matrix with SetInput(), new ScanRho() method
-//    Version 16.2, in parallel to bug-fix in TUnfoldSys
-//    Version 16.1, fix bug with error matrix in case kEConstraintArea is used
-//    Version 16.0, fix calculation of global correlations, improved error messages
-//    Version 15, simplified L-curve scan, new tau definition, new error calc., area preservation
-//    Version 14, with changes in TUnfoldSys.cxx
-//    Version 13, new methods for derived classes and small bug fix
-//    Version 12, report singular matrices
-//    Version 11, reduce the amount of printout
-//    Version 10, more correct definition of the L curve, update references
-//    Version 9, faster matrix inversion and skip edge points for L-curve scan
-//    Version 8, replace all TMatrixSparse matrix operations by private code
-//    Version 7, fix problem with TMatrixDSparse,TMatrixD multiplication
-//    Version 6, replace class XY by std::pair
-//    Version 5, replace run-time dynamic arrays by new and delete[]
-//    Version 4, fix new bug from V3 with initial regularisation condition
-//    Version 3, fix bug with initial regularisation condition
-//    Version 2, with improved ScanLcurve() algorithm
-//    Version 1, added ScanLcurve() method
-//    Version 0, stable version of basic unfolding algorithm
+// @(#)root/unfold:$Id$
+// Author: Stefan Schmitt DESY, 13/10/08
 
 /** \class TUnfold
-    \ingroup Hist
- TUnfold is used to decompose a measurement y into several sources x
- given the measurement uncertainties and a matrix of migrations A
-
- **For most applications, it is better to use TUnfoldDensity
- instead of using TUnfoldSys or TUnfold**
-
- If you use this software, please consider the following citation
-      S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]
-
- More documentation and updates are available on
-     http://www.desy.de/~sschmitt
-
- A short summary of the algorithm is given in the following:
- the "best" x matching the measurement y within errors
- is determined by minimizing the function
-   L1+L2+L3
-
- where
-  L1 = (y-Ax)# Vyy^-1 (y-Ax)
-  L2 = tau^2 (L(x-x0))# L(x-x0)
-  L3 = lambda sum_i(y_i -(Ax)_i)
-
- [the notation # means that the matrix is transposed ]
-
- The term L1 is familiar from a least-square minimisation
- The term L2 defines the regularisation (smootheness condition on x),
-   where the parameter tau^2 gives the strength of the regularisation
- The term L3 is an optional area constraint with Lagrangian parameter
-   lambda, ensuring that that the normalisation of x is consistent with the
-   normalisation of y
-
- The method can be applied to a very large number of problems,
- where the measured distribution y is a linear superposition
- of several Monte Carlo shapes
-
- ## Input from measurement:
-  y: vector of measured quantities  (dimension ny)
-  Vyy: covariance matrix for y (dimension ny x ny)
-       in many cases V is diagonal and calculated from the errors of y
-
- ## From simulation:
-  A: migration matrix               (dimension ny x nx)
-
- ## Result
-  x: unknown underlying distribution (dimension nx)
-     The error matrix of x, V_xx, is also determined
-
- ## Regularisation
-  tau: parameter, defining the regularisation strength
-  L: matrix of regularisation conditions (dimension nl x nx)
-       depends on the structure of the input data
-  x0: bias distribution, from simulation
-
- ## Preservation of the area
-  lambda: Lagrangian multiplier
-  y_i: one component of the vector y
-  (Ax)_i: one component of the vector Ax
-
-
- Determination of the unfolding result x:
-  - (a) not constrained: minimisation is performed as a function of x
-        for fixed lambda=0
-  - (b) constrained: stationary point is found as a function of x and lambda
-
- The constraint can be useful to reduce biases on the result x
- in cases where the vector y follows non-Gaussian probability densities
- (example: Poisson statistics at counting experiments in particle physics)
-
- Some random examples:
-  1. measure a cross-section as a function of, say, E_T(detector)
-       and unfold it to obtain the underlying distribution E_T(generator)
-  2. measure a lifetime distribution and unfold the contributions from
-       different flavours
-  3. measure the transverse mass and decay angle
-       and unfold for the true mass distribution plus background
-
- ## Documentation
- Some technical documentation is available here:
-  http://www.desy.de/~sschmitt
-
- Note:
-
- For most applications it is better to use the derived class
-    TUnfoldSys or even better TUnfoldDensity
-
- TUnfoldSys extends the functionality of TUnfold
-            such that systematic errors are propagated to the result
-            and that the unfolding can be done with proper background
-            subtraction
-
- TUnfoldDensity extends further the functionality of TUnfoldSys
-                complex binning schemes are supported
-                The binning of input histograms is handeld consistently:
-                 (1) the regularisation may be done by density,
-                     i.e respecting the bin widths
-                 (2) methods are provided which preserve the proper binning
-                     of the result histograms
- ## Implementation
- The result of the unfolding is calculated as follows:
-
- Lsquared = L#L            regularisation conditions squared
-
-   epsilon_j = sum_i A_ij    vector of efficiencies
-
-   E^-1  = ((A# Vyy^-1 A)+tau^2 Lsquared)
-
-   x = E (A# Vyy^-1 y + tau^2 Lsquared x0 +lambda/2 * epsilon) is the result
-
- The derivatives
-   dx_k/dy_i
-   dx_k/dA_ij
-   dx_k/d(tau^2)
- are calculated for further usage.
-
- The covariance matrix V_xx is calculated as:
-   Vxx_ij = sum_kl dx_i/dy_k Vyy_kl dx_j/dy_l
-
- ## Warning:
- The algorithm is based on "standard" matrix inversion, with the
- known limitations in numerical accuracy and computing cost for
- matrices with large dimensions.
-
- Thus the algorithm should not used for large dimensions of x and y
-   nx should not be much larger than 200
-   ny should not be much larger than 1000
-
-## Proper choice of tau
- One of the difficult questions is about the choice of tau.
- The method implemented in TUnfold is the L-curve method:
- a two-dimensional curve is plotted
- x-axis: log10(chisquare)
- y-axis: log10(regularisation condition)
- In many cases this curve has an L-shape. The best choice of tau is in the
- kink of the L
-
- Within TUnfold a simple version of the L-curve analysis is available.
- It tests a given number of points in a predefined tau-range and searches
- for the maximum of the curvature in the L-curve (kink position).
- if no tau range is given, the range of the scan is determined automatically
-
- A nice overview of the L-curve method is given in:
-  The L-curve and Its Use in the Numerical Treatment of Inverse Problems
-  (2000) by P. C. Hansen, in Computational Inverse Problems in
-  Electrocardiology, ed. P. Johnston,
-  Advances in Computational Bioengineering
-  http://www.imm.dtu.dk/~pch/TR/Lcurve.ps
-
- ## Alternative Regularisation conditions
- Regularisation is needed for most unfolding problems, in order to avoid
- large oscillations and large correlations on the output bins.
- It means that some extra conditions are applied on the output bins
-
- Within TUnfold these conditions are posed on the difference (x-x0), where
-   x:  unfolding output
-   x0: the bias distribution, by default calculated from
-       the input matrix A. There is a method SetBias() to change the
-       bias distribution.
-       The 3rd argument to DoUnfold() is a scale factor applied to the bias
-         bias_default[j] = sum_i A[i][j]
-         x0[j] = scaleBias*bias[j]
-       The scale factor can be used to
-        (a) completely suppress the bias by setting it to zero
-        (b) compensate differences in the normalisation between data
-            and Monte Carlo
-
- If the regularisation is strong, i.e. large parameter tau,
- then the distribution x or its derivatives will look like the bias
- distribution. If the parameter tau is small, the distribution x is
- independent of the bias.
-
- Three basic types of regularisation are implemented in TUnfold
-
-   condition      |      regularisation
- -----------------|------------------------------------
-   kRegModeNone       |  none
-   kRegModeSize       |  minimize the size of (x-x0)
-   kRegModeDerivative |  minimize the 1st derivative of (x-x0)
-   kRegModeCurvature  |  minimize the 2nd derivative of (x-x0)
-
- kRegModeSize is the regularisation scheme which often is found in
- literature. The second derivative is often named curvature.
- Sometimes the bias is not discussed,  equivalent to a bias scale factor
- of zero.
-
- The regularisation schemes kRegModeDerivative and
- kRegModeCurvature have the nice feature that they create correlations
- between x-bins, whereas the non-regularized unfolding tends to create
- negative correlations between bins. For these regularisation schemes the
- parameter tau could be tuned such that the correlations are smallest,
- as an alternative to the L-curve method.
-
- If kRegModeSize is chosen or if x is a smooth function through all bins,
- the regularisation condition can be set on all bins together by giving
- the appropriate argument in the constructor (see examples above).
-
- If x is composed of independent groups of bins (for example,
- signal and background binning in two variables), it may be necessary to
- set regularisation conditions for the individual groups of bins.
- In this case,  give  kRegModeNone  in the constructor and specify
- the bin grouping with calls to
-         RegularizeBins()   specify a 1-dimensional group of bins
-         RegularizeBins2D() specify a 2-dimensional group of bins
-
-  Note, the class TUnfoldDensity provides an automatic setup of complex
- regularisation schemes
-
- For ultimate flexibility, the regularisation condition can be set on each
- bin individually
- -> give  kRegModeNone  in the constructor and use
-       RegularizeSize()        regularize one bin
-       RegularizeDerivative()  regularize the slope given by two bins
-       RegularizeCurvature()   regularize the curvature given by three bins
-       AddRegularisationCondition()
-                             define an arbitrary regularization condition
+\ingroup Unfold
+
+An algorithm to unfold distributions from detector to truth level
+
+TUnfold is used to decompose a measurement y into several sources x,
+given the measurement uncertainties and a matrix of migrations A.
+The method can be applied to a large number of problems,
+where the measured distribution y is a linear superposition
+of several Monte Carlo shapes. Beyond such a simple template fit,
+TUnfold has an adjustable regularisation term and also supports an
+optional constraint on the total number of events.
+
+<b>For most applications, it is better to use the derived class
+TUnfoldDensity instead of TUnfold</b>. TUnfoldDensity adds various
+features to TUnfold, such as:
+background subtraction, propagation of systematic uncertainties,
+complex multidimensional arrangements of the bins. For innocent
+users, the most notable improvement of TUnfoldDensity over TUnfold are
+the getter functions. For TUnfold, histograms have to be booked by the
+user and the getter functions fill the histogram bins. TUnfoldDensity
+simply returns a new, already filled histogram.
+
+If you use this software, please consider the following citation
+
+<b>S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]</b>
+
+Detailed documentation and updates are available on
+http://www.desy.de/~sschmitt
+
+Brief recipe to use TUnfold:
+
+  - a matrix (truth,reconstructed) is given as a two-dimensional histogram
+    as argument to the constructor of TUnfold
+  - a vector of measurements is given as one-dimensional histogram using
+    the SetInput() method
+  - The unfolding is performed
+
+  - either once with a fixed parameter tau, method DoUnfold(tau)
+  - or multiple times in a scan to determine the best choice of tau,
+    method ScanLCurve()
+
+  - Unfolding results are retrieved using various GetXXX() methods
+
+Basic formulae:
+\f[
+\chi^{2}_{A}=(Ax-y)^{T}V_{yy}^{-1}(Ax-y) \\
+\chi^{2}_{L}=(x-f*x_{0})^{T}L^{T}L(x-f*x_{0}) \\
+\chi^{2}_{unf}=\chi^{2}_{A}+\tau^{2}\chi^{2}_{L}+\lambda\Sigma_{i}(Ax-y)_{i}
+\f]
+
+  - \f$ x \f$:result,
+  - \f$ A \f$:probabilities,
+  - \f$ y \f$:data,
+  - \f$ V_{yy} \f$:data covariance,
+  - \f$ f \f$:bias scale,
+  - \f$ x_{0} \f$:bias,
+  - \f$ L \f$:regularisation conditions,
+  - \f$ \tau \f$:regularisation strength,
+  - \f$ \lambda \f$:Lagrangian multiplier.
+
+ Without area constraint, \f$ \lambda \f$ is set to zero, and
+\f$ \chi^{2}_{unf} \f$ is minimized to determine \f$ x \f$.
+With area constraint, both \f$ x \f$ and \f$ \lambda \f$ are determined.
+
+--------------------------------------------------------------------------------
+This file is part of TUnfold.
+
+TUnfold is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+TUnfold is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with TUnfold.  If not, see <http://www.gnu.org/licenses/>.
+
+<b>Version 17.6, updated doxygen-style comments, add one argument for scanLCurve </b>
+
+#### History:
+  - Version 17.5, fix memory leak with fVyyInv, bugs in GetInputInverseEmatrix(), GetInput(), bug in MultiplyMSparseMSparseTranspVector
+  - Version 17.4, in parallel to changes in TUnfoldBinning
+  - Version 17.3, in parallel to changes in TUnfoldBinning
+  - Version 17.2, bug fix with GetProbabilityMatrix
+  - Version 17.1, bug fixes in GetFoldedOutput, GetOutput
+  - Version 17.0, option to specify an error matrix with SetInput(), new ScanRho() method
+  - Version 16.2, in parallel to bug-fix in TUnfoldSys
+  - Version 16.1, fix bug with error matrix in case kEConstraintArea is used
+  - Version 16.0, fix calculation of global correlations, improved error messages
+  - Version 15, simplified L-curve scan, new tau definition, new error calc., area preservation
+  - Version 14, with changes in TUnfoldSys.cxx
+  - Version 13, new methods for derived classes and small bug fix
+  - Version 12, report singular matrices
+  - Version 11, reduce the amount of printout
+  - Version 10, more correct definition of the L curve, update references
+  - Version 9, faster matrix inversion and skip edge points for L-curve scan
+  - Version 8, replace all TMatrixSparse matrix operations by private code
+  - Version 7, fix problem with TMatrixDSparse,TMatrixD multiplication
+  - Version 6, replace class XY by std::pair
+  - Version 5, replace run-time dynamic arrays by new and delete[]
+  - Version 4, fix new bug from V3 with initial regularisation condition
+  - Version 3, fix bug with initial regularisation condition
+  - Version 2, with improved ScanLcurve() algorithm
+  - Version 1, added ScanLcurve() method
+  - Version 0, stable version of basic unfolding algorithm
 */
 
-/*
- This file is part of TUnfold.
-
- TUnfold is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- TUnfold is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with TUnfold.  If not, see <http://www.gnu.org/licenses/>.
- */
-
 #include <iostream>
 #include <TMatrixD.h>
 #include <TMatrixDSparse.h>
@@ -271,26 +123,28 @@
 #include <map>
 #include <vector>
 
-// this option saves the spline of the L curve curvature to a file
-// named splinec.ps for debugging
-
 //#define DEBUG
 //#define DEBUG_DETAIL
-//#define DEBUG_LCURVE
 //#define FORCE_EIGENVALUE_DECOMPOSITION
 
-#ifdef DEBUG_LCURVE
-#include <TCanvas.h>
-#endif
-
 ClassImp(TUnfold)
-//______________________________________________________________________________
 
-const char *TUnfold::GetTUnfoldVersion(void)
+TUnfold::~TUnfold(void)
 {
-   return TUnfold_VERSION;
+   // delete all data members
+
+   DeleteMatrix(&fA);
+   DeleteMatrix(&fL);
+   DeleteMatrix(&fVyy);
+   DeleteMatrix(&fY);
+   DeleteMatrix(&fX0);
+   DeleteMatrix(&fVyyInv);
+
+   ClearResults();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Initialize data members, for use in constructors.
 
 void TUnfold::InitTUnfold(void)
 {
@@ -305,18 +159,19 @@ void TUnfold::InitTUnfold(void)
    fX0 = 0;
    fTauSquared = 0.0;
    fBiasScale = 0.0;
-   fNdf = 0;
    fConstraint = kEConstraintNone;
    fRegMode = kRegModeNone;
    // output
+   fX = 0;
    fVyyInv = 0;
    fVxx = 0;
-   fX = 0;
+   fVxxInv = 0;
    fAx = 0;
    fChi2A = 0.0;
    fLXsquared = 0.0;
    fRhoMax = 999.0;
    fRhoAvg = -1.0;
+   fNdf = 0;
    fDXDAM[0] = 0;
    fDXDAZ[0] = 0;
    fDXDAM[1] = 0;
@@ -325,23 +180,41 @@ void TUnfold::InitTUnfold(void)
    fDXDY = 0;
    fEinv = 0;
    fE = 0;
-   fVxxInv = 0;
    fEpsMatrix=1.E-13;
    fIgnoredBins=0;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Delete matrix and invalidate pointer.
+///
+/// \param[inout] m pointer to a matrix-pointer
+///
+/// If the matrix pointer os non-zero, the matrix id deleted. The matrix pointer
+/// is set to zero.
+
 void TUnfold::DeleteMatrix(TMatrixD **m)
 {
    if(*m) delete *m;
    *m=0;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Delete sparse matrix and invalidate pointer
+///
+/// \param[inout] m pointer to a matrix-pointer
+///
+/// if the matrix pointer os non-zero, the matrix id deleted. The matrix pointer
+/// is set to zero.
+
 void TUnfold::DeleteMatrix(TMatrixDSparse **m)
 {
    if(*m) delete *m;
    *m=0;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Reset all results.
+
 void TUnfold::ClearResults(void)
 {
    // delete old results (if any)
@@ -369,53 +242,60 @@ void TUnfold::ClearResults(void)
    fRhoAvg = -1.0;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Only for use by root streamer or derived classes.
+
 TUnfold::TUnfold(void)
 {
    // set all matrix pointers to zero
    InitTUnfold();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Core unfolding algorithm.
+///
+/// Main unfolding algorithm. Declared virtual, because other algorithms
+/// could be implemented
+///
+/// Purpose: unfold y -> x
+///
+///  - Data members required:
+///      - fA:  matrix to relate x and y
+///      - fY:  measured data points
+///      - fX0: bias on x
+///      - fBiasScale: scale factor for fX0
+///      - fVyy:  covariance matrix for y
+///      - fL: regularisation conditions
+///      - fTauSquared: regularisation strength
+///      - fConstraint: whether the constraint is applied
+///  - Data members modified:
+///      - fVyyInv: inverse of input data covariance matrix
+///      - fNdf: number of degrees of freedom
+///      - fEinv: inverse of the matrix needed for unfolding calculations
+///      - fE:    the matrix needed for unfolding calculations
+///      - fX:    unfolded data points
+///      - fDXDY: derivative of x wrt y (for error propagation)
+///      - fVxx:  error matrix (covariance matrix) on x
+///      - fAx:   estimate of distribution y from unfolded data
+///      - fChi2A:  contribution to chi**2 from y-Ax
+///      - fChi2L:  contribution to chi**2 from L*(x-x0)
+///      - fDXDtauSquared: derivative of x wrt tau
+///      - fDXDAM[0,1]: matrix parts of derivative x wrt A
+///      - fDXDAZ[0,1]: vector parts of derivative x wrt A
+///      - fRhoMax: maximum global correlation coefficient
+///      - fRhoAvg: average global correlation coefficient
+///  - Return code:
+///      - fRhoMax   if(fRhoMax>=1.0) then the unfolding has failed!
+
 Double_t TUnfold::DoUnfold(void)
 {
-   // main unfolding algorithm. Declared virtual, because other algorithms
-   // could be implemented
-   //
-   // Purpose: unfold y -> x
-   // Data members required:
-   //     fA:  matrix to relate x and y
-   //     fY:  measured data points
-   //     fX0: bias on x
-   //     fBiasScale: scale factor for fX0
-   //     fVyy:  covariance matrix for y
-   //     fL: regularisation conditions
-   //     fTauSquared: regularisation strength
-   //     fConstraint: whether the constraint is applied
-   // Data members modified:
-   //     fVyyInv: inverse of input data covariance matrix
-   //     fNdf: number of degrees of freedom
-   //     fEinv: inverse of the matrix needed for unfolding calculations
-   //     fE:    the matrix needed for unfolding calculations
-   //     fX:    unfolded data points
-   //     fDXDY: derivative of x wrt y (for error propagation)
-   //     fVxx:  error matrix (covariance matrix) on x
-   //     fAx:   estimate of distribution y from unfolded data
-   //     fChi2A:  contribution to chi**2 from y-Ax
-   //     fChi2L:  contribution to chi**2 from L*(x-x0)
-   //     fDXDtauSquared: derivative of x wrt tau
-   //     fDXDAM[0,1]: matrix parts of derivative x wrt A
-   //     fDXDAZ[0,1]: vector parts of derivative x wrt A
-   //     fRhoMax: maximum global correlation coefficient
-   //     fRhoAvg: average global correlation coefficient
-   // return code:
-   //     fRhoMax   if(fRhoMax>=1.0) then the unfolding has failed!
-
    ClearResults();
 
    // get pseudo-inverse matrix Vyyinv and NDF
    if(!fVyyInv) {
       GetInputInverseEmatrix(0);
       if(fConstraint != kEConstraintNone) {
-         fNdf--;
+   fNdf--;
       }
    }
    //
@@ -432,7 +312,7 @@ Double_t TUnfold::DoUnfold(void)
    TMatrixDSparse *rhs=MultiplyMSparseM(AtVyyinv,fY);
    TMatrixDSparse *lSquared=MultiplyMSparseTranspMSparse(fL,fL);
    if (fBiasScale != 0.0) {
-      TMatrixDSparse *rhs2=MultiplyMSparseM(lSquared,fX0);
+     TMatrixDSparse *rhs2=MultiplyMSparseM(lSquared,fX0);
       AddMSparse(rhs, fTauSquared * fBiasScale ,rhs2);
       DeleteMatrix(&rhs2);
    }
@@ -530,7 +410,7 @@ Double_t TUnfold::DoUnfold(void)
          data[i]=one_over_epsEeps;
       }
       TMatrixDSparse *temp=CreateSparseMatrix
-      (1,GetNy(),GetNy(),rows,cols,data);
+         (1,GetNy(),GetNy(),rows,cols,data);
       delete[] data;
       delete[] rows;
       delete[] cols;
@@ -623,7 +503,7 @@ Double_t TUnfold::DoUnfold(void)
    if(fConstraint != kEConstraintNone) {
       // add correction to fDXDAM[0]
       TMatrixDSparse *temp1=MultiplyMSparseMSparseTranspVector
-      (Eepsilon,Eepsilon,0);
+         (Eepsilon,Eepsilon,0);
       AddMSparse(fDXDAM[0], -one_over_epsEeps,temp1);
       DeleteMatrix(&temp1);
       // add correction to fDXDAZ[0]
@@ -636,7 +516,7 @@ Double_t TUnfold::DoUnfold(void)
          data[i]=lambda_half;
       }
       TMatrixDSparse *temp2=CreateSparseMatrix
-      (GetNy(),1,GetNy(),rows,cols,data);
+         (GetNy(),1,GetNy(),rows,cols,data);
       delete[] data;
       delete[] rows;
       delete[] cols;
@@ -677,7 +557,7 @@ Double_t TUnfold::DoUnfold(void)
       for(int ik=Vxx_rows[ix];ik<Vxx_rows[ix+1];ik++) {
          if(ix==Vxx_cols[ik]) {
             Double_t rho_squared =
-            1. - 1. / (VxxInvDiag(ix) * Vxx_data[ik]);
+               1. - 1. / (VxxInvDiag(ix) * Vxx_data[ik]);
             if (rho_squared > rho_squared_max)
                rho_squared_max = rho_squared;
             if(rho_squared>0.0) {
@@ -694,10 +574,24 @@ Double_t TUnfold::DoUnfold(void)
    return fRhoMax;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Create a sparse matrix, given the nonzero elements.
+///
+/// \param[in] nrow number of rows
+/// \param[in] ncol number of columns
+/// \param[in] nel number of non-zero elements
+/// \param[in] row row indexes of non-zero elements
+/// \param[in] col column indexes of non-zero elements
+/// \param[in] data non-zero elements data
+///
+/// return pointer to a new sparse matrix
+///
+/// shortcut to new TMatrixDSparse() followed by SetMatrixArray().
+
 TMatrixDSparse *TUnfold::CreateSparseMatrix
 (Int_t nrow,Int_t ncol,Int_t nel,Int_t *row,Int_t *col,Double_t *data) const
 {
-   // create a sparse matrix
+   // create a sparse matri
    //   nrow,ncol : dimension of the matrix
    //   nel: number of non-zero elements
    //   row[nel],col[nel],data[nel] : indices and data of the non-zero elements
@@ -708,13 +602,21 @@ TMatrixDSparse *TUnfold::CreateSparseMatrix
    return A;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Multiply two sparse matrices.
+///
+/// \param[in] a sparse matrix
+/// \param[in] b sparse matrix
+///
+/// returns a new sparse matrix a*b.
+///
+/// A replacement for:
+///  new TMatrixDSparse(a,TMatrixDSparse::kMult,b)
+/// the root implementation had problems in older versions of root.
+
 TMatrixDSparse *TUnfold::MultiplyMSparseMSparse(const TMatrixDSparse *a,
                                                 const TMatrixDSparse *b) const
 {
-   // calculate the product of two sparse matrices
-   //    a,b: pointers to sparse matrices, where a->GetNcols()==b->GetNrows()
-   // this is a replacement for the call
-   //    new TMatrixDSparse(*a,TMatrixDSparse::kMult,*b);
    if(a->GetNcols()!=b->GetNrows()) {
       Fatal("MultiplyMSparseMSparse",
             "inconsistent matrix col/ matrix row %d !=%d",
@@ -775,17 +677,22 @@ TMatrixDSparse *TUnfold::MultiplyMSparseMSparse(const TMatrixDSparse *a,
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Multiply a transposed Sparse matrix with another sparse matrix,
+///
+/// \param[in] a sparse matrix (to be transposed)
+/// \param[in] b sparse matrix
+///
+/// returns a new sparse matrix a^{T}*b
+///
+/// this is a replacement for the root constructors
+/// new TMatrixDSparse(TMatrixDSparse(TMatrixDSparse::kTransposed,*a),
+/// TMatrixDSparse::kMult,*b)
 
 TMatrixDSparse *TUnfold::MultiplyMSparseTranspMSparse
 (const TMatrixDSparse *a,const TMatrixDSparse *b) const
 {
-   // multiply a transposed Sparse matrix with another Sparse matrix
-   //    a:  pointer to sparse matrix (to be transposed)
-   //    b:  pointer to sparse matrix
-   // this is a replacement for the call
-   //    new TMatrixDSparse(TMatrixDSparse(TMatrixDSparse::kTransposed,*a),
-   //                       TMatrixDSparse::kMult,*b)
-   if(a->GetNrows() != b->GetNrows()) {
+  if(a->GetNrows() != b->GetNrows()) {
       Fatal("MultiplyMSparseTranspMSparse",
             "inconsistent matrix row numbers %d!=%d",
             a->GetNrows(),b->GetNrows());
@@ -855,14 +762,20 @@ TMatrixDSparse *TUnfold::MultiplyMSparseTranspMSparse
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Multiply sparse matrix and a non-sparse matrix.
+///
+/// \param[in] a sparse matrix
+/// \param[in] b matrix
+///
+/// returns a new sparse matrix a*b.
+///  A replacement for:
+///  new TMatrixDSparse(a,TMatrixDSparse::kMult,b)
+/// the root implementation had problems in older versions of root.
+
 TMatrixDSparse *TUnfold::MultiplyMSparseM(const TMatrixDSparse *a,
                                           const TMatrixD *b) const
 {
-   // multiply a Sparse matrix with a non-sparse matrix
-   //    a:  pointer to sparse matrix
-   //    b:  pointer to non-sparse matrix
-   // this is a replacement for the call
-   //    new TMatrixDSparse(*a,TMatrixDSparse::kMult,*b);
    if(a->GetNcols()!=b->GetNrows()) {
       Fatal("MultiplyMSparseM","inconsistent matrix col /matrix row %d!=%d",
             a->GetNcols(),b->GetNrows());
@@ -907,14 +820,22 @@ TMatrixDSparse *TUnfold::MultiplyMSparseM(const TMatrixDSparse *a,
    return r;
 }
 
+
+////////////////////////////////////////////////////////////////////////////////
+/// Calculate a sparse matrix product\f$ M1*V*M2^{T} \f$ where the diagonal matrix V is
+/// given by a vector.
+///
+/// \param[in] m1 pointer to sparse matrix with dimension I*K
+/// \param[in] m2 pointer to sparse matrix with dimension J*K
+/// \param[in] v pointer to vector (matrix) with dimension K*1
+///
+/// returns a sparse matrix R with elements
+/// \f$ r_{ij}=\Sigma_{k}M1_{ik}V_{k}M2_{jk} \f$
+
 TMatrixDSparse *TUnfold::MultiplyMSparseMSparseTranspVector
 (const TMatrixDSparse *m1,const TMatrixDSparse *m2,
  const TMatrixTBase<Double_t> *v) const
 {
-   // calculate M_ij = sum_k [m1_ik*m2_jk*v[k] ].
-   //    m1: pointer to sparse matrix with dimension I*K
-   //    m2: pointer to sparse matrix with dimension J*K
-   //    v: pointer to vector (matrix) with dimension K*1
    if((m1->GetNcols() != m2->GetNcols())||
       (v && ((m1->GetNcols()!=v->GetNrows())||(v->GetNcols()!=1)))) {
       if(v) {
@@ -969,13 +890,11 @@ TMatrixDSparse *TUnfold::MultiplyMSparseMSparseTranspVector
                   Int_t v_index=v_rows[k1];
                   if(v_index<v_rows[k1+1]) {
                      data_r[num_r] += data_m1[index_m1] * data_m2[index_m2]
-                     * v_data[v_index];
-                  } else {
-                     data_r[num_r] =0.0;
+                        * v_data[v_index];
                   }
                } else if(v) {
                   data_r[num_r] += data_m1[index_m1] * data_m2[index_m2]
-                  * (*v)(k1,0);
+                     * (*v)(k1,0);
                } else {
                   data_r[num_r] += data_m1[index_m1] * data_m2[index_m2];
                }
@@ -998,11 +917,22 @@ TMatrixDSparse *TUnfold::MultiplyMSparseMSparseTranspVector
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add a sparse matrix, scaled by a factor, to another scaled matrix.
+///
+/// \param[inout] dest destination matrix
+/// \param[in] f scaling factor
+/// \param[in] src matrix to be added to dest
+///
+/// a replacement for
+/// ~~~
+///     (*dest) += f * (*src)
+/// ~~~
+/// which suffered from a bug in old root versions.
+
 void TUnfold::AddMSparse(TMatrixDSparse *dest,Double_t f,
                          const TMatrixDSparse *src) const
 {
-   // a replacement for
-   //     (*dest) += f*(*src)
    const Int_t *dest_rows=dest->GetRowIndexArray();
    const Int_t *dest_cols=dest->GetColIndexArray();
    const Double_t *dest_data=dest->GetMatrixArray();
@@ -1025,9 +955,9 @@ void TUnfold::AddMSparse(TMatrixDSparse *dest,Double_t f,
       Int_t i_src=src_rows[row];
       while((i_dest<dest_rows[row+1])||(i_src<src_rows[row+1])) {
          Int_t col_dest=(i_dest<dest_rows[row+1]) ?
-         dest_cols[i_dest] : dest->GetNcols();
+            dest_cols[i_dest] : dest->GetNcols();
          Int_t col_src =(i_src <src_rows[row+1] ) ?
-         src_cols [i_src] :  src->GetNcols();
+            src_cols [i_src] :  src->GetNcols();
          result_rows[n]=row;
          if(col_dest<col_src) {
             result_cols[n]=col_dest;
@@ -1060,19 +990,26 @@ void TUnfold::AddMSparse(TMatrixDSparse *dest,Double_t f,
    delete[] result_cols;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get the inverse or pseudo-inverse of a positive, sparse matrix.
+///
+/// \param[in] A the sparse matrix to be inverted, has to be positive
+/// \param[inout] rankPtr if zero, suppress calculation of pseudo-inverse
+/// otherwise the rank of the matrix is returned in *rankPtr
+///
+/// return value: 0 or a new sparse matrix
+///
+///   - if(rankPtr==0) return the inverse if it exists, or return 0
+///   - else return a (pseudo-)inverse and store the rank of the matrix in
+/// *rankPtr
+///
+///
+/// the matrix inversion is optimized in performance for the case
+/// where a large submatrix of A is diagonal
+
 TMatrixDSparse *TUnfold::InvertMSparseSymmPos
 (const TMatrixDSparse *A,Int_t *rankPtr) const
 {
-   // get the inverse or pseudo-inverse of a sparse matrix
-   //    A: the original matrix
-   //    rank:
-   //      if(rankPtr==0)
-   //          return the inverse if it exists, or return NULL
-   //      else
-   //          return the pseudo-invers
-   //          and return the rank of the matrix in *rankPtr
-   // the matrix inversion is optimized for the case
-   // where a large submatrix of A is diagonal
 
    if(A->GetNcols()!=A->GetNrows()) {
       Fatal("InvertMSparseSymmPos","inconsistent matrix row/col %d!=%d",
@@ -1101,7 +1038,6 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
       }
    }
    if(nError>0) {
-      delete [] isZero;
       Fatal("InvertMSparseSymmPos",
             "Matrix has %d negative elements on the diagonal", nError);
       return 0;
@@ -1388,7 +1324,7 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
          minusBD2inv=MultiplyMSparseMSparse(B,D2inv);
          if(minusBD2inv) {
             Int_t mbd2_nMax=minusBD2inv->GetRowIndexArray()
-            [minusBD2inv->GetNrows()];
+               [minusBD2inv->GetNrows()];
             Double_t *mbd2_data=minusBD2inv->GetMatrixArray();
             for(Int_t i=0;i<mbd2_nMax;i++) {
                mbd2_data[i] = -  mbd2_data[i];
@@ -1397,7 +1333,7 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
       }
       if(minusBD2inv && F) {
          TMatrixDSparse *minusBD2invBt=
-         MultiplyMSparseMSparseTranspVector(minusBD2inv,B,0);
+            MultiplyMSparseMSparseTranspVector(minusBD2inv,B,0);
          AddMSparse(F,1.,minusBD2invBt);
          DeleteMatrix(&minusBD2invBt);
       }
@@ -1415,7 +1351,7 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
                if(f_cols[indexF]>=i) c(f_cols[indexF],i)=f_data[indexF];
             }
             // calculate diagonal element
-            Double_t c_ii=c(i,i);
+       Double_t c_ii=c(i,i);
             for(Int_t j=0;j<i;j++) {
                Double_t c_ij=c(i,j);
                c_ii -= c_ij*c_ij;
@@ -1424,8 +1360,8 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
                nErrorF++;
                break;
             }
-            c_ii=TMath::Sqrt(c_ii);
-            c(i,i)=c_ii;
+       c_ii=TMath::Sqrt(c_ii);
+       c(i,i)=c_ii;
             // off-diagonal elements
             for(Int_t j=i+1;j<nF;j++) {
                Double_t c_ji=c(j,i);
@@ -1466,7 +1402,7 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
             }
             TMatrixDSparse cInvSparse(cinv);
             Finv=MultiplyMSparseTranspMSparse
-            (&cInvSparse,&cInvSparse);
+               (&cInvSparse,&cInvSparse);
          }
          DeleteMatrix(&F);
       }
@@ -1496,7 +1432,7 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
          if(D2inv) E=new TMatrixDSparse(*D2inv);
          if(G && minusBD2inv) {
             TMatrixDSparse *minusBD2invTransG=
-            MultiplyMSparseTranspMSparse(minusBD2inv,G);
+               MultiplyMSparseTranspMSparse(minusBD2inv,G);
             if(E) {
                AddMSparse(E,1.,minusBD2invTransG);
                DeleteMatrix(&minusBD2invTransG);
@@ -1643,7 +1579,7 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
          }
          TMatrixDSparse V(Eigen.GetEigenVectors());
          TMatrixDSparse *VDVt=MultiplyMSparseMSparseTranspVector
-         (&V,&V,&inverseEV);
+            (&V,&V,&inverseEV);
 
          // pack matrix VDVt to r
          const Int_t *vdvt_rows=VDVt->GetRowIndexArray();
@@ -1679,8 +1615,8 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
    delete [] isZero;
 
    TMatrixDSparse *r=(rNumEl>=0) ?
-   CreateSparseMatrix(A->GetNrows(),A->GetNrows(),rNumEl,
-                      rEl_row,rEl_col,rEl_data) : 0;
+      CreateSparseMatrix(A->GetNrows(),A->GetNrows(),rNumEl,
+                         rEl_row,rEl_col,rEl_data) : 0;
    delete [] rEl_data;
    delete [] rEl_col;
    delete [] rEl_row;
@@ -1709,19 +1645,19 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
             if(TMath::Abs(ar(i,j)-ar(j,i))>
                epsilonA2*(TMath::Abs(ar(i,j))+TMath::Abs(ar(j,i)))) {
                std::cout<<"Ar is not symmetric Ar("<<i<<","<<j<<")="<<ar(i,j)
-               <<" Ar("<<j<<","<<i<<")="<<ar(j,i)<<"\n";
+                        <<" Ar("<<j<<","<<i<<")="<<ar(j,i)<<"\n";
             }
             // ara should be equal a
             if(TMath::Abs(ara(i,j)-a(i,j))>
                epsilonA2*(TMath::Abs(ara(i,j))+TMath::Abs(a(i,j)))) {
                std::cout<<"ArA is not equal A ArA("<<i<<","<<j<<")="<<ara(i,j)
-               <<" A("<<i<<","<<j<<")="<<a(i,j)<<"\n";
+                        <<" A("<<i<<","<<j<<")="<<a(i,j)<<"\n";
             }
             // ara should be equal a
             if(TMath::Abs(rar(i,j)-R(i,j))>
                epsilonA2*(TMath::Abs(rar(i,j))+TMath::Abs(R(i,j)))) {
                std::cout<<"rAr is not equal r rAr("<<i<<","<<j<<")="<<rar(i,j)
-               <<" r("<<i<<","<<j<<")="<<R(i,j)<<"\n";
+                        <<" r("<<i<<","<<j<<")="<<R(i,j)<<"\n";
             }
          }
       }
@@ -1734,36 +1670,58 @@ TMatrixDSparse *TUnfold::InvertMSparseSymmPos
 
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get bin name of an output bin.
+///
+/// \param[in] iBinX bin number
+///
+/// Return value: name of the bin
+///
+/// For TUnfold and TUnfoldSys, this function simply returns the bin
+/// number as a string. This function really only makes sense in the
+/// context of TUnfoldDensity, where binning schemes are implemented
+/// using the class TUnfoldBinning, and non-trivial bin names are
+/// returned.
+
 TString TUnfold::GetOutputBinName(Int_t iBinX) const
 {
-   // given a bin number, return the name of the output bin
-   // this method makes more sense for the class TUnfoldDnesity
-   // where it gets overwritten
    return TString::Format("#%d",iBinX);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Set up response matrix and regularisation scheme.
+///
+/// \param[in] hist_A matrix of MC events that describes the migrations
+/// \param[in] histmap mapping of the histogram axes
+/// \param[in] regmode (default=kRegModeSize) global regularisation mode
+/// \param[in] constraint (default=kEConstraintArea) type of constraint
+///
+/// Treatment of overflow bins in the matrix hist_A
+///
+///   - Events reconstructed in underflow or overflow bins are counted
+/// as inefficiency. They have to be filled properly.
+///   - Events where the truth level is in underflow or overflow bins are
+/// treated as a part of the generator level distribution.
+/// The full truth level distribution (including underflow and
+/// overflow) is unfolded.
+///
+/// If unsure, do the following:
+///
+///   - store evens where the truth is in underflow or overflow
+/// (sometimes called "fakes") in a separate TH1. Ensure that the
+/// truth-level underflow and overflow bins of hist_A are all zero.
+///   - the fakes are background to the
+/// measurement. Use the classes TUnfoldSys and TUnfoldDensity instead
+/// of the plain TUnfold for subtracting background.
+
 TUnfold::TUnfold(const TH2 *hist_A, EHistMap histmap, ERegMode regmode,
                  EConstraint constraint)
 {
-   // set up unfolding matrix and initial regularisation scheme
-   //    hist_A:  matrix that describes the migrations
-   //    histmap: mapping of the histogram axes to the unfolding output
-   //    regmode: global regularisation mode
-   //    constraint: type of constraint to use
    // data members initialized to something different from zero:
    //    fA: filled from hist_A
    //    fDA: filled from hist_A
    //    fX0: filled from hist_A
    //    fL: filled depending on the regularisation scheme
-   // Treatment of overflow bins
-   //    Bins where the unfolding input (Detector level) is in overflow
-   //    are used for the efficiency correction. They have to be filled
-   //    properly!
-   //    Bins where the unfolding output (Generator level) is in overflow
-   //    are treated as a part of the generator level distribution.
-   //    I.e. the unfolding output could have non-zero overflow bins if the
-   //    input matrix does have such bins.
-
    InitTUnfold();
    SetConstraint(constraint);
    Int_t nx0, nx, ny;
@@ -1824,12 +1782,12 @@ TUnfold::TUnfold(const TH2 *hist_A, EHistMap histmap, ERegMode regmode,
          fSumOverY[nx] = sum;
          if (histmap == kHistMapOutputHoriz) {
             fSumOverY[nx] +=
-            hist_A->GetBinContent(ix, 0) +
-            hist_A->GetBinContent(ix, ny + 1);
+               hist_A->GetBinContent(ix, 0) +
+               hist_A->GetBinContent(ix, ny + 1);
          } else {
             fSumOverY[nx] +=
-            hist_A->GetBinContent(0, ix) +
-            hist_A->GetBinContent(ny + 1, ix);
+               hist_A->GetBinContent(0, ix) +
+               hist_A->GetBinContent(ny + 1, ix);
          }
          nx++;
       } else {
@@ -1879,7 +1837,7 @@ TUnfold::TUnfold(const TH2 *hist_A, EHistMap histmap, ERegMode regmode,
       }
       if(nskipped==(2-underflowBin-overflowBin)) {
          Info("TUnfold","underflow and overflow bin "
-              "do not depend on the input data");
+         "do not depend on the input data");
       } else {
          Warning("TUnfold","%d output bins "
                  "do not depend on the input data %s",nDisconnected,
@@ -1945,23 +1903,16 @@ TUnfold::TUnfold(const TH2 *hist_A, EHistMap histmap, ERegMode regmode,
    }
 }
 
-TUnfold::~TUnfold(void)
-{
-   // delete all data members
-
-   DeleteMatrix(&fA);
-   DeleteMatrix(&fL);
-   DeleteMatrix(&fVyy);
-   DeleteMatrix(&fY);
-   DeleteMatrix(&fX0);
-
-   ClearResults();
-}
+////////////////////////////////////////////////////////////////////////////////
+/// Set bias vector.
+///
+/// \param[in] bias histogram with new bias vector
+///
+/// the initial bias vector is determined from the response matrix
+/// but may be changed by using this method
 
 void TUnfold::SetBias(const TH1 *bias)
 {
-   // initialize alternative bias from histogram
-   // modifies data member fX0
    DeleteMatrix(&fX0);
    fX0 = new TMatrixD(GetNx(), 1);
    for (Int_t i = 0; i < GetNx(); i++) {
@@ -1969,18 +1920,23 @@ void TUnfold::SetBias(const TH1 *bias)
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add a row of regularisation conditions to the matrix L.
+///
+/// \param[in] i0 truth histogram bin number
+/// \param[in] f0 entry in the matrix L, column i0
+/// \param[in] i1 truth histogram bin number
+/// \param[in] f1 entry in the matrix L, column i1
+/// \param[in] i2 truth histogram bin number
+/// \param[in] f2 entry in the matrix L, column i2
+///
+/// the arguments are used to form one row (k) of the matrix L, where
+///   \f$ L_{k,i0}=f0 \f$ and \f$ L_{k,i1}=f1 \f$ and  \f$ L_{k,i2}=f2 \f$
+/// negative indexes i0,i1,i2 are ignored.
+
 Bool_t TUnfold::AddRegularisationCondition
 (Int_t i0,Double_t f0,Int_t i1,Double_t f1,Int_t i2,Double_t f2)
 {
-   // add regularisation condition for a triplet of bins and scale factors
-   // the arguments are used to form one row (k) of the matrix L
-   //   L(k,i0)=f0
-   //   L(k,i1)=f1
-   //   L(k,i2)=f2
-   // the indices i0,i1,i2 are transformed of bin numbers
-   // if i2<0, do not fill  L(k,i2)
-   // if i1<0, do not fill  L(k,i1)
-
    Int_t indices[3];
    Double_t data[3];
    Int_t nEle=0;
@@ -2003,19 +1959,22 @@ Bool_t TUnfold::AddRegularisationCondition
    return AddRegularisationCondition(nEle,indices,data);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add a row of regularisation conditions to the matrix L.
+///
+/// \param[in] nEle number of valid entries in indices and rowData
+/// \param[in] indices column numbers of L to fill
+/// \param[in] rowData data to fill into the new row of L
+///
+/// returns true if a row was added, false otherwise
+///
+/// A new row k is added to the matrix L, its dimension is expanded.
+/// The new elements \f$ L_{ki} \f$ are filled from the array rowData[]
+/// where the indices i which are taken from the array indices[].
+
 Bool_t TUnfold::AddRegularisationCondition
 (Int_t nEle,const Int_t *indices,const Double_t *rowData)
 {
-   // add a regularisation condition
-   // the arguments are used to form one row (k) of the matrix L
-   //   L(k,indices[0])=rowData[0]
-   //    ...
-   //   L(k,indices[nEle-1])=rowData[nEle-1]
-   //
-   // the indices are taken as bin numbers,
-   // transformed to internal bin numbers using the array fHistToX
-
-
    Bool_t r=kTRUE;
    const Int_t *l0_rows=fL->GetRowIndexArray();
    const Int_t *l0_cols=fL->GetColIndexArray();
@@ -2066,6 +2025,24 @@ Bool_t TUnfold::AddRegularisationCondition
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add  a regularisation condition on the magnitude of a truth bin.
+///
+/// \param[in] bin bin number
+/// \param[in] scale (default=1) scale factor
+///
+/// this adds one row to L, where the element <b>bin</b> takes the
+/// value <b>scale</b>
+///
+/// return value: 0 if ok, 1 if the condition has not been
+/// added. Conditions which are not added typically correspond to bin
+/// numbers where the truth can not be unfolded (either response
+/// matrix is empty or the data do not constrain).
+///
+/// The RegularizeXXX() methods can be used to set up a custom matrix
+/// of regularisation conditions. In this case, start with an empty
+/// matrix L (argument regmode=kRegModeNone in the constructor)
+
 Int_t TUnfold::RegularizeSize(int bin, Double_t scale)
 {
    // add regularisation on the size of bin i
@@ -2080,8 +2057,28 @@ Int_t TUnfold::RegularizeSize(int bin, Double_t scale)
    return AddRegularisationCondition(bin,scale) ? 0 : 1;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add  a regularisation condition on the difference of two truth bin.
+///
+/// \param[in] left_bin bin number
+/// \param[in] right_bin bin number
+/// \param[in] scale (default=1) scale factor
+///
+/// this adds one row to L, where the element <b>left_bin</b> takes the
+/// value <b>-scale</b> and the element  <b>right_bin</b> takes the
+/// value <b>+scale</b>
+///
+/// return value: 0 if ok, 1 if the condition has not been
+/// added. Conditions which are not added typically correspond to bin
+/// numbers where the truth can not be unfolded (either response
+/// matrix is empty or the data do not constrain).
+///
+/// The RegularizeXXX() methods can be used to set up a custom matrix
+/// of regularisation conditions. In this case, start with an empty
+/// matrix L (argument regmode=kRegModeNone in the constructor)
+
 Int_t TUnfold::RegularizeDerivative(int left_bin, int right_bin,
-                                    Double_t scale)
+                                   Double_t scale)
 {
    // add regularisation on the difference of two bins
    //   left_bin: 1st bin
@@ -2096,10 +2093,33 @@ Int_t TUnfold::RegularizeDerivative(int left_bin, int right_bin,
    return AddRegularisationCondition(left_bin,-scale,right_bin,scale) ? 0 : 1;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add  a regularisation condition on the curvature of three truth bin.
+///
+/// \param[in] left_bin bin number
+/// \param[in] center_bin bin number
+/// \param[in] right_bin bin number
+/// \param[in] scale_left (default=1) scale factor
+/// \param[in] scale_right (default=1) scale factor
+///
+/// this adds one row to L, where the element <b>left_bin</b> takes the
+/// value <b>-scale_left</b>, the element  <b>right_bin</b> takes the
+/// value <b>-scale_right</b> and the element  <b>center_bin</b> takes
+/// the value <b>scale_left+scale_right</b>
+///
+/// return value: 0 if ok, 1 if the condition has not been
+/// added. Conditions which are not added typically correspond to bin
+/// numbers where the truth can not be unfolded (either response
+/// matrix is empty or the data do not constrain).
+///
+/// The RegularizeXXX() methods can be used to set up a custom matrix
+/// of regularisation conditions. In this case, start with an empty
+/// matrix L (argument regmode=kRegModeNone in the constructor)
+
 Int_t TUnfold::RegularizeCurvature(int left_bin, int center_bin,
-                                   int right_bin,
-                                   Double_t scale_left,
-                                   Double_t scale_right)
+                                  int right_bin,
+                                  Double_t scale_left,
+                                  Double_t scale_right)
 {
    // add regularisation on the curvature through 3 bins (2nd derivative)
    //   left_bin: 1st bin
@@ -2114,16 +2134,36 @@ Int_t TUnfold::RegularizeCurvature(int left_bin, int center_bin,
    if(fRegMode!=kRegModeCurvature) fRegMode=kRegModeMixed;
 
    return AddRegularisationCondition
-   (left_bin,-scale_left,
-    center_bin,scale_left+scale_right,
-    right_bin,-scale_right)
-   ? 0 : 1;
+      (left_bin,-scale_left,
+       center_bin,scale_left+scale_right,
+       right_bin,-scale_right)
+          ? 0 : 1;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add regularisation conditions for a group of bins.
+///
+/// \param[in] start first bin number
+/// \param[in] step step size
+/// \param[in] nbin number of bins
+/// \param[in] regmode regularisation mode (one of: kRegModeSize,
+/// kRegModeDerivative, kRegModeCurvature)
+///
+/// add regularisation conditions for a group of equidistant
+/// bins. There are <b>nbin</b> bins, starting with bin <b>start</b>
+/// and with a distance of <b>step</b> between bins.
+///
+/// Return value: number of regularisation conditions which could not
+/// be added.
+///
+/// Conditions which are not added typically correspond to bin
+/// numbers where the truth can not be unfolded (either response
+/// matrix is empty or the data do not constrain).
+
 Int_t TUnfold::RegularizeBins(int start, int step, int nbin,
-                              ERegMode regmode)
+                             ERegMode regmode)
 {
-   // set regularization on a 1-dimensional curve
+   // set regulatisation on a 1-dimensional curve
    //   start: first bin
    //   step:  distance between neighbouring bins
    //   nbin:  total number of bins
@@ -2160,11 +2200,32 @@ Int_t TUnfold::RegularizeBins(int start, int step, int nbin,
    return nError;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add regularisation conditions for 2d unfolding.
+///
+/// \param[in] start_bin first bin number
+/// \param[in] step1 step size, 1st dimension
+/// \param[in] nbin1 number of bins, 1st dimension
+/// \param[in] step2 step size, 2nd dimension
+/// \param[in] nbin2 number of bins, 2nd dimension
+/// \param[in] regmode regularisation mode (one of: kRegModeSize,
+/// kRegModeDerivative, kRegModeCurvature)
+///
+/// add regularisation conditions for a grid of bins. The start bin is
+/// <b>start_bin</b>. Along the first (second) dimension, there are
+/// <b>nbin1</b> (<b>nbin2</b>) bins and adjacent bins are spaced by
+/// <b>step1</b> (<b>step2</b>) units.
+///
+/// Return value: number of regularisation conditions which could not
+/// be added. Conditions which are not added typically correspond to bin
+/// numbers where the truth can not be unfolded (either response
+/// matrix is empty or the data do not constrain).
+
 Int_t TUnfold::RegularizeBins2D(int start_bin, int step1, int nbin1,
-                                int step2, int nbin2, ERegMode regmode)
+                               int step2, int nbin2, ERegMode regmode)
 {
    // set regularisation on a 2-dimensional grid of bins
-   //     start: first bin
+   //     start_bin: first bin
    //     step1: distance between bins in 1st direction
    //     nbin1: number of bins in 1st direction
    //     step2: distance between bins in 2nd direction
@@ -2183,604 +2244,661 @@ Int_t TUnfold::RegularizeBins2D(int start_bin, int step1, int nbin1,
    return nError;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Perform the unfolding for a given input and regularisation.
+///
+/// \param[in] tau_reg regularisation parameter
+/// \param[in] input input distribution with uncertainties
+/// \param[in] scaleBias (default=0.0) scale factor applied to the bias
+///
+/// This is a shortcut for `{ SetInput(input,scaleBias); DoUnfold(tau); }`
+///
+/// Data members required:
+///  - fA, fX0, fL
+/// Data members modified:
+///  - those documented in SetInput()
+///    and those documented in DoUnfold(Double_t)
+/// Return value:
+///  - maximum global correlation coefficient
+///    NOTE!!! return value >=1.0 means error, and the result is junk
+///
+/// Overflow bins of the input distribution are ignored!
+
 Double_t TUnfold::DoUnfold(Double_t tau_reg,const TH1 *input,
                            Double_t scaleBias)
 {
-   // Do unfolding of an input histogram
-   //   tau_reg: regularisation parameter
-   //   input:   input distribution with errors
-   //   scaleBias:  scale factor applied to the bias
-   // Data members required:
-   //   fA, fX0, fL
-   // Data members modified:
-   //   those documented in SetInput()
-   //   and those documented in DoUnfold(Double_t)
-   // Return value:
-   //   maximum global correlation coefficient
-   //   NOTE!!! return value >=1.0 means error, and the result is junk
-   //
-   // Overflow bins of the input distribution are ignored!
 
    SetInput(input,scaleBias);
    return DoUnfold(tau_reg);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Define input data for subsequent calls to DoUnfold(tau).
+///
+/// \param[in] input input distribution with uncertainties
+/// \param[in] scaleBias (default=0) scale factor applied to the bias
+/// \param[in] oneOverZeroError (default=0) for bins with zero error, this number defines 1/error.
+/// \param[in] hist_vyy (default=0) if non-zero, this defines the data covariance matrix
+/// \param[in] hist_vyy_inv (default=0) if non-zero and hist_vyy is
+/// set, defines the inverse of the data covariance matrix. This
+/// feature can be useful for repeated unfoldings in cases where the
+/// inversion of the input covariance matrix is lengthy
+///
+/// Return value: nError1+10000*nError2
+///
+///   - nError1: number of bins where the uncertainty is zero.
+/// these bins either are not used for the unfolding (if
+/// oneOverZeroError==0) or 1/uncertainty is set to oneOverZeroError.
+///   - nError2: return values>10000 are fatal errors, because the
+/// unfolding can not be done. The number nError2 corresponds to the
+/// number of truth bins which are not constrained by data points.
+///
+/// Data members modified:
+///  - fY, fVyy, , fBiasScale
+/// Data members cleared
+///  - fVyyInv, fNdf
+///  - + see ClearResults
+
 Int_t TUnfold::SetInput(const TH1 *input, Double_t scaleBias,
                         Double_t oneOverZeroError,const TH2 *hist_vyy,
                         const TH2 *hist_vyy_inv)
 {
-   // Define the input data for subsequent calls to DoUnfold(Double_t)
-   //   input:   input distribution with errors
-   //   scaleBias:  scale factor applied to the bias
-   //   oneOverZeroError: for bins with zero error, this number defines 1/error.
-   //   hist_vyy: if non-zero, defines the data covariance matrix
-   //             otherwise it is calculated from the data errors
-   //   hist_vyy_inv: if non-zero and if hist_vyy  is set, defines the inverse of the data covariance matrix
-   // Return value: number of bins with bad error
-   //                 +10000*number of unconstrained output bins
-   //         Note: return values>=10000 are fatal errors,
-   //               for the given input, the unfolding can not be done!
-   // Data members modified:
-   //   fY, fVyy, , fBiasScale
-   // Data members cleared
-   //   fVyyInv, fNdf
-   //   + see ClearResults
+  DeleteMatrix(&fVyyInv);
+  fNdf=0;
 
-   DeleteMatrix(&fVyyInv);
-   fNdf=0;
-
-   fBiasScale = scaleBias;
+  fBiasScale = scaleBias;
 
    // delete old results (if any)
-   ClearResults();
-
-   // construct error matrix and inverted error matrix of measured quantities
-   // from errors of input histogram or use error matrix
-
-   Int_t *rowVyyN=new Int_t[GetNy()*GetNy()+1];
-   Int_t *colVyyN=new Int_t[GetNy()*GetNy()+1];
-   Double_t *dataVyyN=new Double_t[GetNy()*GetNy()+1];
-
-   Int_t *rowVyy1=new Int_t[GetNy()];
-   Int_t *colVyy1=new Int_t[GetNy()];
-   Double_t *dataVyy1=new Double_t[GetNy()];
-   Double_t *dataVyyDiag=new Double_t[GetNy()];
-
-   Int_t nError=0;
-   Int_t nVyyN=0;
-   Int_t nVyy1=0;
-   for (Int_t iy = 0; iy < GetNy(); iy++) {
-      // diagonals
-      Double_t dy2;
-      if(!hist_vyy) {
-         Double_t dy = input->GetBinError(iy + 1);
-         dy2=dy*dy;
-         if (dy2 <= 0.0) {
-            nError++;
-            if(oneOverZeroError>0.0) {
-               dy2 = 1./ ( oneOverZeroError*oneOverZeroError);
-            }
-         }
-      } else {
-         dy2 = hist_vyy->GetBinContent(iy+1,iy+1);
-      }
-      rowVyyN[nVyyN] = iy;
-      colVyyN[nVyyN] = iy;
-      rowVyy1[nVyy1] = iy;
-      colVyy1[nVyy1] = 0;
-      dataVyyDiag[iy] = dy2;
-      if(dy2>0.0) {
-         dataVyyN[nVyyN++] = dy2;
-         dataVyy1[nVyy1++] = dy2;
-      }
-   }
-   if(hist_vyy) {
-      // non-diagonal elements
-      for (Int_t iy = 0; iy < GetNy(); iy++) {
-         // ignore rows where the diagonal is zero
-         if(dataVyyDiag[iy]<=0.0) continue;
-         for (Int_t jy = 0; jy < GetNy(); jy++) {
-            // skip diagonal elements
-            if(iy==jy) continue;
-            // ignore columns where the diagonal is zero
-            if(dataVyyDiag[jy]<=0.0) continue;
-
-            rowVyyN[nVyyN] = iy;
-            colVyyN[nVyyN] = jy;
-            dataVyyN[nVyyN]= hist_vyy->GetBinContent(iy+1,jy+1);
-            if(dataVyyN[nVyyN] == 0.0) continue;
-            nVyyN ++;
-         }
-      }
-      if(hist_vyy_inv) {
-         Warning("SetInput",
-                 "inverse of input covariance is taken from user input");
-         Int_t *rowVyyInv=new Int_t[GetNy()*GetNy()+1];
-         Int_t *colVyyInv=new Int_t[GetNy()*GetNy()+1];
-         Double_t *dataVyyInv=new Double_t[GetNy()*GetNy()+1];
-         Int_t nVyyInv=0;
-         for (Int_t iy = 0; iy < GetNy(); iy++) {
-            for (Int_t jy = 0; jy < GetNy(); jy++) {
-               rowVyyInv[nVyyInv] = iy;
-               colVyyInv[nVyyInv] = jy;
-               dataVyyInv[nVyyInv]= hist_vyy_inv->GetBinContent(iy+1,jy+1);
-               if(dataVyyInv[nVyyInv] == 0.0) continue;
-               nVyyInv ++;
-            }
-         }
-         fVyyInv=CreateSparseMatrix
-         (GetNy(),GetNy(),nVyyInv,rowVyyInv,colVyyInv,dataVyyInv);
-         delete [] rowVyyInv;
-         delete [] colVyyInv;
-         delete [] dataVyyInv;
-      }
-   }
-   DeleteMatrix(&fVyy);
-   fVyy = CreateSparseMatrix
-   (GetNy(),GetNy(),nVyyN,rowVyyN,colVyyN,dataVyyN);
-
-   delete[] rowVyyN;
-   delete[] colVyyN;
-   delete[] dataVyyN;
-
-   TMatrixDSparse *vecV=CreateSparseMatrix
-   (GetNy(),1,nVyy1,rowVyy1,colVyy1, dataVyy1);
-
-   delete[] rowVyy1;
-   delete[] colVyy1;
-   delete[] dataVyy1;
-
-   //
-   // get input vector
-   DeleteMatrix(&fY);
-   fY = new TMatrixD(GetNy(), 1);
-   for (Int_t i = 0; i < GetNy(); i++) {
-      (*fY) (i, 0) = input->GetBinContent(i + 1);
-   }
-   // simple check whether unfolding is possible, given the matrices fA and  fV
-   TMatrixDSparse *mAtV=MultiplyMSparseTranspMSparse(fA,vecV);
-   DeleteMatrix(&vecV);
-   Int_t nError2=0;
-   for (Int_t i = 0; i <mAtV->GetNrows();i++) {
-      if(mAtV->GetRowIndexArray()[i]==
-         mAtV->GetRowIndexArray()[i+1]) {
-         nError2 ++;
-      }
-   }
-   if(nError>0) {
-      if(oneOverZeroError !=0.0) {
-         if(nError>1) {
-            Warning("SetInput","%d/%d input bins have zero error,"
-                    " 1/error set to %lf.",nError,GetNy(),oneOverZeroError);
-         } else {
-            Warning("SetInput","One input bin has zero error,"
-                    " 1/error set to %lf.",oneOverZeroError);
-         }
-      } else {
-         if(nError>1) {
-            Warning("SetInput","%d/%d input bins have zero error,"
-                    " and are ignored.",nError,GetNy());
-         } else {
-            Warning("SetInput","One input bin has zero error,"
-                    " and is ignored.");
-         }
-      }
-      fIgnoredBins=nError;
-   }
-   if(nError2>0) {
-      // check whether data points with zero error are responsible
-      if(oneOverZeroError<=0.0) {
-         //const Int_t *a_rows=fA->GetRowIndexArray();
-         //const Int_t *a_cols=fA->GetColIndexArray();
-         for (Int_t col = 0; col <mAtV->GetNrows();col++) {
-            if(mAtV->GetRowIndexArray()[col]==
-               mAtV->GetRowIndexArray()[col+1]) {
-               TString binlist("no data to constrain output bin ");
-               binlist += GetOutputBinName(fXToHist[col]);
-               /* binlist +=" depends on ignored input bins ";
-                for(Int_t row=0;row<fA->GetNrows();row++) {
-                if(dataVyyDiag[row]>0.0) continue;
-                for(Int_t i=a_rows[row];i<a_rows[row+1];i++) {
-                if(a_cols[i]!=col) continue;
-                binlist +=" ";
-                binlist +=row;
-                }
-                } */
-               Warning("SetInput","%s",binlist.Data());
-            }
-         }
-      }
-      if(nError2>1) {
-         Error("SetInput","%d/%d output bins are not constrained by any data.",
-               nError2,mAtV->GetNrows());
-      } else {
-         Error("SetInput","One output bins is not constrained by any data.");
-      }
-   }
-   DeleteMatrix(&mAtV);
-
-   delete[] dataVyyDiag;
-
-   return nError+10000*nError2;
+  ClearResults();
+
+  // construct error matrix and inverted error matrix of measured quantities
+  // from errors of input histogram or use error matrix
+
+  Int_t *rowVyyN=new Int_t[GetNy()*GetNy()+1];
+  Int_t *colVyyN=new Int_t[GetNy()*GetNy()+1];
+  Double_t *dataVyyN=new Double_t[GetNy()*GetNy()+1];
+
+  Int_t *rowVyy1=new Int_t[GetNy()];
+  Int_t *colVyy1=new Int_t[GetNy()];
+  Double_t *dataVyy1=new Double_t[GetNy()];
+  Double_t *dataVyyDiag=new Double_t[GetNy()];
+
+  Int_t nVarianceZero=0;
+  Int_t nVarianceForced=0;
+  Int_t nVyyN=0;
+  Int_t nVyy1=0;
+  for (Int_t iy = 0; iy < GetNy(); iy++) {
+     // diagonals
+     Double_t dy2;
+     if(!hist_vyy) {
+        Double_t dy = input->GetBinError(iy + 1);
+        dy2=dy*dy;
+        if (dy2 <= 0.0) {
+           if(oneOverZeroError>0.0) {
+              dy2 = 1./ ( oneOverZeroError*oneOverZeroError);
+              nVarianceForced++;
+           } else {
+              nVarianceZero++;
+           }
+        }
+     } else {
+        dy2 = hist_vyy->GetBinContent(iy+1,iy+1);
+        if (dy2 <= 0.0) {
+           nVarianceZero++;
+        }
+     }
+     rowVyyN[nVyyN] = iy;
+     colVyyN[nVyyN] = iy;
+     rowVyy1[nVyy1] = iy;
+     colVyy1[nVyy1] = 0;
+     dataVyyDiag[iy] = dy2;
+     if(dy2>0.0) {
+        dataVyyN[nVyyN++] = dy2;
+        dataVyy1[nVyy1++] = dy2;
+     }
+  }
+  if(hist_vyy) {
+     // non-diagonal elements
+     Int_t nOffDiagNonzero=0;
+     for (Int_t iy = 0; iy < GetNy(); iy++) {
+        // ignore rows where the diagonal is zero
+        if(dataVyyDiag[iy]<=0.0) {
+           for (Int_t jy = 0; jy < GetNy(); jy++) {
+              if(hist_vyy->GetBinContent(iy+1,jy+1)!=0.0) {
+                 nOffDiagNonzero++;
+              }
+           }
+           continue;
+        }
+        for (Int_t jy = 0; jy < GetNy(); jy++) {
+           // skip diagonal elements
+           if(iy==jy) continue;
+           // ignore columns where the diagonal is zero
+           if(dataVyyDiag[jy]<=0.0) continue;
+
+           rowVyyN[nVyyN] = iy;
+           colVyyN[nVyyN] = jy;
+           dataVyyN[nVyyN]= hist_vyy->GetBinContent(iy+1,jy+1);
+           if(dataVyyN[nVyyN] == 0.0) continue;
+           nVyyN ++;
+        }
+     }
+     if(hist_vyy_inv) {
+        Warning("SetInput",
+                "inverse of input covariance is taken from user input");
+        Int_t *rowVyyInv=new Int_t[GetNy()*GetNy()+1];
+        Int_t *colVyyInv=new Int_t[GetNy()*GetNy()+1];
+        Double_t *dataVyyInv=new Double_t[GetNy()*GetNy()+1];
+        Int_t nVyyInv=0;
+        for (Int_t iy = 0; iy < GetNy(); iy++) {
+           for (Int_t jy = 0; jy < GetNy(); jy++) {
+              rowVyyInv[nVyyInv] = iy;
+              colVyyInv[nVyyInv] = jy;
+              dataVyyInv[nVyyInv]= hist_vyy_inv->GetBinContent(iy+1,jy+1);
+              if(dataVyyInv[nVyyInv] == 0.0) continue;
+              nVyyInv ++;
+           }
+        }
+        fVyyInv=CreateSparseMatrix
+           (GetNy(),GetNy(),nVyyInv,rowVyyInv,colVyyInv,dataVyyInv);
+        delete [] rowVyyInv;
+        delete [] colVyyInv;
+        delete [] dataVyyInv;
+     } else {
+        if(nOffDiagNonzero) {
+           Error("SetInput",
+                 "input covariance has elements C(X,Y)!=0 where V(X)==0");
+        }
+     }
+  }
+  DeleteMatrix(&fVyy);
+  fVyy = CreateSparseMatrix
+     (GetNy(),GetNy(),nVyyN,rowVyyN,colVyyN,dataVyyN);
+
+  delete[] rowVyyN;
+  delete[] colVyyN;
+  delete[] dataVyyN;
+
+  TMatrixDSparse *vecV=CreateSparseMatrix
+     (GetNy(),1,nVyy1,rowVyy1,colVyy1, dataVyy1);
+
+  delete[] rowVyy1;
+  delete[] colVyy1;
+  delete[] dataVyy1;
+
+  //
+  // get input vector
+  DeleteMatrix(&fY);
+  fY = new TMatrixD(GetNy(), 1);
+  for (Int_t i = 0; i < GetNy(); i++) {
+     (*fY) (i, 0) = input->GetBinContent(i + 1);
+  }
+  // simple check whether unfolding is possible, given the matrices fA and  fV
+  TMatrixDSparse *mAtV=MultiplyMSparseTranspMSparse(fA,vecV);
+  DeleteMatrix(&vecV);
+  Int_t nError2=0;
+  for (Int_t i = 0; i <mAtV->GetNrows();i++) {
+     if(mAtV->GetRowIndexArray()[i]==
+        mAtV->GetRowIndexArray()[i+1]) {
+        nError2 ++;
+     }
+  }
+  if(nVarianceForced) {
+     if(nVarianceForced>1) {
+        Warning("SetInput","%d/%d input bins have zero error,"
+                " 1/error set to %lf.",
+                nVarianceForced,GetNy(),oneOverZeroError);
+     } else {
+        Warning("SetInput","One input bin has zero error,"
+                " 1/error set to %lf.",oneOverZeroError);
+     }
+  }
+  if(nVarianceZero) {
+     if(nVarianceZero>1) {
+        Warning("SetInput","%d/%d input bins have zero error,"
+                " and are ignored.",nVarianceZero,GetNy());
+     } else {
+        Warning("SetInput","One input bin has zero error,"
+                " and is ignored.");
+     }
+     fIgnoredBins=nVarianceZero;
+  }
+  if(nError2>0) {
+     // check whether data points with zero error are responsible
+     if(oneOverZeroError<=0.0) {
+        //const Int_t *a_rows=fA->GetRowIndexArray();
+        //const Int_t *a_cols=fA->GetColIndexArray();
+        for (Int_t col = 0; col <mAtV->GetNrows();col++) {
+           if(mAtV->GetRowIndexArray()[col]==
+              mAtV->GetRowIndexArray()[col+1]) {
+              TString binlist("no data to constrain output bin ");
+              binlist += GetOutputBinName(fXToHist[col]);
+              /* binlist +=" depends on ignored input bins ";
+              for(Int_t row=0;row<fA->GetNrows();row++) {
+                 if(dataVyyDiag[row]>0.0) continue;
+                 for(Int_t i=a_rows[row];i<a_rows[row+1];i++) {
+                    if(a_cols[i]!=col) continue;
+                    binlist +=" ";
+                    binlist +=row;
+                 }
+                 } */
+              Warning("SetInput","%s",(char const *)binlist);
+           }
+        }
+     }
+     if(nError2>1) {
+        Error("SetInput","%d/%d output bins are not constrained by any data.",
+                nError2,mAtV->GetNrows());
+     } else {
+        Error("SetInput","One output bins is not constrained by any data.");
+     }
+  }
+  DeleteMatrix(&mAtV);
+
+  delete[] dataVyyDiag;
+
+  return nVarianceForced+nVarianceZero+10000*nError2;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Perform the unfolding for a given regularisation parameter tau.
+///
+/// \param[in] tau regularisation parameter
+///
+/// This method sets tau and then calls the core unfolding algorithm
+/// required data members:
+///    - fA:  matrix to relate x and y
+///    - fY:  measured data points
+///    - fX0: bias on x
+///    - fBiasScale: scale factor for fX0
+///    - fV:  inverse of covariance matrix for y
+///    - fL: regularisation conditions
+/// modified data members:
+///    - fTauSquared and those documented in DoUnfold(void)
+
 Double_t TUnfold::DoUnfold(Double_t tau)
 {
-   // Unfold with given value of regularisation parameter tau
-   //     tau: new tau parameter
-   // required data members:
-   //     fA:  matrix to relate x and y
-   //     fY:  measured data points
-   //     fX0: bias on x
-   //     fBiasScale: scale factor for fX0
-   //     fV:  inverse of covariance matrix for y
-   //     fL: regularisation conditions
-   // modified data members:
-   //     fTauSquared and those documented in DoUnfold(void)
    fTauSquared=tau*tau;
    return DoUnfold();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Scan the L curve, determine tau and unfold at the final value of tau.
+///
+/// \param[in] nPoint number of points used for the scan
+/// \param[in] tauMin smallest tau value to study
+/// \param[in] tauMax largest tau value to study. If tauMin=tauMax=0,
+/// a scan interval is determined automatically.
+/// \param[out] lCurve if nonzero, a new TGraph is returned,
+/// containing the L-curve
+/// \param[out] logTauX if nonzero, a new TSpline is returned, to
+/// parameterize the L-curve's x-coordinates as a function of log10(tau)
+/// \param[out] logTauY if nonzero, a new TSpline is returned, to
+/// parameterize the L-curve's y-coordinates as a function of log10(tau)
+/// \param[out] logTauCurvature if nonzero, a new TSpline is returned
+/// of the L-curve curvature as a function of log10(tau)
+///
+/// return value: the coordinate number in the logTauX,logTauY graphs
+/// corresponding to the "final" choice of tau
+///
+/// Recommendation: always check <b>logTauCurvature</b>, it
+/// should be a peaked function (similar to a Gaussian), the maximum
+/// corresponding to the final choice of tau. Also, check the <b>lCurve</b>
+/// it should be approximately L-shaped. If in doubt, adjust tauMin
+/// and tauMax until the results are satisfactory.
+
 Int_t TUnfold::ScanLcurve(Int_t nPoint,
                           Double_t tauMin,Double_t tauMax,
-                          TGraph **lCurve,TSpline **logTauX,
-                          TSpline **logTauY)
+           TGraph **lCurve,TSpline **logTauX,
+                             TSpline **logTauY,TSpline **logTauCurvature)
 {
-   // scan the L curve
-   //   nPoint: number of points on the resulting curve
-   //   tauMin: smallest tau value to study
-   //   tauMax: largest tau value to study
-   //   lCurve: the L curve as graph
-   //   logTauX: output spline of x-coordinates vs tau for the L curve
-   //   logTauY: output spline of y-coordinates vs tau for the L curve
-   // return value: the coordinate number (0..nPoint-1) with the "best" choice
-   //     of tau
-   typedef std::map<Double_t,std::pair<Double_t,Double_t> > XYtau_t;
-   XYtau_t curve;
-
-   //==========================================================
-   // algorithm:
-   //  (1) do the unfolding for nPoint-1 points
-   //      and store the results in the map
-   //        curve
-   //    (1a) store minimum and maximum tau to curve
-   //    (1b) insert additional points, until nPoint-1 values
-   //          have been calculated
-   //
-   //  (2) determine the best choice of tau
-   //      do the unfolding for this point
-   //      and store the result in
-   //        curve
-   //  (3) return the result in
-   //       lCurve logTauX logTauY
-
-   //==========================================================
-   //  (1) do the unfolding for nPoint-1 points
-   //      and store the results in
-   //        curve
-   //    (1a) store minimum and maximum tau to curve
-
-   if((tauMin<=0)||(tauMax<=0.0)||(tauMin>=tauMax)) {
-      // here no range is given, has to be determined automatically
-      // the maximum tau is determined from the chi**2 values
-      // observed from unfolding without regularization
-
-      // first unfolding, without regularisation
-      DoUnfold(0.0);
-
-      // if the number of degrees of freedom is too small, create an error
-      if(GetNdf()<=0) {
-         Error("ScanLcurve","too few input bins, NDF<=0 %d",GetNdf());
-      }
-
-      Double_t x0=GetLcurveX();
-      Double_t y0=GetLcurveY();
-      Info("ScanLcurve","logtau=-Infinity X=%lf Y=%lf",x0,y0);
-      if(!TMath::Finite(x0)) {
-         Fatal("ScanLcurve","problem (too few input bins?) X=%f",x0);
-      }
-      if(!TMath::Finite(y0)) {
-         Fatal("ScanLcurve","problem (missing regularisation?) Y=%f",y0);
-      }
-      {
-         // unfolding guess maximum tau and store it
-         Double_t logTau=
-         0.5*(TMath::Log10(fChi2A+3.*TMath::Sqrt(GetNdf()+1.0))
-              -GetLcurveY());
-         DoUnfold(TMath::Power(10.,logTau));
-         if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
-            Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
-                  GetLcurveX(),GetLcurveY());
-         }
-         curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
-         Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
-              logTau,GetLcurveX(),GetLcurveY());
-      }
-      if((*curve.begin()).second.first<x0) {
-         // if the point at tau==0 seems numerically unstable,
-         // try to find the minimum chi**2 as start value
-         //
-         // "unstable" means that there is a finite tau where the
-         // unfolding chi**2 is smaller than for the case of no
-         // regularisation. Ideally this should never happen
-         do {
-            x0=GetLcurveX();
-            Double_t logTau=(*curve.begin()).first-0.5;
-            DoUnfold(TMath::Power(10.,logTau));
-            if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
-               Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
-                     GetLcurveX(),GetLcurveY());
-            }
-            curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
-            Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
-                 logTau,GetLcurveX(),GetLcurveY());
-         }
-         while(((int)curve.size()<(nPoint-1)/2)&&
-               ((*curve.begin()).second.first<x0));
-      } else {
-         // minimum tau is chosen such that is less than
-         // 1% different from the case of no regularization
-         // log10(1.01) = 0.00432
-
-         // here, more than one point are inserted if necessary
-         while(((int)curve.size()<nPoint-1)&&
-               (((*curve.begin()).second.first-x0>0.00432)||
-                ((*curve.begin()).second.second-y0>0.00432)||
-                (curve.size()<2))) {
-                  Double_t logTau=(*curve.begin()).first-0.5;
-                  DoUnfold(TMath::Power(10.,logTau));
-                  if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
-                     Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
-                           GetLcurveX(),GetLcurveY());
-                  }
-                  curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
-                  Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
-                       logTau,GetLcurveX(),GetLcurveY());
-               }
-      }
-   } else {
-      Double_t logTauMin=TMath::Log10(tauMin);
-      Double_t logTauMax=TMath::Log10(tauMax);
-      if(nPoint>1) {
-         // insert maximum tau
-         DoUnfold(TMath::Power(10.,logTauMax));
-         if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
-            Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
-                  GetLcurveX(),GetLcurveY());
-         }
-         Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
-              logTauMax,GetLcurveX(),GetLcurveY());
-         curve[logTauMax]=std::make_pair(GetLcurveX(),GetLcurveY());
-      }
-      // insert minimum tau
-      DoUnfold(TMath::Power(10.,logTauMin));
-      if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
-         Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
-               GetLcurveX(),GetLcurveY());
-      }
-      Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
-           logTauMin,GetLcurveX(),GetLcurveY());
-      curve[logTauMin]=std::make_pair(GetLcurveX(),GetLcurveY());
-   }
-
-
-   //==========================================================
-   //    (1b) insert additional points, until nPoint-1 values
-   //          have been calculated
-
-   while(int(curve.size())<nPoint-1) {
-      // insert additional points, such that the sizes of the delta(XY) vectors
-      // are getting smaller and smaller
-      XYtau_t::const_iterator i0,i1;
-      i0=curve.begin();
-      i1=i0;
-      Double_t logTau=(*i0).first;
-      Double_t distMax=0.0;
-      for(i1++;i1!=curve.end();i1++) {
-         const std::pair<Double_t,Double_t> &xy0=(*i0).second;
-         const std::pair<Double_t,Double_t> &xy1=(*i1).second;
-         Double_t dx=xy1.first-xy0.first;
-         Double_t dy=xy1.second-xy0.second;
-         Double_t d=TMath::Sqrt(dx*dx+dy*dy);
-         if(d>=distMax) {
-            distMax=d;
-            logTau=0.5*((*i0).first+(*i1).first);
-         }
-         i0=i1;
-      }
-      DoUnfold(TMath::Power(10.,logTau));
-      if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
-         Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
-               GetLcurveX(),GetLcurveY());
-      }
-      Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",logTau,GetLcurveX(),GetLcurveY());
-      curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
-   }
-
-   //==========================================================
-   //  (2) determine the best choice of tau
-   //      do the unfolding for this point
-   //      and store the result in
-   //        curve
-   XYtau_t::const_iterator i0,i1;
-   i0=curve.begin();
-   i1=i0;
-   i1++;
-   Double_t logTauFin=(*i0).first;
-   if( ((int)curve.size())<nPoint) {
-      // set up splines and determine (x,y) curvature in each point
-      Double_t *cTi=new Double_t[curve.size()-1];
-      Double_t *cCi=new Double_t[curve.size()-1];
-      Int_t n=0;
-      {
-         Double_t *lXi=new Double_t[curve.size()];
-         Double_t *lYi=new Double_t[curve.size()];
-         Double_t *lTi=new Double_t[curve.size()];
-         for( XYtau_t::const_iterator i=curve.begin();i!=curve.end();i++) {
-            lXi[n]=(*i).second.first;
-            lYi[n]=(*i).second.second;
-            lTi[n]=(*i).first;
-            n++;
-         }
-         TSpline3 *splineX=new TSpline3("x vs tau",lTi,lXi,n);
-         TSpline3 *splineY=new TSpline3("y vs tau",lTi,lYi,n);
-         // calculate (x,y) curvature for all points
-         // the curvature is stored in the array cCi[] as a function of cTi[]
-         for(Int_t i=0;i<n-1;i++) {
-            Double_t ltau,xy,bi,ci,di;
-            splineX->GetCoeff(i,ltau,xy,bi,ci,di);
-            Double_t tauBar=0.5*(lTi[i]+lTi[i+1]);
-            Double_t dTau=0.5*(lTi[i+1]-lTi[i]);
-            Double_t dx1=bi+dTau*(2.*ci+3.*di*dTau);
-            Double_t dx2=2.*ci+6.*di*dTau;
-            splineY->GetCoeff(i,ltau,xy,bi,ci,di);
-            Double_t dy1=bi+dTau*(2.*ci+3.*di*dTau);
-            Double_t dy2=2.*ci+6.*di*dTau;
-            cTi[i]=tauBar;
-            cCi[i]=(dy2*dx1-dy1*dx2)/TMath::Power(dx1*dx1+dy1*dy1,1.5);
-         }
-         delete splineX;
-         delete splineY;
-         delete[] lXi;
-         delete[] lYi;
-         delete[] lTi;
-      }
-      // create curvature Spline
-      TSpline3 *splineC=new TSpline3("L curve curvature",cTi,cCi,n-1);
-      // find the maximum of the curvature
-      // if the parameter iskip is non-zero, then iskip points are
-      // ignored when looking for the largest curvature
-      // (there are problems with the curvature determined from the first
-      //  few points of splineX,splineY in the algorithm above)
-      Int_t iskip=0;
-      if(n>4) iskip=1;
-      if(n>7) iskip=2;
-      Double_t cCmax=cCi[iskip];
-      Double_t cTmax=cTi[iskip];
-      for(Int_t i=iskip;i<n-2-iskip;i++) {
-         // find maximum on this spline section
-         // check boundary conditions for x[i+1]
-         Double_t xMax=cTi[i+1];
-         Double_t yMax=cCi[i+1];
-         if(cCi[i]>yMax) {
-            yMax=cCi[i];
-            xMax=cTi[i];
-         }
-         // find maximum for x[i]<x<x[i+1]
-         // get spline coefficients and solve equation
-         //   derivative(x)==0
-         Double_t x,y,b,c,d;
-         splineC->GetCoeff(i,x,y,b,c,d);
-         // coefficients of quadratic equation
-         Double_t m_p_half=-c/(3.*d);
-         Double_t q=b/(3.*d);
-         Double_t discr=m_p_half*m_p_half-q;
-         if(discr>=0.0) {
-            // solution found
-            discr=TMath::Sqrt(discr);
-            Double_t xx;
-            if(m_p_half>0.0) {
-               xx = m_p_half + discr;
-            } else {
-               xx = m_p_half - discr;
-            }
-            Double_t dx=cTi[i+1]-x;
-            // check first solution
-            if((xx>0.0)&&(xx<dx)) {
-               y=splineC->Eval(x+xx);
-               if(y>yMax) {
-                  yMax=y;
-                  xMax=x+xx;
-               }
-            }
-            // second solution
-            if(xx !=0.0) {
-               xx= q/xx;
-            } else {
-               xx=0.0;
-            }
-            // check second solution
-            if((xx>0.0)&&(xx<dx)) {
-               y=splineC->Eval(x+xx);
-               if(y>yMax) {
-                  yMax=y;
-                  xMax=x+xx;
-               }
-            }
-         }
-         // check whether this local minimum is a global minimum
-         if(yMax>cCmax) {
-            cCmax=yMax;
-            cTmax=xMax;
-         }
-      }
-#ifdef DEBUG_LCURVE
-      {
-         TCanvas lcc;
-         lcc.Divide(1,1);
-         lcc.cd(1);
-         splineC->Draw();
-         lcc.SaveAs("splinec.ps");
-      }
-#endif
-      delete splineC;
-      delete[] cTi;
-      delete[] cCi;
-      logTauFin=cTmax;
-      DoUnfold(TMath::Power(10.,logTauFin));
-      if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
-         Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
-               GetLcurveX(),GetLcurveY());
-      }
-      Info("ScanLcurve","Result logtau=%lf X=%lf Y=%lf",
-           logTauFin,GetLcurveX(),GetLcurveY());
-      curve[logTauFin]=std::make_pair(GetLcurveX(),GetLcurveY());
-   }
-
-
-   //==========================================================
-   //  (3) return the result in
-   //       lCurve logTauX logTauY
-
-   Int_t bestChoice=-1;
-   if(curve.size()>0) {
-      Double_t *x=new Double_t[curve.size()];
-      Double_t *y=new Double_t[curve.size()];
-      Double_t *logT=new Double_t[curve.size()];
-      int n=0;
+  typedef std::map<Double_t,std::pair<Double_t,Double_t> > XYtau_t;
+  XYtau_t curve;
+
+  //==========================================================
+  // algorithm:
+  //  (1) do the unfolding for nPoint-1 points
+  //      and store the results in the map
+  //        curve
+  //    (1a) store minimum and maximum tau to curve
+  //    (1b) insert additional points, until nPoint-1 values
+  //          have been calculated
+  //
+  //  (2) determine the best choice of tau
+  //      do the unfolding for this point
+  //      and store the result in
+  //        curve
+  //  (3) return the result in
+  //       lCurve logTauX logTauY
+
+  //==========================================================
+  //  (1) do the unfolding for nPoint-1 points
+  //      and store the results in
+  //        curve
+  //    (1a) store minimum and maximum tau to curve
+
+  if((tauMin<=0)||(tauMax<=0.0)||(tauMin>=tauMax)) {
+     // here no range is given, has to be determined automatically
+     // the maximum tau is determined from the chi**2 values
+     // observed from unfolding without regulatisation
+
+     // first unfolding, without regularisation
+     DoUnfold(0.0);
+
+     // if the number of degrees of freedom is too small, create an error
+     if(GetNdf()<=0) {
+        Error("ScanLcurve","too few input bins, NDF<=0 %d",GetNdf());
+     }
+
+     Double_t x0=GetLcurveX();
+     Double_t y0=GetLcurveY();
+     Info("ScanLcurve","logtau=-Infinity X=%lf Y=%lf",x0,y0);
+     if(!TMath::Finite(x0)) {
+        Fatal("ScanLcurve","problem (too few input bins?) X=%f",x0);
+     }
+     if(!TMath::Finite(y0)) {
+        Fatal("ScanLcurve","problem (missing regularisation?) Y=%f",y0);
+     }
+     {
+        // unfolding guess maximum tau and store it
+        Double_t logTau=
+           0.5*(TMath::Log10(fChi2A+3.*TMath::Sqrt(GetNdf()+1.0))
+                -GetLcurveY());
+        DoUnfold(TMath::Power(10.,logTau));
+        if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
+           Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
+                 GetLcurveX(),GetLcurveY());
+        }
+        curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
+        Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
+             logTau,GetLcurveX(),GetLcurveY());
+     }
+     if((*curve.begin()).second.first<x0) {
+        // if the point at tau==0 seems numerically unstable,
+        // try to find the minimum chi**2 as start value
+        //
+        // "unstable" means that there is a finite tau where the
+        // unfolding chi**2 is smaller than for the case of no
+        // regularisation. Ideally this should never happen
+        do {
+           x0=GetLcurveX();
+           Double_t logTau=(*curve.begin()).first-0.5;
+           DoUnfold(TMath::Power(10.,logTau));
+           if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
+              Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
+                    GetLcurveX(),GetLcurveY());
+           }
+           curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
+           Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
+                logTau,GetLcurveX(),GetLcurveY());
+        }
+        while(((int)curve.size()<(nPoint-1)/2)&&
+              ((*curve.begin()).second.first<x0));
+     } else {
+        // minimum tau is chosen such that is less than
+        // 1% different from the case of no regularization
+        // log10(1.01) = 0.00432
+
+        // here, more than one point are inserted if necessary
+        while(((int)curve.size()<nPoint-1)&&
+              (((*curve.begin()).second.first-x0>0.00432)||
+               ((*curve.begin()).second.second-y0>0.00432)||
+               (curve.size()<2))) {
+           Double_t logTau=(*curve.begin()).first-0.5;
+           DoUnfold(TMath::Power(10.,logTau));
+           if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
+              Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
+                    GetLcurveX(),GetLcurveY());
+           }
+           curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
+           Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
+                logTau,GetLcurveX(),GetLcurveY());
+        }
+     }
+  } else {
+     Double_t logTauMin=TMath::Log10(tauMin);
+     Double_t logTauMax=TMath::Log10(tauMax);
+     if(nPoint>1) {
+        // insert maximum tau
+        DoUnfold(TMath::Power(10.,logTauMax));
+        if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
+           Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
+                 GetLcurveX(),GetLcurveY());
+        }
+        Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
+             logTauMax,GetLcurveX(),GetLcurveY());
+        curve[logTauMax]=std::make_pair(GetLcurveX(),GetLcurveY());
+     }
+     // insert minimum tau
+     DoUnfold(TMath::Power(10.,logTauMin));
+     if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
+        Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
+              GetLcurveX(),GetLcurveY());
+     }
+     Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
+          logTauMin,GetLcurveX(),GetLcurveY());
+     curve[logTauMin]=std::make_pair(GetLcurveX(),GetLcurveY());
+  }
+
+
+  //==========================================================
+  //    (1b) insert additional points, until nPoint-1 values
+  //          have been calculated
+
+  while(int(curve.size())<nPoint-1) {
+    // insert additional points, such that the sizes of the delta(XY) vectors
+    // are getting smaller and smaller
+    XYtau_t::const_iterator i0,i1;
+    i0=curve.begin();
+    i1=i0;
+    Double_t logTau=(*i0).first;
+    Double_t distMax=0.0;
+    for(i1++;i1!=curve.end();i1++) {
+      const std::pair<Double_t,Double_t> &xy0=(*i0).second;
+      const std::pair<Double_t,Double_t> &xy1=(*i1).second;
+      Double_t dx=xy1.first-xy0.first;
+      Double_t dy=xy1.second-xy0.second;
+      Double_t d=TMath::Sqrt(dx*dx+dy*dy);
+      if(d>=distMax) {
+        distMax=d;
+        logTau=0.5*((*i0).first+(*i1).first);
+      }
+      i0=i1;
+    }
+    DoUnfold(TMath::Power(10.,logTau));
+    if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
+       Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
+             GetLcurveX(),GetLcurveY());
+    }
+    Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",logTau,GetLcurveX(),GetLcurveY());
+    curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
+  }
+
+  //==========================================================
+  //  (2) determine the best choice of tau
+  //      do the unfolding for this point
+  //      and store the result in
+  //        curve
+  XYtau_t::const_iterator i0,i1;
+  i0=curve.begin();
+  i1=i0;
+  i1++;
+  Double_t logTauFin=(*i0).first;
+  if( ((int)curve.size())<nPoint) {
+    // set up splines and determine (x,y) curvature in each point
+    Double_t *cTi=new Double_t[curve.size()-1];
+    Double_t *cCi=new Double_t[curve.size()-1];
+    Int_t n=0;
+    {
+      Double_t *lXi=new Double_t[curve.size()];
+      Double_t *lYi=new Double_t[curve.size()];
+      Double_t *lTi=new Double_t[curve.size()];
       for( XYtau_t::const_iterator i=curve.begin();i!=curve.end();i++) {
-         if(logTauFin==(*i).first) {
-            bestChoice=n;
-         }
-         x[n]=(*i).second.first;
-         y[n]=(*i).second.second;
-         logT[n]=(*i).first;
-         n++;
-      }
-      if(lCurve) {
-         (*lCurve)=new TGraph(n,x,y);
-         (*lCurve)->SetTitle("L curve");
-      }
-      if(logTauX) (*logTauX)=new TSpline3("log(chi**2)%log(tau)",logT,x,n);
-      if(logTauY) (*logTauY)=new TSpline3("log(reg.cond)%log(tau)",logT,y,n);
-      delete[] x;
-      delete[] y;
-      delete[] logT;
-   }
-
-   return bestChoice;
+        lXi[n]=(*i).second.first;
+        lYi[n]=(*i).second.second;
+        lTi[n]=(*i).first;
+        n++;
+      }
+      TSpline3 *splineX=new TSpline3("x vs tau",lTi,lXi,n);
+      TSpline3 *splineY=new TSpline3("y vs tau",lTi,lYi,n);
+      // calculate (x,y) curvature for all points
+      // the curvature is stored in the array cCi[] as a function of cTi[]
+      for(Int_t i=0;i<n-1;i++) {
+        Double_t ltau,xy,bi,ci,di;
+        splineX->GetCoeff(i,ltau,xy,bi,ci,di);
+        Double_t tauBar=0.5*(lTi[i]+lTi[i+1]);
+        Double_t dTau=0.5*(lTi[i+1]-lTi[i]);
+        Double_t dx1=bi+dTau*(2.*ci+3.*di*dTau);
+        Double_t dx2=2.*ci+6.*di*dTau;
+        splineY->GetCoeff(i,ltau,xy,bi,ci,di);
+        Double_t dy1=bi+dTau*(2.*ci+3.*di*dTau);
+        Double_t dy2=2.*ci+6.*di*dTau;
+        cTi[i]=tauBar;
+        cCi[i]=(dy2*dx1-dy1*dx2)/TMath::Power(dx1*dx1+dy1*dy1,1.5);
+      }
+      delete splineX;
+      delete splineY;
+      delete[] lXi;
+      delete[] lYi;
+      delete[] lTi;
+    }
+    // create curvature Spline
+    TSpline3 *splineC=new TSpline3("L curve curvature",cTi,cCi,n-1);
+    // find the maximum of the curvature
+    // if the parameter iskip is non-zero, then iskip points are
+    // ignored when looking for the largest curvature
+    // (there are problems with the curvature determined from the first
+    //  few points of splineX,splineY in the algorithm above)
+    Int_t iskip=0;
+    if(n>4) iskip=1;
+    if(n>7) iskip=2;
+    Double_t cCmax=cCi[iskip];
+    Double_t cTmax=cTi[iskip];
+    for(Int_t i=iskip;i<n-2-iskip;i++) {
+      // find maximum on this spline section
+      // check boundary conditions for x[i+1]
+      Double_t xMax=cTi[i+1];
+      Double_t yMax=cCi[i+1];
+      if(cCi[i]>yMax) {
+        yMax=cCi[i];
+        xMax=cTi[i];
+      }
+      // find maximum for x[i]<x<x[i+1]
+      // get spline coefficients and solve equation
+      //   derivative(x)==0
+      Double_t x,y,b,c,d;
+      splineC->GetCoeff(i,x,y,b,c,d);
+      // coefficients of quadratic equation
+      Double_t m_p_half=-c/(3.*d);
+      Double_t q=b/(3.*d);
+      Double_t discr=m_p_half*m_p_half-q;
+      if(discr>=0.0) {
+        // solution found
+        discr=TMath::Sqrt(discr);
+        Double_t xx;
+        if(m_p_half>0.0) {
+          xx = m_p_half + discr;
+        } else {
+          xx = m_p_half - discr;
+        }
+        Double_t dx=cTi[i+1]-x;
+        // check first solution
+        if((xx>0.0)&&(xx<dx)) {
+          y=splineC->Eval(x+xx);
+          if(y>yMax) {
+            yMax=y;
+            xMax=x+xx;
+          }
+        }
+        // second solution
+        if(xx !=0.0) {
+          xx= q/xx;
+        } else {
+          xx=0.0;
+        }
+        // check second solution
+        if((xx>0.0)&&(xx<dx)) {
+          y=splineC->Eval(x+xx);
+          if(y>yMax) {
+            yMax=y;
+            xMax=x+xx;
+          }
+        }
+      }
+      // check whether this local minimum is a global minimum
+      if(yMax>cCmax) {
+        cCmax=yMax;
+        cTmax=xMax;
+      }
+    }
+    if(logTauCurvature) {
+       *logTauCurvature=splineC;
+    } else {
+       delete splineC;
+    }
+    delete[] cTi;
+    delete[] cCi;
+    logTauFin=cTmax;
+    DoUnfold(TMath::Power(10.,logTauFin));
+    if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
+       Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
+             GetLcurveX(),GetLcurveY());
+    }
+    Info("ScanLcurve","Result logtau=%lf X=%lf Y=%lf",
+         logTauFin,GetLcurveX(),GetLcurveY());
+    curve[logTauFin]=std::make_pair(GetLcurveX(),GetLcurveY());
+  }
+
+
+  //==========================================================
+  //  (3) return the result in
+  //       lCurve logTauX logTauY
+
+  Int_t bestChoice=-1;
+  if(curve.size()>0) {
+    Double_t *x=new Double_t[curve.size()];
+    Double_t *y=new Double_t[curve.size()];
+    Double_t *logT=new Double_t[curve.size()];
+    int n=0;
+    for( XYtau_t::const_iterator i=curve.begin();i!=curve.end();i++) {
+      if(logTauFin==(*i).first) {
+        bestChoice=n;
+      }
+      x[n]=(*i).second.first;
+      y[n]=(*i).second.second;
+      logT[n]=(*i).first;
+      n++;
+    }
+    if(lCurve) {
+       (*lCurve)=new TGraph(n,x,y);
+       (*lCurve)->SetTitle("L curve");
+   }
+    if(logTauX) (*logTauX)=new TSpline3("log(chi**2)%log(tau)",logT,x,n);
+    if(logTauY) (*logTauY)=new TSpline3("log(reg.cond)%log(tau)",logT,y,n);
+    delete[] x;
+    delete[] y;
+    delete[] logT;
+  }
+
+  return bestChoice;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Histogram of truth bins, determined from summing over the response matrix.
+///
+/// \param[out] out histogram to store the truth bins. The bin contents
+/// are overwritten
+/// \param[in] binMap (default=0) array for mapping truth bins to histogram bins
+///
+/// This vector is also used to initialize the bias
+/// x_{0}. However, the bias vector may be changed using the
+/// SetBias() method.
+///
+/// The use of <b>binMap</b> is explained with the documentation of
+/// the GetOutput() method.
+
 void TUnfold::GetNormalisationVector(TH1 *out,const Int_t *binMap) const
 {
-   // get vector of normalisation factors
-   //   out: output histogram
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
 
    ClearHistogram(out);
    for (Int_t i = 0; i < GetNx(); i++) {
@@ -2791,16 +2909,20 @@ void TUnfold::GetNormalisationVector(TH1 *out,const Int_t *binMap) const
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get bias vector including bias scale.
+///
+/// \param[out] out histogram to store the scaled bias vector. The bin
+/// contents are overwritten
+/// \param[in] binMap (default=0) array for mapping truth bins to histogram bins
+///
+/// This method returns the bias vector times scaling factor, f*x_{0}
+///
+/// The use of <b>binMap</b> is explained with the documentation of
+/// the GetOutput() method
+
 void TUnfold::GetBias(TH1 *out,const Int_t *binMap) const
 {
-   // get bias distribution, possibly with bin remapping
-   //   out: output histogram
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
 
    ClearHistogram(out);
    for (Int_t i = 0; i < GetNx(); i++) {
@@ -2812,17 +2934,21 @@ void TUnfold::GetBias(TH1 *out,const Int_t *binMap) const
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get unfolding result on detector level.
+///
+/// \param[out] out histogram to store the correlation coefficients. The bin
+/// contents and errors are overwritten.
+/// \param[in] binMap (default=0) array for mapping truth bins to histogram bins
+///
+/// This method returns the unfolding output folded by the response
+/// matrix, i.e. the vector Ax.
+///
+/// The use of <b>binMap</b> is explained with the documentation of
+/// the GetOutput() method
+
 void TUnfold::GetFoldedOutput(TH1 *out,const Int_t *binMap) const
 {
-   // get unfolding result, folded back trough the matrix
-   //   out: output histogram
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
-
    ClearHistogram(out);
 
    TMatrixDSparse *AVxx=MultiplyMSparseMSparse(fA,fVxx);
@@ -2842,7 +2968,7 @@ void TUnfold::GetFoldedOutput(TH1 *out,const Int_t *binMap) const
       Double_t e2=0.0;
       Int_t index_a=rows_A[i];
       Int_t index_av=rows_AVxx[i];
-      while((index_a<rows_A[i+1])&&(index_av<rows_AVxx[i])) {
+      while((index_a<rows_A[i+1])&&(index_av<rows_AVxx[i+1])) {
          Int_t j_a=cols_A[index_a];
          Int_t j_av=cols_AVxx[index_av];
          if(j_a<j_av) {
@@ -2860,6 +2986,15 @@ void TUnfold::GetFoldedOutput(TH1 *out,const Int_t *binMap) const
    DeleteMatrix(&AVxx);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get matrix of probabilities.
+///
+/// \param[out] A two-dimensional histogram to store the
+/// probabilities (normalized response matrix). The bin contents are
+/// overwritten
+/// \param[in] histmap specify axis along which the truth bins are
+/// oriented
+
 void TUnfold::GetProbabilityMatrix(TH2 *A,EHistMap histmap) const
 {
    // retrieve matrix of probabilities
@@ -2873,25 +3008,30 @@ void TUnfold::GetProbabilityMatrix(TH2 *A,EHistMap histmap) const
          Int_t ix = cols_A[indexA];
          Int_t ih=fXToHist[ix];
          if (histmap == kHistMapOutputHoriz) {
-            A->SetBinContent(ih, iy,data_A[indexA]);
+            A->SetBinContent(ih, iy+1,data_A[indexA]);
          } else {
-            A->SetBinContent(iy, ih,data_A[indexA]);
+            A->SetBinContent(iy+1, ih,data_A[indexA]);
          }
       }
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Input vector of measurements
+///
+/// \param[out] out histogram to store the measurements. Bin content
+/// and bin errors are overwrite.
+/// \param[in] binMap (default=0) array for mapping truth bins to histogram bins
+///
+/// Bins which had an uncertainty of zero in the call to SetInput()
+/// may acquire bin contents or bin errors different from the
+/// original settings in SetInput().
+///
+/// The use of <b>binMap</b> is explained with the documentation of
+/// the GetOutput() method
+
 void TUnfold::GetInput(TH1 *out,const Int_t *binMap) const
 {
-   // retrieve input distribution
-   //   out: output histogram
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
-
    ClearHistogram(out);
 
    const Int_t *rows_Vyy=fVyy->GetRowIndexArray();
@@ -2899,7 +3039,7 @@ void TUnfold::GetInput(TH1 *out,const Int_t *binMap) const
    const Double_t *data_Vyy=fVyy->GetMatrixArray();
 
    for (Int_t i = 0; i < GetNy(); i++) {
-      Int_t destI=binMap ? binMap[i] : i;
+      Int_t destI=binMap ? binMap[i+1] : i+1;
       if(destI<0) continue;
 
       out->SetBinContent(destI, (*fY) (i, 0)+out->GetBinContent(destI));
@@ -2914,6 +3054,11 @@ void TUnfold::GetInput(TH1 *out,const Int_t *binMap) const
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get inverse of the measurement's covariance matrix.
+///
+/// \param[out] out histogram to store the inverted covariance
+
 void TUnfold::GetInputInverseEmatrix(TH2 *out)
 {
    // calculate the inverse of the contribution to the error matrix
@@ -2936,9 +3081,9 @@ void TUnfold::GetInputInverseEmatrix(TH2 *out)
    }
    if(out) {
       // return matrix as histogram
-      const Int_t *rows_Vyy=fVyy->GetRowIndexArray();
-      const Int_t *cols_Vyy=fVyy->GetColIndexArray();
-      const Double_t *data_Vyy=fVyy->GetMatrixArray();
+      const Int_t *rows_VyyInv=fVyyInv->GetRowIndexArray();
+      const Int_t *cols_VyyInv=fVyyInv->GetColIndexArray();
+      const Double_t *data_VyyInv=fVyyInv->GetMatrixArray();
 
       for(int i=0;i<=out->GetNbinsX()+1;i++) {
          for(int j=0;j<=out->GetNbinsY()+1;j++) {
@@ -2946,15 +3091,27 @@ void TUnfold::GetInputInverseEmatrix(TH2 *out)
          }
       }
 
-      for (Int_t i = 0; i < fVyy->GetNrows(); i++) {
-         for(int index=rows_Vyy[i];index<rows_Vyy[i+1];index++) {
-            Int_t j=cols_Vyy[index];
-            out->SetBinContent(i+1,j+1,data_Vyy[index]);
+      for (Int_t i = 0; i < fVyyInv->GetNrows(); i++) {
+         for(int index=rows_VyyInv[i];index<rows_VyyInv[i+1];index++) {
+            Int_t j=cols_VyyInv[index];
+            out->SetBinContent(i+1,j+1,data_VyyInv[index]);
          }
       }
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get matrix of regularisation conditions squared.
+///
+/// \param[out] out histogram to store the squared matrix of
+/// regularisation conditions. the bin contents are overwritten
+///
+/// This returns the square matrix L^{T}L as a histogram
+///
+/// The histogram should have dimension nx times nx, where nx
+/// corresponds to the number of histogram bins in the response matrix
+/// along the truth axis.
+
 void TUnfold::GetLsquared(TH2 *out) const
 {
    // retrieve matrix of regularisation conditions squared
@@ -2967,31 +3124,54 @@ void TUnfold::GetLsquared(TH2 *out) const
    const Double_t *data=lSquared->GetMatrixArray();
    for (Int_t i = 0; i < GetNx(); i++) {
       for (Int_t cindex = rows[i]; cindex < rows[i+1]; cindex++) {
-         Int_t j=cols[cindex];
-         out->SetBinContent(fXToHist[i], fXToHist[j],data[cindex]);
+        Int_t j=cols[cindex];
+        out->SetBinContent(fXToHist[i], fXToHist[j],data[cindex]);
       }
    }
    DeleteMatrix(&lSquared);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get number of regularisation conditions.
+///
+/// This returns the number of regularisation conditions, useful for
+/// booking a histogram for a subsequent call of GetL().
+
+Int_t TUnfold::GetNr(void) const {
+   return fL->GetNrows();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get matrix of regularisation conditions.
+///
+/// \param[out] out histogram to store the regularisation conditions.
+/// the bin contents are overwritten
+///
+/// The histogram should have dimension nr (x-axis) times nx (y-axis).
+/// nr corresponds to the number of regularisation conditions, it can
+/// be obtained using the method GetNr(). nx corresponds to the number
+/// of histogram bins in the response matrix along the truth axis.
+
 void TUnfold::GetL(TH2 *out) const
 {
-   // retrieve matrix of regularisation conditions
-   //   out: pre-booked matrix
-
    // loop over sparse matrix
    const Int_t *rows=fL->GetRowIndexArray();
    const Int_t *cols=fL->GetColIndexArray();
    const Double_t *data=fL->GetMatrixArray();
    for (Int_t row = 0; row < GetNr(); row++) {
       for (Int_t cindex = rows[row]; cindex < rows[row+1]; cindex++) {
-         Int_t col=cols[cindex];
-         Int_t indexH=fXToHist[col];
-         out->SetBinContent(indexH,row+1,data[cindex]);
+        Int_t col=cols[cindex];
+        Int_t indexH=fXToHist[col];
+        out->SetBinContent(indexH,row+1,data[cindex]);
       }
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Set type of area constraint.
+///
+/// results of a previous unfolding are reset
+
 void TUnfold::SetConstraint(EConstraint constraint)
 {
    // set type of constraint for the next unfolding
@@ -3000,55 +3180,98 @@ void TUnfold::SetConstraint(EConstraint constraint)
    Info("SetConstraint","fConstraint=%d",fConstraint);
 }
 
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return regularisation parameter.
+
 Double_t TUnfold::GetTau(void) const
 {
    // return regularisation parameter
    return TMath::Sqrt(fTauSquared);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get \f$ chi^{2}_{L} \f$ contribution determined in recent unfolding.
+
 Double_t TUnfold::GetChi2L(void) const
 {
    // return chi**2 contribution from regularisation conditions
    return fLXsquared*fTauSquared;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get number of truth parameters determined in recent unfolding.
+///
+/// empty bins of the response matrix or bins which can not be
+/// unfolded due to rank deficits are not counted
+
 Int_t TUnfold::GetNpar(void) const
 {
-   // return number of parameters
    return GetNx();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get value on x-axis of L-curve determined in recent unfolding.
+///
+/// \f$ x=log_{10}(GetChi2A()) \f$
+
 Double_t TUnfold::GetLcurveX(void) const
 {
-   // return value on x axis of L curve
-   return TMath::Log10(fChi2A);
+  return TMath::Log10(fChi2A);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get value on y-axis of L-curve determined in recent unfolding.
+///
+/// \f$ y=log_{10}(GetChi2L()) \f$
+
 Double_t TUnfold::GetLcurveY(void) const
 {
-   // return value on y axis of L curve
-   return TMath::Log10(fLXsquared);
+  return TMath::Log10(fLXsquared);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get output distribution, possibly cumulated over several bins.
+///
+/// \param[out] output existing output histogram. content and errors
+/// will be updated.
+/// \param[in] binMap (default=0) array for mapping truth bins to histogram bins
+///
+/// If nonzero, the array <b>binMap</b> must have dimension n+2, where n
+/// corresponds to the number of bins on the truth axis of the response
+/// matrix (the histogram specified with the TUnfold
+/// constructor). The indexes of <b>binMap</b> correspond to the truth
+/// bins (including underflow and overflow) of the response matrix.
+/// The element binMap[i] specifies the histogram number in
+/// <b>output</b> where the corresponding truth bin will be stored. It is
+/// possible to specify the same <b>output</b> bin number for multiple
+/// indexes, in which case these bins are added. Set binMap[i]=-1 to
+/// ignore an unfolded truth bin. The uncertainties are
+/// calculated from the corresponding parts of the covariance matrix,
+/// properly taking care of added truth bins.
+///
+/// If the pointer <b>binMap</b> is zero, the bins are mapped
+/// one-to-one. Truth bin zero (underflow) is stored in the
+/// <b>output</b> underflow, truth bin 1 is stored in bin number 1, etc.
+///
+///  - output: output histogram
+///  - binMap: for each bin of the original output distribution
+///           specify the destination bin. A value of -1 means that the bin
+///           is discarded. 0 means underflow bin, 1 first bin, ...
+///       - binMap[0] : destination of underflow bin
+///       - binMap[1] : destination of first bin
+///          ...
+
 void TUnfold::GetOutput(TH1 *output,const Int_t *binMap) const
 {
-   // get output distribution, cumulated over several bins
-   //   output: output histogram
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
-
    ClearHistogram(output);
    /* Int_t nbin=output->GetNbinsX();
-    Double_t *c=new Double_t[nbin+2];
-    Double_t *e2=new Double_t[nbin+2];
-    for(Int_t i=0;i<nbin+2;i++) {
-    c[i]=0.0;
-    e2[i]=0.0;
-    } */
+   Double_t *c=new Double_t[nbin+2];
+   Double_t *e2=new Double_t[nbin+2];
+   for(Int_t i=0;i<nbin+2;i++) {
+      c[i]=0.0;
+      e2[i]=0.0;
+      } */
 
    std::map<Int_t,Double_t> e2;
 
@@ -3062,7 +3285,7 @@ void TUnfold::GetOutput(TH1 *output,const Int_t *binMap) const
       Int_t srcBinI=fHistToX[i]; // matrix row index
       if((destBinI>=0)&&(srcBinI>=0)) {
          output->SetBinContent
-         (destBinI, (*fX)(srcBinI,0)+ output->GetBinContent(destBinI));
+            (destBinI, (*fX)(srcBinI,0)+ output->GetBinContent(destBinI));
          // here we loop over the columns of the error matrix
          //   j: counts histogram bins
          //   index: counts sparse matrix index
@@ -3106,18 +3329,23 @@ void TUnfold::GetOutput(TH1 *output,const Int_t *binMap) const
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Add up an error matrix, also respecting the bin mapping.
+///
+/// \param[inout] ematrix error matrix histogram
+/// \param[in] emat error matrix stored with internal mapping (member fXToHist)
+/// \param[in] binMap mapping of histogram bins
+/// \param[in] doClear if true, ematrix is cleared prior to adding
+/// elements of emat to it.
+///
+/// the array <b>binMap</b> is explained with the method GetOutput(). The
+/// matrix emat must have dimension NxN where N=fXToHist.size()
+/// The flag <b>doClear</b> may be used to add covariance matrices from
+/// several uncertainty sources.
+
 void TUnfold::ErrorMatrixToHist(TH2 *ematrix,const TMatrixDSparse *emat,
                                 const Int_t *binMap,Bool_t doClear) const
 {
-   // get an error matrix, cumulated over several bins
-   //   ematrix: output error matrix histogram
-   //   emat: error matrix
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
    Int_t nbin=ematrix->GetNbinsX();
    if(doClear) {
       for(Int_t i=0;i<nbin+2;i++) {
@@ -3160,7 +3388,7 @@ void TUnfold::ErrorMatrixToHist(TH2 *ematrix,const TMatrixDSparse *emat,
                   } else {
                      // add this bin
                      Double_t e2= ematrix->GetBinContent(destBinI,destBinJ)
-                     + data_emat[index_vxx];
+                        + data_emat[index_vxx];
                      ematrix->SetBinContent(destBinI,destBinJ,e2);
                      j++;
                      index_vxx++;
@@ -3172,29 +3400,33 @@ void TUnfold::ErrorMatrixToHist(TH2 *ematrix,const TMatrixDSparse *emat,
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get output covariance matrix, possibly cumulated over several bins.
+///
+/// \param[out] ematrix histogram to store the covariance. The bin
+/// contents are overwritten.
+/// \param[in] binMap (default=0) array for mapping truth bins to histogram bins
+///
+/// The use of <b>binMap</b> is explained with the documentation of
+/// the GetOutput() method
+
 void TUnfold::GetEmatrix(TH2 *ematrix,const Int_t *binMap) const
 {
-   // get output error matrix, cumulated over several bins
-   //   ematrix: output error matrix histogram
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
    ErrorMatrixToHist(ematrix,fVxx,binMap,kTRUE);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get correlation coefficients, possibly cumulated over several bins.
+///
+/// \param[out] rhoij histogram to store the correlation coefficients. The bin
+/// contents are overwritten.
+/// \param[in] binMap (default=0) array for mapping truth bins to histogram bins
+///
+/// The use of <b>binMap</b> is explained with the documentation of
+/// the GetOutput() method
+
 void TUnfold::GetRhoIJ(TH2 *rhoij,const Int_t *binMap) const
 {
-   // get correlation coefficient matrix, cumulated over several bins
-   //   rhoij:  correlation coefficient matrix histogram
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
    GetEmatrix(rhoij,binMap);
    Int_t nbin=rhoij->GetNbinsX();
    Double_t *e=new Double_t[nbin+2];
@@ -3213,18 +3445,29 @@ void TUnfold::GetRhoIJ(TH2 *rhoij,const Int_t *binMap) const
    delete[] e;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get global correlation coefficients, possibly cumulated over several bins.
+///
+/// \param[out] rhoi histogram to store the global correlation
+/// coefficients. The bin contents are overwritten.
+/// \param[in] binMap (default=0) array for mapping truth bins to
+/// histogram bins
+/// \param[out] invEmat (default=0) histogram to store the inverted
+/// covariance matrix
+///
+/// for a given bin, the global correlation coefficient is defined
+/// as \f$ \rho_{i} = \sqrt{1-\frac{1}{(V_{ii}*V^{-1}_{ii})}} \f$
+///
+/// such that the calculation of global correlation coefficients
+/// possibly involves the inversion of a covariance matrix.
+///
+/// return value: maximum global correlation coefficient
+///
+/// The use of <b>binMap</b> is explained with the documentation of
+/// the GetOutput() method
+
 Double_t TUnfold::GetRhoI(TH1 *rhoi,const Int_t *binMap,TH2 *invEmat) const
 {
-   // get global correlation coefficients with arbitrary min map
-   //   rhoi: global correlation histogram
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
-   // return value: maximum global correlation
-
    ClearHistogram(rhoi,-1.);
 
    if(binMap) {
@@ -3272,20 +3515,22 @@ Double_t TUnfold::GetRhoI(TH1 *rhoi,const Int_t *binMap,TH2 *invEmat) const
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get global correlation coefficients with arbitrary min map.
+///
+///  - rhoi: global correlation histogram
+///  - emat: error matrix
+///  - binMap: for each bin of the original output distribution
+///           specify the destination bin. A value of -1 means that the bin
+///           is discarded. 0 means underflow bin, 1 first bin, ...
+///       - binMap[0] : destination of underflow bin
+///       - binMap[1] : destination of first bin
+///          ...
+/// return value: maximum global correlation
+
 Double_t TUnfold::GetRhoIFromMatrix(TH1 *rhoi,const TMatrixDSparse *eOrig,
                                     const Int_t *binMap,TH2 *invEmat) const
 {
-   // get global correlation coefficients with arbitrary min map
-   //   rhoi: global correlation histogram
-   //   emat: error matrix
-   //   binMap: for each bin of the original output distribution
-   //           specify the destination bin. A value of -1 means that the bin
-   //           is discarded. 0 means underflow bin, 1 first bin, ...
-   //        binMap[0] : destination of underflow bin
-   //        binMap[1] : destination of first bin
-   //          ...
-   // return value: maximum global correlation
-
    Double_t rhoMax=0.;
    // original number of bins:
    //    fHistToX.GetSize()
@@ -3391,9 +3636,16 @@ Double_t TUnfold::GetRhoIFromMatrix(TH1 *rhoi,const TMatrixDSparse *eOrig,
    return rhoMax;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Initialize bin contents and bin errors for a given histogram.
+///
+/// \param[out] h histogram
+/// \param[in] x new histogram content
+///
+/// all histgram errors are set to zero, all contents are set to <b>x</b>
+
 void TUnfold::ClearHistogram(TH1 *h,Double_t x) const
 {
-   // clear histogram contents and error
    Int_t nxyz[3];
    nxyz[0]=h->GetNbinsX()+1;
    nxyz[1]=h->GetNbinsY()+1;
@@ -3419,3 +3671,18 @@ void TUnfold::SetEpsMatrix(Double_t eps) {
    // set accuracy for matrix inversion
    if((eps>0.0)&&(eps<1.0)) fEpsMatrix=eps;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return a string describing the TUnfold version.
+///
+/// The version is reported in the form  Vmajor.minor
+/// Changes of the minor version number typically correspond to
+/// bug-fixes. Changes of the major version may result in adding or
+/// removing data attributes, such that the streamer methods are not
+/// compatible between different major versions.
+
+const char *TUnfold::GetTUnfoldVersion(void)
+{
+   return TUnfold_VERSION;
+}
+
diff --git a/hist/unfold/src/TUnfoldBinning.cxx b/hist/unfold/src/TUnfoldBinning.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..242eaaf6991095e148d5039d86208c07a5fedc03
--- /dev/null
+++ b/hist/unfold/src/TUnfoldBinning.cxx
@@ -0,0 +1,2176 @@
+// @(#)root/unfold:$Id$
+// Author: Stefan Schmitt DESY, 10/08/11
+
+/** \class TUnfoldBinning
+\ingroup Unfold
+Binning schemes for use with the unfolding algorithm TUnfoldDensity.
+
+Binning schemes are used to map analysis bins on a single histogram
+axis and back. The analysis bins may include unconnected bins (e.g
+nuisances for background normalisation) or various multidimensional
+histograms (signal bins, differential background normalisation bins, etc).
+
+If you use this software, please consider the following citation
+
+<b>S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]</b>
+
+Detailed documentation and updates are available on
+http://www.desy.de/~sschmitt
+
+### Functionality
+
+The TUnfoldBinning objects are connected by a tree-like structure.
+The structure does not hold any data, but is only responsible for
+arranging the analysis bins in the proper order.
+Each node of the tree is responsible for a group of bins. That group
+may consist of
+
+  -  several unconnected bins, each with a dedicated name.
+  -  bins organized in a multidimensional distribution, defined by a
+set of axes. The axes are defined by a number of bins N and by (N+1)
+bin borders. In addition to the N bins inside there may be an underflow and an
+overflow bin
+
+Each bin has a "global" bin number, which can be found using the
+GetGlobalBinNumber() methods. The global bin number 0 is reserved and
+corresponds to the case where no bin is found in the
+TUnfoldBinning tree.
+
+### Use in the analysis
+Booking histograms:
+
+  - Define binning schemes on detector level and on truth level. This
+can be done using the XML language, use the class TUnfoldBinningXML to
+read the binning scheme. The TUnfoldBinning objects can be written to
+a root file, preferentially together with the corresponding histograms.
+  - For Monte Carlo, book histograms for the response matrix (detector
+vs truth level) using the
+method CreateHistogramOfMigrations()
+  - For data and background, book histograms using the
+"detector level" binning scheme and the method CreateHistogram()
+  - (if required) for the data covariance matrix, book a histogram using the
+"detector level" binning scheme and the method CreateErrorMatrixHistogram()
+  - For truth histograms, book histograms using the
+"truth level" binning scheme and the method CreateHistogram()
+
+The histograms which are booked have all analysis bins arranged on one
+axis (global bin number). TUnfoldBinning provides methods to locate
+the global bin number:
+
+  - Use the method FindNode() to locate a group of bins (e.g. signal,
+control distribution, etc) by their name, then:
+  - Use the method GetGlobalBinNumber() to locate a bin in a
+distribution, then:
+  - Use the TH1::Fill() method and the bin number to fill the
+appropriate bin in one of the histograms booked above.
+
+Unfolding: Specify the response matrix and the binning schemes when
+constructing a TUnfoldDensity object. Tell TUnfoldDensity about the
+data, background, systematic error histograms using the corresponding
+methods of class TUnfoldDensity. Then run the unfolding. Use the
+GetXXX() methods to retrieve the unfolding results into properly
+binned multidimensional histograms.
+
+--------------------------------------------------------------------------------
+
+  This file is part of TUnfold.
+
+  TUnfold is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  TUnfold is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with TUnfold.  If not, see <http://www.gnu.org/licenses/>.
+
+<b>Version 17.6, bug fix to avoid possible crash in method
+CreateHistogramOfMigrations(). Possible bug fix with NaN in GetGlobalBinNUmber() </b>
+
+#### History:
+  - Version 17.5, in parallel to changes in TUnfold
+  - Version 17.4, bug fix with error handling
+  - Version 17.3, bug fix with underflow/overflow bins
+  - Version 17.2, with XML support, bug fix with bin map creation, isPeriodic option for neighbour bins
+  - Version 17.1, in parallel to changes in TUnfold
+  - Version 17.0, initial version, numbered in parallel to TUnfold
+
+*/
+
+#include "TUnfoldBinningXML.h"
+#include <TVectorD.h>
+#include <TAxis.h>
+#include <TString.h>
+#include <TMath.h>
+#include <TF1.h>
+#include <TH1D.h>
+#include <TH2D.h>
+#include <TH3D.h>
+#include <TIterator.h>
+#include <iomanip>
+
+// #define DEBUG
+
+using namespace std;
+
+ClassImp(TUnfoldBinning)
+
+////////////////////////////////////////////////////////////////////////////////
+// Destructor.
+
+TUnfoldBinning::~TUnfoldBinning(void)
+{
+   // delete all children
+   while(childNode) delete childNode;
+   // remove this node from the tree
+   if(GetParentNode() && (GetParentNode()->GetChildNode()==this)) {
+      parentNode->childNode=nextNode;
+   }
+   if(GetPrevNode()) prevNode->nextNode=nextNode;
+   if(GetNextNode()) nextNode->prevNode=prevNode;
+   delete fAxisList;
+   delete fAxisLabelList;
+   if(fBinFactorFunction) {
+      if(!dynamic_cast<TF1 *>(fBinFactorFunction))
+         delete fBinFactorFunction;
+   }
+}
+
+/********************* setup **************************/
+
+////////////////////////////////////////////////////////////////////////////////
+/// Initialize variables for a given number of bins.
+
+void TUnfoldBinning::Initialize(Int_t nBins)
+{
+   parentNode=0;
+   childNode=0;
+   nextNode=0;
+   prevNode=0;
+   fAxisList=new TObjArray();
+   fAxisLabelList=new TObjArray();
+   fAxisList->SetOwner();
+   fAxisLabelList->SetOwner();
+   fHasUnderflow=0;
+   fHasOverflow=0;
+   fDistributionSize=nBins;
+   fBinFactorFunction=0;
+   fBinFactorConstant=1.0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Update fFirstBin and fLastBin members of this node and its children.
+///
+/// \param[in] startWithRootNode if true, start the update with the root node
+
+Int_t TUnfoldBinning::UpdateFirstLastBin(Bool_t startWithRootNode)
+{
+   if(startWithRootNode) {
+      return GetRootNode()->UpdateFirstLastBin(kFALSE);
+   }
+   if(GetPrevNode()) {
+      // if this is not the first node in a sequence,
+      // start with the end bin of the previous node
+      fFirstBin=GetPrevNode()->GetEndBin();
+   } else if(GetParentNode()) {
+      // if this is the first node in a sequence but has a parent,
+      // start with the end bin of the parent's distribution
+      fFirstBin=GetParentNode()->GetStartBin()+
+         GetParentNode()->GetDistributionNumberOfBins();
+   } else {
+      // if this is the top level node, the first bin number is 1
+     fFirstBin=1;
+     //  ... unless the top level node is the only node
+     //  ... with dimension=1
+     //  ... and there are no child nodes
+     //  ... and there is an underflow bin
+     if((!GetChildNode())&&(GetDistributionDimension()==1)&&
+        (fHasUnderflow==1)) {
+        fFirstBin=0;
+     }
+   }
+   fLastBin=fFirstBin+fDistributionSize;
+   // now update count for all children
+   for(TUnfoldBinning *node=childNode;node;node=node->nextNode) {
+      fLastBin=node->UpdateFirstLastBin(kFALSE);
+   }
+   return fLastBin;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Create a new node without axis.
+///
+/// \param[in] name identifier of the node
+/// \param[in] nBin number of unconnected bins (could be zero)
+/// \param[in] binNames (optional) names of the bins separated by ';'
+
+TUnfoldBinning::TUnfoldBinning
+(const char *name,Int_t nBins,const char *binNames)
+   : TNamed(name ? name : "",name ? name : "")
+{
+   Initialize(nBins);
+   if(binNames) {
+      TString nameString(binNames);
+      delete fAxisLabelList;
+      fAxisLabelList=nameString.Tokenize(";");
+   }
+   UpdateFirstLastBin();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Create a new node containing a distribution with one axis.
+///
+/// \param[in] axis the axis to represent
+/// \param[in] includeUnderflow  true if underflow bin should be included
+/// \param[in] includeOverflow true if overflow bin should be included
+
+TUnfoldBinning::TUnfoldBinning
+(const TAxis &axis,Int_t includeUnderflow,Int_t includeOverflow)
+   : TNamed(axis.GetName(),axis.GetTitle())
+{
+   Initialize(0);
+   AddAxis(axis,includeUnderflow,includeOverflow);
+   UpdateFirstLastBin();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Add a new binning node as last last child of this node.
+///
+/// \param[in] name name of the node
+/// \param[in] nBin number of extra bins
+/// \param[in] binNames (optional) names of the bins separated by ';'
+///
+/// this is a shortcut for AddBinning(new TUnfoldBinning(name,nBins,binNames))
+
+TUnfoldBinning *TUnfoldBinning::AddBinning
+(const char *name,Int_t nBins,const char *binNames)
+{
+  return AddBinning(new TUnfoldBinning(name,nBins,binNames));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Add a TUnfoldBinning as the last child of this node.
+///
+/// \param[in] binning the new binning to be added
+///
+/// return value: if succeeded, return "binning"
+///               otherwise return 0
+
+TUnfoldBinning *TUnfoldBinning::AddBinning(TUnfoldBinning *binning)
+{
+  TUnfoldBinning *r=0;
+  if(binning->GetParentNode()) {
+     Error("AddBinning",
+           "binning \"%s\" already has parent \"%s\", can not be added to %s",
+     (char *)binning->GetName(),
+     (char *)binning->GetParentNode()->GetName(),
+     (char *)GetName());
+  } else if(binning->GetPrevNode()) {
+    Error("AddBinning",
+          "binning \"%s\" has previous node \"%s\", can not be added to %s",
+     (char *)binning->GetName(),
+     (char *)binning->GetPrevNode()->GetName(),
+     (char *)GetName());
+  } else if(binning->GetNextNode()) {
+    Error("AddBinning",
+          "binning \"%s\" has next node \"%s\", can not be added to %s",
+     (char *)binning->GetName(),
+     (char *)binning->GetNextNode()->GetName(),
+     (char *)GetName());
+  } else {
+    r=binning;
+    binning->parentNode=this;
+    if(childNode) {
+      TUnfoldBinning *child=childNode;
+      // find last child
+      while(child->nextNode) {
+   child=child->nextNode;
+      }
+      // add as last child
+      child->nextNode=r;
+      r->prevNode=child;
+    } else {
+      childNode=r;
+    }
+    UpdateFirstLastBin();
+    r=binning;
+  }
+  return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Add an axis with equidistant bins.
+///
+/// \param[in] name name of the axis
+/// \param[in] nBin number of bins
+/// \param[in] xMin lower edge of the first bin
+/// \param[in] xMax upper edge of the last bin
+/// \param[in] hasUnderflow decide whether the axis has an underflow bin
+/// \param[in] hasOverflow decide whether the axis has an overflow bin
+///
+/// returns true if the axis has been added
+
+Bool_t TUnfoldBinning::AddAxis
+(const char *name,Int_t nBin,Double_t xMin,Double_t xMax,
+ Bool_t hasUnderflow,Bool_t hasOverflow)
+{
+  Bool_t r=kFALSE;
+   if(nBin<=0) {
+      Fatal("AddAxis","number of bins %d is not positive",
+            nBin);
+   } else if((!TMath::Finite(xMin))||(!TMath::Finite(xMax))||
+      (xMin>=xMax)) {
+      Fatal("AddAxis","xmin=%f required to be smaller than xmax=%f",
+            xMin,xMax);
+   } else {
+     Double_t *binBorders=new Double_t[nBin+1];
+     Double_t x=xMin;
+     Double_t dx=(xMax-xMin)/nBin;
+     for(Int_t i=0;i<=nBin;i++) {
+       binBorders[i]=x+i*dx;
+     }
+     r=AddAxis(name,nBin,binBorders,hasUnderflow,hasOverflow);
+     delete [] binBorders;
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Add an axis to the distribution, using the TAxis as blueprint.
+///
+/// \param[in] axis blueprint of the axis
+/// \param[in] hasUnderflow decide whether the underflow bin should be included
+/// \param[in] hasOverflow decide whether the overflow bin should be included
+///
+/// returns true if the axis has been added
+///
+/// Note: axis labels are not imported
+
+Bool_t TUnfoldBinning::AddAxis
+(const TAxis &axis,Bool_t hasUnderflow,Bool_t hasOverflow)
+{
+  Int_t nBin=axis.GetNbins();
+  Double_t *binBorders=new Double_t[nBin+1];
+  for(Int_t i=0;i<nBin;i++) {
+    binBorders[i]=axis.GetBinLowEdge(i+1);
+  }
+  binBorders[nBin]=axis.GetBinUpEdge(nBin);
+  Bool_t r=AddAxis(axis.GetTitle(),nBin,binBorders,hasUnderflow,hasOverflow);
+  delete [] binBorders;
+  return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Add an axis with the specified bin borders.
+///
+/// \param[in] name name of the axis
+/// \param[in] nBin number of bins
+/// \param[in] binBorders array of bin borders, with nBin+1 elements
+/// \param[in] hasUnderflow decide whether the axis has an underflow bin
+/// \param[in] hasOverflow decide whether the axis has an overflow bin
+///
+/// returns true if the axis has been added
+
+Bool_t TUnfoldBinning::AddAxis
+(const char *name,Int_t nBin,const Double_t *binBorders,
+ Bool_t hasUnderflow,Bool_t hasOverflow)
+{
+  Bool_t r=kFALSE;
+  if(HasUnconnectedBins()) {
+    Fatal("AddAxis","node already has %d bins without axis",
+     GetDistributionNumberOfBins());
+  } else if(nBin<=0) {
+    Fatal("AddAxis","number of bins %d is not positive",
+     nBin);
+  } else {
+    TVectorD *bins=new TVectorD(nBin+1);
+    r=kTRUE;
+    for(Int_t i=0;i<=nBin;i++) {
+      (*bins)(i)=binBorders[i];
+      if(!TMath::Finite((*bins)(i))) {
+   Fatal("AddAxis","bin border %d is not finite",i);
+   r=kFALSE;
+      } else if((i>0)&&((*bins)(i)<=(*bins)(i-1))) {
+   Fatal("AddAxis","bins not in order x[%d]=%f <= %f=x[%d]",
+         i,(*bins)(i),(*bins)(i-1),i-1);
+   r=kFALSE;
+      }
+    }
+    if(r) {
+      Int_t axis=fAxisList->GetEntriesFast();
+      Int_t bitMask=1<<axis;
+      Int_t nBinUO=nBin;
+      if(hasUnderflow) {
+   fHasUnderflow |= bitMask;
+   nBinUO++;
+      } else {
+   fHasUnderflow &= ~bitMask;
+      }
+      if(hasOverflow) {
+   fHasOverflow |= bitMask;
+   nBinUO++;
+      } else {
+   fHasOverflow &= ~bitMask;
+      }
+      fAxisList->AddLast(bins);
+      fAxisLabelList->AddLast(new TObjString(name));
+      if(!fDistributionSize) fDistributionSize=1;
+      fDistributionSize *= nBinUO;
+      UpdateFirstLastBin();
+    }
+  }
+  return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Print some information about this binning tree.
+///
+/// \param[out] out stream to write to
+/// \param[in] indent initial indentation (sub-trees have indent+1)
+/// \param[in] debug if debug&gt;0 print more information
+
+void TUnfoldBinning::PrintStream(ostream &out,Int_t indent,int debug)
+   const {
+   for(Int_t i=0;i<indent;i++) out<<"  ";
+   out<<"TUnfoldBinning \""<<GetName()<<"\" has ";
+   Int_t nBin=GetEndBin()-GetStartBin();
+   if(nBin==1) {
+      out<<"1 bin";
+   } else {
+      out<<nBin<<" bins";
+   }
+   out<<" ["
+      <<GetStartBin()<<","<<GetEndBin()<<"] nTH1x="
+      <<GetTH1xNumberOfBins()
+      <<"\n";
+   if(GetDistributionNumberOfBins()) {
+      for(Int_t i=0;i<indent;i++) out<<"  ";
+      out<<" distribution: "<<GetDistributionNumberOfBins()<<" bins\n";
+      if(fAxisList->GetEntriesFast()) {
+         /* for(Int_t i=0;i<indent;i++) out<<"  ";
+            out<<" axes:\n"; */
+          for(Int_t axis=0;axis<GetDistributionDimension();axis++) {
+             for(Int_t i=0;i<indent;i++) out<<"  ";
+             out<<"  \""
+                 <<GetDistributionAxisLabel(axis)
+                 <<"\" nbin="<<GetDistributionBinning(axis)->GetNrows()-1;
+             if(HasUnderflow(axis)) out<<" plus underflow";
+             if(HasOverflow(axis)) out<<" plus overflow";
+             out<<"\n";
+          }
+      } else {
+         for(Int_t i=0;i<indent;i++) out<<"  ";
+         out<<" no axis\n";
+         for(Int_t i=0;i<indent;i++) out<<"  ";
+         out<<" names: ";
+         for(Int_t ibin=0;(ibin<GetDistributionNumberOfBins())&&
+                (ibin<fAxisLabelList->GetEntriesFast());ibin++) {
+            if(ibin) out<<";";
+            if(GetDistributionAxisLabel(ibin)) {
+               out<<GetDistributionAxisLabel(ibin);
+            }
+         }
+         out<<"\n";
+      }
+      if(debug>0) {
+         // print all bins with full name, size, status, user factor
+         for(int iBin=GetStartBin();iBin<GetEndBin();iBin++) {
+            for(Int_t i=0;i<indent;i++) out<<"  ";
+            out<<GetBinName(iBin)
+               <<" size="<<GetBinSize(iBin)
+               <<" factor="<<GetBinFactor(iBin);
+            out<<"\n";
+         }
+      }
+   }
+   TUnfoldBinning const *child=GetChildNode();
+   if(child) {
+      while(child) {
+         child->PrintStream(out,indent+1,debug);
+         child=child->GetNextNode();
+      }
+   }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Set normalisation factors which are used in calls to GetBinFactor().
+///
+/// \param[in] normalisation normalisation factor
+/// \param[in] binfactor object which defines a factor for each bin
+///
+/// In the present implementation, <b>binfactor</b> can be a TF1 or a
+/// TVectorD. The TF1 is evaluated a the bin centers of the
+/// relevant axes. The TVectorD is indexed by the global bin number
+/// minus the start bin number of this node.
+
+void TUnfoldBinning::SetBinFactor
+(Double_t normalisation,TObject *binfactor) {
+   fBinFactorConstant=normalisation;
+   if(fBinFactorFunction) {
+      if(!dynamic_cast<TF1 *>(fBinFactorFunction))
+         delete fBinFactorFunction;
+   }
+   fBinFactorFunction=binfactor;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Set normalisation factor and function which are used in calls to GetBinFactor().
+///
+/// \param[in] normalisation normalisation factor
+/// \param[in] userFunc function evaluated at the (multi-dimensional)
+/// bin centres
+
+void TUnfoldBinning::SetBinFactorFunction
+(Double_t normalisation,TF1 *userFunc) {
+   SetBinFactor(normalisation,userFunc);
+}
+
+/********************* Navigation **********************/
+
+////////////////////////////////////////////////////////////////////////////////
+/// Traverse the tree and return the first node which matches the given name.
+///
+/// \param[in] name the identifier of the node to find (zero matches
+/// the first node)
+///
+/// returns the node found or zero
+
+TUnfoldBinning const *TUnfoldBinning::FindNode(char const *name) const
+{
+   TUnfoldBinning const *r=0;
+   if((!name)||(!TString(GetName()).CompareTo(name))) {
+      r=this;
+   }
+   for(TUnfoldBinning const *child=GetChildNode();
+       (!r) && child;child=child->GetNextNode()) {
+      r=child->FindNode(name);
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return root node.
+
+TUnfoldBinning *TUnfoldBinning::GetRootNode(void)
+{
+   TUnfoldBinning *node=this;
+   while(node->GetParentNode()) node=node->parentNode;
+   return node;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return root node.
+
+TUnfoldBinning const *TUnfoldBinning::GetRootNode(void) const
+{
+   TUnfoldBinning const *node=this;
+   while(node->GetParentNode()) node=node->GetParentNode();
+   return node;
+}
+
+/********************* Create THxx histograms **********/
+
+////////////////////////////////////////////////////////////////////////////////
+/// Construct a title.
+///
+/// \param[in] histogramName distribution name
+/// \param[in] histogramTitle default title
+/// \param[in] axisList array indicating which axis of this node is
+/// mapped to which histogram axis
+///
+/// if histogramTitle!=0 this title is used. Otherwise, the title is
+/// composed as:
+/// histogramName;axisname[axisList[0]];axisname[axisList[1]];...
+
+TString TUnfoldBinning::BuildHistogramTitle
+(const char *histogramName,const char *histogramTitle,Int_t const *axisList)
+   const
+{
+   TString r;
+   if(histogramTitle) {
+      r=histogramTitle;
+   } else {
+      r=histogramName;
+      Int_t iEnd;
+      for(iEnd=2;iEnd>0;iEnd--) {
+         if(axisList[iEnd]>=0) break;
+      }
+      for(Int_t i=0;i<=iEnd;i++) {
+         r += ";";
+         if(axisList[i]<0) {
+            r += GetName();
+         } else {
+            r += GetNonemptyNode()->GetDistributionAxisLabel(axisList[i]);
+         }
+      }
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Construct a histogram title for a 2D histogram with different
+/// binning schemes on x and y axis.
+///
+/// \param[in] histogramName distribution name
+/// \param[in] histogramTitle default title
+/// \param[in] xAxis indicates which x-axis name to use
+/// \param[in] yAxisBinning binning scheme for y-axis
+/// \param[in] yAxis indicates which y-axis name to use
+///
+/// build a title
+///  - input:
+///    histogramTitle : if this is non-zero, use that title
+///   - otherwise:
+///     title=histogramName;x;y
+///  - xAxis :
+///      - -1 no title for this axis
+///      - >=0 use name of the corresponding axis
+
+TString TUnfoldBinning::BuildHistogramTitle2D
+(const char *histogramName,const char *histogramTitle,
+ Int_t xAxis,const TUnfoldBinning *yAxisBinning,Int_t yAxis) const
+{
+   TString r;
+   if(histogramTitle) {
+      r=histogramTitle;
+   } else {
+      r=histogramName;
+      r += ";";
+      if(xAxis==-1) {
+         r += GetName();
+      } else if(xAxis>=0) {
+         r += GetNonemptyNode()->GetDistributionAxisLabel(xAxis);
+      }
+      r+= ";";
+      if(yAxis==-1) {
+         r += yAxisBinning->GetName();
+      } else if(yAxis>=0) {
+         r += yAxisBinning->GetNonemptyNode()->GetDistributionAxisLabel(yAxis);
+      }
+
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return the number of histogram bins required when storing
+/// this binning in a one-dimensional histogram.
+///
+/// \param[in] originalAxisBinning  if true, try to have the histogram
+/// axis reflect precisely the relevant axis of the binning scheme
+/// \param[in] axisSteering steering to integrate over axis and/or
+/// skip underflow and overflow bins
+///
+/// returns the number of bins of the TH1, where the underflow/overflow
+/// are not used, unless the distribution has only one axis and
+/// originalAxisBinning=true)
+///
+/// axisSteering is a string as follows:
+/// "axis[options];axis[options];..."
+/// where: axis = name or * is an identifier of an axis (* matches all)
+/// and: options is any combination of the letters C,U,O  (other
+/// letters are ignored).
+///
+/// The letter C means that the corresponding axis is collapsed into
+/// one bin, i.e. one dimension is removed from the counting.
+/// The letters U,O remove for the matching axis the underflow.overflow
+/// bins from the counting
+
+Int_t TUnfoldBinning::GetTH1xNumberOfBins
+(Bool_t originalAxisBinning,const char *axisSteering) const
+{
+   Int_t axisBins[3],axisList[3];
+   GetTHxxBinning(originalAxisBinning ? 1 : 0,axisBins,axisList,
+                  axisSteering);
+   return axisBins[0];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Create a THxx histogram capable to hold the bins of this binning
+/// node and its children.
+///
+/// \param[in] histogramName name of the histogram which is created
+/// \param[in] originalAxisBinning if true, try to preserve the axis binning
+/// \param[out] (default=0) binMap mapping of global bins to histogram bins.
+/// if(binMap==0), no binMap is created
+/// \param[in] (default=0) histogramTitle title of the histogram. If zero, a title
+/// is selected automatically
+/// \param[in] (default=0) axisSteering steer the handling of underflow/overflow
+/// and projections
+///
+/// returns a new histogram (TH1D, TH2D or TH3D)
+///
+/// if the parameter <b>originalAxisBinning</b> parameter is true, the
+/// resulting histogram has bin widths and histogram dimension (TH1D,
+/// TH2D, TH3D) in parallel to this binning node, if possible.
+///
+/// The <b>binMap</b> is an array which translates global bin numbers to bin
+/// numbers in the histogram returned by this method. The global bin
+/// numbers correspond to the bin numbers in a histogram created by
+/// calling GetRootNode()->CreateHistogram(name,false,0,0,0)
+///
+/// The <b>axisSteering</b> is a string to steer whether underflow and
+/// overflow bins are included in the bin map. Furthermore, it is
+/// possible to "collapse" axes, such that their content is summed and
+/// the axis does not show up in the created histogram.
+///
+/// The string looks like this: "axis[options];axis[options];..." where
+///
+///   - axis is the name of an axis or equal to *, the latter matches
+/// all axes
+///   - options is a combination of characters chosen from
+/// OUC0123456789
+///
+///   - if O is included, the overflow bin of that axis is discarded
+///   - if U is included, the underflow bin of that axis is discarded
+///   - if C is included, the bins on that axes are collapsed,
+/// i.e. the corresponding histogram axis is not present in the output.
+/// The corresponding bin contents are added up
+/// (projected onto the remaining axes). Using the characters O and U
+/// one can decide to exclude underflow or overflow from the
+/// projection. Using a selection of the characters 0123456789 one can
+/// restrict the sum further to only include the corresponding
+/// bins. In this counting, the first non-underflow bin corresponds to
+/// the character 0. This obviously only works for up to ten
+/// bins.
+
+TH1 *TUnfoldBinning::CreateHistogram
+(const char *histogramName,Bool_t originalAxisBinning,Int_t **binMap,
+ const char *histogramTitle,const char *axisSteering) const
+{
+   Int_t nBin[3],axisList[3];
+   Int_t nDim=GetTHxxBinning(originalAxisBinning ? 3 : 0,nBin,axisList,
+                             axisSteering);
+   const TUnfoldBinning *neNode=GetNonemptyNode();
+   TString title=BuildHistogramTitle(histogramName,histogramTitle,axisList);
+   TH1 *r=0;
+   if(nDim>0) {
+      const TVectorD *axisBinsX=
+         neNode->GetDistributionBinning(axisList[0]);
+      if(nDim>1) {
+         const TVectorD *axisBinsY=
+            neNode->GetDistributionBinning(axisList[1]);
+         if(nDim>2) {
+            const TVectorD *axisBinsZ=
+               neNode->GetDistributionBinning(axisList[2]);
+            r=new TH3D(histogramName,title,
+                       nBin[0],axisBinsX->GetMatrixArray(),
+                       nBin[1],axisBinsY->GetMatrixArray(),
+                       nBin[2],axisBinsZ->GetMatrixArray());
+         } else {
+            r=new TH2D(histogramName,title,
+                       nBin[0],axisBinsX->GetMatrixArray(),
+                       nBin[1],axisBinsY->GetMatrixArray());
+         }
+      } else {
+         r=new TH1D(histogramName,title,nBin[0],axisBinsX->GetMatrixArray());
+      }
+   } else {
+      if(originalAxisBinning) {
+         Warning("CreateHistogram",
+       "Original binning can not be represented as THxx");
+      }
+      r=new TH1D(histogramName,title,nBin[0],0.5,nBin[0]+0.5);
+      nDim=0;
+   }
+   if(binMap) {
+      *binMap=CreateBinMap(r,nDim,axisList,axisSteering);
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Create a TH2D histogram capable to hold a covariance matrix.
+///
+///
+/// \param[in] histogramName name of the histogram which is created
+/// \param[in] originalAxisBinning if true, try to preserve the axis binning
+/// \param[out] (default=0) binMap mapping of global bins to histogram bins.
+/// if(binMap==0), no binMap is created
+/// \param[in] (default=0) histogramTitle title of the histogram. If zero, a title
+/// is selected automatically
+/// \param[in] (default=0) axisSteering steer the handling of underflow/overflow
+/// and projections
+///
+/// returns a new TH2D. The options are described in greater detail
+/// with the CreateHistogram() method.
+
+TH2D *TUnfoldBinning::CreateErrorMatrixHistogram
+(const char *histogramName,Bool_t originalAxisBinning,Int_t **binMap,
+ const char *histogramTitle,const char *axisSteering) const
+{
+   Int_t nBin[3],axisList[3];
+   Int_t nDim=GetTHxxBinning(originalAxisBinning ? 1 : 0,nBin,axisList,
+                             axisSteering);
+   TString title=BuildHistogramTitle(histogramName,histogramTitle,axisList);
+   TH2D *r=0;
+   if(nDim==1) {
+      const TVectorD *axisBinsX=(TVectorD const *)
+         GetNonemptyNode()->fAxisList->At(axisList[0]);
+      r=new TH2D(histogramName,title,nBin[0],axisBinsX->GetMatrixArray(),
+                 nBin[0],axisBinsX->GetMatrixArray());
+   } else {
+      if(originalAxisBinning) {
+         Info("CreateErrorMatrixHistogram",
+              "Original binning can not be represented on one axis");
+      }
+      r=new TH2D(histogramName,title,nBin[0],0.5,nBin[0]+0.5,
+                 nBin[0],0.5,nBin[0]+0.5);
+      nDim=0;
+   }
+   if(binMap) {
+      *binMap=CreateBinMap(r,nDim,axisList,axisSteering);
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Create a TH2D histogram capable to hold the bins of the two
+/// input binning schemes on the x and y axes, respectively.
+///
+/// \paran[in] xAxis binning scheme for the x axis
+/// \param[in] yAxis binning scheme for the y axis
+/// \param[in] histogramName name of the histogram which is created
+/// \param[in] originalXAxisBinning preserve x-axis bin widths if possible
+/// \param[in] originalXAxisBinning preserve y-axis bin widths if possible
+/// \param[in] histogramTitle if is non-zero, it is taken as histogram title
+///                     otherwise, the title is created automatically
+///
+/// returns a new TH2D.
+
+TH2D *TUnfoldBinning::CreateHistogramOfMigrations
+(TUnfoldBinning const *xAxis,TUnfoldBinning const *yAxis,
+ char const *histogramName,Bool_t originalXAxisBinning,
+ Bool_t originalYAxisBinning,char const *histogramTitle)
+{
+   Int_t nBinX[3],axisListX[3];
+   Int_t nDimX=
+      xAxis->GetTHxxBinning(originalXAxisBinning ? 1 : 0,nBinX,axisListX,0);
+   const TUnfoldBinning *neNodeX=xAxis->GetNonemptyNode();
+   Int_t nBinY[3],axisListY[3];
+   Int_t nDimY=
+      yAxis->GetTHxxBinning(originalYAxisBinning ? 1 : 0,nBinY,axisListY,0);
+   const TUnfoldBinning *neNodeY=yAxis->GetNonemptyNode();
+   TString title=xAxis->BuildHistogramTitle2D
+      (histogramName,histogramTitle,axisListX[0],yAxis,axisListY[0]);
+   if(nDimX==1) {
+      const TVectorD *axisBinsX=(TVectorD const *)
+            neNodeX->fAxisList->At(axisListX[0]);
+      if(nDimY==1) {
+         const TVectorD *axisBinsY=(TVectorD const *)
+            neNodeY->fAxisList->At(axisListY[0]);
+         return new TH2D(histogramName,title,
+                         nBinX[0],axisBinsX->GetMatrixArray(),
+                         nBinY[0],axisBinsY->GetMatrixArray());
+      } else {
+         return new TH2D(histogramName,title,
+                         nBinX[0],axisBinsX->GetMatrixArray(),
+                         nBinY[0],0.5,0.5+nBinY[0]);
+      }
+   } else {
+      if(nDimY==1) {
+         const TVectorD *axisBinsY=(TVectorD const *)
+             neNodeY->fAxisList->At(axisListY[0]);
+         return new TH2D(histogramName,title,
+                         nBinX[0],0.5,0.5+nBinX[0],
+                         nBinY[0],axisBinsY->GetMatrixArray());
+      } else {
+         return new TH2D(histogramName,title,
+                         nBinX[0],0.5,0.5+nBinX[0],
+                         nBinY[0],0.5,0.5+nBinY[0]);
+      }
+   }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Calculate properties of a THxx histogram to store this binning.
+///
+/// \param[in] maxDim  maximum dimension of the THxx (0 or 1..3)
+/// maxDim==0 is used to indicate that the histogram should be
+///    dimensional with all bins mapped on one axis,
+///    bin centers equal to bin numbers
+/// \param[in] axisSteering see method CreateHistogram()
+/// \param[out] axisBins[3] number of bins on the THxx axes
+/// \param[out] axisList[3] TUnfoldBinning axis number corresponding
+/// to the THxx axis
+///
+/// returns 1-3 dimension of THxx or 0 for 1-dim THxx with equidistant bins
+
+Int_t TUnfoldBinning::GetTHxxBinning
+(Int_t maxDim,Int_t *axisBins,Int_t *axisList,
+ const char *axisSteering) const
+{
+   for(Int_t i=0;i<3;i++) {
+      axisBins[i]=0;
+      axisList[i]=-1;
+   }
+   const TUnfoldBinning *theNode=GetNonemptyNode();
+   if(theNode) {
+      Int_t r=theNode->GetTHxxBinningSingleNode
+         (maxDim,axisBins,axisList,axisSteering);
+      return r;
+   } else {
+      axisBins[0]=GetTHxxBinsRecursive(axisSteering);
+      return 0;
+   }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Find a node which has non-empty distributions
+/// if there is none or if there are many, return zero.
+
+const TUnfoldBinning *TUnfoldBinning::GetNonemptyNode(void) const
+{
+   const TUnfoldBinning *r=GetDistributionNumberOfBins()>0 ? this : 0;
+   for(TUnfoldBinning const *child=GetChildNode();child;
+       child=child->GetNextNode()) {
+      const TUnfoldBinning *c=child->GetNonemptyNode();
+      if(!r) {
+         // new candidate found
+         r=c;
+      } else {
+         if(c) {
+            // multiple nodes found
+            r=0;
+            break;
+         }
+      }
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get the properties of a histogram capable to hold the distribution
+/// attached to this node.
+///
+/// \param[in] maxDim maximum dimension of the THxx (0 or 1..3)
+///              maxDim==0 is used to indicate that the histogram should
+///              1-dimensional with all bins mapped on one axis
+/// \param[out] axisBins[3] number of bins on the THxx axes
+/// \param[out] axisList[3] TUnfoldBinning axis numbers
+///              corresponding to the THxx axis
+/// \param[in] axisSteering  see method CreateHistogram()
+/// and projection
+///
+/// returns 1-3 dimension of THxx or use 1-dim THxx, binning structure
+/// is not preserved
+
+Int_t TUnfoldBinning::GetTHxxBinningSingleNode
+(Int_t maxDim,Int_t *axisBins,Int_t *axisList,const char *axisSteering) const
+{
+   // decode axisSteering
+   //   isOptionGiven[0] ('C'): bit vector which axes to collapse
+   //   isOptionGiven[1] ('U'): bit vector to discard underflow bins
+   //   isOptionGiven[2] ('O'): bit vector to discard overflow bins
+   Int_t isOptionGiven[3];
+   DecodeAxisSteering(axisSteering,"CUO",isOptionGiven);
+   // count number of axes after projecting
+   Int_t numDimension=GetDistributionDimension();
+   Int_t r=0;
+   for(Int_t i=0;i<numDimension;i++) {
+      if(isOptionGiven[0] & (1<<i)) continue;
+      r++;
+   }
+   if((r>0)&&(r<=maxDim)) {
+      // 0<r<=maxDim
+      //
+      // -> preserve the original binning
+      //    axisList[] and axisBins[] are overwritten
+      r=0;
+      for(Int_t i=0;i<numDimension;i++) {
+         if(isOptionGiven[0] & (1<<i)) continue;
+         axisList[r]=i;
+         axisBins[r]=GetDistributionBinning(i)->GetNrows()-1;
+         r++;
+      }
+   } else {
+      // map everything on one axis
+      //  axisBins[0] is the number of bins
+      if(HasUnconnectedBins() || (GetDistributionNumberOfBins()<=0)) {
+         axisBins[0] = GetDistributionNumberOfBins();
+      } else {
+         Int_t nBin=1;
+         for(Int_t i=0;i<numDimension;i++) {
+            Int_t mask=(1<<i);
+            if(isOptionGiven[0] & mask) continue;
+            Int_t nBinI=GetDistributionBinning(i)->GetNrows()-1;
+            if((fHasUnderflow & mask)&& !(isOptionGiven[1] & mask)) nBinI++;
+            if((fHasOverflow & mask)&& !(isOptionGiven[2] & mask)) nBinI++;
+            nBin *= nBinI;
+         }
+         axisBins[0] = nBin;
+      }
+      r=0;
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Calculate number of bins required to store this binning with the
+/// given axisSteering.
+///
+/// \param[in] axisSteering see method CreateHistogram()
+///
+/// returns the number of bins
+
+Int_t TUnfoldBinning::GetTHxxBinsRecursive(const char *axisSteering) const
+{
+
+   Int_t r=0;
+   for(TUnfoldBinning const *child=GetChildNode();child;
+       child=child->GetNextNode()) {
+      r +=child->GetTHxxBinsRecursive(axisSteering);
+   }
+   // here: process distribution of this node
+   Int_t axisBins[3],axisList[3];
+   GetTHxxBinningSingleNode(0,axisBins,axisList,axisSteering);
+   r += axisBins[0];
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Create an empty bin map, useful together with the getter methods of
+/// class TUnfold and TUnfoldSys.
+///
+/// returns: a new Int array of the proper size, all elements set to -1
+
+Int_t *TUnfoldBinning::CreateEmptyBinMap(void) const {
+   // create empty bin map which can be manipulated by
+   //  MapGlobalBin()
+   Int_t nMax=GetRootNode()->GetEndBin()+1;
+   Int_t *r=new Int_t[nMax];
+   for(Int_t i=0;i<nMax;i++) {
+         r[i]=-1;
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Set one entry in a bin map.
+///
+/// \param[out] binMap to be used with TUnfoldSys::GetOutput() etc
+/// \param[in] source bin, global bin number in this binning scheme
+/// \param[in] destination bin in the output histogram
+
+void TUnfoldBinning::SetBinMapEntry
+(Int_t *binMap,Int_t globalBin,Int_t destBin) const {
+   Int_t nMax=GetRootNode()->GetEndBin()+1;
+   if((globalBin<0)||(globalBin>=nMax)) {
+      Error("SetBinMapEntry","global bin number %d outside range (max=%d)",
+            globalBin,nMax);
+   } else {
+      binMap[globalBin]=destBin;
+   }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Map all global bins referenced by this node to the one-dimensional
+/// histogram destHist, starting with bin firstBinX
+///
+/// \param[out] binMap to be used with TUnfoldSys::GetOutput() etc
+/// \param[in] axisSteering steering for underflow/overflow/projections
+/// \param[in] firstBinX first bin of destination histogram to be filled
+///
+/// returns: highest bin number in destination histogram plus 1
+/// The parameter <b>axisSteering</b> is explained with the
+/// method CreateHistogram()
+
+Int_t TUnfoldBinning::FillBinMap1D
+(Int_t *binMap,const char *axisSteering,Int_t firstBinX) const {
+   Int_t r=firstBinX;
+   Int_t axisBins[3],axisList[3];
+   Int_t nDim=GetTHxxBinningSingleNode(3,axisBins,axisList,axisSteering);
+   if((nDim==1)|| !GetDistributionDimension()) {
+      r+=FillBinMapSingleNode(0,r,0,0,axisSteering,binMap);
+   } else {
+      Error("FillBinMap1D","distribution %s with steering=%s is not 1D",
+            (char *)GetName(),axisSteering);
+   }
+   for(TUnfoldBinning const *child=GetChildNode();child;
+       child=child->GetNextNode()) {
+      r =child->FillBinMap1D(binMap,axisSteering,r);
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Create mapping from global bin number to a histogram for this node.
+///
+/// \param[in] hist destination histogram
+/// \param[in] nDim target dimension
+/// \param[in] axisList map axes in the binning scheme to histogram axes
+/// \param[in] axisSteering steering for underflow/overflow/projections
+///
+/// The <b>axisSteering</b> is explained with the method CreateHistogram()
+/// create mapping from global bin number to a histogram for this node
+/// global bins are the bins of the root node binning scheme
+/// when projecting them on a TH1 histogram "hRootNode" without special
+/// axis steering and without attempting to preserve the axis binning
+///
+/// The bin map is an array of size hRootNode->GetNbinsX()+2
+/// For each bin of the "hRootNode" histogram it holds the target bin in
+/// "hist" or the number -1 if the corresponding "hRootNode" bin is not
+/// represented in "hist"
+///
+/// input
+///  - hist : the histogram (to calculate root bin numbers)
+///  - nDim : target dimension of the TUnfoldBinning
+///          if(nDim==0) all bins are mapped linearly
+///  - axisSteering:
+///       "pattern1;pattern2;...;patternN"
+///       patternI = axis[mode]
+///       axis = name or *
+///       mode = C|U|O
+///       - C: collapse axis into one bin
+///       - U: discard underflow bin
+///       - O: discard overflow bin
+///
+///  - input used only if nDim>0:
+///    axisList : for each THxx axis give the TUnfoldBinning axis number
+///
+///  - return value:
+///    an new array which holds the bin mapping
+///      - r[0] : to which THxx bin to map global bin number 0
+///      - r[1] : to which THxx bin to map global bin number 1
+///      ...
+///      - r[nmax]
+///        where nmax=GetRootNode()->GetEndBin()+1
+
+Int_t *TUnfoldBinning::CreateBinMap
+(const TH1 *hist,Int_t nDim,const Int_t *axisList,const char *axisSteering)
+   const
+{
+   Int_t *r=CreateEmptyBinMap();
+   Int_t startBin=GetRootNode()->GetStartBin();
+   if(nDim>0) {
+     const TUnfoldBinning *nonemptyNode=GetNonemptyNode();
+     if(nonemptyNode) {
+       nonemptyNode->
+          FillBinMapSingleNode(hist,startBin,nDim,axisList,axisSteering,r);
+     } else {
+       Fatal("CreateBinMap","called with nDim=%d but GetNonemptyNode()=0",
+        nDim);
+     }
+   } else {
+     FillBinMapRecursive(startBin,axisSteering,r);
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Recursively fill bin map.
+///
+/// \param[in] startBin first histogram bin
+/// \param[in] axisSteering see CreateHistogram() method
+/// \param[out]  binMap the bin mapping which is to be filled
+///
+/// the positions
+///      - binMap[GetStartBin()]...binMap[GetEndBin()-1]
+/// are filled
+
+Int_t TUnfoldBinning::FillBinMapRecursive
+(Int_t startBin,const char *axisSteering,Int_t *binMap) const
+{
+   Int_t nbin=0;
+   nbin = FillBinMapSingleNode(0,startBin,0,0,axisSteering,binMap);
+   for(TUnfoldBinning const *child=GetChildNode();child;
+       child=child->GetNextNode()) {
+      nbin += child->FillBinMapRecursive(startBin+nbin,axisSteering,binMap);
+   }
+   return nbin;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Fill bin map for a single node.
+///
+/// \param[in] hist the histogram representing this node (used if nDim>0)
+/// \param[in] startBin start bin in the bin map
+/// \param[in] nDim number of dimensions to resolve
+/// \param[in] axisList[3] TUnfoldBinning axis numbers corresponding
+/// to the axes of <b>hist</b>
+/// \param[in] axisSteering see documentation of CreateHistogram()
+/// \param[out] binMap the bin map to fill
+///
+/// returns the number of bins mapped.
+///
+/// The result depends on the parameter <b>nDim</b> as follows
+///
+///   -  nDim==0: bins are mapped in linear order, ignore hist and
+/// axisList
+///   -  nDim==hist->GetDimension():
+/// bins are mapped to "hist" bin numbers
+/// the corresponding TUnfoldBinning axes are taken from
+/// axisList[]
+///   - nDim=1 and hist->GetDimension()>1:
+/// bins are mapped to the x-axis of "hist"
+/// the corresponding TUnfoldBinning axis is taken from
+/// axisList[0]
+
+Int_t TUnfoldBinning::FillBinMapSingleNode
+(const TH1 *hist,Int_t startBin,Int_t nDim,const Int_t *axisList,
+ const char *axisSteering,Int_t *binMap) const
+{
+   // first, decode axisSteering
+   //   isOptionGiven[0] ('C'): bit vector which axes to collapse
+   //   isOptionGiven[1] ('U'): bit vector to discard underflow bins
+   //   isOptionGiven[2] ('O'): bit vector to discard overflow bins
+   Int_t isOptionGiven[3+10];
+   DecodeAxisSteering(axisSteering,"CUO0123456789",isOptionGiven);
+   Int_t haveSelectedBin=0;
+   for(Int_t i=3;i<3+10;i++) {
+      haveSelectedBin |= isOptionGiven[i];
+   }
+
+   Int_t axisBins[MAXDIM];
+   Int_t dimension=GetDistributionDimension();
+   Int_t axisNbin[MAXDIM];
+   for(Int_t i=0;i<dimension;i++) {
+      const TVectorD *binning=GetDistributionBinning(i);
+      axisNbin[i]=binning->GetNrows()-1;
+   };
+   for(Int_t i=0;i<GetDistributionNumberOfBins();i++) {
+      Int_t globalBin=GetStartBin()+i;
+      const TUnfoldBinning *dest=ToAxisBins(globalBin,axisBins);
+      if(dest!=this) {
+         if(!dest) {
+            Fatal("FillBinMapSingleNode",
+                  "bin %d outside binning scheme",
+                  globalBin);
+         } else {
+            Fatal("FillBinMapSingleNode",
+                  "bin %d located in %s %d-%d rather than %s %d=%d",
+                  i,(const char *)dest->GetName(),
+                  dest->GetStartBin(),dest->GetEndBin(),
+                  (const char *)GetName(),GetStartBin(),GetEndBin());
+         }
+      }
+      // check whether this bin has to be skipped
+      Bool_t skip=kFALSE;
+      for(Int_t axis=0;axis<dimension;axis++) {
+         Int_t mask=(1<<axis);
+         // underflow/overflow excluded by steering
+         if(((axisBins[axis]<0)&&(isOptionGiven[1] & mask))||
+            ((axisBins[axis]>=axisNbin[axis])&&(isOptionGiven[2] & mask)))
+            skip=kTRUE;
+         // only certain bins selected by steering
+         if((axisBins[axis]>=0)&&(axisBins[axis]<axisNbin[axis])&&
+            (haveSelectedBin & mask)) {
+            if(!(isOptionGiven[3+axisBins[axis]] & mask)) skip=kTRUE;
+         }
+      }
+      if(skip) {
+         continue;
+      }
+
+      if(nDim>0) {
+         // get bin number from THxx function(s)
+         if(nDim==hist->GetDimension()) {
+            Int_t ibin[3];
+            ibin[0]=ibin[1]=ibin[2]=0;
+            for(Int_t hdim=0;hdim<nDim;hdim++) {
+               Int_t axis=axisList[hdim];
+               ibin[hdim]=axisBins[axis]+1;
+            }
+            binMap[globalBin]=hist->GetBin(ibin[0],ibin[1],ibin[2]);
+         } else if(nDim==1) {
+            // histogram has more dimensions than the binning scheme
+            // and the binning scheme has one axis only
+            //
+            // special case: error histogram is 2-d
+            //   create nor error if ndim==1 && hist->GetDimension()==2
+            if((nDim!=1)||( hist->GetDimension()!=2)) {
+               // -> use the first valid axis only
+               Error("FillBinMapSingleNode","inconsistent dimensions %d %d",nDim,
+                     hist->GetDimension());
+            }
+            for(Int_t ii=0;ii<hist->GetDimension();ii++) {
+               if(axisList[ii]>=0) {
+                  binMap[globalBin]=axisBins[axisList[ii]]+1;
+                  break;
+               }
+            }
+         } else {
+            Fatal("FillBinMapSingleNode","inconsistent dimensions %d %d",nDim,
+                  hist->GetDimension());
+         }
+      } else {
+         // order all bins in sequence
+         // calculation in parallel to ToGlobalBin()
+         // but take care of
+         //   startBin,collapseAxis,discardeUnderflow,discardeOverflow
+         if(dimension>0) {
+            Int_t r=0;
+            for(Int_t axis=dimension-1;axis>=0;axis--) {
+               Int_t mask=(1<<axis);
+               if(isOptionGiven[0] & mask) {
+                  // bins on this axis are integrated over
+                  continue;
+               }
+               Int_t iBin=axisBins[axis];
+               Int_t nMax=axisNbin[axis];
+               if((fHasUnderflow & ~isOptionGiven[1]) & mask) {
+                  nMax +=1;
+                  iBin +=1;
+               }
+               if((fHasOverflow & ~isOptionGiven[2]) & mask) {
+                  nMax += 1;
+               }
+               r = r*nMax +iBin;
+            }
+            binMap[globalBin] = startBin + r;
+         } else {
+      binMap[globalBin] = startBin + axisBins[0];
+         }
+      }
+   }
+   Int_t nbin;
+   if(dimension>0) {
+     nbin=1;
+     for(Int_t axis=dimension-1;axis>=0;axis--) {
+       Int_t mask=(1<<axis);
+       if(isOptionGiven[0] & mask) {
+    // bins on this axis are integrated over
+    continue;
+       }
+       Int_t nMax=axisNbin[axis];
+       if((fHasUnderflow & ~isOptionGiven[1]) & mask) {
+    nMax +=1;
+       }
+       if((fHasOverflow & ~isOptionGiven[2]) & mask) {
+    nMax += 1;
+       }
+       nbin = nbin*nMax;
+     }
+   } else {
+     nbin=GetDistributionNumberOfBins();
+   }
+   return nbin;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Extract a distribution from the given set of global bins.
+///
+/// input:
+///   - histogramName : name of the histogram which ic created
+///   - globalBins : histogram with all bins
+///   - globalBinsEmatrix : corresponding error matrix
+///                 if this pointer is zero, only diagonal errors
+///                 are considered
+///   - originalAxisBinning :  extract  histogram with proper binning
+///                          (if possible)
+///   - axisSteering
+///      - "pattern1;pattern2;...;patternN"
+///      - patternI = axis[mode]
+///      - axis = name or *
+///      - mode = C|U|O
+///         - C: collapse axis into one bin
+///         - U: discard underflow bin
+///         - O: discard overflow bin
+
+TH1 *TUnfoldBinning::ExtractHistogram
+(const char *histogramName,const TH1 *globalBins,
+ const TH2 *globalBinsEmatrix,Bool_t originalAxisBinning,
+ const char *axisSteering) const
+{
+   Int_t *binMap=0;
+   TH1 *r=CreateHistogram(histogramName,originalAxisBinning,&binMap,0,
+                          axisSteering);
+   if(!r) return 0;
+   TUnfoldBinning const *root=GetRootNode();
+   Int_t nMax=-1;
+   for(Int_t iSrc=root->GetStartBin();iSrc<root->GetEndBin();iSrc++) {
+      if(binMap[iSrc]>nMax) nMax=binMap[iSrc];
+   }
+   if(nMax<0) {
+      delete r;
+      r=0;
+   } else {
+      TVectorD eSquared(nMax+1);
+      for(Int_t iSrc=root->GetStartBin();iSrc<root->GetEndBin();iSrc++) {
+         Int_t iDest=binMap[iSrc];
+         if(iDest>=0) {
+            Double_t c=r->GetBinContent(iDest);
+            r->SetBinContent(iDest,c+globalBins->GetBinContent(iSrc));
+            if(!globalBinsEmatrix) {
+               eSquared(iDest)+=TMath::Power(globalBins->GetBinError(iSrc),2.);
+            } else {
+               for(Int_t jSrc=root->GetStartBin();jSrc<root->GetEndBin();
+                   jSrc++) {
+                  if(binMap[jSrc]==iDest) {
+                     eSquared(iDest) +=
+                        TMath::Power(globalBins->GetBinError(jSrc),2.);
+                  }
+               }
+            }
+         }
+      }
+      for(Int_t i=0;i<nMax;i++) {
+         Double_t e2=eSquared(i);
+         if(e2>0.0) {
+            r->SetBinError(i,TMath::Sqrt(e2));
+         }
+      }
+   }
+   delete binMap;
+   return r;
+}
+
+/********************* Calculate global bin number ******/
+
+////////////////////////////////////////////////////////////////////////////////
+/// Locate a bin in a one-dimensional distribution.
+///
+/// \param[in] x coordinate
+///
+/// returns the global bin number within the distribution attached to
+/// this node. The global bin number is valid for the root node of the
+/// binning scheme
+
+Int_t TUnfoldBinning::GetGlobalBinNumber(Double_t x) const
+{
+   if(GetDistributionDimension()!=1) {
+      Fatal("GetBinNumber",
+            "called with 1 argument for %d dimensional distribution",
+            GetDistributionDimension());
+   }
+   return GetGlobalBinNumber(&x);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Locate a bin in a two-dimensional distribution.
+///
+/// \param[in] x coordinate on first axis
+/// \param[in] y coordinate on second axis
+///
+/// returns the global bin number within the distribution attached to
+/// this node. The global bin number is valid for the root node of the
+/// binning scheme
+
+Int_t TUnfoldBinning::GetGlobalBinNumber(Double_t x,Double_t y) const
+{
+   if(GetDistributionDimension()!=2) {
+      Fatal("GetBinNumber",
+            "called with 2 arguments for %d dimensional distribution",
+            GetDistributionDimension());
+   }
+   Double_t xx[2];
+   xx[0]=x;
+   xx[1]=y;
+   return GetGlobalBinNumber(xx);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Locate a bin in a three-dimensional distribution.
+///
+/// \param[in] x coordinate on first axis
+/// \param[in] y coordinate on second axis
+/// \param[in] z coordinate on third axis
+///
+/// returns the global bin number within the distribution attached to
+/// this node. The global bin number is valid for the root node of the
+/// binning scheme
+///
+/// locate bin on a three-dimensional distribution
+///  - input:
+///    x,y,z: coordinates to locate
+
+Int_t TUnfoldBinning::GetGlobalBinNumber
+(Double_t x,Double_t y,Double_t z) const
+{
+   if(GetDistributionDimension()!=3) {
+      Fatal("GetBinNumber",
+            "called with 3 arguments for %d dimensional distribution",
+            GetDistributionDimension());
+   }
+   Double_t xx[3];
+   xx[0]=x;
+   xx[1]=y;
+   xx[2]=z;
+   return GetGlobalBinNumber(xx);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Locate a bin in a four-dimensional distribution.
+///
+/// \param[in] x0 coordinate on first axis
+/// \param[in] x1 coordinate on second axis
+/// \param[in] x2 coordinate on third axis
+/// \param[in] x3 coordinate on fourth axis
+///
+/// returns the global bin number within the distribution attached to
+/// this node. The global bin number is valid for the root node of the
+/// binning scheme
+///
+/// locate bin on a four-dimensional distribution
+///   - input:
+///     x0,x1,x2,x3: coordinates to locate
+
+Int_t TUnfoldBinning::GetGlobalBinNumber
+(Double_t x0,Double_t x1,Double_t x2,Double_t x3) const
+{
+   if(GetDistributionDimension()!=4) {
+      Fatal("GetBinNumber",
+            "called with 4 arguments for %d dimensional distribution",
+            GetDistributionDimension());
+   }
+   Double_t xx[4];
+   xx[0]=x0;
+   xx[1]=x1;
+   xx[2]=x2;
+   xx[3]=x3;
+   return GetGlobalBinNumber(xx);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Locate a bin in a five-dimensional distribution.
+///
+/// \param[in] x0 coordinate on first axis
+/// \param[in] x1 coordinate on second axis
+/// \param[in] x2 coordinate on third axis
+/// \param[in] x3 coordinate on fourth axis
+/// \param[in] x4 coordinate on fifth axis
+///
+/// returns the global bin number within the distribution attached to
+/// this node. The global bin number is valid for the root node of the
+/// binning scheme
+///
+/// locate bin on a five-dimensional distribution
+///  - input:
+///    x0,x1,x2,x3,x4: coordinates to locate
+
+Int_t TUnfoldBinning::GetGlobalBinNumber
+(Double_t x0,Double_t x1,Double_t x2,Double_t x3,Double_t x4) const
+{
+   if(GetDistributionDimension()!=5) {
+      Fatal("GetBinNumber",
+            "called with 5 arguments for %d dimensional distribution",
+            GetDistributionDimension());
+   }
+   Double_t xx[5];
+   xx[0]=x0;
+   xx[1]=x1;
+   xx[2]=x2;
+   xx[3]=x3;
+   xx[4]=x4;
+   return GetGlobalBinNumber(xx);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Locate a bin in a six-dimensional distribution.
+///
+/// \param[in] x0 coordinate on first axis
+/// \param[in] x1 coordinate on second axis
+/// \param[in] x2 coordinate on third axis
+/// \param[in] x3 coordinate on fourth axis
+/// \param[in] x4 coordinate on fifth axis
+/// \param[in] x5 coordinate on sixth axis
+///
+/// returns the global bin number within the distribution attached to
+/// this node. The global bin number is valid for the root node of the
+/// binning scheme
+///
+/// locate bin on a five-dimensional distribution
+///  - input:
+///    x0,x1,x2,x3,x4,x5: coordinates to locate
+
+Int_t TUnfoldBinning::GetGlobalBinNumber
+(Double_t x0,Double_t x1,Double_t x2,Double_t x3,Double_t x4,Double_t x5) const
+{
+   if(GetDistributionDimension()!=6) {
+      Fatal("GetBinNumber",
+            "called with 6 arguments for %d dimensional distribution",
+            GetDistributionDimension());
+   }
+   Double_t xx[6];
+   xx[0]=x0;
+   xx[1]=x1;
+   xx[2]=x2;
+   xx[3]=x3;
+   xx[4]=x4;
+   xx[5]=x5;
+   return GetGlobalBinNumber(xx);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// locate a bin in an N-dimensional distribution
+///
+/// \param[in] x array of coordinates
+/// \param[out] isBelow pointer to an integer (bit vector) to indicate
+/// coordinates which do not fit in the binning scheme
+/// \param[out] isAbove pointer to an integer (bit vector) to indicate
+/// coordinates which do not fit in the binning scheme
+///
+/// returns the global bin number within the distribution attached to
+/// this node. The global bin number is valid for the root node of the
+/// binning scheme. If some coordinates do not fit, zero is returned.
+/// The integers pointed to by isBelow and isAbove are set to zero.
+/// However, if coordinate i is below
+/// the lowest bin border and there is no underflow bin, the bin i is
+/// set in (*isBelow). Overflows are handled in a similar manner with
+/// (*isAbove).
+///
+/// If a coordinate is NaN, the result is undefined for TUnfold
+/// Version<17.6. As of version 17.6, NaN is expected to end up in the
+/// underflow or by setting the corresponding bit in (*isBelow).
+///
+/// locate bin on a n-dimensional distribution
+///  - input
+///    x[]: coordinates to locate
+///  - output:
+///    isBelow,isAbove: bit vectors,
+///       indicating which cut on which axis failed
+
+Int_t TUnfoldBinning::GetGlobalBinNumber
+(const Double_t *x,Int_t *isBelow,Int_t *isAbove) const
+{
+   if(!GetDistributionDimension()) {
+      Fatal("GetBinNumber",
+            "no axes are defined for node %s",
+            (char const *)GetName());
+   }
+   Int_t iAxisBins[MAXDIM];
+   for(Int_t dim=0;dim<GetDistributionDimension();dim++) {
+      TVectorD const *bins=(TVectorD const *) fAxisList->At(dim);
+      Int_t i0=0;
+      Int_t i1=bins->GetNrows()-1;
+      Int_t iBin= 0;
+      if(!(x[dim]>=(*bins)[i0])) {
+         // underflow or NaN
+         iBin += i0-1;
+      } else if(!(x[dim]<(*bins)[i1])) {
+         // overflow
+         iBin += i1;
+      } else {
+         while(i1-i0>1) {
+            Int_t i2=(i0+i1)/2;
+            if(x[dim]<(*bins)[i2]) {
+               i1=i2;
+            } else {
+               i0=i2;
+            }
+         }
+         iBin += i0;
+      }
+      iAxisBins[dim]=iBin;
+   }
+   Int_t r=ToGlobalBin(iAxisBins,isBelow,isAbove);
+   if(r<0) r=0;
+   return r;
+}
+
+/********************* access by global bin number ******/
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get the name of a bin.
+///
+/// \param[in] iBin global bin number
+///
+/// returns a string describing the bin
+///
+/// Get the name of a bin in the given tree
+///    iBin: bin number
+
+TString TUnfoldBinning::GetBinName(Int_t iBin) const
+{
+   Int_t axisBins[MAXDIM];
+   TString r=TString::Format("#%d",iBin);
+   TUnfoldBinning const *distribution=ToAxisBins(iBin,axisBins);
+   if(distribution) {
+      r +=" (";
+      r += distribution->GetName();
+      Int_t dimension=distribution->GetDistributionDimension();
+      if(dimension>0) {
+         TString axisString;
+         for(Int_t axis=0;axis<dimension;axis++) {
+            TString thisAxisString=
+               distribution->GetDistributionAxisLabel(axis);
+            TVectorD const *bins=distribution->GetDistributionBinning(axis);
+            Int_t i=axisBins[axis];
+            if(i<0) thisAxisString += "[ufl]";
+            else if(i>=bins->GetNrows()-1) thisAxisString += "[ofl]";
+            else {
+               thisAxisString +=
+                  TString::Format("[%.3g,%.3g]",(*bins)[i],(*bins)[i+1]);
+            }
+            axisString = ":"+thisAxisString+axisString;
+         }
+         r += axisString;
+      } else {
+         // extra bins
+         Int_t i=axisBins[0];
+         if((i>=0)&&(i<distribution->fAxisLabelList->GetEntriesFast())) {
+            r += distribution->GetDistributionAxisLabel(i);
+         } else {
+            r += TString::Format(" %d",i);
+         }
+      }
+      r +=")";
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get N-dimensional bin size.
+///
+/// \param[in] iBin global bin number
+///
+///    includeUO : include underflow/overflow bins or not
+
+Double_t TUnfoldBinning::GetBinSize(Int_t iBin) const
+{
+   Int_t axisBins[MAXDIM];
+   TUnfoldBinning const *distribution=ToAxisBins(iBin,axisBins);
+   Double_t r=0.0;
+   if(distribution) {
+      if(distribution->GetDistributionDimension()>0) r=1.0;
+      for(Int_t axis=0;axis<distribution->GetDistributionDimension();axis++) {
+         TVectorD const *bins=distribution->GetDistributionBinning(axis);
+         Int_t pos=axisBins[axis];
+         if(pos<0) {
+       r *= distribution->GetDistributionUnderflowBinWidth(axis);
+         } else if(pos>=bins->GetNrows()-1) {
+       r *= distribution->GetDistributionOverflowBinWidth(axis);
+         } else {
+            r *= (*bins)(pos+1)-(*bins)(pos);
+         }
+         if(r<=0.) break;
+      }
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Check whether there is only a global scaling factor for  this node.
+
+Bool_t TUnfoldBinning::IsBinFactorGlobal(void) const {
+   return fBinFactorFunction ? kFALSE : kTRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return global scaling factor for  this node.
+
+Double_t TUnfoldBinning::GetGlobalFactor(void) const {
+   return fBinFactorConstant;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return scaling factor for the given global bin number.
+///
+/// \param[in] iBin global bin number
+///
+/// returns the scaling factor for this bin.
+/// The scaling factors can be set using the method SetBinFactorFunction()
+///
+/// return user factor for a bin
+///    iBin : global bin number
+
+Double_t TUnfoldBinning::GetBinFactor(Int_t iBin) const
+{
+   Int_t axisBins[MAXDIM];
+   TUnfoldBinning const *distribution=ToAxisBins(iBin,axisBins);
+   Double_t r=distribution->fBinFactorConstant;
+   if((r!=0.0) && distribution->fBinFactorFunction) {
+      TF1 *function=dynamic_cast<TF1 *>(distribution->fBinFactorFunction);
+      if(function) {
+         Double_t x[MAXDIM];
+         Int_t dimension=distribution->GetDistributionDimension();
+         if(dimension>0) {
+            for(Int_t  axis=0;axis<dimension;axis++) {
+               x[axis]=distribution->GetDistributionBinCenter
+                  (axis,axisBins[axis]);
+            }
+            r *= function->EvalPar(x,function->GetParameters());
+         } else {
+            x[0]=axisBins[0];
+            r *= function->Eval(x[0]);
+         }
+      } else {
+         TVectorD *vect=dynamic_cast<TVectorD *>
+            (distribution->fBinFactorFunction);
+         if(vect) {
+            r=(*vect)[iBin-GetStartBin()];
+         } else {
+            Error("GetBinFactor",
+                  "internal error: user function is neither TF1 or TVectorD");
+         }
+      }
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get neighbour bins along the specified axis.
+///
+/// \param[in] bin global bin number
+/// \param[in] axis axis number of interest
+/// \param[out] prev bin number of previous bin or -1 if not existing
+/// \param[out] distPrev distance between bin centres
+/// \param[out] next bin number of next bin or -1 if not existing
+/// \param[out] distNext distance between bin centres
+/// \param[in] isPeriodic (default=false) if true, the first bin is counted as neighbour of the last bin
+///
+/// return code
+///
+///   - 0 everything is fine
+///   - 1,2,3 isPeriodic option was reset to false, because underflow/overflow
+/// bins are present
+///
+///   - +1 invalid isPeriodic option was specified with underflow bin
+///   - +2 invalid isPeriodic option was specified with overflow bin
+
+Int_t TUnfoldBinning::GetBinNeighbours
+(Int_t bin,Int_t axis,Int_t *prev,Double_t *distPrev,
+ Int_t *next,Double_t *distNext,Bool_t isPeriodic) const
+{
+   Int_t axisBins[MAXDIM];
+   TUnfoldBinning const *distribution=ToAxisBins(bin,axisBins);
+   Int_t dimension=distribution->GetDistributionDimension();
+   *prev=-1;
+   *next=-1;
+   *distPrev=0.;
+   *distNext=0.;
+   Int_t r=0;
+   if((axis>=0)&&(axis<dimension)) {
+     //TVectorD const *bins=distribution->GetDistributionBinning(axis);
+      //Int_t nBin=bins->GetNrows()-1;
+      Int_t nMax=GetDistributionBinning(axis)->GetNrows()-1;
+      Int_t centerBin= axisBins[axis];
+      axisBins[axis] =centerBin-1;
+      if(isPeriodic) {
+         if(HasUnderflow(axis)) {
+            r +=1;
+         } else if((axisBins[axis]<0)&&(nMax>=3)) {
+            axisBins[axis]=nMax-1;
+         }
+      }
+      *prev=ToGlobalBin(axisBins);
+      if(*prev>=0) {
+   *distPrev=distribution->GetDistributionBinCenter(axis,axisBins[axis])-
+     distribution->GetDistributionBinCenter(axis,centerBin);
+      }
+      axisBins[axis] =centerBin+1;
+      if(isPeriodic) {
+         if(HasOverflow(axis)) {
+            r +=2;
+         } else if((axisBins[axis]==nMax)&&(nMax>=3)) {
+            axisBins[axis]=0;
+         }
+      }
+      *next=ToGlobalBin(axisBins);
+      if(*next>=0) {
+   *distNext=distribution->GetDistributionBinCenter(axis,axisBins[axis])-
+     distribution->GetDistributionBinCenter(axis,centerBin);
+      }
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return bit maps indicating underflow and overflow status.
+///
+/// \param[in] iBin global bin number
+/// \param[out] uStatus bit map indicating whether the bin is underflow
+/// \param[out] oStatus bit map indicating whether the bin is overflow
+
+void TUnfoldBinning::GetBinUnderflowOverflowStatus
+(Int_t iBin,Int_t *uStatus,Int_t *oStatus) const
+{
+  Int_t axisBins[MAXDIM];
+  TUnfoldBinning const *distribution=ToAxisBins(iBin,axisBins);
+  Int_t dimension=distribution->GetDistributionDimension();
+  *uStatus=0;
+  *oStatus=0;
+  for(Int_t axis=0;axis<dimension;axis++) {
+    TVectorD const *bins=distribution->GetDistributionBinning(axis);
+    Int_t nBin=bins->GetNrows()-1;
+    if(axisBins[axis]<0) *uStatus |= (1<<axis);
+    if(axisBins[axis]>=nBin) *oStatus |= (1<<axis);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Check whether there are bins but no axis.
+
+Bool_t TUnfoldBinning::HasUnconnectedBins(void) const
+{
+   return (!GetDistributionDimension())&&(GetDistributionNumberOfBins()>0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return the bin names of unconnected bins.
+///
+/// \param[in] bin local bin number
+
+const TObjString *TUnfoldBinning::GetUnconnectedBinName(Int_t bin) const {
+   TObjString *r=0;
+   if(HasUnconnectedBins()) {
+      if(bin<fAxisLabelList->GetEntriesFast()) {
+         r=((TObjString * const)fAxisLabelList->At(bin));
+      }
+   }
+   return r;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get average bin size on the specified axis.
+///
+/// \param[in] axis axis number
+/// \param[in] includeUnderflow whether to include the underflow bin
+/// \param[in] includeOverflow whether to include the overflow bin
+
+Double_t TUnfoldBinning::GetDistributionAverageBinSize
+(Int_t axis,Bool_t includeUnderflow,Bool_t includeOverflow) const
+{
+   Double_t r=0.0;
+   if((axis>=0)&&(axis<GetDistributionDimension())) {
+      TVectorD const *bins=GetDistributionBinning(axis);
+      Double_t d=(*bins)[bins->GetNrows()-1]-(*bins)[0];
+      Double_t nBins=bins->GetNrows()-1;
+      if(includeUnderflow && HasUnderflow(axis)) {
+         Double_t w=GetDistributionUnderflowBinWidth(axis);
+         if(w>0) {
+            nBins++;
+            d += w;
+         }
+      }
+      if(includeOverflow && HasOverflow(axis)) {
+         Double_t w=GetDistributionOverflowBinWidth(axis);
+         if(w>0.0) {
+            nBins++;
+            d += w;
+         }
+      }
+      if(nBins>0) {
+         r=d/nBins;
+      }
+   } else {
+      Error("GetDistributionAverageBinSize","axis %d does not exist",axis);
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return bin width assigned to the underflow bin.
+///
+/// \param[in] axis axis number
+///
+/// the bin width of the first bin is returned.
+/// The method is virtual, so this behaviour can be adjusted.
+///
+/// return width of the underflow bin
+///   axis: axis number
+
+Double_t TUnfoldBinning::GetDistributionUnderflowBinWidth(Int_t axis) const
+{
+   TVectorD const *bins=GetDistributionBinning(axis);
+   return (*bins)[1]-(*bins)[0];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return bin width assigned to the overflow bin.
+///
+/// \param[in] axis axis number
+///
+/// the bin width of the last bin is returned.
+/// The method is virtual, so this behaviour can be adjusted.
+///
+/// return width of the underflow bin
+///   axis: axis number
+
+Double_t TUnfoldBinning::GetDistributionOverflowBinWidth(Int_t axis) const
+{
+   TVectorD const *bins=GetDistributionBinning(axis);
+   return (*bins)[bins->GetNrows()-1]-(*bins)[bins->GetNrows()-2];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// return bin center for a given axis and bin number
+///
+/// \param[in] axis axis number
+/// \param[in] bin local bin number on the specified axis
+///
+/// returns the geometrical bin center.
+/// for underflow and overflow, the calculation is using the
+/// GetDistributionUnderflowBinWidth() and
+/// GetDistributionOverflowBinWidth() methods.
+///
+/// position of the bin center
+///  - input:
+///     - axis : axis number
+///     - bin : bin number on the axis
+
+Double_t TUnfoldBinning::GetDistributionBinCenter
+(Int_t axis,Int_t bin) const
+{
+   TVectorD const *bins=GetDistributionBinning(axis);
+   Double_t r=0.0;
+   if(bin<0) {
+      // underflow bin
+      r=(*bins)[0]-0.5*GetDistributionUnderflowBinWidth(axis);
+   } else if(bin>=bins->GetNrows()-1) {
+      // overflow bin
+      r=(*bins)[bins->GetNrows()-1]+0.5*GetDistributionOverflowBinWidth(axis);
+   } else {
+      r=0.5*((*bins)[bin+1]+(*bins)[bin]);
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get global bin number, given axis bin numbers.
+///
+/// \param[in] axisBins[] bin numbers on each axis
+/// \param[out] isBelow indicates bins are in underflow but there is
+/// no undeflow bin
+/// \param[out] isAbove indicates bins are in overflow but there is
+/// no overflow bin
+///
+/// return: global bin number or -1 if not matched.
+
+Int_t TUnfoldBinning::ToGlobalBin
+(Int_t const *axisBins,Int_t *isBelow,Int_t *isAbove) const
+{
+  Int_t dimension=GetDistributionDimension();
+  Int_t r=0;
+  if(isBelow) *isBelow=0;
+  if(isAbove) *isAbove=0;
+  if(dimension>0) {
+    for(Int_t axis=dimension-1;axis>=0;axis--) {
+      Int_t nMax=GetDistributionBinning(axis)->GetNrows()-1;
+      Int_t i=axisBins[axis];
+      if(HasUnderflow(axis)) {
+   nMax +=1;
+   i +=1;
+      }
+      if(HasOverflow(axis)) nMax +=1;
+      if((i>=0)&&(i<nMax)) {
+         if(r>=0) r = r*nMax +i;
+      } else {
+         r=-1;
+         if((i<0)&&(isBelow)) *isBelow |= 1<<axis;
+         if((i>=nMax)&&(isAbove)) *isAbove |= 1<<axis;
+      }
+    }
+    if(r>=0) {
+      r += GetStartBin();
+    }
+  } else {
+    if((axisBins[0]>=0)&&(axisBins[0]<GetDistributionNumberOfBins()))
+      r=GetStartBin()+axisBins[0];
+    else
+       Fatal("ToGlobalBin","bad input %d for dimensionless binning %s %d",
+             axisBins[0],(const char *)GetName(),
+             GetDistributionNumberOfBins());
+  }
+  return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Return distribution in which the bin is located
+/// and bin numbers on the corresponding axes.
+///
+/// \param[in] globalBin global bin number
+/// \param[out] local bin numbers of the distribution's axes
+///
+/// returns the distribution in which the globalBin is located
+///  or 0 if the globalBin is outside this node and its children
+
+TUnfoldBinning const *TUnfoldBinning::ToAxisBins
+(Int_t globalBin,Int_t *axisBins) const
+{
+   TUnfoldBinning const *r=0;
+   if((globalBin>=GetStartBin())&&(globalBin<GetEndBin())) {
+      TUnfoldBinning const *node;
+      for(node=GetChildNode();node && !r; node=node->GetNextNode()) {
+         r=node->ToAxisBins(globalBin,axisBins);
+      }
+      if(!r) {
+         r=this;
+         Int_t i=globalBin-GetStartBin();
+         Int_t dimension=GetDistributionDimension();
+         if(dimension>0) {
+            for(int axis=0;axis<dimension;axis++) {
+               Int_t nMax=GetDistributionBinning(axis)->GetNrows()-1;
+               axisBins[axis]=0;
+               if(HasUnderflow(axis)) {
+                  axisBins[axis] =-1;
+                  nMax += 1;
+               }
+               if(HasOverflow(axis)) nMax +=1;
+               axisBins[axis] += i % nMax;
+               i /= nMax;
+            }
+         } else {
+            axisBins[0]=i;
+         }
+      }
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Decode axis steering.
+///
+/// \param[in] axisSteering the steering to decode
+/// \param[in] options the allowed options to extract
+/// \param[out] isOptionGiven array of decoded steering options,
+///            the dimension equal to the number of
+///            characters in <b>options</b>
+///
+/// the axis steering is given in the form
+///  "axis[option];axis[option];..."
+///  axis : the name of the axis for which the optionlist is relevant
+/// the character * matches all axes
+/// option : a list of characters taken from <b>options</b>
+/// for each match the corresponding bit number corresponding to
+///  the axis number is set in
+///  <b>isOptionGiven</b>[i], where i is the position of the matching option
+///  character in <b>options</b>
+
+void TUnfoldBinning::DecodeAxisSteering
+(const char *axisSteering,const char *options,Int_t *isOptionGiven) const
+{
+  Int_t nOpt=TString(options).Length();
+  for(Int_t i=0;i<nOpt;i++) isOptionGiven[i]=0;
+  if(axisSteering) {
+     TObjArray *patterns=TString(axisSteering).Tokenize(";");
+     Int_t nPattern=patterns->GetEntries();
+     Int_t nAxis=fAxisLabelList->GetEntries();
+     for(Int_t i=0;i<nPattern;i++) {
+        TString const &pattern=((TObjString * const)patterns->At(i))
+           ->GetString();
+        Int_t bracketBegin=pattern.Last('[');
+        Int_t len=pattern.Length();
+        if((bracketBegin>0)&&(pattern[len-1]==']')) {
+     TString axisId=pattern(0,bracketBegin);
+     Int_t mask=0;
+     if((axisId[0]=='*')&&(axisId.Length()==1)) {
+       // turn all bins on
+       mask=(1<<nAxis)-1;
+     } else {
+       // if axis is there, turn its bit on
+       for(Int_t j=0;j<nAxis;j++) {
+         if(!axisId.CompareTo(GetDistributionAxisLabel(j))) {
+      mask|= (1<<j);
+         }
+       }
+     }
+     for(Int_t o=0;o<nOpt;o++) {
+       if(pattern.Last(options[o])>bracketBegin) {
+         isOptionGiven[o] |= mask;
+       }
+     }
+        } else {
+           Error("DecodeAxisSteering",
+                 "steering \"%s\" does not end with [options]",
+       (const char *)pattern);
+        }
+     }
+  }
+}
+
diff --git a/hist/unfold/src/TUnfoldBinningXML.cxx b/hist/unfold/src/TUnfoldBinningXML.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7225f10f4115bae624ee92d7d58db7dad709d9bd
--- /dev/null
+++ b/hist/unfold/src/TUnfoldBinningXML.cxx
@@ -0,0 +1,591 @@
+// @(#)root/unfold:$Id$
+// Author: Stefan Schmitt DESY, 10/08/11
+
+/** \class TUnfoldBinningXML
+\ingroup Unfold
+XML interfate to binning schemes, for use with the unfolding algorithm
+TUnfoldDensity.
+
+Binning schemes are used to map analysis bins on a single histogram
+axis and back. The analysis bins may include unconnected bins (e.g
+nuisances for background normalisation) or various multidimensional
+histograms (signal bins, differential background normalisation bins, etc).
+
+If you use this software, please consider the following citation
+
+<b>S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]</b>
+
+Detailed documentation and updates are available on
+http://www.desy.de/~sschmitt
+
+Please consult the documentation of the class TUnfoldBinning about how to use
+binning schemes. This class provides methods to read and write binning
+schemes in the XML language. There is also a method which writes out
+a dtd file for validation.
+
+### Example XML code
+The example below encodes two binning schemes, _detector_ and
+_generator_. The detector scheme consists of a single,
+three-dimensional distribution (pt,eta,discriminator). The generator
+scheme consists of two two-dimensional distributions, signal and background.
+
+~~~
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE TUnfoldBinning SYSTEM "tunfoldbinning.dtd">
+<TUnfoldBinning>
+<BinningNode name="detector" firstbin="1" factor="1">
+ <BinningNode name="detectordistribution" firstbin="1" factor="1">
+  <Axis name="pt" lowEdge="3.5">
+   <Bin repeat="3" width="0.5" />
+   <Bin repeat="3" width="1" />
+   <Bin width="2" />
+   <Bin width="3" />
+   <Bin location="overflow"/>
+   <Axis name="eta" lowEdge="-3">
+    <Bin repeat="2" width="0.5" />
+    <Bin width="1" />
+    <Bin repeat="4" width="0.5" />
+    <Bin width="1" />
+    <Bin repeat="2" width="0.5" />
+    <Axis name="discriminator" lowEdge="0">
+     <Bin width="0.15" />
+     <Bin repeat="2" width="0.35" />
+     <Bin width="0.15" />
+    </Axis>
+   </Axis>
+  </Axis>
+ </BinningNode>
+</BinningNode>
+<BinningNode name="generator" firstbin="1" factor="1">
+ <BinningNode name="signal" firstbin="1" factor="1">
+  <Axis name="ptgen" lowEdge="4">
+   <Bin location="underflow" />
+   <Bin width="1" />
+   <Bin width="2" />
+   <Bin width="3" />
+   <Bin location="overflow" />
+   <Axis name="etagen" lowEdge="-2">
+    <Bin location="underflow" />
+    <Bin width="1.5" />
+    <Bin width="1" />
+    <Bin width="1.5" />
+    <Bin location="overflow" />
+   </Axis>
+  </Axis>
+ </BinningNode>
+ <BinningNode name="background" firstbin="26" factor="1">
+  <Axis name="ptrec" lowEdge="3.5">
+   <Bin repeat="3" width="0.5" />
+   <Bin repeat="3" width="1" />
+   <Bin width="2" />
+   <Bin width="3" />
+   <Bin location="overflow" />
+   <Axis name="etarec" lowEdge="-3">
+    <Bin repeat="2" width="0.5" />
+    <Bin width="1" />
+    <Bin repeat="4" width="0.5" />
+    <Bin width="1" />
+    <Bin repeat="2" width="0.5" />
+   </Axis>
+  </Axis>
+ </BinningNode>
+</BinningNode>
+</TUnfoldBinning>
+~~~
+
+--------------------------------------------------------------------------------
+  This file is part of TUnfold.
+
+  TUnfold is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  TUnfold is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with TUnfold.  If not, see <http://www.gnu.org/licenses/>.
+
+<b>Version 17.6, with updated doxygen comments</b>
+
+#### History:
+  - Version 17.5, in parallel to changes in TUnfold
+  - Version 17.4, in parallel to changes in TUnfoldBinning
+  - Version 17.3, support for the "repeat" attribute for element Bin
+  - Version 17.2, initial version, numbered in parallel to TUnfold
+  */
+
+
+#include "TUnfold.h"
+#include "TUnfoldBinningXML.h"
+
+#include <TXMLDocument.h>
+#include <TXMLNode.h>
+#include <TXMLAttr.h>
+#include <TList.h>
+#include <TVectorD.h>
+
+#include <fstream>
+#include <sstream>
+
+// #define DEBUG
+
+using namespace std;
+
+ClassImp(TUnfoldBinningXML)
+
+/********************* XML **********************/
+
+////////////////////////////////////////////////////////////////////////////////
+/// Write dtd file.
+///
+/// \param[out] out stream for writing the dtd
+
+void TUnfoldBinningXML::WriteDTD(std::ostream &out) {
+   out
+      <<"<!-- TUnfold Version "<<TUnfold::GetTUnfoldVersion()<<" -->\n"
+      <<"<!ELEMENT TUnfoldBinning (BinningNode)+ >\n"
+      <<"<!ELEMENT BinningNode (BinningNode+|(Binfactorlist?,Axis)|Bins) >\n"
+      <<"<!ATTLIST BinningNode name ID #REQUIRED firstbin CDATA \"-1\"\n"
+      <<"    factor CDATA \"1.\">\n"
+      <<"<!ELEMENT Axis ((Bin+,Axis?)|(Axis)) >\n"
+      <<"<!ATTLIST Axis name CDATA #REQUIRED lowEdge CDATA #REQUIRED>\n"
+      <<"<!ELEMENT Binfactorlist (#PCDATA)>\n"
+      <<"<!ATTLIST Binfactorlist length CDATA #REQUIRED>\n"
+      <<"<!ELEMENT Bin EMPTY>\n"
+      <<"<!ATTLIST Bin width CDATA #REQUIRED location CDATA #IMPLIED\n"
+      <<"    center CDATA #IMPLIED repeat CDATA #IMPLIED>\n"
+      <<"<!ELEMENT Bins (BinLabel)* >\n"
+      <<"<!ATTLIST Bins nbin CDATA #REQUIRED>\n"
+      <<"<!ELEMENT BinLabel EMPTY>\n"
+      <<"<!ATTLIST BinLabel index CDATA #REQUIRED name CDATA #REQUIRED>\n";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Write dtd file.
+///
+/// \param[in] file regular file for writing the dtd
+
+void TUnfoldBinningXML::WriteDTD(const char *file) {
+   ofstream out(file);
+   WriteDTD(out);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Import a binning scheme from an XML file.
+///
+/// \param[in] document XMP document tree
+/// \param[in] name identifier of the binning scheme
+///
+/// returns a new TUnfoldBinningXML, if <b>name</b> is found in <b>document</b>
+///
+/// import binning scheme from a XML document
+///  - document: the XML document
+///  - name: the name of the binning scheme to import
+///     if name==0, the first binning scheme found in the tree is imported
+
+TUnfoldBinningXML *TUnfoldBinningXML::ImportXML
+(const TXMLDocument *document,const char *name) {
+   TUnfoldBinningXML *r=0;
+   TXMLNode *root=document->GetRootNode();
+   TXMLNode *binningNode=0;
+   if(root && (!TString(root->GetNodeName()).CompareTo("TUnfoldBinning")) &&
+      (root->GetNodeType()==TXMLNode::kXMLElementNode)) {
+      // loop over all "BinningNode" entities
+      for(TXMLNode *node=root->GetChildren();node && !binningNode;
+          node=node->GetNextNode()) {
+         if(node->GetNodeType()==TXMLNode::kXMLElementNode &&
+            !TString(node->GetNodeName()).CompareTo("BinningNode") &&
+            node->GetAttributes()) {
+            // localize the BinningNode with the given name
+            TIterator *i=node->GetAttributes()->MakeIterator();
+            TXMLAttr *attr;
+            while((attr=(TXMLAttr *)i->Next())) {
+               if((!TString(attr->GetName()).CompareTo("name")) &&
+                  ((!TString(attr->GetValue()).CompareTo(name)) ||
+                   !name)) {
+                  binningNode=node;
+               }
+            }
+         }
+      }
+   }
+
+   if(binningNode) {
+      r=ImportXMLNode(binningNode);
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Recursively import one node from the XML tree.
+///
+/// \param[in] node node in the XML document tree
+///
+/// returns a new TUnfoldBinningXML
+///
+/// import data from a given "BinningNode"
+
+TUnfoldBinningXML *TUnfoldBinningXML::ImportXMLNode
+(TXMLNode *node) {
+   const char *name=0;
+   Double_t factor=1.0;
+   TUnfoldBinningXML *r=0;
+   Int_t nBins=0;
+   const char *binNames=0;
+   TIterator *i=node->GetAttributes()->MakeIterator();
+   TXMLAttr *attr;
+   // extract name and global factor
+   while((attr=(TXMLAttr *)i->Next())) {
+      TString attName(attr->GetName());
+      if(!attName.CompareTo("name")) {
+         name=attr->GetValue();
+      }
+      if(!attName.CompareTo("factor")) {
+         factor=TString(attr->GetValue()).Atof();
+      }
+   }
+   if(name) {
+      TString binNameList="";
+      // loop over all children of this BinningNode
+      for(TXMLNode *child=node->GetChildren();child;
+          child=child->GetNextNode()) {
+         // unconnected bins: children are of type "Bins"
+         if(child->GetNodeType()==TXMLNode::kXMLElementNode &&
+            !TString(child->GetNodeName()).CompareTo("Bins")) {
+            // this node has unconnected bins, no axes
+            // extract number of bins
+            if(child->GetAttributes()) {
+               i=child->GetAttributes()->MakeIterator();
+               while((attr=(TXMLAttr *)i->Next())) {
+                  TString attName(attr->GetName());
+                  if(!attName.CompareTo("nbin")) {
+                     // number of unconnected bins
+                     nBins=TString(attr->GetValue()).Atoi();
+                  }
+               }
+            }
+            // extract names of unconnected bins
+            TObjArray theBinNames;
+            for(TXMLNode *binName=child->GetChildren();binName;
+                binName=binName->GetNextNode()) {
+               if(binName->GetNodeType()==TXMLNode::kXMLElementNode &&
+                  !TString(binName->GetNodeName()).CompareTo("BinLabel")) {
+                  i=binName->GetAttributes()->MakeIterator();
+                  const char *binLabelName=0;
+                  Int_t index=0;
+                  while((attr=(TXMLAttr *)i->Next())) {
+                     TString attName(attr->GetName());
+                     if(!attName.CompareTo("index")) {
+                        index=TString(attr->GetValue()).Atoi();
+                     }
+                     if(!attName.CompareTo("name")) {
+                        binLabelName=attr->GetValue();
+                     }
+                  }
+                  if((index>=0)&&(binLabelName)) {
+                     if(index>=theBinNames.GetEntriesFast()) {
+                        theBinNames.AddAtAndExpand
+                           (new TObjString(binLabelName),index);
+                     }
+                  }
+               }
+            }
+            Int_t emptyName=0;
+            for(Int_t ii=0;ii<theBinNames.GetEntriesFast()&&(ii<nBins);ii++) {
+               if(theBinNames.At(ii)) {
+                  for(Int_t k=0;k<emptyName;k++) binNameList+=";";
+                  emptyName=0;
+                  binNameList+=
+                     ((TObjString *)theBinNames.At(ii))->GetString();
+               }
+               emptyName++;
+            }
+            if(binNameList.Length()>0) {
+               binNames=binNameList;
+            }
+         }
+      }
+      r=new TUnfoldBinningXML(name,nBins,binNames);
+
+      // add add axis information
+      r->AddAxisXML(node);
+
+      // import per-bin normalisation factors if there are any
+      TVectorD *perBinFactors=0;
+      for(TXMLNode *child=node->GetChildren();child;
+          child=child->GetNextNode()) {
+         // unconnected bins: children are of type "Bins"
+         if(child->GetNodeType()==TXMLNode::kXMLElementNode &&
+            !TString(child->GetNodeName()).CompareTo("Binfactorlist")) {
+            int length=0;
+            i=child->GetAttributes()->MakeIterator();
+            while((attr=(TXMLAttr *)i->Next())) {
+               TString attName(attr->GetName());
+               if(!attName.CompareTo("length")) {
+                  length=TString(attr->GetValue()).Atoi();
+               }
+            }
+            int nread=0;
+            if(length==r->GetDistributionNumberOfBins()) {
+               perBinFactors=new TVectorD(length);
+               const char *text=child->GetText();
+               if(text) {
+                  stringstream readFactors(text);
+                  for(;nread<length;nread++) {
+                     readFactors>> (*perBinFactors)(nread);
+                     if(readFactors.fail()) break;
+                  }
+               }
+            }
+            if(!perBinFactors) {
+               child->Error("ImportXMLNode","while reading per-bin factors"
+                            " node=%s length=%d (expected %d)",r->GetName(),
+                            length,r->GetDistributionNumberOfBins());
+            } else if(nread!=length) {
+               child->Error("ImportXMLNode","while reading per-bin factors"
+                            " TUnfoldBinning=%s expected %d found %d",
+                            r->GetName(),length,nread);
+               delete perBinFactors;
+               perBinFactors=0;
+            }
+         }
+      }
+
+      // set normalisation factors
+      r->SetBinFactor(factor,perBinFactors);
+
+      // now: loop over all child binning and add them
+      for(TXMLNode *child=node->GetChildren();child;
+          child=child->GetNextNode()) {
+         if(child->GetNodeType()==TXMLNode::kXMLElementNode &&
+            !TString(child->GetNodeName()).CompareTo("BinningNode") &&
+            child->GetAttributes()) {
+            TUnfoldBinning *childBinning=ImportXMLNode(child);
+            r->AddBinning(childBinning);
+         }
+      }
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Import axis from XML node.
+///
+/// \param[in] node node in the XML document tree
+///
+/// find axis if there is one
+
+void TUnfoldBinningXML::AddAxisXML(TXMLNode *node) {
+   TXMLNode *axis=0;
+   for(TXMLNode *child=node->GetChildren();child;
+       child=child->GetNextNode()) {
+      if(child->GetNodeType()==TXMLNode::kXMLElementNode) {
+         TString nodeName(child->GetNodeName());
+         if(!nodeName.CompareTo("Axis")) axis=child;
+      }
+   }
+   if(axis) {
+      const char *axisName=0;
+      TArrayD binEdges(1);
+      TIterator *i=axis->GetAttributes()->MakeIterator();
+      TXMLAttr *attr;
+      while((attr=(TXMLAttr *)i->Next())) {
+         TString attName(attr->GetName());
+         if(!attName.CompareTo("name")) {
+            axisName=attr->GetValue();
+         }
+         if(!attName.CompareTo("lowEdge")) {
+            binEdges[0]=TString(attr->GetValue()).Atof();
+         }
+      }
+      Bool_t hasMoreAxes=kFALSE;
+      Bool_t underflow=kFALSE,overflow=kFALSE;
+      for(TXMLNode *child=axis->GetChildren();child;
+          child=child->GetNextNode()) {
+         if(child->GetNodeType()==TXMLNode::kXMLElementNode) {
+            TString nodeName(child->GetNodeName());
+            if(!nodeName.CompareTo("Axis")) hasMoreAxes=kTRUE;
+            if(!nodeName.CompareTo("Bin")) {
+               Bool_t isUnderflow=kFALSE,isOverflow=kFALSE;
+               Int_t repeat=1;
+               i=child->GetAttributes()->MakeIterator();
+               while((attr=(TXMLAttr *)i->Next())) {
+                  TString attName(attr->GetName());
+                  TString attText(attr->GetValue());
+                  if(!attName.CompareTo("location")) {
+                     isUnderflow= !attText.CompareTo("underflow");
+                     isOverflow= !attText.CompareTo("overflow");
+                  }
+                  if(!attName.CompareTo("repeat")) {
+                     repeat=attText.Atof();
+                  }
+               }
+               if(repeat<1) {
+                  node->Warning("AddAxisXML",
+                                "attribute repeat=%d changed to repeat=1",
+                                repeat);
+                  repeat=1;
+               }
+               if((isUnderflow || isOverflow)&&(repeat!=1)) {
+                  node->Error("AddAxisXML",
+     "underflow/overflow can not have repeat!=1 attribute");
+               }
+               if(isUnderflow || isOverflow) {
+                  underflow |= isUnderflow;
+                  overflow |= isOverflow;
+               } else {
+                  Int_t iBin0=binEdges.GetSize();
+                  Int_t iBin1=iBin0+repeat;
+                  Double_t binWidth=0.0;
+                  binEdges.Set(iBin1);
+                  i=child->GetAttributes()->MakeIterator();
+                  while((attr=(TXMLAttr *)i->Next())) {
+                     TString attName(attr->GetName());
+                     if(!attName.CompareTo("width")) {
+                        binWidth=TString(attr->GetValue()).Atof();
+                     }
+                  }
+                  if(binWidth<=0.0) {
+                     node->Error("AddAxisXML",
+                                 "bin width can not be smaller than zero");
+                  }
+                  for(int iBin=iBin0;iBin<iBin1;iBin++) {
+                     binEdges[iBin]=binEdges[iBin0-1]+(iBin-iBin0+1)*binWidth;
+                  }
+               }
+            }
+         }
+      }
+      AddAxis(axisName,binEdges.GetSize()-1,binEdges.GetArray(),
+              underflow,overflow);
+      if(hasMoreAxes) {
+         AddAxisXML(axis);
+      }
+   }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Export a binning scheme to a stream in XML format.
+///
+/// \param[in] binning the binning scheme to export
+/// \param[out] stream to write to
+/// \param[in] writeHeader set true when writing the first binning
+/// scheme to this stream
+/// \param[in] writeFooter  set true when writing the last binning
+/// scheme to this stream
+/// \param[in] indent indentation of the XML output
+///
+/// returns true if the writing succeeded
+
+Int_t TUnfoldBinningXML::ExportXML
+(const TUnfoldBinning &binning,std::ostream &out,Bool_t writeHeader,
+ Bool_t writeFooter,Int_t indent) {
+  if(writeHeader) {
+     out<<"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+        <<"<!DOCTYPE TUnfoldBinning SYSTEM \"tunfoldbinning.dtd\">\n"
+        <<"<TUnfoldBinning>\n";
+  }
+  TString trailer(' ',indent);
+  out<<trailer<<"<BinningNode name=\""<<binning.GetName()<<"\" firstbin=\""
+     <<binning.GetStartBin();
+  if(binning.IsBinFactorGlobal()) {
+     out<<"\" factor=\""<<binning.GetGlobalFactor()<<"\">\n";
+  } else {
+     out<<"\">\n";
+     out<<trailer<<" <Binfactorlist length=\""
+        <<binning.GetDistributionNumberOfBins()<<"\">\n";
+     for(int i=0;i<binning.GetDistributionNumberOfBins();i++) {
+        if(!(i % 10)) out<<trailer<<" ";
+        out<<" "<<binning.GetBinFactor(i+binning.GetStartBin());
+        if(((i %10)==9)||(i==binning.GetDistributionNumberOfBins()-1))
+           out<<"\n";
+     }
+     out<<trailer<<" </Binfactorlist>\n";
+  }
+  if(binning.HasUnconnectedBins()) {
+    out<<trailer<<" <Bins nbin=\""<<binning.GetDistributionNumberOfBins()
+       <<"\">\n";
+    for(Int_t i=0;i<binning.GetDistributionNumberOfBins();i++) {
+       const TObjString *name=binning.GetUnconnectedBinName(i);
+       if(!name) break;
+       out<<trailer<<"  <BinLabel index=\""<<i<<"\" name=\""
+     <<name->GetString()<<"\" />\n";
+    }
+    out<<trailer<<" </Bins>\n";
+  } else {
+    for(Int_t axis=0;axis<binning.GetDistributionDimension();axis++) {
+      TString axisTrailer(' ',indent+1+axis);
+      TVectorD const *edges=binning.GetDistributionBinning(axis);
+      out<<axisTrailer<<"<Axis name=\""<<binning.GetDistributionAxisLabel(axis)
+     <<"\" lowEdge=\""<<(*edges)[0]<<"\">\n";
+      if(binning.HasUnderflow(axis)) {
+   out<<axisTrailer<<" <Bin location=\"underflow\" width=\""
+       <<binning.GetDistributionUnderflowBinWidth(axis)<<"\" center=\""
+       <<binning.GetDistributionBinCenter(axis,-1)<<"\" />\n";
+      }
+      for(Int_t i=0;i<edges->GetNrows()-1;i++) {
+        Int_t repeat=1;
+        Double_t width=(*edges)[i+1]-(*edges)[i];
+        Double_t center=binning.GetDistributionBinCenter(axis,i);
+        for(Int_t j=i+1;j<edges->GetNrows()-1;j++) {
+           double xEnd=(j-i+1)*width+(*edges)[i];
+           double xCent=center+(j-i)*width;
+           if((TMath::Abs(xEnd-(*edges)[j+1])<width*1.E-7)&&
+              (TMath::Abs(xCent-binning.GetDistributionBinCenter(axis,j))<
+               width*1.E-7)) {
+              ++repeat;
+           } else {
+              break;
+           }
+        }
+        if(repeat==1) {
+           out<<axisTrailer<<" <Bin width=\""
+              <<width<<"\" center=\""<<center<<"\" />\n";
+        } else {
+           out<<axisTrailer<<" <Bin repeat=\""<<repeat
+              <<"\" width=\""<<width<<"\" center=\""<<center<<"\" />\n";
+           i += repeat-1;
+        }
+      }
+      if(binning.HasOverflow(axis)) {
+   out<<axisTrailer<<" <Bin location=\"overflow\" width=\""
+           <<binning.GetDistributionOverflowBinWidth(axis)<<"\" center=\""
+           <<binning.GetDistributionBinCenter(axis,edges->GetNrows()-1)<<"\"/>\n";
+      }
+    }
+    for(Int_t axis=binning.GetDistributionDimension()-1;axis>=0;axis--) {
+      TString axisTrailer(' ',indent+1+axis);
+      out<<axisTrailer<<"</Axis>\n";
+    }
+  }
+  for(TUnfoldBinning const *child=binning.GetChildNode();child;
+      child=child->GetNextNode()) {
+     ExportXML(*child,out,kFALSE,kFALSE,indent+1);
+  }
+  out<<trailer<<"</BinningNode>\n";
+  if(writeFooter) {
+     out<<"</TUnfoldBinning>\n";
+  }
+  return out.fail() ? 0 : 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Export this binning scheme to a file.
+///
+/// \param[in] fileName name of the file
+///
+/// returns true if the writing succeeded
+///
+/// export this binning scheme to a file
+///  - fileName: name of the xml file
+
+Int_t TUnfoldBinningXML::ExportXML(char const *fileName) const {
+  ofstream outFile(fileName);
+  Int_t r=ExportXML(*this,outFile,kTRUE,kTRUE);
+  outFile.close();
+  return r;
+}
diff --git a/hist/hist/src/TUnfoldDensity.cxx b/hist/unfold/src/TUnfoldDensity.cxx
similarity index 51%
rename from hist/hist/src/TUnfoldDensity.cxx
rename to hist/unfold/src/TUnfoldDensity.cxx
index 18c58726c0ae0de2e37921809003a98cc7ec0811..1bb823ce2a7652625805ba237a38d04e3bf89a33 100644
--- a/hist/hist/src/TUnfoldDensity.cxx
+++ b/hist/unfold/src/TUnfoldDensity.cxx
@@ -1,111 +1,127 @@
-// Author: Stefan Schmitt, Amnon Harel
-// DESY and CERN, 11/08/11
-
-//  Version 17.1, add scan type RhoSquare, small bug fixes with useAxisBinning
-//
-//  History:
-//    Version 17.0, support for density regularisation, complex binning schemes, tau scan
-
-/** \class TUnfoldBinning
- \ingroup Hist
-  TUnfold is used to decompose a measurement y into several sources x
-  given the measurement uncertainties and a matrix of migrations A
-
-  More details are described with the documentation of TUnfold.
-
-  For most applications, it is best to use TUnfoldDensity
-  instead of using TUnfoldSys or TUnfold
-
-  If you use this software, please consider the following citation
-       S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]
-
-  More documentation and updates are available on
-      http://www.desy.de/~sschmitt
-
-  As compared to TUnfold, TUndolfDensity adds the following functionality
-    * background subtraction (see documentation of TUnfoldSys)
-    * error propagation (see documentation of TUnfoldSys)
-    * regularisation schemes respecting the bin widths
-    * support for complex, multidimensional input distributions
-
-  Complex binning schemes are imposed on the measurements y and
-  on the result vector x with the help of the class TUnfoldBinning
-  The components of x or y are part of multi-dimensional distributions.
-  The bin widths along the relevant directions in these distributions
-  are used to calculate bin densities (number of events divided by bin width)
-  or to calculate derivatives taking into account the proper distance of
-  adjacent bin centers
-
-  ## Complex binning schemes
-  in literature on unfolding, the "standard" test case is a
-  one-dimensional distribution without underflow or overflow bins.
-  The migration matrix is almost diagonal.
-
-  This "standard" case is rarely realized for real problems.
-
-  Often one has to deal with multi-dimensional input distributions.
-  In addition, there are underflow and overflow bins
-  or other background bins, possibly determined with the help of auxillary
-  measurements
-
-  In TUnfoldDensity, such complex binning schemes are handled with the help
-  of the class TUnfoldBinning. For each vector there is a tree
-  structure. The tree nodes hold multi-dimensiopnal distributions
-
-  For example, the "measurement" tree could have two leaves, one for
-  the primary distribution and one for auxillary measurements
-
-  Similarly, the "truth" tree could have two leaves, one for the
-  signal and one for the background.
-
-  each of the leaves may then have a multi-dimensional distribution.
-
-  The class TUnfoldBinning takes care to map all bins of the
-  "measurement" to the one-dimensional vector y.
-  Similarly, the "truth" bins are mapped to the vector x.
-
-  ## Choice of the regularisation
-  In TUnfoldDensity, two methods are implemented to determine tau**2
-    1.  ScanLcurve()  locate the tau where the L-curve plot has a "kink"
-      this function is implemented in the TUnfold class
-    2.  ScanTau() finds the solution such that some variable
-           (e.g. global correlation coefficient) is minimized
-      this function is implemented in the TUnfoldDensity class,
-      such that the variable could be made depend on the binning scheme
-
-  Each of the algorithms has its own advantages and disadvantages
-
-  The algorithm (1) does not work if the input data are too similar to the
-  MC prediction, that is unfolding with tau=0 gives a least-square sum
-  of zero. Typical no-go cases of the L-curve scan are:
-    - (a) the number of measurements is too small (e.g. ny=nx)
-    - (b) the input data have no statistical fluctuations
-         [identical MC events are used to fill the matrix of migrations
-          and the vector y]
-
-  The algorithm (2) only works if the variable does have a real minimum
-  as a function of tau.
-  If global correlations are minimized, the situation is as follows:
-  The matrix of migration typically introduces negative correlations.
-   The area constraint introduces some positive correlation.
-   Regularisation on the "size" introduces no correlation.
-   Regularisation on 1st or 2nd derivatives adds positive correlations.
-   For this reason, "size" regularisation does not work well with
-   the tau-scan: the higher tau, the smaller rho, but there is no minimum.
-   In contrast, the tau-scan is expected to work well with 1st or 2nd
-   derivative regularisation, because at some point the negative
-   correlations from migrations are approximately cancelled by the
-   positive correlations from the regularisation conditions.
-
-  whichever algorithm is used, the output has to be checked:
+// @(#)root/unfold:$Id$
+// Authors: Stefan Schmitt, Amnon Harel DESY and CERN, 11/08/11
+
+/** \class TUnfoldDensity
+\ingroup Unfold
+An algorithm to unfold distributions from detector to truth level
+
+TUnfoldDensity is used to decompose a measurement y into several sources x,
+given the measurement uncertainties, background b and a matrix of migrations A.
+The method can be applied to a large number of problems,
+where the measured distribution y is a linear superposition
+of several Monte Carlo shapes. Beyond such a simple template fit,
+TUnfoldDensity has an adjustable regularisation term and also supports an
+optional constraint on the total number of events.
+Background sources can be specified, with a normalisation constant and
+normalisation uncertainty. In addition, variants of the response
+matrix may be specified, these are taken to determine systematic
+uncertainties. Complex, multidimensional arrangements of signal and
+background bins are managed with the help of the class TUnfoldBinning.
+
+If you use this software, please consider the following citation
+
+<b>S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]</b>
+
+Detailed documentation and updates are available on
+http://www.desy.de/~sschmitt
+
+### Brief recipe to use TUnfoldSys:
+
+  - Set up binning schemes for the truth and measured
+distributions. The binning schemes may be coded in the XML language,
+for reading use TUnfoldBinningXML.
+  - A matrix (truth,reconstructed) is given as a two-dimensional histogram
+    as argument to the constructor of TUnfold
+  - A vector of measurements is given as one-dimensional histogram using
+    the SetInput() method
+  - Repeated calls to SubtractBackground() to specify background sources
+  - Repeated calls to AddSysError() to specify systematic uncertainties
+    - The unfolding is performed
+
+    - either once with a fixed parameter tau, method DoUnfold(tau)
+    - or multiple times in a scan to determine the best choice of tau,
+      method ScanLCurve()
+    - or multiple times in a scan to determine the best choice of tau,
+      method ScanTau()
+
+  - Unfolding results are retrieved using various GetXXX() methods
+
+A detailed documentation of the various GetXXX() methods to control
+systematic uncertainties is given with the method TUnfoldSys.
+
+### Why to use complex binning schemes
+
+in literature on unfolding, the "standard" test case is a
+one-dimensional distribution without underflow or overflow bins.
+The migration matrix is almost diagonal.
+
+<b>This "standard" case is rarely realized for real problems.</b>
+
+Often one has to deal with multi-dimensional distributions.
+In addition, there are underflow and overflow bins
+or other background bins, possibly determined with the help of auxiliary
+measurements.
+
+In TUnfoldDensity, such complex binning schemes are handled with the help
+of the class TUnfoldBinning. For both the measurement and the truth
+there is a tree structure. The tree nodes may correspond to single
+bins (e.g. nuisance parameters) or may hold multi-dimensional distributions.
+
+For example, the "measurement" tree could have two leaves, one for
+the primary distribution and one for auxiliary measurements.
+Similarly, the "truth" tree could have two leaves, one for the
+signal and one for the background.
+Each of the leaves may then have a multi-dimensional distribution.
+
+The class TUnfoldBinning takes care to map all bins of the
+"measurement" to a one-dimensional vector y.
+Similarly, the "truth" bins are mapped to the vector x.
+
+### How to choose the regularisation settings
+
+In TUnfoldDensity, two methods are implemented to determine tau**2
+
+  1. ScanLcurve()  locate the tau where the L-curve plot has a "kink"
+     this function is implemented in the TUnfold class
+  2. ScanTau() finds the solution such that some variable
+     (e.g. global correlation coefficient) is minimized.
+     This function is implemented in the TUnfoldDensity class
+
+Each of the algorithms has its own advantages and disadvantages.
+The algorithm (1) does not work if the input data are too similar to the
+MC prediction. Typical no-go cases of the L-curve scan are:
+
+  - the number of measurements is too small (e.g. ny=nx)
+  - the input data have no statistical fluctuations
+ [identical MC events are used to fill the matrix of migrations
+ and the vector y for a "closure test"]
+
+The algorithm (2) only works if the variable does have a real minimum
+as a function of tau. If global correlations are minimized, the situation
+is as follows:
+The matrix of migration typically introduces negative correlations.
+The area constraint introduces some positive correlation.
+Regularisation on the "size" introduces no correlation.
+Regularisation on 1st or 2nd derivatives adds positive correlations.
+
+For these reasons, "size" regularisation does not work well with
+the tau-scan: the higher tau, the smaller rho, but there is no minimum.
+As a result, large values of tau (too strong regularisation) are found.
+In contrast, the tau-scan is expected to work better with 1st or 2nd
+derivative regularisation, because at some point the negative
+correlations from migrations are approximately cancelled by the
+positive correlations from the regularisation conditions.
+
+whichever algorithm is used, the output has to be checked:
+
   1. The L-curve should have approximate L-shape
-       and the final choice of tau should not be at the very edge of the
-       scanned region
+     and the final choice of tau should not be at the very edge of the
+     scanned region
   2. The scan result should have a well-defined minimum and the
-       final choice of tau should sit right in the minimum
-*/
+     final choice of tau should sit right in the minimum
+
 
-/*
+--------------------------------------------------------------------------------
   This file is part of TUnfold.
 
   TUnfold is free software: you can redistribute it and/or modify
@@ -120,6 +136,16 @@
 
   You should have received a copy of the GNU General Public License
   along with TUnfold.  If not, see <http://www.gnu.org/licenses/>.
+
+<b>Version 17.6, with updated doxygen comments and bug-fixes in TUnfoldBinning</b>
+
+#### History:
+  - Version 17.5, bug fix in TUnfold also corrects GetEmatrixSysUncorr()
+  - Version 17.4, in parallel to changes in TUnfoldBinning
+  - Version 17.3, in parallel to changes in TUnfoldBinning
+  - Version 17.2, with new options 'N' and 'c' for axis regularisation steering
+  - Version 17.1, add scan type RhoSquare, small bug fixes with useAxisBinning
+  - Version 17.0, support for density regularisation, complex binning schemes, tau scan
 */
 
 #include "TUnfoldDensity.h"
@@ -129,13 +155,27 @@
 #include <iostream>
 #include <map>
 
-// #define DEBUG
+//#define DEBUG
+
+#ifdef DEBUG
+using namespace std;
+#endif
 
 ClassImp(TUnfoldDensity)
 
+TUnfoldDensity::~TUnfoldDensity(void)
+{
+   // clean up
+   if(fOwnedOutputBins) delete fOwnedOutputBins;
+   if(fOwnedInputBins) delete fOwnedInputBins;
+   if(fRegularisationConditions) delete fRegularisationConditions;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Only for use by root streamer or derived classes.
+
 TUnfoldDensity::TUnfoldDensity(void)
 {
-   // empty constructor, for derived classes
    fConstOutputBins=0;
    fConstInputBins=0;
    fOwnedOutputBins=0;
@@ -143,13 +183,36 @@ TUnfoldDensity::TUnfoldDensity(void)
    fRegularisationConditions=0;
 }
 
-TUnfoldDensity::~TUnfoldDensity(void)
-{
-   // clean up
-   if(fOwnedOutputBins) delete fOwnedOutputBins;
-   if(fOwnedInputBins) delete fOwnedInputBins;
-   if(fRegularisationConditions) delete fRegularisationConditions;
-}
+////////////////////////////////////////////////////////////////////////////////
+/// Eet up response matrix A, uncorrelated uncertainties of A,
+/// regularisation scheme and binning schemes.
+///
+/// \param[in] hist_A matrix that describes the migrations
+/// \param[in] histmap mapping of the histogram axes to the unfolding output
+/// \param[in] regmode (default=kRegModeSize) global regularisation mode
+/// \param[in] constraint (default=kEConstraintArea) type of constraint
+/// \param[in] densityMode (default=kDensityModeBinWidthAndUser)
+/// regularisation scale factors to construct the matrix L
+/// \param[in] outputBins (default=0) binning scheme for truth (unfolding output)
+/// \param[in] inputBins (default=0) binning scheme for measurement (unfolding
+/// input)
+/// \param[in] regularisationDistribution (default=0) selection of
+/// regularized distribution
+/// \param[in] regularisationAxisSteering (default=0) detailed
+/// regularisation steering for selected distribution
+///
+/// The parameters <b>hist_A, histmap, constraint</b> are
+/// explained with the TUnfoldSys constructor.
+///
+/// The parameters <b>outputBins,inputBins</b> set the binning
+/// schemes. If these arguments are zero, simple binning schemes are
+/// constructed which correspond to the axes of the histogram
+/// <b>hist_A</b>.
+///
+/// The parameters
+/// <b>regmode, densityMode, regularisationDistribution, regularisationAxisSteering</b>
+/// together control how the initial matrix L of regularisation conditions
+/// is constructed. as explained in RegularizeDistribution().
 
 TUnfoldDensity::TUnfoldDensity
 (const TH2 *hist_A, EHistMap histmap,ERegMode regmode,EConstraint constraint,
@@ -158,16 +221,6 @@ TUnfoldDensity::TUnfoldDensity
  const char *regularisationAxisSteering) :
    TUnfoldSys(hist_A,histmap,kRegModeNone,constraint)
 {
-   // set up unfolding matrix and regularisation scheme
-   //    hist_A:  matrix that describes the migrations
-   //    histmap: mapping of the histogram axes to the unfolding output
-   //    regmode: global regularisation mode
-   //    constraint: type of constraint to use
-   //    regularisationSteering: detailed steering for the regularisation
-   //                  see method RegularizeDistribution()
-   //    outputBins: binning scheme of the output bins
-   //    inputBins: binning scheme of the input bins
-
    fRegularisationConditions=0;
    // set up binning schemes
    fConstOutputBins = outputBins;
@@ -208,48 +261,77 @@ TUnfoldDensity::TUnfoldDensity
    // check whether binning scheme matches with the histogram
    // in terms of total number of bins
    Int_t nOut=genAxis->GetNbins();
-   Int_t nOutMapped=TMath::Abs(fConstOutputBins->GetTH1xNumberOfBins());
-   if(nOutMapped!= nOut) {
+   Int_t nOutMappedT=TMath::Abs(fConstOutputBins->GetTH1xNumberOfBins(kTRUE));
+   Int_t nOutMappedF=TMath::Abs(fConstOutputBins->GetTH1xNumberOfBins
+                                (fOwnedOutputBins));
+   if((nOutMappedT!= nOut)&&(nOutMappedF!=nOut)) {
       Error("TUnfoldDensity",
-            "Output binning incompatible number of bins %d!=%d",
-            nOutMapped, nOut);
+            "Output binning incompatible number of bins: axis %d binning scheme %d (%d)",
+            nOut,nOutMappedT,nOutMappedF);
    }
    // check whether binning scheme matches with the histogram
    Int_t nInput=detAxis->GetNbins();
-   Int_t nInputMapped=TMath::Abs(fConstInputBins->GetTH1xNumberOfBins());
-   if(nInputMapped!= nInput) {
+   Int_t nInputMappedT=TMath::Abs(fConstInputBins->GetTH1xNumberOfBins(kTRUE));
+   Int_t nInputMappedF=TMath::Abs(fConstInputBins->GetTH1xNumberOfBins
+                                  (fOwnedInputBins));
+   if((nInputMappedT!= nInput)&&(nInputMappedF!= nInput)) {
       Error("TUnfoldDensity",
-            "Input binning incompatible number of bins %d!=%d ",
-            nInputMapped, nInput);
+            "Input binning incompatible number of bins:axis %d binning scheme %d (%d) ",
+            nInput,nInputMappedT,nInputMappedF);
    }
 
    // report detailed list of excluded bins
    for (Int_t ix = 0; ix <= nOut+1; ix++) {
       if(fHistToX[ix]<0) {
-         Info("TUnfold","*NOT* unfolding bin %s",GetOutputBinName(ix).Data());
+   Info("TUnfold","*NOT* unfolding bin %s",(char const *)GetOutputBinName(ix));
       }
    }
 
    // set up the regularisation here
    if(regmode !=kRegModeNone) {
       RegularizeDistribution
-      (regmode,densityMode,regularisationDistribution,
-       regularisationAxisSteering);
+   (regmode,densityMode,regularisationDistribution,
+    regularisationAxisSteering);
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get bin name of an output bin.
+///
+/// \param[in] iBinX bin number
+///
+/// Return value: name of the bin. The name is constructed from the
+/// entries in the binning scheme and includes information about the
+/// bin borders etc.
+
 TString TUnfoldDensity::GetOutputBinName(Int_t iBinX) const {
    if(!fConstOutputBins) return TUnfold::GetOutputBinName(iBinX);
    else return fConstOutputBins->GetBinName(iBinX);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Density correction factor for a given bin.
+///
+/// \param[in]  densityMode type of factor to calculate
+/// \param[in]  iBin  bin number
+///
+/// return a multiplicative factor, for scaling the regularisation
+/// conditions from this bin.
+///
+/// For densityMode=kDensityModeNone the factor is set to unity.
+/// For densityMode=kDensityModeBinWidth
+/// the factor is set to 1/binArea
+/// where the binArea is the product of the bin widths in all
+/// dimensions. If the width of a bin is zero or can not be
+/// determined, the factor is set to zero.
+/// For densityMode=kDensityModeUser the factor is determined from the
+///  method TUnfoldBinning::GetBinFactor().
+/// For densityMode=kDensityModeBinWidthAndUser, the results of
+/// kDensityModeBinWidth and kDensityModeUser are multiplied.
+
 Double_t TUnfoldDensity::GetDensityFactor
 (EDensityMode densityMode,Int_t iBin) const
 {
-   // density correction factor for a given bin
-   //    distributionName : name of the distribution within the output binning
-   //    densityFlags : type of factor to calculate
-   //    iBin : bin number
    Double_t factor=1.0;
    if((densityMode == kDensityModeBinWidth)||
       (densityMode == kDensityModeBinWidthAndUser)) {
@@ -264,50 +346,61 @@ Double_t TUnfoldDensity::GetDensityFactor
    return factor;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Set up regularisation conditions.
+///
+/// \param[in] regmode basic regularisation mode (see class TUnfold)
+/// \param[in] densityMode how to apply bin-wise factors
+/// \param[in] distribution  name of the TUnfoldBinning node for which
+/// the regularisation conditions shall be set (zero matches all nodes)
+/// \param[in] axisSteering  regularisation fine-tuning
+///
+/// <b>axisSteering</b> is a string with several tokens, separated by
+/// a semicolon: `"axisName[options];axisName[options];..."`.
+///
+///  - <b>axisName</b>:
+///    the name of an axis. The special name * matches all.
+///    So the argument <b>distribution</b> selects one (or all)
+///    distributions. Within the selected distribution(s), steering options may be
+///    specified for each axis (or for all axes) to define the
+///    regularisation conditions.
+///  - <b>options</b>
+///    one or several character as follows:
+///    - u : exclude underflow bin from derivatives along this axis
+///    - o : exclude overflow bin from derivatives along this axis
+///    - U : exclude underflow bin
+///    - O : exclude overflow bin
+///    - b : use bin width for derivative calculation
+///    - B : same as 'b', in addition normalize to average bin width
+///    - N : completely exclude derivatives along this axis
+///    - p : axis is periodic (e.g. azimuthal angle), so
+///          include derivatives built from combinations involving bins at
+///          both ends of the axis "wrap around"
+///
+/// example:  <b>axisSteering</b>=`"*[UOB]"` uses bin widths to calculate
+/// derivatives but underflow/overflow bins are not regularized
+
 void TUnfoldDensity::RegularizeDistribution
 (ERegMode regmode,EDensityMode densityMode,const char *distribution,
  const char *axisSteering)
 {
-   // regularize distribution(s) using the given settings
-   //     regmode: basic regularisation mode (see class TUnfold)
-   //     densityMode: how to apply bin density corrections
-   //              (normalisation to bin width or user factor)
-   //     distribution: name of the distribiution where this regularisation
-   //             is applied to (if zero, apply to all)
-   //     axisSteering: regularisation steering specific to the axes
-   //          The steering is defined as follows
-   //             "steering1;steering2;...steeringN"
-   //          each "steeringX" is defined as
-   //             axisName:[options]
-   //          axisName: the name of an axis where "options" applies
-   //                    the special name * matches all axes
-   //          options: one of several character as follows
-   //             u : exclude underflow bin from derivatives along this axis
-   //             o : exclude overflow bin from derivatives along this axis
-   //             U : exclude underflow bin
-   //             O : exclude overflow bin
-   //             b : use bin width for derivative calculation
-   //             B : same as 'b' but in addition normalize to average bin width
-   //
-   //          example:  "*[UOB]" uses bin widths for derivatives and
-   //                             underflow/overflow bins are not regularized
 
    RegularizeDistributionRecursive(GetOutputBinning(),regmode,densityMode,
                                    distribution,axisSteering);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Recursively add regularisation conditions for this node and its children.
+///
+/// \param[in] binning current node
+/// \param[in] regmode regularisation mode
+/// \param[in] densityMode type of regularisation scaling
+/// \param[in] distribution target distribution(s) name
+/// \param[in] axisSteering steering within the target distribution(s)
+
 void TUnfoldDensity::RegularizeDistributionRecursive
 (const TUnfoldBinning *binning,ERegMode regmode,
  EDensityMode densityMode,const char *distribution,const char *axisSteering) {
-   // recursively regularize distribution(s) using the given settings
-   //     binning: distributions for this node an its children are considered
-   //     regmode: basic regularisation mode (see class TUnfold)
-   //     densityMode: how to apply bin density corrections
-   //              (normalisation to bin withd or user factor)
-   //     distribution: name of the distribiution where this regularisation
-   //             is applied to (if zero, apply to all)
-   //     axisSteering: regularisation steering specific to the axes
-   //              (see method RegularizeDistribution())
    if((!distribution)|| !TString(distribution).CompareTo(binning->GetName())) {
       RegularizeOneDistribution(binning,regmode,densityMode,axisSteering);
    }
@@ -318,17 +411,23 @@ void TUnfoldDensity::RegularizeDistributionRecursive
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Regularize the distribution of the given node.
+///
+/// \param[in] binning current node
+/// \param[in] regmode regularisation mode
+/// \param[in] densityMode type of regularisation scaling
+/// \param[in] axisSteering detailed steering for the axes of the distribution
+
 void TUnfoldDensity::RegularizeOneDistribution
 (const TUnfoldBinning *binning,ERegMode regmode,
  EDensityMode densityMode,const char *axisSteering)
 {
-   // regularize the distribution in this node
-   //     binning: the distributions to regularize
-   //     regmode: basic regularisation mode (see class TUnfold)
-   //     densityMode: how to apply bin density corrections
-   //              (normalisation to bin withd or user factor)
-   //     axisSteering: regularisation steering specific to the axes
-   //              (see method RegularizeDistribution())
+#ifdef DEBUG
+   cout<<"TUnfoldDensity::RegularizeOneDistribution node="
+       <<binning->GetName()<<" "<<regmode<<" "<<densityMode
+       <<" "<<(axisSteering ? axisSteering : "")<<"\n";
+#endif
    if(!fRegularisationConditions)
       fRegularisationConditions=new TUnfoldBinning("regularisation");
 
@@ -336,14 +435,23 @@ void TUnfoldDensity::RegularizeOneDistribution
       fRegularisationConditions->AddBinning(binning->GetName());
 
    // decode steering
-   Int_t isOptionGiven[6] = {0};
-   binning->DecodeAxisSteering(axisSteering,"uUoObB",isOptionGiven);
+   Int_t isOptionGiven[8];
+   binning->DecodeAxisSteering(axisSteering,"uUoObBpN",isOptionGiven);
    // U implies u
    isOptionGiven[0] |= isOptionGiven[1];
    // O implies o
    isOptionGiven[2] |= isOptionGiven[3];
    // B implies b
    isOptionGiven[4] |= isOptionGiven[5];
+   // option N is removed if any other option is on
+   for(Int_t i=0;i<7;i++) {
+      isOptionGiven[7] &= ~isOptionGiven[i];
+   }
+   // option "c" does not work with options UuOo
+   if(isOptionGiven[6] & (isOptionGiven[0]|isOptionGiven[2]) ) {
+      Error("RegularizeOneDistribution",
+            "axis steering %s is not valid",axisSteering);
+   }
 #ifdef DEBUG
    cout<<" "<<isOptionGiven[0]
        <<" "<<isOptionGiven[1]
@@ -351,12 +459,14 @@ void TUnfoldDensity::RegularizeOneDistribution
        <<" "<<isOptionGiven[3]
        <<" "<<isOptionGiven[4]
        <<" "<<isOptionGiven[5]
+       <<" "<<isOptionGiven[6]
+       <<" "<<isOptionGiven[7]
        <<"\n";
 #endif
    Info("RegularizeOneDistribution","regularizing %s regMode=%d"
-        " densityMode=%d axisSteering=%s",
-        binning->GetName(),(Int_t) regmode,(Int_t)densityMode,
-        axisSteering ? axisSteering : "");
+   " densityMode=%d axisSteering=%s",
+   binning->GetName(),(Int_t) regmode,(Int_t)densityMode,
+   axisSteering ? axisSteering : "");
    Int_t startBin=binning->GetStartBin();
    Int_t endBin=startBin+ binning->GetDistributionNumberOfBins();
    std::vector<Double_t> factor(endBin-startBin);
@@ -400,6 +510,12 @@ void TUnfoldDensity::RegularizeOneDistribution
          // for each direction
          Int_t nRegBins=0;
          Int_t directionMask=(1<<direction);
+         if(isOptionGiven[7] & directionMask) {
+#ifdef DEBUG
+            cout<<"skip direction "<<direction<<"\n";
+#endif
+            continue;
+         }
          Double_t binDistanceNormalisation=
             (isOptionGiven[5] & directionMask)  ?
             binning->GetDistributionAverageBinSize
@@ -411,8 +527,15 @@ void TUnfoldDensity::RegularizeOneDistribution
             // for each bin, find the neighbour bins
             Int_t iPrev,iNext;
             Double_t distPrev,distNext;
-            binning->GetBinNeighbours
-               (bin,direction,&iPrev,&distPrev,&iNext,&distNext);
+            Int_t error=binning->GetBinNeighbours
+               (bin,direction,&iPrev,&distPrev,&iNext,&distNext,
+                isOptionGiven[6] & directionMask);
+            if(error) {
+               Error("RegularizeOneDistribution",
+                     "invalid option %s (isPeriodic) for axis %s"
+                     " (has underflow or overflow)",axisSteering,
+                     binning->GetDistributionAxisLabel(direction).Data());
+            }
             if((regmode==kRegModeDerivative)&&(iNext>=0)) {
                Double_t f0 = -factor[bin-startBin];
                Double_t f1 = factor[iNext-startBin];
@@ -479,25 +602,56 @@ void TUnfoldDensity::RegularizeOneDistribution
 #endif
 }
 
+///////////////////////////////////////////////////////////////////////
+/// retrieve unfolding result as a new histogram
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// return value: pointer to a new histogram.  If
+/// <b>useAxisBinning</b> is set and if the selected distribution fits
+/// into a root histogram (1,2,3 dimensions) then return a histogram
+/// with the proper binning on each axis. Otherwise, return a 1D
+/// histogram with equidistant binning. If the histogram title is
+/// zero, a title is assigned automatically.
+///
+/// The <b>axisSteering</b> is defines as follows: "axis[mode];axis[mode];..."
+/// where:
+///
+///   - axis = name of an axis or *
+///   - mode = any combination of the letters CUO0123456789
+///
+///   - C collapse axis into one bin (add up results). If
+///     any of the numbers 0-9 are given in addition, only these bins are added up.
+///     Here bins are counted from zero, whereas in root, bins are counted
+///     from 1. Obviously, this only works for up to 10 bins.
+///   - U discard underflow bin
+///   - O discard overflow bin
+///
+/// examples: imagine the binning has two axis, named x and y.
+///
+///   - "*[UO]" exclude underflow and overflow bins for all axis.
+///     So here a TH2 is returned but all undeflow and overflow bins are empty
+///   - "x[UOC123]" integrate over the variable x but only using the
+///     bins 1,2,3 and not the underflow and overflow in x.
+///     Here a TH1 is returned, the axis is labelled "y" and
+///     the underflow and overflow (in y) are filled. However only the x-bins
+///     1,2,3 are used to determine the content.
+///   - "x[C];y[UO]" integrate over the variable x, including
+///     underflow and overflow but exclude underflow and overflow in y.
+///     Here a TH1 is returned, the axis is labelled "y". The underflow
+///     and overflow in y are empty.
+
 TH1 *TUnfoldDensity::GetOutput
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning) const
 {
-   // retreive unfolding result as histogram
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
@@ -511,18 +665,26 @@ TH1 *TUnfoldDensity::GetOutput
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve bias vector as a new histogram.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH1 *TUnfoldDensity::GetBias
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning) const
 {
-   // retreive unfolding bias as histogram
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
+  TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
       (histogramName,useAxisBinning,&binMap,histogramTitle,axisSteering);
@@ -533,18 +695,27 @@ TH1 *TUnfoldDensity::GetBias
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve unfolding result folded back as a new histogram.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+/// \param[in] addBgr (default=false) if true, include the background
+/// contribution (useful for direct comparison to data)
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH1 *TUnfoldDensity::GetFoldedOutput
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning,Bool_t addBgr) const
 {
-   // retreive unfolding result folded back by the matrix
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   addBgr: true if the background shall be included
    TUnfoldBinning const *binning=fConstInputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
@@ -559,44 +730,58 @@ TH1 *TUnfoldDensity::GetFoldedOutput
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve a background source in a new histogram.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] bgrSource the background source to retrieve
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+/// \param[in] includeError (default=3) type of background errors to
+/// be included (+1 uncorrelated bgr errors, +2 correlated bgr errors)
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH1 *TUnfoldDensity::GetBackground
 (const char *histogramName,const char *bgrSource,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,Bool_t useAxisBinning,
- Int_t includeError,Bool_t clearHist) const
+ Int_t includeError) const
 {
-   // retreive a background source
-   //   histogramName:  name of the histogram
-   //   bgrSource: name of the background source
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   include error: +1 if uncorrelated bgr errors should be included
-   //                  +2 if correlated bgr errors should be included
-   //   clearHist: whether the histogram should be cleared
-   //              if false, the background sources are added to the histogram
    TUnfoldBinning const *binning=fConstInputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
       (histogramName,useAxisBinning,&binMap,histogramTitle,axisSteering);
    if(r) {
-      TUnfoldSys::GetBackground(r,bgrSource,binMap,includeError,clearHist);
+      TUnfoldSys::GetBackground(r,bgrSource,binMap,includeError,kTRUE);
    }
    if(binMap) delete [] binMap;
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve input distribution in a new histogram.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH1 *TUnfoldDensity::GetInput
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning) const
 {
-   // retreive input distribution
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
    TUnfoldBinning const *binning=fConstInputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
@@ -608,29 +793,27 @@ TH1 *TUnfoldDensity::GetInput
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve global correlation coefficients including all uncertainty sources.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+/// \param[out] ematInv (default=0) to return the inverse covariance matrix
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments. The inverse of the covariance matrix
+/// is stored in a new histogram returned by <b>ematInv</b> if that
+/// pointer is non-zero.
+
 TH1 *TUnfoldDensity::GetRhoItotal
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning,TH2 **ematInv) {
-   // retreive global correlation coefficients, total error
-   // and inverse of error matrix
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
-   //   ematInv: retreive inverse of error matrix
-   //              if ematInv==0 the inverse is not returned
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
@@ -660,29 +843,28 @@ TH1 *TUnfoldDensity::GetRhoItotal
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve global correlation coefficients including input
+/// (statistical) and background uncertainties.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+/// \param[out] ematInv (default=0) to return the inverse covariance matrix
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments. The inverse of the covariance matrix
+/// is stored in a new histogram returned by <b>ematInv</b> if that
+/// pointer is non-zero.
+
 TH1 *TUnfoldDensity::GetRhoIstatbgr
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning,TH2 **ematInv) {
-   // retreive global correlation coefficients, input error
-   // and inverse of corresponding error matrix
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
-   //   ematInv: retreive inverse of error matrix
-   //              if ematInv==0 the inverse is not returned
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
@@ -712,27 +894,25 @@ TH1 *TUnfoldDensity::GetRhoIstatbgr
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve a correlated systematic 1-sigma shift.
+///
+/// \param[in] source identifier of the systematic uncertainty source
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH1 *TUnfoldDensity::GetDeltaSysSource
 (const char *source,const char *histogramName,
  const char *histogramTitle,const char *distributionName,
  const char *axisSteering,Bool_t useAxisBinning) {
-   // retreive histogram of systematic 1-sigma shifts
-   //   source: name of systematic error
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
@@ -747,28 +927,26 @@ TH1 *TUnfoldDensity::GetDeltaSysSource
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve systematic 1-sigma shift corresponding to a background
+/// scale uncertainty.
+///
+/// \param[in] bgrSource identifier of the background
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH1 *TUnfoldDensity::GetDeltaSysBackgroundScale
 (const char *bgrSource,const char *histogramName,
  const char *histogramTitle,const char *distributionName,
  const char *axisSteering,Bool_t useAxisBinning) {
-   // retreive histogram of systematic 1-sigma shifts due to a background
-   // normalisation uncertainty
-   //   source: name of background source
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
@@ -783,26 +961,25 @@ TH1 *TUnfoldDensity::GetDeltaSysBackgroundScale
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve 1-sigma shift corresponding to the previously specified uncertainty
+/// on tau.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH1 *TUnfoldDensity::GetDeltaSysTau
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,Bool_t useAxisBinning)
 {
-   // retreive histogram of systematic 1-sigma shifts due to tau uncertainty
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH1 *r=binning->CreateHistogram
@@ -817,28 +994,25 @@ TH1 *TUnfoldDensity::GetDeltaSysTau
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve correlation coefficients, including all uncertainties.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH2 *TUnfoldDensity::GetRhoIJtotal
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning)
 {
-   // retreive histogram of total corelation coefficients, including systematic
-   // uncertainties
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
    TH2 *r=GetEmatrixTotal
       (histogramName,histogramTitle,distributionName,
        axisSteering,useAxisBinning);
@@ -848,7 +1022,7 @@ TH2 *TUnfoldDensity::GetRhoIJtotal
          if(e_i>0.0) e_i=TMath::Sqrt(e_i);
          else e_i=0.0;
          for(Int_t j=0;j<=r->GetNbinsY()+1;j++) {
-            if(i==j) continue;
+      if(i==j) continue;
             Double_t e_j=r->GetBinContent(j,j);
             if(e_j>0.0) e_j=TMath::Sqrt(e_j);
             else e_j=0.0;
@@ -861,37 +1035,36 @@ TH2 *TUnfoldDensity::GetRhoIJtotal
          }
       }
       for(Int_t i=0;i<=r->GetNbinsX()+1;i++) {
-         if(r->GetBinContent(i,i)>0.0) {
-            r->SetBinContent(i,i,1.0);
-         } else {
-            r->SetBinContent(i,i,0.0);
-         }
+   if(r->GetBinContent(i,i)>0.0) {
+     r->SetBinContent(i,i,1.0);
+   } else {
+     r->SetBinContent(i,i,0.0);
+   }
       }
    }
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve covariance contribution from uncorrelated (statistical)
+/// uncertainties of the response matrix.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH2 *TUnfoldDensity::GetEmatrixSysUncorr
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning)
 {
-   // get error matrix contribution from uncorrelated errors on the matrix A
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH2 *r=binning->CreateErrorMatrixHistogram
@@ -903,28 +1076,26 @@ TH2 *TUnfoldDensity::GetEmatrixSysUncorr
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Retrieve covariance contribution from uncorrelated background uncertainties.
+///
+/// \param[in] bgrSource identifier of the background
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
 
 TH2 *TUnfoldDensity::GetEmatrixSysBackgroundUncorr
 (const char *bgrSource,const char *histogramName,
  const char *histogramTitle,const char *distributionName,
  const char *axisSteering,Bool_t useAxisBinning)
 {
-   // get error matrix from uncorrelated error of one background source
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH2 *r=binning->CreateErrorMatrixHistogram
@@ -936,27 +1107,26 @@ TH2 *TUnfoldDensity::GetEmatrixSysBackgroundUncorr
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get covariance contribution from the input uncertainties (data
+/// statistical uncertainties).
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH2 *TUnfoldDensity::GetEmatrixInput
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning)
 {
-   // get error contribution from input vector
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH2 *r=binning->CreateErrorMatrixHistogram
@@ -968,15 +1138,21 @@ TH2 *TUnfoldDensity::GetEmatrixInput
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get matrix of probabilities in a new histogram.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. if histogramTitle is null, choose a title
+/// automatically.
+
 TH2 *TUnfoldDensity::GetProbabilityMatrix
 (const char *histogramName,const char *histogramTitle,
  Bool_t useAxisBinning) const
 {
-   // get matrix of probabilities
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   useAxisBinning: if true, try to get the histogram using
-   //                   the original matrix binning
    TH2 *r=TUnfoldBinning::CreateHistogramOfMigrations
       (fConstOutputBins,fConstInputBins,histogramName,
        useAxisBinning,useAxisBinning,histogramTitle);
@@ -984,27 +1160,25 @@ TH2 *TUnfoldDensity::GetProbabilityMatrix
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get covariance matrix including all contributions.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] distributionName (default=0) identifier of the distribution to be extracted
+/// \param[in] axisSteering (default=0) detailed steering within the extracted
+/// distribution
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. See method GetOutput() for a detailed
+/// description of the arguments
+
 TH2 *TUnfoldDensity::GetEmatrixTotal
 (const char *histogramName,const char *histogramTitle,
  const char *distributionName,const char *axisSteering,
  Bool_t useAxisBinning)
 {
-   // get total error including systematic,statistical,background,tau errors
-   //   histogramName:  name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   distributionName: for complex binning schemes specify the name
-   //                of the requested distribution within the TUnfoldBinning
-   //                object
-   //   axisSteering:
-   //       "pattern1;pattern2;...;patternN"
-   //       patternI = axis[mode]
-   //       axis = name or *
-   //       mode = C|U|O
-   //        C: collapse axis into one bin
-   //        U: discarde underflow bin
-   //        O: discarde overflow bin
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the output histogram
    TUnfoldBinning const *binning=fConstOutputBins->FindNode(distributionName);
    Int_t *binMap=0;
    TH2 *r=binning->CreateErrorMatrixHistogram
@@ -1016,15 +1190,20 @@ TH2 *TUnfoldDensity::GetEmatrixTotal
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Access matrix of regularisation conditions in a new histogram.
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+/// \param[in] useAxisBinning (default=true) if set to true, try to extract a histogram with
+/// proper binning and axis labels
+///
+/// returns a new histogram. if histogramTitle is null, choose a title
+/// automatically.
+
 TH2 *TUnfoldDensity::GetL
 (const char *histogramName,const char *histogramTitle,Bool_t useAxisBinning)
 {
-   // return the matrix of regularisation conditions in a histogram
-   // input:
-   //   histogramName: name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
-   //   useAxisBinning: if true, try to use the axis bin widths
-   //                   on the x-axis of the output histogram
    if(fRegularisationConditions &&
       (fRegularisationConditions->GetEndBin()-
        fRegularisationConditions->GetStartBin()!= fL->GetNrows())) {
@@ -1045,19 +1224,24 @@ TH2 *TUnfoldDensity::GetL
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get regularisation conditions multiplied by result vector minus bias
+///   L(x-biasScale*biasVector).
+///
+/// \param[in] histogramName name of the histogram
+/// \param[in] histogramTitle (default=0) title of the histogram
+///
+/// returns a new histogram.
+/// This is a measure of the level of regularization required per
+/// regularisation condition.
+/// If there are (negative or positive) spikes,
+/// these regularisation conditions dominate
+/// over the other regularisation conditions and may introduce
+/// the largest biases.
+
 TH1 *TUnfoldDensity::GetLxMinusBias
 (const char *histogramName,const char *histogramTitle)
 {
-   // get regularisation conditions multiplied by result vector minus bias
-   //   L(x-biasScale*biasVector)
-   // this is a measure of the level of regulartisation required per
-   // regularisation condition
-   // if there are (negative or positive) spikes,
-   // these regularisation conditions dominate
-   // over the other regularisation conditions
-   // input
-   //   histogramName: name of the histogram
-   //   histogramTitle: title of the histogram (could be zero)
    TMatrixD dx(*GetX(), TMatrixD::kMinus, fBiasScale * (*fX0));
    TMatrixDSparse *Ldx=MultiplyMSparseM(fL,&dx);
    if(fRegularisationConditions &&
@@ -1086,6 +1270,14 @@ TH1 *TUnfoldDensity::GetLxMinusBias
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Locate a binning node for the input (measured) quantities.
+///
+/// \param[in] distributionName (default=0) distribution to look
+/// for. if zero, return the root node
+///
+/// returns: pointer to a TUnfoldBinning object or zero if not found
+
 const TUnfoldBinning *TUnfoldDensity::GetInputBinning
 (const char *distributionName) const
 {
@@ -1094,6 +1286,14 @@ const TUnfoldBinning *TUnfoldDensity::GetInputBinning
    return fConstInputBins->FindNode(distributionName);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Locate a binning node for the unfolded (truth level) quantities.
+///
+/// \param[in] distributionName (default=0) distribution to look
+/// for. if zero, return the root node
+///
+/// returns: pointer to a TUnfoldBinning object or zero if not found
+
 const TUnfoldBinning *TUnfoldDensity::GetOutputBinning
 (const char *distributionName) const
 {
@@ -1102,28 +1302,49 @@ const TUnfoldBinning *TUnfoldDensity::GetOutputBinning
    return fConstOutputBins->FindNode(distributionName);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Scan a function wrt tau and determine the minimum.
+///
+/// \param[in] nPoint number of points to be scanned
+/// \param[in] tauMin smallest tau value to study
+/// \param[in] tauMax largest tau value to study
+/// \param[out] scanResult the scanned function wrt log(tau)
+/// \param[in] mode 1st parameter for the scan function
+/// \param[in] distribution 2nd parameter for the scan function
+/// \param[in] projectionMode 3rd parameter for the scan function
+/// \param[out] lCurvePlot for monitoring, shows the L-curve
+/// \param[out] logTauXPlot for monitoring, L-curve(X) as a function of log(tau)
+/// \param[out] logTauYPlot for monitoring, L-curve(Y) as a function of log(tau)
+///
+/// Return value: the coordinate number on the curve <b>scanResult</b>
+/// which corresponds to the minimum
+///
+/// The function is scanned by repeating the following steps <b>nPoint</b>
+/// times
+///
+///   1. Choose a value of tau
+///   2. Perform the unfolding for this choice of tau, DoUnfold(tau)
+///   3. Determine the scan variable GetScanVariable()
+///
+/// The method  GetScanVariable() defines scans of correlation
+/// coefficients, where <b>mode</b> is chosen from the enum
+/// EScanTauMode. In addition one may set <b>distribution</b>
+/// and/or <b>projectionMode</b> to refine the calculation of
+/// correlations (e.g. restrict the calculation to the signal
+/// distribution and/or exclude underflow and overflow bins).
+/// See the documentation of GetScanVariable() for details.
+/// Alternative scan variables may be defined by overriding the
+/// GetScanVariable() method.
+///
+/// Automatic choice of scan range: if (tauMin,tauMax) do not
+/// correspond to a valid tau range (e.g. tauMin=tauMax=0.0) then
+/// the tau range is determined automatically. Use with care!
+
 Int_t TUnfoldDensity::ScanTau
 (Int_t nPoint,Double_t tauMin,Double_t tauMax,TSpline **scanResult,
  Int_t mode,const char *distribution,const char *axisSteering,
  TGraph **lCurvePlot,TSpline **logTauXPlot,TSpline **logTauYPlot)
 {
-   // scan some variable as a function of tau and determine the minimum
-   // input:
-   //   nPoint: number of points to be scanned on the resulting curve
-   //   tauMin: smallest tau value to study
-   //   tauMax: largest tau value to study
-   //     if (mauMin,tauMax) do not correspond to a valid tau range
-   //     (e.g. tauMin=tauMax=0.0) then the tau range is determined
-   //     automatically
-   //   mode,distribution,axisSteering: argument to GetScanVariable()
-   // output:
-   //   scanResult: output spline of the variable as a function of tau
-   // the following plots are produced on request (if pointers are non-zero)
-   //   lCurvePlot: for monitoring: the L-curve
-   //   logTauXPlot: for monitoring: L-curve(x) as a function of log(tau)
-   //   logTauYPlot: for monitoring: L-curve(y) as a function of log(tau)
-   // return value: the coordinate number (0..nPoint-1) corresponding to the
-   //   final choice of tau
    typedef std::map<Double_t,Double_t> TauScan_t;
    typedef std::map<Double_t,std::pair<Double_t,Double_t> > LCurve_t;
    TauScan_t curve;
@@ -1153,7 +1374,7 @@ Int_t TUnfoldDensity::ScanTau
    if((tauMin<=0)||(tauMax<=0.0)||(tauMin>=tauMax)) {
       // here no range is given, has to be determined automatically
       // the maximum tau is determined from the chi**2 values
-      // observed from unfolding without regulatisation
+      // observed from unfolding without regularization
 
       // first unfolding, without regularisation
       DoUnfold(0.0);
@@ -1302,11 +1523,11 @@ Int_t TUnfoldDensity::ScanTau
          xMin=cTi[i];
       }
       // find minimum for x[i]<x<x[i+1]
-      // get spline coefficiencts and solve equation
+      // get spline coefficients and solve equation
       //   derivative(x)==0
       Double_t x,y,b,c,d;
       splineC->GetCoeff(i,x,y,b,c,d);
-      // coefficiencts of quadratic equation
+      // coefficients of quadratic equation
       Double_t m_p_half=-c/(3.*d);
       Double_t q=b/(3.*d);
       Double_t discr=m_p_half*m_p_half-q;
@@ -1418,40 +1639,34 @@ Int_t TUnfoldDensity::ScanTau
    return bestChoice;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Calculate the function for ScanTau().
+///
+/// \param[in] mode the variable to be calculated
+/// \param[in] distribution distribution for which the variable
+///              is to be calculated
+/// \param[in] axisSteering detailed steering for selecting bins on
+/// the axes of the distribution (see method GetRhoItotal())
+///
+/// return value: the scan result for the given choice of tau (for
+/// which the unfolding was performed prior to calling this method)
+///
+/// In ScanTau() the unfolding is repeated for various choices of tau.
+/// For each tau, after unfolding, GetScanVariable() is called to
+/// determine the scan result for this choice of tau.
+///
+/// the following modes are implemented
+///
+///   - kEScanTauRhoAvg : average (stat+bgr) global correlation
+///   - kEScanTauRhoSquaredAvg : average (stat+bgr) global correlation squared
+///   - kEScanTauRhoMax : maximum (stat+bgr) global correlation
+///   - kEScanTauRhoAvgSys : average (stat+bgr+sys) global correlation
+///   - kEScanTauRhoAvgSquaredSys : average (stat+bgr+sys) global correlation squared
+///   - kEScanTauRhoMaxSys : maximum (stat+bgr+sys) global correlation
+
 Double_t TUnfoldDensity::GetScanVariable
 (Int_t mode,const char *distribution,const char *axisSteering)
 {
-   // calculate variable for ScanTau()
-   // the unfolding is repeated for various choices of tau.
-   // For each tau, after unfolding, the ScanTau() method calls
-   // GetScanVariable() to determine the value of the variable which
-   // is to be scanned
-   //
-   // the variable is expected to have a minimum near the "optimal" choice
-   // of tau
-   //
-   // input:
-   //    mode : define the type of variable to be calculated
-   //    distribution : define the distribution for which the variable
-   //              is to be calculated
-   //        the following modes are implemented:
-   //          kEScanTauRhoAvg : average global correlation from input data
-   //          kEScanTauRhoSquaredAvg : average global correlation squared
-   //                                   from input data
-   //          kEScanTauRhoMax : maximum global correlation from input data
-   //          kEScanTauRhoAvgSys : average global correlation
-   //                                 including systematic uncertainties
-   //          kEScanTauRhoAvgSquaredSys : average global correlation squared
-   //                                 including systematic uncertainties
-   //          kEScanTauRhoMaxSys : maximum global correlation
-   //                                 including systematic uncertainties
-   //    distribution : name of the TUnfoldBinning node
-   //                   for which to calculate the correlations
-   //    axisSteering : axis steering for calculating the correlations
-   //              the distribution
-   // return: the value of the variable as determined from the present
-   //    unfolding
-
    Double_t r=0.0;
    TString name("GetScanVariable(");
    name += TString::Format("%d,",mode);
diff --git a/hist/hist/src/TUnfoldSys.cxx b/hist/unfold/src/TUnfoldSys.cxx
similarity index 52%
rename from hist/hist/src/TUnfoldSys.cxx
rename to hist/unfold/src/TUnfoldSys.cxx
index 467254335e781840b6028878a9e54b5199a00d87..d233e3c6b2149dc08f5bc980f84146a6b190e907 100644
--- a/hist/hist/src/TUnfoldSys.cxx
+++ b/hist/unfold/src/TUnfoldSys.cxx
@@ -1,111 +1,95 @@
-// Author: Stefan Schmitt
-// DESY, 23/01/09
-
-//  Version 17.1, bug fix with background uncertainty
-//
-//  History:
-//    Version 17.0, possibility to specify an error matrix with SetInput
-//    Version 16.1, parallel to changes in TUnfold
-//    Version 16.0, parallel to changes in TUnfold
-//    Version 15, fix bugs with uncorr. uncertainties, add backgnd subtraction
-//    Version 14, remove some print-out, do not add unused sys.errors
-//    Version 13, support for systematic errors
+// @(#)root/unfold:$Id$
+// Author: Stefan Schmitt DESY, 23/01/09
 
 /** \class TUnfoldSys
-    \ingroup Hist
-  TUnfold is used to decompose a measurement y into several sources x
-  given the measurement uncertainties and a matrix of migrations A
-
-  TUnfoldSys adds error propagation of systematic errors to TUnfold
-  Also, background sources (with errors) can be subtracted.
-
-  **For most applications, it is better to use TUnfoldDensity
-  instead of using TUnfoldSys or TUnfold**
-
-  If you use this software, please consider the following citation
-       S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]
-
-  More documentation and updates are available on
-      http://www.desy.de/~sschmitt
-
-  The following sources of systematic error are considered in TUnfoldSys
-
-  (a) uncorrelated errors on the input matrix histA, taken as the
-      errors provided with the histogram.
-      These are typically statistical errors from finite Monte Carlo samples
-
-  (b) correlated shifts of the input matrix histA. These shifts are taken
-      as one-sigma effects when switchig on a given error soure.
-      several such error sources may be defined
-
-  (c) a systematic error on the regularisation parameter tau
-
-  (d) uncorrelated errors on background sources, taken as the errors
-      provided with the background histograms
-
-  (e) scale errors on background sources
-
- In addition there is the (statistical) uncertainty of the input vector (i)
-
- Source (a) is providede with the original histogram histA
-     TUnfoldSys(histA,...)
-
- Sources (b) are added by calls to
-     AddSysError()
-
- The systematic uncertainty on tau (c) is set by
-     SetTauError()
-
- Backgound sources causing errors of type (d) and (e) are added by
-     SubtractBackground()
-
- NOTE:
-    Systematic errors (a), (b), (c) are propagated to the result
-       AFTER unfolding
-
-    Background errors (d) and (e) are added to the data errors
-       BEFORE unfolding
-
- For this reason:
-  errors of type (d) and (e) are INCLUDED in the standard error matrix
-  and other methods provided by the base class TUnfold:
-      GetOutput()
-      GetEmatrix()
-      ...
-  whereas errors of type (a), (b), (c) are NOT INCLUDED in the methods
-  provided by the base class TUnfold.
-
-  ## Accessing error matrices:
-  The error sources (b),(c) and (e) propagate to shifts of the result.
-  These shifts may be accessed as histograms using the methods
-     GetDeltaSysSource()            corresponds to (b)
-     GetDeltaSysTau()               corresponds to (c)
-     GetDeltaSysBackgroundScale()   corresponds to (e)
-  The error sources (a) and (d) originate from many uncorrelated errors,
-  which in general are NOT uncorrelated on the result vector.
-  Thus, there is no corresponding shift of the output vector, only error
-  matrices are available
-
-  Method to get error matrix   |     corresponds to error sources
-  -----------------------------|---------------------------------
-   GetEmatrixSysUncorr()           |  (a)
-   GetEmatrixSysSource()           |  (b)
-   GetEmatrixSysTau()              |  (c)
-   GetEmatrixSysBackgroundUncorr() |  (d)
-   GetEmatrixSysBackgroundScale()  |  (e)
-   GetEmatrixInput()               |  (i)
-   GetEmatrix()                    |  (i)+(d)+(e)
-   GetEmatrixTotal()               |  (i)+(a)+(b)+(c)+(d)+(e)
-
-  Error matrices can be added to existing histograms.
-  This is useful to retreive the sum of several error matrices.
-  If the last argument of the GetEmatrixXXX() methods is set to kFALSE,
-  the histogram is not cleared, but the error matrix is simply added to the
-  existing histogram
-*/
-
-/*
-  This file is part of TUnfold.
+\ingroup Unfold
+An algorithm to unfold distributions from detector to truth level,
+with background subtraction and propagation of systematic uncertainties
+
+TUnfoldSys is used to decompose a measurement y into several sources x,
+given the measurement uncertainties, background b and a matrix of migrations A.
+The method can be applied to a large number of problems,
+where the measured distribution y is a linear superposition
+of several Monte Carlo shapes. Beyond such a simple template fit,
+TUnfoldSys has an adjustable regularisation term and also supports an
+optional constraint on the total number of events.
+Background sources can be specified, with a normalisation constant and
+normalisation uncertainty. In addition, variants of the response
+matrix may be specified, these are taken to determine systematic
+uncertainties.
+
+<b>For most applications, it is better to use the derived class
+TUnfoldDensity instead of TUnfoldSys. TUnfoldDensity adds
+features to TUnfoldSys, related to possible complex multidimensional
+arrangements of bins. For innocent
+users, the most notable improvement of TUnfoldDensity over TUnfoldSys are
+the getter functions. For TUnfoldSys, histograms have to be booked by the
+user and the getter functions fill the histogram bins. TUnfoldDensity
+simply returns a new, already filled histogram.</b>
+
+If you use this software, please consider the following citation
+
+<b>S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201]</b>
+
+Detailed documentation and updates are available on
+http://www.desy.de/~sschmitt
+
+Brief recipy to use TUnfoldSys:
+
+  - a matrix (truth,reconstructed) is given as a two-dimensional histogram
+    as argument to the constructor of TUnfold
+  - a vector of measurements is given as one-dimensional histogram using
+    the SetInput() method
+  - repeated calls to SubtractBackground() to specify background sources
+  - repeated calls to AddSysError() to specify systematic uncertainties
+  - The unfolding is performed
+    - either once with a fixed parameter tau, method DoUnfold(tau)
+    - or multiple times in a scan to determine the best chouce of tau,
+      method ScanLCurve()
+  - Unfolding results are retrieved using various GetXXX() methods
+
+
+Description of (systematic) uncertainties available in
+TUnfoldSys. There are covariance matrix contributions and there are
+systematic shifts. Systematic shifts correspond to the variation of a
+(buicance) parameter, for example a background normalisation or a
+one-sigma variation of a correlated systematic error.
+
+|                         | Set by                 | Access covariance matrix        | Access vector of shifts      | Description |
+|-------------------------|------------------------|---------------------------------|------------------------------|-------------|
+| (a)                     | TUnfoldSys constructor | GetEmatrixSysUncorr()           | n.a.                         | uncorrelated errors on the input matrix histA, taken as the errors provided with the histogram. These are typically statistical errors from finite Monte Carlo samples. |
+| (b)                     | AddSysError()          | GetEmatrixSysSource()           | GetDeltaSysSource()          | correlated shifts of the input matrix histA. These shifts are taken as one-sigma effects when switchig on a given error soure. Several such error sources may be defined |
+| (c)                     | SetTauError()          | GetEmatrixSysTau()              | GetDeltaSysTau()             | A systematic error on the regularisation parameter tau |
+| (d)                     | SubtractBackground()   | GetEmatrixSysBackgroundUncorr() | n.a.                         | uncorrelated errors on background sources, originating from the errors provided with the background histograms |
+| (e)                     | SubtractBackground()   | GetEmatrixSysBackgroundScale()  | GetDeltaSysBackgroundScale() | scale errors on background sources |
+| (i)                     | SetInput()             | GetEmatrixInput()               | n.a.                         | statistical uncertainty of the input (the measurement) |
+| (i)+(d)+(e)             | see above              | GetEmatrix()                    | n.a.                         | Partial sun of uncertainties: all sources which are propagated to the covariance before unfolding |
+| (i)+(a)+(b)+(c)+(d)+(e) | see above              | GetEmatrixTotal()               | n.a.                         | All known error sources summed up |
+
+
+Note:  (a), (b), (c) are propagated to the result AFTER unfolding,
+whereas the background errors (d) and (e) are added to the data errors
+BEFORE unfolding. For this reason the errors of type (d) and (e) are
+INCLUDED in the standard error matrix and other methods provided by
+the base class TUnfold, whereas errors of type (a), (b), (c) are NOT
+INCLUDED in the methods provided by the base class TUnfold.
+
+
+--------------------------------------------------------------------------------
+<b>Version 17.6, with updated doxygen comments</b>
+
+#### History:
+  - Version 17.5, in parallel to changes in TUnfold
+  - Version 17.4, in parallel to changes in TUnfoldBinning
+  - Version 17.3, in parallel to changes in TUnfoldBinning
+  - Version 17.2, add methods to find back systematic and background sources
+  - Version 17.1, bug fix with background uncertainty
+  - Version 17.0, possibility to specify an error matrix with SetInput
+  - Version 16.1, parallel to changes in TUnfold
+  - Version 16.0, parallel to changes in TUnfold
+  - Version 15, fix bugs with uncorr. uncertainties, add backgnd subtraction
+  - Version 14, remove some print-out, do not add unused sys.errors
+  - Version 13, support for systematic errors  This file is part of TUnfold.
 
   TUnfold is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -125,6 +109,7 @@
 #include <TMap.h>
 #include <TMath.h>
 #include <TObjString.h>
+#include <TSortedList.h>
 #include <RVersion.h>
 #include <cmath>
 
@@ -132,29 +117,57 @@
 
 ClassImp(TUnfoldSys)
 
+TUnfoldSys::~TUnfoldSys(void)
+{
+   // delete all data members
+   DeleteMatrix(&fDAinRelSq);
+   DeleteMatrix(&fDAinColRelSq);
+   delete fBgrIn;
+   delete fBgrErrUncorrInSq;
+   delete fBgrErrScaleIn;
+   delete fSysIn;
+   ClearResults();
+   delete fDeltaCorrX;
+   delete fDeltaCorrAx;
+   DeleteMatrix(&fYData);
+   DeleteMatrix(&fVyyData);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Only for use by root streamer or derived classes.
+
 TUnfoldSys::TUnfoldSys(void)
 {
    // set all pointers to zero
    InitTUnfoldSys();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Set up response matrix A, uncorrelated uncertainties of A and
+/// regularisation scheme.
+///
+/// \param[in] hist_A matrix that describes the migrations
+/// \param[in] histmap mapping of the histogram axes to the unfolding output
+/// \param[in] regmode (default=kRegModeSize) global regularisation mode
+/// \param[in] constraint (default=kEConstraintArea) type of constraint
+///
+/// For further details, consult the constructir of the class TUnfold.
+/// The uncertainties of hist_A are taken to be uncorrelated and aper
+/// propagated to the unfolding result, method GetEmatrixSysUncorr().
+
 TUnfoldSys::TUnfoldSys
 (const TH2 *hist_A, EHistMap histmap, ERegMode regmode,EConstraint constraint)
    : TUnfold(hist_A,histmap,regmode,constraint)
 {
-   // arguments:
-   //    hist_A:  matrix that describes the migrations
-   //    histmap: mapping of the histogram axes to the unfolding output
-   //    regmode: global regularisation mode
    // data members initialized to something different from zero:
    //    fDA2, fDAcol
 
-   // initialize TUnfold
+   // initialize TUnfoldSys
    InitTUnfoldSys();
 
-   // svae underflow and overflow bins
+   // save underflow and overflow bins
    fAoutside = new TMatrixD(GetNx(),2);
-   // save the romalized errors on hist_A
+   // save the normalized errors on hist_A
    // to the matrices fDAinRelSq and fDAinColRelSq
    fDAinColRelSq = new TMatrixD(GetNx(),1);
 
@@ -213,21 +226,36 @@ TUnfoldSys::TUnfoldSys
    delete[] dataDAinRelSq;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Specify a correlated systematic uncertainty.
+///
+/// \param[in] sysError alternative matrix or matrix of absolute/relative shifts
+/// \param[in] name identifier of the error source
+/// \param[in] histmap mapping of the histogram axes
+/// \param[in] mode format of the error source
+///
+/// <b>sysError</b> corresponds to a one-sigma variation. If
+/// may be given in various forms, specified by <b>mode</b>
+///
+///   - <b>mode=kSysErrModeMatrix</b> the histogram <b>sysError</b>
+///     corresponds to an alternative response matrix.
+///   - <b>mode=kSysErrModeShift</b> the content of the histogram <b>sysError</b> are the absolute shifts of the response matrix
+///   - <b>mode=kSysErrModeRelative</b> the content of the histogram <b>sysError</b>
+///      specifies the relative uncertainties
+///
+/// Internally, all three cases are transformed to the case <b>mode=kSysErrModeMatrix</b>.
+
 void TUnfoldSys::AddSysError
 (const TH2 *sysError,const char *name,EHistMap histmap,ESysErrMode mode)
 {
-   // add a correlated error source
-   //    sysError: alternative matrix or matrix of absolute/relative shifts
-   //    name: name of the error source
-   //    histmap: mapping of the histogram axes to the unfolding output
-   //    mode: format of the error source
 
    if(fSysIn->FindObject(name)) {
       Error("AddSysError","Source %s given twice, ignoring 2nd call.\n",name);
    } else {
       // a copy of fA is made. It can be accessed inside the loop
       // without having to take care that the sparse structure of *fA
-      // may be accidentally destroyed by asking for an element which is zero.
+      // otherwise, *fA may be accidentally destroyed by asking
+      // for an element which is zero.
       TMatrixD aCopy(*fA);
 
       Int_t nmax= GetNx()*GetNy();
@@ -297,9 +325,14 @@ void TUnfoldSys::AddSysError
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Perform background subtraction.
+///
+/// This prepares the data members for the base class TUnfold, such
+/// that the background is properly taken into account.
+
 void TUnfoldSys::DoBackgroundSubtraction(void)
 {
-   // performs background subtraction
    // fY = fYData - fBgrIn
    // fVyy = fVyyData + fBgrErrUncorr^2 + fBgrErrCorr * fBgrErrCorr#
    // fVyyinv = fVyy^(-1)
@@ -407,24 +440,32 @@ void TUnfoldSys::DoBackgroundSubtraction(void)
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Define the input data for subsequent calls to DoUnfold(Double_t).
+///
+///  input:   input distribution with errors
+///  - scaleBias:  scale factor applied to the bias
+///  - oneOverZeroError: for bins with zero error, this number defines 1/error.
+///
+/// Return value: number of bins with bad error
+///                 +10000*number of unconstrained output bins
+///
+///         Note: return values>=10000 are fatal errors,
+///               for the given input, the unfolding can not be done!
+///
+/// Calls the SetInput method of the base class, then renames the input
+/// vectors fY and fVyy, then performs the background subtraction
+///
+/// Data members modified:
+///   fYData,fY,fVyyData,fVyy,fVyyinvData,fVyyinv
+///
+/// and those modified by TUnfold::SetInput()
+/// and those modified by DoBackgroundSubtraction()
+
 Int_t TUnfoldSys::SetInput(const TH1 *hist_y,Double_t scaleBias,
                               Double_t oneOverZeroError,const TH2 *hist_vyy,
                               const TH2 *hist_vyy_inv)
 {
-   // Define the input data for subsequent calls to DoUnfold(Double_t)
-   //  input:   input distribution with errors
-   //  scaleBias:  scale factor applied to the bias
-   //  oneOverZeroError: for bins with zero error, this number defines 1/error.
-   // Return value: number of bins with bad error
-   //                 +10000*number of unconstrained output bins
-   //         Note: return values>=10000 are fatal errors,
-   //               for the given input, the unfolding can not be done!
-   // Calls the SetInput method of the base class, then renames the input
-   // vectors fY and fVyy, then performs the background subtraction
-   // Data members modified:
-   //   fYData,fY,fVyyData,fVyy,fVyyinvData,fVyyinv
-   // and those modified by TUnfold::SetInput()
-   // and those modified by DoBackgroundSubtraction()
 
    Int_t r=TUnfold::SetInput(hist_y,scaleBias,oneOverZeroError,hist_vyy,
                              hist_vyy_inv);
@@ -437,18 +478,31 @@ Int_t TUnfoldSys::SetInput(const TH1 *hist_y,Double_t scaleBias,
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Specify a source of background.
+///
+/// \param[in] bgr background distribution with uncorrelated errors
+/// \param[in] name identifier for this background source
+/// \param[in] scale normalisation factor applied to the background
+/// \param[in] scaleError normalisation uncertainty
+///
+/// The contribution <b>scale</b>*<b>bgr</b> is subtracted from the
+/// measurement prior to unfolding. The following contributions are
+/// added to the input covarianc ematrix
+///
+///   - using the uncorrelated histogram errors <b>dbgr</b>, the contribution
+/// (<b>scale</b>*<b>dbgr<sub>i</sub></b>)<sup>2</sup> is added to the
+/// diagonals of the covariance
+///   - using the histogram contents, the background normalisation uncertainty contribution
+/// <b>dscale</b>*<b>bgr<sub>i</sub></b> <b>dscale</b>*<b>bgr<sub>j</sub></b>
+/// is added to the covariance matrix
+///
+/// Data members modified:
+///   fBgrIn,fBgrErrUncorrInSq,fBgrErrScaleIn and those modified by DoBackgroundSubtraction()
+
 void TUnfoldSys::SubtractBackground
 (const TH1 *bgr,const char *name,Double_t scale,Double_t scale_error)
 {
-   // Store background source
-   //   bgr:    background distribution with uncorrelated errors
-   //   name:   name of this background source
-   //   scale:  scale factor applied to the background
-   //   scaleError: error on scale factor (correlated error)
-   //
-   // Data members modified:
-   //   fBgrIn,fBgrErrUncorrInSq,fBgrErrScaleIn
-   // and those modified by DoBackgroundSubtraction()
 
    // save background source
    if(fBgrIn->FindObject(name)) {
@@ -476,6 +530,23 @@ void TUnfoldSys::SubtractBackground
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get background into a histogram.
+///
+/// \param[inout] bgrHist target histogram, content and errors will be altered
+/// \param[in] bgrSource (default=0) name of backgrond source or zero
+/// to add all sources of background
+/// \param[in] binMap (default=0) remap histogram bins
+/// \param[in] includeError (default=3) include uncorrelated(1),
+/// correlated (2) or both (3) sources of uncertainty in the
+/// histogram errors
+/// \param[in] clearHist (default=true) reset histogram before adding
+/// up the specified background sources
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+/// The flag <b>clearHist</b> may be used to add background from
+/// several sources in successive calls to GetBackground().
+
 void TUnfoldSys::GetBackground
 (TH1 *bgrHist,const char *bgrSource,const Int_t *binMap,
  Int_t includeError,Bool_t clearHist) const
@@ -548,10 +619,11 @@ void TUnfoldSys::GetBackground
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Initialize pointers and TMaps.
+
 void TUnfoldSys::InitTUnfoldSys(void)
 {
-   // initialize pointers and TMaps
-
    // input
    fDAinRelSq = 0;
    fDAinColRelSq = 0;
@@ -589,25 +661,11 @@ void TUnfoldSys::InitTUnfoldSys(void)
    fVyyData=0;
 }
 
-TUnfoldSys::~TUnfoldSys(void)
-{
-   // delete all data members
-   DeleteMatrix(&fDAinRelSq);
-   DeleteMatrix(&fDAinColRelSq);
-   delete fBgrIn;
-   delete fBgrErrUncorrInSq;
-   delete fBgrErrScaleIn;
-   delete fSysIn;
-   ClearResults();
-   delete fDeltaCorrX;
-   delete fDeltaCorrAx;
-   DeleteMatrix(&fYData);
-   DeleteMatrix(&fVyyData);
-}
+////////////////////////////////////////////////////////////////////////////////
+/// Clear all data members which depend on the unfolding results.
 
 void TUnfoldSys::ClearResults(void)
 {
-   // clear all data members which depend on the unfolding results
    TUnfold::ClearResults();
    DeleteMatrix(&fEmatUncorrX);
    DeleteMatrix(&fEmatUncorrAx);
@@ -616,11 +674,14 @@ void TUnfoldSys::ClearResults(void)
    DeleteMatrix(&fDeltaSysTau);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Matrix calculations required to propagate systematic errors.
+///
+/// data members modified:
+///    fEmatUncorrX, fEmatUncorrAx, fDeltaCorrX, fDeltaCorrAx
+
 void TUnfoldSys::PrepareSysError(void)
 {
-   // calculations required for syst.error
-   // data members modified
-   //    fEmatUncorrX, fEmatUncorrAx, fDeltaCorrX, fDeltaCorrAx
    if(!fEmatUncorrX) {
       fEmatUncorrX=PrepareUncorrEmat(GetDXDAM(0),GetDXDAM(1));
    }
@@ -700,117 +761,145 @@ void TUnfoldSys::PrepareSysError(void)
    DeleteMatrix(&AM1);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Covariance contribution from uncorrelated uncertainties of the
+/// response matrix.
+///
+/// \param[inout] ematrix covariance matrix histogram
+/// \param[in] binMap mapping of histogram bins
+/// \param[in] clearEmat if true, ematrix is cleared prior to adding
+/// this covariance matrix contribution
+///
+/// This method propagates the uncertainties of the response matrix
+/// histogram, specified with the constructor, to the unfolding
+/// result. It is assumed that the entries of that histogram are
+/// bin-to-bin uncorrelated. In many cases this corresponds to the
+/// "Monte Carlo statistical uncertainties".
+///
+/// The array <b>binMap</b> is explained with the method GetOutput().
+/// The flag <b>clearEmat</b> may be used to add covariance matrices from
+/// several uncertainty sources.
+///
+/// data members modified:
+///   fVYAx, fESparse, fEAtV, fErrorAStat
+
 void TUnfoldSys::GetEmatrixSysUncorr
 (TH2 *ematrix,const Int_t *binMap,Bool_t clearEmat)
 {
-   // get output error contribution from statistical fluctuations in A
-   //   ematrix: output error matrix histogram
-   //   binMap: see method GetEmatrix()
-   //   clearEmat: set kTRUE to clear the histogram prior to adding the errors
-   // data members modified:
-   //   fVYAx, fESparse, fEAtV, fErrorAStat
    PrepareSysError();
    ErrorMatrixToHist(ematrix,fEmatUncorrX,binMap,clearEmat);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Propagate uncorrelated systematic errors to a covariance matrix.
+///
+/// \param[in] m_0 coefficients for error propagation
+/// \param[in] m_1 coefficients for error propagation
+///
+/// Returns the covariance matrix, propagates uncorrelated systematic errors to
+/// a covariance matrix. m_0,m_1 are the coefficients (matrices) for propagating
+/// the errors.
+///
+/// The error matrix is calculated by standard error propagation, where the
+/// derivative of the result vector X wrt the matrix A is given by:
+///
+///  \f[ \frac{dX_k}{dA_{ij}}  =  M0_{kj} Z0_i  - M1_{ki} Z1_j \f]
+///
+/// where:
+//
+///   the matrices M0 and M1 are arguments to this function
+///   the vectors Z0, Z1 : GetDXDAZ()
+///
+/// The matrix A is calculated from a matrix B as
+///
+///    \f[ A_{ij} = \frac{B_{ij}}{\sum_k B_{kj}} \f]
+///
+/// where k runs over additional indices of B, not present in A.
+/// (underflow and overflow bins, used for efficiency corrections)
+///
+/// define:   \f$ Norm_j = \sum_k B_{kj} \f$   (data member fSumOverY)
+///
+/// the derivative of A wrt this input matrix B is given by:
+///
+///   \f[ \frac{dA_{ij}}{dB_{kj}} = (\delta_{ik} - A_{ij} ) \frac{1}{Norm_j} \f]
+///
+/// The covariance matrix Vxx is:
+///
+///   \f[ Vxx_{mn}  = \sum_{ijlk} \big[   (\frac{dX_m}{dA_{ij}}) (\frac{dA_{ij}}{dB_{}kj}) DB_{kj} (\frac{dX_n}{dA_{lj}}) (\frac{dA_{lj}}{dB_{kj}}) \big] \f]
+///
+/// where \f$ DB_{kj} \f$ is the error on \f$ B_{kj} \f$ squared.
+///
+/// Simplify the sum over k:
+///
+///   \f[   \sum_k \big[ (\frac{dA_{ij}}{dB_{kj}}) DB_{kj} (\frac{dA_{lj}}{dB_{kj}}) \big]
+///      =  \sum_k \big[ (\delta_{ik} - A_{ij} ) \frac{1}{Norm_j} DB_{kj} (\delta_{lk} - A_{lj} ) \frac{1}{Norm_j} \big]
+///      =  \sum_k \big[ (\delta_{ik} \delta_{lk} - \delta_{ik} A_{lj} - \delta_{lk} A_{ij} + A_{ij} A_{lj} ) \frac{DB_{kj}}{Norm_j^2} \big] \f]
+///
+/// introduce normalized errors:  \f$ Rsq_{kj} = \frac{DB_{kj}}{Norm_j^2} \f$
+///
+/// after summing over k:
+///   \f[ \delta_{ik} \delta_{lk} Rsq_{kj}  \to    \delta_{il} Rsq_{ij}            \f]
+///   \f[ \delta_{ik} A_{lj} Rsq_{kj}       \to    A_{lj} Rsq_{ij}                 \f]
+///   \f[ \delta_{lk} A_{ij} Rsq_{kj}       \to    A_{ij} Rsq_{lj}                 \f]
+///   \f[ A_{ij} A_{lj} Rsq_{kj}            \to    A_{ij} A_{lj} \sum_k(Rsq_{kj})  \f]
+///
+/// introduce sum of normalized errors squared:   \f$ SRsq_j = \sum_k(Rsq_{kj}) \f$
+///
+/// Note: \f$ Rsq_{ij} \f$ is stored as `fDAinRelSq` (excludes extra indices of B)
+/// and \f$ SRsq_j \f$ is stored as  `fDAinColRelSq`  (sum includes all indices of B)
+///
+///   \f[ Vxx_{nm} = \sum_{ijl} \big[ (\frac{dX_m}{dA_{ij}}) (\frac{dX_n}{dA_{lj}})
+///     (\delta_{il} Rsq_{ij} - A_{lj} Rsq_{ij} - A_{ij} Rsq_{lj} + A_{ij} A_{lj} SRsq_j) \big] \f]
+///
+///   \f[ Vxx_nm = \sum_j \big[ F_{mj} F_{nj} SRsq_j \big]
+///              - \sum_j \big[ G_{mj} F_{nj} \big]
+///              - \sum_j \big[ F_{mj} G_{nj} \big]
+///              + \sum_{ij} \big[  (\frac{dX_m}{dA_{ij}}) (\frac{dX_n}{dA_{lj}}) Rsq_{ij} \big] \f]
+///
+/// where:
+///
+///   \f[ F_{mj} = \sum_i \big[ (\frac{dX_m}{dA_{ij}}) * A_{ij} \big]   \f]
+///   \f[ G_{mj} = \sum_i \big[ (\frac{dX_m}{dA_{ij}}) Rsq_{ij} \big]   \f]
+///
+/// In order to avoid explicitly calculating the 3-dimensional tensor
+/// \f$(\frac{dX_m}{dA_{ij}}) \f$ the sums are evaluated further, using:
+///
+///   \f[ \frac{dX_k}{dA_{ij}}  =  M0_{kj} Z0_i  - M1_{ki} Z1_j  \f]
+///   \f[ F_{mj} = M0_{mj} * (A\# Z0)_j - (M1 A)_{mj} Z1_j       \f]
+///   \f[ G_{mj} = M0_{mj} * (Rsq\# Z0)_j - (M1 Rsq)_{mj} Z1_j   \f]
+///
+/// and
+///
+///   \f[ \sum_{ij} \big[ (\frac{dX_m}{dA_{ij}}) (\frac{dX_n}{dA_{ij}}) Rsq_{ij} \big] =
+///          \sum_j \big[ M0_{mj} M0_nj \big[ \sum_i (Z0_i)^2 Rsq_{ij} \big] \big]
+///        + \sum_i \big[ M1_{mi} M1_{ni} \big[ \sum_j (Z1_j)^2 Rsq_{ij} \big] \big]
+///        - \sum_i \big[ M1_{mi} H_{ni} + M1_{ni} H_{mi} \big] \f]
+///
+/// where:
+///
+///   \f[ H_{mi} = Z0_i \sum_j \big[ M0_{mj} Z1_j Rsq_{ij} \big] \f]
+///
+/// collect all contributions:
+///
+///   \f[ Vxx_nm = r0 -r1 -r2 +r3 +r4 -r5 -r6 \f]
+///   \f[     r0 = \sum_j \big[ F_{mj} F_nj * SRsq_j \big] \f]
+///   \f[     r1 = \sum_j \big[ G_{mj} F_nj \big] \f]
+///   \f[     r2 = \sum_j \big[ F_{mj} G_nj \big] \f]
+///   \f[     r3 = \sum_j \big[ M0_{mj} M0_nj \big[ \sum_i (Z0_i)^2 Rsq_{ij} \big] \big] \f]
+///   \f[     r4 = \sum_i \big[ M1_{mi} M1_{ni} \big[ \sum_j (Z1_j)^2 Rsq_{ij} \big] \big] \f]
+///   \f[     r5 = \sum_i \big[ M1_{mi} H_{ni} \big] \f]
+///   \f[     r6 = \sum_i \big[ M1_{ni} H_{mi} \big] \f]
+
 TMatrixDSparse *TUnfoldSys::PrepareUncorrEmat
 (const TMatrixDSparse *m_0,const TMatrixDSparse *m_1)
 {
-   // propagate uncorrelated systematic errors to a covariance matrix
-   //   m0,m1 : coefficients (matrices) for propagating the errors
-   //
-   // the error matrix is calculated by standard error propagation, where the
-   // derivative of the result vector X wrt the matrix A is given by
-   //
-   //  dX_k / dA_ij  =  M0_kj * Z0_i  - M1_ki * Z1_j
-   //
-   // where:
-   //   the matrices M0 and M1 are arguments to this function
-   //   the vectors Z0, Z1 : GetDXDAZ()
-   //
-   // The matrix A is calculated from a matrix B as
-   //
-   //    A_ij = B_ij / sum_k B_kj
-   //
-   // where k runs over additional indices of B, not present in A.
-   // (underflow and overflow bins, used for efficiency corrections)
-   //
-   // define:   Norm_j = sum_k B_kj   (data member fSumOverY)
-   //
-   // the derivative of A wrt this input matrix B is given by:
-   //
-   //   dA_ij / dB_kj = (  delta_ik - A_ij ) * 1/Norm_j
-   //
-   // The covariance matrix Vxx is:
-   //
-   //   Vxx_mn  = sum_ijlk [   (dX_m / dA_ij) * (dA_ij / dB_kj) * DB_kj
-   //                        * (dX_n / dA_lj) * (dA_lj / dB_kj)  ]
-   //
-   // where DB_kj is the error on B_kj squared
-   // Simplify the sum over k:
-   //
-   //   sum_k [ (dA_ij / dB_kj) * DB_kj * (dA_lj / dB_kj) ]
-   //      =  sum_k [  ( delta_ik - A_ij ) * 1/Norm_j * DB_kj *
-   //                * ( delta_lk - A_lj ) * 1/Norm_j ]
-   //      =  sum_k [ ( delta_ik*delta_lk - delta_ik*A_lj - delta_lk*A_ij
-   //                  + A_ij * A_lj ) * DB_kj / Norm_j^2 ]
-   //
-   // introduce normalized errors:  Rsq_kj = DB_kj / Norm_j^2
-   // after summing over k:
-   //   delta_ik*delta_lk*Rsq_kj  ->    delta_il*Rsq_ij
-   //   delta_ik*A_lj*Rsq_kj      ->    A_lj*Rsq_ij
-   //   delta_lk*A_ij*Rsq_kj      ->    A_ij*Rsq_lj
-   //   A_ij*A_lj*Rsq_kj          ->    A_ij*A_lj*sum_k(Rsq_kj)
-   //
-   // introduce sum of normalized errors squared:   SRsq_j = sum_k(Rsq_kj)
-   //
-   // Note: Rsq_ij is stored as  fDAinRelSq     (excludes extra indices of B)
-   //   and SRsq_j is stored as  fDAinColRelSq  (sum includes all indices of B)
-   //
-   //  Vxx_nm = sum_ijl [ (dX_m / dA_ij) * (dX_n / dA_lj)
-   //     (delta_il*Rsq_ij - A_lj*Rsq_ij - A_ij*Rsq_lj + A_ij*A_lj *SRsq_j) ]
-   //
-   //  Vxx_nm =    sum_j [ F_mj * F_nj * SRsq_j
-   //            - sum_j [ G_mj * F_nj ]
-   //            - sum_j [ F_mj * G_nj ]
-   //            + sum_ij [  (dX_m / dA_ij) * (dX_n / dA_lj) * Rsq_ij ]
-   //
-   // where:
-   //    F_mj = sum_i [ (dX_m / dA_ij) * A_ij ]
-   //    G_mj = sum_i [ (dX_m / dA_ij) * Rsq_ij ]
-   //
-   // In order to avoid explicitly calculating the 3-dimensional tensor
-   // (dX_m/dA_ij) the sums are evaluated further, using
-   //    dX_k / dA_ij  =  M0_kj * Z0_i  - M1_ki * Z1_j
-   //
-   //   F_mj = M0_mj * (A# Z0)_j - (M1 A)_mj Z1_j
-   //   G_mj = M0_mj * (Rsq# Z0)_j - (M1 Rsq)_mj Z1_j
-   //
-   // and
-   //
-   //   sum_ij [ (dX_m/dA_ij) * (dX_n/dA_ij) * Rsq_ij ] =
-   //      sum_j [ M0_mj * M0_nj *  [ sum_i (Z0_i)^2 * Rsq_ij ] ]
-   //    + sum_i [ M1_mi * M1_ni *  [ sum_j (Z1_j)^2 * Rsq_ij ] ]
-   //    - sum_i [ M1_mi * H_ni + M1_ni * H_mi]
-   // where:
-   //   H_mi = Z0_i * sum_j [ M0_mj * Z1_j * Rsq_ij ]
-   //
-   // collect all contributions:
-   //   Vxx_nm = r0 -r1 -r2 +r3 +r4 -r5 -r6
-   //      r0 = sum_j [ F_mj * F_nj * SRsq_j ]
-   //      r1 = sum_j [ G_mj * F_nj ]
-   //      r2 = sum_j [ F_mj * G_nj ]
-   //      r3 = sum_j [ M0_mj * M0_nj *  [ sum_i (Z0_i)^2 * Rsq_ij ] ]
-   //      r4 = sum_i [ M1_mi * M1_ni *  [ sum_j (Z1_j)^2 * Rsq_ij ] ]
-   //      r5 = sum_i [ M1_mi * H_ni ]
-   //      r6 = sum_i [ M1_ni * H_mi ]
 
    //======================================================
    // calculate contributions containing matrices F and G
    // r0,r1,r2
    TMatrixDSparse *r=0;
    if(fDAinColRelSq && fDAinRelSq) {
-      // calculate matrices (M1*A)_mj * Z1_j  and  (M1*Rsq)_mj * Z1_j
+      // calculate matrices (M1*A)_{mj} * Z1_j  and  (M1*Rsq)_{mj} * Z1_j
       TMatrixDSparse *M1A_Z1=MultiplyMSparseMSparse(m_1,fA);
       ScaleColumnsByVector(M1A_Z1,GetDXDAZ(1));
       TMatrixDSparse *M1Rsq_Z1=MultiplyMSparseMSparse(m_1,fDAinRelSq);
@@ -820,12 +909,12 @@ TMatrixDSparse *TUnfoldSys::PrepareUncorrEmat
       TMatrixDSparse *RsqZ0=
          MultiplyMSparseTranspMSparse(fDAinRelSq,GetDXDAZ(0));
       //calculate matrix F
-      //   F_mj = M0_mj * (A# Z0)_j - (M1 A)_mj Z1_j
+      //   F_{mj} = M0_{mj} * (A# Z0)_j - (M1 A)_{mj} Z1_j
       TMatrixDSparse *F=new TMatrixDSparse(*m_0);
       ScaleColumnsByVector(F,AtZ0);
       AddMSparse(F,-1.0,M1A_Z1);
       //calculate matrix G
-      //   G_mj = M0_mj * (Rsq# Z0)_j - (M1 Rsq)_mj Z1_j
+      //   G_{mj} = M0_{mj} * (Rsq# Z0)_j - (M1 Rsq)_{mj} Z1_j
       TMatrixDSparse *G=new TMatrixDSparse(*m_0);
       ScaleColumnsByVector(G,RsqZ0);
       AddMSparse(G,-1.0,M1Rsq_Z1);
@@ -833,11 +922,11 @@ TMatrixDSparse *TUnfoldSys::PrepareUncorrEmat
       DeleteMatrix(&M1Rsq_Z1);
       DeleteMatrix(&AtZ0);
       DeleteMatrix(&RsqZ0);
-      //      r0 = sum_j [ F_mj * F_nj * SRsq_j ]
+      //      r0 = \sum_j [ F_{mj} * F_nj * SRsq_j ]
       r=MultiplyMSparseMSparseTranspVector(F,F,fDAinColRelSq);
-      //      r1 = sum_j [ G_mj * F_nj ]
+      //      r1 = \sum_j [ G_{mj} * F_nj ]
       TMatrixDSparse *r1=MultiplyMSparseMSparseTranspVector(F,G,0);
-      //      r2 = sum_j [ F_mj * G_nj ]
+      //      r2 = \sum_j [ F_{mj} * G_nj ]
       TMatrixDSparse *r2=MultiplyMSparseMSparseTranspVector(G,F,0);
       // r = r0-r1-r2
       AddMSparse(r,-1.0,r1);
@@ -849,7 +938,7 @@ TMatrixDSparse *TUnfoldSys::PrepareUncorrEmat
    }
    //======================================================
    // calculate contribution
-   //   sum_ij [ (dX_m/dA_ij) * (dX_n/dA_ij) * Rsq_ij ]
+   //   \sum_{ij} [ (dX_m/dA_{ij}) * (dX_n/dA_{ij}) * Rsq_{ij} ]
    //  (r3,r4,r5,r6)
    if(fDAinRelSq) {
       // (Z0_i)^2
@@ -859,9 +948,9 @@ TMatrixDSparse *TUnfoldSys::PrepareUncorrEmat
       for(int index=0;index<Z0sq_rows[Z0sq.GetNrows()];index++) {
          Z0sq_data[index] *= Z0sq_data[index];
       }
-      // Z0sqRsq =  sum_i (Z_i)^2 * Rsq_ij
+      // Z0sqRsq =  \sum_i (Z_i)^2 * Rsq_{ij}
       TMatrixDSparse *Z0sqRsq=MultiplyMSparseTranspMSparse(fDAinRelSq,&Z0sq);
-      //      r3 = sum_j [ M0_mj * M0_nj *  [ sum_i (Z0_i)^2 * Rsq_ij ] ]
+      //      r3 = \sum_j [ M0_{mj} * M0_nj *  [ \sum_i (Z0_i)^2 * Rsq_{ij} ] ]
       TMatrixDSparse *r3=MultiplyMSparseMSparseTranspVector(m_0,m_0,Z0sqRsq);
       DeleteMatrix(&Z0sqRsq);
 
@@ -872,23 +961,23 @@ TMatrixDSparse *TUnfoldSys::PrepareUncorrEmat
       for(int index=0;index<Z1sq_rows[Z1sq.GetNrows()];index++) {
          Z1sq_data[index] *= Z1sq_data[index];
       }
-      // Z1sqRsq = sum_j (Z1_j)^2 * Rsq_ij ]
+      // Z1sqRsq = \sum_j (Z1_j)^2 * Rsq_{ij} ]
       TMatrixDSparse *Z1sqRsq=MultiplyMSparseMSparse(fDAinRelSq,&Z1sq);
-      //      r4 = sum_i [ M1_mi * M1_ni *  [ sum_j (Z1_j)^2 * Rsq_ij ] ]
+      //      r4 = \sum_i [ M1_{mi} * M1_{ni} *  [ \sum_j (Z1_j)^2 * Rsq_{ij} ] ]
       TMatrixDSparse *r4=MultiplyMSparseMSparseTranspVector(m_1,m_1,Z1sqRsq);
       DeleteMatrix(&Z1sqRsq);
 
-      // sum_j [ M0_mj * Z1_j * Rsq_ij ]
+      // \sum_j [ M0_{mj} * Z1_j * Rsq_{ij} ]
       TMatrixDSparse *H=MultiplyMSparseMSparseTranspVector
          (m_0,fDAinRelSq,GetDXDAZ(1));
-      // H_mi = Z0_i * sum_j [ M0_mj * Z1_j * Rsq_ij ]
+      // H_{mi} = Z0_i * \sum_j [ M0_{mj} * Z1_j * Rsq_{ij} ]
       ScaleColumnsByVector(H,GetDXDAZ(0));
-      //      r5 = sum_i [ M1_mi * H_ni ]
+      //      r5 = \sum_i [ M1_{mi} * H_{ni} ]
       TMatrixDSparse *r5=MultiplyMSparseMSparseTranspVector(m_1,H,0);
-      //      r6 = sum_i [ H_mi * M1_ni ]
+      //      r6 = \sum_i [ H_{mi} * M1_{ni} ]
       TMatrixDSparse *r6=MultiplyMSparseMSparseTranspVector(H,m_1,0);
       DeleteMatrix(&H);
-      // r =  r0 -r1 -r2 +r3 +r4 +r5 +r6
+      // r =  r0 -r1 -r2 +r3 +r4 -r5 -r6
       if(r) {
          AddMSparse(r,1.0,r3);
          DeleteMatrix(&r3);
@@ -906,6 +995,13 @@ TMatrixDSparse *TUnfoldSys::PrepareUncorrEmat
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Propagate correlated systematic shift to an output vector.
+///
+/// \param[in] m1 coefficients
+/// \param[in] m2 coeffiicients
+/// \param[in] dsys matrix of correlated shifts from this source
+
 TMatrixDSparse *TUnfoldSys::PrepareCorrEmat
 (const TMatrixDSparse *m1,const TMatrixDSparse *m2,const TMatrixDSparse *dsys)
 {
@@ -916,8 +1012,8 @@ TMatrixDSparse *TUnfoldSys::PrepareCorrEmat
    // delta_m =
    //   sum{i,j}   {
    //      ((*m1)(m,j) * (*fVYAx)(i) - (*m2)(m,i) * (*fX)(j))*dsys(i,j) }
-   //   =    sum_j (*m1)(m,j)  sum_i dsys(i,j) * (*fVYAx)(i)
-   //     -  sum_i (*m2)(m,i)  sum_j dsys(i,j) * (*fX)(j)
+   //   =    \sum_j (*m1)(m,j)  \sum_i dsys(i,j) * (*fVYAx)(i)
+   //     -  \sum_i (*m2)(m,i)  \sum_j dsys(i,j) * (*fX)(j)
 
    TMatrixDSparse *dsysT_VYAx = MultiplyMSparseTranspMSparse(dsys,GetDXDAZ(0));
    TMatrixDSparse *delta =  MultiplyMSparseMSparse(m1,dsysT_VYAx);
@@ -930,6 +1026,13 @@ TMatrixDSparse *TUnfoldSys::PrepareCorrEmat
    return delta;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Specify an uncertainty on tau.
+///
+/// \param[in] delta_tau new uncertainty on tau
+///
+/// The default is to have no uncertyainty on tau.
+
 void TUnfoldSys::SetTauError(Double_t delta_tau)
 {
    // set uncertainty on tau
@@ -937,13 +1040,23 @@ void TUnfoldSys::SetTauError(Double_t delta_tau)
    DeleteMatrix(&fDeltaSysTau);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Correlated one-sigma shifts correspinding to a given systematic uncertainty.
+///
+/// \param[out] hist_delta histogram to store shifts
+/// \param[in] name  identifier of the background source
+/// \param[in] binMap (default=0) remapping of histogram bins
+///
+/// returns true if the error source was found.
+///
+/// This method returns the shifts of the unfolding result induced by
+/// varying the identified systematic source by one sigma.
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+
 Bool_t TUnfoldSys::GetDeltaSysSource(TH1 *hist_delta,const char *name,
                                    const Int_t *binMap)
 {
-   // calculate systematic shift from a given source
-   //    ematrix: output
-   //    source: name of the error source
-   //    binMap: see method GetEmatrix()
    PrepareSysError();
    const TPair *named_emat=(const TPair *)fDeltaCorrX->FindObject(name);
    const TMatrixDSparse *delta=0;
@@ -954,14 +1067,23 @@ Bool_t TUnfoldSys::GetDeltaSysSource(TH1 *hist_delta,const char *name,
    return delta !=0;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Correlated one-sigma shifts from background normalisation uncertainty.
+///
+/// \param[out] hist_delta histogram to store shifts
+/// \param[in] source  identifier of the background source
+/// \param[in] binMap (default=0) remapping of histogram bins
+///
+/// returns true if the background source was found.
+///
+/// This method returns the shifts of the unfolding result induced by
+/// varying the normalisation of the identified background by one sigma.
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+
 Bool_t TUnfoldSys::GetDeltaSysBackgroundScale
 (TH1 *hist_delta,const char *source,const Int_t *binMap)
 {
-   // get correlated shift induced by a background source
-   //   delta: output shift vector histogram
-   //   source: name of background source
-   //   binMap: see method GetEmatrix()
-   //   see PrepareSysError()
    PrepareSysError();
    const TPair *named_err=(const TPair *)fBgrErrScaleIn->FindObject(source);
    TMatrixDSparse *dx=0;
@@ -977,6 +1099,20 @@ Bool_t TUnfoldSys::GetDeltaSysBackgroundScale
    return kFALSE;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Correlated one-sigma shifts from shifting tau.
+///
+/// \param[out] hist_delta histogram to store shifts
+/// \param[in] source  identifier of the background source
+/// \param[in] binMap (default=0) remapping of histogram bins
+///
+/// returns true if the background source was found.
+///
+/// This method returns the shifts of the unfolding result induced by
+/// varying the normalisation of the identified background by one sigma.
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+
 Bool_t TUnfoldSys::GetDeltaSysTau(TH1 *hist_delta,const Int_t *binMap)
 {
    // calculate systematic shift from tau variation
@@ -987,14 +1123,26 @@ Bool_t TUnfoldSys::GetDeltaSysTau(TH1 *hist_delta,const Int_t *binMap)
    return fDeltaSysTau !=0;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Covariance contribution from a systematic variation of the
+/// response matrix.
+///
+/// \param[inout] ematrix covariance matrix histogram
+/// \param[in] name identifier of the systematic variation
+/// \param[in] binMap (default=0) remapping of histogram bins
+/// \param[in] clearEmat (default=true) if true, clear the histogram
+/// prior to adding the covariance matrix contribution
+///
+/// Returns the covariance matrix contribution from shifting the given
+/// uncertainty source within one sigma
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+/// The flag <b>clearEmat</b> may be used to add covariance matrices from
+/// several uncertainty sources.
+
 void TUnfoldSys::GetEmatrixSysSource
 (TH2 *ematrix,const char *name,const Int_t *binMap,Bool_t clearEmat)
 {
-   // calculate systematic shift from a given source
-   //    ematrix: output
-   //    source: name of the error source
-   //    binMap: see method GetEmatrix()
-   //    clearEmat: set kTRUE to clear the histogram prior to adding the errors
    PrepareSysError();
    const TPair *named_emat=(const TPair *)fDeltaCorrX->FindObject(name);
    TMatrixDSparse *emat=0;
@@ -1006,14 +1154,26 @@ void TUnfoldSys::GetEmatrixSysSource
    DeleteMatrix(&emat);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Covariance contribution from background normalisation uncertainty.
+///
+/// \param[inout] ematrix output histogram
+/// \param[in] source identifier of the background source
+/// \param[in] binMap (default=0) remapping of histogram bins
+/// \param[in] clearEmat (default=true) if true, clear the histogram
+/// prior to adding the covariance matrix contribution
+///
+/// this method returns the uncertainties on the unfolding result
+/// arising from the background source <b>source</b> and its normalisation
+/// uncertainty. See method SubtractBackground() how to set the normalisation uncertainty
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+/// The flag <b>clearEmat</b> may be used to add covariance matrices from
+/// several uncertainty sources.
+
 void TUnfoldSys::GetEmatrixSysBackgroundScale
 (TH2 *ematrix,const char *name,const Int_t *binMap,Bool_t clearEmat)
 {
-   // calculate systematic shift from a given background scale error
-   //    ematrix: output
-   //    source: name of the error source
-   //    binMap: see method GetEmatrix()
-   //    clearEmat: set kTRUE to clear the histogram prior to adding the errors
    PrepareSysError();
    const TPair *named_err=(const TPair *)fBgrErrScaleIn->FindObject(name);
    TMatrixDSparse *emat=0;
@@ -1027,13 +1187,30 @@ void TUnfoldSys::GetEmatrixSysBackgroundScale
    DeleteMatrix(&emat);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Covariance matrix contribution from error on regularisation
+/// parameter.
+///
+/// \param[inout] ematrix output histogram
+/// \param[in] binMap (default=0) remapping of histogram bins
+/// \param[in] clearEmat (default=true) if true, clear the histogram
+///
+/// this method returns the covariance contributions to the unfolding result
+/// from the assigned uncertainty on the parameter tau, see method
+/// SetTauError().
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+/// The flag <b>clearEmat</b> may be used to add covariance matrices from
+/// several uncertainty sources.
+///
+/// Calculate error matrix from error in regularisation parameter
+///  - ematrix: output
+///  - binMap: see method GetEmatrix()
+///  - clearEmat: set kTRUE to clear the histogram prior to adding the errors
+
 void TUnfoldSys::GetEmatrixSysTau
 (TH2 *ematrix,const Int_t *binMap,Bool_t clearEmat)
 {
-   // calculate error matrix from error in regularisation parameter
-   //    ematrix: output
-   //    binMap: see method GetEmatrix()
-   //    clearEmat: set kTRUE to clear the histogram prior to adding the errors
    PrepareSysError();
    TMatrixDSparse *emat=0;
    if(fDeltaSysTau) {
@@ -1043,25 +1220,46 @@ void TUnfoldSys::GetEmatrixSysTau
    DeleteMatrix(&emat);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Covariance matrix contribution from input measurement uncertainties.
+///
+/// \param[inout] ematrix output histogram
+/// \param[in] binMap (default=0) remapping of histogram bins
+/// \param[in] clearEmat (default=true) if true, clear the histogram
+///
+/// this method returns the covariance contributions to the unfolding result
+/// from the uncertainties or covariance of the input
+/// data. In many cases, these are the "statistical uncertainties".
+///
+/// The array <b>binMap</b> is explained with the method GetOutput().
+/// The flag <b>clearEmat</b> may be used to add covariance matrices from
+/// several uncertainty sources.
+
 void TUnfoldSys::GetEmatrixInput
 (TH2 *ematrix,const Int_t *binMap,Bool_t clearEmat)
 {
-   // calculate error matrix from error in input vector alone
-   //    ematrix: output
-   //    binMap: see method GetEmatrix()
-   //    clearEmat: set kTRUE to clear the histogram prior to adding the errors
    GetEmatrixFromVyy(fVyyData,ematrix,binMap,clearEmat);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Covariance contribution from background uncorrelated  uncertainty.
+///
+/// \param[in] ematrix output histogram
+/// \param[in] source identifier of the background source
+/// \param[in] binMap (default=0) remapping of histogram bins
+/// \param[in] clearEmat (default=true) if true, clear the histogram
+///
+/// this method returns the covariance contributions to the unfolding result
+/// arising from the background source <b>source</b> and the uncorrelated
+/// (background histogram uncertainties). Also see method SubtractBackground()
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+/// The flag <b>clearEmat</b> may be used to add covariance matrices from
+/// several uncertainty sources.
+
 void TUnfoldSys::GetEmatrixSysBackgroundUncorr
 (TH2 *ematrix,const char *source,const Int_t *binMap,Bool_t clearEmat)
 {
-   // calculate error matrix contribution originating from uncorrelated errors
-   // of one background source
-   //    ematrix: output
-   //    source: name of the error source
-   //    binMap: see method GetEmatrix()
-   //    clearEmat: set kTRUE to clear the histogram prior to adding the errors
    const TPair *named_err=(const TPair *)fBgrErrUncorrInSq->FindObject(source);
    TMatrixDSparse *emat=0;
    if(named_err) {
@@ -1072,14 +1270,24 @@ void TUnfoldSys::GetEmatrixSysBackgroundUncorr
    DeleteMatrix(&emat);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Propagate an error matrix on the input vector to the unfolding result.
+///
+/// \param[in] vyy input error matrix
+/// \param[inout] ematrix histogram to be updated
+/// \param[in] binMap  mapping of histogram bins
+/// \param[in] clearEmat if set, clear histogram before adding this
+/// covariance contribution
+///
+/// propagate error matrix vyy to the result
+///  - vyy: error matrix on input data fY
+///  - ematrix: output
+///  - binMap: see method GetEmatrix()
+///  - clearEmat: set kTRUE to clear the histogram prior to adding the errors
+
 void TUnfoldSys::GetEmatrixFromVyy
 (const TMatrixDSparse *vyy,TH2 *ematrix,const Int_t *binMap,Bool_t clearEmat)
 {
-   // propagate error matrix vyy to the result
-   //    vyy: error matrix on input data fY
-   //    ematrix: output
-   //    binMap: see method GetEmatrix()
-   //    clearEmat: set kTRUE to clear the histogram prior to adding the errors
    PrepareSysError();
    TMatrixDSparse *em=0;
    if(vyy) {
@@ -1091,11 +1299,20 @@ void TUnfoldSys::GetEmatrixFromVyy
    DeleteMatrix(&em);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get total error matrix, summing up all contributions.
+///
+/// \param[out] ematrix histogram which will be filled
+/// \param[in] binMap (default=0) remapping of histogram bins
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+///
+/// get total error including statistical error
+///  - ematrix: output
+///  - binMap: see method GetEmatrix()
+
 void TUnfoldSys::GetEmatrixTotal(TH2 *ematrix,const Int_t *binMap)
 {
-   // get total error including statistical error
-   //    ematrix: output
-   //    binMap: see method GetEmatrix()
    GetEmatrix(ematrix,binMap);  // (stat)+(d)+(e)
    GetEmatrixSysUncorr(ematrix,binMap,kFALSE); // (a)
    TMapIter sysErrPtr(fDeltaCorrX);
@@ -1109,6 +1326,9 @@ void TUnfoldSys::GetEmatrixTotal(TH2 *ematrix,const Int_t *binMap)
    GetEmatrixSysTau(ematrix,binMap,kFALSE); // (c)
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Determine total error matrix on the vector Ax.
+
 TMatrixDSparse *TUnfoldSys::GetSummedErrorMatrixYY(void)
 {
    PrepareSysError();
@@ -1117,7 +1337,9 @@ TMatrixDSparse *TUnfoldSys::GetSummedErrorMatrixYY(void)
    TMatrixDSparse *emat_sum=new TMatrixDSparse(*fVyy);
 
    // uncorrelated systematic error
-   AddMSparse(emat_sum,1.0,fEmatUncorrAx);
+   if(fEmatUncorrAx) {
+      AddMSparse(emat_sum,1.0,fEmatUncorrAx);
+   }
    TMapIter sysErrPtr(fDeltaCorrAx);
    const TObject *key;
 
@@ -1147,6 +1369,9 @@ TMatrixDSparse *TUnfoldSys::GetSummedErrorMatrixYY(void)
    return emat_sum;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Determine total error matrix on the vector x.
+
 TMatrixDSparse *TUnfoldSys::GetSummedErrorMatrixXX(void)
 {
    PrepareSysError();
@@ -1155,7 +1380,9 @@ TMatrixDSparse *TUnfoldSys::GetSummedErrorMatrixXX(void)
    TMatrixDSparse *emat_sum=new TMatrixDSparse(*GetVxx());
 
    // uncorrelated systematic error
-   AddMSparse(emat_sum,1.0,fEmatUncorrX);
+   if(fEmatUncorrX) {
+      AddMSparse(emat_sum,1.0,fEmatUncorrX);
+   }
    TMapIter sysErrPtr(fDeltaCorrX);
    const TObject *key;
 
@@ -1184,9 +1411,11 @@ TMatrixDSparse *TUnfoldSys::GetSummedErrorMatrixXX(void)
 }
 
 
+////////////////////////////////////////////////////////////////////////////////
+/// Calculate total chi**2 including all systematic errors.
+
 Double_t TUnfoldSys::GetChi2Sys(void)
 {
-   // calculate total chi**2 including systematic errors
 
    TMatrixDSparse *emat_sum=GetSummedErrorMatrixYY();
 
@@ -1208,14 +1437,28 @@ Double_t TUnfoldSys::GetChi2Sys(void)
    return r;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Get global correlatiocn coefficients, summing up all contributions.
+///
+/// \param[out] rhoi histogram which will be filled
+/// \param[in] binMap (default=0) remapping of histogram bins
+/// \param[out] invEmat (default=0) inverse of error matrix
+///
+/// return the global correlation coefficients, including all error
+/// sources. If <b>invEmat</b> is nonzero, the inverse of the error
+/// matrix is returned in that histogram
+///
+/// the array <b>binMap</b> is explained with the method GetOutput().
+///
+/// get global correlation coefficients including systematic,statistical,background,tau errors
+///  - rhoi: output histogram
+///  - binMap: for each global bin, indicate in which histogram bin
+///            to store its content
+///  - invEmat: output histogram for inverse of error matrix
+///              (pointer may zero if inverse is not requested)
+
 void TUnfoldSys::GetRhoItotal(TH1 *rhoi,const Int_t *binMap,TH2 *invEmat)
 {
-   // get global correlation coefficients including systematic,statistical,background,tau errors
-   //    rhoi: output histogram
-   //    binMap: for each global bin, indicate in which histogram bin
-   //            to store its content
-   //    invEmat: output histogram for inverse of error matrix
-   //              (pointer may zero if inverse is not requested)
    ClearHistogram(rhoi,-1.);
    TMatrixDSparse *emat_sum=GetSummedErrorMatrixXX();
    GetRhoIFromMatrix(rhoi,emat_sum,binMap,invEmat);
@@ -1223,13 +1466,22 @@ void TUnfoldSys::GetRhoItotal(TH1 *rhoi,const Int_t *binMap,TH2 *invEmat)
    DeleteMatrix(&emat_sum);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Scale columns of a matrix by the corresponding rows of a vector.
+///
+/// \param[inout] m matrix
+/// \param[in] v vector
+///
+/// the entries m<sub>ij</sub> are multiplied by v<sub>j</sub>.
+///
+/// scale columns of m by the corresponding rows of v
+/// input:
+///  - m:  pointer to sparse matrix of dimension NxM
+///  - v:  pointer to matrix of dimension Mx1
+
 void TUnfoldSys::ScaleColumnsByVector
 (TMatrixDSparse *m,const TMatrixTBase<Double_t> *v) const
 {
-   // scale columns of m by the corresponding rows of v
-   // input:
-   //   m:  pointer to sparse matrix of dimension NxM
-   //   v:  pointer to matrix of dimension Mx1
    if((m->GetNcols() != v->GetNrows())||(v->GetNcols()!=1)) {
       Fatal("ScaleColumnsByVector error",
             "matrix cols/vector rows %d!=%d OR vector cols %d !=1\n",
@@ -1255,19 +1507,34 @@ void TUnfoldSys::ScaleColumnsByVector
       }
    } else {
       for(Int_t i=0;i<m->GetNrows();i++) {
-         for(Int_t index=rows_m[i];index<rows_m[i+1];index++) {
-            data_m[index] *= (*v)(cols_m[index],0);
+         for(Int_t index_m=rows_m[i];index_m<rows_m[i+1];index_m++) {
+            Int_t j=cols_m[index_m];
+            data_m[index_m] *= (*v)(j,0);
          }
       }
    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Map delta to hist_delta, possibly summing up bins.
+///
+/// \param[out] hist_delta result histogram
+/// \param[in] delta vector to be mapped to the histogram
+/// \param[in] binMap  mapping of histogram bins
+///
+/// groups of bins of <b>delta</b> are mapped to bins of
+/// <b>hist_delta</b>. The histogram contents are set to the sum over
+/// the group of bins. The histogram errors are reset to zero.
+///
+/// The array <b>binMap</b> is explained with the method GetOutput()
+///
+/// sum over bins of *delta, as defined in binMap,fXToHist
+///  - hist_delta: histogram to return summed vector
+///  - delta: vector to sum and remap
+
 void TUnfoldSys::VectorMapToHist
 (TH1 *hist_delta,const TMatrixDSparse *delta,const Int_t *binMap)
 {
-   // sum over bins of *delta, as defined in binMap,fXToHist
-   //   hist_delta: histogram to return summed vector
-   //   delta: vector to sum and remap
    Int_t nbin=hist_delta->GetNbinsX();
    Double_t *c=new Double_t[nbin+2];
    for(Int_t i=0;i<nbin+2;i++) {
@@ -1294,3 +1561,33 @@ void TUnfoldSys::VectorMapToHist
    }
    delete[] c;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get a new list of all systematic uuncertainty sources.
+///
+/// The user is responsible for deleting the list
+/// get list of names of systematic sources
+
+TSortedList *TUnfoldSys::GetSysSources(void) const {
+   TSortedList *r=new TSortedList();
+   TMapIter i(fSysIn);
+   for(const TObject *key=i.Next();key;key=i.Next()) {
+      r->Add(((TObjString *)key)->Clone());
+   }
+   return r;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Get a new list of all background sources.
+///
+/// The user is responsible for deleting the list
+/// get list of name of background sources
+
+TSortedList *TUnfoldSys::GetBgrSources(void) const {
+   TSortedList *r=new TSortedList();
+   TMapIter i(fBgrIn);
+   for(const TObject *key=i.Next();key;key=i.Next()) {
+      r->Add(((TObjString *)key)->Clone());
+   }
+   return r;
+}