Skip to content
Snippets Groups Projects
daily.py 28.45 KiB
from lib import *
from lib import CONNECTIONS as C
import numpy as np
from itertools import product
import sys
import time
from pathlib import Path

timestamp = get_timestamp()
print(timestamp)
outdir = DATADIRS.daily.joinpath(timestamp)

comments = """
"""[1:-1]

# FLIR OPTIONS
flir_config = dict(
    exposure_time = 300, # us
    gain = 47.99, # dB
)

# use `t_<...>` for definite times
# use `tau_<...>` for durations and relative timings
# use `B_<...>` for MOT coil servo settings
# use `shims_<direction>` for shim coil settings
# use `det_<...>` for detunings
# use `f_<...>` for absolute frequencies
# use `delta_<name>` for small steps in corresponding parameters
# use ALL_CAPS for arrays
# add a comment for any literal numbers used

## GLOBAL PARAMETERS
reps = 1 # repeat shots for statistics
take_background = False # include a background shot in frame capture
flir_prerelease = True # use the Flir to take a pre-release image
probe_image = True # use the probe beams for recapture imaging, else CMOT beams

## TIMINGS

# timeline (with concurrencies)
#            |                      tau_all                       |
# start | t0 |          tau_ncool           | tau_tof | tau_image | end
#            |                              |         |
#        <tau_comp> | tau_comp_dur          |         |
#            |                     <tau_flir_pre> <tau_flir>
#            |                              |     <tau_andor>
#            | t_ramp | tau_ramp |  <idle>  |  <off>  | <CMOT on if not probe_image>
#            |
#        <tau_ref>

# general sequence timings
t0 = 300e-3 # blue MOT loading time
tau_flux_block = -15e-3 # time relative to t0 to stop atom flux; s
tau_blue_overlap = 2e-3 # overlap time of blue and green beams relative to t0; s
tau_ncool = 100e-3 # narrow cooling/compression time; s
tau_comp = 46e-3 # start compression ramping relative to t0; s
tau_comp_dur = 4e-3 # duration of coil ramp
tau_image = 1.5e-3 # imaging time; s
tau_freqpow = 20e-3 # start of frequency/power ramp after t0; s
tau_freqpow_dur = 30e-3 # frequency/power ramp duration; s

# camera timings
tau_flir_pre = -20e-3 # Flir pre-release image time rel. to end of narrow_cooling; s
tau_flir = +0.05e-3 # Flir post-tof image time rel. to end of tof; s
# tau_flir = -20e-3 # Flir post-tof image time rel. to end of tof; s # used for debugging CMOT
tau_andor = +0e-3 # EMCCD post-tof image time rel. to end of tof; s

# coil settings
B_blue = int(441815) # blue MOT gradient setting
B_green = int(55227) # green MOT gradient setting; 174: 48600
B_comp = 1.8 # compression ramp endpoint multiplier (= B_comp * B_green)
shim_fb = +1.255 # front/back shim; 174:  1.2
shim_lr = +0.165 # left/right shim; 174: -0.2
shim_ud = +0.565 #    up/down shim; 174:  0.4

# CMOT AOM settings
f_freqpow = 90.0 # start of frequency ramp; MHz
p_freqpow_beg = 29.0 # start of power ramp; dBm
p_freqpow_end = 0.0 # end of ramp; dBm
p_image = 23.0 # power for imaging; dBm
p_image_cmot = 20.0 # power for imaging with CMOT beams; dBm

# PARAMETERS
nu_freqpow0 = 3.58 # extent of CMOT frequency ramp; MHz
NU_FREQPOW = np.linspace(3.3, 3.775, 20) # ^
det_image0 = 0.18 # detuning for imaging rel. to AOM-fiber optimal 93.5; MHz
DET_IMAGE = np.arange(-2.2, +3.8, 150e-3) # ^
tau_tof0 = 0.0e-3 # time of flight for free-space imaging; s
TAU_TOF = np.array([0.1e-3, 0.5e-3, 1.0e-3, 2.0e-3, 3.0e-3, 4.0e-3]) # ^
# TAU_TOF = np.array([0.1e-3])

