__main__.py 8.59 KB
Newer Older
Sean Leavey's avatar
Sean Leavey committed
1 2 3 4 5 6 7
"""Finesse command line interface

Sean Leavey
<sean.leavey@ligo.org>
"""

import sys
8
import os
Sean Leavey's avatar
Sean Leavey committed
9 10 11 12 13 14 15 16
import numpy as np
import click

from . import __version__
from .finesse import kat as katparser

@click.command(help="Python interface and tools for FINESSE")
@click.argument("file", type=click.File())
17
@click.option("--simulate/--no-simulate", is_flag=True, default=True,
18 19
              help="Simulate FILE in Finesse. Can be set to --no-simulate if for example "
              "you only want to display the node graph for the model specified in FILE.")
Sean Leavey's avatar
Sean Leavey committed
20 21 22 23 24 25 26 27 28 29
@click.option("--xstart", type=float,
              help="Simulation start value. If specified, this overrides the xaxis start "
              "value specified in the parsed file.")
@click.option("--xstop", type=float,
              help="Simulation stop value. If specified, this overrides the xaxis stop "
              "value specified in the parsed file.")
@click.option("--xsteps", type=int,
              help="Number of steps to simulate between --start and --stop. If specified, "
              "this overrides the number of xaxis steps specified in the parsed file.")
@click.option("--xscale", type=click.Choice(["lin", "log"]), help="Scaling for the xaxis.")
30
@click.option("--noxaxis", is_flag=True, default=False, help="Switch off x-axis.")
Sean Leavey's avatar
Sean Leavey committed
31 32
@click.option("--trace", type=click.Choice(["tem", "cavity", "mismatch", "beams", "gouy",
                                            "coupling", "modechanges", "nodes", "all"]),
Sean Leavey's avatar
Sean Leavey committed
33 34
              multiple=True, help="Show simulation trace results. This option can be specified "
                                  "multiple times. The following values are supported: "
Sean Leavey's avatar
Sean Leavey committed
35 36 37 38 39 40 41 42 43
                                  "'tem': list TEM modes used, "
                                  "'cavity': cavity eigenvalues and other parameters, "
                                  "'mismatch': mode mismatch parameters for the initial setup, "
                                  "'beams': beam parameters for every node, "
                                  "'gouy': Gouy phases for all spaces, "
                                  "'coupling': coupling coefficients for all components, "
                                  "'modechanges': mode matching parameter changes during calculations, "
                                  "'nodes': nodes found during cavity tracing, "
                                  "'all': all trace results.")
44
@click.option("--powers", type=click.Choice(["dc", "carrier", "tem00"]),
45
              multiple=True, help="Show powers (W) at each node in the interferometer. This "
46 47 48 49 50
                                  "option can be specified multiple times. The following "
                                  "values are supported: "
                                  "'dc': list dc powers, "
                                  "'carrier': list powers in the f=0 fields, "
                                  "'tem00': list powers in the TEM00 mode.")
Sean Leavey's avatar
Sean Leavey committed
51 52
@click.option("--maxtem", type=str, help="Maximum transverse electric mode. Can be either "
              "an integer or 'off'.")
53 54 55 56 57
@click.option("--phase", type=int, help="Set Gouy phase behaviour.")
@click.option("--retrace", type=click.Choice(["force", "off"]),
              help="Set retrace behaviour: 'force' recomputes the Gaussian parameters at each "
              "node for every data point, and will trace a cavity even if it is unstable; 'off' "
              "switches off retracing even if it normally would be done.")
58 59
@click.option("--deriv-h", type=float, help="Step size for numerical differentiation.")
@click.option("--lambda0", type=str, help="Reference wavelength (m). Supports SI prefixes.")
60 61 62 63 64 65
@click.option("--print-frequencies", is_flag=True, default=False,
              help="Print a table listing all the frequencies used in the simulation: carriers, "
              "modulation sidebands and signal/quantum sidebands.")
@click.option("--print-noises", is_flag=True, default=False,
              help="Print a list of all the quantum noise sources being considered in the "
              "simulation and at which components and nodes it is present.")
Sean Leavey's avatar
Sean Leavey committed
66 67 68 69 70 71
@click.option("--ignore-block", "ignored_blocks", multiple=True,
              help="Ignore the specified block. Can be specified multiple times.")
@click.option("--plot/--no-plot", default=True, show_default=True,
              help="Display results as figure.")
@click.option("--save-figure", type=click.File("wb", lazy=False),
              help="Save image of figure to file.")
