diff --git a/.gitattributes b/.gitattributes
index 1bccc1fa..201c7c94 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,3 @@
*.h5 filter=lfs diff=lfs merge=lfs -text
+*.aps2 filter=lfs diff=lfs merge=lfs -text
+*.aps1 filter=lfs diff=lfs merge=lfs -text
diff --git a/.gitignore b/.gitignore
index fcfad9a8..7150e5b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,5 @@
*.h5
*.py~
*.py#
+*.egg-info
+QGL.egg-info/
diff --git a/.travis.yml b/.travis.yml
index 6e781a45..d8a7fa46 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,10 @@
language: python
python:
- - 3.5
+ - 3.6
+env:
+ - CONDA_TYPE=miniconda CONDA_VERS=https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
+ - CONDA_TYPE=miniconda CONDA_VERS=https://repo.continuum.io/miniconda/Miniconda3-4.5.11-Linux-x86_64.sh
before_install:
# install git lfs and fetch test data
@@ -22,11 +25,11 @@ install:
# We do this conditionally because it saves us some downloading if the
# version is the same.
- - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
+ - echo "Using $CONDA_TYPE"
+ - wget $CONDA_VERS -O miniconda.sh
+ - bash miniconda.sh -h | sed '4q;d'
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- - export BBN_MEAS_FILE="$PWD/tests/test_measure.yml"
- - echo "Measure file at $BBN_MEAS_FILE"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
@@ -34,10 +37,12 @@ install:
- conda info -a
# Create conda environment with dependencies
- - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy bokeh h5py jupyter scipy networkx future
+ - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy sqlalchemy jupyter scipy networkx
- source activate test-environment
- - conda install -c ecpy atom;
- - pip install watchdog coveralls
+ - pip install coveralls
+ - pip install bqplot
+ - pip install git+https://github.com/BBN-Q/bbndb.git
+ - if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then pip install pygsti; fi
script:
- coverage run -m unittest discover
diff --git a/QGL.egg-info/PKG-INFO b/QGL.egg-info/PKG-INFO
new file mode 100644
index 00000000..ac9daf85
--- /dev/null
+++ b/QGL.egg-info/PKG-INFO
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: QGL
+Version: 2.1
+Summary: UNKNOWN
+Home-page: https://github.com/BBN-Q/QGL
+Author: UNKNOWN
+Author-email: UNKNOWN
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/QGL.egg-info/SOURCES.txt b/QGL.egg-info/SOURCES.txt
new file mode 100644
index 00000000..945e4a89
--- /dev/null
+++ b/QGL.egg-info/SOURCES.txt
@@ -0,0 +1,41 @@
+README.md
+QGL/BlockLabel.py
+QGL/ChannelLibraries.py
+QGL/Channels.py
+QGL/Cliffords.py
+QGL/Compiler.py
+QGL/ControlFlow.py
+QGL/GSTTools.py
+QGL/PatternUtils.py
+QGL/Plotting.py
+QGL/PulsePrimitives.py
+QGL/PulseSequencePlotter.py
+QGL/PulseSequencer.py
+QGL/PulseShapes.py
+QGL/Scheduler.py
+QGL/TdmInstructions.py
+QGL/Tomography.py
+QGL/__init__.py
+QGL/config.py
+QGL/config_location.py
+QGL/mm.py
+QGL.egg-info/PKG-INFO
+QGL.egg-info/SOURCES.txt
+QGL.egg-info/dependency_links.txt
+QGL.egg-info/requires.txt
+QGL.egg-info/top_level.txt
+QGL/BasicSequences/AllXY.py
+QGL/BasicSequences/BlankingSweeps.py
+QGL/BasicSequences/CR.py
+QGL/BasicSequences/Decoupling.py
+QGL/BasicSequences/Feedback.py
+QGL/BasicSequences/FlipFlop.py
+QGL/BasicSequences/RB.py
+QGL/BasicSequences/Rabi.py
+QGL/BasicSequences/SPAM.py
+QGL/BasicSequences/T1T2.py
+QGL/BasicSequences/__init__.py
+QGL/BasicSequences/helpers.py
+QGL/drivers/APS2Pattern.py
+QGL/drivers/APSPattern.py
+QGL/drivers/__init__.py
\ No newline at end of file
diff --git a/QGL.egg-info/dependency_links.txt b/QGL.egg-info/dependency_links.txt
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/QGL.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/QGL.egg-info/requires.txt b/QGL.egg-info/requires.txt
new file mode 100644
index 00000000..2aa45f83
--- /dev/null
+++ b/QGL.egg-info/requires.txt
@@ -0,0 +1,6 @@
+bbndb>=0.1
+numpy>=1.11.1
+scipy>=0.17.1
+networkx>=1.11
+bqplot>=0.11.5
+sqlalchemy>=1.2.17
diff --git a/QGL.egg-info/top_level.txt b/QGL.egg-info/top_level.txt
new file mode 100644
index 00000000..0e533603
--- /dev/null
+++ b/QGL.egg-info/top_level.txt
@@ -0,0 +1 @@
+QGL
diff --git a/QGL/APS2CustomInstructions.py b/QGL/APS2CustomInstructions.py
new file mode 100644
index 00000000..971bd16b
--- /dev/null
+++ b/QGL/APS2CustomInstructions.py
@@ -0,0 +1,86 @@
+'''
+Copyright 2019 Raytheon BBN Technologies
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+
+# Instructions for the the prototype APS2-TDM hardware.
+
+from .TdmInstructions import CustomInstruction, WriteAddr, Invalidate, LoadCmpVram
+from .ControlFlow import LoadCmp, Call
+
+##custom APS OP_CODES
+#APS_CLIFFORD_SET_SEED: Set 32 bit seed for random number generator
+#APS_CLIFFORD_SET_OFFSET: Stores jump table starting offset
+#APS_CLIFFORD_SET_SPACING: Stores jump table spacing (integer to shift left),
+# including interal address representation
+#APS_CLIFFORD_INVERSE_RESET: Reset inverse tracker
+#APS_CLIFFORD_RAND: Choose randomly from set of 24 waveforms,
+# returns starting address of jump table entry from RAM
+#APS_CLIFFORD_INVERSE: Store waveform address of inverse waveform to be jumped to
+
+APS2_CUSTOM = {"APS_RAND": 0,
+ "APS_CLIFFORD_RAND": 2,
+ "APS_CLIFFORD_INVERSE": 6,
+ "APS_CLIFFORD_INVERSE_RESET": 7,
+ "APS_CLIFFORD_SET_SEED": 3,
+ "APS_CLIFFORD_SET_OFFSET": 4,
+ "APS_CLIFFORD_SET_SPACING": 5}
+
+APS2_CUSTOM_DECODE = {v: k for k, v in APS2_CUSTOM.items()}
+
+##Note that the expected call pattern for the randomizer is:
+
+# APS_CLIFFORD_RAND / APS_CLIFFORD_INVERSE
+# LOADCMP
+# CALL
+
+def RandomCliffordSetOffset(addr, offset):
+ return [Invalidate(addr, 0, tdm=False),
+ WriteAddr(addr, offset, tdm=False),
+ LoadCmpVram(addr, 0xFFFFFFFF, tdm=False), #
+ CustomInstruction("APS_CLIFFORD_SET_OFFSET", addr, 0xA),
+ LoadCmpVram(0xA, 0xFFFFFFFF, tdm=False)]
+
+def RandomCliffordSetSpacing(addr, spacing):
+ return [Invalidate(addr, 0, tdm=False),
+ WriteAddr(addr, spacing, tdm=False),
+ LoadCmpVram(addr, 0xFFFFFFFF, tdm=False),
+ CustomInstruction("APS_CLIFFORD_SET_SPACING", addr, 0xA),
+ LoadCmpVram(0xA, 0xFFFFFFFF, tdm=False)]
+
+def RandomClifford(target, addr):
+ return [Invalidate(addr, 0, tdm=False),
+ CustomInstruction("APS_CLIFFORD_RAND", 0x0, addr),
+ LoadCmpVram(addr, 0xFFFFFFFF, tdm=False),
+ Call(target, indirect=True)]
+
+def RandomCliffordInverse(target, addr):
+ return [Invalidate(addr, 0, tdm=False),
+ CustomInstruction("APS_CLIFFORD_INVERSE", 0x0, addr),
+ LoadCmpVram(addr, 0xFFFFFFFF, tdm=False),
+ Call(target, indirect=True)]
+
+def RandomCliffordInverseReset(val=0x0, addr=0xD): #for now don't use addr
+ return [Invalidate(addr, 0, tdm=False),
+ WriteAddr(addr, val, tdm=False),
+ LoadCmpVram(addr, 0xFFFFFFFF, tdm=False),
+ CustomInstruction("APS_CLIFFORD_INVERSE_RESET", addr, 0xA),
+ LoadCmpVram(0xA, 0xFFFFFFFF, tdm=False)]
+
+def RandomCliffordSeed(seed):
+ return [Invalidate(0xB, 0, tdm=False),
+ WriteAddr(0xB, seed, tdm=False),
+ LoadCmpVram(0xB, 0xFFFFFFFF, tdm=False),
+ CustomInstruction("APS_CLIFFORD_SET_SEED", 0xB, 0xA),
+ LoadCmpVram(0xA, 0xFFFFFFFF, tdm=False)]
diff --git a/QGL/BasicSequences/Feedback.py b/QGL/BasicSequences/Feedback.py
index b7833556..6efabbfe 100644
--- a/QGL/BasicSequences/Feedback.py
+++ b/QGL/BasicSequences/Feedback.py
@@ -124,8 +124,8 @@ def BitFlip3(data_qs, ancilla_qs, theta=None, phi=None, nrounds=1, meas_delay=1e
raise Exception("Wrong number of qubits")
seqs = [
DecodeSetRounds(1,0,nrounds),
- Invalidate(addr=10, mask=2*nrounds),
- Invalidate(addr=11, mask=0x1)]
+ Invalidate(10, 2*nrounds),
+ Invalidate(11, 0x1)]
# encode single-qubit state into 3 qubits
if theta and phi:
@@ -153,7 +153,7 @@ def BitFlip3(data_qs, ancilla_qs, theta=None, phi=None, nrounds=1, meas_delay=1e
if docals:
seqs += create_cal_seqs(qubits,
calRepeats)
- metafile = compile_to_hardware(seqs, 'BitFlip/BitFlip')
+ metafile = compile_to_hardware(seqs, 'BitFlip/BitFlip', tdm_seq=True)
return metafile
def MajorityVoteN(qubits, nrounds, prep=[], meas_delay=1e-6, docals=False, calRepeats=2):
@@ -172,9 +172,9 @@ def MajorityVoteN(qubits, nrounds, prep=[], meas_delay=1e-6, docals=False, calRe
metafile : metafile path
"""
nqubits = len(qubits)
- seqs = [MajorityMask(nrounds*nqubits),
- Invalidate(addr=10, mask=nrounds*nqubits),
- Invalidate(addr=11, mask=1)]
+ seqs = [MajorityMask(1, 0, nrounds*nqubits),
+ Invalidate(10, nrounds*nqubits),
+ Invalidate(11, 1)]
if prep:
seqs += [reduce(operator.mul, [X(q) for n,q in enumerate(qubits) if prep[n]])]
for n in range(nrounds):
@@ -187,5 +187,4 @@ def MajorityVoteN(qubits, nrounds, prep=[], meas_delay=1e-6, docals=False, calRe
if docals:
seqs += create_cal_seqs(qubits,
calRepeats)
- metafile = compile_to_hardware(seqs, 'MajorityVote/MajorityVote')
- return metafile
+ metafile = compile_to_hardware(seqs, 'MajorityVote/MajorityVote', tdm_seq=True)
diff --git a/QGL/BasicSequences/Rabi.py b/QGL/BasicSequences/Rabi.py
index 3acb5329..c65028b2 100644
--- a/QGL/BasicSequences/Rabi.py
+++ b/QGL/BasicSequences/Rabi.py
@@ -108,6 +108,8 @@ def RabiAmp_NQubits(qubits,
if docals:
seqs += create_cal_seqs(qubits, calRepeats, measChans=measChans)
+ else:
+ calRepeats = 0
axis_descriptor = [
{
diff --git a/QGL/BasicSequences/StarkShift.py b/QGL/BasicSequences/StarkShift.py
new file mode 100644
index 00000000..070d5c50
--- /dev/null
+++ b/QGL/BasicSequences/StarkShift.py
@@ -0,0 +1,167 @@
+from ..PulsePrimitives import *
+from ..Compiler import compile_to_hardware
+from ..ChannelLibraries import EdgeFactory
+from ..PulseSequencePlotter import plot_pulse_files
+from .helpers import create_cal_seqs, delay_descriptor, cal_descriptor
+import numpy as np
+from collections.abc import Iterable
+from itertools import product
+
+def StarkSpectroscopy(qubit, measurement, amplitude,
+ delay=200e-9, length=1e-6, showPlot=False):
+ """Stark shift spectroscopy experiment. Applies a coherent displacement
+ to the qubit readout cavity while doing pulsed spectroscopy.
+
+ Args:
+ qubit: Qubit channel to apply spectroscopy pulse to.
+
+ measurement: Measurement channel to apply displacement pulse to.
+
+ amplitude: Measurement pulse amplitude(s)
+
+ delay: Delay between end of spectroscopy pulse and start of MEAS(qubit).
+
+ length: Total length of cavity displacement pulse.
+
+ Returns:
+ metafile: Path to compiled sequence metafile.
+ """
+
+ if not isinstance(amplitude, Iterable):
+ amplitude = [amplitude]
+
+ def stark_shift_pulse(amp):
+ pump_pulse = Utheta(measurement, amp=amp, length=length)
+ l1 = length - delay - qubit.pulse_params["length"] - delay
+ spec_pulse = Id(qubit, length=l1)+X(qubit)+Id(qubit,length=delay)
+ return spec_pulse*pump_pulse
+
+ seqs = [[stark_shift_pulse(a), MEAS(qubit)] for a in amplitude]
+ axis_descriptor = [{
+ 'name': 'Stark Shift Amplitude',
+ 'unit': None,
+ 'points': list(amplitude),
+ 'partition': 1
+ }]
+ metafile = compile_to_hardware(seqs, 'StarkSpec/StarkSpec', axis_descriptor=axis_descriptor)
+
+ if showPlot:
+ plot_pulse_files(metafile)
+
+ return metafile
+
+def StarkEcho(qubit, measurement, amplitudes, delays,
+ wait=200e-9, periods=4, showPlot=False):
+ """Hahn echo sequence with a coherent displacement of the qubit measurement cavity.
+ Used to measure photon-induced dephasing. This sequence can cause a lot of cache pressure
+ so number of points may be limited.
+
+ TODO: Use QGL intrinsics to reduce sequence and memory cache utilization.
+
+ Args:
+ qubit: Qubit channel for Hahn echo.
+
+ measurement: Measurement channel of qubit.
+
+ amplitudes: Amplitude(s) of cavity displacement pulse.
+
+ delays: Hahn echo delays - the t in 90-t-180-t-180.
+
+ wait: Delay between end of cavity displacement pulse and start of MEAS(qubit).
+
+ periods: Number of artificial oscillations.
+
+ Returns:
+ metafile: Path to compiled sequence metafile.
+ """
+
+ if not isinstance(amplitudes, Iterable):
+ amplitudes = [amplitudes]
+
+ if not isinstance(delays, Iterable):
+ delays = [delays]
+
+ def echo_phase(n):
+ return 2*np.pi*periods/len(delays)*n
+
+ def echo_stark(n, amp, max_delay, meas_delay=200e-9):
+ x_len = qubit.pulse_params["length"]
+ max_len = 3*x_len + 2*max_delay + meas_delay
+ echo_wait = max_len - (3*x_len + 2*delays[n])
+
+ echo_seq = Id(qubit, echo_wait) + X90(qubit) + Id(qubit, delays[n]) + \
+ Y(qubit) + Id(qubit, delays[n]) + U90(qubit, echo_phase(n))
+
+ meas_seq = Utheta(measurement, amp=amp, length=max_len)
+
+ return echo_seq*meas_seq
+
+
+ seqs = [[echo_stark(n, amp, np.max(delays)), Id(measurement, length=wait), MEAS(qubit)]
+ for n, amp in product(range(len(delays)), amplitudes)]
+
+ axis_descriptor = [delay_descriptor(delays)] * len(amplitudes)
+
+ metafile = compile_to_hardware(seqs, 'StarkEcho/StarkEcho', axis_descriptor=axis_descriptor)
+
+ if showPlot:
+ plot_pulse_files(metafile)
+
+ return metafile
+
+
+def CavityPumpProbe(qubit, measurement, offsets, amplitude,
+ length=1e-6, wait=1e-6, showPlot=False):
+ """Time resolved cavity spectroscopy. Applies a coherent displacement to qubit
+ readout cavity while sweeping qubit spectroscopy pulse delay. Useful to measure
+ cavity kappa and cavity population.
+
+ Args:
+ qubit: Qubit channel for spectroscopy.
+
+ measurement: Measurement channel of qubit.
+
+ offsets: Spectroscopy pulse offset relative to start of cavity displacement pulse.
+
+ amplitude: Measurement pulse amplitude.
+
+ length: Total length of cavity displacement pulse.
+
+ wait: Delay between end of cavity displacement pulse and start of MEAS(qubit).
+
+ Returns:
+ metafile: Path to compiled sequence metafile.
+ """
+
+ if not isinstance(offsets, Iterable):
+ offsets = [offsets]
+
+ def cavity_probe(offset):
+ pump_pulse = Utheta(measurement, amp=amplitude, length=length)
+ x_len = qubit.pulse_params["length"]
+ if offset < -1*x_len:
+ return [X(qubit), Id(qubit, length=(-x_len-offset)), pump_pulse, Id(qubit, length=wait)]
+ elif offset < 0:
+ total_len = length-offset
+ pm = Id(measurement, length=offset)+pump_pulse
+ pq = X(qubit)+Id(qubit, length=(total_len-x_len))
+ return [pm*pq, Id(qubit, length=wait)]
+ elif offset < length:
+ pq = Id(qubit, length=offset)+X(qubit)+Id(qubit, length=(length-offset-x_len))
+ return [pump_pulse*pq, Id(qubit, length=wait)]
+ elif offset >= length:
+ assert offset < (length+wait), f"Wait time {wait} is too short!"
+ wait_len = wait - (offset-length+x_len)
+ return [pump_pulse, Id(qubit, length=(offset-length)), X(qubit), Id(qubit, length=wait_len)]
+
+ seqs = [[cavity_probe(off), MEAS(qubit)] for off in offsets]
+ axis_descriptor = [delay_descriptor(offsets)]
+ metafile = compile_to_hardware(seqs, 'CavityPumpProbe/CavityPumpProbe', axis_descriptor=axis_descriptor)
+
+ if showPlot:
+ plot_pulse_files(metafile)
+
+ return metafile
+
+
+
diff --git a/QGL/BasicSequences/__init__.py b/QGL/BasicSequences/__init__.py
index d05862f9..882f430e 100644
--- a/QGL/BasicSequences/__init__.py
+++ b/QGL/BasicSequences/__init__.py
@@ -8,3 +8,4 @@
from .CR import EchoCRPhase, EchoCRLen, EchoCRAmp, PiRabi
from .AllXY import AllXY
from .Feedback import Reset, BitFlip3, MajorityVoteN
+from .StarkShift import StarkSpectroscopy, StarkEcho, CavityPumpProbe
diff --git a/QGL/BlockLabel.py b/QGL/BlockLabel.py
index 52db8b63..6725cd13 100644
--- a/QGL/BlockLabel.py
+++ b/QGL/BlockLabel.py
@@ -2,8 +2,10 @@
class BlockLabel(object):
- def __init__(self, label):
+ def __init__(self, label, jump_table=False, table_size=0):
self.label = label
+ self.jump_table = jump_table
+ self.table_size = table_size
def __repr__(self):
return self.__str__()
diff --git a/QGL/ChannelLibraries.py b/QGL/ChannelLibraries.py
index 6afb03b2..3b4b818c 100644
--- a/QGL/ChannelLibraries.py
+++ b/QGL/ChannelLibraries.py
@@ -3,10 +3,12 @@
real channels.
Split from Channels.py on Jan 14, 2016.
+Moved to SQLAlchemy ORM from atom 2018
Original Author: Colm Ryan
+Modified By: Graham Rowlands
-Copyright 2016 Raytheon BBN Technologies
+Copyright 2016-2018 Raytheon BBN Technologies
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -30,133 +32,322 @@
import sys
import os
import re
+import datetime
import traceback
import datetime
import importlib
-from atom.api import Atom, Str, Int, Typed
+import inspect
+import operator
+from functools import wraps, reduce
+import itertools
+import numpy as np
import networkx as nx
-import yaml
+import logging
+
+import bbndb
-# FSEvents observer in watchdog cannot have multiple watchers of the same path
-# use kqueue instead
-if sys.platform == 'darwin':
- from watchdog.observers.kqueue import KqueueObserver as Observer
-else:
- from watchdog.observers import Observer
-from watchdog.events import FileSystemEventHandler
-import time
+from bqplot import Figure, LinearScale, Axis, Lines, Figure
+from bqplot.marks import Graph, Lines, Label
+from ipywidgets import Layout, VBox, HBox
+from . import config
from . import Channels
from . import PulseShapes
-from . import config
+from .PulsePrimitives import clear_pulse_cache
+
+from IPython.display import HTML, display
channelLib = None
-class MyEventHandler(FileSystemEventHandler):
-
- def __init__(self, file_paths, callback):
- super(MyEventHandler, self).__init__()
- self.file_paths = [os.path.normpath(fn) for fn in file_paths]
- self.callback = callback
- self.paused = True
-
- # The spotlight indexer in MacOSX retriggers events... maybe we should hash the files?
- self.grace_period = 3.0 if sys.platform == 'darwin' else 1.0
- self.last_library_update = datetime.datetime.now()
-
- def on_modified(self, event):
- try:
- if any([os.path.samefile(event.src_path, fp) for fp in self.file_paths]):
- if not self.paused:
- # Build in some sanity checking since we seem to get multiple
- # events firing in a number of situations.
- now = datetime.datetime.now()
-
- if (now-self.last_library_update).total_seconds() > (self.grace_period):
- self.last_library_update = now
- """
- Hold off for half a second
- If the event is from the file being opened to be written this gives
- time for it to be written.
- """
- time.sleep(0.5)
- self.callback()
- except FileNotFoundError:
- #Temporary settings files generated using yaml_dump get deleted
- #faster than the above code can catch it.
- pass
-
-class LibraryFileWatcher(object):
- def __init__(self, main_path, callback):
- super(LibraryFileWatcher, self).__init__()
-
- self.main_path = os.path.normpath(main_path)
- self.callback = callback
-
- # Perform a preliminary loading to find all of the connected files...
- # TODO: modularity
- with open(os.path.abspath(self.main_path), 'r') as FID:
- loader = config.Loader(FID)
- try:
- tmpLib = loader.get_single_data()
- self.filenames = [os.path.normpath(lf) for lf in loader.filenames]
- finally:
- loader.dispose()
-
- self.eventHandler = MyEventHandler(self.filenames, self.callback)
- self.observer = Observer()
- self.observer.schedule(self.eventHandler, path=os.path.dirname(os.path.abspath(main_path)))
-
- self.observer.start()
- self.resume()
-
- def __del__(self):
- self.observer.stop()
- self.observer.join()
-
- def pause(self):
- self.eventHandler.paused = True
-
- def resume(self):
- self.eventHandler.paused = False
-
-class ChannelLibrary(Atom):
- # channelDict = Dict(Str, Channel)
- channelDict = Typed(dict)
- connectivityG = Typed(nx.DiGraph)
- library_file = Str()
- fileWatcher = Typed(LibraryFileWatcher)
- version = Int(5)
- last_library_update = Str()
-
- specialParams = ['phys_chan', 'gate_chan', 'trig_chan', 'receiver_chan',
- 'source', 'target']
-
- def __init__(self, library_file=None, blank=False, channelDict={}, **kwargs):
- """Create the channel library. We assume that the user wants the config file in the
- usual locations specified in the config files."""
-
- # Load the basic config options from the yaml
- self.library_file = config.load_config(library_file)
-
- if blank: # we want a blank library if library_file is none
- super(ChannelLibrary, self).__init__(channelDict={})
- self.connectivityG = nx.DiGraph()
+logger = logging.getLogger("QGL")
+
+def check_session_dirty(f):
+ """Since we can't mix db objects from separate sessions, re-fetch entities by their unique IDs"""
+ @wraps(f)
+ def wrapper(cls, *args, **kwargs):
+ if (len(cls.session.dirty | cls.session.new)) == 0:
+ if 'force' in kwargs:
+ kwargs.pop('force')
+ return f(cls, *args, **kwargs)
+ elif 'force' in kwargs and kwargs['force']:
+ kwargs.pop('force')
+ return f(cls, *args, **kwargs)
else:
- super(ChannelLibrary, self).__init__(channelDict=channelDict, library_file=self.library_file, **kwargs)
- self.connectivityG = nx.DiGraph()
- yaml_filenames = self.load_from_library()
- if self.library_file and yaml_filenames:
- self.fileWatcher = LibraryFileWatcher(self.library_file, self.update_from_file)
+ raise Exception("Uncommitted transactions for working database. Either use force=True or commit/revert your changes.")
+ return wrapper
+
+def check_for_duplicates(f):
+ """Since we can't mix db objects from separate sessions, re-fetch entities by their unique IDs"""
+ @wraps(f)
+ def wrapper(cls, label, *args, **kwargs):
+ if label in cls.channelDict:
+ logger.warning(f"A database item with the name {label} already exists. Updating parameters of this existing item instead.")
+ cls.channelDict[label].__dict__.update(kwargs)
+ return cls.channelDict[label] #should check for difference in args
+ else:
+ return f(cls, label, *args, **kwargs)
+ return wrapper
+
+class ChannelLibrary(object):
+
+ def __init__(self, db_resource_name=":memory:", db_provider="sqlite"):
+ """Create the channel library."""
- # Update the global reference
global channelLib
- if channelLib:
- # Don't let the
- channelLib.fileWatcher = None
+
+ bbndb.initialize_db(f'{db_provider}:///{db_resource_name}')
+ self.session = bbndb.get_cl_session()
+ self.connectivityG = nx.DiGraph()
+ self.db_provider = db_provider
+ self.db_resource_name = db_resource_name
+
+ # Check to see whether there is already a temp database
+ working_dbs = self.query(Channels.ChannelDatabase, label="working").all()
+ if len(working_dbs) > 1:
+ raise Exception("More than one working database exists!")
+ elif len(working_dbs) == 1:
+ self.channelDatabase = working_dbs[0]
+ elif len(working_dbs) == 0:
+ self.channelDatabase = Channels.ChannelDatabase(label="working", time=datetime.datetime.now())
+ self.add_and_update_dict(self.channelDatabase)
+ self.session.commit()
+
+ self.update_channelDict()
+
+ # Update the global reference
+ channelLib = self
+
+ def query(self, obj_type, **kwargs):
+ return self.session.query(obj_type).filter_by(**kwargs)
+
+ def get_current_channels(self):
+ return (self.channelDatabase.channels +
+ self.channelDatabase.generators +
+ self.channelDatabase.transmitters +
+ self.channelDatabase.receivers +
+ self.channelDatabase.transceivers +
+ self.channelDatabase.instruments +
+ self.channelDatabase.processors +
+ self.channelDatabase.attenuators +
+ self.channelDatabase.DCSources +
+ self.channelDatabase.spectrum_analyzers)
+
+ def update_channelDict(self):
+ self.channelDict = {c.label: c for c in self.get_current_channels()}
+ self.build_connectivity_graph()
+
+ def ls(self):
+ cdb = Channels.ChannelDatabase
+ q = self.session.query(cdb.label, cdb.time, cdb.id).\
+ order_by(Channels.ChannelDatabase.id, Channels.ChannelDatabase.label).all()
+ table_code = ""
+ for i, (label, time, id) in enumerate(q):
+ y, d, t = map(time.strftime, ["%Y", "%b. %d", "%I:%M:%S %p"])
+ # t = time.strftime("(%Y) %b. %d @ %I:%M:%S %p")
+ table_code += f"
| {id} | {y} | {d} | {t} | {label} |
"
+ display(HTML(f"| id | Year | Date | Time | Name |
|---|
{table_code}
"))
+
+ def ent_by_type(self, obj_type, show=False):
+ q = self.session.query(obj_type).filter(obj_type.channel_db.has(label="working")).order_by(obj_type.label).all()
+ if show:
+ for i, el in enumerate(q):
+ print(f"[{i}] -> {el.label}")
+ else:
+ return q
+
+ def show(self, qubits=[]):
+ # nodes = list(dgraph.nodes())
+ edges = []
+ qub_objs = qubits if not qubits == [] else self.qubits()
+ for q in qub_objs:
+ edges.append((q, q.measure_chan))
+ edges.append((q.measure_chan, q.measure_chan.phys_chan))
+ edges.append((q.measure_chan.phys_chan,q.measure_chan.phys_chan.transmitter))
+ edges.append((q, q.phys_chan))
+ edges.append((q.phys_chan, q.phys_chan.transmitter))
+
+ #Generators
+ if q.measure_chan.phys_chan.generator:
+ edges.append((q.measure_chan.phys_chan, q.measure_chan.phys_chan.generator))
+ if q.phys_chan.generator:
+ edges.append((q.phys_chan, q.phys_chan.generator))
+
+ # Triggers
+ if q.measure_chan.trig_chan:
+ edges.append((q.measure_chan, q.measure_chan.trig_chan))
+
+
+ graph = nx.digraph.DiGraph()
+ graph.add_edges_from(edges)
+
+ indices = {n: i for i, n in enumerate(graph.nodes())}
+ node_data = [{'label': str(n).replace('(','\r\n(')} for n in graph.nodes()]
+ link_data = [{'source': indices[s], 'target': indices[t]} for s, t in graph.edges()]
+
+ qub_objs.sort(key=lambda x: x.label)
+ qubit_names = [q.label for q in qub_objs]
+
+ loc = {}
+ def next_level(nodes, iteration=0, offset=0, accum=[]):
+ if len(accum) == 0:
+ loc[nodes[0]] = {'x': 0, 'y': 0}
+ accum = [nodes]
+ next_gen_nodes = list(reduce(operator.add, [list(graph.successors(n)) for n in nodes]))
+ l = len(next_gen_nodes)
+ if l > 0:
+ for k,n in enumerate(next_gen_nodes):
+ loc[n] = {'x': k, 'y': -(iteration+1)}
+ accum.append(next_gen_nodes)
+ return next_level(next_gen_nodes, iteration=iteration+1, offset=2.5*l, accum=accum)
+ else:
+ return accum
+
+ hierarchy = [next_level([q]) for q in qub_objs]
+ widest = [max([len(row) for row in qh]) for qh in hierarchy]
+ for i in range(1, len(qub_objs)):
+ offset = sum(widest[:i])
+ loc[qub_objs[i]]['x'] += offset*3
+ for n in nx.descendants(graph, qub_objs[i]):
+ loc[n]['x'] += offset*3
+
+ x = [loc[n]['x'] for n in graph.nodes()]
+ y = [loc[n]['y'] for n in graph.nodes()]
+ xs = LinearScale(min=min(x)-0.5, max=max(x)+0.6)
+ ys = LinearScale(min=min(y)-0.5, max=max(y)+0.6)
+ fig_layout = Layout(width='960px', height='500px')
+ bq_graph = Graph(node_data=node_data, link_data=link_data, x=x, y=y, scales={'x': xs, 'y': ys},
+ link_type='line', colors=['orange'] * len(node_data), directed=False)
+ bgs_lines = []
+ middles = []
+ for i in range(len(qub_objs)):
+ if i==0:
+ start = -0.4
+ end = widest[0]-0.6
+ elif i == len(qub_objs):
+ start = sum(widest)-0.4
+ end = max(x)+0.4
+ else:
+ start = sum(widest[:i])-0.4
+ end = sum(widest[:i+1])-0.6
+
+ fig = Figure(marks=[bq_graph], layout=fig_layout)
+ return fig
+
+ def show_frequency_plan(self):
+ c_freqs = {}
+ m_freqs = {}
+ for qubit in self.qubits():
+ c_freqs[qubit.label] = qubit.frequency*1e-9
+ if qubit.phys_chan.generator:
+ c_freqs[qubit.label] += qubit.phys_chan.generator.frequency*1e-9
+
+ m_freqs[qubit.label] = qubit.measure_chan.frequency*1e-9
+ if qubit.measure_chan.phys_chan.generator:
+ m_freqs[qubit.label] += qubit.measure_chan.phys_chan.generator.frequency*1e-9
+ def spike_at(f):
+ fs = np.linspace(f-0.02,f+0.02,50)
+ return fs, np.exp(-(fs-f)**2/0.01**2)
+ figs = []
+ for freqs, ss in zip([c_freqs, m_freqs],["Control","Measure"]):
+ sx = LinearScale()
+ sy = LinearScale()
+ ax = Axis(scale=sx, label="Frequency (GHz)")
+ ay = Axis(scale=sy, orientation='vertical')
+ lines = []
+ for k,f in freqs.items():
+ fs, a = spike_at(f)
+ lines.append(Lines(x=fs, y=a, scales={'x': sx, 'y': sy}))
+ labels = Label(x=list(freqs.values()), y=[1.1 for f in freqs], text=list(freqs.keys()), align='middle', scales= {'x': sx, 'y': sy},
+ default_size=14, font_weight='bolder', colors=['#4f6367'])
+ figs.append(Figure(marks=lines+[labels], axes=[ax, ay], title=f"{ss} Frequency Plan"))
+ return HBox(figs)
+
+ def receivers(self):
+ return self.ent_by_type(Channels.Receiver)
+
+ def transmitters(self):
+ return self.ent_by_type(Channels.Transmitter)
+
+ def transceivers(self):
+ return self.ent_by_type(Channels.Transceiver)
+
+ def qubits(self):
+ return self.ent_by_type(Channels.Qubit)
+
+ def meas(self):
+ return self.ent_by_type(Channels.Measurement)
+
+ def markers(self):
+ return self.ent_by_type(Channels.LogicalMarkerChannel)
+
+ @check_session_dirty
+ def load(self, name, index=1):
+ """Load the latest instance for a particular name. Specifying index = 2 will select the second most recent instance """
+ cdb = Channels.ChannelDatabase
+ items = self.session.query(cdb).filter(cdb.label==name).order_by(cdb.time.desc()).all()
+ self.load_obj(items[-index])
+
+ @check_session_dirty
+ def load_by_id(self, id_num):
+ item = self.session.query(Channels.ChannelDatabase).filter_by(id=id_num).first()
+ self.load_obj(item)
+
+ def clear(self, channel_db=None, create_new=True):
+ # If no database is specified, clear self.database
+ channel_db = channel_db if channel_db else self.channelDatabase
+
+ self.session.delete(channel_db)
+ self.session.commit()
+
+ if create_new:
+ self.channelDatabase = Channels.ChannelDatabase(label="working", time=datetime.datetime.now())
+ self.add_and_update_dict(self.channelDatabase)
+ self.session.commit()
channelLib = self
- self.last_library_update = str(datetime.datetime.now())
+ def rm(self, library_name, keep_id=-1):
+ """Remove the channel library named `library_name`. If no `keep_version` is specified then
+ all versions are removed. Otherwise """
+ cdb = Channels.ChannelDatabase
+ items = self.session.query(cdb).filter(cdb.label==library_name and cdb.id!=keep_id).all()
+ for item in items:
+ self.session.delete(item)
+
+ def rm_by_id(self, id):
+ """Remove the channel library with id `id`"""
+ item = self.session.query(Channels.ChannelDatabase).filter_by(id=id_num).first()
+ self.session.delete(item)
+
+ def load_obj(self, obj):
+ self.clear(create_new=False)
+ self.channelDatabase = bbndb.deepcopy_sqla_object(obj, self.session)
+ self.channelDatabase.label = "working"
+ self.session.commit()
+ self.update_channelDict()
+
+ def commit(self):
+ self.session.commit()
+ self.update_channelDict()
+
+ def revert(self):
+ self.session.rollback()
+
+ @check_session_dirty
+ def save_as(self, name):
+ if name == "working":
+ raise ValueError("Cannot save as `working` since that is the default working environment name...")
+ self.commit()
+ new_channelDatabase = bbndb.deepcopy_sqla_object(self.channelDatabase, self.session)
+ new_channelDatabase.label = name
+ new_channelDatabase.time = datetime.datetime.now()
+ self.commit()
+
+ def add_and_update_dict(self, el):
+ if isinstance(el, list):
+ self.session.add_all(el)
+ else:
+ self.session.add(el)
+ self.update_channelDict()
#Dictionary methods
def __getitem__(self, key):
@@ -179,395 +370,292 @@ def values(self):
def build_connectivity_graph(self):
# build connectivity graph
- self.connectivityG.clear()
- for chan in self.channelDict.values():
- if isinstance(chan,
- Channels.Qubit) and chan not in self.connectivityG:
- self.connectivityG.add_node(chan)
- for chan in self.channelDict.values():
- if isinstance(chan, Channels.Edge):
- self.connectivityG.add_edge(chan.source, chan.target)
- self.connectivityG[chan.source][chan.target]['channel'] = chan
-
- def load_from_library(self, return_only=False):
- """Loads the YAML library, creates the QGL objects, and returns a list of the visited filenames
- for the filewatcher."""
- if not self.library_file:
- return
- try:
- with open(self.library_file, 'r') as FID:
- loader = config.Loader(FID)
- try:
- tmpLib = loader.get_single_data()
- filenames = loader.filenames
- finally:
- loader.dispose()
-
- # Check to see if we have the mandatory sections
- for section in ['instruments', 'qubits', 'filters']:
- if section not in tmpLib.keys():
- raise ValueError("{} section not present in config file {}.".format(section, self.library_file))
-
- instr_dict = tmpLib['instruments']
- qubit_dict = tmpLib['qubits']
- filter_dict = tmpLib['filters']
- trigger_dict = tmpLib.get('markers', {}) # This section is optional
- edge_dict = tmpLib.get('edges', {}) # This section is optional
- master_awgs = []
-
- # Construct the channel library
- channel_dict = {}
- marker_lens = {}
-
- for name, instr in instr_dict.items():
- if "tx_channels" in instr.keys():
- for chan_name, channel in instr["tx_channels"].items():
- if channel is None:
- params = {}
- else:
- params = {k: v for k,v in channel.items() if k in Channels.PhysicalQuadratureChannel.__atom_members__.keys()}
- params["label"] = name + "-" + chan_name
- params["instrument"] = name
- params["translator"] = instr["type"] + "Pattern"
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "PhysicalQuadratureChannel"
- channel_dict[params["label"]] = params
- if "rx_channels" in instr.keys():
- for chan_name, channel in instr["rx_channels"].items():
- if channel is None:
- params = {}
- else:
- params = {k: v for k,v in channel.items() if k in Channels.PhysicalMarkerChannel.__atom_members__.keys()}
- params["label"] = name + "-" + chan_name
- params["instrument"] = name
- params["translator"] = instr["type"] + "Pattern"
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "PhysicalMarkerChannel"
- channel_dict[params["label"]] = params
- if "markers" in instr.keys():
- for mark_name, marker in instr["markers"].items():
- if marker is None:
- params = {}
- else:
- params = {k: v for k,v in marker.items() if k in Channels.PhysicalMarkerChannel.__atom_members__.keys()}
- params["label"] = name + "-" + mark_name
- params["instrument"] = name
- params["translator"] = instr["type"] + "Pattern"
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "PhysicalMarkerChannel"
- if "length" in marker.keys():
- marker_lens[params["label"]] = marker["length"]
- channel_dict[params["label"]] = params
- if "master" in instr.keys() and instr["master"]:
- if instr['type'] != 'TDM':
- slave_chan = instr["slave_trig"] if "slave_trig" in instr.keys() else "slave"
- master_awgs.append(name + "-" + slave_chan)
- else:
- master_awgs.append(name)
- # Eventually we should support multiple masters...
- if "slave_trig" in instr.keys():
- params = {}
- params["label"] = "slave_trig"
- params["phys_chan"] = name + "-" + instr["slave_trig"]
- if params["phys_chan"] in marker_lens.keys():
- length = marker_lens[params["phys_chan"]]
- else:
- length = 1e-7
- params["pulse_params"] = {"length": length, "shape_fun": "constant"}
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "LogicalMarkerChannel"
- channel_dict[params["label"]] = params
-
- # Establish the slave trigger, assuming for now that we have a single
- # APS master. This might change later.
- if len(master_awgs) > 1:
- raise ValueError("More than one AWG is marked as master.")
- # elif len(master_awgs) == 1 and instr_dict[master_awgs[0].split('-')[0]]['type'] != 'TDM':
- # params = {}
- # params["label"] = "slave_trig"
- # params["phys_chan"] = master_awgs[0]
- # if params["phys_chan"] in marker_lens.keys():
- # length = marker_lens[params["phys_chan"]]
- # else:
- # length = 1e-7
- # params["pulse_params"] = {"length": length, "shape_fun": "constant"}
- # params["__module__"] = "QGL.Channels"
- # params["__class__"] = "LogicalMarkerChannel"
- # channel_dict[params["label"]] = params
-
- for name, filt in filter_dict.items():
- if "StreamSelector" in filt["type"]:
- params = {k: v for k,v in filt.items() if k in Channels.ReceiverChannel.__atom_members__.keys()}
- params["label"] = "RecvChan-" + name # instr_dict[filt["instrument"]]["name"] + "-" + name
- params["channel"] = str(params["channel"]) # Convert to a string
- params["instrument"] = filt["source"]
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "ReceiverChannel"
- if "source" not in filt.keys():
- raise ValueError("No instrument (source) specified for Stream Selector")
- if filt["source"] not in instr_dict.keys() and filt["source"] not in channel_dict.keys():
- raise ValueError("Stream Selector source {} not found among list of instruments.".format(filt["source"]))
- params["instrument"] = filt["source"]
-
- channel_dict[params["label"]] = params
-
- for name, qubit in qubit_dict.items():
- # Create the Qubits
- if len(qubit["control"]["AWG"].split()) != 2:
- print("Control AWG specification for {} ({}) must have a device, channel".format(name, qubit["control"]["AWG"]))
- raise ValueError("Control AWG specification for {} ({}) must have a device, channel".format(name, qubit["control"]["AWG"]))
- ctrl_instr, ctrl_chan = qubit["control"]["AWG"].split()
- params = {k: v for k,v in qubit["control"].items() if k in Channels.Qubit.__atom_members__.keys()}
- params["label"] = name
- params["phys_chan"] = ctrl_instr + "-" + ctrl_chan
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "Qubit"
- channel_dict[params["label"]] = params
- if 'generator' in qubit["control"].keys():
- channel_dict[params["phys_chan"]]["generator"] = qubit["control"]["generator"]
-
- # Create the measurements
- if len(qubit["measure"]["AWG"].split()) != 2:
- print("Measurement AWG specification for {} ({}) must have a device, channel".format(name, qubit["measure"]["AWG"]))
- raise ValueError("Measurement AWG specification for {} ({}) must have a device, channel".format(name, qubit["measure"]["AWG"]))
- meas_instr, meas_chan = qubit["measure"]["AWG"].split()
- params = {k: v for k,v in qubit["measure"].items() if k in Channels.Measurement.__atom_members__.keys()}
- params["label"] = "M-{}".format(name)
- # parse the digitizer trigger from the marker dictionary, if available. If not, expected in the form Instr Ch
- dig_trig = trigger_dict.get(qubit["measure"]["trigger"], qubit["measure"]["trigger"]) if trigger_dict else qubit["measure"]["trigger"]
- params["trig_chan"] = "digTrig-" + dig_trig
- params["phys_chan"] = meas_instr + "-" + meas_chan
- params["meas_type"] = "autodyne"
- params["receiver_chan"] = "RecvChan-" + qubit["measure"]["receiver"]
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "Measurement"
- channel_dict[params["label"]] = params
- if 'generator' in qubit["measure"].keys():
- channel_dict[params["phys_chan"]]["generator"] = qubit["measure"]["generator"]
-
- # Create the receiver channels
- if "receiver" in qubit["measure"].keys():
- if len(qubit["measure"]["receiver"].split()) != 1:
- print("Receiver specification for {} ({}) must have a stream selector".format(name, qubit["measure"]["receiver"]))
- raise ValueError("Receiver specification for {} ({}) must have a stream selector".format(name, qubit["measure"]["receiver"]))
- phys_instr, phys_marker = dig_trig.split()
- params = {}
- params["label"] = "digTrig-" + dig_trig
- params["phys_chan"] = phys_instr + "-" + phys_marker
- if params["phys_chan"] in marker_lens.keys():
- length = marker_lens[params["phys_chan"]]
- else:
- length = 3e-7
- params["pulse_params"] = {"length": length, "shape_fun": "constant"}
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "LogicalMarkerChannel"
- # Don't duplicate triggers to the same digitizer
- if params["label"] not in channel_dict.keys():
- channel_dict[params["label"]] = params
-
- # Create the measurement gate chan:
- if "gate" in qubit["measure"].keys():
- phys_instr, phys_marker = qubit["measure"]["gate"].split()
- params = {}
- params["label"] = "M-{}-gate".format(name)
- params["phys_chan"] = phys_instr + "-" + phys_marker
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "LogicalMarkerChannel"
- channel_dict[params["label"]] = params
- channel_dict["M-{}".format(name)]["gate_chan"] = params["label"]
-
- # Create the control gate chan:
- if "gate" in qubit["control"].keys():
- phys_instr, phys_marker = qubit["control"]["gate"].split()
- params = {}
- params["label"] = "{}-gate".format(name)
- params["phys_chan"] = phys_instr + "-" + phys_marker
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "LogicalMarkerChannel"
- channel_dict[params["label"]] = params
- channel_dict[name]["gate_chan"] = params["label"]
-
-
- for trig_name, trigger in trigger_dict.items():
- phys_instr, phys_marker = trigger.split()
- params = {}
- params["label"] = trig_name
- params["phys_chan"] = phys_instr + "-" + phys_marker
- if params["phys_chan"] in marker_lens.keys():
- length = marker_lens[params["phys_chan"]]
- else:
- length = 1e-7
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "LogicalMarkerChannel"
- channel_dict[params["label"]] = params
-
- for name, edge in edge_dict.items():
- # Create the Edges
- if len(edge["AWG"].split()) != 2:
- print("Control AWG specification for {} ({}) must have a device, channel".format(name, edge["AWG"]))
- raise ValueError("Control AWG specification for {} ({}) must have a device, channel".format(name, edge["AWG"]))
- ctrl_instr, ctrl_chan = edge["AWG"].split()
- params = {k: v for k,v in edge.items() if k in Channels.Edge.__atom_members__.keys()}
- params["label"] = name
- params["phys_chan"] = ctrl_instr + "-" + ctrl_chan
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "Edge"
- channel_dict[params["label"]] = params
- if 'generator' in edge.keys():
- channel_dict[params["phys_chan"]]["generator"] = edge["generator"]
-
- # Create the edge gate chan:
- if "gate" in edge.keys():
- phys_instr, phys_marker = edge["gate"].split()
- params = {}
- params["label"] = "{}-gate".format(name)
- params["phys_chan"] = phys_instr + "-" + phys_marker
- params["__module__"] = "QGL.Channels"
- params["__class__"] = "LogicalMarkerChannel"
- channel_dict[params["label"]] = params
- channel_dict[name]["gate_chan"] = params["label"]
-
- if return_only:
- return channel_dict
- else:
- channel_dict = {k: self.instantiate(v) for k,v in channel_dict.items()}
- # connect objects labeled by strings
- for chan in channel_dict.values():
- for param in self.specialParams:
- if hasattr(chan, param) and getattr(chan, param) is not None:
- chan_to_find = channel_dict.get(getattr(chan, param), None)
- if not chan_to_find:
- print("Couldn't find {} of {} in the channel_dict!".format(param, chan))
- setattr(chan, param, chan_to_find)
-
- self.channelDict.update(channel_dict)
- self.build_connectivity_graph()
- return filenames
-
- except IOError:
- print('No channel library found.')
- except Exception as e:
- print('Failed to load channel library: received exception', e)
- exc_type, exc_value, exc_traceback = sys.exc_info()
- traceback.print_tb(exc_traceback, limit=4, file=sys.stdout)
-
- def instantiate(self, paramDict):
- if 'pulse_params' in paramDict:
- if 'shape_fun' in paramDict['pulse_params']:
- shape_fun = paramDict['pulse_params']['shape_fun']
- paramDict['pulse_params']['shape_fun'] = getattr(PulseShapes, shape_fun)
- if '__class__' in paramDict:
- className = paramDict.pop('__class__')
- moduleName = paramDict.pop('__module__')
- __import__(moduleName)
- return getattr(sys.modules[moduleName], className)(**paramDict)
-
-
- def update_from_file(self):
+ for chan in self.session.query(Channels.Qubit).filter(Channels.Qubit not in self.connectivityG).all():
+ self.connectivityG.add_node(chan)
+ for chan in self.session.query(Channels.Edge): #select(e for e in Channels.Edge):
+ self.connectivityG.add_edge(chan.source, chan.target)
+ self.connectivityG[chan.source][chan.target]['channel'] = chan
+
+ @check_for_duplicates
+ def new_APS2(self, label, address, **kwargs):
+ chan1 = Channels.PhysicalQuadratureChannel(label=f"{label}-1", channel=0, instrument=label, translator="APS2Pattern", channel_db=self.channelDatabase)
+ m1 = Channels.PhysicalMarkerChannel(label=f"{label}-m1", channel=0, instrument=label, translator="APS2Pattern", channel_db=self.channelDatabase)
+ m2 = Channels.PhysicalMarkerChannel(label=f"{label}-m2", channel=1, instrument=label, translator="APS2Pattern", channel_db=self.channelDatabase)
+ m3 = Channels.PhysicalMarkerChannel(label=f"{label}-m3", channel=2, instrument=label, translator="APS2Pattern", channel_db=self.channelDatabase)
+ m4 = Channels.PhysicalMarkerChannel(label=f"{label}-m4", channel=3, instrument=label, translator="APS2Pattern", channel_db=self.channelDatabase)
+
+ this_transmitter = Channels.Transmitter(label=label, model="APS2", address=address, channels=[chan1, m1, m2, m3, m4], channel_db=self.channelDatabase, **kwargs)
+ this_transmitter.trigger_source = "external"
+ this_transmitter.address = address
+
+ self.add_and_update_dict(this_transmitter)
+ return this_transmitter
+
+ @check_for_duplicates
+ def new_APS(self, label, address, **kwargs):
+ chan1 = Channels.PhysicalQuadratureChannel(label=f"{label}-12", channel = 0, instrument=label, translator="APSPattern", channel_db=self.channelDatabase)
+ chan2 = Channels.PhysicalQuadratureChannel(label=f"{label}-34", channel = 1, instrument=label, translator="APSPattern", channel_db=self.channelDatabase)
+ m1 = Channels.PhysicalMarkerChannel(label=f"{label}-1m1", channel=0, instrument=label, translator="APSPattern", channel_db=self.channelDatabase)
+ m2 = Channels.PhysicalMarkerChannel(label=f"{label}-2m1", channel=1, instrument=label, translator="APSPattern", channel_db=self.channelDatabase)
+ m3 = Channels.PhysicalMarkerChannel(label=f"{label}-3m1", channel=2, instrument=label, translator="APSPattern", channel_db=self.channelDatabase)
+ m4 = Channels.PhysicalMarkerChannel(label=f"{label}-4m1", channel=3, instrument=label, translator="APSPattern", channel_db=self.channelDatabase)
+
+ this_transmitter = Channels.Transmitter(label=label, model="APS", address=address, channels=[chan1, chan2, m1, m2, m3, m4], channel_db=self.channelDatabase)
+ this_transmitter.trigger_source = "external"
+ this_transmitter.address = address
+
+ self.add_and_update_dict(this_transmitter)
+ return this_transmitter
+
+ @check_for_duplicates
+ def new_TDM(self, label, address, **kwargs):
+ return Channels.Processor(label=label, model="TDM", address=address, trigger_interval=250e-6)
+
+ @check_for_duplicates
+ def new_spectrum_analzyer(self, label, address, source, **kwargs):
+ sa = Channels.SpectrumAnalyzer(label=label, model="SpectrumAnalyzer", address=address, LO_source=source, channel_db=self.channelDatabase, **kwargs)
+ self.add_and_update_dict(sa)
+ return sa
+
+ @check_for_duplicates
+ def new_DC_source(self, label, address, **kwargs):
+ dcsource = Channels.DCSource(label=label, model="YokogawaGS200", address=address, standalone=True, channel_db=self.channelDatabase, **kwargs)
+ self.add_and_update_dict(dcsource)
+ return dcsource
+
+ @check_for_duplicates
+ def new_attenuator(self,label,address,attenuation=0):
+ chan1 = Channels.AttenuatorChannel(label=f"AttenChan-{label}-1", channel=1, attenuation=attenuation, channel_db=self.channelDatabase)
+ chan2 = Channels.AttenuatorChannel(label=f"AttenChan-{label}-2", channel=2, attenuation=attenuation, channel_db=self.channelDatabase)
+ chan3 = Channels.AttenuatorChannel(label=f"AttenChan-{label}-3", channel=3, attenuation=attenuation, channel_db=self.channelDatabase)
+ thing = Channels.Attenuator(label=label,model="DigitalAttenuator",address=address,channels=[chan1, chan2, chan3], standalone=True, channel_db=self.channelDatabase)
+ self.add_and_update_dict(thing)
+ return thing
+
+ @check_for_duplicates
+ def new_APS2_rack(self, label, ip_addresses, tdm_ip=None, **kwargs):
+ transmitters = [self.new_APS2(f"{label}_U{n+1}", f"{ip}") for n, ip in enumerate(ip_addresses)]
+ this_transceiver = Channels.Transceiver(label=label, model="APS2", master=True, address=ip_addresses[0], transmitters=transmitters, channel_db=self.channelDatabase, **kwargs)
+ for t in transmitters:
+ t.transceiver = this_transceiver
+
+ if tdm_ip:
+ tdm = self.new_TDM(f"{label}_TDM", tdm_ip)
+ this_transceiver.processors = [tdm]
+ for t in transmitters:
+ t.trigger_source = 'system'
+
+ self.add_and_update_dict(this_transceiver)
+ return this_transceiver
+
+ @check_for_duplicates
+ def new_X6(self, label, address, dsp_channel=0, record_length=1024, **kwargs):
+
+ phys_channels = (1, 2)
+ chans = []
+
+ for phys_chan in (1,2):
+ chans.append(Channels.ReceiverChannel(label=f"RecvChan-{label}-{phys_chan}",
+ channel=phys_chan, channel_db=self.channelDatabase))
+
+ this_receiver = Channels.Receiver(label=label, model="X6", address=address, channels=chans,
+ record_length=record_length, channel_db=self.channelDatabase, **kwargs)
+ this_receiver.trigger_source = "external"
+ this_receiver.stream_types = "raw, demodulated, integrated"
+ this_receiver.address = address
+ this_receiver.stream_sel = "X6StreamSelector"
+
+ self.add_and_update_dict(this_receiver)
+ return this_receiver
+
+ @check_for_duplicates
+ def new_Alazar(self, label, address, record_length=1024, **kwargs):
+ chan1 = Channels.ReceiverChannel(label=f"RecvChan-{label}-1", channel=1, channel_db=self.channelDatabase)
+ chan2 = Channels.ReceiverChannel(label=f"RecvChan-{label}-2", channel=2, channel_db=self.channelDatabase)
+
+ this_receiver = Channels.Receiver(label=label, model="AlazarATS9870", address=address, channels=[chan1, chan2],
+ record_length=record_length, channel_db=self.channelDatabase, **kwargs)
+ this_receiver.trigger_source = "external"
+ this_receiver.stream_types = "raw"
+ this_receiver.address = address
+ this_receiver.stream_sel = "AlazarStreamSelector"
+
+ self.add_and_update_dict(this_receiver)
+ return this_receiver
+
+ @check_for_duplicates
+ def new_qubit(self, label, **kwargs):
+ thing = Channels.Qubit(label=label, channel_db=self.channelDatabase, **kwargs)
+ self.add_and_update_dict(thing)
+ return thing
+
+ @check_for_duplicates
+ def new_marker(self, label, phys_chan, **kwargs):
+ thing = Channels.LogicalMarkerChannel(label=label, phys_chan = phys_chan, channel_db=self.channelDatabase, **kwargs)
+ self.add_and_update_dict(thing)
+ return thing
+
+ @check_for_duplicates
+ def new_source(self, label, model, address, power=-30.0, frequency=5.0e9, reference='10MHz', **kwargs):
+ thing = Channels.Generator(label=label, model=model, address=address, power=power,
+ frequency=frequency, reference=reference,
+ channel_db=self.channelDatabase, **kwargs)
+ self.add_and_update_dict(thing)
+ return thing
+
+ def set_control(self, qubit_or_edge, transmitter, generator=None):
+
+ if isinstance(transmitter, Channels.Transmitter):
+ quads = [c for c in transmitter.channels if isinstance(c, Channels.PhysicalQuadratureChannel)]
+ markers = [c for c in transmitter.channels if isinstance(c, Channels.PhysicalMarkerChannel)]
+ if len(quads) > 1:
+ raise ValueError("In set_control the Transmitter must have a single quadrature channel or a specific channel must be passed instead")
+ elif len(quads) == 1:
+ phys_chan = quads[0]
+ elif isinstance(transmitter, Channels.PhysicalQuadratureChannel):
+ phys_chan = transmitter
+ markers = [c for c in transmitter.transmitter.channels if isinstance(c, Channels.PhysicalMarkerChannel)]
+ else:
+ raise ValueError("In set_control the Transmitter must have a single quadrature channel or a specific channel must be passed instead")
+
+ qubit_or_edge.phys_chan = phys_chan
+ if generator:
+ qubit_or_edge.phys_chan.generator = generator
+ self.update_channelDict()
+
+ def new_edge(self, source, target):
+ label = f"{source.label}->{target.label}"
+ if label in self.channelDict:
+ edge = self.channelDict[f"{source.label}->{target.label}"]
+ logger.warning(f"The edge {source.label}->{target.label} already exists: using this edge.")
+ else:
+ edge = Channels.Edge(label=f"{source.label}->{target.label}", source=source, target=target, channel_db=self.channelDatabase)
+ self.add_and_update_dict(edge)
+ return edge
+
+ def set_qubit_connectivity(self, graph):
"""
- Only update relevant parameters
- Helps avoid both stale references from replacing whole channel objects (as in load_from_library)
- and the overhead of recreating everything.
+ Graph is a networkx DiGraph consisting of edges (source qubit, target qubit)
"""
+ new_edges = [Channels.Edge(label=f"{source.label}->{target.label}", source=source, target=target) for source, target in graph.edges()]
+ self.add_and_update_dict(new_edges)
+ return new_edges
+
+ def set_measure(self, qubit, transmitter, receivers, generator=None, trig_channel=None, gate=False, gate_channel=None, trigger_length=1e-7):
+
+ if isinstance(transmitter, Channels.Transmitter):
+ quads = [c for c in transmitter.channels if isinstance(c, Channels.PhysicalQuadratureChannel)]
+ markers = [c for c in transmitter.channels if isinstance(c, Channels.PhysicalMarkerChannel)]
+ if len(quads) > 1:
+ raise ValueError("In set_measure the Transmitter must have a single quadrature channel or a specific channel must be passed instead")
+ elif len(quads) == 1:
+ phys_chan = quads[0]
+ elif isinstance(transmitter, Channels.PhysicalQuadratureChannel):
+ phys_chan = transmitter
+ markers = [c for c in transmitter.transmitter.channels if isinstance(c, Channels.PhysicalMarkerChannel)]
+ else:
+ raise ValueError("In set_measure the Transmitter must have a single quadrature channel or a specific channel must be passed instead")
- if not self.library_file:
- return
- try:
- all_params = self.load_from_library(return_only=True)
-
- # update & insert
- for chName, chParams in all_params.items():
- if chName in self.channelDict:
- self.update_from_json(chName, chParams)
- else:
- self.channelDict[chName] = self.instantiate(chParams)
- self.update_from_json(chName, chParams)
-
- # remove
- for chName in list(self.channelDict.keys()):
- if chName not in all_params:
- del self.channelDict[chName]
-
- self.build_connectivity_graph()
-
- print("Updated library")
- self.last_library_update = str(datetime.datetime.now())
- except:
- print('Failed to update channel library from file. Is there a typo?.')
- return
-
- # reset pulse cache
- from . import PulsePrimitives
- PulsePrimitives._memoize.cache.clear()
-
-
- def update_from_json(self, chName, chParams):
- # connect objects labeled by strings
- if 'pulse_params' in chParams.keys():
- paramDict = {str(k): v for k, v in chParams['pulse_params'].items()}
- shapeFunName = paramDict.pop('shape_fun', None)
- if shapeFunName:
- paramDict['shape_fun'] = getattr(PulseShapes, shapeFunName)
- self.channelDict[chName].pulse_params = paramDict
-
- for param in self.specialParams:
- if param in chParams.keys():
- setattr(self.channelDict[chName],
- param,
- self.channelDict.get(chParams[param], None)
- )
- # TODO: how do we follow changes to selected AWG or generator?
-
- # ignored or specially handled parameters
- ignoreList = self.specialParams + ['pulse_params', 'AWG', 'generator', '__class__', '__module__']
- for paramName in chParams:
- if paramName not in ignoreList:
- setattr(self.channelDict[chName], paramName, chParams[paramName])
-
- def on_awg_change(self, oldName, newName):
- print("Change AWG", oldName, newName)
- for chName in self.channelDict:
- if isinstance(self.channelDict[chName],
- (Channels.PhysicalMarkerChannel,
- Channels.PhysicalQuadratureChannel)):
- awgName, awgChannel = chName.rsplit('-', 1)
- if awgName == oldName:
- newLabel = "{0}-{1}".format(newName, awgChannel)
- print("Changing {0} to {1}".format(chName, newLabel))
- self.physicalChannelManager.name_changed(chName, newLabel)
-
-def MarkerFactory(label, **kwargs):
- '''Return a marker channel by name. Must be defined under top-level `markers`
- keyword in measurement configuration YAML.
- '''
- if not channelLib:
- raise ValueError('ChannelLibrary not found, has an instance of ChannelLibrary been created?')
- if label in channelLib and isinstance(channelLib[label], Channels.LogicalMarkerChannel):
- return channelLib[label]
- else:
- raise ValueError("Marker channel {} not found in channel library.".format(label))
-
-def QubitFactory(label, **kwargs):
- ''' Return a saved qubit channel or create a new one. '''
- if not channelLib:
- raise ValueError('ChannelLibrary not found, has an instance of ChannelLibrary been created?')
- if label in channelLib and isinstance(channelLib[label], Channels.Qubit):
- return channelLib[label]
+ if f"M-{qubit.label}" in self.channelDict:
+ logger.warning(f"The measurement M-{qubit.label} already exists: using this measurement.")
+ meas = self.channelDict[f"M-{qubit.label}"]
+ else:
+ meas = Channels.Measurement(label=f"M-{qubit.label}", channel_db=self.channelDatabase)
+ meas.phys_chan = phys_chan
+ if generator:
+ meas.phys_chan.generator = generator
+
+ phys_trig_channel = trig_channel if trig_channel else transmitter.get_chan("m1")
+
+ if f"ReceiverTrig-{qubit.label}" in self.channelDict:
+ logger.warning(f"The Receiver trigger ReceiverTrig-{qubit.label} already exists: using this channel.")
+ trig_chan = self.channelDict[f"ReceiverTrig-{qubit.label}"]
+ else:
+ trig_chan = Channels.LogicalMarkerChannel(label=f"ReceiverTrig-{qubit.label}", channel_db=self.channelDatabase)
+ self.session.add(trig_chan)
+ trig_chan.phys_chan = phys_trig_channel
+ trig_chan.pulse_params = {"length": trigger_length, "shape_fun": "constant"}
+ meas.trig_chan = trig_chan
+ qubit.measure_chan = meas
+
+ if isinstance(receivers, Channels.Receiver) and len(receivers.channels) > 1:
+ raise ValueError("In set_measure the Receiver must have a single receiver channel or a specific channel must be passed instead")
+ elif isinstance(receivers, Channels.Receiver) and len(receivers.channels) == 1:
+ rcv_chan = receivers.channels[0]
+ elif isinstance(receivers, Channels.ReceiverChannel):
+ rcv_chan = receivers
+ else:
+ raise ValueError("In set_measure the Transmitter must have a single quadrature channel or a specific channel must be passed instead")
+
+ meas.receiver_chan = rcv_chan
+ self.add_and_update_dict([meas, trig_chan])
+
+ if gate:
+ phys_gate_channel = gate_channel if gate_channel else transmitter.get_chan("m2")
+ if f"M-{qubit.label}-gate" in self.channelDict:
+ logger.warning(f"The gate channel M-{qubit.label}-gate already exists: using this channel.")
+ gate_chan = self.channelDict[f"M-{qubit.label}-gate"]
+ gate_chan = Channels.LogicalMarkerChannel(label=f"M-{qubit.label}-gate", channel_db=self.channelDatabase)
+ gate_chan.phys_chan = phys_gate_channel
+ meas.gate_chan = gate_chan
+ self.add_and_update_dict([gate_chan])
+
+ def set_master(self, master_instrument, trig_channel=None, pulse_length=1e-7):
+
+ if isinstance(master_instrument, Channels.Processor):
+ master_instrument.master = True
+
+ elif trig_channel:
+
+ if not isinstance(trig_channel, Channels.PhysicalMarkerChannel):
+ raise ValueError("In set_master the trigger channel must be an instance of PhysicalMarkerChannel")
+
+ if "slave_trig" in self.channelDict:
+ logger.warning(f"The slave trigger slave_trig already exists: using this trigger.")
+ st = self.channelDict["slave_trig"]
+ else:
+ st = Channels.LogicalMarkerChannel(label="slave_trig", channel_db=self.channelDatabase)
+ st.phys_chan = trig_channel
+ st.pulse_params = {"length": pulse_length, "shape_fun": "constant"}
+ master_instrument.master = True
+ master_instrument.trigger_source = "internal"
+ self.add_and_update_dict([st])
+
+ else:
+ raise ValueError(f"Could not determine which transmitter to set as master for {transmitter}:{trig_channel}")
+
+def QubitFactory(label):
+ ''' Return a saved qubit channel'''
+ channelLib.update_channelDict()
+ cs = [c for c in channelLib.channelDatabase.channels if c.label==label]
+ # q = channelLib.session.query(Channels.Qubit).filter(Channels.Qubit.label==label and Channels.Qubit.channel_db==channelLib.channelDatabase).all()
+ if len(cs) == 1:
+ return cs[0]
else:
- return Channels.Qubit(label=label, **kwargs)
+ raise Exception(f"Expected to find a single qubit {label} but found {len(cs)} qubits with the same label instead.")
-def MeasFactory(label, meas_type='autodyne', **kwargs):
+def MeasFactory(label):
''' Return a saved measurement channel or create a new one. '''
- if not channelLib:
- raise ValueError('ChannelLibrary not found, has an instance of ChannelLibrary been created?')
- if label in channelLib and isinstance(channelLib[label], Channels.Measurement):
- return channelLib[label]
+ channelLib.update_channelDict()
+ cs = [c for c in channelLib.channelDatabase.channels if c.label==label]
+ # q = channelLib.session.query(Channels.Qubit).filter(Channels.Qubit.label==label and Channels.Qubit.channel_db==channelLib.channelDatabase).all()
+ if len(cs) == 1:
+ return cs[0]
+ else:
+ raise Exception(f"Expected to find a single measurement {label} but found {len(cs)} measurements with the same label instead.")
+
+def MarkerFactory(label):
+ ''' Return a saved Marker channel or create a new one. '''
+ cs = [c for c in channelLib.channelDatabase.channels if c.label==label]
+ channelLib.update_channelDict()
+ # q = channelLib.session.query(Channels.Qubit).filter(Channels.Qubit.label==label and Channels.Qubit.channel_db==channelLib.channelDatabase).all()
+ if len(cs) == 1:
+ return cs[0]
else:
- return Channels.Measurement(label=label, meas_type=meas_type, **kwargs)
+ raise Exception(f"Expected to find a single marker {label} but found {len(cs)} markers with the same label instead.")
def EdgeFactory(source, target):
- if not channelLib:
- raise ValueError('Connectivity graph not found. Has a ChannelLibrary has been created?')
+ channelLib.update_channelDict()
if channelLib.connectivityG.has_edge(source, target):
return channelLib.connectivityG[source][target]['channel']
elif channelLib.connectivityG.has_edge(target, source):
diff --git a/QGL/Channels.py b/QGL/Channels.py
index c0c85163..1c9807d4 100644
--- a/QGL/Channels.py
+++ b/QGL/Channels.py
@@ -4,6 +4,7 @@
Created on Jan 19, 2012
Original Author: Colm Ryan
+Modified By: Graham Rowlands
Copyright 2013 Raytheon BBN Technologies
@@ -20,204 +21,6 @@
limitations under the License.
'''
+from . import config
from . import PulseShapes
-import numpy as np
-
-from math import tan, cos, pi
-# Python 2/3 compatibility: use the py3 meaning of 'str'
-from builtins import str
-
-from atom.api import Atom, Str, Float, Instance, \
- Dict, Enum, Bool, Typed, Int
-
-from copy import deepcopy
-
-
-class Channel(Atom):
- '''
- Every channel has a label and some printers.
- '''
- label = Str()
- enabled = Bool(True)
-
- def __repr__(self):
- return str(self)
-
- def __str__(self):
- return "{0}('{1}')".format(self.__class__.__name__, self.label)
-
- def json_encode(self):
- jsonDict = self.__getstate__()
-
- #Turn objects into labels
- for member in ["phys_chan", "gate_chan", "trig_chan", "receiver_chan", "source", "target"]:
- if member in jsonDict and not isinstance(jsonDict[member], str):
- obj = jsonDict.pop(member)
- if obj:
- jsonDict[member] = obj.label
-
- #We want the name of shape functions
- if "pulse_params" in jsonDict:
- pulse_params = deepcopy(jsonDict.pop("pulse_params"))
- if "shape_fun" in pulse_params:
- pulse_params["shape_fun"] = pulse_params["shape_fun"].__name__
- jsonDict["pulse_params"] = pulse_params
-
- return jsonDict
-
-
-class PhysicalChannel(Channel):
- '''
- The main class for actual AWG channels.
- '''
- instrument = Str() # i.e. the AWG or receiver
- translator = Str()
- generator = Str()
- sampling_rate = Float(default=1.2e9)
- delay = Float()
-
-
-class LogicalChannel(Channel):
- '''
- The main class from which we will generate sequences.
- At some point it needs to be assigned to a physical channel.
- '''
- #During initilization we may just have a string reference to the channel
- phys_chan = Instance((str, PhysicalChannel))
-
- def __init__(self, **kwargs):
- super(LogicalChannel, self).__init__(**kwargs)
- if self.phys_chan is None:
- self.phys_chan = PhysicalChannel(label=kwargs['label'] + '-phys')
-
-
-class PhysicalMarkerChannel(PhysicalChannel):
- '''
- A digital output channel on an AWG.
- '''
- gate_buffer = Float(0.0).tag(
- desc="How much extra time should be added onto the beginning of a gating pulse")
- gate_min_width = Float(0.0).tag(desc="The minimum marker pulse width")
-
-
-class PhysicalQuadratureChannel(PhysicalChannel):
- '''
- Something used to implement a standard qubit channel with two analog channels and a microwave gating channel.
- '''
- I_channel = Str()
- Q_channel = Str()
- #During initilization we may just have a string reference to the channel
- amp_factor = Float(1.0)
- phase_skew = Float(0.0)
-
- @property
- def correctionT(self):
- return np.array(
- [[self.amp_factor, self.amp_factor * tan(self.phase_skew * pi / 180)],
- [0, 1 / cos(self.phase_skew * pi / 180)]])
-
-class ReceiverChannel(PhysicalChannel):
- '''
- A trigger input on a receiver.
- '''
- channel = Str()
-
-class LogicalMarkerChannel(LogicalChannel):
- '''
- A class for digital channels for gating sources or triggering other things.
- '''
- pulse_params = Dict(default={'shape_fun': PulseShapes.constant,
- 'length': 10e-9})
-
-
-class Qubit(LogicalChannel):
- '''
- The main class for generating qubit pulses. Effectively a logical "QuadratureChannel".
- '''
- pulse_params = Dict(default={'length': 20e-9,
- 'piAmp': 1.0,
- 'pi2Amp': 0.5,
- 'shape_fun': PulseShapes.gaussian,
- 'cutoff': 2,
- 'drag_scaling': 0,
- 'sigma': 5e-9})
- gate_chan = Instance((str, LogicalMarkerChannel))
- frequency = Float(0.0).tag(
- desc='modulation frequency of the channel (can be positive or negative)')
-
- def __init__(self, **kwargs):
- super(Qubit, self).__init__(**kwargs)
-
-
-class Measurement(LogicalChannel):
- '''
- A class for measurement channels.
- Measurements are special because they can be different types:
- autodyne which needs an IQ pair or hetero/homodyne which needs just a marker channel.
- '''
- meas_type = Enum('autodyne', 'homodyne').tag(
- desc='Type of measurement (autodyne, homodyne)')
-
- autodyne_freq = Float(0.0).tag(
- desc='use to bake the modulation into the pulse, so that it has constant phase')
- frequency = Float(0.0).tag(
- desc='use frequency to asssociate modulation with the channel')
- pulse_params = Dict(default={'length': 100e-9,
- 'amp': 1.0,
- 'shape_fun': PulseShapes.tanh,
- 'cutoff': 2,
- 'sigma': 1e-9})
- gate_chan = Instance((str, LogicalMarkerChannel))
- trig_chan = Instance((str, LogicalMarkerChannel))
- receiver_chan = Instance((str, ReceiverChannel))
-
- def __init__(self, **kwargs):
- super(Measurement, self).__init__(**kwargs)
- if self.trig_chan is None:
- self.trig_chan = LogicalMarkerChannel(label='digitizerTrig')
-
-
-class Edge(LogicalChannel):
- '''
- Defines an arc/directed edge between qubit vertices. If a device supports bi-directional
- connectivity, that is represented with two independent Edges.
-
- An Edge is also effectively an abstract channel, so it carries the same properties as a
- Qubit channel.
- '''
- # allow string in source and target so that we can store a label or an object
- source = Instance((str, Qubit))
- target = Instance((str, Qubit))
- pulse_params = Dict(default={'length': 20e-9,
- 'amp': 1.0,
- 'phase': 0.0,
- 'shape_fun': PulseShapes.gaussian,
- 'cutoff': 2,
- 'drag_scaling': 0,
- 'sigma': 5e-9,
- 'riseFall': 20e-9})
- gate_chan = Instance((str, LogicalMarkerChannel))
- frequency = Float(0.0).tag(
- desc='modulation frequency of the channel (can be positive or negative)')
-
- def __init__(self, **kwargs):
- super(Edge, self).__init__(**kwargs)
-
- def isforward(self, source, target):
- ''' Test whether (source, target) matches the directionality of the edge. '''
- nodes = (self.source, self.target)
- if (source not in nodes) or (target not in nodes):
- raise ValueError('One of {0} is not a node in the edge'.format((
- source, target)))
- if (self.source, self.target) == (source, target):
- return True
- else:
- return False
-
-
-NewLogicalChannelList = [Qubit, Edge, LogicalMarkerChannel, Measurement]
-NewPhysicalChannelList = [
- PhysicalMarkerChannel,
- PhysicalQuadratureChannel,
- ReceiverChannel
-]
+from bbndb.qgl import *
\ No newline at end of file
diff --git a/QGL/Compiler.py b/QGL/Compiler.py
index 599e8d18..f6538f88 100644
--- a/QGL/Compiler.py
+++ b/QGL/Compiler.py
@@ -24,30 +24,34 @@
from functools import reduce
from importlib import import_module
import json
-
from . import config
from . import PatternUtils
from .PatternUtils import flatten, has_gate
from . import Channels
from . import ChannelLibraries
from . import PulseShapes
-from .PulsePrimitives import Id
+from . import PulsePrimitives
+from .PulsePrimitives import Id, clear_pulse_cache
from .PulseSequencer import Pulse, PulseBlock, CompositePulse
from . import ControlFlow
from . import BlockLabel
from . import TdmInstructions # only for APS2-TDM
+from . import APS2CustomInstructions
+from .RandomCliffordTools import default_clifford_options, VALID_CLIFFORD_TYPES
+from . import RandomCliffordTools
+import gc
logger = logging.getLogger(__name__)
def map_logical_to_physical(wires):
- # construct a mapping of physical channels to lists of logical channels
- # (there will be more than one logical channel if multiple logical
- # channels share a physical channel)
+ """construct a mapping of physical channels to lists of logical channels
+ (there will be more than one logical channel if multiple logical
+ channels share a physical channel)"""
physicalChannels = {}
for logicalChan in wires.keys():
phys_chan = logicalChan.phys_chan
if not phys_chan:
- raise ValueError("LogicalChannel {} does not have a PhysicalChannel".format(phys_chan))
+ raise ValueError("LogicalChannel {} does not have a PhysicalChannel".format(logicalChan))
if phys_chan not in physicalChannels:
physicalChannels[phys_chan] = [logicalChan]
else:
@@ -101,7 +105,7 @@ def merge_channels(wires, channels):
[e.amp * e.frequency for e in entries])[0]
assert len(nonZeroSSBChan) <= 1, \
"Unable to handle merging more than one non-zero entry with non-zero frequency."
- if nonZeroSSBChan:
+ if nonZeroSSBChan.size > 0:
frequency = entries[nonZeroSSBChan[0]].frequency
else:
frequency = 0.0
@@ -221,6 +225,10 @@ def generate_waveforms(physicalWires):
for pulse in flatten(wire):
if not isinstance(pulse, Pulse):
continue
+ if pulse.isRunTime:
+ #skip run-time pulses as we need to add the set of all possible pulses to
+ #the waveform table
+ continue
if pulse.hashshape() not in wfs[ch]:
if pulse.isTimeAmp:
wfs[ch][pulse.hashshape()] = np.ones(1, dtype=np.complex)
@@ -228,6 +236,69 @@ def generate_waveforms(physicalWires):
wfs[ch][pulse.hashshape()] = pulse.shape
return wfs
+def get_clifford_type(wire, allowed_types=VALID_CLIFFORD_TYPES):
+ rt_pulses = []
+ for pulse in flatten(wire):
+ if isinstance(pulse, Pulse) and pulse.isRunTime:
+ rt_pulses.append(pulse)
+ elif isinstance(pulse, PulseBlock) and pulse.isRunTime:
+ for p in pulse.pulses.values():
+ if p.isRunTime:
+ rt_pulses.append(p)
+
+ if len(rt_pulses) == 0:
+ return None
+ pulse_type = list(set([pulse.label for pulse in rt_pulses]))
+ #Remove pulses that are not the actual cliffords we want to play.
+ #We assume the RandomInverse is of the same type as the RandomCliffords!
+ for p in ('RandomInverse', 'RandomInverseReset'):
+ if p in pulse_type:
+ pulse_type.remove(p)
+ pulse_logical_chan = list(set([pulse.channel for pulse in rt_pulses]))
+ if len(pulse_type) > 1:
+ raise Exception(f"All run-time pulses must have the same label. Found: {pulse_type}.")
+ if len(pulse_logical_chan) > 1:
+ raise Exception(f"Found more than one channel per run-time pulse set: {pulse_logical_chan}.")
+ if pulse_type[0] not in allowed_types:
+ raise Exception(f"Unknown run time pulse type {pulse_type}.")
+ pulse_fn = getattr(PulsePrimitives, pulse_type[0].split('Random')[-1], None)
+ if pulse_fn is None:
+ raise Exception("Was unable to get pulse type for run-time generated pulses.")
+ return lambda x: pulse_fn(pulse_logical_chan[0], x)
+
+
+def add_runtime_pulse_set(physicalWires, wfs):
+ for ch, wire in physicalWires.items():
+ pulse_fn = get_clifford_type(wire)
+ if pulse_fn is None:
+ continue
+ all_pulses = []
+ all_cliffords = [pulse_fn(n) for n in range(24)]
+ #Some could be CompositePulses so crack into indvidual pulses
+ for cliff in all_cliffords:
+ try:
+ for p in cliff.pulses:
+ all_pulses.append(p)
+ except AttributeError:
+ all_pulses.append(cliff)
+
+ for cp in all_pulses: #make all-pulses a set?
+ if cp.hashshape() not in wfs[ch]: #don't duplicate data
+ if cp.isTimeAmp:
+ wfs[ch][cp.hashshape()] = np.ones(1, dtype=np.complex)
+ else:
+ wfs[ch][cp.hashshape()] = cp.shape
+
+ return wfs
+
+def create_clifford_waveforms(physicalWires):
+ clifford_sets = {}
+ for ch, wire in physicalWires.items():
+ pulse_fn = get_clifford_type(wire)
+ if pulse_fn is None:
+ continue
+ clifford_sets[ch] = [[Waveform(pulse_fn(n))] for n in range(24)]
+ return clifford_sets
def pulses_to_waveforms(physicalWires):
logger.debug("Converting pulses_to_waveforms:")
@@ -276,7 +347,8 @@ def bundle_wires(physWires, wfs):
awgData = setup_awg_channels(physWires.keys())
for chan in physWires.keys():
_, awgChan = chan.label.rsplit('-', 1)
- awgChan = 'ch' + awgChan
+ if awgChan[0] != 'm':
+ awgChan = 'ch' + awgChan
awgData[chan.instrument][awgChan]['linkList'] = physWires[chan]
awgData[chan.instrument][awgChan]['wfLib'] = wfs[chan]
if hasattr(chan, 'correctionT'):
@@ -299,31 +371,13 @@ def collect_specializations(seqs):
done.append(target)
return funcs
+def compile_to_IR(seqs, add_slave_trigger=True, tdm_seq=False, random_cliffords=False,
+ clifford_options=default_clifford_options):
-def compile_to_hardware(seqs,
- fileName,
- suffix='',
- axis_descriptor=None,
- add_slave_trigger=True,
- extra_meta=None,
- tdm_seq = False):
- '''
- Compiles 'seqs' to a hardware description and saves it to 'fileName'.
- Other inputs:
- suffix (optional): string to append to end of fileName, e.g. with
- fileNames = 'test' and suffix = 'foo' might save to test-APSfoo.h5
- axis_descriptor (optional): a list of dictionaries describing the effective
- axes of the measurements that the sequence will yield. For instance,
- if `seqs` generates a Ramsey experiment, axis_descriptor would describe
- the time delays between pulses.
- add_slave_trigger (optional): add the slave trigger(s)
- tdm_seq (optional): compile for TDM
- '''
+ ChannelLibraries.channelLib.update_channelDict()
+ clear_pulse_cache()
logger.debug("Compiling %d sequence(s)", len(seqs))
- # save input code to file
- save_code(seqs, fileName + suffix)
-
# all sequences should start with a WAIT for synchronization
for seq in seqs:
if not isinstance(seq[0], ControlFlow.Wait):
@@ -331,11 +385,11 @@ def compile_to_hardware(seqs,
seq.insert(0, ControlFlow.Wait())
# Add the digitizer trigger to measurements
- logger.debug("Adding digitizer trigger")
+ logger.info("Adding digitizer trigger")
PatternUtils.add_digitizer_trigger(seqs)
# Add gating/blanking pulses
- logger.debug("Adding blanking pulses")
+ logger.info("Adding blanking pulses")
for seq in seqs:
PatternUtils.add_gate_pulses(seq)
@@ -345,23 +399,25 @@ def compile_to_hardware(seqs,
PatternUtils.add_slave_trigger(seqs,
ChannelLibraries.channelLib['slave_trig'])
else:
- logger.debug("Not adding slave trigger")
+ logger.info("Not adding slave trigger")
# find channel set at top level to account for individual sequence channel variability
+ logger.info("Finding unique channels.")
channels = set()
for seq in seqs:
channels |= find_unique_channels(seq)
# Compile all the pulses/pulseblocks to sequences of pulses and control flow
- wireSeqs = compile_sequences(seqs, channels)
+ logger.info("Compiling sequences.")
+ wireSeqs = compile_sequences(seqs, channels, random_cliffords=random_cliffords, clifford_options=clifford_options)
if not validate_linklist_channels(wireSeqs.keys()):
print("Compile to hardware failed")
return
-
logger.debug('')
logger.debug("Now after gating constraints:")
# apply gating constraints
+ logger.info("Applying gating constraints")
for chan, seq in wireSeqs.items():
if isinstance(chan, Channels.LogicalMarkerChannel):
wireSeqs[chan] = PatternUtils.apply_gating_constraints(
@@ -369,6 +425,7 @@ def compile_to_hardware(seqs,
debug_print(wireSeqs, 'Gated sequence')
# save number of measurements for meta info
+ logger.info("Counting measurements.")
num_measurements = count_measurements(wireSeqs)
wire_measurements = count_measurements_per_wire(wireSeqs)
@@ -376,52 +433,104 @@ def compile_to_hardware(seqs,
# PhysicalQuadratureChannels and PhysicalMarkerChannels
# for the APS, the naming convention is:
# ASPName-12, or APSName-12m1
+ logger.info("Mapping logical to physical channels.")
physWires = map_logical_to_physical(wireSeqs)
# Pave the way for composite instruments, not useful yet...
- files = {}
- label_to_inst = {}
- label_to_chan = {}
- old_wire_names = {}
- old_wire_instrs = {}
+ extra_info = {}
+ extra_info["files"] = {}
+ extra_info["label_to_inst"] = {}
+ extra_info["label_to_chan"] = {}
+ extra_info["old_wire_names"] = {}
+ extra_info["old_wire_instrs"] = {}
+
+ extra_info["num_measurements"] = num_measurements
+ extra_info["wire_measurements"] = wire_measurements
+ extra_info["channels"] = channels
+
for wire, pulses in physWires.items():
pattern_module = import_module('QGL.drivers.' + wire.translator)
if pattern_module.SEQFILE_PER_CHANNEL:
- inst_name = pattern_module.get_true_inst_name(wire.label)
- chan_name = pattern_module.get_true_chan_name(wire.label)
+ inst_name = wire.transmitter.label
+ chan_name = wire.label
has_non_id_pulses = any([len([p for p in ps if isinstance(p,Pulse) and p.label!="Id"]) > 0 for ps in pulses])
- label_to_inst[wire.label] = inst_name
+ extra_info["label_to_inst"][wire.label] = inst_name
if has_non_id_pulses:
- label_to_chan[wire.label] = chan_name
+ extra_info["label_to_chan"][wire.label] = chan_name
# Change the name/inst for uniqueness, but we must restore this later!
- old_wire_names[wire] = wire.label
- old_wire_instrs[wire] = wire.instrument
+ extra_info["old_wire_names"][wire] = wire.label
+ extra_info["old_wire_instrs"][wire] = wire.instrument
wire.instrument = wire.label
wire.label = chan_name
- files[inst_name] = {}
+ extra_info["files"][inst_name] = {}
# construct channel delay map
+ logger.info("Constructing delay map.")
delays = channel_delay_map(physWires)
# apply delays
+ logger.info("Applying delays.")
for chan, wire in physWires.items():
PatternUtils.delay(wire, delays[chan])
debug_print(physWires, 'Delayed wire')
# generate wf library (base shapes)
+ logger.info("Generating waveform library.")
wfs = generate_waveforms(physWires)
+ # If there are run-time pulses add these to the library
+ if random_cliffords:
+ wfs = add_runtime_pulse_set(physWires, wfs)
+
# replace Pulse objects with Waveforms
+ logger.info("Replacing pulses with waveforms")
physWires = pulses_to_waveforms(physWires)
# bundle wires on instruments, or channels depending
# on whether we have one sequence per channel
+ logger.info("Bundling wires.")
awgData = bundle_wires(physWires, wfs)
+ return awgData, extra_info
+
+def compile_to_hardware(seqs,
+ fileName,
+ library_version=None,
+ suffix='',
+ axis_descriptor=None,
+ add_slave_trigger=True,
+ extra_meta=None,
+ tdm_seq = False):
+ '''
+ Compiles 'seqs' to a hardware description and saves it to 'fileName'.
+ Other inputs:
+ library_version (optional): string or ChannelLibrary instance to pack in the
+ metafile. This will be the version of the library loaded during program
+ execution. Default None uses the current working version.
+ suffix (optional): string to append to end of fileName, e.g. with
+ fileNames = 'test' and suffix = 'foo' might save to test-APSfoo.h5
+ axis_descriptor (optional): a list of dictionaries describing the effective
+ axes of the measurements that the sequence will yield. For instance,
+ if `seqs` generates a Ramsey experiment, axis_descriptor would describe
+ the time delays between pulses.
+ add_slave_trigger (optional): add the slave trigger(s)
+ tdm_seq (optional): compile for TDM
+ '''
+ # save input code to file
+
+ save_code(seqs, fileName + suffix)
+
+ if any([p.isRunTime for p in flatten(seqs)]):
+ random_cliffords = True
+ else:
+ random_cliffords = False
+
+ awgData, extra_info = compile_to_IR(seqs, add_slave_trigger=add_slave_trigger, tdm_seq=tdm_seq, random_cliffords=random_cliffords)
# convert to hardware formats
# files = {}
awg_metas = {}
- for awgName, data in awgData.items():
+ for awgName in list(awgData.keys()):
+ data = awgData[awgName]
# create the target folder if it does not exist
targetFolder = os.path.split(os.path.normpath(os.path.join(
config.AWGDir, fileName)))[0]
@@ -430,16 +539,23 @@ def compile_to_hardware(seqs,
fullFileName = os.path.normpath(os.path.join(
config.AWGDir, fileName + '-' + awgName + suffix + data[
'seqFileExt']))
+ logger.info("Writing sequence file for: {}".format(awgName))
new_meta = data['translator'].write_sequence_file(data, fullFileName)
if new_meta:
awg_metas[awgName] = new_meta
+ ChannelLibraries.channelLib[awgName].extra_meta = new_meta
# Allow for per channel and per AWG seq files
- if awgName in label_to_inst:
- if awgName in label_to_chan:
- files[label_to_inst[awgName]][label_to_chan[awgName]] = fullFileName
+ if awgName in extra_info["label_to_inst"]:
+ if awgName in extra_info["label_to_chan"]:
+ files[extra_info["label_to_inst"][awgName]][extra_info["label_to_chan"][awgName]] = fullFileName
else:
- files[awgName] = fullFileName
+ extra_info["files"][awgName] = fullFileName
+
+ del data
+ del awgData[awgName]
+ gc.collect()
+
# generate TDM sequences FIXME: what's the best way to identify the need for a TDM seq.? Support for single TDM
if tdm_seq and 'APS2Pattern' in [wire.translator for wire in physWires]:
aps2tdm_module = import_module('QGL.drivers.APS2Pattern') # this is redundant with above
@@ -454,22 +570,31 @@ def compile_to_hardware(seqs,
else:
extra_meta = awg_metas
# create meta output
+ db_info = {
+ 'db_provider': ChannelLibraries.channelLib.db_provider,
+ 'db_resource_name': ChannelLibraries.channelLib.db_resource_name,
+ 'library_name': 'working',
+ 'library_id': ChannelLibraries.channelLib.channelDatabase.id
+ }
if not axis_descriptor:
axis_descriptor = [{
'name': 'segment',
'unit': None,
- 'points': list(range(1, 1 + num_measurements)),
+ 'points': list(range(1, 1 + extra_info["num_measurements"])),
'partition': 1
}]
receiver_measurements = {}
- for wire, n in wire_measurements.items():
+ for wire, n in extra_info["wire_measurements"].items():
if wire.receiver_chan and n>0:
receiver_measurements[wire.receiver_chan.label] = n
meta = {
- 'instruments': files,
+ 'database_info': db_info,
+ 'instruments': extra_info["files"],
'num_sequences': len(seqs),
- 'num_measurements': num_measurements,
+ 'num_measurements': extra_info["num_measurements"],
'axis_descriptor': axis_descriptor,
+ 'qubits': [c.label for c in extra_info["channels"] if isinstance(c, Channels.Qubit)],
+ 'measurements': [c.label for c in extra_info["channels"] if isinstance(c, Channels.Measurement)],
'receivers': receiver_measurements
}
if extra_meta:
@@ -479,16 +604,17 @@ def compile_to_hardware(seqs,
json.dump(meta, FID, indent=2, sort_keys=True)
# Restore the wire info
- for wire in old_wire_names.keys():
- wire.label = old_wire_names[wire]
- for wire in old_wire_instrs.keys():
- wire.instrument = old_wire_instrs[wire]
+ for wire in extra_info["old_wire_names"].keys():
+ wire.label = extra_info["old_wire_names"][wire]
+ for wire in extra_info["old_wire_instrs"].keys():
+ wire.instrument = extra_info["old_wire_instrs"][wire]
# Return the filenames we wrote
return metafilepath
-def compile_sequences(seqs, channels=set()):
+def compile_sequences(seqs, channels=set(), random_cliffords=False,
+ clifford_options=default_clifford_options):
'''
Main function to convert sequences to miniLL's and waveform libraries.
'''
@@ -502,6 +628,23 @@ def compile_sequences(seqs, channels=set()):
subroutines = collect_specializations(seqs)
seqs += subroutines
+ if random_cliffords:
+
+ qubits = [q for q in list(channels) if isinstance(q, Channels.Qubit)]
+ if len(qubits) > 1:
+ raise Exception("Too many qubits! Don't know how to deal with this yet.")
+ #replace cliffords with
+ cliffords = [[get_clifford_type(seqs)(n)] for n in range(24)]
+ jt_label = RandomCliffordTools.generate_clifford_jump_table(cliffords)
+ RandomCliffordTools.insert_clifford_calls(seqs, jt_label=jt_label, clifford_options=clifford_options)
+
+ # if not isinstance(seqs[0][0], BlockLabel.BlockLabel):
+ # raise Exception("Fist instruciton must be block label!")
+ # start_label = seqs[0][0]
+ seqs += cliffords
+ #seqs[0:0] = cliffords
+ #seqs[0].insert(0, ControlFlow.Goto(start_label))
+
#expand the channel definitions for anything defined in subroutines
for func in subroutines:
channels |= find_unique_channels(subroutines)
@@ -564,9 +707,8 @@ def flatten_to_pulses(obj):
continue
# control flow broadcasts to all channels if channel attribute is None
if (isinstance(block, ControlFlow.ControlInstruction) or
- isinstance(block, TdmInstructions.WriteAddrInstruction) or
- isinstance(block, TdmInstructions.CustomInstruction) or
- isinstance(block, TdmInstructions.LoadCmpVramInstruction)):
+ isinstance(block, TdmInstructions.VRAMInstruction) or
+ isinstance(block, TdmInstructions.CustomInstruction)):
# Need to deal with attaching measurements and edges to control
# instruction. Until we have a proper solution for that, we will
# always broadcast control instructions to all channels
@@ -575,6 +717,9 @@ def flatten_to_pulses(obj):
for chan in block_channels:
wires[chan] += [copy(block)]
continue
+ #Don't propagate VRAM instructions
+ #if isinstance(block, TdmInstructions.VRAMInstruction) or isinstance(block, TdmInstructions.CustomInstruction):
+ # continue
# propagate frame change from nodes to edges
for chan in channels:
if block.pulses[chan].frameChange == 0:
@@ -584,7 +729,14 @@ def flatten_to_pulses(obj):
wires = propagate_node_frame_to_edges(
wires, chan, block.pulses[chan].frameChange)
# drop length 0 blocks but push nonzero frame changes onto previous entries
- if block.length == 0:
+
+ is_subroutine = False
+ if isinstance(seq[-1], ControlFlow.Return):
+ #Make sure we do not drop frame update instructions for subroutines that are only Z pulses
+ is_subroutine = True
+
+
+ if block.length == 0 and not is_subroutine:
for chan in channels:
if block.pulses[chan].frameChange == 0:
continue
@@ -656,11 +808,29 @@ def normalize(seq, channels=None):
block.pulses[ch] = Id(ch, blocklen)
return seq
+class MemoizedObject(type):
+ """Metaclass for memoizing objects. Designed to save memory when processing
+ very long sequences. Overrides __call__ to prevent creating a new instance.
+ Idea from https://stackoverflow.com/questions/47785795/memoized-objects-still-have-their-init-invoked
+ """
+ def __init__(self, name, bases, namespace):
+ super().__init__(name, bases, namespace)
+ self.cache = {}
+ def __call__(self, pulse=None):
+ hash = pulse.hashshape()
+ if pulse is not None and hash not in self.cache:
+ self.cache[hash] = super().__call__(pulse=pulse)
+ return self.cache[hash]
+
class Waveform(object):
"""
Simplified channel independent version of a Pulse with a key into waveform library.
"""
+ #Use slots to create attributes to save on memory.
+ __slots__ = ["label", "key", "amp", "length", "phase", "frameChange",
+ "isTimeAmp", "frequency", "logicalChan", "maddr", "startTime",
+ "isRunTime"]
def __init__(self, pulse=None):
if pulse is None:
@@ -674,6 +844,7 @@ def __init__(self, pulse=None):
self.frequency = 0
self.logicalChan = ""
self.maddr = (-1, 0)
+ self.isRunTime = False
else:
self.label = pulse.label
self.key = pulse.hashshape()
@@ -685,11 +856,14 @@ def __init__(self, pulse=None):
self.frequency = pulse.frequency
self.logicalChan = pulse.channel
self.maddr = pulse.maddr
+ self.isRunTime = pulse.isRunTime
def __repr__(self):
return self.__str__()
def __str__(self):
+ if self.isRunTime:
+ return f"Hardware-Generated({self.label}, {self.length})"
if self.isTimeAmp:
TA = 'HIGH' if self.amp != 0 else 'LOW'
return "Waveform-TA(" + TA + ", " + str(self.length) + ")"
@@ -698,15 +872,18 @@ def __str__(self):
self.key)[:6] + ", " + str(self.length) + ")"
def __eq__(self, other):
+ if self.isRunTime or other.isRunTime:
+ return False
if isinstance(other, self.__class__):
- return self.__dict__ == other.__dict__
+ #No __dict__ property so we check all properties.
+ return all((getattr(self, attr, None) == getattr(other, attr, None) for attr in self.__slots__))
return False
def __ne__(self, other):
return not self == other
def __hash__(self):
- return hash(frozenset(self.__dict__.items()))
+ return hash(frozenset((attr, getattr(self, attr, None)) for attr in self.__slots__))
@property
def isZero(self):
diff --git a/QGL/ControlFlow.py b/QGL/ControlFlow.py
index 719a2964..692958ff 100644
--- a/QGL/ControlFlow.py
+++ b/QGL/ControlFlow.py
@@ -151,8 +151,16 @@ def __init__(self, target):
class Call(ControlInstruction):
# target is a BlockLabel
- def __init__(self, target):
+ def __init__(self, target, indirect=False):
super(Call, self).__init__("CALL", target=target)
+ self.indirect = indirect
+
+ def __str__(self):
+ if not self.indirect:
+ return f"{self.instruction}({str(self.target)})"
+ else:
+ return f"{self.instruction}({str(self.target)}, INDIRECT)"
+
class Return(ControlInstruction):
diff --git a/QGL/GSTTools.py b/QGL/GSTTools.py
index fda0a579..49ad9749 100644
--- a/QGL/GSTTools.py
+++ b/QGL/GSTTools.py
@@ -23,13 +23,19 @@
from .Cliffords import *
from .BasicSequences.helpers import create_cal_seqs
from .Compiler import compile_to_hardware
-from pygsti.objects import GateString
from itertools import chain
from random import choices
+PYGSTI_PRESENT = False
+try:
+ from pygsti.objects.circuit import Circuit
+ PYGSTI_PRESENT = True
+except:
+ pass
+
#Default mapping from pyGSTi naming convention to QGL gates.
-gst_gate_map = {"Gx": X,
- "Gy": Y,
+gst_gate_map = {"Gx": X90,
+ "Gy": Y90,
"Gi": Id}
def gst_map_1Q(gst_list, qubit, qgl_map=gst_gate_map, append_meas=True):
@@ -45,11 +51,11 @@ def gst_map_1Q(gst_list, qubit, qgl_map=gst_gate_map, append_meas=True):
Returns:
QGL sequences, preserving the input list nesting (as a generator)
"""
- if isinstance(gst_list, GateString):
+ if isinstance(gst_list, Circuit):
gst_list = [gst_list]
for item in gst_list:
- if isinstance(item, GateString):
- mapped = map(lambda x: qgl_map[x](qubit), item.tup)
+ if isinstance(item, Circuit):
+ mapped = map(lambda x: qgl_map[str(x)](qubit), item.tup)
if append_meas:
yield list(chain(mapped, [MEAS(qubit)]))
else:
@@ -57,6 +63,31 @@ def gst_map_1Q(gst_list, qubit, qgl_map=gst_gate_map, append_meas=True):
elif isinstance(item, list):
yield list(gst_map_1Q(item, qubit, qgl_map=qgl_map, append_meas=append_meas))
+def gst_map_2Q(gst_list, qubits, qgl_map=None, append_meas=False):
+ """
+ Helper function that takes an arbitrarily nested list of pygsti gatestrings
+ and converts them into QGL sequences, keeping the same nesting of lists.
+
+ Inputs:
+ gst_list: GateString to convert, or possibly nested list of pyGSTi GateStrings.
+ qubit: QGL qubit to apply the sequence to
+ qgl_map: Dictionary that maps between pyGSTi "Gx" string to QGL pulse
+ append_meas: Append a measurement to each sequence.
+ Returns:
+ QGL sequences, preserving the input list nesting (as a generator)
+ """
+ if isinstance(gst_list, GateString):
+ gst_list = [gst_list]
+ for item in gst_list:
+ if isinstance(item, GateString):
+ mapped = map(lambda x: qgl_map[x], item.tup)
+ if append_meas:
+ yield list(chain(mapped, [reduce(lambda x,y: x*y, map(MEAS, qubits))]))
+ else:
+ yield list(mapped)
+ elif isinstance(item, list):
+ yield list(gst_map_2Q(item, qubit, qgl_map=qgl_map, append_meas=append_meas))
+
def create_gst_sequence_from_pygsti(gst_list, qubit, gate_map=gst_gate_map):
""" Returns list of QGL sequences from a pyGSTi GateString list. See gst_map_1Q.
The return value is a list of sequences that can be complied by QGL.
diff --git a/QGL/PatternUtils.py b/QGL/PatternUtils.py
index 9748b35d..0719a3e0 100644
--- a/QGL/PatternUtils.py
+++ b/QGL/PatternUtils.py
@@ -202,12 +202,17 @@ def add_digitizer_trigger(seqs):
#find corresponding digitizer trigger
chanlist = list(flatten([seq[ct].channel]))
for chan in chanlist:
- if hasattr(chan, 'trig_chan'):
+ if hasattr(chan, 'trig_chan') and chan.trig_chan is not None:
trig_chan = chan.trig_chan
if not (hasattr(seq[ct], 'pulses') and
trig_chan in seq[ct].pulses.keys()):
seq[ct] = align('left', seq[ct], TAPulse("TRIG", trig_chan, trig_chan.pulse_params['length'], 1.0, 0.0, 0.0))
+def contains_runtime_pulses(seqs):
+ """
+ Determines if sequences contain run-time generated pulses.
+ """
+ return any([hasattr(entry, 'isRunTime') and entry.isRunTime for entry in flatten(seqs)])
def contains_measurement(entry):
"""
@@ -334,5 +339,5 @@ def flatten_pulses():
awg, [str(p) for p in ps.values()]))
continue
print("Updating pulses for {}".format(awg))
- translators[awg].update_wf_library(path + "-" + awg + ".h5", ps,
+ translators[awg].update_wf_library(path + "-" + awg + ".aps", ps,
offsets)
diff --git a/QGL/Plotting.py b/QGL/Plotting.py
index 25c3c1a5..8051cb7d 100644
--- a/QGL/Plotting.py
+++ b/QGL/Plotting.py
@@ -22,29 +22,10 @@
'''
import os.path, uuid, tempfile
-import bokeh.plotting as bk
-from bokeh.layouts import column
-from bokeh.util.warnings import BokehUserWarning
-from bokeh.resources import INLINE
import numpy as np
import warnings
from . import config
-def output_notebook(local=True, suppress_warnings=False):
- if suppress_warnings:
- warnings.simplefilter("ignore", BokehUserWarning)
- if local:
- bk.output_notebook(resources=INLINE)
- else:
- bk.output_notebook()
-
-def output_file(local=True, suppress_warnings=True):
- if suppress_warnings:
- warnings.simplefilter("ignore", BokehUserWarning)
- mode = "inline" if local else "cdn"
- bk.output_file(os.path.join(tempfile.gettempdir(), str(uuid.uuid4()) +
- ".html"), mode=mode)
-
def build_waveforms(seq):
# import here to avoid circular imports
from . import Compiler, PulseSequencer, BlockLabel, ControlFlow
@@ -76,30 +57,30 @@ def build_waveforms(seq):
concatShapes[q] = np.append(concatShapes[q], 0)
return concatShapes
-
-def plot_waveforms(waveforms, figTitle=''):
- channels = waveforms.keys()
- # plot
- plots = []
- for (ct, chan) in enumerate(channels):
- fig = bk.figure(title=figTitle + repr(chan),
- plot_width=800,
- plot_height=350,
- y_range=[-1.05, 1.05],
- x_axis_label=u'Time (μs)')
- fig.background_fill_color = config.plotBackground
- if config.gridColor:
- fig.xgrid.grid_line_color = config.gridColor
- fig.ygrid.grid_line_color = config.gridColor
- waveformToPlot = waveforms[chan]
- xpts = np.linspace(0, len(waveformToPlot) / chan.phys_chan.sampling_rate
- / 1e-6, len(waveformToPlot))
- fig.line(xpts, np.real(waveformToPlot), color='red')
- fig.line(xpts, np.imag(waveformToPlot), color='blue')
- plots.append(fig)
- bk.show(column(*plots))
-
-
-def show(seq):
- waveforms = build_waveforms(seq)
- plot_waveforms(waveforms)
+#
+# def plot_waveforms(waveforms, figTitle=''):
+# channels = waveforms.keys()
+# # plot
+# plots = []
+# for (ct, chan) in enumerate(channels):
+# fig = bk.figure(title=figTitle + repr(chan),
+# plot_width=800,
+# plot_height=350,
+# y_range=[-1.05, 1.05],
+# x_axis_label=u'Time (μs)')
+# fig.background_fill_color = config.plotBackground
+# if config.gridColor:
+# fig.xgrid.grid_line_color = config.gridColor
+# fig.ygrid.grid_line_color = config.gridColor
+# waveformToPlot = waveforms[chan]
+# xpts = np.linspace(0, len(waveformToPlot) / chan.phys_chan.sampling_rate
+# / 1e-6, len(waveformToPlot))
+# fig.line(xpts, np.real(waveformToPlot), color='red')
+# fig.line(xpts, np.imag(waveformToPlot), color='blue')
+# plots.append(fig)
+# bk.show(column(*plots))
+
+#
+# def show(seq):
+# waveforms = build_waveforms(seq)
+# plot_waveforms(waveforms)
diff --git a/QGL/PulsePrimitives.py b/QGL/PulsePrimitives.py
index 59d48099..b9d66f2a 100644
--- a/QGL/PulsePrimitives.py
+++ b/QGL/PulsePrimitives.py
@@ -24,13 +24,15 @@
from .PulseSequencer import Pulse, TAPulse, CompoundGate, align
from functools import wraps, reduce
-
-def overrideDefaults(chan, updateParams):
+def overrideDefaults(chan, updateParams, ignoredStrParams=['isRunTime', 'maddr', 'moffset']):
'''Helper function to update any parameters passed in and fill in the defaults otherwise.'''
# The default parameter list depends on the channel type so pull out of channel
# Then update passed values
paramDict = chan.pulse_params.copy()
paramDict.update(updateParams)
+ for param in ignoredStrParams:
+ if param in paramDict.keys():
+ paramDict.pop(param)
return paramDict
@@ -91,6 +93,10 @@ def Utheta(qubit,
del params["amp"]
if "phase" in params:
del params["phase"]
+ if "frequency" in kwargs:
+ frequency = kwargs["frequency"]
+ else:
+ frequency = None
# allow override of angle -> amplitude lookup if the user provides an "amp"
# keyword argument
if "amp" in kwargs:
@@ -109,7 +115,7 @@ def Utheta(qubit,
else:
# linearly scale based upon the 'pi/2' amplitude
amp = (angle / (pi/2)) * qubit.pulse_params['pi2Amp']
- return Pulse(label, qubit, params, amp, phase, 0.0, ignoredStrParams)
+ return Pulse(label, qubit, params, amp, phase, 0.0, ignoredStrParams, frequency=frequency)
# generic pulses around X, Y, and Z axes
@@ -333,6 +339,57 @@ def arb_axis_drag(qubit,
return Pulse(kwargs["label"] if "label" in kwargs else "ArbAxis", qubit,
params, 1.0, aziAngle, frameChange)
+def RandomCliff(qubit):
+ """A randomly generated clifford gate, using the standard clifford library.
+ """
+ params = overrideDefaults(qubit, {})
+ return Pulse("RandomCliff", qubit, params, isRunTime=True)
+
+def RandomAC(qubit):
+ """A randomly generated clifford gate, using the diatomic clifford library.
+ """
+ params = overrideDefaults(qubit, {})
+ return Pulse("RandomAC", qubit, params, isRunTime=True)
+
+def RandomDiAC(qubit):
+ """A randomly generated clifford gate, using the atomic clifford library.
+ """
+ params = overrideDefaults(qubit, {})
+ params["length"] *= 2.0
+ return Pulse("RandomDiAC", qubit, params, isRunTime=True)
+
+def RandomInverse(qubit):
+ """The currently-stored `Inverse` clifford generated by the on-board frame
+ tracking hardware.
+ """
+ params = overrideDefaults(qubit, {})
+ return Pulse("RandomInverse", qubit, params, isRunTime=True)
+
+def RandomInverseReset(qubit, reset_value=0):
+ """Reset the on-board frame tracker to the given value (clifford index).
+ NOTE: Because of potential timing issues with the random clifford firmware,
+ this "pulse" will be played in the "dead time" between sequences (i.e.
+ BEFORE the first WAIT of a sequence.) No guarantees as to what will happen if
+ you try to put this pulse inside of a sequence...
+ """
+ params = overrideDefaults(qubit, {})
+ #note that we store the reset value in the `maddr` paramter, otherwise unused
+ #TODO: this is a bit hacky and should probably be changed.
+ return Pulse("RandomInverseReset", qubit, params, isRunTime=True, maddr=reset_value)
+
+from . import Cliffords
+
+def RandomTestCliff(qubit):
+ params = overrideDefaults(qubit, {})
+ return Pulse("RandomTestCliff", qubit, params, isRunTime=True)
+
+def TestCliff(qubit, cliffNum):
+ params = overrideDefaults(qubit, {'shape_fun': 'constant'})
+ amp = cliffNum * (1.0/24.0) + (1.0/24.0)
+ return Pulse("TCPulse", qubit, params, amp, 0.0, 0.0, frequency=0.0)
+
+def Cliff(qubit, cliffNum):
+ return reduce(operator.add, [p for p in Cliffords.clifford_seq(cliffNum, qubit)])
def AC(qubit, cliffNum):
"""
@@ -357,7 +414,7 @@ def AC(qubit, cliffNum):
#Now a big else if chain for to get the specific Clifford
if cliffNum == 0:
#Identity gate
- return Id(qubit, length=0)
+ return Id(qubit)#Id(qubit, length=0)
elif cliffNum == 1:
#X90
return X90(qubit)
diff --git a/QGL/PulseSequencePlotter.py b/QGL/PulseSequencePlotter.py
index e2b14ed5..27b61d87 100644
--- a/QGL/PulseSequencePlotter.py
+++ b/QGL/PulseSequencePlotter.py
@@ -25,12 +25,6 @@
import os.path
import json
from importlib import import_module
-from bokeh.layouts import column
-from bokeh.models import CustomJS, ColumnDataSource, Slider
-from bokeh.plotting import Figure, show
-from bokeh.palettes import d3, brewer, Inferno
-
-from jinja2 import Template
import numpy as np
from . import config
@@ -71,14 +65,14 @@ def resolve_translator(filename, translators):
raise NameError("No translator found to open the given file %s", filename)
-def plot_pulse_files(metafile, time=False):
+def plot_pulse_files(metafile, time=True, backend='bqplot'):
'''
plot_pulse_files(metafile)
- Helper function to plot a list of AWG files. A JS slider allows choice of sequence number.
+ Helper function to plot a list of AWG files. A jupyter slider widget allows choice of sequence number.
'''
#If we only go one filename turn it into a list
-
+
with open(metafile, 'r') as FID:
meta_info = json.load(FID)
fileNames = []
@@ -94,67 +88,45 @@ def plot_pulse_files(metafile, time=False):
localname = os.path.split(fileNames[0])[1]
sequencename = localname.split('-')[0]
- data = {line_name: ColumnDataSource(data=dat) for line_name,dat in data_dicts.items()}
- plot = Figure(title=sequencename, plot_width=1000)
- if config.plotBackground:
- plot.background_fill_color = config.plotBackground
- if config.gridColor:
- plot.xgrid.grid_line_color = config.gridColor
- plot.ygrid.grid_line_color = config.gridColor
-
- if len(line_names) < 10:
- # Colobrewer2 qualitative Set1 (http://colorbrewer2.org)
- colors = brewer['Set1'][max(3, len(line_names))]
- elif 9 < len(line_names) < 19:
- # d3 Category20 for up to 18 channels
- colors = d3['Category20'][len(line_names)]
- else:
- # 256 palette
- colors = [Inferno[256][np.int(ct-1)] for ct in np.floor(np.linspace(0,256,len(line_names)))]
- js_sources = data
- for ct, k in enumerate(line_names):
- k_ = k.replace("-", "_")
- line = plot.line(data_dicts[k + "_1"]["x"],
- data_dicts[k + "_1"]["y"],
- color=colors[ct % len(colors)],
- line_width=2,
- legend=k.replace("_", "-"))
- js_sources[k_] = line.data_source
-
- code_template = Template("""
- var seq_num = cb_obj.getv('value');
- // console.log(seq_num);
- var all_data = {
- {% for trace in trace_names %}
- '{{trace}}': {{trace}}.getv('data'),
- {% endfor %}
- };
- {% for line in line_names %}
- {{line}}['data'] = {'x': (all_data['{{line}}_'.concat(seq_num.toString())])['x'],
- 'y': (all_data['{{line}}_'.concat(seq_num.toString())])['y']};
- {% endfor %}
- """)
- rendered = code_template.render(
- line_names=line_names,
- trace_names=list(data.keys())[:-len(line_names)]
- )
-
- callback = CustomJS(
- args=dict(**js_sources),
- code=rendered)
-
- if num_seqs > 1:
- slider = Slider(start=1,
- end=num_seqs,
- value=1,
- step=1,
- title="Sequence",
- callback=callback)
-
- layout = column(slider, plot)
- show(layout)
- else:
- show(plot)
+ if backend=='matplotlib':
+ import matplotlib.pyplot as plt
+ from ipywidgets import interact, IntSlider
+ def update_plot(seq_ind):
+ for line_name in line_names:
+ dat = data_dicts[f"{line_name}_{seq_ind}"]
+ plt.plot(dat['x'], dat['y'], label=line_name, linewidth=1.0)
+ interact(update_plot, seq_ind=IntSlider(min=1,max=num_seqs,step=1,value=1,description="Sequence Number"))
+
+ elif backend=='bqplot':
+ from bqplot import DateScale, LinearScale, Axis, Lines, Figure, Tooltip
+ from bqplot.colorschemes import CATEGORY10, CATEGORY20
+ from ipywidgets import interact, IntSlider, VBox
+ sx = LinearScale()
+ sy = LinearScale(min=-1.0, max=2*len(line_names)-1.0)
+ if time:
+ ax = Axis(label='Time (ns)', scale=sx)
+ else:
+ ax = Axis(label="Samples", scale=sx)
+ ay = Axis(label='Amplitude', scale=sy, orientation='vertical')
+
+ colors = CATEGORY10 if len(line_names)<10 else CATEGORY20
+ lines = []
+ tt = Tooltip(fields=['name'], labels=['Channel'])
+ x_mult = 1.0e9 if time else 1
+ for i, line_name in enumerate(line_names):
+ dat = data_dicts[f"{line_name}_1"]
+ lines.append(Lines(labels=[line_name], x=x_mult*dat['x'], y=dat['y'], scales={'x': sx, 'y': sy},
+ tooltip=tt, animate=False, colors=[colors[i]]))
+
+ slider = IntSlider(min=1, max=num_seqs, step=1, description='Segment', value=1)
+ def segment_changed(change):
+ for line, line_name in zip(lines, line_names):
+ dat = data_dicts[f"{line_name}_{slider.value}"]
+ line.x = x_mult*dat['x']
+ line.y = dat['y']
+ slider.observe(segment_changed, 'value')
+ fig = Figure(marks=lines, axes=[ax, ay], title='Waveform Plotter',animation_duration=50)
+ return VBox([slider, fig])
def extract_waveforms(fileNames, nameDecorator='', time=False):
@@ -166,8 +138,8 @@ def extract_waveforms(fileNames, nameDecorator='', time=False):
# Assume a naming convention path/to/file/SequenceName-AWGName.h5
AWGName = "-".join((os.path.split(os.path.splitext(fileName)[0])[1]).split('-')[1:])
# Strip any _ suffix
- if '_' in AWGName:
- AWGName = AWGName[:AWGName.index('_')]
+ # if '_' in AWGName:
+ # AWGName = AWGName[:AWGName.index('_')]
translator = resolve_translator(fileName, translators)
wfs = translator.read_sequence_file(fileName)
@@ -177,7 +149,7 @@ def extract_waveforms(fileNames, nameDecorator='', time=False):
if all_zero_seqs(seqs):
continue
num_seqs = max(num_seqs, len(seqs))
- line_names.append((AWGName + nameDecorator + '_' + k).replace("-","_"))
+ line_names.append((AWGName + nameDecorator + '_' + k).replace("-","_"))
k_ = line_names[-1].replace("-", "_")
for ct, seq in enumerate(seqs):
data_dicts[k_ + "_{:d}".format(ct + 1)] = {}
@@ -193,101 +165,101 @@ def extract_waveforms(fileNames, nameDecorator='', time=False):
return line_names, num_seqs, data_dicts
-def plot_pulse_files_compare(metafile1, metafile2, time=False):
- '''
- plot_pulse_files_compare(fileNames1, fileNames2)
-
- Helper function to plot a list of AWG files. A JS slider allows choice of sequence number.
- '''
- #If we only go one filename turn it into a list
- fileNames1 = []
- fileNames2 = []
-
- with open(metafile1, 'r') as FID:
- meta_info1 = json.load(FID)
-
- for el in meta_info1["instruments"].values():
- # Accomodate seq_file per instrument and per channel
- if isinstance(el, str):
- fileNames1.append(el)
- elif isinstance(el, dict):
- for file in el.values():
- fileNames1.append(file)
-
- with open(metafile2, 'r') as FID:
- meta_info2 = json.load(FID)
-
- for el in meta_info2["instruments"].values():
- # Accomodate seq_file per instrument and per channel
- if isinstance(el, str):
- fileNames2.append(el)
- elif isinstance(el, dict):
- for file in el.values():
- fileNames2.append(file)
-
- line_names1, num_seqs1, data_dicts1 = extract_waveforms(fileNames1, 'A', time=time)
- line_names2, num_seqs2, data_dicts2 = extract_waveforms(fileNames2, 'B', time=time)
- num_seqs = max(num_seqs1, num_seqs2)
- data_dicts1.update(data_dicts2)
- line_names = line_names1 + line_names2
-
- localname = os.path.split(fileNames1[0])[1]
- sequencename = localname.split('-')[0]
-
- data = {line_name: ColumnDataSource(data=dat) for line_name,dat in data_dicts1.items()}
- plot = Figure(title=sequencename, plot_width=1000)
- plot.background_fill_color = config.plotBackground
- if config.gridColor:
- plot.xgrid.grid_line_color = config.gridColor
- plot.ygrid.grid_line_color = config.gridColor
-
- # Colobrewer2 qualitative Set1 (http://colorbrewer2.org)
- colours = [
- "#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33",
- "#a65628", "#f781bf", "#999999"
- ]
-
- js_sources = data
- for ct, k in enumerate(line_names):
- k_ = k.replace("-", "_")
- line = plot.line(data_dicts1[k + "_1"]["x"],
- data_dicts1[k + "_1"]["y"],
- color=colours[ct % len(colours)],
- line_width=2,
- legend=k.replace("_", "-"))
- js_sources[k_] = line.data_source
-
- code_template = Template("""
- var seq_num = cb_obj.getv('value');
- // console.log(seq_num);
- var all_data = {
- {% for trace in trace_names %}
- '{{trace}}': {{trace}}.getv('data'),
- {% endfor %}
- };
- {% for line in line_names %}
- {{line}}['data'] = {'x': (all_data['{{line}}_'.concat(seq_num.toString())])['x'],
- 'y': (all_data['{{line}}_'.concat(seq_num.toString())])['y']};
- {% endfor %}
- """)
- rendered = code_template.render(
- line_names=line_names,
- trace_names=list(data.keys())[:-len(line_names)]
- )
-
- callback = CustomJS(
- args=dict(**js_sources),
- code=rendered)
-
- if num_seqs > 1:
- slider = Slider(start=1,
- end=num_seqs,
- value=1,
- step=1,
- title="Sequence",
- callback=callback)
-
- layout = column(slider, plot)
- show(layout)
- else:
- show(plot)
+# def plot_pulse_files_compare(metafile1, metafile2, time=False):
+# '''
+# plot_pulse_files_compare(fileNames1, fileNames2)
+
+# Helper function to plot a list of AWG files. A JS slider allows choice of sequence number.
+# '''
+# #If we only go one filename turn it into a list
+# fileNames1 = []
+# fileNames2 = []
+
+# with open(metafile1, 'r') as FID:
+# meta_info1 = json.load(FID)
+
+# for el in meta_info1["instruments"].values():
+# # Accomodate seq_file per instrument and per channel
+# if isinstance(el, str):
+# fileNames1.append(el)
+# elif isinstance(el, dict):
+# for file in el.values():
+# fileNames1.append(file)
+
+# with open(metafile2, 'r') as FID:
+# meta_info2 = json.load(FID)
+
+# for el in meta_info2["instruments"].values():
+# # Accomodate seq_file per instrument and per channel
+# if isinstance(el, str):
+# fileNames2.append(el)
+# elif isinstance(el, dict):
+# for file in el.values():
+# fileNames2.append(file)
+
+# line_names1, num_seqs1, data_dicts1 = extract_waveforms(fileNames1, 'A', time=time)
+# line_names2, num_seqs2, data_dicts2 = extract_waveforms(fileNames2, 'B', time=time)
+# num_seqs = max(num_seqs1, num_seqs2)
+# data_dicts1.update(data_dicts2)
+# line_names = line_names1 + line_names2
+
+# localname = os.path.split(fileNames1[0])[1]
+# sequencename = localname.split('-')[0]
+
+# data = {line_name: ColumnDataSource(data=dat) for line_name,dat in data_dicts1.items()}
+# plot = Figure(title=sequencename, plot_width=1000)
+# plot.background_fill_color = config.plotBackground
+# if config.gridColor:
+# plot.xgrid.grid_line_color = config.gridColor
+# plot.ygrid.grid_line_color = config.gridColor
+
+# # Colobrewer2 qualitative Set1 (http://colorbrewer2.org)
+# colours = [
+# "#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33",
+# "#a65628", "#f781bf", "#999999"
+# ]
+
+# js_sources = data
+# for ct, k in enumerate(line_names):
+# k_ = k.replace("-", "_")
+# line = plot.line(data_dicts1[k + "_1"]["x"],
+# data_dicts1[k + "_1"]["y"],
+# color=colours[ct % len(colours)],
+# line_width=2,
+# legend=k.replace("_", "-"))
+# js_sources[k_] = line.data_source
+
+# code_template = Template("""
+# var seq_num = cb_obj.getv('value');
+# // console.log(seq_num);
+# var all_data = {
+# {% for trace in trace_names %}
+# '{{trace}}': {{trace}}.getv('data'),
+# {% endfor %}
+# };
+# {% for line in line_names %}
+# {{line}}['data'] = {'x': (all_data['{{line}}_'.concat(seq_num.toString())])['x'],
+# 'y': (all_data['{{line}}_'.concat(seq_num.toString())])['y']};
+# {% endfor %}
+# """)
+# rendered = code_template.render(
+# line_names=line_names,
+# trace_names=list(data.keys())[:-len(line_names)]
+# )
+
+# callback = CustomJS(
+# args=dict(**js_sources),
+# code=rendered)
+
+# if num_seqs > 1:
+# slider = Slider(start=1,
+# end=num_seqs,
+# value=1,
+# step=1,
+# title="Sequence",
+# callback=callback)
+
+# layout = column(slider, plot)
+# show(layout)
+# else:
+# show(plot)
diff --git a/QGL/PulseSequencer.py b/QGL/PulseSequencer.py
index be0c6143..e25abac8 100644
--- a/QGL/PulseSequencer.py
+++ b/QGL/PulseSequencer.py
@@ -33,11 +33,14 @@
class Pulse(namedtuple("Pulse", ["label", "channel", "length", "amp", "phase", "frequency",
"frameChange", "shapeParams", "isTimeAmp",
"isZero", "ignoredStrParams",
- "maddr", "moffset"])):
+ "maddr", "moffset", "isRunTime"])):
__slots__ = ()
- def __new__(cls, label, channel, shapeParams, amp=1.0, phase=0, frameChange=0, ignoredStrParams=[], maddr=-1, moffset=0):
- if hasattr(channel, 'frequency'):
+ def __new__(cls, label, channel, shapeParams, amp=1.0, phase=0, frameChange=0,
+ ignoredStrParams=[], maddr=-1, moffset=0, frequency=None, isRunTime=False):
+ if frequency:
+ frequency = frequency
+ elif hasattr(channel, 'frequency'):
frequency = channel.frequency
else:
frequency = 0
@@ -46,12 +49,14 @@ def __new__(cls, label, channel, shapeParams, amp=1.0, phase=0, frameChange=0, i
if param not in shapeParams.keys():
raise NameError("shapeParams must include {0}".format(param))
isTimeAmp = (shapeParams['shape_fun'] == PulseShapes.constant)
+ if isRunTime:
+ isTimeAmp = False
isZero = (amp == 0)
return super(cls, Pulse).__new__(cls, label, channel,
shapeParams['length'], amp, phase,
frequency, frameChange, shapeParams,
isTimeAmp, isZero, ignoredStrParams,
- maddr, moffset)
+ maddr, moffset, isRunTime)
def __str__(self):
kwvals = []
@@ -77,6 +82,12 @@ def _repr_pretty_(self, p, cycle):
def hashshape(self):
return hash(frozenset(self.shapeParams.items()))
+ def __hash__(self):
+ d = self._asdict()
+ d['shapeParams'] = self.hashshape()
+ del d['ignoredStrParams']
+ return hash(frozenset(d.items()))
+
def __add__(self, other):
if self.channel != other.channel:
raise NameError(
@@ -107,7 +118,10 @@ def shape(self):
params = copy(self.shapeParams)
params['sampling_rate'] = self.channel.phys_chan.sampling_rate
params.pop('shape_fun')
- return self.shapeParams['shape_fun'](**params)
+ if isinstance(self.shapeParams['shape_fun'],str):
+ return getattr(PulseShapes, self.shapeParams['shape_fun'])(**params)
+ else:
+ return self.shapeParams['shape_fun'](**params)
def TAPulse(label,
@@ -184,6 +198,10 @@ def frameChange(self):
def isZero(self):
return all(p.isZero for p in self.pulses)
+ @property
+ def isRunTime(self):
+ return any(hasattr(entry, 'isRunTime') and entry.isRunTime for entry in self.pulses)
+
class PulseBlock(object):
'''
@@ -248,6 +266,11 @@ def __eq__(self, other):
def __ne__(self, other):
return not self == other
+ @property
+ def isRunTime(self):
+ #Check if any of the member pulses contain a run-time pulse
+ return any([hasattr(entry, 'isRunTime') and entry.isRunTime for entry in self.pulses.values()])
+
@property
def channel(self):
return self.pulses.keys()
@@ -271,7 +294,14 @@ def flatten_to_pulses(obj):
for pulse in obj.pulses.values():
yield from flatten_to_pulses(pulse)
+ def rec_length(obj):
+ if hasattr(obj, "length"):
+ return obj.length
+ else:
+ return rec_length(obj[0])
+
pulse_lengths = np.array([pulse.length for pulse in pulses])
+ # pulse_lengths = np.array([rec_length(pulse) for pulse in pulses])
pad_lengths = max(pulse_lengths) - pulse_lengths
pulse_list = []
for k,pulse in enumerate(pulses):
diff --git a/QGL/PulseShapes.py b/QGL/PulseShapes.py
index 2ba601bf..17899d33 100644
--- a/QGL/PulseShapes.py
+++ b/QGL/PulseShapes.py
@@ -174,7 +174,10 @@ def autodyne(frequency=10e6, baseShape=constant, **params):
'''
A pulse with modulation at a particular frequency baked in.
'''
- shape = baseShape(**params)
+ if isinstance(baseShape,str):
+ shape = globals()[baseShape](**params)
+ else:
+ shape = baseShape(**params)
# Apply the autodyne frequency
timePts = np.linspace(0, params['length'], len(shape))
shape *= np.exp(-1j * 2 * np.pi * frequency * timePts)
diff --git a/QGL/RandomCliffordTools.py b/QGL/RandomCliffordTools.py
new file mode 100644
index 00000000..1f61c34e
--- /dev/null
+++ b/QGL/RandomCliffordTools.py
@@ -0,0 +1,121 @@
+'''
+Functions for dealing with random clifford pulse sequences
+
+Copyright 2019 Raytheon BBN Technologies
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+
+from . import config
+from functools import reduce
+from . import PatternUtils
+from .PatternUtils import flatten, has_gate
+from . import Channels
+from . import ChannelLibraries
+from . import PulseShapes
+from . import PulsePrimitives
+from . import Compiler
+from .PulsePrimitives import Id, clear_pulse_cache
+from .PulseSequencer import Pulse, PulseBlock, CompositePulse
+from . import ControlFlow
+from . import BlockLabel
+from . import TdmInstructions # only for APS2-TDM
+from .APS2CustomInstructions import *
+from .Cliffords import C1, inverse_clifford, clifford_multiply
+
+default_clifford_options = {"offset": 0x0, "spacing": 0x1, "seed": 0x31}
+
+VALID_CLIFFORD_TYPES = ('RandomAC', 'RandomCliff', 'RandomTestCliff', 'RandomDiAC')
+
+def generate_clifford_jump_table(cliff_wires, jt_label = None):
+ """Generate the jump table that will be used to call into the clifford set"""
+
+ if jt_label is None:
+ jt_label = BlockLabel.BlockLabel("JT", jump_table=True, table_size=48)
+ if not isinstance(jt_label, BlockLabel.BlockLabel):
+ raise ValueError("Jump table label must be a BlockLabel.")
+
+ cliff_labels = [BlockLabel.BlockLabel(f"C{n}") for n in range(24)]
+ jump_table = [jt_label]
+ for cl in cliff_labels:
+ jump_table.append(ControlFlow.Call(cl))
+ jump_table.append(ControlFlow.Return())
+
+ for cliff, cl in zip(cliff_wires, cliff_labels):
+ cliff.insert(0, cl)
+ cliff.append(ControlFlow.Return())
+
+ cliff_wires.insert(0, jump_table)
+
+ return jt_label
+
+def insert_clifford_calls(seqs, jt_label=None, cliff_addr=0x3, add_inv = True,
+ inv_addr=0x4, inv_values=[],
+ clifford_options=default_clifford_options):
+
+ if jt_label is None:
+ jt_label = BlockLabel.BlockLabel("JT")
+ if not isinstance(jt_label, BlockLabel.BlockLabel):
+ raise ValueError("Jump table label must be a BlockLabel.")
+
+ #Insert defaults
+ for k,v in default_clifford_options.items():
+ if k not in clifford_options.keys():
+ cliford_options[k] = v
+
+ for idx, seq in enumerate(seqs[:]):
+ if not PatternUtils.contains_runtime_pulses(seq):
+ continue
+
+ new_seq = []
+ inverse_val = 0
+
+ for pulse in seq:
+ if isinstance(pulse, Pulse) and pulse.isRunTime:
+ if pulse.label in VALID_CLIFFORD_TYPES:
+ has_random_cliff = True
+ new_seq.extend(RandomClifford(jt_label, cliff_addr))
+ elif pulse.label == 'RandomInverse':
+ new_seq.extend(RandomCliffordInverse(jt_label, inv_addr))
+ elif pulse.label == 'RandomInverseReset':
+ inverse_val = pulse.maddr
+ else:
+ raise Exception(f"Unhandled run-time pulse: {pulse.label}")
+ #print("Inserting clifford pulse!")
+ else:
+ new_seq.append(pulse)
+
+ if add_inv:
+ w_idx = next(i for i, v in enumerate(new_seq) if isinstance(v, ControlFlow.Wait))
+ new_seq.insert(w_idx, RandomCliffordInverseReset(val=inverse_val))
+ seqs[idx] = new_seq
+
+ #Helper "sequence" to set the random clifford settings.
+ info_seqs = []
+ info_seqs.extend(RandomCliffordSetOffset(0x1, clifford_options["offset"]))
+ info_seqs.extend(RandomCliffordSetSpacing(0x2, clifford_options["spacing"]))
+ info_seqs.extend(RandomCliffordSeed(clifford_options["seed"]))
+ seqs.insert(0, info_seqs)
+
+
+def randomize_clifford_sequences(qubit, seqs, clifford_type=PulsePrimitives.RandomCliff):
+ """Randomize a sequence of cliffords (given as integers).
+ """
+ rseqs = []
+ for seq in seqs:
+ inverse = reduce(clifford_multiply, seq)
+ rseq = ([PulsePrimitives.RandomInverse(qubit, reset_value=inverse)] +
+ [clifford_type(qubit)]*len(seq) +
+ [RandomInverse(qubit), MEAS(qubit)])
+ rseqs.append(rseq)
+ return rseqs
diff --git a/QGL/TdmInstructions.py b/QGL/TdmInstructions.py
index 945743c9..cbb919b5 100644
--- a/QGL/TdmInstructions.py
+++ b/QGL/TdmInstructions.py
@@ -36,22 +36,32 @@ def __eq__(self, other):
def __ne__(self, other):
return not self == other
+ def __str__(self):
+ return f"{self.instruction}({hex(self.in_addr)}, {hex(self.out_addr)})"
+
+ def __repr__(self):
+ return self.__str__()
+
+
def MajorityVote(in_addr, out_addr, nmeas): # alternatively, append the loadcmpvram instruction when compiling (see STOREMEAS)
return [LoadCmpVramInstruction('LOADCMPVRAM', 1, in_addr, 2**nmeas-1, True), CustomInstruction('MAJORITY', in_addr, out_addr)]
def MajorityMask(in_addr, out_addr, value):
- return [WriteAddrInstruction('INVALIDATE', None, 1, in_addr, 0x0, True), WriteAddrInstruction('WRITEADDR', None, 0, in_addr, value, True), LoadCmpVramInstruction('LOADCMPVRAM', 1, in_addr, 0xffff, True), CustomInstruction('MAJORITYMASK', in_addr, out_addr)]
+ return [WriteAddrInstruction('INVALIDATE', None, 1, in_addr, 0x0, True), WriteAddrInstruction('WRITEADDR', None, 0, in_addr, 2**value-1, True), LoadCmpVramInstruction('LOADCMPVRAM', 1, in_addr, 0xffff, True), CustomInstruction('MAJORITYMASK', in_addr, out_addr)]
def Decode(in_addr, out_addr, nmeas):
return [LoadCmpVramInstruction('LOADCMPVRAM', 1, in_addr, 2**nmeas-1, True), CustomInstruction('TSM', in_addr, out_addr)]
def DecodeSetRounds(in_addr, out_addr, value):
- return [WriteAddrInstruction('INVALIDATE', None, 1, in_addr, 0x0, True), WriteAddrInstruction('WRITEADDR', None, 0, in_addr, value, True), LoadCmpVramInstruction('LOADCMPVRAM', 1, in_addr, 0xffff, True), CustomInstruction('TSM_SET_ROUNDS', in_addr, out_addr)]
+ return [WriteAddrInstruction('INVALIDATE', None, 1, in_addr, 0x0, True), WriteAddrInstruction('WRITEADDR', None, 0, in_addr, 2**value-1, True), LoadCmpVramInstruction('LOADCMPVRAM', 1, in_addr, 0xffff, True), CustomInstruction('TSM_SET_ROUNDS', in_addr, out_addr)]
# TODO: the rest of the CUSTOM instructions
-class WriteAddrInstruction(object):
+class VRAMInstruction(object):
+ pass
+
+class WriteAddrInstruction(VRAMInstruction):
def __init__(self, name, channel, modifier, addr, value, tdm, **kwargs):
self.instruction = name
@@ -74,6 +84,12 @@ def __eq__(self, other):
def __ne__(self, other):
return not self == other
+ def __str__(self):
+ return f"{self.instruction}({hex(self.addr)}, {hex(self.value)})"
+
+ def __repr__(self):
+ return self.__str__()
+
def WriteAddr(addr, value, channel=None, tdm=True):
return WriteAddrInstruction('WRITEADDR', channel, 0, addr, value, tdm)
@@ -86,7 +102,7 @@ def CrossBar(addr, value, channel=None, tdm=True): # should this be a high-level
def StoreMeas(addr, value, channel=None, tdm=True):
return WriteAddrInstruction('STOREMEAS', channel, 5, addr, value, tdm)
-class LoadCmpVramInstruction(object):
+class LoadCmpVramInstruction(VRAMInstruction):
def __init__(self, name, use_vram, addr, mask, tdm):
# TODO: sanity checks on input values
@@ -108,6 +124,12 @@ def __eq__(self, other):
def __ne__(self, other):
return not self == other
+ def __str__(self):
+ return f"{self.instruction}({hex(self.addr)}, {hex(self.mask)})"
+
+ def __repr__(self):
+ return self.__str__()
+
-# def LoadCmpVram(addr, mask):
-# return LoadCmpVramInstruction('LOADCMPVRAM', 1, addr, mask)
+def LoadCmpVram(addr, mask, tdm=True):
+ return LoadCmpVramInstruction('LOADCMPVRAM', 1, addr, mask, tdm)
diff --git a/QGL/__init__.py b/QGL/__init__.py
index 2433b99a..82defa84 100644
--- a/QGL/__init__.py
+++ b/QGL/__init__.py
@@ -1,11 +1,12 @@
-from .Channels import Qubit, Measurement, Edge
+from .Channels import Qubit, Measurement, Edge, Generator, ChannelDatabase, Transmitter, Receiver, Transceiver
from .ChannelLibraries import QubitFactory, MeasFactory, EdgeFactory, MarkerFactory, ChannelLibrary, channelLib
+# from .ChannelLibraries import new_APS2, new_X6, new_APS2_rack, new_Alazar, new_qubit, set_control, set_measure, set_master, new_source
from .PulsePrimitives import *
from .Compiler import compile_to_hardware, set_log_level
from .PulseSequencer import align
from .ControlFlow import repeat, repeatall, qif, qwhile, qdowhile, qfunction, qwait, qsync, Barrier
from .BasicSequences import *
-from .Plotting import output_file, output_notebook, show, build_waveforms, plot_waveforms
+from .Plotting import build_waveforms #, show, , plot_waveforms
from .PulseSequencePlotter import plot_pulse_files
from .Tomography import state_tomo, process_tomo
from .Scheduler import schedule
diff --git a/QGL/config.py b/QGL/config.py
index ef088fd6..e8ae133d 100644
--- a/QGL/config.py
+++ b/QGL/config.py
@@ -1,18 +1,30 @@
#Package configuration information
import os.path
+import sys
import re
-import yaml
+import importlib
+import tempfile
+import logging
+
+logger = logging.getLogger("QGL")
# Where to store AWG data
-AWGDir = None
+if os.getenv('AWG_DIR'):
+ AWGDir = os.getenv('AWG_DIR')
+else:
+ logger.warning("AWG_DIR environment variable not defined. Unless otherwise specified, using temporary directory for AWG sequence file outputs.")
+ AWGDir = tempfile.mkdtemp(prefix="AWG")
+
+# The db file, where the channel libraries are stored
+db_resource_name = None
-# The measurement file
-meas_file = None
+# The config file (executed upon channel library loading)
+# config_file = None
# plotting options
-plotBackground = '#EAEAF2'
-gridColor = None
+plotBackground = '#EAEAF2'
+gridColor = None
# select pulse library (standard or all90)
pulse_primitives_lib = "standard"
@@ -21,77 +33,18 @@
# CNOT in your gate set, e.g. CNOT_simple or CNOT_CR)
cnot_implementation = "CNOT_simple"
-class LoaderMeta(type):
- def __new__(metacls, __name__, __bases__, __dict__):
- """Add include constructer to class."""
- # register the include constructor on the class
- cls = super().__new__(metacls, __name__, __bases__, __dict__)
- cls.add_constructor('!include', cls.construct_include)
- return cls
-class Loader(yaml.Loader, metaclass=LoaderMeta):
- """YAML Loader with `!include` constructor."""
- def __init__(self, stream):
- """Initialise Loader."""
- try:
- self._root = os.path.split(stream.name)[0]
- except AttributeError:
- self._root = os.path.curdir
- super().__init__(stream)
- self.add_implicit_resolver(
- u'tag:yaml.org,2002:float',
- re.compile(u'''^(?:
- [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
- |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
- |\\.[0-9_]+(?:[eE][-+][0-9]+)?
- |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*
- |[-+]?\\.(?:inf|Inf|INF)
- |\\.(?:nan|NaN|NAN))$''', re.X),
- list(u'-+0123456789.'))
- self.filenames = [os.path.abspath(stream.name)]
- def construct_include(self, node):
- """Include file referenced at node."""
- filename = os.path.abspath(os.path.join(
- self._root, self.construct_scalar(node)
- ))
- extension = os.path.splitext(filename)[1].lstrip('.')
- self.filenames.append(filename)
- with open(filename, 'r') as f:
- if extension in ('yaml', 'yml'):
- return yaml.load(f, Loader)
- else:
- return ''.join(f.readlines())
-
-def find_meas_file():
- if os.getenv('BBN_MEAS_FILE'):
- return os.getenv('BBN_MEAS_FILE')
- raise Exception("Could not find the measurement file in the environment variables or the auspex globals.")
-
-def load_config(filename=None):
- global meas_file, AWGDir, plotBackground, gridColor, pulse_primitives_lib, cnot_implementation
-
- if filename:
- meas_file = filename
- else:
- meas_file = find_meas_file()
-
- with open(meas_file, 'r') as FID:
- # cfg = yaml.load(f)
- loader = Loader(FID)
+def load_config():
+ global config_file
+ if os.getenv('BBN_CONFIG'):
try:
- cfg = loader.get_single_data()
- finally:
- loader.dispose()
-
- # pull out the variables
- # abspath allows the use of relative file names in the config file
- if 'AWGDir' in cfg['config'].keys():
- AWGDir = os.path.abspath(cfg['config']['AWGDir'])
- else:
- raise KeyError("Could not find AWGDir in the YAML config section")
-
- plotBackground = cfg['config'].get('PlotBackground', '#EAEAF2')
- gridColor = cfg['config'].get('GridColor', None)
- pulse_primitives_lib = cfg['config'].get('PulsePrimitivesLibrary', 'standard')
- cnot_implementation = cfg['config'].get('cnot_implementation', 'CNOT_simple')
-
- return meas_file
\ No newline at end of file
+ config_file = os.getenv("BBN_CONFIG")
+ sys.path.append(os.path.dirname(config_file))
+ importlib.import_module(os.path.splitext(os.path.basename(config_file))[0])
+ except:
+ raise Exception(f"Could not import/execute the BBN_CONFIG {os.getenv('BBN_CONFIG')}")
+
+def load_db():
+ global db_resource_name
+ if os.getenv('BBN_DB'):
+ db_resource_name = os.getenv("BBN_DB")
+ return db_resource_name
\ No newline at end of file
diff --git a/QGL/config_location.py b/QGL/config_location.py
index 16566195..d9304dec 100644
--- a/QGL/config_location.py
+++ b/QGL/config_location.py
@@ -50,7 +50,7 @@
CONFIG_PATH = None
-_CONFIG_FILE_NAME = 'config.json'
+_CONFIG_FILE_NAME = 'BBN_config.py'
def _set_default_config_path():
"""
diff --git a/QGL/drivers/APS2Pattern.py b/QGL/drivers/APS2Pattern.py
index 224690e3..6ece1645 100644
--- a/QGL/drivers/APS2Pattern.py
+++ b/QGL/drivers/APS2Pattern.py
@@ -1,5 +1,5 @@
'''
-Module for writing hdf5 APS2 files from sequences and patterns
+Module for writing .aps APS2 files from sequences and patterns
Copyright 2014 Raytheon BBN Technologies
@@ -20,16 +20,19 @@
import logging
from warnings import warn
from copy import copy
-from future.moves.itertools import zip_longest
+from itertools import zip_longest
import pickle
-import h5py
+import struct
+import sys
import numpy as np
from QGL import Compiler, ControlFlow, BlockLabel, PatternUtils
from QGL import PulseSequencer
from QGL.PatternUtils import hash_pulse, flatten
from QGL import TdmInstructions
+from QGL import APS2CustomInstructions
+from QGL.APS2CustomInstructions import APS2_CUSTOM, APS2_CUSTOM_DECODE
# Python 2/3 compatibility: use 'int' that subclasses 'long'
from builtins import int
@@ -85,15 +88,12 @@
CMPTABLE = {'==': EQUAL, '!=': NOTEQUAL, '>': GREATERTHAN, '<': LESSTHAN}
-# custom OP_CODES
+# custom TDM OP_CODES
TDM_MAJORITY_VOTE = 0
TDM_MAJORITY_VOTE_SET_MASK = 1
TDM_TSM_SET_ROUNDS = 2
TDM_TSM = 3
-APS_CUSTOM_DECODE = ["APS_RAND", "APS_CLIFFORD_RAND","APS_CLIFFORD_SET_SEED" ,"APS_CLIFFORD_SET_OFFSET"
-, "APS_CLIFFORD_SET_SPACING"]
-
TDM_CUSTOM_DECODE = ["TDM_MAJORITY_VOTE", "TDM_MAJORITY_VOTE_SET_MASK", "TDM_TSM_SET_ROUNDS", "TDM_TSM"]
# Whether we use PHASE_OFFSET modulation commands or bake it into waveform
@@ -107,19 +107,15 @@
SEQFILE_PER_CHANNEL = False
def get_empty_channel_set():
- return {'ch12': {}, 'ch12m1': {}, 'ch12m2': {}, 'ch12m3': {}, 'ch12m4': {}}
-
+ return {'ch1': {}, 'm1': {}, 'm2': {}, 'm3': {}, 'm4': {}}
def get_seq_file_extension():
- return '.h5'
-
+ return '.aps2'
def is_compatible_file(filename):
- with h5py.File(filename, 'r') as FID:
- target = FID['/'].attrs['target hardware']
- if isinstance(target, str):
- target = target.encode('utf-8')
- if target == b'APS2':
+ with open(filename, 'rb') as FID:
+ byte = FID.read(4)
+ if byte == b'APS2':
return True
return False
@@ -164,7 +160,7 @@ def create_wf_vector(wfLib, seqs):
else:
#otherwise fill in one cache line at a time
- CACHE_LINE_LENGTH = WAVEFORM_CACHE_SIZE / 2
+ CACHE_LINE_LENGTH = int(np.round(WAVEFORM_CACHE_SIZE / 2)) - 1
wfVec = np.zeros(CACHE_LINE_LENGTH, dtype=np.int16)
offsets = [{}]
cache_lines = []
@@ -182,7 +178,7 @@ def create_wf_vector(wfLib, seqs):
idx = int(CACHE_LINE_LENGTH * (
(idx + CACHE_LINE_LENGTH) // CACHE_LINE_LENGTH))
wfVec = np.append(wfVec,
- np.zeros(CACHE_LINE_LENGTH,
+ np.zeros(int(CACHE_LINE_LENGTH),
dtype=np.int16))
offsets.append({})
@@ -263,9 +259,9 @@ def __str__(self):
wfOpCode = (self.payload >> 46) & 0x3
wfOpCodes = ["PLAY", "TRIG", "SYNC", "PREFETCH"]
out += wfOpCodes[wfOpCode]
- out += "; TA bit={}".format((self.payload >> 45) & 0x1)
- out += ", count = {}".format((self.payload >> 24) & 2**21 - 1)
- out += ", addr = {}".format(self.payload & 2**24 - 1)
+ out += "; TA_bit={}".format((self.payload >> 45) & 0x1)
+ out += ", count={}".format((self.payload >> 24) & 2**21 - 1)
+ out += ", addr={}".format(self.payload & 2**24 - 1)
# # APS3/TDM modifier to use VRAM output
# if self.payload & (1 << 48):
@@ -276,7 +272,7 @@ def __str__(self):
mrkOpCodes = ["PLAY", "TRIG", "SYNC"]
out += mrkOpCodes[mrkOpCode]
out += "; state={}".format((self.payload >> 32) & 0x1)
- out += ", count = {}".format(self.payload & 2**32 - 1)
+ out += ", count={}".format(self.payload & 2**32 - 1)
elif instrOpCode == MODULATION:
modulatorOpCode = (self.payload >> 45) & 0x7
@@ -298,21 +294,27 @@ def __str__(self):
cmpCodes = ["EQUAL", "NOTEQUAL", "GREATERTHAN", "LESSTHAN"]
cmpCode = (self.payload >> 8) & 0x3
out += " | " + cmpCodes[cmpCode]
- out += ", value = {}".format(self.payload & 0xff)
+ out += ", value={}".format(self.payload & 0xff)
elif any(
[instrOpCode == op for op in [GOTO, CALL, RET, REPEAT, PREFETCH]]):
- out += " | target addr = {}".format(self.payload & 2**26 - 1)
+ if self.use_ram:
+ out += " RAM"
+ out += " | target_addr={}".format(self.payload & 2**26 - 1)
+
elif instrOpCode == LOAD:
- out += " | count = {}".format(self.payload)
+ out += " | count={}".format(self.payload)
elif instrOpCode == CUSTOM:
store_addr = self.payload & 0xFFFF
load_addr = (self.payload >> 16) & 0xFFFF
instruction = (self.payload >> 32) & 0xFF
- instructionAPS = TDM_CUSTOM_DECODE[instruction]
- out += " | instruction = {0} ({1}), load_addr = 0x{2:0x}, store_addr = 0x{3:0x}".format(instruction, instructionAPS, load_addr, store_addr)
+ if self.decode_as_tdm:
+ instructionAPS = TDM_CUSTOM_DECODE[instruction]
+ else:
+ instructionAPS = APS2_CUSTOM_DECODE[instruction]
+ out += " | instruction={0} ({1}), load_addr=0x{2:0x}, store_addr=0x{3:0x}".format(instruction, instructionAPS, load_addr, store_addr)
elif instrOpCode == WRITEADDR:
addr = self.payload & 0xFFFF
@@ -338,19 +340,18 @@ def __str__(self):
addr = (self.payload >> 16) & 0xFFFF
value = (self.payload >> 32) & 0xFFFF
- out += "{0} | addr = 0x{1:0x}, {2} = 0x{3:0x}".format(instrStr, addr, valueType, value)
+ out += "{0} | addr=0x{1:0x}, {2}=0x{3:0x}".format(instrStr, addr, valueType, value)
elif instrOpCode == LOADCMP:
addr = self.payload & 0xFFFF
mask = (self.payload >> 16) & 0xFFFF
- use_ram = (self.payload >> 48) & 0x1
- if self.decode_as_tdm and not use_ram:
+ if self.decode_as_tdm and not self.use_ram:
out += "WAITMEAS"
else:
src = "EXT"
- if use_ram:
+ if self.use_ram:
src = "RAM"
- out += "LOADCMP | source = {0}, addr = 0x{1:0x}, read_mask = 0x{2:0x}".format(src, addr, mask)
+ out += "LOADCMP | source={0}, addr=0x{1:0x}, read_mask=0x{2:0x}".format(src, addr, mask)
return out
def __eq__(self, other):
@@ -362,6 +363,9 @@ def __ne__(self, other):
def __hash__(self):
return hash((self.header, self.payload, self.label))
+ def isa(self, value):
+ return (self.header >> 4) == value
+
@property
def address(self):
return self.payload & 0xffffffff # bottom 32-bits of payload
@@ -376,7 +380,17 @@ def writeFlag(self):
@writeFlag.setter
def writeFlag(self, value):
- self.header |= value & 0x1
+ self.header &= ~(0x1 << 0) #clear bit
+ self.header |= (value & 0x1) #set bit
+
+ @property
+ def use_ram(self):
+ return ((self.payload >> 48) & 0x1)
+
+ @use_ram.setter
+ def use_ram(self, value):
+ self.payload &= ~(0x1 << 48) #clear bit
+ self.payload |= ((value & 0x1) << 48)
@property
def opcode(self):
@@ -449,8 +463,10 @@ def Goto(addr, label=None):
return Command(GOTO, addr, label=label)
-def Call(addr, label=None):
- return Command(CALL, addr, label=label)
+def Call(addr, indirect=False, label=None):
+ cmd = Command(CALL, addr, label=label)
+ cmd.use_ram = indirect
+ return cmd
def Return(label=None):
@@ -515,7 +531,6 @@ def LoadCmpVram(addr, mask, label=None):
payload = (1 << 48) | (mask << 16) | addr
return Instruction(header, payload, label=label)
-
def preprocess(seqs, shapeLib):
seqs = PatternUtils.convert_lengths_to_samples(
seqs, SAMPLING_RATE, ADDRESS_UNIT, Compiler.Waveform)
@@ -584,19 +599,13 @@ def to_instruction(self, write_flag=True, label=None):
NCO_SELECT_OP_OFFSET = 40
MODULATION_CLOCK = 300e6
- nco_select_bits = {1 : 0b0001,
- 2 : 0b0010,
- 3 : 0b0100,
- 4 : 0b1000,
- 15: 0b1111}[self.nco_select]
-
op_code_map = {"MODULATE": 0x0,
"RESET_PHASE": 0x2,
"SET_FREQ": 0x6,
"SET_PHASE": 0xa,
"UPDATE_FRAME": 0xe}
payload = (op_code_map[self.instruction] << MODULATOR_OP_OFFSET) | (
- (nco_select_bits) << NCO_SELECT_OP_OFFSET)
+ (self.nco_select) << NCO_SELECT_OP_OFFSET)
if self.instruction == "MODULATE":
#zero-indexed quad count
payload |= np.uint32(self.length / ADDRESS_UNIT - 1)
@@ -624,33 +633,38 @@ def inject_modulation_cmds(seqs):
for ct,seq in enumerate(seqs):
#check whether we have modulation commands
freqs = np.unique([entry.frequency for entry in filter(lambda s: isinstance(s,Compiler.Waveform), seq)])
- if len(freqs) > NUM_NCO:
- raise Exception("Max {} frequencies on the same channel allowed.".format(NUM_NCO))
- no_freq_cmds = np.allclose(freqs, 0)
+ if len(freqs) > 2:
+ raise Exception("Max {} frequencies on the same channel allowed.".format(2))
+ no_freq_cmds = np.all(np.less(np.abs(freqs), 1e-8))
phases = [entry.phase for entry in filter(lambda s: isinstance(s,Compiler.Waveform), seq)]
- no_phase_cmds = np.allclose(phases, 0)
+ no_phase_cmds = np.all(np.less(np.abs(phases), 1e-8))
frame_changes = [entry.frameChange for entry in filter(lambda s: isinstance(s,Compiler.Waveform), seq)]
- no_frame_cmds = np.allclose(frame_changes, 0)
+ no_frame_cmds = np.all(np.less(np.abs(frame_changes), 1e-8))
no_modulation_cmds = no_freq_cmds and no_phase_cmds and no_frame_cmds
-
if no_modulation_cmds:
continue
mod_seq = []
pending_frame_update = False
+ force_phase_update = False
+
+ #check to see if we are in a subroutine by using last instruction as return as a tell
+ #if so, ensure frame updates do not get dropped
+ if isinstance(seq[-1], ControlFlow.Return):
+ force_phase_update = True
for entry in seq:
#copies to avoid same object having different timestamps later
#copy through BlockLabel
- if isinstance(entry, BlockLabel.BlockLabel):
+ if isinstance(entry, BlockLabel.BlockLabel) or isinstance(entry, TdmInstructions.CustomInstruction):
mod_seq.append(copy(entry))
#mostly copy through control-flow
- elif isinstance(entry, ControlFlow.ControlInstruction) or isinstance(entry, TdmInstructions.LoadCmpVramInstruction) or isinstance(entry, TdmInstructions.WriteAddrInstruction):
+ elif isinstance(entry, ControlFlow.ControlInstruction) or isinstance(entry, TdmInstructions.VRAMInstruction):
#heuristic to insert phase reset before trigger if we have modulation commands
if isinstance(entry, ControlFlow.Wait):
if not ( no_modulation_cmds and (cur_freq == 0) and (cur_phase == 0)):
- mod_seq.append(ModulationCommand("RESET_PHASE", 0xF))
+ mod_seq.append(ModulationCommand("RESET_PHASE", 0x3))
for nco_ind, freq in enumerate(freqs):
mod_seq.append( ModulationCommand("SET_FREQ", nco_ind + 1, frequency = -freq) )
elif isinstance(entry, ControlFlow.Return):
@@ -675,10 +689,11 @@ def inject_modulation_cmds(seqs):
mod_seq.append( ModulationCommand("MODULATE", nco_select, length = entry.length))
pending_frame_update = False
#now apply non-zero frame changes after so it is applied at end
+
if entry.frameChange != 0:
pending_frame_update = True
#zero length frame changes (Z pulses) need to be combined with the previous frame change or injected where possible
- if entry.length == 0:
+ if entry.length == 0 and not force_phase_update:
#if the last is a frame change then we can add to the frame change
if isinstance(mod_seq[-1], ModulationCommand) and mod_seq[-1].instruction == "UPDATE_FRAME":
mod_seq[-1].phase += entry.frameChange
@@ -725,7 +740,6 @@ def synchronize_clocks(seqs):
syncInstructions = [list(filter(
lambda s: isinstance(s, ControlFlow.ControlInstruction), seq))
for seq in seqs if seq]
-
# Add length to control-flow instructions to make accumulated time match at end of CFI.
# Keep running tally of how much each channel has been shifted so far.
localShift = [0 for _ in syncInstructions]
@@ -805,14 +819,13 @@ def create_seq_instructions(seqs, offsets, label = None):
write_flags = [True] * len(entries)
for ct, (entry, seq_idx) in enumerate(entries):
-
#use first non empty sequence for control flow
if seq_idx == first_non_empty and (
isinstance(entry, ControlFlow.ControlInstruction) or
isinstance(entry, BlockLabel.BlockLabel) or
isinstance(entry, TdmInstructions.CustomInstruction) or
- isinstance(entry, TdmInstructions.WriteAddrInstruction) or
- isinstance(entry, TdmInstructions.LoadCmpVramInstruction)):
+ #isinstance(entry, TdmInstructions.Instruction) or ??????
+ isinstance(entry, TdmInstructions.VRAMInstruction)):
if isinstance(entry, BlockLabel.BlockLabel):
# carry label forward to next entry
label = entry
@@ -830,7 +843,7 @@ def create_seq_instructions(seqs, offsets, label = None):
elif isinstance(entry, ControlFlow.Goto):
instructions.append(Goto(entry.target, label=label))
elif isinstance(entry, ControlFlow.Call):
- instructions.append(Call(entry.target, label=label))
+ instructions.append(Call(entry.target, indirect = entry.indirect, label=label))
elif isinstance(entry, ControlFlow.Repeat):
instructions.append(Repeat(entry.target, label=label))
# value argument commands
@@ -845,11 +858,19 @@ def create_seq_instructions(seqs, offsets, label = None):
instructions.append(LoadCmpVram(entry.addr, entry.mask, label=label))
# some TDM instructions are ignored by the APS
elif isinstance(entry, TdmInstructions.CustomInstruction):
- pass
+ #print(str(entry))
+ try:
+ instructions.append(Custom(entry.in_addr, entry.out_addr,
+ APS2_CUSTOM[entry.instruction], label=label))
+ except KeyError as e:
+ raise Exception(f"Got unknown APS2 instruction: {e.args[0]} in {str(entry)}.")
elif isinstance(entry, TdmInstructions.WriteAddrInstruction):
+ #print(str(entry))
if entry.instruction == 'INVALIDATE' and entry.tdm == False:
instructions.append(Invalidate(entry.addr, entry.value, label=label))
-
+ if entry.instruction == 'WRITEADDR' and entry.tdm == False:
+ instructions.append(WriteAddr(entry.addr, entry.value, label=label))
+ label=None #Reset label to prevent it propagating in a jump table
continue
if seq_idx == 0:
@@ -929,7 +950,6 @@ def create_instr_data(seqs, offsets, cache_lines):
except:
pass
instructions += seq
-
#if we have any subroutines then group in cache lines
if subroutines_start >= 0:
subroutine_instrs = []
@@ -957,12 +977,25 @@ def create_instr_data(seqs, offsets, cache_lines):
CACHE_LINE_LENGTH))
#inject prefetch commands before waits
wait_idx = [idx for idx, instr in enumerate(instructions)
- if (instr.header >> 4) == WAIT] + [len(instructions)]
+ if instr.isa(WAIT)] + [len(instructions)]
instructions_with_prefetch = instructions[:wait_idx[0]]
last_prefetch = None
+
for start, stop in zip(wait_idx[:-1], wait_idx[1:]):
call_targets = [instr.target for instr in instructions[start:stop]
- if (instr.header >> 4) == CALL]
+ if instr.isa(CALL)]
+
+ #Check if we call into any jump tables
+ jump_tables = [label for label in call_targets if label.jump_table]
+ if len(jump_tables) > 0:
+ for jt in set(jump_tables):
+ #Find the start of the jump table
+ start_idx = next(j for j, instr in enumerate(subroutine_instrs)
+ if instr.label == jt)
+ stop_idx = start_idx + jt.table_size
+ call_targets.extend([instr.target for instr in
+ subroutine_instrs[start_idx:stop_idx]
+ if instr.isa(CALL)])
needed_lines = set()
for target in call_targets:
needed_lines.add(subroutine_cache_line[target])
@@ -979,9 +1012,9 @@ def create_instr_data(seqs, offsets, cache_lines):
#pad out instruction vector to ensure circular cache never loads a subroutine
pad_instrs = 7 * 128 + (128 - ((len(instructions) + 128) % 128))
instructions += [NoOp()] * pad_instrs
-
instructions += subroutine_instrs
+
#turn symbols into integers addresses
resolve_symbols(instructions)
@@ -993,20 +1026,28 @@ def create_instr_data(seqs, offsets, cache_lines):
def resolve_symbols(seq):
- symbols = {}
- # create symbol look-up table
- for ct, entry in enumerate(seq):
- if entry.label and entry.label not in symbols:
- symbols[entry.label] = ct
- # then update
- for (ct, entry) in enumerate(seq):
- if entry.target:
- # find next available label. The TDM may miss some labels if branches only contain waveforms (which are ignored)
- for k in range(len(seq)-ct):
- temp = seq[ct+k]
- if temp.target in symbols:
- break
- entry.address = symbols[temp.target]
+
+ labeled_entries = [(idx, entry.label) for idx, entry in enumerate(seq) if entry.label is not None]
+ symbols = {label: idx for idx, label in labeled_entries}
+ logger.info(f"Found labels: {symbols}")
+ for entry in seq:
+ if entry.target is not None and entry.target in symbols.keys():
+ entry.address = symbols[entry.target]
+
+ # symbols = {}
+ # # create symbol look-up table
+ # for ct, entry in enumerate(seq):
+ # if entry.label and entry.label not in symbols:
+ # symbols[entry.label] = ct
+ # # then update
+ # for (ct, entry) in enumerate(seq):
+ # if entry.target:
+ # # find next available label. The TDM may miss some labels if branches only contain waveforms (which are ignored)
+ # for k in range(len(seq)-ct):
+ # temp = seq[ct+k]
+ # if temp.label in symbols:
+ # break
+ # entry.address = symbols[temp.label]
def compress_marker(markerLL):
@@ -1031,11 +1072,11 @@ def write_sequence_file(awgData, fileName):
Main function to pack channel sequences into an APS2 h5 file.
'''
# Convert QGL IR into a representation that is closer to the hardware.
- awgData['ch12']['linkList'], wfLib = preprocess(
- awgData['ch12']['linkList'], awgData['ch12']['wfLib'])
+ awgData['ch1']['linkList'], wfLib = preprocess(
+ awgData['ch1']['linkList'], awgData['ch1']['wfLib'])
# compress marker data
- for field in ['ch12m1', 'ch12m2', 'ch12m3', 'ch12m4']:
+ for field in ['m1', 'm2', 'm3', 'm4']:
if 'linkList' in awgData[field].keys():
PatternUtils.convert_lengths_to_samples(awgData[field]['linkList'],
SAMPLING_RATE, 1,
@@ -1048,10 +1089,10 @@ def write_sequence_file(awgData, fileName):
wfInfo = []
wfInfo.append(create_wf_vector({key: wf.real
for key, wf in wfLib.items()}, awgData[
- 'ch12']['linkList']))
+ 'ch1']['linkList']))
wfInfo.append(create_wf_vector({key: wf.imag
for key, wf in wfLib.items()}, awgData[
- 'ch12']['linkList']))
+ 'ch1']['linkList']))
if SAVE_WF_OFFSETS:
#create a set of all waveform signatures in offset dictionaries
@@ -1062,7 +1103,7 @@ def write_sequence_file(awgData, fileName):
wf_sigs |= set(offset_dict.keys())
#create dictionary linking entry labels (that's what we'll have later) with offsets
offsets = {}
- for seq in awgData['ch12']['linkList']:
+ for seq in awgData['ch1']['linkList']:
for entry in seq:
if len(wf_sigs) == 0:
break
@@ -1086,45 +1127,42 @@ def write_sequence_file(awgData, fileName):
# build instruction vector
seq_data = [awgData[s]['linkList']
- for s in ['ch12', 'ch12m1', 'ch12m2', 'ch12m3', 'ch12m4']]
+ for s in ['ch1', 'm1', 'm2', 'm3', 'm4']]
instructions = create_instr_data(seq_data, wfInfo[0][1], wfInfo[0][2])
- #Open the HDF5 file
+ #Open the binary file
if os.path.isfile(fileName):
os.remove(fileName)
- with h5py.File(fileName, 'w') as FID:
- FID['/'].attrs['Version'] = 4.0
- FID['/'].attrs['target hardware'] = 'APS2'
- FID['/'].attrs['minimum firmware version'] = 4.0
- FID['/'].attrs['channelDataFor'] = np.uint16([1, 2])
+
+ with open(fileName, 'wb') as FID:
+ FID.write(b'APS2') # target hardware
+ FID.write(np.float32(4.0).tobytes()) # Version
+ FID.write(np.float32(4.0).tobytes()) # minimum firmware version
+ FID.write(np.uint16(2).tobytes()) # number of channels
+ # FID.write(np.uint16([1, 2]).tobytes()) # channelDataFor
+ FID.write(np.uint64(instructions.size).tobytes()) # instructions length
+ FID.write(instructions.tobytes()) # instructions in uint64 form
#Create the groups and datasets
for chanct in range(2):
- chanStr = '/chan_{0}'.format(chanct + 1)
- chanGroup = FID.create_group(chanStr)
#Write the waveformLib to file
if wfInfo[chanct][0].size == 0:
#If there are no waveforms, ensure that there is some element
#so that the waveform group gets written to file.
#TODO: Fix this in libaps2
- data = np.array([0], dtype=np.uint16)
+ data = np.array([0], dtype=np.int16)
else:
data = wfInfo[chanct][0]
- FID.create_dataset(chanStr + '/waveforms', data=data)
-
- #Write the instructions to channel 1
- if np.mod(chanct, 2) == 0:
- FID.create_dataset(chanStr + '/instructions',
- data=instructions)
-
+ FID.write(np.uint64(data.size).tobytes()) # waveform data length for channel
+ FID.write(data.tobytes())
def read_sequence_file(fileName):
"""
- Reads a HDF5 sequence file and returns a dictionary of lists.
- Dictionary keys are channel strings such as ch1, ch12m1
+ Reads a .aps sequence file and returns a dictionary of lists.
+ Dictionary keys are channel strings such as ch1, m1
Lists are or tuples of time-amplitude pairs (time, output)
"""
- chanStrs = ['ch1', 'ch2', 'ch12m1', 'ch12m2', 'ch12m3', 'ch12m4',
+ chanStrs = ['ch1', 'ch2', 'm1', 'm2', 'm3', 'm4',
'mod_phase']
seqs = {ch: [] for ch in chanStrs}
@@ -1137,16 +1175,22 @@ def start_new_seq():
#marker channel
seqs[ch].append([])
- with h5py.File(fileName, 'r') as FID:
- file_version = FID["/"].attrs["Version"]
+ with open(fileName, 'rb') as FID:
+ target_hw = FID.read(4).decode('utf-8')
+ file_version = struct.unpack('> 2) & 0x3) + 1)
+ chan = 'm' + str(((instr.header >> 2) & 0x3) + 1)
count = instr.payload & 0xffffffff
count = (count + 1) * ADDRESS_UNIT
state = (instr.payload >> 32) & 0x1
@@ -1452,14 +1496,16 @@ def write_tdm_seq(seq, tdm_fileName):
# Utility Functions for displaying programs
-def get_channel_instructions_string(channel):
- return '/chan_{}/instructions'.format(channel)
+def raw_instructions(fileName):
+ with open(fileName, 'rb') as FID:
+ target_hw = FID.read(4).decode('utf-8')
+ file_version = struct.unpack(' 0).tobytes()) # LL for chan1
+ FID.write(np.uint8(len(LLData[1]) > 0).tobytes()) # LL for chan3
+ for chanct in [0,2]:
#For A channels (1 & 3) we write link list data if we actually have any
- if (np.mod(chanct, 2) == 0) and LLData[chanct // 2]:
- groupStr = chanStr + '/linkListData'
- LLGroup = FID.create_group(groupStr)
+ if LLData[chanct // 2]:
LLDataVecs, numEntries = create_LL_data(
LLData[chanct // 2], wfInfo[chanct][1],
os.path.basename(fileName))
- LLGroup.attrs['length'] = numEntries
+ FID.write(np.uint64(len(LLDataVecs.keys())).tobytes()) # numKeys
+ FID.write(np.uint64(numEntries).tobytes()) # numEntries
for key, dataVec in LLDataVecs.items():
- FID.create_dataset(groupStr + '/' + key, data=dataVec)
- else:
- chanGroup.attrs['isLinkListData'] = np.uint8(0)
+ FID.write(key.ljust(32,"#").encode("utf-8")) # Key 32 byte utf-8
+ FID.write(dataVec.tobytes()) # Data np.uint16
def read_sequence_file(fileName):
@@ -741,79 +736,99 @@ def read_sequence_file(fileName):
chanStrs = ['ch1', 'ch2', 'ch3', 'ch4']
chanStrs2 = ['chan_1', 'chan_2', 'chan_3', 'chan_4']
mrkStrs = ['ch1m1', 'ch2m1', 'ch3m1', 'ch4m1']
-
- with h5py.File(fileName, 'r') as FID:
- for chanct, chanStr in enumerate(chanStrs2):
- #If we're in IQ mode then the Q channel gets its linkListData from the I channel
- if FID[chanStr].attrs['isIQMode']:
- tmpChan = 2 * (chanct // 2)
- curLLData = FID[chanStrs2[tmpChan]][
- 'linkListData'] if "linkListData" in FID[chanStrs2[
- tmpChan]] else []
- else:
- curLLData = FID[chanStr][
- 'linkListData'] if "linkListData" in FID[chanStrs2[
- tmpChan]] else []
-
- if curLLData:
- #Pull out the LL data in sample units
- #Cast type to avoid uint16 overflow
- addr = (curLLData['addr'].value.astype(np.uint)) * ADDRESS_UNIT
- count = ((curLLData['count'].value + 1).astype(np.uint)
- ) * ADDRESS_UNIT
- repeat = curLLData['repeat'].value
- trigger1 = (
- curLLData['trigger1'].value.astype(np.uint)) * ADDRESS_UNIT
- trigger2 = (
- curLLData['trigger2'].value.astype(np.uint)) * ADDRESS_UNIT
-
- #Pull out and scale the waveform data
- wf_lib = (
- 1.0 /
- MAX_WAVEFORM_VALUE) * FID[chanStr]['waveformLib'].value
-
- #Initialize the lists of time-amplitude pairs
- AWGData[chanStrs[chanct]] = []
- AWGData[mrkStrs[chanct]] = []
-
- cum_time = 0
-
- #Loop over LL entries
- for ct in range(curLLData.attrs['length']):
- #If we are starting a new sequence push back an empty array
- if START_MINILL_MASK & repeat[ct]:
- AWGData[chanStrs[chanct]].append([])
- trigger_delays = [0]
- cum_time = 0
-
- #Record the trigger delays
- if np.mod(chanct, 2) == 0:
- if trigger1[ct] > 0:
- trigger_delays.append(cum_time + trigger1[ct])
- else:
- if trigger2[ct] > 0:
- trigger_delays.append(cum_time + trigger2[ct])
-
- #waveforms
- wf_repeat = (repeat[ct] & REPEAT_MASK) + 1
- if TA_PAIR_MASK & repeat[ct]:
- AWGData[chanStrs[chanct]][-1].append(
- (wf_repeat * count[ct], wf_lib[addr[ct]]))
- else:
- for repct in range(wf_repeat):
- for sample in wf_lib[addr[ct]:addr[ct] + count[
- ct]]:
- AWGData[chanStrs[chanct]][-1].append(
- (1, sample))
-
- cum_time += count[ct]
-
- #Create the trigger sequence
- if END_MINILL_MASK & repeat[ct]:
- AWGData[mrkStrs[chanct]].append([])
- for delay in np.diff(trigger_delays):
- AWGData[mrkStrs[chanct]][-1].append((delay - 1, 0))
- AWGData[mrkStrs[chanct]][-1].append((1, 1))
+
+ data = {}
+ with open(fileName, 'rb') as FID:
+ target_hw = FID.read(4).decode('utf-8')
+ file_version = struct.unpack(' 0:
+ trigger_delays.append(cum_time + trigger1[ct])
+ else:
+ if trigger2[ct] > 0:
+ trigger_delays.append(cum_time + trigger2[ct])
+
+ #waveforms
+ wf_repeat = (repeat[ct] & REPEAT_MASK) + 1
+ if TA_PAIR_MASK & repeat[ct]:
+ AWGData[chanStrs[chanct]][-1].append(
+ (wf_repeat * count[ct], wf_lib[addr[ct]]))
+ else:
+ for repct in range(wf_repeat):
+ for sample in wf_lib[addr[ct]:addr[ct] + count[
+ ct]]:
+ AWGData[chanStrs[chanct]][-1].append(
+ (1, sample))
+
+ cum_time += count[ct]
+
+ #Create the trigger sequence
+ if END_MINILL_MASK & repeat[ct]:
+ AWGData[mrkStrs[chanct]].append([])
+ for delay in np.diff(trigger_delays):
+ AWGData[mrkStrs[chanct]][-1].append((delay - 1, 0))
+ AWGData[mrkStrs[chanct]][-1].append((1, 1))
return AWGData
diff --git a/QGL/drivers/TekPattern.py b/QGL/drivers/TekPattern.py
deleted file mode 100644
index 11464977..00000000
--- a/QGL/drivers/TekPattern.py
+++ /dev/null
@@ -1,405 +0,0 @@
-"""
-TekPattern for creating Tek AWG files. Based off of the Matlab version.
-
-Created on Tue May 8 20:39:26 2012
-
-Copyright 2013 Raytheon BBN Technologies
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-"""
-
-import struct
-import io
-import h5py
-import numpy as np
-import re
-
-MAX_WAVEFORM_VALUE = 2**13 - 1 #maximum waveform value i.e. 14bit DAC
-
-# Do we want a pulse file per instrument or per channel
-SEQFILE_PER_CHANNEL = False
-
-def get_empty_channel_set():
- return {'ch12': {},
- 'ch34': {},
- 'ch1m1': {},
- 'ch1m2': {},
- 'ch2m1': {},
- 'ch2m2': {},
- 'ch3m1': {},
- 'ch3m2': {},
- 'ch4m1': {},
- 'ch4m2': {}}
-
-
-def get_seq_file_extension():
- return '.awg'
-
-
-def is_compatible_file(filename):
- import os
- if os.path.splitext(filename)[1] == get_seq_file_extension():
- return True
- else:
- return False
-
-
-def write_field(FID, fieldName, data, dataType):
- typeSizes = {'int16': 2, 'int32': 4, 'double': 8, 'uint128': 16}
- formatChars = {'int16': ' 1] = 1.0
- analog[analog < -1] = -1.0
-
- maxLength = max(analog.size, marker1.size, marker2.size)
-
- if marker1.size < maxLength:
- marker1 = np.append(marker1,
- np.zeros(maxLength - marker1.size,
- dtype=np.bool))
- if marker2.size < maxLength:
- marker2 = np.append(marker2,
- np.zeros(maxLength - marker2.size,
- dtype=np.bool))
- if analog.size < maxLength:
- analog = np.append(analog,
- np.zeros(maxLength - analog.size,
- dtype=np.float64))
-
- binData = np.uint16(MAX_WAVEFORM_VALUE * analog + MAX_WAVEFORM_VALUE)
- binData += 2**14 * np.uint16(marker1) + 2**15 * np.uint16(marker2)
-
- return binData
-
-
-def write_waveform(FID, WFname, WFnumber, data):
- '''
- Helper function to write a waveform
- '''
- numString = str(WFnumber)
-
- write_field(FID, 'WAVEFORM_NAME_' + numString, WFname, 'char')
-
- #Set integer format
- write_field(FID, 'WAVEFORM_TYPE_' + numString, 1, 'int16')
-
- write_field(FID, 'WAVEFORM_LENGTH_' + numString, data.size, 'int32')
-
- write_field(FID, 'WAVEFORM_TIMESTAMP_' + numString, 0, 'uint128')
- tmpString = 'WAVEFORM_DATA_' + numString + chr(0)
- dataSize = 2 * data.size
- FID.write(struct.pack('> 14
- wfData[name + 'm2'] = (wf & marker2Mask) >> 15
- elif nameRE.match(name):
- wfNum = nameRE.findall(name)[0]
- waveformNames[data] = 'WAVEFORM_DATA_' + wfNum
- elif seqNameRE.match(name):
- channel, seqNum = seqNameRE.findall(name)[0]
- if not ('ch' + channel) in seqTable:
- seqTable['ch' + channel] = {int(seqNum): data}
- else:
- seqTable['ch' + channel][int(seqNum)] = data
-
- # check if there is more to read
- b = FID.read(1)
- if b == '':
- break
- else:
- FID.seek(-1, 1)
-
- # now that we have everything, loop through seqTable to build AWGData
- AWGData = {ch: [] for ch in seqTable.keys()}
- # add in marker keys
- for ch in seqTable.keys():
- AWGData[ch + 'm1'] = []
- AWGData[ch + 'm2'] = []
-
- seqLength = max([int(x) for x in seqTable['ch1'].keys()])
-
- for channel in seqTable.keys():
- for seqct in range(seqLength):
- seqEntry = seqTable[channel][seqct + 1]
- wfName = waveformNames[seqEntry]
- AWGData[channel].append(wfData[wfName])
- AWGData[channel + 'm1'].append(wfData[wfName + 'm1'])
- AWGData[channel + 'm2'].append(wfData[wfName + 'm2'])
-
- return AWGData
-
-
-if __name__ == '__main__':
-
- pass
diff --git a/.gitmodules b/QGL/test_helpers.py
similarity index 100%
rename from .gitmodules
rename to QGL/test_helpers.py
diff --git a/README.md b/README.md
index 57b51930..545757d1 100644
--- a/README.md
+++ b/README.md
@@ -50,20 +50,14 @@ going to System -> Advanced Settings -> Environment variables. On Mac/Linux
machines add the following line to your .bashrc or .bash_profile: ``` export
PYTHONPATH=/path/to/QGL/repo:$PYTHONPATH```
+
The QGL config file will be created the first time you run `import QGL` or `from QGL import *`.
## Dependencies
* Python 2.7 or 3.4+
-* JSONLibraryUtils (https://github.com/BBN-Q/JSONLibraryUtils, integrated as a Git submodule)
* Numpy/Scipy
-* Nucleic atom (from ecpy channel for Python 3)
* h5py
-* watchdog
* Bokeh 0.11
* networkx 2.0
* iPython/Jupyter 4.0 (only for Jupyter notebooks)
-* ruamel_yaml
-
-## UnitTest data support
-This repository uses the Git Large File Storage (LFS) extension to manage a few
-UnitTest data files (see https://git-lfs.github.com/).
+* bbndb
diff --git a/doc/config/filters.yml b/doc/config/filters.yml
deleted file mode 100644
index 546d978d..00000000
--- a/doc/config/filters.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-q1-RawSS:
- type: X6StreamSelector
- source: X6-1
- channel: '1'
diff --git a/doc/config/instruments.yml b/doc/config/instruments.yml
deleted file mode 100644
index 14fd6b6f..00000000
--- a/doc/config/instruments.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-BBNAPS1:
- type: APS2
- tx_channels:
- '12':
- markers:
- 12m1:
- delay: -5.0e-08
-
-BBNAPS2:
- type: APS2
- tx_channels:
- '12':
-
-X6-1:
- type: X6
- rx_channels:
- '1':
- '2':
diff --git a/doc/config/measure.yml b/doc/config/measure.yml
deleted file mode 100644
index 58327b57..00000000
--- a/doc/config/measure.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-# Minimal QGL configuration for QGL-demo notebook
-# Imports can be made using the !include keyword. e.g.
-# instruments: !include instruments.yml
-config:
- AWGDir: "./awg/"
-qubits:
- q1:
- measure:
- AWG: BBNAPS1 12
- trigger: BBNAPS1 12m1
- receiver: q1-RawSS
- control:
- AWG: BBNAPS2 12
-
-instruments: !include instruments.yml
-filters: !include filters.yml
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..31600f5c
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,6 @@
+bbndb >= 0.1
+numpy >= 1.11.1
+scipy >= 0.17.1
+networkx >= 1.11
+bqplot >= 0.11.5
+sqlalchemy >= 1.2.15
\ No newline at end of file
diff --git a/setup.py b/setup.py
index dee9e96b..07db1d0b 100644
--- a/setup.py
+++ b/setup.py
@@ -5,16 +5,10 @@
url='https://github.com/BBN-Q/QGL',
packages=find_packages(exclude=["tests"]),
install_requires=[
- "numpy >= 1.11.1",
- "scipy >= 0.17.1",
- "jupyter >= 1.0.0",
- "atom >= 0.4.1",
- "h5py >= 2.6.0",
- "networkx >= 2.0",
- "future >= 0.16",
- "watchdog >= 0.8.3",
- "bokeh >= 0.11",
- "ruamel_yaml >= 0.11.14"
- ],
- extras_require={"gst": "pygsti>0.9.4"}
-)
+ "bbndb >= 0.1",
+ "numpy >= 1.11.1",
+ "scipy >= 0.17.1",
+ "networkx >= 1.11",
+ "bqplot >= 0.11.5",
+ "sqlalchemy >= 1.2.15"
+ ])
diff --git a/tests/compare_test_data.py b/tests/compare_test_data.py
index 34f7daa8..3a49a58c 100644
--- a/tests/compare_test_data.py
+++ b/tests/compare_test_data.py
@@ -1,7 +1,6 @@
import os
import sys
import glob
-import h5py
from builtins import input
from QGL import *
@@ -18,17 +17,14 @@ def compare_sequences(seq_filter=""):
for test in testdirs:
# build up subdirectory name
_, name = os.path.split(test)
- testfiles = glob.glob(os.path.join(test, '*.h5'))
+ testfiles = glob.glob(os.path.join(test, '*.aps*'))
# recurse into subdirectories
while len(testfiles) == 1 and os.path.isdir(testfiles[0]):
_, subname = os.path.split(testfiles[0])
name = os.path.join(name, subname)
testfiles = glob.glob(os.path.join(testfiles[0], '*'))
newpath = os.path.join(BASE_AWG_DIR, subdir, name)
- newfiles = glob.glob(os.path.join(newpath, '*.h5'))
- #filter py27 look for py27 versions
- testfiles = filter_py27(testfiles)
- newfiles = filter_py27(newfiles)
+ newfiles = glob.glob(os.path.join(newpath, '*.aps*'))
if seq_filter and any(seq_filter in seq_file for seq_file in testfiles):
print("{0} comparing to {1}".format(test, newpath))
PulseSequencePlotter.plot_pulse_files_compare(testfiles, newfiles)
@@ -36,32 +32,19 @@ def compare_sequences(seq_filter=""):
if c == 'q':
break
-
-def filter_py27(filenames):
- py27_files = [f for f in filenames if f[-8:] == "_py27.h5"]
- if py27_files:
- if sys.version_info[0] > 2:
- #strip them out for python3 (and above?)
- filenames = [f for f in filenames if f[-8:] != "_py27.h5"]
- else:
- #otherwise strip the non "_py27" version
- filenames = [f for f in filenames
- if f.replace(".h5", "_py27.h5") not in py27_files]
- return filenames
-
-
def update_test_files():
- for device in ['APS1', 'APS2']:
- testdirs = glob.glob(os.path.join(BASE_TEST_DIR, 'Test' + device, '*'))
- for test in testdirs:
- testfiles = glob.glob(os.path.join(test, '*'))
- # recurse into subdirectories
- while len(testfiles) == 1 and os.path.isdir(testfiles[0]):
- testfiles = glob.glob(os.path.join(testfiles[0], '*'))
- for tfile in testfiles:
- FID = h5py.File(tfile)
- FID['/'].attrs['target hardware'] = device
- FID.close()
+ raise Exception("update_test_files must be updated for new binary format")
+ # for device in ['APS1', 'APS2']:
+ # testdirs = glob.glob(os.path.join(BASE_TEST_DIR, 'Test' + device, '*'))
+ # for test in testdirs:
+ # testfiles = glob.glob(os.path.join(test, '*'))
+ # # recurse into subdirectories
+ # while len(testfiles) == 1 and os.path.isdir(testfiles[0]):
+ # testfiles = glob.glob(os.path.join(testfiles[0], '*'))
+ # for tfile in testfiles:
+ # FID = h5py.File(tfile)
+ # FID['/'].attrs['target hardware'] = device
+ # FID.close()
if __name__ == '__main__':
diff --git a/tests/helpers.py b/tests/helpers.py
index 97f3e7f8..1f663643 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -1,20 +1,24 @@
from QGL import *
def setup_test_lib():
- ChannelLibrary(blank=True)
-
- q1 = Qubit(label='q1')
- q2 = Qubit(label='q2')
- q3 = Qubit(label='q3')
- q4 = Qubit(label='q4')
+ cl = ChannelLibrary(db_resource_name=":memory:")
+ cl.clear()
+ q1 = cl.new_qubit(label='q1')
+ q2 = cl.new_qubit(label='q2')
+ q3 = cl.new_qubit(label='q3')
+ q4 = cl.new_qubit(label='q4')
+ m1 = Measurement(label='M-q1', control_chan=q1, channel_db=cl.channelDatabase)
+ m2 = Measurement(label='M-q2', control_chan=q2, channel_db=cl.channelDatabase)
+ m3 = Measurement(label='M-q3', control_chan=q3, channel_db=cl.channelDatabase)
+ m4 = Measurement(label='M-q4', control_chan=q4, channel_db=cl.channelDatabase)
ChannelLibraries.channelLib.channelDict = {
'q1': q1,
'q2': q2,
'q3': q3,
'q4': q4,
- 'q1q2': Edge(label='q1q2', source=q1, target=q2),
- 'q2q3': Edge(label='q2q3', source=q2, target=q3),
- 'q3q4': Edge(label='q3q4', source=q3, target=q4)
+ 'q1q2': Edge(label='q1q2', source=q1, target=q2, channel_db=cl.channelDatabase),
+ 'q2q3': Edge(label='q2q3', source=q2, target=q3, channel_db=cl.channelDatabase),
+ 'q3q4': Edge(label='q3q4', source=q3, target=q4, channel_db=cl.channelDatabase)
}
- ChannelLibraries.channelLib.build_connectivity_graph()
+ cl.update_channelDict()
diff --git a/tests/test_APS2Pattern.py b/tests/test_APS2Pattern.py
index 636d7843..08874cea 100644
--- a/tests/test_APS2Pattern.py
+++ b/tests/test_APS2Pattern.py
@@ -1,4 +1,3 @@
-import h5py
import unittest
import numpy as np
from copy import copy
@@ -9,15 +8,12 @@
class APSPatternUtils(unittest.TestCase):
def setUp(self):
- self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate')
- self.q1 = Qubit(label='q1', gate_chan=self.q1gate)
- self.q1 = Qubit(label='q1')
+ self.cl = ChannelLibrary(db_resource_name=":memory:")
+ self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate', channel_db=self.cl.channelDatabase)
+ self.q1 = self.cl.new_qubit(label='q1')
+ self.q1.gate_chan = self.q1gate
self.q1.pulse_params['length'] = 30e-9
-
- ChannelLibrary(blank=True) # Create a blank ChannelLibrary
- ChannelLibraries.channelLib.channelDict = {'q1': self.q1,
- 'q1-gate': self.q1gate}
- ChannelLibraries.channelLib.build_connectivity_graph()
+ self.cl.update_channelDict()
def test_synchronize_control_flow(self):
q1 = self.q1
diff --git a/tests/test_APSPattern.py b/tests/test_APSPattern.py
index 163f3d21..f2e8d3e5 100644
--- a/tests/test_APSPattern.py
+++ b/tests/test_APSPattern.py
@@ -1,4 +1,3 @@
-import h5py
import unittest
import numpy as np
@@ -8,14 +7,12 @@
class APSPatternUtils(unittest.TestCase):
def setUp(self):
- # self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate')
- # self.q1 = Qubit(label='q1', gate_chan=self.q1gate)
- self.q1 = Qubit(label='q1')
+ self.cl = ChannelLibrary(db_resource_name=":memory:")
+ self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate', channel_db=self.cl.channelDatabase)
+ self.q1 = self.cl.new_qubit(label='q1')
+ self.q1.gate_chan = self.q1gate
self.q1.pulse_params['length'] = 30e-9
-
- ChannelLibrary(blank=True) # Create a blank ChannelLibrary
- ChannelLibraries.channelLib.channelDict = {'q1': self.q1}
- ChannelLibraries.channelLib.build_connectivity_graph()
+ self.cl.update_channelDict()
def test_unroll_loops_simple(self):
q1 = self.q1
diff --git a/tests/test_Compiler.py b/tests/test_Compiler.py
index 8c1bd9c7..0482b3e2 100644
--- a/tests/test_Compiler.py
+++ b/tests/test_Compiler.py
@@ -1,4 +1,3 @@
-import h5py
import unittest
import numpy as np
@@ -7,23 +6,28 @@
class CompileUtils(unittest.TestCase):
def setUp(self):
- self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate')
- self.q1 = Qubit(label='q1', gate_chan=self.q1gate)
+ print("Running setup")
+ self.cl = ChannelLibrary(db_resource_name=":memory:")
+ self.cl.clear()
+ self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate', channel_db=self.cl.channelDatabase)
+ self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate', channel_db=self.cl.channelDatabase)
+ self.q1phys = Channels.PhysicalChannel(label='q1-phys', sampling_rate=1.2e9, channel_db=self.cl.channelDatabase)
+ self.q1 = Qubit(label='q1', gate_chan=self.q1gate, channel_db=self.cl.channelDatabase)
+ self.q1.phys_chan = self.q1phys
self.q1.pulse_params['length'] = 30e-9
- self.q2gate = Channels.LogicalMarkerChannel(label='q2-gate')
- self.q2 = Qubit(label='q2', gate_chan=self.q2gate)
+ self.q2gate = Channels.LogicalMarkerChannel(label='q2-gate', channel_db=self.cl.channelDatabase)
+ self.q2phys = Channels.PhysicalChannel(label='q2-phys', sampling_rate=1.2e9, channel_db=self.cl.channelDatabase)
+ self.q2 = Qubit(label='q2', gate_chan=self.q2gate, channel_db=self.cl.channelDatabase)
+ self.q2.phys_chan = self.q2phys
self.q2.pulse_params['length'] = 30e-9
- self.trigger = Channels.LogicalMarkerChannel(label='trigger')
- self.measq1 = Channels.Measurement(label='M-q1', meas_type='autodyne')
+ self.trigger = Channels.LogicalMarkerChannel(label='trigger', channel_db=self.cl.channelDatabase)
+ self.measq1 = Channels.Measurement(label='M-q1', meas_type='autodyne', channel_db=self.cl.channelDatabase)
self.measq1.trig_chan = self.trigger
-
- ChannelLibrary(blank=True) # Create a blank ChannelLibrary
- ChannelLibraries.channelLib.channelDict = {'q1': self.q1,
- 'q2': self.q2,
- 'M-q1': self.measq1}
- ChannelLibraries.channelLib.build_connectivity_graph()
+ self.measq2 = Channels.Measurement(label='M-q2', meas_type='autodyne', channel_db=self.cl.channelDatabase)
+ self.measq2.trig_chan = self.trigger
+ self.cl.update_channelDict()
def test_add_digitizer_trigger(self):
q1 = self.q1
diff --git a/tests/test_ControlFlow.py b/tests/test_ControlFlow.py
index 5e430427..f9bbaf41 100644
--- a/tests/test_ControlFlow.py
+++ b/tests/test_ControlFlow.py
@@ -7,12 +7,12 @@
class ControlFlowTest(unittest.TestCase):
def setUp(self):
- self.q1 = Qubit(label='q1')
- self.q2 = Qubit(label='q2')
-
- ChannelLibrary(blank=True) # Create a blank ChannelLibrary
- ChannelLibraries.channelLib.channelDict = {'q1': self.q1, 'q2': self.q2}
- ChannelLibraries.channelLib.build_connectivity_graph()
+ cl = ChannelLibrary(db_resource_name=":memory:")
+ self.q1 = cl.new_qubit(label='q1')
+ self.q2 = cl.new_qubit(label='q2')
+ self.q3 = cl.new_qubit(label='q3')
+ self.q4 = cl.new_qubit(label='q4')
+ cl.update_channelDict()
def test_qif(self):
q1 = self.q1
@@ -20,8 +20,6 @@ def test_qif(self):
seq2 = [X(q1), Y(q1), Z(q1)]
label(seq1)
label(seq2)
- # print qif(0, seq1, seq2)
- # print ([CmpEq(0), Goto(label(seq1))] + seq2 + [Goto(endlabel(seq1))] + seq1
assert (qif(0, seq1, seq2) == [CmpEq("m", 0), Goto(label(seq1))] + seq2 +
[Goto(endlabel(seq1))] + seq1)
diff --git a/tests/test_QGL.py b/tests/test_QGL.py
index b91156b0..6255d509 100644
--- a/tests/test_QGL.py
+++ b/tests/test_QGL.py
@@ -1,9 +1,9 @@
-import h5py
import unittest
import numpy as np
import time
import os.path
-
+import struct
+from bbndb.qgl import PhysicalChannel, LogicalChannel, Measurement
from QGL import *
# Waveform numpy assert_allclose Test for QGL
@@ -33,7 +33,7 @@ def __init__(self):
# all available sequences (which are defined in subclasses)
self.generate()
self.compile()
- self.load()
+ self.load()
def generate(self):
# this function should be overridden in a subclass to define
@@ -55,28 +55,29 @@ def show(self):
def build_filename(self, name):
# utility for reading and writing
- return self.testFileDirectory + self.fileHeader + '-' + name + '.h5'
+ return self.testFileDirectory + self.fileHeader + '-' + name + '.aps2'
def write(self):
# writes each sequence to a file in the test data directory a file header
# which may be overridden in the subclasses
for name, waveform in self.waveforms.items():
+
fileName = self.build_filename(name)
- #Open the HDF5 file
if os.path.isfile(fileName):
os.remove(fileName)
- with h5py.File(fileName, 'w') as FID:
- FID['/'].attrs['Type'] = 'test_case'
- FID['/'].attrs['Version'] = 1.0
+ with open(fileName, 'wb') as FID:
+ FID.write(b'TEST') # target
+ FID.write(np.float32(1.0).tobytes()) # Version
+ FID.write(np.float32(1.0).tobytes()) # minimum firmware version
+ FID.write(np.uint16(len(waveform)).tobytes()) # number of channels
- #Create the groups and datasets
channels = waveform.keys()
- chanStr = '/channels'
- chanGroup = FID.create_group(chanStr)
for channel in channels:
- channelStr = channel.label
- FID.create_dataset('/' + chanStr + '/' + channelStr,
- data=waveform[channel])
+ channel.label.ljust(32,"#").encode("utf-8")
+ FID.write(channel.label.ljust(32,"#").encode("utf-8"))
+ FID.write(np.uint64(waveform[channel].size).tobytes())
+ FID.write(np.complex128(waveform[channel]).tobytes()) # waveform data length for channel
+
def load(self):
# attempts to load valid waveforms for each of the sequences test cases
@@ -89,22 +90,30 @@ def load(self):
caseName, fileName))
continue
# -----
- # print( "\n\rDBG::Calling \"with h5py.File( {0}, 'r')\"...".format( fileName) )
+ # print( "\n\rDBG::Calling \"with open({0}, 'wb')\"...".format( fileName) )
# -----
# The following pulls in Git Large File Storage (LFS) data files
- # from cached signature references; if the h5py.File call fails
+ # from cached signature references; if the open call fails
# with an OSError, double-check git-lfs library installation (in
# addition to git) --
#
- # Where git-lfs was NOT installed the h5py.File() call was observed
+ # Where git-lfs was NOT installed the open call was observed
# returning:
#
# OSError: Unable to open file (file signature not found))
#
- with h5py.File(fileName, 'r') as FID:
- # print( "DBG::FID: {0}".format( FID))
- for name, waveform in FID['/channels'].items():
- validWaveform[name] = waveform[:]
+ with open(fileName, 'rb') as FID:
+ target_hw = FID.read(4).decode('utf-8')
+ file_version = struct.unpack(' 2:
- #strip them out for python3 (and above?)
- filenames = [f for f in filenames if f[-8:] != "_py27.h5"]
- else:
- #otherwise strip the non "_py27" version
- filenames = [f for f in filenames
- if f.replace(".h5", "_py27.h5") not in py27_files]
-
for filename in filenames:
truthFile = os.path.join(truthDirectory, filename)
- testFile = os.path.join(searchDirectory, filename.replace("_py27",
- ""))
+ testFile = os.path.join(searchDirectory, filename)
self.assertTrue(
os.path.isfile(truthFile),
@@ -179,7 +176,6 @@ def compare_sequence(self, seqA, seqB, errorHeader):
for ta in seqA]) if len(seqA) else np.empty(0)
wfB = np.concatenate([ta[1] * np.ones(int(ta[0]))
for ta in seqB]) if len(seqB) else np.empty(0)
-
self.assertTrue(
len(wfA) == len(wfB), "{} size {} != size {}".format(
errorHeader, len(wfA), len(wfB)))
@@ -384,40 +380,108 @@ def test_RB_SimultaneousRB_AC(self):
SimultaneousRB_AC((self.q1, self.q2), (seqs1, seqs2))
self.compare_sequences('RB')
+ @unittest.skip("Need to update to new pygsti API")
+ def test_1Q_GST(self):
+
+ if istravis:
+ raise unittest.SkipTest("FIX ME -- Figure out pygsti integration for Travis.")
+
+ self.set_awg_dir('GST')
+ # list of GST gate strings
+ if GSTTools.PYGSTI_PRESENT:
+ # generate the gate gatestrings
+ import pygsti
+ from pygsti.construction import std1Q_XYI
+
+ #Create a data set
+ gs_target = std1Q_XYI.gs_target
+ fiducials = std1Q_XYI.fiducials
+ germs = std1Q_XYI.germs
+ maxLengths = [1,2,4]
+
+ listOfExperiments = pygsti.construction.make_lsgst_experiment_list(gs_target.gates.keys(), fiducials, fiducials, germs, maxLengths)
+ else:
+ listOfExperiments = list(np.load('tests/test_data/awg/TestAPS2/GST/GST/listOfExperiments.npy'))
+
+ seqs = list(GSTTools.gst_map_1Q(listOfExperiments, self.q1))
+ filenames = compile_to_hardware(seqs, 'GST/GST')
+ self.compare_sequences('GST')
+
+ @unittest.skip("Need to update to new pygsti API")
+ def test_2Q_GST(self):
+
+ if istravis:
+ raise unittest.SkipTest("FIX ME -- Figure out pygsti integration for Travis.")
+
+ self.set_awg_dir('GST')
+ def gst_2Qgate_map(q1, q2):
+ return {"Gxi": X90(q1)*Id(q2),
+ "Gyi": Y90(q1)*Id(q2),
+ "Gii": Id(q1)*Id(q2),
+ "Gix": Id(q1)*X90(q2),
+ "Giy": Id(q1)*Y90(q2),
+ "Gcnot": CNOT_CR(q2,q1)}
+
+ if GSTTools.PYGSTI_PRESENT:
+ import pygsti
+ from pygsti.construction import std1Q_XYI, std2Q_XYICNOT
+ from itertools import product
+ from QGL.GSTTools import SingleQubitCliffordGST, gst_map_2Q
+ # note the use of the germs_lite!
+ gs = std2Q_XYICNOT
+ gs_target = std2Q_XYICNOT.gs_target.copy()
+
+ prep_fiducials = std2Q_XYICNOT.prepStrs
+ effect_fiducials = std2Q_XYICNOT.effectStrs
+ gs_germs = std2Q_XYICNOT.germs_lite
+ #maxLengths = [1,2,4,8,16]
+ maxLengths = [1,2]
+
+ print('Creating GST sequences...')
+ listOfExperiments = pygsti.construction.make_lsgst_experiment_list(gs_target.gates.keys(), prep_fiducials, effect_fiducials, gs_germs, maxLengths)
+ else:
+ # list of GST gate strings
+ listOfExperiments = list(np.load('tests/test_data/awg/TestAPS2/GST/GST2Q/listOfExperiments.npy'))
+
+ seqs = list(GSTTools.gst_map_2Q(listOfExperiments, (self.q1, self.q2), qgl_map = gst_2Qgate_map(self.q1, self.q2), append_meas=True))
+
+ filenames = compile_to_hardware(seqs, 'GST/GST2Q')
+ self.compare_sequences('GST2Q')
+
class APS2Helper(AWGTestHelper):
def setUp(self):
AWGTestHelper.__init__(self, APS2Pattern)
for name in ['APS1', 'APS2', 'APS3', 'APS4', 'APS5', 'APS6']:
- channelName = name + '-12'
- channel = PhysicalQuadratureChannel(label=channelName)
+ channelName = name + '-1'
+ channel = PhysicalQuadratureChannel(label=channelName, channel=0)
channel.sampling_rate = 1.2e9
channel.instrument = name
channel.translator = 'APS2Pattern'
self.channels[channelName] = channel
for m in range(1, 5):
- channelName = "{0}-12m{1}".format(name, m)
- channel = PhysicalMarkerChannel(label=channelName)
+ channelName = "{0}-m{1}".format(name, m)
+ channel = PhysicalMarkerChannel(label=channelName, channel=m-1)
channel.sampling_rate = 1.2e9
channel.instrument = name
channel.translator = 'APS2Pattern'
self.channels[channelName] = channel
- mapping = {'digitizerTrig': 'APS1-12m1',
- 'slave_trig': 'APS1-12m2',
- 'q1': 'APS1-12',
- 'q1-gate': 'APS1-12m3',
- 'M-q1': 'APS2-12',
- 'M-q1-gate': 'APS2-12m1',
- 'q2': 'APS3-12',
- 'q2-gate': 'APS3-12m1',
- 'M-q2': 'APS4-12',
- 'M-q2-gate': 'APS4-12m1',
- 'cr': 'APS5-12',
- 'cr-gate': 'APS5-12m1',
- 'M-q1q2': 'APS6-12',
- 'M-q1q2-gate': 'APS6-12m1'}
+ mapping = {'digitizerTrig': 'APS1-m1',
+ 'slave_trig': 'APS1-m2',
+ 'q1': 'APS1-1',
+ 'q1-gate': 'APS1-m3',
+ 'M-q1': 'APS2-1',
+ 'M-q1-gate': 'APS2-m1',
+ 'q2': 'APS3-1',
+ 'q2-gate': 'APS3-m1',
+ 'M-q2': 'APS4-1',
+ 'M-q2-gate': 'APS4-m1',
+ 'cr': 'APS5-1',
+ 'cr-gate': 'APS5-m1',
+ 'M-q1q2': 'APS6-1',
+ 'M-q1q2-gate': 'APS6-m1'}
self.finalize_map(mapping)
@@ -434,7 +498,7 @@ def test_mux_CR(self):
self.channels['cr'].phys_chan = self.channels['q1'].phys_chan
self.channels['q1'].frequency = 100e6
self.channels['cr'].frequency = 200e6
- ChannelLibraries.channelLib.build_connectivity_graph()
+ self.cl.update_channelDict()
seqs = [[CNOT_CR(self.q1, self.q2)]]
filenames = compile_to_hardware(seqs, 'CNOT_CR_mux/CNOT_CR_mux')
@@ -445,9 +509,9 @@ class TestAPS1(unittest.TestCase, AWGTestHelper, TestSequences):
def setUp(self):
AWGTestHelper.__init__(self, APSPattern)
for name in ['APS1', 'APS2', 'APS3']:
- for ch in ['12', '34']:
+ for i, ch in enumerate(['12', '34']):
channelName = name + '-' + ch
- channel = PhysicalQuadratureChannel(label=channelName)
+ channel = PhysicalQuadratureChannel(label=channelName, channel=i)
channel.sampling_rate = 1.2e9
channel.instrument = name
channel.translator = 'APSPattern'
@@ -455,7 +519,7 @@ def setUp(self):
for m in range(1, 5):
channelName = "{0}-{1}m1".format(name, m)
- channel = PhysicalMarkerChannel(label=channelName)
+ channel = PhysicalMarkerChannel(label=channelName, channel=m-1)
channel.sampling_rate = 1.2e9
channel.instrument = name
channel.translator = 'APSPattern'
@@ -552,186 +616,5 @@ def test_RB_SimultaneousRB_AC(self):
"""
TestSequences.test_RB_SimultaneousRB_AC(self)
-
-class TestTek5014(unittest.TestCase, AWGTestHelper, TestSequences):
- def setUp(self):
- AWGTestHelper.__init__(self, TekPattern)
- for name in ['TEK1', 'TEK2']:
- for ch in ['12', '34']:
- channelName = name + '-' + ch
- channel = PhysicalQuadratureChannel(label=channelName)
- channel.sampling_rate = 1.2e9
- channel.instrument = name
- channel.translator = 'TekPattern'
- self.channels[channelName] = channel
-
- for m in ['1m1', '1m2', '2m1', '2m2', '3m1', '3m2', '4m1', '4m2']:
- channelName = "{0}-{1}".format(name, m)
- channel = PhysicalMarkerChannel(label=channelName)
- channel.sampling_rate = 1.2e9
- channel.instrument = name
- channel.translator = 'TekPattern'
- self.channels[channelName] = channel
-
- mapping = {'digitizerTrig': 'TEK1-1m2',
- 'slave_trig': 'TEK1-2m2',
- 'q1': 'TEK1-12',
- 'M-q1': 'TEK1-12',
- 'M-q1-gate': 'TEK1-1m1',
- 'q1-gate': 'TEK1-2m1',
- 'q2': 'TEK1-34',
- 'M-q2': 'TEK1-34',
- 'M-q2-gate': 'TEK1-3m1',
- 'q2-gate': 'TEK1-4m1',
- 'cr': 'TEK2-12',
- 'cr-gate': 'TEK2-1m1',
- 'M-q1q2': 'TEK2-34',
- 'M-q1q2-gate': 'TEK2-2m1'}
-
- self.finalize_map(mapping)
-
- @unittest.skip("Tek5014 unused in years")
- def test_misc_seqs2(self):
- """ Fails due to a divide by zero
- File "C:\Projects\Q\lib\PyQLab\QGL\TekPattern.py", line 77, in merge_waveform
- for entry in chAB['linkList'][n % len(chAB['linkList'])]:
- ZeroDivisionError: integer division or modulo by zero
- """
- TestSequences.test_misc_seqs2(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_misc_seqs5(self):
- """ Fails due to a divide by zero
- File "C:\Projects\Q\lib\PyQLab\QGL\TekPattern.py", line 77, in merge_waveform
- for entry in chAB['linkList'][n % len(chAB['linkList'])]:
- ZeroDivisionError: integer division or modulo by zero
- """
- TestSequences.test_misc_seqs5(self)
-
- # multiple tests will fail with an attribute error:
- # AttributeError: 'Wait' object has no attribute 'isTimeAmp' at line 78
- # in TekPattern.py in merge_waveform
-
- @unittest.skip("Tek5014 unused in years")
- def test_misc_seqs1(self):
- TestSequences.test_misc_seqs1(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_misc_seqs3(self):
- TestSequences.test_misc_seqs3(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_misc_seqs4(self):
- TestSequences.test_misc_seqs4(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_mux_CR(self):
- TestSequences.test_mux_CR(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_AllXY(self):
- TestSequences.test_AllXY(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_CR_PiRabi(self):
- TestSequences.test_CR_PiRabi(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_CR_EchoCRLen(self):
- TestSequences.test_CR_EchoCRLen(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_CR_EchoCRPhase(self):
- TestSequences.test_CR_EchoCRPhase(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_Decoupling_HannEcho(self):
- TestSequences.test_Decoupling_HannEcho(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_Decoupling_CPMG(self):
- TestSequences.test_Decoupling_CPMG(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_FlipFlop(self):
- TestSequences.test_FlipFlop(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_T1T2_InversionRecovery(self):
- TestSequences.test_T1T2_InversionRecovery(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_T1T2_Ramsey(self):
- TestSequences.test_T1T2_Ramsey(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_SPAM(self):
- TestSequences.test_SPAM(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_Rabi_RabiAmp(self):
- TestSequences.test_Rabi_RabiAmp(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_Rabi_RabiWidth(self):
- TestSequences.test_Rabi_RabiWidth(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_Rabi_RabiAmp_NQubits(self):
- TestSequences.test_Rabi_RabiAmp_NQubits(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_Rabi_RabiAmpPi(self):
- TestSequences.test_Rabi_RabiAmpPi(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_Rabi_SingleShot(self):
- TestSequences.test_Rabi_SingleShot(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_Rabi_PulsedSpec(self):
- TestSequences.test_Rabi_PulsedSpec(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_RB_SingleQubitRB(self):
- TestSequences.test_RB_SingleQubitRB(self)
-
- @unittest.skip("Tek5014 unused in years")
- def test_RB_SimultaneousRB_AC(self):
- TestSequences.test_RB_SimultaneousRB_AC(self)
-
-# class TestTek7000(unittest.TestCase, AWGTestHelper, TestSequences):
-
-# def setUp(self):
-# AWGTestHelper.__init__(self, TekPattern.read_Tek_file)
-# for name in ['TEK1', 'TEK2', 'TEK3', 'TEK4', 'TEK5']:
-# self.instruments[name] = Tek7000(label=name)
-
-# for ch in ['12']:
-# channelName = name + '-' + ch
-# channel = PhysicalQuadratureChannel(label=channelName)
-# channel.instrument = self.instruments[name]
-# self.channels[channelName] = channel
-
-# for m in ['1m1', '1m2', '2m1', '2m2']:
-# channelName = "{0}-{1}".format(name,m)
-# channel = PhysicalMarkerChannel(label=channelName)
-# channel.instrument = self.instruments[name]
-# self.channels[channelName] = channel
-
-# mapping = { 'digitizerTrig' :'TEK1-1m2',
-# 'slave_trig' :'TEK1-2m2',
-# 'q1' :'TEK1-12',
-# 'M-q1' :'TEK2-12',
-# 'M-q1-gate' :'TEK1-1m1',
-# 'q1-gate' :'TEK1-2m1',
-# 'q2' :'TEK3-12',
-# 'M-q2' :'TEK4-12',
-# 'M-q2-gate' :'TEK2-1m1',
-# 'q2-gate' :'TEK2-2m1',
-# 'cr' :'TEK5-12',
-# 'cr-gate' :'TEK5-1m1'}
-# self.finalize_map(mapping)
-
if __name__ == "__main__":
unittest.main()
diff --git a/tests/test_config.py b/tests/test_config.py
index 41e5bea3..1513abfe 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -38,6 +38,7 @@ def setUp(self):
def tearDown(self):
shutil.rmtree('./tmp')
+ @unittest.skip("Need to update config API")
def test_env(self):
"""
Test that if the BBN_MEAS_FILE environment variable is set, it is used
@@ -59,7 +60,7 @@ def test_env(self):
assert QGL.config.meas_file == meas_name
assert QGL.config.AWGDir == os.path.realpath("./foo/bar/xyz")
-
+ @unittest.skip("Need to update config API")
def test_override1(self):
"""
Tests manually supplying a different config file when instantiating the channel library.
diff --git a/tests/test_data/awg/TestAPS1/AllXY/AllXY-APS1.aps1 b/tests/test_data/awg/TestAPS1/AllXY/AllXY-APS1.aps1
new file mode 100644
index 00000000..9578434c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/AllXY/AllXY-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:93a7ed05a9c679de05915e51500f6d9ee9d4e5ef0016b1a8c2ff26bdf622b1e0
+size 3991
diff --git a/tests/test_data/awg/TestAPS1/AllXY/AllXY-APS1.h5 b/tests/test_data/awg/TestAPS1/AllXY/AllXY-APS1.h5
deleted file mode 100644
index d4b9ab22..00000000
--- a/tests/test_data/awg/TestAPS1/AllXY/AllXY-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:598ec4cd4a90c6ef37b3bf78a6a07e093dafd68b23037179dc8f3ee604196ff3
-size 20568
diff --git a/tests/test_data/awg/TestAPS1/CPMG/CPMG-APS1.aps1 b/tests/test_data/awg/TestAPS1/CPMG/CPMG-APS1.aps1
new file mode 100644
index 00000000..7f055d16
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/CPMG/CPMG-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f224b52bf73aeb376166df84f6f166e5d48a7c4a2214a73fd40e41c3ef52e96b
+size 2357
diff --git a/tests/test_data/awg/TestAPS1/CPMG/CPMG-APS1.h5 b/tests/test_data/awg/TestAPS1/CPMG/CPMG-APS1.h5
deleted file mode 100644
index 8e80f58b..00000000
--- a/tests/test_data/awg/TestAPS1/CPMG/CPMG-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dd0994b6ef60cc0a19315aa45512f1c7f6a6612ce06895f161f4ae60fa7917d7
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/Echo/Echo-APS1.aps1 b/tests/test_data/awg/TestAPS1/Echo/Echo-APS1.aps1
new file mode 100644
index 00000000..42b91ac5
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/Echo/Echo-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b35762b99a622467e594bf295ed35d923ff944bc6aa6c07a7832895a0c53f8f6
+size 2927
diff --git a/tests/test_data/awg/TestAPS1/Echo/Echo-APS1.h5 b/tests/test_data/awg/TestAPS1/Echo/Echo-APS1.h5
deleted file mode 100644
index 00c28e4d..00000000
--- a/tests/test_data/awg/TestAPS1/Echo/Echo-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0f14162bcf50abb771326b2db3ea36288e704d1224dbd1660dbec60de215121f
-size 20568
diff --git a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS1.aps1 b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS1.aps1
new file mode 100644
index 00000000..9bb93800
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9fe524d7623feccacec0293a877c02afc44f75ee77d1d5269f795a85de341b7c
+size 4209
diff --git a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS1.h5 b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS1.h5
deleted file mode 100644
index 0f589d2c..00000000
--- a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f1e0f1039e90c8361735fe98ddbd24e434fb9b760169a62ec946ae40274d1a60
-size 20552
diff --git a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS2.aps1 b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS2.aps1
new file mode 100644
index 00000000..969d00e7
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS2.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2e3dc99287d4dc53f54900f61f8c3390214e6dbaeb065f991a9dd513a83bd63d
+size 3149
diff --git a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS2.h5 b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS2.h5
deleted file mode 100644
index b5872b5f..00000000
--- a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:92b69fd2c1d4208e22cb652dfac0e78de7d7502fc1a0028e4df32c7319cd9d02
-size 20552
diff --git a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS3.aps1 b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS3.aps1
new file mode 100644
index 00000000..67db4db5
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS3.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2e7b0034fd155a7fd2d37388d977b0af521b194b1c47b3e8f78d5fa86b22861d
+size 3369
diff --git a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS3.h5 b/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS3.h5
deleted file mode 100644
index 953bfa04..00000000
--- a/tests/test_data/awg/TestAPS1/EchoCRLen/EchoCR/EchoCR-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:aa055382df427f2625eb61ec6c112603c36891bf69e2e2d5037e2ef0af8d725b
-size 18136
diff --git a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS1.aps1 b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS1.aps1
new file mode 100644
index 00000000..b30daca4
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:71c17a0aa26078892e47aeb2ae0dcea71532b6b614a42ad90a15f7a07c1e25ab
+size 4209
diff --git a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS1.h5 b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS1.h5
deleted file mode 100644
index 9c6f0102..00000000
--- a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e1bc671bcfbba1005d9e593edf45288d0b6d830ff0445cf6c9360c31daa0753b
-size 20552
diff --git a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS2.aps1 b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS2.aps1
new file mode 100644
index 00000000..0b249f5b
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS2.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3059c3d4b37c9f9de1e95e31f3a14bcdfd8f1017189ef697bbaeab4419dd8caa
+size 3513
diff --git a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS2.h5 b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS2.h5
deleted file mode 100644
index 041cb89c..00000000
--- a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8e1b9e57467e487b23c15743b839e640c168bb5b0fe48fc55df83ade33e69558
-size 20552
diff --git a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS3.aps1 b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS3.aps1
new file mode 100644
index 00000000..7c0fccb8
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS3.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b99cd5f2d629ff33ee53b070b0a687d000fa9681bcaac3bbd3b3a71ec87e0ccb
+size 11409
diff --git a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS3.h5 b/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS3.h5
deleted file mode 100644
index 9898ef3b..00000000
--- a/tests/test_data/awg/TestAPS1/EchoCRPhase/EchoCR/EchoCR-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c5e77f05e76a9b655cccc9c76aae4f3e412c88f4e7259b18db9a2a1b21c0fe4e
-size 26992
diff --git a/tests/test_data/awg/TestAPS1/FlipFlop/FlipFlop-APS1.aps1 b/tests/test_data/awg/TestAPS1/FlipFlop/FlipFlop-APS1.aps1
new file mode 100644
index 00000000..e185c0d9
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/FlipFlop/FlipFlop-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8dcc6f62fb04a90ae74b6b80f2963736145fcd3672762641ac1dcc74c6f0c985
+size 23531
diff --git a/tests/test_data/awg/TestAPS1/FlipFlop/FlipFlop-APS1.h5 b/tests/test_data/awg/TestAPS1/FlipFlop/FlipFlop-APS1.h5
deleted file mode 100644
index 5c65333c..00000000
--- a/tests/test_data/awg/TestAPS1/FlipFlop/FlipFlop-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:757f73118a7c633b5d5161401bab8443bb4bb98a965b1f9978c71f9d0d694149
-size 41192
diff --git a/tests/test_data/awg/TestAPS1/GST/GST/listOfExperiments.npy b/tests/test_data/awg/TestAPS1/GST/GST/listOfExperiments.npy
new file mode 100644
index 00000000..7e552e2d
Binary files /dev/null and b/tests/test_data/awg/TestAPS1/GST/GST/listOfExperiments.npy differ
diff --git a/tests/test_data/awg/TestAPS1/GST/GST2Q/listOfExperiments.npy b/tests/test_data/awg/TestAPS1/GST/GST2Q/listOfExperiments.npy
new file mode 100644
index 00000000..44e229ed
Binary files /dev/null and b/tests/test_data/awg/TestAPS1/GST/GST2Q/listOfExperiments.npy differ
diff --git a/tests/test_data/awg/TestAPS1/MISC1/MISC1-APS1.aps1 b/tests/test_data/awg/TestAPS1/MISC1/MISC1-APS1.aps1
new file mode 100644
index 00000000..eb78325e
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC1/MISC1-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0082cb2b408b942eac05a48e77344cb3f63edd606f6a7849041652b8f2852559
+size 3843
diff --git a/tests/test_data/awg/TestAPS1/MISC1/MISC1-APS1.h5 b/tests/test_data/awg/TestAPS1/MISC1/MISC1-APS1.h5
deleted file mode 100644
index 74151403..00000000
--- a/tests/test_data/awg/TestAPS1/MISC1/MISC1-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:964f74ba4a169ab0f60f9f39aeaa4f497f7a63f339d4773ee5e4b563b8859056
-size 20568
diff --git a/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS1.aps1 b/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS1.aps1
new file mode 100644
index 00000000..c79110f8
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1b4d6e3c6244e4efad5925136379931db5be619a147bd82f9e6e2b7ae92e1397
+size 659
diff --git a/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS1.h5 b/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS1.h5
deleted file mode 100644
index adc1bfc8..00000000
--- a/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8f7e131852cac2f0b8dc2a9dbcd738be9dc1b5e8bc0323d06362c5d5a49cc372
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS3.aps1 b/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS3.aps1
new file mode 100644
index 00000000..386f8af3
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS3.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:11a4702cfb925a868d316c4549786d225e0ac115a8395640522c9221ab4e5b74
+size 755
diff --git a/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS3.h5 b/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS3.h5
deleted file mode 100644
index 43c67a89..00000000
--- a/tests/test_data/awg/TestAPS1/MISC2/MISC2-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:79a4a4a1cf2cab3bedbf060b4dc4bf7166eaabe7781de4dcc0bf9d1923075b5f
-size 16104
diff --git a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS1.aps1 b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS1.aps1
new file mode 100644
index 00000000..673bf3d7
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:efe2ba032c43485ea55dd8b9cc9470ce19968eca2dabf744a958f7d6a369cefe
+size 685
diff --git a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS1.h5 b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS1.h5
deleted file mode 100644
index e9be50b1..00000000
--- a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6d059bb8d6ea48d80336179c280d8fbff658165f7823b85f173dd541205068ca
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS2.aps1 b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS2.aps1
new file mode 100644
index 00000000..197a426e
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS2.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f711c3304df1cfc8c32f5ae85de38023c33f070bd89b86752ad09992e35c37e9
+size 443
diff --git a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS2.h5 b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS2.h5
deleted file mode 100644
index ee2a676f..00000000
--- a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:85c3c4ede4a0cc4f75fe45a99c712982af0a90cd12e3131bbc447f460e379384
-size 16104
diff --git a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS3.aps1 b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS3.aps1
new file mode 100644
index 00000000..d076e9bf
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS3.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:bb173426f6db57e38d836a81eebb96058918ef7403406184ece584fd447599ac
+size 755
diff --git a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS3.h5 b/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS3.h5
deleted file mode 100644
index f5180ba9..00000000
--- a/tests/test_data/awg/TestAPS1/MISC3/MISC3-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a79d97a95d1f4d010df4f9a9116d92099d9920c3fec64cf456d1ba71fcb4c506
-size 16104
diff --git a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS1.aps1 b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS1.aps1
new file mode 100644
index 00000000..f4984818
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f9f9c622f7a08a002c42b382b3c2b12ecc97f3625c79e9cb64dae118af52570f
+size 1151
diff --git a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS1.h5 b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS1.h5
deleted file mode 100644
index 8c50f48f..00000000
--- a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c0e436ad63f7ce73f53211ce6ceeff3e2d4d880fbeb6c942e16142f3294deab2
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS2.aps1 b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS2.aps1
new file mode 100644
index 00000000..28147007
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS2.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3faa203b1c058d66a6499f9aba6e1cc04d49129e973bc131f900b26fc5c1ebfd
+size 905
diff --git a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS2.h5 b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS2.h5
deleted file mode 100644
index 85cf1477..00000000
--- a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a0915cda20a3a66881b7701da17189c2be8dda857dcbe7180ac27ec8509c3b51
-size 16104
diff --git a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS3.aps1 b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS3.aps1
new file mode 100644
index 00000000..6161fa40
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS3.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4ef90629a3658816f53523c9e2e80d96705187bd68e835f0d468dda368e9a694
+size 775
diff --git a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS3.h5 b/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS3.h5
deleted file mode 100644
index 7c6ded4c..00000000
--- a/tests/test_data/awg/TestAPS1/MISC4/MISC4-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:65be23387c62f3a8a08547cea77a6e9ff8c649301fe60b33bacfbd96fc9433a5
-size 16104
diff --git a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS1.aps1 b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS1.aps1
new file mode 100644
index 00000000..10fc0bb5
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f2979185871f56a5143138c031de487b54aacc4a4085689f6b630a48d5afd440
+size 2999
diff --git a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS1.h5 b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS1.h5
deleted file mode 100644
index bb89df1a..00000000
--- a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:665f63cb2a9ba48fdd3e890c3db66f0607d4e20263d8d77db35c77bfda76c63c
-size 20568
diff --git a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS2.aps1 b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS2.aps1
new file mode 100644
index 00000000..2b990dea
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS2.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ca5bdf91c5f9d3d1d4c4ac67bad05c6418a4db32c53949a82adfa82a86289800
+size 2379
diff --git a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS2.h5 b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS2.h5
deleted file mode 100644
index 99029ac8..00000000
--- a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:99adec81a02115317caeddc332063fef5fd5bcb5342a3a15ad92fb5567a6c3fc
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS3.aps1 b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS3.aps1
new file mode 100644
index 00000000..a6e4f937
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS3.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:269cf8968cc6d1c11426b6db80ba679e50269528eebff2647a4d64376f8e1cf9
+size 1889
diff --git a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS3.h5 b/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS3.h5
deleted file mode 100644
index dce42a8f..00000000
--- a/tests/test_data/awg/TestAPS1/PiRabi/PiRabi-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6dc366b846ff17aea66ecfe7154088da73ae3803033c3ba2a90cba8ab4b3ac13
-size 16104
diff --git a/tests/test_data/awg/TestAPS1/RabiAmp/Rabi/Rabi-APS1.aps1 b/tests/test_data/awg/TestAPS1/RabiAmp/Rabi/Rabi-APS1.aps1
new file mode 100644
index 00000000..4bc0eb82
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/RabiAmp/Rabi/Rabi-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:03384c3fcbe4ebeb39a43df1e47173d5276ff431c44cd10c6a5891414c12022d
+size 2905
diff --git a/tests/test_data/awg/TestAPS1/RabiAmp/Rabi/Rabi-APS1.h5 b/tests/test_data/awg/TestAPS1/RabiAmp/Rabi/Rabi-APS1.h5
deleted file mode 100644
index e21de48c..00000000
--- a/tests/test_data/awg/TestAPS1/RabiAmp/Rabi/Rabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:1878b25a724b98b176070fbb562b7a54ba4f6d0ca67724e4b5bc31a43e491fae
-size 20568
diff --git a/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS1.aps1 b/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS1.aps1
new file mode 100644
index 00000000..4bc0eb82
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:03384c3fcbe4ebeb39a43df1e47173d5276ff431c44cd10c6a5891414c12022d
+size 2905
diff --git a/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS1.h5 b/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS1.h5
deleted file mode 100644
index e21de48c..00000000
--- a/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:1878b25a724b98b176070fbb562b7a54ba4f6d0ca67724e4b5bc31a43e491fae
-size 20568
diff --git a/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS2.aps1 b/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS2.aps1
new file mode 100644
index 00000000..ce5c9406
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS2.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4e5c52c3c9a278381d328e3388d75d4d2296041c0c1a6c1c0a3083a8459b087f
+size 2805
diff --git a/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS2.h5 b/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS2.h5
deleted file mode 100644
index 110969d5..00000000
--- a/tests/test_data/awg/TestAPS1/RabiAmp2/Rabi/Rabi-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:db62cca9c591811789eb181b4c0ddb0a904ce2dc7d05e7fb8050033daefd6ee0
-size 20568
diff --git a/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS1.aps1 b/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS1.aps1
new file mode 100644
index 00000000..2a6a3109
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6ac20319939b6dc7f0d64a1347a82bb9b671f767fe8b5e7a1bc06794d3d8cf77
+size 2425
diff --git a/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS1.h5 b/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS1.h5
deleted file mode 100644
index db4fa613..00000000
--- a/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:757050fe27d6d6fcbfc2d9d4b6b02d09745ef75948e7012f8ffab9cc520bac99
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS2.aps1 b/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS2.aps1
new file mode 100644
index 00000000..82b0b907
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS2.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9757b597ae5551218c1368ee3db777a3b411faed53fa7485d879b1c5a804856a
+size 1839
diff --git a/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS2.h5 b/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS2.h5
deleted file mode 100644
index b9c277eb..00000000
--- a/tests/test_data/awg/TestAPS1/RabiAmpPi/Rabi/Rabi-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ea5abdf66a0317b1ac458e9a102a0f4feb1850f3f3f7114b310eee161804ee50
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/RabiWidth/Rabi/Rabi-APS1.aps1 b/tests/test_data/awg/TestAPS1/RabiWidth/Rabi/Rabi-APS1.aps1
new file mode 100644
index 00000000..afc9515c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/RabiWidth/Rabi/Rabi-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:30c8ee6a5193280bdc158fdd762c7c05a744dc78045dc9100286b3dd501f9e24
+size 13
diff --git a/tests/test_data/awg/TestAPS1/RabiWidth/Rabi/Rabi-APS1.h5 b/tests/test_data/awg/TestAPS1/RabiWidth/Rabi/Rabi-APS1.h5
deleted file mode 100644
index 1c37d756..00000000
--- a/tests/test_data/awg/TestAPS1/RabiWidth/Rabi/Rabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6f450ffb720bb132c6db69679f24efaeace7ac3e377a089205025af9d1394f3b
-size 6240
diff --git a/tests/test_data/awg/TestAPS1/Ramsey/Ramsey-APS1.aps1 b/tests/test_data/awg/TestAPS1/Ramsey/Ramsey-APS1.aps1
new file mode 100644
index 00000000..084ba0e7
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/Ramsey/Ramsey-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6ed98961c6bcb69b90e43cfc6eb4369e94070691496236fd2ccf9df913fe0624
+size 2363
diff --git a/tests/test_data/awg/TestAPS1/Ramsey/Ramsey-APS1.h5 b/tests/test_data/awg/TestAPS1/Ramsey/Ramsey-APS1.h5
deleted file mode 100644
index 14734f5a..00000000
--- a/tests/test_data/awg/TestAPS1/Ramsey/Ramsey-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3783ad1b01a211e762dc1f7ff450852792638d739caabe2a2e4f735ef195e95d
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/SPAM/SPAM-APS1.aps1 b/tests/test_data/awg/TestAPS1/SPAM/SPAM-APS1.aps1
new file mode 100644
index 00000000..7bdf4f68
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/SPAM/SPAM-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:332f9f54ee51746281533a5c854afe85e924763bd80a5aa07d51a76fb16cfb63
+size 39821
diff --git a/tests/test_data/awg/TestAPS1/SPAM/SPAM-APS1.h5 b/tests/test_data/awg/TestAPS1/SPAM/SPAM-APS1.h5
deleted file mode 100644
index 73756191..00000000
--- a/tests/test_data/awg/TestAPS1/SPAM/SPAM-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:90c2eb18127ca1d8811d3d5cc3522f16f19748279ffc003d421b0181bdbd351f
-size 56762
diff --git a/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS1.aps1 b/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS1.aps1
new file mode 100644
index 00000000..afc9515c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:30c8ee6a5193280bdc158fdd762c7c05a744dc78045dc9100286b3dd501f9e24
+size 13
diff --git a/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS1.h5 b/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS1.h5
deleted file mode 100644
index 1c37d756..00000000
--- a/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6f450ffb720bb132c6db69679f24efaeace7ac3e377a089205025af9d1394f3b
-size 6240
diff --git a/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2.aps1 b/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2.aps1
new file mode 100644
index 00000000..afc9515c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:30c8ee6a5193280bdc158fdd762c7c05a744dc78045dc9100286b3dd501f9e24
+size 13
diff --git a/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2.h5 b/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2.h5
deleted file mode 100644
index 1c37d756..00000000
--- a/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6f450ffb720bb132c6db69679f24efaeace7ac3e377a089205025af9d1394f3b
-size 6240
diff --git a/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2_py27.h5 b/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2_py27.h5
deleted file mode 100644
index 39bfc4da..00000000
--- a/tests/test_data/awg/TestAPS1/SimultaneousRB_AC/RB/RB-APS2_py27.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dcc7226c4d9e8f9f5e56794d7e057003af6eaaecd4c841fdef2fedc2bf9b45f1
-size 6240
diff --git a/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1.aps1 b/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1.aps1
new file mode 100644
index 00000000..0b1b623e
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:904e7c9a02ec999e6fc7aaa2f28a98384eb67a4a031319b5c799dbd2aa998be2
+size 121307
diff --git a/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1.h5 b/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1.h5
deleted file mode 100644
index 128fe7e0..00000000
--- a/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:18a60bc56608e36d178c60119cb9526ad4caa68f520aa8f5c2924db45342b31a
-size 138680
diff --git a/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1_py27.h5 b/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1_py27.h5
deleted file mode 100644
index 748f1796..00000000
--- a/tests/test_data/awg/TestAPS1/SingleQubitRB/RB/RB-APS1_py27.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a322f8589452532de3f3d7feeefd1e58dbb83796250e37529c854deef24f1534
-size 138680
diff --git a/tests/test_data/awg/TestAPS1/SingleShot/SingleShot-APS1.aps1 b/tests/test_data/awg/TestAPS1/SingleShot/SingleShot-APS1.aps1
new file mode 100644
index 00000000..4012d581
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/SingleShot/SingleShot-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:13fc8118413ab1d83e6390cb06029e66aa126d33cc8404d92f0123da772705fb
+size 1149
diff --git a/tests/test_data/awg/TestAPS1/SingleShot/SingleShot-APS1.h5 b/tests/test_data/awg/TestAPS1/SingleShot/SingleShot-APS1.h5
deleted file mode 100644
index 4f0f920c..00000000
--- a/tests/test_data/awg/TestAPS1/SingleShot/SingleShot-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0c5996784d291c3dde24b082854188a5704304e70be802478a07ededf6993e92
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/Spec/Spec-APS1.aps1 b/tests/test_data/awg/TestAPS1/Spec/Spec-APS1.aps1
new file mode 100644
index 00000000..b4b0497d
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/Spec/Spec-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:40da4a38af7ff4312e61f0055908cd6273beaa80be8fdd70581a8a2154ca12b1
+size 1109
diff --git a/tests/test_data/awg/TestAPS1/Spec/Spec-APS1.h5 b/tests/test_data/awg/TestAPS1/Spec/Spec-APS1.h5
deleted file mode 100644
index f4f6922a..00000000
--- a/tests/test_data/awg/TestAPS1/Spec/Spec-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ea122c4f469e951782d29dc14dc83878dcad293e6e54ac284a3940186b32c30b
-size 18520
diff --git a/tests/test_data/awg/TestAPS1/T1/T1-APS1.aps1 b/tests/test_data/awg/TestAPS1/T1/T1-APS1.aps1
new file mode 100644
index 00000000..44568cfc
--- /dev/null
+++ b/tests/test_data/awg/TestAPS1/T1/T1-APS1.aps1
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8613cbca09ccd2a961c84c340b50414cbdef98be371675f39ff64f31ced993da
+size 1909
diff --git a/tests/test_data/awg/TestAPS1/T1/T1-APS1.h5 b/tests/test_data/awg/TestAPS1/T1/T1-APS1.h5
deleted file mode 100644
index 63c12621..00000000
--- a/tests/test_data/awg/TestAPS1/T1/T1-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fd60ddb02bfb69b40191e2d93683ced7d77f409d160af71f489bb9f28e174651
-size 18520
diff --git a/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS1.aps2 b/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS1.aps2
new file mode 100644
index 00000000..c4cf5611
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:84c8e5cc7c128b976fb19122933276d9a1263524fd17a016764d10b3992480f4
+size 5550
diff --git a/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS1.h5 b/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS1.h5
deleted file mode 100644
index b4146f64..00000000
--- a/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fbc0210f06102970cce4b843f2d11080ae9a47824cabc6bcc0c6cb7791675819
-size 14128
diff --git a/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS2.aps2 b/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS2.aps2
new file mode 100644
index 00000000..b7b1c359
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f601221c8a1df53d6defc97aba63c77780e9b97d69726c6a3b0b9ef987e2cb89
+size 2894
diff --git a/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS2.h5 b/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS2.h5
deleted file mode 100644
index 63de3f69..00000000
--- a/tests/test_data/awg/TestAPS2/AllXY/AllXY-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:b78617f09c3fc6e4e9ec43d35f512be6422750099e532c0a843e0f570b2ad7c1
-size 11472
diff --git a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS1.aps2 b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS1.aps2
new file mode 100644
index 00000000..c57aa3f2
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2f847ac93b35b559fbe0afab344c8d23ef064b4ac5c2bc9612b6723cd680e1ff
+size 854
diff --git a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS1.h5 b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS1.h5
deleted file mode 100644
index e8522425..00000000
--- a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f1aa4d2064d8c94bd5a2c861f5137c74b47bac9912de8e362650de79b9353632
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS3.aps2 b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS3.aps2
new file mode 100644
index 00000000..2d360388
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a2127036b39a846267d5a4cd8b5659abed0d8bcd22b200acbaf0f30265e23d2d
+size 278
diff --git a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS3.h5 b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS3.h5
deleted file mode 100644
index 16aa0539..00000000
--- a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e656cf6d7f1ec5d289c44dfdf3395c21b5002cfa0d099106e28d1bb279ee998c
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS5.aps2 b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS5.aps2
new file mode 100644
index 00000000..148df35e
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS5.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:142a223f060a567f1fc94f06817e41256779fea86bd04cf006a000a284cfb680
+size 98
diff --git a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS5.h5 b/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS5.h5
deleted file mode 100644
index cf8c86e4..00000000
--- a/tests/test_data/awg/TestAPS2/CNOT_CR_mux/CNOT_CR_mux-APS5.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:7248ddc03f87ba4062fb2cfdd5c8e9ff4c916a0bbff610de2ee4a13b3c9b09c9
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS1.aps2 b/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS1.aps2
new file mode 100644
index 00000000..87cf1736
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3be613e095ae800922fe93d3d1511cbba01fa2a9955578c53d7dcbaf68c8e012
+size 1982
diff --git a/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS1.h5 b/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS1.h5
deleted file mode 100644
index d5777ec0..00000000
--- a/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2e2e47343922a82e1258e6510001963cdd46acb7a7841565704c0175f255136a
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS2.aps2 b/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS2.aps2
new file mode 100644
index 00000000..11ea6c5c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ab7bdc5ad53a54bf0ef6eb859d746255df47be061489b93e3c5a733060085425
+size 1246
diff --git a/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS2.h5 b/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS2.h5
deleted file mode 100644
index 377ce4bc..00000000
--- a/tests/test_data/awg/TestAPS2/CPMG/CPMG-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:7d5be72267a5b599abcce2bcdf9968da5b9dfaab58cee5cf472c8fe8f3dce8cc
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/Echo/Echo-APS1.aps2 b/tests/test_data/awg/TestAPS2/Echo/Echo-APS1.aps2
new file mode 100644
index 00000000..7ef6e389
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/Echo/Echo-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d8777be258150c69db56d7bf5446bdbf07b44eab9d1cd07ca85afb609c2f4677
+size 2886
diff --git a/tests/test_data/awg/TestAPS2/Echo/Echo-APS1.h5 b/tests/test_data/awg/TestAPS2/Echo/Echo-APS1.h5
deleted file mode 100644
index 176b812c..00000000
--- a/tests/test_data/awg/TestAPS2/Echo/Echo-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4321e2efd619bb40368ad6238687cd97f465c94909f3969a4d80a5a09de36efc
-size 11464
diff --git a/tests/test_data/awg/TestAPS2/Echo/Echo-APS2.aps2 b/tests/test_data/awg/TestAPS2/Echo/Echo-APS2.aps2
new file mode 100644
index 00000000..d5e38136
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/Echo/Echo-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b87d3f879174b7af4502443943bc099eb69a9a559df4ba618cd52b084ae0d9ae
+size 1598
diff --git a/tests/test_data/awg/TestAPS2/Echo/Echo-APS2.h5 b/tests/test_data/awg/TestAPS2/Echo/Echo-APS2.h5
deleted file mode 100644
index a62f3b9d..00000000
--- a/tests/test_data/awg/TestAPS2/Echo/Echo-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c2354707a7b3471650d08145218677beb569d9ea2d87283b56ad84473dfed599
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS1.aps2 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS1.aps2
new file mode 100644
index 00000000..f9ce9f77
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:27882f98f2386e02b8f7bab8dc0cbbc9c70f8892a621e8f07d550f87392eaf8e
+size 4310
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS1.h5 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS1.h5
deleted file mode 100644
index ab15aa85..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:074d02801fc6b663db6f9250ceb639ca7b2e755ddb04ae70f3b9dd87e50c586c
-size 12792
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS2.aps2 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS2.aps2
new file mode 100644
index 00000000..5ff1fa82
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:27544612cfc2a8f7e8b9b1306672e5f9ecf16b8b22712de3482797da6417ea3b
+size 2862
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS2.h5 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS2.h5
deleted file mode 100644
index 9d8b12af..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:61084d6ac1164b7568c446759cb0baca6d850926162b7adc3073d4caa2aed0c7
-size 11344
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS3.aps2 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS3.aps2
new file mode 100644
index 00000000..bad77e86
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:094c46db9912e1a4a1c2e5fd3f4e8affb52ff59b84e17b042a75d6dfc4c86f7d
+size 2318
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS3.h5 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS3.h5
deleted file mode 100644
index 0ab91628..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6749480ab0b75672d39dd6005238719b1e76e3b3f9e6814894220076158ee1aa
-size 10800
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS4.aps2 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS4.aps2
new file mode 100644
index 00000000..5ff1fa82
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS4.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:27544612cfc2a8f7e8b9b1306672e5f9ecf16b8b22712de3482797da6417ea3b
+size 2862
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS4.h5 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS4.h5
deleted file mode 100644
index 9d8b12af..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS4.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:61084d6ac1164b7568c446759cb0baca6d850926162b7adc3073d4caa2aed0c7
-size 11344
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS5.aps2 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS5.aps2
new file mode 100644
index 00000000..1957c297
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS5.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c596ac8bb53ceb5afbaaa2a76eeec682298d26e4e11aca1694d060fdaffbe507
+size 5710
diff --git a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS5.h5 b/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS5.h5
deleted file mode 100644
index fae1d541..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRLen/EchoCR/EchoCR-APS5.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e7da7ea9ae19ea57b6e1cc5783c4ebb53ad2522ef51979d1fb656738ecc0aaf6
-size 14192
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS1.aps2 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS1.aps2
new file mode 100644
index 00000000..c14e60e7
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f5c00e601b1472df2167f948d585a951e4c8f369785db23f91a94ea9a8de7ed4
+size 4310
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS1.h5 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS1.h5
deleted file mode 100644
index 8696d76b..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:aace28a1695a9111804ab0bec5d783d482b835646ef86ca46e8e72b95092c8eb
-size 12792
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS2.aps2 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS2.aps2
new file mode 100644
index 00000000..1b50f181
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8989adb01d5d1b23c36bebcfa6707a1000fab28057cec9f6ddeb3d385c0cfb70
+size 2862
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS2.h5 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS2.h5
deleted file mode 100644
index 0779fc89..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:31849839f1cef008563c60475daae27687e16d87fd14f793eabdf80b4140cdc6
-size 11344
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS3.aps2 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS3.aps2
new file mode 100644
index 00000000..3f26f413
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:67e54be6fc7da5fea7b15ee46bdeb84aa97483cd1f5da827f298be78a75e28e6
+size 2814
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS3.h5 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS3.h5
deleted file mode 100644
index 3944eb32..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f4e95177c552f582aa32d9fac036db4cc9acd19214eabb4d74bec2a31fbb885f
-size 11296
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS4.aps2 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS4.aps2
new file mode 100644
index 00000000..1b50f181
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS4.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8989adb01d5d1b23c36bebcfa6707a1000fab28057cec9f6ddeb3d385c0cfb70
+size 2862
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS4.h5 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS4.h5
deleted file mode 100644
index 9220854d..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS4.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f2000631a2233d3c5b19d2fa7e53d5c6b65f3a09433bd0b8aedc85906d9bccc3
-size 11344
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS5.aps2 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS5.aps2
new file mode 100644
index 00000000..c2d1bbd1
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS5.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:998ed2c3fb7c85f69823c69e6ce567ead8a65003fe9df78e4d4891bd95a89493
+size 13758
diff --git a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS5.h5 b/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS5.h5
deleted file mode 100644
index 043f2ada..00000000
--- a/tests/test_data/awg/TestAPS2/EchoCRPhase/EchoCR/EchoCR-APS5.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4f8df32e2cf8c12ad3b48430f82500f8aa5fcdbf20d321825ae1f487d6f091db
-size 22240
diff --git a/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS1.aps2 b/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS1.aps2
new file mode 100644
index 00000000..591b20d6
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:16b1ab91da85f6996eb88a4f480dc646247cf284a1cf2c6f68cfc171b1c11cbb
+size 27566
diff --git a/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS1.h5 b/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS1.h5
deleted file mode 100644
index a02c1072..00000000
--- a/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:83900cc7545b582b4094661ffe46cdf13ae1b0c5fe0f26b81889c85e948482a6
-size 36144
diff --git a/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS2.aps2 b/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS2.aps2
new file mode 100644
index 00000000..5ceec56e
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d1fa32e761c559b4d4f286bbb5a1203c5cc4b18554d4d72282716649eb68330c
+size 15198
diff --git a/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS2.h5 b/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS2.h5
deleted file mode 100644
index 35bb1250..00000000
--- a/tests/test_data/awg/TestAPS2/FlipFlop/FlipFlop-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:cc3a30d96dafb22cd52d508ed0770c129fdf99338b33471480580fdf959eeed6
-size 23776
diff --git a/tests/test_data/awg/TestAPS2/GST/GST/listOfExperiments.npy b/tests/test_data/awg/TestAPS2/GST/GST/listOfExperiments.npy
new file mode 100644
index 00000000..7e552e2d
Binary files /dev/null and b/tests/test_data/awg/TestAPS2/GST/GST/listOfExperiments.npy differ
diff --git a/tests/test_data/awg/TestAPS2/GST/GST2Q/listOfExperiments.npy b/tests/test_data/awg/TestAPS2/GST/GST2Q/listOfExperiments.npy
new file mode 100644
index 00000000..44e229ed
Binary files /dev/null and b/tests/test_data/awg/TestAPS2/GST/GST2Q/listOfExperiments.npy differ
diff --git a/tests/test_data/awg/TestAPS2/MISC1/MISC1-APS1.aps2 b/tests/test_data/awg/TestAPS2/MISC1/MISC1-APS1.aps2
new file mode 100644
index 00000000..cbf62bbb
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC1/MISC1-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fb695b5795e4c1ab729d4800d939687489312e675b8bbb2bdde34d129d15a2f7
+size 3566
diff --git a/tests/test_data/awg/TestAPS2/MISC1/MISC1-APS1.h5 b/tests/test_data/awg/TestAPS2/MISC1/MISC1-APS1.h5
deleted file mode 100644
index b0a3a6a7..00000000
--- a/tests/test_data/awg/TestAPS2/MISC1/MISC1-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:86e48fbb5d9ee98c3c04a98c7a473d5ff61d41be88fbb73c7ad9cf4e5a005ce4
-size 12144
diff --git a/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS1.aps2 b/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS1.aps2
new file mode 100644
index 00000000..d7d18a41
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6c9c042af3d9890243f33df8c82ad8858dca532e86115b33dbf065e8ecd6df7a
+size 302
diff --git a/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS1.h5 b/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS1.h5
deleted file mode 100644
index 03a088e7..00000000
--- a/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9adb85c5ce6cb9816addc5e8604b27a8111e6b28dde262f63dfc5057f9d7a06d
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS5.aps2 b/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS5.aps2
new file mode 100644
index 00000000..73c2d580
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS5.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9d8f4baee00287d69c030d07c58b55dabc45d4d4a68028c0b517c95c7f67ceae
+size 638
diff --git a/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS5.h5 b/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS5.h5
deleted file mode 100644
index c2c2df99..00000000
--- a/tests/test_data/awg/TestAPS2/MISC2/MISC2-APS5.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:915e457884f2c97a47c28d3d8c27390c9c8058262ce6394ccdf0b1c2d744abbf
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS1.aps2 b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS1.aps2
new file mode 100644
index 00000000..05147f69
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2648062292b4b86379641948f42f9b3e580f061e646ebc719518fae5ae2b47b5
+size 366
diff --git a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS1.h5 b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS1.h5
deleted file mode 100644
index c51d3682..00000000
--- a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:416c37f8cdd7f8ce8bf1abe4b72a4173e3a661148e0db3aefe4d5665b1f0a147
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS3.aps2 b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS3.aps2
new file mode 100644
index 00000000..2d360388
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a2127036b39a846267d5a4cd8b5659abed0d8bcd22b200acbaf0f30265e23d2d
+size 278
diff --git a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS3.h5 b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS3.h5
deleted file mode 100644
index 16aa0539..00000000
--- a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e656cf6d7f1ec5d289c44dfdf3395c21b5002cfa0d099106e28d1bb279ee998c
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS5.aps2 b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS5.aps2
new file mode 100644
index 00000000..9e74a68a
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS5.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a2e3ecdb003db075586c2a206bc7d7682b1ea64e298934c3f9d4fe5e80df989b
+size 654
diff --git a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS5.h5 b/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS5.h5
deleted file mode 100644
index cee1a3cd..00000000
--- a/tests/test_data/awg/TestAPS2/MISC3/MISC3-APS5.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:effecd5635e103d6cfd24c33e8a2433c044c9ea8738f726d20db2d3a8688033b
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS1.aps2 b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS1.aps2
new file mode 100644
index 00000000..7e82c465
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:afc0ad90fef6b1152038b523a4d9e60ebe07b4b873118f5af886299d0c4084b3
+size 542
diff --git a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS1.h5 b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS1.h5
deleted file mode 100644
index 5c356fdd..00000000
--- a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8ff47cb0de965b5eeee007073e18cf1595db07704bea14860301b4ebc7269558
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS3.aps2 b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS3.aps2
new file mode 100644
index 00000000..9349b597
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:30ae36b2e96aff26f55a71282a6e3c5dab02439e39c0ace27add0eea05383224
+size 790
diff --git a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS3.h5 b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS3.h5
deleted file mode 100644
index b43355ab..00000000
--- a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ad29c5d9ad6bdcf2d71e26167aced2f450382754cd23d764ad21165f2b268f15
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS5.aps2 b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS5.aps2
new file mode 100644
index 00000000..e0e78833
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS5.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5c561c0e4b1bfbe9f1cbb503eb755a0323b5be68ff3e7a145edfa27a324ed2a8
+size 694
diff --git a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS5.h5 b/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS5.h5
deleted file mode 100644
index 2276be6d..00000000
--- a/tests/test_data/awg/TestAPS2/MISC4/MISC4-APS5.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:b101668cd5d7ea4ced46a8d357ce9145984d66bf18610f222df20666846fcdaf
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS1.aps2 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS1.aps2
new file mode 100644
index 00000000..058335ff
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5db547eede6bb82dedff31595a5f103867edd64487509451e40be0f47fcc5431
+size 3166
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS1.h5 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS1.h5
deleted file mode 100644
index fa599be4..00000000
--- a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:7c311beb3a70d927d1939705577029ae1939822593558d2cf1ba50cb3351cda7
-size 11744
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS2.aps2 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS2.aps2
new file mode 100644
index 00000000..30caceef
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5077d62fe51b3fad882dbd73f5783eb4aa0a9f8dcd2dd43d31d518878a95fc87
+size 2246
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS2.h5 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS2.h5
deleted file mode 100644
index b9f33eb5..00000000
--- a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:81a88bcc43f757356ad54647b515bb508c7fd4767da4f806c48f20fc082af080
-size 10824
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS3.aps2 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS3.aps2
new file mode 100644
index 00000000..6aa6816e
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:365c689f3611c49bae72fde4db099063f1b6bcc6fc90b12bacef100f21f53647
+size 1702
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS3.h5 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS3.h5
deleted file mode 100644
index 69a02bfb..00000000
--- a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8960fdf72531618dbacf7c8b1c10334184a4a7ef6ded1c0fdadce1c002cfae77
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS4.aps2 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS4.aps2
new file mode 100644
index 00000000..30caceef
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS4.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5077d62fe51b3fad882dbd73f5783eb4aa0a9f8dcd2dd43d31d518878a95fc87
+size 2246
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS4.h5 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS4.h5
deleted file mode 100644
index b9f33eb5..00000000
--- a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS4.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:81a88bcc43f757356ad54647b515bb508c7fd4767da4f806c48f20fc082af080
-size 10824
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS5.aps2 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS5.aps2
new file mode 100644
index 00000000..3577086d
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS5.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a005b4fab6c710c68cd3fa008ac4f25d4f8b4358f4d65f97a4cb4726e1098d32
+size 2614
diff --git a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS5.h5 b/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS5.h5
deleted file mode 100644
index 099c3395..00000000
--- a/tests/test_data/awg/TestAPS2/PiRabi/PiRabi-APS5.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:5d863d35d6ecf34db2e931f291c41f1d5e89a76c6dc56218f206397daf2eb411
-size 11192
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS1.aps2 b/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS1.aps2
new file mode 100644
index 00000000..e7d23b5e
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:84c2f406fc1765013f9c203a8e6eaffc97cfc228a6bbb4a1ad235b7d55de2e63
+size 2590
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS1.h5 b/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS1.h5
deleted file mode 100644
index 3c3c7192..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:d054d3bf07b82bcd8fceb169441aa52653742fe6be83b2eb799fd339675ee120
-size 11168
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS2.aps2 b/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS2.aps2
new file mode 100644
index 00000000..e9188c2c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:959f0c471be1bcf3fd7177b80184f464afa2657c80a29892f10ac62eb50754fa
+size 1070
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS2.h5 b/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS2.h5
deleted file mode 100644
index 8ad9d24c..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmp/Rabi/Rabi-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:14db8318fc956cc9428038237eb83de6ef9d7dd8e343a627f5af6d8be8f2808b
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS1.aps2 b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS1.aps2
new file mode 100644
index 00000000..e7d23b5e
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:84c2f406fc1765013f9c203a8e6eaffc97cfc228a6bbb4a1ad235b7d55de2e63
+size 2590
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS1.h5 b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS1.h5
deleted file mode 100644
index 3c3c7192..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:d054d3bf07b82bcd8fceb169441aa52653742fe6be83b2eb799fd339675ee120
-size 11168
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS2.aps2 b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS2.aps2
new file mode 100644
index 00000000..e9188c2c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:959f0c471be1bcf3fd7177b80184f464afa2657c80a29892f10ac62eb50754fa
+size 1070
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS2.h5 b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS2.h5
deleted file mode 100644
index 8ad9d24c..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:14db8318fc956cc9428038237eb83de6ef9d7dd8e343a627f5af6d8be8f2808b
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS3.aps2 b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS3.aps2
new file mode 100644
index 00000000..a4b21884
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f0a75b4f3a1ac4fb541d65a89e1050ddf2d5b3827b3ef1d50d6d6a7daf0bde17
+size 2150
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS3.h5 b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS3.h5
deleted file mode 100644
index 4eac161e..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:969244eeb80756e810991823154a170fd7c781eeb6e6458a5c29e72851547e93
-size 10728
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS4.aps2 b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS4.aps2
new file mode 100644
index 00000000..e9188c2c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS4.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:959f0c471be1bcf3fd7177b80184f464afa2657c80a29892f10ac62eb50754fa
+size 1070
diff --git a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS4.h5 b/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS4.h5
deleted file mode 100644
index 8ad9d24c..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmp2/Rabi/Rabi-APS4.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:14db8318fc956cc9428038237eb83de6ef9d7dd8e343a627f5af6d8be8f2808b
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS1.aps2 b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS1.aps2
new file mode 100644
index 00000000..f3e01bba
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6dd034f72cef034a68543bb4739f3748da2b8b978c2e8532e862c6cb4bb6ebbb
+size 2718
diff --git a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS1.h5 b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS1.h5
deleted file mode 100644
index 15c902a5..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:d0775ac3780f687769e78cad08d9b7d92bf95e3e3c2f3050ce58a974f5fda4c7
-size 11296
diff --git a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS3.aps2 b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS3.aps2
new file mode 100644
index 00000000..1c87b609
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8d47634aa2cc2809834475a0f117e9d9d828e85bca3b24e582affdc224a7b2f1
+size 1086
diff --git a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS3.h5 b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS3.h5
deleted file mode 100644
index 4c178a11..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3c7dc446b904881261db1c6633dd34ebae89e9c2ffc6889a54581bfdf7d25697
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS4.aps2 b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS4.aps2
new file mode 100644
index 00000000..31bd854f
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS4.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8fa84799426b4229cc3b14d4ee352d7e8086d1b4364ff12247302d7ae63f3124
+size 1246
diff --git a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS4.h5 b/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS4.h5
deleted file mode 100644
index 33dea5d2..00000000
--- a/tests/test_data/awg/TestAPS2/RabiAmpPi/Rabi/Rabi-APS4.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:bdc238f311f839735033b037991ba9f78bc867ba8b1c6c8a15f235eaa66a0837
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS1.aps2 b/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS1.aps2
new file mode 100644
index 00000000..10040774
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1760a6778f5be4e1ed2ff400754eed899bbfcb2eaf023ba549888d2f1761377c
+size 133022
diff --git a/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS1.h5 b/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS1.h5
deleted file mode 100644
index 5259eba8..00000000
--- a/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a339b76ebcc9d086cd3803a89b1c5e6c90b3fd06e103e450abe6d74648827995
-size 141600
diff --git a/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS2.aps2 b/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS2.aps2
new file mode 100644
index 00000000..9ec47b44
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:63a70eb6ace79b1e32d3c4c84e8289ac6ff3bcf03b3af2a98b72becf1788497d
+size 1070
diff --git a/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS2.h5 b/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS2.h5
deleted file mode 100644
index bd8942d8..00000000
--- a/tests/test_data/awg/TestAPS2/RabiWidth/Rabi/Rabi-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ec5f1a8ba8396b3ba1319ce825fc8e4ec0d9fc6415768905f758a15a54193f4b
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS1.aps2 b/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS1.aps2
new file mode 100644
index 00000000..2e35f4eb
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3ed0361d46fee45b792ab01bce498043fc666f814de55237f1fb5b6fc2d9876e
+size 1982
diff --git a/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS1.h5 b/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS1.h5
deleted file mode 100644
index 40d604b3..00000000
--- a/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ef6338bddfdcab213e12581b6a97b1316884838167748b0c5e98cd4330b64b22
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS2.aps2 b/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS2.aps2
new file mode 100644
index 00000000..46375518
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c9814858177b26e6d187ee30920547db85d9ac00e2a16c6260cb84a9a2aa9a8f
+size 1430
diff --git a/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS2.h5 b/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS2.h5
deleted file mode 100644
index ac0be242..00000000
--- a/tests/test_data/awg/TestAPS2/Ramsey/Ramsey-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c3cba432c0f7d9b7207a9ce43f8301c743c630271106d2a80712c89e75c46ef5
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS1.aps2 b/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS1.aps2
new file mode 100644
index 00000000..05f7d108
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0a347e86c8e15f8e8cc42c36f2c3fcd46cca15192d03ecf24de864a63f9ffed7
+size 40886
diff --git a/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS1.h5 b/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS1.h5
deleted file mode 100644
index 5fd4a6cb..00000000
--- a/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:43b14db680f80a369c2540c565cefac2a2870aea59c7bad31c05d2d74956c270
-size 49464
diff --git a/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS2.aps2 b/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS2.aps2
new file mode 100644
index 00000000..af7fa503
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:693869c98824b15aaf89f43edfab1005b6382564d16b8545b3f1a9c5d07634b8
+size 23118
diff --git a/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS2.h5 b/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS2.h5
deleted file mode 100644
index 6583bfa6..00000000
--- a/tests/test_data/awg/TestAPS2/SPAM/SPAM-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:54c4f9ef853fedffb8fa8715d725328e4af6d73e6027e8a38916ab914d76e729
-size 31696
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1.aps2 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1.aps2
new file mode 100644
index 00000000..ebad8370
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:714f3bf47f611b39dd0fd544b7d517a5cb99ca52bd86a748d27ac6dc2cc17bea
+size 101214
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1.h5 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1.h5
deleted file mode 100644
index d2e4d179..00000000
--- a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dd966f8d48d3cfa94237cc2c112b70157d35230ca2dcd4664bf4c4c731d3a061
-size 109792
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1_py27.h5 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1_py27.h5
deleted file mode 100644
index dfca1f76..00000000
--- a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS1_py27.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:afa8cc3c99fea314c9e01d7159c8222932760cf47bc93ff6780452ebd4e7e14f
-size 109792
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2.aps2 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2.aps2
new file mode 100644
index 00000000..5b941d80
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5281ef48b48391cbc4542ad51a21a7dcfb3d34556b535ac47e8946c5a526980a
+size 40174
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2.h5 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2.h5
deleted file mode 100644
index 13bd0b3a..00000000
--- a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:222857cb4e7df9c271e1583a94d1e6696dd2c29104e7ee60dcfeace5b8af541a
-size 48752
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2_py27.h5 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2_py27.h5
deleted file mode 100644
index 2b9cb45f..00000000
--- a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS2_py27.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:09bf8d013355b15c3f97a641bb2d70eed3e28f4e0d678c718048634d447e60c3
-size 48752
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3.aps2 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3.aps2
new file mode 100644
index 00000000..f263f76a
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:153c21514cf092be2f49b28dd716a2ea3395b688dbe9d7a73122835f50aa8526
+size 94174
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3.h5 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3.h5
deleted file mode 100644
index bb804166..00000000
--- a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2af3590d082ccb86ee8593c3913f8b505dba80f7fae8a21fa7d763b5e753bd36
-size 102752
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3_py27.h5 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3_py27.h5
deleted file mode 100644
index bc8caa68..00000000
--- a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS3_py27.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e42789e76e1d2e544847ddb2f4131198188a8aa5971097a537dd354fd8149bb1
-size 102752
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4.aps2 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4.aps2
new file mode 100644
index 00000000..5b941d80
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5281ef48b48391cbc4542ad51a21a7dcfb3d34556b535ac47e8946c5a526980a
+size 40174
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4.h5 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4.h5
deleted file mode 100644
index 13bd0b3a..00000000
--- a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:222857cb4e7df9c271e1583a94d1e6696dd2c29104e7ee60dcfeace5b8af541a
-size 48752
diff --git a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4_py27.h5 b/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4_py27.h5
deleted file mode 100644
index b3de0972..00000000
--- a/tests/test_data/awg/TestAPS2/SimultaneousRB_AC/RB/RB-APS4_py27.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:51493c82b6a380853c1644469efff8e2234c0233e48b5508759a066e1f16fc1b
-size 48752
diff --git a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1.aps2 b/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1.aps2
new file mode 100644
index 00000000..26476cff
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7d08252ecf794842f96ea5b7b2132283e351316258b1d42c963fc507e02034c5
+size 113798
diff --git a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1.h5 b/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1.h5
deleted file mode 100644
index 062da429..00000000
--- a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fd2e0d3b890dc1010ad4b55381c11b6f7744a8c58106c950d7a445620fdf8c44
-size 122376
diff --git a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1_py27.h5 b/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1_py27.h5
deleted file mode 100644
index d86f0f00..00000000
--- a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS1_py27.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:43e610294922c1e73d59fcdb0c6473d9f9c2338c3d8351c2dd6a2eda075fa55d
-size 122376
diff --git a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2.aps2 b/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2.aps2
new file mode 100644
index 00000000..71ed0ab7
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fb7f55567c34c01fe5d88a02cdb2fdff6ad554eda1622d7aa5524c0d5abd038c
+size 68670
diff --git a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2.h5 b/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2.h5
deleted file mode 100644
index dacb3ba2..00000000
--- a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9e805e568677dda8a06e7070204af604ed0b84926b4cf1fc0dbe617d8a13b5a9
-size 77248
diff --git a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2_py27.h5 b/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2_py27.h5
deleted file mode 100644
index 23bf2dfa..00000000
--- a/tests/test_data/awg/TestAPS2/SingleQubitRB/RB/RB-APS2_py27.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8792254cb7b487fdc6cde009a8950654b674d4a31903f875f056399131db928c
-size 77248
diff --git a/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS1.aps2 b/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS1.aps2
new file mode 100644
index 00000000..1cfc0072
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e6697f675afe2b24ec3ba066632789487de2c4382d9592a2c22286d472c88fe5
+size 374
diff --git a/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS1.h5 b/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS1.h5
deleted file mode 100644
index 6d9c8d34..00000000
--- a/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fecac08fc9b57eb04f0d4aaf88ac64479e74860b93a5576452ef3cb4cb68ffef
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS2.aps2 b/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS2.aps2
new file mode 100644
index 00000000..7cf89baf
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fd31cbd1f5a73e2e315d16835183a44de585fe39b7eb150a4d4de70097a5cdbc
+size 638
diff --git a/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS2.h5 b/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS2.h5
deleted file mode 100644
index 5d400603..00000000
--- a/tests/test_data/awg/TestAPS2/SingleShot/SingleShot-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e4125f49979cef1af9af1aa16d7795f50be4cb39ae02f60aca1a79a31eab3a93
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/Spec/Spec-APS1.aps2 b/tests/test_data/awg/TestAPS2/Spec/Spec-APS1.aps2
new file mode 100644
index 00000000..eded4da5
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/Spec/Spec-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5c8b7bf6a97cb17eb48dd46c110a9087bb77a0934cf8053dcc9e6b9ad70bcde4
+size 294
diff --git a/tests/test_data/awg/TestAPS2/Spec/Spec-APS1.h5 b/tests/test_data/awg/TestAPS2/Spec/Spec-APS1.h5
deleted file mode 100644
index 0f6b1e0d..00000000
--- a/tests/test_data/awg/TestAPS2/Spec/Spec-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9d52de2c3596cc0f61bf8dee2c224d26b5b6bdc378332001d0eea00a15dfe328
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/Spec/Spec-APS2.aps2 b/tests/test_data/awg/TestAPS2/Spec/Spec-APS2.aps2
new file mode 100644
index 00000000..0f81835b
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/Spec/Spec-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:921a848eed51b9289ca78c382f8bc1efb915f32a7cb2452ba41d0da2a2ab6dde
+size 590
diff --git a/tests/test_data/awg/TestAPS2/Spec/Spec-APS2.h5 b/tests/test_data/awg/TestAPS2/Spec/Spec-APS2.h5
deleted file mode 100644
index e89591a9..00000000
--- a/tests/test_data/awg/TestAPS2/Spec/Spec-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4fed627361f76485e09a21c1e72186e64b710ca9a6bf1e71aff1b5cbefebf108
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/T1/T1-APS1.aps2 b/tests/test_data/awg/TestAPS2/T1/T1-APS1.aps2
new file mode 100644
index 00000000..cd52185c
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/T1/T1-APS1.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:89a2e446a2e8efe6c2b532211dfb6245154566e3a4eaaffedc91172c89f6cdc9
+size 1590
diff --git a/tests/test_data/awg/TestAPS2/T1/T1-APS1.h5 b/tests/test_data/awg/TestAPS2/T1/T1-APS1.h5
deleted file mode 100644
index 5c23cfc1..00000000
--- a/tests/test_data/awg/TestAPS2/T1/T1-APS1.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:1ae2feab747be8b5ef6804c3cae154b6099dc30d22c0dd4f62b9bdc121a7beee
-size 10664
diff --git a/tests/test_data/awg/TestAPS2/T1/T1-APS2.aps2 b/tests/test_data/awg/TestAPS2/T1/T1-APS2.aps2
new file mode 100644
index 00000000..591b8899
--- /dev/null
+++ b/tests/test_data/awg/TestAPS2/T1/T1-APS2.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:eab22cfd02f7e5def78a2d83115256554074ea2202ec2406b99e46d4b07921af
+size 1342
diff --git a/tests/test_data/awg/TestAPS2/T1/T1-APS2.h5 b/tests/test_data/awg/TestAPS2/T1/T1-APS2.h5
deleted file mode 100644
index 126007b4..00000000
--- a/tests/test_data/awg/TestAPS2/T1/T1-APS2.h5
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:09d114f4c75921bf7aea9db671bbf3618046c1965a4229e405ad0c8d2f7e7805
-size 10664
diff --git a/tests/test_data/multi-align.aps2 b/tests/test_data/multi-align.aps2
new file mode 100644
index 00000000..9d8fd6b2
--- /dev/null
+++ b/tests/test_data/multi-align.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0be50748c40f8b3bdafc4ff4daa193b607dae69808f0bad20c34b1b31ca32cce
+size 5150
diff --git a/tests/test_data/multi-composite.aps2 b/tests/test_data/multi-composite.aps2
new file mode 100644
index 00000000..1499f19a
--- /dev/null
+++ b/tests/test_data/multi-composite.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e992af922f5470372cd7471c401e39ec89c846f7c56652f3b9ecd622b5a3de20
+size 3614
diff --git a/tests/test_data/multi-operators.aps2 b/tests/test_data/multi-operators.aps2
new file mode 100644
index 00000000..98006e46
--- /dev/null
+++ b/tests/test_data/multi-operators.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ae9ec04d4585feae8d183dff7cab85c0ba4546b152a1a020421c6cbefc4daf38
+size 8294
diff --git a/tests/test_data/single-ramsey.aps2 b/tests/test_data/single-ramsey.aps2
new file mode 100644
index 00000000..317594ac
--- /dev/null
+++ b/tests/test_data/single-ramsey.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:20f946802a58a5eca8b380c3decbd1efa5b11af7e0218a9aff9b7d7667567361
+size 118358
diff --git a/tests/test_data/single-repeat.aps2 b/tests/test_data/single-repeat.aps2
new file mode 100644
index 00000000..5f927b97
--- /dev/null
+++ b/tests/test_data/single-repeat.aps2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:79bb0e61d5cbc53767734ea544e111ad5670f1ab4cf9c2945ea7c4e3c82e8be9
+size 4054
diff --git a/tests/test_measure.yml b/tests/test_measure.yml
deleted file mode 100644
index fd601cca..00000000
--- a/tests/test_measure.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-config:
- AWGDir: /tmp/awg
- KernelDir: /tmp/kern
- LogDir: /tmp/alog
-
\ No newline at end of file
diff --git a/tests/test_perf.py b/tests/test_perf.py
new file mode 100644
index 00000000..1830e1e2
--- /dev/null
+++ b/tests/test_perf.py
@@ -0,0 +1,19 @@
+#simple file added for performace testing...
+
+from QGL import *
+import random
+
+def random_sequence_test():
+ N = 1000
+
+ cl = ChannelLibrary()
+ q1 = QubitFactory("q1")
+
+ gates = (X90(q1), Y90(q1), X(q1), Y(q1), Id(q1, length=1e-7))
+
+ seqs = []
+ ks = random.choices(range(1,100), k = N)
+ for k in ks:
+ seqs.append(random.choices(gates, k=k) + [MEAS(q1)])
+
+ compile_to_hardware(seqs, 'test/test')
diff --git a/utils/convert_h5_to_aps.py b/utils/convert_h5_to_aps.py
new file mode 100644
index 00000000..3b0eb8b6
--- /dev/null
+++ b/utils/convert_h5_to_aps.py
@@ -0,0 +1,106 @@
+import numpy as np
+import h5py
+import sys
+import os.path
+
+def write_to_aps1(fileName, data):
+ channelDataFor = np.array([i in data['channelDataFor'] for i in range(1,5)], dtype=np.bool)
+ try:
+ with open(fileName, 'wb') as FID:
+ FID.write(b'APS1') # target hardware
+ FID.write(np.float32(2.2).tobytes()) # Version
+ FID.write(channelDataFor.tobytes()) # channelDataFor
+ FID.write(np.array(data['miniLLRepeat'], dtype=np.bool).tobytes()) # MiniLLRepeat
+ for name in data['channels'].keys():
+ FID.write(np.uint8(data['channels'][name]['isIQMode']).tobytes()) # isIQMode
+ FID.write(np.uint64(data['channels'][name]['waveformLib'].size).tobytes()) # Length of waveforms
+ FID.write(data['channels'][name]['waveformLib'].tobytes()) # Waveforms np.int16
+ FID.write(np.uint8('linkListData' in data['channels']['chan_1'].keys()).tobytes()) # LL for chan1
+ FID.write(np.uint8('linkListData' in data['channels']["chan_3"].keys()).tobytes()) # LL for chan3
+ for name in ['chan_1', 'chan_3']:
+ if 'linkListData' in data['channels'][name].keys():
+ FID.write(np.uint64(data['channels'][name]['linkListNumKeys']).tobytes()) # numKeys
+ FID.write(np.uint64(data['channels'][name]['linkListDataLength']).tobytes()) # numEntries
+ for key, dataVec in data['channels'][name]['linkListData'].items():
+ FID.write(key.ljust(32,"#").encode("utf-8")) # Key 32 byte utf-8
+ FID.write(dataVec.tobytes())
+ except:
+ print(f"Warning: could not write aps1 file {fileName}")
+
+def write_to_aps2(fileName, data):
+ instructions = data['instructions']
+ wfInfo = {}
+ wfInfo[0] = data['chan1']
+ wfInfo[1] = data['chan2']
+
+ with open(fileName, 'wb') as FID:
+ FID.write(b'APS2') # target
+ FID.write(np.float32(data['file_version']).tobytes()) # Version
+ FID.write(np.float32(data['fw_version']).tobytes()) # minimum firmware version
+ FID.write(np.uint16(2).tobytes()) # number of channels
+ # FID.write(np.uint16([1, 2]).tobytes()) # channelDataFor
+ FID.write(np.uint64(instructions.size).tobytes()) # instructions length
+ FID.write(instructions.tobytes()) # instructions in uint64 form
+
+ #Create the groups and datasets
+ for chanct in range(2):
+ #Write the waveformLib to file
+ if wfInfo[chanct].size == 0:
+ #If there are no waveforms, ensure that there is some element
+ #so that the waveform group gets written to file.
+ #TODO: Fix this in libaps2
+ data = np.array([0], dtype=np.int16)
+ else:
+ data = wfInfo[chanct]
+ FID.write(np.uint64(data.size).tobytes()) # waveform data length for channel
+ FID.write(data.tobytes())
+
+def get_type(fileName):
+ with h5py.File(fileName, 'r') as FID:
+ t = FID['/'].attrs['target hardware']
+ return t
+
+def read_aps2_from_h5(fileName):
+ data = {}
+ with h5py.File(fileName, 'r') as FID:
+ data["instrument"] = FID['/'].attrs['target hardware']
+ data["file_version"] = FID["/"].attrs["Version"]
+ data["fw_version"] = FID['/'].attrs['minimum firmware version']
+ data["chan1"] = FID['/chan_1/waveforms'].value.flatten()
+ data["chan2"] = FID['/chan_2/waveforms'].value.flatten()
+ data["instructions"] = FID['/chan_1/instructions'].value.flatten()
+ return data
+
+def read_aps1_from_h5(fileName):
+ data = {}
+ with h5py.File(fileName, 'r') as FID:
+ data["instrument"] = FID['/'].attrs['target hardware']
+ data["file_version"] = FID["/"].attrs["Version"]
+ data["channelDataFor"] = FID["/"].attrs["channelDataFor"]
+ data["miniLLRepeat"] = FID['/'].attrs['miniLLRepeat']
+ channels = list(FID['/'].keys())
+ data['channels'] = {}
+ for channel in channels:
+ data['channels'][channel] = {'waveformLib': FID[f'/{channel}/waveformLib'].value.flatten()}
+ data['channels'][channel]['isIQMode'] = FID[f'/{channel}'].attrs['isIQMode']
+ if 'linkListData' in list(FID[f'/{channel}'].keys()):
+ data['channels'][channel]['linkListData'] = {}
+ for key in FID[f'/{channel}/linkListData'].keys():
+ data['channels'][channel]['linkListNumKeys'] = len(FID[f'/{channel}/linkListData'].keys())
+ data['channels'][channel]['linkListDataLength'] = FID[f'/{channel}/linkListData'].attrs['length']
+ data['channels'][channel]['linkListData'][key] = FID[f'/{channel}/linkListData/{key}'].value.flatten()
+ return data
+
+if __name__ == '__main__':
+ for filename in sys.argv[1:]:
+ basename, ext = os.path.splitext(filename)
+ print(f"Converting {basename+'.h5'}")
+ inst = get_type(basename+'.h5')
+ if inst == "APS2":
+ data = read_aps2_from_h5(basename+'.h5')
+ write_to_aps2(basename+".aps2", data)
+ if inst == "APS1":
+ data = read_aps1_from_h5(basename+'.h5')
+ write_to_aps1(basename+".aps1", data)
+
+
diff --git a/utils/disassemble_aps.py b/utils/disassemble_aps.py
new file mode 100755
index 00000000..1b7919c4
--- /dev/null
+++ b/utils/disassemble_aps.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+
+import numpy as np
+import sys
+import os.path
+
+from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QTableWidget, QTableWidgetItem, QVBoxLayout, QAbstractItemView, QPushButton
+from PyQt5.QtGui import QIcon, QColor, QFont
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
+from matplotlib.figure import Figure
+
+colors = {"WFM": QColor(0,200,0),
+ "GOTO": QColor(0,100,100),
+ "MARKER": QColor(150,150,200),
+ "CUSTOM": QColor(200,65,200),
+ "WRITEADDR": QColor(245, 105, 65),
+ "INVALIDATE": QColor(245, 105, 65),
+ "CALL": QColor(65, 205, 245),
+ "RET": QColor(65, 205, 245),
+ "LOADCMP": QColor(245, 225, 65),
+ "MODULATION": QColor(175, 255, 185)}
+
+table_font = QFont("Arial", weight=QFont.Bold)
+
+class MatplotlibWidget(QWidget):
+ def __init__(self, I, Q, parent=None):
+ super(MatplotlibWidget, self).__init__(parent)
+ self.title = 'Waveform'
+ self.left = 100
+ self.top = 100
+ self.width = 800
+ self.height = 600
+ self.setWindowTitle(self.title)
+ self.setGeometry(self.left, self.top, self.width, self.height)
+
+ self.figure = Figure()
+ self.canvas = FigureCanvasQTAgg(self.figure)
+
+ self.axis = self.figure.add_subplot(111)
+ self.axis.plot(I)
+ self.axis.plot(Q)
+ self.layout = QVBoxLayout(self)
+ self.layout.addWidget(self.canvas)
+ self.setLayout(self.layout)
+ self.canvas.draw()
+ self.show()
+
+
+class DisassemblerApp(QWidget):
+
+ COLUMN_COUNT = 7
+
+ def __init__(self, instructions, waveforms):
+ super().__init__()
+ self.title = 'APS2 Disassembled Instructions'
+ self.left = 100
+ self.top = 100
+ self.width = 1000
+ self.height = 1200
+ self.instructions = instructions
+ self.waveforms = waveforms
+ self.initUI()
+ self.plotters = []
+
+ def initUI(self):
+ self.setWindowTitle(self.title)
+ self.setGeometry(self.left, self.top, self.width, self.height)
+
+ self.createTable()
+ self.layout = QVBoxLayout()
+ self.layout.addWidget(self.tableWidget)
+ self.setLayout(self.layout)
+
+ # Show widget
+ self.show()
+
+ def createTable(self):
+ # Create table
+ self.tableWidget = QTableWidget()
+ self.tableWidget.setRowCount(len(self.instructions))
+ self.tableWidget.setColumnCount(self.COLUMN_COUNT)
+
+ for k, instr in enumerate(self.instructions):
+ fields = str(instr).replace(',','').replace(';', '').split(" ")
+ if "|" in fields:
+ fields.remove("|")
+ if fields[0] in colors:
+ color = colors[fields[0]]
+ else:
+ color = None
+ for l, f in enumerate(fields):
+ text = fields[l]
+ if text == "GOTO":
+ btn = QPushButton(self.tableWidget)
+ btn.setText('GOTO')
+ target_row = int(fields[1].split("=")[1])
+ def scroll_to_goto_target(row=target_row, tab=self.tableWidget):
+ tab.scrollToItem(tab.item(row, 0))
+ btn.clicked.connect(scroll_to_goto_target)
+ btn.setStyleSheet("background-color: #006464; color: white; font-weight: bold; text-align: left;")
+ self.tableWidget.setCellWidget(k, l, btn)
+ if text == "WFM" and int(fields[4].split("=")[1])==0:
+ # Not a TA pair
+ btn = QPushButton(self.tableWidget)
+ btn.setText(' WFM')
+ addr = int(fields[6].split("=")[1])
+ count = int(fields[5].split("=")[1])
+ def open_plotter(addr=None, I=self.waveforms[0][addr:addr+count], Q=self.waveforms[1][addr:addr+count]):
+ w = MatplotlibWidget(I,Q)
+ self.plotters.append(w)
+ btn.clicked.connect(open_plotter)
+ btn.setStyleSheet("background-color: #00C800; color: white; font-weight: bold; text-align: left;")
+ self.tableWidget.setCellWidget(k, l, btn)
+ else:
+ item = QTableWidgetItem(text)
+ item.setFont(table_font)
+ if color:
+ item.setBackground(color)
+ self.tableWidget.setItem(k, l, item)
+ if l < self.COLUMN_COUNT-1:
+ for j in range(l+1, self.COLUMN_COUNT):
+ item = QTableWidgetItem("")
+ if color:
+ item.setBackground(color)
+ self.tableWidget.setItem(k, j, item)
+
+ self.tableWidget.move(0,0)
+ self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
+
+def get_target_hardware(filename):
+ with open(filename, 'rb') as FID:
+ target_hw = FID.read(4).decode('utf-8')
+ return target_hw
+
+if __name__ == '__main__':
+ if len(sys.argv) == 2:
+ filename = sys.argv[1]
+ try:
+ hw = get_target_hardware(filename)
+ if hw == "APS2":
+ from QGL.drivers.APS2Pattern import read_instructions, read_waveforms
+ app = QApplication(sys.argv[:1])
+ ex = DisassemblerApp(read_instructions(sys.argv[1]), read_waveforms(sys.argv[1]))
+ sys.exit(app.exec_())
+ elif hw == "APS1":
+ print("APS1 disassmbler not yet implemented")
+ else:
+ raise Exception("Unknown hardware target.")
+ except:
+ print(f"The supplied file {filename} does not appear to be APS1 or APS2 format.")
+
+ else:
+ print("Expected single file (.aps1 or .aps2 format) as an argument.")
+
+
+
+