## CONSTANTS AND DERIVED QUANTITIES
freespace_res = 93.68 # AOM RF-equivalent to guessed free-space resonance; MHz
aom_fiber_optim = 93.5 # RF frequency used for AOM+fiber optimization
T_COMP = t0 + tau_comp + np.linspace(0.0, tau_comp_dur, 101) # compression ramp times; s
B_COMP = np.linspace(B_green, B_green * 1.8, T_COMP.shape[0]) # compression ramp coil vals; s
bits_Bset = int(20) # number of bits to send in a servo setting
bits_DACset = int(4) # number of bits to send in a DAC-mode setting
det_block = 10.0 # shift the RF on the MOT beams to decouple the fiber; MHz
f_image0 = aom_fiber_optim + det_image0 # (nominal) CMOT final AOM frequency; MHz
mogramp_N = 1000 # number of steps in the frequency/power ramp
dailies_config = dict(
    probe_image = probe_image,
    CMOT_freq = f_image0,
    CMOT_pow = p_freqpow_end,
)

def make_sequences(meas_type: DailyMeasType, name: str,
        tau_tof: float, det_image: float, nu_freqpow: float) \
    -> (SuperSequence, MOGTable):
    if meas_type in {
        DailyMeasType.TOF,
        DailyMeasType.DET,
        DailyMeasType.CMOT_DET,
    }:
        tau_all = tau_ncool + tau_tof + tau_image # main sequence time; s
        sseq = SuperSequence(
            outdir.joinpath("sequences"),
            name,
            {
                "Scope": (Sequence()
                    + Sequence.digital_pulse(
                        *C.scope_trig,
                        t0,
                        tau_ncool,
                    )
                ).with_color("k"),

                "Load blue MOT": load_blue_mot(
                    outdir,
                    0.0, # start at sequence beginning
                    t0,
                    tau_all,
                    tau_flux_block,
                ).to_sequence().with_color("C0"),

                "Load green MOT": (Sequence()
                    + Sequence.digital_hilo(
                        *C.mot3_green_aom,
                        t0 - 5e-3, # the mogtable is triggered on a falling edge
                        t0
                    )
                    + Sequence([
                        Event.digital1(
                            **C.mot3_green_sh, s=1)
                        @ (t0 - 5e-3) # open shutter ahead of AOM
                    ])
                    + Sequence.serial_bits_c(
                        C.mot3_coils_sig,
                        t0,
                        B_green, bits_Bset,
                        AD5791_DAC, bits_DACset,
                        C.mot3_coils_clk, C.mot3_coils_sync
                    )
                    + Sequence([
                        Event.digital1(**c, s=not c.default)
                            @ (t0 - 4.5e-3 + k * 1e-16) # 4.5ms delay with offset from simultaneity
                        for k, (c, v) in enumerate([
                            (C.shim_coils_p_fb, shim_fb),
                            (C.shim_coils_p_lr, shim_lr),
                            (C.shim_coils_p_ud, shim_ud)
                        ])
                        if v < 0.0
                    ])
                    + Sequence([
                        Event.analog(**c, s=abs(s))
                            @ (t0 + k * 1e-16) # have to offset times from e/o
                        for k, (c, s) in enumerate([
                            (C.shim_coils_fb, shim_fb),
                            (C.shim_coils_lr, shim_lr),
                            (C.shim_coils_ud, shim_ud)
                        ])
                    ])
                ).with_color("C6"),

                "CMOT servo ramp": (Sequence.joinall(*[
                    Sequence.serial_bits_c(
                        C.mot3_coils_sig,
                        t_comp,
                        int(b_comp), bits_Bset,
                        AD5791_DAC, bits_DACset,
                        C.mot3_coils_clk, C.mot3_coils_sync
                    ) for t_comp, b_comp in zip(T_COMP, B_COMP)
                ])).with_color("C1"),

                "Free space": (Sequence()
                    + Sequence.serial_bits_c(
                        C.mot3_coils_sig,
                        t0 + tau_ncool,
                        0, bits_Bset, # turn off to disperse MOT before imaging
                        AD5791_DAC, bits_DACset,
                        C.mot3_coils_clk, C.mot3_coils_sync
                    )
                    + Sequence([
                        Event.analog(**c, s=0.0)
                            @ (t0 + tau_ncool + k * 1e-16) # have to offset times from e/o
                        for k, c in enumerate([
                            C.shim_coils_fb, C.shim_coils_lr, C.shim_coils_ud
                        ])
                    ])
                ).with_color("C8"),

                "Imaging": (Sequence()
                    + (
                        (
                            Sequence.digital_pulse(
                                *C.probe_green_aom,
                                t0 + tau_ncool + tau_tof,
                                tau_image,
                                invert=True
                            ) 
                            + Sequence.digital_pulse(
                                *C.probe_green_sh,
                                0.0,
                                t0 + tau_all
                            )
                        ) if probe_image else Sequence()
                    )
                    + (
                        Sequence.digital_pulse(
                            *C.flir_trig,
                            # Flir needs ~20ms between shots
                            t0 + tau_ncool + min(tau_flir_pre, tau_flir - 20e-3),
                            flir_config["exposure_time"] * 1e-6 # convert us -> s
                        ) if flir_prerelease else Sequence()
                    )
                    + Sequence.digital_pulse(
                        *C.flir_trig,
                        t0 + tau_ncool + tau_tof + tau_flir,
                        flir_config["exposure_time"] * 1e-6 # convert us -> s
                    )
                    + Sequence.digital_pulse(
                        *C.andor_trig,
                        t0 + tau_ncool + tau_tof + tau_andor - 27e-3, # shutter time
                        1e-3 # exposure time is controlled separately
                    )
                ).with_color("C2"),

                "Reset": (Sequence()
                    + Sequence.serial_bits_c(
                        C.mot3_coils_sig,
                        t0 + tau_all,
                        B_blue, bits_Bset,
                        AD5791_DAC, bits_DACset,
                        C.mot3_coils_clk, C.mot3_coils_sync
                    )
                    + Sequence([
                        Event.analog(**c, s=c.default)
                            @ (t0 + tau_all + k * 1e-16) # have to offset times from e/o
                        for k, c in enumerate([
                            C.shim_coils_fb, C.shim_coils_lr, C.shim_coils_ud
                        ])
                    ])
                    + Sequence([
                        Event.digital1(**c, s=c.default)
                            @ (t0 + tau_all - 4.5e-3 + k * 1e-16) # 4.5ms delay with offset from simultaneity
                        for k, (c, v) in enumerate([
                            (C.shim_coils_p_fb, shim_fb),
                            (C.shim_coils_p_lr, shim_lr),
                            (C.shim_coils_p_ud, shim_ud)
                        ])
                        if v < 0.0
                    ])
                ).with_color("C7"),
            },
            CONNECTIONS
        )
    elif meas_type in {
        DailyMeasType.BMOT_NUM,
        DailyMeasType.BMOT_DET,
    }:
        tau_all = flir_config["exposure_time"] * 1e-6 + tau_image
        sseq = SuperSequence(
            outdir.joinpath("sequences"),
            name,
            {
                "Scope": (Sequence()
                    + Sequence.digital_pulse(
                        *C.scope_trig,
                        t0,
                        1e-3, # arbitrary
                    )
                ).with_color("k"),

                "Load blue MOT": load_blue_mot(
                    outdir,
                    0.0, # start at sequence beginning
                    t0,
                    tau_all,
                    tau_flux_block,
                ).to_sequence().with_color("C0"),

                "Free space": (Sequence()
                    + Sequence.serial_bits_c(
                        C.mot3_coils_sig,
                        t0,
                        0, bits_Bset,
                        AD5791_DAC, bits_DACset,
                        C.mot3_coils_clk, C.mot3_coils_sync
                    )
                    + Sequence([
                        Event.analog(**c, s=0.0)
                            @ (t0 + k * 1e-16) # have to offset times from e/o
                        for k, c in enumerate([
                            C.shim_coils_fb, C.shim_coils_lr, C.shim_coils_ud
                        ])
                    ])
                ).with_color("C8"),

                "Imaging": (Sequence()
                    + Sequence.digital_pulse(
                        *C.probe_green_aom,
                        t0 + tau_flir - tau_image / 2.0,
                        tau_all, # account for exposure delay
                        invert=True
                    )
                    + Sequence.digital_pulse(
                        *C.probe_green_sh,
                        0.0,
                        t0 + tau_all
                    )
                    + Sequence.digital_pulse(
                        *C.flir_trig,
                        t0 + tau_flir, # minimal TOF to allow everything to turn off
                        flir_config["exposure_time"] * 1e-6 # convert us -> s
                    )
                ).with_color("C2"),

                "Reset": (Sequence()
                    + Sequence.serial_bits_c(
                        C.mot3_coils_sig,
                        t0 + tau_all,
                        B_blue, bits_Bset,
                        AD5791_DAC, bits_DACset,
                        C.mot3_coils_clk, C.mot3_coils_sync
                    )
                    + Sequence([
                        Event.analog(**c, s=c.default)
                            @ (t0 + tau_all + k * 1e-16) # have to offset times from e/o
                        for k, c in enumerate([
                            C.shim_coils_fb, C.shim_coils_lr, C.shim_coils_ud
                        ])
                    ])
                    + Sequence([
                        Event.digital1(**c, s=c.default)
                            @ (t0 + tau_all - 4.5e-3 + k * 1e-16) # 4.5ms delay with offset from simultaneity
                        for k, (c, v) in enumerate([
                            (C.shim_coils_p_fb, shim_fb),
                            (C.shim_coils_p_lr, shim_lr),
                            (C.shim_coils_p_ud, shim_ud)
                        ])
                        if v < 0.0
                    ])
                ).with_color("C7"),
            },
            CONNECTIONS
        )
    sseq["Sequence"] = Sequence.digital_hilo(*C.dummy, 0.0, sseq.max_time() + 10e-3).with_color("0.25")

    # mogramp_N is the number of steps, not points, so use mogramp_N + 1 for number of points
    MOGRAMP_T = np.linspace(tau_freqpow, tau_freqpow + tau_freqpow_dur, mogramp_N + 1)
    MOGRAMP_F = np.linspace(f_freqpow, f_freqpow + nu_freqpow, mogramp_N + 1)
    MOGRAMP_P = np.linspace(p_freqpow_beg, p_freqpow_end, mogramp_N + 1)
    tab = MOGTable()
    # make sure the frequency/power is right at t0
    tab << MOGEvent(frequency=MOGRAMP_F[0], power=MOGRAMP_P[0]) @ (0.0)
    for t, f, p in zip(MOGRAMP_T, MOGRAMP_F, MOGRAMP_P):
        tab << MOGEvent(frequency=f, power=p) @ t
    # detune and depower the MOT beams for TOF after the CMOT hold
    tab << MOGEvent(frequency=MOGRAMP_F[-1] + det_block, power=-50.0) \
        @ (tau_ncool + 1.7e-3) # unknown source of timing errors
    if not probe_image:
        (tab
            << MOGEvent(frequency=aom_fiber_optim + det_image, power=p_image_cmot)
                @ (tau_ncool + tau_tof + 1.7e-3) # unknown source of timing errors
            << MOGEvent(frequency=aom_fiber_optim + det_image + det_block, power=-50.0)
                @ (tau_ncool + tau_tof + tau_image + 1.7e-3) # unknown source of timing errors
        )

    return sseq, tab

