# Copyright (C) 2016 Christopher M. Biwer, Alexander Harvey Nitz, Collin Capano
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
Module that contains functions for setting up the inference workflow.
"""
import logging
from pycbc.workflow.core import (Executable, makedir)
from pycbc.workflow.plotting import PlotExecutable
from pycbc.results import layout
logger = logging.getLogger('pycbc.workflow.inference_followups')
[docs]
def make_inference_plot(workflow, input_file, output_dir,
name, analysis_seg=None,
tags=None, input_file_opt='input-file',
output_file_extension='.png',
add_to_workflow=False):
"""Boiler-plate function for creating a standard plotting job.
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
input_file: (list of) pycbc.workflow.File
The file used for the input. May provide either a single file or a
list of files.
output_dir: str
The directory to store result plots.
name: str
The name in the [executables] section of the configuration file
to use.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
input_file_opt : str, optional
The name of the input-file option used by the executable. Default
is ``input-file``.
output_file_extension : str, optional
What file type to create. Default is ``.png``.
add_to_workflow : bool, optional
If True, the node will be added to the workflow before being returned.
**This means that no options may be added to the node afterward.**
Default is ``False``.
Returns
-------
pycbc.workflow.plotting.PlotExecutable
The job node for creating the plot.
"""
# default values
if tags is None:
tags = []
if analysis_seg is None:
analysis_seg = workflow.analysis_time
# make the directory that will contain the output files
makedir(output_dir)
# Catch if a parameters option was specified:
# we need to do this because PlotExecutable will automatically add any
# option in the section to the node. However, we need to add the
# appropriate escapes to the parameters option so pegasus will render it
# properly (see _params_for_pegasus for details).
parameters = None
if workflow.cp.has_option(name, 'parameters'):
parameters = workflow.cp.get(name, 'parameters')
workflow.cp.remove_option(name, 'parameters')
# make a node for plotting the posterior as a corner plot
node = PlotExecutable(workflow.cp, name, ifos=workflow.ifos,
out_dir=output_dir,
tags=tags).create_node()
# add back the parameters option if it was specified
if parameters is not None:
node.add_opt("--parameters", _params_for_pegasus(parameters))
# and put the opt back in the config file in memory
workflow.cp.set(name, 'parameters', parameters)
# add input and output options
if isinstance(input_file, list):
# list of input files are given, use input_list_opt
node.add_input_list_opt("--{}".format(input_file_opt), input_file)
else:
# assume just a single file
node.add_input_opt("--{}".format(input_file_opt), input_file)
node.new_output_file_opt(analysis_seg, output_file_extension,
"--output-file")
# add node to workflow
if add_to_workflow:
workflow += node
return node
[docs]
def make_inference_prior_plot(workflow, config_file, output_dir,
name="plot_prior",
analysis_seg=None, tags=None):
"""Sets up the corner plot of the priors in the workflow.
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
config_file: pycbc.workflow.File
The WorkflowConfigParser parasable inference configuration file..
output_dir: str
The directory to store result plots and files.
name: str
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_prior``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of the output files.
"""
node = make_inference_plot(workflow, config_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
input_file_opt='config-file',
add_to_workflow=True)
return node.output_files
[docs]
def create_posterior_files(workflow, samples_files, output_dir,
parameters=None, name="extract_posterior",
analysis_seg=None, tags=None):
"""Sets up job to create posterior files from some given samples files.
Parameters
----------
workflow: pycbc.workflow.Workflow
The workflow instance we are populating
samples_files : str or list of str
One or more files to extract the posterior samples from.
output_dir: str
The directory to store result plots and files.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``extract_posterior``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
if analysis_seg is None:
analysis_seg = workflow.analysis_time
if tags is None:
tags = []
# Catch if a parameters option was specified:
# we need to do this because Executable will automatically add any
# option in the section to the node. However, we need to add the
# appropriate escapes to the parameters option so pegasus will render it
# properly (see _params_for_pegasus for details).
parameters = None
if workflow.cp.has_option(name, 'parameters'):
parameters = workflow.cp.get(name, 'parameters')
workflow.cp.remove_option(name, 'parameters')
extract_posterior_exe = Executable(workflow.cp, name,
ifos=workflow.ifos,
out_dir=output_dir)
node = extract_posterior_exe.create_node()
# add back the parameters option if it was specified
if parameters is not None:
node.add_opt("--parameters", _params_for_pegasus(parameters))
# and put the opt back in the config file in memory
workflow.cp.set(name, 'parameters', parameters)
if not isinstance(samples_files, list):
samples_files = [samples_files]
node.add_input_list_opt("--input-file", samples_files)
node.new_output_file_opt(analysis_seg, ".hdf", "--output-file", tags=tags)
# add node to workflow
workflow += node
return node.output_files
[docs]
def create_fits_file(workflow, inference_file, output_dir,
name="create_fits_file",
analysis_seg=None, tags=None):
"""Sets up job to create fits files from some given samples files.
Parameters
----------
workflow: pycbc.workflow.Workflow
The workflow instance we are populating
inference_file: pycbc.workflow.File
The file with posterior samples.
output_dir: str
The directory to store result plots and files.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``create_fits_file``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
if analysis_seg is None:
analysis_seg = workflow.analysis_time
if tags is None:
tags = []
create_fits_exe = Executable(workflow.cp, name,
ifos=workflow.ifos,
out_dir=output_dir)
node = create_fits_exe.create_node()
node.add_input_opt("--input-file", inference_file)
node.new_output_file_opt(analysis_seg, ".fits", "--output-file", tags=tags)
# add node to workflow
workflow += node
return node.output_files
[docs]
def make_inference_skymap(workflow, fits_file, output_dir,
name="plot_skymap", analysis_seg=None,
tags=None):
"""Sets up the skymap plot.
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
fits_file: pycbc.workflow.File
The fits file with the sky location.
output_dir: str
The directory to store result plots and files.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_skymap``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of result and output files.
"""
node = make_inference_plot(workflow, fits_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
add_to_workflow=True)
return node.output_files
[docs]
def make_inference_summary_table(workflow, inference_file, output_dir,
parameters=None, print_metadata=None,
name="table_summary",
analysis_seg=None, tags=None):
"""Sets up the html table summarizing parameter estimates.
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
inference_file: pycbc.workflow.File
The file with posterior samples.
output_dir: str
The directory to store result plots and files.
parameters : list or str
A list or string of parameters to generate the table for. If a string
is provided, separate parameters should be space or new-line separated.
print_metadata : list or str
A list or string of metadata parameters to print. Syntax is the same
as for ``parameters``.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``table_summary``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
# we'll use make_inference_plot even though this isn't a plot; the
# setup is the same, we just change the file extension
node = make_inference_plot(workflow, inference_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
output_file_extension='.html',
add_to_workflow=False)
# now add the parameters and print metadata options; these are pulled
# from separate sections in the workflow config file, which is why we
# add them separately here
if parameters is not None:
node.add_opt("--parameters", _params_for_pegasus(parameters))
if print_metadata is not None:
node.add_opt("--print-metadata", _params_for_pegasus(print_metadata))
workflow += node
return node.output_files
[docs]
def make_inference_posterior_plot(workflow, inference_file, output_dir,
parameters=None, plot_prior_from_file=None,
name="plot_posterior",
analysis_seg=None, tags=None):
"""Sets up the corner plot of the posteriors in the workflow.
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
inference_file: pycbc.workflow.File
The file with posterior samples.
output_dir: str
The directory to store result plots and files.
parameters : list or str
The parameters to plot.
plot_prior_from_file : str, optional
Plot the prior from the given config file on the 1D marginal plots.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_posterior``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
# create the node, but delay adding it to the workflow so we can add
# the prior file if it is requested
node = make_inference_plot(workflow, inference_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
add_to_workflow=False)
if parameters is not None:
node.add_opt("--parameters", _params_for_pegasus(parameters))
if plot_prior_from_file is not None:
node.add_input_opt('--plot-prior', plot_prior_from_file)
# now add the node to workflow
workflow += node
return node.output_files
[docs]
def make_inference_samples_plot(workflow, inference_file, output_dir,
name="plot_samples",
analysis_seg=None, tags=None):
"""Sets up a plot of the samples versus iteration (for MCMC samplers).
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
inference_file: pycbc.workflow.File
The file with posterior samples.
output_dir: str
The directory to store result plots and files.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_samples``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
node = make_inference_plot(workflow, inference_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
add_to_workflow=True)
return node.output_files
[docs]
def make_inference_acceptance_rate_plot(workflow, inference_file, output_dir,
name="plot_acceptance_rate",
analysis_seg=None, tags=None):
"""Sets up a plot of the acceptance rate (for MCMC samplers).
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
inference_file: pycbc.workflow.File
The file with posterior samples.
output_dir: str
The directory to store result plots and files.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_acceptance_rate``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
node = make_inference_plot(workflow, inference_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
add_to_workflow=True)
return node.output_files
[docs]
def make_inference_plot_mcmc_history(workflow, inference_file, output_dir,
name="plot_mcmc_history",
analysis_seg=None, tags=None):
"""Sets up a plot showing the checkpoint history of an MCMC sampler.
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
inference_file: pycbc.workflow.File
The file with posterior samples.
output_dir: str
The directory to store result plots and files.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_mcmc_history``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
node = make_inference_plot(workflow, inference_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
add_to_workflow=True)
return node.output_files
[docs]
def make_inference_dynesty_run_plot(workflow, inference_file, output_dir,
name="plot_dynesty_run",
analysis_seg=None, tags=None):
"""Sets up a debugging plot for the dynesty run (for Dynesty sampler).
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
inference_file: pycbc.workflow.File
The file with posterior samples.
output_dir: str
The directory to store result plots and files.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_dynesty_run``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
node = make_inference_plot(workflow, inference_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
add_to_workflow=True)
return node.output_files
[docs]
def make_inference_dynesty_trace_plot(workflow, inference_file, output_dir,
name="plot_dynesty_traceplot",
analysis_seg=None, tags=None):
"""Sets up a trace plot for the dynesty run (for Dynesty sampler).
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
inference_file: pycbc.workflow.File
The file with posterior samples.
output_dir: str
The directory to store result plots and files.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_dynesty_traceplot``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
node = make_inference_plot(workflow, inference_file, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
add_to_workflow=True)
return node.output_files
[docs]
def make_inference_pp_table(workflow, posterior_files, output_dir,
parameters=None, injection_samples_map=None,
name="pp_table_summary",
analysis_seg=None, tags=None):
"""Performs a PP, writing results to an html table.
Parameters
----------
workflow : pycbc.workflow.Workflow
The core workflow instance we are populating
posterior_files : pycbc.workflow.core.FileList
List of files with posteriors of injections.
output_dir : str
The directory to store result plots and files.
parameters : list or str, optional
A list or string of parameters to generate the table for. If a string
is provided, separate parameters should be space or new-line separated.
injection_samples_map : (list of) str, optional
Map between injection parameters and parameters in the posterior file.
Format is ``INJECTION_PARAM:SAMPLES_PARAM``.
name : str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``table_summary``.
analysis_segs : igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags : list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
# we'll use make_inference_plot even though this isn't a plot; the
# setup is the same, we just change the file extension
node = make_inference_plot(workflow, posterior_files, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
output_file_extension='.html',
add_to_workflow=False)
# add the parameters and inj/samples map
if parameters is not None:
node.add_opt("--parameters", _params_for_pegasus(parameters))
if injection_samples_map is not None:
node.add_opt("--injection-samples-map",
_params_for_pegasus(injection_samples_map))
workflow += node
return node.output_files
[docs]
def make_inference_pp_plot(workflow, posterior_files, output_dir,
parameters=None, injection_samples_map=None,
name="plot_pp",
analysis_seg=None, tags=None):
"""Sets up a pp plot in the workflow.
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
posterior_files: pycbc.workflow.core.FileList
List of files with posteriors of injections.
output_dir: str
The directory to store result plots and files.
parameters : list or str, optional
The parameters to plot.
injection_samples_map : (list of) str, optional
Map between injection parameters and parameters in the posterior file.
Format is ``INJECTION_PARAM:SAMPLES_PARAM``.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``plot_pp``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
node = make_inference_plot(workflow, posterior_files, output_dir,
name, analysis_seg=analysis_seg, tags=tags,
add_to_workflow=False)
# add the parameters and inj/samples map
if parameters is not None:
node.add_opt("--parameters", _params_for_pegasus(parameters))
if injection_samples_map is not None:
node.add_opt("--injection-samples-map",
_params_for_pegasus(injection_samples_map))
# now add the node to workflow
workflow += node
return node.output_files
[docs]
def make_inference_inj_recovery_plot(workflow, posterior_files, output_dir,
parameter, injection_samples_map=None,
name="inj_recovery",
analysis_seg=None, tags=None):
"""Sets up the recovered versus injected parameter plot in the workflow.
Parameters
----------
workflow: pycbc.workflow.Workflow
The core workflow instance we are populating
inference_files: pycbc.workflow.core.FileList
List of files with posteriors of injections.
output_dir: str
The directory to store result plots and files.
parameter : str
The parameter to plot.
injection_samples_map : (list of) str, optional
Map between injection parameters and parameters in the posterior file.
Format is ``INJECTION_PARAM:SAMPLES_PARAM``.
name: str, optional
The name in the [executables] section of the configuration file
to use, and the section to read for additional arguments to pass to
the executable. Default is ``inj_recovery``.
analysis_segs: igwn_segments.segment, optional
The segment this job encompasses. If None then use the total analysis
time from the workflow.
tags: list, optional
Tags to add to the inference executables.
Returns
-------
pycbc.workflow.FileList
A list of output files.
"""
# arguments are the same as plot_pp, so just call that with the
# different executable name
return make_inference_pp_plot(
workflow, posterior_files, output_dir, parameters=parameter,
injection_samples_map=injection_samples_map,
name=name, analysis_seg=analysis_seg, tags=tags)
[docs]
def get_plot_group(cp, section_tag):
"""Gets plotting groups from ``[workflow-section_tag]``."""
group_prefix = "plot-group-"
# parameters for the summary plots
plot_groups = {}
opts = [opt for opt in cp.options("workflow-{}".format(section_tag))
if opt.startswith(group_prefix)]
for opt in opts:
group = opt.replace(group_prefix, "").replace("-", "_")
plot_groups[group] = cp.get_opt_tag("workflow", opt, section_tag)
return plot_groups
[docs]
def get_diagnostic_plots(workflow):
"""Determines what diagnostic plots to create based on workflow.
The plots to create are based on what executable's are specified in the
workflow's config file. A list of strings is returned giving the diagnostic
plots to create. This list may contain:
* ``samples``: For MCMC samplers, a plot of the sample chains as a function
of iteration. This will be created if ``plot_samples`` is in the
executables section.
* ``acceptance_rate``: For MCMC samplers, a plot of the acceptance rate.
This will be created if ``plot_acceptance_rate`` is in the executables
section.
Returns
-------
list :
List of names of diagnostic plots.
"""
diagnostics = []
if "plot_samples" in workflow.cp.options("executables"):
diagnostics.append('samples')
if "plot_acceptance_rate" in workflow.cp.options("executables"):
diagnostics.append('acceptance_rate')
if "plot_mcmc_history" in workflow.cp.options("executables"):
diagnostics.append('mcmc_history')
if "plot_dynesty_run" in workflow.cp.options("executables"):
diagnostics.append('dynesty_run')
if "plot_dynesty_traceplot" in workflow.cp.options("executables"):
diagnostics.append('dynesty_traceplot')
return diagnostics
[docs]
def make_diagnostic_plots(workflow, diagnostics, samples_file, label, rdir,
tags=None):
"""Makes diagnostic plots.
Diagnostic plots are sampler-specific plots the provide information on
how the sampler performed. All diagnostic plots use the output file
produced by ``pycbc_inference`` as their input. Diagnostic plots are added
to the results directory ``rdir/NAME`` where ``NAME`` is the name of the
diagnostic given in ``diagnostics``.
Parameters
----------
workflow : pycbc.workflow.core.Workflow
The workflow to add the plotting jobs to.
diagnostics : list of str
The names of the diagnostic plots to create. See
:py:func:`get_diagnostic_plots` for recognized names.
samples_file : (list of) pycbc.workflow.File
One or more samples files with which to create the diagnostic plots.
If a list of files is provided, a diagnostic plot for each file will
be created.
label : str
Event label for the diagnostic plots.
rdir : pycbc.results.layout.SectionNumber
Results directory layout.
tags : list of str, optional
Additional tags to add to the file names.
Returns
-------
dict :
Dictionary of diagnostic name -> list of files giving the plots that
will be created.
"""
if tags is None:
tags = []
out = {}
if not isinstance(samples_file, list):
samples_file = [samples_file]
if 'samples' in diagnostics:
# files for samples summary subsection
base = "samples/{}".format(label)
samples_plots = []
for kk, sf in enumerate(samples_file):
samples_plots += make_inference_samples_plot(
workflow, sf, rdir[base],
analysis_seg=workflow.analysis_time,
tags=tags+[label, str(kk)])
out['samples'] = samples_plots
layout.group_layout(rdir[base], samples_plots)
if 'acceptance_rate' in diagnostics:
# files for samples acceptance_rate subsection
base = "acceptance_rate/{}".format(label)
acceptance_plots = []
for kk, sf in enumerate(samples_file):
acceptance_plots += make_inference_acceptance_rate_plot(
workflow, sf, rdir[base],
analysis_seg=workflow.analysis_time,
tags=tags+[label, str(kk)])
out['acceptance_rate'] = acceptance_plots
layout.single_layout(rdir[base], acceptance_plots)
if 'mcmc_history' in diagnostics:
# files for samples mcmc history subsection
base = "mcmc_history/{}".format(label)
history_plots = []
for kk, sf in enumerate(samples_file):
history_plots += make_inference_plot_mcmc_history(
workflow, sf, rdir[base],
analysis_seg=workflow.analysis_time,
tags=tags+[label, str(kk)])
out['mcmc_history'] = history_plots
layout.single_layout(rdir[base], history_plots)
if 'dynesty_run' in diagnostics:
# files for dynesty run subsection
base = "dynesty_run/{}".format(label)
dynesty_run_plots = []
for kk, sf in enumerate(samples_file):
dynesty_run_plots += make_inference_dynesty_run_plot(
workflow, sf, rdir[base],
analysis_seg=workflow.analysis_time,
tags=tags+[label, str(kk)])
out['dynesty_run'] = dynesty_run_plots
layout.single_layout(rdir[base], dynesty_run_plots)
if 'dynesty_traceplot' in diagnostics:
# files for samples dynesty tyrace plots subsection
base = "dynesty_traceplot/{}".format(label)
dynesty_trace_plots = []
for kk, sf in enumerate(samples_file):
dynesty_trace_plots += make_inference_dynesty_trace_plot(
workflow, sf, rdir[base],
analysis_seg=workflow.analysis_time,
tags=tags+[label, str(kk)])
out['dynesty_traceplot'] = dynesty_trace_plots
layout.single_layout(rdir[base], dynesty_trace_plots)
return out
[docs]
def make_posterior_workflow(workflow, samples_files, config_file, label,
rdir, posterior_file_dir='posterior_files',
tags=None):
"""Adds jobs to a workflow that make a posterior file and subsequent plots.
A posterior file is first created from the given samples file(s). The
settings for extracting the posterior are set by the
``[extract_posterior]`` section. If that section has a ``parameters``
argument, then the parameters in the posterior file (and for use in all
subsequent plotting) will be whatever that option is set to. Otherwise,
the parameters in the posterior file will be whatever is common to
all of the given samples file(s).
Except for prior plots (which use the given inference config file), all
subsequent jobs use the posterior file. The following are created:
* **Summary table**: an html table created using the ``table_summary``
executable. The parameters to print in the table are retrieved from the
``table-params`` option in the ``[workflow-summary_table]`` section.
Metadata may also be printed by adding a ``print-metadata`` option to
that section.
* **Summary posterior plots**: a collection of posterior plots to include
in the summary page, after the summary table. The parameters to plot
are read from ``[workflow-summary_plots]``. Parameters should be grouped
together by providing
``plot-group-NAME = PARAM1[:LABEL1] PARAM2[:LABEL2]`` in that section,
where ``NAME`` is a unique name for each group. One posterior plot will
be created for each plot group. For clarity, only one or two parameters
should be plotted in each summary group, but this is not enforced.
Settings for the plotting executable are read from the
``plot_posterior_summary`` section; likewise, the executable used
is read from ``plot_posterior_summary`` in the
``[executables]`` section.
* **Sky maps**: if *both* ``create_fits_file`` and ``plot_skymap``
are listed in the ``[executables]`` section, then a ``.fits`` file and
sky map plot will be produced. The sky map plot will be included in
the summary plots. You must be running in a python 3 environment to
create these.
* **Prior plots**: plots of the prior will be created using the
``plot_prior`` executable. By default, all of the variable
parameters will be plotted. The prior plots are added to
``priors/LALBEL/`` in the results directory, where ``LABEL`` is the
given ``label``.
* **Posterior plots**: additional posterior plots are created using the
``plot_posterior`` executable. The parameters to plot are
read from ``[workflow-plot_params]`` section. As with the summary
posterior plots, parameters are grouped together by providing
``plot-group-NAME`` options in that section. A posterior plot will be
created for each group, and added to the ``posteriors/LABEL/`` directory.
Plot settings are read from the ``[plot_posterior]`` section; this
is kept separate from the posterior summary so that different settings
can be used. For example, you may want to make a density plot for the
summary plots, but a scatter plot colored by SNR for the posterior plots.
Parameters
----------
samples_file : pycbc.workflow.core.FileList
List of samples files to combine into a single posterior file.
config_file : pycbc.worfkow.File
The inference configuration file used to generate the samples file(s).
This is needed to make plots of the prior.
label : str
Unique label for the plots. Used in file names.
rdir : pycbc.results.layout.SectionNumber
The results directory to save the plots to.
posterior_file_dir : str, optional
The name of the directory to save the posterior file to. Default is
``posterior_files``.
tags : list of str, optional
Additional tags to add to the file names.
Returns
-------
posterior_file : pycbc.workflow.File
The posterior file that was created.
summary_files : list
List of files to go on the summary results page.
prior_plots : list
List of prior plots that will be created. These will be saved to
``priors/LABEL/`` in the resuls directory, where ``LABEL`` is the
provided label.
posterior_plots : list
List of posterior plots that will be created. These will be saved to
``posteriors/LABEL/`` in the results directory.
"""
# the list of plots to go in the summary
summary_files = []
if tags is None:
tags = []
analysis_seg = workflow.analysis_time
# figure out what parameters user wants to plot from workflow configuration
# parameters for the summary plots
summary_plot_params = get_plot_group(workflow.cp, 'summary_plots')
# parameters to plot in large corner plots
plot_params = get_plot_group(workflow.cp, 'plot_params')
# get parameters for the summary tables
table_params = workflow.cp.get_opt_tag('workflow', 'table-params',
'summary_table')
# get any metadata that should be printed
if workflow.cp.has_option('workflow-summary_table', 'print-metadata'):
table_metadata = workflow.cp.get_opt_tag('workflow', 'print-metadata',
'summary_table')
else:
table_metadata = None
# figure out if we are making a skymap
make_skymap = ("create_fits_file" in workflow.cp.options("executables") and
"plot_skymap" in workflow.cp.options("executables"))
make_prior = ("plot_prior" in workflow.cp.options("executables"))
_config = None
if make_prior:
_config = config_file
# make node for running extract samples
posterior_file = create_posterior_files(
workflow, samples_files, posterior_file_dir,
analysis_seg=analysis_seg, tags=tags+[label])[0]
# summary table
summary_files += (make_inference_summary_table(
workflow, posterior_file, rdir.base,
parameters=table_params, print_metadata=table_metadata,
analysis_seg=analysis_seg,
tags=tags+[label]),)
# summary posteriors
summary_plots = []
for group, params in summary_plot_params.items():
summary_plots += make_inference_posterior_plot(
workflow, posterior_file, rdir.base,
name='plot_posterior_summary',
parameters=params, plot_prior_from_file=_config,
analysis_seg=analysis_seg,
tags=tags+[label, group])
# sky map
if make_skymap:
# create the fits file
fits_file = create_fits_file(
workflow, posterior_file, rdir.base, analysis_seg=analysis_seg,
tags=tags+[label])[0]
# now plot the skymap
skymap_plot = make_inference_skymap(
workflow, fits_file, rdir.base, analysis_seg=analysis_seg,
tags=tags+[label])
summary_plots += skymap_plot
summary_files += list(layout.grouper(summary_plots, 2))
# files for posteriors summary subsection
base = "posteriors/{}".format(label)
posterior_plots = []
for group, params in plot_params.items():
posterior_plots += make_inference_posterior_plot(
workflow, posterior_file, rdir[base],
parameters=params, plot_prior_from_file=_config,
analysis_seg=analysis_seg,
tags=tags+[label, group])
layout.single_layout(rdir[base], posterior_plots)
prior_plots = []
# files for priors summary section
if make_prior:
base = "priors/{}".format(label)
prior_plots += make_inference_prior_plot(
workflow, config_file, rdir[base],
analysis_seg=workflow.analysis_time, tags=tags+[label])
layout.single_layout(rdir[base], prior_plots)
return posterior_file, summary_files, prior_plots, posterior_plots
def _params_for_pegasus(parameters):
"""Escapes $ and escapes in parameters string for pegasus.
Pegaus kickstart tries to do variable substitution if it sees a ``$``, and
it will strip away back slashes. This can be problematic when trying to use
LaTeX in parameter labels. This function adds escapes to all ``$`` and
backslashes in a parameters argument, so the argument can be safely passed
through pegasus-kickstart.
Parameters
----------
parameters : list or str
The parameters argument to modify. If a list, the output will be
converted to a space-separated string.
"""
if isinstance(parameters, list):
parameters = " ".join(parameters)
return parameters.replace('\\', '\\\\').replace('$', '\$')