raven_analyze_runΒΆ

#!/usr/bin/python

#
# Project Librarian: Brandon Piotrzkowski
#              Staff Scientist
#              UW-Milwaukee Department of Physics
#              Center for Gravitation & Cosmology
#              <brandon.piotrzkowski@ligo.org>
#
# 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, see <http://www.gnu.org/licenses/>.
#

"""
Script to perform offline RAVEN search, where the inputs can be any combination
of two online GraceDB instances or local files.
"""
__author__ = "Brandon Piotrzkowski <brandon.piotrzkowski@ligo.org>"


# Global imports
from ligo.raven.offline_search import offline_search
from ligo.raven.mock_gracedb import choose_gracedb

import argparse
from astropy.table import vstack


# Command line options.
parser = argparse.ArgumentParser(description='Perform query of GraceDB')
parser.add_argument("-i", "--inputs", nargs=2, metavar="input.csv https://gracedb.ligo.org/api/",
                    action="append", default=None,
                    help="Filepath of input file(s) or URL of GraceDB API(s) (any combination of the two)"),
parser.add_argument("-o", "--output_path", metavar="results", default="results",
                    help="Filepath of output directory"),
parser.add_argument("-s", "--ext_searches", metavar="GRB SubGRB SubGRBTargeted", nargs='+', default=None,
                    help="Run ID supported by GraceDB (e.g. O4a)"), 
parser.add_argument("-R", "--runid", metavar="O4a", default=None,
                    help="Run ID supported by GraceDB (e.g. O4a)"),       
parser.add_argument("-P", "--omit_plots", dest="omit_plots", action="store_true",
                    help="Choose to not generate plots of results."),
parser.add_argument("-G", "--load_gw_fars", dest="load_gw_fars", action="store_true",
                    help="Load and include GW FARs for comparison."),
args = parser.parse_args()
print(args)

# Check required options are there
if not args.inputs:
    raise AssertionError('Inputs (GraceDB API URL(s) and/or or file path(s)) not given')
else:
    input1, input2 = str(args.inputs[0][0]), str(args.inputs[0][1])

secs_per_year = 365. * 24. * 60. * 60.
runid = str(args.runid)

# Apply historical rates based on RunID
# Only Fermi+Swift during this time, in O3+ including INTEGRAL. However
# INTEGRAL is only ~5/year so including/discluding this doesn't matter much.
if runid in {'O2', 'O3', 'O4a', 'O4b'}:
    grb_rate = 305 / secs_per_year
# Rate in O4c and going forward for now after including SVOM
else:
    grb_rate = 325 / secs_per_year

# SubGRB rate adds an additional 65 candidates to whatever the GRB rate is
subgrb_rate = grb_rate + 65 / secs_per_year

