Writing a new analysis
All experiments in the QruiseOS Experiment catalogue come with a pre-defined analysis class. However, if you want to use a different type of analysis or write your own experiment, you'll need to write your own analysis class. This guide shows you how to do this step by step.
Writing your analysis class¶
Your new analysis class will look something like the codeblock below. Don't worry if it looks a bit overwhelming — we'll explain it in more detail in the following sections.
# imports
import xarray as xr
from qruise.experiment.analysis.base import AnalysisBase
from qruise.kb.plot import DatasetPlotOptionsBuilder
# analysis name
class QubitSpectroscopyAnalysis(AnalysisBase):
def __init__(
# initialisation function
self,
experiment_data: xr.Dataset,
title: str,
) -> None:
super().__init__(experiment_data, title)
self.plot_opts = DatasetPlotOptionsBuilder("flux")
output = self.analyse(self.data)
self.record(output)
self.explicit_plotting()
self.data.attrs["plot_opts"] = self.plot_opts.build()
def analyse(self, data):
# define your analysis method
output = get_peak(data)
return output
def record(self, output):
# choose what to record (store)
self.freq = output.estimated_qubit_frequency
def explicit_plotting(self):
# set up plot
self.plot_opts.add_points(
x="qubit_drive_frequency",
y="amplitude",
xlabel="drive",
ylabel="amplitude (a.u.)",
)
self.plot_opts.add_vline(
x=self.freq,
color="green",
)
def print_summary(self):
# print summary of results
return super().print_summary()
Name your analysis¶
Excluding imports, the first thing you need to do is name your analysis; here, QubitSpectroscopyAnalysis. This inherits from the AnalysisBase class, which supplies the base methods and structure for all analyses in QruiseOS.
Define the initialisation method¶
The __init__ method ties together the functions that make up the analysis: processing the data, storing the results, and visualising the output. It calls these functions in the right order so the analysis runs smoothly from start to finish. This will be much easier to follow once we've seen what these other functions do, so we'll come back to the __init__ method later.
Define analysis method¶
This is the key step, where you define the analysis method you want to use. In this example, we're using a helper function, get_peak (defined elsewhere), that locates the peak in your spectroscopy data and returns the results.
Define what to record¶
Your analysis might output multiple values, but you may not want to record them all. For example, get_peak could return the peak frequency, amplitude, and linewidth, but you're only interested in the frequency. Here, we're using record to extract the estimated_qubit_frequency from the analysis results and save it for later use.
Define plotting¶
Once you've performed your analysis and defined which results to record, you'll probably want to visualise them. Here, we've defined a function explicit_plotting that contains all the instructions for plotting. add_points plots the data and defines the axes, while add_vline adds a vertical line at your extracted frequency (x=self.freq).
def explicit_plotting(self):
# set up plot
self.plot_opts.add_points(
x="qubit_drive_frequency",
y="amplitude",
xlabel="drive",
ylabel="amplitude (a.u.)",
)
self.plot_opts.add_vline(
x=self.freq,
color="green",
)
Here, plot_opts is an instance of DatasetPlotOptionsBuilder, which is created in the __init__ method and allows you to specify what to plot and how it should appear in the dashboard. The argument ("flux") specifies which variable in your dataset will be used for the x-axis.
Print results¶
You can also print a summary of your results. To do this, you can simply call the print_summary method from the AnalysisBase parent class using super().
Tying it all together with __init__¶
Okay, now we've explained the different functions, we can tie them together with __init__. This method runs when you create an instance of your analysis and calls the other functions in the correct order so the full analysis runs from start to finish.
def __init__(
self,
experiment_data: xr.Dataset,
title: str,
) -> None:
super().__init__(experiment_data, title) # 1
self.plot_opts = DatasetPlotOptionsBuilder("flux") # 2
output = self.analyse(self.data) # 3
self.record(output) # 4
self.explicit_plotting() # 5
self.data.attrs["plot_opts"] = self.plot_opts.build() # 6
Here’s what happens step by step:
-
The parent class (
AnalysisBase) is initialised with your data and title:super().__init__(experiment_data, title). -
The
plot_optsobject is created for setting up the plot:self.plot_opts = DatasetPlotOptionsBuilder("flux"). This defines"flux"as the sweep variable for the plot’s x-axis. -
The data is analysed using your chosen method:
output = self.analyse(self.data). -
The key results are recorded:
self.record(output). -
The plot is defined:
self.explicit_plotting(). -
Finally, the plot configuration is attached to the dataset so it can be displayed in the dashboard:
self.data.attrs["plot_opts"] = self.plot_opts.build().
Using your analysis class¶
Now that our analysis class is ready, we can try running it on some data. To do this, create an instance of your analysis with your dataset as experiment_data, along with a descriptive title. This triggers __init__.
# run analysis with data
analysis = QubitSpectroscopyAnalysis(
experiment_data=data,
title=f"Qubit spectroscopy vs. flux - {QUBIT_NAME}",
)
You can then plot the results and print a summary.