From e49b0c3608656ccbd8acb47cc2ac1e7ccfec0b5f Mon Sep 17 00:00:00 2001 From: Vanya Belyaev Date: Tue, 21 Jan 2025 12:00:57 +0100 Subject: [PATCH] fixes... --- ostap/fitting/adjust.py | 475 ++++++++---------------------------- ostap/fitting/fit1d.py | 2 +- ostap/fitting/fithelpers.py | 45 ++-- ostap/fitting/pdf_ops.py | 10 +- ostap/fitting/pdfbasic.py | 115 ++++++--- ostap/fitting/variables.py | 71 ++++-- 6 files changed, 264 insertions(+), 454 deletions(-) diff --git a/ostap/fitting/adjust.py b/ostap/fitting/adjust.py index 963b2b67..95d20432 100644 --- a/ostap/fitting/adjust.py +++ b/ostap/fitting/adjust.py @@ -12,215 +12,20 @@ __author__ = "Vanya BELYAEV Ivan.Belyaev@itep.ru" __date__ = "2011-07-25" __all__ = ( - ## - 'Adjust1D' , ## helper class to adjust 1D-pdf - 'Adjust2D' , ## helper class to adjust 2D-pdf - 'Adjust3D' , ## helper class to adjust 3D-pdf ## 'Adjust1D_pdf' , ## make adjusted 1D-pdf 'Adjust2D_pdf' , ## make adjusted 2D-pdf 'Adjust3D_pdf' , ## make adjusted 3D-pdf ) # ============================================================================= -from ostap.fitting.fithelpers import VarMaker -from ostap.fitting.pdfbasic import ( PDF1 , Generic1D_pdf , Flat1D , - PDF2 , Generic2D_pdf , Flat2D , - PDF3 , Generic3D_pdf , Flat3D ) -import ROOT +from ostap.core.ostap_types import num_types +from ostap.fitting.pdfbasic import ( Sum1D , Flat1D , + Sum2D , Flat2D , + Sum3D , Flat3D ) # ============================================================================= from ostap.logger.logger import getLogger if '__main__' == __name__ : logger = getLogger ( 'ostap.fitting.adjust' ) else : logger = getLogger ( __name__ ) -# ============================================================================= -## @class Adjust1D -# simple class to adjust certain PDF to avoid zeroes -class Adjust1D(VarMaker) : - """ Simple class to ``adjust'' certain PDF to avoid zeroes - - a small flat component is added and the compound PDF is constructed - """ - ## constructor - def __init__ ( self , - name , - xvar , - pdf , - fraction = 1.e-5 ) : - - assert isinstance ( pdf , ROOT.RooAbsPdf ) , "``pdf'' must be ROOT.RooAbsPdf" - assert isinstance ( xvar , ROOT.RooAbsReal ) , "``xvar'' must be ROOT.RooAbsReal" - - self.name = name - self.__old_pdf = pdf - - from ostap.fitting.basic import Flat1D - self.__flat = Flat1D ( xvar , name = 'flat_' + name ) - self.__frac = self.make_var ( fraction , 'fracA_%s' % name , - 'small fraction of flat component %s' % name , - fraction , 1.e-5 , 0 , 1 ) - - self.__alist1 = ROOT.RooArgList ( self.__flat.pdf , self.__old_pdf ) - self.__alist2 = ROOT.RooArgList ( self.__frac ) - # - ## final PDF - # - self.__pdf = ROOT.RooAddPdf ( - self.roo_name ( "adjust_" ) , - "Adjust %s" % self.name , - self.__alist1 , - self.__alist2 ) - - @property - def fraction( self ) : - """``fraction''-parameter: the fraction of flat ``background'' added""" - return self.__frac - @fraction.setter - def fraction( self , value ) : - value = float ( value ) - assert 0 < value < 1 , 'Fraction must be between 0 and 1' - self.__frac.setVal ( value ) - - @property - def flat ( self ) : - """new artificial ``flat'' component for the Pdf""" - return self.__flat - - @property - def pdf ( self ) : - """``new'' (adjusted) Pdf""" - return self.__pdf - - @property - def old_pdf ( self ) : - """``old'' (non-adjusted) Pdf""" - return self.__old_pdf - -# ============================================================================= -## @class Adjust2D -# simple class to adjust certain PDF to avoid zeroes -class Adjust2D(VarMaker) : - """ Simple class to ``adjust'' certain PDF to avoid zeroes - - a small flat component is added and the compound PDF is constructed - """ - ## constructor - def __init__ ( self , - name , - xvar , - yvar , - pdf , - fraction = 1.e-5 ) : - - assert isinstance ( pdf , ROOT.RooAbsPdf ) , "``pdf'' must be ROOT.RooAbsPdf" - assert isinstance ( xvar , ROOT.RooAbsReal ) , "``xvar'' must be ROOT.RooAbsReal" - assert isinstance ( yvar , ROOT.RooAbsReal ) , "``yvar'' must be ROOT.RooAbsReal" - - self.name = name - self.__old_pdf = pdf - - self.__flat = Flat2D ( xvar , yvar , name = 'flat_' + name ) - self.__frac = self.make_var ( fraction , 'fracA_%s' % name , - 'small fraction of flat component %s' % name , - fraction , 1.e-5 , 0 , 1 ) - - self.__alist1 = ROOT.RooArgList ( self.__flat.pdf , self.__old_pdf ) - self.__alist2 = ROOT.RooArgList ( self.__frac ) - # - ## final PDF - # - self.__pdf = ROOT.RooAddPdf ( - self.roo_name ( "adjust2_" ) , - "Adjust 2D %s" % self.name , - self.__alist1 , - self.__alist2 ) - - @property - def fraction( self ) : - """``fraction''-parameter: the fraction of flat ``background'' added""" - return self.__frac - @fraction.setter - def fraction( self , value ) : - value = float ( value ) - assert 0 < value < 1 , 'Fraction must be between 0 and 1' - self.__frac.setVal ( value ) - - @property - def flat ( self ) : - """new artificial ``flat'' component for the Pdf""" - return self.__flat - - @property - def pdf ( self ) : - """``new'' (adjusted) Pdf""" - return self.__pdf - - @property - def old_pdf ( self ) : - """``old'' (non-adjusted) Pdf""" - return self.__old_pdf - -# ============================================================================= -## @class Adjust3D -# simple class to adjust certain PDF to avoid zeroes -class Adjust3D(VarMaker) : - """ Simple class to ``adjust'' certain PDF to avoid zeroes - - a small flat component is added and the compound PDF is constructed - """ - ## constructor - def __init__ ( self , - name , - xvar , - yvar , - zvar , - pdf , - fraction = 1.e-5 ) : - - assert isinstance ( pdf , ROOT.RooAbsPdf ) , "``pdf'' must be ROOT.RooAbsPdf" - assert isinstance ( xvar , ROOT.RooAbsReal ) , "``xvar'' must be ROOT.RooAbsReal" - assert isinstance ( yvar , ROOT.RooAbsReal ) , "``yvar'' must be ROOT.RooAbsReal" - assert isinstance ( zvar , ROOT.RooAbsReal ) , "``zvar'' must be ROOT.RooAbsReal" - - self.name = name - self.__old_pdf = pdf - - self.__flat = Flat3D ( xvar , yvar , xvar , name = 'flat_' + name ) - self.__frac = self.make_var ( fraction , 'fracA_%s' % name , - 'small fraction of flat component %s' % name , - fraction , 1.e-5 , 0 , 1 ) - - self.__alist1 = ROOT.RooArgList ( self.__flat.pdf , self.__old_pdf ) - self.__alist2 = ROOT.RooArgList ( self.__frac ) - # - ## final PDF - # - self.__pdf = ROOT.RooAddPdf ( - self.roo_name ( "adjust3_" ) , - "Adjust 3D %s" % self.name , - self.__alist1 , - self.__alist2 ) - - @property - def fraction( self ) : - """``fraction''-parameter: the fraction of flat ``background'' added""" - return self.__frac - @fraction.setter - def fraction( self , value ) : - value = float ( value ) - assert 0 < value < 1 , 'Fraction must be between 0 and 1' - self.__frac.setVal ( value ) - - @property - def flat ( self ) : - """new artificial ``flat'' component for the Pdf""" - return self.__flat - - @property - def pdf ( self ) : - """``new'' (adjusted) Pdf""" - return self.__pdf - - @property - def old_pdf ( self ) : - """``old'' (non-adjusted) Pdf""" - return self.__old_pdf - # ============================================================================= ## @class Adjust1D_pdf # Create adjusted PDF @@ -230,7 +35,7 @@ def old_pdf ( self ) : # @endcode # @see Adjust1D # @author Vanya BELYAEV Ivan.Belyaev@itep.ru -class Adjust1D_pdf(PDF1) : +class Adjust1D_pdf(Sum1D) : """ Simple class to ``adjust'' certain 1D-PDF to avoid zeroes - a small flat component is added and the compound 1D-PDF is constructed @@ -242,67 +47,45 @@ def __init__ ( self , pdf , xvar = None , fraction = 1.e-5 , - name = '' ) : - - if isinstance ( pdf , PDF ) : - self.__old_pdf = pdf - if xvar and not xvar is pdf.xvar : self.warning("mismatch in xvar?") - xvar = pdf.xvar - elif insinstance ( pdf , ROOT.RooAbsPdf ) and xvar : - self.__old_pdf = Generic1D_pdf ( pdf , xvar = xvar ) - else : - raise TypeError ("Unknown type of pdf %s/%s" % ( pdf , type ( pdf ) ) ) - - assert isinstance ( xvar , ROOT.RooAbsReal ) , "``xvar'' must be ROOT.RooAbsReal" - - - name = name if name else self.generate_name ( 'Adjust1D_' + self.old_pdf.name ) - - - ## initialize the base - PDF1.__init__ ( self , name = name , xvar = xvar ) - - em = self.old_pdf.pdf.extendMode() - if 1 == em : self.warning("PDF ``canBeExtended''") - elif 2 == em : self.warning("PDF ``mustBeExtended''") - - ## make the real adjustment - self.__adjustment = Adjust1D ( name , - pdf = self.old_pdf.pdf , - xvar = xvar , - fraction = fraction ) - - self.pdf = self.adjustment.pdf - self.pdf.fixCoefNormalization ( self.vars ) ## VB: added 10/10/2024 to suppress warnings + name = '' , + prefix = 'f' , ## prefix for fraction names + suffix = '' , ## suffix for fraction names + fix_norm = False ) : + + pdf1 , xvar = self.make_PDF1 ( pdf , xvar ) + flat = Flat1D ( xvar = xvar ) + Sum1D.__init__ ( self , [ flat , pdf ] , + name = name , + fraction = fraction , + prefix = prefix , + suffix = suffix , + fix_norm = fix_norm ) + + self.F.fix() self.config = { - 'xvar' : self.xvar , - 'name' : self.name , - 'pdf' : self.old_pdf , - 'fraction' : self.fraction - } - - @property - def adjustment ( self ) : - """``adjustment'' : the adjustment object""" - return self.__adjustment - - @property - def fraction( self ) : - """``fraction''-parameter: the fraction of flat ``background'' added""" - return self.adjustment.fraction - @fraction.setter - def fraction( self , value ) : - self.adjustment.fraction = value + 'xvar' : self.xvar , + 'name' : self.name , + 'pdf' : self.old_pdf , + 'fraction' : self.fraction , + 'prefix' : self.prefix , + 'suffix' : self.suffix , + 'fix_norm' : self.fix_norm + } @property def old_pdf ( self ) : """``old'' (non-adjusted) PDF""" - return self.__old_pdf + return self.pdf2 + + @property + def flat ( self ) : + """`flat` : get flat component""" + return self.pdf1 ## redirect any other attributes to original PDF def __getattr__ ( self , attr ) : - """Get all extra attributes from the original PDF""" + """ Get all extra attributes from the original PDF""" opdf = self.old_pdf return getattr ( opdf , attr ) @@ -315,12 +98,12 @@ def __getattr__ ( self , attr ) : # @endcode # @see Adjust2D # @author Vanya BELYAEV Ivan.Belyaev@itep.ru -class Adjust2D_pdf(PDF2) : +class Adjust2D_pdf(Sum2D) : """ Simple class to ``adjust'' certain 1D-PDF to avoid zeroes - a small flat component is added and the compound 2D-PDF is constructed >>> opdf = ... - >>> apdf = Adjust1D_pdf ( pdf = opdf , fraction = 1e-5 ) + >>> apdf = Adjust2D_pdf ( pdf = opdf , fraction = 1e-5 ) """ ## constructor def __init__ ( self , @@ -328,70 +111,46 @@ def __init__ ( self , xvar = None , yvar = None , fraction = 1.e-5 , - name = '' ) : - - if isinstance ( pdf , PDF2 ) : - self.__old_pdf = pdf - if xvar and not xvar is pdf.xvar : self.warning("mismatch in xvar?") - if yvar and not yvar is pdf.yvar : self.warning("mismatch in yvar?") - xvar = pdf.xvar - yvar = pdf.yvar - elif insinstance ( pdf , ROOT.RooAbsPdf ) and xvar and yvar : - self.__old_pdf = Generic2D_pdf ( pdf , xvar = xvar , yvar = yvar) - else : - raise TypeError ("Unknown type of pdf %s/%s" % ( pdf , type ( pdf ) ) ) - - assert isinstance ( xvar , ROOT.RooAbsReal ) , "``xvar'' must be ROOT.RooAbsReal" - assert isinstance ( yvar , ROOT.RooAbsReal ) , "``yvar'' must be ROOT.RooAbsReal" - - name = name if name else self.generate_name ( 'Adjust2D_' + self.old_pdf.name ) - - ## initialize the base - PDF2.__init__ ( self , name = name , xvar = xvar , yvar = yvar ) - - em = self.old_pdf.pdf.extendMode() - if 1 == em : self.warning("PDF ``canBeExtended''") - elif 2 == em : self.warning("PDF ``mustBeExtended''") - - ## make the real adjustment - self.__adjustment = Adjust2D ( name , - pdf = self.old_pdf.pdf , - xvar = xvar , - yvar = yvar , - fraction = fraction ) - - self.pdf = self.adjustment.pdf - self.pdf.fixCoefNormalization ( self.vars ) ## VB: added 10/10/2024 to suppress warnings + name = '' , + prefix = 'f' , ## prefix for fraction names + suffix = '' , ## suffix for fraction names + fix_norm = False ) : + + pdf1 , xvar , yvar = self.make_PDF2 ( pdf , xvar , yvar ) + flat = Flat2D ( xvar = xvar , yvar = yvar ) + Sum2D.__init__ ( self , [ flat , pdf ] , + name = name , + fraction = fraction , + prefix = prefix , + suffix = suffix , + fix_norm = fix_norm ) + + self.F.fix() self.config = { - 'xvar' : self.xvar , - 'yvar' : self.yvar , - 'name' : self.name , - 'pdf' : self.old_pdf , - 'fraction' : self.fraction - } - - @property - def adjustment ( self ) : - """``adjustment'' : the adjustment object""" - return self.__adjustment + 'xvar' : self.xvar , + 'yvar' : self.yvar , + 'name' : self.name , + 'pdf' : self.old_pdf , + 'fraction' : self.fraction , + 'prefix' : self.prefix , + 'suffix' : self.suffix , + 'fix_norm' : self.fix_norm + } + + @property + def flat ( self ) : + """`flat` : get flat component""" + return self.pdf2 - @property - def fraction( self ) : - """``fraction''-parameter: the fraction of flat ``background'' added""" - return self.adjustment.fraction - @fraction.setter - def fraction( self , value ) : - self.adjustment.fraction = value - @property def old_pdf ( self ) : """``old'' (non-adjusted) PDF""" - return self.__old_pdf - + return self.pdf1 + ## redirect any other attributes to original PDF def __getattr__ ( self , attr ) : - """Get all extra attributes from the original PDF""" + """ Get all extra attributes from the original PDF""" opdf = self.old_pdf return getattr ( opdf , attr ) @@ -408,7 +167,7 @@ def __getattr__ ( self , attr ) : # @endcode # @see Adjust2D # @author Vanya BELYAEV Ivan.Belyaev@itep.ru -class Adjust3D_pdf(PDF3) : +class Adjust3D_pdf(Sum3D) : """ Simple class to ``adjust'' certain 1D-PDF to avoid zeroes - a small flat component is added and the compound 2D-PDF is constructed @@ -422,75 +181,47 @@ def __init__ ( self , yvar = None , zvar = None , fraction = 1.e-5 , - name = '' ) : - - if isinstance ( pdf , PDF3 ) : - self.__old_pdf = pdf - if xvar and not xvar is pdf.xvar : self.warning("mismatch in xvar?") - if yvar and not yvar is pdf.yvar : self.warning("mismatch in yvar?") - if zvar and not zvar is pdf.zvar : self.warning("mismatch in yvar?") - xvar = pdf.xvar - yvar = pdf.yvar - zvar = pdf.zvar - elif insinstance ( pdf , ROOT.RooAbsPdf ) and xvar and yvar and zvar : - self.__old_pdf = Generic3D_pdf ( pdf , xvar = xvar , yvar = yvar , zvar = zvar ) - else : - raise TypeError ("Unknown type of pdf %s/%s" % ( pdf , type ( pdf ) ) ) - - assert isinstance ( xvar , ROOT.RooAbsReal ) , "``xvar'' must be ROOT.RooAbsReal" - assert isinstance ( yvar , ROOT.RooAbsReal ) , "``yvar'' must be ROOT.RooAbsReal" - assert isinstance ( zvar , ROOT.RooAbsReal ) , "``zvar'' must be ROOT.RooAbsReal" - - name = name if name else self.generate_name ( 'Adjust3D_' + self.old_pdf.name ) - - ## initialize the base - PDF3.__init__ ( self , name = name , xvar = xvar , yvar = yvar , zvar = zvar ) - - em = self.old_pdf.pdf.extendMode() - if 1 == em : self.warning("PDF ``canBeExtended''") - elif 2 == em : self.warning("PDF ``mustBeExtended''") - - ## make the real adjustment - self.__adjustment = Adjust3D ( name , - pdf = self.old_pdf.pdf , - xvar = xvar , - yvar = yvar , - zvar = yvar , - fraction = fraction ) - - self.pdf = self.adjustment.pdf - self.pdf.fixCoefNormalization ( self.vars ) ## VB: added 10/10/2024 to suppress warnings + name = '' , + prefix = 'f' , ## prefix for fraction names + suffix = '' , ## suffix for fraction names + fix_norm = False ) : + + pdf1 , xvar , yvar , zvar = self.make_PDF3 ( pdf , xvar , yvar , zvar ) + flat = Flat3D ( xvar = xvar , yvar = yvar , zvar = zvar ) + Sum3D.__init__ ( self , [ flat , pdf ] , + name = name , + fraction = fraction , + prefix = prefix , + suffix = suffix , + fix_norm = fix_norm ) + + self.F.fix() self.config = { - 'xvar' : self.xvar , - 'yvar' : self.yvar , - 'zvar' : self.zvar , - 'name' : self.name , - 'pdf' : self.old_pdf , - 'fraction' : self.fraction - } - - @property - def adjustment ( self ) : - """``adjustment'' : the adjustment object""" - return self.__adjustment + 'xvar' : self.xvar , + 'yvar' : self.yvar , + 'zvar' : self.zvar , + 'name' : self.name , + 'pdf' : self.old_pdf , + 'fraction' : self.fraction , + 'prefix' : self.prefix , + 'suffix' : self.suffix , + 'fix_norm' : self.fix_norm + } + + @property + def flat ( self ) : + """`flat` : get flat component""" + return self.pdf1 - @property - def fraction( self ) : - """``fraction''-parameter: the fraction of flat ``background'' added""" - return self.adjustment.fraction - @fraction.setter - def fraction( self , value ) : - self.adjustment.fraction = value - @property def old_pdf ( self ) : """``old'' (non-adjusted) PDF""" - return self.__old_pdf - + return self.pdf2 + ## redirect any other attributes to original PDF def __getattr__ ( self , attr ) : - """Get all extra attributes from the original PDF""" + """ Get all extra attributes from the original PDF""" opdf = self.old_pdf return getattr ( opdf , attr ) diff --git a/ostap/fitting/fit1d.py b/ostap/fitting/fit1d.py index f001b005..b39ec075 100755 --- a/ostap/fitting/fit1d.py +++ b/ostap/fitting/fit1d.py @@ -28,7 +28,7 @@ integer_types , num_types , list_types , all_numerics ) from ostap.fitting.funbasic import FUN1 -from ostap.fitting.pdfbasic import PDF1, APDF1, Constrained +from ostap.fitting.pdfbasic import PDF1, APDF1, Sum1D from ostap.fitting.utils import make_name import ROOT, math, random # ============================================================================= diff --git a/ostap/fitting/fithelpers.py b/ostap/fitting/fithelpers.py index adccab28..5b9c017e 100644 --- a/ostap/fitting/fithelpers.py +++ b/ostap/fitting/fithelpers.py @@ -2378,7 +2378,7 @@ def make_fracs ( self , # @endcode def make_fractions ( self , N , - name = 'f%d' , ## pattern to contruct the fraction name from index + name = 'f%d' , ## pattern to contruct the fraction name from the index title = '' , recursive = True , fractions = () ) : @@ -2391,17 +2391,15 @@ def make_fractions ( self , >>> fractions = MV.make_fractions ( 5 , name = 'F%d_C' , fractions = (0.4, 0.1 , 0.3 , 0.1 ) ) """ - assert is_integer ( N ) and 2 <= N ,\ - "make_fractions: there must be at least two components!" + assert is_integer ( N ) and 2 <= N , "make_fractions: there must be at least two components!" - my_fractions = make_iterable ( fractions , None ) + my_fractions = make_iterable ( fractions , None , N -1 ) fracs = [] value = 1.0 prod = 1.0 - - for i , ff in zip ( range ( N - 1 ) , my_fractions ) : + for i , ff in enumerate ( my_fractions ) : value = 1.0 / N @@ -2410,16 +2408,16 @@ def make_fractions ( self , value /= prod prod *= ( 1.0 - value ) - if isinstance ( ff , num_types ) and not 0 <= ff <= 1 : - self.error ("make_fractions: fraction %s is outside [0,1] interval, ignore it!" % ff ) + if isinstance ( ff , num_types ) and not 0 <= float ( ff ) <= 1 : + self.error ("make_fractions: fraction[%d] %s is outside [0,1] interval, ignore it!" % ( i , ff ) ) ff = value elif isinstance ( ff , ROOT.RooAbsReal ) and not 0 <= float ( ff ) <= 1 : - self.warning ("make_fractions: fraction %s is outside [0,1] interval" % ff ) + self.warning ("make_fractions: fraction[%d,%s] %s is outside [0,1] interval" % ( i , ff.name , float ( ff ) ) ) if ff is None : ff = value - fname = name if ( 2 == N and '%s' not in name and '%d' not in name ) else name % i + fname = name if ( 2 == N and '%s' not in name and '%d' not in name ) else name % i tit = title if title else 'Fraction #%d: %s %s' % ( i , fname , self.name ) fvar = self.make_var ( ff , fname , tit , False , value , 0 , 1 ) @@ -3309,7 +3307,6 @@ def pars ( self , values ) : def pars_lst ( self ) : """'pars_lst' : polynomial parameters as RooArgList""" return self.phis_lst - # ============================================================================= ## @class Fractions @@ -3340,7 +3337,13 @@ def __init__ ( self , self.__suffix = suffix self.__recursive = True if recursive else False - fr_name = make_name ( self.prefix , '%d' if 2 < len ( self.pdfs ) else '' , self.suffix ) + nf = len ( self.pdfs ) - 1 + name_format= '' if nf < 2 else \ + ( '%d' if nf < 10 else \ + ( '%02d' if nf < 100 else \ + ( '%03d' if nf < 1000 else \ + ( '%04d' if nf < 10000 else '%d' ) ) ) ) + fr_name = make_name ( self.prefix , name_format , self.suffix ) ## make list of fractions self.__fractions = tuple ( self.make_fractions ( len ( self.pdfs ) , @@ -3352,29 +3355,29 @@ def pdfs ( self ) : """'pdfs' : get list/tuple of involved PDFs (same as 'components')""" return self.__pdfs + @property + def components ( self ) : + """'components' : get list/tuple of involved PDFs (same as 'pdfs')""" + return self.pdfs + @property def pdf1 ( self ) : """'pdf1' : the first PDF""" - return self.__pdfs[0] if 1<= len ( self.__pdfs ) else None + return self.__pdfs [ 0 ] @property def pdf2 ( self ) : """'pdf2' : the second PDF""" - return self.__pdfs[1] if 2<= len ( self.__pdfs ) else None + return self.__pdfs [ 1 ] @property def tail( self ) : """'tail' : other PDFs (if any)""" - return self.pdfs[2:] if 2<= len ( self.__pdfs ) else () + return self.pdfs [ 2 : ] - @property - def components ( self ) : - """'components' : get list/tuple of involved PDFs (same as 'pdfs')""" - return self.pdfs - @property def prefix ( self ) : - """'fr_prefix' : prefix for fraction names""" + """'prefix' : prefix for fraction names""" return self.__prefix @property diff --git a/ostap/fitting/pdf_ops.py b/ostap/fitting/pdf_ops.py index 5fc9f542..45ff3032 100644 --- a/ostap/fitting/pdf_ops.py +++ b/ostap/fitting/pdf_ops.py @@ -491,7 +491,7 @@ def pdf1_sum ( pdf1 , pdf2 , *other ) : """ Make an non-extended sum of the 1D PDFs - see Sum1D """ - if isinstance ( pdf2 , PDF1 ) : pass + if isinstance ( pdf2 , PDF1 ) : pass elif isinstance ( pdf2 , sequence_types ) : args = tuple ( pdf2 ) + other return pdf1_sum ( pdf1 , *args ) @@ -506,7 +506,7 @@ def pdf1_sum ( pdf1 , pdf2 , *other ) : if not isinstance ( p , PDF1 ) : return NotImplemented if not p.xvar in head.vars : return NotImplemented - from ostap.fitting.fit1d import Sum1D + from ostap.fitting.pdfbasic import Sum1D return Sum1D ( pall ) # ============================================================================= @@ -516,7 +516,7 @@ def pdf2_sum ( pdf1 , pdf2 , *other ) : """ Make an non-extended sum of the 2D PDFs - see Sum2D """ - if isinstance ( pdf2 , PDF2 ) : pass + if isinstance ( pdf2 , PDF2 ) : pass elif isinstance ( pdf2 , sequence_types ) : args = tuple ( pdf2 ) + other return pdf2_sum ( pdf1 , *args ) @@ -532,7 +532,7 @@ def pdf2_sum ( pdf1 , pdf2 , *other ) : if not p.xvar in head.vars : return NotImplemented if not p.yvar in head.vars : return NotImplemented - from ostap.fitting.fit2d import Sum2D + from ostap.fitting.pdfbasic import Sum2D return Sum2D ( pall , xvar = head.xvar , yvar = head.yvar ) # ============================================================================= @@ -560,7 +560,7 @@ def pdf3_sum ( pdf1 , pdf2 , *other ) : if not p.yvar in head.vars : return NotImplemented if not p.zvar in head.vars : return NotImplemented - from ostap.fitting.fit3d import Sum3D + from ostap.fitting.pdfbasic import Sum3D return Sum3D ( pall , xvar = head.xvar , yvar = head.yvar , zvar = head.zvar ) diff --git a/ostap/fitting/pdfbasic.py b/ostap/fitting/pdfbasic.py index 4e10937c..09f6cb36 100644 --- a/ostap/fitting/pdfbasic.py +++ b/ostap/fitting/pdfbasic.py @@ -6392,14 +6392,15 @@ class Sum1D (PDF1,Fractions) : - see RooAddPdf >>> sum = Sum1D ( [ pdf1 , pdf2 , pdf3 ] ) """ - def __init__ ( self , - pdfs , ## input list of PDFs - xvar = None , - name = '' , - recursive = True , - prefix = 'f' , ## prefix for fraction names - suffix = '' , ## suffix for fraction names - fractions = None ) : + def __init__ ( self , + pdfs , ## input list of PDFs + xvar = None , + name = '' , + recursive = True , + prefix = 'f' , ## prefix for fraction names + suffix = '' , ## suffix for fraction names + fractions = None , + fix_norm = False ) : assert 2 <= len ( pdfs ) , 'Sum1D: at least two PDFs are needed!' pdf_list = [] @@ -6429,7 +6430,10 @@ def __init__ ( self , self.alist1 , self.alist2 , self.recursive ) - + + ## attention! + if fix_norm : self.pdf.SetCoefNormalization ( self.vars ) + self.config = { 'pdfs' : self.pdfs , 'xvar' : self.xvar , @@ -6437,9 +6441,19 @@ def __init__ ( self , 'prefix' : self.prefix , 'suffix' : self.suffix , 'fractions' : self.fractions , - 'recursive' : self.recursive + 'recursive' : self.recursive , + 'fix_norm' : self.fix_norm } - + + @property + def fix_norm ( self ) : + """`fix-norm`: + - see `ROOT.RooAbsPdf.SetCoefNormalization` + - see `ROOT.RooAbsPdf.getCoefNormalization` + """ + pars = self.pdf.getCoefNormalization() + return True if pars else False + # ============================================================================= ## @class Sum2D # Non-extended sum of several PDFs @@ -6454,16 +6468,17 @@ class Sum2D (PDF2,Fractions) : >>> sum = Sum2D ( [ pdf1 , pdf2 , pdf3 ] ) """ - def __init__ ( self , - pdfs , ## input list of PDFs - xvar = None , - yvar = None , - name = '' , - recursive = True , - prefix = 'f' , ## prefix for fraction names - suffix = '' , ## suffix for fraction names - fractions = None ) : - + def __init__ ( self , + pdfs , ## input list of PDFs + xvar = None , + yvar = None , + name = '' , + recursive = True , + prefix = 'f' , ## prefix for fraction names + suffix = '' , ## suffix for fraction names + fractions = None , + fix_norm = False ) : + assert 2 <= len ( pdfs ) , 'Sum2D: at least two PDFs are needed!' pdf_list = [] @@ -6494,8 +6509,10 @@ def __init__ ( self , self.alist1 , self.alist2 , self.recursive ) - self.pdf.fixCoefNormalization ( self.vars ) ## VB: added 10/10/2024 to suppress warnings + ## attention! + if fix_norm : self.pdf.SetCoefNormalization ( self.vars ) + self.config = { 'pdfs' : self.pdfs , 'xvar' : self.xvar , @@ -6504,12 +6521,20 @@ def __init__ ( self , 'prefix' : self.prefix , 'suffix' : self.suffix , 'fractions' : self.fractions , - 'recursive' : self.recursive + 'recursive' : self.recursive , + 'fix_norm' : self.fix_norm } - - - + @property + def fix_norm ( self ) : + """`fix-norm`: + - see `ROOT.RooAbsPdf.SetCoefNormalization` + - see `ROOT.RooAbsPdf.getCoefNormalization` + """ + pars = self.pdf.getCoefNormalization() + return True if pars else False + + # ============================================================================= ## @class Sum3D # Non-extended sum of several PDFs @@ -6524,16 +6549,17 @@ class Sum3D (PDF3,Fractions) : >>> sum = Sum3D ( [ pdf1 , pdf2 , pdf3 ] ) """ - def __init__ ( self , - pdfs , ## input list of PDFs - xvar = None , - yvar = None , - zvar = None , - name = '' , - recursive = True , - prefix = 'f' , ## prefix for fraction names - suffix = '' , ## suffix for fraction names - fractions = None ) : + def __init__ ( self , + pdfs , ## input list of PDFs + xvar = None , + yvar = None , + zvar = None , + name = '' , + recursive = True , + prefix = 'f' , ## prefix for fraction names + suffix = '' , ## suffix for fraction names + fractions = None , + fix_norm = False ) : assert 2 <= len ( pdfs ) , 'Sum3D: at least two PDFs are needed!' @@ -6564,8 +6590,10 @@ def __init__ ( self , self.alist1 , self.alist2 , self.recursive ) - self.pdf.fixCoefNormalization ( self.vars ) ## VB: added 10/10/2024 to suppress warnings - + + ## attention! + if fix_norm : self.pdf.SetCoefNormalization ( self.vars ) + self.config = { 'pdfs' : self.pdfs , 'xvar' : self.xvar , @@ -6575,9 +6603,18 @@ def __init__ ( self , 'prefix' : self.prefix , 'suffix' : self.suffix , 'fractions' : self.fractions , - 'recursive' : self.recursive + 'recursive' : self.recursive , + 'fix_norm' : self.fix_norm } + @property + def fix_norm ( self ) : + """`fix-norm`: + - see `ROOT.RooAbsPdf.SetCoefNormalization` + - see `ROOT.RooAbsPdf.getCoefNormalization` + """ + pars = self.pdf.getCoefNormalization() + return True if pars else False # ============================================================================= if '__main__' == __name__ : diff --git a/ostap/fitting/variables.py b/ostap/fitting/variables.py index 52096d70..8aa34f59 100644 --- a/ostap/fitting/variables.py +++ b/ostap/fitting/variables.py @@ -96,7 +96,7 @@ ## Factory for deserialization of generic objects # @attention it stores the constructor parameters as local attributes def root_store_factory ( klass , *params ) : - """Factory for deserialization of generic object + """ Factory for deserialization of generic object - attention: it stores the constructor parameters as local attributes """ ## create the objects @@ -110,7 +110,7 @@ def root_store_factory ( klass , *params ) : # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2012-09-20 def _fix_par_ ( var , value = None ) : - """Fix parameter at some value : + """ Fix parameter at some value : >>> par = ... >>> par.fix ( 10 ) @@ -126,21 +126,21 @@ def _fix_par_ ( var , value = None ) : var.setVal ( value ) if not var.isConstant() : var.setConstant ( True ) # - return var.ve() + return var.asVE () # ============================================================================= ## release the parameter # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2012-09-20 def _rel_par_ ( var ) : - """Release the parameters + """ Release the parameters >>> par = ... >>> par.release () """ if var.isConstant() : var.setConstant ( False ) # - return var.ve() + return var.asVE () # ============================================================================== ## Convert RooRealVar into ValueWithError @@ -220,10 +220,6 @@ def _rrv_contains_ ( var , value ) : ROOT.RooRealVar . as_VE = _rrv_ve_ ROOT.RooRealVar . asVE = _rrv_ve_ ROOT.RooRealVar . ve = _rrv_ve_ -ROOT.RooRealVar . fix = _fix_par_ -ROOT.RooRealVar . Fix = _fix_par_ -ROOT.RooRealVar . release = _rel_par_ -ROOT.RooRealVar . Release = _rel_par_ ## convert to float ROOT.RooRealVar . __float__ = lambda s : s.getVal() ## print it in more suitable form @@ -244,6 +240,42 @@ def _rrv_contains_ ( var , value ) : ROOT.RooAbsArg .__contains__ = _var_contains_ ROOT.RooAbsRealLValue .__contains__ = _rrv_contains_ +ROOT.RooAbsRealLValue . fix = _fix_par_ +ROOT.RooAbsRealLValue . release = _rel_par_ +ROOT.RooAbsRealLValue . Fix = _fix_par_ +ROOT.RooAbsRealLValue . Felease = _rel_par_ + + +# ======================================================================== +def _rel_const_par_ ( v ) : + """`ROOT.RooConstVar` can not be released! warn and skip!""" + logger.warning ( "ROOT.RooConstVar cannot be `released`! ignore") + return s.asVE() + +# ======================================================================== +def _fix_const_par_ ( v ) : + """`ROOT.RooConstVar` can not be released! warn and skip!""" + logger.warning ( "ROOT.RooConstVar cannot be `released`! ignore") + return s.asVE() + +ROOT.RooConstVar . release = _rel_const_par_ +ROOT.RooConstVar . Release = _rel_const_par_ + +## fix parameter at some value +# @author Vanya BELYAEV Ivan.Belyaev@itep.ru +# @date 2012-09-20 +def _fix_const_par_ ( var , value = None ) : + """ Fix parameter at some value + """ + if value is None : return var.asVE () + varval = float ( var ) + if value == varval : return var.asVE () + logger.warning ( "ROOT.RooConstVar[%s] cannot be changed to %s)! ignore" % ( varval , value ) ) + return s.asVE() + +ROOT.RooConstVar . fix = _fix_const_par_ +ROOT.RooConstVar . Fix = _fix_const_par_ + # ===================================================================== ROOT.RooAbsReal. minmax = lambda s : () @@ -254,13 +286,20 @@ def _rrv_contains_ ( var , value ) : ROOT.RooAbsRealLValue .xminmax = lambda s : ( s.xmin() , s.xmax() ) _new_methods_ += [ - ROOT.RooRealVar . as_VE , - ROOT.RooRealVar . asVE , - ROOT.RooRealVar . ve , - ROOT.RooRealVar . fix , - ROOT.RooRealVar . Fix , - ROOT.RooRealVar . release , - ROOT.RooRealVar . Release , + ROOT.RooRealVar . as_VE , + ROOT.RooRealVar . asVE , + ROOT.RooRealVar . ve , + ## + ROOT.RooAbsRealLValue . fix , + ROOT.RooAbsRealLValue . release , + ROOT.RooAbsRealLValue . Fix , + ROOT.RooAbsRealLValue . Felease , + ## + ROOT.RooConstVar . fix , + ROOT.RooConstVar . Fix , + ROOT.RooConstVar . release , + ROOT.RooConstVar . Release , + ## ## convert to float ROOT.RooRealVar . __float__ , ## print it in more suitable form