Example #1
0
def correlated_values(param_names, roofitresult):
    """
    Return symbolic values from a `RooFitResult` taking into account covariance

    This is useful for numerically computing the uncertainties for expressions
    using correlated values arising from a fit.

    Parameters
    ----------

    param_names: list of strings
        A list of parameters to extract from the result. The order of the names
        is the order of the return value.

    roofitresult : RooFitResult
        A RooFitResult from a fit.

    Returns
    -------

    list of correlated values from the uncertainties package.

    Examples
    --------

    .. sourcecode:: python

        # Fit a pdf to a histogram
        pdf = some_roofit_pdf_with_variables("f(x, a, b, c)")
        fitresult = pdf.fitTo(histogram, ROOT.RooFit.Save())
        a, b, c = correlated_values(["a", "b", "c"], fitresult)
        # Arbitrary math expression according to what the `uncertainties`
        # package supports, automatically computes correct error propagation
        sum_value = a + b + c
        value, error = sum_value.nominal_value, sum_value.std_dev()

    """
    pars = roofitresult.floatParsFinal()
    #pars.Print()
    pars = [pars[i] for i in range(pars.getSize())]
    parnames = [p.GetName() for p in pars]

    values = [(p.getVal(), p.getError()) for p in pars]
    #values = [as_ufloat(p) for p in pars]
    matrix = asrootpy(roofitresult.correlationMatrix()).to_numpy()

    uvalues = U.correlated_values_norm(values, matrix.tolist())
    uvalues = dict((n, v) for n, v in zip(parnames, uvalues))

    assert all(
        n in uvalues
        for n in parnames), ("name {0} isn't in parameter list {1}".format(
            n, parnames))

    # Return a tuple in the order it was asked for
    return tuple(uvalues[n] for n in param_names)
def correlated_values(param_names, roofitresult):
    """
    Return symbolic values from a `RooFitResult` taking into account covariance

    This is useful for numerically computing the uncertainties for expressions
    using correlated values arising from a fit.

    Parameters
    ----------

    param_names: list of strings
        A list of parameters to extract from the result. The order of the names
        is the order of the return value.

    roofitresult : RooFitResult
        A RooFitResult from a fit.

    Returns
    -------

    list of correlated values from the uncertainties package.

    Examples
    --------

    .. sourcecode:: python

        # Fit a pdf to a histogram
        pdf = some_roofit_pdf_with_variables("f(x, a, b, c)")
        fitresult = pdf.fitTo(histogram, ROOT.RooFit.Save())
        a, b, c = correlated_values(["a", "b", "c"], fitresult)
        # Arbitrary math expression according to what the `uncertainties`
        # package supports, automatically computes correct error propagation
        sum_value = a + b + c
        value, error = sum_value.nominal_value, sum_value.std_dev()

    """
    pars = roofitresult.floatParsFinal()
    #pars.Print()
    pars = [pars[i] for i in range(pars.getSize())]
    parnames = [p.GetName() for p in pars]

    values = [(p.getVal(), p.getError()) for p in pars]
    #values = [as_ufloat(p) for p in pars]
    matrix = asrootpy(roofitresult.correlationMatrix()).to_numpy()

    uvalues = U.correlated_values_norm(values, matrix.tolist())
    uvalues = dict((n, v) for n, v in zip(parnames, uvalues))

    assert all(n in uvalues for n in parnames), (
        "name {0} isn't in parameter list {1}".format(n, parnames))

    # Return a tuple in the order it was asked for
    return tuple(uvalues[n] for n in param_names)
Example #3
0
def correlated(input1, input2, operation="+", correlation=1.0):
    corr_matrix = np.array([[1.0, correlation], [correlation, 1.0]])
    (output1, output2) = unc.correlated_values_norm([(input1.n, input1.s), (input2.n, input2.s)], corr_matrix)
    if operation == "+":
        return output1 + output2
    elif operation == "-":
        return output1 - output2
    elif operation == "*":
        return output1 * output2
    elif operation == "/":
        return output1 / output2 if output2 > 0.0 else unc.ufloat(np.inf, np.inf)
    else:
        return unc.float(np.nan, np.nan)
Example #4
0
def correlated(input1, input2, operation="+", correlation=1.0):
    corr_matrix = np.array([[1., correlation], [correlation, 1.]])
    (output1, output2) = unc.correlated_values_norm([(input1.n, input1.s),
                                                     (input2.n, input2.s)],
                                                    corr_matrix)
    if operation == "+": return output1 + output2
    elif operation == "-": return output1 - output2
    elif operation == "*": return output1 * output2
    elif operation == "/":
        return output1 / output2 if output2 > 0. else unc.ufloat(
            np.inf, np.inf)
    else:
        return unc.float(np.nan, np.nan)
