Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 407477bc5adf
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: d95a9cac9a23
Choose a head ref
  • 2 commits
  • 23 files changed
  • 1 contributor

Commits on Mar 8, 2015

  1. Copy the full SHA
    f2e3dfb View commit details
  2. Copy the full SHA
    d95a9ca View commit details
1 change: 1 addition & 0 deletions artiq/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from artiq.language.core import *
from artiq.language.experiment import Experiment
from artiq.language.db import *
from artiq.language.units import check_unit
from artiq.language.units import ps, ns, us, ms, s
18 changes: 10 additions & 8 deletions artiq/frontend/artiq_client.py
Original file line number Diff line number Diff line change
@@ -40,12 +40,13 @@ def get_argparser():
parser_add.add_argument(
"-t", "--timeout", default=None, type=float,
help="specify a timeout for the experiment to complete")
parser_add.add_argument("-u", "--unit", default=None,
help="unit to run")
parser_add.add_argument("-e", "--experiment", default=None,
help="experiment to run")
parser_add.add_argument("--rtr-group", default=None, type=str,
help="real-time result group "
"(defaults to filename)")
parser_add.add_argument("file", help="file containing the unit to run")
parser_add.add_argument("file",
help="file containing the experiment to run")
parser_add.add_argument("arguments", nargs="*",
help="run arguments")

@@ -103,7 +104,7 @@ def _action_submit(remote, args):

