Exemple #1
0
def print_gsl_errors():
    """Catch GSL errors from C++ and print the summary table at exit
    """

    gsl_cnt = Ostap.Utils.GslCount
    if 0 == gsl_cnt.size(): return  ## No GSL errors

    ## get the summary
    table = gsl_cnt.table()
    rows = []
    for tline in table:

        try:
            n, code, msg, reason, file, line = tline
            code = int(code)
            n = int(n)
        except:
            logger.warning(
                'print_gs_errors: failure to decode line: %s, skip it!' %
                str(tline))
            continue

        row = '%4d' % n, '%3d:%s' % (code, msg), reason, file, line
        rows.append(row)

    if rows:

        from ostap.logger.logger import getLogger
        logger = getLogger('ostap.utils.gsl')

        rows = [('#', 'error', 'reason', 'file', 'line')] + rows

        title = 'Summary of GSL errors'

        import ostap.logger.table as T
        from ostap.logger.colorized import attention
        logger.error(
            '%s\n%s' %
            (attention(title),
             T.table(rows, title=title, prefix='# ', alignment='ccccl')))

    ## clear the errors
    gsl_cnt.clear()
    del gsl_cnt
Exemple #2
0
def _rfr_table_ ( r , title = '' , prefix = '' , more_vars = {} ) :
    """ print RooFitResult  as a table
    >>> result = ...
    >>> result.table() 
    """

    from  ostap.fitting.utils    import fit_status, cov_qual
    rows = []

    ##  1. fit status
    status = r.status() 
    if status :
        row = attention ( 'Status' )  , '' , attention ( fit_status ( status ) ) , '' 
        rows.append ( row )
    else :
        row = 'Status'                , '' , allright  ( fit_status ( status ) ) , '' 
        rows.append ( row )

    ## 2. minumum NLL
    s , n = pretty_float ( r.minNll() )
    if n : n = '[10^%+d]' % n
    else : n = '' 

    rows.append ( ( "Minimized FCN/NLL value"    , n , '  ' + s , '' ) )

    s , n = pretty_float ( r.edm () )
    if n : n = '[10^%+d]' % n
    else : n = '' 

    rows.append ( ( 'Estimated distance to minimum' , n , '  ' + s , '' ) )
    
    cq = r.covQual()
    cn = '' 
    if  -1 == cq :
        cn = cov_qual  ( cq ) 
    elif 3 == cq :
        cn = allright  ( cov_qual ( cq ) )
    elif cq in (  0 , 1 , 2 ) :
        cn = attention ( cov_qual ( cq ) )
    else :
        cn = cov_qual  ( cq ) 
        
    rows.append ( ( 'Covariance matrix quality'     , '' , '  ' + cn , '' ) )
    
    for i in  range ( r.numStatusHistory() ) :
        label =  r.statusLabelHistory ( i )
        code  =  r.statusCodeHistory  ( i )
        row   =  'Status: %s '% label   , '' ,             '%d' % code             
        if not code in ( 0 , -1 ) :
            row = attention  ( row [ 0 ] ) , row [ 1 ] , '   ' + attention ( row [ 2 ] ) , '' 
        else    :
            row =              row [ 0 ]   , row [ 1 ] , '   ' + allright  ( row [ 2 ] ) , ''
        rows.append ( row )

    nbadnll = r.numInvalidNLL()
    if 0 < nbadnll :
        rows.append ( ( 'Invalid FCN/NLL evaluations' , '' , '  %d' % nbadnll , '' ) )


    with_globcorr = not ( (6,24) <= root_info < (6,28) )


    if with_globcorr : rows = [ ( '', 'Unit', 'Value' , 'Global/max correlation [%]') ] + rows
    else             : rows = [ ( '', 'Unit', 'Value' , 'Max correlation [%]') ] + rows

    pars_all   = r.params ( float_only = False )
    pars_float = r.params ( float_only = True  )

    ## constant/fix parameters 
    crows = [] 
    for p in pars_all :

        if p in pars_float : continue 
        v , a = pars_all [ p ]

        s , n = pretty_float  ( v.value()  ) 

        if n : n = '[10^%+d]' % n
        else : n = '' 
        row = p , n , '  ' + s + ' (fix)' , ''  
        crows.append ( row ) 

    ## floating parameters
    max_corr = False
    frows    = []
    for p in pars_float :

        v , a = pars_float [ p ]

        if not a.hasAsymError() :
            s , n = pretty_ve  ( v ) 
        else :
            s , n = pretty_2ve (  a.getVal() , a.getAsymErrorHi() , a.getAsymErrorLo() )

        if n : n = '[10^%+d]' % n
        else : n = '' 


        if 0 <= cq and 1 < len ( pars_float ) :

            mxr , mxv = r.max_cor    ( p )

            if with_globcorr :
                
                gc = -1.0 
                gc    = r.globalCorr ( p ) if 3 == cq else -1.00
                if 0 <= gc :  cc = '% +5.1f/(% +5.1f,%s)' % ( gc*100 , mxr*100   , mxv )
                else       :  cc = '% +5.1f : %-s'        % (          mxr * 100 , mxv )                
                if 0.95 < abs ( mxr ) or 0.95 < gc : cc = attention ( cc )

            else :
                
                cc = '% +5.1f : %-s'  % ( mxr * 100 , mxv )                
                if 0.95 < abs ( mxr ) : cc = attention ( cc )

                max_corr = True

            row = p , n , s , cc
            
        else :
            
            row = p , n , s
            
        frows.append ( row ) 

    ## more parameters
    mrows = []
    for p in sorted ( more_vars ) :

        func  = more_vars [ p ]
        
        v     = func ( r )
        
        s , n = pretty_ve  ( v ) 
        
        if n : n = '[10^%+d]' % n
        else : n = '' 

        cc = 'derived'
        row = p , n , s , cc
        mrows.append ( row ) 

    crows.sort()
    frows.sort()

    all = rows + crows + frows + mrows  

    import ostap.logger.table as T

    return T.table ( all , title = title if title else r.GetTitle() , prefix = prefix , alignment = 'llll' )
