Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALInspiral 5.0.3.1-ea7c608
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
lalinspiral_thinca.py
Go to the documentation of this file.
1##python
2#
3# Copyright (C) 2008--2017 Kipp Cannon
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms of the GNU General Public License as published by the
7# Free Software Foundation; either version 2 of the License, or (at your
8# option) any later version.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13# Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19
20#
21# =============================================================================
22#
23# Preamble
24#
25# =============================================================================
26#
27
28
29from optparse import OptionParser
30import sys
31
32
33from igwn_ligolw import lsctables
34from igwn_ligolw import utils as ligolw_utils
35from igwn_ligolw.utils import process as ligolw_process
36from igwn_ligolw.utils import segments as ligolw_segments
37import lal
38from lalinspiral import thinca
39from igwn_segments import utils as segmentsUtils
40
41
42__author__ = "Kipp Cannon <kipp.cannon@ligo.org>"
43from lalinspiral.git_version import date as __date__
44from lalinspiral.git_version import version as __version__
45
46
47#
48# =============================================================================
49#
50# Command Line
51#
52# =============================================================================
53#
54
55
57 parser = OptionParser(
58 version = "Name: %%prog\n%s" % __version__,
59 usage = "%prog [options] [file ...]",
60 description = "%prog implements the inspiral coincidence algorithm for use in performing trigger-based multi-instrument searches for gravitational wave events. The LIGO Light Weight XML files listed on the command line are processed one by one in order, and over-written with the results. If no files are named, then input is read from stdin and output written to stdout. Gzipped files will be autodetected on input, if a file's name ends in \".gz\" it will be gzip-compressed on output."
61 )
62 parser.add_option("-c", "--comment", metavar = "text", help = "Set comment string in process table (default = None).")
63 parser.add_option("-f", "--force", action = "store_true", help = "Process document even if it has already been processed.")
64 parser.add_option("-t", "--threshold", metavar = "float", type = "float", help = "Set the coincidence window in seconds, not including light travel time (required). The value entered here will be dilated by the light travel time between detectors to define the coincidence window for each detector pair.")
65 parser.add_option("--min-instruments", metavar = "number", default = "2", type = "int", help = "Set the minimum number of instruments that must participate in a coincidence (default = 2). The value must be greater than 0.")
66 # FIXME: the test documents I have don't have SNR segments in
67 # them, but really that's what this should be using
68 parser.add_option("--snr-segments-name", metavar = "string", default = "whitehtsegments", help = "From the input document, use the segment list with this name to define when each detector was operating (default = \"whitehtsegments\").")
69 parser.add_option("--vetoes-segments-name", metavar = "string", help = "From the input document, use the segment list with this name to veto single-detector triggers before considering them for coincidence (default = do not apply vetoes.")
70 parser.add_option("--coinc-end-time-segment", metavar = "seg", help = "The segment of time to retain coincident triggers from. Uses segmentUtils.from_range_strings() format \"START:END\" for an interval of the form [START,END), \"START:\" for an interval of the form [START,INF), and \":END\" for an interval of the form (-INF,END) (default = retain all coincidences)")
71 parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.")
72 options, filenames = parser.parse_args()
73
74 process_params = options.__dict__.copy()
75
76 #
77 # check arguments
78 #
79
80 required_options = ["threshold"]
81 missing_options = [option for option in required_options if getattr(options, option) is None]
82 if missing_options:
83 raise ValueError("missing required option(s) %s" % ", ".join("--%s" % option.replace("_", "-") for option in missing_options))
84 if options.min_instruments < 1:
85 raise ValueError("invalid --min-instruments: \"%s\"" % options.min_instruments)
86
87 if options.coinc_end_time_segment is not None:
88 if ',' in options.coinc_end_time_segment:
89 raise ValueError("--coinc-end-time-segment may only contain a single segment")
90 options.coinc_end_time_segs = segmentsUtils.from_range_strings([options.coinc_end_time_segment], boundtype = lal.LIGOTimeGPS).coalesce()
91 else:
92 options.coinc_end_time_segs = None
93
94 #
95 # done
96 #
97
98 return options, process_params, (filenames or [None])
99
100
101#
102# =============================================================================
103#
104# Process Information
105#
106# =============================================================================
107#
108
109
110process_program_name = "lalapps_thinca"
111
112
113#
114# =============================================================================
115#
116# Main
117#
118# =============================================================================
119#
120
121
122#
123# Command line
124#
125
126
127options, process_params, filenames = parse_command_line()
128
129
130#
131# Select ntuple_comparefunc form
132#
133
134
135if options.coinc_end_time_segs is not None:
136 # Custom Ntuple Comparison Function
137 def ntuple_comparefunc(events, offset_vector, seg = options.coinc_end_time_segs):
138 """
139 Return False (ntuple should be retained) if the end time of
140 the coinc is in the segmentlist segs.
141 """
142 return thinca.coinc_inspiral_end_time(events, offset_vector) not in seg
143else:
144 ntuple_comparefunc = None
145
146
147#
148# Iterate over files.
149#
150
151
152for n, filename in enumerate(filenames, start = 1):
153 #
154 # Load the file.
155 #
156
157 if options.verbose:
158 print("%d/%d:" % (n, len(filenames)), end=' ', file=sys.stderr)
159 xmldoc = ligolw_utils.load_filename(filename, verbose = options.verbose)
160
161 #
162 # Have we already processed it?
163 #
164
165 if ligolw_process.doc_includes_process(xmldoc, process_program_name):
166 if options.verbose:
167 print("warning: %s already processed," % (filename or "stdin"), end=' ', file=sys.stderr)
168 if not options.force:
169 if options.verbose:
170 print("skipping", file=sys.stderr)
171 continue
172 if options.verbose:
173 print("continuing by --force", file=sys.stderr)
174
175 #
176 # Add an entry to the process table.
177 #
178
179 process = ligolw_process.register_to_xmldoc(
180 xmldoc,
181 process_program_name,
182 process_params,
183 comment = options.comment,
184 version = __version__,
185 cvs_repository = "lscsoft",
186 cvs_entry_time = __date__
187 )
188
189 #
190 # LAL writes all triggers with event_id = 0. Detect this and barf
191 # on it.
192 #
193
194 tbl = lsctables.SnglInspiralTable.get_table(xmldoc)
195 assert len(set(tbl.getColumnByName("event_id"))) == len(tbl), "degenerate sngl_inspiral event_id detected"
196
197 #
198 # Extract veto segments if present.
199 #
200 # FIXME: using the tools in the igwn_ligolw.utils.segments module
201 # it's not hard to modify the veto segments in the .xml to be just
202 # those that intersect the search summary segments. That way, if
203 # multiple documents are inserted into the same database, or merged
204 # with ligolw_add, the veto lists will not get duplicated.
205 #
206
207 seglists = ligolw_segments.segmenttable_get_by_name(xmldoc, options.snr_segments_name).coalesce()
208 if options.vetoes_segments_name is not None:
209 vetoes = ligolw_segments.segmenttable_get_by_name(xmldoc, options.vetoes_segments_name).coalesce()
210 else:
211 vetoes = None
212
213 #
214 # Run coincidence algorithm.
215 #
216
217 thinca.ligolw_thinca(
218 xmldoc,
219 process_id = process.process_id,
220 delta_t = options.threshold,
221 ntuple_comparefunc = ntuple_comparefunc,
222 seglists = seglists,
223 veto_segments = vetoes,
224 min_instruments = options.min_instruments,
225 verbose = options.verbose
226 )
227
228 #
229 # Close out the process table.
230 #
231
232 process.set_end_time_now()
233
234 #
235 # Write back to disk, and clean up.
236 #
237
238 ligolw_utils.write_filename(xmldoc, filename, verbose = options.verbose)
239 xmldoc.unlink()
240 lsctables.reset_next_ids(lsctables.TableByName.values())