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
@@ -1,134 +0,0 @@
1
- from decimal import ROUND_DOWN, Decimal
2
-
3
- import numpy as np
4
-
5
- from .const import EXP_UNIT_MAP, PARAM_METADATA
6
- from .read import read_json
7
-
8
-
9
- def _cut_to_significant_digits(number, n):
10
- """Cut a number to n significant digits."""
11
- if number == 0:
12
- return 0 # Zero has no significant digits
13
- d = Decimal(str(number))
14
- shift = d.adjusted() # Get the exponent of the number
15
- rounded = d.scaleb(-shift).quantize(
16
- Decimal("1e-{0}".format(n - 1)), rounding=ROUND_DOWN
17
- )
18
- return float(rounded.scaleb(shift))
19
-
20
-
21
- def format_number(
22
- num: float | np.ndarray, precision: int = 3, unit: str = "", latex: bool = True
23
- ) -> str:
24
- """Format a number (or an array of numbers) in a nice way for printing.
25
-
26
- Parameters
27
- ----------
28
- num : float | np.ndarray
29
- Input number (or array). Should not be rescaled,
30
- e.g. input values in Hz, NOT GHz
31
- precision : int
32
- The number of digits of the output number. Must be >= 3.
33
- unit : str, optional
34
- Unit of measurement, by default ''
35
- latex : bool, optional
36
- Include Latex syntax, by default True
37
-
38
- Returns
39
- -------
40
- str
41
- Formatted number
42
- """
43
- # Handle arrays
44
- if isinstance(num, (list, np.ndarray)):
45
- return [format_number(n, unit, latex) for n in num]
46
-
47
- # Return if not a number
48
- if not isinstance(num, (int, float, complex)):
49
- return num
50
-
51
- # Format number
52
- exp_form = f"{num:.12e}"
53
- base, exponent = exp_form.split("e")
54
- # Make exponent a multiple of 3
55
- base = float(base) * 10 ** (int(exponent) % 3)
56
- exponent = (int(exponent) // 3) * 3
57
- # Apply precision to the base
58
- if precision < 3:
59
- precision = 3
60
- base_precise = _cut_to_significant_digits(
61
- base, precision + 1
62
- ) # np.round(base, precision - (int(exponent) % 3))
63
- base_precise = np.round(
64
- base_precise, precision - len(str(base_precise).split(".")[0])
65
- )
66
- if int(base_precise) == float(base_precise):
67
- base_precise = int(base_precise)
68
-
69
- # Build string
70
- if unit:
71
- res = f"{base_precise}{'~' if latex else ' '}{EXP_UNIT_MAP[exponent]}{unit}"
72
- else:
73
- res = f"{base_precise}" + (f" x 10^{{{exponent}}}" if exponent != 0 else "")
74
- return f"${res}$" if latex else res
75
-
76
-
77
- def get_name_and_unit(param_id: str) -> str:
78
- """Get the name and unit of measurement of a prameter, e.g. Frequency [GHz].
79
-
80
- Parameters
81
- ----------
82
- param : str
83
- Parameter ID, as defined in the param_dict.json file.
84
-
85
- Returns
86
- -------
87
- str
88
- Name and [unit]
89
- """
90
- meta = PARAM_METADATA[param_id]
91
- scale = meta["scale"] if "scale" in meta else 1
92
- exponent = -(int(f"{scale:.0e}".split("e")[1]) // 3) * 3
93
- return f"{meta['name']} [{EXP_UNIT_MAP[exponent]}{meta['unit']}]"
94
-
95
-
96
- def get_x_id_by_plot_dim(exp_id: str, plot_dim: str, sweep_param: str | None) -> str:
97
- if exp_id == "CW_onetone":
98
- if plot_dim == "1":
99
- return sweep_param or "ro_freq"
100
- return "ro_freq"
101
-
102
-
103
- def build_title(title: str, path: str, params: list[str]) -> str:
104
- """Build a plot title that includes the values of given parameters found in
105
- the params_dict.json file, e.g. One tone with I = 0.5 mA.
106
-
107
- Parameters
108
- ----------
109
- title : str
110
- Title of the plot to which the parameters will be appended.
111
-
112
- path: str
113
- Path to the param_dict.json file.
114
-
115
- params : List[str]
116
- List of keys of parameters in the param_dict.json file.
117
-
118
- Returns
119
- -------
120
- str
121
- The original title followed by parameter values.
122
- """
123
- dic = read_json(f"{path}/param_dict.json")
124
- title += " with "
125
- for idx, param in enumerate(params):
126
- if not (param in PARAM_METADATA.keys()) or not (param in dic):
127
- title += f"{param} = ? & "
128
- continue
129
- meta = PARAM_METADATA[param]
130
- value = format_number(dic[param], meta["unit"])
131
- title += f"${meta['symbol']} =${value} & "
132
- if idx % 2 == 0 and idx != 0:
133
- title += "\n"
134
- return title[0:-3]
sqil_core/utils/read.py DELETED
@@ -1,156 +0,0 @@
1
- import json
2
- import os
3
-
4
- import h5py
5
- import numpy as np
6
-
7
- from .const import PARAM_METADATA
8
-
9
-
10
- def extract_h5_data(
11
- path: str, keys: list[str] | None = None
12
- ) -> dict | tuple[np.ndarray, ...]:
13
- """Extract data at the given keys from an HDF5 file. If no keys are
14
- given (None) returns the data field of the object.
15
-
16
- Parameters
17
- ----------
18
- path : str
19
- path to the HDF5 file or a folder in which is contained a data.ddh5 file
20
- keys : None or List, optional
21
- list of keys to extract from file['data'], by default None
22
-
23
- Returns
24
- -------
25
- Dict or Tuple[np.ndarray, ...]
26
- The full data dictionary if keys = None.
27
- The tuple with the requested keys otherwise.
28
-
29
- Example
30
- -------
31
- Extract the data object from the dataset:
32
- >>> data = extract_h5_data(path)
33
- Extracting only 'amp' and 'phase' from the dataset:
34
- >>> amp, phase = extract_h5_data(path, ['amp', 'phase'])
35
- Extracting only 'phase':
36
- >>> phase, = extract_h5_data(path, ['phase'])
37
- """
38
- # If the path is to a folder open /data.ddh5
39
- if os.path.isdir(path):
40
- path = os.path.join(path, "data.ddh5")
41
-
42
- with h5py.File(path, "r") as h5file:
43
- data = h5file["data"]
44
- data_keys = data.keys()
45
- # Extract only the requested keys
46
- if bool(keys) and (len(keys) > 0):
47
- res = []
48
- for key in keys:
49
- key = str(key)
50
- if (not bool(key)) | (key not in data_keys):
51
- res.append([])
52
- continue
53
- res.append(np.array(data[key][:]))
54
- return tuple(res)
55
- # Extract the whole data dictionary
56
- return _h5_to_dict(data)
57
-
58
-
59
- def _h5_to_dict(obj) -> dict:
60
- """Convert h5 data into a dictionary"""
61
- data_dict = {}
62
- for key in obj.keys():
63
- item = obj[key]
64
- if isinstance(item, h5py.Dataset):
65
- data_dict[key] = item[:]
66
- elif isinstance(item, h5py.Group):
67
- data_dict[key] = extract_h5_data(item)
68
- return data_dict
69
-
70
-
71
- def read_json(path: str) -> dict:
72
- """Reads a json file and returns the data as a dictionary."""
73
- with open(path) as f:
74
- dictionary = json.load(f)
75
- return dictionary
76
-
77
-
78
- class ParamInfo:
79
- """Parameter information for items of param_dict
80
-
81
- Attributes:
82
- id (str): param_dict key
83
- value (any): the value of the parameter
84
- name (str): full name of the parameter (e.g. Readout frequency)
85
- symbol (str): symbol of the parameter in Latex notation (e.g. f_{RO})
86
- unit (str): base unit of measurement (e.g. Hz)
87
- scale (int): the scale that should be generally applied to raw data (e.g. 1e-9 to take raw Hz to GHz)
88
- """
89
-
90
- def __init__(self, id, value):
91
- self.id = id
92
- self.value = value
93
- if id in PARAM_METADATA:
94
- meta = PARAM_METADATA[id]
95
- else:
96
- meta = {}
97
- self.name = meta["name"] if "name" in meta else id
98
- self.symbol = meta["symbol"] if "symbol" in meta else id
99
- self.unit = meta["unit"] if "unit" in meta else ""
100
- self.scale = meta["scale"] if "scale" in meta else 1
101
-
102
- def to_dict(self):
103
- """Convert ParamInfo to a dictionary."""
104
- return {
105
- "id": self.id,
106
- "value": self.value,
107
- "name": self.name,
108
- "symbol": self.symbol,
109
- "unit": self.unit,
110
- "scale": self.scale,
111
- }
112
-
113
- def __str__(self):
114
- """Return a JSON-formatted string of the object."""
115
- return json.dumps(self.to_dict())
116
-
117
- def __eq__(self, other):
118
- if isinstance(other, ParamInfo):
119
- return (self.id == other.id) & (self.value == other.value)
120
- if isinstance(other, (int, float, complex, str)):
121
- return self.value == other
122
- return False
123
-
124
-
125
- ParamDict = dict[str, ParamInfo | dict[str, ParamInfo]]
126
-
127
-
128
- def _enrich_param_dict(param_dict: dict) -> ParamDict:
129
- """Add metadata to param_dict entries."""
130
- res = {}
131
- for key, value in param_dict.items():
132
- if isinstance(value, dict):
133
- # Recursive step for nested dictionaries
134
- res[key] = _enrich_param_dict(value)
135
- else:
136
- res[key] = ParamInfo(key, value)
137
- return res
138
-
139
-
140
- def read_param_dict(path: str) -> ParamDict:
141
- """Read param_dict and include additional information for each entry.
142
-
143
- Parameters
144
- ----------
145
- path : str
146
- Path to the file or a folder in which is contained a param_dict.json file
147
-
148
- Returns
149
- -------
150
- ParamDict
151
- The param_dict with additional metadata
152
- """
153
- # If the path is to a folder open /param_dict.json
154
- if os.path.isdir(path):
155
- path = os.path.join(path, "param_dict.json")
156
- return _enrich_param_dict(read_json(path))
@@ -1,10 +0,0 @@
1
- sqil_core/__init__.py,sha256=JzMIz-0dEtF2rpf7ZBoIG4Ypd-0R4Xt87E8UKk6Was4,105
2
- sqil_core/utils/__init__.py,sha256=KzCQaJ11jGja82QXC7lHI1MYKi4Gxz_qwxCr8oTxK3k,156
3
- sqil_core/utils/analysis.py,sha256=CrtZ06KlNq-CcROoJiKgQWtUV9xnN3Ppv7QsUGFAY08,2106
4
- sqil_core/utils/const.py,sha256=gfZL9MOzAxJ0BeKMxIelVN3yY0dG-Px9W5fwGiZRYfw,953
5
- sqil_core/utils/formatter.py,sha256=VyYY2qGhWnt6TU3dOcwGpPUsNqMt-0TIZdzw3CnyCh4,4190
6
- sqil_core/utils/read.py,sha256=BSbv-audrnILJceCMOTr8KWsjza-4OypGBiV1FVY4yM,4963
7
- sqil_core-0.0.2.dist-info/METADATA,sha256=Zz1mChc4jhii-k8TLfS_oLlLTTDWyxUOLIh8w7_wp5s,2434
8
- sqil_core-0.0.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
9
- sqil_core-0.0.2.dist-info/entry_points.txt,sha256=2IYIJomhGZYKEZRBeCuH07ng82_2RzvrZOfhmBdhYxY,99
10
- sqil_core-0.0.2.dist-info/RECORD,,