From 24f8ea05e57993e618ed417b67bbbc3d426d7664 Mon Sep 17 00:00:00 2001
From: Kipp Cannon <kipp.cannon@ligo.org>
Date: Thu, 24 Aug 2017 17:53:00 +0900
Subject: [PATCH] plotpsd:  add cumulative SNRs plot

---
 gstlal/python/plotpsd.py | 67 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/gstlal/python/plotpsd.py b/gstlal/python/plotpsd.py
index 96a93bedc0..9dba8f8591 100644
--- a/gstlal/python/plotpsd.py
+++ b/gstlal/python/plotpsd.py
@@ -61,6 +61,52 @@ def summarize_coinc_xmldoc(coinc_xmldoc):
 	return sngl_inspirals, mass1, mass2, end_time, on_instruments
 
 
+def axes_plot_cummulative_snr(axes, psds, coinc_xmldoc):
+	sngl_inspirals, mass1, mass2, end_time, on_instruments = summarize_coinc_xmldoc(coinc_xmldoc)
+
+	axes.grid(which = "both", linestyle = "-", linewidth = 0.2)
+	axes.minorticks_on()
+
+	for instrument, sngl_inspiral in sngl_inspirals.items():
+		logging.info("found %s event with SNR %g" % (instrument, sngl_inspirals[instrument].snr))
+
+		if instrument not in psds:
+			logging.info("no PSD for %s" % instrument)
+			continue
+		psd = psds[instrument]
+		if psd is None:
+			logging.info("no PSD for %s" % instrument)
+			continue
+		psd_data = psd.data.data
+		f = psd.f0 + numpy.arange(len(psd_data)) * psd.deltaF
+		logging.info("found PSD for %s spanning [%g Hz, %g Hz]" % (instrument, f[0], f[-1]))
+
+		# FIXME: horizon distance stopped at 0.9 max frequency due
+		# to low pass filter messing up the end of the PSD.  if we
+		# could figure out the frequency bounds and delta F we
+		# could move this out of the loop for some speed
+		horizon_distance = reference_psd.HorizonDistance(10., 0.9 * f[-1], psd.deltaF, mass1, mass2)
+
+		# generate inspiral spectrum and clip PSD to its frequency
+		# range
+		inspiral_spectrum_x, inspiral_spectrum_y = horizon_distance(psd, sngl_inspiral.snr)[1]
+		lo = int(round((inspiral_spectrum_x[0] - psd.f0) / psd.deltaF))
+		hi = int(round((inspiral_spectrum_x[-1] - psd.f0) / psd.deltaF)) + 1
+		f = f[lo:hi]
+		psd_data = psd_data[lo:hi]
+
+		# plot
+		snr2 = (inspiral_spectrum_y / psd_data).cumsum() * psd.deltaF
+		axes.semilogx(f, snr2**.5, color = plotutil.colour_from_instruments([instrument]), alpha = 0.8, linestyle = "-", label = "%s SNR = %.3g" % (instrument, sngl_inspiral.snr))
+
+	axes.set_ylim([0., axes.get_ylim()[1]])
+
+	axes.set_title(r"Cumulative SNRs for $%.3g\,\mathrm{M}_{\odot}$--$%.3g\,\mathrm{M}_{\odot}$ Merger Candidate at %.2f GPS" % (mass1, mass2, float(end_time)))
+	axes.set_xlabel(r"Frequency (Hz)")
+	axes.set_ylabel(r"Cumulative SNR")
+	axes.legend(loc = "upper left")
+
+
 def axes_plot_psds(axes, psds, coinc_xmldoc = None):
 	"""!
 	Places a PSD plot into a matplotlib Axes object.
@@ -158,3 +204,24 @@ def plot_psds(psds, coinc_xmldoc = None, plot_width = 640):
 	axes_plot_psds(fig.gca(), psds, coinc_xmldoc = coinc_xmldoc)
 	fig.tight_layout(pad = .8)
 	return fig
+
+
+def plot_cumulative_snrs(psds, coinc_xmldoc, plot_width = 640):
+	"""!
+	Produces a matplotlib figure of cumulative SNRs.
+
+	@param psds A dictionary of PSDs as REAL8FrequencySeries keyed by
+	instrument
+
+	@param coinc_xmldoc An XML document containing a single event with all
+	of the metadata as would be uploaded to gracedb.
+
+	@param plot_width How wide to make the figure object in pixels
+	(ignored if axes is provided).
+	"""
+	fig = figure.Figure()
+	FigureCanvas(fig)
+	fig.set_size_inches(plot_width / float(fig.get_dpi()), int(round(plot_width / plotutil.golden_ratio)) / float(fig.get_dpi()))
+	axes_plot_cummulative_snr(fig.gca(), psds, coinc_xmldoc)
+	fig.tight_layout(pad = .8)
+	return fig
-- 
GitLab