gstlal-inspiral  0.4.2
 All Classes Namespaces Files Functions Variables Pages
gstlal_inspiral_followups_from_gracedb
1 #!/usr/bin/env python
2 #
3 # Copyright (C) 2012 Kipp Cannon, Chad Hanna, Drew Keppel
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 ## @file
20 # A program to request some followup data from a running gstlal_inspiral job based on gracedb submissions notified by lvalert
21 
22 import sys, os
23 import logging
24 from pylal import rate
25 os.environ["MPLCONFIGDIR"] = "/tmp"
26 import matplotlib
27 matplotlib.use('Agg')
28 import pylab
29 import numpy
30 from glue.ligolw import utils
31 import copy
32 from gstlal import far
33 import time
34 from glue.ligolw import ligolw, table, lsctables, param, array
35 array.use_in(ligolw.LIGOLWContentHandler)
36 param.use_in(ligolw.LIGOLWContentHandler)
37 lsctables.use_in(ligolw.LIGOLWContentHandler)
38 import urllib
39 import urlparse
40 import httplib
41 import subprocess
42 from ligo.gracedb.rest import GraceDb
43 import glob
44 from ligo.lvalert.utils import get_LVAdata_from_stdin
45 
46 def get_filename(gracedb_client, graceid, filename, retries = 3, retry_delay = 10.0, ignore_404 = False):
47  for i in range(retries):
48  logging.info("retrieving \"%s\" for %s" % (filename, graceid))
49  response = gracedb_client.files(graceid, filename)
50  if response.status == httplib.OK:
51  return response
52  if response.status == httplib.NOT_FOUND and ignore_404:
53  logging.warning("retrieving \"%s\" for %s: (%d) %s. skipping ..." % (filename, graceid, response.status, response.reason))
54  return None
55  logging.warning("retrieving \"%s\" for %s: (%d) %s. pausing ..." % (filename, graceid, response.status, response.reason))
56  time.sleep(retry_delay)
57  raise Exception("retrieving \"%s\" for %s: (%d) %s" % (filename, graceid, response.status, response.reason))
58 
59 
60 if len(sys.argv) == 1:
61  lvalert_data = get_LVAdata_from_stdin(sys.stdin, as_dict = True)
62  logging.info("%(alert_type)s-type alert for event %(uid)s" % lvalert_data)
63  logging.info("lvalert data: %s" % repr(lvalert_data))
64  filename = os.path.split(urlparse.urlparse(lvalert_data["file"]).path)[-1]
65  if filename not in (u"coinc.xml",) and "_CBC_" not in filename:
66  logging.info("filename is not 'coinc.xml'. skipping")
67  sys.exit()
68  gid = str(lvalert_data["uid"])
69 else:
70  gid = sys.argv[1]
71 
72 try:
73  os.mkdir(gid)
74 except OSError:
75  pass
76 
77 gracedb = GraceDb()
78 filename = get_filename(gracedb, gid, "coinc.xml", retries = 3, retry_delay = 10.0, ignore_404 = False)
79 xmldoc, checksum = utils.load_fileobj(filename, contenthandler = ligolw.LIGOLWContentHandler)
80 coinc_inspiral_row = lsctables.table.get_table(xmldoc, lsctables.CoincInspiralTable.tableName)[0]
81 sngl_inspiral_table = lsctables.table.get_table(xmldoc, lsctables.SnglInspiralTable.tableName)
82 process = lsctables.table.get_table(xmldoc, lsctables.ProcessTable.tableName)
83 params = lsctables.table.get_table(xmldoc, lsctables.ProcessParamsTable.tableName)
84 snr_chisq_dict = dict(((ifo,(None,None)) for ifo in ['H1','L1', 'V1']))
85 for r in sngl_inspiral_table:
86  snr_chisq_dict[r.ifo] = (r.snr, r.chisq)
87 for r in params:
88  if r.program == "gstlal_inspiral" and r.param == "--likelihood-file":
89  path = r.value
90  if r.program == "gstlal_inspiral" and r.param == "--job-tag":
91  tag = r.value
92 for r in process:
93  if r.program == "gstlal_inspiral":
94  node = r.node
95 
96 url = open("%s_registry.txt" % tag).readline().strip()
97 
98 #
99 # SNR / Time plot
100 #
101 
102 #FIXME don't hardcode port number
103 t,snr = numpy.loadtxt(urllib.urlopen("%ssnr_history.txt" % url), unpack = True)
104 t -= coinc_inspiral_row.get_end()
105 pylab.figure()
106 pylab.semilogy(t, snr)
107 pylab.ylabel('SNR')
108 pylab.xlabel('Time from event (s)')
109 fname = '%s/%s_snrtime.png' % (gid, gid)
110 pylab.ylim([min(snr), max(snr)])
111 pylab.xlim([min(t), max(t)])
112 pylab.grid()
113 pylab.savefig(fname)
114 gracedb.writeLog(gid, "SNR vs time", filename = fname, filecontents = open(fname).read(), tagname = "background")
115 
116 #
117 # SNR / Chisq plots
118 #
119 
120 likelihood_data = far.parse_likelihood_control_doc(utils.load_filename(path, contenthandler = far.ThincaCoincParamsDistributions.LIGOLWContentHandler))[0]
121 
122 counts = likelihood_data.background_rates
123 inj = likelihood_data.injection_rates
124 
125 bgcol = (224/255.,224/255.,224/255.)
126 
127 likely = copy.deepcopy(inj)
128 for i, ifo in enumerate(['H1', 'L1', 'V1']):
129  snrm, chisqm = snr_chisq_dict[ifo]
130  if snrm is None:
131  continue
132  likely[ifo+"_snr_chi"].array /= counts[ifo+"_snr_chi"].array
133  for name, obj in (("background", counts),):
134  fig = pylab.figure(figsize=(6,4), facecolor = 'g')
135  fig.patch.set_alpha(0.0)
136  H1 = obj[ifo+"_snr_chi"].array
137  snr = obj[ifo+"_snr_chi"].bins[0].centres()[1:-1]
138  chi = obj[ifo+"_snr_chi"].bins[1].centres()[1:-1]
139  chi[0] = 0 # not inf
140  ax = pylab.subplot(111)
141  pylab.pcolormesh(snr, chi, numpy.log10(H1.T +1)[1:-1,1:-1])
142  if snrm is not None and chisqm is not None:
143  pylab.plot(snrm, chisqm / snrm / snrm, 'ko', mfc = 'None', ms = 14, mew=4)
144  if "Log" in str(obj[ifo+"_snr_chi"].bins[0]):
145  ax.set_xscale('log')
146  if "Log" in str(obj[ifo+"_snr_chi"].bins[1]):
147  ax.set_yscale('log')
148  pylab.colorbar()
149  pylab.xlabel('SNR')
150  pylab.ylabel('reduced chi^2 / SNR^2')
151  pylab.ylim([0.001, 1])
152  pylab.xlim([4, 200])
153  pylab.title('%s: %s log base 10 (number + 1)' % (ifo, name))
154  pylab.grid(color=(0.1,0.4,0.5), linewidth=2)
155  fname = '%s/%s_%s_snrchi.png' % (gid, gid, ifo)
156  pylab.savefig(fname)
157  gracedb.writeLog(gid, "%s SNR/Chisq" % ifo, filename = fname, filecontents = open(fname).read(), tagname = "background")
158 
159 sys.exit()
160 
161 #
162 # QScans
163 # FIXME currently broken
164 #
165 
166 for r in sngl_inspiral_table:
167  cachefile = "%s/%sframes.cache" % (gid, r.ifo)
168  subprocess.call(["createframecache.pl", cachefile, "/scratch/llcache/llhoft/%s" % r.ifo])
169  conffile = "%s/%sconfig.txt" % (gid, r.ifo)
170  f = open(conffile , "w")
171  channel = "%s:%s" % (r.ifo, r.channel)
172  f.write("""[%s,%s]
173 
174 {
175  channelName: '%s'
176  frameType: '%s_llhoft'
177  sampleFrequency: 16384
178  searchFrequencyRange: [10 2048]
179  #searchChirpRange: [+0 +0]
180  searchTimeRange: 64
181  searchQRange: [4 64]
182  searchMaximumEnergyLoss: 0.2
183  searchWindowDuration: 0.25
184  whiteNoiseFalseRate: 1e-3
185  plotTimeRanges: 10
186  plotFrequencyRange: []
187  plotNormalizedEnergyRange: [0 25.5]
188  alwaysPlotFlag: 1
189 } """ % (channel, channel, channel, r.ifo))
190  f.close()
191 
192  tstr = str(r.get_end())
193 
194  # actually run the scan
195  subprocess.call(["dmt_wscan", str(r.get_end()), conffile, cachefile, gid, "1", "1"])
196 
197 # upload some plots to gracedb
198 for f in glob.glob("%s/*_spectrogram_autoscaled.png" % gid):
199  gracedb.writeLog(gid, "DMT omega scan", filename = f, filecontents = open(f).read(), tagname = "background")
200 
201 sys.exit()