diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b88a77cdbcf2dfc1106d3725cd8638c6aebb4d00..6621a33c0ae2bb32f36c0c115ce23ff20bfa6040 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,11 +21,13 @@ exitcode-jessie: - pip install -r requirements.txt - pip install coverage - pip install coverage-badge + - python setup.py install - coverage erase - coverage run --include=tupak/* -a test/prior_tests.py - coverage run --include=tupak/* -a test/tests.py - coverage run --include=tupak/* -a test/waveform_generator_tests.py - coverage run --include=tupak/* -a test/noise_realisation_tests.py + - coverage run --include=tupak/* -a test/example_tests.py - coverage html - coverage-badge -o coverage_badge.svg -f artifacts: diff --git a/examples/injection_examples/create_your_own_time_domain_source_model.py b/examples/injection_examples/create_your_own_time_domain_source_model.py index 4563e767c718f92252ecb439316f6fc9616cf28e..eb95e7f379cfd73e30b872a274e3ea4b18ed2f2f 100644 --- a/examples/injection_examples/create_your_own_time_domain_source_model.py +++ b/examples/injection_examples/create_your_own_time_domain_source_model.py @@ -64,7 +64,7 @@ prior['phase'] = tupak.prior.Uniform(-np.pi/2, np.pi/2, r'$\phi$') # define likelihood -likelihood = tupak.likelihood.Likelihood(IFOs, waveform) +likelihood = tupak.likelihood.GravitationalWaveTransient(IFOs, waveform) # launch sampler result = tupak.sampler.run_sampler(likelihood, prior, sampler='dynesty', npoints=1000, diff --git a/examples/other_examples/alternative_likelihoods.py b/examples/other_examples/alternative_likelihoods.py index 329f9f339053ad67bc598a8cb83be0e169ab6f2a..0bc5227759fef817ae62c4fbb584f84590713eb2 100644 --- a/examples/other_examples/alternative_likelihoods.py +++ b/examples/other_examples/alternative_likelihoods.py @@ -20,7 +20,7 @@ outdir = 'outdir' # use of the `tupak` waveform_generator to make the signal (more on this later) # But, one could make this work without the waveform generator. -class GaussianLikelihood(): +class GaussianLikelihood(tupak.likelihood.Likelihood): def __init__(self, x, y, waveform_generator): self.x = x self.y = y diff --git a/requirements.txt b/requirements.txt index 636cb022bbb446aa2d3eb86133f7b5fdc72d9fb9..f71732b9408956a5cac6709a0079630222d20fde 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ future dynesty corner numpy -matplotlib>=1.4 +matplotlib>=2.0 scipy gwpy pandas diff --git a/test/example_tests.py b/test/example_tests.py new file mode 100644 index 0000000000000000000000000000000000000000..ab7a738cf11ce2f6530daa7711b445efdf9a9a61 --- /dev/null +++ b/test/example_tests.py @@ -0,0 +1,47 @@ +import unittest +import os +import shutil +import logging +import subprocess + + +class Test(unittest.TestCase): + outdir = 'outdir' + dir_path = os.path.dirname(os.path.realpath(__file__)) + dir_path = os.path.abspath(os.path.join(dir_path, os.path.pardir)) + + @classmethod + def setUpClass(self): + if os.path.isdir(self.outdir): + try: + shutil.rmtree(self.outdir) + except OSError: + logging.warning( + "{} not removed prior to tests".format(self.outdir)) + + @classmethod + def tearDownClass(self): + if os.path.isdir(self.outdir): + try: + shutil.rmtree(self.outdir) + except OSError: + logging.warning( + "{} not removed prior to tests".format(self.outdir)) + + def test_examples(self): + """ Loop over examples to check they run """ + examples = ['examples/injection_examples/basic_tutorial.py', + 'examples/injection_examples/change_sampled_parameters.py', + 'examples/injection_examples/marginalized_likelihood.py', + 'examples/injection_examples/create_your_own_time_domain_source_model.py', + 'examples/other_examples/alternative_likelihoods.py', + ] + for filename in examples: + print("Testing {}".format(filename)) + subprocess.check_call(['python', filename, '--test']) + + +if __name__ == '__main__': + unittest.main() + + diff --git a/tupak/result.py b/tupak/result.py index 3ef71a34cebf5d37ba05652b026c0922aa3726e7..07023b03cace71d61d721e7fffcd2817e547c1b0 100644 --- a/tupak/result.py +++ b/tupak/result.py @@ -3,14 +3,14 @@ import os import numpy as np import deepdish import pandas as pd -import tupak try: from chainconsumer import ChainConsumer except ImportError: def ChainConsumer(): - raise ImportError( - "You do not have the optional module chainconsumer installed") + logging.warning( + "You do not have the optional module chainconsumer installed" + " unable to generate a corner plot") def result_file_name(outdir, label): @@ -142,10 +142,11 @@ class Result(dict): if label is None: self.parameter_labels[i] = 'Unknown' c = ChainConsumer() - c.add_chain(self.samples, parameters=self.parameter_labels, - name=self.label) - fig = c.plotter.plot(**kwargs) - return fig + if c: + c.add_chain(self.samples, parameters=self.parameter_labels, + name=self.label) + fig = c.plotter.plot(**kwargs) + return fig def plot_walks(self, save=True, **kwargs): """ Plot the chain walks using chain-consumer @@ -165,12 +166,13 @@ class Result(dict): if save: kwargs['filename'] = '{}/{}_walks.png'.format(self.outdir, self.label) logging.info('Saving walker plot to {}'.format(kwargs['filename'])) - if self.injection_parameters is not None: + if getattr(self, 'injection_parameters', None) is not None: kwargs['truth'] = [self.injection_parameters[key] for key in self.search_parameter_keys] c = ChainConsumer() - c.add_chain(self.samples, parameters=self.parameter_labels) - fig = c.plotter.plot_walks(**kwargs) - return fig + if c: + c.add_chain(self.samples, parameters=self.parameter_labels) + fig = c.plotter.plot_walks(**kwargs) + return fig def plot_distributions(self, save=True, **kwargs): """ Plot the chain walks using chain-consumer @@ -190,12 +192,13 @@ class Result(dict): if save: kwargs['filename'] = '{}/{}_distributions.png'.format(self.outdir, self.label) logging.info('Saving distributions plot to {}'.format(kwargs['filename'])) - if self.injection_parameters is not None: + if getattr(self, 'injection_parameters', None) is not None: kwargs['truth'] = [self.injection_parameters[key] for key in self.search_parameter_keys] c = ChainConsumer() - c.add_chain(self.samples, parameters=self.parameter_labels) - fig = c.plotter.plot_distributions(**kwargs) - return fig + if c: + c.add_chain(self.samples, parameters=self.parameter_labels) + fig = c.plotter.plot_distributions(**kwargs) + return fig def write_prior_to_file(self, outdir): """ diff --git a/tupak/sampler.py b/tupak/sampler.py index c6e9565b9574ec9ff0b86ddfc4b88d241373cbcf..16f7a34fe8d2ca72c66f1c67b238911224e03bd6 100644 --- a/tupak/sampler.py +++ b/tupak/sampler.py @@ -190,6 +190,9 @@ class Sampler(object): def run_sampler(self): pass + def _run_test(self): + raise ValueError("Method not yet implemented") + def check_cached_result(self): """ Check if the cached data file exists and can be used """ @@ -263,6 +266,18 @@ class Nestle(Sampler): self.result.logzerr = out.logzerr return self.result + def _run_test(self): + nestle = self.external_sampler + self.external_sampler_function = nestle.sample + self.external_sampler_function( + loglikelihood=self.log_likelihood, + prior_transform=self.prior_transform, + ndim=self.ndim, maxiter=10, **self.kwargs) + self.result.samples = np.random.uniform(0, 1, (100, self.ndim)) + self.result.logz = np.nan + self.result.logzerr = np.nan + return self.result + class Dynesty(Sampler): @@ -312,6 +327,22 @@ class Dynesty(Sampler): self.result.logzerr = out.logzerr[-1] return self.result + def _run_test(self): + dynesty = self.external_sampler + nested_sampler = dynesty.NestedSampler( + loglikelihood=self.log_likelihood, + prior_transform=self.prior_transform, + ndim=self.ndim, **self.kwargs) + nested_sampler.run_nested( + dlogz=self.kwargs['dlogz'], + print_progress=self.kwargs['verbose'], + maxiter=10) + + self.result.samples = np.random.uniform(0, 1, (100, self.ndim)) + self.result.logz = np.nan + self.result.logzerr = np.nan + return self.result + class Pymultinest(Sampler): @@ -458,7 +489,11 @@ def run_sampler(likelihood, priors=None, label='label', outdir='outdir', logging.info("Using cached result") return sampler.cached_result - result = sampler.run_sampler() + if utils.command_line_args.test: + result = sampler._run_test() + else: + result = sampler.run_sampler() + result.noise_logz = likelihood.noise_log_likelihood() if use_ratio: result.log_bayes_factor = result.logz diff --git a/tupak/utils.py b/tupak/utils.py index 3bf1baf0e8cd785c911a0670fade064ab96eb985..5d096ace0321700ff570da440916bad3305324e0 100644 --- a/tupak/utils.py +++ b/tupak/utils.py @@ -530,6 +530,9 @@ def set_up_command_line_arguments(): default=['H1', 'L1', 'V1'], help=("List of detectors to use in open data calls, " "e.g. -d H1 L1 for H1 and L1")) + parser.add_argument("-t", "--test", action="store_true", + help=("Used for testing only: don't run full PE, but" + " just check nothing breaks")) args, _ = parser.parse_known_args() if args.quite: