qiboteam__qibocal METASEP

doc/source/getting-started/runcard.rst METASEP
.. _runcard:

How to write your runcard?
==========================

In ``qcvv`` we adopt a declarative programming paradigm, i.e. the user should specify directly
what he wants to do without caring about the underlying implementation.

This paradigm is implemented in ``qcvv`` in the form of runcards. A runcard will contain all
the essential information to run a specific task.

In the case of the ``qq`` command a possible runcard should look like this:

.. code-block:: yaml

    platform: tii5q

    qubit: 0

    format: pickle

    actions:
        first_routine:
            arg1: ...
            arg2: ...

        second_routine:
            arg1: ...
            arg2: ...


First, the user will need to specify some global parameters including:
    * ``platform``: the platform name.
    * ``qubit``: the qubit(s) that we are calibrating.
    * ``format``: the format for storing the measurements.

After those the user will simply populate ``actions`` with all the routines
that he will like to run followed by their respective arguments.

doc/source/getting-started/interface.rst METASEP
Interface
=========

In this section we present the different commands implemented in ``qcvv`` and how to use them.

``qq``
^^^^^^
``qq`` is the base command in ``qcvv``. It can be launched from the command line using:

.. code-block::

    qq <runcard> -o <output_folder>

It will run all the calibration routines specified in the ``<runcard>`` file and save all results
in the ``<output_folder>``. The runcard layout is specified in the :ref:`this <runcard>` section.
If no ``<output_folder>`` is specified ``qq`` will automatically create a default folder containing
the current date and the username.


``qq-live``
^^^^^^^^^^^

``qq-live`` is the command dedicated to live-plotting. It can be launched from the command line using:

.. code-block::

    qq-live <output_folder>

where ``<output_folder>``  is the directory where all the measurements are saved after running ``qq``.
``qq-live`` will produce specific plots depending on the calibration routines executed. If the ``qq`` command
is still running ``qq-live`` will instead produce a live-plotting.

``qq-upload``
^^^^^^^^^^^^^

``qq-compare``
^^^^^^^^^^^^^^

doc/source/getting-started/installation.rst METASEP
Installation instructions
=========================

.. _installing-qcvv:

Qcvv
^^^^

Installing with pip
"""""""""""""""""""

Installing with conda
"""""""""""""""""""""

Installing from source
""""""""""""""""""""""

In order to install ``qcvv`` from source, you can simply clone the GitHub repository
with:

.. code-block::

      git clone https://github.com/qiboteam/qcvv.git
      cd qcvv
      pip install .

You can also use `poetry <https://python-poetry.org/>`_ to install ``qcvv`` from source:

.. code-block::

      git clone https://github.com/qiboteam/qcvv.git
      cd qcvv
      poetry install

doc/source/getting-started/index.rst METASEP
Getting started
===============

In this section we present the basic aspects of the Qcvv design and provide installation instructions.

.. toctree::
    :maxdepth: 1

    installation
    interface
    runcard

doc/source/developer-guides/index.rst METASEP
Developer guides
================

In this section we provide a code overview and contribution guidelines for
developers.

.. toctree::
    :maxdepth: 2

    general
    contributing

doc/source/developer-guides/general.rst METASEP
Code overview
=============

doc/source/developer-guides/contributing.rst METASEP
How to contribute?
==================

If you are looking to contribute make sure to install ``qcvv`` using poetry.

.. code-block::

      git clone https://github.com/qiboteam/qcvv.git
      cd qcvv
      poetry install

We also invite you to use `precommit <https://pre-commit.com/>`_ to enforce automation
and standardize tools for all the developers. Once you have downloaded the ``qcvv`` package
you can install the pre-commit hooks by typing:


.. code-block::

      pre-commit install

inside the installation directory.

doc/source/api-reference/qcvv.rst METASEP
Calibration routines
--------------------

In ``qcvv`` we provide the following calibration routines:

Resonator Spectroscopy with Attenuation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. automodule:: qcvv.calibrations.resonator_spectroscopy
   :members:
   :undoc-members:
   :show-inheritance:

Utils
^^^^^

.. automodule:: qcvv.calibrations.utils
   :members:
   :undoc-members:
   :show-inheritance:


Data structure
--------------

In ``qcvv`` all the data are stored using the :class:`qcvv.data.Dataset` which provide
different formats for storing the data including `pickle <https://docs.python.org/3/library/pickle.html>`_
and `csv <https://docs.python.org/3/library/csv.html>`_.

.. autoclass:: qcvv.data.Dataset
    :members:
    :member-order: bysource

doc/source/api-reference/index.rst METASEP
.. _Components:

API reference
=============

In this section we present the main Qcvv components and primitives included in
the public API.

.. toctree::
    :maxdepth: 3

    qcvv

serverscripts/web/styles.css METASEP
/*
 * Sidebar
 */

.sidebar {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 100;
  /* Behind the navbar */
  padding: 48px 0 0;
  /* Height of navbar */
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
}

.sidebar-sticky {
  height: calc(100vh - 48px);
  overflow-x: hidden;
  overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
}

.list-group-item.active {
  background-color: #6600ff1c;
  border-color: #6600ff1c;
}

.list-group-item {
  background-color: inherit;
  border-width: 0px;
}

/*
 * Navbar
 */

.navbar {
  background-color: #6400FF;
}

.navbar-brand {
  padding-top: .75rem;
  padding-bottom: .75rem;
}

.navbar .navbar-toggler {
  right: 1rem;
}

/*
 * Side bar buttom menu
 */

.btn-toggle {
  padding: .25rem .5rem;
  font-weight: 600;
  color: rgba(0, 0, 0, .65);
  background-color: transparent;
}

.btn-toggle:hover,
.btn-toggle:focus {
  color: rgba(0, 0, 0, .85);
  background-color: #6600ff1c;
}

.btn-toggle::before {
  width: 1.25em;
  line-height: 0;
  content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");
  transition: transform .35s ease;
  transform-origin: .5em 50%;
}

.btn-toggle[aria-expanded="true"] {
  color: rgba(0, 0, 0, .85);
}

.btn-toggle[aria-expanded="true"]::before {
  transform: rotate(90deg);
}

.btn-toggle-nav a {
  padding: .1875rem .5rem;
  margin-top: .125rem;
  margin-left: 1.25rem;
}

.btn-toggle-nav a:hover,
.btn-toggle-nav a:focus {
  background-color: #6600ff1c;
}

serverscripts/web/index.html METASEP
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>QCVV reports</title>
  <link rel="icon" href="data:;base64,iVBORw0KGgo=">

  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
  <link rel="stylesheet" href="styles.css">

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
  <script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.10.13/js/jquery.dataTables.min.js"></script>

  <script type="text/javascript">
  $(document).ready(function() {
    $.getJSON("index.json", function(json){
      var data = json['data'];
      var global_table = $('#global').DataTable({
        "data": data,
        "order": [[2, "desc"]],
        "dom": "frtipl"
      });
    });
  });
  </script>
</head>

<body>

  <header class="navbar navbar-dark sticky-top p-0">
    <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 fs-6" href="/"><span class="fs-4">QCVV Reports</span></a>
  </header>

  <div class="container-fluid">

    <main class="col-md-10 mx-sm-auto col-lg-8 px-md-4">
      <div
        class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
        <h2>Uploaded Reports</h2>
      </div>
      <p>
        Please select a report from the table below:
      </p>

      <table id="global" class="table table-striped table-sm">
        <thead>
          <tr>
            <th scope="col">Title</th>
            <th scope="col">Date</th>
            <th scope="col">Platform</th>
            <th scope="col">Start-time (UTC)</th>
            <th scope="col">End-time (UTC)</th>
          </tr>
        </thead>
      </table>

    </main>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"
    crossorigin="anonymous"></script>
</body>

</html>

doc/source/index.rst METASEP
.. title::
      Qcvv

What is QCVV?
=============

Qcvv is a python module that implements Quatum Characterization Validation and Verification using
`Qibo <https://github.com/qiboteam/qibo>`_ and `Qibolab <https://github.com/qiboteam/qibolab>`_.

Qcvv key features:

* Automatization of calibration routines.
* Declarative inputs using runcard.
* Generation of a report.

This documentation refers to qcvv |release|.

Contents
========

.. toctree::
    :maxdepth: 2
    :caption: Introduction

    getting-started/index

.. toctree::
    :maxdepth: 2
    :caption: Main documentation

    api-reference/index
    developer-guides/index


Indices and tables
==================

* :ref:`genindex`
* :ref:`search`

doc/source/conf.py METASEP
# -*- coding: utf-8 -*-
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys

from recommonmark.transform import AutoStructify

sys.path.insert(0, os.path.abspath(".."))

import qcvv

# -- Project information -----------------------------------------------------

project = "qcvv"
copyright = "2022, The Qibo team"
author = "The Qibo team"

# The full version, including alpha/beta/rc tags
release = qcvv.__version__


# -- General configuration ---------------------------------------------------

# https://stackoverflow.com/questions/56336234/build-fail-sphinx-error-contents-rst-not-found
master_doc = "index"

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    "sphinx.ext.autodoc",
    "sphinx.ext.doctest",
    "sphinx.ext.coverage",
    "sphinx.ext.napoleon",
    "sphinx.ext.intersphinx",
    "recommonmark",
    "sphinx_markdown_tables",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# Markdown configuration

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
source_suffix = {".rst": "restructuredtext", ".txt": "markdown", ".md": "markdown"}

autosectionlabel_prefix_document = True
# Allow to embed rst syntax in  markdown files.
enable_eval_rst = True


# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = "sphinx_rtd_theme"

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = []

# -- Intersphinx  -------------------------------------------------------------

intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}

# -- Autodoc ------------------------------------------------------------------
#
autodoc_member_order = "bysource"

# Adapted this from
# https://github.com/readthedocs/recommonmark/blob/ddd56e7717e9745f11300059e4268e204138a6b1/docs/conf.py
# app setup hook
def setup(app):
    app.add_config_value("recommonmark_config", {"enable_eval_rst": True}, True)
    app.add_transform(AutoStructify)

runcards/example5q.yml METASEP
platform: tii5q

qubits: [0, 1, 2]

format: csv

actions:
    resonator_spectroscopy:
      lowres_width: 5_000_000
      lowres_step: 2_000_000
      highres_width: 1_500_000
      highres_step: 200_000
      precision_width: 1_500_000
      precision_step: 100_000
      software_averages: 1
      points: 5

runcards/example1q.yml METASEP
platform: tii1q

qubits: [0]

format: csv

actions:
    resonator_spectroscopy:
      lowres_width: 5_000_000
      lowres_step: 2_000_000
      highres_width: 1_500_000
      highres_step: 200_000
      precision_width: 1_500_000
      precision_step: 100_000
      software_averages: 1
      points: 5

runcards/example.yml METASEP
platform: tii5q

qubits: [0]

format: csv

actions:
  resonator_spectroscopy_attenuation:
    lowres_width: 10_000_000
    lowres_step: 5_000_000 # 100_000
    highres_width: 1_000_000
    highres_step: 500_000 # 50_000
    min_att: 0
    max_att: 60
    step_att: 10
    software_averages: 2
    points: 10

runcards/dummy.yml METASEP
platform: dummy

qubits: [0]

format: csv

actions:
  resonator_spectroscopy:
    lowres_width: 10_000_000
    lowres_step: 5_000_000 # 100_000
    highres_width: 1_000_000
    highres_step: 500_000 # 50_000
    min_att: 0
    max_att: 60
    step_att: 10
    software_averages: 2
    points: 10

runcards/actions_qq_5q.yml METASEP
platform: tii5q

qubits: [1, 2]

format: csv

actions:
  resonator_spectroscopy:
    lowres_width: 5_000_000
    lowres_step: 2_000_000
    highres_width: 1_500_000
    highres_step: 200_000
    precision_width: 1_500_000
    precision_step: 100_000
    software_averages: 1
    points: 5

  resonator_spectroscopy_flux:
    freq_width: 3_000_000
    freq_step: 200_000
    current_max: +0.000 # absolute max is 40 mA
    current_min: -10.e-3 # absolute min is -40 mA
    current_step: 3.e-3
    fluxline: qubit # Ask alvaro automatic way to obtain fluxline from runcard
    software_averages: 1
    points: 10

  resonator_spectroscopy_flux_matrix:
    freq_width: 3_000_000
    freq_step: 200_000
    current_max: +0.000 # absolute max is 40 mA
    current_min: -10.e-3 # absolute min is -40 mA
    current_step: 3.e-3
    fluxlines: [1, 2] # Ask alvaro automatic way to obtain fluxline from runcard
    software_averages: 2
    points: 10

  resonator_punchout:
    freq_width: 10_000_000
    freq_step: 500_000
    min_att: 10
    max_att: 40
    step_att: 10 # attenuation must be a multiple of 2
    software_averages: 1
    points: 10

  qubit_spectroscopy:
    fast_start: -50_000_000
    fast_end: 50_000_000
    fast_step: 500_000
    precision_start: -500_000
    precision_end: 500_000
    precision_step: 100_000
    software_averages: 1
    points: 10

  qubit_spectroscopy_flux:
    freq_width: 50_000_000
    freq_step: 200_000
    current_min: -0.0012 # -0.0025 # absolute min is -40 mA
    current_max: -0.0004 # +0.001 # absolute max is 40 mA
    current_step: 0.00002 # 0.0001
    fluxline: 1 # Ask alvaro automatic way to obtain fluxline from runcard
    software_averages: 2
    points: 10

  # rabi_pulse_amplitude:
  #   pulse_amplitude_start: 0 # 0<=a<=1
  #   pulse_amplitude_end: 1
  #   pulse_amplitude_step: 0.02
  #   software_averages: 1
  #   points: 10

  # rabi_pulse_gain:
  #   pulse_gain_start: 0 # -1.0<=g<=1.0
  #   pulse_gain_end: 1
  #   pulse_gain_step: 0.02
  #   software_averages: 1
  #   points: 10

  # rabi_pulse_length_and_amplitude:
  #   pulse_duration_start: 4 # minimum 4ns
  #   pulse_duration_end: 200
  #   pulse_duration_step: 4
  #   pulse_amplitude_start: 0 # -1.0<= amplitude <=1.0
  #   pulse_amplitude_end: 1
  #   pulse_amplitude_step: 0.02
  #   software_averages: 1
  #   points: 10

  # rabi_pulse_length_and_gain:
  #   pulse_duration_start: 4 # minimum 4ns
  #   pulse_duration_end: 200
  #   pulse_duration_step: 4
  #   pulse_gain_start: 0 # -1.0<=g<=1.0
  #   pulse_gain_end: 1
  #   pulse_gain_step: 0.02
  #   software_averages: 1
  #   points: 10

  # rabi_pulse_length:
  #   pulse_duration_start: 4 # minimum 4ns
  #   pulse_duration_end: 200
  #   pulse_duration_step: 4
  #   software_averages: 1
  #   points: 10

  # allXY_iteration:
  #   beta_start: -1
  #   beta_end: 1
  #   beta_step: 0.2
  #   software_averages: 1
  #   points: 1

  # allXY:
  #   beta_param: Null
  #   software_averages: 1
  #   points: 1

  # calibrate_qubit_states:
  #   niter: 1024
  #   points: 1

  # dispersive_shift:
  #   freq_width: 5_000_000
  #   freq_step: 200_000
  #   software_averages: 1
  #   points: 5

  # flipping:
  #   niter: 10
  #   step: 2

  # ramsey_frequency_detuned:
  #   t_start: 4
  #   t_end: [2000] #t_end (optimal) = 3.5 * T2 (limited by HW to 8000ns)
  #   t_step: 16
  #   n_osc: 4
  #   software_averages: 1
  #   points: 1

  # ramsey:
  #   delay_between_pulses_start: 0 # must be a multiple of 4 incl 0
  #   delay_between_pulses_end: 4000
  #   delay_between_pulses_step: 16 # must be a multiple of 4
  #   software_averages: 1
  #   points: 1

  # RO_matrix:
  #   niter: 10 # set niter = 1024 to collect good statistics

  # ro_pulse_phase:
  #   pulse_phase_start: 0
  #   pulse_phase_end: 6.28318
  #   pulse_phase_step: 0.1
  #   software_averages: 1
  #   points: 10

  # t1:
  #   delay_before_readout_start: 4
  #   delay_before_readout_end: 50_000
  #   delay_before_readout_step: 500
  #   software_averages: 1
  #   points: 5

  # spin_echo:
  #   delay_between_pulses_start: 4
  #   delay_between_pulses_end: 4000
  #   delay_between_pulses_step: 20
  #   software_averages: 1
  #   points: 5

  # spin_echo_3pulses:
  #   delay_between_pulses_start: 4
  #   delay_between_pulses_end: 30000
  #   delay_between_pulses_step: 20
  #   software_averages: 1
  #   points: 5

runcards/actions_qq_1q.yml METASEP
platform: tii1q

qubits: [0]

format: csv

actions:
  # resonator_spectroscopy:
  #   lowres_width: 5_000_000
  #   lowres_step: 2_000_000
  #   highres_width: 1_500_000
  #   highres_step: 200_000
  #   precision_width: 1_500_000
  #   precision_step: 100_000
  #   software_averages: 1
  #   points: 5

  # resonator_punchout:
  #   freq_width: 10_000_000
  #   freq_step: 200_000
  #   min_att: 0
  #   max_att: 60
  #   step_att: 2 # attenuation must be a multiple of 2
  #   software_averages: 1
  #   points: 10

  qubit_spectroscopy:
    fast_start: -5_000_000
    fast_end: 5_000_000
    fast_step: 200_000
    precision_start: -500_000
    precision_end: 500_000
    precision_step: 20_000
    software_averages: 1
    points: 10

  # rabi_pulse_amplitude:
  #   pulse_amplitude_start: 0 # 0<=a<=1
  #   pulse_amplitude_end: 1
  #   pulse_amplitude_step: 0.02
  #   software_averages: 1
  #   points: 10

  # rabi_pulse_gain:
  #   pulse_gain_start: 0 # -1.0<=g<=1.0
  #   pulse_gain_end: 1
  #   pulse_gain_step: 0.02
  #   software_averages: 1
  #   points: 10

  # rabi_pulse_length_and_amplitude:
  #   pulse_duration_start: 4 # minimum 4ns
  #   pulse_duration_end: 200
  #   pulse_duration_step: 4
  #   pulse_amplitude_start: 0 # -1.0<= amplitude <=1.0
  #   pulse_amplitude_end: 1
  #   pulse_amplitude_step: 0.02
  #   software_averages: 1
  #   points: 10

  # rabi_pulse_length_and_gain:
  #   pulse_duration_start: 4 # minimum 4ns
  #   pulse_duration_end: 200
  #   pulse_duration_step: 4
  #   pulse_gain_start: 0 # -1.0<=g<=1.0
  #   pulse_gain_end: 1
  #   pulse_gain_step: 0.02
  #   software_averages: 1
  #   points: 10

  # rabi_pulse_length:
  #   pulse_duration_start: 4 # minimum 4ns
  #   pulse_duration_end: 200
  #   pulse_duration_step: 4
  #   software_averages: 1
  #   points: 10

  # allXY_iteration:
  #   beta_start: -1
  #   beta_end: 1
  #   beta_step: 0.2
  #   software_averages: 1
  #   points: 1

  # allXY:
  #   beta_param: Null
  #   software_averages: 1
  #   points: 1

  # calibrate_qubit_states:
  #   niter: 1024
  #   points: 1

  # dispersive_shift:
  #   freq_width: 5_000_000
  #   freq_step: 200_000
  #   software_averages: 1
  #   points: 5

  # flipping:
  #   niter: 10
  #   step: 2

  # ramsey_frequency_detuned:
  #   t_start: 4
  #   t_end: [2000] #t_end (optimal) = 3.5 * T2 (limited by HW to 8000ns)
  #   t_step: 16
  #   n_osc: 4
  #   software_averages: 1
  #   points: 1

  # ramsey:
  #   delay_between_pulses_start: 0 # must be a multiple of 4 incl 0
  #   delay_between_pulses_end: 4000
  #   delay_between_pulses_step: 16 # must be a multiple of 4
  #   software_averages: 1
  #   points: 1

  # RO_matrix:
  #   niter: 10 # set niter = 1024 to collect good statistics

  # ro_pulse_phase:
  #   pulse_phase_start: 0
  #   pulse_phase_end: 6.28318
  #   pulse_phase_step: 0.1
  #   software_averages: 1
  #   points: 10

  # t1:
  #   delay_before_readout_start: 4
  #   delay_before_readout_end: 50_000
  #   delay_before_readout_step: 500
  #   software_averages: 1
  #   points: 5

  # spin_echo:
  #   delay_between_pulses_start: 4
  #   delay_between_pulses_end: 4000
  #   delay_between_pulses_step: 20
  #   software_averages: 1
  #   points: 5

  # spin_echo_3pulses:
  #   delay_between_pulses_start: 4
  #   delay_between_pulses_end: 30000
  #   delay_between_pulses_step: 20
  #   software_averages: 1
  #   points: 5

doc/Makefile METASEP
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS    ?=
SPHINXBUILD   ?= sphinx-build
SOURCEDIR     = source
BUILDDIR      = build

# Put it first so that "make" without argument is like "make help".
help:
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

serverscripts/qcvv-update-on-change.py METASEP
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import argparse

import curio
import inotify.adapters
import inotify.constants
from curio import subprocess


async def main(folder, exe_args):
    i = inotify.adapters.Inotify()
    i.add_watch(folder)

    for event in i.event_gen(yield_nones=False):
        if event is not None:
            (header, _, _, _) = event
            if (
                (header.mask & inotify.constants.IN_CREATE)
                or (header.mask & inotify.constants.IN_DELETE)
                or (header.mask & inotify.constants.IN_MODIFY)
            ):
                await subprocess.run(exe_args)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("folder")
    parser.add_argument("exe_args", nargs="+")
    args = parser.parse_args()
    curio.run(main(args.folder, args.exe_args))

