3 # Copyright (C) 2013 Kipp Cannon
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.
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.
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.
19 ## @file gstlal_inspiral_lvalert_psd_plotter
20 # A program to listen to lvalerts, download the psd from gstlal gracedb events, plot it, and upload the results
22 # ### Command line interface
24 # + `--no-upload`: Write plots to disk.
25 # + `--skip-404`: Skip events that give 404 (file not found) errors (default is to abort).
26 # + `--verbose`: Be verbose.
28 # =============================================================================
32 # =============================================================================
40 from optparse
import OptionParser
48 from glue.ligolw
import ligolw
49 from glue.ligolw
import array as ligolw_array
50 from glue.ligolw
import param as ligolw_param
51 from glue.ligolw
import lsctables
52 from glue.ligolw
import utils as ligolw_utils
54 from gstlal
import plotpsd
56 from ligo.gracedb
import cli as gracedb
58 from ligo
import gracedb
59 from ligo.lvalert.utils
import get_LVAdata_from_stdin
60 from pylal
import series as lal_series
63 class LIGOLWContentHandler(ligolw.LIGOLWContentHandler):
65 ligolw_array.use_in(LIGOLWContentHandler)
66 ligolw_param.use_in(LIGOLWContentHandler)
67 lsctables.use_in(LIGOLWContentHandler)
71 # =============================================================================
75 # =============================================================================
79 def get_filename(gracedb_client, graceid, filename, retries = 3, retry_delay = 10.0, ignore_404 = False):
80 for i in range(retries):
81 logging.info("retrieving \"%s\" for %s" % (filename, graceid))
82 response = gracedb_client.files(graceid, filename)
83 if response.status == httplib.OK:
85 if response.status == httplib.NOT_FOUND and ignore_404:
86 logging.warning("retrieving \"%s\" for %s: (%d) %s. skipping ..." % (filename, graceid, response.status, response.reason))
88 logging.warning("retrieving \"%s\" for %s: (%d) %s. pausing ..." % (filename, graceid, response.status, response.reason))
89 time.sleep(retry_delay)
90 raise Exception("retrieving \"%s\" for %s: (%d) %s" % (filename, graceid, response.status, response.reason))
93 def get_psds(gracedb_client, graceid, filename = "psd.xml.gz", ignore_404 = False):
94 response = get_filename(gracedb_client, graceid, filename = filename, ignore_404 = ignore_404)
97 return lal_series.
read_psd_xmldoc(ligolw_utils.load_fileobj(response, contenthandler = LIGOLWContentHandler)[0])
100 def get_coinc_xmldoc(gracedb_client, graceid, filename = "coinc.xml"):
101 return ligolw_utils.load_fileobj(get_filename(gracedb_client, graceid, filename = filename), contenthandler = LIGOLWContentHandler)[0]
104 def upload_fig(fig, gracedb_client, graceid, filename = "psd.png"):
105 plotfile = StringIO.StringIO()
106 fig.savefig(plotfile, format = os.path.splitext(filename)[-1][1:])
107 logging.info("uploading \"%s\" for %s" % (filename, graceid))
108 response = gracedb_client.writeLog(graceid, "strain spectral densities", filename = filename, filecontents = plotfile.getvalue(), tagname = "psd")
109 if response.status != httplib.CREATED:
110 raise Exception("upload of \"%s\" for %s failed: %s" % (filename, graceid, response["error"]))
114 # =============================================================================
118 # =============================================================================
122 def parse_command_line():
123 parser = OptionParser()
124 parser.add_option("--no-upload", action = "store_true", help = "Write plots to disk.")
125 parser.add_option("--skip-404", action = "store_true", help = "Skip events that give 404 (file not found) errors (default is to abort).")
126 parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.")
127 options, graceids = parser.parse_args()
130 # FIXME: lvalert_listen doesn't allow command-line options
133 # can only call basicConfig once (otherwise need to switch to more
134 # complex logging configuration)
136 logging.basicConfig(format = "%(asctime)s:%(message)s", level = logging.INFO)
138 logging.basicConfig(format = "%(asctime)s:%(message)s")
140 return options, graceids
144 # =============================================================================
148 # =============================================================================
152 options, graceids = parse_command_line()
156 lvalert_data = get_LVAdata_from_stdin(sys.stdin, as_dict = True)
157 logging.info("%(alert_type)s-type alert for event %(uid)s" % lvalert_data)
158 logging.info("lvalert data: %s" % repr(lvalert_data))
159 filename = os.path.split(urlparse.urlparse(lvalert_data["file"]).path)[-1]
160 if filename not in (u"coinc.xml",) and "_CBC_" not in filename:
161 logging.info("filename is not 'coinc.xml'. skipping")
163 graceids = [str(lvalert_data["uid"])]
164 # pause to give the psd file a chance to get uploaded.
168 gracedb_client = gracedb.Client()
171 for graceid in graceids:
172 psds = get_psds(gracedb_client, graceid, ignore_404 = options.skip_404)
175 fig = plotpsd.
plot_psds(psds, get_coinc_xmldoc(gracedb_client, graceid))
176 if options.no_upload:
177 filename = "psd_%s.png" % graceid
178 logging.info("writing %s ..." % filename)
179 fig.savefig(filename)
181 upload_fig(fig, gracedb_client, graceid)
182 logging.info("finished processing %s" % graceid)