Source code for golemflavor.llh

# author : S. Mandalia
#          s.p.mandalia@qmul.ac.uk
#
# date   : April 04, 2018

"""
Likelihood functions for the BSM flavor ratio analysis
"""

from __future__ import absolute_import, division, print_function

from copy import deepcopy
from functools import partial

import numpy as np
import scipy
from scipy.stats import multivariate_normal, truncnorm

from golemflavor import fr as fr_utils
from golemflavor import gf as gf_utils
from golemflavor.enums import Likelihood, ParamTag, PriorsCateg, StatCateg
from golemflavor.misc import enum_parse, gen_identifier, parse_bool


[docs]def GaussianBoundedRV(loc=0., sigma=1., lower=-np.inf, upper=np.inf): """Normalized Gaussian bounded between lower and upper values""" low, up = (lower - loc) / sigma, (upper - loc) / sigma g = scipy.stats.truncnorm(loc=loc, scale=sigma, a=low, b=up) return g
[docs]def multi_gaussian(fr, fr_bf, smearing, offset=-320): """ Multivariate Gaussian log likelihood. Parameters ---------- fr : List[float], length 3 The flavour composition to evaluate at. fr_bf : List[float], length 3 The bestfit / injected flavour composition. smearing : float The amount of smearing. offset : float, optional An amount to offset the magnitude of the log likelihood. Returns ---------- llh : float The log likelihood evaluated at `fr`. """ cov_fr = np.identity(3) * pow(smearing, 2) return np.log(multivariate_normal.pdf(fr, mean=fr_bf, cov=cov_fr)) + offset
def llh_argparse(parser): parser.add_argument( '--stat-method', default='bayesian', type=partial(enum_parse, c=StatCateg), choices=StatCateg, help='Statistical method to employ' )
[docs]def lnprior(theta, paramset): """Priors on theta.""" if len(theta) != len(paramset): raise AssertionError( 'Length of MCMC scan is not the same as the input ' 'params\ntheta={0}\nparamset={1}'.format(theta, paramset) ) for idx, param in enumerate(paramset): param.value = theta[idx] ranges = paramset.ranges for value, range in zip(theta, ranges): if range[0] <= value <= range[1]: pass else: return -np.inf prior = 0 for param in paramset: if param.prior is PriorsCateg.GAUSSIAN: prior += GaussianBoundedRV( loc=param.nominal_value, sigma=param.std ).logpdf(param.value) elif param.prior is PriorsCateg.LIMITEDGAUSS: prior += GaussianBoundedRV( loc=param.nominal_value, sigma=param.std, lower=param.ranges[0], upper=param.ranges[1] ).logpdf(param.value) return prior
[docs]def triangle_llh(theta, args, asimov_paramset, llh_paramset): """Log likelihood function for a given theta.""" if len(theta) != len(llh_paramset): raise AssertionError( 'Length of MCMC scan is not the same as the input ' 'params\ntheta={0}\nparamset]{1}'.format(theta, llh_paramset) ) hypo_paramset = asimov_paramset for param in llh_paramset.from_tag(ParamTag.NUISANCE): hypo_paramset[param.name].value = param.value spectral_index = -hypo_paramset['astroDeltaGamma'].value # Assigning llh_paramset values from theta happens in this function. fr = fr_utils.flux_averaged_BSMu(theta, args, spectral_index, llh_paramset) flavor_angles = fr_utils.fr_to_angles(fr) # print('flavor_angles', list(map(float, flavor_angles))) for idx, param in enumerate(hypo_paramset.from_tag(ParamTag.BESTFIT)): param.value = flavor_angles[idx] if args.likelihood is Likelihood.GOLEMFIT: llh = gf_utils.get_llh(hypo_paramset) elif args.likelihood is Likelihood.GF_FREQ: llh = gf_utils.get_llh_freq(hypo_paramset) return llh
def ln_prob(theta, args, asimov_paramset, llh_paramset): dc_asimov_paramset = deepcopy(asimov_paramset) dc_llh_paramset = deepcopy(llh_paramset) lp = lnprior(theta, paramset=dc_llh_paramset) if not np.isfinite(lp): return -np.inf return lp + triangle_llh( theta, args=args, asimov_paramset=dc_asimov_paramset, llh_paramset=dc_llh_paramset )