Exemple #3
0
def makeWeights(
        dataset,
        plots=[],
        database="weights.db",
        compare=None,  ## comparison function 
        delta=0.01,  ## delta for ``mean''  weight variation
        minmax=0.03,  ## delta for ``minmax'' weight variation
        power=None,  ## auto-determination
        debug=True,  ## save intermediate information in DB
        make_plots=False,  ## make plots 
        tag="Reweighting"):
    """The main  function: perform one re-weighting iteration 
    and reweight ``MC''-data set to looks as ``data''(reference) dataset
    >>> results = makeWeights (
    ... dataset           , ## data source to be  reweighted (DataSet, TTree, abstract source)
    ... plots             , ## reweighting plots
    ... database          , ## datadabse to store/update reweigting results
    ... delta             , ## stopping criteria for `mean`    weight variation
    ... minmax            , ## stopping criteria for `min/max` weight variation
    ... power             , ## effective power to apply to the weigths
    ... debug      = True , ## store debuig information in database
    ... make_plots = True , ## produce useful comparison plots
    ... tag        = 'RW' ) ## tag for better printout
    
    If `make_plots = False`,  it returns the tuple of active reweitings:
    >>> active        = makeWeights ( ... , make_plots = False , ... )
    
    Otherwise it also returns list of comparison plots 
    >>> active, cmp_plots = makeWeights ( ... , make_plots = True  , ... )
    >>> for item in  cmp_plots :
    ...    what    = item.what
    ...    hdata   = item.data
    ...    hmc     = item.mc
    ...    hweight = item.weight
    
    If no more rewighting iteratios required, <code>active</code> is an empty tuple 
    """

    assert 0 < delta, "makeWeights(%s): Invalid value for ``delta''  %s" % (
        tag, delta)
    assert 0 < minmax, "makeWeights(%s): Invalid value for ``minmax'' %s" % (
        tag, minmax)

    from ostap.logger.colorized import allright, attention, infostr
    from ostap.utils.basic import isatty

    nplots = len(plots)
    ## if 1 < nplots :
    ##     import  math
    ##     fudge_factor = math.sqrt ( 1.0 / max ( 2.0 , nplots -  1.0 ) )
    ##     delta   = delta  * fudge_factor
    ##     minmax  = minmax * fudge_factor

    ## list of plots to compare
    cmp_plots = []
    ## reweighting summary table
    header = ('Reweighting', 'wmin/wmax', 'OK?', 'wrms[%]', 'OK?', 'chi2/ndf',
              'ww', 'exp')

    rows = {}
    save_to_db = []
    ## number of active plots for reweighting
    for wplot in plots:

        what = wplot.what  ## variable/function to plot/compare
        how = wplot.how  ## weight and/or additional cuts
        address = wplot.address  ## address in database
        hdata0 = wplot.data  ## original "DATA" object
        hmc0 = wplot.mc_histo  ## original "MC"   histogram
        ww = wplot.w  ## relative weight
        projector = wplot.projector  ## projector for MC data
        ignore = wplot.ignore  ## ignore for weigtht building?
        #
        # normalize the data
        #
        hdata = hdata0
        if isinstance(hdata, ROOT.TH1): hdata = hdata.density()

        # =====================================================================
        ## make a plot on (MC) data with the weight
        # =====================================================================
        hmc0 = projector(dataset, hmc0, what, how)

        st = hmc0.stat()
        mnmx = st.minmax()
        if iszero(mnmx[0]):
            logger.warning("%s: statistic goes to zero %s/``%s''" %
                           (tag, st, address))
        elif mnmx[0] <= 0:
            logger.warning("%s: statistic is negative  %s/``%s''" %
                           (tag, st, address))

        # =====================================================================
        ## normalize MC
        # =====================================================================
        hmc = hmc0.density()

        # =====================================================================
        ## calculate  the reweighting factor : a bit conservative (?)
        #  this is the only important line
        # =====================================================================

        #  try to exploit finer binning if/when possible
        hboth = isinstance(hmc, ROOT.TH1) and isinstance(hdata, ROOT.TH1)

        if   hboth and 1 == hmc.dim () and 1 == hdata.dim () and \
               len ( hmc ) >= len( hdata ) :
            w = (1.0 / hmc) * hdata  ## NB!
        elif hboth and 2 == hmc.dim () and 2 == hdata.dim () and \
                 ( hmc.binsx() >= hdata.binsx() ) and \
                 ( hmc.binsy() >= hdata.binsy() ) :
            w = (1.0 / hmc) * hdata  ## NB!
        elif hboth and 3 == hmc.dim () and 3 == hdata.dim () and \
                 ( hmc.binsx() >= hdata.binsx() ) and \
                 ( hmc.binsy() >= hdata.binsy() ) and \
                 ( hmc.binsz() >= hdata.binsz() ) :
            w = (1.0 / hmc) * hdata  ## NB!
        else:
            w = hdata / hmc  ## NB!

        # =====================================================================
        ## scale & get the statistics of weights
        w /= w.stat().mean().value()
        cnt = w.stat()
        #
        mnw, mxw = cnt.minmax()
        wvar = cnt.rms() / cnt.mean()
        good1 = wvar.value() <= delta
        good2 = abs(mxw - mnw) <= minmax
        good = good1 and good2  ## small variance?
        #

        c2ndf = 0
        for i in w:
            c2ndf += w[i].chi2(1.0)
        c2ndf /= (len(w) - 1)

        ## build  the row in the summary table
        row = address  ,  \
              '%-5.3f/%5.3f' % ( cnt.minmax()[0]    , cnt.minmax()[1] ) , \
              allright ( '+' ) if good2 else attention ( '-' ) , \
              (wvar * 100).toString('%6.2f+-%-6.2f') , \
              allright ( '+' ) if good1 else attention ( '-' ) , '%6.2f' % c2ndf

        ## make plots at the start of  each iteration?
        if make_plots:
            item = ComparisonPlot(what, hdata, hmc, w)
            cmp_plots.append(item)

        row = tuple(list(row) + ['%4.3f' % ww if 1 != ww else ''])

        rows[address] = row

        #
        ## make decision based on the variance of weights
        #
        mnw, mxw = cnt.minmax()
        if (not good) and (not ignore):  ## small variance?
            save_to_db.append((address, ww, hdata0, hmc0, hdata, hmc, w))

        # =====================================================================
        ## make a comparison (if needed)
        # =====================================================================
        if compare: compare(hdata0, hmc0, address)

    active = tuple([p[0] for p in save_to_db])
    nactive = len(active)

    if power and callable(power):
        eff_exp = power(nactive)
    elif isinstance(power, num_types) and 0 < power <= 1.5:
        eff_exp = 1.0 * power
    elif 1 == nactive and 1 < len(plots):
        eff_exp = 0.95
    elif 1 == nactive:
        eff_exp = 1.00
    else:
        eff_exp = 1.10 / max(nactive, 1)

    while database and save_to_db:

        entry = save_to_db.pop()

        address, ww, hd0, hm0, hd, hm, weight = entry

        cnt = weight.stat()
        mnw, mxw = cnt.minmax()

        ## avoid too large or too small  weights
        for i in weight:
            w = weight[i]
            if w.value() < 0.5:
                weight[i] = VE(0.5, w.cov2())
            elif w.value() > 2.0:
                weight[i] = VE(2.0, w.cov2())

        if 1 < nactive and 1 != ww:
            eff_exp *= ww
            logger.info("%s: apply ``effective exponent'' of %.3f for ``%s''" %
                        (tag, eff_exp, address))

        if 1 != eff_exp and 0 < eff_exp:
            weight = weight**eff_exp
            row = list(rows[address])
            row.append('%4.3f' % eff_exp)
            rows[address] = tuple(row)

        with DBASE.open(database) as db:

            db[address] = db.get(address, []) + [weight]

            if debug:
                addr = address + ':REWEIGHTING'
                db[addr] = db.get(addr, []) + list(entry[2:])

        del hd0, hm0, hd, hm, weight, entry

    table = [header]
    for row in rows:
        table.append(rows[row])

    import ostap.logger.table as Table
    logger.info(
        '%s, active:#%d \n%s ' %
        (tag, nactive,
         Table.table(table, title=tag, prefix='# ', alignment='lccccccc')))

    cmp_plots = tuple(cmp_plots)
    return (active, cmp_plots) if make_plots else active
Exemple #4
0
from   ostap.logger.colorized import allright, attention 
# =============================================================================
# logging 
# =============================================================================
from ostap.logger.logger      import getLogger 
if '__main__' ==  __name__ : logger = getLogger( 'ostap.fitting.minuit' )
else                       : logger = getLogger( __name__ )
# =============================================================================
logger.debug ( 'Some useful decorations for (T)Minuit functions')
# =============================================================================
partypes = integer_types
# =============================================================================
## return codes from MINUIT commands
return_codes = {
    0  : allright  ( 'command executed normally'                         ) ,
    1  : attention ( 'command is blank, ignored'                         ) ,
    2  : attention ( 'command line unreadable, ignored'                  ) ,
    3  : attention ( 'unknown command, ignored'                          ) ,
    4  : attention ( 'abnormal termination (e.g., MIGRAD not converged)' ),
    5  : 'command is a request to read PARAMETER definitions' , 
    6  : "'SET INPUT' command"   ,
    7  : "'SET TITLE' command"   ,
    8  : "'SET COVAR' command"   ,
    9  : 'reserved'              ,
    10 : 'END command'           ,
    11 : 'EXIT or STOP command'  ,
    12 : 'RETURN command'        ,
    }
