opticalib 2.0.0__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.
Files changed (159) hide show
  1. opticalib-2.2.0/CITATION.bib +10 -0
  2. {opticalib-2.0.0 → opticalib-2.2.0}/MANIFEST.in +6 -4
  3. {opticalib-2.0.0/opticalib.egg-info → opticalib-2.2.0}/PKG-INFO +45 -23
  4. {opticalib-2.0.0 → opticalib-2.2.0}/README.md +12 -1
  5. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/__init__.py +12 -16
  6. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/__version__.py +1 -1
  7. opticalib-2.2.0/opticalib/analyzer/__init__.py +13 -0
  8. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/analyzer/image_processing.py +49 -20
  9. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/analyzer/signals.py +9 -10
  10. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/analyzer/timeseries.py +10 -28
  11. opticalib-2.2.0/opticalib/core/__init__.py +17 -0
  12. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/core/_configurations/configuration.yaml +4 -1
  13. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/core/_types.py +85 -16
  14. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/core/config.py +99 -22
  15. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/core/data_classes.py +20 -5
  16. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/core/exceptions.py +9 -1
  17. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/core/root.py +32 -42
  18. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/_API/alpaoAPI.py +185 -64
  19. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/_API/base_devices.py +24 -11
  20. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/_API/i4dAPI.py +5 -2
  21. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/_API/piAPI.py +41 -17
  22. opticalib-2.2.0/opticalib/devices/__init__.py +33 -0
  23. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/cameras.py +8 -13
  24. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/deformable_mirrors.py +151 -128
  25. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/interferometer.py +63 -37
  26. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/wfs.py +7 -19
  27. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/dmutils/__actuator_identification_wip.py +4 -4
  28. opticalib-2.2.0/opticalib/dmutils/__init__.py +33 -0
  29. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/dmutils/__pupil_calibration_wip.py +1 -0
  30. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/dmutils/flattening.py +63 -66
  31. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/dmutils/iff_preparation.py +30 -54
  32. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/dmutils/iff_processing.py +71 -60
  33. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/dmutils/slaving.py +18 -11
  34. opticalib-2.2.0/opticalib/ground/__init__.py +13 -0
  35. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/ground/_stitching_algorithm.py +16 -16
  36. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/ground/geometry.py +18 -13
  37. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/ground/logger.py +17 -28
  38. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/ground/modal_decomposer.py +24 -45
  39. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/ground/osutils.py +19 -13
  40. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/ground/reconstructor.py +64 -10
  41. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/ground/roi.py +40 -20
  42. opticalib-2.2.0/opticalib/gui/__init__.py +56 -0
  43. opticalib-2.2.0/opticalib/gui/activity.py +1069 -0
  44. opticalib-2.2.0/opticalib/gui/app.py +1377 -0
  45. opticalib-2.2.0/opticalib/gui/kernel.py +1177 -0
  46. opticalib-2.2.0/opticalib/gui/kernel_backend.py +63 -0
  47. opticalib-2.2.0/opticalib/gui/kernel_side.py +510 -0
  48. opticalib-2.2.0/opticalib/gui/plugins.py +130 -0
  49. opticalib-2.2.0/opticalib/gui/procedures/__init__.py +14 -0
  50. opticalib-2.2.0/opticalib/gui/procedures/alignment.py +129 -0
  51. opticalib-2.2.0/opticalib/gui/procedures/base.py +732 -0
  52. opticalib-2.2.0/opticalib/gui/procedures/dm_calibration.py +381 -0
  53. opticalib-2.2.0/opticalib/gui/procedures/params.py +684 -0
  54. opticalib-2.2.0/opticalib/gui/procedures/phasing.py +190 -0
  55. opticalib-2.2.0/opticalib/gui/procedures/stitching.py +116 -0
  56. opticalib-2.2.0/opticalib/gui/procedures/timeseries.py +123 -0
  57. opticalib-2.2.0/opticalib/gui/resources/opticalib.ico +0 -0
  58. opticalib-2.2.0/opticalib/gui/resources/opticalib.png +0 -0
  59. opticalib-2.2.0/opticalib/gui/resources/opticalib.svg +25 -0
  60. opticalib-2.2.0/opticalib/gui/theme.py +598 -0
  61. opticalib-2.2.0/opticalib/gui/widgets/__init__.py +9 -0
  62. opticalib-2.2.0/opticalib/gui/widgets/common.py +144 -0
  63. opticalib-2.2.0/opticalib/gui/widgets/config_editor.py +556 -0
  64. opticalib-2.2.0/opticalib/gui/widgets/connect_dialog.py +262 -0
  65. opticalib-2.2.0/opticalib/gui/widgets/data_browser.py +314 -0
  66. opticalib-2.2.0/opticalib/gui/widgets/device_panel.py +857 -0
  67. opticalib-2.2.0/opticalib/gui/widgets/device_registry.py +735 -0
  68. opticalib-2.2.0/opticalib/gui/widgets/plot_viewer.py +839 -0
  69. opticalib-2.2.0/opticalib/gui/widgets/workspace.py +218 -0
  70. opticalib-2.2.0/opticalib/procedures/__init__.py +21 -0
  71. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/procedures/alignment.py +24 -101
  72. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/procedures/iff.py +41 -27
  73. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/procedures/phasing.py +10 -5
  74. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/procedures/stitching.py +20 -16
  75. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/_API/__init__.py +2 -0
  76. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/_API/base_fake_adopticadm.py +74 -79
  77. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/_API/base_fake_alpao.py +28 -85
  78. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/_API/base_petalmirror.py +14 -54
  79. opticalib-2.2.0/opticalib/simulator/_API/base_simulated_dm.py +378 -0
  80. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/__init__.py +2 -0
  81. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/factory.py +3 -3
  82. opticalib-2.2.0/opticalib/simulator/fake_dms.py +278 -0
  83. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/fake_interf.py +5 -5
  84. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/visualization.py +108 -7
  85. {opticalib-2.0.0 → opticalib-2.2.0/opticalib.egg-info}/PKG-INFO +45 -23
  86. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib.egg-info/SOURCES.txt +39 -4
  87. opticalib-2.2.0/opticalib.egg-info/entry_points.txt +5 -0
  88. opticalib-2.2.0/opticalib.egg-info/requires.txt +43 -0
  89. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib.egg-info/top_level.txt +0 -1
  90. opticalib-2.2.0/pyproject.toml +103 -0
  91. opticalib-2.2.0/setup.cfg +4 -0
  92. opticalib-2.2.0/setup_calpy.py +724 -0
  93. opticalib-2.2.0/tests/README.md +110 -0
  94. {opticalib-2.0.0 → opticalib-2.2.0}/tests/conftest.py +53 -3
  95. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_analyzer_images_processing.py +24 -0
  96. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_core_read_config.py +78 -1
  97. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_core_root.py +2 -2
  98. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_devices_deformable_mirrors.py +1 -1
  99. opticalib-2.2.0/tests/test_devices_interferometer.py +93 -0
  100. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_dmutils_flattening.py +2 -2
  101. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_dmutils_iff_acquisition_preparation.py +6 -6
  102. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_dmutils_iff_module.py +2 -2
  103. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_dmutils_iff_processing.py +51 -7
  104. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_ground_roi.py +166 -0
  105. opticalib-2.2.0/tests/test_gui_activity.py +134 -0
  106. opticalib-2.2.0/tests/test_gui_app.py +217 -0
  107. opticalib-2.2.0/tests/test_gui_config_editor.py +232 -0
  108. opticalib-2.2.0/tests/test_gui_devices.py +448 -0
  109. opticalib-2.2.0/tests/test_gui_kernel_bridge.py +310 -0
  110. opticalib-2.2.0/tests/test_gui_kernel_side.py +303 -0
  111. opticalib-2.2.0/tests/test_gui_procedures.py +470 -0
  112. opticalib-2.2.0/tests/test_gui_widgets.py +399 -0
  113. opticalib-2.2.0/tests/test_setup_calpy.py +230 -0
  114. opticalib-2.0.0/opticalib/analyzer/__init__.py +0 -3
  115. opticalib-2.0.0/opticalib/core/__init__.py +0 -21
  116. opticalib-2.0.0/opticalib/devices/__init__.py +0 -45
  117. opticalib-2.0.0/opticalib/dmutils/__init__.py +0 -44
  118. opticalib-2.0.0/opticalib/ground/__init__.py +0 -30
  119. opticalib-2.0.0/opticalib/gui/__init__.py +0 -22
  120. opticalib-2.0.0/opticalib/gui/app.py +0 -1534
  121. opticalib-2.0.0/opticalib/procedures/__init__.py +0 -27
  122. opticalib-2.0.0/opticalib/simulator/_API/_rbf_gpu.py +0 -367
  123. opticalib-2.0.0/opticalib/simulator/fake_dms.py +0 -867
  124. opticalib-2.0.0/opticalib.egg-info/entry_points.txt +0 -2
  125. opticalib-2.0.0/opticalib.egg-info/requires.txt +0 -18
  126. opticalib-2.0.0/requirements.txt +0 -18
  127. opticalib-2.0.0/setup.cfg +0 -28
  128. opticalib-2.0.0/setup.py +0 -48
  129. opticalib-2.0.0/setup_calpy.py +0 -276
  130. opticalib-2.0.0/tests/test_setup_calpy.py +0 -54
  131. {opticalib-2.0.0 → opticalib-2.2.0}/LICENSE +0 -0
  132. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/__init_script__/initCalpy.py +0 -0
  133. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/core/decorators.py +0 -0
  134. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/core/fitsarray.py +0 -0
  135. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/_API/__init__.py +0 -0
  136. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/_API/micAPI.py +0 -0
  137. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/devices/_API/splattAPI.py +0 -0
  138. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/dmutils/_misc.py +0 -0
  139. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/procedures/measurements.py +0 -0
  140. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/py.typed +0 -0
  141. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/_API/alpao_conf.yaml +0 -0
  142. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib/simulator/_API/simdata.py +0 -0
  143. {opticalib-2.0.0 → opticalib-2.2.0}/opticalib.egg-info/dependency_links.txt +0 -0
  144. {opticalib-2.0.0 → opticalib-2.2.0}/tests/__init__.py +0 -0
  145. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_analyzer_signals.py +0 -0
  146. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_analyzer_timeseries.py +0 -0
  147. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_core_dataclass.py +0 -0
  148. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_core_exceptions.py +0 -0
  149. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_core_fits.py +0 -0
  150. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_dmutils_slaving.py +0 -0
  151. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_ground_computerec.py +0 -0
  152. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_ground_geometry.py +0 -0
  153. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_ground_logger.py +0 -0
  154. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_ground_modal_decomposer.py +0 -0
  155. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_ground_osutils.py +0 -0
  156. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_measurements.py +0 -0
  157. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_simulator_factory_functions.py +0 -0
  158. {opticalib-2.0.0 → opticalib-2.2.0}/tests/test_simulator_simdata.py +0 -0
  159. {opticalib-2.0.0 → 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,7 +1,9 @@
1
1
  include README.md
2
- include requirements.txt
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
7
- recursive-include labott *.py
6
+ include opticalib/__init_script__/initCalpy.py
7
+ recursive-include opticalib/gui/resources *.svg *.png *.ico
8
+ graft tests
9
+ global-exclude __pycache__ *.py[cod]
@@ -1,15 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opticalib
3
- Version: 2.0.0
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
- Home-page: https://github.com/ArcetriAdaptiveOptics/opticalib
6
- Author: Adaptive Optics Group - INAF - Osservatorio Astrofisico di Arcetri
7
- Author-email: pietro.ferraiuolo@inaf.it
8
- Maintainer: Pietro Ferraiuolo
9
- License: MIT License
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
- Classifier: Operating System :: Unix
12
+ Classifier: Operating System :: Microsoft :: Windows
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Operating System :: MacOS
13
15
  Requires-Python: >=3.10
14
16
  Description-Content-Type: text/markdown
15
17
  License-File: LICENSE
@@ -22,31 +24,43 @@ Requires-Dist: pipython
22
24
  Requires-Dist: photutils
23
25
  Requires-Dist: scipy
24
26
  Requires-Dist: ruamel.yaml
27
+ Requires-Dist: PyYAML
25
28
  Requires-Dist: Pyro4
26
29
  Requires-Dist: h5py
27
30
  Requires-Dist: jdcal
28
31
  Requires-Dist: tqdm
29
32
  Requires-Dist: matplotlib
30
- Requires-Dist: xupy
31
33
  Requires-Dist: numpy
32
- Requires-Dist: PyQt5
33
- Requires-Dist: qtconsole
34
- Dynamic: author
35
- Dynamic: author-email
36
- Dynamic: classifier
37
- Dynamic: description
38
- Dynamic: description-content-type
39
- Dynamic: home-page
40
- Dynamic: license
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"
41
56
  Dynamic: license-file
42
- Dynamic: maintainer
43
- Dynamic: requires-dist
44
- Dynamic: requires-python
45
- Dynamic: summary
46
57
 
47
58
  # OptiCalib : python framework for OPTical CALibration of deformable mirrors and AO experimentation
48
59
 
49
60
  ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ArcetriAdaptiveOptics/opticalib/tests.yml)
