sqil-core 0.0.2__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. sqil_core/__init__.py +6 -2
  2. sqil_core/config.py +13 -0
  3. sqil_core/config_log.py +42 -0
  4. sqil_core/experiment/__init__.py +11 -0
  5. sqil_core/experiment/_analysis.py +95 -0
  6. sqil_core/experiment/_events.py +25 -0
  7. sqil_core/experiment/_experiment.py +553 -0
  8. sqil_core/experiment/data/plottr.py +778 -0
  9. sqil_core/experiment/helpers/_function_override_handler.py +111 -0
  10. sqil_core/experiment/helpers/_labone_wrappers.py +12 -0
  11. sqil_core/experiment/instruments/__init__.py +2 -0
  12. sqil_core/experiment/instruments/_instrument.py +190 -0
  13. sqil_core/experiment/instruments/drivers/SignalCore_SC5511A.py +515 -0
  14. sqil_core/experiment/instruments/local_oscillator.py +205 -0
  15. sqil_core/experiment/instruments/server.py +175 -0
  16. sqil_core/experiment/instruments/setup.yaml +21 -0
  17. sqil_core/experiment/instruments/zurich_instruments.py +55 -0
  18. sqil_core/fit/__init__.py +38 -0
  19. sqil_core/fit/_core.py +1084 -0
  20. sqil_core/fit/_fit.py +1191 -0
  21. sqil_core/fit/_guess.py +232 -0
  22. sqil_core/fit/_models.py +127 -0
  23. sqil_core/fit/_quality.py +266 -0
  24. sqil_core/resonator/__init__.py +13 -0
  25. sqil_core/resonator/_resonator.py +989 -0
  26. sqil_core/utils/__init__.py +85 -5
  27. sqil_core/utils/_analysis.py +415 -0
  28. sqil_core/utils/_const.py +105 -0
  29. sqil_core/utils/_formatter.py +259 -0
  30. sqil_core/utils/_plot.py +373 -0
  31. sqil_core/utils/_read.py +262 -0
  32. sqil_core/utils/_utils.py +164 -0
  33. {sqil_core-0.0.2.dist-info → sqil_core-1.0.0.dist-info}/METADATA +40 -7
  34. sqil_core-1.0.0.dist-info/RECORD +36 -0
  35. {sqil_core-0.0.2.dist-info → sqil_core-1.0.0.dist-info}/WHEEL +1 -1
  36. {sqil_core-0.0.2.dist-info → sqil_core-1.0.0.dist-info}/entry_points.txt +1 -1
  37. sqil_core/utils/analysis.py +0 -68
  38. sqil_core/utils/const.py +0 -38
  39. sqil_core/utils/formatter.py +0 -134
  40. sqil_core/utils/read.py +0 -156
  41. sqil_core-0.0.2.dist-info/RECORD +0 -10
sqil_core/__init__.py CHANGED
@@ -1,3 +1,7 @@
1
- from .utils import extract_h5_data, read_param_dict
1
+ import sqil_core.experiment as experiment
2
+ import sqil_core.fit as fit
3
+ import sqil_core.resonator as resonator
4
+ import sqil_core.utils as utils
5
+ from sqil_core.utils import *
2
6
 