# =============================================================================
## get the parameter from (T)Minuit
#  @code
Exemple #5
0
def makeWeights(
        dataset,
        plots=[],
        database="weights.db",
        compare=None,  ## comparison function 
        delta=0.001,  ## delta for ``mean''  weight variation
        minmax=0.05,  ## delta for ``minmax'' weight variation
        power=0,  ## auto-determination
        debug=True,  ## save intermediate information in DB
        tag="Reweighting"):

    assert 0 < delta, "makeWeights(%s): Invalid value for ``delta''  %s" % (
        tag, delta)
    assert 0 < minmax, "makeWeights(%s): Invalid value for ``minmax'' %s" % (
        tag, minmax)

    from ostap.logger.colorized import allright, attention, infostr
    from ostap.utils.basic import isatty

    power = power if power >= 1 else len(plots)

    nplots = len(plots)
    if 1 < nplots:
        import math
        fudge_factor = math.sqrt(1.0 / max(2.0, nplots - 1.0))
        delta = delta * fudge_factor
        minmax = minmax * fudge_factor

    save_to_db = []
    ## number of active plots for reweighting
    for wplot in plots:

        what = wplot.what  ## variable/function to plot/compare
        how = wplot.how  ## weight and/or additional cuts
        address = wplot.address  ## address in database
        hdata0 = wplot.data  ## original "DATA" object
        hmc0 = wplot.mc_histo  ## original "MC"   histogram
        ww = wplot.w  ## relative weight
        #
        # normailze the data
        #
        hdata = hdata0
        if isinstance(hdata, ROOT.TH1): hdata = hdata.density()

        # =====================================================================
        ## make a plot on (MC) data with the weight
        # =====================================================================
        dataset.project(hmc0, what, how)

        st = hmc0.stat()
        mnmx = st.minmax()
        if iszero(mnmx[0]):
            logger.warning("Reweighting: statistic goes to zero %s/``%s''" %
                           (st, address))

        # =====================================================================
        ## normalize MC
        # =====================================================================
        hmc = hmc0.density()

        # =====================================================================
        ## calculate  the reweighting factor : a bit conservative (?)
        #  this is the only important line
        # =====================================================================

        #  try to exploit finer binning if/when possible
        if   isinstance ( hmc   , ( ROOT.TH1F , ROOT.TH1D ) ) and \
           isinstance ( hdata , ( ROOT.TH1F , ROOT.TH1D ) )   and \
           len ( hmc ) >= len( hdata )                        :
            w = (1.0 / hmc) * hdata  ## NB!
            ## elif isinstance ( hmc   , ( ROOT.TH2F , ROOT.TH2D ) ) and \
            ##    isinstance ( hdata , ( ROOT.TH2F , ROOT.TH2D ) )   and \
            ##    len ( hmc.GetXaxis() ) >= len( hdata.GetXaxis () ) and \
            ##    len ( hmc.GetYaxis() ) >= len( hdata.GetYaxis () ) : w = ( 1.0 / hmc ) * hdata ## NB!
            ## elif isinstance ( hmc   , ( ROOT.TH3F , ROOT.TH3D ) ) and \
            ##    isinstance ( hdata , ( ROOT.TH3F , ROOT.TH3D ) )   and \
            ##    len ( hmc.GetXaxis() ) >= len( hdata.GetXaxis () ) and \
            ##    len ( hmc.GetYaxis() ) >= len( hdata.GetYaxis () ) and \
            ##    len ( hmc.GetZaxis() ) >= len( hdata.GetZaxis () ) : w = ( 1.0 / hmc ) * hdata ## NB!
        else:
            w = hdata / hmc  ## NB!

        # =====================================================================
        ## scale & get the statistics of weights
        w /= w.stat().mean().value()
        cnt = w.stat()
        #
        mnw, mxw = cnt.minmax()
        wvar = cnt.rms() / cnt.mean()
        good1 = wvar.value() <= delta
        good2 = abs(mxw - mnw) <= minmax
        good = good1 and good2  ## small variance?
        #
        afunc1 = allright if good1 else attention
        afunc2 = allright if good2 else attention
        #
        message = "%s: %24s:" % (tag, address)
        message += ' ' + 'mean=%12s' % cnt.mean().toString('(%4.2f+-%4.2f)')
        message += ' ' + afunc2('min/max=%-5.3f/%5.3f' %
                                (cnt.minmax()[0], cnt.minmax()[1]))
        message += ' ' + afunc1('rms=%s[%%]' %
                                (wvar * 100).toString('(%4.2f+-%4.2f)'))
        logger.info(message)
        #
        ## make decision based on the variance of weights
        #
        mnw, mxw = cnt.minmax()
        if good:  ## small variance?
            message = "%s: No more reweights for %s" % (tag, address)
            message += ' ' + allright("min/max/rms=%+3.1f/%+3.1f/%3.1f[%%]" %
                                      ((mnw - 1) * 100,
                                       (mxw - 1) * 100, 100 * wvar))
            logger.info(message)
            del w, hdata, hmc
        else:
            save_to_db.append((address, ww, hdata0, hmc0, hdata, hmc, w))
        # =====================================================================
        ## make a comparison (if needed)
        # =====================================================================
        if compare: compare(hdata0, hmc0, address)

    ## for single reweighting
    ## if 1 == nplots : power = 1

    ## if power != nplots :
    #    logger.info ( "%s: ``power'' is %g/#%d"  % ( tag , power , nplots  ) )

    active = [p[0] for p in save_to_db]
    all = [p.address for p in plots]
    for i, a in enumerate(all):
        if a in active:
            if isatty(): all[i] = attention(a)
            else: all[i] = '*' + a + '*'
        else:
            if isatty(): all[i] = allright(a)

    logger.info("%s: reweights are: %s" % (tag, (', '.join(all))))

    ## if len ( active ) != nplots :
    ##    if database and save_to_db :
    ##        power += ( nplots - len ( active ) )
    ##        logger.info  ("%s: ``power'' is changed to %g" %  ( tag , power ) )

    nactive = len(active)
    while database and save_to_db:

        entry = save_to_db.pop()

        address, ww, hd0, hm0, hd, hm, weight = entry

        ## eff_exp = 1.0  / power
        ## eff_exp = 0.95 / ( 1.0 * nactive ) ** 0.5

        cnt = weight.stat()
        mnw, mxw = cnt.minmax()

        if 0.95 < mnw and mxw < 1.05:
            eff_exp = 0.75 if 1 < nactive else 1.50
        elif 0.90 < mnw and mxw < 1.10:
            eff_exp = 0.70 if 1 < nactive else 1.30
        elif 0.80 < mnw and mxw < 1.20:
            eff_exp = 0.65 if 1 < nactive else 1.25
        elif 0.70 < mnw and mxw < 1.30:
            eff_exp = 0.60 if 1 < nactive else 1.15
        elif 0.50 < mnw and mxw < 1.50:
            eff_exp = 0.55 if 1 < nactive else 1.10
        else:
            eff_exp = 0.50 if 1 < nactive else 1.0

        ## print 'effective exponent is:', eff_exp , address , mnw , mxw , (1.0/mnw)*mnw**eff_exp , (1.0/mxw)*mxw**eff_exp

        if 1 < nactive and 1 != ww:
            eff_exp *= ww
            logger.info("%s: apply ``effective exponent'' of %.3f for ``%s''" %
                        (tag, eff_exp, address))

        if 1 != eff_exp and 0 < eff_exp:
            weight = weight**eff_exp

        ## print 'WEIGHT stat', eff_exp, weight.stat()

        ## hmmmm... needed ? yes!
        #if 1 < power : weight = weight ** ( 1.0 / power )

        ## relative importance
        #if 1 != ww :
        #    logger.info  ("%s: apply ``relative importance factor'' of %.3g for ``'%s'" % ( tag , ww , address ) )
        #    weight = weight ** ww

        with DBASE.open(database) as db:

            db[address] = db.get(address, []) + [weight]

            if debug:
                addr = address + ':REWEIGHTING'
                db[addr] = db.get(addr, []) + list(entry[2:])

        del hd0, hm0, hd, hm, weight, entry

    return active
