diff --git a/src/qibocal/protocols/couplers/coupler_chevron.py b/src/qibocal/protocols/couplers/coupler_chevron.py index 2a5195dd2..dc69a71a9 100644 --- a/src/qibocal/protocols/couplers/coupler_chevron.py +++ b/src/qibocal/protocols/couplers/coupler_chevron.py @@ -1,10 +1,7 @@ -from dataclasses import dataclass -from typing import Optional - import numpy as np from qibolab import AcquisitionType, AveragingMode, ExecutionParameters from qibolab.platform import Platform -from qibolab.pulses import PulseSequence +from qibolab.pulses import PulseSequence, PulseType from qibolab.qubits import QubitPairId from qibolab.sweeper import Parameter, Sweeper, SweeperType @@ -18,25 +15,8 @@ from ..two_qubit_interaction.utils import order_pair -@dataclass -class ChevronCouplersParameters(ChevronParameters): - - native_gate: Optional[str] = "CZ" - """Native gate to implement, CZ or iSWAP.""" - - """ChevronCouplers protocol parameters. - - Amplitude and duration are referred to the coupler pulse. - """ - - -@dataclass -class ChevronCouplersData(ChevronData): - """Data structure for chevron couplers protocol.""" - - -def _aquisition( - params: ChevronCouplersParameters, +def _acquisition( + params: ChevronParameters, platform: Platform, targets: list[QubitPairId], ) -> ChevronData: @@ -50,7 +30,7 @@ def _aquisition( targets (list): List of pairs to use sequentially. Returns: - ChevronCouplersData: Acquisition data. + ChevronData: Acquisition data. """ # define the parameter to sweep and its range: delta_amplitude_range = np.arange( @@ -62,16 +42,14 @@ def _aquisition( params.duration_min, params.duration_max, params.duration_step ) - # create a DataUnits object to store the results, data = ChevronData() - # sort high and low frequency qubit for pair in targets: sequence = PulseSequence() ordered_pair = order_pair(pair, platform) - # initialize in system in 11(CZ) or 10(iSWAP) state - if params.native_gate == "CZ": + # initialize system to state 11(CZ) or 10(iSWAP) + if params.native == "CZ": initialize_lowfreq = platform.create_RX_pulse(ordered_pair[0], start=0) sequence.add(initialize_lowfreq) @@ -79,12 +57,12 @@ def _aquisition( sequence.add(initialize_highfreq) - if params.native_gate == "CZ": + if params.native == "CZ": native_gate, _ = platform.create_CZ_pulse_sequence( (ordered_pair[1], ordered_pair[0]), start=sequence.finish + params.dt, ) - elif params.native_gate == "iSWAP": + elif params.native == "iSWAP": native_gate, _ = platform.create_iSWAP_pulse_sequence( (ordered_pair[1], ordered_pair[0]), start=sequence.finish + params.dt, @@ -103,56 +81,61 @@ def _aquisition( sequence += ro_pulse1 + ro_pulse2 + coupler_flux_pulses = [p for p in native_gate.coupler_pulses(*pair)] + assert ( + len(coupler_flux_pulses) == 1 + ), f"coupler_chevron expects exactly one coupler flux pulse, but {len(coupler_flux_pulses)} are present." + qubit_flux_pulses = [ + p for p in native_gate.get_qubit_pulses(*pair) if p.type is PulseType.FLUX + ] + assert all( + len(list(filter(lambda x: x.qubit == q, qubit_flux_pulses))) < 2 + for q in pair + ), f"coupler_chevron expects no more than 1 flux pulse for each qubit, but more are present for the pair {pair}" sweeper_amplitude = Sweeper( Parameter.amplitude, delta_amplitude_range, - pulses=[p for p in native_gate.coupler_pulses(*pair)][:1], + pulses=coupler_flux_pulses, type=SweeperType.FACTOR, ) sweeper_duration = Sweeper( Parameter.duration, delta_duration_range, - pulses=[p for p in native_gate.coupler_pulses(*pair)], + pulses=coupler_flux_pulses + qubit_flux_pulses, ) - # repeat the experiment as many times as defined by nshots results = platform.sweep( sequence, ExecutionParameters( nshots=params.nshots, - acquisition_type=AcquisitionType.INTEGRATION, + acquisition_type=AcquisitionType.DISCRIMINATION, averaging_mode=AveragingMode.CYCLIC, ), sweeper_duration, sweeper_amplitude, ) - # TODO: Explore probabilities instead of magnitude data.register_qubit( ordered_pair[0], ordered_pair[1], delta_duration_range, delta_amplitude_range * data.native_amplitude[ordered_pair], - results[ordered_pair[0]].magnitude, - results[ordered_pair[1]].magnitude, + results[ordered_pair[0]].probability(state=1), + results[ordered_pair[1]].probability(state=1), ) + data.label = "Probability of state |1>" return data -@dataclass -class ChevronCouplersResults(Results): - """Empty fitting outputs for chevron couplers is not implemented in this case.""" - - -def _fit(data: ChevronCouplersData) -> ChevronCouplersResults: - """ "Results for ChevronCouplers.""" - return ChevronCouplersResults() +def _fit(data: ChevronData) -> Results: + """Results for ChevronCouplers.""" + return Results() -def plot(data: ChevronCouplersData, fit: ChevronCouplersResults, target): +def plot(data: ChevronData, fit: Results, target): return _plot(data, None, target) -coupler_chevron = Routine(_aquisition, _fit, plot, two_qubit_gates=True) +coupler_chevron = Routine(_acquisition, _fit, plot, two_qubit_gates=True) """Coupler cz/swap flux routine.""" diff --git a/src/qibocal/protocols/two_qubit_interaction/chevron/chevron.py b/src/qibocal/protocols/two_qubit_interaction/chevron/chevron.py index c65ce9aeb..d11714e81 100644 --- a/src/qibocal/protocols/two_qubit_interaction/chevron/chevron.py +++ b/src/qibocal/protocols/two_qubit_interaction/chevron/chevron.py @@ -109,6 +109,9 @@ class ChevronData(Data): """Sweetspot value for high frequency qubit.""" data: dict[QubitPairId, npt.NDArray[ChevronType]] = field(default_factory=dict) + label: Optional[str] = None + """Label for the data.""" + def register_qubit(self, low_qubit, high_qubit, length, amp, prob_low, prob_high): """Store output for single qubit.""" size = len(length) * len(amp) @@ -308,7 +311,7 @@ def _plot(data: ChevronData, fit: ChevronResults, target: QubitPairId): fig.update_layout( xaxis_title="Duration [ns]", xaxis2_title="Duration [ns]", - yaxis_title="Amplitude [a.u.]", + yaxis_title=data.label or "Amplitude [a.u.]", legend=dict(orientation="h"), ) fig.update_layout( diff --git a/tests/runcards/protocols_couplers.yml b/tests/runcards/protocols_couplers.yml index 0c8dd1644..78a31ae02 100644 --- a/tests/runcards/protocols_couplers.yml +++ b/tests/runcards/protocols_couplers.yml @@ -66,7 +66,7 @@ actions: duration_min: 50 duration_max: 100 duration_step: 10 - native_gate: "CZ" + native: "CZ" dt: 5 nshots: 10 @@ -81,6 +81,6 @@ actions: duration_min: 50 duration_max: 100 duration_step: 10 - native_gate: "iSWAP" + native: "iSWAP" dt: 5 nshots: 10