serverscripts/qcvv-index.reports.py METASEP
# -*- coding: utf-8 -*-
"""qcvv-index-reports.py
Generates a JSON index with reports information.
"""
import json
import pathlib
import sys
from collections import ChainMap

import yaml

ROOT = "/home/users/qcvv/qcvv-reports"
ROOT_URL = "http://login.qrccluster.com:9000/"
OUT = "/home/users/qcvv/qcvv-reports/index.json"
DEFAULTS = {
    "title": "-",
    "date": "-",
    "platform": "-",
    "start-time": "-",
    "end-time": "-",
}
REQUIRED_FILE_METADATA = {"title", "date", "platform", "start-time" "end-time"}


def meta_from_path(p):
    meta = ChainMap(DEFAULTS)
    yaml_meta = p / "meta.yml"
    yaml_res = {}
    if yaml_meta.exists():
        with yaml_meta.open() as f:
            try:
                yaml_res = yaml.safe_load(f)
            except yaml.YAMLError as e:
                print(f"Error processing {yaml_meta}: {e}", file=sys.stderr)
    meta = meta.new_child(yaml_res)
    return meta


def register(p):
    path_meta = meta_from_path(p)
    title, date, platform, start_time, end_time = (
        path_meta["title"],
        path_meta["date"],
        path_meta["platform"],
        path_meta["start-time"],
        path_meta["end-time"],
    )
    url = ROOT_URL + p.name
    titlelink = f'<a href="{url}">{title}</a>'
    return (titlelink, date, platform, start_time, end_time)


def make_index():
    root_path = pathlib.Path(ROOT)
    data = []
    for p in root_path.iterdir():
        if p.is_dir():
            try:
                res = register(p)
                data.append(res)
            except:
                print("Error processing folder", p, file=sys.stderr)
                raise

    with open(OUT, "w") as f:
        json.dump({"data": data}, f)


if __name__ == "__main__":
    make_index()

src/qcvv/web/templates/template.html METASEP
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  {% if report %}
  <title>{{ report.title }}</title>
  {% else %}
  <title>QCVV {{version}}</title>
  {% endif %}

  <link rel="icon" type="image/x-icon" href="/_favicon.ico?v=2.6.0">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">

  {% if is_static %}
  <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
  <!-- Reading the plotly js library from online to save space (not the latest version) -->
  <!-- This is required for the report plots to remain interactive -->
  <script type="text/javascript" src="https://cdn.plot.ly/plotly-latest.min.js"></script>
  {{ css_styles }}
  {% else %}
  <link rel="stylesheet" href="/static/styles.css">
  {% endif %}

</head>

<body>

  <header class="navbar navbar-dark sticky-top p-0">
    <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 fs-6" href="/"><span class="fs-4">QCVV Reports</span></a>
    <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-bs-toggle="collapse"
      data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
  </header>

  <div class="container-fluid">

    <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
      <div class="position-sticky pt-4 p-2 sidebar-sticky">
        <ul class="list-unstyled ps-0">
          {% if report %}
          <li class="mb-1">
            <buttom class="btn btn-toggle d-inline-flex align-items-center rounded border-0" data-bs-toggle="collapse"
              data-bs-target="#home-collapse" aria-expanded="true">
              Home
            </buttom>
            <div class="collapse show" id="home-collapse">
              <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
                <li><a href="#" class="link-dark d-inline-flex text-decoration-none rounded">
                    Timestamp</a></li>
                <li><a href="#summary" class="link-dark d-inline-flex text-decoration-none rounded">
                    Summary</a></li>
              </ul>
            </div>
          </li>
          <li class="mb-1">
            <button class="btn btn-toggle d-inline-flex align-items-center rounded border-0" data-bs-toggle="collapse"
              data-bs-target="#actions-collapse" aria-expanded="true">
              Actions
            </button>
            <div class="collapse show" id="actions-collapse">
              {% for routine in report.routines %}
              <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
                <li><a href="#{{ routine }}" class="link-dark d-inline-flex text-decoration-none rounded">{{
                    report.get_routine_name(routine) }}</a></li>
                {% for header, method in routine.plots %}
                <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
                  <li><a class="link-dark d-inline-flex text-decoration-none rounded"
                      href="#{{ routine }}-{{ method }}">- {{ header }}</a></li>
                {% endfor %}
                </ul>
              </ul>
              {% endfor %}
            </div>
          </li>
          <li class="border-top my-3"></li>
          {% endif %}
          {% if not is_static %}
          <li class="mb-1">
            <button class="btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed"
              data-bs-toggle="collapse" data-bs-target="#saved-reports" aria-expanded="true">
              Saved reports
            </button>
            <div class="collapse show list-group" id="saved-reports">
              <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
                {% for folder in folders %}
                <li><a id="reports" href="{{ url_for('page', path=folder) }}"
                    class="link-dark d-inline-flex text-decoration-none rounded list-group-item {{ 'active' if folder == report.path else '' }}">{{ folder }}</a></li>
                {% endfor %}
              </ul>
            </div>
          </li>
          {% endif %}
        </ul>

      </div>

    </nav>

    <main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">

      {% if report.path %}
      <div
        class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
        <h1>{{ report.title }}</h1>
      </div>
      <p>
        Platform: {{ report.metadata.get('platform')}}<br>
        Run date: {{ report.metadata.get('date') }}<br>
        Start time (UTC): {{ report.metadata.get('start-time') }}<br>
        End time (UTC): {{ report.metadata.get('end-time') }}
      </p>
      <h3 id="summary" style="scroll-margin-top: 2.5em;"
        class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
        Summary</h3>

      <p>In the table below we show the libraries and respective versions used in {{ report.title }}.</p>

      <div class="table-responsive col-md-5 col-lg-3">
        <table class="table table-striped table-sm">
          <thead>
            <tr>
              <th scope="col">Library</th>
              <th scope="col">Version</th>
            </tr>
          </thead>
          <tbody>
            {% for library, version in report.metadata.get('versions').items() %}
            <tr>
              <td>{{ library }}</td>
              <td>{{ version }}</td>
            </tr>
            {% endfor %}
          </tbody>
        </table>
      </div>

      <h3 id="actions"
        class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
        Actions</h3>
      <p>Please find below data generated by actions:</p>

      {% for routine in report.routines %}
      <div id="{{ routine }}" style="scroll-margin-top: 4em;">
        <h4
          class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
          {{ report.get_routine_name(routine) }}</h4>
        {% if routine.plots %}
        {% for header, method in routine.plots %}
        <div id="{{ routine }}-{{ method }}" style="scroll-margin-top: 4em;">
          {% for qubit in report.qubits %}
          <div id="{{ routine }}-{{ method }}-{{ qubit }}" style="scroll-margin-top: 4em;">
          <h5
            class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
            {{ header }} - Qubit {{ qubit }}</h5>
          {% if is_static %}
            {{ report.get_figure(routine, method, qubit) }}
          {% else %}
          <!-- find a way to change height and width depending on screen type -->
          <iframe src="{{ report.get_live_figure(routine, method, qubit) }}"
            style="position: relative; height: 500px; width: 100%;"></iframe>
          {% endif %}
          </div>
          {% endfor %}
        </div>
        {% endfor %}
        {% else %}
        <p>No plots available for {{ routine.__name__ }}.</p>
        {% endif %}
      </div>
      {% endfor %}

      {% else %}
      <div
        class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
        <h2>Welcome to QCVV live!</h2>
      </div>
      <p>
        Please select a report from the <mark>Saved reports</mark> in the sidebar .
      </p>
      {% endif %}
    </main>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"
    crossorigin="anonymous"></script>
</body>

</html>

src/qcvv/web/static/styles.css METASEP
/*
 * Sidebar
 */

.sidebar {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 100;
  /* Behind the navbar */
  padding: 48px 0 0;
  /* Height of navbar */
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
}

.sidebar-sticky {
  height: calc(100vh - 48px);
  overflow-x: hidden;
  overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
}

.list-group-item.active {
  background-color: #6600ff1c;
  border-color: #6600ff1c;
}

.list-group-item {
  background-color: inherit;
  border-width: 0px;
}

/*
 * Navbar
 */

.navbar {
  background-color: #6400FF;
}

.navbar-brand {
  padding-top: .75rem;
  padding-bottom: .75rem;
}

.navbar .navbar-toggler {
  right: 1rem;
}

/*
 * Side bar buttom menu
 */

.btn-toggle {
  padding: .25rem .5rem;
  font-weight: 600;
  color: rgba(0, 0, 0, .65);
  background-color: transparent;
}

.btn-toggle:hover,
.btn-toggle:focus {
  color: rgba(0, 0, 0, .85);
  background-color: #6600ff1c;
}

.btn-toggle::before {
  width: 1.25em;
  line-height: 0;
  content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");
  transition: transform .35s ease;
  transform-origin: .5em 50%;
}

.btn-toggle[aria-expanded="true"] {
  color: rgba(0, 0, 0, .85);
}

.btn-toggle[aria-expanded="true"]::before {
  transform: rotate(90deg);
}

.btn-toggle-nav a {
  padding: .1875rem .5rem;
  margin-top: .125rem;
  margin-left: 1.25rem;
}

.btn-toggle-nav a:hover,
.btn-toggle-nav a:focus {
  background-color: #6600ff1c;
}

pyproject.toml METASEP
[tool.poetry]
name = "qcvv"
version = "0.0.1.dev0"
description = ""
authors = ["andrea-pasquale <andreapasquale97@gmail.com>"]
license = "Apache License 2.0"
readme = "README.md"
homepage = ""
repository = "https://github.com/qiboteam/qcvv/"
documentation = ""
keywords = []
classifiers=[
    "Programming Language :: Python :: 3",
    "Topic :: Scientific/Engineering :: Physics",
    ]

[tool.poetry.dependencies]
python = ">=3.8"
qibo = {git = "https://github.com/qiboteam/qibo.git", rev = "master"}
qibolab = {git = "git@github.com:qiboteam/qibolab.git", rev = "main"}
pandas = "^1.4.3"
Pint-Pandas = {git = "https://github.com/hgrecco/pint-pandas.git", rev = "master"}
dash = "^2.6.0"

[tool.poetry.dev-dependencies]
black = "^22.6.0"
pylint = "2.12.2"
pre-commit = "^2.20.0"
pytest = "^7.1.2"
pytest-cov = "^3.0.0"
poethepoet = "^0.16.0"
Sphinx = "^4.3.2"
sphinx-rtd-theme = "^1.0.0"
sphinxcontrib-bibtex = "^2.4.1"
recommonmark = "^0.7.1"
sphinx-markdown-tables = "^0.0.17"

[tool.poetry.extras]
docs = ["sphinx", "sphinx-rtd-theme", "sphinxcontrib-bibtex", "recommonmark", "sphinx-markdown-tables"]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.scripts]
qq = "qcvv:command"
qq-live = "qcvv:live_plot"
qq-upload = "qcvv:upload"

[tool.poe.tasks]
test = "pytest src/qcvv/tests"
lint = "pylint src/**/*.py -E"
lint-warnings = "pylint src/**/*.py --exit-zero"
docs = "make -C doc html"
docs-clean = "make -C doc clean"

[tool.pytest.ini_options]
testpaths = ['src/qcvv/tests/']
addopts = [
    '--cov=qcvv',
    '--cov-report=xml'
]

[tool.pylint.master]
# extensions not to check
extension-pkg-whitelist = ["numpy"]
jobs = 1

[tool.pylint.messages_control]
disable = ["invalid-name", "fixme"]

[tool.pylint.reports]
# Available formats are:
# text, parseable, colorized, json and msvs (visual studio).
output-format = "colorized"

[tool.pylint.format]
# Maximum number of characters on a single line.
max-line-length = 100

[tool.pylint.design]
# Maximum number of arguments for function / method
max-args = 10

poetry.lock METASEP
[[package]]
name = "alabaster"
version = "0.7.12"
description = "A configurable sidebar-enabled Sphinx theme"
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "appnope"
version = "0.1.3"
description = "Disable App Nap on macOS >= 10.9"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "argon2-cffi"
version = "21.3.0"
description = "The secure Argon2 password hashing algorithm."
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
argon2-cffi-bindings = "*"

[package.extras]
dev = ["pre-commit", "cogapp", "tomli", "coverage[toml] (>=5.0.2)", "hypothesis", "pytest", "sphinx", "sphinx-notfound-page", "furo"]
docs = ["sphinx", "sphinx-notfound-page", "furo"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"]

[[package]]
name = "argon2-cffi-bindings"
version = "21.2.0"
description = "Low-level CFFI bindings for Argon2"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
cffi = ">=1.0.1"

[package.extras]
dev = ["pytest", "cogapp", "pre-commit", "wheel"]
tests = ["pytest"]

[[package]]
name = "asteval"
version = "0.9.27"
description = "Safe, minimalistic evaluator of python expression using ast module"
category = "main"
optional = false
python-versions = ">=3.7"

[package.extras]
all = ["build", "twine", "coverage", "pytest", "pytest-cov", "sphinx"]
dev = ["build", "twine"]
doc = ["sphinx"]
test = ["coverage", "pytest", "pytest-cov"]

[[package]]
name = "astroid"
version = "2.9.3"
description = "An abstract syntax tree for Python with inference support."
category = "dev"
optional = false
python-versions = ">=3.6.2"

[package.dependencies]
lazy-object-proxy = ">=1.4.0"
typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""}
wrapt = ">=1.11,<1.14"

[[package]]
name = "asttokens"
version = "2.0.5"
description = "Annotate AST trees with source code positions"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
six = "*"

[package.extras]
test = ["astroid", "pytest"]

[[package]]
name = "atomicwrites"
version = "1.4.1"
description = "Atomic file writes."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[[package]]
name = "attrs"
version = "22.1.0"
description = "Classes Without Boilerplate"
category = "main"
optional = false
python-versions = ">=3.5"

[package.extras]
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"]

[[package]]
name = "azure-core"
version = "1.24.2"
description = "Microsoft Azure Core Library for Python"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
requests = ">=2.18.4"
six = ">=1.11.0"
typing-extensions = ">=4.0.1"

[[package]]
name = "azure-identity"
version = "1.10.0"
description = "Microsoft Azure Identity Library for Python"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
azure-core = ">=1.11.0,<2.0.0"
cryptography = ">=2.5"
msal = ">=1.12.0,<2.0.0"
msal-extensions = ">=0.3.0,<2.0.0"
six = ">=1.12.0"

[[package]]
name = "babel"
version = "2.10.3"
description = "Internationalization utilities"
category = "dev"
optional = false
python-versions = ">=3.6"

[package.dependencies]
pytz = ">=2015.7"

[[package]]
name = "backcall"
version = "0.2.0"
description = "Specifications for callback functions passed in to an API"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "beautifulsoup4"
version = "4.11.1"
description = "Screen-scraping library"
category = "main"
optional = false
python-versions = ">=3.6.0"

[package.dependencies]
soupsieve = ">1.2"

[package.extras]
html5lib = ["html5lib"]
lxml = ["lxml"]

[[package]]
name = "black"
version = "22.6.0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6.2"

[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}

[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]

[[package]]
name = "bleach"
version = "5.0.1"
description = "An easy safelist-based HTML-sanitizing tool."
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
six = ">=1.9.0"
webencodings = "*"

[package.extras]
css = ["tinycss2 (>=1.1.0,<1.2)"]
dev = ["build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "Sphinx (==4.3.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)", "black (==22.3.0)", "mypy (==0.961)"]

[[package]]
name = "broadbean"
version = "0.10.0"
description = "Package for easily generating and manipulating signal pulses. Developed for use with qubits in the quantum computing labs of Copenhagen, Delft, and Sydney, but should be generally useable."
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
matplotlib = "*"
numpy = ">=1.12.1"
schema = "*"

[[package]]
name = "brotli"
version = "1.0.9"
description = "Python bindings for the Brotli compression library"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "cachetools"
version = "3.1.1"
description = "Extensible memoizing collections and decorators"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "certifi"
version = "2022.6.15"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "cffi"
version = "1.15.1"
description = "Foreign Function Interface for Python calling C code."
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
pycparser = "*"

[[package]]
name = "cfgv"
version = "3.3.1"
description = "Validate configuration and produce human readable error messages."
category = "dev"
optional = false
python-versions = ">=3.6.1"

[[package]]
name = "charset-normalizer"
version = "2.0.12"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
python-versions = ">=3.5.0"

[package.extras]
unicode_backport = ["unicodedata2"]

[[package]]
name = "click"
version = "8.1.3"
description = "Composable command line interface toolkit"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}

[[package]]
name = "cma"
version = "3.2.2"
description = "CMA-ES, Covariance Matrix Adaptation Evolution Strategy for non-linear numerical optimization in Python"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
numpy = "*"

[package.extras]
constrained-solution-tracking = ["moarchiving"]
plotting = ["matplotlib"]

[[package]]
name = "colorama"
version = "0.4.5"
description = "Cross-platform colored terminal text."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"

[[package]]
name = "commonmark"
version = "0.9.1"
description = "Python parser for the CommonMark Markdown spec"
category = "dev"
optional = false
python-versions = "*"

[package.extras]
test = ["hypothesis (==3.55.3)", "flake8 (==3.7.8)"]

[[package]]
name = "contextlib2"
version = "21.6.0"
description = "Backports and enhancements for the contextlib module"
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "coverage"
version = "6.4.2"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
python-versions = ">=3.7"

[package.dependencies]
tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}

[package.extras]
toml = ["tomli"]

[[package]]
name = "cryptography"
version = "37.0.4"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
cffi = ">=1.12"

[package.extras]
docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"]
docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
sdist = ["setuptools_rust (>=0.11.4)"]
ssh = ["bcrypt (>=3.1.5)"]
test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"]

[[package]]
name = "cycler"
version = "0.11.0"
description = "Composable style cycles"
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "dash"
version = "2.6.1"
description = "A Python framework for building reactive web-apps. Developed by Plotly."
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
dash-core-components = "2.0.0"
dash-html-components = "2.0.0"
dash-table = "5.0.0"
Flask = ">=1.0.4"
flask-compress = "*"
plotly = ">=5.0.0"

[package.extras]
celery = ["redis (>=3.5.3)", "celery[redis] (>=5.1.2)"]
ci = ["dash-flow-example (==0.0.5)", "dash-dangerously-set-inner-html", "flake8 (==3.9.2)", "flaky (==3.7.0)", "flask-talisman (==1.0.0)", "mimesis", "mock (==4.0.3)", "numpy", "preconditions", "pylint (==2.13.5)", "pytest-mock", "pytest-sugar (==0.9.4)", "pytest-rerunfailures", "black (==21.6b0)", "isort (==4.3.21)", "orjson (==3.5.4)", "pyarrow (<3)", "pandas (==1.1.5)", "xlrd (<2)", "black (==22.3.0)", "orjson (==3.6.7)", "pyarrow", "openpyxl", "pandas (>=1.4.0)", "xlrd (>=2.0.1)"]
dev = ["coloredlogs (>=15.0.1)", "fire (>=0.4.0)", "PyYAML (>=5.4.1)"]
diskcache = ["diskcache (>=5.2.1)", "multiprocess (>=0.70.12)", "psutil (>=5.8.0)"]
testing = ["beautifulsoup4 (>=4.8.2)", "lxml (>=4.6.2)", "percy (>=2.0.2)", "pytest (>=6.0.2)", "requests[security] (>=2.21.0)", "selenium (>=3.141.0,<=4.2.0)", "waitress (>=1.4.4)", "cryptography (<3.4)"]

[[package]]
name = "dash-core-components"
version = "2.0.0"
description = "Core component suite for Dash"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "dash-html-components"
version = "2.0.0"
description = "Vanilla HTML components for Dash"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "dash-table"
version = "5.0.0"
description = "Dash table"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "debugpy"
version = "1.6.2"
description = "An implementation of the Debug Adapter Protocol for Python"
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "decorator"
version = "5.1.1"
description = "Decorators for Humans"
category = "main"
optional = false
python-versions = ">=3.5"

[[package]]
name = "defusedxml"
version = "0.7.1"
description = "XML bomb protection for Python stdlib modules"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"

[[package]]
name = "distlib"
version = "0.3.5"
description = "Distribution utilities"
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "docutils"
version = "0.17.1"
description = "Docutils -- Python Documentation Utilities"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"

[[package]]
name = "entrypoints"
version = "0.4"
description = "Discover and load entry points from installed packages."
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "executing"
version = "0.9.1"
description = "Get the currently executing AST node of a frame, and other information"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "fastjsonschema"
version = "2.16.1"
description = "Fastest Python implementation of JSON schema"
category = "main"
optional = false
python-versions = "*"

[package.extras]
devel = ["colorama", "jsonschema", "json-spec", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"]

[[package]]
name = "filelock"
version = "3.7.1"
description = "A platform independent file lock."
category = "dev"
optional = false
python-versions = ">=3.7"

[package.extras]
docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"]
testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"]

[[package]]
name = "flask"
version = "2.2.0"
description = "A simple framework for building complex web applications."
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
click = ">=8.0"
importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
itsdangerous = ">=2.0"
Jinja2 = ">=3.0"
Werkzeug = ">=2.2.0"

[package.extras]
dotenv = ["python-dotenv"]
async = ["asgiref (>=3.2)"]

[[package]]
name = "flask-compress"
version = "1.12"
description = "Compress responses in your Flask app with gzip, deflate or brotli."
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
brotli = "*"
flask = "*"

[[package]]
name = "fonttools"
version = "4.34.4"
description = "Tools to manipulate font files"
category = "main"
optional = false
python-versions = ">=3.7"

[package.extras]
all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"]
graphite = ["lz4 (>=1.7.4.2)"]
interpolatable = ["scipy", "munkres"]
lxml = ["lxml (>=4.0,<5)"]
pathops = ["skia-pathops (>=0.5.0)"]
plot = ["matplotlib"]
repacker = ["uharfbuzz (>=0.23.0)"]
symfont = ["sympy"]
type1 = ["xattr"]
ufo = ["fs (>=2.2.0,<3)"]
unicode = ["unicodedata2 (>=14.0.0)"]
woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"]

[[package]]
name = "future"
version = "0.18.2"
description = "Clean single-source support for Python 3 and 2"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"

[[package]]
name = "google-api-core"
version = "2.8.2"
description = "Google API client core library"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
google-auth = ">=1.25.0,<3.0dev"
googleapis-common-protos = ">=1.56.2,<2.0dev"
protobuf = ">=3.15.0,<5.0.0dev"
requests = ">=2.18.0,<3.0.0dev"

[package.extras]
grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio-status (>=1.33.2,<2.0dev)"]

[[package]]
name = "google-auth"
version = "2.9.1"
description = "Google Authentication Library"
category = "main"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"

[package.dependencies]
cachetools = ">=2.0.0,<6.0"
pyasn1-modules = ">=0.2.1"
rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""}
six = ">=1.9.0"

