ligolw.py 8.28 KB
Newer Older
1
#
2
# Copyright (C) 2013-2016  Leo Singer
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#
# 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 2 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.
#
"""
LIGO-LW convenience functions.
"""
__author__ = "Leo Singer <leo.singer@ligo.org>"


# Python standard library imports.
import itertools
import operator

# LIGO-LW XML imports.
from glue.ligolw.utils import process as ligolw_process
30
from glue.ligolw import ligolw
31 32
from glue.ligolw import array as ligolw_array
from glue.ligolw import param as ligolw_param
33 34
from glue.ligolw import table as ligolw_table
from glue.ligolw import lsctables
35
import lal.series
36 37


38 39 40 41 42 43 44 45 46 47
# FIXME: Copied from pylal.ligolw_thinca to avoid dependency.
# Should be moved to lalinspiral.
InspiralCoincDef = lsctables.CoincDef(search = u"inspiral", search_coinc_type = 0, description = u"sngl_inspiral<-->sngl_inspiral coincidences")


# FIXME: Copied from pylal.ligolw_inspinjfind to avoid dependency.
# Should be moved to lalinspiral.
InspiralSCExactCoincDef = lsctables.CoincDef(search = u"inspiral", search_coinc_type = 3, description = u"sim_inspiral<-->coinc_event coincidences (exact)")


48 49 50 51 52
# FIXME: This should be imported from pycbc, or even better, embedded in the
# pycbc PSD files.
PYCBC_DYN_RANGE_FAC =  5.9029581035870565e+20


Leo Pound Singer's avatar
Leo Pound Singer committed
53
def get_template_bank_f_low(xmldoc):
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
    """Determine the low frequency cutoff from a template bank file,
    whether the template bank was produced by lalapps_tmpltbank or
    lalapps_cbc_sbank. bayestar_sim_to_tmpltbank does not have a command
    line for the low-frequency cutoff; instead, it is recorded in a row
    of the search_summvars table."""
    try:
        template_bank_f_low, = ligolw_process.get_process_params(xmldoc,
            'tmpltbank', '--low-frequency-cutoff')
    except ValueError:
        try:
            template_bank_f_low, = ligolw_process.get_process_params(xmldoc,
                'lalapps_cbc_sbank', '--flow')
        except ValueError:
            try:
                search_summvars_table = ligolw_table.get_table(xmldoc,
                    lsctables.SearchSummVarsTable.tableName)
                template_bank_f_low, = (search_summvars.value
                    for search_summvars in search_summvars_table
                    if search_summvars.name == 'low-frequency cutoff')
            except ValueError:
                raise ValueError("Could not determine low-frequency cutoff")
    return template_bank_f_low


Leo Singer's avatar
Leo Singer committed
78
def sim_coinc_and_sngl_inspirals_for_xmldoc(xmldoc):
79
    """Retrieve (as a generator) all of the
Leo Singer's avatar
Leo Singer committed
80 81
    (sim_inspiral, coinc_event, (sngl_inspiral, sngl_inspiral, ... sngl_inspiral)
    tuples from found coincidences in a LIGO-LW XML document."""
82 83 84 85 86 87 88 89

    # Look up necessary tables.
    coinc_table = ligolw_table.get_table(xmldoc, lsctables.CoincTable.tableName)
    coinc_def_table = ligolw_table.get_table(xmldoc, lsctables.CoincDefTable.tableName)
    coinc_map_table = ligolw_table.get_table(xmldoc, lsctables.CoincMapTable.tableName)

    # Look up coinc_def ids.
    sim_coinc_def_id = coinc_def_table.get_coinc_def_id(
90 91
        InspiralSCExactCoincDef.search,
        InspiralSCExactCoincDef.search_coinc_type,
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
        create_new=False)

    def events_for_coinc_event_id(coinc_event_id):
        for coinc_map in coinc_map_table:
            if coinc_map.coinc_event_id == coinc_event_id:
                for row in ligolw_table.get_table(xmldoc, coinc_map.table_name):
                    column_name = coinc_map.event_id.column_name
                    if getattr(row, column_name) == coinc_map.event_id:
                        yield coinc_map.event_id, row

    # Loop over all coinc_event <-> sim_inspiral coincs.
    for sim_coinc in coinc_table:

        # If this is not a coinc_event <-> sim_inspiral coinc, skip it.
        if sim_coinc.coinc_def_id != sim_coinc_def_id:
            continue

        # Locate the sim_inspiral and coinc events.
        sim_inspiral = None
        coinc = None
        for event_id, event in events_for_coinc_event_id(sim_coinc.coinc_event_id):
113
            if event_id.table_name == ligolw_table.Table.TableName(lsctables.SimInspiralTable.tableName):
114 115 116
                if sim_inspiral is not None:
                    raise RuntimeError("Found more than one matching sim_inspiral entry")
                sim_inspiral = event
