m-labs / artiq

A leading-edge control system for quantum information experiments
https://m-labs.hk/artiq
GNU Lesser General Public License v3.0
434 stars 201 forks source link

gui plotting: plots break, gui configuration not restored on restart #158

Closed ghost closed 8 years ago

ghost commented 9 years ago

Setup plotting commonhist1* as histogram and default_brightmean* as xy plot. Start and stop both the master and gui several times. Observed behavior

std_include.py

from artiq import *
import numpy as np
from scipy.optimize import curve_fit
import time
import logging

class StdCool(HasEnvironment):
    """Standard cooling and state perparation
    """
    def build(self):
        self.core = self.get_device("core")
        self.doppler_sw = self.get_device("doppler_sw")
        self.repump_sw = self.get_device("repump_sw")
        self.led = self.get_device("led")

        gui_group = "Standard Cool"
        self.cool_t = self.get_argument("cool_t",
                           NumberValue(default=3e-3, unit="ms", scale=1e-3,
                                       step=1e-3, ndecimals=0,
                                       min=100e-6, max=1), gui_group)
        self.repump_t = self.get_argument("repump_t",
                           NumberValue(1e-3, unit="ms", scale=1e-3, step=1e-3,
                                       ndecimals=0, min=0, max=1), gui_group)

    @kernel
    def go(self):
        """cooling and repumping
        """
        with parallel:
            self.led.on()
            self.doppler_sw.on()
            self.repump_sw.on() 
            delay(self.cool_t)
            self.doppler_sw.off()
            delay(self.repump_t)
            self.repump_sw.off()
            self.led.off()

class StdDetect(HasEnvironment):
    """state detection
    """
    def build(self):
        self.core = self.get_device("core")
        self.doppler_sw = self.get_device("doppler_sw")
        self.repump_sw = self.get_device("repump_sw")
        self.led = self.get_device("led")
        self.sideview_pmt = self.get_device("sideview_pmt")

        gui_group = "Standard Detect"
        self.hist_nbins = self.get_argument("hist_nbins",
                           NumberValue(60, step=10, ndecimals=0, min=0),
                           gui_group)
        self.hist_nmax = self.get_argument("hist_nmax",
                           NumberValue(200, step=10, ndecimals=0,
                                       min=10), gui_group)
        self.nreps = self.get_argument("nreps",
                           NumberValue(100, step=10, ndecimals=0, min=2,
                                       max=1000), gui_group)
        self.detect_t = self.get_argument("detect_t",
                           NumberValue(1e-3, unit="ms", scale=1e-3, step=1e-3,
                                       ndecimals=0, min=0, max=1), gui_group)

    @kernel
    def rep(self):
        """measurement; single experiment repetition
        """
        with parallel:
            self.led.pulse(self.detect_t)
            self.doppler_sw.pulse(self.detect_t)
            self.sideview_pmt.gate_rising(self.detect_t)
        cts = self.sideview_pmt.count()
        self.counts[self.rep_i] = cts
        self.rep_i += 1

    @kernel
    def rep_done(self):
        """call at conclusion of a set of identical experiment reps
        """
        return self.counts

    @kernel
    def rep_start(self):
        """initialize count buffer
        """
        self.rep_i = 0
        self.counts = [0 for _ in range(int(self.nreps))]

    def hist_rpc(self, counts):
        """update histogram in GUI
        """
        hist, hist_bins = np.histogram(counts, self.hist_nbins,
            range=(0, self.hist_nmax))
        hist = hist.tolist()
        hist_bins = hist_bins.tolist()
        # update histogram
        self.set_dataset("common_hist1_bins", hist_bins,
                         broadcast=True, persist=True, save=False)
        self.set_dataset("common_hist1_counts", hist,
                         broadcast=True, persist=True, save=False)
        self.set_dataset("detect_bright_mean", float(np.mean(counts)),
                         broadcast=True, persist=True, save=False)
        # update timeseries

        def stripchart_roll(xs, x0):
            xsnp = np.roll(np.array(xs), -1)
            xsnp[-1] = float(x0)
            return xsnp
        # I only want to run these one to initialize the dataset.
        # They could reside in program file that I only run as needed to init things.
        # For now I'll just comment them out after the first run.
        self.set_dataset("default_bright_mean_strip_x", [int(time.time())]*100,
                         broadcast=True, persist=True, save=False)
        self.set_dataset("default_bright_mean_strip_y", [float(0)]*100,
                         broadcast=True, persist=True, save=False)
        x = self.get_dataset("default_bright_mean_strip_x")
        y = self.get_dataset("default_bright_mean_strip_y")
        y = stripchart_roll(y, np.mean(counts))
        x = stripchart_roll(x, int(time.time()))
        self.set_dataset("default_bright_mean_strip_x", x, broadcast=True)
        self.set_dataset("default_bright_mean_strip_y", y, broadcast=True)

    def hist_model(n, mean):
        return mean**n*np.exp(-1*mean)/np.math.factorial(n)

    def sim_nreps(self):
        # add small random walk to mean for dramatic effect
        bright_mean = self.get_dataset('detect_bright_mean')
        mean = bright_mean + np.random.normal(loc=0, scale=3)

        return np.random.poisson(abs(mean), size=self.nreps)

