示例#1
0
    def checkInstallation(self, compile=True):
        """
        Checks if installation of tool is correct by looking for executable and
        executing it. If check is False and compile is True, then try and compile it.

        :returns: True, if everything is ok

        """
        if not os.path.exists(self.executablePath):
            if compile:
                logger.warn(
                    "%s executable not found. Trying to compile it now. This may take a while."
                    % self.name)
                self.compile()
            else:
                logger.warn("%s exectuable not found." % self.name)
                self.complain()
                return False
        if not os.path.exists(self.executablePath):
            logger.error(
                "Compilation of %s failed Is a according compiler installed?" %
                self.name)
            self.complain()
        if not os.access(self.executablePath, os.X_OK):
            logger.warning("%s is not executable Trying to chmod" %
                           self.executable)
            self.chmod()
        return True
示例#2
0
 def writeToFile(self, args):
     toFile = None
     if args.tofile:
         toFile = "highest"
     if args.alltofile:
         if toFile == "highest":
             logger.warn ( "Specified both --tofile and --alltofile. Will use "\
                           "--alltofile" )
         toFile = "all"
     return toFile
示例#3
0
    def unlink(self, unlinkdir=True):
        """
        Remove temporary files.

        :param unlinkdir: remove temp directory completely

        """
        if self.tempdir == None:
            return
        if self.keepTempDir:
            logger.warn("Keeping everything in " + self.tempdir)
            return
        logger.debug( "Unlinking " + self.tempdir )
        for inputFile in ["fort.61", "fort.68", "log"]:
            if os.path.exists(self.tempdir + "/" + inputFile):
                os.unlink(self.tempdir + "/" + inputFile)
        if unlinkdir:
            for inputFile in ["temp.cfg"]:
                os.unlink(self.tempdir + "/" + inputFile)
            if os.path.exists(self.tempdir):
                os.rmdir(self.tempdir)
                self.tempdir = None
示例#4
0
    def checkInstallation(self, compile=True ):
        """
        Checks if installation of tool is correct by looking for executable and
        executing it. If check is False and compile is True, then try and compile it.

        :returns: True, if everything is ok

        """
        if not os.path.exists(self.executablePath):
            if compile:
                logger.warn("%s executable not found. Trying to compile it now. This may take a while." % self.name )
                self.compile()
            else:
                logger.warn("%s exectuable not found." % self.name )
                self.complain()
                return False
        if not os.path.exists(self.executablePath):
            logger.error("Compilation of %s failed Is a according compiler installed?" % self.name )
            self.complain()
        if not os.access(self.executablePath, os.X_OK):
            logger.warning("%s is not executable Trying to chmod" % self.executable)
            self.chmod()
        return True
