diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9c6d0878810b7d8955aeb118e9a0286f27fbb1b0..d1572e049c48385afb8d9a75148da796cffb07a8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,7 +43,7 @@ basic-3.7: # test example on python 3.7 python-3.7: stage: test - image: bilbydev/v2-dockerfile-test-suite-python37 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python37 script: - python -m pip install . @@ -69,7 +69,7 @@ python-3.7: # test example on python 3.8 python-3.8: stage: test - image: bilbydev/v2-dockerfile-test-suite-python38 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python38 script: - python -m pip install . @@ -78,7 +78,7 @@ python-3.8: # test example on python 3.6 python-3.6: stage: test - image: bilbydev/v2-dockerfile-test-suite-python36 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python36 script: - python -m pip install . @@ -87,7 +87,7 @@ python-3.6: # test samplers on python 3.7 python-3.7-samplers: stage: test - image: bilbydev/v2-dockerfile-test-suite-python37 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python37 script: - python -m pip install . @@ -97,7 +97,7 @@ python-3.7-samplers: # test samplers on python 3.6 python-3.6-samplers: stage: test - image: bilbydev/v2-dockerfile-test-suite-python36 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python36 script: - python -m pip install . @@ -106,7 +106,7 @@ python-3.6-samplers: # Test containers are up to date containers: stage: test - image: bilbydev/v2-dockerfile-test-suite-python37 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python37 script: - cd containers - python write_dockerfiles.py @@ -117,7 +117,7 @@ containers: # Tests run at a fixed schedule rather than on push scheduled-python-3.7: stage: test - image: bilbydev/v2-dockerfile-test-suite-python37 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python37 only: - schedules script: @@ -129,7 +129,7 @@ scheduled-python-3.7: plotting: stage: test - image: bilbydev/bilby-test-suite-python37 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python37 only: - schedules script: @@ -140,7 +140,7 @@ plotting: authors: stage: test - image: bilbydev/bilby-test-suite-python37 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python37 script: - python test/check_author_list.py @@ -162,7 +162,7 @@ pages: deploy_release: stage: deploy - image: bilbydev/v2-dockerfile-test-suite-python37 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python37 variables: TWINE_USERNAME: $PYPI_USERNAME TWINE_PASSWORD: $PYPI_PASSWORD @@ -177,7 +177,7 @@ deploy_release: precommits-py3.7: stage: test - image: bilbydev/v2-dockerfile-test-suite-python37 + image: quay.io/bilbydev/v2-dockerfile-test-suite-python37 script: - source activate python37 - mkdir -p .pip37 diff --git a/CHANGELOG.md b/CHANGELOG.md index 612437929298e18624c5d170b790075909a6e7c6..ddbd703b36f04a438a61bcc14338310d13c0ef43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # All notable changes will be documented in this file +## [1.0.3] 2020-11-23 +Version 1.0.4 release of bilby + +### Added +- Added a chirp-mass and mass-ratio prior which are uniform in component masses (!891) + +### Changes +- Fixed issue in the CI + ## [1.0.3] 2020-10-23 Version 1.0.3 release of bilby diff --git a/bilby/core/prior/analytical.py b/bilby/core/prior/analytical.py index 7a7fb2b6b5c59b5be7178e60172c889a0b20d380..a2aa4cac57a9ea2c44f0768fc697bdbca5ef520a 100644 --- a/bilby/core/prior/analytical.py +++ b/bilby/core/prior/analytical.py @@ -370,8 +370,8 @@ class SymmetricLogUniform(Prior): class Cosine(Prior): - def __init__(self, name=None, latex_label=None, unit=None, - minimum=-np.pi / 2, maximum=np.pi / 2, boundary=None): + def __init__(self, minimum=-np.pi / 2, maximum=np.pi / 2, name=None, + latex_label=None, unit=None, boundary=None): """Cosine prior with bounds Parameters @@ -389,8 +389,8 @@ class Cosine(Prior): boundary: str See superclass """ - super(Cosine, self).__init__(name=name, latex_label=latex_label, unit=unit, - minimum=minimum, maximum=maximum, boundary=boundary) + super(Cosine, self).__init__(minimum=minimum, maximum=maximum, name=name, + latex_label=latex_label, unit=unit, boundary=boundary) def rescale(self, val): """ @@ -425,8 +425,8 @@ class Cosine(Prior): class Sine(Prior): - def __init__(self, name=None, latex_label=None, unit=None, minimum=0, - maximum=np.pi, boundary=None): + def __init__(self, minimum=0, maximum=np.pi, name=None, + latex_label=None, unit=None, boundary=None): """Sine prior with bounds Parameters @@ -444,8 +444,8 @@ class Sine(Prior): boundary: str See superclass """ - super(Sine, self).__init__(name=name, latex_label=latex_label, unit=unit, - minimum=minimum, maximum=maximum, boundary=boundary) + super(Sine, self).__init__(minimum=minimum, maximum=maximum, name=name, + latex_label=latex_label, unit=unit, boundary=boundary) def rescale(self, val): """ diff --git a/bilby/core/sampler/dynesty.py b/bilby/core/sampler/dynesty.py index e1b0dd1f2831e60df867905709e317def3b425c2..206ed9a42ccb28af6a251e8a0dfa9f7c20fb753a 100644 --- a/bilby/core/sampler/dynesty.py +++ b/bilby/core/sampler/dynesty.py @@ -612,7 +612,7 @@ class Dynesty(NestedSampler): fig = dyplot.traceplot(self.sampler.results, labels=labels)[0] fig.tight_layout() fig.savefig(filename) - except (RuntimeError, np.linalg.linalg.LinAlgError, ValueError) as e: + except (RuntimeError, np.linalg.linalg.LinAlgError, ValueError, OverflowError, Exception) as e: logger.warning(e) logger.warning('Failed to create dynesty state plot at checkpoint') finally: @@ -690,6 +690,16 @@ class Dynesty(NestedSampler): """ return self.priors.rescale(self._search_parameter_keys, theta) + def calc_likelihood_count(self): + if self.likelihood_benchmark: + if hasattr(self, 'sampler'): + self.result.num_likelihood_evaluations = \ + getattr(self.sampler, 'ncall', 0) + else: + self.result.num_likelihood_evaluations = 0 + else: + return None + def sample_rwalk_bilby(args): """ Modified bilby-implemented version of dynesty.sampling.sample_rwalk """ diff --git a/bilby/core/sampler/ultranest.py b/bilby/core/sampler/ultranest.py index fdae9a8e9c4393b857a58a27a8f075d2bc704d12..9fa12578ddb9154d5ccdab5101c482891d83fa6d 100644 --- a/bilby/core/sampler/ultranest.py +++ b/bilby/core/sampler/ultranest.py @@ -61,7 +61,7 @@ class Ultranest(NestedSampler): log_interval=None, dlogz=None, max_iters=None, - update_interval_iter_fraction=0.2, + update_interval_volume_fraction=0.2, viz_callback=None, dKL=0.5, frac_remain=0.01, @@ -232,7 +232,7 @@ class Ultranest(NestedSampler): ] else: keys = [ - "update_interval_iter_fraction", + "update_interval_volume_fraction", "update_interval_ncall", "log_interval", "show_status", diff --git a/bilby/gw/detector/detectors/A1.interferometer b/bilby/gw/detector/detectors/A1.interferometer new file mode 100644 index 0000000000000000000000000000000000000000..2cfb564a3b36b4aa3e41d7e6623b8b74e98264cf --- /dev/null +++ b/bilby/gw/detector/detectors/A1.interferometer @@ -0,0 +1,13 @@ +# LIGO India Aundha at Aplus sensitvity. +# LIGO-T2000158 +# https://dcc.ligo.org/LIGO-T2000012/public +name = 'A1' +power_spectral_density = PowerSpectralDensity(asd_file='Aplus_asd.txt') +minimum_frequency = 20 +maximum_frequency = 2048 +length = 4 +latitude = 19 + 36. / 60 + 47.9017 / 3600 +longitude = 77 + 1. / 60 + 51.0997 / 3600 +elevation = 440.0 +xarm_azimuth = 117.6157 +yarm_azimuth = 207.6165 diff --git a/bilby/gw/detector/strain_data.py b/bilby/gw/detector/strain_data.py index 6ba6db039ef244e5bb3295ba8796347af868a60f..da0a397827c3892316962513cc1a1da3e9ef2d6d 100644 --- a/bilby/gw/detector/strain_data.py +++ b/bilby/gw/detector/strain_data.py @@ -31,7 +31,7 @@ class InterferometerStrainData(object): time_array = PropertyAccessor('_times_and_frequencies', 'time_array') def __init__(self, minimum_frequency=0, maximum_frequency=np.inf, - roll_off=0.2): + roll_off=0.2, notch_list=None): """ Initiate an InterferometerStrainData object The initialised object contains no data, this should be added using one @@ -46,11 +46,14 @@ class InterferometerStrainData(object): roll_off: float The roll-off (in seconds) used in the Tukey window, default=0.2s. This corresponds to alpha * duration / 2 for scipy tukey window. + notch_list: bilby.gw.detector.strain_data.NotchList + A list of notches """ self.minimum_frequency = minimum_frequency self.maximum_frequency = maximum_frequency + self.notch_list = notch_list self.roll_off = roll_off self.window_factor = 1 @@ -122,18 +125,46 @@ class InterferometerStrainData(object): self._maximum_frequency = maximum_frequency self._frequency_mask_updated = False + @property + def notch_list(self): + return self._notch_list + + @notch_list.setter + def notch_list(self, notch_list): + """ Set the notch_list + + Parameters + ---------- + notch_list: list, bilby.gw.detector.strain_data.NotchList + A list of length-2 tuples of the (max, min) frequency for the + notches or a pre-made bilby NotchList. + + """ + if notch_list is None: + self._notch_list = NotchList(None) + elif isinstance(notch_list, list): + self._notch_list = NotchList(notch_list) + elif isinstance(notch_list, NotchList): + self._notch_list = notch_list + else: + raise ValueError("notch_list {} not understood".format(notch_list)) + self._frequency_mask_updated = False + @property def frequency_mask(self): - """Masking array for limiting the frequency band. + """ Masking array for limiting the frequency band. Returns ------- - array_like: An array of boolean values + mask: np.ndarray + An array of boolean values """ if not self._frequency_mask_updated: frequency_array = self._times_and_frequencies.frequency_array mask = ((frequency_array >= self.minimum_frequency) & (frequency_array <= self.maximum_frequency)) + for notch in self.notch_list: + mask[notch.get_idxs(frequency_array)] = False self._frequency_mask = mask self._frequency_mask_updated = True return self._frequency_mask @@ -683,3 +714,104 @@ class InterferometerStrainData(object): strain = strain.resample(sampling_frequency) self.set_from_gwpy_timeseries(strain) + + +class Notch(object): + def __init__(self, minimum_frequency, maximum_frequency): + """ A notch object storing the maximum and minimum frequency of the notch + + Parameters + ---------- + minimum_frequency, maximum_frequency: float + The minimum and maximum frequency of the notch + + """ + + if 0 < minimum_frequency < maximum_frequency < np.inf: + self.minimum_frequency = minimum_frequency + self.maximum_frequency = maximum_frequency + else: + msg = ("Your notch minimum_frequency {} and maximum_frequency {} are invalid" + .format(minimum_frequency, maximum_frequency)) + raise ValueError(msg) + + def get_idxs(self, frequency_array): + """ Get a boolean mask for the frequencies in frequency_array in the notch + + Parameters + ---------- + frequency_array: np.ndarray + An array of frequencies + + Returns + ------- + idxs: np.ndarray + An array of booleans which are True for frequencies in the notch + + """ + lower = (frequency_array > self.minimum_frequency) + upper = (frequency_array < self.maximum_frequency) + return lower & upper + + def check_frequency(self, freq): + """ Check if freq is inside the notch + + Parameters + ---------- + freq: float + The frequency to check + + Returns + ------- + True/False: + If freq inside the notch, return True, else False + """ + + if self.minimum_frequency < freq < self.maximum_frequency: + return True + else: + return False + + +class NotchList(list): + def __init__(self, notch_list): + """ A list of notches + + Parameters + ---------- + notch_list: list + A list of length-2 tuples of the (max, min) frequency for the + notches. + + Raises + ------ + ValueError + If the list is malformed. + """ + + if notch_list is not None: + for notch in notch_list: + if isinstance(notch, tuple) and len(notch) == 2: + self.append(Notch(*notch)) + else: + msg = "notch_list {} is malformed".format(notch_list) + raise ValueError(msg) + + def check_frequency(self, freq): + """ Check if freq is inside the notch list + + Parameters + ---------- + freq: float + The frequency to check + + Returns + ------- + True/False: + If freq inside any of the notches, return True, else False + """ + + for notch in self: + if notch.check_frequency(freq): + return True + return False diff --git a/bilby/gw/prior.py b/bilby/gw/prior.py index 7d1b37da3bf3c0f35000fc699f6c48cd85aa772e..3ffcfb193df6f34ed07deb9689def2adf444bb60 100644 --- a/bilby/gw/prior.py +++ b/bilby/gw/prior.py @@ -4,11 +4,13 @@ import copy import numpy as np from scipy.interpolate import InterpolatedUnivariateSpline, interp1d from scipy.integrate import cumtrapz +from scipy.special import hyp2f1 from scipy.stats import norm from ..core.prior import (PriorDict, Uniform, Prior, DeltaFunction, Gaussian, Interped, Constraint, conditional_prior_factory, - BaseJointPriorDist, JointPrior, JointPriorDistError) + BaseJointPriorDist, JointPrior, JointPriorDistError, + PowerLaw) from ..core.utils import infer_args_from_method, logger from .conversion import ( convert_to_lal_binary_black_hole_parameters, @@ -285,6 +287,93 @@ class UniformSourceFrame(Cosmological): return zs, p_dz +class UniformInComponentsChirpMass(PowerLaw): + + def __init__(self, minimum, maximum, name='chirp_mass', + latex_label='$\mathcal{M}$', unit=None, boundary=None): + """ + Prior distribution for chirp mass which is uniform in component masses. + + This is useful when chirp mass and mass ratio are sampled while the + prior is uniform in component masses. + + Parameters + ---------- + minimum : float + The minimum of chirp mass + maximum : float + The maximum of chirp mass + name: see superclass + latex_label: see superclass + unit: see superclass + boundary: see superclass + """ + super(UniformInComponentsChirpMass, self).__init__( + alpha=1., minimum=minimum, maximum=maximum, + name=name, latex_label=latex_label, unit=unit, boundary=boundary) + + +class WrappedInterp1d(interp1d): + """ A wrapper around scipy interp1d which sets equality-by-instantiation """ + def __eq__(self, other): + + for key in self.__dict__: + if type(self.__dict__[key]) is np.ndarray: + if not np.array_equal(self.__dict__[key], other.__dict__[key]): + return False + elif key == "_spline": + pass + elif getattr(self, key) != getattr(other, key): + return False + return True + + +class UniformInComponentsMassRatio(Prior): + + def __init__(self, minimum, maximum, name='mass_ratio', latex_label='$q$', + unit=None, boundary=None): + """ + Prior distribution for mass ratio which is uniform in component masses. + + This is useful when chirp mass and mass ratio are sampled while the + prior is uniform in component masses. + + Parameters + ---------- + minimum : float + The minimum of mass ratio + maximum : float + The maximum of mass ratio + name: see superclass + latex_label: see superclass + unit: see superclass + boundary: see superclass + """ + super(UniformInComponentsMassRatio, self).__init__( + minimum=minimum, maximum=maximum, name=name, + latex_label=latex_label, unit=unit, boundary=boundary) + self.norm = self._integral(maximum) - self._integral(minimum) + qs = np.linspace(minimum, maximum, 1000) + self.icdf = WrappedInterp1d( + self.cdf(qs), qs, kind='cubic', + bounds_error=False, fill_value=(minimum, maximum)) + + @staticmethod + def _integral(q): + return -5. * q**(-1. / 5.) * hyp2f1(-2. / 5., -1. / 5., 4. / 5., -q) + + def cdf(self, val): + return (self._integral(val) - self._integral(self.minimum)) / self.norm + + def rescale(self, val): + self.test_valid_for_rescaling(val) + return self.icdf(val) + + def prob(self, val): + in_prior = (val >= self.minimum) & (val <= self.maximum) + return (1. + val)**(2. / 5.) / (val**(6. / 5.)) / self.norm * in_prior + + class AlignedSpin(Interped): def __init__(self, a_prior=Uniform(0, 1), z_prior=Uniform(-1, 1), diff --git a/bilby/gw/source.py b/bilby/gw/source.py index 69109364a149304926318ebd8b73fc1adf96425e..3a346725d74c4a8ddf669bc1ec612c6acb87b75f 100644 --- a/bilby/gw/source.py +++ b/bilby/gw/source.py @@ -343,6 +343,15 @@ def _base_lal_cbc_fd_waveform( lalsim_SimInspiralWaveformParamsInsertTidalLambda2( waveform_dictionary, lambda_2) + for key, value in waveform_kwargs.items(): + func = getattr(lalsim, "SimInspiralWaveformParamsInsert" + key, None) + if func is not None: + func(waveform_dictionary, value) + + if waveform_kwargs.get('numerical_relativity_file', None) is not None: + lalsim.SimInspiralWaveformParamsInsertNumRelData( + waveform_dictionary, waveform_kwargs['numerical_relativity_file']) + if ('mode_array' in waveform_kwargs) and waveform_kwargs['mode_array'] is not None: mode_array = waveform_kwargs['mode_array'] mode_array_lal = lalsim.SimInspiralCreateModeArray() diff --git a/containers/dockerfile-template b/containers/dockerfile-template index 46d4f54700cb9bfad245e7d1e3113b85589d73f4..eb2fa024cae7f1f93bdfa0d6ef256d6867538809 100644 --- a/containers/dockerfile-template +++ b/containers/dockerfile-template @@ -1,4 +1,4 @@ -FROM continuumio/miniconda3 +FROM containers.ligo.org/docker/base:conda LABEL name="bilby Base miniconda3" \ maintainer="Gregory Ashton <gregory.ashton@ligo.org>" diff --git a/containers/v2-dockerfile-test-suite-python35 b/containers/v2-dockerfile-test-suite-python35 index 38d4c8b2fcaebd5dc78e87cd699cc8419b69c1dc..544b562f37dc870538b71a4207139a90e8101c5d 100644 --- a/containers/v2-dockerfile-test-suite-python35 +++ b/containers/v2-dockerfile-test-suite-python35 @@ -1,6 +1,6 @@ # This dockerfile is written automatically and should not be modified by hand. -FROM continuumio/miniconda3 +FROM containers.ligo.org/docker/base:conda LABEL name="bilby Base miniconda3" \ maintainer="Gregory Ashton <gregory.ashton@ligo.org>" diff --git a/containers/v2-dockerfile-test-suite-python36 b/containers/v2-dockerfile-test-suite-python36 index ae75fff03aa80026a56fa48bc7682f8acb852881..d9a2782cfb22c020520375665ff1668e7c5f6aa4 100644 --- a/containers/v2-dockerfile-test-suite-python36 +++ b/containers/v2-dockerfile-test-suite-python36 @@ -1,6 +1,6 @@ # This dockerfile is written automatically and should not be modified by hand. -FROM continuumio/miniconda3 +FROM containers.ligo.org/docker/base:conda LABEL name="bilby Base miniconda3" \ maintainer="Gregory Ashton <gregory.ashton@ligo.org>" diff --git a/containers/v2-dockerfile-test-suite-python37 b/containers/v2-dockerfile-test-suite-python37 index 9e27fcab40ae8a7c0561a32b508449e0943925a6..b77f489227fd58720727a24d1a8989cc7b9dc36a 100644 --- a/containers/v2-dockerfile-test-suite-python37 +++ b/containers/v2-dockerfile-test-suite-python37 @@ -1,6 +1,6 @@ # This dockerfile is written automatically and should not be modified by hand. -FROM continuumio/miniconda3 +FROM containers.ligo.org/docker/base:conda LABEL name="bilby Base miniconda3" \ maintainer="Gregory Ashton <gregory.ashton@ligo.org>" diff --git a/containers/v2-dockerfile-test-suite-python38 b/containers/v2-dockerfile-test-suite-python38 index 690055494c8798269a17a80386fe76de313a81ad..71cf85d0197a80f01ef5e7765d3a2875e40d8a11 100644 --- a/containers/v2-dockerfile-test-suite-python38 +++ b/containers/v2-dockerfile-test-suite-python38 @@ -1,6 +1,6 @@ # This dockerfile is written automatically and should not be modified by hand. -FROM continuumio/miniconda3 +FROM containers.ligo.org/docker/base:conda LABEL name="bilby Base miniconda3" \ maintainer="Gregory Ashton <gregory.ashton@ligo.org>" diff --git a/examples/core_examples/multidimensional_gaussian.py b/examples/core_examples/multidimensional_gaussian.py index 451afe3e06b8c6904de63b4991a34225d850b14c..c0078d50bb7e1e9b203b6b547b1822f8f46f8d87 100644 --- a/examples/core_examples/multidimensional_gaussian.py +++ b/examples/core_examples/multidimensional_gaussian.py @@ -33,6 +33,7 @@ class MultidimGaussianLikelihood(bilby.Likelihood): """ def __init__(self, data, dim): + super().__init__() self.dim = dim self.data = np.array(data) self.N = len(data) diff --git a/sampler_requirements.txt b/sampler_requirements.txt index 06a065393d711783bbd43dbb1e3a7ccc8b8b9560..08202cc3890a9fa56ea2b84a0f786f7568d515cb 100644 --- a/sampler_requirements.txt +++ b/sampler_requirements.txt @@ -7,5 +7,5 @@ pymc3==3.6; python_version <= '2.7' pymc3>=3.6; python_version > '3.4' pymultinest kombine -ultranest>=2.2.1 -dnest4 \ No newline at end of file +ultranest>=3.0.0 +dnest4 diff --git a/setup.py b/setup.py index daf2db2fc7252f02126b564695a821e93e2ee7c4..0882ade9b33e1477ff5ffccad7ee8a22be36fecc 100644 --- a/setup.py +++ b/setup.py @@ -64,7 +64,7 @@ def readfile(filename): return filecontents -VERSION = '1.0.3' +VERSION = '1.0.4' version_file = write_version_file(VERSION) long_description = get_long_description() diff --git a/test/core/sampler/ultranest_test.py b/test/core/sampler/ultranest_test.py index 76354e08281c379d28eda0abd9d18992220c4989..e70a70fdfb7785bd2457c01ee6399d022e88a91e 100644 --- a/test/core/sampler/ultranest_test.py +++ b/test/core/sampler/ultranest_test.py @@ -44,7 +44,7 @@ class TestUltranest(unittest.TestCase): log_interval=None, dlogz=None, max_iters=None, - update_interval_iter_fraction=0.2, + update_interval_volume_fraction=0.2, viz_callback=None, dKL=0.5, frac_remain=0.01, @@ -79,7 +79,7 @@ class TestUltranest(unittest.TestCase): log_interval=None, dlogz=None, max_iters=None, - update_interval_iter_fraction=0.2, + update_interval_volume_fraction=0.2, viz_callback=None, dKL=0.5, frac_remain=0.01, diff --git a/test/gw/detector/strain_data_test.py b/test/gw/detector/strain_data_test.py index a11e347df563b96afdde5e025abc47974a5fc989..9cba741042a714e9875e2995d55bc628d7b78cfd 100644 --- a/test/gw/detector/strain_data_test.py +++ b/test/gw/detector/strain_data_test.py @@ -35,6 +35,49 @@ class TestInterferometerStrainData(unittest.TestCase): np.array_equal(self.ifosd.frequency_mask, [False, True, False]) ) + def test_frequency_mask_2(self): + strain_data = bilby.gw.detector.InterferometerStrainData( + minimum_frequency=20, maximum_frequency=512) + strain_data.set_from_time_domain_strain( + time_domain_strain=np.random.normal(0, 1, 4096), + time_array=np.arange(0, 4, 4 / 4096) + ) + + # Test from init + freqs = strain_data.frequency_array[strain_data.frequency_mask] + self.assertTrue(all(freqs >= 20)) + self.assertTrue(all(freqs <= 512)) + + # Test from update + strain_data.minimum_frequency = 30 + strain_data.maximum_frequency = 256 + freqs = strain_data.frequency_array[strain_data.frequency_mask] + self.assertTrue(all(freqs >= 30)) + self.assertTrue(all(freqs <= 256)) + + def test_notches_frequency_mask(self): + strain_data = bilby.gw.detector.InterferometerStrainData( + minimum_frequency=20, maximum_frequency=512, notch_list=[(100, 101)]) + strain_data.set_from_time_domain_strain( + time_domain_strain=np.random.normal(0, 1, 4096), + time_array=np.arange(0, 4, 4 / 4096) + ) + + # Test from init + freqs = strain_data.frequency_array[strain_data.frequency_mask] + idxs = (freqs > 100) * (freqs < 101) + self.assertTrue(len(freqs[idxs]) == 0) + + # Test from setting + idxs = (freqs > 200) * (freqs < 201) + self.assertTrue(len(freqs[idxs]) > 0) + strain_data.notch_list = [(100, 101), (200, 201)] + freqs = strain_data.frequency_array[strain_data.frequency_mask] + idxs = (freqs > 200) * (freqs < 201) + self.assertTrue(len(freqs[idxs]) == 0) + idxs = (freqs > 100) * (freqs < 101) + self.assertTrue(len(freqs[idxs]) == 0) + def test_set_data_fails(self): with mock.patch("bilby.core.utils.create_frequency_series") as m: m.return_value = [1, 2, 3] @@ -316,5 +359,67 @@ class TestInterferometerStrainDataEquals(unittest.TestCase): self.assertNotEqual(self.ifosd_1, self.ifosd_2) +class TestNotch(unittest.TestCase): + def setUp(self): + self.minimum_frequency = 20 + self.maximum_frequency = 1024 + + def test_init(self): + notch = bilby.gw.detector.strain_data.Notch(self.minimum_frequency, self.maximum_frequency) + self.assertEqual(notch.minimum_frequency, self.minimum_frequency) + self.assertEqual(notch.maximum_frequency, self.maximum_frequency) + + def test_init_fail(self): + # Infinite frequency + with self.assertRaises(ValueError): + bilby.gw.detector.strain_data.Notch(self.minimum_frequency, np.inf) + + # Negative frequency + with self.assertRaises(ValueError): + bilby.gw.detector.strain_data.Notch(-10, 1024) + with self.assertRaises(ValueError): + bilby.gw.detector.strain_data.Notch(10, -1024) + + # Ordering + with self.assertRaises(ValueError): + bilby.gw.detector.strain_data.Notch(30, 20) + + def test_idxs(self): + notch = bilby.gw.detector.strain_data.Notch(self.minimum_frequency, self.maximum_frequency) + freqs = np.linspace(0, 2048, 100) + idxs = notch.get_idxs(freqs) + self.assertEqual(len(idxs), len(freqs)) + freqs_masked = freqs[idxs] + self.assertTrue(all(freqs_masked > notch.minimum_frequency)) + self.assertTrue(all(freqs_masked < notch.maximum_frequency)) + + +class TestNotchList(unittest.TestCase): + + def test_init_single(self): + notch_list_of_tuples = [(32, 34)] + notch_list = bilby.gw.detector.strain_data.NotchList(notch_list_of_tuples) + self.assertEqual(len(notch_list), len(notch_list_of_tuples)) + for notch, notch_tuple in zip(notch_list, notch_list_of_tuples): + self.assertEqual(notch.minimum_frequency, notch_tuple[0]) + self.assertEqual(notch.maximum_frequency, notch_tuple[1]) + + def test_init_multiple(self): + notch_list_of_tuples = [(32, 34), (56, 59)] + notch_list = bilby.gw.detector.strain_data.NotchList(notch_list_of_tuples) + self.assertEqual(len(notch_list), len(notch_list_of_tuples)) + for notch, notch_tuple in zip(notch_list, notch_list_of_tuples): + self.assertEqual(notch.minimum_frequency, notch_tuple[0]) + self.assertEqual(notch.maximum_frequency, notch_tuple[1]) + + def test_init_fail(self): + with self.assertRaises(ValueError): + bilby.gw.detector.strain_data.NotchList([20, 30]) + with self.assertRaises(ValueError): + bilby.gw.detector.strain_data.NotchList([(30, 20), (20)]) + with self.assertRaises(ValueError): + bilby.gw.detector.strain_data.NotchList([(30, 20, 20)]) + + if __name__ == "__main__": unittest.main() diff --git a/test/gw/plot_test.py b/test/gw/plot_test.py index 2a33fdec04df34257dbc76aaf07dc22f5a72d01e..e85aac75a6582834c504e66ab66aa7a90077a484 100644 --- a/test/gw/plot_test.py +++ b/test/gw/plot_test.py @@ -140,7 +140,7 @@ class TestCBCResult(unittest.TestCase): objid="test", instruments="H1L1", load_pickle=True, - colorbar=True, + colorbar=False, ) diff --git a/test/gw/source_test.py b/test/gw/source_test.py index d14517acf9549d08e7d329532d47eb4475bdb85f..ec4a2929ad96638b541ae7d39ac567d2c9fe7c4d 100644 --- a/test/gw/source_test.py +++ b/test/gw/source_test.py @@ -79,6 +79,19 @@ class TestLalBBH(unittest.TestCase): # bilby.gw.source.lal_binary_black_hole( # self.frequency_array, **self.parameters), dict) + def test_lal_bbh_xpprecession_version(self): + self.parameters.update(self.waveform_kwargs) + self.parameters["waveform_approximant"] = "IMRPhenomXP" + + # Test that we can modify the XP precession version + out_v223 = bilby.gw.source.lal_binary_black_hole( + self.frequency_array, PhenomXPrecVersion=223, **self.parameters + ) + out_v102 = bilby.gw.source.lal_binary_black_hole( + self.frequency_array, PhenomXPrecVersion=102, **self.parameters + ) + self.assertFalse(np.all(out_v223["plus"] == out_v102["plus"])) + class TestLalBNS(unittest.TestCase): def setUp(self):