Source code for bilby_pipe.data_analysis
#!/usr/bin/env python
""" Script to perform data analysis """
import os
import signal
import sys
import numpy as np
import bilby
from bilby_pipe.input import Input
from bilby_pipe.main import parse_args
from bilby_pipe.parser import create_parser
from bilby_pipe.utils import (
CHECKPOINT_EXIT_CODE,
BilbyPipeError,
DataDump,
log_version_information,
logger,
)
# fmt: off
import matplotlib # isort:skip
matplotlib.use("agg")
# fmt: on
[docs]
def sighandler(signum, frame):
logger.info("Performing periodic eviction")
sys.exit(CHECKPOINT_EXIT_CODE)
[docs]
class DataAnalysisInput(Input):
"""Handles user-input for the data analysis script
Parameters
----------
parser: BilbyArgParser, optional
The parser containing the command line / ini file inputs
args_list: list, optional
A list of the arguments to parse. Defaults to `sys.argv[1:]`
"""
def __init__(self, args, unknown_args, test=False):
super().__init__(args, unknown_args)
# Generic initialisation
# Admin arguments
# Naming arguments
# Data dump file to run on
# Choices for running
self.sampling_seed = args.sampling_seed
# Frequencies
# Waveform, source model and likelihood
# ROQ
# Calibration
# Marginalization
if test is False:
self._load_data_dump()
@property
@sampling_seed.setter
def sampling_seed(self, sampling_seed):
if sampling_seed is None:
sampling_seed = np.random.randint(1, 1e6)
self._sampling_seed = sampling_seed
np.random.seed(sampling_seed)
logger.info(f"Sampling seed set to {sampling_seed}")
if not any(
[
k in self.sampler_kwargs
for k in bilby.core.sampler.Sampler.sampling_seed_equiv_kwargs
]
):
self.sampler_kwargs["sampling_seed"] = self._sampling_seed
@property
[docs]
def interferometers(self):
try:
return self._interferometers
except AttributeError:
ifos = self.data_dump.interferometers
names = [ifo.name for ifo in ifos]
logger.info(f"Found data for detectors = {names}")
ifos_to_use = [ifo for ifo in ifos if ifo.name in self.detectors]
names_to_use = [ifo.name for ifo in ifos_to_use]
logger.info(f"Using data for detectors = {names_to_use}")
self._interferometers = bilby.gw.detector.InterferometerList(ifos_to_use)
self.print_detector_information(self._interferometers)
return self._interferometers
@staticmethod
[docs]
def print_detector_information(interferometers):
for ifo in interferometers:
logger.info(
"{}: sampling-frequency={}, segment-start-time={}, duration={}".format(
ifo.name,
ifo.strain_data.sampling_frequency,
ifo.strain_data.start_time,
ifo.strain_data.duration,
)
)
@property
[docs]
def data_dump(self):
if hasattr(self, "_data_dump"):
return self._data_dump
else:
raise BilbyPipeError("Data dump not loaded")
[docs]
def _load_data_dump(self):
filename = self.data_dump_file
self.meta_data["data_dump"] = filename
logger.debug("Data dump not previously loaded")
if os.path.isfile(filename):
pass
elif os.path.isfile(os.path.basename(filename)):
filename = os.path.basename(filename)
else:
raise FileNotFoundError(
"No dump data {} file found. Most likely the generation "
"step failed".format(filename)
)
self._data_dump = DataDump.from_pickle(filename)
self.meta_data.update(self._data_dump.meta_data)
return self._data_dump
@property
[docs]
def result_class(self):
"""The bilby result class to store results in"""
try:
return bilby.gw.result.CompactBinaryCoalescenceResult
except AttributeError:
logger.debug("Unable to use CBC specific result class")
return None
@property
[docs]
def result_directory(self):
result_dir = os.path.join(self.outdir, "result")
return os.path.relpath(result_dir)
[docs]
def get_likelihood_and_priors(self):
"""Read in the likelihood and prior from the data dump
This reads in the data dump values and reconstructs the likelihood and
priors. Note, care must be taken to use the "search_priors" which differ
from the true prior when using marginalization
Returns
-------
likelihood, priors
The bilby likelihood and priors
"""
priors = self.data_dump.priors_class(self.data_dump.priors_dict)
self.priors = priors
self.likelihood_lookup_table = self.data_dump.likelihood_lookup_table
self.likelihood_roq_weights = self.data_dump.likelihood_roq_weights
self.likelihood_roq_params = self.data_dump.likelihood_roq_params
likelihood = self.likelihood
priors = self.search_priors
return likelihood, priors
[docs]
def run_sampler(self):
if self.scheduler.lower() == "condor":
signal.signal(signal.SIGALRM, handler=sighandler)
signal.alarm(self.periodic_restart_time)
likelihood, priors = self.get_likelihood_and_priors()
self.result = bilby.run_sampler(
likelihood=likelihood,
priors=priors,
sampler=self.sampler,
label=self.label,
outdir=self.result_directory,
conversion_function=self.parameter_generation,
injection_parameters=self.meta_data["injection_parameters"],
meta_data=self.meta_data,
result_class=self.result_class,
exit_code=CHECKPOINT_EXIT_CODE,
save=self.result_format,
**self.sampler_kwargs,
)
[docs]
def create_analysis_parser():
"""Data analysis parser creation"""
return create_parser(top_level=False)
[docs]
def main():
"""Data analysis main logic"""
args, unknown_args = parse_args(sys.argv[1:], create_analysis_parser())
log_version_information()
analysis = DataAnalysisInput(args, unknown_args)
analysis.run_sampler()
sys.exit(0)