Creating interface to the instruments and quantum device

Hi!

We are evaluating what OQS Juice could do for our labs. One critical element for our setups is how multi users with interact with a single physical set of instruments with a quantum device.

From the architecture page (Architecture — OrangeQS Juice documentation) I gather this is to be done via a Quantum Device Manager that is itself a Task. Is that correct?

Is there any documentation on the Quantum Device Manger? Or even better: an example of how to create a device manger for a set of QCoDeS instruments?

Kind regards,

Pieter Eendebak

1 Like

Hi Pieter,

Thanks for checking out the OQS Juice OS. The Quantum Device Manager shown in the figure is a Service which spawns Tasks within itself ( Architecture — OrangeQS Juice documentation ). The service by itself is an empty jupyterlab IPython kernel, so, it would run the same way with python scripts/console commands as how you would instantiate a set of QCoDeS instruments. As for an example on how to create a Service within OQS Juice, one of which is for the System Monitor service (System Monitor — OrangeQS Juice documentation).

Hope that helps and let us know if you got further questions.

Kind regards,

Kelvin

Hi Kelvin,

What I am looking for is instructions how to setup juice OS for a set of real instruments and perform measurements with these instruments.

In the documentation I have not found examples, or a structure for this. For example:

  • How to specify which instruments to connect to (driver, IP address, COM port, etc.)
  • What an interface could look like from the user side (since this is multi-user, there needs to be some way to interface and schedule measurement tasks).

I could not find the Quantum Device Manager in the codebase, Do you have some more information on this? In particular: if the QDM starts an empty ipython kernel where a user can connect to the instruments using QCoDeS, how will a second user be able to connect to the same set of instruments?

With kind regards,

Pieter Eendebak

Hi Pieter,

I will send over a quick-er start guide (likely later tomorrow) especially for this use-case as it is obviously representative for the typical applications we expect from JuiceOS users.

As for the connectivity, as long as the hostOS (e.g. AlmaLinux) can ping/connect to the instruments, then it is simply configuring the orchestration.toml file within `/etc/juice/config` to forward the correct ports (only necessary for serial devices) to the respective service (which I will cover in the document, or in more detail: orchestration.toml: Orchestration Settings — OrangeQS Juice documentation).

The default Services that are out-of-the-box configured in a barebones installation are the Task Manager, System Monitor, and influxdb database service. The Quantum Device Manager is an example Service for which you can create yourself (First steps after installation — OrangeQS Juice documentation) using the example of the System Monitor (which always come preconfigured). Naturally, we always set it all up for our FLEX line products, the same way as shown in the system architecture diagram.