Example #5
0
    def test_correlated_values_correlation_mat():
        '''
        Tests the input of correlated value.

        Test through their correlation matrix (instead of the
        covariance matrix).
        '''

        x = ufloat((1, 0.1))
        y = ufloat((2, 0.3))
        z = -3 * x + y

        cov_mat = uncertainties.covariance_matrix([x, y, z])

        std_devs = numpy.sqrt(numpy.array(cov_mat).diagonal())

        corr_mat = cov_mat / std_devs / std_devs[numpy.newaxis].T

        # We make sure that the correlation matrix is indeed diagonal:
        assert (corr_mat - corr_mat.T).max() <= 1e-15
        # We make sure that there are indeed ones on the diagonal:
        assert (corr_mat.diagonal() - 1).max() <= 1e-15

        # We try to recover the correlated variables through the
        # correlation matrix (not through the covariance matrix):

        nominal_values = [v.nominal_value for v in (x, y, z)]
        std_devs = [v.std_dev() for v in (x, y, z)]
        x2, y2, z2 = uncertainties.correlated_values_norm(
            list(zip(nominal_values, std_devs)), corr_mat)

        # matrices_close() is used instead of _numbers_close() because
        # it compares uncertainties too:

        # Test of individual variables:
        assert matrices_close(numpy.array([x]), numpy.array([x2]))
        assert matrices_close(numpy.array([y]), numpy.array([y2]))
        assert matrices_close(numpy.array([z]), numpy.array([z2]))

        # Partial correlation test:
        assert matrices_close(numpy.array([0]),
                              numpy.array([z2 - (-3 * x2 + y2)]))

        # Test of the full covariance matrix:
        assert matrices_close(
            numpy.array(cov_mat),
            numpy.array(uncertainties.covariance_matrix([x2, y2, z2])))
Example #6
0
    def test_correlated_values_correlation_mat():
        '''
        Tests the input of correlated value.

        Test through their correlation matrix (instead of the
        covariance matrix).
        '''

        x = ufloat((1, 0.1))
        y = ufloat((2, 0.3))
        z = -3*x+y

        cov_mat = uncertainties.covariance_matrix([x, y, z])

        std_devs = numpy.sqrt(numpy.array(cov_mat).diagonal())

        corr_mat = cov_mat/std_devs/std_devs[numpy.newaxis].T

        # We make sure that the correlation matrix is indeed diagonal:
        assert (corr_mat-corr_mat.T).max() <= 1e-15
        # We make sure that there are indeed ones on the diagonal:
        assert (corr_mat.diagonal()-1).max() <= 1e-15

        # We try to recover the correlated variables through the
        # correlation matrix (not through the covariance matrix):

        nominal_values = [v.nominal_value for v in (x, y, z)]
        std_devs = [v.std_dev() for v in (x, y, z)]
        x2, y2, z2 = uncertainties.correlated_values_norm(
            list(zip(nominal_values, std_devs)), corr_mat)

        # matrices_close() is used instead of _numbers_close() because
        # it compares uncertainties too:

        # Test of individual variables:
        assert matrices_close(numpy.array([x]), numpy.array([x2]))
        assert matrices_close(numpy.array([y]), numpy.array([y2]))
        assert matrices_close(numpy.array([z]), numpy.array([z2]))

        # Partial correlation test:
        assert matrices_close(numpy.array([0]), numpy.array([z2-(-3*x2+y2)]))

        # Test of the full covariance matrix:
        assert matrices_close(
            numpy.array(cov_mat),
            numpy.array(uncertainties.covariance_matrix([x2, y2, z2])))
