{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "aa11bb22",
   "metadata": {},
   "source": [
    "# How to run an automated routine with Boulder Opal\n",
    "\n",
    "**Execute autonomous Routines to automatically characterize or calibrate a component(s) on your quantum hardware**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa11body",
   "metadata": {},
   "source": [
    "A routine runs a set of experiments to accomplish a specific characterization or calibration goal, while extracting the relevant parameters to the virtual device. The available routines cover discovering and characterizing all system components (resonators, qubits, and couplers) and calibrating their respective gate operations (readout, 1Q, 2Q).\n",
    "\n",
    "Running a routine requires a virtual device with some prerequisite data. If you do not have virtual device, complete the [get started tutorial](https://docs.q-ctrl.com/boulder-opal/autocalibration/get-started-with-boulder-opal-autocalibration) first. The relevant prerequisite data depends on the routine you intend to run. See the chart below for specifics."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb22cc33",
   "metadata": {},
   "source": [
    "## 1. Set the device context\n",
    "\n",
    "Select the target device. All experiments run against the currently active device."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cc33dd44",
   "metadata": {},
   "outputs": [],
   "source": [
    "await client.set_current_device(\"<your-device-name>\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd44ee55",
   "metadata": {},
   "source": [
    "## 2. Available routines\n",
    "\n",
    "Seven routines are available. Each one runs a set of interdependent experiments and writes the resulting parameters to the device data, so later routines and experiments act on up-to-date values.\n",
    "\n",
    "| Routine               | Target component | Purpose                                                                | Inputs                                                | Parameter outputs                                        |\n",
    "| --------------------- | ---------------- | ---------------------------------------------------------------------- | ----------------------------------------------------- | -------------------------------------------------------- |\n",
    "| `ResonatorMapping`    | Feedline         | Characterize readout resonators and pair them to respective transmons. | `feedlines`, `run_mixer_calibration`                  | Readout resonator frequencies, resonator-to-transmon map |\n",
    "| `TransmonDiscovery`   | Qubit            | Locate transmon frequencies and drive parameters.                      | `transmon`, `spectroscopy_waveform`                   | Qubit frequency, anharmonicity, drive amplitude         |\n",
    "| `OneQubitCalibration` | Qubit            | Calibrate single-qubit gates (π and π/2 pulses).                       | `transmon`, `gate` (`\"x\"` or `\"sx\"`), `force_rerun`   | Gate amplitude, gate duration, DRAG coefficient         |\n",
    "| `TransmonCoherence`   | Qubit            | Measure T1, T2, and T2 echo coherence times.                           | `transmon`, `run_mixer_calibration`                   | T1, T2, T2 echo                                          |\n",
    "| `TransmonRetuning`    | Qubit            | Re-tune transmon frequencies compensating for drift.                   | `transmon`, `spectroscopy_waveform`                   | Updated qubit frequency                                  |\n",
    "| `CouplerDiscovery`    | Qubit pair       | Characterize coupler interactions between transmons.                   | `control_transmon`, `target_transmon`, `biases`       | Coupling strength, coupler bias point                    |\n",
    "| `CZCalibrationFixedCoupler` | Qubit pair       | Calibrate CZ gate operating point for fixed-coupler architectures.     | `transmons`, `flux_vp_bounds` (optional), `coupling_rate`, `force_rerun` | Flux pulse operating point, CZ phase/leakage calibration parameters |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee55ff66",
   "metadata": {},
   "source": [
    "## 3. Configure and run a routine\n",
    "\n",
    "Import the routine class from `boulderopalscaleup.routines`, instantiate it with the parameters from the table above, and submit it with `run_routine()`. The call is asynchronous and returns a job ID, which you use to query status and fetch results. The example below runs `OneQubitCalibration` for the X gate on transmon `q0`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ff66aa77",
   "metadata": {},
   "outputs": [],
   "source": [
    "from boulderopalscaleup.routines import OneQubitCalibration\n",
    "\n",
    "routine = OneQubitCalibration(transmon=\"q0\", gate=\"x\")\n",
    "job_id = await client.run_routine(routine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa77bb88",
   "metadata": {},
   "source": [
    "## 4. Restrict qubit targets\n",
    "\n",
    "By default routines assume all qubits might be targeted. Use `enable_qubits()` to limit execution to a subset, for example when some qubits are already characterized or offline. The restriction persists across routines and experiments until you call `enable_all_qubits()` to restore the full set."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb88cc99",
   "metadata": {},
   "outputs": [],
   "source": [
    "await client.enable_qubits(\"q0\", \"q1\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cc99dd00",
   "metadata": {},
   "outputs": [],
   "source": [
    "await client.enable_all_qubits()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd00ee11",
   "metadata": {},
   "source": [
    "## 5. Monitor results\n",
    "\n",
    "Use `get_job_summary()` to check the routine status while the job is running. Use `get_job_data()` once the job finishes to retrieve the job data. `client.display()` renders either object inline."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ee11ff22",
   "metadata": {},
   "outputs": [],
   "source": [
    "job_summary = await client.get_job_summary(job_id)\n",
    "client.display(job_summary)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ff22aa33",
   "metadata": {},
   "outputs": [],
   "source": [
    "job_data = await client.get_job_data(job_id)\n",
    "client.display(job_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa33bb44",
   "metadata": {},
   "source": [
    "## 6. When a routine fails\n",
    "\n",
    "If a routine job reports a failed status, inspect the results in the job data to identify which internal experiment did not converge or returned measurements outside the expected range. See [How to debug failed routines](https://docs.q-ctrl.com/boulder-opal/autocalibration/apply/how-to-debug-a-failed-routine-with-boulder-opal) for the diagnosis workflow."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb44cc55",
   "metadata": {},
   "source": [
    "## Next steps\n",
    "\n",
    "- Run individual experiments for targeted measurements: see [How to run a custom experiment](https://docs.q-ctrl.com/boulder-opal/autocalibration/apply/how-to-run-a-custom-experiment-with-boulder-opal).\n",
    "- Measure coherence times separately: see [How to run coherence measurements](https://docs.q-ctrl.com/boulder-opal/autocalibration/apply/how-to-run-coherence-measurements-with-boulder-opal).\n",
    "- Understand how routines work internally: see [Calibration routines](https://docs.q-ctrl.com/boulder-opal/autocalibration/apply/how-to-run-an-automated-routine-with-boulder-opal)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
