tergite-autocalibration

Node classes

The execution of most of the nodes consists of a single schedule compilation, a single measurement and a single post-processing. Although for most of the nodes this workflow suffices, there are exceptions while this workflow can become limiting in more advanced implementations.

To allow greater flexibility in the node implementations the nodes are categorized:

Below, there is an example for an ExternalParameterNode implementation.

import numpy as np

from tergite_autocalibration.lib.nodes.coupler.spectroscopy.analysis import (
    CouplerSpectroscopyNodeAnalysis,
)

from tergite_autocalibration.lib.nodes.external_parameter_node import (
    ExternalParameterNode,
)

from tergite_autocalibration.lib.nodes.qubit_control.spectroscopy.measurement import (
    TwoTonesMultidimMeasurement,
)

from tergite_autocalibration.lib.utils.samplespace import qubit_samples
from tergite_autocalibration.utils.dto.enums import MeasurementMode
from tergite_autocalibration.utils.hardware.spi import SpiDAC


class CouplerSpectroscopyNode(ExternalParameterNode):
    measurement_obj = TwoTonesMultidimMeasurement
    analysis_obj = CouplerSpectroscopyNodeAnalysis
    coupler_qois = ["parking_current", "current_range"]

    def __init__(
            self, name: str, all_qubits: list[str], couplers: list[str], **schedule_keywords
    ):
        super().__init__(name, all_qubits, **schedule_keywords)
        self.name = name
        self.couplers = couplers
        self.qubit_state = 0
        self.schedule_keywords["qubit_state"] = self.qubit_state
        self.coupled_qubits = self.get_coupled_qubits()
        self.coupler = self.couplers[0]

        self.mode = MeasurementMode.real
        self.spi_dac = SpiDAC(self.mode)
        self.dac = self.spi_dac.create_spi_dac(self.coupler)

        self.all_qubits = self.coupled_qubits

        self.schedule_samplespace = {
            "spec_frequencies": {
                qubit: qubit_samples(qubit) for qubit in self.all_qubits
            }
        }

        self.external_samplespace = {
            "dc_currents": {self.coupler: np.arange(-2.5e-3, 2.5e-4, 280e-6)},
        }

    def get_coupled_qubits(self) -> list:
        if len(self.couplers) > 1:
            print("Multiple couplers, lets work with only one")
        coupled_qubits = self.couplers[0].split(sep="_")
        self.coupler = self.couplers[0]
        return coupled_qubits

    def pre_measurement_operation(self, reduced_ext_space):
        iteration_dict = reduced_ext_space["dc_currents"]
        this_iteration_value = list(iteration_dict.values())[0]
        print(f"{ this_iteration_value = }")
        self.spi_dac.set_dac_current(self.dac, this_iteration_value)

    def final_operation(self):
        print("Final Operation")
        self.spi_dac.set_dac_current(self.dac, 0)

Please read the guide about how to create a new node to learn more about nodes. This guide also contains an example for a ScheduleNode.

Examples of nodes requiring an external samplespace