def main(): signal.signal(signal.SIGINT, signal.SIG_DFL) args = parser.parse_args() ########## # initial arg processing if os.path.splitext(os.path.basename(args.IFO))[1] in DATA_SAVE_FORMATS: if args.freq: parser.exit(2, "Frequency specification not allowed when loading traces from file.\n") if args.ifo: parser.exit(2, "IFO parameter specification not allowed when loading traces from file.\n") from .io import load_hdf5 budget = None freq, traces, attrs = load_hdf5(args.IFO) ifo = attrs.get('ifo') # FIXME: deprecate 'IFO' ifo = attrs.get('IFO', ifo) plot_style = attrs else: budget = load_budget(args.IFO) ifo = budget.ifo if args.freq: try: freq = freq_from_spec(args.freq) except IndexError: parser.exit(2, "Improper frequency specification: {}\n".format(args.freq)) else: freq = getattr(budget, 'freq', freq_from_spec(FREQ)) plot_style = getattr(budget, 'plot_style', {}) traces = None if args.ifo: for paramval in args.ifo: param, val = paramval.split('=', 1) ifo[param] = float(val) if args.yaml: if not ifo: parser.exit(2, "IFO structure not provided.\n") print(ifo.to_yaml(), end='') return if args.text: if not ifo: parser.exit(2, "IFO structure not provided.\n") print(ifo.to_txt(), end='') return if args.diff: if not ifo: parser.exit(2, "IFO structure not provided.\n") dbudget = load_budget(args.diff) diffs = ifo.diff(dbudget.ifo) if diffs: w = max([len(d[0]) for d in diffs]) fmt = '{{:{}}} {{:>20}} {{:>20}}'.format(w) print(fmt.format('', args.IFO, args.diff)) print(fmt.format('', '-----', '-----')) for p in diffs: k = str(p[0]) v = repr(p[1]) ov = repr(p[2]) print(fmt.format(k, v, ov)) return out_data_files = set() out_plot_files = set() if args.save: args.plot = False for path in args.save: if os.path.splitext(path)[1] in DATA_SAVE_FORMATS: out_data_files.add(path) out_plot_files = set(args.save) - out_data_files if args.plot or out_plot_files: if out_plot_files: # FIXME: this silliness seems to be the only way to have # matplotlib usable on systems without a display. There must # be a better way. 'AGG' is a backend that works without # displays. but it has to be set before any other matplotlib # stuff is imported. and we *don't* want it set if we do want # to show an interactive plot. there doesn't seem a way to # set this opportunistically. import matplotlib matplotlib.use('AGG') try: from matplotlib import pyplot as plt except RuntimeError: logger.warning("no display, plotting disabled.") args.plot = False try: import inspiral_range logger_ir = logging.getLogger('inspiral_range') logger_ir.setLevel(logger.getEffectiveLevel()) handler = logging.StreamHandler() handler.setFormatter(logging.Formatter('%(name)s: %(message)s')) logger_ir.addHandler(handler) except ModuleNotFoundError: logger.warning("WARNING: inspiral_range package not available, figure of merit will not be calculated.") args.fom = None if args.fom: try: range_func, range_func_args = args.fom.split(':') except ValueError: range_func = args.fom range_func_args = '' range_params = {} for param in range_func_args.split(','): if not param: continue p, v = param.split('=') if not v: raise ValueError('missing parameter value "{}"'.format(p)) try: v = float(v) except ValueError: pass range_params[p] = v ########## # main calculations if not traces: logger.info("calculating budget...") traces = budget.run(freq=freq) if args.title: plot_style['title'] = args.title elif 'title' in plot_style: pass elif budget: plot_style['title'] = "GWINC Noise Budget: {}".format(budget.name) else: plot_style['title'] = "GWINC Noise Budget: {}".format(args.IFO) if args.fom: logger.info("calculating inspiral {}...".format(range_func)) H = inspiral_range.CBCWaveform(freq, **range_params) logger.debug("waveform params: {}".format(H.params)) fom = eval('inspiral_range.{}'.format(range_func))(freq, traces['Total'][0], H=H) logger.info("{}({}) = {:.2f} Mpc".format(range_func, range_func_args, fom)) fom_title = 'inspiral {func} {m1}/{m2} $\mathrm{{M}}_\odot$: {fom:.0f} Mpc'.format( func=range_func, m1=H.params['m1'], m2=H.params['m2'], fom=fom, ) plot_style['title'] += '\n{}'.format(fom_title) ########## # interactive # interactive shell plotting if args.interactive: banner = """GWINC interactive shell The 'ifo' Struct and 'traces' data objects are available for inspection. Use the 'whos' command to view the workspace. """ if not args.plot: banner += """ You may plot the budget using the 'plot_noise()' function: In [.]: plot_noise(freq, traces, **plot_style) """ banner += """ You may interact with the plot using the 'plt' functions, e.g.: In [.]: plt.title("foo") In [.]: plt.savefig("foo.pdf") """ from IPython.terminal.embed import InteractiveShellEmbed ipshell = InteractiveShellEmbed( banner1=banner, user_ns={ 'freq': freq, 'traces': traces, 'ifo': ifo, 'plot_style': plot_style, 'plot_noise': plot_noise, }, ) ipshell.enable_pylab() if args.plot: ipshell.ex("fig = plot_noise(freq, traces, **plot_style)") ipshell.ex("plt.title(plot_style['title'])") ipshell() ########## # output # save noise traces to HDF5 file if out_data_files: from .io import save_hdf5 attrs = dict(plot_style) for path in out_data_files: logger.info("saving budget traces: {}".format(path)) save_hdf5( path=path, freq=freq, traces=traces, ifo=ifo, **attrs, ) # standard plotting if args.plot or out_plot_files: logger.debug("plotting noises...") fig = plt.figure() ax = fig.add_subplot(1, 1, 1) plot_noise( freq, traces, ax=ax, **plot_style ) fig.tight_layout() if out_plot_files: for path in out_plot_files: logger.info("saving budget plot: {}".format(path)) fig.savefig(path) else: plt.show()
def main(): signal.signal(signal.SIGINT, signal.SIG_DFL) args = parser.parse_args() ########## # initial arg processing if os.path.splitext(os.path.basename(args.IFO))[1] in [".hdf5", ".h5"]: Budget = None freq, traces, attrs = io.load_hdf5(args.IFO) ifo = getattr(attrs, "IFO", None) plot_style = attrs else: Budget, ifo, freq, plot_style = load_ifo(args.IFO) # FIXME: this should be done only if specified, to allow for # using any FREQ specified in budget module by default freq = np.logspace(np.log10(args.flo), np.log10(args.fhi), args.npoints) traces = None if args.yaml: if not ifo: parser.exit(2, "no IFO structure available.") print(ifo.to_yaml(), end="") return if args.text: if not ifo: parser.exit(2, "no IFO structure available.") print(ifo.to_txt(), end="") return if args.diff: if not ifo: parser.exit(2, "no IFO structure available.") fmt = "{:30} {:>20} {:>20}" Budget, ifoo, freq, plot_style = load_ifo(args.diff) diffs = ifo.diff(ifoo) if diffs: print(fmt.format("", args.IFO, args.diff)) for p in diffs: k = str(p[0]) v = repr(p[1]) ov = repr(p[2]) print(fmt.format(k, v, ov)) return if args.title: plot_style["title"] = args.title elif Budget: plot_style["title"] = "GWINC Noise Budget: {}".format(Budget.name) else: plot_style["title"] = "GWINC Noise Budget: {}".format(args.IFO) if args.plot: if args.save: # FIXME: this silliness seems to be the only way to have # matplotlib usable on systems without a display. There must # be a better way. 'AGG' is a backend that works without # displays. but it has to be set before any other matplotlib # stuff is imported. and we *don't* want it set if we do want # to show an interactive plot. there doesn't seem a way to # set this opportunistically. import matplotlib matplotlib.use("AGG") try: from matplotlib import pyplot as plt except RuntimeError: logging.warning("no display, plotting disabled.") args.plot = False if args.fom: import inspiral_range try: range_func, fargs = args.fom.split(":") except ValueError: range_func = args.fom fargs = "" range_params = {} for param in fargs.split(","): if not param: continue p, v = param.split("=") if not v: raise ValueError('missing parameter value "{}"'.format(p)) if p != "approximant": v = float(v) range_params[p] = v ########## # main calculations if not traces: if ifo: logging.info("precomputing ifo...") ifo = precompIFO(freq, ifo) logging.info("calculating budget...") budget = Budget(freq=freq, ifo=ifo) budget.load() budget.update() traces = budget.calc_trace() # logging.info('recycling factor: {: >0.3f}'.format(ifo.gwinc.prfactor)) # logging.info('BS power: {: >0.3f} W'.format(ifo.gwinc.pbs)) # logging.info('arm finesse: {: >0.3f}'.format(ifo.gwinc.finesse)) # logging.info('arm power: {: >0.3f} kW'.format(ifo.gwinc.parm/1000)) if args.fom: logging.info("calculating inspiral {}...".format(range_func)) H = inspiral_range.CBCWaveform(freq, **range_params) logging.debug("params: {}".format(H.params)) fom = eval("inspiral_range.{}".format(range_func))(freq, noises["Total"], H=H) logging.info("{}({}) = {:.2f} Mpc".format(range_func, fargs, fom)) fom_title = "{func} {m1}/{m2} Msol: {fom:.2f} Mpc".format( func=range_func, m1=H.params["m1"], m2=H.params["m2"], fom=fom, ) plot_style["title"] += "\n{}".format(fom_title) ########## # output # save noise traces to HDF5 file if args.save and os.path.splitext(args.save)[1] in [".hdf5", ".h5"]: logging.info("saving budget traces {}...".format(args.save)) if ifo: plot_style["IFO"] = ifo.to_yaml() io.save_hdf5(path=args.save, freq=freq, traces=traces, **plot_style) # interactive shell plotting elif args.interactive: ipshell = InteractiveShellEmbed( user_ns={ "freq": freq, "traces": traces, "ifo": ifo, "plot_style": plot_style, "plot_noise": plot_noise, }, banner1=""" GWINC interactive plotter You may interact with plot using "plt." methods, e.g.: >>> plt.title("foo") >>> plt.savefig("foo.pdf") """, ) ipshell.enable_pylab() ipshell.run_code("plot_noise(freq, traces, **plot_style)") ipshell.run_code("plt.title('{}')".format(plot_style["title"])) ipshell() # standard plotting elif args.plot: logging.info("plotting noises...") fig = plt.figure() ax = fig.add_subplot(1, 1, 1) plot_noise(freq, traces, ax=ax, **plot_style) fig.tight_layout() if args.save: fig.savefig( args.save, ) else: plt.show()