run_params = {
"file": args.file,
"unit": args.unit,
"experiment": args.experiment,
"timeout": args.timeout,
"arguments": arguments,
"rtr_group": args.rtr_group if args.rtr_group is not None \
@@ -147,10 +148,11 @@ def _action_del_parameter(remote, args):
def _show_queue(queue):
clear_screen()
if queue:
table = PrettyTable(["RID", "File", "Unit", "Timeout", "Arguments"])
table = PrettyTable(["RID", "File", "Experiment", "Timeout",
"Arguments"])
for rid, run_params in queue:
row = [rid, run_params["file"]]
for x in run_params["unit"], run_params["timeout"]:
for x in run_params["experiment"], run_params["timeout"]:
row.append("" if x is None else x)
row.append(format_arguments(run_params["arguments"]))
table.add_row(row)
@@ -162,13 +164,13 @@ def _show_queue(queue):
def _show_timed(timed):
clear_screen()
if timed:
table = PrettyTable(["Next run", "TRID", "File", "Unit",
table = PrettyTable(["Next run", "TRID", "File", "Experiment",
"Timeout", "Arguments"])
sp = sorted(timed.items(), key=lambda x: (x[1][0], x[0]))
for trid, (next_run, run_params) in sp:
row = [time.strftime("%m/%d %H:%M:%S", time.localtime(next_run)),
trid, run_params["file"]]
for x in run_params["unit"], run_params["timeout"]:
for x in run_params["experiment"], run_params["timeout"]:
row.append("" if x is None else x)
row.append(format_arguments(run_params["arguments"]))
table.add_row(row)
57 changes: 30 additions & 27 deletions artiq/frontend/artiq_run.py
Original file line number Diff line number Diff line change
@@ -3,13 +3,13 @@
import argparse
import sys
import time
from inspect import isclass
from operator import itemgetter
from itertools import chain

import h5py

from artiq.language.db import *
from artiq.language.experiment import is_experiment
from artiq.protocols import pyon
from artiq.protocols.file_db import FlatFileDB
from artiq.master.worker_db import DBHub, ResultDB
@@ -68,15 +68,15 @@ def get_argparser():
parser.add_argument("-p", "--pdb", default="pdb.pyon",
help="parameter database file")

parser.add_argument("-e", "--elf", default=False, action="store_true",
parser.add_argument("-E", "--elf", default=False, action="store_true",
help="run ELF binary")
parser.add_argument("-u", "--unit", default=None,
help="unit to run")
parser.add_argument("-e", "--experiment", default=None,
help="experiment to run")
parser.add_argument("-o", "--hdf5", default=None,
help="write results to specified HDF5 file"
" (default: print them)")
parser.add_argument("file",
help="file containing the unit to run")
help="file containing the experiment to run")
parser.add_argument("arguments", nargs="*",
help="run arguments")

@@ -98,34 +98,38 @@ def main():
ddb = FlatFileDB(args.ddb)
pdb = FlatFileDB(args.pdb)
pdb.hooks.append(SimpleParamLogger())
rdb = ResultDB(set())
rdb = ResultDB(lambda description: None, lambda mod: None)
dbh = DBHub(ddb, pdb, rdb)
try:
if args.elf:
if args.arguments:
print("Run arguments are not supported in ELF mode")
sys.exit(1)
unit_inst = ELFRunner(dps)
unit_inst.run(args.file)
exp_inst = ELFRunner(dps)
exp_inst.run(args.file)
else:
module = file_import(args.file)
if args.unit is None:
units = [(k, v) for k, v in module.__dict__.items()
if isclass(v) and hasattr(v, "__artiq_unit__")]
l = len(units)
if args.experiment is None:
exps = [(k, v) for k, v in module.__dict__.items()
if is_experiment(v)]
l = len(exps)
if l == 0:
print("No units found in module")
print("No experiments found in module")
sys.exit(1)
elif l > 1:
print("More than one unit found in module:")
for k, v in sorted(units, key=itemgetter(0)):
print(" {} ({})".format(k, v.__artiq_unit__))
print("Use -u to specify which unit to use.")
print("More than one experiment found in module:")
for k, v in sorted(experiments, key=itemgetter(0)):
if v.__doc__ is None:
print(" {}".format(k))
else:
print(" {} ({})".format(
k, v.__doc__.splitlines()[0].strip()))
print("Use -u to specify which experiment to use.")
sys.exit(1)
else:
unit = units[0][1]
exp = exps[0][1]
else:
unit = getattr(module, args.unit)
exp = getattr(module, args.experiment)

try:
arguments = _parse_arguments(args.arguments)
@@ -135,17 +139,16 @@ def main():

run_params = {
"file": args.file,
"unit": args.unit,
"experiment": args.experiment,
"timeout": None,
"arguments": arguments
}
unit_inst = unit(dbh,
scheduler=DummyScheduler(),
run_params=run_params,
**run_params["arguments"])
unit_inst.run()
if hasattr(unit_inst, "analyze"):
unit_inst.analyze()
exp_inst = exp(dbh,
scheduler=DummyScheduler(),
run_params=run_params,
**run_params["arguments"])
exp_inst.run()
exp_inst.analyze()

if args.hdf5 is not None:
f = h5py.File(args.hdf5, "w")
2 changes: 1 addition & 1 deletion artiq/gui/explorer.py
Original file line number Diff line number Diff line change
@@ -146,7 +146,7 @@ def run(self, widget):
arguments = self.controls.get_arguments()
run_params = {
"file": data["file"],
"unit": data["unit"],
"experiment": data["experiment"],
"timeout": None,
"arguments": arguments,
"rtr_group": data["file"]
8 changes: 4 additions & 4 deletions artiq/gui/scheduler.py
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ class _QueueStoreSyncer(ListSyncer):
def convert(self, x):
rid, run_params = x
row = [rid, run_params["file"]]
for e in run_params["unit"], run_params["timeout"]:
for e in run_params["experiment"], run_params["timeout"]:
row.append("" if e is None else str(e))
row.append(format_arguments(run_params["arguments"]))
return row
@@ -27,7 +27,7 @@ def convert(self, trid, x):
next_run, run_params = x
row = [time.strftime("%m/%d %H:%M:%S", time.localtime(next_run)),
trid, run_params["file"]]
for e in run_params["unit"], run_params["timeout"]:
for e in run_params["experiment"], run_params["timeout"]:
row.append("" if e is None else str(e))
row.append(format_arguments(run_params["arguments"]))
return row
@@ -57,7 +57,7 @@ def __init__(self, schedule_ctl, **kwargs):

self.queue_store = Gtk.ListStore(int, str, str, str, str)
self.queue_tree = Gtk.TreeView(self.queue_store)
for i, title in enumerate(["RID", "File", "Unit", "Timeout", "Arguments"]):
for i, title in enumerate(["RID", "File", "Experiment", "Timeout", "Arguments"]):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(title, renderer, text=i)
self.queue_tree.append_column(column)
@@ -81,7 +81,7 @@ def __init__(self, schedule_ctl, **kwargs):

self.timed_store = Gtk.ListStore(str, int, str, str, str, str)
self.timed_tree = Gtk.TreeView(self.timed_store)
for i, title in enumerate(["Next run", "TRID", "File", "Unit",
for i, title in enumerate(["Next run", "TRID", "File", "Experiment",
"Timeout", "Arguments"]):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(title, renderer, text=i)
25 changes: 5 additions & 20 deletions artiq/language/db.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
"""
Connection to device, parameter and result database.
"""

class _AttributeKind:
pass


class Device(_AttributeKind):
"""Represents a device for ``AutoDB`` to process.
"""
"""Represents a device for ``AutoDB`` to process."""
pass


class NoDefault:
"""Represents the absence of a default value for ``Parameter``
and ``Argument``.
"""
pass

@@ -28,7 +24,6 @@ class Parameter(_AttributeKind):
:param default: Default value of the parameter to be used if not found
in the database.
"""
def __init__(self, default=NoDefault):
self.default = default
@@ -40,16 +35,13 @@ class Argument(_AttributeKind):
:param default: Default value of the argument to be used if not specified
at instance creation.
"""
def __init__(self, default=NoDefault):
self.default = default


class Result(_AttributeKind):
"""Represents a result for ``AutoDB`` to process.
"""
"""Represents a result for ``AutoDB`` to process."""
pass


@@ -63,14 +55,11 @@ class AutoDB:
:param dbh: database hub to use. If ``None``, all devices and parameters
must be supplied as keyword arguments, and reporting results and
modifying parameters is not supported.
"""
class DBKeys:
pass

@staticmethod
def realtime_results():
return dict()
realtime_results = dict()

def __init__(self, dbh=None, **kwargs):
self.dbh = dbh
@@ -92,8 +81,9 @@ def __init__(self, dbh=None, **kwargs):
except KeyError:
raise KeyError("Device '{}' not found".format(k))
object.__setattr__(self, k, dev)

self.build()
if self.dbh is not None:
self.dbh.init_results(self.realtime_results)

def __getattr__(self, name):
ak = getattr(self.DBKeys, name)
@@ -130,16 +120,11 @@ def __setattr__(self, name, value):
else:
raise ValueError

@classmethod
def get_realtime_results():
return dict()

def build(self):
"""This is called by ``__init__`` after the parameter initialization
is done.
The user may overload this method to complete the object's
initialization with all parameters available.
"""
pass
40 changes: 40 additions & 0 deletions artiq/language/experiment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from inspect import isclass


class Experiment:
"""Base class for experiments.
Deriving from this class enables automatic experiment discovery in
Python modules.
"""
def run(self):
"""The main entry point of the experiment.
This method must be overloaded by the user to implement the main
control flow of the experiment.
"""
raise NotImplementedError

def analyze(self):
"""Entry point for analyzing the results of the experiment.
This method may be overloaded by the user to implement the analysis
phase of the experiment, for example fitting curves.
Splitting this phase from ``run`` enables tweaking the analysis
algorithm on pre-existing data, and CPU-bound analyses to be run
overlapped with the next experiment in a pipelined manner.
This method must not interact with the hardware.
"""
pass


def has_analyze(experiment):
"""Checks if an experiment instance overloaded its ``analyze`` method."""
return experiment.analyze.__func__ is not Experiment.analyze


def is_experiment(o):
"""Checks if a Python object is an instantiable experiment."""
return isclass(o) and issubclass(o, Experiment) and o is not Experiment
14 changes: 10 additions & 4 deletions artiq/master/repository.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import os
from inspect import isclass

from artiq.protocols.sync_struct import Notifier
from artiq.tools import file_import
from artiq.language.experiment import is_experiment


def scan_experiments():
@@ -14,13 +14,19 @@ def scan_experiments():
except:
continue
for k, v in m.__dict__.items():
if isclass(v) and hasattr(v, "__artiq_unit__"):
if is_experiment(v):
if v.__doc__ is None:
name = k
else:
name = v.__doc__.splitlines()[0].strip()
if name[-1] == ".":
name = name[:-1]
entry = {
"file": os.path.join("repository", f),
"unit": k,
"experiment": k,
"gui_file": getattr(v, "__artiq_gui_file__", None)
}
r[v.__artiq_unit__] = entry
r[name] = entry
return r


Loading