opticalib 2.1.3__tar.gz → 2.2.0__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/CITATION.bib +10 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/MANIFEST.in +5 -4
- {opticalib-2.1.3/opticalib.egg-info → opticalib-2.2.0}/PKG-INFO +41 -27
- {opticalib-2.1.3 → opticalib-2.2.0}/README.md +11 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/__init__.py +11 -15
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/__version__.py +1 -1
- opticalib-2.2.0/opticalib/analyzer/__init__.py +13 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/analyzer/image_processing.py +37 -3
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/_types.py +16 -1
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/config.py +2 -2
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/root.py +4 -4
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/_API/alpaoAPI.py +22 -14
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/_API/base_devices.py +23 -10
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/_API/piAPI.py +5 -5
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/deformable_mirrors.py +64 -98
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/interferometer.py +52 -27
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/dmutils/flattening.py +32 -1
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/dmutils/iff_processing.py +1 -3
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/ground/_stitching_algorithm.py +13 -13
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/ground/reconstructor.py +5 -5
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/__init__.py +9 -2
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/activity.py +47 -14
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/app.py +307 -39
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/kernel.py +131 -14
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/plugins.py +3 -1
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/procedures/alignment.py +30 -8
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/procedures/base.py +51 -14
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/procedures/dm_calibration.py +145 -31
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/procedures/params.py +64 -18
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/procedures/phasing.py +76 -17
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/procedures/stitching.py +31 -5
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/procedures/timeseries.py +24 -5
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/common.py +9 -2
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/config_editor.py +225 -5
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/connect_dialog.py +23 -7
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/data_browser.py +22 -8
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/device_panel.py +49 -19
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/device_registry.py +132 -39
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/plot_viewer.py +60 -13
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/workspace.py +6 -2
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/procedures/iff.py +9 -11
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/_API/__init__.py +2 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/_API/base_fake_adopticadm.py +19 -75
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/_API/base_fake_alpao.py +28 -85
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/_API/base_petalmirror.py +11 -52
- opticalib-2.2.0/opticalib/simulator/_API/base_simulated_dm.py +378 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/__init__.py +2 -0
- opticalib-2.2.0/opticalib/simulator/fake_dms.py +278 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/visualization.py +88 -0
- {opticalib-2.1.3 → opticalib-2.2.0/opticalib.egg-info}/PKG-INFO +41 -27
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib.egg-info/SOURCES.txt +5 -4
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib.egg-info/requires.txt +22 -3
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib.egg-info/top_level.txt +0 -1
- opticalib-2.2.0/pyproject.toml +103 -0
- opticalib-2.2.0/setup.cfg +4 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/setup_calpy.py +2 -13
- opticalib-2.2.0/tests/README.md +110 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/conftest.py +3 -3
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_analyzer_images_processing.py +24 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_core_read_config.py +1 -1
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_core_root.py +2 -2
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_devices_deformable_mirrors.py +1 -1
- opticalib-2.2.0/tests/test_devices_interferometer.py +93 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_gui_config_editor.py +84 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_gui_kernel_bridge.py +31 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_gui_kernel_side.py +23 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_gui_widgets.py +47 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_setup_calpy.py +13 -11
- opticalib-2.1.3/opticalib/analyzer/__init__.py +0 -3
- opticalib-2.1.3/opticalib/simulator/_API/_rbf_gpu.py +0 -367
- opticalib-2.1.3/opticalib/simulator/fake_dms.py +0 -846
- opticalib-2.1.3/requirements.txt +0 -24
- opticalib-2.1.3/setup.cfg +0 -28
- opticalib-2.1.3/setup.py +0 -56
- {opticalib-2.1.3 → opticalib-2.2.0}/LICENSE +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/__init_script__/initCalpy.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/analyzer/signals.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/analyzer/timeseries.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/_configurations/configuration.yaml +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/data_classes.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/decorators.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/exceptions.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/core/fitsarray.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/_API/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/_API/i4dAPI.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/_API/micAPI.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/_API/splattAPI.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/cameras.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/devices/wfs.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/dmutils/__actuator_identification_wip.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/dmutils/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/dmutils/__pupil_calibration_wip.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/dmutils/_misc.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/dmutils/iff_preparation.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/dmutils/slaving.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/ground/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/ground/geometry.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/ground/logger.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/ground/modal_decomposer.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/ground/osutils.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/ground/roi.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/kernel_backend.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/kernel_side.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/procedures/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/resources/opticalib.ico +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/resources/opticalib.png +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/resources/opticalib.svg +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/theme.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/gui/widgets/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/procedures/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/procedures/alignment.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/procedures/measurements.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/procedures/phasing.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/procedures/stitching.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/py.typed +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/_API/alpao_conf.yaml +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/_API/simdata.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/factory.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib/simulator/fake_interf.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib.egg-info/dependency_links.txt +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/opticalib.egg-info/entry_points.txt +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/__init__.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_analyzer_signals.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_analyzer_timeseries.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_core_dataclass.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_core_exceptions.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_core_fits.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_dmutils_flattening.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_dmutils_iff_acquisition_preparation.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_dmutils_iff_module.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_dmutils_iff_processing.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_dmutils_slaving.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_ground_computerec.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_ground_geometry.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_ground_logger.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_ground_modal_decomposer.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_ground_osutils.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_ground_roi.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_gui_activity.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_gui_app.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_gui_devices.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_gui_procedures.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_measurements.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_simulator_factory_functions.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_simulator_simdata.py +0 -0
- {opticalib-2.1.3 → opticalib-2.2.0}/tests/test_typings.py +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
@misc{opticalib,
|
|
2
|
+
doi = {10.20371/INAF/SW/2026_00013},
|
|
3
|
+
url = {https://openscience.inaf.it/?page_id=696},
|
|
4
|
+
author = {{Pietro Ferraiuolo} and {Marco Xompero} and {Runa Briguglio} and {Matteo Menessini}},
|
|
5
|
+
language = {en},
|
|
6
|
+
title = {OPTICALIB: A Python Framework for Adaptive Optics Experimentation},
|
|
7
|
+
publisher = {O.A. Arcetri},
|
|
8
|
+
year = {2025},
|
|
9
|
+
copyright = {MIT License}
|
|
10
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
include README.md
|
|
2
|
-
include
|
|
2
|
+
include LICENSE
|
|
3
|
+
include CITATION.bib
|
|
3
4
|
include opticalib/core/_configurations/configuration.yaml
|
|
4
|
-
include setup_calpy.py
|
|
5
|
-
include opticalib/__init_script__/initCalpy.py
|
|
6
5
|
include opticalib/simulator/_API/alpao_conf.yaml
|
|
6
|
+
include opticalib/__init_script__/initCalpy.py
|
|
7
7
|
recursive-include opticalib/gui/resources *.svg *.png *.ico
|
|
8
|
-
|
|
8
|
+
graft tests
|
|
9
|
+
global-exclude __pycache__ *.py[cod]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opticalib
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
Author-email: Adaptive Optics Group - INAF - Osservatorio Astrofisico di Arcetri <pietro.ferraiuolo@inaf.it>
|
|
6
|
+
Maintainer-email: Pietro Ferraiuolo <pietro.ferraiuolo@inaf.it>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/ArcetriAdaptiveOptics/opticalib
|
|
9
|
+
Project-URL: Repository, https://github.com/ArcetriAdaptiveOptics/opticalib
|
|
10
|
+
Project-URL: Issues, https://github.com/ArcetriAdaptiveOptics/opticalib/issues
|
|
10
11
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Classifier: Operating System :: Microsoft :: Windows
|
|
13
13
|
Classifier: Operating System :: POSIX :: Linux
|
|
14
14
|
Classifier: Operating System :: MacOS
|
|
@@ -24,37 +24,43 @@ Requires-Dist: pipython
|
|
|
24
24
|
Requires-Dist: photutils
|
|
25
25
|
Requires-Dist: scipy
|
|
26
26
|
Requires-Dist: ruamel.yaml
|
|
27
|
+
Requires-Dist: PyYAML
|
|
27
28
|
Requires-Dist: Pyro4
|
|
28
29
|
Requires-Dist: h5py
|
|
29
30
|
Requires-Dist: jdcal
|
|
30
31
|
Requires-Dist: tqdm
|
|
31
32
|
Requires-Dist: matplotlib
|
|
32
|
-
Requires-Dist: xupy
|
|
33
33
|
Requires-Dist: numpy
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Requires-Dist:
|
|
41
|
-
Requires-Dist:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
Requires-Dist: rbfgpu
|
|
35
|
+
Requires-Dist: xupy>=2.0
|
|
36
|
+
Requires-Dist: ipython
|
|
37
|
+
Provides-Extra: gui
|
|
38
|
+
Requires-Dist: PySide6-Essentials; extra == "gui"
|
|
39
|
+
Requires-Dist: QtPy; extra == "gui"
|
|
40
|
+
Requires-Dist: qtconsole; extra == "gui"
|
|
41
|
+
Requires-Dist: ipykernel; extra == "gui"
|
|
42
|
+
Requires-Dist: jupyter_client; extra == "gui"
|
|
43
|
+
Requires-Dist: pyqtgraph; extra == "gui"
|
|
44
|
+
Requires-Dist: qtawesome; extra == "gui"
|
|
45
|
+
Requires-Dist: psutil; extra == "gui"
|
|
46
|
+
Provides-Extra: cuda12
|
|
47
|
+
Requires-Dist: xupy[cuda12]>=2.0; extra == "cuda12"
|
|
48
|
+
Provides-Extra: cuda13
|
|
49
|
+
Requires-Dist: xupy[cuda13]>=2.0; extra == "cuda13"
|
|
50
|
+
Provides-Extra: test
|
|
51
|
+
Requires-Dist: pytest; extra == "test"
|
|
52
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
53
|
+
Provides-Extra: dev
|
|
54
|
+
Requires-Dist: opticalib[gui,test]; extra == "dev"
|
|
55
|
+
Requires-Dist: flake8; extra == "dev"
|
|
49
56
|
Dynamic: license-file
|
|
50
|
-
Dynamic: maintainer
|
|
51
|
-
Dynamic: requires-dist
|
|
52
|
-
Dynamic: requires-python
|
|
53
|
-
Dynamic: summary
|
|
54
57
|
|
|
55
58
|
# OptiCalib : python framework for OPTical CALibration of deformable mirrors and AO experimentation
|
|
56
59
|
|
|
57
60
|

|
|
61
|
+
[](https://pypi.org/project/opticalib/)
|
|
62
|
+
[](https://pypi.org/project/opticalib/)
|
|
63
|
+
[](LICENSE)
|
|
58
64
|
|
|
59
65
|
`Adaptive Optics Group, INAF - Osservatorio Astrofisico di Arcetri`
|
|
60
66
|
|
|
@@ -86,6 +92,14 @@ The latests, stable, version can be installed from pypi:
|
|
|
86
92
|
pip install opticalib
|
|
87
93
|
```
|
|
88
94
|
|
|
95
|
+
The base install contains everything needed to talk to the hardware, run the simulators and the calibration routines, and use the `calpy` shell. Two optional extras add the rest:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install "opticalib[gui]" # the graphical interface (calpy --gui / OptiCalib)
|
|
99
|
+
pip install "opticalib[cuda13]" # GPU backend (CuPy, via xupy); use cuda12 for CUDA 12.x
|
|
100
|
+
pip install "opticalib[gui,cuda13]" # extras can be combined
|
|
101
|
+
```
|
|
102
|
+
|
|
89
103
|
The in-development version can be installed directly from this repository:
|
|
90
104
|
|
|
91
105
|
```bash
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# OptiCalib : python framework for OPTical CALibration of deformable mirrors and AO experimentation
|
|
2
2
|
|
|
3
3
|

|
|
4
|
+
[](https://pypi.org/project/opticalib/)
|
|
5
|
+
[](https://pypi.org/project/opticalib/)
|
|
6
|
+
[](LICENSE)
|
|
4
7
|
|
|
5
8
|
`Adaptive Optics Group, INAF - Osservatorio Astrofisico di Arcetri`
|
|
6
9
|
|
|
@@ -32,6 +35,14 @@ The latests, stable, version can be installed from pypi:
|
|
|
32
35
|
pip install opticalib
|
|
33
36
|
```
|
|
34
37
|
|
|
38
|
+
The base install contains everything needed to talk to the hardware, run the simulators and the calibration routines, and use the `calpy` shell. Two optional extras add the rest:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install "opticalib[gui]" # the graphical interface (calpy --gui / OptiCalib)
|
|
42
|
+
pip install "opticalib[cuda13]" # GPU backend (CuPy, via xupy); use cuda12 for CUDA 12.x
|
|
43
|
+
pip install "opticalib[gui,cuda13]" # extras can be combined
|
|
44
|
+
```
|
|
45
|
+
|
|
35
46
|
The in-development version can be installed directly from this repository:
|
|
36
47
|
|
|
37
48
|
```bash
|
|
@@ -5,20 +5,15 @@ OPTICALIB: adaptive OPTIcs package for dm CALIBration
|
|
|
5
5
|
Author(s)
|
|
6
6
|
---------
|
|
7
7
|
- Pietro Ferraiuolo : pietro.ferraiuolo@inaf.it
|
|
8
|
+
- Runa Briguglio: runa.briguglio@inaf.it
|
|
9
|
+
- Marco Xompero: marco.xompero@inaf.it
|
|
10
|
+
- Matteo Menessini: matteo.menessini@inaf.it
|
|
8
11
|
|
|
9
12
|
Description
|
|
10
13
|
-----------
|
|
11
14
|
OptiCalib is a package for the control of laboratory instrumentations, like
|
|
12
15
|
Interferometers and Deformable Mirrors. It also provides tools for the
|
|
13
16
|
analysis of wavefronts and images.
|
|
14
|
-
|
|
15
|
-
How to Use:
|
|
16
|
-
-----------
|
|
17
|
-
```python
|
|
18
|
-
> import opticalib
|
|
19
|
-
> interf = opticalib.PhaseCam('193.206.155.218', 8011)
|
|
20
|
-
> img = interf.acquire_map()
|
|
21
|
-
```
|
|
22
17
|
"""
|
|
23
18
|
|
|
24
19
|
from __future__ import annotations
|
|
@@ -34,13 +29,6 @@ from .core.root import (
|
|
|
34
29
|
from .core import config
|
|
35
30
|
from .core import _types as typings
|
|
36
31
|
from .core.fitsarray import fits_array
|
|
37
|
-
from .devices import *
|
|
38
|
-
from .devices.interferometer import _4DInterferometer
|
|
39
|
-
|
|
40
|
-
get_camera_settings = _4DInterferometer.get_camera_settings
|
|
41
|
-
get_frame_rate = _4DInterferometer.get_frame_rate
|
|
42
|
-
|
|
43
|
-
del _4DInterferometer
|
|
44
32
|
|
|
45
33
|
from . import (
|
|
46
34
|
analyzer,
|
|
@@ -51,6 +39,14 @@ from . import (
|
|
|
51
39
|
visualization,
|
|
52
40
|
)
|
|
53
41
|
|
|
42
|
+
from .devices.interferometer import _4DInterferometer
|
|
43
|
+
|
|
44
|
+
get_camera_settings = _4DInterferometer.get_camera_settings
|
|
45
|
+
get_frame_rate = _4DInterferometer.get_frame_rate
|
|
46
|
+
del _4DInterferometer
|
|
47
|
+
|
|
48
|
+
from .devices import *
|
|
49
|
+
|
|
54
50
|
vis = visualization
|
|
55
51
|
|
|
56
52
|
__all__ = [
|
|
@@ -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.2.0"
|
|
13
13
|
__author__ = "Adaptive Optics Group - INAF - Osservatorio Astrofisico di Arcetri"
|
|
14
14
|
__maintainer__ = "Pietro Ferraiuolo"
|
|
15
15
|
__author_email__ = "pietro.ferraiuolo@inaf.it"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .image_processing import *
|
|
2
|
+
from .signals import *
|
|
3
|
+
from .timeseries import *
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _get_safe_interf_fullframe():
|
|
7
|
+
from ..devices.interferometer import _4DInterferometer
|
|
8
|
+
|
|
9
|
+
func = _4DInterferometer.into_full_frame
|
|
10
|
+
return func
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
into_4d_full_frame = _get_safe_interf_fullframe()
|
|
@@ -20,6 +20,38 @@ from ..ground import osutils as osu, modal_decomposer as _md
|
|
|
20
20
|
from scipy import stats as _stats, fft as _fft, ndimage as _ndimage
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
def pad_image_to_shape(
|
|
24
|
+
img: _ot.ImageData,
|
|
25
|
+
shape: tuple[int, int],
|
|
26
|
+
offset: tuple[int, int],
|
|
27
|
+
fill_value: float = 0.0,
|
|
28
|
+
) -> _ot.ImageData:
|
|
29
|
+
"""
|
|
30
|
+
Pads an image to a specified shape with a given offset and fill value.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
img : _ot.ImageData
|
|
35
|
+
The image to be padded.
|
|
36
|
+
shape : tuple[int, int]
|
|
37
|
+
The target shape (height, width) for the padded image.
|
|
38
|
+
offset : tuple[int, int]
|
|
39
|
+
The (y, x) offset at which to place the original image in the padded image.
|
|
40
|
+
fill_value : float, optional
|
|
41
|
+
The value to fill the padded areas with. Default is 0.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
padded_img : _ot.ImageData
|
|
46
|
+
The padded image.
|
|
47
|
+
"""
|
|
48
|
+
padded_img = _np.full(shape, fill_value)
|
|
49
|
+
y, x = offset
|
|
50
|
+
h, w = _np.shape(img)
|
|
51
|
+
padded_img[y : y + h, x : x + w] = img.data
|
|
52
|
+
return padded_img
|
|
53
|
+
|
|
54
|
+
|
|
23
55
|
def frame(idx: int, mylist: list[_ot.ImageData] | _ot.CubeData) -> _ot.ImageData:
|
|
24
56
|
"""
|
|
25
57
|
Returns a single frame from a list of files or from a cube.
|
|
@@ -225,7 +257,7 @@ def push_pull_reduction_algorithm(
|
|
|
225
257
|
# Template weights computation
|
|
226
258
|
w = _xp.asarray(
|
|
227
259
|
template.astype(_np.result_type(template, imagelist[0].data), copy=True),
|
|
228
|
-
dtype=
|
|
260
|
+
dtype=_ot.compute_float(),
|
|
229
261
|
)
|
|
230
262
|
if n_images > 2:
|
|
231
263
|
w[1:-1] *= 2.0
|
|
@@ -233,9 +265,9 @@ def push_pull_reduction_algorithm(
|
|
|
233
265
|
master_mask = _np.logical_or.reduce([ima.mask for ima in imagelist])
|
|
234
266
|
# Compute weighted sum over realizations on raw data
|
|
235
267
|
stack = _xp.stack(
|
|
236
|
-
[_xp.asarray(ima.data, dtype=
|
|
268
|
+
[_xp.asarray(ima.data, dtype=_ot.compute_float()) for ima in imagelist],
|
|
237
269
|
axis=0,
|
|
238
|
-
dtype=
|
|
270
|
+
dtype=_ot.compute_float(),
|
|
239
271
|
) # (n, H, W)
|
|
240
272
|
image = _xp.asnumpy(_xp.tensordot(w, stack, axes=(0, 0))) # (H, W)
|
|
241
273
|
|
|
@@ -860,6 +892,8 @@ def rebin2_d_array(
|
|
|
860
892
|
|
|
861
893
|
|
|
862
894
|
__all__ = [
|
|
895
|
+
"pad_image_to_shape",
|
|
896
|
+
# "into_4d_full_frame",
|
|
863
897
|
"frame",
|
|
864
898
|
"unwrap_piston",
|
|
865
899
|
"unwrap_image",
|
|
@@ -162,7 +162,7 @@ class _DMProtocol(Protocol):
|
|
|
162
162
|
def set_shape(self, cmd: MatrixLike, differential: bool) -> None: ...
|
|
163
163
|
def get_shape(self) -> ArrayLike: ...
|
|
164
164
|
def upload_cmd_history(
|
|
165
|
-
self, cmdhist: MatrixLike, *,
|
|
165
|
+
self, cmdhist: MatrixLike, *, slaving: bool | str = False
|
|
166
166
|
) -> None: ...
|
|
167
167
|
def run_cmd_history(
|
|
168
168
|
self,
|
|
@@ -453,3 +453,18 @@ def get_device_type(device: object) -> str:
|
|
|
453
453
|
elif isinstance_(device, "CameraDevice"):
|
|
454
454
|
return "camera"
|
|
455
455
|
return device._name
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def compute_float():
|
|
459
|
+
"""
|
|
460
|
+
Floating dtype for numerical work on the active xupy backend.
|
|
461
|
+
|
|
462
|
+
``float32`` on GPU (CuPy) for speed, ``float64`` on CPU (NumPy). This is
|
|
463
|
+
what the removed ``xupy.float`` alias used to resolve to; it is evaluated
|
|
464
|
+
at call time, so it follows ``xupy.use_cpu()`` / ``xupy.use_gpu()``.
|
|
465
|
+
"""
|
|
466
|
+
import xupy as xp
|
|
467
|
+
|
|
468
|
+
dtype = xp.float32 if xp.on_gpu else xp.float64
|
|
469
|
+
del xp
|
|
470
|
+
return dtype
|
|
@@ -558,8 +558,8 @@ def get_cmd_delay(bpath: str = _cfold):
|
|
|
558
558
|
sub_section="DM",
|
|
559
559
|
path=bpath,
|
|
560
560
|
)
|
|
561
|
-
if "
|
|
562
|
-
cmdDelay = float(dm_config["
|
|
561
|
+
if "sequential_delay" in dm_config:
|
|
562
|
+
cmdDelay = float(dm_config["sequential_delay"])
|
|
563
563
|
elif "delay" in dm_config:
|
|
564
564
|
cmdDelay = float(dm_config["delay"])
|
|
565
565
|
elif "triggeredMode" in dm_config and "cmdDelay" in dm_config["triggeredMode"]:
|
|
@@ -351,7 +351,7 @@ class ConfSettingReader4D:
|
|
|
351
351
|
defined object:
|
|
352
352
|
|
|
353
353
|
>>> cr = ConfSettingReader4D(file_path)
|
|
354
|
-
>>> cr.
|
|
354
|
+
>>> cr.get_image_width_in_pixels()
|
|
355
355
|
2000
|
|
356
356
|
>>> cr.get_image_height_in_pixels()
|
|
357
357
|
2000
|
|
@@ -382,13 +382,13 @@ class ConfSettingReader4D:
|
|
|
382
382
|
frame_rate = self.config.get(self.camera_section, "FrameRate")
|
|
383
383
|
return float(frame_rate)
|
|
384
384
|
|
|
385
|
-
def
|
|
385
|
+
def get_image_width_in_pixels(self):
|
|
386
386
|
"""
|
|
387
|
-
Returns the image
|
|
387
|
+
Returns the image width in pixel scale
|
|
388
388
|
|
|
389
389
|
Returns
|
|
390
390
|
-------
|
|
391
|
-
|
|
391
|
+
image_width_in_pixels : int
|
|
392
392
|
Image pixel width.
|
|
393
393
|
"""
|
|
394
394
|
image_width_in_pixels = self.config.get(
|
|
@@ -5,6 +5,7 @@ from opticalib.core import _types as _t
|
|
|
5
5
|
|
|
6
6
|
import weakref
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
def _shutdown_dm(dm, reset: bool, logger, name: str) -> None:
|
|
9
10
|
"""Stop (and optionally Reset) a raw SDK handle. Module-level so it
|
|
10
11
|
holds no reference to the wrapper object."""
|
|
@@ -112,12 +113,15 @@ class BaseAlpaoMirror:
|
|
|
112
113
|
self._resolve_init(sdk_params, plico_params)
|
|
113
114
|
self._is_plico = bool(plico_params[0])
|
|
114
115
|
|
|
115
|
-
self.n_acts =
|
|
116
|
-
self._plico_dm.get_number_of_actuators()
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
self.n_acts = (
|
|
117
|
+
int(self._plico_dm.get_number_of_actuators())
|
|
118
|
+
if self._is_plico
|
|
119
|
+
else int(self._sdk_dm.Get("NbOfActuator"))
|
|
120
|
+
)
|
|
121
|
+
|
|
119
122
|
if self.n_acts != int(nacts):
|
|
120
123
|
import warnings
|
|
124
|
+
|
|
121
125
|
warnings.warn(
|
|
122
126
|
f"Number of actuators reported by the SDK ({self.n_acts}) "
|
|
123
127
|
f"does not match the called number ({nacts}). Verify your BAX files",
|
|
@@ -131,7 +135,7 @@ class BaseAlpaoMirror:
|
|
|
131
135
|
self._name
|
|
132
136
|
].get("diameter", None)
|
|
133
137
|
self.mirrorModes = None
|
|
134
|
-
self.
|
|
138
|
+
self._cmd_history = None
|
|
135
139
|
self.refAct = None
|
|
136
140
|
self.ff = None
|
|
137
141
|
|
|
@@ -194,12 +198,14 @@ class BaseAlpaoMirror:
|
|
|
194
198
|
if not self._is_plico:
|
|
195
199
|
return int(self._sdk_dm.Get("VersionInfo"))
|
|
196
200
|
else:
|
|
197
|
-
raise AttributeError(
|
|
201
|
+
raise AttributeError(
|
|
202
|
+
"Version information is not available for PLICO devices."
|
|
203
|
+
)
|
|
198
204
|
|
|
199
205
|
def close(self) -> None:
|
|
200
206
|
"""
|
|
201
207
|
Stop the DM (and Reset it if ``reset_on_close``) and release the hardware
|
|
202
|
-
resources.
|
|
208
|
+
resources.
|
|
203
209
|
|
|
204
210
|
Should be called when the DM object is no longer needed to
|
|
205
211
|
ensure a clean shutdown of the Alpao SDK connection.
|
|
@@ -311,15 +317,13 @@ class BaseAlpaoMirror:
|
|
|
311
317
|
|
|
312
318
|
def _resolve_init(
|
|
313
319
|
self,
|
|
314
|
-
sdk_params: tuple[str|None, str|None, str|None],
|
|
315
|
-
plico_params: tuple[str|None, str|None, int|None]
|
|
320
|
+
sdk_params: tuple[str | None, str | None, str | None],
|
|
321
|
+
plico_params: tuple[str | None, str | None, int | None],
|
|
316
322
|
):
|
|
317
323
|
sn, sdk_fold, acfg_p = sdk_params
|
|
318
324
|
plico, plico_ip, plico_port = plico_params
|
|
319
325
|
|
|
320
|
-
config = get_section_config(
|
|
321
|
-
"DEVICES", "DEFORMABLE.MIRRORS"
|
|
322
|
-
).get(self._name, {})
|
|
326
|
+
config = get_section_config("DEVICES", "DEFORMABLE.MIRRORS").get(self._name, {})
|
|
323
327
|
|
|
324
328
|
if plico:
|
|
325
329
|
self._plico_ip = config.get("plico_ip", plico_ip)
|
|
@@ -396,9 +400,13 @@ class BaseAlpaoMirror:
|
|
|
396
400
|
os.environ["ACECFG"] = self.acfg_path
|
|
397
401
|
|
|
398
402
|
try:
|
|
399
|
-
sdk_path = self.sdk_folder_path or os.path.join(
|
|
403
|
+
sdk_path = self.sdk_folder_path or os.path.join(
|
|
404
|
+
CONFIGURATION_FOLDER, "alpao_sdk"
|
|
405
|
+
)
|
|
400
406
|
|
|
401
|
-
if self.sdk_folder_path is not None and not os.path.exists(
|
|
407
|
+
if self.sdk_folder_path is not None and not os.path.exists(
|
|
408
|
+
self.sdk_folder_path
|
|
409
|
+
):
|
|
402
410
|
sdk_path = os.path.join(CONFIGURATION_FOLDER, self.sdk_folder_path)
|
|
403
411
|
|
|
404
412
|
if not os.path.exists(sdk_path):
|
|
@@ -36,6 +36,26 @@ class BaseDeformableMirror(ABC):
|
|
|
36
36
|
Base class for all deformable mirror devices.
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
|
+
@property
|
|
40
|
+
def slave_ids(self):
|
|
41
|
+
return self._slaveIds
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def border_ids(self):
|
|
45
|
+
return self._borderIds
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def cmd_history(self) -> _ot.Optional[_ot.MatrixLike]:
|
|
49
|
+
"""
|
|
50
|
+
Get the command history of the simulated deformable mirror (DM).
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
cmd_history : _ot.Optional[_ot.MatrixLike]
|
|
55
|
+
The command history of the DM, or None if no history has been uploaded.
|
|
56
|
+
"""
|
|
57
|
+
return self._cmd_history
|
|
58
|
+
|
|
39
59
|
@abstractmethod
|
|
40
60
|
def set_shape(self, cmd):
|
|
41
61
|
"""
|
|
@@ -97,24 +117,17 @@ class BaseDeformableMirror(ABC):
|
|
|
97
117
|
return None
|
|
98
118
|
return "minimum-rms" if (s and b) else "zero-force"
|
|
99
119
|
|
|
100
|
-
def _apply_slaving(self, cmd: _ot.ArrayLike, slave: bool | str) -> _ot.ArrayLike:
|
|
120
|
+
def _apply_slaving(self, cmd: _ot.ArrayLike|_ot.MatrixLike, slave: bool | str) -> _ot.ArrayLike|_ot.MatrixLike:
|
|
101
121
|
"""
|
|
102
122
|
Apply actuator slaving to a command when requested.
|
|
103
123
|
"""
|
|
104
124
|
method = self._get_slaving_method(slave)
|
|
105
125
|
if method is None:
|
|
106
126
|
return cmd
|
|
127
|
+
if _ot.isinstance_(cmd, "MatrixLike"):
|
|
128
|
+
return compute_slaved_command_matrix(self, cmdmat=cmd, method=slave)
|
|
107
129
|
return compute_slave_cmd(self, cmd, method=method)
|
|
108
130
|
|
|
109
|
-
def _slave_cmdmat(self, cmdmat: _ot.ArrayLike, slave: bool | str) -> _ot.MatrixLike:
|
|
110
|
-
"""
|
|
111
|
-
Apply actuator slaving to a command matrix when requested.
|
|
112
|
-
"""
|
|
113
|
-
method = self._get_slaving_method(slave)
|
|
114
|
-
if method is None:
|
|
115
|
-
return cmdmat
|
|
116
|
-
return compute_slaved_command_matrix(self, cmdmat, method=method)
|
|
117
|
-
|
|
118
131
|
|
|
119
132
|
class BaseCamera(ABC):
|
|
120
133
|
|
|
@@ -31,9 +31,9 @@ class BasePetalMirror:
|
|
|
31
31
|
|
|
32
32
|
self._had_error = False
|
|
33
33
|
self.is_segmented = True
|
|
34
|
-
self.
|
|
35
|
-
self.
|
|
36
|
-
self.n_acts = self.
|
|
34
|
+
self.n_segments = 6
|
|
35
|
+
self.n_acts_per_segment = 3
|
|
36
|
+
self.n_acts = self.n_segments * self.n_acts_per_segment
|
|
37
37
|
self._slaveIds = ptl_config.get("slave_ids", [])
|
|
38
38
|
self._borderIds = ptl_config.get("border_ids", [])
|
|
39
39
|
|
|
@@ -213,7 +213,7 @@ class BasePetalMirror:
|
|
|
213
213
|
CommandError
|
|
214
214
|
If any command is outside the allowed limits.
|
|
215
215
|
"""
|
|
216
|
-
for k in self.
|
|
216
|
+
for k in range(self.n_segments):
|
|
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}")
|
|
@@ -326,4 +326,4 @@ class BasePetalMirror:
|
|
|
326
326
|
raise RuntimeError("Failed to check/enable axes") from err
|
|
327
327
|
|
|
328
328
|
def __repr__(self):
|
|
329
|
-
return f"PetalMirror(
|
|
329
|
+
return f"PetalMirror(n_segments={self.n_segments}, n_acts_per_segment={self.n_acts_per_segment})"
|