117
            elif event_id.table_name == ligolw_table.Table.TableName(lsctables.CoincTable.tableName):
118 119 120 121 122 123 124 125 126
                if coinc is not None:
                    raise RuntimeError("Found more than one matching coinc entry")
                coinc = event
            else:
                raise RuntimeError("Did not expect coincidence to contain an event of type '%s'" % event_id.table_name)

        sngl_inspirals = tuple(event
            for event_id, event in events_for_coinc_event_id(coinc.coinc_event_id))

Leo Singer's avatar
Leo Singer committed
127
        yield sim_inspiral, coinc, sngl_inspirals
128 129 130 131 132 133 134 135 136 137 138 139 140 141


def coinc_and_sngl_inspirals_for_xmldoc(xmldoc):
    """Retrieve (as a generator) all of the
    (sngl_inspiral, sngl_inspiral, ... sngl_inspiral) tuples from coincidences
    in a LIGO-LW XML document."""

    # Look up necessary tables.
    coinc_table = ligolw_table.get_table(xmldoc, lsctables.CoincTable.tableName)
    coinc_def_table = ligolw_table.get_table(xmldoc, lsctables.CoincDefTable.tableName)
    coinc_map_table = ligolw_table.get_table(xmldoc, lsctables.CoincMapTable.tableName)
    sngl_inspiral_table = ligolw_table.get_table(xmldoc, lsctables.SnglInspiralTable.tableName)

    # Look up coinc_def id.
Leo Pound Singer's avatar
Leo Pound Singer committed
142
    sngl_sngl_coinc_def_ids = {row.coinc_def_id for row in coinc_def_table
143
        if (row.search, row.search_coinc_type) ==
Leo Pound Singer's avatar
Leo Pound Singer committed
144
        (InspiralCoincDef.search, InspiralCoincDef.search_coinc_type)}
145 146 147

    # Indices to speed up lookups by ID.
    key = operator.attrgetter('coinc_event_id')
Leo Pound Singer's avatar
Leo Pound Singer committed
148
    coinc_maps_by_coinc_event_id = {coinc_event_id: tuple(coinc_maps)
149
        for coinc_event_id, coinc_maps
Leo Pound Singer's avatar
Leo Pound Singer committed
150 151 152
        in itertools.groupby(sorted(coinc_map_table, key=key), key=key)}
    sngl_inspirals_by_event_id = {sngl_inspiral.event_id: sngl_inspiral
        for sngl_inspiral in sngl_inspiral_table}
153 154 155

    # Loop over all sngl_inspiral <-> sngl_inspiral coincs.
    for coinc in coinc_table:
156
        if coinc.coinc_def_id in sngl_sngl_coinc_def_ids:
157 158 159 160 161 162 163
            coinc_maps = coinc_maps_by_coinc_event_id[coinc.coinc_event_id]
            yield coinc, tuple(sngl_inspirals_by_event_id[coinc_map.event_id]
                for coinc_map in coinc_maps)


def psd_filenames_by_process_id_for_xmldoc(xmldoc):
    """Retrieve a dictionary mapping process_ids to reference PSD filenames."""
Leo Pound Singer's avatar
Leo Pound Singer committed
164
    return {process_param.process_id: process_param.value
165 166
        for process_param
        in ligolw_table.get_table(xmldoc, lsctables.ProcessParamsTable.tableName)
Leo Pound Singer's avatar
Leo Pound Singer committed
167
        if process_param.param == '--reference-psd'}
168 169


170 171 172
def _snr_series_by_sngl_inspiral_id_for_xmldoc(xmldoc):
    for elem in xmldoc.getElementsByTagName(ligolw.LIGO_LW.tagName):
        try:
173
            if elem.Name != lal.COMPLEX8TimeSeries.__name__:
174 175 176 177 178 179 180 181
                continue
            array_elem = ligolw_array.get_array(elem, 'snr')
            event_id = ligolw_param.get_pyvalue(elem, 'event_id')
            if not isinstance(event_id, lsctables.SnglInspiralID):
                continue
        except (AttributeError, ValueError):
            continue
        else:
182
            yield event_id, lal.series.parse_COMPLEX8TimeSeries(elem)
183 184 185 186 187 188


def snr_series_by_sngl_inspiral_id_for_xmldoc(xmldoc):
    return dict(_snr_series_by_sngl_inspiral_id_for_xmldoc(xmldoc))


189 190 191
@lsctables.use_in
class LSCTablesContentHandler(ligolw.LIGOLWContentHandler):
	"""Content handler for reading LIGO-LW XML files with LSC table schema."""
192 193 194 195 196 197 198 199


@ligolw_array.use_in
@ligolw_param.use_in
@lsctables.use_in
class LSCTablesAndSeriesContentHandler(ligolw.LIGOLWContentHandler):
    """Content handler for reading LIGO-LW XML files with LSC table schema and
    gridded arrays."""