3
- __all__ = ["extract_h5_data", "read_param_dict"]
7
+ __all__ = utils.__all__ + ["utils", "fit", "resonator"]
sqil_core/config.py ADDED
@@ -0,0 +1,13 @@
1
+ _EXCLUDED_PACKAGES = [
2
+ "os",
3
+ "sys",
4
+ "inspect",
5
+ "np",
6
+ "spopt",
7
+ "lmfit",
8
+ "h5py",
9
+ "json",
10
+ "tabulate",
11
+ "matplotlib",
12
+ "plt",
13
+ ]
@@ -0,0 +1,42 @@
1
+ import logging
2
+
3
+ from colorama import Fore, Style, init
4
+
5
+ # Initialize Colorama
6
+ init(autoreset=True, strip=False, convert=False)
7
+
8
+
9
+ class SqilFormatter(logging.Formatter):
10
+ FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
11
+
12
+ COLOR_MAP = {
13
+ "DEBUG": Fore.BLUE,
14
+ "INFO": Fore.GREEN,
15
+ "WARNING": Fore.YELLOW,
16
+ "ERROR": Fore.RED,
17
+ "CRITICAL": Fore.RED + Style.BRIGHT,
18
+ }
19
+
20
+ def format(self, record):
21
+ log_color = self.COLOR_MAP.get(record.levelname, "")
22
+ record.levelname = f"{log_color}{record.levelname}{Style.RESET_ALL}"
23
+ return super().format(record)
24
+
25
+
26
+ class SqilLogger(logging.Logger):
27
+ # By default show the stack trace when errors are logged
28
+ def error(self, msg, *args, exc_info=True, **kwargs):
29
+ super().error(msg, *args, exc_info=exc_info, **kwargs)
30
+
31
+
32
+ logging.setLoggerClass(SqilLogger)
33
+ logger = logging.getLogger("sqil_logger")
34
+ logger.setLevel(logging.DEBUG)
35
+
36
+ console_handler = logging.StreamHandler()
37
+ console_handler.setLevel(logging.DEBUG)
38
+ console_handler.setFormatter(SqilFormatter(SqilFormatter.FORMAT))
39
+
40
+ # Avoid adding multiple handlers if the logger is reused
41
+ if not logger.hasHandlers():
42
+ logger.addHandler(console_handler)
@@ -0,0 +1,11 @@
1
+ from ._analysis import AnalysisResult
2
+ from ._events import after_experiment, before_experiment
3
+ from ._experiment import ExperimentHandler
4
+ from .instruments._instrument import Instrument
5
+ from .instruments.local_oscillator import LocalOscillator
6
+ from .instruments.server import (
7
+ InstrumentServer,
8
+ link_instrument_server,
9
+ start_instrument_server,
10
+ unlink_instrument_server,
11
+ )
@@ -0,0 +1,95 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING
6
+
7
+ import h5py
8
+ import mpld3
9
+ import numpy as np
10
+
11
+ from sqil_core.utils import get_measurement_id
12
+
13
+ if TYPE_CHECKING:
14
+ from matplotlib.figure import Figure
15
+
16
+ from sqil_core.fit import FitResult
17
+
18
+
19
+ class AnalysisResult:
20
+ updated_params: dict[str, dict] = {}
21
+ figures: dict[str, Figure] = {}
22
+ fits: dict[str, FitResult] = {}
23
+ extra_data: dict[str, np.ndarray] = {}
24
+
25
+ def __init__(
26
+ self,
27
+ updated_params: dict[str, dict] = {},
28
+ figures: dict[str, Figure] = {},
29
+ fits: dict[str, FitResult] = {},
30
+ extra_data: dict[str, np.ndarray] = {},
31
+ ):
32
+ self.updated_params = updated_params or {}
33
+ self.figures = figures or {}
34
+ self.fits = fits or {}
35
+ self.extra_data = extra_data or {}
36
+
37
+ def add_exp_info_to_figures(self, dir_path: str):
38
+ if not self.figures:
39
+ return
40
+ id = get_measurement_id(dir_path)
41
+ cooldown_name = Path(dir_path).parts[-3]
42
+ for _, fig in self.figures.items():
43
+ # Add dummy text to infer font size
44
+ dummy_text = fig.text(0, 0, "dummy", visible=False)
45
+ font_size = dummy_text.get_fontsize()
46
+ dummy_text.remove()
47
+ fig.text(
48
+ 0.98,
49
+ 0.98,
50
+ f"{cooldown_name}\n{id} | {dir_path[-16:]}",
51
+ ha="right",
52
+ va="top",
53
+ color="gray",
54
+ fontsize=font_size * 0.8,
55
+ )
56
+
57
+ def save_figures(self, dir_path: str):
58
+ """Saves figures both as png and interactive html."""
59
+ for key, fig in self.figures.items():
60
+ path = os.path.join(dir_path, key)
61
+ fig.savefig(os.path.join(f"{path}.png"), bbox_inches="tight", dpi=300)
62
+ html = mpld3.fig_to_html(fig)
63
+ with open(f"{path}.html", "w") as f:
64
+ f.write(html)
65
+
66
+ def aggregate_fit_summaries(self):
67
+ """Aggreate all the fit summaries and include model name."""
68
+ result = ""
69
+ for key, fit in self.fits.items():
70
+ summary = fit.summary(no_print=True)
71
+ result += f"{key}\nModel: {fit.model_name}\n{summary}\n"
72
+ return result
73
+
74
+ def save_fits(self, dir_path: str):
75
+ if not self.fits:
76
+ return
77
+ with open(os.path.join(dir_path, "fit.mono.md"), "w", encoding="utf-8") as f:
78
+ f.write(self.aggregate_fit_summaries())
79
+
80
+ def save_extra_data(self, dir_path: str):
81
+ if not self.extra_data:
82
+ return
83
+ with h5py.File(os.path.join(dir_path, "extra.ddh5"), "a") as f:
84
+ grp = f.require_group("data")
85
+ for key, array in self.extra_data.items():
86
+ # Overwrite if already exists
87
+ if key in grp:
88
+ del grp[key]
89
+ grp.create_dataset(key, data=array)
90
+
91
+ def save_all(self, dir_path: str):
92
+ self.add_exp_info_to_figures(dir_path)
93
+ self.save_figures(dir_path)
94
+ self.save_fits(dir_path)
95
+ self.save_extra_data(dir_path)
@@ -0,0 +1,25 @@
1
+ from blinker import NamedSignal
2
+
3
+ before_experiment = NamedSignal("before_experiment")
4
+ after_experiment = NamedSignal("after_experiment")
5
+
6
+ before_sequence = NamedSignal("before_sequence")
7
+ after_sequence = NamedSignal("after_sequence")
8
+
9
+
10
+ def clear_signal(signal):
11
+ """Removes all listeners (receivers) from an event (signal)."""
12
+ receivers = list(signal.receivers.values())
13
+ for receiver in receivers:
14
+ signal.disconnect(receiver)
15
+
16
+
17
+ def one_time_listener(signal, func):
18
+ """Listens for an event only once."""
19
+
20
+ def wrapper(*args, **kwargs):
21
+ signal.disconnect(wrapper)
22
+ return func(*args, **kwargs)
23
+
24
+ signal.connect(wrapper, weak=False)
25
+ return wrapper