## SCRIPT CONTROLLER
class DailyMeasurement(Controller):
    def precmd(self, *args):
        self.comp = MAIN.connect()
        self.comp.set_defaults()
        if probe_image:
            self.comp.def_digital(*C.probe_green_sh, 1)

        # self.cam = FLIR.connect()
        # self.cam.configure_capture(**flir_config).configure_trigger()

        self.mog = MOGRF.connect()

        self.tb = TIMEBASE.connect()
        if probe_image:
            self.tb.set_frequency(aom_fiber_optim + det_image0).set_amplitude(p_image)

        # pre-construct all unique sequences and mogtables so we con't have to
        #   do it in the main loop

        if self.mode == DailyMeasType.TOF:
            # if doing TOF temperature
            self.names = [
                f"tau-tof={tau_tof:.5f}"
                f"_det-image={det_image0:+.5f}"
                f"_nu-freqpow={nu_freqpow0:+.5f}"
                f"_{rep}"
                for rep, tau_tof in product(range(reps), TAU_TOF)
            ]
            self.ssequences, self.mogtables \
                = zip(*[
                    make_sequences(
                        self.mode,
                        f"tau_tof={tau_tof:.5f}"
                        f"_det-image={det_image0:+.5f}"
                        f"_nu-freqpow={nu_freqpow0:+.5f}",
                        tau_tof,
                        det_image0,
                        nu_freqpow0,
                    ) for tau_tof in TAU_TOF
                ])
            self.sequences = [sseq.to_sequence() for sseq in self.ssequences]

        elif self.mode == DailyMeasType.DET:
            # if doing free-space resonance via CMOT release
            self.names = [
                f"tau-tof={tau_tof0:.5f}"
                f"_det-image={det_image:+.5f}"
                f"_nu-freqpow={nu_freqpow0:+.5f}"
                f"_{rep}"
                for rep, det_image in product(range(reps), DET_IMAGE)
            ]
            self.ssequences, self.mogtables \
                = zip(*[
                    make_sequences(
                        self.mode,
                        f"tau-tof={tau_tof0:.5f}"
                        f"_det-image={det_image:+.5f}"
                        f"_nu-freqpow={nu_freqpow0:+.5f}",
                        tau_tof0,
                        det_image,
                        nu_freqpow0,
                    ) for det_image in DET_IMAGE
                ])
            self.sequences = [sseq.to_sequence() for sseq in self.ssequences]

        elif self.mode == DailyMeasType.CMOT_DET:
            # if doing free-space resonance via CMOT detuning
            self.names = [
                f"tau-tof={tau_tof0:.5f}"
                f"_det-image={det_image0:+.5f}"
                f"_nu-freqpow={nu_freqpow:+.5f}"
                f"_{rep}"
                for rep, nu_freqpow in product(range(reps), NU_FREQPOW)
            ]
            self.ssequences, self.mogtables \
                = zip(*[
                    make_sequences(
                        self.mode,
                        f"tau-tof={tau_tof0:.5f}"
                        f"_det-image={det_image0:+.5f}"
                        f"_nu-freqpow={nu_freqpow:+.5f}",
                        tau_tof0,
                        det_image0,
                        nu_freqpow,
                    ) for nu_freqpow in NU_FREQPOW
                ])
            self.sequences = [sseq.to_sequence() for sseq in self.ssequences]

        elif self.mode == DailyMeasType.BMOT_NUM:
            # if measuring the blue MOT number
            self.names = [
                f"tau-tof={tau_tof0:.5f}"
                f"_det-image={det_image0:+.5f}"
                f"_{rep}"
                for rep in range(reps)
            ]
            self.ssequences, self.mogtables \
                = zip(*[
                    make_sequences(
                        self.mode,
                        f"tau-tof={tau_tof0:.5f}"
                        f"_det-image={det_image0:+.5f}",
                        tau_tof0,
                        det_image0,
                        nu_freqpow0
                    )
                ])
            self.sequences = [sseq.to_sequence() for sseq in self.ssequences]

        elif self.mode == DailyMeasType.BMOT_DET:
            # if doing free-space resonance via blue MOT release
            self.names = [
                f"tau-tof={tau_tof0:.5f}"
                f"_det-image={det_image:+.5f}"
                f"_{rep}"
                for rep, det_image in product(range(reps), DET_IMAGE)
            ]
            self.ssequences, self.mogtables \
                = zip(*[
                    make_sequences(
                        self.mode,
                        f"tau-tof={tau_tof0:.5f}"
                        f"_det-image={det_image:+.5f}",
                        tau_tof0,
                        det_image,
                        nu_freqpow0,
                    ) for det_image in DET_IMAGE
                ])
            self.sequences = [sseq.to_sequence() for sseq in self.ssequences]

        else:
            raise Exception

    def run_sequence(self, *args):
        for rep in range(reps):
            for k, (seq, tab) in enumerate(zip(self.sequences, self.mogtables)):
                if self.mode in {DailyMeasType.DET, DailyMeasType.BMOT_DET}:
                    self.tb.set_frequency(aom_fiber_optim + DET_IMAGE[k])
                (self.mog
                    .set_frequency(1, 90.0).set_power(1, -50.0) # make sure CMOT AOM is off
                    .set_mode(1, "TSB")
                    .table_load(1, tab)
                    .table_arm(1)
                    .set_table_rearm(1, True)
                )
                self.comp.enqueue(seq).run().clear()
                self.mog.table_stop(1).table_clear(1)

        if take_background:
            time.sleep(0.5)
            sseq_bkgd = background_flir(
                outdir.joinpath("sequences"),
                exposure_time=flir_config["exposure_time"] * 1e-6, # convert us -> s
                free_time=100e-3, # no trapping for 100ms
                with_blue_beams=False,
                with_green_beams=False,
                with_probe_beams=False,
            )
            (self.comp
                .enqueue(sseq_bkgd.to_sequence())
                .run()
                .clear()
            )

        self.comp.clear().set_defaults().disconnect()

        (self.mog
            .table_stop(1)
            .table_clear(1)
            .set_frequency(1, 90.0).set_power(1, 29.04)
            .set_frequency(3, aom_fiber_optim + det_image0).set_power(3, p_image)
            .set_frequency(4, aom_fiber_optim + det_image0).set_power(4, p_image)
            .set_mode(1, "NSB")
            .set_output(1, True)
            .disconnect()
        )

    # def run_camera(self, *args):
    #     self.frames = self.cam.acquire_frames(
    #         num_frames=(
    #             len(self.names)
    #             + int(flir_prerelease) * len(self.names)
    #             + int(take_background)
    #         ),
    #         timeout=5, # s
    #         roi=[976, 740, 40, 40]
    #     )
    #     self.cam.disconnect()

    def cmd_run(self, *args):
        run_modes = {
            "temperature": DailyMeasType.TOF,
            "resonance": DailyMeasType.DET,
            "tof_resonance": DailyMeasType.CMOT_DET,
            "blue_mot_number": DailyMeasType.BMOT_NUM,
            "blue_mot_resonance": DailyMeasType.BMOT_DET,
        }
        if len(args) < 1 or args[0] not in run_modes.keys():
            print(
                "Must provide subcommand"
                f"\n  one of {set(run_modes.keys())}"
            )
            sys.exit(0)
        self.mode = run_modes[args[0]]
        global dailies_config
        dailies_config["mode"] = self.mode.name
        self._perform_actions("run_", args[1:])

    def on_error(self, ERR: Exception, *args):
        # try to exit gracefully on error, even if it means this part is
        #   rather dirty
        try:
            self.comp.clear().disconnect()
        except BaseException as err:
            print(f"couldn't disconnect from computer"
                f"\n{type(err).__name__}: {err}")
        # try:
        #     self.cam.disconnect()
        # except AttributeError:
        #     pass
        # except BaseException as err:
        #     print(f"couldn't disconnect from Flir camera"
        #         f"\n{type(err).__name__}: {err}")

        try:
            (self.mog
                .table_stop(1)
                .table_clear(1)
                .set_frequency(1, 90.0).set_power(1, 29.04)
                .set_frequency(3, aom_fiber_optim + det_image0).set_power(3, p_image)
                .set_frequency(4, aom_fiber_optim + det_image0).set_power(4, p_image)
                .set_mode(1, "NSB")
                .set_output(1, True)
                .disconnect()
            )
        except BaseException as err:
            print(f"couldn't reset MOGRF"
                f"\n{type(err).__name__}: {err}")

    def postcmd(self, *args):
        pass
        # names = list()
        # for name in self.names:
        #     if flir_prerelease:
        #         avgimgdir = outdir.joinpath("images").joinpath("averages")
        #         avgimgdir_pre = avgimgdir.joinpath("pre")
        #         avgimgdir_pre.mkdir(parents=True, exist_ok=True)
        #         avgimgdir_post = avgimgdir.joinpath("post")
        #         avgimgdir_post.mkdir(parents=True, exist_ok=True)
        #         name_split = name.split("_")
        #         names.append(str(
        #             Path(avgimgdir_pre.name).joinpath(
        #                 "_".join(name_split[:-1]) + "_pre_" + name_split[-1])
        #         ))
        #         names.append(str(
        #             Path(avgimgdir_post.name).joinpath(
        #                 "_".join(name_split[:-1]) + "_post_" + name_split[-1])
        #         ))
        #     else:
        #         names.append(name)
        # if take_background:
        #     names.append("background")
        # arrays = { name: frame for name, frame in zip(names, self.frames) }
        # data = DailyMeasurementData(
        #     outdir=outdir,
        #     arrays=arrays,
        #     config={ **flir_config, **dailies_config },
        #     comments=comments
        # )
        # try:
        #     data.compute_results(
        #         measurement_type=self.mode,
        #         size_fit=True,
        #         subtract_bkgd=take_background,
        #         debug=False,
        #         mot_number_params={ # for pre-release image
        #             # from measurement on 02.21.22
        #             "intensity_parameter": 2.0 * 3.55 * 10**(p_freqpow_end / 10.0),
        #             # from measurement on 02.15.22
        #             "detuning": abs(f_image0 - freespace_res) * 1e6 * 2.0 * np.pi,
        #         },
        #         N_det_peaks=4,
        #     )
        #     data.save(arrays=True)
        # except Exception as err:
        #     print(
        #         f"[postcmd] encountered exception {type(err).__name__} while processing data:"
        #         f"\n{err}"
        #     )
        #     print("[postcmd] emergency-saving data")
        #     data.save(arrays=True)
        # #data.render_arrays()

    def cmd_visualize(self, *args):
        run_modes = {
            "temperature": DailyMeasType.TOF,
            "resonance": DailyMeasType.DET,
            "tof_resonance": DailyMeasType.CMOT_DET,
            "blue_mot_number": DailyMeasType.BMOT_NUM,
            "blue_mot_resonance": DailyMeasType.BMOT_DET,
        }
        if len(args) < 1 or args[0] not in run_modes.keys():
            print(
                "Must provide subcommand"
                f"\n  one of {set(run_modes.keys())}"
            )
            sys.exit(0)
        self.mode = run_modes[args[0]]
        if self.mode == DailyMeasType.TOF:
            sseq, tab = make_sequences(self.mode, "", TAU_TOF.max(), det_image0, nu_freqpow0)
        elif self.mode == DailyMeasType.DET:
            sseq, tab = make_sequences(self.mode, "", tau_tof0, DET_IMAGE.max(), nu_freqpow0)
        elif self.mode == DailyMeasType.CMOT_DET:
            sseq, tab = make_sequences(self.mode, "", tau_tof0, det_image0, NU_FREQPOW.max())
        elif self.mode == DailyMeasType.BMOT_NUM:
            sseq, tab = make_sequences(self.mode, "", tau_tof0, det_image0, nu_freqpow0)
        elif self.mode == DailyMeasType.BMOT_DET:
            sseq, tab = make_sequences(self.mode, "", tau_tof0, DET_IMAGE.max(), nu_freqpow0)
        try:
            tmin, tmax = float(args[1]), float(args[2])
        except IndexError:
            tmin, tmax = sseq.min_time(), sseq.max_time()
        sseq.draw_detailed(
            mogtables=[
                ( tab.with_color("C6"), dict(name="Green MOT AOM", offset=t0) ),
            ] if self.mode not in {
                DailyMeasType.BMOT_NUM,
                DailyMeasType.BMOT_DET,
            } else list()
        ).set_xlim(tmin, tmax).show()
        sys.exit(0)

if __name__ == "__main__":
    DailyMeasurement().RUN()