Exemple #6
0
def test_carlson_values():
    """Test predefined values, (section 3), arXiv:math/9409227
    """

    logger = getLogger('test_carlson_values')
    logger.info('Test predefined values, (section 3), arXiv:math/9409227')

    test_RF = [
        ('RF', RF, (1, 2, 0), 1.3110287771461),
        ('RF', RF, (2, 3, 4), 0.58408284167715),
        ## ( 'RF'      , RF     , (1,2,4) , 0.6850858166       ) , ## extra
        ('RF', RF, (1, 2, 4), 0.6850858166334359),  ## extra  
        ##
        ('RF_int', RF_int, (1, 2, 0), 1.3110287771461),
        ('RF_int', RF_int, (2, 3, 4), 0.58408284167715),
        ## ( 'RF_int'  , RF_int , (1,2,4) , 0.6850858166     ) , ## extra
        ('RF_int', RF_int, (1, 2, 4), 0.6850858166334359),  ## extra  

        ##
        ('RF_gsl', RF_gsl, (1, 2, 0), 1.3110287771461),
        ('RF_gsl', RF_gsl, (2, 3, 4), 0.58408284167715),
        ## ( 'RF_gsl'  , RF_gsl , (1,2,4) , 0.6850858166     ) , ## extra
        ('RF_gsl', RF_gsl, (1, 2, 4), 0.6850858166334359),  ## extra  
        ##
        ('RF2', RF, (1, 2), 1.3110287771461),  ## 2-argument form 
    ]

    test_RC = [
        ('RC', RC, (0, 0.25), math.pi),
        ('RC', RC, (0.25 * 9, 2), math.log(2.0)),
        ('RC', RC, (0.25, -2), math.log(2.0) / 3.0),
        ##
        ('RC_gsl', RC_gsl, (0, 0.25), math.pi),
        ('RC_gsl', RC_gsl, (0.25 * 9, 2), math.log(2.0)),
        ('RC_gsl', RC_gsl, (0.25, -2), math.log(2.0) / 3.0),
        ##
        ('RC_int', RC_int, (0, 0.25), math.pi),
        ('RC_int', RC_int, (0.25 * 9, 2), math.log(2.0)),
        ('RC_int', RC_int, (0.25, -2), math.log(2.0) / 3.0),
    ]

    test_RJ = [
        ('RJ', RJ, (0, 1, 2, 3), 0.77688623778582),
        ('RJ', RJ, (2, 3, 4, 5), 0.14297579667157),
        ##
        ('RJ_gsl', RJ_gsl, (0, 1, 2, 3), 0.77688623778582),
        ('RJ_gsl', RJ_gsl, (2, 3, 4, 5), 0.14297579667157),
        ##
        ('RJ_int', RJ_int, (0, 1, 2, 3), 0.77688623778582),
        ('RJ_int', RJ_int, (2, 3, 4, 5), 0.14297579667157),
    ]

    test_RD = [
        ('RD', RD, (0, 2, 1), 1.7972103521034),
        ('RD', RD, (2, 3, 4), 0.16510527294261),
        ##
        ('RD_gsl', RD_gsl, (0, 2, 1), 1.7972103521034),
        ('RD_gsl', RD_gsl, (2, 3, 4), 0.16510527294261),
        ##
        ('RD_int', RD_int, (0, 2, 1), 1.7972103521034),
        ('RD_int', RD_int, (2, 3, 4), 0.16510527294261),
    ]

    test_RG = [
        ('RG', RG, (0, 16, 16), math.pi),
        ('RG', RG, (2, 3, 4), 1.7255030280692),
        ('RG', RG, (0, 0.0796, 4), 1.0284758090288),
        ##
        ('RG_gsl', RG_gsl, (0, 16, 16), math.pi),
        ('RG_gsl', RG_gsl, (2, 3, 4), 1.7255030280692),
        ('RG_gsl', RG_gsl, (0, 0.0796, 4), 1.0284758090288),
        ##
        ('RG_int', RG_int, (0, 16, 16), math.pi),
        ('RG_int', RG_int, (2, 3, 4), 1.7255030280692),
        ('RG_int', RG_int, (0, 0.0796, 4), 1.0284758090288),
        ##
        ('RG2', RG, (16, 16), math.pi),  ## 2-argument form 
        ('RG2', RG, (0.0796, 4), 1.0284758090288),  ## 2-argument form         
    ]

    rows = [('Function', 'Arguments', 'Result', 'Expected', 'abs-delta',
             'rel-delta')]

    ad_max = -1
    rd_max = -1

    with gslCount():
        for test in test_RF + test_RC + test_RJ + test_RD + test_RG:

            name, fun, args, r = test
            result = fun(*args)

            ad = abs(result - r)
            rd = abs(result / r - 1)

            at, rt = '%.4g' % ad, '%.4g' % rd

            if prec_TIGHT < ad: at = attention(at)
            if prec_TIGHT < rd: rt = attention(rt)

            row = name, str(args), '%+.12f' % result, '%+.12f' % r, at, rt
            rows.append(row)
            ad_max = max(ad_max, ad)
            rd_max = max(rd_max, rd)

    table = T.table(rows,
                    title='Test of Carlson forms',
                    prefix='# ',
                    alignment='llllll')

    logger.info('Test Carlson forms:\n%s' % table)

    if max(ad_max, rd_max) < prec_TIGHT:
        logger.info('Maximal differences are %.5g/%.5g (abs/rel)' %
                    (ad_max, rd_max))
    elif max(ad_max, rd_max) < prec_LOOSE:
        logger.warning('Maximal differences are %.5g/%.5g (abs/rel)' %
                       (ad_max, rd_max))
    else:
        logger.error('Maximal differences are %.5g/%.5g (abs/rel)' %
                     (ad_max, rd_max))