def geometric_elements_with_uncertainties(thiele_innes_parameters,
                                          thiele_innes_parameters_errors=None,
                                          correlation_matrix=None,
                                          post_process=False,
                                          return_angles_in_deg=True):
    """
    Return geometrical orbit elements a, omega, OMEGA, i. If errors are not given
    they are assumed to be 0 and correlation matrix is set to identity.
    Complement to the pystrometry.geometric_elements function that allows to 
    compute parameter uncertainties as well.

    Parameters
    ----------
    thiele_innes_parameters : array
        Array of Thiele Innes parameters [A,B,F,G] in milli-arcsecond
    thiele_innes_parameters_errors : array, optional
        Array of the errors of the Thiele Innes parameters [A,B,F,G] in milli-arcsecond
    correlation_matrix : (4, 4) array, optional
        Correlation matrix for the Thiele Innes parameters [A,B,F,G]

    Returns
    -------
    geometric_parameters : array
        Orbital elements [a_mas, omega_deg, OMEGA_deg, i_deg]
    geometric_parameters_errors : array
        Errors of the orbital elements [a_mas, omega_deg, OMEGA_deg, i_deg]

    """

    # Checks on the errors and correlation matrix
    if (thiele_innes_parameters_errors is None) and (correlation_matrix is
                                                     None):
        # Define errors to 0 and correlation matrix to identity
        thiele_innes_parameters_errors = [0, 0, 0, 0]
        correlation_matrix = np.identity(4)
    elif (thiele_innes_parameters_errors is not None) and (correlation_matrix
                                                           is not None):
        # If both are given continue to the calculation
        pass
    else:
        # If either one of them is provided but not the other raise an error
        raise ValueError("thieles_innes_parameters_erros and correlation_matrix must be" \
                          "specified together.")

    # Define uncorrelated (value, uncertainty) pairs
    A_u = (thiele_innes_parameters[0], thiele_innes_parameters_errors[0])
    B_u = (thiele_innes_parameters[1], thiele_innes_parameters_errors[1])
    F_u = (thiele_innes_parameters[2], thiele_innes_parameters_errors[2])
    G_u = (thiele_innes_parameters[3], thiele_innes_parameters_errors[3])

    # Create correlated quantities
    A, B, F, G = correlated_values_norm([A_u, B_u, F_u, G_u],
                                        correlation_matrix)

    p = (A**2 + B**2 + G**2 + F**2) / 2.
    q = A * G - B * F

    a_mas = unp.sqrt(p + unp.sqrt(p**2 - q**2))
    i_rad = unp.arccos(q / (a_mas**2.))
    omega_rad = (unp.arctan2(B - F, A + G) + unp.arctan2(-B - F, A - G)) / 2.
    OMEGA_rad = (unp.arctan2(B - F, A + G) - unp.arctan2(-B - F, A - G)) / 2.

    if post_process:
        # convert angles to nominal ranges
        omega_rad, OMEGA_rad = pystrometry.adjust_omega_OMEGA(
            omega_rad, OMEGA_rad)

    if return_angles_in_deg:
        # Convert radians to degrees
        i_deg = i_rad * 180 / np.pi
        omega_deg = omega_rad * 180 / np.pi
        OMEGA_deg = OMEGA_rad * 180 / np.pi
    else:
        i_deg = i_rad
        omega_deg = omega_rad
        OMEGA_deg = OMEGA_rad

    # Extract nominal values and standard deviations
    geometric_parameters = np.array([
        unp.nominal_values(a_mas),
        unp.nominal_values(omega_deg),
        unp.nominal_values(OMEGA_deg),
        unp.nominal_values(i_deg)
    ])

    geometric_parameters_errors = np.array([
        unp.std_devs(a_mas),
        unp.std_devs(omega_deg),
        unp.std_devs(OMEGA_deg),
        unp.std_devs(i_deg)
    ])

    return geometric_parameters, geometric_parameters_errors