72
@click.option("--display-graph", is_flag=True, help="Generate and display model node graph.")
73 74 75 76
@click.option("--save-input", is_flag=True, default=False,
              help="Save generated Finesse input file.")
@click.option("--save-output", is_flag=True, default=False,
              help="Save generated Finesse output file.")
77 78 79
@click.option("--finesse-dir", type=click.Path(exists=True, file_okay=False, dir_okay=True),
              envvar='FINESSE_DIR', help="Path to directory containing the Finesse 'kat' "
              "executable. If not specified, the environment variable FINESSE_DIR is used.")
Sean Leavey's avatar
Sean Leavey committed
80
@click.version_option(version=__version__, prog_name="Pykat")
81
def cli(file, simulate, xstart, xstop, xsteps, xscale, noxaxis, trace, powers, maxtem, phase,
82 83
        retrace, deriv_h, lambda0, print_frequencies, print_noises, ignored_blocks, plot,
        save_figure, display_graph, save_input, save_output, finesse_dir):
Sean Leavey's avatar
Sean Leavey committed
84
    """Base CLI command group"""
85 86 87 88
    if finesse_dir is None:
        # Use default as required by kat object.
        finesse_dir = ""
    kat = katparser(katdir=finesse_dir)
Sean Leavey's avatar
Sean Leavey committed
89
    kat.load(file.name)
90
    has_xaxis = hasattr(kat, "xaxis") and not noxaxis
Sean Leavey's avatar
Sean Leavey committed
91 92 93 94 95

    if ignored_blocks:
        for block in ignored_blocks:
            kat.removeBlock(block)

96 97 98 99 100
    if display_graph:
        from .tools.plotting.graph import NodeGraph
        nodegraph = NodeGraph(kat)
        nodegraph.view_pdf()

101
    if simulate:
102 103 104
        # Default flag for showing simulation output. Overridden below as necessary.
        output_to_show = False

105 106
        if xstart is not None or xstop is not None or xsteps is not None or xscale is not None:
            if not has_xaxis:
107 108
                click.echo("Limits can only be overridden when an xaxis is defined in FILE and "
                           "when --noxaxis is unset.", err=True)
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
                sys.exit(1)
            # Override xaxis.
            limits = kat.xaxis.limits
            set_limits = False
            if xstart is not None:
                limits[0] = xstart
                set_limits = True
            if xstop is not None:
                limits[1] = xstop
                set_limits = True
            if xsteps is not None:
                kat.xaxis.steps = xsteps
            if xscale is not None:
                kat.xaxis.scale = xscale
            
            if set_limits:
                kat.xaxis.limits = np.array(limits).astype(float)

127
        if not has_xaxis:
128
            kat.noxaxis = True
129 130 131 132
            if save_figure is not None:
                click.echo("Cannot plot or save figure without an xaxis defined in FILE.",
                           err=True)
                sys.exit(1)
Sean Leavey's avatar
Sean Leavey committed
133

134
        if maxtem is not None:
135
            kat.maxtem = maxtem
136 137 138 139 140
        if phase is not None:
            kat.phase = phase
        if retrace is not None:
            kat.retrace = retrace
        if deriv_h is not None:
141
            kat.deriv_h = deriv_h
142
        if lambda0 is not None:
143
            kat.lambda0 = lambda0
144 145 146 147 148 149
        if print_frequencies:
            kat.parse("frequency")
            output_to_show = True
        if print_noises:
            kat.parse("printnoises")
            output_to_show = True
Sean Leavey's avatar
Sean Leavey committed
150

151 152 153 154 155 156 157 158 159 160
        if trace:
            traceval = 0
            if "all" in trace:
                traceval = 255
            else:
                traceints = {"tem": 1, "cavity": 2, "mismatch": 4, "beams": 8,
                            "gouy": 16, "coupling": 32, "modechanges": 64, "nodes": 128}
                for tracetype in trace:
                    traceval |= traceints[tracetype]
            kat.trace = traceval
161 162
            output_to_show = True

163 164 165 166 167 168
        if powers:
            powerval = 0
            powerints = {"dc": 1, "carrier": 2, "tem00": 4}
            for powertype in powers:
                powerval |= powerints[powertype]
            kat.parse("powers %i" % powerval)
169
            output_to_show = True
170

171
        results = kat.run(save_output=save_output, save_kat=save_input)
172

173
        if output_to_show and results.rundata:
174
            click.echo(results.rundata)
175

176 177
        if has_xaxis and (plot or save_figure is not None):
            results.plot(show=plot, filename=save_figure)
178
        elif not output_to_show and not display_graph:
179
            click.echo("No output requested.")