opticalib 2.2.0__tar.gz → 2.3.1__tar.gz
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.
- {opticalib-2.2.0/opticalib.egg-info → opticalib-2.3.1}/PKG-INFO +6 -2
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/__version__.py +1 -1
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/analyzer/image_processing.py +27 -6
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/config.py +51 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/_API/alpaoAPI.py +2 -2
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/_API/base_devices.py +4 -2
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/_API/piAPI.py +12 -3
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/deformable_mirrors.py +7 -1
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/dmutils/_misc.py +14 -6
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/ground/osutils.py +11 -4
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/__init__.py +10 -1
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/app.py +191 -23
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/kernel.py +15 -3
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/kernel_side.py +88 -0
- opticalib-2.3.1/opticalib/gui/plugins.py +304 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/theme.py +10 -0
- opticalib-2.3.1/opticalib/gui/widgets/common.py +298 -0
- opticalib-2.3.1/opticalib/gui/widgets/connect_dialog.py +503 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/widgets/device_panel.py +128 -27
- opticalib-2.3.1/opticalib/gui/widgets/device_registry.py +1272 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/procedures/alignment.py +28 -16
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/procedures/phasing.py +4 -2
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/_API/base_fake_alpao.py +2 -7
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/_API/base_petalmirror.py +2 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/_API/base_simulated_dm.py +64 -47
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/_API/simdata.py +11 -8
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/fake_dms.py +4 -1
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/visualization.py +18 -9
- {opticalib-2.2.0 → opticalib-2.3.1/opticalib.egg-info}/PKG-INFO +6 -2
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib.egg-info/SOURCES.txt +1 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/pyproject.toml +5 -1
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_analyzer_images_processing.py +127 -5
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_core_read_config.py +62 -0
- opticalib-2.3.1/tests/test_gui_devices.py +923 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_gui_kernel_bridge.py +15 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_gui_kernel_side.py +63 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_gui_procedures.py +78 -1
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_gui_widgets.py +126 -0
- opticalib-2.3.1/tests/test_simulator_run_cmd_history.py +48 -0
- opticalib-2.2.0/opticalib/gui/plugins.py +0 -130
- opticalib-2.2.0/opticalib/gui/widgets/common.py +0 -144
- opticalib-2.2.0/opticalib/gui/widgets/connect_dialog.py +0 -262
- opticalib-2.2.0/opticalib/gui/widgets/device_registry.py +0 -735
- opticalib-2.2.0/tests/test_gui_devices.py +0 -448
- {opticalib-2.2.0 → opticalib-2.3.1}/CITATION.bib +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/LICENSE +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/MANIFEST.in +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/README.md +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/__init_script__/initCalpy.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/analyzer/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/analyzer/signals.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/analyzer/timeseries.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/_configurations/configuration.yaml +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/_types.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/data_classes.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/decorators.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/exceptions.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/fitsarray.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/core/root.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/_API/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/_API/i4dAPI.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/_API/micAPI.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/_API/splattAPI.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/cameras.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/interferometer.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/devices/wfs.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/dmutils/__actuator_identification_wip.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/dmutils/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/dmutils/__pupil_calibration_wip.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/dmutils/flattening.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/dmutils/iff_preparation.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/dmutils/iff_processing.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/dmutils/slaving.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/ground/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/ground/_stitching_algorithm.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/ground/geometry.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/ground/logger.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/ground/modal_decomposer.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/ground/reconstructor.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/ground/roi.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/activity.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/kernel_backend.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/procedures/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/procedures/alignment.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/procedures/base.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/procedures/dm_calibration.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/procedures/params.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/procedures/phasing.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/procedures/stitching.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/procedures/timeseries.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/resources/opticalib.ico +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/resources/opticalib.png +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/resources/opticalib.svg +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/widgets/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/widgets/config_editor.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/widgets/data_browser.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/widgets/plot_viewer.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/gui/widgets/workspace.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/procedures/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/procedures/iff.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/procedures/measurements.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/procedures/stitching.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/py.typed +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/_API/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/_API/alpao_conf.yaml +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/_API/base_fake_adopticadm.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/factory.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib/simulator/fake_interf.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib.egg-info/dependency_links.txt +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib.egg-info/entry_points.txt +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib.egg-info/requires.txt +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/opticalib.egg-info/top_level.txt +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/setup.cfg +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/setup_calpy.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/README.md +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/__init__.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/conftest.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_analyzer_signals.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_analyzer_timeseries.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_core_dataclass.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_core_exceptions.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_core_fits.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_core_root.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_devices_deformable_mirrors.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_devices_interferometer.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_dmutils_flattening.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_dmutils_iff_acquisition_preparation.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_dmutils_iff_module.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_dmutils_iff_processing.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_dmutils_slaving.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_ground_computerec.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_ground_geometry.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_ground_logger.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_ground_modal_decomposer.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_ground_osutils.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_ground_roi.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_gui_activity.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_gui_app.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_gui_config_editor.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_measurements.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_setup_calpy.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_simulator_factory_functions.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_simulator_simdata.py +0 -0
- {opticalib-2.2.0 → opticalib-2.3.1}/tests/test_typings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opticalib
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.1
|
|
4
4
|
Summary: This package is a python interface for laboratory adaptive optics systems, with a focus on the calibration of deformable mirrors (DMs) and the acquisition of wavefront data using wavefront sensors.
|
|
5
5
|
Author-email: Adaptive Optics Group - INAF - Osservatorio Astrofisico di Arcetri <pietro.ferraiuolo@inaf.it>
|
|
6
6
|
Maintainer-email: Pietro Ferraiuolo <pietro.ferraiuolo@inaf.it>
|
|
@@ -9,10 +9,14 @@ Project-URL: Homepage, https://github.com/ArcetriAdaptiveOptics/opticalib
|
|
|
9
9
|
Project-URL: Repository, https://github.com/ArcetriAdaptiveOptics/opticalib
|
|
10
10
|
Project-URL: Issues, https://github.com/ArcetriAdaptiveOptics/opticalib/issues
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
16
|
Classifier: Operating System :: Microsoft :: Windows
|
|
13
17
|
Classifier: Operating System :: POSIX :: Linux
|
|
14
18
|
Classifier: Operating System :: MacOS
|
|
15
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.11
|
|
16
20
|
Description-Content-Type: text/markdown
|
|
17
21
|
License-File: LICENSE
|
|
18
22
|
Requires-Dist: arte
|
|
@@ -9,7 +9,7 @@ Pietro Ferraiuolo
|
|
|
9
9
|
__title__ = "opticalib"
|
|
10
10
|
__long_title__ = "OPTICALIB : python framework for OPTIcal CALIBration of deformable mirrors and adaptive optics experimentation"
|
|
11
11
|
__description__ = "This package is a python interface for laboratory adaptive optics systems, with a focus on the calibration of deformable mirrors (DMs) and the acquisition of wavefront data using wavefront sensors."
|
|
12
|
-
__version__ = "2.
|
|
12
|
+
__version__ = "2.3.1"
|
|
13
13
|
__author__ = "Adaptive Optics Group - INAF - Osservatorio Astrofisico di Arcetri"
|
|
14
14
|
__maintainer__ = "Pietro Ferraiuolo"
|
|
15
15
|
__author_email__ = "pietro.ferraiuolo@inaf.it"
|
|
@@ -45,11 +45,27 @@ def pad_image_to_shape(
|
|
|
45
45
|
padded_img : _ot.ImageData
|
|
46
46
|
The padded image.
|
|
47
47
|
"""
|
|
48
|
-
|
|
49
|
-
y, x
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
y, x, Y, X, h, w = [*offset, *shape, *img.shape]
|
|
49
|
+
if any(p < 0 for p in [y, x, Y - h - y, X - w - x]):
|
|
50
|
+
raise ValueError("Invalid padding dimensions")
|
|
51
|
+
pad_width = ((y, Y - h - y), (x, X - w - x))
|
|
52
|
+
pimg = _np.pad(
|
|
53
|
+
img.data,
|
|
54
|
+
pad_width=pad_width,
|
|
55
|
+
mode='constant',
|
|
56
|
+
constant_values=fill_value
|
|
57
|
+
)
|
|
58
|
+
mask = _np.pad(
|
|
59
|
+
_np.ma.getmaskarray(img),
|
|
60
|
+
pad_width=pad_width,
|
|
61
|
+
mode='constant',
|
|
62
|
+
constant_values=True
|
|
63
|
+
)
|
|
64
|
+
if hasattr(img, 'header'):
|
|
65
|
+
header = img.header
|
|
66
|
+
else:
|
|
67
|
+
header = None
|
|
68
|
+
return _fa.fits_array(pimg, mask=mask, header=header)
|
|
53
69
|
|
|
54
70
|
|
|
55
71
|
def frame(idx: int, mylist: list[_ot.ImageData] | _ot.CubeData) -> _ot.ImageData:
|
|
@@ -301,13 +317,18 @@ def create_cube(fl_or_il: list[str], register: bool = False) -> _ot.CubeData:
|
|
|
301
317
|
cube : ndarray
|
|
302
318
|
Data cube containing the images/frames stacked, with shape (npx, npy, nframes).
|
|
303
319
|
"""
|
|
320
|
+
memmap = True
|
|
304
321
|
# check it is a list
|
|
305
322
|
if not isinstance(fl_or_il, list):
|
|
306
323
|
raise TypeError("filelist must be a list of strings or images")
|
|
307
324
|
|
|
308
325
|
# check if it is composed of file paths to load
|
|
309
326
|
if all([isinstance(item, str) for item in fl_or_il]):
|
|
310
|
-
|
|
327
|
+
N = len(fl_or_il) # Number of files
|
|
328
|
+
if N > 1000:
|
|
329
|
+
memmap = False
|
|
330
|
+
print("Disabling memory mapping for large file list: N =", N)
|
|
331
|
+
fl_or_il = [osu.read_phasemap(f, memmap=memmap) for f in fl_or_il]
|
|
311
332
|
|
|
312
333
|
# Is the list now full of images?
|
|
313
334
|
if not any(
|
|
@@ -15,6 +15,7 @@ Most accessors also accept an explicit ``bpath`` to point at a specific
|
|
|
15
15
|
|
|
16
16
|
import os as _os
|
|
17
17
|
import re as _re
|
|
18
|
+
from collections.abc import Mapping as _Mapping
|
|
18
19
|
from ast import literal_eval as _literal_eval
|
|
19
20
|
|
|
20
21
|
import numpy as _np
|
|
@@ -276,6 +277,52 @@ def get_section_config(section: str, sub_section: str | None = None) -> dict[str
|
|
|
276
277
|
return _get_section_config(section=section, sub_section=sub_section, path=_cfile)
|
|
277
278
|
|
|
278
279
|
|
|
280
|
+
class LazySection(_Mapping):
|
|
281
|
+
"""
|
|
282
|
+
A section of ``configuration.yaml``, read when it is used.
|
|
283
|
+
|
|
284
|
+
Modules that need a section at import time use it instead of reading the
|
|
285
|
+
file immediately, so that an experiment that does not define the
|
|
286
|
+
section (or sets it to ``null``) can still import opticalib. A missing
|
|
287
|
+
section reads as empty; ``section[key]`` then raises a ``KeyError``
|
|
288
|
+
naming the section. The file is read on every access, so the values
|
|
289
|
+
follow :func:`opticalib.set_configuration_file`.
|
|
290
|
+
|
|
291
|
+
Parameters
|
|
292
|
+
----------
|
|
293
|
+
section : str
|
|
294
|
+
Top-level section name.
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
def __init__(self, section: str) -> None:
|
|
298
|
+
"""Remember the section; nothing is read yet."""
|
|
299
|
+
self._section = section
|
|
300
|
+
|
|
301
|
+
def _load(self) -> dict[str, _Any]:
|
|
302
|
+
try:
|
|
303
|
+
data = get_section_config(self._section)
|
|
304
|
+
except KeyError:
|
|
305
|
+
data = None
|
|
306
|
+
return dict(data) if isinstance(data, dict) else {}
|
|
307
|
+
|
|
308
|
+
def __getitem__(self, key: str) -> _Any:
|
|
309
|
+
data = self._load()
|
|
310
|
+
if key not in data:
|
|
311
|
+
raise KeyError(
|
|
312
|
+
f"`{key}` not found in the `{self._section}` section of the configuration file"
|
|
313
|
+
)
|
|
314
|
+
return data[key]
|
|
315
|
+
|
|
316
|
+
def __iter__(self):
|
|
317
|
+
return iter(self._load())
|
|
318
|
+
|
|
319
|
+
def __len__(self) -> int:
|
|
320
|
+
return len(self._load())
|
|
321
|
+
|
|
322
|
+
def __repr__(self) -> str:
|
|
323
|
+
return f"LazySection({self._section!r})"
|
|
324
|
+
|
|
325
|
+
|
|
279
326
|
def get_device_config(device_type: str, device_name: str | None = None):
|
|
280
327
|
"""
|
|
281
328
|
Retrieves the device configuration from the YAML configuration file.
|
|
@@ -696,6 +743,10 @@ def get_alignment_config():
|
|
|
696
743
|
The alignment configuration as a class, for backwards compatibility.
|
|
697
744
|
"""
|
|
698
745
|
config = get_section_config("SYSTEM.ALIGNMENT")
|
|
746
|
+
if not isinstance(config, dict):
|
|
747
|
+
raise KeyError(
|
|
748
|
+
"The `SYSTEM.ALIGNMENT` section of the configuration file is empty."
|
|
749
|
+
)
|
|
699
750
|
config["slices"] = [slice(item["start"], item["stop"]) for item in config["slices"]]
|
|
700
751
|
|
|
701
752
|
class AlignmentConfig:
|
|
@@ -355,12 +355,12 @@ class BaseAlpaoMirror:
|
|
|
355
355
|
The serial number is resolved in the following priority order:
|
|
356
356
|
|
|
357
357
|
1. The *serial_number* argument, if not ``None``.
|
|
358
|
-
2. The ``
|
|
358
|
+
2. The ``serial_number`` key in the device configuration file
|
|
359
359
|
(looked up by *nacts*).
|
|
360
360
|
|
|
361
361
|
When *nacts* is provided the device configuration block
|
|
362
362
|
``Alpao{nacts}`` is read from the configuration file, allowing
|
|
363
|
-
``
|
|
363
|
+
``serial_number``, ``sdk_folder_path``, and ``acfg_path`` to be
|
|
364
364
|
set there instead of being passed as arguments. When only
|
|
365
365
|
*serial_number* is given the configuration lookup is skipped and
|
|
366
366
|
the caller is responsible for having ``ACECFG`` set in the
|
|
@@ -43,7 +43,7 @@ class BaseDeformableMirror(ABC):
|
|
|
43
43
|
@property
|
|
44
44
|
def border_ids(self):
|
|
45
45
|
return self._borderIds
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
@property
|
|
48
48
|
def cmd_history(self) -> _ot.Optional[_ot.MatrixLike]:
|
|
49
49
|
"""
|
|
@@ -117,7 +117,9 @@ class BaseDeformableMirror(ABC):
|
|
|
117
117
|
return None
|
|
118
118
|
return "minimum-rms" if (s and b) else "zero-force"
|
|
119
119
|
|
|
120
|
-
def _apply_slaving(
|
|
120
|
+
def _apply_slaving(
|
|
121
|
+
self, cmd: _ot.ArrayLike | _ot.MatrixLike, slave: bool | str
|
|
122
|
+
) -> _ot.ArrayLike | _ot.MatrixLike:
|
|
121
123
|
"""
|
|
122
124
|
Apply actuator slaving to a command when requested.
|
|
123
125
|
"""
|
|
@@ -7,8 +7,8 @@ from opticalib.core.exceptions import CommandError
|
|
|
7
7
|
|
|
8
8
|
_CMDLIMITS = { # temporary limits to overcome the hardware connection refusal
|
|
9
9
|
0: [0, 12],
|
|
10
|
-
1: [-
|
|
11
|
-
2: [-
|
|
10
|
+
1: [-230, 230],
|
|
11
|
+
2: [-230, 230],
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
|
|
@@ -199,7 +199,7 @@ class BasePetalMirror:
|
|
|
199
199
|
self._had_error = True
|
|
200
200
|
raise RuntimeError("Failed to send mirror command") from err
|
|
201
201
|
|
|
202
|
-
def _check_cmd_integrity(self, cmd: _ot.ArrayLike) ->
|
|
202
|
+
def _check_cmd_integrity(self, cmd: _ot.ArrayLike) -> bool:
|
|
203
203
|
"""
|
|
204
204
|
Check the integrity of the command array.
|
|
205
205
|
|
|
@@ -217,6 +217,7 @@ class BasePetalMirror:
|
|
|
217
217
|
for ax, c in enumerate(cmd[k * 3 : k * 3 + 3]):
|
|
218
218
|
if not (_CMDLIMITS[ax][0] <= c <= _CMDLIMITS[ax][1]):
|
|
219
219
|
raise CommandError(f"Command for actuator {ax} out of bounds: {c}")
|
|
220
|
+
return True
|
|
220
221
|
|
|
221
222
|
def _morning_routine(self) -> None:
|
|
222
223
|
"""
|
|
@@ -227,6 +228,14 @@ class BasePetalMirror:
|
|
|
227
228
|
import time
|
|
228
229
|
|
|
229
230
|
pos = self._read_act_position()
|
|
231
|
+
if not self._check_cmd_integrity(pos):
|
|
232
|
+
self._logger.warning(
|
|
233
|
+
"Initial actuator positions are not within command limits. "
|
|
234
|
+
"Setting to mid-range.")
|
|
235
|
+
midpoint = lambda v: (v[0] + v[1]) / 2
|
|
236
|
+
pos = np.asarray(
|
|
237
|
+
[midpoint(_CMDLIMITS[ax]) for ax in range(3)] * self.n_segments
|
|
238
|
+
)
|
|
230
239
|
try:
|
|
231
240
|
if not self._had_morning_routine:
|
|
232
241
|
self._logger.info(f"Warming up the segments piezos.")
|
|
@@ -30,6 +30,7 @@ from opticalib.ground.logger import SystemLogger as _SL
|
|
|
30
30
|
|
|
31
31
|
from ._API.piAPI import BasePetalMirror
|
|
32
32
|
|
|
33
|
+
|
|
33
34
|
class PetalMirror(BasePetalMirror, BaseDeformableMirror):
|
|
34
35
|
"""
|
|
35
36
|
Petal Deformable Mirror interface.
|
|
@@ -186,6 +187,7 @@ class PetalMirror(BasePetalMirror, BaseDeformableMirror):
|
|
|
186
187
|
|
|
187
188
|
from ._API.micAPI import BaseAdOpticaDm
|
|
188
189
|
|
|
190
|
+
|
|
189
191
|
class AdOpticaDm(BaseAdOpticaDm, BaseDeformableMirror):
|
|
190
192
|
"""
|
|
191
193
|
AdOptica Deformable Mirror interface.
|
|
@@ -443,6 +445,7 @@ class AdOpticaDm(BaseAdOpticaDm, BaseDeformableMirror):
|
|
|
443
445
|
def __repr__(self):
|
|
444
446
|
return f"{self._name}(n_segments={self.n_segments}, n_acts_per_segment={self.n_acts_per_segment})"
|
|
445
447
|
|
|
448
|
+
|
|
446
449
|
class DP(AdOpticaDm):
|
|
447
450
|
"""
|
|
448
451
|
Deformable Mirror interface for the Deformable Platform (DP) of the ELT.
|
|
@@ -586,6 +589,7 @@ class DP(AdOpticaDm):
|
|
|
586
589
|
# Store in both the yielded dict and class attribute
|
|
587
590
|
self.bufferData = result.copy()
|
|
588
591
|
|
|
592
|
+
|
|
589
593
|
class M4AU(AdOpticaDm):
|
|
590
594
|
"""
|
|
591
595
|
Deformable Mirror interface for the M4 Auxiliary Unit (M4AU) of the ELT.
|
|
@@ -611,6 +615,7 @@ class M4AU(AdOpticaDm):
|
|
|
611
615
|
|
|
612
616
|
from ._API.alpaoAPI import BaseAlpaoMirror
|
|
613
617
|
|
|
618
|
+
|
|
614
619
|
class AlpaoDm(BaseAlpaoMirror, BaseDeformableMirror):
|
|
615
620
|
"""
|
|
616
621
|
Alpao Deformable Mirror interface.
|
|
@@ -757,7 +762,7 @@ class AlpaoDm(BaseAlpaoMirror, BaseDeformableMirror):
|
|
|
757
762
|
if not _ot.isinstance_(tcmdhist, "MatrixLike"):
|
|
758
763
|
raise _oe.MatrixError(
|
|
759
764
|
f"Expecting a 2D Matrix of shape (nacts, nmodes), got instead: {tcmdhist.shape}"
|
|
760
|
-
)
|
|
765
|
+
)
|
|
761
766
|
tcmdhist = self._apply_slaving(cmd=tcmdhist, slave=slaving)
|
|
762
767
|
self._cmd_history = tcmdhist
|
|
763
768
|
|
|
@@ -889,6 +894,7 @@ class AlpaoDm(BaseAlpaoMirror, BaseDeformableMirror):
|
|
|
889
894
|
|
|
890
895
|
from ._API.splattAPI import SPLATTEngine
|
|
891
896
|
|
|
897
|
+
|
|
892
898
|
class SplattDm(BaseDeformableMirror):
|
|
893
899
|
"""
|
|
894
900
|
SPLATT deformable mirror interface.
|
|
@@ -4,9 +4,10 @@ from ..core import _types as _ot
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def make_modal_base(
|
|
7
|
-
rm: _ot.MatrixLike,
|
|
8
7
|
modes: int | list[int],
|
|
9
8
|
mask: _ot.MaskData,
|
|
9
|
+
im: _ot.MatrixLike|None = None,
|
|
10
|
+
rm: _ot.MatrixLike|None = None,
|
|
10
11
|
basis: str = "zernike",
|
|
11
12
|
) -> _ot.MatrixLike:
|
|
12
13
|
"""
|
|
@@ -14,8 +15,10 @@ def make_modal_base(
|
|
|
14
15
|
|
|
15
16
|
Parameters
|
|
16
17
|
----------
|
|
17
|
-
|
|
18
|
-
The
|
|
18
|
+
im : MatrixLike
|
|
19
|
+
The Interaction Matrix (nacts, npix).
|
|
20
|
+
rm : MatrixLike
|
|
21
|
+
The reconstruction matrix (npix, nacts).
|
|
19
22
|
modes : int or list of int
|
|
20
23
|
The number of modes to compute, or the list of mode indices to compute.
|
|
21
24
|
mask : MaskData
|
|
@@ -30,7 +33,7 @@ def make_modal_base(
|
|
|
30
33
|
|
|
31
34
|
Returns
|
|
32
35
|
-------
|
|
33
|
-
|
|
36
|
+
m2c : MatrixLike
|
|
34
37
|
The modal base.
|
|
35
38
|
|
|
36
39
|
"""
|
|
@@ -64,8 +67,13 @@ def make_modal_base(
|
|
|
64
67
|
masked_data = surf[~mask]
|
|
65
68
|
mat[i, :] = masked_data
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
if rm is not None:
|
|
71
|
+
m2c = (mat @ rm).T
|
|
72
|
+
elif im is not None:
|
|
73
|
+
m2c = (mat @ im.T).T
|
|
74
|
+
else:
|
|
75
|
+
raise ValueError("Either `rm` or `im` must be provided.")
|
|
76
|
+
return m2c
|
|
69
77
|
|
|
70
78
|
|
|
71
79
|
__all__ = ["make_modal_base"]
|
|
@@ -457,7 +457,7 @@ def load_cube_from_filelist(
|
|
|
457
457
|
return cube
|
|
458
458
|
|
|
459
459
|
|
|
460
|
-
def read_phasemap(file_path: str) -> _ot.ImageData:
|
|
460
|
+
def read_phasemap(file_path: str, **kwargs: dict[str, _ot.Any]) -> _ot.ImageData:
|
|
461
461
|
"""
|
|
462
462
|
Function to read interferometric data, in the three possible formats
|
|
463
463
|
(FITS, 4D, H5)
|
|
@@ -474,13 +474,15 @@ def read_phasemap(file_path: str) -> _ot.ImageData:
|
|
|
474
474
|
"""
|
|
475
475
|
ext = file_path.split(".")[-1]
|
|
476
476
|
if ext in ["fits", "4Ds"]:
|
|
477
|
-
image = load_fits(file_path)
|
|
477
|
+
image = load_fits(file_path, **kwargs)
|
|
478
478
|
elif ext in ["4D", "h5"]:
|
|
479
479
|
image = _InterferometerConverter.from_phase_cam6110(file_path)
|
|
480
480
|
return image
|
|
481
481
|
|
|
482
482
|
|
|
483
|
-
def load_fits(
|
|
483
|
+
def load_fits(
|
|
484
|
+
filepath: str, on_gpu: bool = False, **kwargs: dict[str, _ot.Any]
|
|
485
|
+
) -> _ot.FitsData | list[_ot.FitsData]:
|
|
484
486
|
"""
|
|
485
487
|
Loads a FITS file.
|
|
486
488
|
|
|
@@ -505,7 +507,12 @@ def load_fits(filepath: str, on_gpu: bool = False) -> _ot.FitsData | list[_ot.Fi
|
|
|
505
507
|
filepath += ".fits"
|
|
506
508
|
|
|
507
509
|
multi_hdu = False
|
|
508
|
-
with
|
|
510
|
+
# memmap=False: with memory mapping (astropy's default) the returned arrays
|
|
511
|
+
# are views on the mmap, which keeps a file descriptor open for as long as
|
|
512
|
+
# the data is alive, even after the `with` block exits. Loading many files
|
|
513
|
+
# (e.g. in `load_cube_from_filelist`) would then hit "Too many open files".
|
|
514
|
+
memmap = kwargs.pop("memmap", True)
|
|
515
|
+
with _fits.open(filepath, memmap=memmap, **kwargs) as hdul:
|
|
509
516
|
H = len(hdul)
|
|
510
517
|
|
|
511
518
|
# Simple HDU case
|
|
@@ -20,6 +20,11 @@ From Python::
|
|
|
20
20
|
Via the CLI::
|
|
21
21
|
|
|
22
22
|
calpy -f /path/to/experiment --gui
|
|
23
|
+
|
|
24
|
+
Packages building on opticalib subclass :class:`CalpyGUI` to add their own
|
|
25
|
+
procedures (:class:`~opticalib.gui.plugins.Procedure`, windows built on
|
|
26
|
+
:class:`~opticalib.gui.procedures.base.ProcedureWindow`) and startup
|
|
27
|
+
scripts, then call ``launch_gui(config_path, window_class=MyGUI)``.
|
|
23
28
|
"""
|
|
24
29
|
|
|
25
30
|
import os as _os
|
|
@@ -38,7 +43,7 @@ if _os.environ["QT_API"].lower() in _PYQTGRAPH_LIBS:
|
|
|
38
43
|
"PYQTGRAPH_QT_LIB", _PYQTGRAPH_LIBS[_os.environ["QT_API"].lower()]
|
|
39
44
|
)
|
|
40
45
|
|
|
41
|
-
__all__ = ["CalpyGUI", "launch_gui"]
|
|
46
|
+
__all__ = ["CalpyGUI", "launch_gui", "Procedure", "PROCEDURES"]
|
|
42
47
|
|
|
43
48
|
|
|
44
49
|
def __getattr__(name: str):
|
|
@@ -49,6 +54,10 @@ def __getattr__(name: str):
|
|
|
49
54
|
inside the IPython kernel, which must not pay for (or require) a Qt
|
|
50
55
|
import; the main window is therefore only loaded on first access.
|
|
51
56
|
"""
|
|
57
|
+
if name in ("Procedure", "PROCEDURES"):
|
|
58
|
+
from . import plugins
|
|
59
|
+
|
|
60
|
+
return getattr(plugins, name)
|
|
52
61
|
if name in __all__:
|
|
53
62
|
from . import app
|
|
54
63
|
|