Commit 07ad50ed authored by Kelvin Loh's avatar Kelvin Loh 🖖
Browse files

Merge branch 'refactor/zhinst-settings-builder' into 'develop'

refactor(zhinst-backend): Compile backend with ZISettingsBuilder

Closes #106

See merge request !87
parents 02506b8c 04fc6339
Loading
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -71,10 +71,10 @@ timedomain_schedules
.. automodule:: quantify.scheduler.schedules.timedomain_schedules
    :members:

acquisition
~~~~~~~~~~~
timedomain_schedules
~~~~~~~~~~~~~~~~~~~~

.. automodule:: quantify.scheduler.schedules.acquisition
.. automodule:: quantify.scheduler.schedules.trace_schedules
    :members:

compilation
@@ -111,6 +111,9 @@ zhinst_backend
types
~~~~~

.. automodule:: quantify.scheduler.backends.types.common
    :members:

.. automodule:: quantify.scheduler.backends.types.qblox
    :members:

@@ -148,6 +151,9 @@ zhinst
.. automodule:: quantify.scheduler.backends.zhinst.seqc_il_generator
    :members:

.. automodule:: quantify.scheduler.backends.zhinst.settings
    :members:

helpers
-------

+4 −4
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ Tutorial 1. Basic experiments

The benefit of allowing the user to mix the high-level gate description of a circuit with the lower-level pulse description can be understood through an example.
Below we first give an example of basic usage using `Bell violations`.
We next show the `Chevron` experiment in which the user is required to mix gate-type and pulse-type information when defining the :class:`~quantify.scheduler.Schedule`.
We next show the `Chevron` experiment in which the user is required to mix gate-type and pulse-type information when defining the :class:`~quantify.scheduler.types.Schedule`.

Basics: The Bell experiment
---------------------------
@@ -55,7 +55,7 @@ Bell circuit
We create this experiment using :ref:`gates acting on qubits<Gate-level description>` .


We start by initializing an empty :class:`~quantify.scheduler.Schedule`
We start by initializing an empty :class:`~quantify.scheduler.types.Schedule`

.. jupyter-execute::

@@ -67,7 +67,7 @@ We start by initializing an empty :class:`~quantify.scheduler.Schedule`
    sched = Schedule('Bell experiment')
    sched

Under the hood, the :class:`~quantify.scheduler.Schedule` is based on a dictionary that can be serialized
Under the hood, the :class:`~quantify.scheduler.types.Schedule` is based on a dictionary that can be serialized

.. jupyter-execute::

@@ -117,7 +117,7 @@ And we can use this to create a default visualization:

Datastructure internals
~~~~~~~~~~~~~~~~~~~~~~~
Let's take a look at the internals of the :class:`~quantify.scheduler.Schedule`.
Let's take a look at the internals of the :class:`~quantify.scheduler.types.Schedule`.

.. jupyter-execute::