示例#5
0
def likelihoodFromLimits(upperLimit, expectedUpperLimit, nsig, nll=False):
    """ computes the likelihood from an expected and an observed upper limit.
    :param upperLimit: observed upper limit, as a yield (i.e. unitless)
    :param expectedUpperLimit: expected upper limit, also as a yield
    :param nSig: number of signal events
    :param nll: if True, return negative log likelihood

    :returns: likelihood (float)
    """
    assert (upperLimit > 0.)

    def getSigma(ul, muhat=0.):
        """ get the standard deviation sigma, given
            an upper limit and a central value. assumes a truncated Gaussian likelihood """
        # the expected scale, eq 3.24 in arXiv:1202.3415
        return (ul - muhat) / 1.96

    def llhd(nsig, mumax, sigma_exp, nll):
        ## need to account for the truncation!
        ## first compute how many sigmas left of center is 0.
        Zprime = mumax / sigma_exp
        ## now compute the area of the truncated gaussian
        A = stats.norm.cdf(Zprime)
        if nll:
            return np.log(A) - stats.norm.logpdf(nsig, mumax, sigma_exp)
        return float(stats.norm.pdf(nsig, mumax, sigma_exp) / A)

    dr = 2. * (upperLimit - expectedUpperLimit) / (expectedUpperLimit +
                                                   upperLimit)
    if dr > runtime._drmax:
        if runtime._cap_likelihoods == False:
            logger.warn(
                "asking for likelihood from limit but difference between oUL(%.2f) and eUL(%.2f) is too large (dr=%.2f>%.2f)"
                % (upperLimit, expectedUpperLimit, dr, runtime._drmax))
            return None
        oldUL = upperLimit
        upperLimit = expectedUpperLimit * (2. + runtime._drmax) / (
            2. - runtime._drmax)
        logger.warn("asking for likelihood from limit but difference between oUL(%.2f) and eUL(%.2f) is too large (dr=%.2f>%.2f). capping to %.2f." % \
                ( oldUL, expectedUpperLimit, dr, runtime._drmax, upperLimit ) )
        ## we are asked to cap likelihoods, so we set observed UL such that dr == drmax

    # sigma_exp = expectedUpperLimit / 1.96 # the expected scale, eq 3.24 in arXiv:1202.3415
    sigma_exp = getSigma(
        expectedUpperLimit)  # the expected scale, eq 3.24 in arXiv:1202.3415
    if upperLimit < expectedUpperLimit:
        ## underfluctuation. mumax = 0.
        return llhd(nsig, 0., sigma_exp, nll)

    def root_func(x):  ## we want the root of this one
        return (erf((upperLimit - x) / denominator) +
                erf(x / denominator)) / (1. + erf(x / denominator)) - .95

    denominator = np.sqrt(2.) * sigma_exp

    fA = root_func(0.)
    fB = root_func(max(upperLimit, expectedUpperLimit))
    if np.sign(fA * fB) > 0.:
        ## the have the same sign
        logger.error("when computing likelihood: fA and fB have same sign")
        return None
    mumax = optimize.brentq(root_func,
                            0.,
                            max(upperLimit, expectedUpperLimit),
                            rtol=1e-03,
                            xtol=1e-06)
    llhdexp = llhd(nsig, mumax, sigma_exp, nll)
    return llhdexp