[package.extras]
aiohttp = ["requests (>=2.20.0,<3.0.0dev)", "aiohttp (>=3.6.2,<4.0.0dev)"]
enterprise_cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"]
pyopenssl = ["pyopenssl (>=20.0.0)"]
reauth = ["pyu2f (>=0.1.5)"]

[[package]]
name = "googleapis-common-protos"
version = "1.56.4"
description = "Common protobufs used in Google APIs"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
protobuf = ">=3.15.0,<5.0.0dev"

[package.extras]
grpc = ["grpcio (>=1.0.0,<2.0.0dev)"]

[[package]]
name = "h5netcdf"
version = "1.0.2"
description = "netCDF4 via h5py"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
h5py = "*"
packaging = "*"

[[package]]
name = "h5py"
version = "3.7.0"
description = "Read and write HDF5 files from Python"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
numpy = ">=1.14.5"

[[package]]
name = "identify"
version = "2.5.2"
description = "File identification library for Python"
category = "dev"
optional = false
python-versions = ">=3.7"

[package.extras]
license = ["ukkonen"]

[[package]]
name = "idna"
version = "3.3"
description = "Internationalized Domain Names in Applications (IDNA)"
category = "main"
optional = false
python-versions = ">=3.5"

[[package]]
name = "imagesize"
version = "1.4.1"
description = "Getting image size from png/jpeg/jpeg2000/gif file"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[[package]]
name = "importlib-metadata"
version = "4.12.0"
description = "Read metadata from Python packages"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
zipp = ">=0.5"

[package.extras]
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
perf = ["ipython"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]

[[package]]
name = "importlib-resources"
version = "5.9.0"
description = "Read resources from Python packages"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}

[package.extras]
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]

[[package]]
name = "iniconfig"
version = "1.1.1"
description = "iniconfig: brain-dead simple config-ini parsing"
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "ipykernel"
version = "6.15.1"
description = "IPython Kernel for Jupyter"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
appnope = {version = "*", markers = "platform_system == \"Darwin\""}
debugpy = ">=1.0"
ipython = ">=7.23.1"
jupyter-client = ">=6.1.12"
matplotlib-inline = ">=0.1"
nest-asyncio = "*"
packaging = "*"
psutil = "*"
pyzmq = ">=17"
tornado = ">=6.1"
traitlets = ">=5.1.0"

[package.extras]
test = ["flaky", "ipyparallel", "pre-commit", "pytest-cov", "pytest-timeout", "pytest (>=6.0)"]

[[package]]
name = "ipython"
version = "8.4.0"
description = "IPython: Productive Interactive Computing"
category = "main"
optional = false
python-versions = ">=3.8"

[package.dependencies]
appnope = {version = "*", markers = "sys_platform == \"darwin\""}
backcall = "*"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
decorator = "*"
jedi = ">=0.16"
matplotlib-inline = "*"
pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""}
pickleshare = "*"
prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0"
pygments = ">=2.4.0"
stack-data = "*"
traitlets = ">=5"

[package.extras]
all = ["black", "Sphinx (>=1.3)", "ipykernel", "nbconvert", "nbformat", "ipywidgets", "notebook", "ipyparallel", "qtconsole", "pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "numpy (>=1.19)", "pandas", "trio"]
black = ["black"]
doc = ["Sphinx (>=1.3)"]
kernel = ["ipykernel"]
nbconvert = ["nbconvert"]
nbformat = ["nbformat"]
notebook = ["ipywidgets", "notebook"]
parallel = ["ipyparallel"]
qtconsole = ["qtconsole"]
test = ["pytest (<7.1)", "pytest-asyncio", "testpath"]
test_extra = ["pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "trio"]

[[package]]
name = "ipython-genutils"
version = "0.2.0"
description = "Vestigial utilities from IPython"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "ipywidgets"
version = "7.7.1"
description = "IPython HTML widgets for Jupyter"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
ipykernel = ">=4.5.1"
ipython = {version = ">=4.0.0", markers = "python_version >= \"3.3\""}
ipython-genutils = ">=0.2.0,<0.3.0"
jupyterlab-widgets = {version = ">=1.0.0", markers = "python_version >= \"3.6\""}
traitlets = ">=4.3.1"
widgetsnbextension = ">=3.6.0,<3.7.0"

[package.extras]
test = ["pytest (>=3.6.0)", "pytest-cov", "mock"]

[[package]]
name = "isort"
version = "4.3.21"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[package.extras]
pipfile = ["pipreqs", "requirementslib"]
pyproject = ["toml"]
requirements = ["pipreqs", "pip-api"]
xdg_home = ["appdirs (>=1.4.0)"]

[[package]]
name = "itsdangerous"
version = "2.1.2"
description = "Safely pass data to untrusted environments and back."
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "jedi"
version = "0.18.1"
description = "An autocompletion tool for Python that can be used for text editors."
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
parso = ">=0.8.0,<0.9.0"

[package.extras]
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"]

[[package]]
name = "jinja2"
version = "3.1.2"
description = "A very fast and expressive template engine."
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
MarkupSafe = ">=2.0"

[package.extras]
i18n = ["Babel (>=2.7)"]

[[package]]
name = "joblib"
version = "1.1.0"
description = "Lightweight pipelining with Python functions"
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "jsonschema"
version = "4.9.0"
description = "An implementation of JSON Schema validation for Python"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
attrs = ">=17.4.0"
importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""}
pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""}
pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2"

[package.extras]
format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]

[[package]]
name = "jupyter-client"
version = "7.3.4"
description = "Jupyter protocol implementation and client libraries"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
entrypoints = "*"
jupyter-core = ">=4.9.2"
nest-asyncio = ">=1.5.4"
python-dateutil = ">=2.8.2"
pyzmq = ">=23.0"
tornado = ">=6.0"
traitlets = "*"

[package.extras]
doc = ["ipykernel", "myst-parser", "sphinx-rtd-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt"]
test = ["codecov", "coverage", "ipykernel (>=6.5)", "ipython", "mypy", "pre-commit", "pytest", "pytest-asyncio (>=0.18)", "pytest-cov", "pytest-timeout"]

[[package]]
name = "jupyter-core"
version = "4.11.1"
description = "Jupyter core package. A base package on which Jupyter projects rely."
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""}
traitlets = "*"

[package.extras]
test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"]

[[package]]
name = "jupyterlab-pygments"
version = "0.2.2"
description = "Pygments theme using JupyterLab CSS variables"
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "jupyterlab-widgets"
version = "1.1.1"
description = "A JupyterLab extension."
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "kiwisolver"
version = "1.4.4"
description = "A fast implementation of the Cassowary constraint solver"
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "latexcodec"
version = "2.0.1"
description = "A lexer and codec to work with LaTeX code in Python."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[package.dependencies]
six = ">=1.4.1"

[[package]]
name = "lazy-object-proxy"
version = "1.7.1"
description = "A fast and thorough lazy object proxy."
category = "dev"
optional = false
python-versions = ">=3.6"

[[package]]
name = "lmfit"
version = "1.0.3"
description = "Least-Squares Minimization with Bounds and Constraints"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
asteval = ">=0.9.22"
numpy = ">=1.18"
scipy = ">=1.4"
uncertainties = ">=3.0.1"

[[package]]
name = "markdown"
version = "3.4.1"
description = "Python implementation of Markdown."
category = "dev"
optional = false
python-versions = ">=3.7"

[package.dependencies]
importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}

[package.extras]
testing = ["coverage", "pyyaml"]

[[package]]
name = "markupsafe"
version = "2.1.1"
description = "Safely add untrusted strings to HTML/XML markup."
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "matplotlib"
version = "3.5.2"
description = "Python plotting package"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
cycler = ">=0.10"
fonttools = ">=4.22.0"
kiwisolver = ">=1.0.1"
numpy = ">=1.17"
packaging = ">=20.0"
pillow = ">=6.2.0"
pyparsing = ">=2.2.1"
python-dateutil = ">=2.7"
setuptools_scm = ">=4"

[[package]]
name = "matplotlib-inline"
version = "0.1.3"
description = "Inline Matplotlib backend for Jupyter"
category = "main"
optional = false
python-versions = ">=3.5"

[package.dependencies]
traitlets = "*"

[[package]]
name = "mccabe"
version = "0.6.1"
description = "McCabe checker, plugin for flake8"
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "mistune"
version = "0.8.4"
description = "The fastest markdown parser in pure Python"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "mpmath"
version = "1.2.1"
description = "Python library for arbitrary-precision floating-point arithmetic"
category = "main"
optional = false
python-versions = "*"

[package.extras]
develop = ["pytest (>=4.6)", "pycodestyle", "pytest-cov", "codecov", "wheel"]
tests = ["pytest (>=4.6)"]

[[package]]
name = "msal"
version = "1.18.0"
description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect."
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
cryptography = ">=0.6,<40"
PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]}
requests = ">=2.0.0,<3"

[[package]]
name = "msal-extensions"
version = "1.0.0"
description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism."
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
msal = ">=0.4.1,<2.0.0"
portalocker = [
    {version = ">=1.0,<3", markers = "python_version >= \"3.5\" and platform_system != \"Windows\""},
    {version = ">=1.6,<3", markers = "python_version >= \"3.5\" and platform_system == \"Windows\""},
]

[[package]]
name = "mypy-extensions"
version = "0.4.3"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "nbclient"
version = "0.6.6"
description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor."
category = "main"
optional = false
python-versions = ">=3.7.0"

[package.dependencies]
jupyter-client = ">=6.1.5"
nbformat = ">=5.0"
nest-asyncio = "*"
traitlets = ">=5.2.2"

[package.extras]
sphinx = ["autodoc-traits", "mock", "moto", "myst-parser", "Sphinx (>=1.7)", "sphinx-book-theme"]
test = ["black", "check-manifest", "flake8", "ipykernel", "ipython (<8.0.0)", "ipywidgets (<8.0.0)", "mypy", "pip (>=18.1)", "pre-commit", "pytest (>=4.1)", "pytest-asyncio", "pytest-cov (>=2.6.1)", "setuptools (>=60.0)", "testpath", "twine (>=1.11.0)", "xmltodict"]

[[package]]
name = "nbconvert"
version = "6.5.0"
description = "Converting Jupyter Notebooks"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
beautifulsoup4 = "*"
bleach = "*"
defusedxml = "*"
entrypoints = ">=0.2.2"
jinja2 = ">=3.0"
jupyter-core = ">=4.7"
jupyterlab-pygments = "*"
MarkupSafe = ">=2.0"
mistune = ">=0.8.1,<2"
nbclient = ">=0.5.0"
nbformat = ">=5.1"
packaging = "*"
pandocfilters = ">=1.4.1"
pygments = ">=2.4.1"
tinycss2 = "*"
traitlets = ">=5.0"

[package.extras]
all = ["pytest", "pytest-cov", "pytest-dependency", "ipykernel", "ipywidgets (>=7)", "pre-commit", "pyppeteer (>=1,<1.1)", "tornado (>=6.1)", "sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "ipython"]
docs = ["sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "ipython"]
serve = ["tornado (>=6.1)"]
test = ["pytest", "pytest-cov", "pytest-dependency", "ipykernel", "ipywidgets (>=7)", "pre-commit", "pyppeteer (>=1,<1.1)"]
webpdf = ["pyppeteer (>=1,<1.1)"]

[[package]]
name = "nbformat"
version = "5.4.0"
description = "The Jupyter Notebook format"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
fastjsonschema = "*"
jsonschema = ">=2.6"
jupyter-core = "*"
traitlets = ">=5.1"

[package.extras]
test = ["check-manifest", "testpath", "pytest", "pre-commit"]

[[package]]
name = "nest-asyncio"
version = "1.5.5"
description = "Patch asyncio to allow nested event loops"
category = "main"
optional = false
python-versions = ">=3.5"

[[package]]
name = "nodeenv"
version = "1.7.0"
description = "Node.js virtual environment builder"
category = "dev"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"

[[package]]
name = "notebook"
version = "6.4.12"
description = "A web-based notebook environment for interactive computing"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
argon2-cffi = "*"
ipykernel = "*"
ipython-genutils = "*"
jinja2 = "*"
jupyter-client = ">=5.3.4"
jupyter-core = ">=4.6.1"
nbconvert = ">=5"
nbformat = "*"
nest-asyncio = ">=1.5"
prometheus-client = "*"
pyzmq = ">=17"
Send2Trash = ">=1.8.0"
terminado = ">=0.8.3"
tornado = ">=6.1"
traitlets = ">=4.2.1"

[package.extras]
docs = ["sphinx", "nbsphinx", "sphinxcontrib-github-alt", "sphinx-rtd-theme", "myst-parser"]
json-logging = ["json-logging"]
test = ["pytest", "coverage", "requests", "testpath", "nbval", "selenium", "pytest-cov", "requests-unixsocket"]

[[package]]
name = "numpy"
version = "1.23.1"
description = "NumPy is the fundamental package for array computing with Python."
category = "main"
optional = false
python-versions = ">=3.8"

[[package]]
name = "opencensus"
version = "0.8.0"
description = "A stats collection and distributed tracing framework"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
google-api-core = {version = ">=1.0.0,<3.0.0", markers = "python_version >= \"3.6\""}
opencensus-context = "0.1.2"

[[package]]
name = "opencensus-context"
version = "0.1.2"
description = "OpenCensus Runtime Context"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "opencensus-ext-azure"
version = "1.1.4"
description = "OpenCensus Azure Monitor Exporter"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
azure-core = ">=1.12.0,<2.0.0"
azure-identity = ">=1.5.0,<2.0.0"
opencensus = ">=0.8.0,<1.0.0"
psutil = ">=5.6.3"
requests = ">=2.19.0"

[[package]]
name = "packaging"
version = "21.3"
description = "Core utilities for Python packages"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"

[[package]]
name = "pandas"
version = "1.4.3"
description = "Powerful data structures for data analysis, time series, and statistics"
category = "main"
optional = false
python-versions = ">=3.8"

[package.dependencies]
numpy = [
    {version = ">=1.18.5", markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and python_version < \"3.10\""},
    {version = ">=1.19.2", markers = "platform_machine == \"aarch64\" and python_version < \"3.10\""},
    {version = ">=1.20.0", markers = "platform_machine == \"arm64\" and python_version < \"3.10\""},
    {version = ">=1.21.0", markers = "python_version >= \"3.10\""},
]
python-dateutil = ">=2.8.1"
pytz = ">=2020.1"

[package.extras]
test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"]

[[package]]
name = "pandocfilters"
version = "1.5.0"
description = "Utilities for writing pandoc filters in python"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[[package]]
name = "parso"
version = "0.8.3"
description = "A Python Parser"
category = "main"
optional = false
python-versions = ">=3.6"

[package.extras]
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
testing = ["docopt", "pytest (<6.0.0)"]

[[package]]
name = "pastel"
version = "0.2.1"
description = "Bring colors to your terminal."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[[package]]
name = "pathspec"
version = "0.9.0"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"

[[package]]
name = "pexpect"
version = "4.8.0"
description = "Pexpect allows easy control of interactive console applications."
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
ptyprocess = ">=0.5"

[[package]]
name = "pickleshare"
version = "0.7.5"
description = "Tiny 'shelve'-like database with concurrency support"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "pillow"
version = "9.2.0"
description = "Python Imaging Library (Fork)"
category = "main"
optional = false
python-versions = ">=3.7"

[package.extras]
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"]
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]

[[package]]
name = "pint"
version = "0.19.2"
description = "Physical quantities module"
category = "main"
optional = false
python-versions = ">=3.8"

[package.extras]
numpy = ["numpy (>=1.19.5)"]
test = ["pytest", "pytest-mpl", "pytest-cov", "pytest-subtests"]
uncertainties = ["uncertainties (>=3.1.6)"]

[[package]]
name = "Pint-Pandas"
version = "0.3.dev56+gcf527e4"
description = "Physical quantities module"
category = "main"
optional = false
python-versions = ">=3.6"
develop = false

[package.dependencies]
pandas = ">=1.2"
pint = ">=0.17"

[package.extras]
test = ["pytest", "pytest-mpl", "pytest-cov", "pytest-subtests", "codecov", "coveralls", "nbval", "pyarrow"]

[package.source]
type = "git"
url = "https://github.com/hgrecco/pint-pandas.git"
reference = "master"
resolved_reference = "cf527e48557a1e028c6f2d4e628aa7a6cd1b30d4"

[[package]]
name = "pkgutil-resolve-name"
version = "1.3.10"
description = "Resolve a name to an object."
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "platformdirs"
version = "2.5.2"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"

[package.extras]
docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]

[[package]]
name = "plotly"
version = "5.9.0"
description = "An open-source, interactive data visualization library for Python"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
tenacity = ">=6.2.0"

[[package]]
name = "pluggy"
version = "1.0.0"
description = "plugin and hook calling mechanisms for python"
category = "dev"
optional = false
python-versions = ">=3.6"

[package.extras]
testing = ["pytest-benchmark", "pytest"]
dev = ["tox", "pre-commit"]

[[package]]
name = "poethepoet"
version = "0.16.0"
description = "A task runner that works well with poetry."
category = "dev"
optional = false
python-versions = ">=3.7"

[package.dependencies]
pastel = ">=0.2.1,<0.3.0"
tomli = ">=1.2.2"

[package.extras]
poetry_plugin = ["poetry (>=1.0,<2.0)"]

[[package]]
name = "portalocker"
version = "2.5.1"
description = "Wraps the portalocker recipe for easy usage"
category = "main"
optional = false
python-versions = ">=3.5"

[package.dependencies]
pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""}

[package.extras]
docs = ["sphinx (>=1.7.1)"]
redis = ["redis"]
tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-timeout (>=2.1.0)", "sphinx (>=3.0.3)", "pytest-mypy (>=0.8.0)", "redis"]

[[package]]
name = "pre-commit"
version = "2.20.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
category = "dev"
optional = false
python-versions = ">=3.7"

[package.dependencies]
cfgv = ">=2.0.0"
identify = ">=1.0.0"
nodeenv = ">=0.11.1"
pyyaml = ">=5.1"
toml = "*"
virtualenv = ">=20.0.8"

[[package]]
name = "prometheus-client"
version = "0.14.1"
description = "Python client for the Prometheus monitoring system."
category = "main"
optional = false
python-versions = ">=3.6"

[package.extras]
twisted = ["twisted"]

[[package]]
name = "prompt-toolkit"
version = "3.0.30"
description = "Library for building powerful interactive command lines in Python"
category = "main"
optional = false
python-versions = ">=3.6.2"

[package.dependencies]
wcwidth = "*"

[[package]]
name = "protobuf"
version = "4.21.4"
description = ""
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "psutil"
version = "5.9.1"
description = "Cross-platform lib for process and system monitoring in Python."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[package.extras]
test = ["ipaddress", "mock", "enum34", "pywin32", "wmi"]

[[package]]
name = "ptyprocess"
version = "0.7.0"
description = "Run a subprocess in a pseudo terminal"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "pure-eval"
version = "0.2.2"
description = "Safely evaluate AST nodes without side effects"
category = "main"
optional = false
python-versions = "*"

[package.extras]
tests = ["pytest"]

[[package]]
name = "py"
version = "1.11.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"

[[package]]
name = "pyasn1"
version = "0.4.8"
description = "ASN.1 types and codecs"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "pyasn1-modules"
version = "0.2.8"
description = "A collection of ASN.1-based protocols modules."
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
pyasn1 = ">=0.4.6,<0.5.0"

[[package]]
name = "pybtex"
version = "0.24.0"
description = "A BibTeX-compatible bibliography processor in Python"
category = "dev"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*"

[package.dependencies]
latexcodec = ">=1.0.4"
PyYAML = ">=3.01"
six = "*"

[package.extras]
test = ["pytest"]

[[package]]
name = "pybtex-docutils"
version = "1.0.2"
description = "A docutils backend for pybtex."
category = "dev"
optional = false
python-versions = ">=3.6"

[package.dependencies]
docutils = ">=0.8"
pybtex = ">=0.16"

[[package]]
name = "pycparser"
version = "2.21"
description = "C parser in Python"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[[package]]
name = "pygments"
version = "2.12.0"
description = "Pygments is a syntax highlighting package written in Python."
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "pyjwt"
version = "2.4.0"
description = "JSON Web Token implementation in Python"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
cryptography = {version = ">=3.3.1", optional = true, markers = "extra == \"crypto\""}

[package.extras]
crypto = ["cryptography (>=3.3.1)"]
dev = ["sphinx", "sphinx-rtd-theme", "zope.interface", "cryptography (>=3.3.1)", "pytest (>=6.0.0,<7.0.0)", "coverage[toml] (==5.0.4)", "mypy", "pre-commit"]
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
tests = ["pytest (>=6.0.0,<7.0.0)", "coverage[toml] (==5.0.4)"]

