Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • john-veitch/bilby
  • duncanmmacleod/bilby
  • colm.talbot/bilby
  • lscsoft/bilby
  • matthew-pitkin/bilby
  • salvatore-vitale/tupak
  • charlie.hoy/bilby
  • bfarr/bilby
  • virginia.demilio/bilby
  • vivien/bilby
  • eric-howell/bilby
  • sebastian-khan/bilby
  • rhys.green/bilby
  • moritz.huebner/bilby
  • joseph.mills/bilby
  • scott.coughlin/bilby
  • matthew.carney/bilby
  • hyungwon.lee/bilby
  • monica.rizzo/bilby
  • christopher-berry/bilby
  • lindsay.demarchi/bilby
  • kaushik.rao/bilby
  • charles.kimball/bilby
  • andrew.matas/bilby
  • juan.calderonbustillo/bilby
  • patrick-meyers/bilby
  • hannah.middleton/bilby
  • eve.chase/bilby
  • grant.meadors/bilby
  • khun.phukon/bilby
  • sumeet.kulkarni/bilby
  • daniel.reardon/bilby
  • cjhaster/bilby
  • sylvia.biscoveanu/bilby
  • james-clark/bilby
  • meg.millhouse/bilby
  • joshua.willis/bilby
  • nikhil.sarin/bilby
  • paul.easter/bilby
  • youngmin/bilby
  • daniel-williams/bilby
  • shanika.galaudage/bilby
  • bruce.edelman/bilby
  • avi.vajpeyi/bilby
  • isobel.romero-shaw/bilby
  • andrew.kim/bilby
  • dominika.zieba/bilby
  • jonathan.davies/bilby
  • marc.arene/bilby
  • srishti.tiwari/bilby-tidal-heating-eccentric
  • aditya.vijaykumar/bilby
  • michael.williams/bilby
  • cecilio.garcia-quiros/bilby
  • rory-smith/bilby
  • maite.mateu-lucena/bilby
  • wushichao/bilby
  • kaylee.desoto/bilby
  • brandon.piotrzkowski/bilby
  • rossella.gamba/bilby
  • hunter.gabbard/bilby
  • deep.chatterjee/bilby
  • tathagata.ghosh/bilby
  • arunava.mukherjee/bilby
  • philip.relton/bilby
  • reed.essick/bilby
  • pawan.gupta/bilby
  • francisco.hernandez/bilby
  • rhiannon.udall/bilby
  • leo.tsukada/bilby
  • will-farr/bilby
  • vijay.varma/bilby
  • jeremy.baier/bilby
  • joshua.brandt/bilby
  • ethan.payne/bilby
  • ka-lok.lo/bilby
  • antoni.ramos-buades/bilby
  • oliviastephany.wilk/bilby
  • jack.heinzel/bilby
  • samson.leong/bilby-psi4
  • viviana.caceres/bilby
  • nadia.qutob/bilby
  • michael-coughlin/bilby
  • hemantakumar.phurailatpam/bilby
  • boris.goncharov/bilby
  • sama.al-shammari/bilby
  • siqi.zhong/bilby
  • jocelyn-read/bilby
  • marc.penuliar/bilby
  • stephanie.letourneau/bilby
  • alexandresebastien.goettel/bilby
  • alec.gunny/bilby
  • serguei.ossokine/bilby
  • pratyusava.baral/bilby
  • sophie.hourihane/bilby
  • eunsub/bilby
  • james.hart/bilby
  • pratyusava.baral/bilby-tg
  • zhaozc/bilby
  • pratyusava.baral/bilby_SoG
  • tomasz.baka/bilby
  • nicogerardo.bers/bilby
  • soumen.roy/bilby
  • isaac.mcmahon/healpix-redundancy
  • asamakai.baker/bilby-frequency-dependent-antenna-pattern-functions
  • anna.puecher/bilby
  • pratyusava.baral/bilby-x-g
  • thibeau.wouters/bilby
  • christian.adamcewicz/bilby
  • raffi.enficiaud/bilby
