LALBurst 2.0.7.1-eeff03c
lalburst_gen_timeslides.py
Go to the documentation of this file.
1##python
2#
3# Copyright (C) 2006--2014 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 ligolw
34from igwn_ligolw import lsctables
35from igwn_ligolw import utils as ligolw_utils
36from igwn_ligolw.utils import process as ligolw_process
37from igwn_ligolw.utils import time_slide as ligolw_time_slide
38from lalburst import git_version
39from lalburst import timeslides
40
41
42__author__ = "Kipp Cannon <kipp.cannon@ligo.org>"
43__version__ = "git id %s" % git_version.id
44__date__ = git_version.date
45
46
47#
48# =============================================================================
49#
50# Command Line
51#
52# =============================================================================
53#
54
55
56def parse_normalize(normalize):
57 return dict((name.strip(), float(offset)) for name, offset in map(lambda s: s.split("="), normalize))
58
59
61 parser = OptionParser(
62 version = "Name: %%prog\n%s" % git_version.verbose_msg,
63 usage = "%prog [options] [filename ...]",
64 description = "%prog constructs time_slide tables, writing the result to one or more files. The time slide table to be constructed is described by specifying one or more ranges of offsets for each instrument. If more than one instrument and set of offsets is given, then the time slide table will contain entries corresponding to all combinations of offsets, one each from the different instuments. If no file names are given on the command line, output is written to stdout. If more than one file name is given on the command line, then the time slides are distributed uniformly between files with each file being given a disjoint subset of the time slides. Output files whose names end in \".gz\" will be gzip compressed.\n\nExample:\n\n%prog --verbose --instrument H1=-100:+100:10 --instrument L1=-100:+100:+10 time_slides.xml.gz"
65 )
66 parser.add_option("-a", "--add-to", metavar = "filename", action = "append", default = [], help = "Add the time slides from this file to the newly-generated time slides. If the name ends in \".gz\" it will be gzip-decompressed on input.")
67 parser.add_option("--comment", metavar = "text", help = "Set comment string in process table (default = None).")
68 parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.")
69 parser.add_option("-i", "--instrument", metavar = "name=first:last:step[,first:last:step[,...]]", action = "append", default = [], help = "Provide a description of the set of offsets to use for a particular instrument. The set of offsets is (first + n * step) where n is an integer such that first <= offset <= last. More than one set of offsets can be given for the same instrument, in which case the union is used. As a short-hand, the sets can be combined into a single command line argument by separating the first:last:step triples with commas.")
70 parser.add_option("--inspiral-num-slides", metavar = "count:instrument=offset[,instrument=offset...]", action = "append", default = [], help = "Generate a set of inspiral group style time slides. The collection of instrument/offset pairs defines an offset vector, and the time slides produced are integer multiples of that vector n * {offsets} where n is a non-zero integer in [-count, +count] (so if count=50, you get 101 time slides). If this option is given more than once, then multiple sets of inspiral-style time slides are generated.")
71 parser.add_option("-n", "--normalize", metavar = "name=offset", default = [], action = "append", help = "Normalize the time slides so that this instrument has the specified offset in all. The other offsets in each time slide are adjusted so that the relative offsets are preserved. Time slides that do not involve this instrument are unaffected. If this option is given multiple times, then for each time slide they are considered in alphabetical order by instrument until the first is found that affects the offsets of that time slide.")
72 parser.add_option("--remove-zero-lag", action = "store_true", help = "Remove the time slide with offsets of 0 for all instruments.")
73 options, filenames = parser.parse_args()
74
75 try:
76 parse_normalize(options.normalize)
77 except Exception as e:
78 raise ValueError("unable to parse --normalize arguments: %s" % str(e))
79
80 return options, (filenames or [None])
81
82
83#
84# =============================================================================
85#
86# Preparation
87#
88# =============================================================================
89#
90
91
92def new_doc(comment = None, **kwargs):
93 doc = ligolw.Document()
94 doc.appendChild(ligolw.LIGO_LW())
95 process = ligolw_process.register_to_xmldoc(
96 doc,
97 program = "lalburst_gen_timeslides",
98 paramdict = kwargs,
99 version = __version__,
100 cvs_repository = "lscsoft",
101 cvs_entry_time = __date__,
102 comment = comment
103 )
104 doc.childNodes[0].appendChild(lsctables.TimeSlideTable.new())
105
106 return doc, process
107
108
109#
110# =============================================================================
111#
112# Main
113#
114# =============================================================================
115#
116
117
118#
119# Command line.
120#
121
122
123options, filenames = parse_command_line()
124
125
126#
127# Load initial time slides.
128#
129
130
131time_slides = {}
132for filename in options.add_to:
133 time_slide_table = lsctables.TimeSlideTable.get_table(ligolw_utils.load_filename(filename, verbose = options.verbose))
134 extra_time_slides = time_slide_table.as_dict().values()
135 if options.verbose:
136 print("Loaded %d time slides." % len(extra_time_slides), file=sys.stderr)
137 for offsetvect in extra_time_slides:
138 time_slides[lsctables.TimeSlideTable.get_next_id()] = offsetvect
139
140
141#
142# Make new time slides.
143#
144
145
146if options.verbose:
147 print("Computing new time slides ...", file=sys.stderr)
148
149# dictionary mapping time_slide_id --> (dictionary mapping insrument --> offset)
150
151for offsetvect in timeslides.SlidesIter(timeslides.parse_slides(options.instrument)):
152 time_slides[lsctables.TimeSlideTable.get_next_id()] = offsetvect
153for inspiral_slidespec in options.inspiral_num_slides:
154 for offsetvect in timeslides.Inspiral_Num_Slides_Iter(*timeslides.parse_inspiral_num_slides_slidespec(inspiral_slidespec)):
155 time_slides[lsctables.TimeSlideTable.get_next_id()] = offsetvect
156
157if options.verbose:
158 print("Total of %d time slides." % len(time_slides), file=sys.stderr)
159
160
161#
162# Remove duplicates.
163#
164
165
166if options.verbose:
167 print("Identifying and removing duplicates ...", file=sys.stderr)
168
169map(time_slides.pop, timeslides.vacuum(time_slides, verbose = options.verbose).keys())
170
171if options.verbose:
172 print("%d time slides remain." % len(time_slides), file=sys.stderr)
173
174
175#
176# Remove zero-lag
177#
178
179
180if options.remove_zero_lag:
181 if options.verbose:
182 print("Identifying and removing zero-lag ...", file=sys.stderr)
183
184 null_ids = [time_slide_id for time_slide_id, offsetvect in time_slides.items() if not any(offsetvect.deltas.values())]
185 for time_slide_id in null_ids:
186 del time_slides[time_slide_id]
187
188 if options.verbose:
189 print("%d time slides remain." % len(time_slides), file=sys.stderr)
190
191
192#
193# Convert to list of offset dictionaries. We no longer require the IDs,
194# new ones will be assigned as they are put into the output XML document.
195#
196
197
198time_slides = list(time_slides.values())
199
200
201#
202# Normalize the time slides
203#
204
205
206if options.normalize:
207 if options.verbose:
208 print("Normalizing the time slides ...", file=sys.stderr)
209 constraints = parse_normalize(options.normalize)
210 time_slides = [offsetvect.normalize(**constraints) for offsetvect in time_slides]
211
212
213#
214# Make documents.
215#
216
217
218lsctables.TimeSlideTable.reset_next_id()
219while filenames:
220 #
221 # Create an empty document, populate the process information.
222 #
223
224 xmldoc, process = new_doc(**options.__dict__)
225 timeslidetable = lsctables.TimeSlideTable.get_table(xmldoc)
226
227 #
228 # How many slides will go into this file?
229 #
230
231 N = int(round(float(len(time_slides)) / len(filenames)))
232
233 #
234 # Put them in.
235 #
236
237 for offsetvect in time_slides[:N]:
238 timeslidetable.append_offsetvector(offsetvect, process)
239 del time_slides[:N]
240
241 #
242 # Finish off the document.
243 #
244
245 process.set_end_time_now()
246
247 #
248 # Write.
249 #
250
251 filename = filenames.pop(0)
252 ligolw_utils.write_filename(xmldoc, filename, verbose = options.verbose)
253
254assert not time_slides
def new_doc(comment=None, **kwargs)