# FIXME: Add new searches here once they are online. This will include CHIME
# FRBs, Einstein Probe Xrays, IceCube HENs, and potentially Rubin Optical
# vents
settings = \
[
    {
        'ext_search': 'GRB',
        'group': 'CBC',
        'pipeline': None,
        'se_search': None,
        'tl': -1,
        'th': 5,
        'ext_rate': grb_rate,
        'gw_far_thresh': None,
        'ext_far_thresh': None,
        'joint_far_method': 'untargeted',
        'trials_factor': (7 - 1),
        'alert_far_thresh': 12 / secs_per_year
    },
    {
        'ext_search': 'GRB',
        'group': 'Burst',
        'pipeline': None,
        'se_search': 'BBH',
        'tl': -1,
        'th': 5,
        'ext_rate': grb_rate,
        'gw_far_thresh': None,
        'ext_far_thresh': None,
        'joint_far_method': 'untargeted',
        'trials_factor': (7 - 1),
        'alert_far_thresh': 12 / secs_per_year
    },
    {
        'ext_search': 'GRB',
        'group': 'Burst',
        'pipeline': None,
        'se_search': 'AllSky',
        'tl': -60,
        'th': 600,
        'ext_rate': grb_rate,
        'gw_far_thresh': None,
        'ext_far_thresh': None,
        'joint_far_method': 'untargeted',
        'trials_factor': (3 - 1),
        'alert_far_thresh': 1 / secs_per_year
    },
    {
        'ext_search': 'SubGRB',
        'group': 'CBC',
        'pipeline': None,
        'se_search': None,
        'tl': -1,
        'th': 11,
        'ext_rate': subgrb_rate,
        'gw_far_thresh': None,
        'ext_far_thresh': None,
        'joint_far_method': 'untargeted',
        'trials_factor': (7 - 1),
        'alert_far_thresh': 12 / secs_per_year
    },
    {
        'ext_search': 'SubGRB',
        'group': 'Burst',
        'pipeline': None,
        'se_search': 'BBH',
        'tl': -1,
        'th': 11,
        'ext_rate': subgrb_rate,
        'gw_far_thresh': None,
        'ext_far_thresh': None,
        'joint_far_method': 'untargeted',
        'trials_factor': (7 - 1),
        'alert_far_thresh': 12 / secs_per_year
    },
    {
        'ext_search': 'SubGRBTargeted',
        'group': 'CBC',
        'pipeline': 'Fermi',
        'se_search': 'AllSky',
        'tl': -1,
        'th': 11,
        'ext_rate': None,
        'gw_far_thresh': 2 / (1 * 86400) * 8,
        'ext_far_thresh': 1e-4,
        'joint_far_method': 'targeted',
        'trials_factor': (7 - 1),
        'alert_far_thresh': 12 / secs_per_year
    },
    {
        'ext_search': 'SubGRBTargeted',
        'group': 'Burst',
        'pipeline': 'Fermi',
        'se_search': 'BBH',
        'tl': -1,
        'th': 11,
        'ext_rate': None,
        'gw_far_thresh': 2 / (1 * 86400) * 8,
        'ext_far_thresh': 1e-4,
        'joint_far_method': 'targeted',
        'trials_factor': (7 - 1),
        'alert_far_thresh': 12 / secs_per_year
    },
    {
        'ext_search': 'SubGRBTargeted',
        'group': 'Burst',
        'pipeline': 'Fermi',
        'se_search': 'AllSky',
        'tl': -1,
        'th': 11,
        'ext_rate': None,
        'gw_far_thresh': 2 / (1 * 86400) * 8,
        'ext_far_thresh': 1e-4,
        'joint_far_method': 'targeted',
        'trials_factor': (3 - 1),
        'alert_far_thresh': 1 / secs_per_year
    },
    {
        'ext_search': 'SubGRBTargeted',
        'group': 'CBC',
        'pipeline': 'Swift',
        'se_search': 'AllSky',
        'tl': -10,
        'th': 20,
        'ext_rate': None,
        'gw_far_thresh': 2 / (1 * 86400) * 8,
        'ext_far_thresh': 1e-3,
        'joint_far_method': 'targeted',
        'trials_factor': (7 - 1),
        'alert_far_thresh': 12 / secs_per_year
    },
    {
        'ext_search': 'SubGRBTargeted',
        'group': 'Burst',
        'pipeline': 'Swift',
        'se_search': 'BBH',
        'tl': -10,
        'th': 20,
        'ext_rate': None,
        'gw_far_thresh': 2 / (1 * 86400) * 8,
        'ext_far_thresh': 1e-3,
        'joint_far_method': 'targeted',
        'trials_factor': (7 - 1),
        'alert_far_thresh': 12 / secs_per_year
    },
    {
        'ext_search': 'SubGRBTargeted',
        'group': 'Burst',
        'pipeline': 'Swift',
        'se_search': 'AllSky',
        'tl': -10,
        'th': 20,
        'ext_rate': None,
        'gw_far_thresh': 2 / (1 * 86400) * 8,
        'ext_far_thresh': 1e-3,
        'joint_far_method': 'targeted',
        'trials_factor': (3 - 1),
        'alert_far_thresh': 1 / secs_per_year
    }
]

# Filter out searches not given
settings = [s for s in settings if s['ext_search'] in args.ext_searches]

print(f"Settings used: {settings}")
outputs = []

# Perform search
for s in settings:
    path = args.output_path + f"/{runid}_{s['group']}_{s['ext_search']}"
    if s.get('se_search'):
        path += f"_{s['se_search']}"
    if s.get('pipeline'):
        path += f"_{s['pipeline']}"
    output = offline_search(
        input1, input2, runid=runid,
        tl=s['tl'], th=s['th'],
        ext_rate=s['ext_rate'],
        gw_far_thresh=s['gw_far_thresh'],
        ext_far_thresh=s['ext_far_thresh'],
        alert_far_thresh=s['alert_far_thresh'],
        trials_factor=s['trials_factor'],
        output_path=path,
        create_plots=not args.omit_plots,
        load_gw_fars=args.load_gw_fars,
        joint_far_method=s['joint_far_method'],
        group=s['group'], pipeline=s['pipeline'],
        ext_search=s['ext_search'], se_search=s['se_search'])
    if output is not None:
        outputs.append(output)

if outputs:
    final_table = vstack(outputs)
    final_table.write(args.output_path + "/total_results.csv", overwrite=True)