示例#6
0
def llhdFromLimits_moments(upperLimit,
                           expectedUpperLimit,
                           nll=False,
                           underfluct="norm_0"):
    """Compute the Expected Value, Variance, Skewness and Mode of normalized Likelihood that was computed with the Expected and observed Upper Limit.
    :param upperLimit: observed upper limit, as a yield (i.e. unitless)
    :param expectedUpperLimit: expected upper limit, also as a yield
    :param nSig: number of signal events
    :param nll: if True, return negative log likelihood
    :param underfluct: How to handle Unfderfluctuations, "norm_0" uses a gaussian with maximum at 0,
        "norm_neg" uses a gaussian with negative maximum, "exp" uses an exponential distribution,
        defaults to "norm_0"


    :returns: EV, Var, Skew and Mode of computed Likelihood as dict
    """
    assert (upperLimit > 0.)

    def getSigma(ul, muhat=0.):
        """ get the standard deviation sigma, given
            an upper limit and a central value. assumes a truncated Gaussian likelihood """
        # the expected scale, eq 3.24 in arXiv:1202.3415
        return (ul - muhat) / 1.96

    sigma_exp = getSigma(
        expectedUpperLimit)  # the expected scale, eq 3.24 in arXiv:1202.3415

    denominator = np.sqrt(2.) * sigma_exp

    def root_func(x):  ## we want the root of this one
        return (erf((upperLimit - x) / denominator) +
                erf(x / denominator)) / (1. + erf(x / denominator)) - .95

    def find_neg_mumax(upperLimit, expectedUpperLimit, xa, xb):
        while root_func(xa) * root_func(xb) > 0:
            xa = 2 * xa
        mumax = optimize.brentq(root_func, xa, xb, rtol=1e-03, xtol=1e-06)
        return mumax

    def getLam(ul):
        """ get the scale for the exponential destribution that reproduces the upper limit"""
        return -np.log(0.05) / ul

    def llhdexponential(nsig, lam, nll):
        ## exponential distribution
        if nll:
            return float(lam * nsig - np.log(lam))
        return float(stats.expon.pdf(nsig, scale=1 / lam))

    def trunc_norm_moments(mumax, sigma):
        rho = np.exp(
            -mumax**2 /
            (2 * sigma**2)) / (np.sqrt(2 * np.pi) *
                               (1 - stats.norm.cdf(0, loc=mumax, scale=sigma)))
        h = -mumax / sigma

        ev = mumax + (sigma * rho)
        var = sigma**2 * (1 + rho * h - rho**2)
        #skew = sigma**3 * rho* ( (rho-h)**2 + rho*(rho-h) - 1 )
        skew = rho * (2 * rho**2 - 3 * rho * h + h**2 - 1) / (1 + h * rho -
                                                              rho**2)**(3 / 2)
        #skew = sigma*rho*(ev**2 - var)
        if mumax < 0:
            mod = 0.
        else:
            mod = mumax

        return ({"ev": ev, "var": var, "skew": skew, "mode": mod})

    def exp_moments(lam):
        ev = 1 / lam
        var = 1 / (lam)**2
        skew = 2
        mod = 0.
        return ({"ev": ev, "var": var, "skew": skew, "mode": mod})

    dr = 2. * (upperLimit - expectedUpperLimit) / (expectedUpperLimit +
                                                   upperLimit)
    if dr > runtime._drmax:
        if runtime._cap_likelihoods == False:
            logger.warn(
                "asking for likelihood from limit but difference between oUL(%.2f) and eUL(%.2f) is too large (dr=%.2f>%.2f)"
                % (upperLimit, expectedUpperLimit, dr, runtime._drmax))
            return None
        oldUL = upperLimit
        upperLimit = expectedUpperLimit * (2. + runtime._drmax) / (
            2. - runtime._drmax)
        logger.warn("asking for likelihood from limit but difference between oUL(%.2f) and eUL(%.2f) is too large (dr=%.2f>%.2f). capping to %.2f." % \
                ( oldUL, expectedUpperLimit, dr, runtime._drmax, upperLimit ) )
        ## we are asked to cap likelihoods, so we set observed UL such that dr == drmax

    if upperLimit <= expectedUpperLimit:
        ## underfluctuation.
        if underfluct == "norm_0":
            mumax = 0
            return trunc_norm_moments(mumax, sigma_exp)
        elif underfluct == "norm_neg":
            xa = -expectedUpperLimit
            xb = 1
            mumax = find_neg_mumax(upperLimit, expectedUpperLimit, xa, xb)
            return trunc_norm_moments(mumax, sigma_exp)
        elif underfluct == "exp":
            lam = getLam(upperLimit)
            return exp_moments(lam)
        else:
            logger.warn(
                "underfluct not defined, choose one of norm_0, norm_neg and exp"
            )

    fA = root_func(0.)
    fB = root_func(max(upperLimit, expectedUpperLimit))
    if np.sign(fA * fB) > 0.:
        ## the have the same sign
        logger.error("when computing likelihood: fA and fB have same sign")
        return None
    mumax = optimize.brentq(root_func,
                            0.,
                            max(upperLimit, expectedUpperLimit),
                            rtol=1e-03,
                            xtol=1e-06)
    return trunc_norm_moments(mumax, sigma_exp)
