├── hcipy ├── _math │ ├── __init__.py │ └── cpu.py ├── field │ ├── spherical_grid.py │ ├── __init__.py │ └── polar_grid.py ├── coronagraphy │ ├── shaped_pupil.py │ ├── fqpm.py │ ├── __init__.py │ └── fiber_nuller.py ├── mode_basis │ ├── karhunen_loeve.py │ ├── __init__.py │ ├── gaussian_pokes.py │ └── gaussian_laguerre.py ├── atmosphere │ ├── stored_atmospheric_layer.py │ └── __init__.py ├── wavefront_control │ └── __init__.py ├── config │ ├── __init__.py │ └── default_config.yaml ├── optics │ ├── influence_dm5v2.fits │ ├── tip_tilt_mirror.py │ ├── vibration.py │ ├── thin_lens.py │ ├── periodic_optical_element.py │ ├── magnifier.py │ ├── photonic_lantern.py │ ├── __init__.py │ ├── dynamic_optical_system.py │ ├── segmented_mirror.py │ └── gaussian_beam.py ├── propagation │ ├── propagator.py │ ├── __init__.py │ └── fraunhofer.py ├── metrics │ ├── __init__.py │ └── contrast.py ├── interpolation │ ├── __init__.py │ ├── nearest.py │ └── linear.py ├── plotting │ ├── __init__.py │ ├── error_bars.py │ └── color_scheme.py ├── util │ ├── __init__.py │ ├── matrix_inversion.py │ ├── finite_difference.py │ ├── stats.py │ └── singular_value_decomposition.py ├── fourier │ ├── __init__.py │ └── chirp_z_transform.py ├── wavefront_sensing │ ├── __init__.py │ └── shack_hartmann.py ├── aperture │ └── __init__.py ├── dev.py └── __init__.py ├── tests ├── test_wavefront_control.py ├── test_metrics.py ├── baseline_for_apertures │ ├── eac2 │ │ ├── pupil.fits.gz │ │ └── pupil_without_segment_gaps.fits.gz │ ├── elt │ │ ├── pupil.fits.gz │ │ └── pupil_without_spiders.fits.gz │ ├── gmt │ │ ├── pupil.fits.gz │ │ └── pupil_without_spiders.fits.gz │ ├── habex │ │ └── pupil.fits.gz │ ├── hale │ │ ├── pupil.fits.gz │ │ └── pupil_without_spiders.fits.gz │ ├── hst │ │ ├── pupil.fits.gz │ │ ├── pupil_without_pads.fits.gz │ │ ├── pupil_without_spiders.fits.gz │ │ └── pupil_without_spiders_without_pads.fits.gz │ ├── jwst │ │ ├── pupil.fits.gz │ │ └── pupil_without_spiders.fits.gz │ ├── keck │ │ ├── pupil.fits.gz │ │ ├── pupil_without_spiders.fits.gz │ │ ├── pupil_without_segment_gaps.fits.gz │ │ └── pupil_without_spiders_without_segment_gaps.fits.gz │ ├── tmt │ │ ├── pupil.fits.gz │ │ └── pupil_without_spiders.fits.gz │ ├── vlti │ │ ├── pupil.fits.gz │ │ ├── pupil_non_zenith.fits.gz │ │ ├── pupil_without_spiders.fits.gz │ │ └── pupil_non_zenith_without_spiders.fits.gz │ ├── scexao │ │ ├── pupil.fits.gz │ │ ├── pupil_without_masks.fits │ │ ├── pupil_without_masks.fits.gz │ │ ├── pupil_without_spiders.fits │ │ ├── pupil_without_spiders.fits.gz │ │ ├── pupil_without_spiders_without_masks.fits │ │ ├── pupil_without_spiders_without_masks.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits │ │ ├── lyot_stopouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz │ │ ├── lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz │ │ └── lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz │ ├── subaru │ │ ├── pupil.fits.gz │ │ ├── pupil_without_spiders.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.30_spider=1.00.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.30_spider=1.50.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.35_spider=1.00.fits.gz │ │ ├── lyot_stopouter=0.90_inner=0.35_spider=1.50.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.30_spider=1.00.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.30_spider=1.50.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.35_spider=1.00.fits.gz │ │ ├── lyot_stopouter=0.95_inner=0.35_spider=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50.fits.gz │ │ ├── lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00.fits.gz │ │ └── lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50.fits.gz │ ├── vlt │ │ ├── pupil_ut4.fits.gz │ │ ├── pupil_ut123.fits.gz │ │ ├── pupil_ut4_with_M3_cover.fits.gz │ │ ├── pupil_ut123_without_spiders.fits.gz │ │ ├── pupil_ut4_without_spiders.fits.gz │ │ └── pupil_ut4_without_spiders_with_M3_cover.fits.gz │ ├── hicat_lyot │ │ ├── pupil.fits.gz │ │ └── pupil_without_spiders.fits.gz │ ├── luvoir_a │ │ ├── pupil.fits.gz │ │ ├── pupil_without_spiders.fits.gz │ │ ├── pupil_without_segment_gaps.fits.gz │ │ └── pupil_without_spiders_without_segment_gaps.fits.gz │ ├── luvoir_b │ │ ├── pupil.fits.gz │ │ └── pupil_without_segment_gaps.fits.gz │ ├── magellan │ │ ├── pupil.fits.gz │ │ └── pupil_without_spiders.fits.gz │ ├── hicat_pupil │ │ ├── pupil.fits.gz │ │ ├── pupil_without_spiders.fits.gz │ │ ├── pupil_without_segment_gaps.fits.gz │ │ └── pupil_without_spiders_without_segment_gaps.fits.gz │ ├── polygon │ │ ├── pupil_hex.fits.gz │ │ ├── pupil_pent.fits.gz │ │ ├── pupil_rotated_hex.fits.gz │ │ └── pupil_rotated_pent.fits.gz │ ├── circular │ │ ├── pupil_large.fits.gz │ │ └── pupil_small.fits.gz │ ├── ellipse │ │ ├── pupil_round.fits.gz │ │ └── pupil_elongated.fits.gz │ ├── rectangular │ │ ├── pupil_square.fits.gz │ │ └── pupil_elongated.fits.gz │ ├── luvoir_a_lyot │ │ ├── pupil_1spideroversize_80od.fits.gz │ │ ├── pupil_1spideroversize_90od.fits.gz │ │ ├── pupil_3spideroversize_80od.fits.gz │ │ ├── pupil_3spideroversize_90od.fits.gz │ │ ├── pupil_withoutspiders_1spideroversize_80od.fits.gz │ │ ├── pupil_withoutspiders_1spideroversize_90od.fits.gz │ │ ├── pupil_withoutspiders_3spideroversize_80od.fits.gz │ │ └── pupil_withoutspiders_3spideroversize_90od.fits.gz │ ├── super_gaussian │ │ ├── pupil_large_largeshape_noshift.fits.gz │ │ ├── pupil_large_largeshape_shifted.fits.gz │ │ ├── pupil_large_smallshape_noshift.fits.gz │ │ ├── pupil_large_smallshape_shifted.fits.gz │ │ ├── pupil_small_largeshape_noshift.fits.gz │ │ ├── pupil_small_largeshape_shifted.fits.gz │ │ ├── pupil_small_smallshape_noshift.fits.gz │ │ └── pupil_small_smallshape_shifted.fits.gz │ ├── hexagonal_segmented │ │ ├── pupil_largegap_3rings_largesegment_withcenter.fits.gz │ │ ├── pupil_largegap_3rings_smallsegment_withcenter.fits.gz │ │ ├── pupil_largegap_5rings_largesegment_withcenter.fits.gz │ │ ├── pupil_largegap_5rings_smallsegment_withcenter.fits.gz │ │ ├── pupil_smallgap_3rings_largesegment_withcenter.fits.gz │ │ ├── pupil_smallgap_3rings_smallsegment_withcenter.fits.gz │ │ ├── pupil_smallgap_5rings_largesegment_withcenter.fits.gz │ │ ├── pupil_smallgap_5rings_smallsegment_withcenter.fits.gz │ │ ├── pupil_largegap_3rings_largesegment_withoutcenter.fits.gz │ │ ├── pupil_largegap_3rings_smallsegment_withoutcenter.fits.gz │ │ ├── pupil_largegap_5rings_largesegment_withoutcenter.fits.gz │ │ ├── pupil_largegap_5rings_smallsegment_withoutcenter.fits.gz │ │ ├── pupil_smallgap_3rings_largesegment_withoutcenter.fits.gz │ │ ├── pupil_smallgap_3rings_smallsegment_withoutcenter.fits.gz │ │ ├── pupil_smallgap_5rings_largesegment_withoutcenter.fits.gz │ │ └── pupil_smallgap_5rings_smallsegment_withoutcenter.fits.gz │ └── obstructed_circular │ │ ├── pupil_large_obscuration_3spiders_thickspiders.fits.gz │ │ ├── pupil_large_obscuration_3spiders_thinspiders.fits.gz │ │ ├── pupil_large_obscuration_5spiders_thickspiders.fits.gz │ │ ├── pupil_large_obscuration_5spiders_thinspiders.fits.gz │ │ ├── pupil_small_obscuration_3spiders_thickspiders.fits.gz │ │ ├── pupil_small_obscuration_3spiders_thinspiders.fits.gz │ │ ├── pupil_small_obscuration_5spiders_thickspiders.fits.gz │ │ └── pupil_small_obscuration_5spiders_thinspiders.fits.gz ├── test_config.py ├── conftest.py ├── test_interpolation.py ├── test_math.py └── test_wavefront_sensing.py ├── .github ├── conda_environments │ ├── optional_dependencies.txt │ ├── testing_env.yml │ └── docs_env.yml ├── workflows │ ├── lint.yml │ ├── testing.yml │ └── docs.yml └── flake8_problem_matcher.json ├── .coveragerc ├── doc ├── hcipy_banner.jpg ├── hcipy_banner.png ├── _static │ ├── no_thumb.png │ └── css │ │ └── custom.css ├── tutorial_notebooks │ └── VectorApodizingPhasePlate │ │ ├── vAPP_phase.fits.gz │ │ └── vAPP_amplitude.fits.gz ├── getting_started │ └── index.rst ├── modules │ ├── field.rst │ ├── config.rst │ ├── mode_basis.rst │ ├── util.rst │ ├── fourier.rst │ ├── metrics.rst │ ├── optics.rst │ ├── coronagraphy.rst │ ├── plotting.rst │ ├── aperture.rst │ ├── atmosphere.rst │ ├── propagation.rst │ ├── interpolation.rst │ ├── wavefront_control.rst │ └── wavefront_sensing.rst ├── Makefile ├── citing.rst ├── index.rst ├── team.rst └── development │ ├── new_release.rst │ └── contributing_guide.rst ├── setup.py ├── .gitignore ├── .flake8 ├── .git-blame-ignore-revs ├── LICENSE ├── examples ├── angular_spectrum_propagator.py ├── wavefront_sensor.py ├── phase_screens.py └── noisy_detector.py ├── pyproject.toml └── README.md /hcipy/_math/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hcipy/field/spherical_grid.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test_wavefront_control.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hcipy/coronagraphy/shaped_pupil.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hcipy/mode_basis/karhunen_loeve.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hcipy/atmosphere/stored_atmospheric_layer.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hcipy/wavefront_control/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [] 2 | -------------------------------------------------------------------------------- /.github/conda_environments/optional_dependencies.txt: -------------------------------------------------------------------------------- 1 | mkl_fft 2 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [report] 2 | omit = 3 | */python?.?/* 4 | */tests/* -------------------------------------------------------------------------------- /tests/test_metrics.py: -------------------------------------------------------------------------------- 1 | # check fwhm, contrast, strehl of known functions 2 | -------------------------------------------------------------------------------- /doc/hcipy_banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/doc/hcipy_banner.jpg -------------------------------------------------------------------------------- /doc/hcipy_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/doc/hcipy_banner.png -------------------------------------------------------------------------------- /doc/_static/no_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/doc/_static/no_thumb.png -------------------------------------------------------------------------------- /hcipy/config/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'Configuration' 3 | ] 4 | 5 | from .config import * 6 | -------------------------------------------------------------------------------- /hcipy/optics/influence_dm5v2.fits: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/hcipy/optics/influence_dm5v2.fits -------------------------------------------------------------------------------- /hcipy/propagation/propagator.py: -------------------------------------------------------------------------------- 1 | from ..optics import OpticalElement 2 | 3 | class Propagator(OpticalElement): 4 | pass 5 | -------------------------------------------------------------------------------- /tests/baseline_for_apertures/eac2/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/eac2/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/elt/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/elt/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/gmt/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/gmt/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/habex/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/habex/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hale/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hale/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hst/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hst/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/jwst/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/jwst/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/keck/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/keck/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/tmt/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/tmt/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlti/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlti/pupil.fits.gz -------------------------------------------------------------------------------- /.github/conda_environments/testing_env.yml: -------------------------------------------------------------------------------- 1 | name: ci-env 2 | dependencies: 3 | - numpy 4 | - scipy 5 | - ffmpeg 6 | - conda-forge::pyfftw 7 | -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlt/pupil_ut4.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlt/pupil_ut4.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hicat_lyot/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hicat_lyot/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_b/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_b/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/magellan/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/magellan/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlt/pupil_ut123.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlt/pupil_ut123.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hicat_pupil/pupil.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hicat_pupil/pupil.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/polygon/pupil_hex.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/polygon/pupil_hex.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/polygon/pupil_pent.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/polygon/pupil_pent.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/circular/pupil_large.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/circular/pupil_large.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/circular/pupil_small.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/circular/pupil_small.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/ellipse/pupil_round.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/ellipse/pupil_round.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlti/pupil_non_zenith.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlti/pupil_non_zenith.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/ellipse/pupil_elongated.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/ellipse/pupil_elongated.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hst/pupil_without_pads.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hst/pupil_without_pads.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/pupil_without_masks.fits: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/pupil_without_masks.fits -------------------------------------------------------------------------------- /tests/baseline_for_apertures/elt/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/elt/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/gmt/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/gmt/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hale/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hale/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hst/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hst/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/jwst/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/jwst/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/keck/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/keck/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/polygon/pupil_rotated_hex.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/polygon/pupil_rotated_hex.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/polygon/pupil_rotated_pent.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/polygon/pupil_rotated_pent.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/rectangular/pupil_square.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/rectangular/pupil_square.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/pupil_without_masks.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/pupil_without_masks.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/pupil_without_spiders.fits: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/pupil_without_spiders.fits -------------------------------------------------------------------------------- /tests/baseline_for_apertures/tmt/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/tmt/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlti/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlti/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/rectangular/pupil_elongated.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/rectangular/pupil_elongated.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlt/pupil_ut4_with_M3_cover.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlt/pupil_ut4_with_M3_cover.fits.gz -------------------------------------------------------------------------------- /doc/tutorial_notebooks/VectorApodizingPhasePlate/vAPP_phase.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/doc/tutorial_notebooks/VectorApodizingPhasePlate/vAPP_phase.fits.gz -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | if __name__ == "__main__": 4 | setuptools.setup( 5 | use_scm_version=True, 6 | setup_requires=['setuptools_scm'] 7 | ) 8 | -------------------------------------------------------------------------------- /tests/baseline_for_apertures/eac2/pupil_without_segment_gaps.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/eac2/pupil_without_segment_gaps.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/keck/pupil_without_segment_gaps.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/keck/pupil_without_segment_gaps.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/magellan/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/magellan/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlt/pupil_ut123_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlt/pupil_ut123_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlt/pupil_ut4_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlt/pupil_ut4_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hicat_lyot/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hicat_lyot/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hicat_pupil/pupil_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hicat_pupil/pupil_without_spiders.fits.gz -------------------------------------------------------------------------------- /.github/conda_environments/docs_env.yml: -------------------------------------------------------------------------------- 1 | name: ci-env 2 | dependencies: 3 | - numpy 4 | - scipy 5 | - ffmpeg 6 | - conda-forge::pyfftw 7 | - mkl_fft 8 | - conda-forge::pandoc 9 | -------------------------------------------------------------------------------- /doc/tutorial_notebooks/VectorApodizingPhasePlate/vAPP_amplitude.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/doc/tutorial_notebooks/VectorApodizingPhasePlate/vAPP_amplitude.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a/pupil_without_segment_gaps.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a/pupil_without_segment_gaps.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_b/pupil_without_segment_gaps.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_b/pupil_without_segment_gaps.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hicat_pupil/pupil_without_segment_gaps.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hicat_pupil/pupil_without_segment_gaps.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hst/pupil_without_spiders_without_pads.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hst/pupil_without_spiders_without_pads.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlti/pupil_non_zenith_without_spiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlti/pupil_non_zenith_without_spiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a_lyot/pupil_1spideroversize_80od.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a_lyot/pupil_1spideroversize_80od.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a_lyot/pupil_1spideroversize_90od.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a_lyot/pupil_1spideroversize_90od.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a_lyot/pupil_3spideroversize_80od.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a_lyot/pupil_3spideroversize_80od.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a_lyot/pupil_3spideroversize_90od.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a_lyot/pupil_3spideroversize_90od.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/pupil_without_spiders_without_masks.fits: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/pupil_without_spiders_without_masks.fits -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/pupil_without_spiders_without_masks.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/pupil_without_spiders_without_masks.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/vlt/pupil_ut4_without_spiders_with_M3_cover.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/vlt/pupil_ut4_without_spiders_with_M3_cover.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/super_gaussian/pupil_large_largeshape_noshift.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/super_gaussian/pupil_large_largeshape_noshift.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/super_gaussian/pupil_large_largeshape_shifted.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/super_gaussian/pupil_large_largeshape_shifted.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/super_gaussian/pupil_large_smallshape_noshift.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/super_gaussian/pupil_large_smallshape_noshift.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/super_gaussian/pupil_large_smallshape_shifted.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/super_gaussian/pupil_large_smallshape_shifted.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/super_gaussian/pupil_small_largeshape_noshift.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/super_gaussian/pupil_small_largeshape_noshift.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/super_gaussian/pupil_small_largeshape_shifted.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/super_gaussian/pupil_small_largeshape_shifted.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/super_gaussian/pupil_small_smallshape_noshift.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/super_gaussian/pupil_small_smallshape_noshift.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/super_gaussian/pupil_small_smallshape_shifted.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/super_gaussian/pupil_small_smallshape_shifted.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/keck/pupil_without_spiders_without_segment_gaps.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/keck/pupil_without_spiders_without_segment_gaps.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a/pupil_without_spiders_without_segment_gaps.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a/pupil_without_spiders_without_segment_gaps.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stopouter=0.90_inner=0.30_spider=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stopouter=0.90_inner=0.30_spider=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stopouter=0.90_inner=0.30_spider=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stopouter=0.90_inner=0.30_spider=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stopouter=0.90_inner=0.35_spider=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stopouter=0.90_inner=0.35_spider=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stopouter=0.90_inner=0.35_spider=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stopouter=0.90_inner=0.35_spider=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stopouter=0.95_inner=0.30_spider=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stopouter=0.95_inner=0.30_spider=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stopouter=0.95_inner=0.30_spider=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stopouter=0.95_inner=0.30_spider=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stopouter=0.95_inner=0.35_spider=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stopouter=0.95_inner=0.35_spider=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stopouter=0.95_inner=0.35_spider=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stopouter=0.95_inner=0.35_spider=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hicat_pupil/pupil_without_spiders_without_segment_gaps.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hicat_pupil/pupil_without_spiders_without_segment_gaps.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a_lyot/pupil_withoutspiders_1spideroversize_80od.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a_lyot/pupil_withoutspiders_1spideroversize_80od.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a_lyot/pupil_withoutspiders_1spideroversize_90od.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a_lyot/pupil_withoutspiders_1spideroversize_90od.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a_lyot/pupil_withoutspiders_3spideroversize_80od.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a_lyot/pupil_withoutspiders_3spideroversize_80od.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/luvoir_a_lyot/pupil_withoutspiders_3spideroversize_90od.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/luvoir_a_lyot/pupil_withoutspiders_3spideroversize_90od.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits -------------------------------------------------------------------------------- /doc/getting_started/index.rst: -------------------------------------------------------------------------------- 1 | Getting started with HCIPy 2 | ========================== 3 | 4 | .. toctree:: 5 | 1_coordinates_grids_fields 6 | 2_wavefronts_optical_systems 7 | 3_atmosphere_adaptive_optics 8 | 4_coronagraphy -------------------------------------------------------------------------------- /doc/modules/field.rst: -------------------------------------------------------------------------------- 1 | field - Fields and Grids 2 | ======================== 3 | 4 | .. currentmodule:: hcipy.field 5 | 6 | .. automodapi:: hcipy.field 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stopouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | /dist/ 3 | /*.egg-info 4 | /.vscode 5 | tags 6 | /doc/_build/ 7 | /doc/api/ 8 | /doc/tutorials/ 9 | /.idea/ 10 | /build/ 11 | /.pytest_cache/ 12 | /.eggs/ 13 | .ipynb_checkpoints/ 14 | _version.py 15 | .DS_Store 16 | -------------------------------------------------------------------------------- /doc/modules/config.rst: -------------------------------------------------------------------------------- 1 | config - Configuration file 2 | =========================== 3 | 4 | .. currentmodule:: hcipy.config 5 | 6 | .. automodapi:: hcipy.config 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /doc/modules/mode_basis.rst: -------------------------------------------------------------------------------- 1 | mode_basis - Mode Bases 2 | ======================= 3 | 4 | .. currentmodule:: hcipy.mode_basis 5 | 6 | .. automodapi:: hcipy.mode_basis 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /doc/modules/util.rst: -------------------------------------------------------------------------------- 1 | util - Miscellaneous Utilities 2 | ============================== 3 | 4 | .. currentmodule:: hcipy.util 5 | 6 | .. automodapi:: hcipy.util 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /doc/modules/fourier.rst: -------------------------------------------------------------------------------- 1 | fourier - Fourier transforms 2 | ============================ 3 | 4 | .. currentmodule:: hcipy.fourier 5 | 6 | .. automodapi:: hcipy.fourier 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /doc/modules/metrics.rst: -------------------------------------------------------------------------------- 1 | metrics - Strehl and Contrast 2 | ============================= 3 | 4 | .. currentmodule:: hcipy.metrics 5 | 6 | .. automodapi:: hcipy.metrics 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_3rings_largesegment_withcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_3rings_largesegment_withcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_3rings_smallsegment_withcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_3rings_smallsegment_withcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_5rings_largesegment_withcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_5rings_largesegment_withcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_5rings_smallsegment_withcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_5rings_smallsegment_withcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_3rings_largesegment_withcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_3rings_largesegment_withcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_3rings_smallsegment_withcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_3rings_smallsegment_withcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_5rings_largesegment_withcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_5rings_largesegment_withcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_5rings_smallsegment_withcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_5rings_smallsegment_withcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/obstructed_circular/pupil_large_obscuration_3spiders_thickspiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/obstructed_circular/pupil_large_obscuration_3spiders_thickspiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/obstructed_circular/pupil_large_obscuration_3spiders_thinspiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/obstructed_circular/pupil_large_obscuration_3spiders_thinspiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/obstructed_circular/pupil_large_obscuration_5spiders_thickspiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/obstructed_circular/pupil_large_obscuration_5spiders_thickspiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/obstructed_circular/pupil_large_obscuration_5spiders_thinspiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/obstructed_circular/pupil_large_obscuration_5spiders_thinspiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/obstructed_circular/pupil_small_obscuration_3spiders_thickspiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/obstructed_circular/pupil_small_obscuration_3spiders_thickspiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/obstructed_circular/pupil_small_obscuration_3spiders_thinspiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/obstructed_circular/pupil_small_obscuration_3spiders_thinspiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/obstructed_circular/pupil_small_obscuration_5spiders_thickspiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/obstructed_circular/pupil_small_obscuration_5spiders_thickspiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/obstructed_circular/pupil_small_obscuration_5spiders_thinspiders.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/obstructed_circular/pupil_small_obscuration_5spiders_thinspiders.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/subaru/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50.fits.gz -------------------------------------------------------------------------------- /doc/modules/optics.rst: -------------------------------------------------------------------------------- 1 | optics - General Optical Elements 2 | ================================= 3 | 4 | .. currentmodule:: hcipy.optics 5 | 6 | .. automodapi:: hcipy.optics 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_3rings_largesegment_withoutcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_3rings_largesegment_withoutcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_3rings_smallsegment_withoutcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_3rings_smallsegment_withoutcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_5rings_largesegment_withoutcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_5rings_largesegment_withoutcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_5rings_smallsegment_withoutcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_largegap_5rings_smallsegment_withoutcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_3rings_largesegment_withoutcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_3rings_largesegment_withoutcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_3rings_smallsegment_withoutcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_3rings_smallsegment_withoutcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_5rings_largesegment_withoutcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_5rings_largesegment_withoutcenter.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_5rings_smallsegment_withoutcenter.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/hexagonal_segmented/pupil_smallgap_5rings_smallsegment_withoutcenter.fits.gz -------------------------------------------------------------------------------- /doc/modules/coronagraphy.rst: -------------------------------------------------------------------------------- 1 | coronagraphy - Coronagraphs 2 | =========================== 3 | 4 | .. currentmodule:: hcipy.coronagraphy 5 | 6 | .. automodapi:: hcipy.coronagraphy 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits -------------------------------------------------------------------------------- /doc/modules/plotting.rst: -------------------------------------------------------------------------------- 1 | plotting - Field Plotting Routines 2 | ================================== 3 | 4 | .. currentmodule:: hcipy.plotting 5 | 6 | .. automodapi:: hcipy.plotting 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /doc/modules/aperture.rst: -------------------------------------------------------------------------------- 1 | aperture - Telescope Pupil Generators 2 | ===================================== 3 | 4 | .. currentmodule:: hcipy.aperture 5 | 6 | .. automodapi:: hcipy.aperture 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /doc/modules/atmosphere.rst: -------------------------------------------------------------------------------- 1 | atmosphere - Turbulence generation 2 | ================================== 3 | 4 | .. currentmodule:: hcipy.atmosphere 5 | 6 | .. automodapi:: hcipy.atmosphere 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /doc/modules/propagation.rst: -------------------------------------------------------------------------------- 1 | propagation - Optical Propagators 2 | ================================= 3 | 4 | .. currentmodule:: hcipy.propagation 5 | 6 | .. automodapi:: hcipy.propagation 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spidersouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /doc/modules/interpolation.rst: -------------------------------------------------------------------------------- 1 | interpolation - Interpolation routines 2 | ====================================== 3 | 4 | .. currentmodule:: hcipy.interpolation 5 | 6 | .. automodapi:: hcipy.interpolation 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /doc/modules/wavefront_control.rst: -------------------------------------------------------------------------------- 1 | wavefront_control - Wavefront Control 2 | ===================================== 3 | 4 | .. currentmodule:: hcipy.wavefront_control 5 | 6 | .. automodapi:: hcipy.wavefront_control 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /doc/modules/wavefront_sensing.rst: -------------------------------------------------------------------------------- 1 | wavefront_sensing - Wavefront Sensors 2 | ===================================== 3 | 4 | .. currentmodule:: hcipy.wavefront_sensing 5 | 6 | .. automodapi:: hcipy.wavefront_sensing 7 | :no-inheritance-diagram: 8 | :include-all-objects: 9 | :no-heading: -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.30_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.90_inner=0.35_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.30_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.00_mask=1.50.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.00.fits.gz -------------------------------------------------------------------------------- /tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehpor/hcipy/HEAD/tests/baseline_for_apertures/scexao/lyot_stop_without_spiders_without_masksouter=0.95_inner=0.35_spider=1.50_mask=1.50.fits.gz -------------------------------------------------------------------------------- /hcipy/propagation/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'Propagator', 3 | 'FresnelPropagator', 4 | 'FraunhoferPropagator', 5 | 'AngularSpectrumPropagator' 6 | ] 7 | 8 | from .propagator import * 9 | from .angular_spectrum import * 10 | from .fresnel import * 11 | from .fraunhofer import * 12 | -------------------------------------------------------------------------------- /hcipy/metrics/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'get_strehl_from_focal', 3 | 'get_strehl_from_pupil', 4 | 'get_mean_intensity_in_roi', 5 | 'get_mean_raw_contrast', 6 | 'binned_profile', 7 | 'azimutal_profile', 8 | 'radial_profile' 9 | ] 10 | 11 | from .contrast import * 12 | from .profile import * 13 | -------------------------------------------------------------------------------- /hcipy/interpolation/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'make_linear_interpolator_separated', 3 | 'make_linear_interpolator_unstructured', 4 | 'make_linear_interpolator', 5 | 'make_nearest_interpolator_separated', 6 | 'make_nearest_interpolator_unstructured', 7 | 'make_nearest_interpolator' 8 | ] 9 | 10 | from .linear import * 11 | from .nearest import * 12 | -------------------------------------------------------------------------------- /tests/test_config.py: -------------------------------------------------------------------------------- 1 | from hcipy import * 2 | 3 | def test_config(): 4 | Configuration()['test_config'] = 1 5 | assert Configuration()['test_config'] == 1 6 | 7 | Configuration().test_config = 2 8 | assert Configuration()['test_config'] == 2 9 | 10 | Configuration().update({'test_section': {'test_value': 3}}) 11 | assert Configuration().test_section.test_value == 3 12 | -------------------------------------------------------------------------------- /hcipy/coronagraphy/fqpm.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from .multi_scale import MultiScaleCoronagraph 4 | from ..field import Field 5 | 6 | class FQPMCoronagraph(MultiScaleCoronagraph): 7 | def __init__(self, input_grid, lyot_stop=None, q=1024, scaling_factor=4, window_size=32): 8 | complex_mask = lambda grid: Field(np.sign(grid.x) * np.sign(grid.y), grid).astype('complex') 9 | super().__init__(input_grid, complex_mask, lyot_stop, q, scaling_factor, window_size) 10 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E,W,F,N 3 | 4 | select = 5 | E101 6 | E128 7 | E131 8 | E201 9 | E202 10 | E203 11 | E225 12 | E226 13 | E231 14 | E241 15 | E261 16 | E262 17 | E265 18 | E271 19 | W291 20 | W292 21 | W293 22 | F401 23 | F841 24 | N801 25 | N802 26 | N804 27 | N805 28 | 29 | exclude = 30 | .git 31 | __pycache__ 32 | doc 33 | build 34 | dist 35 | .eggs 36 | examples 37 | -------------------------------------------------------------------------------- /hcipy/plotting/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'FrameWriter', 3 | 'GifWriter', 4 | 'FFMpegWriter', 5 | 'set_color_scheme', 6 | 'colors', 7 | 'errorfill', 8 | 'imshow_field', 9 | 'imsave_field', 10 | 'contour_field', 11 | 'contourf_field', 12 | 'complex_field_to_rgb', 13 | 'imshow_psf', 14 | 'imshow_pupil_phase' 15 | ] 16 | 17 | from .animation import * 18 | from .color_scheme import * 19 | from . import colors 20 | from .error_bars import * 21 | from .field import * 22 | from .util import * 23 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # This file contains all git hashes with far-reaching commits into the codebase. 2 | # We often want to remove these commits from git blame. The commit hashes in 3 | # this file are already removed from the git-blame on Github. You can do the 4 | # same locally with: 5 | # 6 | # > git blame --ignore-revs-file .git-blame-ignore-revs 7 | # 8 | # or set it permanently with: 9 | # 10 | # > git config blame.ignoreRevsFile .git-blame-ignore-revs 11 | 12 | # Changed indentation from tabs to spaces. 13 | f4c6376e9cb198596e7e32cc584ad6ffed31e2ea 14 | 15 | # Changed indentation from tabs to spaces. 16 | 7b9277ee6012a5a230db9aa5b2bf85a879cd8674 17 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import hcipy 3 | 4 | def pytest_addoption(parser): 5 | parser.addoption('--runslow', action='store_true', help='run slow tests') 6 | 7 | def pytest_runtest_setup(item): 8 | if 'slow' in item.keywords and not item.config.getoption('--runslow'): 9 | pytest.skip('Need --runslow option to run.') 10 | 11 | def pytest_configure(config): 12 | config.addinivalue_line('markers', 'slow: marks tests as slow') 13 | 14 | @pytest.fixture(scope='session', autouse=True) 15 | def disable_user_config(): 16 | hcipy.Configuration().reset(enable_user_overrides=False) 17 | yield 18 | hcipy.Configuration().reset() 19 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Linting 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | flake8-lint: 7 | runs-on: ubuntu-latest 8 | name: Flake8 9 | steps: 10 | - name: Check out source repository 11 | uses: actions/checkout@v4 12 | - name: Set up Python environment 13 | uses: actions/setup-python@v5 14 | with: 15 | python-version: "3.11" 16 | - name: Install linting dependencies 17 | run: | 18 | python -m pip install flake8 19 | shell: bash 20 | - name: Lint with flake8 21 | run: | 22 | echo "::add-matcher::.github/flake8_problem_matcher.json" 23 | flake8 . --max-line-length=127 --count --statistics 24 | shell: bash 25 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = HCIPy 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | clean: 18 | rm -rf api 19 | rm -rf _build 20 | rm -rf tutorials 21 | 22 | # Catch-all target: route all unknown targets to Sphinx using the new 23 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 24 | %: Makefile 25 | @python -u "$(SOURCEDIR)/compile_tutorials.py" 26 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 27 | -------------------------------------------------------------------------------- /hcipy/optics/tip_tilt_mirror.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ..mode_basis import ModeBasis 3 | from ..field import Field 4 | from .deformable_mirror import DeformableMirror 5 | 6 | class TipTiltMirror(DeformableMirror): 7 | '''A tip-tilt mirror. 8 | 9 | This deformable mirror class provides a tip-tilt mirror, where the 10 | actuators are controlled in OPD. 11 | 12 | Parameters 13 | ---------- 14 | input_grid : Grid 15 | The grid that corresponds to the input wavefront 16 | ''' 17 | def __init__(self, input_grid): 18 | self.input_grid = input_grid 19 | self.actuators = np.zeros((2,)) 20 | 21 | modes = ModeBasis([Field(self.input_grid.x, self.input_grid), Field(self.input_grid.y, self.input_grid)]) 22 | 23 | super(TipTiltMirror, self).__init__(modes) 24 | -------------------------------------------------------------------------------- /hcipy/coronagraphy/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'generate_app_keller', 3 | 'generate_app_por', 4 | 'VectorApodizingPhasePlate', 5 | 'KnifeEdgeLyotCoronagraph', 6 | 'LyotCoronagraph', 7 | 'MultiScaleCoronagraph', 8 | 'OccultedLyotCoronagraph', 9 | 'PerfectCoronagraph', 10 | 'FQPMCoronagraph', 11 | 'VortexCoronagraph', 12 | 'VectorVortexCoronagraph', 13 | 'make_ravc_masks', 14 | 'get_ravc_planet_transmission', 15 | 'FiberNuller', 16 | 'VortexFiberNuller', 17 | 'PhotonicLanternNuller' 18 | ] 19 | 20 | from .apodizing_phase_plate import * 21 | from .fqpm import * 22 | from .knife_edge import * 23 | from .lyot import * 24 | from .multi_scale import * 25 | from .perfect_coronagraph import * 26 | from .shaped_pupil import * 27 | from .vortex import * 28 | from .fiber_nuller import * 29 | -------------------------------------------------------------------------------- /hcipy/plotting/error_bars.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib as mpl 3 | 4 | def errorfill(x, y, y_err_pos, y_err_neg=None, color=None, alpha_fill=0.25, ax=None, **kwargs): 5 | """ 6 | Plot a line with filled errorbars. 7 | """ 8 | import matplotlib.pyplot as plt 9 | 10 | if ax is None: 11 | ax = plt.gca() 12 | 13 | if y_err_neg is None: 14 | y_err_neg = y_err_pos 15 | 16 | y_min = np.array(y) - np.array(y_err_neg) 17 | y_max = np.array(y) + np.array(y_err_pos) 18 | if color is None: 19 | l = ax.plot(x, y, **kwargs) 20 | color = l[0].get_color() 21 | else: 22 | l = ax.plot(x, y, color=color, **kwargs) 23 | 24 | facecolor = mpl.colors.colorConverter.to_rgba(color, alpha=alpha_fill) 25 | edgecolor = (0, 0, 0, 0) 26 | ax.fill_between(x, y_max, y_min, edgecolor=edgecolor, facecolor=facecolor) 27 | 28 | return l 29 | -------------------------------------------------------------------------------- /hcipy/util/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'SpectralNoiseFactory', 3 | 'SpectralNoise', 4 | 'SpectralNoiseFactoryFFT', 5 | 'SpectralNoiseFFT', 6 | 'SpectralNoiseFactoryMultiscale', 7 | 'SpectralNoiseMultiscale', 8 | 'large_poisson', 9 | 'large_gamma', 10 | 'make_emccd_noise', 11 | 'inverse_truncated', 12 | 'inverse_truncated_modal', 13 | 'inverse_tikhonov', 14 | 'SVD', 15 | 'read_fits', 16 | 'write_fits', 17 | 'read_grid', 18 | 'write_grid', 19 | 'read_field', 20 | 'write_field', 21 | 'read_mode_basis', 22 | 'write_mode_basis', 23 | 'generate_convolution_matrix', 24 | 'make_laplacian_matrix', 25 | 'make_derivative_matrix' 26 | ] 27 | 28 | from .spectral_noise import * 29 | from .stats import * 30 | from .matrix_inversion import * 31 | from .singular_value_decomposition import * 32 | from .io import * 33 | from .finite_difference import * 34 | -------------------------------------------------------------------------------- /hcipy/fourier/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'make_fourier_transform', 3 | 'FourierTransform', 4 | 'ChirpZTransform', 5 | 'make_fft_grid', 6 | 'get_fft_parameters', 7 | 'is_fft_grid', 8 | 'FastFourierTransform', 9 | 'FourierFilter', 10 | 'FourierShift', 11 | 'FourierShear', 12 | 'FourierRotation', 13 | 'MatrixFourierTransform', 14 | 'NaiveFourierTransform', 15 | 'ZoomFastFourierTransform', 16 | 'compute_fourier_performance_dataset', 17 | 'fit_fourier_performance_data', 18 | 'plot_fourier_performance_data', 19 | 'tune_fourier_transforms', 20 | ] 21 | 22 | from .fourier_transform import * 23 | from .chirp_z_transform import * 24 | from .fast_fourier_transform import * 25 | from .fourier_operations import * 26 | from .matrix_fourier_transform import * 27 | from .naive_fourier_transform import * 28 | from .zoom_fast_fourier_transform import * 29 | from .tuning import * 30 | -------------------------------------------------------------------------------- /hcipy/atmosphere/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'MultiLayerAtmosphere', 3 | 'AtmosphericLayer', 4 | 'phase_covariance_von_karman', 5 | 'phase_structure_function_von_karman', 6 | 'power_spectral_density_von_karman', 7 | 'Cn_squared_from_fried_parameter', 8 | 'fried_parameter_from_Cn_squared', 9 | 'seeing_to_fried_parameter', 10 | 'fried_parameter_to_seeing', 11 | 'FiniteAtmosphericLayer', 12 | 'InfiniteAtmosphericLayer', 13 | 'ModalAdaptiveOpticsLayer', 14 | 'make_standard_atmospheric_layers', 15 | 'make_mauna_kea_atmospheric_layers', 16 | 'make_las_campanas_atmospheric_layers', 17 | 'make_keck_atmospheric_layers', 18 | 'make_standard_atmosphere', 19 | ] 20 | 21 | from .atmospheric_model import * 22 | from .finite_atmospheric_layer import * 23 | from .infinite_atmospheric_layer import * 24 | from .modal_adaptive_optics_layer import * 25 | from .standard_atmosphere import * 26 | -------------------------------------------------------------------------------- /.github/flake8_problem_matcher.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "flake8-error", 5 | "severity": "error", 6 | "pattern": [ 7 | { 8 | "regexp": "^([^:]*):(\\d+):(\\d+): ([E]\\d\\d\\d) (.*)$", 9 | "file": 1, 10 | "line": 2, 11 | "column": 3, 12 | "code": 4, 13 | "message": 5 14 | } 15 | ] 16 | }, 17 | { 18 | "owner": "flake8-warning", 19 | "severity": "warning", 20 | "pattern": [ 21 | { 22 | "regexp": "^([^:]*):(\\d+):(\\d+): ([FWN]\\d\\d\\d) (.*)$", 23 | "file": 1, 24 | "line": 2, 25 | "column": 3, 26 | "code": 4, 27 | "message": 5 28 | } 29 | ] 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /hcipy/wavefront_sensing/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'WavefrontSensorOptics', 3 | 'WavefrontSensorEstimator', 4 | 'make_odwfs_amplitude_filter', 5 | 'make_polarization_odwfs_amplitude_filter', 6 | 'optical_differentiation_surface', 7 | 'OpticalDifferentiationWavefrontSensorOptics', 8 | 'OpticalDifferentiationWavefrontSensorEstimator', 9 | 'ModulatedPyramidWavefrontSensorOptics', 10 | 'PyramidWavefrontSensorOptics', 11 | 'PyramidWavefrontSensorEstimator', 12 | 'ShackHartmannWavefrontSensorOptics', 13 | 'SquareShackHartmannWavefrontSensorOptics', 14 | 'ShackHartmannWavefrontSensorEstimator', 15 | 'ZernikeWavefrontSensorOptics', 16 | 'ZernikeWavefrontSensorEstimator', 17 | 'VectorZernikeWavefrontSensorOptics' 18 | ] 19 | 20 | from .optical_differentiation_wavefront_sensor import * 21 | from .pyramid import * 22 | from .shack_hartmann import * 23 | from .wavefront_sensor import * 24 | from .zernike_wavefront_sensor import * 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Emiel H. Por 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. 22 | -------------------------------------------------------------------------------- /hcipy/mode_basis/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'ModeBasis', 3 | 'make_gaussian_hermite_basis', 4 | 'gaussian_hermite_index', 5 | 'gaussian_hermite', 6 | 'index_to_hermite', 7 | 'gaussian_laguerre', 8 | 'make_gaussian_laguerre_basis', 9 | 'make_gaussian_pokes', 10 | 'make_sine_basis', 11 | 'make_cosine_basis', 12 | 'make_fourier_basis', 13 | 'make_complex_fourier_basis', 14 | 'make_lp_modes', 15 | 'make_LP_modes', 16 | 'make_hexike_basis', 17 | 'hexike', 18 | 'hexike_ansi', 19 | 'hexike_noll', 20 | 'make_zernike_basis', 21 | 'zernike', 22 | 'zernike_noll', 23 | 'zernike_ansi', 24 | 'noll_to_zernike', 25 | 'zernike_to_noll', 26 | 'ansi_to_zernike', 27 | 'zernike_to_ansi', 28 | 'disk_harmonic', 29 | 'disk_harmonic_energy', 30 | 'make_disk_harmonic_basis', 31 | ] 32 | 33 | from .disk_harmonic import * 34 | from .fourier import * 35 | from .gaussian_hermite import * 36 | from .gaussian_laguerre import * 37 | from .gaussian_pokes import * 38 | from .karhunen_loeve import * 39 | from .mode_basis import * 40 | from .lp_fiber_modes import * 41 | from .zernike import * 42 | -------------------------------------------------------------------------------- /examples/angular_spectrum_propagator.py: -------------------------------------------------------------------------------- 1 | from hcipy import * 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | wavelength = 1e-6 # m 6 | D_tel = 100 * wavelength 7 | N_over = 4 8 | F_num = 3 9 | distance = D_tel * F_num 10 | k = 2*np.pi / wavelength 11 | 12 | N_samp = 1024 13 | pupil_grid = make_pupil_grid(N_samp, D_tel*N_over) 14 | aperture = make_circular_aperture(D_tel) 15 | focal_grid = make_focal_grid(pupil_grid, 1, 500) 16 | 17 | fresnel = FresnelPropagator(pupil_grid, distance) 18 | ASP = AngularSpectrumPropagator(pupil_grid, distance) 19 | props = [fresnel, ASP] 20 | 21 | aper = aperture(pupil_grid) * np.exp(-1j * k * pupil_grid.as_('polar').r**2 / (2 * distance)) 22 | tilts = ((0, 0), (10, 10), (20, 20)) 23 | Ntilts = len(tilts) 24 | 25 | for j, tilt in enumerate(tilts): 26 | 27 | phase_tilt = 2*np.pi * (pupil_grid.x / D_tel * tilt[0] + pupil_grid.y / D_tel * tilt[1]) 28 | aper *= np.exp(1j * phase_tilt) 29 | 30 | wf = Wavefront(aper, wavelength) 31 | wf.total_power = 1 32 | 33 | for i, prop in enumerate(props): 34 | img = prop(wf) 35 | 36 | plt.subplot(Ntilts, 2, 2*j + i + 1) 37 | imshow_field(np.log10(img.intensity / img.intensity.max()), vmin=-5) 38 | plt.show() 39 | -------------------------------------------------------------------------------- /doc/citing.rst: -------------------------------------------------------------------------------- 1 | Citing HCIPy 2 | ============ 3 | 4 | If you use HCIPy for your own research, we ask you to cite the HCIPy proceeding (`Por et al. 2018 `__). If there is no appropriate place in the body text to cite the proceeding, please include something along the lines of the following in your acknowledgements: 5 | 6 | This research made use of HCIPy, an open-source object-oriented framework written in Python for performing end-to-end simulations of high-contrast imaging instruments (`Por et al. 2018 `__). 7 | 8 | The BibTeX citation can be found below: 9 | 10 | .. code-block:: bib 11 | 12 | @inproceedings{por2018hcipy, 13 | author = {Por, E.~H. and Haffert, S.~Y. and Radhakrishnan, V.~M. and Doelman, D.~S. and Van Kooten, M. and Bos, S.~P.}, 14 | title = "{High Contrast Imaging for Python (HCIPy): an open-source adaptive optics and coronagraph simulator}", 15 | booktitle = {Adaptive Optics Systems VI}, 16 | year = 2018, 17 | series = {Proc. {{SPIE}}}, 18 | volume = 10703, 19 | doi = {10.1117/12.2314407}, 20 | URL = {https://doi.org/10.1117/12.2314407} 21 | } 22 | -------------------------------------------------------------------------------- /hcipy/optics/vibration.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from .optical_element import OpticalElement 4 | 5 | class SimpleVibration(OpticalElement): 6 | def __init__(self, mode, amplitude, frequency, phase_0=0): 7 | self.mode = mode 8 | self.amplitude = amplitude 9 | self.frequency = frequency 10 | self.phase_0 = phase_0 11 | self.t = 0 12 | 13 | @property 14 | def frequency(self): 15 | return self._frequency 16 | 17 | @frequency.setter 18 | def frequency(self, frequency): 19 | delta_phase = 2 * np.pi * (self.frequency + self.frequency) 20 | self.phase_0 += delta_phase 21 | self._frequency = frequency 22 | 23 | @property 24 | def phase(self): 25 | return 2 * np.pi * self.frequency * self.t + self.phase_0 26 | 27 | def forward(self, wavefront): 28 | wf = wavefront.copy() 29 | 30 | wf.electric_field *= np.exp(1j * (self.mode * self.amplitude / wf.wavelength * np.sin(self.phase))) 31 | return wf 32 | 33 | def backward(self, wavefront): 34 | wf = wavefront.copy() 35 | 36 | wf.electric_field *= np.exp(-1j * (self.mode * self.amplitude / wf.wavelength * np.sin(self.phase))) 37 | return wf 38 | -------------------------------------------------------------------------------- /hcipy/field/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'Grid', 3 | 'Field', 4 | 'CartesianGrid', 5 | 'PolarGrid', 6 | 'UnstructuredCoords', 7 | 'SeparatedCoords', 8 | 'RegularCoords', 9 | 'field_einsum', 10 | 'field_dot', 11 | 'field_trace', 12 | 'field_inv', 13 | 'field_inverse_tikhonov', 14 | 'field_inverse_truncated', 15 | 'field_inverse_truncated_modal', 16 | 'field_svd', 17 | 'make_field_operation', 18 | 'field_conjugate_transpose', 19 | 'field_transpose', 20 | 'field_determinant', 21 | 'field_adjoint', 22 | 'field_cross', 23 | 'field_kron', 24 | 'make_uniform_grid', 25 | 'make_pupil_grid', 26 | 'make_focal_grid_from_pupil_grid', 27 | 'make_focal_grid', 28 | 'make_hexagonal_grid', 29 | 'make_chebyshev_grid', 30 | 'make_supersampled_grid', 31 | 'make_subsampled_grid', 32 | 'subsample_field', 33 | 'evaluate_supersampled', 34 | 'make_uniform_vector_field', 35 | 'make_uniform_vector_field_generator', 36 | 'is_field', 37 | ] 38 | 39 | from .grid import * 40 | from .coordinates import * 41 | from .cartesian_grid import * 42 | from .operations import * 43 | from .polar_grid import * 44 | from .spherical_grid import * 45 | from .field import * 46 | from .util import * 47 | -------------------------------------------------------------------------------- /hcipy/aperture/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'circular_aperture', 3 | 'make_circular_aperture', 4 | 'elliptical_aperture', 5 | 'make_elliptical_aperture', 6 | 'rectangular_aperture', 7 | 'make_rectangular_aperture', 8 | 'irregular_polygon_aperture', 9 | 'make_irregular_polygon_aperture', 10 | 'regular_polygon_aperture', 11 | 'make_regular_polygon_aperture', 12 | 'hexagonal_aperture', 13 | 'make_hexagonal_aperture', 14 | 'make_spider', 15 | 'make_spider_infinite', 16 | 'make_obstructed_circular_aperture', 17 | 'make_obstruction', 18 | 'make_rotated_aperture', 19 | 'make_shifted_aperture', 20 | 'make_inverted_aperture', 21 | 'make_segmented_aperture', 22 | 'make_super_gaussian_aperture', 23 | 'make_elt_aperture', 24 | 'make_gmt_aperture', 25 | 'make_tmt_aperture', 26 | 'make_hexagonal_segmented_aperture', 27 | 'make_magellan_aperture', 28 | 'make_luvoir_a_aperture', 29 | 'make_luvoir_a_lyot_stop', 30 | 'make_luvoir_b_aperture', 31 | 'make_hale_aperture', 32 | 'make_hicat_aperture', 33 | 'make_hicat_lyot_stop', 34 | 'make_vlt_aperture', 35 | 'make_vlti_aperture', 36 | 'make_vlti_dopd_map', 37 | 'make_habex_aperture', 38 | 'make_hst_aperture', 39 | 'make_jwst_aperture', 40 | 'make_keck_aperture', 41 | 'make_eac2_aperture', 42 | 'make_subaru_aperture', 43 | 'make_subaru_lyot_stop', 44 | 'make_scexao_aperture', 45 | 'make_scexao_lyot_stop', 46 | ] 47 | 48 | from .generic import * 49 | from .realistic import * 50 | -------------------------------------------------------------------------------- /hcipy/optics/thin_lens.py: -------------------------------------------------------------------------------- 1 | from .surface_profiles import parabolic_surface_sag 2 | from .apodization import SurfaceApodizer 3 | 4 | class ThinLens(SurfaceApodizer): 5 | '''A parabolic thin lens. 6 | 7 | Parameters 8 | ---------- 9 | focal_length : scalar 10 | The focal length of the thin lens at the refernce wavelength. 11 | refractive_index : scalar or function of wavelength 12 | The refractive index of the lens material. 13 | reference_wavelength : scalar 14 | The wavelength for which the focal length is defined. 15 | 16 | ''' 17 | def __init__(self, focal_length, refractive_index, reference_wavelength): 18 | self._focal_length = focal_length 19 | self._refractive_index = refractive_index 20 | self._reference_wavelength = reference_wavelength 21 | 22 | n0 = refractive_index(reference_wavelength) 23 | radius_of_curvature = focal_length * (n0 - 1) 24 | sag = parabolic_surface_sag(-radius_of_curvature) 25 | super().__init__(sag, refractive_index) 26 | 27 | @property 28 | def focal_length(self): 29 | '''The focal length of the lens. 30 | ''' 31 | return self._focal_length 32 | 33 | @focal_length.setter 34 | def focal_length(self, focal_length): 35 | self._focal_length = focal_length 36 | 37 | n0 = self._refractive_index(self._reference_wavelength) 38 | radius_of_curvature = focal_length * (n0 - 1) 39 | sag = parabolic_surface_sag(-radius_of_curvature) 40 | 41 | self.surface_sag = sag 42 | -------------------------------------------------------------------------------- /hcipy/dev.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import warnings 3 | 4 | def deprecated(reason): # pragma: no cover 5 | '''Decorator for deprecating functions. 6 | 7 | Parameters 8 | ---------- 9 | reason : str 10 | The reason for deprecation. This will be printed with the warning. 11 | 12 | Returns 13 | ------- 14 | function 15 | The new function that emits a DeprecationWarning upon use. 16 | ''' 17 | def decorator(func): 18 | @functools.wraps(func) 19 | def wrapped(*args, **kwargs): 20 | warnings.warn(f'{func.__name__} is deprecated. {reason}', DeprecationWarning, stacklevel=2) 21 | return func(*args, **kwargs) 22 | 23 | return wrapped 24 | return decorator 25 | 26 | def deprecated_name_changed(new_func): # pragma: no cover 27 | '''Decorator for deprecating functions with a name change. 28 | 29 | Parameters 30 | ---------- 31 | new_func : function 32 | The new function with the same functionality. 33 | 34 | Returns 35 | ------- 36 | function 37 | The new function that emits a DeprecationWarning upon use. 38 | ''' 39 | def decorator(old_func): 40 | # I'm sure there is a way to use deprecated() above, but I can't figure that out right now. 41 | @functools.wraps(new_func) 42 | def wrapped(*args, **kwargs): 43 | message = f'{old_func.__name__} is deprecated. Its new name is {new_func.__name__}.' 44 | warnings.warn(message, DeprecationWarning, stacklevel=2) 45 | 46 | return new_func(*args, **kwargs) 47 | 48 | return wrapped 49 | return decorator 50 | -------------------------------------------------------------------------------- /hcipy/_math/cpu.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import multiprocessing 4 | 5 | def get_num_available_cores(): 6 | '''Get the number of cores available on the system. 7 | 8 | The attempt at retrieving the number of cores that our process 9 | is assigned may not be available on all operating systems. On 10 | unsupported operating systems, the total number of cores is 11 | returned instead. 12 | 13 | Returns 14 | ------- 15 | int 16 | The number of available cores. 17 | 18 | Raises 19 | ------ 20 | RuntimeError 21 | If we are unable to 22 | ''' 23 | if hasattr(os, 'sched_getaffinity'): 24 | return len(os.sched_getaffinity(0)) 25 | elif platform.system() == 'Windows': 26 | import ctypes 27 | import ctypes.wintypes 28 | 29 | kernel32 = ctypes.WinDLL('kernel32') 30 | 31 | DWORD_PTR = ctypes.wintypes.WPARAM 32 | PDWORD_PTR = ctypes.POINTER(DWORD_PTR) 33 | 34 | GetCurrentProcess = kernel32.GetCurrentProcess 35 | GetCurrentProcess.restype = ctypes.wintypes.HANDLE 36 | 37 | GetProcessAffinityMask = kernel32.GetProcessAffinityMask 38 | GetProcessAffinityMask.argtypes = (ctypes.wintypes.HANDLE, PDWORD_PTR, PDWORD_PTR) 39 | 40 | mask = DWORD_PTR() 41 | 42 | if GetProcessAffinityMask(GetCurrentProcess(), ctypes.byref(mask), ctypes.byref(DWORD_PTR())): 43 | # Call successful. Return result. 44 | return bin(mask.value).count('1') 45 | 46 | # Operating system is unsupported or the call to retrieve the 47 | # core count has failed. Fall back to all cores. 48 | return multiprocessing.cpu_count() 49 | -------------------------------------------------------------------------------- /hcipy/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa 2 | 3 | try: 4 | from ._version import version as __version__ 5 | except ImportError: 6 | __version__ = '' 7 | 8 | # Import all submodules. 9 | from . import aperture 10 | from . import atmosphere 11 | from . import config 12 | from . import coronagraphy 13 | from . import field 14 | from . import fourier 15 | from . import interpolation 16 | from . import metrics 17 | from . import mode_basis 18 | from . import optics 19 | from . import plotting 20 | from . import propagation 21 | from . import util 22 | from . import wavefront_control 23 | from . import wavefront_sensing 24 | 25 | # Import all core submodules in default namespace. 26 | from .aperture import * 27 | from .atmosphere import * 28 | from .config import * 29 | from .coronagraphy import * 30 | from .field import * 31 | from .fourier import * 32 | from .interpolation import * 33 | from .metrics import * 34 | from .mode_basis import * 35 | from .optics import * 36 | from .plotting import * 37 | from .propagation import * 38 | from .util import * 39 | from .wavefront_control import * 40 | from .wavefront_sensing import * 41 | 42 | # Export default namespaces. 43 | __all__ = [] 44 | __all__.extend(aperture.__all__) 45 | __all__.extend(atmosphere.__all__) 46 | __all__.extend(config.__all__) 47 | __all__.extend(coronagraphy.__all__) 48 | __all__.extend(field.__all__) 49 | __all__.extend(fourier.__all__) 50 | __all__.extend(interpolation.__all__) 51 | __all__.extend(metrics.__all__) 52 | __all__.extend(mode_basis.__all__) 53 | __all__.extend(optics.__all__) 54 | __all__.extend(plotting.__all__) 55 | __all__.extend(propagation.__all__) 56 | __all__.extend(util.__all__) 57 | __all__.extend(wavefront_control.__all__) 58 | __all__.extend(wavefront_sensing.__all__) 59 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | HCIPy: High Contrast Imaging for Python 2 | ======================================= 3 | 4 | .. image:: hcipy_banner.jpg 5 | 6 | HCIPy is a framework written in Python for high contrast imaging simulation work. It implements adaptive optics simulation, coronagraphy and optical diffraction calculations. This page contains the HCIPy documentation. 7 | 8 | The banner above shows a number of simulations done with HCIPy. From left to right: Gaussian-Laguerre modes plotted in combined phase-amplitude images, a pupil-plane image showing atmospheric scintillation, a focal-plane image of speckles for a self-coherent camera with a charge 4 vortex coronagraph, a focal-plane image of a circumstellar disk in polarization with a broadband vector apodizing phase plate coronagraph, and an image for a Pyramid wavefront sensor. Please visit the :doc:`tutorials` for more examples of what HCIPy can do. 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | :caption: Getting Started 13 | 14 | installation 15 | getting_started/index 16 | tutorials/index 17 | citing 18 | team 19 | changelog 20 | 21 | .. toctree:: 22 | :maxdepth: 1 23 | :caption: HCIPy Package 24 | 25 | modules/aperture 26 | modules/atmosphere 27 | modules/config 28 | modules/coronagraphy 29 | modules/field 30 | modules/fourier 31 | modules/interpolation 32 | modules/metrics 33 | modules/mode_basis 34 | modules/optics 35 | modules/plotting 36 | modules/propagation 37 | modules/util 38 | modules/wavefront_control 39 | modules/wavefront_sensing 40 | 41 | .. toctree:: 42 | :maxdepth: 1 43 | :caption: Developer resources 44 | 45 | development/contributing_guide 46 | development/project_setup 47 | development/new_release 48 | -------------------------------------------------------------------------------- /tests/test_interpolation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | import hcipy 4 | 5 | def make_separated_field(): 6 | grid = hcipy.make_uniform_grid([4, 4], [1, 1]) 7 | values = np.arange(grid.size) 8 | 9 | return hcipy.Field(values, grid) 10 | 11 | def make_unstructured_field(): 12 | field = make_separated_field() 13 | grid = hcipy.CartesianGrid(hcipy.UnstructuredCoords((field.grid.x, field.grid.y))) 14 | 15 | return hcipy.Field(field, grid) 16 | 17 | def make_separated_grid(): 18 | return hcipy.make_uniform_grid([2, 2], [0.8, 0.8]) 19 | 20 | def make_unstructured_grid(): 21 | grid = make_separated_grid() 22 | return hcipy.CartesianGrid(hcipy.UnstructuredCoords((grid.x, grid.y))) 23 | 24 | fields = [ 25 | pytest.param(make_separated_field(), id='separated_in'), 26 | pytest.param(make_unstructured_field(), id='unstructured_in'), 27 | ] 28 | 29 | grids = [ 30 | pytest.param(make_separated_grid(), id='separated_out'), 31 | pytest.param(make_unstructured_grid(), id='unstructured_out'), 32 | ] 33 | 34 | @pytest.mark.parametrize('grid_out', grids) 35 | @pytest.mark.parametrize('field_in', fields) 36 | def test_linear_interpolator(field_in, grid_out): 37 | interpolator = hcipy.make_linear_interpolator(field_in) 38 | field_out = interpolator(grid_out) 39 | 40 | expected_values = np.array([3.5, 5.1, 9.9, 11.5]) 41 | assert np.allclose(field_out, expected_values) 42 | 43 | @pytest.mark.parametrize('grid_out', grids) 44 | @pytest.mark.parametrize('field_in', fields) 45 | def test_nearest_interpolator(field_in, grid_out): 46 | interpolator = hcipy.make_nearest_interpolator(field_in) 47 | field_out = interpolator(grid_out) 48 | 49 | expected_values = np.array([5, 6, 9, 10]) 50 | assert np.allclose(field_out, expected_values) 51 | -------------------------------------------------------------------------------- /hcipy/optics/periodic_optical_element.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .optical_element import OpticalElement 3 | from ..field import CartesianGrid, UnstructuredCoords 4 | 5 | class PeriodicOpticalElement(OpticalElement): 6 | def __init__(self, input_grid, pitch, apodization, orientation=0, even_grid=False): 7 | '''An even asphere micro-lens array. 8 | 9 | Parameters 10 | ---------- 11 | input_grid : Grid 12 | The grid on which the periodic optical element is evaluated. 13 | pitch : scalar 14 | The pitch of the periodic optical element. 15 | apodization : Apodizer 16 | The apodizer that will be evaluated on the periodic grid. 17 | orientation : scalar 18 | The orientation of the periodic optical element. 19 | even_grid : bool 20 | This determines whether zero is in between two elements or if it is the center of an element. 21 | ''' 22 | self.input_grid = input_grid.copy() 23 | self.input_grid = self.input_grid.rotated(orientation) 24 | 25 | if even_grid: 26 | xf = (np.fmod(abs(self.input_grid.x), pitch) - pitch / 2) * np.sign(self.input_grid.x) 27 | yf = (np.fmod(abs(self.input_grid.y), pitch) - pitch / 2) * np.sign(self.input_grid.y) 28 | else: 29 | xf = (np.fmod(abs(self.input_grid.x) + pitch / 2, pitch) - pitch / 2) * np.sign(self.input_grid.x) 30 | yf = (np.fmod(abs(self.input_grid.y) + pitch / 2, pitch) - pitch / 2) * np.sign(self.input_grid.y) 31 | 32 | periodic_grid = CartesianGrid(UnstructuredCoords((xf, yf))) 33 | self.apodization = apodization(periodic_grid) 34 | 35 | def forward(self, wavefront): 36 | wf = wavefront.copy() 37 | return self.apodization.forward(wf) 38 | 39 | def backward(self, wavefront): 40 | wf = wavefront.copy() 41 | return self.apodization.backward(wf) 42 | -------------------------------------------------------------------------------- /examples/wavefront_sensor.py: -------------------------------------------------------------------------------- 1 | from hcipy import * 2 | from matplotlib import pyplot as plt 3 | import numpy as np 4 | 5 | def test_pupil_plane_wavefront_sensors(): 6 | # Create the input grid 7 | D = 1 8 | pupil_grid = make_pupil_grid(128, D) 9 | aperture = make_circular_aperture(D) 10 | 11 | # Make zernike basis 12 | num_zernike = 3 13 | zernike_basis = make_zernike_basis(num_zernike, D, pupil_grid, 2) 14 | 15 | # Create wavefront sensors 16 | pyramid_wfs = PyramidWavefrontSensorOptics(pupil_grid) 17 | zernike_wfs = ZernikeWavefrontSensorOptics(pupil_grid, q=32, num_airy=20) 18 | god_wfs = gODWavefrontSensorOptics(40, 1/3, pupil_grid, pupil_separation=1.5, q=16, num_airy=40) 19 | pod_wfs = PolgODWavefrontSensorOptics(40, 1/3, pupil_grid, pupil_separation=1.5, q=16, num_airy=40) 20 | 21 | wavefront_sensors = (pyramid_wfs, zernike_wfs, god_wfs, pod_wfs) 22 | num_wfs = len(wavefront_sensors) 23 | 24 | # Create reference images 25 | wf = Wavefront(aperture(pupil_grid)) 26 | wf.total_power = 1 27 | refs = [wfs.forward(wf).intensity for wfs in wavefront_sensors] 28 | eff = [wfs.forward(wf).total_power for wfs in wavefront_sensors] 29 | print("Total efficiency : ", eff) 30 | 31 | for i in range(num_wfs): 32 | plt.subplot(2,2,i+1) 33 | imshow_field(refs[i], wavefront_sensors[i].output_grid) 34 | plt.show() 35 | 36 | for i, zern in enumerate(zernike_basis): 37 | # create input 38 | wf = Wavefront(aperture(pupil_grid) * np.exp(1j * 0.01 * zern)) 39 | wf.total_power = 1 40 | 41 | # Measure the response of all wavefront sensors 42 | for j, wfs in enumerate(wavefront_sensors): 43 | wf_out = wfs.forward(wf) 44 | print(wf_out.total_power) 45 | plt.subplot(num_wfs, num_zernike, i+1 + num_zernike*j) 46 | imshow_field(wf_out.intensity-refs[j]) 47 | 48 | plt.show() 49 | 50 | 51 | 52 | if __name__ == "__main__": 53 | test_pupil_plane_wavefront_sensors() 54 | -------------------------------------------------------------------------------- /hcipy/mode_basis/gaussian_pokes.py: -------------------------------------------------------------------------------- 1 | from ..field import evaluate_supersampled 2 | import numpy as np 3 | from scipy.sparse import csr_matrix 4 | 5 | def make_gaussian_pokes(grid, mu, sigma, cutoff=5): 6 | '''Make a basis of Gaussians. 7 | 8 | Parameters 9 | ---------- 10 | grid : Grid or None 11 | The grid on which to calculate the mode basis. If this is None, a list of Field 12 | generators will be returned instead of a mode basis. 13 | mu : Grid 14 | The centers for each of the Gaussians. 15 | sigma : ndarray or scalar 16 | The standard deviation of each of the Gaussians. If this is a scalar, 17 | this value will be used for all Gaussians. 18 | cutoff : scalar or None 19 | The factor of sigma beyond which the Gaussian will be set to zero. The ModeBasis will 20 | be sparse to reduce memory usage. If the cutoff is None, there will be no cutoff, and 21 | the returned ModeBasis will be dense. 22 | 23 | Returns 24 | ------- 25 | ModeBasis or list of Field generators. 26 | The sparse mode basis. If cutoff is None, a dense mode basis will be returned. 27 | ''' 28 | sigma = np.ones(mu.size) * sigma 29 | 30 | def poke(m, s): 31 | def eval_func(func_grid): 32 | if func_grid.is_('cartesian'): 33 | r2 = (func_grid.x - m[0])**2 + (func_grid.y - m[1])**2 34 | else: 35 | r2 = func_grid.shifted(-m).as_('polar').r**2 36 | 37 | res = np.exp(-0.5 * r2 / s**2) 38 | 39 | if cutoff is not None: 40 | res -= np.exp(-0.5 * cutoff**2) 41 | res[r2 > (cutoff * s)**2] = 0 42 | 43 | res = csr_matrix(res) 44 | res.eliminate_zeros() 45 | 46 | return res 47 | return eval_func 48 | 49 | pokes = [poke(m, s) for m, s in zip(mu.points, sigma)] 50 | 51 | if grid is None: 52 | return pokes 53 | else: 54 | return evaluate_supersampled(pokes, grid, 1, make_sparse=True) 55 | -------------------------------------------------------------------------------- /hcipy/config/default_config.yaml: -------------------------------------------------------------------------------- 1 | fourier: 2 | fft: 3 | # Whether to emulate FFTshifts in the FFT using field multiplications. 4 | # This provides a 3x speedup, in exchange for a 10x reduction in accuracy. 5 | emulate_fftshifts: true 6 | 7 | # The backend to use for the FFTs. 8 | method: ['mkl', 'scipy', 'fftw', 'numpy'] 9 | 10 | # The performance prediction parameters for an FFT. 11 | # The default parameters are based on an Apple M2 Max chip. 12 | execution_time_prediction_coefficients: 13 | a: 3.746 14 | b: 0.881 15 | c: -4.749 16 | 17 | mft: 18 | # Whether to precompute the matrices used in the MFT. 19 | # This provides a 20-30% speedup, in exchange for higher memory usage. 20 | precompute_matrices: true 21 | 22 | # Whether to reserve memory for intermediate results. 23 | # This provides a 5-10% speedup, in exchange for higher memory usage. 24 | allocate_intermediate: true 25 | 26 | # The performance prediction parameters for an MFT. 27 | # The default parameters are based on an Apple M2 Max chip. 28 | execution_time_prediction_coefficients: 29 | a: 1.667 30 | b: 0.716 31 | c: -4.624 32 | 33 | nft: 34 | # Whether to precompute the matrices used in the NFT. 35 | # Enabling this is not recommended, as it requires vast amounts of memory. 36 | precompute_matrices: false 37 | 38 | zfft: 39 | # The performance prediction parameters for an ZFFT. 40 | # The default parameters are based on an Apple M2 Max chip. 41 | execution_time_prediction_coefficients: 42 | a: 4.093 43 | b: 0.847 44 | c: -2.973 45 | 46 | plotting: 47 | # The path to the ffmpeg binary. If this is empty, ffmpeg should be available from PATH 48 | # for some functions to work. 49 | ffmpeg_path: 50 | 51 | # The default colormap for imshow_psf(). 52 | psf_colormap: 'inferno' 53 | 54 | # The default colormap for imshow_pupil_phase(). 55 | pupil_phase_colormap: 'RdBu' 56 | 57 | core: 58 | # Whether to use new-style or old-style fields. 59 | use_new_style_fields: false 60 | -------------------------------------------------------------------------------- /.github/workflows/testing.yml: -------------------------------------------------------------------------------- 1 | name: Testing 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | pytest: 13 | name: Pytest (${{ matrix.os }} Python${{ matrix.python_version }}) 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest, windows-latest, macos-latest] 19 | python_version: ["3.10", "3.11", "3.12", "3.13", "3.14"] 20 | 21 | steps: 22 | - name: Check out repo 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | filter: tree:0 27 | - name: Set up conda environment 28 | uses: conda-incubator/setup-miniconda@v3 29 | with: 30 | activate-environment: ci-env 31 | python-version: ${{ matrix.python_version }} 32 | environment-file: .github/conda_environments/testing_env.yml 33 | auto-activate-base: false 34 | - name: Install optional dependencies if available 35 | run: | 36 | while read requirement; do 37 | conda install --yes $requirement || true 38 | done < .github/conda_environments/optional_dependencies.txt 39 | shell: bash -l {0} 40 | - name: Install our package 41 | run: | 42 | pip install -e ".[dev]" 43 | shell: bash -l {0} 44 | - name: Print package versions 45 | run: | 46 | python --version 47 | python -c "import numpy; print('Numpy', numpy.__version__)" 48 | python -c "import scipy; print('Scipy', scipy.__version__)" 49 | python -c "import matplotlib; print('Matplotlib', matplotlib.__version__)" 50 | python -c "import hcipy; print('HCIPy', hcipy.__version__)" 51 | conda list 52 | shell: bash -l {0} 53 | - name: Run tests 54 | run: | 55 | pytest ./tests -ra --cov=./ --cov-report=xml 56 | shell: bash -l {0} 57 | - name: Upload coverage to codecov.io 58 | if: always() 59 | uses: codecov/codecov-action@v4 60 | with: 61 | files: ./coverage.xml 62 | token: ${{ secrets.CODECOV_TOKEN }} 63 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "hcipy" 3 | dynamic = ["version"] 4 | authors = [ 5 | {name = "Emiel Por", email = "epor@stsci.edu"}, 6 | ] 7 | description = "A framework for performing optical propagation simulations, meant for high contrast imaging, in Python." 8 | readme = "README.md" 9 | license = {file = "LICENSE"} 10 | classifiers = [ 11 | "Development Status :: 4 - Beta", 12 | "License :: OSI Approved :: MIT License", 13 | "Operating System :: OS Independent", 14 | "Programming Language :: Python :: 3", 15 | "Programming Language :: Python :: 3.10", 16 | "Programming Language :: Python :: 3.11", 17 | "Programming Language :: Python :: 3.12", 18 | "Programming Language :: Python :: 3.13", 19 | "Programming Language :: Python :: 3.14", 20 | "Topic :: Scientific/Engineering :: Astronomy" 21 | ] 22 | 23 | requires-python = ">=3.7" 24 | dependencies = [ 25 | "numpy", 26 | "scipy", 27 | "matplotlib>=2.0.0", 28 | "Pillow", 29 | "pyyaml", 30 | "astropy", 31 | "imageio", 32 | "xxhash", 33 | "numexpr", 34 | "asdf", 35 | "importlib_metadata", 36 | "importlib_resources>=1.4 ; python_version<'3.9'", 37 | "tqdm" 38 | ] 39 | 40 | [project.optional-dependencies] 41 | dev = [ 42 | "pytest", 43 | "pytest-cov", 44 | "mpmath", 45 | "dill", 46 | "flake8", 47 | ] 48 | doc = [ 49 | "numpydoc", 50 | "sphinx_rtd_theme", 51 | "nbsphinx", 52 | "jupyter_client", 53 | "ipykernel", 54 | "poppy", 55 | "nbclient", 56 | "nbformat", 57 | "nbconvert", 58 | "sphinx-automodapi", 59 | "tqdm", 60 | "ipywidgets", 61 | ] 62 | 63 | [project.urls] 64 | homepage = "https://hcipy.org" 65 | documentation = "https://docs.hcipy.org" 66 | repository = "https://github.com/ehpor/hcipy" 67 | 68 | [build-system] 69 | requires = ["setuptools>=61.2", "setuptools_scm[toml]>=7"] 70 | build-backend = "setuptools.build_meta" 71 | 72 | [tool.setuptools] 73 | packages = ["hcipy"] 74 | zip-safe = false 75 | include-package-data = true 76 | 77 | [tool.setuptools_scm] 78 | write_to = "hcipy/_version.py" 79 | 80 | [project.scripts] 81 | hcipy_tune_fourier = "hcipy.fourier.tuning:_cli" 82 | -------------------------------------------------------------------------------- /tests/test_math.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import hcipy 3 | import numpy as np 4 | 5 | 6 | def _parameters(): 7 | for func in ['fft', 'ifft', 'fft2', 'ifft2', 'fftn', 'ifftn', 'rfft', 'irfft', 'rfft2', 'irfft2', 'rfftn', 'irfftn', 'hfft', 'ihfft']: 8 | for dtype_in in ['float32', 'float64', 'complex64', 'complex128']: 9 | real_out = func.startswith('ir') or func.startswith('h') 10 | 11 | if dtype_in == 'float32' or dtype_in == 'complex64': 12 | dtype_out = 'float32' if real_out else 'complex64' 13 | else: 14 | dtype_out = 'float64' if real_out else 'complex128' 15 | 16 | if func.startswith('r') and dtype_in.startswith('complex'): 17 | continue 18 | 19 | if func.startswith('ih') and dtype_in.startswith('complex'): 20 | continue 21 | 22 | for method in ['numpy', 'scipy', 'fftw', 'mkl']: 23 | if ('r' in func or 'h' in func) and method == 'mkl': 24 | # MKL doesn't implement rffts or hffts. 25 | continue 26 | 27 | yield (func, method, dtype_in, dtype_out) 28 | 29 | @pytest.mark.parametrize('func,method,dtype_in,dtype_out', list(_parameters())) 30 | def test_fft_acceleration(func, method, dtype_in, dtype_out): 31 | rng = np.random.default_rng(seed=0) 32 | 33 | if method == 'fftw': 34 | pytest.importorskip('pyfftw') 35 | 36 | if method == 'mkl': 37 | pytest.importorskip('mkl_fft') 38 | 39 | for N in [32, 128, 1024]: 40 | x = rng.standard_normal((N, N)).astype(dtype_in) 41 | 42 | if dtype_in.startswith('complex'): 43 | x = x + 1j * rng.standard_normal((N, N)).astype(dtype_in) 44 | 45 | numpy_func = getattr(np.fft, func) 46 | hcipy_func = getattr(hcipy._math.fft, func) 47 | 48 | y_numpy = numpy_func(x).astype(dtype_out) 49 | y_method = hcipy_func(x, method=method) 50 | 51 | if dtype_out == 'complex64' or dtype_out == 'float32': 52 | rtol = 5e-4 53 | else: 54 | rtol = 1e-8 55 | 56 | assert np.allclose(y_numpy, y_method, rtol=rtol, atol=rtol) 57 | assert y_method.dtype == dtype_out 58 | -------------------------------------------------------------------------------- /doc/_static/css/custom.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --hcipy-primary: #455265;/*#27ae60;*/ 3 | --hcipy-secondary: #2c3645; 4 | --hcipy-tertiary: #1e2530; 5 | --hcipy-accent: #2980b9; 6 | } 7 | 8 | div.tutorial-item { 9 | border: none; 10 | border-left: 10px solid var(--hcipy-accent); 11 | border-radius: 10px; 12 | box-shadow: 3px 2px 8px 2px rgba(0, 0, 0, 0.3); 13 | margin-bottom: 20px; 14 | padding: 10px; 15 | display: block; 16 | } 17 | 18 | div.tutorial-item:hover { 19 | box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.2); 20 | } 21 | 22 | div.tutorial-item a { 23 | font-size: 125%; 24 | font-weight: 700; 25 | color: black; 26 | padding-left: 10px; 27 | padding-top: 10px; 28 | } 29 | 30 | div.tutorial-item p { 31 | margin-bottom: 15px; 32 | } 33 | 34 | div.tutorial-row { 35 | display: flex; 36 | flex-wrap: wrap; 37 | } 38 | 39 | div.tutorial-thumbnail { 40 | padding: 0px 3px 0px 0px; 41 | display: block; 42 | max-width: 25%; 43 | min-width: 100px; 44 | } 45 | 46 | div.tutorial-thumbnail img { 47 | vertical-align: middle; 48 | } 49 | 50 | div.tutorial-description { 51 | display: block; 52 | max-width: 75%; 53 | padding-left: 20px; 54 | } 55 | 56 | .wy-side-nav-search, .wy-nav-top { 57 | background-color: var(--hcipy-secondary); 58 | } 59 | 60 | .wy-nav-side { 61 | background-color: var(--hcipy-secondary); 62 | } 63 | 64 | .wy-menu-vertical a:hover { 65 | background-color: var(--hcipy-primary); 66 | } 67 | 68 | .wy-menu-vertical p.caption { 69 | color: var(--hcipy-accent); 70 | } 71 | 72 | .rst-content a:link, .rst-content a:visited { 73 | color: var(--hcipy-accent); 74 | } 75 | 76 | body { 77 | color: var(--hcipy-tertiary); 78 | } 79 | 80 | .wy-nav-content { 81 | max-width: 900px; 82 | margin: auto; 83 | } 84 | 85 | .rst-content video { 86 | max-width: 100%; 87 | } 88 | 89 | .rst-content blockquote { 90 | border-left: 4px solid var(--hcipy-accent); 91 | padding-left: 16px; 92 | margin-left: 0; 93 | font-style: italic; 94 | } 95 | 96 | .classifier:before { 97 | font-style: normal; 98 | margin: 0.5em; 99 | content: ":"; 100 | } 101 | -------------------------------------------------------------------------------- /hcipy/optics/magnifier.py: -------------------------------------------------------------------------------- 1 | from .optical_element import AgnosticOpticalElement, make_agnostic_forward, make_agnostic_backward 2 | 3 | import numpy as np 4 | 5 | class Magnifier(AgnosticOpticalElement): 6 | def __init__(self, magnification): 7 | ''' An ideal magnifier. 8 | 9 | This class magnifies a wavefront in an energy conserving manner. 10 | 11 | Parameters 12 | ---------- 13 | magnification : scalar or function of wavelength 14 | The magnification of the system. 15 | ''' 16 | self._magnification = magnification 17 | 18 | AgnosticOpticalElement.__init__(self, False, True) 19 | 20 | def make_instance(self, instance_data, input_grid, output_grid, wavelength): 21 | instance_data.magnification = self.evaluate_parameter(self._magnification, input_grid, output_grid, wavelength) * np.ones(2) 22 | 23 | @property 24 | def magnification(self): 25 | return self._magnification 26 | 27 | @magnification.setter 28 | def magnification(self, magnification): 29 | self._magnification = magnification 30 | 31 | self.clear_cache() 32 | 33 | def get_input_grid(self, output_grid, wavelength): 34 | magnification = self.evaluate_parameter(self._magnification, None, None, wavelength) * np.ones(2) 35 | 36 | return output_grid.scaled(1.0 / magnification) 37 | 38 | def get_output_grid(self, input_grid, wavelength): 39 | magnification = self.evaluate_parameter(self._magnification, input_grid, None, wavelength) * np.ones(2) 40 | 41 | return input_grid.scaled(magnification) 42 | 43 | @make_agnostic_forward 44 | def forward(self, instance_data, wavefront): 45 | wf = wavefront.copy() 46 | 47 | wf.electric_field.grid = wf.electric_field.grid.scaled(instance_data.magnification) 48 | wf.electric_field /= np.sqrt(np.prod(instance_data.magnification)) 49 | 50 | return wf 51 | 52 | @make_agnostic_backward 53 | def backward(self, instance_data, wavefront): 54 | wf = wavefront.copy() 55 | 56 | wf.electric_field.grid = wf.electric_field.grid.scaled(1.0 / instance_data.magnification) 57 | wf.electric_field *= np.sqrt(np.prod(instance_data.magnification)) 58 | 59 | return wf 60 | -------------------------------------------------------------------------------- /hcipy/optics/photonic_lantern.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from ..optics import OpticalElement, Wavefront 4 | from ..field import Field, CartesianGrid, RegularCoords 5 | from ..mode_basis import ModeBasis 6 | 7 | class PhotonicLantern(OpticalElement): 8 | '''A generic photonic lantern 9 | 10 | Parameters 11 | ---------- 12 | lantern_modes : ModeBasis 13 | The modes corresponding to the lantern ports. 14 | wavelength : scalar 15 | The wavelength of the simulation. 16 | ''' 17 | def __init__(self, lantern_modes): 18 | self.lantern_modes = lantern_modes 19 | self.num_modes = len(self.lantern_modes) 20 | self.input_grid = self.lantern_modes.grid 21 | 22 | self.lantern_modes = [m / np.sqrt(np.sum(np.abs(m)**2 * self.input_grid.weights)) for m in self.lantern_modes] 23 | self.lantern_modes = ModeBasis(self.lantern_modes) 24 | 25 | self.output_grid = CartesianGrid(RegularCoords([1, 1], [self.num_modes, 1], np.zeros(2))) 26 | self.output_grid.weights = 1 27 | 28 | self.projection_matrix = self.lantern_modes.transformation_matrix 29 | 30 | def forward(self, wavefront): 31 | '''Forward propagate the light through the photonic lantern 32 | 33 | Parameters 34 | ---------- 35 | wavefront : Wavefront 36 | The incoming wavefront. 37 | 38 | Returns 39 | ------- 40 | Wavefront 41 | The complex amplitudes of each output port. 42 | ''' 43 | output = self.projection_matrix.T.dot(wavefront.electric_field.conj() * self.input_grid.weights) 44 | output = Field(output, self.output_grid) 45 | 46 | return Wavefront(output, wavefront.wavelength) 47 | 48 | def backward(self, wavefront): 49 | '''Backwards propagate the light through the photonic lantern. 50 | 51 | Parameters 52 | ---------- 53 | wavefront : Wavefront 54 | The complex amplitudes for each of the input ports. 55 | 56 | Returns 57 | ------- 58 | Wavefront 59 | The outgoing wavefront. 60 | ''' 61 | res = self.projection_matrix.dot(wavefront.electric_field) 62 | 63 | return Wavefront(Field(res, self.input_grid), wavefront.wavelength) 64 | -------------------------------------------------------------------------------- /hcipy/metrics/contrast.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def get_strehl_from_focal(img, ref_img): 4 | '''Get the Strehl ratio from a focal-plane image. 5 | 6 | Parameters 7 | ---------- 8 | img : Field or array_like 9 | The focal-plane image. 10 | ref_img : Field or array_like 11 | The reference focal-plane image without aberrations. 12 | 13 | Returns 14 | ------- 15 | scalar 16 | The Strehl ratio. 17 | ''' 18 | return img[np.argmax(ref_img)] / ref_img.max() 19 | 20 | def get_strehl_from_pupil(aperture, ref_aperture): 21 | '''Get the Strehl ratio from a pupil-plane electric field. 22 | 23 | Parameters 24 | ---------- 25 | aperture : Field or array_like 26 | The pupil-plane electric field. 27 | ref_aperture : Field or array_like 28 | The reference pupil-plane electric field without aberrations. 29 | 30 | Returns 31 | ------- 32 | scalar 33 | The Strehl ratio. 34 | ''' 35 | return np.abs(np.sum(aperture) / np.sum(ref_aperture))**2 36 | 37 | def get_mean_intensity_in_roi(img, mask): 38 | '''Get the mean intensity in a masked region of interest. 39 | 40 | Parameters 41 | ---------- 42 | img : Field or array_like 43 | The focal-plane image. 44 | mask : Field or array_like 45 | A binary array describing the region of interest. 46 | 47 | Returns 48 | ------- 49 | scalar 50 | The mean intensity in the region of interest. 51 | ''' 52 | return np.mean(img[mask]) 53 | 54 | def get_mean_raw_contrast(img, mask, ref_img): 55 | '''Get the mean raw contrast in a masked region of interest. 56 | 57 | Parameters 58 | ---------- 59 | img : Field or array_like 60 | The focal-plane image. 61 | mask : Field or array_like 62 | A binary array describing the region of interest. 63 | img_ref : Field or array_like 64 | A reference focal-plane image without aberrations. This is used 65 | to determine the Strehl ratio. 66 | 67 | Returns 68 | ------- 69 | scalar 70 | The mean raw contrast in the region of interest. 71 | ''' 72 | mean_intensity = get_mean_intensity_in_roi(img, mask) 73 | strehl = get_strehl_from_focal(img, ref_img) 74 | 75 | return mean_intensity / strehl 76 | -------------------------------------------------------------------------------- /examples/phase_screens.py: -------------------------------------------------------------------------------- 1 | from hcipy import * 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import time 5 | 6 | from hcipy.atmosphere import * 7 | 8 | pupil_grid = make_pupil_grid(256, 1) 9 | focal_grid = make_focal_grid(pupil_grid, 8, 16) 10 | 11 | r0 = 0.3 12 | wavelength = 500e-9 13 | L0 = 10 14 | velocity = 3 15 | height = 0 16 | stencil_length = 2 17 | oversampling = 128 18 | 19 | mode_basis = make_zernike_basis(500, 1, pupil_grid, 1) 20 | 21 | layers = [] 22 | layer = InfiniteAtmosphericLayer(pupil_grid, Cn_squared_from_fried_parameter(r0, wavelength), L0, velocity, 0, stencil_length) 23 | layer2 = ModalAdaptiveOpticsLayer(layer, mode_basis, 1) 24 | layers.append(layer2) 25 | layer = InfiniteAtmosphericLayer(pupil_grid, Cn_squared_from_fried_parameter(r0, wavelength), L0, velocity, 0, stencil_length) 26 | layer3 = ModalAdaptiveOpticsLayer(layer, mode_basis, 1) 27 | layers.append(layer3) 28 | layer = InfiniteAtmosphericLayer(pupil_grid, Cn_squared_from_fried_parameter(r0, wavelength), L0, velocity, 0, stencil_length) 29 | layer4 = ModalAdaptiveOpticsLayer(layer, mode_basis, 1) 30 | layers.append(layer4) 31 | layer = InfiniteAtmosphericLayer(pupil_grid, Cn_squared_from_fried_parameter(r0, wavelength), L0, velocity, 0, stencil_length) 32 | layer5 = ModalAdaptiveOpticsLayer(layer, mode_basis, 1) 33 | layers.append(layer5) 34 | layer = InfiniteAtmosphericLayer(pupil_grid, Cn_squared_from_fried_parameter(r0, wavelength), L0, velocity, 0, stencil_length) 35 | layer6 = ModalAdaptiveOpticsLayer(layer, mode_basis, 1) 36 | layers.append(layer6) 37 | 38 | atmosphere = MultiLayerAtmosphere(layers, False) 39 | atmosphere.Cn_squared = Cn_squared_from_fried_parameter(1/40, wavelength) 40 | prop = FraunhoferPropagator(pupil_grid, focal_grid.scaled(wavelength)) 41 | 42 | aperture = make_circular_aperture(1)(pupil_grid) 43 | wf = Wavefront(Field(np.ones(pupil_grid.size), pupil_grid), wavelength) 44 | 45 | for t in np.linspace(0, 100, 5001): 46 | atmosphere.evolve_until(t) 47 | 48 | wf2 = atmosphere.forward(wf) 49 | wf2.electric_field *= aperture 50 | img = Field(prop(wf2).intensity, focal_grid) 51 | 52 | plt.clf() 53 | plt.subplot(1,2,1) 54 | imshow_field(wf2.phase, cmap='RdBu') 55 | plt.subplot(1,2,2) 56 | imshow_field(np.log10(img / img.max()), vmin=-6) 57 | plt.draw() 58 | plt.pause(0.00001) 59 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build_docs: 13 | name: Build 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Check out repo 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | filter: tree:0 22 | - name: Set up conda environment 23 | uses: conda-incubator/setup-miniconda@v3 24 | with: 25 | activate-environment: ci-env 26 | python-version: 3.11 27 | environment-file: .github/conda_environments/docs_env.yml 28 | auto-activate-base: false 29 | - name: Install our package 30 | run: | 31 | pip install -e ".[doc]" 32 | shell: bash -l {0} 33 | - name: Print package versions 34 | run: | 35 | python --version 36 | python -c "import numpy; print('Numpy', numpy.__version__)" 37 | python -c "import scipy; print('Scipy', scipy.__version__)" 38 | python -c "import matplotlib; print('Matplotlib', matplotlib.__version__)" 39 | python -c "import hcipy; print('HCIPy', hcipy.__version__)" 40 | conda list 41 | shell: bash -l {0} 42 | - name: Build documentation 43 | run: | 44 | cd doc 45 | make html 46 | shell: bash -l {0} 47 | - name: Upload documentation artifact 48 | uses: actions/upload-artifact@v4 49 | with: 50 | name: docs 51 | path: ./doc/_build/html 52 | retention-days: 14 53 | 54 | deploy: 55 | name: Deploy 56 | runs-on: ubuntu-latest 57 | if: ${{ github.event_name == 'push' }} 58 | needs: build_docs 59 | 60 | steps: 61 | - name: Download documentation artifact 62 | uses: actions/download-artifact@v4 63 | with: 64 | name: docs 65 | path: ./doc 66 | 67 | - name: Configure AWS credentials 68 | uses: aws-actions/configure-aws-credentials@v1 69 | with: 70 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 71 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 72 | aws-region: ${{ vars.AWS_REGION }} 73 | 74 | - name: Upload documentation to website 75 | run: | 76 | aws s3 sync --acl public-read --delete --cache-control max-age=86400,public ./doc s3://docs.hcipy.org/dev 77 | shell: bash -l {0} 78 | -------------------------------------------------------------------------------- /hcipy/wavefront_sensing/shack_hartmann.py: -------------------------------------------------------------------------------- 1 | from .wavefront_sensor import WavefrontSensorOptics, WavefrontSensorEstimator 2 | from ..optics import OpticalSystem, MicroLensArray 3 | from ..field import CartesianGrid, Field, SeparatedCoords 4 | from ..propagation import FresnelPropagator 5 | 6 | import numpy as np 7 | from scipy import ndimage 8 | 9 | class ShackHartmannWavefrontSensorOptics(WavefrontSensorOptics): 10 | def __init__(self, input_grid, micro_lens_array): 11 | # Make propagator 12 | sh_prop = FresnelPropagator(input_grid, micro_lens_array.focal_length) 13 | 14 | # Make optical system 15 | OpticalSystem.__init__(self, (micro_lens_array, sh_prop)) 16 | self.mla_index = micro_lens_array.mla_index 17 | self.mla_grid = micro_lens_array.mla_grid 18 | self.micro_lens_array = micro_lens_array 19 | 20 | class SquareShackHartmannWavefrontSensorOptics(ShackHartmannWavefrontSensorOptics): 21 | ## Helper class to create a Shack-Hartmann WFS with square microlens array 22 | def __init__(self, input_grid, f_number, num_lenslets, pupil_diameter): 23 | lenslet_diameter = float(pupil_diameter) / num_lenslets 24 | x = np.arange(-pupil_diameter, pupil_diameter, lenslet_diameter) 25 | self.mla_grid = CartesianGrid(SeparatedCoords((x, x))) 26 | 27 | focal_length = f_number * lenslet_diameter 28 | self.micro_lens_array = MicroLensArray(input_grid, self.mla_grid, focal_length) 29 | 30 | ShackHartmannWavefrontSensorOptics.__init__(self, input_grid, self.micro_lens_array) 31 | 32 | class ShackHartmannWavefrontSensorEstimator(WavefrontSensorEstimator): 33 | def __init__(self, mla_grid, mla_index, estimation_subapertures=None): 34 | self.mla_grid = mla_grid 35 | self.mla_index = mla_index 36 | if estimation_subapertures is None: 37 | self.estimation_subapertures = np.unique(self.mla_index) 38 | else: 39 | self.estimation_subapertures = np.flatnonzero(np.array(estimation_subapertures)) 40 | self.estimation_grid = self.mla_grid.subset(estimation_subapertures) 41 | 42 | def estimate(self, images): 43 | image = images[0] 44 | 45 | fluxes = ndimage.measurements.sum(image, self.mla_index, self.estimation_subapertures) 46 | sum_x = ndimage.measurements.sum(image * image.grid.x, self.mla_index, self.estimation_subapertures) 47 | sum_y = ndimage.measurements.sum(image * image.grid.y, self.mla_index, self.estimation_subapertures) 48 | 49 | centroid_x = sum_x / fluxes 50 | centroid_y = sum_y / fluxes 51 | 52 | centroids = np.array((centroid_x, centroid_y)) - np.array(self.mla_grid.points[self.estimation_subapertures, :]).T 53 | return Field(centroids, self.estimation_grid) 54 | -------------------------------------------------------------------------------- /hcipy/optics/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'make_power_law_error', 3 | 'make_high_pass_power_law_error', 4 | 'SurfaceAberration', 5 | 'SurfaceAberrationAtDistance', 6 | 'Apodizer', 7 | 'PhaseApodizer', 8 | 'SurfaceApodizer', 9 | 'ComplexSurfaceApodizer', 10 | 'MultiplexedComplexSurfaceApodizer', 11 | 'DynamicOpticalSystem', 12 | 'make_actuator_positions', 13 | 'make_gaussian_influence_functions', 14 | 'make_xinetics_influence_functions', 15 | 'find_illuminated_actuators', 16 | 'DeformableMirror', 17 | 'label_actuator_centroid_positions', 18 | 'Detector', 19 | 'NoiselessDetector', 20 | 'NoisyDetector', 21 | 'make_gaussian_fiber_mode', 22 | 'StepIndexFiber', 23 | 'SingleModeFiber', 24 | 'SingleModeFiberInjection', 25 | 'SingleModeFiberArray', 26 | 'GaussianBeam', 27 | 'make_sellmeier_glass', 28 | 'make_cauchy_glass', 29 | 'get_refractive_index', 30 | 'get_glasses_in_catalogue', 31 | 'Magnifier', 32 | 'EvenAsphereMicroLensArray', 33 | 'SphericalMicroLensArray', 34 | 'MicroLensArray', 35 | 'closest_points', 36 | 'OpticalElement', 37 | 'EmptyOpticalElement', 38 | 'AgnosticOpticalElement', 39 | 'make_agnostic_forward', 40 | 'make_agnostic_backward', 41 | 'make_agnostic_optical_element', 42 | 'OpticalSystem', 43 | 'PeriodicOpticalElement', 44 | 'jones_to_mueller', 45 | 'JonesMatrixOpticalElement', 46 | 'PhaseRetarder', 47 | 'LinearRetarder', 48 | 'CircularRetarder', 49 | 'QuarterWavePlate', 50 | 'HalfWavePlate', 51 | 'GeometricPhaseElement', 52 | 'LinearPolarizer', 53 | 'LinearPolarizingBeamSplitter', 54 | 'CircularPolarizingBeamSplitter', 55 | 'SegmentedDeformableMirror', 56 | 'spherical_surface_sag', 57 | 'parabolic_surface_sag', 58 | 'conical_surface_sag', 59 | 'even_aspheric_surface_sag', 60 | 'TipTiltMirror', 61 | 'SimpleVibration', 62 | 'Wavefront', 63 | 'ThinLens', 64 | 'Prism', 65 | 'ThinPrism', 66 | 'TiltElement', 67 | 'PhaseGrating', 68 | 'PhotonicLantern', 69 | 'fresnel_reflection_coefficients', 70 | 'fresnel_transmission_coefficients' 71 | ] 72 | 73 | from .optical_element import * 74 | from .wavefront import * 75 | 76 | from .aberration import * 77 | from .apodization import * 78 | from .deformable_mirror import * 79 | from .detector import * 80 | from .dispersion_optics import * 81 | from .dynamic_optical_system import * 82 | from .fiber import * 83 | from .gaussian_beam import * 84 | from .glass import * 85 | from .magnifier import * 86 | from .micro_lens_array import * 87 | from .periodic_optical_element import * 88 | from .polarization import * 89 | from .segmented_mirror import * 90 | from .surface_profiles import * 91 | from .thin_lens import * 92 | from .tip_tilt_mirror import * 93 | from .vibration import * 94 | from .photonic_lantern import * 95 | -------------------------------------------------------------------------------- /doc/team.rst: -------------------------------------------------------------------------------- 1 | The team 2 | ======== 3 | 4 | HCIPy was originally developed by a small team of astronomers at Leiden University, but has since received external constributions from scientists and software developers around the world. 5 | 6 | Direct contributors to code 7 | --------------------------- 8 | * Emiel Por (`@ehpor `__), University of California Santa Cruz 9 | * Sebastiaan Haffert (`@syhaffert `__), Leiden University 10 | * Steven Bos (`@spbos `__), Leiden University 11 | * Maaike van Kooten (`@vkooten `__), NRC Herzberg 12 | * Vikram Radhakrishnan (`@VikramRadhakrishnan `__), Leiden University 13 | * David Doelman (`@dsdoelman `__), Space Research Organization Netherlands 14 | * Christoph Keller (`@cukeller `__), Lowell Observatory 15 | * Iva Laginja (`@ivalaginja `__), Université de Paris 16 | * Jamie Noss (`@jamienoss `__), Space Telescope Science Institute 17 | * Rémi Soummer (`@RemiSoummer `__), Space Telescope Science Institute 18 | * Kathryn St Laurent (`@kstlaurent `__), Space Telescope Science Institute 19 | * Matthew Kenworthy (`@mkenworthy `__), Leiden University 20 | * David Kleingeld (`@dskleingeld `__), Leiden University 21 | * Gilles Orban de Xivry (`@GillesOrban `__), Université de Liège 22 | * Brett Graham (`@braingram `__), Space Telescope Science Institute 23 | * Rachel Morgan (`@rmnasa `__), NASA Ames Research Center 24 | * Miles Lucas (`@mileslucas `__), University of Hawaii 25 | * Arielle Bertrou-Cantou (`@abertrou `__), California Institute of Technology 26 | * Yinzi Xin (`@yinzi-xin `__), California Institute of Technology 27 | 28 | Testing and QA 29 | -------------- 30 | * Rebecca Jensen-Clem (`@rmjc `__), University of California Santa Cruz 31 | * Aditya Sengupta (`@aditya-sengupta `__), University of California Santa Cruz 32 | * Fedde Fagginger Auer (`@fjfaggingerauer `__), Leiden Observatory 33 | * Joost Wardenier (`@joostwardenier `__), University of Oxford 34 | * Raphaël Pourcelot (`@raphaelpclt `__), Space Telescope Science Institute 35 | 36 | Contributing 37 | ------------ 38 | 39 | If you would like to contribute to the development of HCIPy, we refer you to the :doc:`contributing guide `. Contributions can be as small as reporting a bug. 40 | -------------------------------------------------------------------------------- /hcipy/mode_basis/gaussian_laguerre.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from math import sqrt 3 | from scipy.special import eval_genlaguerre 4 | 5 | def gaussian_laguerre(p, l, mode_field_diameter=1, grid=None): 6 | r'''Creates a Gaussian-Laguerre mode. 7 | 8 | This function evaluates a (p,l) order Gaussian-Laguerre mode on a grid. 9 | The definition of the modes are the following, 10 | 11 | .. math:: 12 | \exp{\left(-\frac{r^2}{w_0^2}\right)} L_p^{|l|}\left(\frac{2r^2}{w_0^2} \right) \left(\sqrt{2}\frac{r}{w_0}\right) 13 | 14 | Here :math:`w_0` is the mode_field_radius, which is :math:`\mathrm{MFD}/2`. 15 | And :math:`L_p^{|l|}` are the generalized Laguerre Polynomials. 16 | All modes are numerical normalized to have a total power of 1. 17 | 18 | More details on generalized Laguerre Polynomials can be found on: 19 | http://mathworld.wolfram.com/AssociatedLaguerrePolynomial.html 20 | 21 | Parameters 22 | ---------- 23 | p : int 24 | The radial order. 25 | l : int 26 | The azimuthal order. 27 | mode_field_diameter : scalar 28 | The mode field diameter of the mode. 29 | grid : Grid 30 | The grid on which to evaluate the mode. 31 | 32 | Returns 33 | ------- 34 | Field 35 | The evaluated mode. 36 | ''' 37 | from ..field import Field 38 | 39 | if grid.is_separated and grid.is_('polar'): 40 | R, Theta = grid.separated_coords 41 | else: 42 | R, Theta = grid.as_('polar').coords 43 | 44 | # Easy access 45 | r = 2 * R / mode_field_diameter 46 | r2 = r**2 47 | 48 | # Compute the mode 49 | lg = (r * sqrt(2))**abs(l) * np.exp(-r2) * np.exp(-1j * l * Theta) * eval_genlaguerre(p, abs(l), 2 * r2) 50 | 51 | # Numerically normalize the mode 52 | lg /= np.sqrt(np.sum(np.abs(lg)**2 * grid.weights)) 53 | 54 | return Field(lg, grid) 55 | 56 | # High level functions 57 | def make_gaussian_laguerre_basis(grid, pmax, lmax, mode_field_diameter, pmin=0): 58 | '''Creates a Gaussian-Laguerre mode basis. 59 | 60 | This function evaluates Gaussian-Laguerre modes. For each radial order 61 | within [pmin, pmax] it will calculate the azimuthal order [-lmax, lmax] inclusive. 62 | This function returns a ModeBasis made out of these Gaussian-Laguerre modes. 63 | 64 | Parameters 65 | ---------- 66 | grid : Grid 67 | The grid on which to evaluate the Gaussian-Laguerre mode. 68 | pmax : int 69 | The maximum radial order of the modes. 70 | lmax : int 71 | The maximum azimuthal order. 72 | mode_field_diameter : scalar 73 | The mode field diameter of the Gaussian-Laguerre mode. 74 | pmin : int 75 | The minimal radial order. 76 | 77 | Returns 78 | ------- 79 | ModeBasis 80 | The Gaussian-Laguerre modes. 81 | ''' 82 | from .mode_basis import ModeBasis 83 | 84 | modes = [gaussian_laguerre(pi, li, mode_field_diameter, grid) for li in range(-lmax, lmax + 1) for pi in range(pmin, pmax)] 85 | return ModeBasis(modes, grid) 86 | -------------------------------------------------------------------------------- /examples/noisy_detector.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | from hcipy import * 5 | 6 | N = 512 7 | 8 | #Defining the grids. 9 | pupil_grid = make_pupil_grid(N) 10 | focal_grid = make_focal_grid(pupil_grid, 8, 5) 11 | 12 | #The propagator. 13 | prop = FraunhoferPropagator(pupil_grid, focal_grid) 14 | 15 | #Aperture function 16 | aperture = make_circular_aperture(1)(pupil_grid) 17 | 18 | #The wavefront in the pupil. 19 | pupil_wavefront = Wavefront(aperture) 20 | 21 | #Now we propagate it to the focal plane. 22 | focal_wavefront = prop(pupil_wavefront) 23 | 24 | #Setting the amount of photons per unit time. 25 | focal_wavefront.total_power = 1000 26 | 27 | #--------------------------------------------------------------------------------- 28 | #First example with scalars for the noise sources. 29 | #--------------------------------------------------------------------------------- 30 | 31 | flatfield = 0.05 # = 5% flat field error 32 | darkcurrentrate = 2 # = dark current counts per second 33 | readnoise = 100 # = rms counts per read out 34 | photonnoise = True 35 | 36 | #Creating our detector. 37 | detector_example_1 = NoisyDetector(input_grid=focal_grid, include_photon_noise=photonnoise, flat_field=flatfield, dark_current_rate=darkcurrentrate, read_noise=readnoise) 38 | 39 | integration_time = np.logspace(1,6,6) 40 | 41 | for t in integration_time: 42 | 43 | #Science measurement. 44 | detector_example_1.integrate(focal_wavefront, t) 45 | measurement = detector_example_1.read_out() 46 | 47 | plt.figure() 48 | imshow_field(measurement) 49 | plt.colorbar() 50 | plt.title('Example 1, t = ' + str(t) + ' seconds') 51 | 52 | plt.show() 53 | 54 | #--------------------------------------------------------------------------------- 55 | #Second example with arrays for the noise sources. 56 | #--------------------------------------------------------------------------------- 57 | 58 | flatfield = 1 + Field(np.random.rand(focal_wavefront.power.size) * 0.05, focal_grid) 59 | darkcurrentrate = Field(np.random.rand(focal_wavefront.power.size) * 2, focal_grid) 60 | readnoise = Field(np.random.rand(focal_wavefront.power.size) * 100, focal_grid) 61 | photonnoise = True 62 | 63 | plt.figure() 64 | imshow_field(flatfield) 65 | plt.colorbar() 66 | plt.title('Flat field map') 67 | 68 | plt.figure() 69 | imshow_field(darkcurrentrate) 70 | plt.colorbar() 71 | plt.title('Dark current map') 72 | 73 | plt.figure() 74 | imshow_field(readnoise) 75 | plt.colorbar() 76 | plt.title('RMS read-noise map') 77 | 78 | #Creating our detector. 79 | detector_example_2 = NoisyDetector(input_grid=focal_grid, include_photon_noise=photonnoise, flat_field=flatfield, dark_current_rate=darkcurrentrate, read_noise=readnoise) 80 | 81 | integration_time = np.logspace(1,6,6) 82 | 83 | for t in integration_time: 84 | 85 | #Science measurement. 86 | detector_example_2.integrate(focal_wavefront, t) 87 | measurement = detector_example_2.read_out() 88 | 89 | plt.figure() 90 | imshow_field(measurement) 91 | plt.colorbar() 92 | plt.title('Example 2, t = ' + str(t) + ' seconds') 93 | 94 | plt.show() 95 | -------------------------------------------------------------------------------- /hcipy/optics/dynamic_optical_system.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | class DynamicOpticalSystem(object): 4 | '''A dynamically varying optical system. 5 | 6 | This can be used as a starting point for an implementation of an adaptive optics system. The optics 7 | are changed as specific moments in time, which can be scheduled by submitting a callback. The time 8 | points are bridged using the integrate function, which is written by the derived class. This 9 | function should integrate on each detector without reading out the detector. Detector readouts or 10 | DM changes should be implemented as callbacks. 11 | ''' 12 | def __init__(self): 13 | self.callbacks = [] 14 | self.t = 0 15 | self.callback_counter = 0 16 | 17 | def evolve_until(self, t): 18 | '''Evolve the optical system until time `t`. 19 | 20 | Parameters 21 | ---------- 22 | t : scalar 23 | The point in time to which to simulate this optical system. Callbacks and integrations 24 | are handled along the way. 25 | ''' 26 | if t < self.t: 27 | raise ValueError('Backwards evolution is not allowed.') 28 | 29 | end = False 30 | while not end: 31 | t_next, _, callback = self.callbacks[0] 32 | if t_next < t: 33 | integration_time = t_next - self.t 34 | heapq.heappop(self.callbacks) 35 | else: 36 | integration_time = t - self.t 37 | end = True 38 | 39 | # Avoid multiple expensive integrations if we have multiple callbacks 40 | # at the same time. 41 | if integration_time > 1e-6: 42 | self.integrate(integration_time) 43 | self.t += integration_time 44 | 45 | if not end: 46 | callback() 47 | 48 | def integrate(self, integration_time): 49 | '''Integrate the current optical system for a certain integration time. 50 | 51 | This function should be implemented by a user in a derived class. 52 | 53 | Parameters 54 | ---------- 55 | integration_time : scalar 56 | The integration time with which to integrate the optical system. 57 | ''' 58 | pass 59 | 60 | def add_callback(self, t, callback): 61 | '''Add a callback to the list of callbacks. 62 | 63 | This function can even be called during handling of a callback. This is 64 | especially useful when implementing periodic callbacks: a callback can 65 | reinsert itself at a later time at the end of handling of the callback. 66 | 67 | Parameters 68 | ---------- 69 | t : scalar 70 | The time at which to call the callback. 71 | callback : function 72 | The function to call at time `t`. This function should have no arguments. 73 | ''' 74 | # Callback counter is to avoid comparison of callback functions 75 | # if the times are equal, as comparison of functions is not allowed. 76 | heapq.heappush(self.callbacks, (t, self.callback_counter, callback)) 77 | self.callback_counter += 1 78 | -------------------------------------------------------------------------------- /hcipy/interpolation/nearest.py: -------------------------------------------------------------------------------- 1 | from scipy.interpolate import RegularGridInterpolator, NearestNDInterpolator 2 | import numpy as np 3 | from ..field import Field 4 | 5 | def make_nearest_interpolator_separated(field, grid=None): 6 | '''Make a nearest interpolator for a field on a separated grid. 7 | 8 | Parameters 9 | ---------- 10 | field : Field or ndarray 11 | The field to interpolate. 12 | grid : Grid or None 13 | The grid of the field. If it is given, the grid of `field` is replaced by this grid. 14 | 15 | Returns 16 | ------- 17 | Field generator 18 | The interpolator, as a Field generator. The grid on which this field generator will evaluated, does 19 | not have to be separated. 20 | ''' 21 | if grid is None: 22 | grid = field.grid 23 | else: 24 | field = Field(field, grid) 25 | 26 | # RegularGridInterpolator expects data to be in ij indexing rather than xy. We 27 | # need to reverse the axes of the data and the coordinates. 28 | data = np.moveaxis(field.shaped, range(-1, -grid.ndim - 1, -1), range(-grid.ndim, 0, 1)) 29 | 30 | interp = RegularGridInterpolator(grid.separated_coords, data, 'nearest', False) 31 | 32 | def interpolator(evaluated_grid): 33 | res = interp(evaluated_grid.points) 34 | 35 | return Field(res.ravel(), evaluated_grid) 36 | 37 | return interpolator 38 | 39 | def make_nearest_interpolator_unstructured(field, grid=None): 40 | '''Make a nearest interpolator for an unstructured grid. 41 | 42 | Parameters 43 | ---------- 44 | field : Field or array_like 45 | The field to interpolate. 46 | grid : Grid or None 47 | The grid of the field. If it is given, the grid of `field` is replaced by this grid. 48 | 49 | Returns 50 | ------- 51 | Field generator 52 | The interpolator as a Field generator. The grid on which this field generator will be evaluated does 53 | not need to have any structure. 54 | ''' 55 | if grid is None: 56 | grid = field.grid 57 | else: 58 | field = Field(field, grid) 59 | 60 | interp = NearestNDInterpolator(grid.points, field) 61 | 62 | def interpolator(evaluated_grid): 63 | res = interp(evaluated_grid.points) 64 | 65 | return Field(res, evaluated_grid) 66 | 67 | return interpolator 68 | 69 | def make_nearest_interpolator(field, grid=None): 70 | '''Make a nearest interpolator for any type of grid. 71 | 72 | Parameters 73 | ---------- 74 | field : Field or array_like 75 | The field to interpolate. 76 | grid : Grid or None 77 | The grid of the field. If it is given, the grid of `field` is replaced by this grid. 78 | 79 | Returns 80 | ------- 81 | Field generator 82 | The interpolator as a Field generator. The grid on which this field generator will be evaluated does 83 | not need to have any structure. 84 | ''' 85 | if grid is None: 86 | grid = field.grid 87 | 88 | if grid.is_unstructured: 89 | return make_nearest_interpolator_unstructured(field, grid) 90 | else: 91 | return make_nearest_interpolator_separated(field, grid) 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![PyPI Status](https://img.shields.io/pypi/v/hcipy.svg?logo=pypi&logoColor=white)](https://pypi.org/project/hcipy/) 2 | [![Conda Status](https://img.shields.io/conda/vn/conda-forge/hcipy?logo=anaconda&logoColor=white)](https://anaconda.org/conda-forge/hcipy) 3 | [![Build Status](https://img.shields.io/github/checks-status/ehpor/hcipy/master?logo=github&label=build)](https://github.com/ehpor/hcipy/actions?query=branch%3Amaster) 4 | [![Coverage Status](https://img.shields.io/codecov/c/gh/ehpor/hcipy?logo=codecov&logoColor=white)](https://codecov.io/gh/ehpor/hcipy) 5 | [![Documentation Status](https://img.shields.io/badge/docs-latest%20build-brightgreen?logo=read-the-docs&logoColor=white)](https://docs.hcipy.org/dev) 6 | [![License](https://img.shields.io/github/license/ehpor/hcipy.svg?logo=open-source-initiative&logoColor=white)](https://opensource.org/licenses/MIT) 7 | 8 | # HCIPy: High Contrast Imaging for Python 9 | 10 | ![HCIPy banner](https://github.com/ehpor/hcipy/raw/master/doc/hcipy_banner.png "HCIPy banner") 11 | 12 | HCIPy is an open-source object-oriented framework written in Python for performing end-to-end simulations of high-contrast imaging instruments for astronomy. 13 | 14 | The library defines wavefronts and optical elements for defining an optical system, and provides both Fraunhofer and Fresnel diffraction propgators. Polarization is supported using Jones calculus, with polarizers and waveplates included out of the box. It implements atmospheric turbulence using thin infinitely-long phase screens, and can model scintillation using Fresnel propagation between individual layers. Many wavefront sensors are implemented including a Shack-Hartmann and Pyramid wavefront sensor. Implemented coronagraphs include the vortex, Lyot and APP coronagraph. 15 | 16 | By including simulation of both adaptive optics and coronagraphy into a single framework, HCIPy allows simulations including feedback from post-coronagraphic focal-plane wavefront sensors to the AO system. 17 | 18 | The main website is hosted at . For documentation, see . 19 | 20 | ## Team 21 | 22 | HCIPy was originally developed by a small team of astronomers at Leiden Observatory, but has since received external constributions from scientists and software developers around the world. For a current list, please visit our [website](https://hcipy.org/team.html). 23 | 24 | ## Citing 25 | 26 | If you use HCIPy for your own research, we ask you to cite the HCIPy proceeding ([Por et al. 2018](https://doi.org/10.1117/12.2314407)). If there is no appropriate place in the body text to cite the proceeding, please include something along the lines of the following in your acknowledgements: 27 | 28 | > This research made use of HCIPy, an open-source object-oriented framework written in Python for performing end-to-end simulations of high-contrast imaging instruments ([Por et al. 2018](https://doi.org/10.1117/12.2314407)). 29 | 30 | ## Contributions 31 | 32 | If you have something to add, or want something added to HCIPy, please let us know using a Github issue. We actively support external contributions to HCIPy, small and large. Please look at the [contributing guide](https://docs.hcipy.org/dev/development/contributing_guide.html) for more information. 33 | -------------------------------------------------------------------------------- /hcipy/plotting/color_scheme.py: -------------------------------------------------------------------------------- 1 | from cycler import cycler 2 | from . import colors 3 | 4 | # Blue, red, green, orange, purple, brown 5 | palettes = { 6 | 'dark': cycler(color=[colors.blue_700, colors.red_700, colors.green_700, colors.orange_700, colors.purple_700, colors.brown_700]) 7 | } 8 | 9 | def set_color_scheme(dark=False, publication_quality=False, cmap='viridis'): # pragma: no cover 10 | """ 11 | Apply a color scheme to all matplotlib figures. The setting 12 | publication_quality uses LaTeX for all text in the figure. 13 | """ 14 | import warnings 15 | warnings.warn( 16 | 'set_color_scheme() is deprecated. Copy the color scheme to your own file if you want to continue using it in the future.', 17 | DeprecationWarning, 18 | stacklevel=2 19 | ) 20 | 21 | import matplotlib as mpl 22 | 23 | mpl.rc('lines', linewidth=1.5, markeredgewidth=0.25) 24 | mpl.rc('image', cmap=cmap) 25 | mpl.rc('legend', scatterpoints=1, numpoints=1, labelspacing=0.3) 26 | mpl.rc('axes.formatter', limits=(-4, 4)) 27 | mpl.rc('text.latex', preamble=['\\usepackage{amsmath}']) 28 | 29 | mpl.rc('xtick', labelsize='small') 30 | mpl.rc('ytick', labelsize='small') 31 | mpl.rc('axes', titlesize='medium', labelsize='medium') 32 | mpl.rc('legend', fontsize='medium') 33 | 34 | mpl.rc('savefig', transparent=True) 35 | 36 | if dark: 37 | mpl.rc('axes', prop_cycle=palettes['light'], facecolor='k', labelcolor='w', edgecolor='w') 38 | mpl.rc('xtick', color='w') 39 | mpl.rc('ytick', color='w') 40 | mpl.rc('grid', color='w') 41 | mpl.rc('figure', facecolor='k', edgecolor='k') 42 | mpl.rc('text', color='w') 43 | else: 44 | mpl.rc('axes', prop_cycle=palettes['dark'], facecolor='w', labelcolor='k', edgecolor='k') 45 | mpl.rc('xtick', color='k') 46 | mpl.rc('ytick', color='k') 47 | mpl.rc('grid', color='k') 48 | mpl.rc('figure', facecolor='w', edgecolor='w') 49 | mpl.rc('text', color='k') 50 | 51 | if publication_quality: 52 | mpl.rc('text', usetex=True) 53 | mpl.rc('font', family='sans-serif') 54 | mpl.rc('font', serif=['computer modern roman'], monospace=['computer modern typewriter']) 55 | mpl.rcParams['font.sans-serif'] = ['computer modern sans serif'] 56 | 57 | mpl.rc('font', size=11) 58 | mpl.rc('figure', figsize=(7.2, 5.1)) 59 | else: 60 | mpl.rc('text', usetex=False) 61 | mpl.rc('font', family='sans-serif') 62 | mpl.rc('font', serif=[ 63 | 'Bitstream Vera Serif', 'New Century Schoolbook', 'Century Schoolbook L', 'Utopia', 64 | 'ITC Bookman', 'Bookman', 'Nimbus Roman No9 L', 'Times New Roman', 'Times', 'Palatino', 'Charter', 'serif']) 65 | mpl.rcParams['font.sans-serif'] = [ 66 | 'Bitstream Vera Sans', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', 'Arial', 67 | 'Helvetica', 'Avant Garde', 'sans-serif'] 68 | mpl.rc('font', monospace=[ 69 | 'Bitstream Vera Sans Mono', 'Andale Mono', 'Nimbus Mono L', 'Courier New', 'Courier', 70 | 'Fixed', 'Terminal', 'monospace']) 71 | 72 | mpl.rc('figure', figsize=(10, 7.1)) 73 | mpl.rc('font', size=14) 74 | -------------------------------------------------------------------------------- /tests/test_wavefront_sensing.py: -------------------------------------------------------------------------------- 1 | from hcipy import * 2 | import numpy as np 3 | 4 | def test_optical_differentiation_wavefront_sensor(): 5 | pupil_grid = make_pupil_grid(128, 1) 6 | wfs_grid = make_pupil_grid(256, 2) 7 | amplitude_filter = make_polarization_odwfs_amplitude_filter(0.0) 8 | 9 | odwfs = OpticalDifferentiationWavefrontSensorOptics(amplitude_filter, pupil_grid, wfs_grid) 10 | 11 | zernike_modes = make_zernike_basis(20, 1, pupil_grid) 12 | aberration = zernike_modes.linear_combination(np.random.randn(20)) * 0.1 13 | 14 | wf = Wavefront(make_circular_aperture(1)(pupil_grid) * np.exp(1j * aberration)) 15 | odwfs(wf).intensity 16 | 17 | def test_pyramid_wavefront_sensor(): 18 | pupil_grid = make_pupil_grid(128) 19 | wfs_grid = make_pupil_grid(256, 2) 20 | 21 | pywfs = PyramidWavefrontSensorOptics(pupil_grid, wfs_grid, 1.0) 22 | 23 | zernike_modes = make_zernike_basis(20, 1, pupil_grid) 24 | aberration = zernike_modes.linear_combination(np.random.randn(20)) * 0.1 25 | 26 | wf = Wavefront(make_circular_aperture(1)(pupil_grid) * np.exp(1j * aberration)) 27 | pywfs(wf).intensity 28 | 29 | def test_modulated_pyramid_wavefront_sensor(): 30 | pupil_grid = make_pupil_grid(128) 31 | wfs_grid = make_pupil_grid(256, 2) 32 | 33 | num_steps = 12 34 | 35 | pywfs = PyramidWavefrontSensorOptics(pupil_grid, wfs_grid, 1.0, q=3) 36 | mpywfs = ModulatedPyramidWavefrontSensorOptics(pywfs, 2, num_steps=num_steps) 37 | fast_mpywfs = ModulatedPyramidWavefrontSensorOptics(pywfs, 2, num_steps=num_steps, fast_modulation_method=True) 38 | 39 | zernike_modes = make_zernike_basis(20, 1, pupil_grid) 40 | aberration = zernike_modes.linear_combination(np.random.randn(20)) * 0.1 41 | 42 | wf = Wavefront(make_circular_aperture(1)(pupil_grid) * np.exp(1j * aberration)) 43 | modulated_wfs = mpywfs(wf) 44 | 45 | assert len(modulated_wfs) == num_steps 46 | 47 | total_image = 0 48 | for wi in modulated_wfs: 49 | total_image += wi.power / num_steps 50 | 51 | total_image_fast = 0 52 | for wi in fast_mpywfs(wf): 53 | total_image_fast += wi.power / num_steps 54 | 55 | assert (abs(total_image - total_image_fast).max() / total_image.max()) < 2e-2 56 | 57 | def test_zernike_wavefront_sensor(): 58 | pupil_grid = make_pupil_grid(128) 59 | 60 | zwfs = ZernikeWavefrontSensorOptics(pupil_grid) 61 | 62 | zernike_modes = make_zernike_basis(20, 1, pupil_grid) 63 | aberration = zernike_modes.linear_combination(np.random.randn(20)) * 0.1 64 | 65 | wf = Wavefront(make_circular_aperture(1)(pupil_grid) * np.exp(1j * aberration)) 66 | zwfs(wf).intensity 67 | 68 | def test_vector_zernike_wavefront_sensor(): 69 | pupil_grid = make_pupil_grid(128) 70 | 71 | vzwfs = VectorZernikeWavefrontSensorOptics(pupil_grid) 72 | 73 | zwfs_plus = ZernikeWavefrontSensorOptics(pupil_grid, np.pi / 2) 74 | zwfs_neg = ZernikeWavefrontSensorOptics(pupil_grid, -np.pi / 2) 75 | 76 | zernike_modes = make_zernike_basis(20, 1, pupil_grid) 77 | aberration = zernike_modes.linear_combination(np.random.randn(20)) * 0.1 78 | 79 | wf = Wavefront(make_circular_aperture(1)(pupil_grid) * np.exp(1j * aberration)) 80 | 81 | vector_img = vzwfs(wf).intensity 82 | ref_img = (zwfs_plus(wf).intensity + zwfs_neg(wf).intensity) / 2 83 | 84 | assert np.allclose(vector_img, ref_img) 85 | -------------------------------------------------------------------------------- /doc/development/new_release.rst: -------------------------------------------------------------------------------- 1 | How to make a new release? 2 | ========================== 3 | 4 | This page is intended for the maintainer of HCIPy, and contains step-by-step instructions on how to release a new version of HCIPy. 5 | 6 | 1. Pull the latest version of the master branch. 7 | 8 | .. code-block:: shell 9 | 10 | git checkout master 11 | git pull 12 | 13 | Make sure that all unit tests are functioning without errors, including slow tests: 14 | 15 | .. code-block:: shell 16 | 17 | pytest ./tests --runslow 18 | 19 | Also make sure that the latest CI for the master branch on `Azure Pipelines `__ is passing. Build the documentation and check if it is building without errors or problematic warnings. 20 | 21 | .. code-block:: shell 22 | 23 | cd doc 24 | make clean 25 | make html 26 | cd .. 27 | 28 | 2. Write release notes mimicking other release notes. Add those release notes to the :doc:`changelog <../changelog>` in the documentation and commit these changes. 29 | 30 | 3. Add tag information on Github. You can do this by releasing a new version. Add the written release notes, mimicking previous release notes. After you've released the new version, a new tag will have been added on the Github repository. 31 | 32 | 4. Fetch the tags on your local git repository. Update the version information, and check that the version was changed: 33 | 34 | .. code-block:: shell 35 | 36 | git fetch 37 | python setup.py egg_info 38 | python setup.py --version 39 | 40 | 5. Re-build the documentation: 41 | 42 | .. code-block:: shell 43 | 44 | cd doc 45 | make clean 46 | make html 47 | cd .. 48 | 49 | Load the built documentation (in *doc/_build/html/index.html*) locally, and make sure that the version number has changed (in the upper left), and that everything looks okay. Then upload to the documentation website: 50 | 51 | .. code-block:: shell 52 | 53 | aws s3 sync --acl public-read --cache-control max-age=2629800,public doc/_build/html s3://docs.hcipy.org/0.5.1 54 | 55 | where ``0.5.1`` has been changed to the correct version number. 56 | 57 | 6. Build the source distribution and wheels: 58 | 59 | .. code-block:: shell 60 | 61 | python3 -m build 62 | 63 | Then submit to PyPI: 64 | 65 | .. code-block:: shell 66 | 67 | python -m twine upload dist/* 68 | 69 | Enter username and password, and everything will be uploaded. Then add the source distribution and wheel to the Github release as assets. 70 | 71 | 7. Update all links on the website (*www/index.html*, *www/news.html* and *docs/stable/index.html*) and add release to list of releases. Upload website to AWS S3: 72 | 73 | .. code-block:: shell 74 | 75 | aws s3 sync --acl public-read --delete --cache-control max-age=604800,public www s3://hcipy.org 76 | aws s3 sync --acl public-read --cache-control max-age=604800,public docs s3://docs.hcipy.org 77 | 78 | 8. Purge the `CloudFlare `__ cache for `hcipy.org `__. This step is not necessary. Without it the website will update in at maximum seven days, due to caching of the old website by CloudFlare. 79 | 80 | 9. Update this document with any issues, problems or peculiarities that you encountered for later reference. 81 | -------------------------------------------------------------------------------- /hcipy/util/matrix_inversion.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def inverse_truncated_modal(M, num_modes, svd=None): 4 | '''Invert `M` with `num_modes` modes. 5 | 6 | Modes are given by a singular value decomposition of the input matrix. 7 | If `svd` is given, it is used instead. Modes are ordered in descending 8 | order by their singular values. 9 | 10 | Parameters 11 | ---------- 12 | M : ndarray 13 | The matrix to invert. This matrix must be two-dimensional. 14 | num_modes : integer 15 | The number of modes to use for the inversion. Higher-order modes 16 | are ignored. 17 | svd : SVD object 18 | A precalculated singular value decomposition object. This will 19 | be used if supplied, to avoid recalculation of an SVD. 20 | 21 | Returns 22 | ------- 23 | ndarray 24 | The inverted matrix. 25 | ''' 26 | if svd is None: 27 | from .singular_value_decomposition import SVD 28 | svd = SVD(M, num_modes) 29 | 30 | U, S, Vt = svd.svd 31 | 32 | U = U[:, :num_modes] 33 | S = S[:num_modes] 34 | Vt = Vt[:num_modes, :] 35 | 36 | return (Vt.T / S).dot(U.T) 37 | 38 | def inverse_truncated(M, rcond=1e-15, svd=None): 39 | '''Invert `M` truncating the number of modes. 40 | 41 | Modes are given by a singular value decomposition of the input matrix. 42 | If `svd` is given, it is used instead. Modes are ordered in descending 43 | order by their singular values. All modes with a singular value lower than 44 | `rcond` times the maximum singular value, will be ignored. 45 | 46 | Parameters 47 | ---------- 48 | M : ndarray 49 | The matrix to invert. This matrix must be two-dimensional. 50 | rcond : scalar 51 | The relative condition number of the highest-order mode that must 52 | be used for inversion. 53 | svd : SVD object 54 | A precalculated singular value decomposition object. This will 55 | be used if supplied, to avoid recalculation of an SVD. 56 | 57 | Returns 58 | ------- 59 | ndarray 60 | The inverted matrix. 61 | ''' 62 | if svd is None: 63 | from .singular_value_decomposition import SVD 64 | svd = SVD(M) 65 | 66 | U, S, Vt = svd.svd 67 | S_inv = np.array([1 / s if abs(s) > (rcond * S.max()) else 0 for s in S]) 68 | 69 | return (Vt.T * S_inv).dot(U.T) 70 | 71 | def inverse_tikhonov(M, rcond=1e-15, svd=None): 72 | '''Invert `M` using Tikhonov regularization. 73 | 74 | Tikhonov regularization will be an identity matrix, with strength 75 | `rcond` * the maximum singular value of the matrix. 76 | 77 | Parameters 78 | ---------- 79 | M : ndarray 80 | The matrix to invert. This matrix must be two-dimensional. 81 | rcond : scalar 82 | The relative strength of the regularization. An identity matrix 83 | will be used for the regularization. 84 | svd : SVD object 85 | A precalculated singular value decomposition object. This will 86 | be used if supplied, to avoid recalculation of an SVD. 87 | 88 | Returns 89 | ------- 90 | ndarray 91 | The inverted matrix. 92 | ''' 93 | if svd is None: 94 | from .singular_value_decomposition import SVD 95 | svd = SVD(M) 96 | 97 | U, S, Vt = svd.svd 98 | S_inv = S / (S**2 + (rcond * S.max())**2) 99 | 100 | return (Vt.T * S_inv).dot(U.T) 101 | -------------------------------------------------------------------------------- /hcipy/propagation/fraunhofer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from ..optics import Wavefront, AgnosticOpticalElement, make_agnostic_forward, make_agnostic_backward 4 | from ..field import Field 5 | from ..fourier import make_fourier_transform 6 | 7 | class FraunhoferPropagator(AgnosticOpticalElement): 8 | '''A monochromatic perfect lens propagator. 9 | 10 | This implements the propagation of a wavefront through a perfect lens. The wavefront 11 | is assumed to be exactly in the front focal plane of the lens and is propagated to the 12 | back focal plane. The implementation follows [Goodman2005]_. 13 | 14 | .. [Goodman2005] Goodman, J.W., 2005 Introduction to Fourier optics. Roberts and Company Publishers. 15 | 16 | Parameters 17 | ---------- 18 | input_grid : Grid 19 | The grid on which the incoming wavefront is defined. 20 | output_grid : Grid 21 | The grid on which the outgoing wavefront is to be evaluated. 22 | focal_length : scalar 23 | The focal length of the lens system. 24 | ''' 25 | def __init__(self, input_grid, output_grid, focal_length=1): 26 | self._input_grid = input_grid 27 | self._output_grid = output_grid 28 | self._focal_length = focal_length 29 | 30 | AgnosticOpticalElement.__init__(self, grid_dependent=True, wavelength_dependent=True) 31 | 32 | def make_instance(self, instance_data, input_grid, output_grid, wavelength): 33 | focal_length = self.evaluate_parameter(self.focal_length, input_grid, output_grid, wavelength) 34 | 35 | instance_data.uv_grid = output_grid.scaled(2 * np.pi / (focal_length * wavelength)) 36 | instance_data.fourier_transform = make_fourier_transform(input_grid, instance_data.uv_grid) 37 | 38 | instance_data.norm_factor = 1 / (1j * focal_length * wavelength) 39 | 40 | @property 41 | def focal_length(self): 42 | return self._focal_length 43 | 44 | @focal_length.setter 45 | def focal_length(self, focal_length): 46 | self._focal_length = focal_length 47 | 48 | self.clear_cache() 49 | 50 | def get_input_grid(self, output_grid, wavelength): 51 | return self._input_grid 52 | 53 | def get_output_grid(self, input_grid, wavelength): 54 | return self._output_grid 55 | 56 | @make_agnostic_forward 57 | def forward(self, instance_data, wavefront): 58 | '''Propagate a wavefront forward through the lens. 59 | 60 | Parameters 61 | ---------- 62 | wavefront : Wavefront 63 | The incoming wavefront. 64 | 65 | Returns 66 | ------- 67 | Wavefront 68 | The wavefront after the propagation. 69 | ''' 70 | U_new = instance_data.fourier_transform.forward(wavefront.electric_field) * instance_data.norm_factor 71 | return Wavefront(Field(U_new, instance_data.output_grid), wavefront.wavelength, wavefront.input_stokes_vector) 72 | 73 | @make_agnostic_backward 74 | def backward(self, instance_data, wavefront): 75 | '''Propagate a wavefront backward through the lens. 76 | 77 | Parameters 78 | ---------- 79 | wavefront : Wavefront 80 | The incoming wavefront. 81 | 82 | Returns 83 | ------- 84 | Wavefront 85 | The wavefront after the propagation. 86 | ''' 87 | U_new = instance_data.fourier_transform.backward(wavefront.electric_field) / instance_data.norm_factor 88 | return Wavefront(Field(U_new, instance_data.input_grid), wavefront.wavelength, wavefront.input_stokes_vector) 89 | -------------------------------------------------------------------------------- /hcipy/optics/segmented_mirror.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse 3 | 4 | from ..mode_basis import ModeBasis 5 | from .deformable_mirror import DeformableMirror 6 | 7 | class SegmentedDeformableMirror(DeformableMirror): 8 | '''A segmented deformable mirror. 9 | 10 | This deformable mirror class can simulate devices such as those 11 | made by IrisAO and BMC. All segments are controlled in piston, 12 | tip and tilt. 13 | 14 | Parameters 15 | ---------- 16 | segments : ModeBasis 17 | A mode basis with all segments. 18 | ''' 19 | def __init__(self, segments): 20 | self.segments = segments 21 | self.actuators = np.zeros(len(segments) * 3) 22 | self.input_grid = segments.grid 23 | 24 | @property 25 | def segments(self): 26 | '''The segments of this deformable mirror in a ModeBasis. 27 | ''' 28 | return self._segments 29 | 30 | @segments.setter 31 | def segments(self, segments): 32 | self._segments = segments 33 | 34 | tip = [] 35 | tilt = [] 36 | 37 | for segment in segments: 38 | segment_mean = segment.mean() 39 | norm = np.mean(segment**2) - segment_mean**2 40 | 41 | tip_mode = segment * segment.grid.x 42 | if norm != 0: 43 | beta = ((tip_mode * segment).mean() - segment_mean * tip_mode.mean()) / norm 44 | tip_mode -= beta * segment 45 | 46 | tip_mode = scipy.sparse.csr_matrix(tip_mode) 47 | tip_mode.eliminate_zeros() 48 | tip.append(tip_mode) 49 | 50 | tilt_mode = segment * segment.grid.y 51 | if norm != 0: 52 | beta = ((tilt_mode * segment).mean() - segment_mean * tilt_mode.mean()) / norm 53 | tilt_mode -= beta * segment 54 | 55 | tilt_mode = scipy.sparse.csr_matrix(tilt_mode) 56 | tilt_mode.eliminate_zeros() 57 | tilt.append(tilt_mode) 58 | 59 | tip = ModeBasis(tip) 60 | tilt = ModeBasis(tilt) 61 | 62 | self.influence_functions = segments + tip + tilt 63 | 64 | def get_segment_actuators(self, segment_id): 65 | '''Get the actuators for an individual segment of the DM. 66 | 67 | Parameters 68 | ---------- 69 | segment_id : int 70 | The index of the segment for which to get the actuators. 71 | 72 | Returns 73 | ------- 74 | piston : scalar 75 | The piston of the segment in meters. 76 | tip : scalar 77 | The tip of the segment in radians. 78 | tilt : scalar 79 | The tilt of the segment in radians. 80 | ''' 81 | piston = self.actuators[segment_id] 82 | tip = self.actuators[segment_id + len(self._segments)] 83 | tilt = self.actuators[segment_id + 2 * len(self._segments)] 84 | 85 | return (piston, tip, tilt) 86 | 87 | def set_segment_actuators(self, segment_id, piston, tip, tilt): 88 | '''Set the actuators for an individual segment of the DM. 89 | 90 | Parameters 91 | ---------- 92 | segment_id : int 93 | The index of the segment for which to get the actuators. 94 | piston : scalar 95 | The piston of the segment in meters. 96 | tip : scalar 97 | The tip of the segment in radians. 98 | tilt : scalar 99 | The tilt of the segment in radians. 100 | ''' 101 | self.actuators[segment_id] = piston 102 | self.actuators[segment_id + len(self._segments)] = tip 103 | self.actuators[segment_id + 2 * len(self._segments)] = tilt 104 | -------------------------------------------------------------------------------- /doc/development/contributing_guide.rst: -------------------------------------------------------------------------------- 1 | Contributing guide 2 | ================== 3 | 4 | You don't have to be an expert or know the internal workings of HCIPy to provide a worthwhile contribution to HCIPy. We welcome bug reports and/or fixes, changes to documentation, new optical elements and other improvements. 5 | 6 | Reporting bugs or requesting enhancements 7 | ----------------------------------------- 8 | 9 | Bug reports or enhancement requests can be made on `Github `__. If possible, bug reports should contain a code example or an error traceback to give us information on how to fix the bug. Enhancement requests are requests for a new feature in HCIPy. Depending on the amount of effort it would take to implement this feature, we may decide to implement it. Otherwise, it'll get put on a list for later implementation, when the need becomes greater, or you'll have to implement the feature yourself. 10 | 11 | Contributing code 12 | ----------------- 13 | 14 | The first step in making a code contribution to HCIPy is to get in touch with us. Create an issue with the bug you want to fix, or the feature you want to add. You can indicate in this Github issue that you'd be willing to do the work. Getting in touch early on ensures that your contribution will not be in vain. For example, your bug fix could be for code that we intend to remove or rewrite soon anyway, or your enhancement could be something that we are working on already. If you think the bug or enhancement is low impact, you may choose to ignore this advice. 15 | 16 | We are working in a feature-branching workflow. This means that pushing to the master branch directly is prohibited. Pull requests from feature branches are used to merge changes into the master branch. 17 | 18 | 1. Depending on if you are a collaborator on the HCIPy repository, you may need to fork HCIPy. You can do this by clicking ``Fork`` in the repository on Github. If you are already a collaborator, you do not have fork the HCIPy repository. 19 | 20 | 2. Create your *feature branch*: 21 | 22 | .. code-block:: shell 23 | 24 | git checkout -b my_new_feature 25 | 26 | where ``my_new_feature`` is a short name for the new feature or bug report. 27 | 28 | 3. Commit your changes as usual with git. Do not commit a whole feature consisting of many-hundreds of new lines of code in a single commit. Useful commits should show the line of development separated in logical parts. See :ref:`git style` for more information on our preferences. 29 | 30 | 4. Push the *feature branch* to the remote repository: 31 | 32 | .. code-block:: shell 33 | 34 | git push origin my_new_feature 35 | 36 | 5. Create a new *pull request* on Github. Please mention any Github issue that this solves, so that the pull request and issue are linked by Github. 37 | 38 | 6. We will review the changes. 39 | 40 | There are a few important things to take note of when introducing new code: 41 | 42 | * Follow the existing :ref:`HCIPy coding style`. 43 | 44 | * Add docstrings for each class and function that is available outside of the HCIPy package. 45 | 46 | * Add unit tests for added code. The test coverage should not have decreased due to your contribution without a good reason. 47 | 48 | * Make sure that the documentation still builds, and that the full testing suite still run as expected. 49 | 50 | * Any new optical element should have its ``backward()`` function implemented, unless the physical object does not support such an operation. Please refer to the :doc:`"Creating your own optical elements" tutorial<../tutorials/CreatingYourOwnOpticalElements/CreatingYourOwnOpticalElements>` on how to do this. 51 | 52 | * For tutorials: make sure that you clean all outputs of the notebook. This is to avoid growing the size of the repository too quickly. 53 | -------------------------------------------------------------------------------- /hcipy/field/polar_grid.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from .field import Field 4 | from .grid import Grid 5 | from .coordinates import UnstructuredCoords 6 | 7 | class PolarGrid(Grid): 8 | '''A grid representing a two-dimensional Polar coordinate system. 9 | ''' 10 | _coordinate_system = 'polar' 11 | 12 | @property 13 | def r(self): 14 | '''The radial coordinate (dimension 0). 15 | ''' 16 | return Field(self.coords[0], self) 17 | 18 | @property 19 | def theta(self): 20 | ''' The angular coordinate (dimension 1). 21 | ''' 22 | return Field(self.coords[1], self) 23 | 24 | def scale(self, scale): 25 | '''Scale the grid in-place. 26 | 27 | Parameters 28 | ---------- 29 | scale : array_like 30 | The factor with which to scale the grid. 31 | 32 | Returns 33 | ------- 34 | Grid 35 | Itself to allow for chaining these transformations. 36 | ''' 37 | self.coords *= np.array([scale, 1]) 38 | self.weights *= np.abs(scale)**(self.ndim) 39 | return self 40 | 41 | def shift(self, shift): 42 | '''Shift the grid in-place. 43 | 44 | .. caution:: 45 | All structure in the coordinates will be destroyed. 46 | 47 | Parameters 48 | ---------- 49 | shift : array_like 50 | The amount with which to shift the grid. 51 | 52 | Returns 53 | ------- 54 | Grid 55 | Itself to allow for chaining these transformations. 56 | ''' 57 | new_grid = PolarGrid(UnstructuredCoords(self.coords)).as_('cartesian') 58 | self.coords = new_grid.shifted(shift).as_('polar').coords 59 | 60 | return self 61 | 62 | def shifted(self, shift): 63 | '''A shifted copy of this grid. 64 | 65 | .. caution:: 66 | The returned grid is a Cartesian grid. 67 | 68 | Parameters 69 | ---------- 70 | shift : array_like 71 | The amount with which to shift the grid. 72 | 73 | Returns 74 | ------- 75 | Grid 76 | The scaled grid. 77 | ''' 78 | grid = self.as_('cartesian') 79 | grid.shift(shift) 80 | return grid 81 | 82 | def rotate(self, angle, axis=None): 83 | '''Rotate the grid in-place. 84 | 85 | Parameters 86 | ---------- 87 | angle : scalar 88 | The angle in radians. 89 | axis : ndarray or None 90 | The axis of rotation. For this (polar) grid, it is ignored. 91 | 92 | Returns 93 | ------- 94 | Grid 95 | Itself to allow for chaining these transformations. 96 | ''' 97 | self.coords += (0, angle) 98 | return self 99 | 100 | @staticmethod 101 | def _get_automatic_weights(coords): 102 | return None 103 | 104 | def _cartesian_to_polar(self): 105 | from .coordinates import UnstructuredCoords 106 | 107 | x = self.x 108 | y = self.y 109 | r = np.hypot(x, y) 110 | theta = np.arctan2(y, x) 111 | return PolarGrid(UnstructuredCoords([r, theta])) 112 | 113 | def _polar_to_cartesian(self): 114 | from .coordinates import UnstructuredCoords 115 | from .cartesian_grid import CartesianGrid 116 | 117 | r = self.r 118 | theta = self.theta 119 | x = r * np.cos(theta) 120 | y = r * np.sin(theta) 121 | return CartesianGrid(UnstructuredCoords([x, y])) 122 | 123 | Grid._add_coordinate_system('polar', PolarGrid) 124 | 125 | Grid._add_coordinate_system_transformation('cartesian', 'polar', _cartesian_to_polar) 126 | Grid._add_coordinate_system_transformation('polar', 'cartesian', _polar_to_cartesian) 127 | -------------------------------------------------------------------------------- /hcipy/util/finite_difference.py: -------------------------------------------------------------------------------- 1 | from ..field import Field, make_uniform_grid 2 | import numpy as np 3 | from scipy import sparse 4 | 5 | def generate_convolution_matrix(grid, kernel): 6 | '''Create the matrix that applies a convolution with kernel. 7 | 8 | The created matrix is a sparse matrix. 9 | 10 | Parameters 11 | ---------- 12 | grid : Grid 13 | The :class:`Grid` for which the convolution matrix will be created. 14 | kernel : Field or array_like 15 | The convolution kernel 16 | 17 | Returns 18 | ------- 19 | array_like 20 | The matrix that applies the convolution. 21 | ''' 22 | if hasattr(kernel, 'grid'): 23 | if np.allclose(kernel.grid.delta, grid.delta): 24 | num_x = kernel.grid.shape[1] 25 | num_y = kernel.grid.shape[0] 26 | else: 27 | raise ValueError("Kernel and grid are sampled with different grid spacings.") 28 | else: 29 | if kernel.ndim == 2: 30 | num_x = kernel.shape[1] 31 | num_y = kernel.shape[0] 32 | kernel = kernel.ravel() 33 | elif kernel.ndim == 1: 34 | raise NotImplementedError("Can not create a convolution kernel from a 1D array.") 35 | 36 | index_y, index_x = np.indices((num_y, num_x)) 37 | offsets = ((index_x - num_x // 2) + (index_y - num_y // 2) * grid.shape[0]).ravel() 38 | convolution_matrix = sparse.diags(kernel, offsets, shape=(grid.size, grid.size)) 39 | return convolution_matrix 40 | 41 | def make_laplacian_matrix(grid): 42 | '''Make the Laplacian operator using the 5-point stencil approximation 43 | 44 | Parameters 45 | ---------- 46 | grid : Grid 47 | The grid for which the derivative matrix is calculated. 48 | 49 | Returns 50 | ------- 51 | array_like 52 | The convolution matrix. 53 | ''' 54 | if grid.is_('cartesian') and grid.is_separated and grid.is_regular: 55 | num_x = 3 56 | num_y = 3 57 | kernel_grid = make_uniform_grid((num_x, num_y), (num_x * grid.delta[0], num_y * grid.delta[1]), has_center=True) 58 | kernel = kernel_grid.zeros().shaped 59 | kernel[1, 1] = 4 60 | kernel[1, 0] = -1 61 | kernel[1, 2] = -1 62 | kernel[0, 1] = -1 63 | kernel[2, 1] = -1 64 | kernel = Field(kernel.ravel(), kernel_grid) 65 | 66 | return generate_convolution_matrix(grid, kernel) 67 | else: 68 | raise NotImplementedError() 69 | 70 | def make_derivative_matrix(grid, axis='x'): 71 | '''Make the derivative operator using the central difference approximation. 72 | 73 | Parameters 74 | ---------- 75 | grid : Grid 76 | The grid for which the derivative matrix is calculated. 77 | axis : string 78 | The axis for which the convolution kernel is calculated default is 'x'. 79 | 80 | Returns 81 | ------- 82 | array_like 83 | The convolution matrix. 84 | ''' 85 | if grid.is_('cartesian') and grid.is_separated and grid.is_regular: 86 | num_x = 3 87 | num_y = 3 88 | kernel_grid = make_uniform_grid((num_x, num_y), (num_x * grid.delta[0], num_y * grid.delta[1]), has_center=True) 89 | kernel = kernel_grid.zeros() 90 | kernel = kernel.shaped 91 | 92 | if axis == 'x': 93 | kernel[1, 0] = -1 / (2 * grid.delta[1]) 94 | kernel[1, 2] = 1 / (2 * grid.delta[1]) 95 | elif axis == 'y': 96 | kernel[0, 1] = -1 / (2 * grid.delta[0]) 97 | kernel[2, 1] = 1 / (2 * grid.delta[0]) 98 | else: 99 | raise NotImplementedError() 100 | 101 | kernel = Field(kernel.ravel(), kernel_grid) 102 | return generate_convolution_matrix(grid, kernel) 103 | else: 104 | raise NotImplementedError() 105 | -------------------------------------------------------------------------------- /hcipy/fourier/chirp_z_transform.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.fft import next_fast_len 3 | 4 | from .fourier_transform import _get_float_and_complex_dtype 5 | from .._math import fft as _fft_module 6 | 7 | class ChirpZTransform: 8 | r'''The Chirp Z-transform (CZT). 9 | 10 | This class evaluates: 11 | 12 | .. math:: X_k = \sum_{n=0}^{N-1} x(n) z_k^{-n} 13 | 14 | where :math:`N` is the number of points along the real space, :math:`M` 15 | is the number of points in the Z-plane. The Chirp Z-transform samples 16 | the Z-plane on equidistant points along spiral arcs, where the arcs are 17 | given by the starting point :math:`A` and the complex ratio between points 18 | :math:`W`: 19 | 20 | .. math:: z_k = A * W^{-k}, k=0, 1, \ldots, M - 1 21 | 22 | This implementation uses Bluestein's algorithm to compute the CZT using Fast 23 | Fourier Transforms. 24 | 25 | Parameters 26 | ---------- 27 | n : integer 28 | The number of points in the real plane. 29 | m : integer 30 | The number of points in the Z-plane. 31 | w : scalar 32 | The complex ratio between points in the Z-plane. Note: ensure that its 33 | absolute value is close to one, so that w**(max(n, m)**2) does not 34 | overflow. 35 | a : scalar 36 | The starting point in the complex Z-plane. Note: ensure that its absolute 37 | value is close to one, so that a**max(n, m) does not overflow. 38 | ''' 39 | def __init__(self, n, m, w, a): 40 | # Ensure that w and a are complex scalars. 41 | w = complex(w) 42 | a = complex(a) 43 | 44 | self.n = n 45 | self.m = m 46 | self.w = w 47 | self.a = a 48 | 49 | self._current_dtype = None 50 | 51 | def _compute_kernel_and_weights(self, dtype): 52 | _, complex_dtype = _get_float_and_complex_dtype(dtype) 53 | 54 | if complex_dtype != self._current_dtype: 55 | k = np.arange(max(self.m, self.n)) 56 | self.k = k 57 | 58 | wk2 = self.w**(self.k**2 / 2) 59 | 60 | self.nfft = next_fast_len(self.n + self.m - 1) 61 | 62 | self._Awk2 = self.a**-k[:self.n] * wk2[:self.n] 63 | self._Fwk2 = _fft_module.fft(1 / np.hstack((wk2[self.n - 1:0:-1], wk2[:self.m])), self.nfft) 64 | self._wk2 = wk2[:self.m] 65 | self._yidx = slice(self.n - 1, self.n + self.m - 1) 66 | 67 | self._Awk2 = self._Awk2.astype(complex_dtype, copy=False) 68 | self._Fwk2 = self._Fwk2.astype(complex_dtype, copy=False) 69 | self._wk2 = self._wk2.astype(complex_dtype, copy=False) 70 | 71 | self._current_dtype = complex_dtype 72 | 73 | def __call__(self, x): 74 | '''Compute the Chirp Z-transform along the last axis. 75 | 76 | The input is expected to have `n` points along the last axis. 77 | This is assumed but not checked. The transform is multiplexed 78 | along all other axes. 79 | 80 | The return value has the same number of axes, with the last axis 81 | having `m` elements. 82 | 83 | Parameters 84 | ---------- 85 | x : array_like 86 | The array to compute the chirp Z-transform for. 87 | 88 | Returns 89 | ------- 90 | array_like 91 | The chirp Z-transformed array. 92 | ''' 93 | self._compute_kernel_and_weights(x.dtype) 94 | 95 | # Perform the CZT. 96 | x = x * self._Awk2 97 | 98 | intermediate = _fft_module.fft(x, self.nfft) 99 | intermediate *= self._Fwk2 100 | res = _fft_module.ifft(intermediate) 101 | 102 | res = res[..., self._yidx] * self._wk2 103 | 104 | _, complex_dtype = _get_float_and_complex_dtype(x.dtype) 105 | return res.astype(complex_dtype, copy=False) 106 | -------------------------------------------------------------------------------- /hcipy/util/stats.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ..field import Field 3 | 4 | def large_poisson(lam, thresh=1e6): 5 | """ 6 | Draw samples from a Poisson distribution, taking care of large values of `lam`. 7 | 8 | At large values of `lam` the distribution automatically switches to the corresponding normal distribution. 9 | This switch is independently decided for each expectation value in the `lam` array. 10 | 11 | Parameters 12 | ---------- 13 | lam : array_like 14 | Expectation value for the Poisson distribution. Must be >= 0. 15 | thresh : float 16 | The threshold at which the distribution switched from a Poisson to a normal distribution. 17 | 18 | Returns 19 | ------- 20 | array_like 21 | The drawn samples from the Poisson or normal distribution, depending on the expectation value. 22 | """ 23 | large = lam > thresh 24 | small = ~large 25 | 26 | # Use normal approximation if the number of photons is large 27 | n = np.zeros(lam.shape) 28 | n[large] = np.round(lam[large] + np.random.normal(size=np.sum(large)) * np.sqrt(lam[large])) 29 | n[small] = np.random.poisson(lam[small], size=np.sum(small)) 30 | 31 | if hasattr(lam, 'grid'): 32 | n = Field(n, lam.grid) 33 | 34 | return n 35 | 36 | def large_gamma(lam, theta, thresh=1e6): 37 | """ 38 | Draw samples from a Gamma distribution, taking care of large values of `lam`. 39 | 40 | At large values of `lam` the distribution automatically switches to the corresponding normal distribution. 41 | This switch is independently decided for each expectation value in the `lam` array. 42 | 43 | Parameters 44 | ---------- 45 | lam : array_like 46 | The shape parameter distribution. Must be >= 0. 47 | theta : array_like 48 | The scale parameter of the Gamma distribution. 49 | thresh : float 50 | The threshold at which the distribution switched from a Gamma to a normal distribution. 51 | 52 | Returns 53 | ------- 54 | array_like 55 | The drawn samples from the Gamma or normal distribution, depending on the expectation value. 56 | """ 57 | large = lam > thresh 58 | small = ~large 59 | 60 | theta = theta * np.ones_like(lam) 61 | 62 | # Use normal approximation if the shape parameter is large 63 | n = np.zeros(lam.shape) 64 | mean = lam * theta 65 | std = np.sqrt(mean * theta) 66 | 67 | n[large] = mean[large] + std[large] * np.random.normal(size=np.sum(large)) 68 | n[small] = np.random.gamma(lam[small], theta[small], size=np.sum(small)) 69 | 70 | if hasattr(lam, 'grid'): 71 | n = Field(n, lam.grid) 72 | 73 | return n 74 | 75 | def make_emccd_noise(photo_electron_flux, read_noise, emgain): 76 | """ 77 | Draw samples from a Poisson-Gamma-Normal distribution, which is an accurate model of EMCCDs (following [Hirsch2013]_). 78 | 79 | The model is most accurate for high emgains. 80 | 81 | .. [Hirsch2013] Michael Hirsch et al. " A stochastic model for electron multiplication 82 | charge-coupled devices - from theory to practice." PloS one 8.1 (2013): e53671. 83 | 84 | Parameters 85 | ---------- 86 | photo_electron_flux : array_like 87 | The incoming photo-electron flux, which is usually a combination of QE * (photon_flux + background) + dark current. 88 | read_noise : array_like 89 | The read noise of the camera. 90 | emgain : float 91 | The electron multiplying gain of the EMCCD process. Must be larger than 0. 92 | 93 | Returns 94 | ------- 95 | array_like 96 | The noisy realization of the EMCCD detection. 97 | """ 98 | photo_electrons = large_poisson(photo_electron_flux) 99 | 100 | detector_counts = large_gamma(photo_electrons, emgain) + read_noise * np.random.standard_normal(photo_electron_flux.shape) 101 | 102 | return detector_counts 103 | -------------------------------------------------------------------------------- /hcipy/interpolation/linear.py: -------------------------------------------------------------------------------- 1 | from scipy.interpolate import RegularGridInterpolator, LinearNDInterpolator 2 | import numpy as np 3 | from ..field import Field 4 | 5 | def make_linear_interpolator_separated(field, grid=None, fill_value=np.nan): 6 | '''Make a linear interpolator for a Field on a separated grid. 7 | 8 | Parameters 9 | ---------- 10 | field : Field or ndarray 11 | The field to interpolate. 12 | grid : Grid or None 13 | The grid of the field. If it is given, the grid of `field` is replaced by this grid. 14 | fill_value : scalar 15 | The value to use for points outside of the domain of the input field. If this is None, the values 16 | outside the domain are extrapolated. 17 | 18 | Returns 19 | ------- 20 | Field generator 21 | The interpolator, as a Field generator. The grid on which this field generator will evaluated, does 22 | not have to be separated. 23 | ''' 24 | if grid is None: 25 | grid = field.grid 26 | else: 27 | field = Field(field, grid) 28 | 29 | # RegularGridInterpolator expects data to be in ij indexing rather than xy. We 30 | # need to reverse the axes of the data and the coordinates. 31 | data = np.moveaxis(field.shaped, range(-1, -grid.ndim - 1, -1), range(-grid.ndim, 0, 1)) 32 | 33 | interp = RegularGridInterpolator(grid.separated_coords, data, 'linear', False, fill_value) 34 | 35 | def interpolator(evaluated_grid): 36 | res = interp(evaluated_grid.points) 37 | 38 | return Field(res.ravel(), evaluated_grid) 39 | 40 | return interpolator 41 | 42 | def make_linear_interpolator_unstructured(field, grid=None, fill_value=np.nan): 43 | '''Make a linear interpolator for a Field on an unstructured grid. 44 | 45 | Parameters 46 | ---------- 47 | field : Field or array_like 48 | The field to interpolate. 49 | grid : Grid or None 50 | The grid of the field. If it is given, the grid of `field` is replaced by this grid. 51 | fill_value : scalar 52 | The value to use for points outside of the domain of the input field. Linear extrapolation 53 | is not supported. 54 | 55 | Returns 56 | ------- 57 | Field generator 58 | The interpolator as a Field generator. The grid on which this field generator will be evaluated does 59 | not need to have any structure. 60 | ''' 61 | if grid is None: 62 | grid = field.grid 63 | else: 64 | field = Field(field, grid) 65 | 66 | interp = LinearNDInterpolator(grid.points, np.asarray(field), fill_value) 67 | 68 | def interpolator(evaluated_grid): 69 | res = interp(evaluated_grid.points) 70 | 71 | if fill_value is not np.nan: 72 | res[~np.isfinite(res)] = fill_value 73 | 74 | return Field(res, evaluated_grid) 75 | 76 | return interpolator 77 | 78 | def make_linear_interpolator(field, grid=None, fill_value=np.nan): 79 | '''Make a linear interpolator for a Field on any type of grid. 80 | 81 | Parameters 82 | ---------- 83 | field : Field or array_like 84 | The field to interpolate. 85 | grid : Grid or None 86 | The grid of the field. If it is given, the grid of `field` is replaced by this grid. 87 | fill_value : scalar or None 88 | The value to use for points outside of the domain of the input field. Extrapolation is not supported. 89 | If it is None, a numpy.nan value will be used for points outside of the domain. 90 | 91 | Returns 92 | ------- 93 | Field generator 94 | The interpolator as a Field generator. The grid on which this field generator will be evaluated does 95 | not need to have any structure. 96 | ''' 97 | if grid is None: 98 | grid = field.grid 99 | 100 | if grid.is_unstructured: 101 | return make_linear_interpolator_unstructured(field, grid, fill_value) 102 | else: 103 | return make_linear_interpolator_separated(field, grid, fill_value) 104 | -------------------------------------------------------------------------------- /hcipy/util/singular_value_decomposition.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse 3 | import scipy.sparse.linalg 4 | 5 | from ..mode_basis import ModeBasis 6 | 7 | class SVD(object): 8 | '''The Singular Value Decomposition for the provided matrix. 9 | 10 | This class wraps two versions of the SVD in numpy and scipy, and provides 11 | easy access to singular modes (as mode bases) and allows for calculation 12 | of the SVD for a limited number of modes. 13 | 14 | When a sparse matrix is passed, and no number of modes is given, all but one 15 | mode will be calculated. The reason is that the sparse SVD implementation in Scipy 16 | doesn't allow calculation of all modes. If all modes are required, the user 17 | must pass a densified version of the matrix (ie. `matrix.toarray()`). 18 | 19 | Parameters 20 | ---------- 21 | matrix : ndarray or any sparse matrix 22 | The matrix on which to perform the SVD. 23 | num_modes : int or None 24 | The number of singular values and modes to calculate. If this is None, 25 | and `matrix` is not sparse, all modes will be computed. If this is None and 26 | `matrix` is sparse, all but one mode will be computed. 27 | ''' 28 | def __init__(self, matrix=None, num_modes=None, M=None): 29 | if matrix is None: 30 | import warnings 31 | warnings.warn('Deprecated: use "matrix" instead of "M".', DeprecationWarning, stacklevel=2) 32 | matrix = M 33 | 34 | if matrix is None: 35 | raise ValueError('You need to supply a matrix.') 36 | 37 | self._matrix = matrix 38 | self._num_modes = num_modes 39 | 40 | is_sparse = scipy.sparse.issparse(matrix) 41 | 42 | if is_sparse and self.num_modes is None: 43 | self._num_modes = min(matrix.shape) - 1 44 | 45 | if self.num_modes is None: 46 | self._svd = np.linalg.svd(matrix, full_matrices=False) 47 | else: 48 | self._svd = scipy.sparse.linalg.svds(matrix, int(self.num_modes)) 49 | 50 | @property 51 | def left_singular_modes(self): 52 | '''The left singular modes of the matrix, as a ModeBasis. 53 | ''' 54 | 55 | return ModeBasis([m for m in self.U.conj().T]) 56 | 57 | @property 58 | def right_singular_modes(self): 59 | '''The right singular modes of the matrix, as a ModeBasis. 60 | ''' 61 | from ..mode_basis import ModeBasis 62 | 63 | return ModeBasis([m for m in self.Vt.conj()]) 64 | 65 | @property 66 | def singular_values(self): 67 | '''The singular values of the matrix. 68 | ''' 69 | return self.S 70 | 71 | @property 72 | def U(self): # noqa: N802 73 | '''The U matrix of the SVD. 74 | ''' 75 | return self.svd[0] 76 | 77 | @property 78 | def S(self): # noqa: N802 79 | '''The singular values of the matrix. 80 | ''' 81 | return self.svd[1] 82 | 83 | @property 84 | def Vt(self): # noqa: N802 85 | '''The V^T matrix of the SVD. 86 | ''' 87 | return self.svd[2] 88 | 89 | def __getitem__(self, i): 90 | '''The raw U, S, and V^T matrices of the SVD by index. 91 | ''' 92 | return self.svd[i] 93 | 94 | @property 95 | def svd(self): 96 | '''The raw U, S, and V^T matrices of the SVD as a tuple. 97 | ''' 98 | return self._svd 99 | 100 | @property 101 | def num_modes(self): 102 | '''The number of singular modes that were calculated in this SVD. 103 | ''' 104 | return self._num_modes 105 | 106 | @property 107 | def matrix(self): 108 | '''The matrix for which the SVD was calculated. 109 | ''' 110 | return self._matrix 111 | 112 | @property 113 | def M(self): # noqa: N802 114 | import warnings 115 | warnings.warn('Deprecated: use "matrix" instead of "M".', DeprecationWarning, stacklevel=2) 116 | return self.matrix 117 | -------------------------------------------------------------------------------- /hcipy/optics/gaussian_beam.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ..field import Field 3 | from .wavefront import Wavefront 4 | 5 | class GaussianBeam(object): 6 | '''An analytical description of a light beam with a Gaussian profile. 7 | 8 | Parameters 9 | ---------- 10 | w0 : scalar 11 | The beam waist. 12 | z : scalar 13 | The current distance from the beam waist. 14 | wavelength : scalar 15 | The wavelength of the light. 16 | ''' 17 | def __init__(self, w0, z, wavelength): 18 | self.w0 = w0 19 | self.z = z 20 | self.wavelength = wavelength 21 | 22 | @property 23 | def beam_waist(self): 24 | '''The beam waist of the Gaussian beam. 25 | ''' 26 | return self.w0 27 | 28 | @beam_waist.setter 29 | def beam_waist(self, w0): 30 | self.w0 = w0 31 | 32 | @property 33 | def zR(self): # noqa: N802 34 | '''The Rayleight distance of the Gaussian beam. 35 | ''' 36 | return np.pi * self.w0**2 / self.wavelength 37 | 38 | @zR.setter 39 | def zR(self, zR): # noqa: N802 40 | self.w0 = np.sqrt(zR * self.wavelength / np.pi) 41 | 42 | rayleigh_distance = zR 43 | 44 | @property 45 | def q(self): 46 | '''The complex beam parameter of the Gaussian beam. 47 | ''' 48 | return self.z + 1j * self.zR 49 | 50 | @q.setter 51 | def q(self, q): 52 | self.z = np.real(q) 53 | self.zR = np.imag(q) 54 | 55 | complex_beam_parameter = q 56 | 57 | @property 58 | def theta(self): 59 | '''The beam divergence of the Gaussian beam. 60 | ''' 61 | return self.wavelength / (np.pi * self.w0) 62 | 63 | @theta.setter 64 | def theta(self, theta): 65 | self.w0 = self.wavelength / (theta * np.pi) 66 | 67 | beam_divergence = theta 68 | 69 | @property 70 | def R(self): # noqa: N802 71 | '''The current radius of curvature of the Gaussian beam. 72 | ''' 73 | epsilon = 1e-16 74 | if abs(self.z) < epsilon: 75 | return np.inf 76 | else: 77 | return self.z * (1 + (self.zR / self.z)**2) 78 | 79 | radius_of_curvature = R 80 | 81 | @property 82 | def psi(self): 83 | '''The current Gouy phase of the Gaussian beam. 84 | ''' 85 | return np.arctan(self.z / self.zR) 86 | 87 | gouy_phase = psi 88 | 89 | @property 90 | def w(self): 91 | '''The current beam radius of the Gaussian beam. 92 | ''' 93 | return self.w0 * np.sqrt(1 + (self.z / self.zR)**2) 94 | 95 | beam_radius = w 96 | 97 | @property 98 | def FWHM(self): # noqa: N802 99 | '''The current FWHM of the Gaussian beam. 100 | ''' 101 | return self.w * np.sqrt(2 * np.log(2)) 102 | 103 | full_width_half_maximum = FWHM 104 | 105 | @property 106 | def k(self): 107 | '''The wavenumber of the Gaussian beam. 108 | ''' 109 | return 2 * np.pi / self.wavelength 110 | 111 | @k.setter 112 | def k(self, k): 113 | self.wavelength = 2 * np.pi / k 114 | 115 | wavenumber = k 116 | 117 | def evaluate(self, grid): 118 | '''Evaluate the wavefront of the Gaussian beam at the current position on 119 | the given grid. 120 | 121 | Parameters 122 | ---------- 123 | grid : Grid 124 | The grid on which to calculate the wavefront for the Gaussian beam. 125 | 126 | Returns 127 | ------- 128 | Wavefront 129 | The evaluated wavefront of the Gaussian beam. 130 | ''' 131 | if grid.is_('cartesian'): 132 | r2 = grid.x**2 + grid.y**2 133 | else: 134 | r2 = grid.as_('polar').r**2 135 | 136 | K1 = self.w0 / self.w 137 | K2 = np.exp(-r2 / self.w**2) 138 | K3 = np.exp(-1j * (self.k * self.z + self.k * r2 / (2 * self.R) - self.psi)) 139 | 140 | return Wavefront(Field(K1 * K2 * K3, grid), self.wavelength) 141 | 142 | __call__ = evaluate 143 | -------------------------------------------------------------------------------- /hcipy/coronagraphy/fiber_nuller.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from ..optics import OpticalElement, PhaseApodizer, PhotonicLantern 4 | from ..propagation import FraunhoferPropagator 5 | from ..field import Field, CartesianGrid, RegularCoords 6 | from ..mode_basis import make_lp_modes 7 | 8 | class FiberNuller(OpticalElement): 9 | '''A generic fiber nuller 10 | 11 | Parameters 12 | ---------- 13 | input_grid : Grid 14 | The grid on which the incoming wavefront is defined. 15 | fiber : OpticalElement 16 | The fiber the light is injected into. 17 | apodizer : OpticalElement 18 | The apodizer, assumed to be in the pupil plane. 19 | ''' 20 | def __init__(self, input_grid, fiber, apodizer=None): 21 | self.input_grid = input_grid 22 | self.fiber = fiber 23 | self.focal_grid = self.fiber.input_grid 24 | self.apodizer = apodizer 25 | 26 | self.prop = FraunhoferPropagator(self.input_grid, self.focal_grid) 27 | 28 | self.output_grid = CartesianGrid(RegularCoords([1, 1], [1, 1], np.zeros(2))) 29 | self.output_grid.weights = 1 30 | 31 | def forward(self, wavefront): 32 | '''Propagate a wavefront through the fiber nuller 33 | 34 | Parameters 35 | ---------- 36 | wavefront : Wavefront 37 | The wavefront to propagate. This wavefront is expected to be 38 | in the pupil plane. 39 | 40 | Returns 41 | ------- 42 | Wavefront 43 | The coupling amplitude through the fiber nuller. 44 | ''' 45 | if self.apodizer is not None: 46 | wavefront = self.apodizer.forward(wavefront) 47 | 48 | foc = self.prop.forward(wavefront) 49 | output = self.fiber.forward(foc) 50 | 51 | return output 52 | 53 | def backward(self, wavefront): 54 | '''Propagate backwards through the fiber nuller 55 | 56 | Parameters 57 | ---------- 58 | wavefront : scalar 59 | The wavefront to propagate. This wavefront is expected to be 60 | a complex scalar representing light emerging from the fiber. 61 | 62 | Returns 63 | ------- 64 | Wavefront 65 | The pupil plane wavefront. 66 | ''' 67 | foc = self.fiber.backward(wavefront) 68 | output = self.prop.backward(foc) 69 | 70 | if self.apodizer is not None: 71 | output = self.apodizer.backward(output) 72 | 73 | return output 74 | 75 | class VortexFiberNuller(FiberNuller): 76 | '''A vortex fiber nuller 77 | 78 | Parameters 79 | ---------- 80 | input_grid : Grid 81 | The grid on which the incoming wavefront is defined. 82 | fiber : OpticalElement 83 | The fiber the light is injected into. 84 | vortex_charge : integer 85 | The vortex charge. 86 | ''' 87 | def __init__(self, input_grid, fiber, vortex_charge=1): 88 | phase_screen = Field(vortex_charge * input_grid.as_('polar').theta, input_grid) 89 | phase_apodizer = PhaseApodizer(phase_screen) 90 | 91 | super().__init__(input_grid, fiber, phase_apodizer) 92 | 93 | class PhotonicLanternNuller(FiberNuller): 94 | '''A 6 port mode-selective photonic lantern nuller 95 | 96 | Parameters 97 | ---------- 98 | input_grid : Grid 99 | The grid on which the incoming wavefront is defined. 100 | focal_grid : Grid 101 | The focal grid where light is injected into the lantern. 102 | mode_field_diameter : scalar 103 | (Optional) The mode field diameter of the lantern modes. 104 | vortex_charge : integer 105 | (Optional) The charge of an optional pupil plane vortex mask. 106 | ''' 107 | def __init__(self, input_grid, focal_grid, mode_field_diameter=1.31, vortex_charge=None): 108 | lp_modes = make_lp_modes(focal_grid, 1.5 * np.pi, mode_field_diameter) 109 | photonic_lantern = PhotonicLantern(lp_modes) 110 | 111 | if vortex_charge is not None: 112 | phase_screen = Field(vortex_charge * input_grid.as_('polar').theta, input_grid) 113 | phase_apodizer = PhaseApodizer(phase_screen) 114 | else: 115 | phase_apodizer = None 116 | 117 | super().__init__(input_grid, photonic_lantern, phase_apodizer) 118 | --------------------------------------------------------------------------------