diff --git a/pycbc/boundaries.py b/pycbc/boundaries.py index cef305dfa42..4199308c864 100644 --- a/pycbc/boundaries.py +++ b/pycbc/boundaries.py @@ -311,12 +311,16 @@ def __init__(self, min_bound=-numpy.inf, max_bound=numpy.inf, # can be used with arrays if self._min.name == 'reflected' and self._max.name == 'reflected': self._reflect = numpy.vectorize(self._reflect_well) + self.reflected = 'well' elif self._min.name == 'reflected': self._reflect = numpy.vectorize(self._min.reflect_right) + self.reflected = 'min' elif self._max.name == 'reflected': self._reflect = numpy.vectorize(self._max.reflect_left) + self.reflected = 'max' else: self._reflect = _pass + self.reflected = False def __repr__(self): return str(self.__class__)[:-1] + " " + " ".join( diff --git a/pycbc/distributions/joint.py b/pycbc/distributions/joint.py index d99e4ef4f85..f0c7b7eb2b8 100644 --- a/pycbc/distributions/joint.py +++ b/pycbc/distributions/joint.py @@ -195,6 +195,38 @@ def rvs(self, size=1): return out + @property + def well_reflected(self): + """ Get list of which parameters are well reflected + """ + reflect = [] + bounds = self.bounds + for param in bounds: + if bounds[param].reflected == 'well': + reflect.append(param) + return reflect + + @property + def cyclic(self): + """ Get list of which parameters are cyclic + """ + cyclic = [] + bounds = self.bounds + for param in bounds: + if bounds[param].cyclic: + cyclic.append(param) + return cyclic + + @property + def bounds(self): + """ Get the dict of boundaries + """ + bnds = {} + for dist in self.distributions: + if hasattr(dist, 'bounds'): + bnds.update(dist.bounds) + return bnds + def cdfinv(self, **original): """ Apply the inverse cdf to the array of values [0, 1]. Every variable parameter must be given as a keyword argument. diff --git a/pycbc/inference/sampler/dynesty.py b/pycbc/inference/sampler/dynesty.py index a7fd4972216..9857ff239b4 100644 --- a/pycbc/inference/sampler/dynesty.py +++ b/pycbc/inference/sampler/dynesty.py @@ -104,6 +104,29 @@ def __init__(self, model, nlive, nprocesses=1, else: self.run_with_checkpoint = False + # Check for cyclic boundaries + periodic = [] + cyclic = self.model.prior_distribution.cyclic + for i, param in enumerate(self.variable_params): + if param in cyclic: + logging.info('Param: %s will be cyclic', param) + periodic.append(i) + + if len(periodic) == 0: + periodic = None + + # Check for reflected boundaries. Dynesty only supports + # reflection on both min and max of boundary. + reflective = [] + reflect = self.model.prior_distribution.well_reflected + for i, param in enumerate(self.variable_params): + if param in reflect: + logging.info("Param: %s will be well reflected", param) + reflective.append(i) + + if len(reflective) == 0: + reflective = None + if self.nlive < 0: # Interpret a negative input value for the number of live points # (which is clearly an invalid input in all senses) @@ -111,6 +134,8 @@ def __init__(self, model, nlive, nprocesses=1, self._sampler = dynesty.DynamicNestedSampler(log_likelihood_call, prior_call, self.ndim, pool=self.pool, + reflective=reflective, + periodic=periodic, **kwargs) self.run_with_checkpoint = False logging.info("Checkpointing not currently supported with" @@ -119,6 +144,8 @@ def __init__(self, model, nlive, nprocesses=1, self._sampler = dynesty.NestedSampler(log_likelihood_call, prior_call, self.ndim, nlive=self.nlive, + reflective=reflective, + periodic=periodic, pool=self.pool, **kwargs) # properties of the internal sampler which should not be pickled