示例#7
0
def likelihoodFromLimits(upperLimit,
                         expectedUpperLimit,
                         nsig,
                         nll=False,
                         underfluct="norm_0"):
    """ computes the likelihood from an expected and an observed upper limit.
    :param upperLimit: observed upper limit, as a yield (i.e. unitless)
    :param expectedUpperLimit: expected upper limit, also as a yield
    :param nSig: number of signal events
    :param nll: if True, return negative log likelihood
    :param underfluct: How to handle Unfderfluctuations, "norm_0" uses a gaussian with maximum at 0,
        "norm_neg" uses a gaussian with negative maximum, "exp" uses an exponential distribution,
        defaults to "norm_0"


    :returns: likelihood (float)
    """
    assert (upperLimit > 0.)

    def getSigma(ul, muhat=0.):
        """ get the standard deviation sigma, given
            an upper limit and a central value. assumes a truncated Gaussian likelihood """
        # the expected scale, eq 3.24 in arXiv:1202.3415
        return (ul - muhat) / 1.96

    def llhd(nsig, mumax, sigma_exp, nll):
        ## need to account for the truncation!
        ## first compute how many sigmas left of center is 0.
        Zprime = mumax / sigma_exp
        ## now compute the area of the truncated gaussian
        A = stats.norm.cdf(Zprime)
        if nll:
            return np.log(A) - stats.norm.logpdf(nsig, mumax, sigma_exp)
        return float(stats.norm.pdf(nsig, mumax, sigma_exp) / A)

    # sigma_exp = expectedUpperLimit / 1.96 # the expected scale, eq 3.24 in arXiv:1202.3415
    sigma_exp = getSigma(
        expectedUpperLimit)  # the expected scale, eq 3.24 in arXiv:1202.3415

    denominator = np.sqrt(2.) * sigma_exp

    def root_func(x):  ## we want the root of this one
        return (erf((upperLimit - x) / denominator) +
                erf(x / denominator)) / (1. + erf(x / denominator)) - .95

    def find_neg_mumax(upperLimit, expectedUpperLimit, xa, xb):
        while root_func(xa) * root_func(xb) > 0:
            xa = 2 * xa
            #logger.error (xa, root_func(xa), xb, root_func(xb))
        mumax = optimize.brentq(root_func, xa, xb, rtol=1e-03, xtol=1e-06)
        return mumax

    def getLam(ul):
        """ get the scale for the exponential destribution that reproduces the upper limit"""
        return -np.log(0.05) / ul

    def llhdexponential(nsig, lam, nll):
        ## exponential distribution
        if nll:
            return float(lam * nsig - np.log(lam))
        return float(stats.expon.pdf(nsig, scale=1 / lam))

    dr = 2. * (upperLimit - expectedUpperLimit) / (expectedUpperLimit +
                                                   upperLimit)
    if dr > runtime._drmax:
        if runtime._cap_likelihoods == False:
            logger.warn(
                "asking for likelihood from limit but difference between oUL(%.2f) and eUL(%.2f) is too large (dr=%.2f>%.2f)"
                % (upperLimit, expectedUpperLimit, dr, runtime._drmax))
            return None
        oldUL = upperLimit
        upperLimit = expectedUpperLimit * (2. + runtime._drmax) / (
            2. - runtime._drmax)
        logger.warn("asking for likelihood from limit but difference between oUL(%.2f) and eUL(%.2f) is too large (dr=%.2f>%.2f). capping to %.2f." % \
                ( oldUL, expectedUpperLimit, dr, runtime._drmax, upperLimit ) )
        ## we are asked to cap likelihoods, so we set observed UL such that dr == drmax

    if upperLimit <= expectedUpperLimit:
        ## underfluctuation.
        if underfluct == "norm_0":
            return llhd(nsig, 0., sigma_exp, nll)
        elif underfluct == "norm_neg":
            xa = -expectedUpperLimit
            xb = 1
            mumax = find_neg_mumax(upperLimit, expectedUpperLimit, xa, xb)
            return llhd(nsig, mumax, sigma_exp, nll)
        elif underfluct == "exp":
            lam = getLam(upperLimit)
            return llhdexponential(nsig, lam, nll)
        else:
            logger.warn(
                "underfluct not defined, choose one of norm_0, norm_neg and exp"
            )

    fA = root_func(0.)
    fB = root_func(max(upperLimit, expectedUpperLimit))
    if np.sign(fA * fB) > 0.:
        ## the have the same sign
        logger.error("when computing likelihood: fA and fB have same sign")
        return None
    mumax = optimize.brentq(root_func,
                            0.,
                            max(upperLimit, expectedUpperLimit),
                            rtol=1e-03,
                            xtol=1e-06)
    llhdexp = llhd(nsig, mumax, sigma_exp, nll)
    return llhdexp