Example #8
0
    def calculate(self, dataframe, ibin):

        # >>> acceptance selection
        var0 = [True,]*len(dataframe)
        if self.delR:
            var0 = var0 & (dataframe['delR'] > self.delR)
        if self.delDxy:
            var0 = var0 & (dataframe['delDxy'] < self.delDxy)
        if self.delDz:
            var0 = var0 & (dataframe['delDz'] < self.delDz)

        if all(var0):
            df = dataframe.copy()
        else:
            df = dataframe.loc[var0].copy()
        # <<< acceptance selection

        # >>> columns for tnp efficiency
        df['pass_muon'] = df['muon_ID'] >= self.ID
        df['pass_antiMuon'] = df['antiMuon_ID'] >= self.ID
        if self.pfIso:
            df['pass_muon'] = df['pass_muon'] & (df['muon_pfIso'] < self.pfIso)
            df['pass_antiMuon'] = df['pass_antiMuon'] & (df['antiMuon_pfIso'] < self.pfIso)

        if self.tkIso:
            df['pass_muon'] = df['pass_muon'] & (df['muon_tkIso'] < self.tkIso)
            df['pass_antiMuon'] = df['pass_antiMuon'] & (df['antiMuon_tkIso'] < self.tkIso)

        df['pass_muon_antiMuon'] = df['pass_muon'] & df['pass_antiMuon']

        nMinus = df['pass_muon'].sum()
        nPlus = df['pass_antiMuon'].sum()
        nPlusMinus = df['pass_muon_antiMuon'].sum()

        if self.HLT:
            df['pass_muon_HLT'] = df['pass_muon_antiMuon'] & df['muon_hlt_{0}'.format(self.HLT)]
            df['pass_antiMuon_HLT'] = df['pass_muon_antiMuon'] & df['antiMuon_hlt_{0}'.format(self.HLT)]
            df['pass_muon_antiMuon_HLT'] = df['pass_muon_HLT'] & df['pass_antiMuon_HLT']

            nMinus_HLT = df['pass_muon_HLT'].sum()
            nPlus_HLT = df['pass_antiMuon_HLT'].sum()
            nPlusMinus_HLT = df['pass_muon_antiMuon_HLT'].sum()
        # <<< columns for tnp efficiency

        # >>> columns for true efficiency
        if self.HLT:
            df['reco'] = df['pass_muon_antiMuon'] & (df['pass_muon_HLT'] | df['pass_antiMuon_HLT'])
        else:
            df['reco'] = df['pass_muon_antiMuon']

        df['not_reco'] = ~df['reco']

        nZReco = df['reco'].sum()
        nZNotReco = df['not_reco'].sum()
        # <<< columns for true efficiency

        # >>> construct full covariance matrix
        if self.HLT:
            corr_matrix = df[['reco','not_reco','pass_muon_antiMuon','pass_muon','pass_antiMuon','pass_muon_antiMuon_HLT','pass_muon_HLT','pass_antiMuon_HLT']].corr()

            nZReco, nZNotReco, nPlusMinus, nMinus, nPlus, nPlusMinus_HLT, nMinus_HLT, nPlus_HLT = unc.correlated_values_norm(
                [(nZReco, np.sqrt(nZReco)), (nZNotReco, np.sqrt(nZNotReco)),
                (nPlusMinus, np.sqrt(nPlusMinus)), (nMinus, np.sqrt(nMinus)), (nPlus, np.sqrt(nPlus)),
                (nPlusMinus_HLT, np.sqrt(nPlusMinus_HLT)), (nMinus_HLT, np.sqrt(nMinus_HLT)), (nPlus_HLT, np.sqrt(nPlus_HLT))],
                corr_matrix)

        else:
            corr_matrix = df[['reco','not_reco','pass_muon_antiMuon','pass_muon','pass_antiMuon']].corr()

            nZReco, nZNotReco, nPlusMinus, nMinus, nPlus = unc.correlated_values_norm(
                [(nZReco, np.sqrt(nZReco)), (nZNotReco, np.sqrt(nZNotReco)),
                (nPlusMinus, np.sqrt(nPlusMinus)), (nMinus, np.sqrt(nMinus)), (nPlus, np.sqrt(nPlus))],
                corr_matrix)
        # <<< construct full covariance matrix

        # >>> compute true and tnp efficiency
        eff_true = nZReco / (nZNotReco + nZReco)

        MuPlusEff = nPlusMinus/nMinus
        MuMinusEff = nPlusMinus/nPlus

        eff_tnp = MuPlusEff * MuMinusEff

        if self.HLT:
            MuPlusEff_HLT = nPlusMinus_HLT/nMinus_HLT
            MuMinusEff_HLT = nPlusMinus_HLT/nPlus_HLT

            eff_tnpZ = (1 - (1 - MuPlusEff_HLT) * (1 - MuMinusEff_HLT) ) * eff_tnp
        # <<< compute true and tnp efficiency
        else:
            eff_tnpZ = eff_tnp

        # >>> store
        self.eff_corr.append(unc.covariance_matrix([eff_tnpZ, eff_true]))
        self.eff_tnp.append(eff_tnp)
        self.eff_tnpZ.append(eff_tnpZ)
        self.eff_true.append(eff_true)
Example #9
0
import numpy as np
import ROOT
import matplotlib.pyplot as plt
import uncertainties as unc

lPHYS = np.array([36.330, 41.480, 59.830])
lPHYS_Unc = np.array([0.424, 0.962, 1.501])

cPHYS = np.array([[1.00, 0.20, 0.41], [0.20, 1.00, 0.34], [0.41, 0.34, 1.00]])

uPHYS = unc.correlated_values_norm(zip(lPHYS, lPHYS_Unc), cPHYS)