Exemple #7
0
def test_carlson_cmp():
    """Compare local/GSL and plain integration methods
    """

    logger = getLogger('test_carlson_1')
    logger.info('Compare local/GSL and plain integration methods  ')

    cF1 = SE()
    cF2 = SE()

    cD1 = SE()
    cD2 = SE()

    cC1 = SE()
    cC2 = SE()

    cJ1 = SE()
    cJ2 = SE()

    cG1 = SE()
    cG2 = SE()

    with gslCount():
        for i in range(10000):

            x = random.uniform(0, 1)
            y = random.uniform(0, 1)
            z = random.uniform(0, 1)
            p = random.uniform(0, 1)

            ## RF

            v1 = RF(x, y, z)
            v2 = RF_gsl(x, y, z)
            v3 = RF_int(x, y, z)
            cF1 += (v1 / v2) - 1
            cF2 += (v1 / v3) - 1

            v1 = RF(x, y, p)
            v2 = RF_gsl(x, y, p)
            v3 = RF_int(x, y, p)
            cF1 += (v1 / v2) - 1
            cF2 += (v1 / v3) - 1

            v1 = RF(x, p, z)
            v2 = RF_gsl(x, p, z)
            v3 = RF_int(x, p, z)
            cF1 += (v1 / v2) - 1
            cF2 += (v1 / v3) - 1

            v1 = RF(p, x, z)
            v2 = RF_gsl(p, x, z)
            v3 = RF_int(p, x, z)
            cF1 += (v1 / v2) - 1
            cF2 += (v1 / v3) - 1

            ## RJ

            v1 = RJ(x, y, z, p)
            v2 = RJ_gsl(x, y, z, p)
            v3 = RJ_int(x, y, z, p)
            cJ1 += (v1 / v2) - 1
            cJ2 += (v1 / v3) - 1

            v1 = RJ(x, y, p, z)
            v2 = RJ_gsl(x, y, p, z)
            v3 = RJ_int(x, y, p, z)
            cJ1 += (v1 / v2) - 1
            cJ2 += (v1 / v3) - 1

            v1 = RJ(x, p, z, y)
            v2 = RJ_gsl(x, p, z, y)
            v3 = RJ_int(x, p, z, y)
            cJ1 += (v1 / v2) - 1
            cJ2 += (v1 / v3) - 1

            v1 = RJ(p, y, z, x)
            v2 = RJ_gsl(p, y, z, x)
            v3 = RJ_int(p, y, z, x)
            cJ1 += (v1 / v2) - 1
            cJ2 += (v1 / v3) - 1

            ## RD

            v1 = RD(x, y, z)
            v2 = RD_gsl(x, y, z)
            v3 = RD_int(x, y, z)
            cD1 += (v1 / v2) - 1
            cD2 += (v1 / v3) - 1

            v1 = RD(x, y, p)
            v2 = RD_gsl(x, y, p)
            v3 = RD_int(x, y, p)
            cD1 += (v1 / v2) - 1
            cD2 += (v1 / v3) - 1

            v1 = RD(x, p, z)
            v2 = RD_gsl(x, p, z)
            v3 = RD_int(x, p, z)
            cD1 += (v1 / v2) - 1
            cD2 += (v1 / v3) - 1

            v1 = RD(p, y, z)
            v2 = RD_gsl(p, y, z)
            v3 = RD_int(p, y, z)
            cD1 += (v1 / v2) - 1
            cD2 += (v1 / v3) - 1

            ## RC

            v1 = RC(x, y)
            v2 = RC_gsl(x, y)
            v3 = RC_int(x, y)
            cC1 += (v1 / v2) - 1
            cC2 += (v1 / v2) - 1

            v1 = RC(x, z)
            v2 = RC_gsl(x, z)
            v3 = RC_int(x, z)
            cC1 += (v1 / v2) - 1
            cC2 += (v1 / v2) - 1

            v1 = RC(x, p)
            v2 = RC_gsl(x, p)
            v3 = RC_int(x, p)
            cC1 += (v1 / v2) - 1
            cC2 += (v1 / v2) - 1

            v1 = RC(y, z)
            v2 = RC_gsl(y, z)
            v3 = RC_int(y, z)
            cC1 += (v1 / v2) - 1
            cC2 += (v1 / v2) - 1

            v1 = RC(y, p)
            v2 = RC_gsl(y, p)
            v3 = RC_int(y, p)
            cC1 += (v1 / v2) - 1
            cC2 += (v1 / v2) - 1

            v1 = RC(z, p)
            v2 = RC_gsl(z, p)
            v3 = RC_int(z, p)
            cC1 += (v1 / v2) - 1
            cC2 += (v1 / v2) - 1

            ## RG

            v1 = RG(x, y, z)
            v2 = RG_gsl(x, y, z)
            v3 = RG_int(x, y, z)
            cG1 += (v1 / v2) - 1
            cG2 += (v1 / v2) - 1

            v1 = RG(x, y, p)
            v2 = RG_gsl(x, y, p)
            v3 = RG_int(x, y, p)
            cG1 += (v1 / v2) - 1
            cG2 += (v1 / v2) - 1

            v1 = RG(x, p, z)
            v2 = RG_gsl(x, p, z)
            v3 = RG_int(x, p, z)
            cG1 += (v1 / v2) - 1
            cG2 += (v1 / v2) - 1

            v1 = RG(p, y, z)
            v2 = RG_gsl(p, y, z)
            v3 = RG_int(p, y, z)
            cG1 += (v1 / v2) - 1
            cG2 += (v1 / v2) - 1

    rows = [('Name', '#', 'Mean', 'rms', 'min', 'max')]

    for n, c in [('RF', cF1), ('RJ', cJ1), ('RD', cD1), ('RC', cC1),
                 ('RG', cG1)]:

        mean = c.mean()
        tmean = '%+.5g' % mean
        if prec_TIGHT < abs(mean): tmean = attention(tmean)

        rms = c.rms()
        trms = '%+.5g' % rms
        if prec_TIGHT < abs(rms): trms = attention(trms)

        vmin = c.min()
        tmin = '%+.5g' % vmin
        if prec_TIGHT < abs(vmin): tmin = attention(tmin)

        vmax = c.max()
        tmax = '%+.5g' % vmax
        if prec_TIGHT < abs(vmax): tmax = attention(tmax)

        row = n, '%d' % c.nEntries(), tmean, trms, tmin, tmax
        rows.append(row)

    table = T.table(rows,
                    title='Test of Carlson forms, Local vs GSL ',
                    prefix='# ',
                    alignment='lrllll')

    logger.info('Test Carlson forms, Local vs GSL:\n%s' % table)

    rows = [('Name', '#', 'Mean', 'rms', 'min', 'max')]
    for n, c in [('RF', cF2), ('RJ', cJ2), ('RD', cD2), ('RC', cC2),
                 ('RG', cG2)]:

        mean = c.mean()
        tmean = '%+.5g' % mean
        if prec_TIGHT < abs(mean): tmean = attention(tmean)

        rms = c.rms()
        trms = '%+.5g' % rms
        if prec_TIGHT < abs(rms): trms = attention(trms)

        vmin = c.min()
        tmin = '%+.5g' % vmin
        if prec_TIGHT < abs(vmin): tmin = attention(tmin)

        vmax = c.max()
        tmax = '%+.5g' % vmax
        if prec_TIGHT < abs(vmax): tmax = attention(tmax)

        row = n, '%d' % c.nEntries(), tmean, trms, tmin, tmax
        rows.append(row)

    table = T.table(rows,
                    title='Test of Carlson forms, Local vs plain integration',
                    prefix='# ',
                    alignment='lrllll')

    logger.info('Test Carlson forms, Local vs plain integrtation:\n%s' % table)
Exemple #8
0
def _fit_table_ ( rfit , title = '' , prefix = '' ) :
    """Print <code>TFitResult</code> as a table
    """
    from  ostap.fitting.utils    import fit_status, cov_qual
    from ostap.logger.colorized  import attention, allright
    from ostap.logger.utils      import pretty_float, pretty_ve, pretty_2ve, fmt_pretty_ve 
    
    header = ( '', 'Unit' , 'Value' )

    rows = []

    ##  0. minimized type
    row = "Minimizer Type" , '' , rfit.MinimizerType() 
    rows.append ( row )

    ##  0. minimized type
    v = rfit.IsValid()
    if v : row = "Valid"   , '' , 'True'
    else : row = "Valid"   , '' , attention ( 'False') 
    rows.append ( row )
    
    ##  1. fit status
    status = rfit.Status() 
    if status :
        row = attention ( 'Status' )  , '' , attention ( fit_status ( status ) ) 
        rows.append ( row )
    else :
        row =             'Status' , '' , allright ( fit_status ( status ) )   
        rows.append ( row )

    ## 4. covariance status
    cq = rfit.CovMatrixStatus() 
    cn = '' 
    if  -1 == cq              : cn = cov_qual  ( cq ) 
    elif 3 == cq              : cn = allright  ( cov_qual ( cq ) )
    elif cq in (  0 , 1 , 2 ) : cn = attention ( cov_qual ( cq ) )
    else                      : cn = cov_qual  ( cq )         
    rows.append ( ( 'Covariance matrix quality'     , '' , '  ' + cn  ) )


    ## 3-6. chi2,nDoF,chi2/nDoF,minFCN
    chi2 = rfit.Chi2 () 
    s , n = pretty_float ( chi2 )
    if n : n = '[10^%+d]' % n
    else : n = '' 
    rows.append ( ( "Chi2"       , n , '  ' + s ) )
    ##
    ndf = rfit.Ndf()
    rows.append ( ( "nDoF"       , '' , '  ' + '%d' % ndf   ) )
    ##
    c2ndf = rfit.Chi2 () /  ndf  
    s , n = pretty_float ( c2ndf  )
    if n : n = '[10^%+d]' % n
    else : n = '' 
    rows.append ( ( "Chi2/nDoF"  , n , '  ' + s   ) )
    ##
    minfcn = rfit.MinFcnValue() 
    s , n = pretty_float ( minfcn  )
    if n : n = '[10^%+d]' % n
    else : n = '' 
    rows.append ( ( "Minimal FCN"  , n , '  ' + s   ) )

    ## 7.Probability in %[%]
    prob = rfit.Prob() / 100
    rows.append ( ( "Probability"  , '[%]' , '  %5.3e' % prob ) )

    ## 8. distrance to minimum 
    edm  = rfit.Edm()
    s , n = pretty_float ( edm  )
    if n : n = '[10^%+d]' % n
    else : n = '' 
    rows.append ( ( "Estimated distance to minimum" , n , '  ' + s ) )

    ncalls = rfit.NCalls()
    rows.append ( ( "FCN calls" , '' , '  ' + '%d' % ncalls  ) )
    ##
    
    has_minos = False
    for i in rfit :
        if not rfit.HasMinosError( i ) : continue 
        has_minos = True
        break

    if has_minos :
        rows   = [ row + ('','','') for row in rows ]
        header = header + ( 'neg-minos' , 'pos-minos' , 'Global corr.' )   
    else         :
        rows = [ row + ('',)      for row in rows ] 
        header = header + ( 'Global corr.' , )   

    
    for i in rfit :
        
        pname  = rfit.GetParameterName ( i )
        value  = rfit.Value            ( i )  
        
        fixed  = rfit.IsParameterFixed ( i )
        fmte = '' 
        if fixed :
            v = value
            s  , n = pretty_float ( v )
            s = s + '(fixed)'
            nv = n
        else :
            error = rfit.Error ( i )
            v     = VE ( value , error * error )
            ##
            fmt , fmtv , fmte , n = fmt_pretty_ve  ( v )
            s = fmt % ( value / 10**n , error / 10**n )
            nv = n 
        if n : n = '[10^%+d]' % n
        else : n = '' 
        pname = "%-2d: %s"% ( i , pname )

        row = pname , n , '  ' + s             
        if not fixed and rfit.HasMinosError( i ) :
            if fmte : 
                error_low  = fmte   % ( rfit.LowerError ( i ) / 10**nv ) 
                error_up   = fmte   % ( rfit.UpperError ( i ) / 10**nv )
            else : 
                error_low  = "%+8g" % ( rfit.LowerError ( i ) / 10**nv ) 
                error_up   = "%+8g" % ( rfit.UpperError ( i ) / 10**nv ) 
        else :
            error_low  = '' 
            error_up   = '' 

        if has_minos  :
            row  = row  + ( error_low , error_up )

            
        gcc    = rfit.GlobalCC         ( i ) * 100 
        gcc  = '%+5.1f%%' % gcc
        row = row + ( gcc, )
        
        rows.append ( row ) 
        
    if not title :  title = rfit.GetTitle()
    
    import ostap.logger.table as T

    rows  = [ header ] + rows  

    return T.table ( rows , title = title , prefix = prefix )