示例#8
0
    def ulSigma (self, expected=False, workspace_index=None):
        """
        Compute the upper limit on the signal strength modifier with:
            - by default, the combination of the workspaces contained into self.workspaces
            - if workspace_index is specified, self.workspace[workspace_index] (useful for computation of the best upper limit)

        :param expected:  - if set to `True`: uses expected SM backgrounds as signals
                          - else: uses `self.nsignals`
        :param workspace_index: - if different from `None`: index of the workspace to use for upper limit
                          - else: all workspaces are combined
        :return: the upper limit at `self.cl` level (0.95 by default)
        """
        startUL = time.time()
        logger.debug("Calling ulSigma")
        if self.data.errorFlag or self.workspaces == None: # For now, this flag can only be turned on by PyhfData.checkConsistency
            return None
        if self.nWS == 1:
            if self.zeroSignalsFlag[0] == True:
                logger.warning("There is only one workspace but all signals are zeroes")
                return None
        else:
            if workspace_index == None:
                logger.error("There are several workspaces but no workspace index was provided")
                return None
            elif self.zeroSignalsFlag[workspace_index] == True:
                logger.debug("Workspace number %d has zero signals" % workspace_index)
                return None
        def updateWorkspace():
            if self.nWS == 1:
                return self.workspaces[0]
            else:
                return self.workspaces[workspace_index]
        workspace = updateWorkspace()
        def root_func(mu):
            # Same modifiers_settings as those use when running the 'pyhf cls' command line
            msettings = {'normsys': {'interpcode': 'code4'}, 'histosys': {'interpcode': 'code4p'}}
            model = workspace.model(modifier_settings=msettings)
            start = time.time()
            stat = "qtilde" # by default
            args = { "return_expected": expected }
            pver = float ( pyhf.__version__[:3] )
            if pver < 0.6:
                args["qtilde"]=True
            else:
                args["test_stat"]=stat
            with np.testing.suppress_warnings() as sup:
                if pyhfinfo["backend"] == "numpy":
                    sup.filter ( RuntimeWarning, r'invalid value encountered in log')
                result = pyhf.infer.hypotest(mu, workspace.data(model), model, **args )
            end = time.time()
            logger.debug("Hypotest elapsed time : %1.4f secs" % (end - start))
            if expected:
                logger.debug("expected = {}, mu = {}, result = {}".format(expected, mu, result))
                try:
                    CLs = float(result[1].tolist())
                except TypeError:
                    CLs = float(result[1][0])
            else:
                logger.debug("expected = {}, mu = {}, result = {}".format(expected, mu, result))
                CLs = float(result)
            # logger.debug("Call of root_func(%f) -> %f" % (mu, 1.0 - CLs))
            return 1.0 - self.cl - CLs
        # Rescaling singals so that mu is in [0, 10]
        factor = 10.
        wereBothLarge = False
        wereBothTiny = False
        nattempts = 0
        nNan = 0
        lo_mu, hi_mu = .2, 5.
        while "mu is not in [lo_mu,hi_mu]":
            nattempts += 1
            if nNan > 5:
                logger.warn("encountered NaN 5 times while trying to determine the bounds for brent bracketing. now trying with q instead of qtilde test statistic")
                stat = "q"
                nattempts = 0
            if nattempts > 10:
                logger.warn ( "tried 10 times to determine the bounds for brent bracketing. we abort now." )
                return None
            # Computing CL(1) - 0.95 and CL(10) - 0.95 once and for all
            rt1 = root_func(lo_mu)
            rt10 = root_func(hi_mu)
            if rt1 < 0. and 0. < rt10: # Here's the real while condition
                break
            if self.alreadyBeenThere:
                factor = 1 + (factor-1)/2
                logger.debug("Diminishing rescaling factor")
            if np.isnan(rt1):
                nNan += 1
                self.rescale(factor)
                workspace = updateWorkspace()
                continue
            if np.isnan(rt10):
                nNan += 1
                self.rescale(1/factor)
                workspace = updateWorkspace()
                continue
            # Analyzing previous values of wereBoth***
            if rt10 < 0 and rt1 < 0 and wereBothLarge:
                factor = 1 + (factor-1)/2
                logger.debug("Diminishing rescaling factor")
            if rt10 > 0 and rt1 > 0 and wereBothTiny:
                factor = 1 + (factor-1)/2
                logger.debug("Diminishing rescaling factor")
            # Preparing next values of wereBoth***
            wereBothTiny = rt10 < 0 and rt1 < 0
            wereBothLarge = rt10 > 0 and rt1 > 0
            # Main rescaling code
            if rt10 < 0.:
                self.rescale(factor)
                workspace = updateWorkspace()
                continue
            if rt1 > 0.:
                self.rescale(1/factor)
                workspace = updateWorkspace()
                continue
        # Finding the root (Brent bracketing part)
        logger.debug("Final scale : %f" % self.scale)
        logger.debug("Starting brent bracketing")
        ul = optimize.brentq(root_func, lo_mu, hi_mu, rtol=1e-3, xtol=1e-3)
        endUL = time.time()
        logger.debug("ulSigma elpased time : %1.4f secs" % (endUL - startUL))
        return ul*self.scale # self.scale has been updated whithin self.rescale() method