default_std.py

from artiq import *
from artiq.coredevice.runtime_exceptions import RTIOUnderflow
import numpy as np
import time
import std_include
import logging

def print_underflow():
    print("Joe's RTIO underflow occured")

class DefaultStd(EnvExperiment):
    """default experiment using std_include

    Default experiment that runs at priority 0. Cooling, histogram.
    """

    def build(self):
        self.core = self.get_device("core")
        self.scheduler = self.get_device("scheduler")
        self.std_cool = std_include.StdCool(parent=self)
        self.no_cool_t = self.get_argument("no_cool_t",
                           NumberValue(default=10e-3, unit="ms", scale=1e-3,
                                       min=0, max=200e-3,
                                       ndecimals=0, step=5e-3))
        self.sim = self.get_argument("simulate ions",
                                     BooleanValue(default=True))
        self.std_detect = std_include.StdDetect(parent=self)

    @kernel
    def run_kernel(self):
        while True:
            self.detect.rep_start()
            for i in range(int(self.detect.nreps)):
                self.core.break_realtime()
                self.std_cool.go()
                # experiment meat would go here if this were a fancy experiment
                self.detect.rep()
                delay(self.no_cool_t)
            counts = self.detect.rep_done()
            self.hist_rpc(counts)
            self.scheduler.pause()

    def run_sim(self):
        while True:
            counts = self.std_detect.sim_nreps()
            self.std_detect.hist_rpc(counts)
            t_one_rep = self.std_cool.cool_t + self.std_cool.repump_t + \
                        self.no_cool_t + self.std_detect.detect_t
            time.sleep(t_one_rep*self.std_detect.nreps)
            self.scheduler.pause()

    def run(self):
        try:
            logging.debug("run()")
            if self.sim:
                self.run_sim()
            else:
                self.run_kernel()

        except TerminationRequested:
            logging.info("Terminated gracefully")
ghost commented 9 years ago

How I start the ARTIQ stuff.

(py35)rabi@688penningA:~/gitlab/nistpenning/artiq$ cat start.bash
#!/bin/bash 
pkill artiq 
source ~/.bashrc 
cd ~/gitlab/nistpenning/artiq
source activate py35
artiq_master --bind 688penninga.bw.nist.gov --log-file master_log.txt&
artiq_ctlmgr --bind 688penninga.bw.nist.gov --server 688penninga.bw.nist.gov&
artiq_gui --server 688penninga.bw.nist.gov&
artiq_influxdb --user-db rabi --password-db cos^2+sin^2=1 --database artiq_penning --bind 688penninga.bw.nist.gov --server-master 688penninga.bw.nist.gov&
ghost commented 9 years ago

Run with "simulate ions" checked. The @kernel code crud and not needed to exhibit the problems with the GUI.

sbourdeauducq commented 9 years ago

What do you mean by "real-time update of datasets breaks upon stop and restart"?

sbourdeauducq commented 9 years ago

The rest looks like a pyqtgraph dock bug (which doesn't happen frequently here). Can you comment out this line (which will disable dock layout save/restore) and see if the problem still happens: https://github.com/m-labs/artiq/blob/30842a71743f9fdfe0c7c5aa997c994bbb724326/artiq/frontend/artiq_gui.py#L81

ghost commented 9 years ago

OK. I figured this problem out and the GUI is beautifully stable! The root of the problem lies with initializing new dataset entries. I propose making default a required argument for get_dataset(key, default).

https://github.com/m-labs/artiq/blob/master/artiq/language/environment.py#L224

That way there's always a well-defined result from get_dataset().

sbourdeauducq commented 9 years ago

I don't understand. The GUI does not use get_dataset. If get_dataset raised an exception in your experiment due to the dataset not being present, this should not crash the GUI.

sbourdeauducq commented 9 years ago

Is that different from #104?

ghost commented 9 years ago

I will look at this again over the weekend.

On Tue, Oct 27, 2015 at 7:55 AM, Sébastien Bourdeauducq < notifications@github.com> wrote:

Is that different from #104 https://github.com/m-labs/artiq/issues/104?

— Reply to this email directly or view it on GitHub https://github.com/m-labs/artiq/issues/158#issuecomment-151503626.