[[package]]
name = "pylint"
version = "2.12.2"
description = "python code static checker"
category = "dev"
optional = false
python-versions = ">=3.6.2"

[package.dependencies]
astroid = ">=2.9.0,<2.10"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
isort = ">=4.2.5,<6"
mccabe = ">=0.6,<0.7"
platformdirs = ">=2.2.0"
toml = ">=0.9.2"
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}

[[package]]
name = "pyparsing"
version = "3.0.9"
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
category = "main"
optional = false
python-versions = ">=3.6.8"

[package.extras]
diagrams = ["railroad-diagrams", "jinja2"]

[[package]]
name = "pyrsistent"
version = "0.18.1"
description = "Persistent/Functional/Immutable data structures"
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "pytest"
version = "7.1.2"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
python-versions = ">=3.7"

[package.dependencies]
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
py = ">=1.8.2"
tomli = ">=1.0.0"

[package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]

[[package]]
name = "pytest-cov"
version = "3.0.0"
description = "Pytest plugin for measuring coverage."
category = "dev"
optional = false
python-versions = ">=3.6"

[package.dependencies]
coverage = {version = ">=5.2.1", extras = ["toml"]}
pytest = ">=4.6"

[package.extras]
testing = ["virtualenv", "pytest-xdist", "six", "process-tests", "hunter", "fields"]

[[package]]
name = "python-dateutil"
version = "2.8.2"
description = "Extensions to the standard Python datetime module"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"

[package.dependencies]
six = ">=1.5"

[[package]]
name = "pytz"
version = "2022.1"
description = "World timezone definitions, modern and historical"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "pyvisa"
version = "1.11.3"
description = "Python VISA bindings for GPIB, RS232, TCPIP and USB instruments"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
typing-extensions = "*"

[[package]]
name = "pywin32"
version = "304"
description = "Python for Window Extensions"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "pywinpty"
version = "2.0.6"
description = "Pseudo terminal support for Windows from Python."
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "pyyaml"
version = "6.0"
description = "YAML parser and emitter for Python"
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "pyzmq"
version = "23.2.0"
description = "Python bindings for 0MQ"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
cffi = {version = "*", markers = "implementation_name == \"pypy\""}
py = {version = "*", markers = "implementation_name == \"pypy\""}

[[package]]
name = "qcodes"
version = "0.32.0"
description = "Python-based data acquisition framework developed by the Copenhagen / Delft / Sydney / Microsoft quantum computing consortium"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
broadbean = ">=0.9.1"
h5netcdf = ">=0.8.0"
h5py = ">=2.10.0"
ipywidgets = ">=7.5.0"
jsonschema = ">=3.0.0"
matplotlib = ">=3.3.0"
numpy = ">=1.17.0"
opencensus = ">=0.7.10,<0.9.0"
opencensus-ext-azure = ">=1.0.4,<2.0.0"
packaging = ">=20.0"
pandas = ">=1.0.0"
pyvisa = ">=1.11.0,<1.12.0"
"ruamel.yaml" = ">=0.16.0,<0.16.6 || >0.16.6"
tabulate = ">=0.8.0"
tqdm = ">=4.32.2"
typing-extensions = ">=3.10.0"
uncertainties = ">=3.1.4"
versioningit = ">=0.3.0"
websockets = ">=7.0"
wrapt = ">=1.10.4"
xarray = ">=0.18.0"

[package.extras]
qtplot = ["pyqtgraph (>=0.11.0)"]
slack = ["slack-sdk (>=3.4.2)"]
zurichinstruments = ["zhinst-qcodes (>=0.1.1)"]
test = ["pytest (>=6.0.0)", "PyVisa-sim (>=0.4.0)", "hypothesis (>=5.49.0)", "pytest-xdist (>=2.0.0)", "deepdiff (>=5.0.2)", "pytest-mock (>=3.0.0)", "pytest-rerunfailures (>=5.0.0)", "lxml (>=4.3.0)", "types-requests (>=0.1.8)", "types-setuptools (>=57.0.0)", "types-tabulate (>=0.1.0)", "Sphinx (>=4.1.2)"]

[[package]]
name = "qibo"
version = "0.1.8rc1.dev0"
description = "A framework for quantum computing with hardware acceleration."
category = "main"
optional = false
python-versions = ">=3.7.0"
develop = false

[package.dependencies]
cma = "*"
importlib-metadata = "*"
joblib = "*"
matplotlib = "*"
psutil = "*"
pyyaml = "*"
scipy = "*"
sympy = "*"
tabulate = "*"

[package.extras]
docs = ["sphinx", "sphinx-rtd-theme", "recommonmark", "sphinxcontrib-bibtex", "sphinx-markdown-tables", "nbsphinx", "ipython"]
tests = ["pytest", "cirq", "ply", "sklearn", "dill"]

[package.source]
type = "git"
url = "https://github.com/qiboteam/qibo.git"
reference = "master"
resolved_reference = "1af034218bb34871294aa7ac6d34b3694856444c"

[[package]]
name = "qibolab"
version = "0.0.1.dev4"
description = "Quantum hardware backend for Qibo"
category = "main"
optional = false
python-versions = ">=3.6.0"
develop = false

[package.dependencies]
lmfit = "*"
qcodes = "*"
qibo = ">=0.1.8rc0"

[package.extras]
docs = ["sphinx", "sphinx-rtd-theme", "recommonmark", "sphinxcontrib-bibtex", "sphinx-markdown-tables", "nbsphinx", "ipython"]
tiiq = ["qblox-instruments", "quantify-core", "dash"]

[package.source]
type = "git"
url = "git@github.com:qiboteam/qibolab.git"
reference = "main"
resolved_reference = "063d313f2746f6835daec499d1adae46c1bcee77"

[[package]]
name = "recommonmark"
version = "0.7.1"
description = "A docutils-compatibility bridge to CommonMark, enabling you to write CommonMark inside of Docutils & Sphinx projects."
category = "dev"
optional = false
python-versions = "*"

[package.dependencies]
commonmark = ">=0.8.1"
docutils = ">=0.11"
sphinx = ">=1.3.1"

[[package]]
name = "requests"
version = "2.27.1"
description = "Python HTTP for Humans."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"

[package.dependencies]
certifi = ">=2017.4.17"
charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
urllib3 = ">=1.21.1,<1.27"

[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]

[[package]]
name = "rsa"
version = "4.4"
description = "Pure-Python RSA implementation"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
pyasn1 = ">=0.1.3"

[[package]]
name = "ruamel.yaml"
version = "0.17.21"
description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
category = "main"
optional = false
python-versions = ">=3"

[package.dependencies]
"ruamel.yaml.clib" = {version = ">=0.2.6", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}

[package.extras]
docs = ["ryd"]
jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]

[[package]]
name = "ruamel.yaml.clib"
version = "0.2.6"
description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
category = "main"
optional = false
python-versions = ">=3.5"

[[package]]
name = "schema"
version = "0.7.5"
description = "Simple data validation library"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
contextlib2 = ">=0.5.5"

[[package]]
name = "scipy"
version = "1.6.1"
description = "SciPy: Scientific Library for Python"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
numpy = ">=1.16.5"

[[package]]
name = "send2trash"
version = "1.8.0"
description = "Send file to trash natively under Mac OS X, Windows and Linux."
category = "main"
optional = false
python-versions = "*"

[package.extras]
nativelib = ["pyobjc-framework-cocoa", "pywin32"]
objc = ["pyobjc-framework-cocoa"]
win32 = ["pywin32"]

[[package]]
name = "setuptools-scm"
version = "7.0.5"
description = "the blessed package to manage your versions by scm tags"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
packaging = ">=20.0"
tomli = ">=1.0.0"
typing-extensions = "*"

[package.extras]
test = ["pytest (>=6.2)", "virtualenv (>20)"]
toml = ["setuptools (>=42)"]

[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"

[[package]]
name = "snowballstemmer"
version = "2.2.0"
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "soupsieve"
version = "2.3.2.post1"
description = "A modern CSS selector implementation for Beautiful Soup."
category = "main"
optional = false
python-versions = ">=3.6"

[[package]]
name = "sphinx"
version = "4.5.0"
description = "Python documentation generator"
category = "dev"
optional = false
python-versions = ">=3.6"

[package.dependencies]
alabaster = ">=0.7,<0.8"
babel = ">=1.3"
colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""}
docutils = ">=0.14,<0.18"
imagesize = "*"
importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
Jinja2 = ">=2.3"
packaging = "*"
Pygments = ">=2.0"
requests = ">=2.5.0"
snowballstemmer = ">=1.1"
sphinxcontrib-applehelp = "*"
sphinxcontrib-devhelp = "*"
sphinxcontrib-htmlhelp = ">=2.0.0"
sphinxcontrib-jsmath = "*"
sphinxcontrib-qthelp = "*"
sphinxcontrib-serializinghtml = ">=1.1.5"

[package.extras]
docs = ["sphinxcontrib-websupport"]
lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "docutils-stubs", "types-typed-ast", "types-requests"]
test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"]

[[package]]
name = "sphinx-markdown-tables"
version = "0.0.17"
description = "A Sphinx extension for rendering tables written in markdown"
category = "dev"
optional = false
python-versions = "*"

[package.dependencies]
markdown = ">=3.4"

[[package]]
name = "sphinx-rtd-theme"
version = "1.0.0"
description = "Read the Docs theme for Sphinx"
category = "dev"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"

[package.dependencies]
docutils = "<0.18"
sphinx = ">=1.6"

[package.extras]
dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client"]

[[package]]
name = "sphinxcontrib-applehelp"
version = "1.0.2"
description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books"
category = "dev"
optional = false
python-versions = ">=3.5"

[package.extras]
test = ["pytest"]
lint = ["docutils-stubs", "mypy", "flake8"]

[[package]]
name = "sphinxcontrib-bibtex"
version = "2.4.2"
description = "Sphinx extension for BibTeX style citations."
category = "dev"
optional = false
python-versions = ">=3.6"

[package.dependencies]
docutils = ">=0.8"
pybtex = ">=0.24"
pybtex-docutils = ">=1.0.0"
Sphinx = ">=2.1"

[[package]]
name = "sphinxcontrib-devhelp"
version = "1.0.2"
description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document."
category = "dev"
optional = false
python-versions = ">=3.5"

[package.extras]
test = ["pytest"]
lint = ["docutils-stubs", "mypy", "flake8"]

[[package]]
name = "sphinxcontrib-htmlhelp"
version = "2.0.0"
description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
category = "dev"
optional = false
python-versions = ">=3.6"

[package.extras]
test = ["html5lib", "pytest"]
lint = ["docutils-stubs", "mypy", "flake8"]

[[package]]
name = "sphinxcontrib-jsmath"
version = "1.0.1"
description = "A sphinx extension which renders display math in HTML via JavaScript"
category = "dev"
optional = false
python-versions = ">=3.5"

[package.extras]
test = ["mypy", "flake8", "pytest"]

[[package]]
name = "sphinxcontrib-qthelp"
version = "1.0.3"
description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document."
category = "dev"
optional = false
python-versions = ">=3.5"

[package.extras]
test = ["pytest"]
lint = ["docutils-stubs", "mypy", "flake8"]

[[package]]
name = "sphinxcontrib-serializinghtml"
version = "1.1.5"
description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)."
category = "dev"
optional = false
python-versions = ">=3.5"

[package.extras]
lint = ["flake8", "mypy", "docutils-stubs"]
test = ["pytest"]

[[package]]
name = "stack-data"
version = "0.3.0"
description = "Extract data from python stack frames and tracebacks for informative displays"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
asttokens = "*"
executing = "*"
pure-eval = "*"

[package.extras]
tests = ["cython", "littleutils", "pygments", "typeguard", "pytest"]

[[package]]
name = "sympy"
version = "1.10.1"
description = "Computer algebra system (CAS) in Python"
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
mpmath = ">=0.19"

[[package]]
name = "tabulate"
version = "0.8.10"
description = "Pretty-print tabular data"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"

[package.extras]
widechars = ["wcwidth"]

[[package]]
name = "tenacity"
version = "8.0.1"
description = "Retry code until it succeeds"
category = "main"
optional = false
python-versions = ">=3.6"

[package.extras]
doc = ["reno", "sphinx", "tornado (>=4.5)"]

[[package]]
name = "terminado"
version = "0.15.0"
description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library."
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
ptyprocess = {version = "*", markers = "os_name != \"nt\""}
pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""}
tornado = ">=6.1.0"

[package.extras]
test = ["pre-commit", "pytest-timeout", "pytest (>=6.0)"]

[[package]]
name = "tinycss2"
version = "1.1.1"
description = "A tiny CSS parser"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
webencodings = ">=0.4"

[package.extras]
doc = ["sphinx", "sphinx-rtd-theme"]
test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"]

[[package]]
name = "toml"
version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"

[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "tornado"
version = "6.2"
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
category = "main"
optional = false
python-versions = ">= 3.7"

[[package]]
name = "tqdm"
version = "4.64.0"
description = "Fast, Extensible Progress Meter"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"

[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}

[package.extras]
dev = ["py-make (>=0.1.0)", "twine", "wheel"]
notebook = ["ipywidgets (>=6)"]
slack = ["slack-sdk"]
telegram = ["requests"]

[[package]]
name = "traitlets"
version = "5.3.0"
description = ""
category = "main"
optional = false
python-versions = ">=3.7"

[package.extras]
test = ["pre-commit", "pytest"]

[[package]]
name = "typing-extensions"
version = "4.3.0"
description = "Backported and Experimental Type Hints for Python 3.7+"
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "uncertainties"
version = "3.1.7"
description = "Transparent calculations with uncertainties on the quantities involved (aka error propagation); fast calculation of derivatives"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
future = "*"

[package.extras]
all = ["sphinx", "nose", "numpy"]
docs = ["sphinx"]
optional = ["numpy"]
tests = ["nose", "numpy"]

[[package]]
name = "urllib3"
version = "1.22"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
python-versions = "*"

[package.extras]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]

[[package]]
name = "versioningit"
version = "2.0.1"
description = "Versioning It with your Version In Git"
category = "main"
optional = false
python-versions = ">=3.6"

[package.dependencies]
importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""}
packaging = ">=17.1"
tomli = ">=1.2,<3.0"

[[package]]
name = "virtualenv"
version = "20.16.2"
description = "Virtual Python Environment builder"
category = "dev"
optional = false
python-versions = ">=3.6"

[package.dependencies]
distlib = ">=0.3.1,<1"
filelock = ">=3.2,<4"
platformdirs = ">=2,<3"

[package.extras]
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"]
testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "packaging (>=20.0)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)"]

[[package]]
name = "wcwidth"
version = "0.2.5"
description = "Measures the displayed width of unicode strings in a terminal"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "webencodings"
version = "0.5.1"
description = "Character encoding aliases for legacy web content"
category = "main"
optional = false
python-versions = "*"

[[package]]
name = "websockets"
version = "10.3"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
category = "main"
optional = false
python-versions = ">=3.7"

[[package]]
name = "werkzeug"
version = "2.2.1"
description = "The comprehensive WSGI web application library."
category = "main"
optional = false
python-versions = ">=3.7"

[package.dependencies]
MarkupSafe = ">=2.1.1"

[package.extras]
watchdog = ["watchdog"]

[[package]]
name = "widgetsnbextension"
version = "3.6.1"
description = "IPython HTML widgets for Jupyter"
category = "main"
optional = false
python-versions = "*"

[package.dependencies]
notebook = ">=4.4.1"

[[package]]
name = "wrapt"
version = "1.13.3"
description = "Module for decorators, wrappers and monkey patching."
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"

[[package]]
name = "xarray"
version = "2022.6.0"
description = "N-D labeled arrays and datasets in Python"
category = "main"
optional = false
python-versions = ">=3.8"

[package.dependencies]
numpy = ">=1.19"
packaging = ">=20.0"
pandas = ">=1.2"

[package.extras]
accel = ["scipy", "bottleneck", "numbagg", "flox"]
complete = ["netcdf4", "h5netcdf", "scipy", "pydap", "zarr", "fsspec", "cftime", "rasterio", "cfgrib", "pooch", "bottleneck", "numbagg", "flox", "dask", "matplotlib", "seaborn", "nc-time-axis"]
docs = ["netcdf4", "h5netcdf", "scipy", "pydap", "zarr", "fsspec", "cftime", "rasterio", "cfgrib", "pooch", "bottleneck", "numbagg", "flox", "dask", "matplotlib", "seaborn", "nc-time-axis", "sphinx-autosummary-accessors", "sphinx-rtd-theme", "ipython", "ipykernel", "jupyter-client", "nbsphinx", "scanpydoc"]
io = ["netcdf4", "h5netcdf", "scipy", "pydap", "zarr", "fsspec", "cftime", "rasterio", "cfgrib", "pooch"]
parallel = ["dask"]
viz = ["matplotlib", "seaborn", "nc-time-axis"]

[[package]]
name = "zipp"
version = "3.8.1"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "main"
optional = false
python-versions = ">=3.7"

[package.extras]
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]

[extras]
docs = []

[metadata]
lock-version = "1.1"
python-versions = ">=3.8"
content-hash = "709e36add02b33c72a9ed4f566acd570edd239c68ce9af102ca2efa902fd83ab"