61
+ [![PyPI version](https://img.shields.io/pypi/v/opticalib.svg)](https://pypi.org/project/opticalib/)
62
+ [![Python versions](https://img.shields.io/pypi/pyversions/opticalib.svg)](https://pypi.org/project/opticalib/)
63
+ [![License: MIT](https://img.shields.io/pypi/l/opticalib.svg)](LICENSE)
50
64
 
51
65
  `Adaptive Optics Group, INAF - Osservatorio Astrofisico di Arcetri`
52
66
 
@@ -78,6 +92,14 @@ The latests, stable, version can be installed from pypi:
78
92
  pip install opticalib
79
93
  ```
80
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
+
81
103
  The in-development version can be installed directly from this repository:
82
104
 
83
105
  ```bash
@@ -113,7 +135,7 @@ dm = opt.AlpaoDm(820) # set in the configuration file
113
135
  # an Influence Function by just doing
114
136
 
115
137
  tn = dmutils.iff_module.iffDataAcquisition(dm, interf) # Optional paramenters
116
- # are `modesList, modesAmplitude, template`, which if not specified are
138
+ # are `modeslist, modesAmplitude, template`, which if not specified are
117
139
  # read from the configuration file
118
140
  ```
119
141
 
@@ -1,6 +1,9 @@
1
1
  # OptiCalib : python framework for OPTical CALibration of deformable mirrors and AO experimentation
2
2
 
3
3
  ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ArcetriAdaptiveOptics/opticalib/tests.yml)
4
+ [![PyPI version](https://img.shields.io/pypi/v/opticalib.svg)](https://pypi.org/project/opticalib/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/opticalib.svg)](https://pypi.org/project/opticalib/)
6
+ [![License: MIT](https://img.shields.io/pypi/l/opticalib.svg)](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
@@ -67,7 +78,7 @@ dm = opt.AlpaoDm(820) # set in the configuration file
67
78
  # an Influence Function by just doing
68
79
 
69
80
  tn = dmutils.iff_module.iffDataAcquisition(dm, interf) # Optional paramenters
70
- # are `modesList, modesAmplitude, template`, which if not specified are
81
+ # are `modeslist, modesAmplitude, template`, which if not specified are
71
82
  # read from the configuration file
72
83
  ```
73
84
 
@@ -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
- `opticalib` is a package for the control of laboratory instrumentations, like
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.0.0"
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()
@@ -1,21 +1,14 @@
1
1
  """
2
- Module: images_processing
3
- =========================
2
+ Analyzer — offline image, cube and signal processing
3
+ =====================================================
4
4
 
5
- Author(s)
6
- ---------
7
- - Pietro Ferraiuolo
5
+ Offline analysis of acquired data: single-frame reduction, cube-level
6
+ processing (push-pull, rebin, piston unwrap), spectral analysis (PSD,
7
+ periodograms, Fourier filtering) and time-series diagnostics.
8
8
 
9
- Description
10
- -----------
9
+ These are pure functions — they take arrays in and give arrays (or
10
+ numbers) out, with no device access and no persisted state.
11
11
 
12
- This module provides utilities to process masked optical phase maps and
13
- image cubes, including piston unwrapping, push-pull reduction, rebinning,
14
- Zernike-mode removal, Fourier-domain filtering, and power spectral density
15
- analysis.
16
-
17
- The functions are designed to operate on Opticalib typing aliases and
18
- ``fitsarray``-compatible masked arrays used across the analysis pipeline.
19
12
  """
20
13
 
21
14
  import xupy as _xp
@@ -27,6 +20,38 @@ from ..ground import osutils as osu, modal_decomposer as _md
27
20
  from scipy import stats as _stats, fft as _fft, ndimage as _ndimage
28
21
 
29
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
+
30
55
  def frame(idx: int, mylist: list[_ot.ImageData] | _ot.CubeData) -> _ot.ImageData:
31
56
  """
32
57
  Returns a single frame from a list of files or from a cube.
@@ -213,12 +238,13 @@ def push_pull_reduction_algorithm(
213
238
  Parameters
214
239
  ----------
215
240
  imagelist : list of ImageData | CubeData
216
- List of images for the PushPull acquisition, organized according to the template.
241
+ List of images for the PushPull acquisition, organized according to the
242
+ template.
217
243
  template: int | ArrayLike
218
244
  Template for the PushPull acquisition.
219
245
  normalization : float | int, optional
220
- Normalization factor for the final image. If None, the normalization factor
221
- is set to the template length minus one.
246
+ Normalization factor for the final image. If None, the normalization
247
+ factor is set to the template length minus one.
222
248
 
223
249
  Returns
224
250
  -------
@@ -231,7 +257,7 @@ def push_pull_reduction_algorithm(
231
257
  # Template weights computation
232
258
  w = _xp.asarray(
233
259
  template.astype(_np.result_type(template, imagelist[0].data), copy=True),
234
- dtype=_xp.float,
260
+ dtype=_ot.compute_float(),
235
261
  )
236
262
  if n_images > 2:
237
263
  w[1:-1] *= 2.0
@@ -239,9 +265,9 @@ def push_pull_reduction_algorithm(
239
265
  master_mask = _np.logical_or.reduce([ima.mask for ima in imagelist])
240
266
  # Compute weighted sum over realizations on raw data
241
267
  stack = _xp.stack(
242
- [_xp.asarray(ima.data, dtype=_xp.float) for ima in imagelist],
268
+ [_xp.asarray(ima.data, dtype=_ot.compute_float()) for ima in imagelist],
243
269
  axis=0,
244
- dtype=_xp.float,
270
+ dtype=_ot.compute_float(),
245
271
  ) # (n, H, W)
246
272
  image = _xp.asnumpy(_xp.tensordot(w, stack, axes=(0, 0))) # (H, W)
247
273
 
@@ -262,6 +288,7 @@ def create_cube(fl_or_il: list[str], register: bool = False) -> _ot.CubeData:
262
288
  ----------
263
289
  fl_or_il : list of str
264
290
  Either:
291
+
265
292
  - the list of image file paths;
266
293
  - a list of ImageData.
267
294
  register : int or tuple, optional
@@ -865,6 +892,8 @@ def rebin2_d_array(
865
892
 
866
893
 
867
894
  __all__ = [
895
+ "pad_image_to_shape",
896
+ # "into_4d_full_frame",
868
897
  "frame",
869
898
  "unwrap_piston",
870
899
  "unwrap_image",
@@ -1,16 +1,11 @@
1
1
  """
2
- Module: signals
3
- ===============
2
+ Signal-processing utilities — FFT, PSD, filtering and periodograms
3
+ ==================================================================
4
4
 
5
- Author(s)
6
- ---------
7
- - Pietro Ferraiuolo
5
+ Functions for frequency-domain analysis: Fourier filtering, power spectral
6
+ density estimation, periodogram computation and signal detrending. All
7
+ functions operate on plain arrays and return plain arrays.
8
8
 
9
- Description
10
- -----------
11
-
12
- Module containing functions for signal processing and frequency analysis within
13
- the Opticalib framework.
14
9
  """
15
10
 
16
11
  import numpy as _np
@@ -45,6 +40,7 @@ def extract_frequency_spectrum(
45
40
  Axis along which to compute the FFT (default: -1, last axis).
46
41
  window : str or None, optional
47
42
  Window function to apply before FFT to reduce spectral leakage:
43
+
48
44
  - None: No windowing (rectangular window)
49
45
  - "hann": Hann window (default, good general purpose)
50
46
  - "hamming": Hamming window
@@ -52,17 +48,20 @@ def extract_frequency_spectrum(
52
48
  - "tukey": Tukey window
53
49
  detrend : str or None, optional
54
50
  Detrending method applied before FFT:
51
+
55
52
  - None: No detrending
56
53
  - "constant": Remove mean (default)
57
54
  - "linear": Remove linear trend
58
55
  scaling : str, optional
59
56
  Scaling of the power spectral density:
57
+
60
58
  - "density": Power spectral density (default)
61
59
  - "magnitude": Magnitude spectrum
62
60
 
63
61
  Returns
64
62
  -------
65
63
  dict with keys:
64
+
66
65
  - "frequencies" : 1D ndarray
67
66
  Frequency axis in Hz
68
67
  - "magnitude" : ndarray
@@ -1,32 +1,11 @@
1
1
  """
2
- Module: timeseries
3
- ==================
4
-
5
- Author(s)
6
- ---------
7
- - Runa Briguglio
8
- - Pietro Ferraiuolo
9
-
10
- Description
11
- -----------
12
-
13
- This module provides functions to handle and analyze time series data in the context of Optical Imaging.
14
- It includes utilities for frame extraction, averaging frames, saving and loading averaged images,
15
- computing running differences, calculating running means, and estimating structure functions from
16
- time series data.
17
-
18
- Functions:
19
- - frame: Retrieve a single frame from a list or cube.
20
- - average_frames: Average multiple frames to create an averaged image.
21
- - save_average: Save the averaged image to a file.
22
- - open_average: Load an averaged image from a file.
23
- - running_diff: Compute the running difference between frames with optional zernike removal.
24
- - timevec: Generate a time vector for a set of frames based on their timestamps.
25
- - running_mean: Calculate the running mean of a 1D array.
26
- - structfunc: Compute the structure function for a given time series.
27
-
28
-
29
- This module is part of the OPTICALIB library and relies on other modules within the package for data handling and processing.
2
+ Time-series analysis — frame extraction, running statistics, structure functions
3
+ ================================================================================
4
+
5
+ Utilities for handling time-ordered data: frame extraction and averaging,
6
+ running differences and means, structure-function estimation, and
7
+ timestamp-based time-vector generation.
8
+
30
9
  """
31
10
 
32
11
  import os as _os
@@ -139,6 +118,7 @@ def save_average(
139
118
  be passed on
140
119
  **kwargs : additional optional arguments
141
120
  The same arguments as `average_frames`, to specify the averaging method.
121
+
142
122
  - first : int, optional
143
123
  Index number of the first file to consider. If None, the first file in
144
124
  the list is considered.
@@ -210,6 +190,7 @@ def running_diff(
210
190
  ----------
211
191
  tn_or_fl : str or list[str] or list[ImageData] or CubeData
212
192
  It can either be:
193
+
213
194
  - a tracking number where the frames to process are;
214
195
  - a list of strings with the file list of images to process;
215
196
  - a list of ImageData objects;
@@ -408,6 +389,7 @@ def noise_pushpull(
408
389
  ----------
409
390
  tn_or_fl : str | list[ImageData] | list[str] | CubeData
410
391
  The data to be processed. Can be either:
392
+
411
393
  - A tracking number (str)
412
394
  - A list of file paths (str)
413
395
  - A list of ImageData objects
@@ -0,0 +1,17 @@
1
+ """
2
+ Core — configuration, data folders, shared types and I/O
3
+ ========================================================
4
+
5
+ The :mod:`opticalib.core` package is the foundation of the library. It
6
+ owns the YAML configuration file, the on-disk data folder tree, the
7
+ exception hierarchy, shared decorators, structured data classes for
8
+ passing calibration results between components, and the FITS-aware masked
9
+ array wrappers.
10
+
11
+ Every other area of the library depends on core. Importing it reads
12
+ ``AOCONF``, opens the configuration file, and calls
13
+ :func:`~opticalib.core.root.create_folder_tree` — set the environment
14
+ variable before import (or use the ``calpy`` entry point, which handles
15
+ it automatically).
16
+
17
+ """
@@ -61,11 +61,14 @@ DEVICES:
61
61
  DEFORMABLE.MIRRORS:
62
62
  AlpaoXXX:
63
63
  # AlpaoDM serial number, BAX<YYY>
64
- serialNumber:
64
+ serial_number:
65
65
  # Parent folder containing Lib64/ (e.g. .../Linux/Samples/Python3)
66
66
  sdk_folder_path:
67
67
  # Folder containing the .acfg hardware config file (sets ACECFG env var)
68
68
  acfg_path:
69
+ # IP and PORT needed for the plico_dm backend
70
+ plico_ip:
71
+ plico_port:
69
72
  diameter:
70
73
  slave_ids: []
71
74
  border_ids: []
@@ -1,19 +1,32 @@
1
1
  """
2
- TYPINGS module
3
- ==============
4
- 2025
5
-
6
- Author(s)
7
- ---------
8
- - Pietro Ferraiuolo : pietro.ferraiuolo@inaf.it
9
-
10
- Description
11
- -----------
12
- This module defines custom type aliases and protocols for type hinting
13
- within the `opticalib` package. It includes protocols for matrix-like
14
- objects, image data, cube data, interferometer devices, and deformable
15
- mirror devices. Additionally, it provides a custom `isinstance_` function
16
- to check if an object conforms to these protocols.
2
+ Type System — structural type aliases and device protocols for OptiCalib
3
+ ========================================================================
4
+
5
+ OptiCalib is deliberately *hardware agnostic*. Instead of coupling
6
+ algorithms to concrete classes, this module defines **structural type
7
+ aliases** and **Protocol classes** that describe the *shape* and
8
+ *capabilities* an object must have.
9
+
10
+ Two complementary layers:
11
+
12
+ **Data aliases** — ``MatrixLike``, ``MaskData``, ``ImageData``,
13
+ ``CubeData``, ``FitsData`` — capture what array-shaped payloads look like
14
+ (dimensionality, presence of a mask, FITS serialisability). Every alias
15
+ is a :class:`~typing.TypeVar` bound to a :class:`~typing.Protocol`, so
16
+ static type checkers verify compatibility without any inheritance
17
+ relationship.
18
+
19
+ **Device protocols** — ``InterferometerDevice``, ``WFSDevice``,
20
+ ``CameraDevice``, ``DeformableMirrorDevice`` and their ``Fake*``
21
+ counterparts — specify the *methods* a device must expose. Any object
22
+ that structurally matches the protocol can be passed where the alias is
23
+ expected, whether it is a real driver, a simulator, or a test double.
24
+
25
+ The module is re-exported publicly as ``opticalib.typings``.
26
+
27
+ Because the aliases are structural (not nominal), ``isinstance(x,
28
+ ImageData)`` does **not** work. Use :func:`isinstance_` instead — it
29
+ dispatches to the correct runtime check for the given name.
17
30
 
18
31
  """
19
32
 
@@ -39,7 +52,10 @@ if TYPE_CHECKING:
39
52
  #################################
40
53
  ## DATA TYPES AND TYPE ALIASES ##
41
54
  #################################
55
+ #: A reconstructor object used to convert raw interferometer frames into
56
+ #: phase maps, or ``None`` when no reconstruction is needed.
42
57
  Reconstructor: TypeAlias = Union["ComputeReconstructor", None]
58
+ #: Any plain Python number, i.e. an ``int``, a ``float`` or a ``complex``.
43
59
  Number: TypeAlias = Union[int, float, complex]
44
60
 
45
61
 
@@ -82,10 +98,21 @@ class _CubeProtocol(Protocol):
82
98
  def __array__(self) -> ArrayLike: ...
83
99
 
84
100
 
101
+ #: A generic 2-D matrix, i.e. any object with a ``shape`` that can be
102
+ #: indexed, such as a ``numpy.ndarray`` or a nested list. Used for command matrices,
103
+ #: command histories and other plain numeric tables.
85
104
  MatrixLike = TypeVar("MatrixLike", bound=_MatrixProtocol)
105
+ #: A 2-D boolean (or integer 0/1) mask, typically marking which pixels lie
106
+ #: outside the pupil or region of interest.
86
107
  MaskData = TypeVar("MaskData", bound=_MatrixProtocol)
108
+ #: A single 2-D image with a mask attached, such as a phase map returned by
109
+ #: an interferometer. In practice this is a ``numpy.ma.MaskedArray``.
87
110
  ImageData = TypeVar("ImageData", bound=_ImageDataProtocol)
111
+ #: A 3-D stack of masked images, with shape ``(ny, nx, n_frames)``, such as
112
+ #: the set of influence functions measured for a deformable mirror.
88
113
  CubeData = TypeVar("CubeData", bound=_CubeProtocol)
114
+ #: An array (masked or not) that can be saved to and loaded from a FITS file,
115
+ #: e.g. a :class:`~opticalib.core.fitsarray.FitsArray`.
89
116
  FitsData = TypeVar("FitsData", _FitsArrayProtocol, _FitsMaskedArrayProtocol)
90
117
 
91
118
 
@@ -118,8 +145,13 @@ class _WFSProtocol(Protocol):
118
145
  def acquire_detector(self, **kwargs: dict[str, Any]) -> ImageData: ...
119
146
 
120
147
 
148
+ #: Any interferometer, real or simulated, that can acquire phase maps and
149
+ #: capture/produce raw frame sequences.
121
150
  InterferometerDevice = TypeVar("InterferometerDevice", bound=_InterfProtocol)
151
+ #: Any camera that can acquire frames and get/set its exposure time.
122
152
  CameraDevice = TypeVar("CameraDevice", bound=_CameraProtocol)
153
+ #: Any wavefront sensor that can acquire phase maps, pupil images and raw
154
+ #: detector frames.
123
155
  WFSDevice = TypeVar("WFSDevice", bound=_WFSProtocol)
124
156
 
125
157
 
@@ -130,7 +162,7 @@ class _DMProtocol(Protocol):
130
162
  def set_shape(self, cmd: MatrixLike, differential: bool) -> None: ...
131
163
  def get_shape(self) -> ArrayLike: ...
132
164
  def upload_cmd_history(
133
- self, cmdhist: MatrixLike, *, slave: bool | str = False
165
+ self, cmdhist: MatrixLike, *, slaving: bool | str = False
134
166
  ) -> None: ...
135
167
  def run_cmd_history(
136
168
  self,
@@ -162,14 +194,22 @@ class _FakeInterfProtocol(_InterfProtocol, Protocol):
162
194
  def toggle_shape_removal(self, modes: list[int]) -> None: ...
163
195
 
164
196
 
197
+ #: Any deformable mirror, real or simulated, that can apply a shape, read it
198
+ #: back, and run a timed history of commands.
165
199
  DeformableMirrorDevice = TypeVar("DeformableMirrorDevice", bound=_DMProtocol)
200
+ #: A simulated deformable mirror. It is a ``DeformableMirrorDevice`` that
201
+ #: also exposes its internal mask, Zernike generator and computed wavefront.
166
202
  FakeDeformableMirrorDevice = TypeVar(
167
203
  "FakeDeformableMirrorDevice", bound=_FakeDMProtocol
168
204
  )
205
+ #: A simulated interferometer. It is an ``InterferometerDevice`` that also
206
+ #: offers live-view controls (surface view, noise, shape removal, ...).
169
207
  FakeInterferometerDevice = TypeVar(
170
208
  "FakeInterferometerDevice", bound=_FakeInterfProtocol
171
209
  )
172
210
 
211
+ #: Any device object, with no required methods. Used where a function works
212
+ #: with whichever instrument it is given.
173
213
  GenericDevice = TypeVar("GenericDevice")
174
214
 
175
215
  #######################
@@ -399,3 +439,32 @@ class InstanceCheck:
399
439
 
400
440
 
401
441
  isinstance_ = InstanceCheck.isinstance_
442
+
443
+ ######################
444
+ ## Helper Functions ##
445
+ ######################
446
+
447
+
448
+ def get_device_type(device: object) -> str:
449
+ if isinstance_(device, "InterferometerDevice"):
450
+ return "interf"
451
+ elif isinstance_(device, "WFSDevice"):
452
+ return "wfs"
453
+ elif isinstance_(device, "CameraDevice"):
454
+ return "camera"
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