Exemple #9
0
def _rfr_table_(r, title='', prefix=''):
    """ print RooFitResult  as a table
    >>> result = ...
    >>> result.table() 
    """

    from ostap.fitting.utils import fit_status, cov_qual
    rows = []
    if r.status():
        row = attention(' Status'), '', attention(fit_status(r.status())), ''
        rows.append(row)

    s, n = pretty_float(r.minNll())
    if n: n = '[10^%+d]' % n
    else: n = ''

    rows.append(("Minimized FCN/NLL value", n, '  ' + s, ''))

    s, n = pretty_float(r.edm())
    if n: n = '[10^%+d]' % n
    else: n = ''

    rows.append(('Estimated distance to minimum', n, '  ' + s, ''))

    cq = r.covQual()
    cn = ''
    if -1 == cq:
        cn = cov_qual(cq)
    elif 3 == cq:
        cn = allright(cov_qual(cq))
    elif cq in (0, 1, 2):
        cn = attention(cov_qual(cq))
    else:
        cn = cov_qual(cq)

    rows.append(('Covariance matrix quality', '', '  ' + cn, ''))

    for i in range(r.numStatusHistory()):
        label = r.statusLabelHistory(i)
        code = r.statusCodeHistory(i)
        row = 'Status: %s ' % label, '', '%d' % code
        if not code in (0, -1):
            row = attention(row[0]), row[1], '   ' + attention(row[2]), ''
        else:
            row = row[0], row[1], '   ' + allright(row[2]), ''
        rows.append(row)

    nbadnll = r.numInvalidNLL()
    if 0 < nbadnll:
        rows.append(('Invalid FCN/NLL evaluations', '', '  %d' % nbadnll, ''))

    rows = [('', 'Unit', 'Value', 'Global/max correlation')] + rows

    pars_all = r.params(float_only=False)
    pars_float = r.params(float_only=True)

    ## constant/fix parameters
    crows = []
    for p in pars_all:
        if p in pars_float: continue
        v, a = pars_all[p]

        s, n = pretty_float(v.value())

        if n: n = '[10^%+d]' % n
        else: n = ''
        row = p, n, '  ' + s, ''
        crows.append(row)

    ## floating parameters
    frows = []
    for p in pars_float:
        v, a = pars_float[p]

        if not a.hasAsymError():
            s, n = pretty_ve(v)
        else:
            s, n = pretty_2ve(a.getVal(), a.getAsymErrorHi(),
                              a.getAsymErrorLo())

        if n: n = '[10^%+d]' % n
        else: n = ''

        cc = 'Not available'
        if 0 <= cq:
            mxr, mxv = r.max_cor(p)
            gc = r.globalCorr(p)

            cc = '%+5.3f/(%+5.3f,%s)' % (gc, mxr, mxv)
            if 0.95 < abs(gc) or 0.95 < abs(mxr): cc = attention(cc)

        row = p, n, s, cc
        frows.append(row)

    crows.sort()
    frows.sort()

    all = rows + crows + frows

    import ostap.logger.table as T

    all = T.align_column(all, 0, 'left')
    all = T.align_column(all, 1, 'left')
    all = T.align_column(all, 2, 'left')
    all = T.align_column(all, 3, 'left')

    for l in range(len(rows), len(all)):
        line = all[l]
        line = list(line)
        line[0] = allright(line[0])
        all[l] = tuple(line)

    if title:
        return T.table(all, title=title, prefix=prefix)
    else:
        return T.table(all, title=r.GetTitle(), prefix=prefix)