+8 −3
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ A Device describes the type of Zurich Instruments and the physical setup.
    :linenos:

    {
      "backend": "quantify.scheduler.backends.zhinst_backend.setup_zhinst_backend",
      "backend": "quantify.scheduler.backends.zhinst_backend.compile_backend",
      "devices": [
        
      ]
@@ -41,6 +41,11 @@ according to the :class:`~quantify.scheduler.backends.types.zhinst.Device` and
  :class:`~quantify.scheduler.backends.types.zhinst.Device`'s `name` must be equal to 
  the name given to the QCodes Instrument during instantiation. 

* The `type` property defines the instrument's model. The :enum:`~quantify.scheduler.backends.types.zhinst.DeviceType`
  is parsed from the string as well as the number of channels.
    
    * Example: "HDAWG8"

* The `ref` property describes if the instrument uses Markers (`int`), Triggers (`ext`) or `none`.

    * `int` Enables sending Marker
@@ -58,7 +63,7 @@ according to the :class:`~quantify.scheduler.backends.types.zhinst.Device` and
    :emphasize-lines: 5,17

    {
      "backend": "quantify.scheduler.backends.zhinst_backend.setup_zhinst_backend",
      "backend": "quantify.scheduler.backends.zhinst_backend.compile_backend",
      "devices": [
        {
          "name": "hdawg0",
@@ -114,7 +119,7 @@ according to the :class:`~quantify.scheduler.backends.types.zhinst.Device` and
    :linenos:

    {
      "backend": "quantify.scheduler.backends.zhinst_backend.setup_zhinst_backend",
      "backend": "quantify.scheduler.backends.zhinst_backend.compile_backend",
      "devices": [
        {
          "name": "hdawg0",
+36 −26
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ Tutorial 1. UHFQA Monitor
This tutorial describes how to use :mod:`quantify.scheduler` to generate pulses and acquire monitor data,
also visualized in the Quantum Analyzer Input tab of LabOne, using the UHFQA's AWG.

For this tutorial lets use :func:`~quantify.scheduler.schedules.acquisition.raw_trace_schedule` to create a
For this tutorial lets use :func:`~quantify.scheduler.schedules.trace_schedules.trace_schedule` to create a
pulse level Schedule. This utility function is used for debugging :class:`~quantify.scheduler.acquisition_library.Trace` 
acquisition with pulses of a large fixed duration.

@@ -18,18 +18,18 @@ Requirements
.. code-block:: python
    :linenos:

    from typing import Dict, Any, Callable
    from typing import Dict, Any
    import logging
    import json
    import numpy as np
    import matplotlib.pyplot as plt
    from pathlib import Path

    from qcodes.instrument.base import Instrument
    from zhinst.qcodes import UHFQA

    from quantify.scheduler.schedules.acquisition import raw_trace_schedule
    from quantify.scheduler.schedules.trace_schedules import trace_schedule
    from quantify.scheduler.compilation import qcompile
    import quantify.scheduler.backends.zhinst_backend as zhinst_backend

    # Debug only
    # logging.getLogger().setLevel(logging.DEBUG)
@@ -38,14 +38,18 @@ Requirements
    :linenos:

    # Create a schedule using the `Trace` acquisition protocol
    # The `raw_trace_schedule` is a Schedule defined on pulse-level.
    # The `trace_schedule` is a Schedule defined on pulse-level.
    # This schedule should only be used for testing UHFQA monitor output.
    schedule = raw_trace_schedule(
    schedule = trace_schedule(
        pulse_amp=1,
        pulse_duration=16e-9,
        pulse_delay=0,
        frequency=7.04e9,
        acquisition_delay=2e-9,
        integration_time=1e-6,
        port="q0:res", 
        clock="q0.ro", 
        integration_time=1e-6,
        spec_pulse_amp=1,
        frequency=7.04e9
        init_duration=1e-5,
    )
    schedule.repetitions = 1

@@ -54,14 +58,9 @@ Requirements
    :emphasize-lines: 24

    def load_example_json_scheme(filename: str) -> Dict[str, Any]:
        import quantify.scheduler.schemas.examples as es
        import os, inspect
        import json

        examples_path:str = inspect.getfile(es)
        config_file_path = os.path.abspath(os.path.join(examples_path, '..', filename))

        return json.loads(Path(config_file_path).read_text())
        import quantify.scheduler.schemas.examples as examples
        path = Path(examples.__file__).parent.joinpath(filename)
        return json.loads(path.read_text())
    
    # Load example configuration from quantify.scheduler.schemas.examples
    device_config_map = (load_example_json_scheme('transmon_test_config.json'))
@@ -71,10 +70,11 @@ Requirements
    zhinst_hardware_map: Dict[str, Any] = json.loads(
    """
    {
      "backend": "quantify.scheduler.backends.zhinst_backend.create_pulsar_backend",
      "backend": "quantify.scheduler.backends.zhinst_backend.compile_backend",
      "devices": [
        {
          "name": "uhfqa0",
          "type": "UHFQA", 
          "ref": "none",
          "channel_0": {
            "port": "q0:res",
@@ -92,8 +92,8 @@ Requirements
.. code-block:: python
    :linenos:

    # Compile schedule with configurations
    schedule = qcompile(schedule, device_config_map, zhinst_hardware_map)
    # Compile schedule for the backend configuration
    zi_backend = qcompile(schedule, device_config_map, zhinst_hardware_map)

.. code-block:: python
    :linenos:
@@ -106,8 +106,18 @@ Requirements
.. code-block:: python
    :linenos:
    
    # Run the backend setup
    acq_channel_resolvers_map = zhinst_backend.setup_zhinst_backend(schedule, zhinst_hardware_map)
    # Configure the Instruments
    for instrument_name, settings_builder in zi_backend.settings.items():
        instrument = Instrument.find_instrument(instrument_name)
        zi_settings = settings_builder.build(instrument)

        # Apply settings to the Instrument
        zi_settings.apply()

        # Optionally serialize the settings to file storage
        root = Path('.')
        zi_settings.serialize(root)


.. code-block:: python
    :linenos:
@@ -117,7 +127,7 @@ Requirements
    uhfqa.awg.wait_done()

    # Resolve the results by querying the UHFQA monitor nodes
    acq_channel_results: Dict[int, Callable[..., Any]] = dict()
    acq_channel_results = dict()
    for acq_channel, resolve in acq_channel_resolvers_map.items():
        acq_channel_results[acq_channel] = resolve()

+35 −26
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ Tutorial 2. UHFQA Result
This tutorial describes how to use quantify-schedule to generate pulses and acquire result data,
also visualized in the Quantum Analyzer Result tab of LabOne, using the UHFQA's AWG.

For this tutorial lets use :func:`~quantify.scheduler.schedules.acquisition.ssb_integration_complex_schedule` to create a
For this tutorial lets use :func:`~quantify.scheduler.schedules.spectroscopy_schedules.heterodyne_spec_sched` to create a
pulse level Schedule. This utility function is used for debugging :class:`~quantify.scheduler.acquisition_library.SSBIntegrationComplex`
acquisition with pulses of a large fixed duration.

@@ -25,11 +25,11 @@ Requirements
    import matplotlib.pyplot as plt
    from pathlib import Path

    from qcodes.instrument.base import Instrument
    from zhinst.qcodes import UHFQA

    from quantify.scheduler.schedules.acquisition import ssb_integration_complex_schedule
    from quantify.scheduler.schedules.spectroscopy_schedules import heterodyne_spec_sched
    from quantify.scheduler.compilation import qcompile
    import quantify.scheduler.backends.zhinst_backend as zhinst_backend

    # Debug only
    # logging.getLogger().setLevel(logging.DEBUG)
@@ -38,14 +38,16 @@ Requirements
    :linenos:

    # Create a schedule using the `SSBIntegrationComplex` acquisition protocol
    # The `ssb_integration_complex_schedule` is a Schedule defined on pulse-level.
    # This schedule should only be used for testing UHFQA output.
    schedule = ssb_integration_complex_schedule(
    # The `heterodyne_spec_sched` is a Schedule defined on pulse-level.
    schedule = heterodyne_spec_sched(
        pulse_amp=1,
        pulse_duration=16e-9,
        frequency=7.04e9,
        acquisition_delay=0,
        integration_time=1e-6, 
        port="q0:res", 
        clock="q0.ro", 
        integration_time=1e-6,
        spec_pulse_amp=1,
        frequency=7.04e9
        buffer_time=1e-5, 
    )
    schedule.repetitions = 1

@@ -54,14 +56,9 @@ Requirements
    :emphasize-lines: 24

    def load_example_json_scheme(filename: str) -> Dict[str, Any]:
        import quantify.scheduler.schemas.examples as es
        import os, inspect
        import json

        examples_path:str = inspect.getfile(es)
        config_file_path = os.path.abspath(os.path.join(examples_path, '..', filename))

        return json.loads(Path(config_file_path).read_text())
        import quantify.scheduler.schemas.examples as examples
        path = Path(examples.__file__).parent.joinpath(filename)
        return json.loads(path.read_text())
    
    # Load example configuration from quantify.scheduler.schemas.examples
    device_config_map = (load_example_json_scheme('transmon_test_config.json'))
@@ -71,10 +68,11 @@ Requirements
    zhinst_hardware_map: Dict[str, Any] = json.loads(
    """
    {
      "backend": "quantify.scheduler.backends.zhinst_backend.create_pulsar_backend",
      "backend": "quantify.scheduler.backends.zhinst_backend.compile_backend",
      "devices": [
        {
          "name": "uhfqa0",
          "type": "UHFQA", 
          "ref": "none",
          "channel_0": {
            "port": "q0:res",
@@ -93,7 +91,7 @@ Requirements
    :linenos:

    # Compile schedule with configurations
    schedule = qcompile(schedule, device_config_map, zhinst_hardware_map)
    zi_backend = qcompile(schedule, device_config_map, zhinst_hardware_map)

.. code-block:: python
    :linenos:
@@ -107,21 +105,32 @@ Requirements
    :linenos:

    # Run the backend setup
    acq_channel_resolvers_map = zhinst_backend.setup_zhinst_backend(schedule, zhinst_hardware_map)
    # Configure the Instruments
    for instrument_name, settings_builder in zi_backend.settings.items():
        instrument = Instrument.find_instrument(instrument_name)
        zi_settings = settings_builder.build(instrument)

        # Apply settings to the Instrument
        zi_settings.apply()

        # Optionally serialize the settings to file storage
        root = Path('.')
        zi_settings.serialize(root)

.. code-block:: python
    :linenos:

    # Arm the UHFQA Quantum Analyzer Results unit
    uhfqa.arm(length=schedule.repetitions, averages=1)
    n_acquisitions = 1
    uhfqa.arm(length=n_acquisitions, averages=1)

    # Run the UHFQA AWG
    uhfqa.awg.run()
    uhfqa.awg.wait_done()

    # Resolve the results by querying the UHFQA monitor nodes
    acq_channel_results: Dict[int, Callable[..., Any]] = dict()
    for acq_channel, resolve in acq_channel_resolvers_map.items():
    acq_channel_results: Dict[int, Callable] = dict()
    for acq_channel, resolve in zi_backend.acquisition_resolvers.items():
        acq_channel_results[acq_channel] = resolve()

.. code-block:: python
Loading