[metadata.files]
alabaster = [
    {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
    {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
]
appnope = []
argon2-cffi = []
argon2-cffi-bindings = []
asteval = []
astroid = [
    {file = "astroid-2.9.3-py3-none-any.whl", hash = "sha256:506daabe5edffb7e696ad82483ad0228245a9742ed7d2d8c9cdb31537decf9f6"},
    {file = "astroid-2.9.3.tar.gz", hash = "sha256:1efdf4e867d4d8ba4a9f6cf9ce07cd182c4c41de77f23814feb27ca93ca9d877"},
]
asttokens = [
    {file = "asttokens-2.0.5-py2.py3-none-any.whl", hash = "sha256:0844691e88552595a6f4a4281a9f7f79b8dd45ca4ccea82e5e05b4bbdb76705c"},
    {file = "asttokens-2.0.5.tar.gz", hash = "sha256:9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"},
]
atomicwrites = [
    {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
]
attrs = [
    {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
    {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
]
azure-core = []
azure-identity = []
babel = [
    {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"},
    {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"},
]
backcall = []
beautifulsoup4 = []
black = []
bleach = []
broadbean = []
brotli = [
    {file = "Brotli-1.0.9-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:268fe94547ba25b58ebc724680609c8ee3e5a843202e9a381f6f9c5e8bdb5c70"},
    {file = "Brotli-1.0.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:c2415d9d082152460f2bd4e382a1e85aed233abc92db5a3880da2257dc7daf7b"},
    {file = "Brotli-1.0.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5913a1177fc36e30fcf6dc868ce23b0453952c78c04c266d3149b3d39e1410d6"},
    {file = "Brotli-1.0.9-cp27-cp27m-win32.whl", hash = "sha256:afde17ae04d90fbe53afb628f7f2d4ca022797aa093e809de5c3cf276f61bbfa"},
    {file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7cb81373984cc0e4682f31bc3d6be9026006d96eecd07ea49aafb06897746452"},
    {file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:db844eb158a87ccab83e868a762ea8024ae27337fc7ddcbfcddd157f841fdfe7"},
    {file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9744a863b489c79a73aba014df554b0e7a0fc44ef3f8a0ef2a52919c7d155031"},
    {file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a72661af47119a80d82fa583b554095308d6a4c356b2a554fdc2799bc19f2a43"},
    {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee83d3e3a024a9618e5be64648d6d11c37047ac48adff25f12fa4226cf23d1c"},
    {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:19598ecddd8a212aedb1ffa15763dd52a388518c4550e615aed88dc3753c0f0c"},
    {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:44bb8ff420c1d19d91d79d8c3574b8954288bdff0273bf788954064d260d7ab0"},
    {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e23281b9a08ec338469268f98f194658abfb13658ee98e2b7f85ee9dd06caa91"},
    {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3496fc835370da351d37cada4cf744039616a6db7d13c430035e901443a34daa"},
    {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83bb06a0192cccf1eb8d0a28672a1b79c74c3a8a5f2619625aeb6f28b3a82bb"},
    {file = "Brotli-1.0.9-cp310-cp310-win32.whl", hash = "sha256:26d168aac4aaec9a4394221240e8a5436b5634adc3cd1cdf637f6645cecbf181"},
    {file = "Brotli-1.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:622a231b08899c864eb87e85f81c75e7b9ce05b001e59bbfbf43d4a71f5f32b2"},
    {file = "Brotli-1.0.9-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:c83aa123d56f2e060644427a882a36b3c12db93727ad7a7b9efd7d7f3e9cc2c4"},
    {file = "Brotli-1.0.9-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6b2ae9f5f67f89aade1fab0f7fd8f2832501311c363a21579d02defa844d9296"},
    {file = "Brotli-1.0.9-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:68715970f16b6e92c574c30747c95cf8cf62804569647386ff032195dc89a430"},
    {file = "Brotli-1.0.9-cp35-cp35m-win32.whl", hash = "sha256:defed7ea5f218a9f2336301e6fd379f55c655bea65ba2476346340a0ce6f74a1"},
    {file = "Brotli-1.0.9-cp35-cp35m-win_amd64.whl", hash = "sha256:88c63a1b55f352b02c6ffd24b15ead9fc0e8bf781dbe070213039324922a2eea"},
    {file = "Brotli-1.0.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:503fa6af7da9f4b5780bb7e4cbe0c639b010f12be85d02c99452825dd0feef3f"},
    {file = "Brotli-1.0.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:40d15c79f42e0a2c72892bf407979febd9cf91f36f495ffb333d1d04cebb34e4"},
    {file = "Brotli-1.0.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:93130612b837103e15ac3f9cbacb4613f9e348b58b3aad53721d92e57f96d46a"},
    {file = "Brotli-1.0.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87fdccbb6bb589095f413b1e05734ba492c962b4a45a13ff3408fa44ffe6479b"},
    {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:6d847b14f7ea89f6ad3c9e3901d1bc4835f6b390a9c71df999b0162d9bb1e20f"},
    {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:495ba7e49c2db22b046a53b469bbecea802efce200dffb69b93dd47397edc9b6"},
    {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:4688c1e42968ba52e57d8670ad2306fe92e0169c6f3af0089be75bbac0c64a3b"},
    {file = "Brotli-1.0.9-cp36-cp36m-win32.whl", hash = "sha256:61a7ee1f13ab913897dac7da44a73c6d44d48a4adff42a5701e3239791c96e14"},
    {file = "Brotli-1.0.9-cp36-cp36m-win_amd64.whl", hash = "sha256:1c48472a6ba3b113452355b9af0a60da5c2ae60477f8feda8346f8fd48e3e87c"},
    {file = "Brotli-1.0.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b78a24b5fd13c03ee2b7b86290ed20efdc95da75a3557cc06811764d5ad1126"},
    {file = "Brotli-1.0.9-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9d12cf2851759b8de8ca5fde36a59c08210a97ffca0eb94c532ce7b17c6a3d1d"},
    {file = "Brotli-1.0.9-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6c772d6c0a79ac0f414a9f8947cc407e119b8598de7621f39cacadae3cf57d12"},
    {file = "Brotli-1.0.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29d1d350178e5225397e28ea1b7aca3648fcbab546d20e7475805437bfb0a130"},
    {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7bbff90b63328013e1e8cb50650ae0b9bac54ffb4be6104378490193cd60f85a"},
    {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ec1947eabbaf8e0531e8e899fc1d9876c179fc518989461f5d24e2223395a9e3"},
    {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12effe280b8ebfd389022aa65114e30407540ccb89b177d3fbc9a4f177c4bd5d"},
    {file = "Brotli-1.0.9-cp37-cp37m-win32.whl", hash = "sha256:f909bbbc433048b499cb9db9e713b5d8d949e8c109a2a548502fb9aa8630f0b1"},
    {file = "Brotli-1.0.9-cp37-cp37m-win_amd64.whl", hash = "sha256:97f715cf371b16ac88b8c19da00029804e20e25f30d80203417255d239f228b5"},
    {file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e16eb9541f3dd1a3e92b89005e37b1257b157b7256df0e36bd7b33b50be73bcb"},
    {file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:160c78292e98d21e73a4cc7f76a234390e516afcd982fa17e1422f7c6a9ce9c8"},
    {file = "Brotli-1.0.9-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b663f1e02de5d0573610756398e44c130add0eb9a3fc912a09665332942a2efb"},
    {file = "Brotli-1.0.9-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5b6ef7d9f9c38292df3690fe3e302b5b530999fa90014853dcd0d6902fb59f26"},
    {file = "Brotli-1.0.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a674ac10e0a87b683f4fa2b6fa41090edfd686a6524bd8dedbd6138b309175c"},
    {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e2d9e1cbc1b25e22000328702b014227737756f4b5bf5c485ac1d8091ada078b"},
    {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b336c5e9cf03c7be40c47b5fd694c43c9f1358a80ba384a21969e0b4e66a9b17"},
    {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:85f7912459c67eaab2fb854ed2bc1cc25772b300545fe7ed2dc03954da638649"},
    {file = "Brotli-1.0.9-cp38-cp38-win32.whl", hash = "sha256:35a3edbe18e876e596553c4007a087f8bcfd538f19bc116917b3c7522fca0429"},
    {file = "Brotli-1.0.9-cp38-cp38-win_amd64.whl", hash = "sha256:269a5743a393c65db46a7bb982644c67ecba4b8d91b392403ad8a861ba6f495f"},
    {file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2aad0e0baa04517741c9bb5b07586c642302e5fb3e75319cb62087bd0995ab19"},
    {file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5cb1e18167792d7d21e21365d7650b72d5081ed476123ff7b8cac7f45189c0c7"},
    {file = "Brotli-1.0.9-cp39-cp39-manylinux1_i686.whl", hash = "sha256:16d528a45c2e1909c2798f27f7bf0a3feec1dc9e50948e738b961618e38b6a7b"},
    {file = "Brotli-1.0.9-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:56d027eace784738457437df7331965473f2c0da2c70e1a1f6fdbae5402e0389"},
    {file = "Brotli-1.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bf919756d25e4114ace16a8ce91eb340eb57a08e2c6950c3cebcbe3dff2a5e7"},
    {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e4c4e92c14a57c9bd4cb4be678c25369bf7a092d55fd0866f759e425b9660806"},
    {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e48f4234f2469ed012a98f4b7874e7f7e173c167bed4934912a29e03167cf6b1"},
    {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ed4c92a0665002ff8ea852353aeb60d9141eb04109e88928026d3c8a9e5433c"},
    {file = "Brotli-1.0.9-cp39-cp39-win32.whl", hash = "sha256:cfc391f4429ee0a9370aa93d812a52e1fee0f37a81861f4fdd1f4fb28e8547c3"},
    {file = "Brotli-1.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:854c33dad5ba0fbd6ab69185fec8dab89e13cda6b7d191ba111987df74f38761"},
    {file = "Brotli-1.0.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9749a124280a0ada4187a6cfd1ffd35c350fb3af79c706589d98e088c5044267"},
    {file = "Brotli-1.0.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:76ffebb907bec09ff511bb3acc077695e2c32bc2142819491579a695f77ffd4d"},
    {file = "Brotli-1.0.9.zip", hash = "sha256:4d1b810aa0ed773f81dceda2cc7b403d01057458730e309856356d4ef4188438"},
]
cachetools = []
certifi = []
cffi = []
cfgv = []
charset-normalizer = []
click = []
cma = []
colorama = []
commonmark = [
    {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
    {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
]
contextlib2 = []
coverage = [
    {file = "coverage-6.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e"},
    {file = "coverage-6.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c"},
    {file = "coverage-6.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8"},
    {file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39"},
    {file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0"},
    {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee"},
    {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d"},
    {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc"},
    {file = "coverage-6.4.2-cp310-cp310-win32.whl", hash = "sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386"},
    {file = "coverage-6.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0"},
    {file = "coverage-6.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46"},
    {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07"},
    {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039"},
    {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996"},
    {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f"},
    {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e"},
    {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083"},
    {file = "coverage-6.4.2-cp37-cp37m-win32.whl", hash = "sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7"},
    {file = "coverage-6.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120"},
    {file = "coverage-6.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452"},
    {file = "coverage-6.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32"},
    {file = "coverage-6.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae"},
    {file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8"},
    {file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1"},
    {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63"},
    {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933"},
    {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de"},
    {file = "coverage-6.4.2-cp38-cp38-win32.whl", hash = "sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783"},
    {file = "coverage-6.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6"},
    {file = "coverage-6.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f"},
    {file = "coverage-6.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f"},
    {file = "coverage-6.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe"},
    {file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29"},
    {file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55"},
    {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b"},
    {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978"},
    {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c"},
    {file = "coverage-6.4.2-cp39-cp39-win32.whl", hash = "sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd"},
    {file = "coverage-6.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf"},
    {file = "coverage-6.4.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97"},
    {file = "coverage-6.4.2.tar.gz", hash = "sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe"},
]
cryptography = []
cycler = []
dash = [
    {file = "dash-2.6.1-py3-none-any.whl", hash = "sha256:911c0d5ef017e3c2ff2e756a01fb9388f2a80ed6084a5beaac812fb436192f90"},
    {file = "dash-2.6.1.tar.gz", hash = "sha256:8c88375a7335419b685e336dad7fbee567e9a2fe1fcf15632b73747db3921643"},
]
dash-core-components = [
    {file = "dash_core_components-2.0.0-py3-none-any.whl", hash = "sha256:52b8e8cce13b18d0802ee3acbc5e888cb1248a04968f962d63d070400af2e346"},
    {file = "dash_core_components-2.0.0.tar.gz", hash = "sha256:c6733874af975e552f95a1398a16c2ee7df14ce43fa60bb3718a3c6e0b63ffee"},
]
dash-html-components = [
    {file = "dash_html_components-2.0.0-py3-none-any.whl", hash = "sha256:b42cc903713c9706af03b3f2548bda4be7307a7cf89b7d6eae3da872717d1b63"},
    {file = "dash_html_components-2.0.0.tar.gz", hash = "sha256:8703a601080f02619a6390998e0b3da4a5daabe97a1fd7a9cebc09d015f26e50"},
]
dash-table = [
    {file = "dash_table-5.0.0-py3-none-any.whl", hash = "sha256:19036fa352bb1c11baf38068ec62d172f0515f73ca3276c79dee49b95ddc16c9"},
    {file = "dash_table-5.0.0.tar.gz", hash = "sha256:18624d693d4c8ef2ddec99a6f167593437a7ea0bf153aa20f318c170c5bc7308"},
]
debugpy = []
decorator = []
defusedxml = []
distlib = [
    {file = "distlib-0.3.5-py2.py3-none-any.whl", hash = "sha256:b710088c59f06338ca514800ad795a132da19fda270e3ce4affc74abf955a26c"},
    {file = "distlib-0.3.5.tar.gz", hash = "sha256:a7f75737c70be3b25e2bee06288cec4e4c221de18455b2dd037fe2a795cab2fe"},
]
docutils = [
    {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"},
    {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"},
]
entrypoints = []
executing = [
    {file = "executing-0.9.1-py2.py3-none-any.whl", hash = "sha256:4ce4d6082d99361c0231fc31ac1a0f56979363cc6819de0b1410784f99e49105"},
    {file = "executing-0.9.1.tar.gz", hash = "sha256:ea278e2cf90cbbacd24f1080dd1f0ac25b71b2e21f50ab439b7ba45dd3195587"},
]
fastjsonschema = [
    {file = "fastjsonschema-2.16.1-py3-none-any.whl", hash = "sha256:2f7158c4de792555753d6c2277d6a2af2d406dfd97aeca21d17173561ede4fe6"},
    {file = "fastjsonschema-2.16.1.tar.gz", hash = "sha256:d6fa3ffbe719768d70e298b9fb847484e2bdfdb7241ed052b8d57a9294a8c334"},
]
filelock = []
flask = [
    {file = "Flask-2.2.0-py3-none-any.whl", hash = "sha256:10dc2bae7a9b6ab59111d6dbece2e08fb0015d2e88d296c40323cc0c7aac2c2e"},
    {file = "Flask-2.2.0.tar.gz", hash = "sha256:98b33b13ad76ee9c7a80d2f56a6c578780e55bf8281790c62d50d4b7fadec2b8"},
]
flask-compress = [
    {file = "Flask-Compress-1.12.tar.gz", hash = "sha256:e2159499f39d618a4d56ba0484e7b58b57956b9a2c6d3510f095f5bb14b7afc5"},
    {file = "Flask_Compress-1.12-py3-none-any.whl", hash = "sha256:9f4e40211755e86f85e5eb7d414856ef1e8751912caa78d62853169400335f0c"},
]
fonttools = []
future = []
google-api-core = []
google-auth = [
    {file = "google-auth-2.9.1.tar.gz", hash = "sha256:14292fa3429f2bb1e99862554cde1ee730d6840ebae067814d3d15d8549c0888"},
    {file = "google_auth-2.9.1-py2.py3-none-any.whl", hash = "sha256:5a7eed0cb0e3a83989fad0b59fe1329dfc8c479543039cd6fd1e01e9adf39475"},
]
googleapis-common-protos = [
    {file = "googleapis-common-protos-1.56.4.tar.gz", hash = "sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417"},
    {file = "googleapis_common_protos-1.56.4-py2.py3-none-any.whl", hash = "sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394"},
]
h5netcdf = [
    {file = "h5netcdf-1.0.2-py2.py3-none-any.whl", hash = "sha256:4a4c277e18a906ab66e78ae2d95d27de4eec3519b87871adfd137974265bc250"},
    {file = "h5netcdf-1.0.2.tar.gz", hash = "sha256:8808a1e095f0122b4fb408cc98c60adf399bd57fef48d1ca7cdf4cda1d0a6b4a"},
]
h5py = []
identify = [
    {file = "identify-2.5.2-py2.py3-none-any.whl", hash = "sha256:feaa9db2dc0ce333b453ce171c0cf1247bbfde2c55fc6bb785022d411a1b78b5"},
    {file = "identify-2.5.2.tar.gz", hash = "sha256:a3d4c096b384d50d5e6dc5bc8b9bc44f1f61cefebd750a7b3e9f939b53fb214d"},
]
idna = []
imagesize = [
    {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
    {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
]
importlib-metadata = []
importlib-resources = [
    {file = "importlib_resources-5.9.0-py3-none-any.whl", hash = "sha256:f78a8df21a79bcc30cfd400bdc38f314333de7c0fb619763f6b9dabab8268bb7"},
    {file = "importlib_resources-5.9.0.tar.gz", hash = "sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681"},
]
iniconfig = [
    {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
    {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
ipykernel = []
ipython = []
ipython-genutils = []
ipywidgets = []
isort = [
    {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"},
    {file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"},
]
itsdangerous = [
    {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"},
    {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"},
]
jedi = []
jinja2 = []
joblib = []
jsonschema = [
    {file = "jsonschema-4.9.0-py3-none-any.whl", hash = "sha256:5d0be0cd1b670438b71c3d3145b2abba1f9d197e3e91adc4c4bae4c0e114e252"},
    {file = "jsonschema-4.9.0.tar.gz", hash = "sha256:df10e65c8f3687a48e93d0d348ce0ce5f897b5a28e9bbcbbe8f7c7eaf019e850"},
]
jupyter-client = []
jupyter-core = []
jupyterlab-pygments = []
jupyterlab-widgets = []
kiwisolver = [
    {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"},
    {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"},
    {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"},
    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"},
    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"},
    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"},
    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"},
    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"},
    {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"},
    {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"},
    {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"},
    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"},
    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"},
    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"},
    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"},
    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"},
    {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"},
    {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"},
    {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"},
    {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"},
    {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"},
    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"},
    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"},
    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"},
    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"},
    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"},
    {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"},
    {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"},
    {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"},
    {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"},
    {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"},
    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"},
    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"},
    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"},
    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"},
    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"},
    {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"},
    {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"},
    {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"},
    {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"},
    {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"},
    {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"},
    {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"},
]
latexcodec = [
    {file = "latexcodec-2.0.1-py2.py3-none-any.whl", hash = "sha256:c277a193638dc7683c4c30f6684e3db728a06efb0dc9cf346db8bd0aa6c5d271"},
    {file = "latexcodec-2.0.1.tar.gz", hash = "sha256:2aa2551c373261cefe2ad3a8953a6d6533e68238d180eb4bb91d7964adb3fe9a"},
]
lazy-object-proxy = [
    {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"},
    {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"},
]
lmfit = []
markdown = [
    {file = "Markdown-3.4.1-py3-none-any.whl", hash = "sha256:08fb8465cffd03d10b9dd34a5c3fea908e20391a2a90b88d66362cb05beed186"},
    {file = "Markdown-3.4.1.tar.gz", hash = "sha256:3b809086bb6efad416156e00a0da66fe47618a5d6918dd688f53f40c8e4cfeff"},
]
markupsafe = []
matplotlib = []
matplotlib-inline = []
mccabe = [
    {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
    {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
mistune = []
mpmath = []
msal = []
msal-extensions = []
mypy-extensions = []
nbclient = []
nbconvert = []
nbformat = []
nest-asyncio = []
nodeenv = []
notebook = []
numpy = []
opencensus = []
opencensus-context = []
opencensus-ext-azure = []
packaging = []
pandas = []
pandocfilters = []
parso = []
pastel = [
    {file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"},
    {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"},
]
pathspec = []
pexpect = []
pickleshare = []
pillow = []
pint = [
    {file = "Pint-0.19.2.tar.gz", hash = "sha256:e1d4989ff510b378dad64f91711e7bdabe5ca78d75b06a18569ac454678c4baf"},
]
Pint-Pandas = []
pkgutil-resolve-name = [
    {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"},
    {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"},
]
platformdirs = []
plotly = [
    {file = "plotly-5.9.0-py2.py3-none-any.whl", hash = "sha256:9acf168915101caac82ed6da3390840c622d9d4e4a78cbe1260f52501efc3117"},
    {file = "plotly-5.9.0.tar.gz", hash = "sha256:b0536e72bbc0b3cf169ac1fd00759d77aae7bb12ae378cdc75c5dc362f5de576"},
]
pluggy = [
    {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
    {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
]
poethepoet = [
    {file = "poethepoet-0.16.0-py3-none-any.whl", hash = "sha256:87482ea8bba4e5db4abbd8e6360baee73b2ce0f3d5f5e99e81cdfa39d72d118f"},
    {file = "poethepoet-0.16.0.tar.gz", hash = "sha256:6455aec39f198be92dbf210a4416e1635119e967204c092b431c8b10024db1d1"},
]
portalocker = []
pre-commit = []
prometheus-client = []
prompt-toolkit = []
protobuf = [
    {file = "protobuf-4.21.4-cp310-abi3-win32.whl", hash = "sha256:e113f3d1629cebc911b107ce704f1a17d7e1589efef5c498e202bd47df223955"},
    {file = "protobuf-4.21.4-cp310-abi3-win_amd64.whl", hash = "sha256:cb50d93ef748671b7e2537658869e00aaa8175d717d8e73a23fcd58842883229"},
    {file = "protobuf-4.21.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:142ef5d73d6cd1bd8ab539d7d73c3722f31d33e64914e01bb91439cfcef11a9f"},
    {file = "protobuf-4.21.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:47b7cf3e542fd50a3a7c24d0da13451bc362a32c0a9b905714942ea8cf35fa11"},
    {file = "protobuf-4.21.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:adeccfbffbf4c9d1e77da86dc995d76c837d01387e412066cc803ad037000892"},
    {file = "protobuf-4.21.4-cp37-cp37m-win32.whl", hash = "sha256:5e47947fbfefd5a1bdc7c28eea1d197ea6dba5812789c2429667831a55ef71b7"},
    {file = "protobuf-4.21.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d9b0398ff68017015ec2a37fb0ab390363a654362b15ca2e4543d3c82587768f"},
    {file = "protobuf-4.21.4-cp38-cp38-win32.whl", hash = "sha256:2ea8c841cc6422aea07d0f4f71f0e5e6e130de9a4b6c31a53b9d2a41a75f2d54"},
    {file = "protobuf-4.21.4-cp38-cp38-win_amd64.whl", hash = "sha256:a8119c029c60cf29b7eea5a9f56648482388e874611243f41cd10aff0a0e5461"},
    {file = "protobuf-4.21.4-cp39-cp39-win32.whl", hash = "sha256:0275902f8292039d4a022319d3f86e8b231ac4c51d7be4cb797890fb78c16b85"},
    {file = "protobuf-4.21.4-cp39-cp39-win_amd64.whl", hash = "sha256:5b95c5f515334dd3a811762e3c588b469bf39d4ee7b7f47ac1e0c41dc73809f7"},
    {file = "protobuf-4.21.4-py2.py3-none-any.whl", hash = "sha256:fd62b6eda64e199b5da651d6be42af2aa8e30805961af1fc5f70292affca78e3"},
    {file = "protobuf-4.21.4-py3-none-any.whl", hash = "sha256:7e51f6244e53e936abadf624ab3a0f06dc106b27473997374fbb34e6b2eb1e60"},
    {file = "protobuf-4.21.4.tar.gz", hash = "sha256:5783dc0d6edae631145337fabb18503b4f77274f94cdd22a4b26b9fe5029e718"},
]
psutil = []
ptyprocess = []
pure-eval = [
    {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"},
    {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"},
]
py = []
pyasn1 = []
pyasn1-modules = []
pybtex = [
    {file = "pybtex-0.24.0-py2.py3-none-any.whl", hash = "sha256:e1e0c8c69998452fea90e9179aa2a98ab103f3eed894405b7264e517cc2fcc0f"},
    {file = "pybtex-0.24.0.tar.gz", hash = "sha256:818eae35b61733e5c007c3fcd2cfb75ed1bc8b4173c1f70b56cc4c0802d34755"},
]
pybtex-docutils = [
    {file = "pybtex-docutils-1.0.2.tar.gz", hash = "sha256:43aa353b6d498fd5ac30f0073a98e332d061d34fe619d3d50d1761f8fd4aa016"},
    {file = "pybtex_docutils-1.0.2-py3-none-any.whl", hash = "sha256:6f9e3c25a37bcaac8c4f69513272706ec6253bb708a93d8b4b173f43915ba239"},
]
pycparser = []
pygments = []
pyjwt = []
pylint = [
    {file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"},
    {file = "pylint-2.12.2.tar.gz", hash = "sha256:9d945a73640e1fec07ee34b42f5669b770c759acd536ec7b16d7e4b87a9c9ff9"},
]
pyparsing = []
pyrsistent = []
pytest = [
    {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"},
    {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"},
]
pytest-cov = [
    {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"},
    {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"},
]
python-dateutil = []
pytz = []
pyvisa = []
pywin32 = []
pywinpty = []
pyyaml = []
pyzmq = []
qcodes = []
qibo = []
qibolab = []
recommonmark = [
    {file = "recommonmark-0.7.1-py2.py3-none-any.whl", hash = "sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f"},
    {file = "recommonmark-0.7.1.tar.gz", hash = "sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67"},
]
requests = []
rsa = []
"ruamel.yaml" = []
"ruamel.yaml.clib" = []
schema = []
scipy = []
send2trash = []
setuptools-scm = []
six = []
snowballstemmer = [
    {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
    {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
]
soupsieve = []
sphinx = [
    {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"},
    {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"},
]
sphinx-markdown-tables = [
    {file = "sphinx-markdown-tables-0.0.17.tar.gz", hash = "sha256:6bc6d3d400eaccfeebd288446bc08dd83083367c58b85d40fe6c12d77ef592f1"},
    {file = "sphinx_markdown_tables-0.0.17-py3-none-any.whl", hash = "sha256:2bd0c30779653e4dd120300cbd9ca412c480738cc2241f6dea477a883f299e04"},
]
sphinx-rtd-theme = [
    {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"},
    {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"},
]
sphinxcontrib-applehelp = [
    {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"},
    {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"},
]
sphinxcontrib-bibtex = [
    {file = "sphinxcontrib-bibtex-2.4.2.tar.gz", hash = "sha256:65b023ee47f35f1f03ac4d71c824e67c624c7ecac1bb26e83623271a01f9da86"},
    {file = "sphinxcontrib_bibtex-2.4.2-py3-none-any.whl", hash = "sha256:608512afde6b732148cdc9123550bd560bf48e071d1fb7bb1bab4f4437ff04f4"},
]
sphinxcontrib-devhelp = [
    {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"},
    {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"},
]
sphinxcontrib-htmlhelp = [
    {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"},
    {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"},
]
sphinxcontrib-jsmath = [
    {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
    {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
]
sphinxcontrib-qthelp = [
    {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"},
    {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"},
]
sphinxcontrib-serializinghtml = [
    {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"},
    {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"},
]
stack-data = [
    {file = "stack_data-0.3.0-py3-none-any.whl", hash = "sha256:aa1d52d14d09c7a9a12bb740e6bdfffe0f5e8f4f9218d85e7c73a8c37f7ae38d"},
    {file = "stack_data-0.3.0.tar.gz", hash = "sha256:77bec1402dcd0987e9022326473fdbcc767304892a533ed8c29888dacb7dddbc"},
]
sympy = []
tabulate = []
tenacity = [
    {file = "tenacity-8.0.1-py3-none-any.whl", hash = "sha256:f78f4ea81b0fabc06728c11dc2a8c01277bfc5181b321a4770471902e3eb844a"},
    {file = "tenacity-8.0.1.tar.gz", hash = "sha256:43242a20e3e73291a28bcbcacfd6e000b02d3857a9a9fff56b297a27afdc932f"},
]
terminado = []
tinycss2 = []
toml = []
tomli = []
tornado = []
tqdm = []
traitlets = []
typing-extensions = []
uncertainties = []
urllib3 = []
versioningit = [
    {file = "versioningit-2.0.1-py3-none-any.whl", hash = "sha256:cff3426d9154013df7eb34c0a48c12868a0e1f616d5ac10b11159e98e62eddf7"},
    {file = "versioningit-2.0.1.tar.gz", hash = "sha256:8097e260d9bdf676585bd8133bf7b5fffac37a8c76296255b42d86cb512ab2e3"},
]
virtualenv = [
    {file = "virtualenv-20.16.2-py2.py3-none-any.whl", hash = "sha256:635b272a8e2f77cb051946f46c60a54ace3cb5e25568228bd6b57fc70eca9ff3"},
    {file = "virtualenv-20.16.2.tar.gz", hash = "sha256:0ef5be6d07181946891f5abc8047fda8bc2f0b4b9bf222c64e6e8963baee76db"},
]
wcwidth = []
webencodings = []
websockets = []
werkzeug = [
    {file = "Werkzeug-2.2.1-py3-none-any.whl", hash = "sha256:7e1db6a5ba6b9a8be061e47e900456355b8714c0f238b0313f53afce1a55a79a"},
    {file = "Werkzeug-2.2.1.tar.gz", hash = "sha256:4d7013ef96fd197d1cdeb03e066c6c5a491ccb44758a5b2b91137319383e5a5a"},
]
widgetsnbextension = []
wrapt = [
    {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"},
    {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"},
    {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"},
    {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"},
    {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"},
    {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"},
    {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"},
    {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"},
    {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"},
    {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"},
    {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"},
    {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"},
    {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"},
    {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"},
    {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"},
    {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"},
    {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"},
    {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"},
    {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"},
    {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"},
    {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"},
    {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"},
    {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"},
    {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"},
    {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"},
    {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"},
    {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"},
    {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"},
    {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"},
    {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"},
    {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"},
    {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"},
    {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"},
    {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"},
    {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"},
    {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"},
    {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"},
    {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"},
    {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"},
    {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"},
    {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"},
    {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"},
    {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"},
    {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"},
    {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"},
    {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"},
    {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"},
    {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"},
    {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"},
    {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"},
    {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"},
]
xarray = [
    {file = "xarray-2022.6.0-py3-none-any.whl", hash = "sha256:c052208afc3f261984049f28b962d64eb6741a7967898315642f5da85448b6b0"},
    {file = "xarray-2022.6.0.tar.gz", hash = "sha256:1028d198493f66bb15bd35dcfdd11defd831cbee3af6589fff16f41bddd67e84"},
]
zipp = []

README.md METASEP
# QCVV

This package provides Quantum Characterization Validation and Verification protocols using [Qibo](https://github.com/qiboteam/qibo) and [Qibolab](https://github.com/qiboteam/qibolab).

## Installation

The package can be installed by source:
```sh
git clone https://github.com/qiboteam/qcvv.git
cd qcvv
pip install .
```


### Developer instructions
For development make sure to install the package using [`poetry`](https://python-poetry.org/) and to install the pre-commit hooks:
```sh
git clone https://github.com/qiboteam/qcvv.git
cd qcvv
poetry install
pre-commit install
```

When installing QCVV poetry will also install [Qibolab](https://github.com/qiboteam/qibolab). Make sure to setup SSH authentication for your GitHub account
to avoid errors during installation. Here are the instructions on how to [generate](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) a new SSH key and to [add](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account) it to your GitHub account.

If you are looking to test new features in Qibolab make sure to reinstall Qibolab in the same environment where qcvv is installed.

```sh
git clone git@github.com:qiboteam/qibolab.git
cd qibolab
git checkout <your_branch>
pip install -e .[tiiq]
```



## Minimal working example
The command for executing calibration routines is the following:
```sh
qq <runcard>
```
where:
- `<runcard>`: yaml file containing the calibration routines to be performed. For more information see the documentation or the runcard examples in the `runcards` folder.

### Uploading reports to server

In order to upload the report to a centralized server, send to the server administrators your public ssh key (from the machine(s) you are planning to upload the report) and then use the `qq-upload <output_folder>` command. This program will upload your report to the server and generate an unique URL.

src/qcvv/web/server.py METASEP
# -*- coding: utf-8 -*-
import os
import pathlib

import yaml
from flask import Flask, render_template

from qcvv import __version__
from qcvv.cli.builders import ReportBuilder

server = Flask(__name__)


@server.route("/")
@server.route("/data/<path>")
def page(path=None):
    folders = [
        folder
        for folder in reversed(sorted(os.listdir(os.getcwd())))
        if os.path.isdir(folder) and "meta.yml" in os.listdir(folder)
    ]

    report = None
    if path is not None:
        try:
            report = ReportBuilder(path)
        except (FileNotFoundError, TypeError):
            pass

    return render_template(
        "template.html",
        version=__version__,
        folders=folders,
        report=report,
    )

src/qcvv/web/report.py METASEP
# -*- coding: utf-8 -*-
import os
import pathlib

from jinja2 import Environment, FileSystemLoader

from qcvv import __version__
from qcvv.cli.builders import ReportBuilder


def create_report(path):
    """Creates an HTML report for the data in the given path."""
    filepath = pathlib.Path(__file__)

    with open(os.path.join(filepath.with_name("static"), "styles.css"), "r") as file:
        css_styles = f"<style>\n{file.read()}\n</style>"

    report = ReportBuilder(path)
    env = Environment(loader=FileSystemLoader(filepath.with_name("templates")))
    template = env.get_template("template.html")

    html = template.render(
        is_static=True,
        css_styles=css_styles,
        version=__version__,
        report=report,
    )

    with open(os.path.join(path, "index.html"), "w") as file:
        file.write(html)

src/qcvv/web/app.py METASEP
# -*- coding: utf-8 -*-
import os

import pandas as pd
import yaml
from dash import Dash, Input, Output, dcc, html

from qcvv import plots
from qcvv.data import Dataset
from qcvv.web.server import server

Dataset()  # dummy dataset call to suppress ``pint[V]`` error

app = Dash(
    server=server,
    suppress_callback_exceptions=True,
)

app.layout = html.Div(
    [
        dcc.Location(id="url", refresh=False),
        dcc.Graph(id="graph", figure={}),
        dcc.Interval(
            id="interval",
            # TODO: Perhaps the user should be allowed to change the refresh rate
            interval=1000,
            n_intervals=0,
            disabled=False,
        ),
    ]
)


@app.callback(
    Output("graph", "figure"),
    Input("interval", "n_intervals"),
    Input("graph", "figure"),
    Input("url", "pathname"),
)
def get_graph(n, current_figure, url):
    method, folder, routine, qubit, format = url.split(os.sep)[2:]
    try:
        # data = Dataset.load_data(folder, routine, format, "precision_sweep")
        # with open(f"{folder}/platform.yml", "r") as f:
        #     nqubits = yaml.safe_load(f)["nqubits"]
        # if len(data) > 2:
        #     params, fit = resonator_spectroscopy_fit(folder, format, nqubits)
        # else:
        #     params, fit = None, None
        # return getattr(plots.resonator_spectroscopy, method)(data, params, fit)

        # # FIXME: Temporarily hardcode the plotting method to test
        # # multiple routines with different names in one folder
        # # should be changed to:
        # # return getattr(getattr(plots, routine), method)(data)

        return getattr(plots, method)(folder, routine, qubit, format)
    except (FileNotFoundError, pd.errors.EmptyDataError):
        return current_figure

src/qcvv/web/__init__.py METASEP

src/qcvv/tests/test_data.py METASEP
# -*- coding: utf-8 -*-
"""Some tests for the Dataset class"""
import tempfile

import numpy as np
import pytest
from pint import DimensionalityError, UndefinedUnitError

from qcvv.data import Dataset


def random_dataset(length):
    data = Dataset()
    for _ in range(length):
        msr, i, q, phase = np.random.rand(len(data.df.columns))
        data.add({"MSR[V]": msr, "i[V]": i, "q[V]": q, "phase[deg]": phase})
    return data


def test_data_initialization():
    """Test Dataset constructor"""
    data = Dataset()
    assert len(data.df.columns) == 4
    assert list(data.df.columns) == ["MSR", "i", "q", "phase"]

    data1 = Dataset(quantities={"attenuation": "dB"})
    assert len(data1.df.columns) == 5
    assert list(data1.df.columns) == ["attenuation", "MSR", "i", "q", "phase"]


def test_units():
    """Test units of measure in Dataset"""
    data = Dataset()
    assert data.df.MSR.values.units == "volt"

    data1 = Dataset(quantities={"frequency": "Hz"})
    assert data1.df.frequency.values.units == "hertz"

    with pytest.raises(UndefinedUnitError):
        data2 = Dataset(quantities={"fake_unit": "fake"})


def test_add():
    """Test add method of Dataset"""
    data = random_dataset(5)
    assert len(data) == 5

    data1 = Dataset(quantities={"attenuation": "dB"})
    msr, i, q, phase, att = np.random.rand(len(data1.df.columns))
    data1.add(
        {
            "MSR[V]": msr,
            "i[V]": i,
            "q[V]": q,
            "phase[deg]": phase,
            "attenuation[dB]": att,
        }
    )
    assert len(data1) == 1

    data1.add(
        {
            "MSR[V]": 0,
            "i[V]": 0.0,
            "q[V]": 0.0,
            "phase[deg]": 0,
            "attenuation[dB]": 1,
        }
    )
    assert len(data1) == 2

    data2 = Dataset()
    msr, i, q, phase = np.random.rand(len(data2.df.columns))
    with pytest.raises(DimensionalityError):
        data2.add({"MSR[dB]": msr, "i[V]": i, "q[V]": q, "phase[deg]": phase})

    with pytest.raises(UndefinedUnitError):
        data2.add({"MSR[test]": msr, "i[V]": i, "q[V]": q, "phase[deg]": phase})

src/qcvv/plots/scatters.py METASEP
# -*- coding: utf-8 -*-
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots

from qcvv.data import Data, Dataset
from qcvv.fitting.utils import lorenzian


def frequency_msr_phase__fast_precision(folder, routine, qubit, format):
    try:
        data_fast = Dataset.load_data(folder, routine, format, f"fast_sweep_q{qubit}")
    except:
        data_fast = Dataset(quantities={"frequency": "Hz"})
    try:
        data_precision = Dataset.load_data(
            folder, routine, format, f"precision_sweep_q{qubit}"
        )
    except:
        data_precision = Dataset(quantities={"frequency": "Hz"})
    try:
        data_fit = Data.load_data(folder, routine, format, f"fit_q{qubit}")
    except:
        data_fit = Data(
            quantities=[
                "fit_amplitude",
                "fit_center",
                "fit_sigma",
                "fit_offset",
                "label1",
                "label2",
            ]
        )

    fig = make_subplots(
        rows=1,
        cols=2,
        horizontal_spacing=0.1,
        vertical_spacing=0.1,
        subplot_titles=(
            "MSR (V)",
            "phase (rad)",
        ),
    )

    fig.add_trace(
        go.Scatter(
            x=data_fast.get_values("frequency", "GHz"),
            y=data_fast.get_values("MSR", "uV"),
            name="Fast",
        ),
        row=1,
        col=1,
    )
    fig.add_trace(
        go.Scatter(
            x=data_fast.get_values("frequency", "GHz"),
            y=data_fast.get_values("phase", "rad"),
            name="Fast",
        ),
        row=1,
        col=2,
    )
    fig.add_trace(
        go.Scatter(
            x=data_precision.get_values("frequency", "GHz"),
            y=data_precision.get_values("MSR", "uV"),
            name="Precision",
        ),
        row=1,
        col=1,
    )
    fig.add_trace(
        go.Scatter(
            x=data_precision.get_values("frequency", "GHz"),
            y=data_precision.get_values("phase", "rad"),
            name="Precision",
        ),
        row=1,
        col=2,
    )
    if len(data_fast) > 0 and len(data_fit) > 0:
        freqrange = np.linspace(
            min(data_fast.get_values("frequency", "GHz")),
            max(data_fast.get_values("frequency", "GHz")),
            20,
        )
        params = [i for i in list(data_fit.df.keys()) if "fit" not in i]
        fig.add_trace(
            go.Scatter(
                x=freqrange,
                y=lorenzian(
                    freqrange,
                    data_fit.df["fit_amplitude"][0],
                    data_fit.df["fit_center"][0],
                    data_fit.df["fit_sigma"][0],
                    data_fit.df["fit_offset"][0],
                ),
                name="Fit",
                line=go.scatter.Line(dash="dot"),
            ),
            row=1,
            col=1,
        )
        fig.add_annotation(
            dict(
                font=dict(color="black", size=12),
                x=0,
                y=-0.25,
                showarrow=False,
                text=f"The estimated {params[0]} is {data_fit.df[params[0]][0]:.1f} Hz.",
                textangle=0,
                xanchor="left",
                xref="paper",
                yref="paper",
            )
        )
        fig.add_annotation(
            dict(
                font=dict(color="black", size=12),
                x=0,
                y=-0.30,
                showarrow=False,
                text=f"The estimated {params[1]} is {data_fit.df[params[1]][0]:.3f} uV.",
                textangle=0,
                xanchor="left",
                xref="paper",
                yref="paper",
            )
        )
    fig.update_layout(
        showlegend=True,
        uirevision="0",  # ``uirevision`` allows zooming while live plotting
        xaxis_title="Frequency (GHz)",
        yaxis_title="MSR (uV)",
        xaxis2_title="Frequency (GHz)",
        yaxis2_title="Phase (rad)",
    )
    return fig


def frequency_attenuation_msr_phase__cut(folder, routine, qubit, format):
    data = Dataset.load_data(folder, routine, format, f"data_q{qubit}")
    plot1d_attenuation = 30  # attenuation value to use for 1D frequency vs MSR plot

    fig = go.Figure()
    # index data on a specific attenuation value
    smalldf = data.df[data.get_values("attenuation", "dB") == plot1d_attenuation].copy()
    # split multiple software averages to different datasets
    datasets = []
    while len(smalldf):
        datasets.append(smalldf.drop_duplicates("frequency"))
        smalldf.drop(datasets[-1].index, inplace=True)
        fig.add_trace(
            go.Scatter(
                x=datasets[-1]["frequency"].pint.to("GHz").pint.magnitude,
                y=datasets[-1]["MSR"].pint.to("V").pint.magnitude,
            ),
        )

    fig.update_layout(
        showlegend=False,
        uirevision="0",  # ``uirevision`` allows zooming while live plotting,
        xaxis_title="Frequency (GHz)",
        yaxis_title="MSR (V)",
    )
    return fig

src/qcvv/plots/heatmaps.py METASEP
# -*- coding: utf-8 -*-
import os.path

import plotly.graph_objects as go
from plotly.subplots import make_subplots

from qcvv.data import Dataset


def frequency_flux_msr_phase(folder, routine, qubit, format):
    data = Dataset.load_data(folder, routine, format, f"data_q{qubit}")
    fig = make_subplots(
        rows=1,
        cols=2,
        horizontal_spacing=0.1,
        vertical_spacing=0.1,
        subplot_titles=(
            "MSR (V)",
            "phase (rad)",
        ),
    )

    fig.add_trace(
        go.Heatmap(
            x=data.get_values("frequency", "GHz"),
            y=data.get_values("current", "A"),
            z=data.get_values("MSR", "V"),
            colorbar_x=0.45,
        ),
        row=1,
        col=1,
    )
    fig.add_trace(
        go.Heatmap(
            x=data.get_values("frequency", "GHz"),
            y=data.get_values("current", "A"),
            z=data.get_values("phase", "rad"),
            colorbar_x=1.0,
        ),
        row=1,
        col=2,
    )
    fig.update_layout(
        showlegend=False,
        uirevision="0",  # ``uirevision`` allows zooming while live plotting
        xaxis_title="Frequency (GHz)",
        yaxis_title="Current (A)",
        xaxis2_title="Frequency (GHz)",
        yaxis2_title="Current (A)",
    )
    return fig


def frequency_attenuation_msr_phase(folder, routine, qubit, format):
    data = Dataset.load_data(folder, routine, format, f"data_q{qubit}")
    fig = make_subplots(
        rows=1,
        cols=2,
        horizontal_spacing=0.1,
        vertical_spacing=0.1,
        subplot_titles=(
            "MSR (V)",
            "phase (rad)",
        ),
    )

    fig.add_trace(
        go.Heatmap(
            x=data.get_values("frequency", "GHz"),
            y=data.get_values("attenuation", "dB"),
            z=data.get_values("MSR", "V"),
            colorbar_x=0.45,
        ),
        row=1,
        col=1,
    )
    fig.add_trace(
        go.Heatmap(
            x=data.get_values("frequency", "GHz"),
            y=data.get_values("attenuation", "dB"),
            z=data.get_values("phase", "rad"),
            colorbar_x=1.0,
        ),
        row=1,
        col=2,
    )
    fig.update_layout(
        showlegend=False,
        uirevision="0",  # ``uirevision`` allows zooming while live plotting
        xaxis_title="Frequency (GHz)",
        yaxis_title="Attenuation (dB)",
        xaxis2_title="Frequency (GHz)",
        yaxis2_title="Attenuation (dB)",
    )
    return fig


def frequency_flux_msr_phase__matrix(folder, routine, qubit, format):
    fluxes = []
    for i in range(25):  # FIXME: 25 is hardcoded
        file = f"{folder}/data/{routine}/data_q{qubit}_f{i}.csv"
        if os.path.exists(file):
            fluxes += [i]

    if len(fluxes) < 1:
        nb = 1
    else:
        nb = len(fluxes)
    fig = make_subplots(
        rows=2,
        cols=nb,
        horizontal_spacing=0.1,
        vertical_spacing=0.1,
        x_title="Frequency (Hz)",
        y_title="Current (A)",
        shared_xaxes=True,
        shared_yaxes=True,
    )

    for j in fluxes:
        if j == fluxes[-1]:
            showscale = True
        else:
            showscale = False
        data = Dataset.load_data(folder, routine, format, f"data_q{qubit}_f{j}")
        fig.add_trace(
            go.Heatmap(
                x=data.get_values("frequency", "GHz"),
                y=data.get_values("current", "A"),
                z=data.get_values("MSR", "V"),
                showscale=showscale,
            ),
            row=1,
            col=j,
        )
        fig.add_trace(
            go.Heatmap(
                x=data.get_values("frequency", "GHz"),
                y=data.get_values("current", "A"),
                z=data.get_values("phase", "rad"),
                showscale=showscale,
            ),
            row=2,
            col=j,
        )
    fig.update_layout(
        showlegend=False,
        uirevision="0",  # ``uirevision`` allows zooming while live plotting
    )
    return fig

src/qcvv/plots/__init__.py METASEP
# -*- coding: utf-8 -*-
from qcvv.plots.heatmaps import *
from qcvv.plots.scatters import *

src/qcvv/fitting/utils.py METASEP
# -*- coding: utf-8 -*-
import re

import numpy as np


def lorenzian(frequency, amplitude, center, sigma, offset):
    # http://openafox.com/science/peak-function-derivations.html
    return (amplitude / np.pi) * (
        sigma / ((frequency - center) ** 2 + sigma**2)
    ) + offset


def parse(key):
    name = key.split("[")[0]
    unit = re.search(r"\[([A-Za-z0-9_]+)\]", key).group(1)
    return name, unit

src/qcvv/fitting/methods.py METASEP
# -*- coding: utf-8 -*-
"""Routine-specific method for post-processing data acquired."""
import lmfit
import numpy as np

from qcvv.config import log
from qcvv.data import Data
from qcvv.fitting.utils import lorenzian, parse


def lorentzian_fit(data, x, y, qubit, nqubits, labels):
    """Fitting routine for resonator spectroscopy"""

    data_fit = Data(
        name=f"fit_q{qubit}",
        quantities=[
            "fit_amplitude",
            "fit_center",
            "fit_sigma",
            "fit_offset",
            labels[1],
            labels[0],
        ],
    )

    frequencies = data.get_values(*parse(x))
    voltages = data.get_values(*parse(y))

    # Create a lmfit model for fitting equation defined in resonator_peak
    model_Q = lmfit.Model(lorenzian)

    # Guess parameters for Lorentzian max or min
    if (nqubits == 1 and labels[0] == "resonator_freq") or (
        nqubits != 1 and labels[0] == "qubit_freq"
    ):
        guess_center = frequencies[
            np.argmax(voltages)
        ]  # Argmax = Returns the indices of the maximum values along an axis.
        guess_offset = np.mean(
            voltages[np.abs(voltages - np.mean(voltages) < np.std(voltages))]
        )
        guess_sigma = abs(frequencies[np.argmin(voltages)] - guess_center)
        guess_amp = (np.max(voltages) - guess_offset) * guess_sigma * np.pi

    else:
        guess_center = frequencies[
            np.argmin(voltages)
        ]  # Argmin = Returns the indices of the minimum values along an axis.
        guess_offset = np.mean(
            voltages[np.abs(voltages - np.mean(voltages) < np.std(voltages))]
        )
        guess_sigma = abs(frequencies[np.argmax(voltages)] - guess_center)
        guess_amp = (np.min(voltages) - guess_offset) * guess_sigma * np.pi

    # Add guessed parameters to the model
    model_Q.set_param_hint("center", value=guess_center, vary=True)
    model_Q.set_param_hint("sigma", value=guess_sigma, vary=True)
    model_Q.set_param_hint("amplitude", value=guess_amp, vary=True)
    model_Q.set_param_hint("offset", value=guess_offset, vary=True)
    guess_parameters = model_Q.make_params()

    # fit the model with the data and guessed parameters
    try:
        fit_res = model_Q.fit(
            data=voltages, frequency=frequencies, params=guess_parameters
        )
    except:
        log.warning("The fitting was not successful")
        return data_fit

    # get the values for postprocessing and for legend.
    f0 = fit_res.best_values["center"]
    BW = fit_res.best_values["sigma"] * 2
    Q = abs(f0 / BW)
    peak_voltage = (
        fit_res.best_values["amplitude"] / (fit_res.best_values["sigma"] * np.pi)
        + fit_res.best_values["offset"]
    )

    freq = f0 * 1e6

    data_fit.add(
        {
            labels[1]: peak_voltage,
            labels[0]: freq,
            "fit_amplitude": fit_res.best_values["amplitude"],
            "fit_center": fit_res.best_values["center"],
            "fit_sigma": fit_res.best_values["sigma"],
            "fit_offset": fit_res.best_values["offset"],
        }
    )
    return data_fit

    # params = resonator_freq, peak_voltage

    # for keys in fit_res.best_values:
    #     fit_res.best_values[keys] = float(fit_res.best_values[keys])

    # with open(f"{folder}/data/resonator_spectroscopy/fit.yml", "w+") as file:
    #     yaml.dump(
    #         fit_res.best_values,
    #         file,
    #         sort_keys=False,
    #         indent=4,
    #         default_flow_style=None,
    #     )

    # return params, fit_res.best_values

src/qcvv/fitting/__init__.py METASEP

src/qcvv/cli/builders.py METASEP
# -*- coding: utf-8 -*-
import datetime
import inspect
import os
import shutil

import yaml

from qcvv import calibrations
from qcvv.config import log, raise_error
from qcvv.data import Data


def load_yaml(path):
    """Load yaml file from disk."""
    with open(path, "r") as file:
        data = yaml.safe_load(file)
    return data


class ActionBuilder:
    """Class for parsing and executing runcards.

    Args:
        runcard (path): path containing the runcard.
        folder (path): path for the output folder.
        force (bool): option to overwrite the output folder if it exists already.
    """

    def __init__(self, runcard, folder=None, force=False):
        path, self.folder = self._generate_output_folder(folder, force)
        self.runcard = load_yaml(runcard)
        platform_name = self.runcard["platform"]
        self._allocate_platform(platform_name)
        self.qubits = self.runcard["qubits"]
        self.format = self.runcard["format"]

        # Saving runcard
        self.save_runcards(path, runcard)
        self.save_meta(path, self.folder, platform_name)

    @staticmethod
    def _generate_output_folder(folder, force):
        """Static method for generating the output folder.

        Args:
            folder (path): path for the output folder. If None it will be created a folder automatically
            force (bool): option to overwrite the output folder if it exists already.
        """
        if folder is None:
            import getpass

            e = datetime.datetime.now()
            user = getpass.getuser().replace(".", "-")
            date = e.strftime("%Y-%m-%d")
            folder = f"{date}-{'000'}-{user}"
            num = 0
            while os.path.exists(folder):
                log.warning(f"Directory {folder} already exists.")
                num += 1
                folder = f"{date}-{str(num).rjust(3, '0')}-{user}"
                log.warning(f"Trying to create directory {folder}")
        elif os.path.exists(folder) and not force:
            raise_error(RuntimeError, f"Directory {folder} already exists.")
        elif os.path.exists(folder) and force:
            log.warning(f"Deleting previous directory {folder}.")
            shutil.rmtree(os.path.join(os.getcwd(), folder))

        path = os.path.join(os.getcwd(), folder)
        log.info(f"Creating directory {folder}.")
        os.makedirs(path)
        return path, folder

    def _allocate_platform(self, platform_name):
        """Allocate the platform using Qibolab."""
        from qibo.backends import construct_backend

        self.platform = construct_backend("qibolab", platform=platform_name).platform

    def save_runcards(self, path, runcard):
        """Save the output runcards."""
        from qibolab.paths import qibolab_folder

        platform_runcard = (
            qibolab_folder / "runcards" / f"{self.runcard['platform']}.yml"
        )
        shutil.copy(platform_runcard, f"{path}/platform.yml")
        shutil.copy(runcard, f"{path}/runcard.yml")

    def save_meta(self, path, folder, platform_name):
        import qibo
        import qibolab

        import qcvv

        e = datetime.datetime.now(datetime.timezone.utc)
        meta = {}
        meta["title"] = folder
        meta["platform"] = platform_name
        meta["date"] = e.strftime("%Y-%m-%d")
        meta["start-time"] = e.strftime("%H:%M:%S")
        meta["end-time"] = e.strftime("%H:%M:%S")
        meta["versions"] = {
            "qibo": qibo.__version__,
            "qibolab": qibolab.__version__,
            "qcvv": qcvv.__version__,
        }
        with open(f"{path}/meta.yml", "w") as file:
            yaml.dump(meta, file)

    def _build_single_action(self, name):
        """Helper method to parse the actions in the runcard."""
        f = getattr(calibrations, name)
        path = os.path.join(self.folder, f"data/{name}/")
        os.makedirs(path)
        sig = inspect.signature(f)
        params = self.runcard["actions"][name]
        for param in list(sig.parameters)[2:-1]:
            if param not in params:
                raise_error(AttributeError, f"Missing parameter {param} in runcard.")
        return f, params, path

    def execute(self):
        """Method to execute sequentially all the actions in the runcard."""
        self.platform.connect()
        self.platform.setup()
        self.platform.start()
        for action in self.runcard["actions"]:
            routine, args, path = self._build_single_action(action)
            self._execute_single_action(routine, args, path)
        self.platform.stop()
        self.platform.disconnect()

    def _execute_single_action(self, routine, arguments, path):
        """Method to execute a single action and retrieving the results."""
        for qubit in self.qubits:
            results = routine(self.platform, qubit, **arguments)
            if self.format is None:
                raise_error(
                    ValueError, f"Cannot store data using {self.format} format."
                )
            for data in results:
                getattr(data, f"to_{self.format}")(path)

            self.update_platform_runcard(qubit, routine.__name__)

    def update_platform_runcard(self, qubit, routine):

        try:
            data_fit = Data.load_data(
                self.folder, routine, self.format, f"fit_q{qubit}"
            )
        except:
            data_fit = Data()

        params = [i for i in list(data_fit.df.keys()) if "fit" not in i]
        settings = load_yaml(f"{self.folder}/platform.yml")

        for param in params:
            settings["characterization"]["single_qubit"][qubit][param] = int(
                data_fit.df[param][0]
            )

        with open(f"{self.folder}/data/{routine}/platform.yml", "a+") as file:
            yaml.dump(
                settings, file, sort_keys=False, indent=4, default_flow_style=None
            )

    def dump_report(self):
        from qcvv.web.report import create_report

        # update end time
        meta = load_yaml(f"{self.folder}/meta.yml")
        e = datetime.datetime.now(datetime.timezone.utc)
        meta["end-time"] = e.strftime("%H:%M:%S")
        with open(f"{self.folder}/meta.yml", "w") as file:
            yaml.dump(meta, file)

        create_report(self.folder)


class ReportBuilder:
    """Parses routines and plots to report and live plotting page.

    Args:
        path (str): Path to the data folder to generate report for.
    """

    def __init__(self, path):
        self.path = path
        self.metadata = load_yaml(os.path.join(path, "meta.yml"))

        # find proper path title
        base, self.title = os.path.join(os.getcwd(), path), ""
        while self.title in ("", "."):
            base, self.title = os.path.split(base)

        self.runcard = load_yaml(os.path.join(path, "runcard.yml"))
        self.format = self.runcard.get("format")
        self.qubits = self.runcard.get("qubits")

        # create calibration routine objects
        # (could be incorporated to :meth:`qcvv.cli.builders.ActionBuilder._build_single_action`)
        self.routines = []
        for action in self.runcard.get("actions"):
            routine = getattr(calibrations, action)
            if not hasattr(routine, "plots"):
                routine.plots = []
            self.routines.append(routine)

    def get_routine_name(self, routine):
        """Prettify routine's name for report headers."""
        return routine.__name__.replace("_", " ").title()

    def get_figure(self, routine, method, qubit):
        """Get html figure for report.

        Args:
            routine (Callable): Calibration method.
            method (Callable): Plot method.
            qubit (int): Qubit id.
        """
        import tempfile

        figure = method(self.path, routine.__name__, qubit, self.format)
        with tempfile.NamedTemporaryFile() as temp:
            figure.write_html(temp.name, include_plotlyjs=False, full_html=False)
            fightml = temp.read().decode("utf-8")
        return fightml

    def get_live_figure(self, routine, method, qubit):
        """Get url to dash page for live plotting.

        This url is used by :meth:`qcvv.web.app.get_graph`.

        Args:
            routine (Callable): Calibration method.
            method (Callable): Plot method.
            qubit (int): Qubit id.
        """
        return os.path.join(
            method.__name__,
            self.path,
            routine.__name__,
            str(qubit),
            self.format,
        )

src/qcvv/cli/_base.py METASEP
# -*- coding: utf-8 -*-
"""Adds global CLI options."""
import base64
import pathlib
import shutil
import socket
import subprocess
import uuid
from urllib.parse import urljoin

import click
from qibo.config import log, raise_error

from qcvv.cli.builders import ActionBuilder

CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])

# options for report upload
UPLOAD_HOST = (
    "qcvv@localhost"
    if socket.gethostname() == "saadiyat"
    else "qcvv@login.qrccluster.com"
)
TARGET_DIR = "qcvv-reports/"
ROOT_URL = "http://login.qrccluster.com:9000/"


@click.command(context_settings=CONTEXT_SETTINGS)
@click.argument("runcard", metavar="RUNCARD", type=click.Path(exists=True))
@click.option(
    "folder",
    "-o",
    type=click.Path(),
    help="Output folder. If not provided a standard name will generated.",
)
@click.option(
    "force",
    "-f",
    is_flag=True,
    help="Use --force option to overwrite the output folder.",
)
def command(runcard, folder, force=None):

    """qcvv: Quantum Calibration Verification and Validation using Qibo.

    Arguments:

     - RUNCARD: runcard with declarative inputs.
    """

    action_builder = ActionBuilder(runcard, folder, force)
    action_builder.execute()
    action_builder.dump_report()


@click.command(context_settings=CONTEXT_SETTINGS)
@click.option(
    "port",
    "-p",
    "--port",
    default=8050,
    type=int,
    help="Localhost port to launch dash server.",
)
@click.option(
    "debug",
    "-d",
    "--debug",
    is_flag=True,
    help="Launch server in debugging mode.",
)
def live_plot(port, debug):
    """Real time plotting of calibration data on a dash server."""
    import socket

    from qcvv.web.app import app

    # change port if it is already used
    while True:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            if s.connect_ex(("localhost", port)) != 0:
                break
        port += 1

    app.run_server(debug=debug, port=port)


@click.command(context_settings=CONTEXT_SETTINGS)
@click.argument("output_folder", metavar="FOLDER", type=click.Path(exists=True))
def upload(output_folder):
    """Uploads output folder to server"""

    output_path = pathlib.Path(output_folder)

    # check the rsync command exists.
    if not shutil.which("rsync"):
        raise_error(
            RuntimeError,
            "Could not find the rsync command. Please make sure it is installed.",
        )

    # check that we can authentica with a certificate
    ssh_command_line = (
        "ssh",
        "-o",
        "PreferredAuthentications=publickey",
        "-q",
        UPLOAD_HOST,
        "exit",
    )

    str_line = " ".join(repr(ele) for ele in ssh_command_line)

    log.info(f"Checking SSH connection to {UPLOAD_HOST}.")

    try:
        subprocess.run(ssh_command_line, check=True)
    except subprocess.CalledProcessError as e:
        raise RuntimeError(
            (
                "Could not validate the SSH key. "
                "The command\n%s\nreturned a non zero exit status. "
                "Please make sure that your public SSH key is on the server."
            )
            % str_line
        ) from e
    except OSError as e:
        raise RuntimeError(
            "Could not run the command\n{}\n: {}".format(str_line, e)
        ) from e

    log.info("Connection seems OK.")

    # upload output
    randname = base64.urlsafe_b64encode(uuid.uuid4().bytes).decode()
    newdir = TARGET_DIR + randname

    rsync_command = (
        "rsync",
        "-aLz",
        "--chmod=ug=rwx,o=rx",
        f"{output_path}/",
        f"{UPLOAD_HOST}:{newdir}",
    )

    log.info(f"Uploading output ({output_path}) to {UPLOAD_HOST}")
    try:
        subprocess.run(rsync_command, check=True)
    except subprocess.CalledProcessError as e:
        msg = f"Failed to upload output: {e}"
        raise RuntimeError(msg) from e

    url = urljoin(ROOT_URL, randname)
    log.info(f"Upload completed. The result is available at:\n{url}")

src/qcvv/cli/__init__.py METASEP
# -*- coding: utf-8 -*-

"""CLI entry point."""
from ._base import command, live_plot, upload

src/qcvv/decorators.py METASEP
# -*- coding: utf-8 -*-
"""Decorators implementation."""
import os

from qcvv.config import raise_error


def plot(header, method):
    """Decorator for adding plots in the report and live plotting page.

    Args:
        header (str): Header of the plot to use in the report.
        method (Callable): Plotting method defined under ``qcvv.plots``.
    """

    def wrapped(f):
        if hasattr(f, "plots"):
            # insert in the beginning of the list to have
            # proper plot ordering in the report
            f.plots.insert(0, (header, method))
        else:
            f.plots = [(header, method)]
        return f

    return wrapped

src/qcvv/data.py METASEP
# -*- coding: utf-8 -*-
"""Implementation of Dataset class to store measurements."""

from abc import abstractmethod

import pandas as pd
import pint_pandas

from qcvv.config import raise_error


class AbstractDataset:
    def __init__(self, name=None):

        if name is None:
            self.name = "data"
        else:
            self.name = name

        self.df = pd.DataFrame()

    def __add__(self, data):
        self.df = pd.concat([self.df, data.df], ignore_index=True)
        return self

    @abstractmethod
    def add(self, data):
        raise_error(NotImplementedError)

    def __len__(self):
        """Computes the length of the dataset."""
        return len(self.df)

    @abstractmethod
    def load_data(cls, folder, routine, format, name):
        raise_error(NotImplementedError)

    @abstractmethod
    def to_csv(self, path):
        """Save data in csv file.

        Args:
            path (str): Path containing output folder."""
        if self.quantities == None:
            self.df.to_csv(f"{path}/{self.name}.csv")
        else:
            self.df.pint.dequantify().to_csv(f"{path}/{self.name}.csv")

    def to_pickle(self, path):
        """Save data in pickel file.

        Args:
            path (str): Path containing output folder."""
        self.df.to_pickle(f"{path}/{self.name}.pkl")


class Dataset(AbstractDataset):
    """Class to store the data measured during the calibration routines.
    It is a wrapper to a pandas DataFrame with units of measure from the Pint
    library.

    Args:
        quantities (dict): dictionary containing additional quantities that the user
                        may save other than the pulse sequence output. The keys are the name of the
                        quantities and the corresponding values are the units of measure.
    """

    def __init__(self, name=None, quantities=None):

        super().__init__(name=name)

        self.df = pd.DataFrame(
            {
                "MSR": pd.Series(dtype="pint[V]"),
                "i": pd.Series(dtype="pint[V]"),
                "q": pd.Series(dtype="pint[V]"),
                "phase": pd.Series(dtype="pint[deg]"),
            }
        )
        self.quantities = {"MSR": "V", "i": "V", "q": "V", "phase": "deg"}

        if quantities is not None:
            self.quantities.update(quantities)
            for name, unit in quantities.items():
                self.df.insert(0, name, pd.Series(dtype=f"pint[{unit}]"))

    def add(self, data):
        """Add a row to dataset.

        Args:
            data (dict): dictionary containing the data to be added.
                        Every key should have the following form:
                        ``<name>[<unit>]``.
        """
        import re

        from pint import UnitRegistry

        ureg = UnitRegistry()
        l = len(self)
        for key, value in data.items():
            name = key.split("[")[0]
            unit = re.search(r"\[([A-Za-z0-9_]+)\]", key).group(1)
            # TODO: find a better way to do this
            self.df.loc[l, name] = value * ureg(unit)

    def get_values(self, quantity, unit):
        """Get values of a quantity in specified units.

        Args:
            quantity (str): Quantity to get the values of.
            unit (str): Unit of the returned values.

        Returns:
            ``pd.Series`` with the quantity values in the given units.
        """
        return self.df[quantity].pint.to(unit).pint.magnitude

    @classmethod
    def load_data(cls, folder, routine, format, name):
        """Load data from specific format.

        Args:
            folder (path): path to the output folder from which the data will be loaded
            routine (str): calibration routine data to be loaded
            format (str): data format. Possible choices are 'csv' and 'pickle'.

        Returns:
            dataset (``Dataset``): dataset object with the loaded data.
        """
        obj = cls()
        if format == "csv":
            file = f"{folder}/data/{routine}/{name}.csv"
            obj.df = pd.read_csv(file, header=[0, 1])
            obj.df = obj.df.pint.quantify(level=-1)
            obj.df.pop("Unnamed: 0_level_0")
        elif format == "pickle":
            file = f"{folder}/data/{routine}/{name}.pkl"
            obj.df = pd.read_pickle(file)
        else:
            raise_error(ValueError, f"Cannot load data using {format} format.")

        return obj

    def to_csv(self, path):
        """Save data in csv file.

        Args:
            path (str): Path containing output folder."""
        self.df.pint.dequantify().to_csv(f"{path}/{self.name}.csv")


class Data(AbstractDataset):
    """Class to store the data obtained from calibration routines.
    It is a wrapper to a pandas DataFrame.

    Args:
        quantities (dict): dictionary quantities to be saved.
    """

    def __init__(self, name=None, quantities=None):

        super().__init__(name=name)

        if quantities is not None:
            self.quantities = quantities
            for name in quantities:
                self.df.insert(0, name, pd.Series(dtype=object))

    def add(self, data):
        """Add a row to dataset.

        Args:
            data (dict): dictionary containing the data to be added.
                        Every key should have the following form:
                        ``<name>[<unit>]``.
        """
        l = len(self)
        for key, value in data.items():
            self.df.loc[l, key] = value

    def get_values(self, quantity):
        """Get values of a quantity in specified units.

        Args:
            quantity (str): Quantity to get the values of.

        Returns:
            ``pd.Series`` with the quantity values in the given units.
        """
        return self.df[quantity]

    @classmethod
    def load_data(cls, folder, routine, format, name):
        """Load data from specific format.

        Args:
            folder (path): path to the output folder from which the data will be loaded
            routine (str): calibration routine data to be loaded
            format (str): data format. Possible choices are 'csv' and 'pickle'.

        Returns:
            dataset (``Dataset``): dataset object with the loaded data.
        """
        obj = cls()
        if format == "csv":
            file = f"{folder}/data/{routine}/{name}.csv"
            obj.df = pd.read_csv(file)
            obj.df.pop("Unnamed: 0")
        elif format == "pickle":
            file = f"{folder}/data/{routine}/{name}.pkl"
            obj.df = pd.read_pickle(file)
        else:
            raise_error(ValueError, f"Cannot load data using {format} format.")

        return obj

    def to_csv(self, path):
        """Save data in csv file.

        Args:
            path (str): Path containing output folder."""
        self.df.to_csv(f"{path}/{self.name}.csv")

    def to_pickle(self, path):
        """Save data in pickel file.

        Args:
            path (str): Path containing output folder."""
        self.df.to_pickle(f"{path}/{self.name}.pkl")

src/qcvv/config.py METASEP
# -*- coding: utf-8 -*-
"""Custom logger implemenation."""
import logging
import os

# Logging level from 0 (all) to 4 (errors) (see https://docs.python.org/3/library/logging.html#logging-levels)
QCVV_LOG_LEVEL = 1
if "QCVV_LOG_LEVEL" in os.environ:  # pragma: no cover
    QCVV_LOG_LEVEL = 10 * int(os.environ.get("QCVV_LOG_LEVEL"))


def raise_error(exception, message=None, args=None):
    """Raise exception with logging error.

    Args:
        exception (Exception): python exception.
        message (str): the error message.
    """
    log.error(message)
    if args:
        raise exception(message, args)
    else:
        raise exception(message)


# Configuration for logging mechanism
class CustomHandler(logging.StreamHandler):
    """Custom handler for logging algorithm."""

    def format(self, record):
        """Format the record with specific format."""
        from qcvv import __version__

        fmt = f"[Qcvv {__version__}|%(levelname)s|%(asctime)s]: %(message)s"
        return logging.Formatter(fmt, datefmt="%Y-%m-%d %H:%M:%S").format(record)


# allocate logger object
log = logging.getLogger(__name__)
log.setLevel(QCVV_LOG_LEVEL)
log.addHandler(CustomHandler())

src/qcvv/__init__.py METASEP
# -*- coding: utf-8 -*-
from .cli import command, live_plot, upload

"""qcvv: Quantum Calibration Verification and Validation using Qibo."""
import importlib.metadata as im

__version__ = im.version(__package__)

src/qcvv/calibrations/utils.py METASEP
# -*- coding: utf-8 -*-
import numpy as np


def variable_resolution_scanrange(
    lowres_width, lowres_step, highres_width, highres_step
):
    """Helper function for sweeps."""
    return np.concatenate(
        (
            np.arange(-lowres_width, -highres_width, lowres_step),
            np.arange(-highres_width, highres_width, highres_step),
            np.arange(highres_width, lowres_width, lowres_step),
        )
    )

src/qcvv/calibrations/resonator_spectroscopy.py METASEP
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.calibrations.utils import variable_resolution_scanrange
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import lorentzian_fit


@plot("MSR and Phase vs Frequency", plots.frequency_msr_phase__fast_precision)
def resonator_spectroscopy(
    platform: AbstractPlatform,
    qubit,
    lowres_width,
    lowres_step,
    highres_width,
    highres_step,
    precision_width,
    precision_step,
    software_averages,
    points=10,
):

    platform.reload_settings()
    sequence = PulseSequence()
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=0)
    sequence.add(ro_pulse)

    resonator_frequency = platform.characterization["single_qubit"][qubit][
        "resonator_freq"
    ]

    frequency_range = (
        variable_resolution_scanrange(
            lowres_width, lowres_step, highres_width, highres_step
        )
        + resonator_frequency
    )
    fast_sweep_data = Dataset(
        name=f"fast_sweep_q{qubit}", quantities={"frequency": "Hz"}
    )
    count = 0
    for _ in range(software_averages):
        for freq in frequency_range:
            if count % points == 0 and count > 0:
                yield fast_sweep_data
                yield lorentzian_fit(
                    fast_sweep_data,
                    x="frequency[GHz]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=["resonator_freq", "peak_voltage"],
                )

            platform.ro_port[qubit].lo_frequency = freq - ro_pulse.frequency
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "frequency[Hz]": freq,
            }
            fast_sweep_data.add(results)
            count += 1
    yield fast_sweep_data

    # FIXME: have live ploting work for multiple datasets saved

    if platform.resonator_type == "3D":
        resonator_frequency = fast_sweep_data.df.frequency[
            fast_sweep_data.df.MSR.index[fast_sweep_data.df.MSR.argmax()]
        ].magnitude
        avg_voltage = (
            np.mean(fast_sweep_data.df.MSR.values[: (lowres_width // lowres_step)])
            * 1e6
        )
    else:
        resonator_frequency = fast_sweep_data.df.frequency[
            fast_sweep_data.df.MSR.index[fast_sweep_data.df.MSR.argmin()]
        ].magnitude
        avg_voltage = (
            np.mean(fast_sweep_data.df.MSR.values[: (lowres_width // lowres_step)])
            * 1e6
        )

    precision_sweep__data = Dataset(
        name=f"precision_sweep_q{qubit}", quantities={"frequency": "Hz"}
    )
    freqrange = (
        np.arange(-precision_width, precision_width, precision_step)
        + resonator_frequency
    )

    count = 0
    for _ in range(software_averages):
        for freq in freqrange:
            if count % points == 0 and count > 0:
                yield precision_sweep__data
                yield lorentzian_fit(
                    fast_sweep_data + precision_sweep__data,
                    x="frequency[GHz]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=["resonator_freq", "peak_voltage"],
                )

            platform.ro_port[qubit].lo_frequency = freq - ro_pulse.frequency
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "frequency[Hz]": freq,
            }
            precision_sweep__data.add(results)
            count += 1
    yield precision_sweep__data


@plot("Frequency vs Attenuation", plots.frequency_attenuation_msr_phase)
@plot("MSR vs Frequency", plots.frequency_attenuation_msr_phase__cut)
def resonator_punchout(
    platform: AbstractPlatform,
    qubit,
    freq_width,
    freq_step,
    min_att,
    max_att,
    step_att,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"frequency": "Hz", "attenuation": "dB"}
    )
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=0)
    sequence = PulseSequence()
    sequence.add(ro_pulse)

    # TODO: move this explicit instruction to the platform
    resonator_frequency = platform.characterization["single_qubit"][qubit][
        "resonator_freq"
    ]
    frequency_range = (
        np.arange(-freq_width, freq_width, freq_step)
        + resonator_frequency
        - (freq_width / 4)
    )
    attenuation_range = np.flip(np.arange(min_att, max_att, step_att))
    count = 0
    for _ in range(software_averages):
        for att in attenuation_range:
            for freq in frequency_range:
                if count % points == 0:
                    yield data
                # TODO: move these explicit instructions to the platform
                platform.ro_port[qubit].lo_frequency = freq - ro_pulse.frequency
                platform.ro_port[qubit].attenuation = att
                msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                    ro_pulse.serial
                ]
                results = {
                    "MSR[V]": msr * (np.exp(att / 10)),
                    "i[V]": i,
                    "q[V]": q,
                    "phase[rad]": phase,
                    "frequency[Hz]": freq,
                    "attenuation[dB]": att,
                }
                # TODO: implement normalization
                data.add(results)
                count += 1

    yield data


@plot("MSR and Phase vs Flux Current", plots.frequency_flux_msr_phase)
def resonator_spectroscopy_flux(
    platform: AbstractPlatform,
    qubit,
    freq_width,
    freq_step,
    current_max,
    current_min,
    current_step,
    software_averages,
    fluxline=0,
    points=10,
):
    platform.reload_settings()

    if fluxline == "qubit":
        fluxline = qubit

    sequence = PulseSequence()
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=0)
    sequence.add(ro_pulse)

    data = Dataset(
        name=f"data_q{qubit}", quantities={"frequency": "Hz", "current": "A"}
    )

    resonator_frequency = platform.characterization["single_qubit"][qubit][
        "resonator_freq"
    ]
    qubit_biasing_current = platform.characterization["single_qubit"][qubit][
        "sweetspot"
    ]
    frequency_range = (
        np.arange(-freq_width, freq_width, freq_step) + resonator_frequency
    )
    current_range = (
        np.arange(current_min, current_max, current_step) + qubit_biasing_current
    )

    count = 0
    for _ in range(software_averages):
        for curr in current_range:
            for freq in frequency_range:
                if count % points == 0:
                    yield data
                platform.ro_port[qubit].lo_frequency = freq - ro_pulse.frequency
                platform.qf_port[fluxline].current = curr
                msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                    ro_pulse.serial
                ]
                results = {
                    "MSR[V]": msr,
                    "i[V]": i,
                    "q[V]": q,
                    "phase[rad]": phase,
                    "frequency[Hz]": freq,
                    "current[A]": curr,
                }
                # TODO: implement normalization
                data.add(results)
                count += 1

    yield data
    # TODO: automatically extract the sweet spot current
    # TODO: add a method to generate the matrix


@plot("MSR row 1 and Phase row 2", plots.frequency_flux_msr_phase__matrix)
def resonator_spectroscopy_flux_matrix(
    platform: AbstractPlatform,
    qubit,
    freq_width,
    freq_step,
    current_min,
    current_max,
    current_step,
    fluxlines,
    software_averages,
    points=10,
):
    platform.reload_settings()

    sequence = PulseSequence()
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=0)
    sequence.add(ro_pulse)

    resonator_frequency = platform.characterization["single_qubit"][qubit][
        "resonator_freq"
    ]

    frequency_range = (
        np.arange(-freq_width, freq_width, freq_step) + resonator_frequency
    )
    current_range = np.arange(current_min, current_max, current_step)

    count = 0
    for fluxline in fluxlines:
        fluxline = int(fluxline)
        print(fluxline)
        data = Dataset(
            name=f"data_q{qubit}_f{fluxline}",
            quantities={"frequency": "Hz", "current": "A"},
        )
        for _ in range(software_averages):
            for curr in current_range:
                for freq in frequency_range:
                    if count % points == 0:
                        yield data
                    platform.ro_port[qubit].lo_frequency = freq - ro_pulse.frequency
                    platform.qf_port[fluxline].current = curr
                    msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                        ro_pulse.serial
                    ]
                    results = {
                        "MSR[V]": msr,
                        "i[V]": i,
                        "q[V]": q,
                        "phase[rad]": phase,
                        "frequency[Hz]": freq,
                        "current[A]": curr,
                    }
                    # TODO: implement normalization
                    data.add(results)
                    count += 1

    yield data

src/qcvv/calibrations/qubit_spectroscopy.py METASEP
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import lorentzian_fit


@plot("MSR and Phase vs Frequency", plots.frequency_msr_phase__fast_precision)
def qubit_spectroscopy(
    platform: AbstractPlatform,
    qubit,
    fast_start,
    fast_end,
    fast_step,
    precision_start,
    precision_end,
    precision_step,
    software_averages,
    points=10,
):

    platform.reload_settings()

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=5000)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=5000)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qubit_frequency = platform.characterization["single_qubit"][qubit]["qubit_freq"]

    freqrange = np.arange(fast_start, fast_end, fast_step) + qubit_frequency

    data = Dataset(quantities={"frequency": "Hz", "attenuation": "dB"})

    # FIXME: Waiting for Qblox platform to take care of that
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )

    data = Dataset(name=f"fast_sweep_q{qubit}", quantities={"frequency": "Hz"})
    count = 0
    for _ in range(software_averages):
        for freq in freqrange:
            if count % points == 0 and count > 0:
                yield data
                yield lorentzian_fit(
                    data,
                    x="frequency[GHz]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=["qubit_freq", "peak_voltage"],
                )

            platform.qd_port[qubit].lo_frequency = freq - qd_pulse.frequency
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "frequency[Hz]": freq,
            }
            data.add(results)
            count += 1
    yield data

    if platform.resonator_type == "3D":
        qubit_frequency = data.df.frequency[
            data.df.MSR.index[data.df.MSR.argmin()]
        ].magnitude
        avg_voltage = (
            np.mean(data.df.MSR.values[: ((fast_end - fast_start) // fast_step)]) * 1e6
        )
    else:
        qubit_frequency = data.df.frequency[
            data.df.MSR.index[data.df.MSR.argmax()]
        ].magnitude
        avg_voltage = (
            np.mean(data.df.MSR.values[: ((fast_end - fast_start) // fast_step)]) * 1e6
        )

    prec_data = Dataset(
        name=f"precision_sweep_q{qubit}", quantities={"frequency": "Hz"}
    )
    freqrange = (
        np.arange(precision_start, precision_end, precision_step) + qubit_frequency
    )
    count = 0
    for _ in range(software_averages):
        for freq in freqrange:
            if count % points == 0 and count > 0:
                yield prec_data
                yield lorentzian_fit(
                    data + prec_data,
                    x="frequency[GHz]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=["qubit_freq", "peak_voltage"],
                )
            platform.qd_port[qubit].lo_frequency = freq - qd_pulse.frequency
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "frequency[Hz]": freq,
            }
            prec_data.add(results)
            count += 1
    yield prec_data
    # TODO: Estimate avg_voltage correctly


@plot("MSR and Phase vs Frequency", plots.frequency_flux_msr_phase)
def qubit_spectroscopy_flux(
    platform: AbstractPlatform,
    qubit,
    freq_width,
    freq_step,
    current_max,
    current_min,
    current_step,
    software_averages,
    fluxline,
    points=10,
):
    platform.reload_settings()

    if fluxline == "qubit":
        fluxline = qubit

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=5000)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=5000)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    data = Dataset(
        name=f"data_q{qubit}", quantities={"frequency": "Hz", "current": "A"}
    )

    qubit_frequency = platform.characterization["single_qubit"][qubit]["qubit_freq"]
    qubit_biasing_current = platform.characterization["single_qubit"][qubit][
        "sweetspot"
    ]
    frequency_range = np.arange(-freq_width, freq_width, freq_step) + qubit_frequency
    current_range = (
        np.arange(current_min, current_max, current_step) + qubit_biasing_current
    )

    count = 0
    for _ in range(software_averages):
        for curr in current_range:
            for freq in frequency_range:
                if count % points == 0:
                    yield data
                platform.qd_port[qubit].lo_frequency = freq - qd_pulse.frequency
                platform.qf_port[fluxline].current = curr
                msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                    ro_pulse.serial
                ]
                results = {
                    "MSR[V]": msr,
                    "i[V]": i,
                    "q[V]": q,
                    "phase[rad]": phase,
                    "frequency[Hz]": freq,
                    "current[A]": curr,
                }
                # TODO: implement normalization
                data.add(results)
                count += 1

    yield data

src/qcvv/calibrations/__init__.py METASEP
# -*- coding: utf-8 -*-
from qcvv.calibrations.qubit_spectroscopy import *
from qcvv.calibrations.resonator_spectroscopy import *

src/qcvv/calibrations/rabi_oscillations.py METASEP

# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"duration": "ns", "gain": "dimensionless"}
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )
    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            for gain in qd_pulse_gain_range:
                platform.qd_port[qubit].gain = gain
                if count % points == 0 and count > 0:
                    yield data
                msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                    ro_pulse.serial
                ]
                results = {
                    "MSR[V]": msr,
                    "i[V]": i,
                    "q[V]": q,
                    "phase[rad]": phase,
                    "duration[ns]": duration,
                    "gain[dimensionless]": gain,
                }
                data.add(results)
                count += 1

    yield data


inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"duration": "ns", "gain": "dimensionless"}
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )
    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            for gain in qd_pulse_gain_range:
                platform.qd_port[qubit].gain = gain
                if count % points == 0 and count > 0:
                    yield data
                msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                    ro_pulse.serial
                ]
                results = {
                    "MSR[V]": msr,
                    "i[V]": i,
                    "q[V]": q,
                    "phase[rad]": phase,
                    "duration[ns]": duration,
                    "gain[dimensionless]": gain,
                }
                data.add(results)
                count += 1

    yield data


@plot("MSR vs length and amplitude", plots.duration_amplitude_msr_phase)
def rabi_pulse_length_and_amplitude(
    platform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

inproject
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
common
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
common
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"duration": "ns", "gain": "dimensionless"}
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )
    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
common
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"duration": "ns", "gain": "dimensionless"}
    )

    sequence = PulseSequence()
common
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"duration": "ns", "gain": "dimensionless"}
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
common
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
common
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
non_informative
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"duration": "ns", "gain": "dimensionless"}
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )
    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            for gain in qd_pulse_gain_range:
                platform.qd_port[qubit].gain = gain
                if count % points == 0 and count > 0:
                    yield data
                msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                    ro_pulse.serial
                ]
                results = {
                    "MSR[V]": msr,
                    "i[V]": i,
                    "q[V]": q,
                    "phase[rad]": phase,
                    "duration[ns]": duration,
                    "gain[dimensionless]": gain,
                }
                data.add(results)
                count += 1

    yield data


@plot("MSR vs length and amplitude", plots.duration_amplitude_msr_phase)
def rabi_pulse_length_and_amplitude(
    platform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}",
        quantities={"duration": "ns", "amplitude": "dimensionless"},
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )
    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )
non_informative
# -*- coding: utf-8 -*-
import numpy as np
non_informative
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"duration": "ns", "gain": "dimensionless"}
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )
    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            for gain in qd_pulse_gain_range:
                platform.qd_port[qubit].gain = gain
                if count % points == 0 and count > 0:
                    yield data
                msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                    ro_pulse.serial
                ]
                results = {
                    "MSR[V]": msr,
                    "i[V]": i,
                    "q[V]": q,
                    "phase[rad]": phase,
                    "duration[ns]": duration,
                    "gain[dimensionless]": gain,
                }
                data.add(results)
                count += 1

    yield data


@plot("MSR vs length and amplitude", plots.duration_amplitude_msr_phase)
non_informative
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
random
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
random
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "gain[dimensionless]": gain,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Amplitude", plots.amplitude_msr_phase)
def rabi_pulse_amplitude(
    platform,
    qubit,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_amplitude_range = np.arange(
        pulse_amplitude_start, pulse_amplitude_end, pulse_amplitude_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for amplitude in qd_pulse_amplitude_range:
            qd_pulse.amplitude = amplitude
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="amplitude[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_amplitude",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "amplitude[dimensionless]": amplitude,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs length and gain", plots.duration_gain_msr_phase)
def rabi_pulse_length_and_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}", quantities={"duration": "ns", "gain": "dimensionless"}
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )
    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            for gain in qd_pulse_gain_range:
                platform.qd_port[qubit].gain = gain
                if count % points == 0 and count > 0:
                    yield data
                msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                    ro_pulse.serial
                ]
                results = {
                    "MSR[V]": msr,
                    "i[V]": i,
                    "q[V]": q,
                    "phase[rad]": phase,
                    "duration[ns]": duration,
                    "gain[dimensionless]": gain,
                }
                data.add(results)
                count += 1

    yield data


@plot("MSR vs length and amplitude", plots.duration_amplitude_msr_phase)
def rabi_pulse_length_and_amplitude(
    platform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    pulse_amplitude_start,
    pulse_amplitude_end,
    pulse_amplitude_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(
        name=f"data_q{qubit}",
        quantities={"duration": "ns", "amplitude": "dimensionless"},
    )

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
random
# -*- coding: utf-8 -*-
import numpy as np
from qibolab.platforms.abstract import AbstractPlatform
from qibolab.pulses import PulseSequence

from qcvv import plots
from qcvv.data import Dataset
from qcvv.decorators import plot
from qcvv.fitting.methods import rabi_fit


@plot("MSR vs Time", plots.time_msr_phase)
def rabi_pulse_length(
    platform: AbstractPlatform,
    qubit,
    pulse_duration_start,
    pulse_duration_end,
    pulse_duration_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})

    sequence = PulseSequence()
    qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_duration_range = np.arange(
        pulse_duration_start, pulse_duration_end, pulse_duration_step
    )

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for duration in qd_pulse_duration_range:
            qd_pulse.duration = duration
            ro_pulse.start = duration
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="Time[ns]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_duration",
                        "rabi_oscillations_pi_pulse_max_voltage",
                        "t1",
                    ],
                )
            msr, phase, i, q = platform.execute_pulse_sequence(sequence)[
                ro_pulse.serial
            ]
            results = {
                "MSR[V]": msr,
                "i[V]": i,
                "q[V]": q,
                "phase[rad]": phase,
                "Time[ns]": duration,
            }
            data.add(results)
            count += 1
    yield data


@plot("MSR vs Gain", plots.gain_msr_phase)
def rabi_pulse_gain(
    platform: AbstractPlatform,
    qubit,
    pulse_gain_start,
    pulse_gain_end,
    pulse_gain_step,
    software_averages,
    points=10,
):
    platform.reload_settings()

    data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})

    sequence = PulseSequence()
    qd_pulse = platform.create_RX_pulse(qubit, start=0)
    ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)
    sequence.add(qd_pulse)
    sequence.add(ro_pulse)

    qd_pulse_gain_range = np.arange(pulse_gain_start, pulse_gain_end, pulse_gain_step)

    # FIXME: Waiting to be able to pass qpucard to qibolab
    platform.ro_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["resonator_freq"]
        - ro_pulse.frequency
    )
    platform.qd_port[qubit].lo_frequency = (
        platform.characterization["single_qubit"][qubit]["qubit_freq"]
        - qd_pulse.frequency
    )

    count = 0
    for _ in range(software_averages):
        for gain in qd_pulse_gain_range:
            platform.qd_port[qubit].gain = gain
            if count % points == 0 and count > 0:
                yield data
                yield rabi_fit(
                    data,
                    x="gain[dimensionless]",
                    y="MSR[uV]",
                    qubit=qubit,
                    nqubits=platform.settings["nqubits"],
                    labels=[
                        "pi_pulse_gain",
random
@plot("MSR vs Time", plots.time_msr_phase)             data.add(results) @plot("MSR vs Amplitude", plots.amplitude_msr_phase) @plot("MSR vs length and amplitude", plots.duration_amplitude_msr_phase)     data = Dataset(name=f"data_q{qubit}", quantities={"Time": "ns"})     sequence.add(qd_pulse)     data = Dataset(name=f"data_q{qubit}", quantities={"amplitude": "dimensionless"})     sequence.add(ro_pulse)     data = Dataset( @plot("MSR vs Gain", plots.gain_msr_phase) @plot("MSR vs length and gain", plots.duration_gain_msr_phase)     data = Dataset(name=f"data_q{qubit}", quantities={"gain": "dimensionless"})     ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.duration)     qd_pulse = platform.create_RX_pulse(qubit, start=0)             ro_pulse.start = duration     qd_pulse = platform.create_qubit_drive_pulse(qubit, start=0, duration=4)     ro_pulse = platform.create_qubit_readout_pulse(qubit, start=4)     ro_pulse = platform.create_qubit_readout_pulse(qubit, start=qd_pulse.finish)     ) from qibolab.platforms.abstract import AbstractPlatform def rabi_pulse_length_and_amplitude(     pulse_duration_step,         - qd_pulse.frequency         pulse_duration_start, pulse_duration_end, pulse_duration_step                         "rabi_oscillations_pi_pulse_max_voltage",