diff --git a/gstlal-inspiral/bin/gstlal_bank_splitter b/gstlal-inspiral/bin/gstlal_bank_splitter index 12039e7929cc4d8c596b158a273e7ce040faf438..996eec40d77756e0f5a19a03c0ae96d28d1b6c39 100755 --- a/gstlal-inspiral/bin/gstlal_bank_splitter +++ b/gstlal-inspiral/bin/gstlal_bank_splitter @@ -33,6 +33,9 @@ from gstlal import dagparts from gstlal import chirptime import lal from lal.utils import CacheEntry +import numpy, scipy.interpolate +import lalsimulation +from lal import series ### This program splits template banks into sub banks suitable for singular value decomposition; see gstlal_bank_splitter for more information ### @@ -67,6 +70,42 @@ class LIGOLWContentHandler(ligolw.LIGOLWContentHandler): lsctables.use_in(LIGOLWContentHandler) +def bandwidth(m1, m2, s1, s2, f_min, f_max, delta_f, psd): + def fn(farr, h, n, psd): + df = farr[1] - farr[0] + return 4 * numpy.sum(numpy.abs(h)**2 * farr**n * df / psd(farr)) + + def moment(farr, h, n, psd): + return fn(farr, h, n, psd) / fn(farr, h, 0, psd) + + spin1 = [0., 0., 0.]; spin2 = [0., 0., 0.] + f_min = 10. + f_max = 1024.0 + delta_f = 1.0 + farr = numpy.linspace(0, f_max, f_max / delta_f + delta_f) + hp, hc = lalsimulation.SimInspiralFD( + m1 * lal.MSUN_SI, m2 * lal.MSUN_SI, + spin1[0], spin1[1], spin1[2], + spin2[0], spin2[1], spin2[2], + 1.0, # distance (m) + 0.0, + 0.0, # reference orbital phase (rad) + 0.0, # longitude of ascending nodes (rad) + 0.0, + 0.0, # mean anomaly of periastron + delta_f, + f_min, + f_max + delta_f, + 100., # reference frequency (Hz) + None, # LAL dictionary containing accessory parameters + lalsimulation.GetApproximantFromString("IMRPhenomD") + ) + assert hp.data.length > 0, "huh!? h+ has zero length!" + + h = hp.data.data[:len(farr)] + return (moment(farr, h, 2, psd) - moment(farr, h, 1, psd)**2)**.5 + + def group_templates(templates, n, overlap = 0): """ break up the template table into sub tables of length n with overlap @@ -97,6 +136,7 @@ def parse_command_line(): parser.add_option("--max-f-final", metavar = "float", type="float", help = "Max f_final to populate table with; if f_final over max, use max.") parser.add_option("--instrument", metavar = "ifo", type="string", help = "override the instrument, required") parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.") + parser.add_option("--psd-xml", type = "string", help = "Specify a PSD to use for computing template bandwidth. Required if sort-by is bandwidth") parser.add_option("--approximant", type = "string", action = "append", help = "Must specify an approximant given as mchirp_min:mchirp_max:string") parser.add_option("--f-low", type = "float", metavar = "frequency", help = "Lower frequency cutoff. Required") parser.add_option("--group-by-chi", type = "int", metavar = "N", default = 1, help = "group templates into N groups of chi - helps with SVD. Default 1") @@ -118,6 +158,9 @@ def parse_command_line(): if len(filenames) !=1: raise ValueError("Must give exactly one file name") + if options.sort_by == "bandwidth" and not options.psd_xml: + raise ValueError("must specify psd-xml if sort-by is bandwidth") + approximants = [] for appx in options.approximant: mn, mx, appxstring = appx.split(":") @@ -127,10 +170,16 @@ def parse_command_line(): if options.num_banks: options.num_banks = [int(v) for v in options.num_banks.split(",")] + # FIXME don't hard code L1 + if options.psd_xml: + psd = series.read_psd_xmldoc(ligolw_utils.load_filename(options.psd_xml, verbose = options.verbose, contenthandler = series.PSDContentHandler))["L1"] + f = numpy.arange(len(psd.data.data)) * psd.deltaF + psd = scipy.interpolate.interp1d(f, psd.data.data) + else: + psd = None + return options, filenames[0], psd - return options, filenames[0] - -options, filename = parse_command_line() +options, filename, psd = parse_command_line() def assign_approximant(mchirp, approximants = options.approximant): for lo, hi, appx in approximants: @@ -143,7 +192,12 @@ outputrows = [] xmldoc = ligolw_utils.load_filename(filename, verbose = options.verbose, contenthandler = LIGOLWContentHandler) sngl_inspiral_table = lsctables.SnglInspiralTable.get_table(xmldoc) - +# Add a fake bandwidth column +if options.sort_by == "bandwidth": + for count, row in enumerate(sngl_inspiral_table): + # FIXME don't hard code + row.bandwidth = bandwidth(row.mass1, row.mass1, row.spin1z, row.spin2z, f_min = 10.0, f_max = 1024., delta_f = 0.25, psd = psd) + print count, len(sngl_inspiral_table), row.bandwidth # FIXME #process = ligolw_process.register_to_xmldoc(xmldoc, program = "gstlal_bank_splitter", paramdict = options.__dict__, comment = "Assign template IDs") if options.output_full_bank_file is not None: