ehpor / hcipy

A framework for performing optical propagation simulations, meant for high contrast imaging, in Python.
https://hcipy.org
MIT License
97 stars 31 forks source link

Bug in LyotCoronagraph if used with focal plane OpticalElement #177

Open syhaffert opened 1 year ago

syhaffert commented 1 year ago

There is a bug in the LyotCoronagraph if it is used with an OpticalElement as the focal plane mask. The class tries to automatically guess the coronagraphic focal plane on which the OpticalElement is defined. This is necessary for the Fraunhofer propagation from the pupil to the focal plane. However, when an OpticalElement is used, it tries to get it from the element.input_grid. This does not return the input grid but a function that needs to be evaluated to get the actual input grid. I have attached a minimal working example.

from hcipy import *
import numpy as np

if __name__ == "__main__":
    pupil_grid = make_pupil_grid(256, 1.1)
    focal_grid = make_focal_grid(q=5, num_airy=15)
    prop = FraunhoferPropagator(pupil_grid, focal_grid)
    aperture = evaluate_supersampled(make_circular_aperture(1), pupil_grid, 8)

    lyot_fpm = Apodizer(1 - make_circular_aperture(4.0)(focal_grid))
    coronagraph = LyotCoronagraph(pupil_grid, lyot_fpm)

    wf = Wavefront(aperture)
    wf_cor = prop(coronagraph(wf))

A proposed work around is to add an optional parameter where you explicitly pass the focal plane mask.

def __init__(self, input_grid, focal_plane_mask, lyot_stop=None, focal_length=1, coronagraph_grid=None):
        if coronagraph_grid is None:
            if hasattr(focal_plane_mask, 'input_grid'):
                # Focal plane mask is an optical element.
                coronagraph_grid = focal_plane_mask.input_grid
                self.focal_plane_mask = focal_plane_mask
            else:
                # Focal plane mask is a field.
                coronagraph_grid = focal_plane_mask.grid
                self.focal_plane_mask = Apodizer(focal_plane_mask)

        if lyot_stop is not None and not hasattr(lyot_stop, 'input_grid'):
            lyot_stop = Apodizer(lyot_stop)
        self.lyot_stop = lyot_stop

        self.prop = FraunhoferPropagator(input_grid, coronagraph_grid, focal_length=focal_length)
syhaffert commented 9 months ago

The second approach has been implemented in #217. That has solved this issue for me. @ehpor do you want to keep this issue open to keep track of the original issue?