Exemple #10
0
def test_fitting_fill_1():
    ## if 1 < 2 :
    logger = getLogger('test_fitting_fill_1')

    ## prepare data
    with timing("Prepare test data", logger=logger):
        files = prepare_data(4, 5000)
        data = Data('S', files)

    chain = data.chain

    mJPsi = ROOT.RooRealVar('mJPsi', 'mass(J/Psi) [GeV]', 3.0 * GeV, 3.2 * GeV)

    # =========================================================================
    logger.info(attention('All trivial variables'))
    # =========================================================================

    variables = [
        Variable(mJPsi, accessor='mass'),
        Variable('massMeV', 'mass in MeV', 3000, 3200, 'mass*1000.0'),
        Variable('vv102', 'vv10[2]', -1, 100, '1.0*vv10[2]'),
        Variable('fevt', accessor='1.0*evt'), ('pt', ), ('eta', ),
        ('x', 'some variable', 0, 5000, '(mass+pt+eta)/eta')
    ]

    config = {'variables': variables, 'selection': "pt>7 && eta<3"}

    with timing("No SHORTCUT, no FRAME", logger=None) as t1:
        logger.info(attention(t1.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=False, use_frame=False)
        ds1_1 = selector.data
    with timing("   SHORTCUT, no FRAME", logger=None) as t2:
        logger.info(attention(t2.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=True, use_frame=False)
        ds1_2 = selector.data
    with timing("No SHORTCUT,    FRAME", logger=None) as t3:
        logger.info(attention(t3.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=False, use_frame=True)
        ds1_3 = selector.data
    with timing("   SHORTCUT,    FRAME", logger=None) as t4:
        logger.info(attention(t4.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=True, use_frame=True)
        ds1_4 = selector.data

    if DataSet_NEW_FILL:
        with timing(" pure-FRAME (new) ", logger=None) as t5:
            logger.info(attention(t5.name))
            ds1_5, _ = chain.make_dataset(silent=False, **config)

    table = [('Configuration', 'CPU')]

    table.append((t1.name, '%.3fs' % t1.delta))
    table.append((t2.name, '%.3fs' % t2.delta))
    table.append((t3.name, '%.3fs' % t3.delta))
    table.append((t4.name, '%.3fs' % t4.delta))

    if DataSet_NEW_FILL:
        table.append((t5.name, '%.3fs' % t5.delta))

    title1 = "All trivial variables"
    table1 = T.table(table, title=title1, prefix='# ', alignment='rr')
    logger.info('%s\n%s' % (title1, table1))

    if ds1_1 != ds1_2:
        logger.error('Datasets ds1_1  and ds1_2   are different!')
    if ds1_1 != ds1_3:
        logger.error('Datasets ds1_1  and ds1_3   are different!')
    if ds1_1 != ds1_4:
        logger.error('Datasets ds1_1  and ds1_4   are different!')

    if DataSet_NEW_FILL:
        if ds1_1 != ds1_5:
            logger.error('Datasets ds1_1  and ds1_5   are different!')

    with timing("No SHORTCUT, no FRAME", logger=None) as t1:
        logger.info(attention(t1.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=False,
                            use_frame=False,
                            max_files=1)
        ds1p_1 = selector.data
    with timing("   SHORTCUT, no FRAME", logger=None) as t2:
        logger.info(attention(t2.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=True,
                            use_frame=False,
                            max_files=1)
        ds1p_2 = selector.data
    with timing("No SHORTCUT,    FRAME", logger=None) as t3:
        logger.info(attention(t3.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=False,
                            use_frame=True,
                            max_files=1)
        ds1p_3 = selector.data
    with timing("   SHORTCUT,    FRAME", logger=None) as t4:
        logger.info(attention(t4.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=True,
                            use_frame=True,
                            max_files=1)
        ds1p_4 = selector.data

    table = [('Configuration', 'CPU')]

    table.append((t1.name, '%.3fs' % t1.delta))
    table.append((t2.name, '%.3fs' % t2.delta))
    table.append((t3.name, '%.3fs' % t3.delta))
    table.append((t4.name, '%.3fs' % t4.delta))

    title1p = "All trivial variables (parallel)"
    table1p = T.table(table, title=title1p, prefix='# ', alignment='rr')
    logger.info('%s\n%s' % (title1p, table1p))

    if ds1_1 != ds1p_1:
        logger.error('Datasets ds1_1  and ds1p_1  are different!')
    if ds1_2 != ds1p_2:
        logger.error('Datasets ds1_2  and ds1p_2  are different!')
    if ds1_3 != ds1p_3:
        logger.error('Datasets ds1_3  and ds1p_3  are different!')
    if ds1_4 != ds1p_4:
        logger.error('Datasets ds1_4  and ds1p_4  are different!')

    # =========================================================================
    logger.info(attention('Trivial variables + CUT'))
    # =========================================================================

    variables = [
        Variable(mJPsi, accessor='mass'),
        Variable('massMeV', 'mass in MeV', 3000, 3200, 'mass*1000'),
        Variable('vv102', 'vv10[2]', -1, 100, '1.0*vv10[2]'),
        Variable('fevt', accessor='1.0*evt'), ('pt', ), ('eta', ),
        ('x', 'some variable', 0, 5000, '(mass+pt+eta)/eta')
    ]

    if not DILL_PY3_issue:

        config = {
            'variables': variables,
            'selection': "pt>7 && eta<3",
            'cuts': lambda s: s.pt > 3
        }  ## ATTENTION: no trivial cuts!

    else:

        logger.warning('There is an issue with dill+python3: avoid lambda!')
        config = {
            'variables': variables,
            'selection': "pt>7 && eta<3",
            'cuts': ptcut
        }  ## ATTENTION: no trivial cuts!

    with timing("No SHORTCUT, no FRAME", logger=None) as t1:
        logger.info(attention(t1.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=False, use_frame=False)
        ds2_1 = selector.data
    with timing("   SHORTCUT, no FRAME", logger=None) as t2:
        logger.info(attention(t2.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=True, use_frame=False)
        ds2_2 = selector.data
    with timing("No SHORTCUT,    FRAME", logger=None) as t3:
        logger.info(attention(t3.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=False, use_frame=True)
        ds2_3 = selector.data
    with timing("   SHORTCUT,    FRAME", logger=None) as t4:
        logger.info(attention(t4.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=True, use_frame=True)
        ds2_4 = selector.data

    table = [('Configuration', 'CPU')]

    table.append((t1.name, '%.3fs' % t1.delta))
    table.append((t2.name, '%.3fs' % t2.delta))
    table.append((t3.name, '%.3fs' % t3.delta))
    table.append((t4.name, '%.3fs' % t4.delta))

    title2 = "Trivial variables + CUT"
    table2 = T.table(table, title=title2, prefix='# ', alignment='rr')
    logger.info('%s\n%s' % (title2, table2))

    if ds2_1 != ds2_2:
        logger.error('Datasets ds2_1  and ds2_2   are different!')
    if ds2_1 != ds2_3:
        logger.error('Datasets ds2_1  and ds2_3   are different!')
    if ds2_1 != ds2_4:
        logger.error('Datasets ds2_1  and ds2_4   are different!')

    with timing("No SHORTCUT, no FRAME", logger=None) as t1:
        logger.info(attention(t1.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=False,
                            use_frame=False,
                            maX_files=1)
        ds2p_1 = selector.data
    with timing("   SHORTCUT, no FRAME", logger=None) as t2:
        logger.info(attention(t2.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=True,
                            use_frame=False,
                            maX_files=1)
        ds2p_2 = selector.data
    with timing("No SHORTCUT,    FRAME", logger=None) as t3:
        logger.info(attention(t3.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=False,
                            use_frame=True,
                            max_files=1)
        ds2p_3 = selector.data
    with timing("   SHORTCUT,    FRAME", logger=None) as t4:
        logger.info(attention(t4.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=True,
                            use_frame=True,
                            max_files=1)
        ds2p_4 = selector.data

    table = [('Configuration', 'CPU')]

    table.append((t1.name, '%.3fs' % t1.delta))
    table.append((t2.name, '%.3fs' % t2.delta))
    table.append((t3.name, '%.3fs' % t3.delta))
    table.append((t4.name, '%.3fs' % t4.delta))

    title2p = "Trivial variables + CUT (parallel)"
    table2p = T.table(table, title=title2p, prefix='# ', alignment='rr')
    logger.info('%s\n%s' % (title2p, table2p))

    if ds1_1 != ds2_1:
        logger.error('Datasets ds1_1  and ds2_1   are different!')

    if ds2_1 != ds2p_1:
        logger.error('Datasets ds2_1  and ds2p_1  are different!')
    if ds2_2 != ds2p_2:
        logger.error('Datasets ds2_2  and ds2p_2  are different!')
    if ds2_3 != ds2p_3:
        logger.error('Datasets ds2_3  and ds2p_3  are different!')
    if ds2_4 != ds2p_4:
        logger.error('Datasets ds2_4  and ds2p_4  are different!')

    # =========================================================================
    logger.info(attention('Non-trivial variables'))
    # =========================================================================

    if not DILL_PY3_issue:

        variables = [
            Variable(mJPsi, accessor='mass'),
            Variable('massMeV', 'mass in MeV', 3000, 3200, 'mass*1000'),
            Variable('vv102', 'vv10[2]', -1, 100, '1.0*vv10[2]'),
            Variable('fevt', accessor='1.0*evt'), ('pt', ), ('eta', ),
            ('x', 'some variable', 0, 5000, lambda s:
             (s.mass + s.pt + s.eta) / s.eta)
        ]

    else:

        logger.warning('There is an issue with dill+python3: avoid lambda!')
        variables = [
            Variable(mJPsi, accessor='mass'),
            Variable('massMeV', 'mass in MeV', 3000, 3200, 'mass*1000'),
            Variable('vv102', 'vv10[2]', -1, 100, '1.0*vv10[2]'),
            Variable('fevt', accessor='1.0*evt'), ('pt', ), ('eta', ),
            ('x', 'some variable', 0, 5000, xvar)
        ]

    config = {'variables': variables, 'selection': "pt>7 && eta<3"}

    with timing("No SHORTCUT, no FRAME", logger=None) as t1:
        logger.info(attention(t1.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=False, use_frame=False)
        ds3_1 = selector.data
    with timing("   SHORTCUT, no FRAME", logger=None) as t2:
        logger.info(attention(t2.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=True, use_frame=False)
        ds3_2 = selector.data
    with timing("No SHORTCUT,    FRAME", logger=None) as t3:
        logger.info(attention(t3.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=False, use_frame=True)
        ds3_3 = selector.data
    with timing("   SHORTCUT,    FRAME", logger=None) as t4:
        logger.info(attention(t4.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=True, use_frame=True)
        ds3_4 = selector.data

    table = [('Configuration', 'CPU')]

    table.append((t1.name, '%.3fs' % t1.delta))
    table.append((t2.name, '%.3fs' % t2.delta))
    table.append((t3.name, '%.3fs' % t3.delta))
    table.append((t4.name, '%.3fs' % t4.delta))

    title3 = "Non-trivial variables"
    table3 = T.table(table, title=title3, prefix='# ', alignment='rr')
    logger.info('%s\n%s' % (title3, table3))

    if ds1_1 != ds3_1:
        logger.error('Datasets ds1_1  and ds3_1   are different!')

    if ds3_1 != ds3_2:
        logger.error('Datasets ds3_1  and ds2_2   are different!')
    if ds3_1 != ds3_3:
        logger.error('Datasets ds3_1  and ds2_3   are different!')
    if ds3_1 != ds3_4:
        logger.error('Datasets ds3_1  and ds2_4   are different!')

    with timing("No SHORTCUT, no FRAME", logger=None) as t1:
        logger.info(attention(t1.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=False,
                            use_frame=False,
                            max_files=1)
        ds3p_1 = selector.data
    with timing("   SHORTCUT, no FRAME", logger=None) as t2:
        logger.info(attention(t2.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=True,
                            use_frame=False,
                            max_files=1)
        ds3p_2 = selector.data
    with timing("No SHORTCUT,    FRAME", logger=None) as t3:
        logger.info(attention(t3.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=False,
                            use_frame=True,
                            max_files=1)
        ds3p_3 = selector.data
    with timing("   SHORTCUT,    FRAME", logger=None) as t4:
        logger.info(attention(t4.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=True,
                            use_frame=True,
                            max_files=1)
        ds3p_4 = selector.data

    table = [('Configuration', 'CPU')]

    table.append((t1.name, '%.3fs' % t1.delta))
    table.append((t2.name, '%.3fs' % t2.delta))
    table.append((t3.name, '%.3fs' % t3.delta))
    table.append((t4.name, '%.3fs' % t4.delta))

    title3p = "Non-trivial variables (parallel)"
    table3p = T.table(table, title=title3p, prefix='# ', alignment='rr')
    logger.info('%s\n%s' % (title3p, table3p))

    if ds3_1 != ds3p_1:
        logger.error('Datasets ds3_1  and ds3p_1  are different!')
    if ds3_2 != ds3p_2:
        logger.error('Datasets ds3_2  and ds3p_2  are different!')
    if ds3_3 != ds3p_3:
        logger.error('Datasets ds3_3  and ds3p_3  are different!')
    if ds3_4 != ds3p_4:
        logger.error('Datasets ds3_4  and ds3p_4  are different!')

    # =========================================================================
    logger.info(attention('Non-trivial variables + CUT'))
    # =========================================================================

    if not DILL_PY3_issue:

        variables = [
            Variable(mJPsi, accessor='mass'),
            Variable('massMeV', 'mass in MeV', 3000, 3200, 'mass*1000'),
            Variable('vv102', 'vv10[2]', -1, 100, '1.0*vv10[2]'),
            Variable('fevt', accessor='1.0*evt'), ('pt', ), ('eta', ),
            ('x', 'some variable', 0, 5000, lambda s:
             (s.mass + s.pt + s.eta) / s.eta)
        ]

    else:

        logger.warning('There is an issue with dill+python3: avoid lambda!')
        variables = [
            Variable(mJPsi, accessor='mass'),
            Variable('massMeV', 'mass in MeV', 3000, 3200, 'mass*1000'),
            Variable('vv102', 'vv10[2]', -1, 100, '1.0*vv10[2]'),
            Variable('fevt', accessor='1.0*evt'), ('pt', ), ('eta', ),
            ('x', 'some variable', 0, 5000, xvar)
        ]

    if not DILL_PY3_issue:

        config = {
            'variables': variables,
            'selection': "pt>7 && eta<3",
            'cuts': lambda s: s.pt > 3
        }  ## ATTENTION: no trivial cuts!
    else:

        logger.warning('There is an issue with dill+python3: avoid lambda!')
        config = {
            'variables': variables,
            'selection': "pt>7 && eta<3",
            'cuts': ptcut
        }  ## ATTENTION: no trivial cuts!

    with timing("No SHORTCUT, no FRAME", logger=None) as t1:
        logger.info(attention(t1.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=False, use_frame=False)
        ds4_1 = selector.data
    with timing("   SHORTCUT, no FRAME", logger=None) as t2:
        logger.info(attention(t2.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=True, use_frame=False)
        ds4_2 = selector.data
    with timing("No SHORTCUT,    FRAME", logger=None) as t3:
        logger.info(attention(t3.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=False, use_frame=True)
        ds4_3 = selector.data
    with timing("   SHORTCUT,    FRAME", logger=None) as t4:
        logger.info(attention(t4.name))
        selector = SelectorWithVars(**config)
        chain.fill_dataset(selector, shortcut=True, use_frame=True)
        ds4_4 = selector.data

    table = [('Configuration', 'CPU')]

    table.append((t1.name, '%.3fs' % t1.delta))
    table.append((t2.name, '%.3fs' % t2.delta))
    table.append((t3.name, '%.3fs' % t3.delta))
    table.append((t4.name, '%.3fs' % t4.delta))

    title4 = "Non-trivial variables + CUT"
    table4 = T.table(table, title=title4, prefix='# ', alignment='rr')
    logger.info('%s\n%s' % (title4, table4))

    if ds1_1 != ds4_1:
        logger.error('Datasets ds1_1  and ds4_1   are different!')

    if ds4_1 != ds4_2:
        logger.error('Datasets ds4_1  and ds4_2   are different!')
    if ds4_1 != ds4_3:
        logger.error('Datasets ds4_1  and ds4_3   are different!')
    if ds4_1 != ds4_4:
        logger.error('Datasets ds4_1  and ds4_4   are different!')

    with timing("No SHORTCUT, no FRAME", logger=None) as t1:
        logger.info(attention(t1.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=False,
                            use_frame=False,
                            max_files=1)
        ds4p_1 = selector.data
    with timing("   SHORTCUT, no FRAME", logger=None) as t2:
        logger.info(attention(t2.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=True,
                            use_frame=False,
                            max_files=1)
        ds4p_2 = selector.data
    with timing("No SHORTCUT,    FRAME", logger=None) as t3:
        logger.info(attention(t3.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=False,
                            use_frame=True,
                            max_files=1)
        ds4p_3 = selector.data
    with timing("   SHORTCUT,    FRAME", logger=None) as t4:
        logger.info(attention(t4.name))
        selector = SelectorWithVars(**config)
        chain.parallel_fill(selector,
                            shortcut=True,
                            use_frame=True,
                            max_files=1)
        ds4p_4 = selector.data

    table = [('Configuration', 'CPU')]

    table.append((t1.name, '%.3fs' % t1.delta))
    table.append((t2.name, '%.3fs' % t2.delta))
    table.append((t3.name, '%.3fs' % t3.delta))
    table.append((t4.name, '%.3fs' % t4.delta))

    title4p = "Non-trivial variables + CUT (parallel)"
    table4p = T.table(table, title=title4p, prefix='# ', alignment='rr')
    logger.info('%s\n%s' % (title4p, table4p))

    if ds4_1 != ds4p_1:
        logger.error('Datasets ds4_1  and ds4p_1  are different!')
    if ds4_2 != ds4p_2:
        logger.error('Datasets ds4_2  and ds4p_2  are different!')
    if ds4_3 != ds4p_3:
        logger.error('Datasets ds4_3  and ds4p_3  are different!')
    if ds4_4 != ds4p_4:
        logger.error('Datasets ds4_4  and ds4p_4  are different!')

    logger.info('%s\n%s' % (title1, table1))
    logger.info('%s\n%s' % (title1p, table1p))

    logger.info('%s\n%s' % (title2, table2))
    logger.info('%s\n%s' % (title2p, table2p))

    logger.info('%s\n%s' % (title3, table3))
    logger.info('%s\n%s' % (title3p, table3p))

    logger.info('%s\n%s' % (title4, table4))
    logger.info('%s\n%s' % (title4p, table4p))