# --- from combination of high pileup Z counts
hasZ = [0, 1, 1, 0]
lZ = np.array([41.480, 59.830])
lZ_Unc = np.array([0.637, 1.486])

cZ = np.array([[1.00, 1.00], [1.00, 1.00]])

uZ = unc.correlated_values_norm(zip(lZ, lZ_Unc), cZ)

lComb = np.array([36.330, 41.480, 59.830])
lComb_Unc = np.array([0.405, 0.536, 1.060])

cComb = np.array([[1.00, 0.81, 0.56], [0.81, 1.00, 0.94], [0.56, 0.94, 1.00]])

uComb = unc.correlated_values_norm(zip(lComb, lComb_Unc), cComb)

# # --- from combination of 2017H lumi with high pileup Z counts
# hasZ = [1,1,1,1]
# lZ = np.array([36.330,41.480,59.830])
def test_uncertainties_comparison_general():
  import uncertainties
  from uncertainties import ufloat
  # compare error propagation.
  x = UQ_( '2.5 +/- 0.5 m' )
  y = UQ_( '2.5 +/- 0.5 m' )
  w = x

  xx = ufloat( 2.5, 0.5 )
  yy = ufloat( 2.5, 0.5 )
  ww = xx

  z = x+y
  zz = xx+yy
  assert Close( z.nominal.magnitude, zz.nominal_value, 1e-5 )
  assert Close( z.uncertainty.magnitude, zz.std_dev, 1e-5 )

  z = x-y/2
  zz = xx-yy/2
  assert Close( z.nominal.magnitude, zz.nominal_value, 1e-5 )
  assert Close( z.uncertainty.magnitude, zz.std_dev, 1e-5 )

  z = x*y
  zz = xx*yy
  assert Close( z.nominal.magnitude, zz.nominal_value, 1e-5 )
  assert Close( z.uncertainty.magnitude, zz.std_dev, 1e-5 )

  z = x/y
  zz = xx/yy
  assert Close( z.nominal.magnitude, zz.nominal_value, 1e-5 )
  # linear approximation differs here!
  assert not Close( z.uncertainty.magnitude, zz.std_dev, 1e-5 )


  z = w - x
  zz = ww - xx
  assert Close( z.nominal.magnitude, 0, 1e-5 )
  assert Close( z.nominal.magnitude, zz.nominal_value, 1e-5 )
  assert Close( z.uncertainty.magnitude, zz.std_dev, 1e-5 )

  # add correlation
  x.correlated(y,1)
  (xx,yy) = uncertainties.correlated_values_norm( [(2.5,0.5), (2.5,0.5)], [ [1,1],[1,1] ] )
  z = x - y
  zz = xx - yy
  assert Close( z.nominal.magnitude, 0, 1e-5 )
  assert Close( z.nominal.magnitude, zz.nominal_value, 1e-5 )
  assert Close( z.uncertainty.magnitude, zz.std_dev, 1e-5 )


  num = 2
  data = [ UQ_('2 +/- 0.1 m') ] * num
  ddata = [ ufloat(2,0.1) ] * num

  z = sum(data)
  zz = sum(ddata)

  assert Close( z.nominal.magnitude, 2*2, 1e-5 )
  assert Close( z.uncertainty.magnitude, (2*0.1), 1e-5 )
  assert Close( z.nominal.magnitude, zz.nominal_value, 1e-5 )
  assert Close( z.uncertainty.magnitude, zz.std_dev, 1e-5 )


  num = 10
  data = [ UQ_('2 +/- 0.1 m') ] * num
  ddata = [ ufloat(2,0.1) ] * num

  z = sum(data)
  zz = sum(ddata)

  assert Close( z.nominal.magnitude, 10*2, 1e-5 )
  assert Close( z.uncertainty.magnitude, (10*0.1), 1e-5 )
  assert Close( z.nominal.magnitude, zz.nominal_value, 1e-5 )
  assert Close( z.uncertainty.magnitude, zz.std_dev, 1e-5 )


  zz = 2*xx
  ww = zz + yy

  z = 2*x
  w = z + y

  corr = uncertainties.correlation_matrix( [xx,yy,zz,ww] )

  assert x.correlation(x) == corr[0][0]
  assert x.correlation(y) == corr[0][1]
  assert x.correlation(z) == corr[0][2]
  assert x.correlation(w) == corr[0][3]
  assert x.correlation(x) == corr[0][0]
  assert y.correlation(x) == corr[1][0]
  assert z.correlation(x) == corr[2][0]
  assert w.correlation(x) == corr[3][0]