Source code for qibocal.protocols.flux_dependence.qubit_flux_tracking

from dataclasses import dataclass

import numpy as np
from qibolab import AcquisitionType, AveragingMode, ExecutionParameters
from qibolab.platform import Platform
from qibolab.pulses import PulseSequence
from qibolab.qubits import QubitId
from qibolab.sweeper import Parameter, Sweeper, SweeperType

from qibocal.auto.operation import Routine
from qibocal.config import raise_error

from ..qubit_spectroscopy_ef import DEFAULT_ANHARMONICITY
from . import qubit_flux_dependence, utils


[docs]@dataclass class QubitFluxTrackParameters(qubit_flux_dependence.QubitFluxParameters): """QubitFluxTrack runcard inputs."""
[docs]@dataclass class QubitFluxTrackResults(qubit_flux_dependence.QubitFluxParameters): """QubitFluxTrack outputs."""
[docs]@dataclass class QubitFluxTrackData(qubit_flux_dependence.QubitFluxData): """QubitFluxTrack acquisition outputs."""
[docs] def register_qubit_track(self, qubit, freq, bias, signal, phase): """Store output for single qubit.""" # to be able to handle the 1D sweeper case size = len(freq) ar = np.empty(size, dtype=qubit_flux_dependence.QubitFluxType) ar["freq"] = freq ar["bias"] = [bias] * size ar["signal"] = signal ar["phase"] = phase if qubit in self.data: self.data[qubit] = np.rec.array(np.concatenate((self.data[qubit], ar))) else: self.data[qubit] = np.rec.array(ar)
[docs]def _acquisition( params: QubitFluxTrackResults, platform: Platform, targets: list[QubitId], ) -> QubitFluxTrackData: """Data acquisition for QubitFlux Experiment.""" # create a sequence of pulses for the experiment: # MZ # taking advantage of multiplexing, apply the same set of gates to all qubits in parallel sequence = PulseSequence() ro_pulses = {} qd_pulses = {} qubit_frequency = {} for qubit in targets: qd_pulses[qubit] = platform.create_qubit_drive_pulse( qubit, start=0, duration=params.drive_duration ) qubit_frequency[qubit] = platform.qubits[qubit].drive_frequency if params.transition == "02": if platform.qubits[qubit].anharmonicity != 0: qd_pulses[qubit].frequency -= platform.qubits[qubit].anharmonicity / 2 else: qd_pulses[qubit].frequency -= DEFAULT_ANHARMONICITY / 2 if params.drive_amplitude is not None: qd_pulses[qubit].amplitude = params.drive_amplitude ro_pulses[qubit] = platform.create_qubit_readout_pulse( qubit, start=qd_pulses[qubit].finish ) sequence.add(qd_pulses[qubit]) sequence.add(ro_pulses[qubit]) # define the parameters to sweep and their range: delta_frequency_range = np.arange( -params.freq_width / 2, params.freq_width / 2, params.freq_step ) delta_bias_range = np.arange( -params.bias_width / 2, params.bias_width / 2, params.bias_step ) freq_sweeper = Sweeper( Parameter.frequency, delta_frequency_range, pulses=[qd_pulses[qubit] for qubit in targets], type=SweeperType.OFFSET, ) data = QubitFluxTrackData( resonator_type=platform.resonator_type, qubit_frequency=qubit_frequency, charging_energy={ qubit: -platform.qubits[qubit].anharmonicity for qubit in targets }, ) for bias in delta_bias_range: for qubit in targets: try: freq_resonator = utils.transmon_readout_frequency( xi=bias, xj=0, w_max=platform.qubits[qubit].drive_frequency, d=0, normalization=platform.qubits[qubit].normalization, crosstalk_element=1, offset=-platform.qubits[qubit].sweetspot * platform.qubits[qubit].normalization, resonator_freq=platform.qubits[qubit].bare_resonator_frequency, g=platform.qubits[qubit].coupling, charging_energy=data.charging_energy[qubit], ) # modify qubit resonator frequency platform.qubits[qubit].readout_frequency = freq_resonator except: raise_error ( RuntimeError, "qubit_flux_track: Not enough parameters to estimate the resonator freq for the given bias. Please run resonator spectroscopy flux and update the runcard", ) # modify qubit flux platform.qubits[qubit].flux.offset = bias # execute pulse sequence sweeping only qubit resonator results = platform.sweep( sequence, ExecutionParameters( nshots=params.nshots, relaxation_time=params.relaxation_time, acquisition_type=AcquisitionType.INTEGRATION, averaging_mode=AveragingMode.CYCLIC, ), freq_sweeper, ) # retrieve the results for every qubit for qubit in targets: result = results[ro_pulses[qubit].serial] data.register_qubit_track( qubit, signal=result.magnitude, phase=result.phase, freq=delta_frequency_range + qd_pulses[qubit].frequency, bias=bias + platform.qubits[qubit].sweetspot, ) return data
qubit_flux_tracking = Routine( _acquisition, qubit_flux_dependence._fit, qubit_flux_dependence._plot, qubit_flux_dependence._update, ) """QubitFluxTrack Routine object."""