specula 0.0.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.
- specula-0.0.0/LICENSE +21 -0
- specula-0.0.0/PKG-INFO +86 -0
- specula-0.0.0/README.md +57 -0
- specula-0.0.0/pyproject.toml +50 -0
- specula-0.0.0/requirements.txt +11 -0
- specula-0.0.0/setup.cfg +4 -0
- specula-0.0.0/specula/__init__.py +282 -0
- specula-0.0.0/specula/base_data_obj.py +135 -0
- specula-0.0.0/specula/base_processing_obj.py +267 -0
- specula-0.0.0/specula/base_time_obj.py +115 -0
- specula-0.0.0/specula/base_value.py +75 -0
- specula-0.0.0/specula/calib_manager.py +146 -0
- specula-0.0.0/specula/connections.py +151 -0
- specula-0.0.0/specula/data_objects/__init__.py +0 -0
- specula-0.0.0/specula/data_objects/convolution_kernel.py +427 -0
- specula-0.0.0/specula/data_objects/electric_field.py +338 -0
- specula-0.0.0/specula/data_objects/gaussian_convolution_kernel.py +108 -0
- specula-0.0.0/specula/data_objects/ifunc.py +210 -0
- specula-0.0.0/specula/data_objects/ifunc_inv.py +100 -0
- specula-0.0.0/specula/data_objects/iir_filter_data.py +1191 -0
- specula-0.0.0/specula/data_objects/infinite_phase_screen.py +233 -0
- specula-0.0.0/specula/data_objects/intensity.py +75 -0
- specula-0.0.0/specula/data_objects/intmat.py +265 -0
- specula-0.0.0/specula/data_objects/laser_launch_telescope.py +105 -0
- specula-0.0.0/specula/data_objects/layer.py +104 -0
- specula-0.0.0/specula/data_objects/lenslet.py +76 -0
- specula-0.0.0/specula/data_objects/m2c.py +94 -0
- specula-0.0.0/specula/data_objects/pixels.py +135 -0
- specula-0.0.0/specula/data_objects/pupdata.py +144 -0
- specula-0.0.0/specula/data_objects/pupilstop.py +139 -0
- specula-0.0.0/specula/data_objects/recmat.py +100 -0
- specula-0.0.0/specula/data_objects/simul_params.py +52 -0
- specula-0.0.0/specula/data_objects/slopes.py +280 -0
- specula-0.0.0/specula/data_objects/source.py +182 -0
- specula-0.0.0/specula/data_objects/subap_data.py +83 -0
- specula-0.0.0/specula/data_objects/time_history.py +54 -0
- specula-0.0.0/specula/field_analyser.py +670 -0
- specula-0.0.0/specula/loop_control.py +178 -0
- specula-0.0.0/specula/processing_objects/__init__.py +0 -0
- specula-0.0.0/specula/processing_objects/atmo_evolution.py +290 -0
- specula-0.0.0/specula/processing_objects/atmo_infinite_evolution.py +248 -0
- specula-0.0.0/specula/processing_objects/atmo_propagation.py +285 -0
- specula-0.0.0/specula/processing_objects/atmo_random_phase.py +152 -0
- specula-0.0.0/specula/processing_objects/avc.py +16 -0
- specula-0.0.0/specula/processing_objects/base_generator.py +62 -0
- specula-0.0.0/specula/processing_objects/base_operation.py +141 -0
- specula-0.0.0/specula/processing_objects/base_slicer.py +40 -0
- specula-0.0.0/specula/processing_objects/ccd.py +249 -0
- specula-0.0.0/specula/processing_objects/data_buffer.py +74 -0
- specula-0.0.0/specula/processing_objects/data_print.py +92 -0
- specula-0.0.0/specula/processing_objects/data_source.py +77 -0
- specula-0.0.0/specula/processing_objects/data_store.py +148 -0
- specula-0.0.0/specula/processing_objects/demodulator.py +188 -0
- specula-0.0.0/specula/processing_objects/display_server.py +347 -0
- specula-0.0.0/specula/processing_objects/distributed_sh.py +137 -0
- specula-0.0.0/specula/processing_objects/dm.py +142 -0
- specula-0.0.0/specula/processing_objects/double_roof_slopec.py +44 -0
- specula-0.0.0/specula/processing_objects/electric_field_combinator.py +63 -0
- specula-0.0.0/specula/processing_objects/electric_field_reflection.py +37 -0
- specula-0.0.0/specula/processing_objects/ext_source_pyramid.py +169 -0
- specula-0.0.0/specula/processing_objects/extended_source.py +722 -0
- specula-0.0.0/specula/processing_objects/focal_plane_filter.py +263 -0
- specula-0.0.0/specula/processing_objects/gain_optimizer.py +386 -0
- specula-0.0.0/specula/processing_objects/ideal_derivative_sensor.py +266 -0
- specula-0.0.0/specula/processing_objects/iir_filter.py +197 -0
- specula-0.0.0/specula/processing_objects/im_calibrator.py +194 -0
- specula-0.0.0/specula/processing_objects/integrator.py +52 -0
- specula-0.0.0/specula/processing_objects/linear_combination.py +103 -0
- specula-0.0.0/specula/processing_objects/low_pass_filter.py +32 -0
- specula-0.0.0/specula/processing_objects/mirror_commands_combinator.py +99 -0
- specula-0.0.0/specula/processing_objects/modal_analysis.py +165 -0
- specula-0.0.0/specula/processing_objects/modalrec.py +253 -0
- specula-0.0.0/specula/processing_objects/modalrec_implicit_polc.py +110 -0
- specula-0.0.0/specula/processing_objects/modulated_double_roof.py +219 -0
- specula-0.0.0/specula/processing_objects/modulated_pyramid.py +658 -0
- specula-0.0.0/specula/processing_objects/multi_im_calibrator.py +159 -0
- specula-0.0.0/specula/processing_objects/multi_rec_calibrator.py +83 -0
- specula-0.0.0/specula/processing_objects/mvm.py +71 -0
- specula-0.0.0/specula/processing_objects/optical_gain_estimator.py +130 -0
- specula-0.0.0/specula/processing_objects/phase_flattening.py +63 -0
- specula-0.0.0/specula/processing_objects/poly_chrom_sh.py +68 -0
- specula-0.0.0/specula/processing_objects/poly_chrom_wfs.py +182 -0
- specula-0.0.0/specula/processing_objects/poly_crom_pyramid.py +82 -0
- specula-0.0.0/specula/processing_objects/power_loss.py +44 -0
- specula-0.0.0/specula/processing_objects/psf.py +119 -0
- specula-0.0.0/specula/processing_objects/psf_coronagraph.py +160 -0
- specula-0.0.0/specula/processing_objects/push_pull_generator.py +67 -0
- specula-0.0.0/specula/processing_objects/pyr_pupdata_calibrator.py +346 -0
- specula-0.0.0/specula/processing_objects/pyr_slopec.py +132 -0
- specula-0.0.0/specula/processing_objects/random_generator.py +64 -0
- specula-0.0.0/specula/processing_objects/rec_calibrator.py +86 -0
- specula-0.0.0/specula/processing_objects/schedule_generator.py +52 -0
- specula-0.0.0/specula/processing_objects/sh.py +557 -0
- specula-0.0.0/specula/processing_objects/sh_slopec.py +314 -0
- specula-0.0.0/specula/processing_objects/sh_subap_calibrator.py +110 -0
- specula-0.0.0/specula/processing_objects/slopec.py +132 -0
- specula-0.0.0/specula/processing_objects/sn_calibrator.py +53 -0
- specula-0.0.0/specula/processing_objects/spot_monitor.py +263 -0
- specula-0.0.0/specula/processing_objects/time_history_generator.py +31 -0
- specula-0.0.0/specula/processing_objects/vibration_generator.py +135 -0
- specula-0.0.0/specula/processing_objects/wave_generator.py +75 -0
- specula-0.0.0/specula/processing_objects/windowed_integration.py +55 -0
- specula-0.0.0/specula/processing_objects/zernike_sensor.py +111 -0
- specula-0.0.0/specula/simul.py +1020 -0
- specula-0.0.0/specula/template_processing_obj.py +85 -0
- specula-0.0.0/specula.egg-info/PKG-INFO +86 -0
- specula-0.0.0/specula.egg-info/SOURCES.txt +223 -0
- specula-0.0.0/specula.egg-info/dependency_links.txt +1 -0
- specula-0.0.0/specula.egg-info/entry_points.txt +4 -0
- specula-0.0.0/specula.egg-info/requires.txt +14 -0
- specula-0.0.0/specula.egg-info/top_level.txt +1 -0
- specula-0.0.0/test/test_atmo_evolution.py +430 -0
- specula-0.0.0/test/test_atmo_infinite_evolution.py +557 -0
- specula-0.0.0/test/test_atmo_propagation.py +362 -0
- specula-0.0.0/test/test_atmo_random_phase.py +212 -0
- specula-0.0.0/test/test_atmo_simulation.py +202 -0
- specula-0.0.0/test/test_base_data_obj.py +118 -0
- specula-0.0.0/test/test_base_operation.py +476 -0
- specula-0.0.0/test/test_base_processing_obj.py +246 -0
- specula-0.0.0/test/test_base_slicer.py +57 -0
- specula-0.0.0/test/test_base_time_obj.py +195 -0
- specula-0.0.0/test/test_base_value.py +165 -0
- specula-0.0.0/test/test_calc_psf.py +58 -0
- specula-0.0.0/test/test_calib_manager.py +101 -0
- specula-0.0.0/test/test_ccd.py +153 -0
- specula-0.0.0/test/test_compute_ifs_covmat.py +733 -0
- specula-0.0.0/test/test_compute_zonal_ifunc.py +46 -0
- specula-0.0.0/test/test_connections.py +148 -0
- specula-0.0.0/test/test_convolution_kernel.py +418 -0
- specula-0.0.0/test/test_cov_elong.py +109 -0
- specula-0.0.0/test/test_data_buffer.py +231 -0
- specula-0.0.0/test/test_data_objects.py +42 -0
- specula-0.0.0/test/test_data_print.py +222 -0
- specula-0.0.0/test/test_data_source.py +157 -0
- specula-0.0.0/test/test_data_store.py +215 -0
- specula-0.0.0/test/test_demodulator.py +70 -0
- specula-0.0.0/test/test_diagram.py +130 -0
- specula-0.0.0/test/test_display.py +611 -0
- specula-0.0.0/test/test_display_server.py +40 -0
- specula-0.0.0/test/test_distributed_sh.py +197 -0
- specula-0.0.0/test/test_dm.py +119 -0
- specula-0.0.0/test/test_double_roof.py +145 -0
- specula-0.0.0/test/test_double_roof_calibration.py +136 -0
- specula-0.0.0/test/test_double_roof_slopec.py +89 -0
- specula-0.0.0/test/test_electric_field.py +370 -0
- specula-0.0.0/test/test_elt_m1_ifunc.py +54 -0
- specula-0.0.0/test/test_ext_source_pyr.py +278 -0
- specula-0.0.0/test/test_extended_source.py +372 -0
- specula-0.0.0/test/test_extrapolation_2d.py +237 -0
- specula-0.0.0/test/test_field_analyser.py +288 -0
- specula-0.0.0/test/test_focal_plane_filter.py +390 -0
- specula-0.0.0/test/test_fsoc_lib.py +78 -0
- specula-0.0.0/test/test_gain_optimizer.py +420 -0
- specula-0.0.0/test/test_generators.py +468 -0
- specula-0.0.0/test/test_ideal_derivative_sensor.py +232 -0
- specula-0.0.0/test/test_ifunc.py +130 -0
- specula-0.0.0/test/test_ifunc_inv.py +103 -0
- specula-0.0.0/test/test_iircontrol.py +144 -0
- specula-0.0.0/test/test_iirfilter.py +785 -0
- specula-0.0.0/test/test_im_rec_calibrator.py +362 -0
- specula-0.0.0/test/test_import_class.py +162 -0
- specula-0.0.0/test/test_infinite_phase_screen.py +213 -0
- specula-0.0.0/test/test_init.py +37 -0
- specula-0.0.0/test/test_intensity.py +134 -0
- specula-0.0.0/test/test_interp2d.py +70 -0
- specula-0.0.0/test/test_intmat.py +412 -0
- specula-0.0.0/test/test_laser_launch_telescope.py +137 -0
- specula-0.0.0/test/test_layer.py +86 -0
- specula-0.0.0/test/test_lenslet.py +98 -0
- specula-0.0.0/test/test_linear_combination.py +284 -0
- specula-0.0.0/test/test_local_mean_rebin.py +54 -0
- specula-0.0.0/test/test_loop_control.py +70 -0
- specula-0.0.0/test/test_low_pass_filter_simulation.py +74 -0
- specula-0.0.0/test/test_m2c.py +124 -0
- specula-0.0.0/test/test_make_mask.py +73 -0
- specula-0.0.0/test/test_make_xy.py +76 -0
- specula-0.0.0/test/test_mask.py +154 -0
- specula-0.0.0/test/test_mmse_reconstructor.py +244 -0
- specula-0.0.0/test/test_modal_analysis_simulation.py +58 -0
- specula-0.0.0/test/test_modal_basis.py +104 -0
- specula-0.0.0/test/test_modal_pushpull_signal.py +302 -0
- specula-0.0.0/test/test_modalrec.py +156 -0
- specula-0.0.0/test/test_multi_im_calibrator.py +834 -0
- specula-0.0.0/test/test_multi_rec_calibrator.py +501 -0
- specula-0.0.0/test/test_mvm.py +285 -0
- specula-0.0.0/test/test_optical_gain_estimator.py +103 -0
- specula-0.0.0/test/test_phase_flattening.py +183 -0
- specula-0.0.0/test/test_physical_propagation.py +65 -0
- specula-0.0.0/test/test_pixels.py +92 -0
- specula-0.0.0/test/test_platescale.py +48 -0
- specula-0.0.0/test/test_poly_chrom_pyramid.py +118 -0
- specula-0.0.0/test/test_poly_chrom_sh.py +282 -0
- specula-0.0.0/test/test_power_loss.py +79 -0
- specula-0.0.0/test/test_process_utils.py +48 -0
- specula-0.0.0/test/test_psf.py +435 -0
- specula-0.0.0/test/test_pupdata.py +121 -0
- specula-0.0.0/test/test_pupilstop.py +207 -0
- specula-0.0.0/test/test_pyr.py +553 -0
- specula-0.0.0/test/test_pyr_calibration.py +167 -0
- specula-0.0.0/test/test_pyr_simulation.py +181 -0
- specula-0.0.0/test/test_pyr_slopec.py +153 -0
- specula-0.0.0/test/test_rec_calibrator.py +789 -0
- specula-0.0.0/test/test_recmat.py +99 -0
- specula-0.0.0/test/test_sh.py +147 -0
- specula-0.0.0/test/test_sh_calibration.py +159 -0
- specula-0.0.0/test/test_sh_simulation.py +160 -0
- specula-0.0.0/test/test_sh_slopec.py +400 -0
- specula-0.0.0/test/test_sh_slopec_morfeo.py +687 -0
- specula-0.0.0/test/test_sh_subap_calibrator.py +105 -0
- specula-0.0.0/test/test_simul.py +247 -0
- specula-0.0.0/test/test_simul_params.py +49 -0
- specula-0.0.0/test/test_slopes.py +302 -0
- specula-0.0.0/test/test_sn_calibrator.py +47 -0
- specula-0.0.0/test/test_source.py +89 -0
- specula-0.0.0/test/test_spot_monitor.py +220 -0
- specula-0.0.0/test/test_subapdata.py +77 -0
- specula-0.0.0/test/test_time_history.py +77 -0
- specula-0.0.0/test/test_timehistory_integration.py +66 -0
- specula-0.0.0/test/test_to_xp.py +102 -0
- specula-0.0.0/test/test_toccd.py +99 -0
- specula-0.0.0/test/test_trigger_zero.py +29 -0
- specula-0.0.0/test/test_utils.py +120 -0
- specula-0.0.0/test/test_windowed_integration.py +266 -0
- specula-0.0.0/test/test_zernike.py +113 -0
- specula-0.0.0/test/test_zernike_sensor.py +192 -0
specula-0.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 FabioRossiArcetri
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
specula-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: specula
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: PYramid Simulator Software for Adaptive OpTics Arcetri
|
|
5
|
+
Author: Alfio Puglisi, Guido Agapito, INAF Arcetri Adaptive Optics group
|
|
6
|
+
Author-email: Fabio Rossi <fabio.rossi@inaf.it>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Keywords: Adaptive Optics,Astrophysics,INAF,Arcetri
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: numpy
|
|
16
|
+
Requires-Dist: scipy
|
|
17
|
+
Requires-Dist: astropy
|
|
18
|
+
Requires-Dist: matplotlib
|
|
19
|
+
Requires-Dist: symao>=1.0.1
|
|
20
|
+
Requires-Dist: astro-seeing>=1.1
|
|
21
|
+
Requires-Dist: flask-socketio
|
|
22
|
+
Requires-Dist: python-socketio
|
|
23
|
+
Requires-Dist: requests
|
|
24
|
+
Requires-Dist: pytest
|
|
25
|
+
Requires-Dist: scikit-image
|
|
26
|
+
Provides-Extra: control
|
|
27
|
+
Requires-Dist: iircontrol; extra == "control"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# SPECULA
|
|
31
|
+
Python AO end-to-end simulator
|
|
32
|
+
|
|
33
|
+
SPECULA is a Python-based, object-oriented software derived from [PASSATA](https://arxiv.org/abs/1607.07624) and developed
|
|
34
|
+
by the Adaptive Optics group at the Arcetri Observatory for end-to-end Monte-Carlo simulations of adaptive optics systems.
|
|
35
|
+
It can be accelerated using GPU-CUDA via CuPy.
|
|
36
|
+
|
|
37
|
+
See the documentation here: [specula.readthedocs.io](https://specula.readthedocs.io/en/latest/)
|
|
38
|
+
|
|
39
|
+
## Directories
|
|
40
|
+
|
|
41
|
+
- **docs**: contains the documentation.
|
|
42
|
+
- **main**: contains functions and parameter files to calibrate and run a closed loop of an adaptive optics system (single-conjugated, multi-conjugated, natural, laser, ...).
|
|
43
|
+
- **specula**: the main library, structured as follows:
|
|
44
|
+
- **data_objects**: classes that wrap the data and provide methods to access them.
|
|
45
|
+
- **display**: classes for data visualization.
|
|
46
|
+
- **lib**: utility functions used by multiple objects.
|
|
47
|
+
- **processing_objects**: classes that model the simulation elements as a function of inputs and time.
|
|
48
|
+
- **scripts**: various scripts.
|
|
49
|
+
- **test**: contains functions to test SPECULA using the `unittest` framework.
|
|
50
|
+
|
|
51
|
+
## Requirements
|
|
52
|
+
|
|
53
|
+
- Python 3.8+
|
|
54
|
+
- numpy
|
|
55
|
+
- scipy
|
|
56
|
+
- matplotlib
|
|
57
|
+
- flask
|
|
58
|
+
- flask-socketio
|
|
59
|
+
- socketio
|
|
60
|
+
- scikit-image (for physical propagation)
|
|
61
|
+
- cupy (for GPU acceleration, optional)
|
|
62
|
+
|
|
63
|
+
### Optional libraries
|
|
64
|
+
|
|
65
|
+
Some features require additional libraries:
|
|
66
|
+
- **pycairo**: needed for block diagram generation with orthogram
|
|
67
|
+
- **orthogram**: for automatic block diagram creation (see [orthogram](https://pypi.org/project/orthogram/))
|
|
68
|
+
- **control**: for conversion of transfer function system in SPECULA format and vice-versa and analysis of transfer function
|
|
69
|
+
|
|
70
|
+
Install optional dependencies (pycairo will be installed as dependency of orthogram) with:
|
|
71
|
+
```bash
|
|
72
|
+
pip install orthogram
|
|
73
|
+
pip install control
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Contributing to SPECULA
|
|
77
|
+
To contribute to SPECULA, follow these steps:
|
|
78
|
+
|
|
79
|
+
1. Fork this repository.
|
|
80
|
+
2. Create a branch: `git checkout -b <branch_name>`
|
|
81
|
+
3. Make your changes and **add tests for the new functionality.**
|
|
82
|
+
4. Commit your changes: `git commit -m '<commit_message>'`
|
|
83
|
+
5. Push to the branch: `git push`
|
|
84
|
+
6. Create the pull request.
|
|
85
|
+
|
|
86
|
+
We require tests for all new features to ensure the stability of the project.
|
specula-0.0.0/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# SPECULA
|
|
2
|
+
Python AO end-to-end simulator
|
|
3
|
+
|
|
4
|
+
SPECULA is a Python-based, object-oriented software derived from [PASSATA](https://arxiv.org/abs/1607.07624) and developed
|
|
5
|
+
by the Adaptive Optics group at the Arcetri Observatory for end-to-end Monte-Carlo simulations of adaptive optics systems.
|
|
6
|
+
It can be accelerated using GPU-CUDA via CuPy.
|
|
7
|
+
|
|
8
|
+
See the documentation here: [specula.readthedocs.io](https://specula.readthedocs.io/en/latest/)
|
|
9
|
+
|
|
10
|
+
## Directories
|
|
11
|
+
|
|
12
|
+
- **docs**: contains the documentation.
|
|
13
|
+
- **main**: contains functions and parameter files to calibrate and run a closed loop of an adaptive optics system (single-conjugated, multi-conjugated, natural, laser, ...).
|
|
14
|
+
- **specula**: the main library, structured as follows:
|
|
15
|
+
- **data_objects**: classes that wrap the data and provide methods to access them.
|
|
16
|
+
- **display**: classes for data visualization.
|
|
17
|
+
- **lib**: utility functions used by multiple objects.
|
|
18
|
+
- **processing_objects**: classes that model the simulation elements as a function of inputs and time.
|
|
19
|
+
- **scripts**: various scripts.
|
|
20
|
+
- **test**: contains functions to test SPECULA using the `unittest` framework.
|
|
21
|
+
|
|
22
|
+
## Requirements
|
|
23
|
+
|
|
24
|
+
- Python 3.8+
|
|
25
|
+
- numpy
|
|
26
|
+
- scipy
|
|
27
|
+
- matplotlib
|
|
28
|
+
- flask
|
|
29
|
+
- flask-socketio
|
|
30
|
+
- socketio
|
|
31
|
+
- scikit-image (for physical propagation)
|
|
32
|
+
- cupy (for GPU acceleration, optional)
|
|
33
|
+
|
|
34
|
+
### Optional libraries
|
|
35
|
+
|
|
36
|
+
Some features require additional libraries:
|
|
37
|
+
- **pycairo**: needed for block diagram generation with orthogram
|
|
38
|
+
- **orthogram**: for automatic block diagram creation (see [orthogram](https://pypi.org/project/orthogram/))
|
|
39
|
+
- **control**: for conversion of transfer function system in SPECULA format and vice-versa and analysis of transfer function
|
|
40
|
+
|
|
41
|
+
Install optional dependencies (pycairo will be installed as dependency of orthogram) with:
|
|
42
|
+
```bash
|
|
43
|
+
pip install orthogram
|
|
44
|
+
pip install control
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Contributing to SPECULA
|
|
48
|
+
To contribute to SPECULA, follow these steps:
|
|
49
|
+
|
|
50
|
+
1. Fork this repository.
|
|
51
|
+
2. Create a branch: `git checkout -b <branch_name>`
|
|
52
|
+
3. Make your changes and **add tests for the new functionality.**
|
|
53
|
+
4. Commit your changes: `git commit -m '<commit_message>'`
|
|
54
|
+
5. Push to the branch: `git push`
|
|
55
|
+
6. Create the pull request.
|
|
56
|
+
|
|
57
|
+
We require tests for all new features to ensure the stability of the project.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "specula"
|
|
7
|
+
description = "PYramid Simulator Software for Adaptive OpTics Arcetri"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Fabio Rossi", email = "fabio.rossi@inaf.it" },
|
|
15
|
+
{ name = "Alfio Puglisi" },
|
|
16
|
+
{ name = "Guido Agapito" },
|
|
17
|
+
{ name = "INAF Arcetri Adaptive Optics group" }
|
|
18
|
+
]
|
|
19
|
+
keywords = ["Adaptive Optics", "Astrophysics", "INAF", "Arcetri"]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Operating System :: POSIX :: Linux",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
# IMPORTANT: version must now be declared explicitly or dynamically
|
|
27
|
+
dynamic = ["version", "dependencies"]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
specula_frontend_start = "specula.scripts.web_frontend:start"
|
|
31
|
+
specula_frontend_stop = "specula.scripts.web_frontend:stop"
|
|
32
|
+
specula = "specula.scripts.specula_main:main"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools]
|
|
35
|
+
packages = [
|
|
36
|
+
"specula",
|
|
37
|
+
"specula.data_objects",
|
|
38
|
+
"specula.processing_objects"
|
|
39
|
+
]
|
|
40
|
+
include-package-data = true
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.dynamic]
|
|
43
|
+
dependencies = { file = "requirements.txt" }
|
|
44
|
+
|
|
45
|
+
[project.optional-dependencies]
|
|
46
|
+
control = ["iircontrol"]
|
|
47
|
+
|
|
48
|
+
[tool.setuptools_scm]
|
|
49
|
+
write_to = "specula/_version.py"
|
|
50
|
+
|
specula-0.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import os
|
|
3
|
+
import functools
|
|
4
|
+
from functools import wraps
|
|
5
|
+
|
|
6
|
+
cpu_float_dtype_list = [np.float64, np.float32]
|
|
7
|
+
cpu_complex_dtype_list = [np.complex128, np.complex64]
|
|
8
|
+
array_types = []
|
|
9
|
+
|
|
10
|
+
gpuEnabled = False
|
|
11
|
+
cp = None
|
|
12
|
+
xp = None
|
|
13
|
+
global_precision = None
|
|
14
|
+
float_dtype_list = None
|
|
15
|
+
complex_dtype_list = None
|
|
16
|
+
gpu_float_dtype_list = cpu_float_dtype_list
|
|
17
|
+
gpu_complex_dtype_list = cpu_complex_dtype_list
|
|
18
|
+
float_dtype = None
|
|
19
|
+
complex_dtype = None
|
|
20
|
+
default_target_device_idx = None
|
|
21
|
+
default_target_device = None
|
|
22
|
+
process_comm = None
|
|
23
|
+
process_rank = None
|
|
24
|
+
ASEC2RAD = np.pi / (3600 * 180)
|
|
25
|
+
RAD2ASEC = 1.0 / ASEC2RAD
|
|
26
|
+
MPI_DBG = False
|
|
27
|
+
|
|
28
|
+
MPI_SEND_DBG = False
|
|
29
|
+
|
|
30
|
+
# precision = 0 -> double precision
|
|
31
|
+
# precision = 1 -> single precision
|
|
32
|
+
|
|
33
|
+
# target_device = -1 -> CPU
|
|
34
|
+
# target_device = i>-1 -> GPUi
|
|
35
|
+
|
|
36
|
+
# you might have a GPU working and cupy installed
|
|
37
|
+
# and still want to use the CPU (idx==-1) as default_target_device
|
|
38
|
+
# in this case you might still want to allocate some objects on
|
|
39
|
+
# a GPU device (idx>=0).
|
|
40
|
+
# This can be checked later looking at the value of gpuEnabled.
|
|
41
|
+
|
|
42
|
+
def init(device_idx=-1, precision=0, rank=None, comm=None, mpi_dbg=False):
|
|
43
|
+
global xp
|
|
44
|
+
global cp
|
|
45
|
+
global gpuEnabled
|
|
46
|
+
global global_precision
|
|
47
|
+
global float_dtype_list
|
|
48
|
+
global complex_dtype_list
|
|
49
|
+
global gpu_float_dtype_list
|
|
50
|
+
global gpu_complex_dtype_list
|
|
51
|
+
global array_types
|
|
52
|
+
global float_dtype
|
|
53
|
+
global complex_dtype
|
|
54
|
+
global default_target_device_idx
|
|
55
|
+
global default_target_device
|
|
56
|
+
global process_comm
|
|
57
|
+
global process_rank
|
|
58
|
+
global MPI_DBG
|
|
59
|
+
|
|
60
|
+
MPI_DBG = mpi_dbg
|
|
61
|
+
process_comm = comm
|
|
62
|
+
process_rank = rank
|
|
63
|
+
|
|
64
|
+
default_target_device_idx = device_idx
|
|
65
|
+
systemDisable = os.environ.get('SPECULA_DISABLE_GPU', 'FALSE')
|
|
66
|
+
if systemDisable=='FALSE':
|
|
67
|
+
try:
|
|
68
|
+
import cupy as cp
|
|
69
|
+
print("Cupy import successfull. Installed version is:", cp.__version__)
|
|
70
|
+
gpuEnabled = True
|
|
71
|
+
cp = cp
|
|
72
|
+
except:
|
|
73
|
+
print("Cupy import failed. SPECULA will fall back to CPU use.")
|
|
74
|
+
cp = None
|
|
75
|
+
xp = np
|
|
76
|
+
default_target_device_idx=-1
|
|
77
|
+
else:
|
|
78
|
+
print("env variable SPECULA_DISABLE_GPU prevents using the GPU.")
|
|
79
|
+
cp = None
|
|
80
|
+
xp = np
|
|
81
|
+
default_target_device_idx=-1
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if default_target_device_idx>=0:
|
|
85
|
+
xp = cp
|
|
86
|
+
gpu_float_dtype_list = [cp.float64, cp.float32]
|
|
87
|
+
gpu_complex_dtype_list = [cp.complex128, cp.complex64]
|
|
88
|
+
default_target_device = cp.cuda.Device(default_target_device_idx)
|
|
89
|
+
default_target_device.use()
|
|
90
|
+
print('Default device is GPU number ', default_target_device_idx)
|
|
91
|
+
# print('Using device: ', cp.cuda.runtime.getDeviceProperties(default_target_device)['name'])
|
|
92
|
+
# attributes = default_target_device.attributes
|
|
93
|
+
# properties = cp.cuda.runtime.getDeviceProperties(default_target_device)
|
|
94
|
+
# print('Number of multiprocessors:', attributes['MultiProcessorCount'])
|
|
95
|
+
# print('Global memory size (GB):', properties['totalGlobalMem'] / (1024**3))
|
|
96
|
+
else:
|
|
97
|
+
print('Default device is CPU')
|
|
98
|
+
xp = np
|
|
99
|
+
|
|
100
|
+
if cp is not None:
|
|
101
|
+
array_types = [np.ndarray, cp.ndarray]
|
|
102
|
+
else:
|
|
103
|
+
array_types = [np.ndarray]
|
|
104
|
+
|
|
105
|
+
float_dtype_list = [xp.float64, xp.float32]
|
|
106
|
+
complex_dtype_list = [xp.complex128, xp.complex64]
|
|
107
|
+
global_precision = precision
|
|
108
|
+
float_dtype = float_dtype_list[global_precision]
|
|
109
|
+
complex_dtype = complex_dtype_list[global_precision]
|
|
110
|
+
|
|
111
|
+
# Patch cupy's missing RandomState.random() method
|
|
112
|
+
if cp is not None:
|
|
113
|
+
cp.random.RandomState.random = cp.random.RandomState.random_sample
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# should be used as less as a possible and preferably outside time critical computations
|
|
117
|
+
def cpuArray(v, dtype=None, force_copy=False):
|
|
118
|
+
return to_xp(np, v, dtype=dtype, force_copy=force_copy)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def to_xp(xp, v, dtype=None, force_copy=False):
|
|
122
|
+
'''
|
|
123
|
+
Make sure that v is allocated as an array on this object's device.
|
|
124
|
+
Works for all combinations of np and cp, whether installed or not.
|
|
125
|
+
|
|
126
|
+
Optionally casts to the required dtype (no copy is made if
|
|
127
|
+
the dtype is already the correct one)
|
|
128
|
+
|
|
129
|
+
The main trigger for this function is that np.array() cannot
|
|
130
|
+
be used on a cupy array.
|
|
131
|
+
'''
|
|
132
|
+
if xp is cp:
|
|
133
|
+
if isinstance(v, cp.ndarray) and not force_copy:
|
|
134
|
+
retval = v
|
|
135
|
+
else:
|
|
136
|
+
retval = cp.array(v)
|
|
137
|
+
else:
|
|
138
|
+
if cp is not None and isinstance(v, cp.ndarray):
|
|
139
|
+
retval = v.get()
|
|
140
|
+
elif isinstance(v, np.ndarray) and not force_copy:
|
|
141
|
+
# Avoid extra copy (enabled by numpy default)
|
|
142
|
+
retval = v
|
|
143
|
+
else:
|
|
144
|
+
retval = np.array(v)
|
|
145
|
+
if dtype is None and not force_copy:
|
|
146
|
+
return retval
|
|
147
|
+
else:
|
|
148
|
+
return retval.astype(dtype, copy=force_copy)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class DummyDecoratorAndContextManager():
|
|
152
|
+
def __init__(self):
|
|
153
|
+
pass
|
|
154
|
+
def __enter__(self):
|
|
155
|
+
pass
|
|
156
|
+
def __exit__(self, *args):
|
|
157
|
+
pass
|
|
158
|
+
def __call__(self, f):
|
|
159
|
+
def caller(*args, **kwargs):
|
|
160
|
+
return f(*args, **kwargs)
|
|
161
|
+
return caller
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def show_in_profiler(message=None, color_id=None, argb_color=None, sync=False):
|
|
165
|
+
'''
|
|
166
|
+
Decorator to allow using cupy's TimeRangeDecorator
|
|
167
|
+
in a safe way even when cupy is not installed
|
|
168
|
+
Parameters are the same as TimeRangeDecorator
|
|
169
|
+
'''
|
|
170
|
+
try:
|
|
171
|
+
from cupyx.profiler import time_range
|
|
172
|
+
|
|
173
|
+
return time_range(message=message,
|
|
174
|
+
color_id=color_id,
|
|
175
|
+
argb_color=argb_color,
|
|
176
|
+
sync=sync)
|
|
177
|
+
|
|
178
|
+
except ImportError:
|
|
179
|
+
return DummyDecoratorAndContextManager()
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def fuse(kernel_name=None):
|
|
183
|
+
'''
|
|
184
|
+
Replacement of cupy.fuse() allowing runtime
|
|
185
|
+
dispatch to cupy or numpy.
|
|
186
|
+
|
|
187
|
+
Fused function takes an xp argument that will
|
|
188
|
+
cause it to run as a fused kernel or a standard
|
|
189
|
+
numpy function. The xp argument can be used
|
|
190
|
+
inside the function as usual.
|
|
191
|
+
|
|
192
|
+
Parameters are the same as cp.fuse()
|
|
193
|
+
'''
|
|
194
|
+
def decorator(f):
|
|
195
|
+
f_cp = functools.partial(f, xp=cp)
|
|
196
|
+
f_np = functools.partial(f, xp=np)
|
|
197
|
+
f_cpu = f_np
|
|
198
|
+
if cp:
|
|
199
|
+
f_gpu = cp.fuse(kernel_name=kernel_name)(f_cp)
|
|
200
|
+
else:
|
|
201
|
+
f_gpu = None
|
|
202
|
+
@wraps(f)
|
|
203
|
+
def wrapper(*args, xp, **kwargs):
|
|
204
|
+
if xp == cp:
|
|
205
|
+
return f_gpu(*args, **kwargs)
|
|
206
|
+
else:
|
|
207
|
+
return f_cpu(*args, **kwargs)
|
|
208
|
+
return wrapper
|
|
209
|
+
return decorator
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def main_simul(yml_files: list,
|
|
213
|
+
nsimul = 1,
|
|
214
|
+
cpu: bool=False,
|
|
215
|
+
overrides: str=None,
|
|
216
|
+
target: int=0,
|
|
217
|
+
profile: bool=False,
|
|
218
|
+
mpi: bool=False,
|
|
219
|
+
mpidbg: bool=False,
|
|
220
|
+
stepping: bool=False,
|
|
221
|
+
diagram: bool=False,
|
|
222
|
+
diagram_title: str=None,
|
|
223
|
+
diagram_filename: str=None,
|
|
224
|
+
diagram_colors_on: bool=False):
|
|
225
|
+
|
|
226
|
+
if mpi:
|
|
227
|
+
try:
|
|
228
|
+
from mpi4py import MPI
|
|
229
|
+
from mpi4py.util import pkl5
|
|
230
|
+
print("mpi4py import successfull. Installed version is:", MPI.Get_version())
|
|
231
|
+
except ImportError:
|
|
232
|
+
print("mpi4py import failed.")
|
|
233
|
+
raise
|
|
234
|
+
|
|
235
|
+
comm = pkl5.Intracomm(MPI.COMM_WORLD)
|
|
236
|
+
rank = comm.Get_rank()
|
|
237
|
+
N = 10000000
|
|
238
|
+
datatype = MPI.FLOAT
|
|
239
|
+
num_bytes = N * (datatype.Pack_size(count=1, comm=comm) + MPI.BSEND_OVERHEAD)
|
|
240
|
+
|
|
241
|
+
print(f'MPI buffer size: {num_bytes/1024**2:.2f} MB')
|
|
242
|
+
attached_buf = bytearray(num_bytes)
|
|
243
|
+
MPI.Attach_buffer(attached_buf)
|
|
244
|
+
else:
|
|
245
|
+
rank = None
|
|
246
|
+
comm = None
|
|
247
|
+
|
|
248
|
+
if cpu:
|
|
249
|
+
target_device_idx = -1
|
|
250
|
+
else:
|
|
251
|
+
target_device_idx = target
|
|
252
|
+
|
|
253
|
+
init(target_device_idx, precision=1, rank=rank, comm=comm, mpi_dbg=mpidbg)
|
|
254
|
+
from specula.simul import Simul
|
|
255
|
+
|
|
256
|
+
if profile:
|
|
257
|
+
import cProfile
|
|
258
|
+
import pstats
|
|
259
|
+
pr = cProfile.Profile()
|
|
260
|
+
pr.enable()
|
|
261
|
+
|
|
262
|
+
for simul_idx in range(nsimul):
|
|
263
|
+
print(yml_files)
|
|
264
|
+
Simul(*yml_files,
|
|
265
|
+
simul_idx=simul_idx,
|
|
266
|
+
overrides=overrides,
|
|
267
|
+
stepping=stepping,
|
|
268
|
+
diagram=diagram,
|
|
269
|
+
diagram_filename=diagram_filename,
|
|
270
|
+
diagram_title=diagram_title,
|
|
271
|
+
diagram_colors_on=diagram_colors_on
|
|
272
|
+
).run()
|
|
273
|
+
|
|
274
|
+
if profile:
|
|
275
|
+
pr.disable
|
|
276
|
+
stats = pstats.Stats(pr).sort_stats("cumtime")
|
|
277
|
+
stats.print_stats(r"\((?!\_).*\)$", 200)
|
|
278
|
+
|
|
279
|
+
if mpi:
|
|
280
|
+
MPI.Detach_buffer()
|
|
281
|
+
|
|
282
|
+
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
|
|
2
|
+
import warnings
|
|
3
|
+
from copy import copy
|
|
4
|
+
from functools import lru_cache
|
|
5
|
+
|
|
6
|
+
from specula import cp, np, array_types
|
|
7
|
+
from specula.base_time_obj import BaseTimeObj
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# We use lru_cache() instead of cache() for python 3.8 compatibility
|
|
11
|
+
@lru_cache(maxsize=None)
|
|
12
|
+
def get_properties(cls):
|
|
13
|
+
result = []
|
|
14
|
+
classlist = cls.__mro__
|
|
15
|
+
for cc in classlist:
|
|
16
|
+
result.extend([attr for attr, value in vars(cc).items() if isinstance(value, property) ])
|
|
17
|
+
return result
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BaseDataObj(BaseTimeObj):
|
|
21
|
+
def __init__(self, target_device_idx=None, precision=None):
|
|
22
|
+
"""
|
|
23
|
+
Initialize the base data object.
|
|
24
|
+
|
|
25
|
+
Parameters:
|
|
26
|
+
target_device_idx: int, optional
|
|
27
|
+
device to be targeted for data storage. Set to -1 for CPU,
|
|
28
|
+
to 0 for the first GPU device, 1 for the second GPU device, etc.
|
|
29
|
+
precision: int, optional
|
|
30
|
+
if None will use the global_precision, otherwise set to 0 for double, 1 for single
|
|
31
|
+
"""
|
|
32
|
+
super().__init__(target_device_idx, precision)
|
|
33
|
+
self.generation_time = -1
|
|
34
|
+
self.tag = ''
|
|
35
|
+
|
|
36
|
+
def transferDataTo(self, destobj, force_reallocation=False):
|
|
37
|
+
'''
|
|
38
|
+
Copy CPU/GPU arrays into an existing data object:
|
|
39
|
+
iterate over all self attributes and, if a CPU or GPU array
|
|
40
|
+
is detected, copy data into *destobj* without reallocating.
|
|
41
|
+
|
|
42
|
+
Destination (CPU or GPU device) is inferred by *destobj.target_device_idx*,
|
|
43
|
+
which must be set correctly before calling this method.
|
|
44
|
+
'''
|
|
45
|
+
# Get a list of all attributes, but skip properties
|
|
46
|
+
pp = get_properties(type(self))
|
|
47
|
+
attr_list = [attr for attr in dir(self) if attr not in pp]
|
|
48
|
+
|
|
49
|
+
for attr in attr_list:
|
|
50
|
+
self_attr = getattr(self, attr)
|
|
51
|
+
self_type = type(self_attr)
|
|
52
|
+
if self_type not in array_types:
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
dest_attr = getattr(destobj, attr)
|
|
56
|
+
dest_type = type(dest_attr)
|
|
57
|
+
|
|
58
|
+
if dest_type not in array_types:
|
|
59
|
+
print(f'Warning: destination attribute is not a cupy/numpy array, forcing reallocation ({destobj}.{attr})')
|
|
60
|
+
force_reallocation = True
|
|
61
|
+
|
|
62
|
+
# Destination array had the correct type: perform in-place data copy
|
|
63
|
+
if not force_reallocation:
|
|
64
|
+
# Detect whether the array types are correct for all four cases:
|
|
65
|
+
# Device to CPU, CPU to device, device-to-device, and CPU-CPU. Also check whether
|
|
66
|
+
# the target_device_idx is set correctly for the destination object.
|
|
67
|
+
DtD = cp is not None and (self_type == cp.ndarray) and (dest_type == cp.ndarray) and destobj.target_device_idx >= 0
|
|
68
|
+
DtH = cp is not None and (self_type == cp.ndarray) and (dest_type == np.ndarray) and destobj.target_device_idx == -1
|
|
69
|
+
HtD = cp is not None and (self_type == np.ndarray) and (dest_type == cp.ndarray) and destobj.target_device_idx >= 0
|
|
70
|
+
HtH = (self_type == np.ndarray) and (dest_type == np.ndarray) and destobj.target_device_idx == -1
|
|
71
|
+
if DtD:
|
|
72
|
+
# Performance warnings here are expected, because we might
|
|
73
|
+
# trigger a peer-to-peer transfer between devices
|
|
74
|
+
with warnings.catch_warnings():
|
|
75
|
+
if self.PerformanceWarning:
|
|
76
|
+
warnings.simplefilter("ignore", category=self.PerformanceWarning)
|
|
77
|
+
try:
|
|
78
|
+
dest_attr[:] = self_attr
|
|
79
|
+
except:
|
|
80
|
+
dest_attr = self_attr
|
|
81
|
+
elif DtH:
|
|
82
|
+
# Do not set blocking=True for cupy 12.x compatibility.
|
|
83
|
+
# Blocking is True by default in later versions anyway
|
|
84
|
+
self_attr.get(out=dest_attr)
|
|
85
|
+
elif HtD:
|
|
86
|
+
dest_attr.set(self_attr)
|
|
87
|
+
elif HtH:
|
|
88
|
+
dest_attr[:] = self_attr
|
|
89
|
+
else:
|
|
90
|
+
print(f'Warning: mismatch between target_device_idx and array allocation, forcing reallocation ({destobj}.{attr})')
|
|
91
|
+
force_reallocation = True
|
|
92
|
+
|
|
93
|
+
# Otherwise, reallocate
|
|
94
|
+
if force_reallocation:
|
|
95
|
+
DtD = cp is not None and (self_type == cp.ndarray) and destobj.target_device_idx >= 0
|
|
96
|
+
DtH = cp is not None and (self_type == cp.ndarray) and destobj.target_device_idx == -1
|
|
97
|
+
HtD = (self_type == np.ndarray) and destobj.target_device_idx >= 0
|
|
98
|
+
HtH = (self_type == np.ndarray) and destobj.target_device_idx == -1
|
|
99
|
+
|
|
100
|
+
if DtD:
|
|
101
|
+
# Performance warnings here are expected, because we might
|
|
102
|
+
# trigger a peer-to-peer transfer between devices
|
|
103
|
+
with warnings.catch_warnings():
|
|
104
|
+
if self.PerformanceWarning:
|
|
105
|
+
warnings.simplefilter("ignore", category=self.PerformanceWarning)
|
|
106
|
+
setattr(destobj, attr, cp.asarray(self_attr))
|
|
107
|
+
if DtH:
|
|
108
|
+
# Do not set blocking=True for cupy 12.x compatibility.
|
|
109
|
+
# Blocking is True by default in later versions anyway
|
|
110
|
+
setattr(destobj, attr, self_attr.get())
|
|
111
|
+
if HtD:
|
|
112
|
+
setattr(destobj, attr, cp.asarray(self_attr))
|
|
113
|
+
if HtH:
|
|
114
|
+
setattr(destobj, attr, np.asarray(self_attr))
|
|
115
|
+
|
|
116
|
+
destobj.generation_time = self.generation_time
|
|
117
|
+
|
|
118
|
+
def copyTo(self, target_device_idx):
|
|
119
|
+
'''
|
|
120
|
+
Duplicate a data object on another device,
|
|
121
|
+
alllocating all CPU/GPU arrays on the new device.
|
|
122
|
+
'''
|
|
123
|
+
if target_device_idx == self.target_device_idx:
|
|
124
|
+
return self
|
|
125
|
+
else:
|
|
126
|
+
cloned = copy(self)
|
|
127
|
+
|
|
128
|
+
if target_device_idx >= 0:
|
|
129
|
+
cloned.xp = cp
|
|
130
|
+
else:
|
|
131
|
+
cloned.xp = np
|
|
132
|
+
cloned.target_device_idx = target_device_idx
|
|
133
|
+
|
|
134
|
+
self.transferDataTo(cloned, force_reallocation=True)
|
|
135
|
+
return cloned
|