109 results
Show changes
Commits on Source (24)
Showing
with 574 additions and 123 deletions
......@@ -14,4 +14,4 @@ MANIFEST
*.version
*.ipynb_checkpoints
outdir/*
.idea/*
\ No newline at end of file
.idea/*
# All notable changes will be documented in this file
## [0.6.4] 2020-01-30
### Changes
- Discontinue python2.7 support (!697)
- Minor adjustments to the act calculation method (!679, !707)
- Restructure of the prior module (!688)
- Improvements to the documentation (!708, !700)
- Bug fix when maximum < minimum (!696)
### Added
- Improved waveform error handling (!653)
- Waveform check to the CI (!698)
## [0.6.3] 2020-01-03
### Changed
- Fixed an issue with the ROQ segment scaling (!690)
......
......@@ -14,10 +14,11 @@ Online material to help you get started:
If you need help, find an issue, or just have a question/suggestion you can
- Join our `Slack workspace <https://bilby-code.slack.com/>`__ (you may need to email the support desk to request an invite)
- Email our support desk: contact+lscsoft-bilby-1846-issue-@support.ligo.org
- Join our `Slack workspace <https://bilby-code.slack.com/>`__
- Ask questions (or search through other users questions and answers) on `StackOverflow <https://stackoverflow.com/questions/tagged/bilby>`__ using the bilby tag
- For www.git.ligo.org users, submit issues directly through `the issue tracker <https://git.ligo.org/lscsoft/bilby/issues>`__
- For www.chat.ligo.org users, join the `#bilby-help <https://chat.ligo.org/ligo/channels/bilby-help>`__ or `#bilby-devel <https://chat.ligo.org/ligo/channels/bilby-devel>`__ channels
We encourage you to contribute to the development of bilby. This is done via a merge request. For
help in creating a merge request, see `this page
......
......@@ -991,15 +991,15 @@ class Beta(Prior):
- betaln(self.alpha, self.beta) - xlogy(self.alpha + self.beta - 1, self.maximum - self.minimum)
# deal with the fact that if alpha or beta are < 1 you get infinities at 0 and 1
if isinstance(val, np.ndarray):
if isinstance(val, (float, int)):
if np.isfinite(_ln_prob) and self.minimum <= val <= self.maximum:
return _ln_prob
return -np.inf
else:
_ln_prob_sub = -np.inf * np.ones(len(val))
idx = np.isfinite(_ln_prob) & (val >= self.minimum) & (val <= self.maximum)
_ln_prob_sub[idx] = _ln_prob[idx]
return _ln_prob_sub
else:
if np.isfinite(_ln_prob) and val >= self.minimum and val <= self.maximum:
return _ln_prob
return -np.inf
def cdf(self, val):
if isinstance(val, (float, int)):
......
......@@ -306,6 +306,26 @@ class PriorDict(dict):
"""
return self.sample_subset_constrained(keys=list(self.keys()), size=size)
def sample_subset_constrained_as_array(self, keys=iter([]), size=None):
""" Return an array of samples
Parameters
----------
keys: list
A list of keys to sample in
size: int
The number of samples to draw
Returns
-------
array: array_like
An array of shape (len(key), size) of the samples (ordered by keys)
"""
samples_dict = self.sample_subset_constrained(keys=keys, size=size)
samples_dict = {key: np.atleast_1d(val) for key, val in samples_dict.items()}
samples_list = [samples_dict[key] for key in keys]
return np.array(samples_list)
def sample_subset(self, keys=iter([]), size=None):
"""Draw samples from the prior set for parameters which are not a DeltaFunction
......
......@@ -48,11 +48,6 @@ class BaseJointPriorDist(object):
raise ValueError("Bounds are not properly set")
else:
raise TypeError("Bound must be a list")
logger.warning("If using bounded ranges on the multivariate "
"Gaussian this will lead to biased posteriors "
"for nested sampling routines that require "
"a prior transform.")
else:
bounds = [(-np.inf, np.inf) for _ in self.names]
self.bounds = {name: val for name, val in zip(self.names, bounds)}
......@@ -289,7 +284,7 @@ class BaseJointPriorDist(object):
An vector sample drawn from the multivariate Gaussian
distribution.
"""
samp = np.asarray(value)
samp = np.array(value)
if len(samp.shape) == 1:
samp = samp.reshape(1, self.num_vars)
......@@ -365,6 +360,13 @@ class MultivariateGaussianDist(BaseJointPriorDist):
+/- infinity.
"""
super(MultivariateGaussianDist, self).__init__(names=names, bounds=bounds)
for name in self.names:
bound = self.bounds[name]
if bound[0] != -np.inf or bound[1] != np.inf:
logger.warning("If using bounded ranges on the multivariate "
"Gaussian this will lead to biased posteriors "
"for nested sampling routines that require "
"a prior transform.")
self.distname = 'mvg'
self.mus = []
self.covs = []
......@@ -376,10 +378,6 @@ class MultivariateGaussianDist(BaseJointPriorDist):
self.sqeigvalues = [] # square root of the eigenvalues
self.mvn = [] # list of multivariate normal distributions
self._current_sample = {} # initialise empty sample
self._uncorrelated = None
self._current_lnprob = None
# put values in lists if required
if nmodes == 1:
if mus is not None:
......
......@@ -5,7 +5,7 @@ import numpy as np
from pandas import DataFrame
from ..utils import logger, command_line_args, Counter
from ..prior import Prior, PriorDict, ConditionalPriorDict, DeltaFunction, Constraint
from ..prior import Prior, PriorDict, DeltaFunction, Constraint
from ..result import Result, read_in_result
......@@ -251,19 +251,13 @@ class Sampler(object):
AttributeError
prior can't be sampled.
"""
if isinstance(self.priors, ConditionalPriorDict):
for key in self.priors:
if isinstance(self.priors[key], Constraint):
continue
try:
self.likelihood.parameters = self.priors.sample()
self.priors[key].sample()
except AttributeError as e:
logger.warning('Cannot sample from prior, {}'.format(e))
else:
for key in self.priors:
if isinstance(self.priors[key], Constraint):
continue
try:
self.likelihood.parameters[key] = self.priors[key].sample()
except AttributeError as e:
logger.warning('Cannot sample from {}, {}'.format(key, e))
logger.warning('Cannot sample from {}, {}'.format(key, e))
def _verify_parameters(self):
""" Evaluate a set of parameters drawn from the prior
......@@ -281,13 +275,8 @@ class Sampler(object):
raise IllegalSamplingSetError(
"Your sampling set contains redundant parameters.")
self._check_if_priors_can_be_sampled()
if isinstance(self.priors, ConditionalPriorDict):
theta = self.priors.sample()
theta = [theta[key] for key in self._search_parameter_keys]
else:
theta = [self.priors[key].sample()
for key in self._search_parameter_keys]
theta = self.priors.sample_subset_constrained_as_array(
self.search_parameter_keys, size=1)[:, 0]
try:
self.log_likelihood(theta)
except TypeError as e:
......@@ -308,12 +297,8 @@ class Sampler(object):
t1 = datetime.datetime.now()
for _ in range(n_evaluations):
if isinstance(self.priors, ConditionalPriorDict):
theta = self.priors.sample()
theta = [theta[key] for key in self._search_parameter_keys]
else:
theta = [self.priors[key].sample()
for key in self._search_parameter_keys]
theta = self.priors.sample_subset_constrained_as_array(
self._search_parameter_keys, size=1)[:, 0]
self.log_likelihood(theta)
total_time = (datetime.datetime.now() - t1).total_seconds()
self._log_likelihood_eval_time = total_time / n_evaluations
......
......@@ -17,7 +17,6 @@ from .base_sampler import Sampler, NestedSampler
from numpy import linalg
from dynesty.utils import unitcheck
import warnings
import math
class Dynesty(NestedSampler):
......@@ -402,6 +401,8 @@ class Dynesty(NestedSampler):
self.sampler.live_bound = saved['live_bound']
self.sampler.live_it = saved['live_it']
self.sampler.added_live = saved['added_live']
self.sampler.bound = saved['bound']
self.sampler.nbound = saved['nbound']
self.sampling_time += datetime.timedelta(seconds=saved['sampling_time'])
return True
......@@ -452,6 +453,8 @@ class Dynesty(NestedSampler):
id=self.sampler.saved_id,
it=self.sampler.saved_it,
nc=self.sampler.saved_nc,
bound=self.sampler.bound,
nbound=self.sampler.nbound,
boundidx=self.sampler.saved_boundidx,
bounditer=self.sampler.saved_bounditer,
scale=self.sampler.saved_scale,
......@@ -559,6 +562,7 @@ def sample_rwalk_bilby(args):
walks = kwargs.get('walks', 25) # minimum number of steps
maxmcmc = kwargs.get('maxmcmc', 2000) # Maximum number of steps
nact = kwargs.get('nact', 5) # Number of ACT
old_act = kwargs.get('old_act', walks)
# Initialize internal variables
accept = 0
......@@ -573,28 +577,12 @@ def sample_rwalk_bilby(args):
drhat, dr, du, u_prop, logl_prop = np.nan, np.nan, np.nan, np.nan, np.nan
while len(u_list) < nact * act:
if scale == 0.:
raise RuntimeError("The random walk sampling is stuck! "
"Some useful output quantities:\n"
"u: {0}\n"
"drhat: {1}\n"
"dr: {2}\n"
"du: {3}\n"
"u_prop: {4}\n"
"loglstar: {5}\n"
"logl_prop: {6}\n"
"axes: {7}\n"
"scale: {8}."
.format(u, drhat, dr, du, u_prop,
loglstar, logl_prop, axes, scale))
# Propose a direction on the unit n-sphere.
drhat = rstate.randn(n)
drhat /= linalg.norm(drhat)
# Scale based on dimensionality.
# dr = drhat * rstate.rand()**(1. / n) # CHANGED FROM DYNESTY 1.0
dr = drhat * rstate.rand(n)
dr = drhat * rstate.rand()**(1. / n)
# Transform to proposal distribution.
du = np.dot(axes, dr)
......@@ -619,14 +607,6 @@ def sample_rwalk_bilby(args):
logl_list.append(logl_list[-1])
continue
# Check if we're stuck generating bad numbers.
if nfail > 100 * walks:
warnings.warn("Random number generation appears to be "
"extremely inefficient. Adjusting the "
"scale-factor accordingly.")
nfail = 0
scale *= math.exp(-1. / n)
# Check proposed point.
v_prop = prior_transform(np.array(u_prop))
logl_prop = loglikelihood(np.array(v_prop))
......@@ -649,7 +629,8 @@ def sample_rwalk_bilby(args):
# If we've taken the minimum number of steps, calculate the ACT
if accept + reject > walks:
act = estimate_nmcmc(
accept_ratio=accept / (accept + reject + nfail), maxmcmc=maxmcmc)
accept_ratio=accept / (accept + reject + nfail),
old_act=old_act, maxmcmc=maxmcmc)
# If we've taken too many likelihood evaluations then break
if accept + reject > maxmcmc and accept > 0:
......@@ -663,16 +644,9 @@ def sample_rwalk_bilby(args):
# Break if we are above maxmcmc and have at least one accepted point
break
# Check if we're stuck generating bad points.
if accept + reject > 50 * walks:
scale *= math.exp(-1. / n)
warnings.warn("Random walk proposals appear to be "
"extremely inefficient. Adjusting the "
"scale-factor accordingly.")
# If the act is finite, pick randomly from within the chain
if np.isfinite(act) and act < len(u_list):
idx = np.random.randint(act, len(u_list))
if np.isfinite(act) and int(.5 * nact * act) < len(u_list):
idx = np.random.randint(int(.5 * nact * act), len(u_list))
u = u_list[idx]
v = v_list[idx]
logl = logl_list[idx]
......@@ -689,12 +663,13 @@ def sample_rwalk_bilby(args):
logl = logl_list[idx]
blob = {'accept': accept, 'reject': reject, 'fail': nfail, 'scale': scale}
kwargs["old_act"] = act
ncall = accept + reject
return u, v, logl, ncall, blob
def estimate_nmcmc(accept_ratio, maxmcmc, safety=5, tau=None):
def estimate_nmcmc(accept_ratio, old_act, maxmcmc, safety=5, tau=None):
""" Estimate autocorrelation length of chain using acceptance fraction
Using ACL = (2/acc) - 1 multiplied by a safety margin. Code adapated from
......@@ -706,8 +681,8 @@ def estimate_nmcmc(accept_ratio, maxmcmc, safety=5, tau=None):
----------
accept_ratio: float [0, 1]
Ratio of the number of accepted points to the total number of points
minmcmc: int
The minimum length of the MCMC chain to use
old_act: int
The ACT of the last iteration
maxmcmc: int
The maximum length of the MCMC chain to use
safety: int
......@@ -720,12 +695,14 @@ def estimate_nmcmc(accept_ratio, maxmcmc, safety=5, tau=None):
tau = maxmcmc / safety
if accept_ratio == 0.0:
return np.inf
Nmcmc_exact = (1 + 1 / tau) * old_act
else:
Nmcmc_exact = (safety / tau) * (2. / accept_ratio - 1.)
Nmcmc_exact = (
(1. - 1. / tau) * old_act +
(safety / tau) * (2. / accept_ratio - 1.)
)
Nmcmc_exact = float(min(Nmcmc_exact, maxmcmc))
Nmcmc = max(safety, int(Nmcmc_exact))
return Nmcmc
return max(safety, int(Nmcmc_exact))
class DynestySetupError(Exception):
......
......@@ -974,9 +974,10 @@ class BilbyJsonEncoder(json.JSONEncoder):
def default(self, obj):
from .prior import MultivariateGaussianDist, Prior, PriorDict
from ..gw.prior import HealPixMapPriorDist
if isinstance(obj, PriorDict):
return {'__prior_dict__': True, 'content': obj._get_json_dict()}
if isinstance(obj, (MultivariateGaussianDist, Prior)):
if isinstance(obj, (MultivariateGaussianDist, HealPixMapPriorDist, Prior)):
return {'__prior__': True, '__module__': obj.__module__,
'__name__': obj.__class__.__name__,
'kwargs': dict(obj.get_instantiation_dict())}
......
......@@ -3,6 +3,7 @@ import sys
import warnings
import numpy as np
import math
from ...core import utils
from ...core.utils import logger
......@@ -40,13 +41,32 @@ class InterferometerList(list):
self._check_interferometers()
def _check_interferometers(self):
""" Check certain aspects of the set are the same """
"""Verify IFOs 'duration', 'start_time', 'sampling_frequency' are the same.
If the above attributes are not the same, then the attributes are checked to
see if they are the same up to 5 decimal places.
If both checks fail, then a ValueError is raised.
"""
consistent_attributes = ['duration', 'start_time', 'sampling_frequency']
for attribute in consistent_attributes:
x = [getattr(interferometer.strain_data, attribute)
for interferometer in self]
if not all(y == x[0] for y in x):
raise ValueError("The {} of all interferometers are not the same".format(attribute))
try:
if not all(y == x[0] for y in x):
ifo_strs = ["{ifo}[{attribute}]={value}".format(
ifo=ifo.name,
attribute=attribute,
value=getattr(ifo.strain_data, attribute))
for ifo in self]
raise ValueError(
"The {} of all interferometers are not the same: {}".format(
attribute, ', '.join(ifo_strs)))
except ValueError as e:
if not all(math.isclose(y, x[0], abs_tol=1e-5) for y in x):
raise ValueError(e)
else:
logger.warning(e)
def set_strain_data_from_power_spectral_densities(self, sampling_frequency, duration, start_time=0):
""" Set the `Interferometer.strain_data` from the power spectral densities of the detectors
......
......@@ -563,8 +563,11 @@ class GravitationalWaveTransient(Likelihood):
if self.phase_marginalization:
return np.logspace(-5, 10, self._dist_margd_loglikelihood_array.shape[1])
else:
return np.hstack((-np.logspace(3, -3, self._dist_margd_loglikelihood_array.shape[1] / 2),
np.logspace(-3, 10, self._dist_margd_loglikelihood_array.shape[1] / 2)))
n_negative = self._dist_margd_loglikelihood_array.shape[1] // 2
n_positive = self._dist_margd_loglikelihood_array.shape[1] - n_negative
return np.hstack((
-np.logspace(3, -3, n_negative), np.logspace(-3, 10, n_positive)
))
def _setup_distance_marginalization(self, lookup_table=None):
if isinstance(lookup_table, str) or lookup_table is None:
......
......@@ -2,10 +2,13 @@ import os
import copy
import numpy as np
from scipy.interpolate import InterpolatedUnivariateSpline
from scipy.interpolate import InterpolatedUnivariateSpline, interp1d
from scipy.integrate import cumtrapz
from scipy.stats import norm
from ..core.prior import (PriorDict, Uniform, Prior, DeltaFunction, Gaussian,
Interped, Constraint, conditional_prior_factory)
Interped, Constraint, conditional_prior_factory,
BaseJointPriorDist, JointPrior, JointPriorDistError)
from ..core.utils import infer_args_from_method, logger
from .conversion import (
convert_to_lal_binary_black_hole_parameters,
......@@ -761,3 +764,344 @@ def secondary_mass_condition_function(reference_params, mass_1):
ConditionalCosmological = conditional_prior_factory(Cosmological)
ConditionalUniformComovingVolume = conditional_prior_factory(UniformComovingVolume)
ConditionalUniformSourceFrame = conditional_prior_factory(UniformSourceFrame)
class HealPixMapPriorDist(BaseJointPriorDist):
def __init__(self, hp_file, names=None, bounds=None, distance=False):
"""
Class defining prior according to given HealPix Map, defaults to 2D in ra and dec but can be set to include
Distance as well. This only works with skymaps that include the 2D joint probability in ra/dec and that use the
normal LALInference type skymaps where each pixel has a DISTMU, DISTSIGMA, and DISTNORM defining the conditional
distance distribution along a given line of sight.
hp_file: file path to .fits file
.fits file that containes the 2D or 3D Healpix Map
names: list (optional)
list of names of parameters included in the JointPriorDist, defaults to ['ra', 'dec']
bounds: dict or list (optional)
dictionary or list with given prior bounds. defaults to normal bounds on ra, dev and 0, inf for distance
if this is for a 3D map
"""
self.hp = self._check_imports()
self.hp_file = hp_file
if names is None:
names = ["ra", "dec"]
if bounds is None:
bounds = [[0, 2 * np.pi], [-np.pi / 2.0, np.pi / 2.0]]
elif isinstance(bounds, dict):
bs = [[] for _ in bounds.keys()]
for i, key in enumerate(bounds.keys()):
bs[i] = (bounds[key][0], bounds[key][1])
bounds = bs
if distance:
if len(names) == 2:
names.append("distance")
if len(bounds) == 2:
bounds.append([0, np.inf])
self.distance = True
self.prob, self.distmu, self.distsigma, self.distnorm = self.hp.read_map(
hp_file, verbose=False, field=range(4)
)
else:
self.distance = False
self.prob = self.hp.read_map(hp_file, verbose=False)
super(HealPixMapPriorDist, self).__init__(names=names, bounds=bounds)
self.distname = "hpmap"
self.npix = len(self.prob)
self.nside = self.hp.npix2nside(self.npix)
self.pixel_area = self.hp.nside2pixarea(self.nside)
self.pixel_length = self.pixel_area ** (1 / 2.0)
self.pix_xx = np.arange(self.npix)
self._all_interped = interp1d(x=self.pix_xx, y=self.prob, bounds_error=False, fill_value=0)
self.inverse_cdf = None
self.distance_pdf = None
self.distance_dist = None
self.distance_icdf = None
self._build_attributes()
name = self.names[-1]
if self.bounds[name][1] != np.inf and self.bounds[name][0] != -np.inf:
self.rs = np.linspace(self.bounds[name][0], self.bounds[name][1], 1000)
else:
self.rs = np.linspace(0, 5000, 1000)
def _build_attributes(self):
"""
Method that builds the inverse cdf of the P(pixel) distribution for rescaling
"""
yy = self._all_interped(self.pix_xx)
yy /= np.trapz(yy, self.pix_xx)
YY = cumtrapz(yy, self.pix_xx, initial=0)
YY[-1] = 1
self.inverse_cdf = interp1d(x=YY, y=self.pix_xx, bounds_error=True)
@staticmethod
def _check_imports():
"""
Static method to check that healpy is installed on the machine running bibly
"""
try:
import healpy
except Exception:
raise ImportError("Must have healpy installed on this machine to use HealPixMapPrior")
return healpy
def _rescale(self, samp, **kwargs):
"""
Overwrites the _rescale method of BaseJoint Prior to rescale a single value from the unitcube onto
two values (ra, dec) or 3 (ra, dec, dist) if distance is included
Parameters
----------
samp: float, int
must take in single value for pixel on unitcube to recale onto ra, dec (distance), for the map Prior
kwargs: dict
kwargs are all passed to _rescale() method
Returns
----------
array_like
sample to rescale onto the prior
"""
if self.distance:
dist_samp = samp[:, -1]
samp = samp[:, 0]
else:
samp = samp[:, 0]
pix_rescale = self.inverse_cdf(samp)
sample = np.empty((len(pix_rescale), 2))
dist_samples = np.empty((len(pix_rescale)))
for i, val in enumerate(pix_rescale):
theta, ra = self.hp.pix2ang(self.nside, int(round(val)))
dec = 0.5 * np.pi - theta
sample[i, :] = self.draw_from_pixel(ra, dec, int(round(val)))
if self.distance:
self.update_distance(int(round(val)))
dist_samples[i] = self.distance_icdf(dist_samp[i])
if self.distance:
sample = np.row_stack([sample[:, 0], sample[:, 1], dist_samples])
return sample.reshape((-1, self.num_vars))
def update_distance(self, pix_idx):
"""
Method to update the conditional distance distributions at given pixel used for distance handling in the
JointPrior Parameters. This function updates the current distance pdf, inverse_cdf, and sampler according to
given pixel or line of sight.
----------
pix_idx: int
pixel index value to create the distribtuion for
Returns
----------
None - just updates these functions at new pixel values
"""
self.distance_pdf = lambda r: self.distnorm[pix_idx] * norm(
loc=self.distmu[pix_idx], scale=self.distsigma[pix_idx]
).pdf(r)
pdfs = self.rs ** 2 * norm(loc=self.distmu[pix_idx], scale=self.distsigma[pix_idx]).pdf(self.rs)
cdfs = np.cumsum(pdfs) / np.sum(pdfs)
def sample_distance(n):
gaussian = norm(loc=self.distmu[pix_idx], scale=self.distsigma[pix_idx]).rvs(size=100 * n)
probs = self._check_norm(gaussian[gaussian > 0] ** 2)
ds = np.random.choice(gaussian[gaussian > 0], p=probs, size=n, replace=True)
return ds
self.distance_dist = sample_distance
self.distance_icdf = interp1d(cdfs, self.rs)
@staticmethod
def _check_norm(array):
"""
static method to check if array is properlly normalized and if not to normalize it.
Parameters
----------
array: array_like
input array we want to renormalize if not already normalized
Returns
---------
array_like:
returns input array normalized
"""
norm = np.linalg.norm(array, ord=1)
if norm == 0:
norm = np.finfo(array.dtype).eps
return array / norm
def _sample(self, size, **kwargs):
"""
Overwrites the _sample method of BaseJoint Prior. Picks a pixel value according to their probabilities, then
uniformly samples ra, and decs that are contained in chosen pixel. If the PriorDist includes distance it then
updates the distance distributions and will sample according to the conditional distance distribution along a
given line of sight
Parameters
----------
size: int
number of samples we want to draw
kwargs: dict
kwargs are all passed to be used
Returns
----------
array_like
sample of ra, and dec (and distance if 3D=True)
"""
pixel_choices = np.arange(self.npix)
pixel_probs = self._check_norm(self.prob)
sample_pix = np.random.choice(pixel_choices, size=size, p=pixel_probs, replace=True)
sample = np.empty((size, self.num_vars))
for samp in range(size):
theta, ra = self.hp.pix2ang(self.nside, sample_pix[samp])
dec = 0.5 * np.pi - theta
if self.distance:
self.update_distance(sample_pix[samp])
dist = self.draw_distance(sample_pix[samp])
ra_dec = self.draw_from_pixel(ra, dec, sample_pix[samp])
sample[samp, :] = [ra_dec[0], ra_dec[1], dist]
else:
sample[samp, :] = self.draw_from_pixel(ra, dec, sample_pix[samp])
return sample.reshape((-1, self.num_vars))
def draw_distance(self, pix):
"""
Method to recursively draw a distance value from the given set distance distribution and check that it is in
the bounds
Returns
----------
dist: sample drawn from the distance distribution at set pixel index
"""
if self.distmu[pix] == np.inf or self.distmu[pix] <= 0:
return 0
dist = self.distance_dist(1)
name = self.names[-1]
if (dist > self.bounds[name][1]) | (dist < self.bounds[name][0]):
self.draw_distance(pix)
else:
return dist
def draw_from_pixel(self, ra, dec, pix):
"""
Recursive function to uniformly draw ra, and dec values that are located in the given pixel
Parameters
----------
ra: float, int
value drawn for rightascension
dec: float, int
value drawn for declination
pix: int
pixel index for given pixel we want to get ra, and dec from
Returns
---------
tuple:
this returns a tuple of ra, and dec sampled uniformly that are in the pixel given
"""
if not self.check_in_pixel(ra, dec, pix):
self.draw_from_pixel(ra, dec, pix)
return np.array(
[
np.random.uniform(ra - self.pixel_length, ra + self.pixel_length),
np.random.uniform(dec - self.pixel_length, dec + self.pixel_length),
]
)
def check_in_pixel(self, ra, dec, pix):
"""
Method that checks if given rightacension and declination values are within the given pixel index and the bounds
Parameters
----------
ra: float, int
rightascension value to check
dec: float, int
declination value to check
pix: int
index for pixel we want to check in
Returns
--------
bool:
returns True if values inside pixel, False if not
"""
for val, name in zip([ra, dec], self.names):
if (val < self.bounds[name][0]) or (val > self.bounds[name][1]):
return False
phi, theta = ra, 0.5 * np.pi - dec
pixel = self.hp.ang2pix(self.nside, theta, phi)
return pix == pixel
def _ln_prob(self, samp, lnprob, outbounds):
"""
Overwrites the _lnprob method of BaseJoint Prior
Parameters
----------
samp: array_like
samples of ra, dec to evaluate the lnprob at
lnprob: array_like
array of correct length we want to populate with lnprob values
outbounds: boolean array
boolean array that flags samples that are out of the given bounds
Returns
----------
array_like
lnprob values at each sample
"""
for i in range(samp.shape[0]):
if not outbounds[i]:
if self.distance:
phi, dec, dist = samp[0]
else:
phi, dec = samp[0]
theta = 0.5 * np.pi - dec
pixel = self.hp.ang2pix(self.nside, theta, phi)
lnprob[i] = np.log(self.prob[pixel] / self.pixel_area)
if self.distance:
self.update_distance(pixel)
lnprob[i] += np.log(self.distance_pdf(dist) * dist ** 2)
lnprob[outbounds] = -np.inf
return lnprob
def __eq__(self, other):
skip_keys = ["_all_interped", "inverse_cdf", "distance_pdf", "distance_dist", "distance_icdf"]
if self.__class__ != other.__class__:
return False
if sorted(self.__dict__.keys()) != sorted(other.__dict__.keys()):
return False
for key in self.__dict__:
if key in skip_keys:
continue
if key == "hp_file":
if self.__dict__[key] != other.__dict__[key]:
return False
elif isinstance(self.__dict__[key], (np.ndarray, list)):
thisarr = np.asarray(self.__dict__[key])
otherarr = np.asarray(other.__dict__[key])
if thisarr.dtype == np.float and otherarr.dtype == np.float:
fin1 = np.isfinite(np.asarray(self.__dict__[key]))
fin2 = np.isfinite(np.asarray(other.__dict__[key]))
if not np.array_equal(fin1, fin2):
return False
if not np.allclose(thisarr[fin1], otherarr[fin2], atol=1e-15):
return False
else:
if not np.array_equal(thisarr, otherarr):
return False
else:
if not self.__dict__[key] == other.__dict__[key]:
return False
return True
class HealPixPrior(JointPrior):
def __init__(self, dist, name=None, latex_label=None, unit=None):
if not isinstance(dist, HealPixMapPriorDist):
raise JointPriorDistError("dist object must be instance of HealPixMapPriorDist")
super(HealPixPrior, self).__init__(dist=dist, name=name, latex_label=latex_label, unit=unit)
......@@ -383,10 +383,15 @@ def _base_lal_cbc_fd_waveform(
h_cross = np.zeros_like(frequency_array, dtype=np.complex)
if len(hplus.data.data) > len(frequency_array):
raise ValueError("Waveform longer than frequency array")
h_plus[:len(hplus.data.data)] = hplus.data.data
h_cross[:len(hcross.data.data)] = hcross.data.data
logger.debug("LALsim waveform longer than bilby's `frequency_array`" +
"({} vs {}), ".format(len(hplus.data.data), len(frequency_array)) +
"probably because padded with zeros up to the next power of two length." +
" Truncating lalsim array.")
h_plus = hplus.data.data[:len(h_plus)]
h_cross = hcross.data.data[:len(h_cross)]
else:
h_plus[:len(hplus.data.data)] = hplus.data.data
h_cross[:len(hcross.data.data)] = hcross.data.data
h_plus *= frequency_bounds
h_cross *= frequency_bounds
......
......@@ -44,9 +44,9 @@ errors. To code this up in :code:`bilby`, we would write a class like this::
data: array_like
The data to analyse
"""
super().__init__(parameters={'mu': None, 'sigma': None})
self.data = data
self.N = len(data)
self.parameters = {'mu': None, 'sigma': None}
def log_likelihood(self):
mu = self.parameters['mu']
......@@ -130,7 +130,8 @@ In :code:`bilby`, we can code this up as a likelihood in the following way::
# These lines of code infer the parameters from the provided function
parameters = inspect.getargspec(function).args
parameters.pop(0)
self.parameters = dict.fromkeys(parameters)
super().__init__(parameters=dict.fromkeys(parameters))
def log_likelihood(self):
res = self.y - self.function(self.x, **self.parameters)
......@@ -198,7 +199,9 @@ instantiating the likelihood::
# These lines of code infer the parameters from the provided function
parameters = inspect.getargspec(function).args
parameters.pop(0)
self.parameters = dict.fromkeys(parameters)
super().__init__(parameters=dict.fromkeys(parameters))
self.parameters = dict.fromkeys(parameters)
self.function_keys = self.parameters.keys()
if self.sigma is None:
self.parameters['sigma'] = None
......
......@@ -31,7 +31,7 @@ class SimpleGaussianLikelihood(bilby.Likelihood):
data: array_like
The data to analyse
"""
bilby.Likelihood.__init__(self, parameters={'mu': None, 'sigma': None})
super().__init__(parameters={'mu': None, 'sigma': None})
self.data = data
self.N = len(data)
......
......@@ -64,7 +64,7 @@ def readfile(filename):
return filecontents
VERSION = '0.6.3'
VERSION = '0.6.4'
version_file = write_version_file(VERSION)
long_description = get_long_description()
......
......@@ -1031,6 +1031,23 @@ class TestInterferometerList(unittest.TestCase):
with self.assertRaises(ValueError):
bilby.gw.detector.InterferometerList([self.ifo1, self.ifo2])
@patch.object(bilby.gw.detector.networks.logger, 'warning')
def test_check_interferometers_relative_tolerance(self, mock_warning):
# Value larger than relative tolerance -- not tolerated
self.ifo2.strain_data.start_time = self.ifo1.strain_data.start_time + 1e-4
with self.assertRaises(ValueError):
bilby.gw.detector.InterferometerList([self.ifo1, self.ifo2])
# Value smaller than relative tolerance -- tolerated with warning
self.ifo2.strain_data.start_time = self.ifo1.strain_data.start_time + 1e-6
ifo_list = bilby.gw.detector.InterferometerList([self.ifo1, self.ifo2])
self.assertIsNotNone(ifo_list)
self.assertTrue(mock_warning.called)
warning_log_str = mock_warning.call_args.args[0].args[0]
self.assertIsInstance(warning_log_str, str)
self.assertTrue("The start_time of all interferometers are not the same:" in
warning_log_str)
@patch.object(bilby.gw.detector.Interferometer, 'set_strain_data_from_power_spectral_density')
def test_set_strain_data_from_power_spectral_density(self, m):
self.ifo_list.set_strain_data_from_power_spectral_densities(sampling_frequency=123, duration=6.2, start_time=3)
......
File added
......@@ -161,6 +161,12 @@ class TestPriorClasses(unittest.TestCase):
mus=[1, 1],
covs=np.array([[2., 0.5], [0.5, 2.]]),
weights=1.)
hp_map_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'prior_files/GW150914_testing_skymap.fits')
hp_dist = bilby.gw.prior.HealPixMapPriorDist(hp_map_file,
names=['testra', 'testdec'])
hp_3d_dist = bilby.gw.prior.HealPixMapPriorDist(hp_map_file,
names=['testra', 'testdec', 'testdistance'], distance=True)
def condition_func(reference_params, test_param):
return reference_params.copy()
......@@ -220,7 +226,12 @@ class TestPriorClasses(unittest.TestCase):
bilby.core.prior.ConditionalLogistic(condition_func=condition_func, name='test', unit='unit', mu=0, scale=1),
bilby.core.prior.ConditionalCauchy(condition_func=condition_func, name='test', unit='unit', alpha=0, beta=1),
bilby.core.prior.ConditionalGamma(condition_func=condition_func, name='test', unit='unit', k=1, theta=1),
bilby.core.prior.ConditionalChiSquared(condition_func=condition_func, name='test', unit='unit', nu=2)
bilby.core.prior.ConditionalChiSquared(condition_func=condition_func, name='test', unit='unit', nu=2),
bilby.gw.prior.HealPixPrior(dist=hp_dist, name='testra', unit='unit'),
bilby.gw.prior.HealPixPrior(dist=hp_dist, name='testdec', unit='unit'),
bilby.gw.prior.HealPixPrior(dist=hp_3d_dist, name='testra', unit='unit'),
bilby.gw.prior.HealPixPrior(dist=hp_3d_dist, name='testdec', unit='unit'),
bilby.gw.prior.HealPixPrior(dist=hp_3d_dist, name='testdistance', unit='unit')
]
def tearDown(self):
......@@ -278,14 +289,18 @@ class TestPriorClasses(unittest.TestCase):
def test_sampling_many(self):
"""Test that sampling from the prior always returns values within its domain."""
for prior in self.priors:
many_samples = prior.sample(1000)
self.assertTrue(all((many_samples >= prior.minimum) & (many_samples <= prior.maximum)))
many_samples = prior.sample(5000)
self.assertTrue((all(many_samples >= prior.minimum)) & (all(many_samples <= prior.maximum)))
def test_probability_above_domain(self):
"""Test that the prior probability is non-negative in domain of validity and zero outside."""
for prior in self.priors:
if prior.maximum != np.inf:
outside_domain = np.linspace(prior.maximum + 1, prior.maximum + 1e4, 1000)
if bilby.core.prior.JointPrior in prior.__class__.__mro__:
if not prior.dist.filled_request():
prior.dist.requested_parameters[prior.name] = outside_domain
continue
self.assertTrue(all(prior.prob(outside_domain) == 0))
def test_probability_below_domain(self):
......@@ -293,6 +308,10 @@ class TestPriorClasses(unittest.TestCase):
for prior in self.priors:
if prior.minimum != -np.inf:
outside_domain = np.linspace(prior.minimum - 1e4, prior.minimum - 1, 1000)
if bilby.core.prior.JointPrior in prior.__class__.__mro__:
if not prior.dist.filled_request():
prior.dist.requested_parameters[prior.name] = outside_domain
continue
self.assertTrue(all(prior.prob(outside_domain) == 0))
def test_least_recently_sampled(self):
......@@ -338,6 +357,8 @@ class TestPriorClasses(unittest.TestCase):
def test_cdf_zero_below_domain(self):
for prior in self.priors:
if bilby.core.prior.JointPrior in prior.__class__.__mro__ and prior.maximum == np.inf:
continue
if prior.minimum != -np.inf:
outside_domain = np.linspace(
prior.minimum - 1e4, prior.minimum - 1, 1000)
......@@ -479,7 +500,13 @@ class TestPriorClasses(unittest.TestCase):
if isinstance(prior, bilby.core.prior.DeltaFunction):
continue
surround_domain = np.linspace(prior.minimum - 1, prior.maximum + 1, 1000)
prior.prob(surround_domain)
indomain = (surround_domain >= prior.minimum) | (surround_domain <= prior.maximum)
outdomain = (surround_domain < prior.minimum) | (surround_domain > prior.maximum)
if bilby.core.prior.JointPrior in prior.__class__.__mro__:
if not prior.dist.filled_request():
continue
self.assertTrue(all(prior.prob(surround_domain[indomain]) >= 0))
self.assertTrue(all(prior.prob(surround_domain[outdomain]) == 0))
def test_normalized(self):
"""Test that each of the priors are normalised, this needs care for delta function and Gaussian priors"""
......@@ -634,6 +661,10 @@ class TestPriorClasses(unittest.TestCase):
'MultivariateGaussianDist',
'bilby.core.prior.MultivariateGaussianDist'
)
elif isinstance(prior, bilby.gw.prior.HealPixPrior):
repr_prior_string = 'bilby.gw.prior.'+repr(prior)
repr_prior_string = repr_prior_string.replace('HealPixMapPriorDist',
'bilby.gw.prior.HealPixMapPriorDist')
elif isinstance(prior, bilby.gw.prior.UniformComovingVolume):
repr_prior_string = 'bilby.gw.prior.' + repr(prior)
elif 'Conditional' in prior.__class__.__name__:
......@@ -651,7 +682,7 @@ class TestPriorClasses(unittest.TestCase):
bilby.core.prior.Exponential, bilby.core.prior.StudentT,
bilby.core.prior.Logistic, bilby.core.prior.Cauchy,
bilby.core.prior.Gamma, bilby.core.prior.MultivariateGaussian,
bilby.core.prior.FermiDirac)):
bilby.core.prior.FermiDirac, bilby.gw.prior.HealPixPrior)):
continue
prior.maximum = (prior.maximum + prior.minimum) / 2
self.assertTrue(max(prior.sample(10000)) < prior.maximum)
......@@ -664,7 +695,7 @@ class TestPriorClasses(unittest.TestCase):
bilby.core.prior.Exponential, bilby.core.prior.StudentT,
bilby.core.prior.Logistic, bilby.core.prior.Cauchy,
bilby.core.prior.Gamma, bilby.core.prior.MultivariateGaussian,
bilby.core.prior.FermiDirac)):
bilby.core.prior.FermiDirac, bilby.gw.prior.HealPixPrior)):
continue
prior.minimum = (prior.maximum + prior.minimum) / 2
self.assertTrue(min(prior.sample(10000)) > prior.minimum)
......@@ -836,6 +867,13 @@ class TestPriorDict(unittest.TestCase):
expected = dict(length=np.array([42., 42., 42.]))
self.assertTrue(np.array_equal(expected['length'], samples['length']))
def test_sample_subset_constrained_as_array(self):
size = 3
keys = ["mass", "speed"]
out = self.prior_set_from_dict.sample_subset_constrained_as_array(keys, size)
self.assertTrue(isinstance(out, np.ndarray))
self.assertTrue(out.shape == (len(keys), size))
def test_sample(self):
size = 7
np.random.seed(42)
......@@ -1214,6 +1252,12 @@ class TestJsonIO(unittest.TestCase):
mus=[1, 1],
covs=np.array([[2., 0.5], [0.5, 2.]]),
weights=1.)
hp_map_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'prior_files/GW150914_testing_skymap.fits')
hp_dist = bilby.gw.prior.HealPixMapPriorDist(hp_map_file,
names=['testra', 'testdec'])
hp_3d_dist = bilby.gw.prior.HealPixMapPriorDist(hp_map_file,
names=['testra', 'testdec', 'testdistance'], distance=True)
self.priors = bilby.core.prior.PriorDict(dict(
a=bilby.core.prior.DeltaFunction(name='test', unit='unit', peak=1),
......@@ -1249,7 +1293,12 @@ class TestJsonIO(unittest.TestCase):
ad=bilby.core.prior.MultivariateGaussian(dist=mvg, name='testa', unit='unit'),
ae=bilby.core.prior.MultivariateGaussian(dist=mvg, name='testb', unit='unit'),
af=bilby.core.prior.MultivariateNormal(dist=mvn, name='testa', unit='unit'),
ag=bilby.core.prior.MultivariateNormal(dist=mvn, name='testb', unit='unit')
ag=bilby.core.prior.MultivariateNormal(dist=mvn, name='testb', unit='unit'),
ah=bilby.gw.prior.HealPixPrior(dist=hp_dist, name='testra', unit='unit'),
ai=bilby.gw.prior.HealPixPrior(dist=hp_dist, name='testdec', unit='unit'),
aj=bilby.gw.prior.HealPixPrior(dist=hp_3d_dist, name='testra', unit='unit'),
ak=bilby.gw.prior.HealPixPrior(dist=hp_3d_dist, name='testdec', unit='unit'),
al=bilby.gw.prior.HealPixPrior(dist=hp_3d_dist, name='testdistance', unit='unit')
))
def test_read_write_to_json(self):
......
......@@ -98,7 +98,9 @@ class TestCPNest(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = dict()
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.sampler = bilby.core.sampler.Cpnest(self.likelihood, self.priors,
outdir='outdir', label='label',
use_ratio=False, plot=False,
......@@ -133,9 +135,9 @@ class TestDynesty(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = bilby.core.prior.PriorDict()
self.priors['a'] = bilby.core.prior.Prior()
self.priors['b'] = bilby.core.prior.Prior()
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.sampler = bilby.core.sampler.Dynesty(self.likelihood, self.priors,
outdir='outdir', label='label',
use_ratio=False, plot=False,
......@@ -208,7 +210,9 @@ class TestEmcee(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = dict()
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.sampler = bilby.core.sampler.Emcee(self.likelihood, self.priors,
outdir='outdir', label='label',
use_ratio=False, plot=False,
......@@ -244,11 +248,13 @@ class TestKombine(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = dict()
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.sampler = bilby.core.sampler.Kombine(self.likelihood, self.priors,
outdir='outdir', label='label',
use_ratio=False, plot=False,
skip_import_verification=True)
outdir='outdir', label='label',
use_ratio=False, plot=False,
skip_import_verification=True)
def tearDown(self):
del self.likelihood
......@@ -279,7 +285,9 @@ class TestNestle(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = dict()
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.sampler = bilby.core.sampler.Nestle(self.likelihood, self.priors,
outdir='outdir', label='label',
use_ratio=False, plot=False,
......@@ -316,7 +324,9 @@ class TestPolyChord(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = dict(a=bilby.prior.Uniform(0, 1))
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.sampler = bilby.core.sampler.PyPolyChord(self.likelihood, self.priors,
outdir='outdir', label='polychord',
use_ratio=False, plot=False,
......@@ -363,7 +373,9 @@ class TestPTEmcee(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = dict()
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.sampler = bilby.core.sampler.Ptemcee(self.likelihood, self.priors,
outdir='outdir', label='label',
use_ratio=False, plot=False,
......@@ -410,7 +422,9 @@ class TestPyMC3(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = dict()
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.sampler = bilby.core.sampler.Pymc3(self.likelihood, self.priors,
outdir='outdir', label='label',
use_ratio=False, plot=False,
......@@ -448,7 +462,9 @@ class TestPymultinest(unittest.TestCase):
def setUp(self):
self.likelihood = MagicMock()
self.priors = bilby.core.prior.PriorDict()
self.priors = bilby.core.prior.PriorDict(
dict(a=bilby.core.prior.Uniform(0, 1),
b=bilby.core.prior.Uniform(0, 1)))
self.priors['a'] = bilby.core.prior.Prior(boundary='periodic')
self.priors['b'] = bilby.core.prior.Prior(boundary='reflective')
self.sampler = bilby.core.sampler.Pymultinest(self.likelihood, self.priors,
......