// Author: Stefan Schmitt // DESY, 13/10/08 // 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 // Version 16.0, some cleanup, more getter functions, query version number // Version 15, simplified L-curve scan, new tau definition, new eror calc. // Version 14, with changes in TUnfoldSys.cxx // Version 13, new methods for derived classes // Version 12, with support for preconditioned matrix inversion // Version 11, regularisation methods have return values // Version 10, with bug-fix in TUnfold.cxx // Version 9, implements method for optimized inversion of sparse matrix // Version 8, replace all TMatrixSparse matrix operations by private code // Version 7, fix problem with TMatrixDSparse,TMatrixD multiplication // Version 6, completely remove definition of class XY // Version 5, move definition of class XY from TUnfold.C to this file // Version 4, with bug-fix in TUnfold.C // Version 3, with bug-fix in TUnfold.C // Version 2, with changed ScanLcurve() arguments // Version 1, added ScanLcurve() method // Version 0, stable version of basic unfolding algorithm #ifndef ROOT_TUnfold #define ROOT_TUnfold ////////////////////////////////////////////////////////////////////////// // // // // // TUnfold provides functionality to correct data // // for migration effects. // // // // Citation: S.Schmitt, JINST 7 (2012) T10003 [arXiv:1205.6201] // // // // // // TUnfold solves the inverse problem // // // // T -1 2 T // // chi**2 = (y-Ax) Vyy (y-Ax) + tau (L(x-x0)) L(x-x0) // // // // Monte Carlo input // // y: vector of measured quantities (dimension ny) // // Vyy: covariance matrix for y (dimension ny x ny) // // A: migration matrix (dimension ny x nx) // // x: unknown underlying distribution (dimension nx) // // Regularisation // // tau: parameter, defining the regularisation strength // // L: matrix of regularisation conditions (dimension nl x nx) // // x0: underlying distribution bias // // // // where chi**2 is minimized as a function of x // // // // 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 // // dim(x) should not exceed O(100) // // dim(y) should not exceed O(500) // // // ////////////////////////////////////////////////////////////////////////// /* 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 . */ #include #include #include #include #include #include #include #include #define TUnfold_VERSION "V17.6" #define TUnfold_CLASS_VERSION 17 class TUnfold : public TObject { private: void InitTUnfold(void); // initialize all data members public: /// type of extra constraint enum EConstraint { /// 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 }; /// 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: /// 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: /// 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-1 TMatrixDSparse *fVxxInv; /// inverse of the input covariance matrix Vyy-1 TMatrixDSparse *fVyyInv; /// result x folded back A*x TMatrixDSparse *fAx; /// chi**2 contribution from (y-Ax)Vyy-1(y-Ax) Double_t fChi2A; /// chi**2 contribution from (x-s*x0)TLTL(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: // Int_t IsNotSymmetric(TMatrixDSparse const &m) const; virtual Double_t DoUnfold(void); // the unfolding algorithm virtual void ClearResults(void); // clear all results void ClearHistogram(TH1 *h,Double_t x=0.) const; virtual TString GetOutputBinName(Int_t iBinX) const; // name a bin TMatrixDSparse *MultiplyMSparseM(const TMatrixDSparse *a,const TMatrixD *b) const; // multiply sparse and non-sparse matrix TMatrixDSparse *MultiplyMSparseMSparse(const TMatrixDSparse *a,const TMatrixDSparse *b) const; // multiply sparse and sparse matrix TMatrixDSparse *MultiplyMSparseTranspMSparse(const TMatrixDSparse *a,const TMatrixDSparse *b) const; // multiply transposed sparse and sparse matrix TMatrixDSparse *MultiplyMSparseMSparseTranspVector (const TMatrixDSparse *m1,const TMatrixDSparse *m2, const TMatrixTBase *v) const; // calculate M_ij = sum_k [m1_ik*m2_jk*v[k] ]. the pointer v may be zero (means no scaling). 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(); } /// 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(); } /// 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-1, 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 /// 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: 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); // 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, TSpline **logTauCurvature=0); // 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 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; // 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 χ2A contribution determined in recent unfolding inline Double_t GetChi2A(void) const { return fChi2A; } Double_t GetChi2L(void) const; // get χ2L 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 /// 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 // 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 }; #endif