Coverage for pesummary/gw/file/formats/bilby.py: 51.3%
115 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-05-02 08:42 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-05-02 08:42 +0000
1# Licensed under an MIT style license -- see LICENSE.md
3import numpy as np
4from pesummary.core.file.formats.bilby import Bilby as CoreBilby
5from pesummary.gw.file.formats.base_read import GWSingleAnalysisRead
6from pesummary.gw.plots.latex_labels import GWlatex_labels
7from pesummary.utils.utils import logger
9__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"]
12def read_bilby(
13 path, disable_prior=False, latex_dict=GWlatex_labels,
14 complex_params=["matched_filter_snr", "optimal_snr"], **kwargs
15):
16 """Grab the parameters and samples in a bilby file
18 Parameters
19 ----------
20 path: str
21 path to the result file you wish to read in
22 disable_prior: Bool, optional
23 if True, do not collect prior samples from the `bilby` result file.
24 Default False
25 complex_params: list, optional
26 list of parameters stored in the bilby result file which are complex
27 and you wish to store the `amplitude` and `angle` as seperate
28 posterior distributions
29 latex_dict: dict, optional
30 list of latex labels for each parameter
31 """
32 from pesummary.core.file.formats.bilby import (
33 read_bilby as _read_bilby
34 )
36 return _read_bilby(
37 path, disable_prior=disable_prior, latex_dict=latex_dict,
38 complex_params=complex_params, _bilby_class=Bilby, **kwargs
39 )
42def prior_samples_from_file(path, cls="BBHPriorDict", nsamples=5000, **kwargs):
43 """Return a dict of prior samples from a `bilby` prior file
45 Parameters
46 ----------
47 path: str
48 path to a `bilby` prior file
49 cls: str, optional
50 class you wish to read in the prior file
51 nsamples: int, optional
52 number of samples to draw from a prior file. Default 5000
53 """
54 from pesummary.core.file.formats.bilby import (
55 prior_samples_from_file as _prior_samples_from_file
56 )
57 from bilby.gw import prior
59 if isinstance(cls, str):
60 cls = getattr(prior, cls)
61 return _prior_samples_from_file(path, cls=cls, nsamples=nsamples, **kwargs)
64class Bilby(GWSingleAnalysisRead):
65 """PESummary wrapper of `bilby` (https://git.ligo.org/lscsoft/bilby). The
66 path_to_results_file argument will be passed directly to
67 `bilby.core.result.read_in_result`. All functions therefore use `bilby`
68 methods and requires `bilby` to be installed.
70 Parameters
71 ----------
72 path_to_results_file: str
73 path to the results file that you wish to read in with `bilby`.
74 disable_prior: Bool, optional
75 if True, do not collect prior samples from the `bilby` result file.
76 Default False
77 disable_prior_conversion: Bool, optional
78 if True, disable the conversion module from deriving alternative prior
79 distributions. Default False
80 pe_algorithm: str
81 name of the algorithm used to generate the posterior samples
82 remove_nan_likelihood_samples: Bool, optional
83 if True, remove samples which have log_likelihood='nan'. Default True
85 Attributes
86 ----------
87 parameters: list
88 list of parameters stored in the result file
89 converted_parameters: list
90 list of parameters that have been derived from the sampled distributions
91 samples: 2d list
92 list of samples stored in the result file
93 samples_dict: dict
94 dictionary of samples stored in the result file keyed by parameters
95 input_version: str
96 version of the result file passed.
97 extra_kwargs: dict
98 dictionary of kwargs that were extracted from the result file
99 prior: dict
100 dictionary of prior samples extracted from the bilby result file. The
101 analytic priors are evaluated for 5000 samples
102 injection_parameters: dict
103 dictionary of injection parameters stored in the result file
104 converted_parameters: list
105 list of parameters that have been added
107 Methods
108 -------
109 to_dat:
110 save the posterior samples to a .dat file
111 to_latex_table:
112 convert the posterior samples to a latex table
113 generate_latex_macros:
114 generate a set of latex macros for the stored posterior samples
115 to_lalinference:
116 convert the posterior samples to a lalinference result file
117 generate_all_posterior_samples:
118 generate all posterior distributions that may be derived from
119 sampled distributions
120 """
121 def __init__(self, path_to_results_file, **kwargs):
122 super(Bilby, self).__init__(path_to_results_file, **kwargs)
123 self.load(self._grab_data_from_bilby_file, **kwargs)
125 @staticmethod
126 def grab_priors(bilby_object, nsamples=5000):
127 """Draw samples from the prior functions stored in the bilby file
128 """
129 from pesummary.utils.array import Array
131 f = bilby_object
132 try:
133 samples = f.priors.sample(size=nsamples)
134 priors = {key: Array(samples[key]) for key in samples}
135 except Exception as e:
136 logger.info("Failed to draw prior samples because {}".format(e))
137 priors = {}
138 return priors
140 @staticmethod
141 def grab_extra_kwargs(bilby_object):
142 """Grab any additional information stored in the bilby file
143 """
144 from pesummary.core.file.formats.bilby import config_from_object
145 import ast
147 f = bilby_object
148 kwargs = CoreBilby.grab_extra_kwargs(bilby_object)
149 try:
150 kwargs["meta_data"]["f_ref"] = \
151 f.meta_data["likelihood"]["waveform_arguments"]["reference_frequency"]
152 except Exception:
153 pass
154 for key, item in f.meta_data["likelihood"].items():
155 if not isinstance(item, dict):
156 try:
157 if isinstance(item, bool):
158 kwargs["meta_data"][key] = str(item)
159 else:
160 kwargs["meta_data"][key] = item
161 except Exception:
162 pass
163 try:
164 kwargs["meta_data"]["approximant"] = \
165 f.meta_data["likelihood"]["waveform_arguments"]["waveform_approximant"]
166 except Exception:
167 pass
168 try:
169 kwargs["meta_data"]["IFOs"] = \
170 " ".join(f.meta_data["likelihood"]["interferometers"].keys())
171 except Exception:
172 pass
173 _config = config_from_object(f)
174 if len(_config):
175 if "config" in _config.keys():
176 _config = _config["config"]
177 options = [
178 "minimum_frequency", "reference_frequency",
179 "waveform_approximant", "maximum_frequency"
180 ]
181 pesummary_names = ["f_low", "f_ref", "approximant", "f_final"]
182 for opt, name in zip(options, pesummary_names):
183 if opt in _config.keys():
184 try:
185 _option = ast.literal_eval(_config[opt])
186 except ValueError:
187 try:
188 import re
189 _config[opt] = re.sub(
190 r'([A-Za-z/\.0-9\-\+][^\[\],:"}]*)', r'"\g<1>"', _config[opt]
191 )
192 _option = ast.literal_eval(_config[opt])
193 except Exception:
194 _option = _config[opt]
195 if isinstance(_option, dict):
196 _value = np.min([
197 ast.literal_eval(value) for key, value in _option.items() if
198 key != "waveform"
199 ])
200 else:
201 _value = _option
202 kwargs["meta_data"][name] = _value
203 return kwargs
205 @property
206 def calibration_spline_posterior(self):
207 if not any("recalib_" in i for i in self.parameters):
208 return super(Bilby, self).calibration_spline_posterior
209 ifos = np.unique(
210 [
211 param.split('_')[1] for param in self.parameters if 'recalib_'
212 in param and "non_reweighted" not in param
213 ]
214 )
215 amp_params, phase_params, log_freqs = {}, {}, {}
216 for ifo in ifos:
217 amp_params[ifo], phase_params[ifo] = [], []
218 freq_params = np.sort(
219 [
220 param for param in self.parameters if
221 'recalib_%s_frequency_' % (ifo) in param
222 and "non_reweighted" not in param
223 ]
224 )
225 posterior = self.samples_dict
226 log_freqs[ifo] = np.log(
227 [posterior[param][0] for param in freq_params]
228 )
229 amp_parameters = np.sort(
230 [
231 param for param in self.parameters if
232 'recalib_%s_amplitude_' % (ifo) in param
233 and "non_reweighted" not in param
234 ]
235 )
236 amplitude = np.array([posterior[param] for param in amp_parameters])
237 phase_parameters = np.sort(
238 [
239 param for param in self.parameters if
240 'recalib_%s_phase_' % (ifo) in param
241 and "non_reweighted" not in param
242 ]
243 )
244 phase = np.array([posterior[param] for param in phase_parameters])
245 for num, i in enumerate(amplitude):
246 amp_params[ifo].append(i)
247 phase_params[ifo].append(phase[num])
248 return log_freqs, amp_params, phase_params
250 @staticmethod
251 def load_strain_data(path_to_strain_file):
252 """Load the strain data
254 Parameters
255 ----------
256 path_to_strain_file: str
257 path to the strain file that you wish to load
258 """
259 Bilby.load_from_function(
260 Bilby._timeseries_from_bilby_pickle, path_to_strain_file)
262 @staticmethod
263 def _timeseries_from_bilby_pickle(path_to_strain_file):
264 """Load a bilby pickle file containing the strain data
266 Parameters
267 ----------
268 path_to_strain_file: str
269 path to the strain file that you wish to load
270 """
271 import pickle
272 import gwpy
274 with open(path_to_strain_file, "rb") as f:
275 data = pickle.load(f)
277 strain_data = {}
278 for i in data.interferometers:
279 strain_data[i.name] = gwpy.timeseries.TimeSeries(
280 data=i.strain_data.time_domain_strain,
281 times=i.strain_data.time_array)
282 return strain_data
284 @staticmethod
285 def _grab_data_from_bilby_file(path, disable_prior=False, **kwargs):
286 """
287 Load the results file using the `bilby` library
289 Complex matched filter SNRs are stored in the result file.
290 The amplitude and angle are extracted here.
291 """
292 return read_bilby(path, disable_prior=disable_prior, **kwargs)
294 def add_marginalized_parameters_from_config_file(self, config_file):
295 """Search the configuration file and add the marginalized parameters
296 to the list of parameters and samples
298 Parameters
299 ----------
300 config_file: str
301 path to the configuration file
302 """
303 pass