All user kernels serve as proxy kernels when connecting to a Service kernel (Accessing services — OrangeQS Juice documentation). This allows then multiple user proxy kernels to interact with the Service kernel (also note the “Connecting to a busy kernel” section for the case of the second user to connect to the same set of instruments (because only the Service kernel is connected to the instrument). If you want to schedule tasks/measurements to run on these services, then sending Tasks from the personal kernels to the Services is the easiest way, allowing you to run your own measurement code on the service (See Tasks — OrangeQS Juice documentation)

Hope this helps for now and until tomorrow.

Kind regards,

Kelvin

Quicker user guide

Introduction

This is a very condensed user guide meant to provide a quick start for you to create a Quantum Device Manager “device” service within the Juice OS.

It should create the blank “device” service first. After that, you will be introduced to an example of creating a lab initialization script to be run automatically whenever the service starts. Then it moves on to modifying the default orchestration.toml file to set up the database bucket for this service and configuring the device service to run the initialization script.

Housekeeping

These sequential set of instructions assume you have root access to the AlmaLinux distro, and have a basic linux admin ability (i.e. file copy and creation, terminal navigation).

The guide itself

  1. Follow all the instructions for installation here ( Installation — OrangeQS Juice documentation )

  2. Verify that you are able to connect to the default juice environment by navigating with a browser to “localhost:8888”. You should see a login page as shown below:

2a. Enter the login details for your AlmaLinux account.

2b. Once logged in, you should be seeing a similar starting page:

2c. Enter the Jupyterlab environment

2d. Edit the default pyproject.toml file within the shared/lib/lab/ directory as shown below to reflect the contents also shown within the image which installs the qcodes, quantify, pyvisa-py and pyserial dependencies on top of the orangeqs-juice-core packages. Save the changes.

2e. After that, create an init_device_service.py file within the shared/lib/lab/src/lab directory with the following content:

from __future__ import annotations

# ---------------
# basic imports
# ---------------
import time

# for benchmarking purposes
t0 = time.time()

import os
import sys
from pathlib import Path
from importlib import reload
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display, SVG
import warnings
from typing import Optional, Any, Tuple
from qcodes import validators
from qcodes.instrument.base import Instrument
from qcodes.instrument.parameter import ManualParameter

warnings.filterwarnings("ignore")

t1 = time.time()
print(f"Finished basic imports {t1-t0:.2f} s")

class DummyFluxCurrent(Instrument):
    """A Dummy QCoDeS instrument for a current source."""

    def __init__(self, name: str, channel_list: list[str]):
        super().__init__(name)

        for channel in channel_list:
            self.add_parameter(
                channel,
                unit="A",
                initial_value=0,
                vals=validators.Numbers(),
                parameter_class=ManualParameter,
            )


class DummyVNA(Instrument):
    """A dummy VNA driver"""

    def __init__(self, name: str):
        super().__init__(name)

        self.MAX_NPTS = 1001


# -------------------------------------------------------------------------------------------------
# Connect VNA
# -------------------------------------------------------------------------------------------------
try:
    vna = DummyVNA(
        name="vna",
    )
    print("Connected to VNA")
except Exception as e:
    print("Something went wrong connecting to the vna:", e)

# -------------------------------------------------------------------------------------------------
# Connect FLUX
# -------------------------------------------------------------------------------------------------
try:
    flux = DummyFluxCurrent(
        name="flux",
        channel_list=["output_1", "output_2", "output_3"]
    )
    print("Connected to current source")
except Exception as e:
    print("Something went wrong connecting to the current source:", e)

t3 = time.time()
print(f"\nFinished loading settings {t3-t0:.2f} s")

This file will be used later in the construction of the orchestration.toml file.

  1. Open the AlmaLinux terminal. Turn on root access by sudo -i and enter the credentials.

4a. Edit the default /etc/juice/config/orchestration.toml file to duplicate these entries:

# Add the lab extension to the default environment.
# This environment will be used by all services and singleuser containers unless overridden.
# See below for some examples.
[environments.default]
type = "uv"
dependencies = ["lab"]
sources = { lab = { editable = true, path = "~/shared/lib/lab" }}

# This entry creates a device service kernel
[services.device]
entrypoint = "orangeqs.juice.service:IPythonService"

# This entry tells the device service to run a python script called init_device_service.py within the shared/lab repo.
[services.device.init_kwargs]
init_module = "lab.init_device_service"

# This entry creates a service-device data bucket within the influxdb2 database service
[influxdb2.buckets.service-device]
name = "service-device"

## This entry sets any necessary environments for the device service container (e.g.) device port forwarding or volume mounts from hostOS to the service container.

[environments.device.envinronment]
type = "uv"
dependencies = ["lab"]
sources = { lab = { editable = true, path = "~/shared/lib/lab" }}

[services.device.environment.container]
volumes = [
        "/etc/machine-id:/etc/machine-id:ro"
]
# Forward the device /dev/tty1 from AlmaLinux to the device service container device /dev/custom_6
devices = ["/dev/tty1:/dev/custom_6"]
group_add = ["dialout"]

The comments within the file should help explain the reasons why they’re there, especially about the device forwarding from AlmaLinux to the service container.

4b. As for the instruments to connect to, as long as the host OS (AlmaLinux) can ping to the device (this is assuming an ethernet connection with the instrument), then any service spawned will be able to connect to it.

  1. After you’re done editing, run juice install --rebuild --restart --no-parallel-build. You should be able to see the output from the terminal after it has finished rebuilding and restarted.

  2. Go to a web browser and navigate back to localhost:8888 to spawn the Jupyterlab environment. You should now be able to see an extra Service: device button within the Notebook and Console. These will spawn proxy kernels to send instructions directly to the device service kernel. For example, open up the Console for the device service.

  3. You should be taken to a familiar ipython console which is behind the scenes has a proxy kernel which communicates with the device service. The user experience however does not change from your point of view. A simple dir() should tell you what objects are available in the device service kernel. If the init script was executed properly, you should be able to see the vna and flux qcodes instruments and are also able to print their respective snapshots from this same console as shown here:


  4. And to further check that COM devices are forwarded correctly, do an !ls /dev/ within the same console. In the example orchestration.toml we deliberately forwarded the /dev/tty1 instrument from AlmaLinux to /dev/custom_6 instrument in the device service container. You should verify that the output is as shown below:

You now have a very basic Quantum Device Manager “device” service running within your JuiceOS installation.