#!/usr/bin/env python
#
# Copyright (C) 2010  Kipp Cannon, Chad Hanna, Leo Singer
# Copyright (C) 2009  Kipp Cannon, Chad Hanna
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
"""Build time-sliced, SVD'd filter banks for use with gstlal_inspiral"""


from optparse import OptionParser
import uuid


from glue.ligolw import ligolw
from glue.ligolw import array
from glue.ligolw import param
array.use_in(ligolw.LIGOLWContentHandler)
param.use_in(ligolw.LIGOLWContentHandler)
from glue.ligolw import utils
from gstlal import svd_bank
from pylal import series as lalseries


#
# parse command line
#


parser = OptionParser(description = __doc__)
parser.add_option("--flow", metavar = "Hz", type = "float", default = 40.0, help = "Set the template low-frequency cut-off (default = 40.0).")
parser.add_option("--identity-transform", action = "store_true", default = False, help = "Do not perform an SVD; instead, use the original templates as the analyzing templates and the identity matrix as the reconstruction matrix.")
parser.add_option("--padding", metavar = "pad", type = "float", default = 1.5, help = "Fractional amount to pad time slices.")
parser.add_option("--svd-tolerance", metavar = "match", type = "float", default = 0.9995, help = "Set the SVD reconstruction tolerance (default = 0.9995).")
parser.add_option("--reference-psd", metavar = "filename", help = "Instead of measuring the noise spectrum, load the spectrum from this LIGO light-weight XML file (required).")
parser.add_option("--template-bank", metavar = "filename", help = "Set the name of the LIGO light-weight XML file from which to load the template bank (required).")
parser.add_option("--ortho-gate-fap", metavar = "probability", type = "float", default = 1e-2, help = "Set the orthogonal SNR projection gate false-alarm probability (default = 1e-2).")
parser.add_option("--snr-threshold", metavar = "SNR", type = "float", default = 5.5, help = "Set the SNR threshold (default = 5.5).")
parser.add_option("--write-svd-bank", metavar = "filename", help = "Set the filename in which to save the template bank (required).")
parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose (optional).")
parser.add_option("--clipleft", type = "int", default = 0, help = "Remove poorly reconstructable templates from the left edge of each sub-bank.")
parser.add_option("--clipright", type = "int", default = 0, help = "Remove poorly reconstructable templates from the right edge of each sub-bank.")
parser.add_option("--autocorrelation-length", type = "int", default = 201, help = "The minimum number of samples to use for auto-chisquared, default 201 should be odd")
parser.add_option("--samples-min", type = "int", default = 1024, help = "The minimum number of samples to use for time slices default 1024")
parser.add_option("--samples-max-256", type = "int", default = 1024, help = "The maximum number of samples to use for time slices with frequencies above 256Hz, default 1024")
parser.add_option("--samples-max-64", type = "int", default = 2048, help = "The maximum number of samples to use for time slices with frequencies above 64Hz, default 2048")
parser.add_option("--samples-max", type = "int", default = 4096, help = "The maximum number of samples to use for time slices with frequencies below 64Hz, default 4096")
parser.add_option("--bank-id", metavar = "id", help = "Set a string to be used as the globally unique ID for this bank (default = generate a UUID).")

options, filenames = parser.parse_args()

required_options = ("reference_psd", "template_bank", "write_svd_bank")

missing_options = [option for option in required_options if getattr(options, option) is None]
if missing_options:
	raise ValueError, "missing required option(s) %s" % ", ".join("--%s" % option.replace("_", "-") for option in sorted(missing_options))

if not options.autocorrelation_length % 2:
	raise ValueError("--autocorrelation-length must be odd")

if options.bank_id is None:
	options.bank_id = str(uuid.uuid4())


#
#
# =============================================================================
#
#                                     Main
#
# =============================================================================
#


svd_bank.write_bank(
	options.write_svd_bank,
	svd_bank.build_bank(
		options.template_bank,
		lalseries.read_psd_xmldoc(utils.load_filename(
			options.reference_psd,
			verbose=options.verbose,
			contenthandler=ligolw.LIGOLWContentHandler
		)),
		options.flow,
		options.ortho_gate_fap,
		options.snr_threshold,
		options.svd_tolerance,
		padding = options.padding,
		identity_transform = options.identity_transform,
		verbose = options.verbose,
		autocorrelation_length = options.autocorrelation_length,
		samples_min = options.samples_min,
		samples_max_256 = options.samples_max_256,
		samples_max_64 = options.samples_max_64, 
		samples_max = options.samples_max,
		bank_id = options.bank_id
	),
	options.clipleft,
	options.clipright
)
