How to use the coronagraph module


Coronagraph

Overview

The coronagraph module simulates electric field propagation through a coronagraph located downstream the AO loop. The input is the target residual phase, and the main output is the coronagraph image. Two types of coronagraphs are implemented : a perfect coronagraph and a more realistic coronagraph called four-plane coronagraph hereafter.

Perfect coronagraph

The perfect coronagraph substracts the diffractive effect of the telescope. Mathematically speaking, the following operations are performed:

  1. Electric field is computed from the incoming phase screen
  2. The average of the electric field over the pupil is substracted to the electric field
  3. Optical Fourier transform and square modulus yield the image in focal plane

References : Galicher, Raphaël : PhD thesis, section I.2.2.4 Sauvage, Jean-François : PhD thesis, section 2.4.3.1

Four-plane coronagraph

The four-plane coronagraph includes the different pupil and focal planes of a stellar coronagraph, in this order following the light in the instrument:

  1. an amplitude apodizer located in a pupil plane
  2. a focal plane mask located in a focal plane
  3. a Lyot stop located in a pupil plane
  4. and the image plane located in a focal plane.

An optical Fourier transform is performed to propagate the electric field from one plane to the next one. In the image plane, the square modulus of the electric field is computed.

For the four-plane coronagraph, you have the choice between the APLCs of SPHERE (Beuzit et al., 2019) and a user-defined coronagraph.

Images and PSF

The coronagraph module delivers the coronagraph image and the image with no coronagraph that we call point spread function (PSF) hereafter. The PSF is computed with the same residual phase than the coronagraph image. For the four-plane coronagraph, the PSF is computed without focal plane mask but with apodizer and Lyot stop. For the perfect coronagraph, the PSF is computed by removing the step number two in the description of “Perfect coronagraph”.

The image is centered between four pixels while the PSF is centered on one pixel. Both the coronagraph image and the PSF are without any noise and normalized to the maximum intensity of the diffraction pattern. The diffraction pattern is computed the same way as the PSF but with a flat incoming wavefront.

Polychromatism

The coronagraph module can handle polychromatic image formation. The simulated wavelengths are evenly distributed in $$ \left[ \lambda_0 - \Delta \lambda / 2, \lambda_0 + \Delta \lambda / 2 \right]$$ where λ0 is the coronagraph wavelength and Δλ the spectral bandwidth.

The incoming AO residual from Compass is a unique optical path difference screen, in micron, assumed to be achromatic. For each simulated wavelength, an electric field screen is computed from this optical path difference. Those screens are propagated through the coronagraph. The resulting image intensity is the sum of intensities for each simulated wavelength.

How to use it in Compass

Interface with the simulation

The coronagraph is a supervisor component, as well as a wfs, a dm or a rtc. During a simulation, the useful commands are available in the instance supervisor.corono. They are briefly described below. Please take a look at the docstrings for more technical information.

Every methods take as first parameter coro_index, namely the index of the coronagraph. Indeed, several coronagraphs may be used in the same simulation. The indexing is defined by the parameter file (see next section).

  • supervisor.corono.get_image(coro_index, expo_type='le') Return the image. If expo_type='le' (default), return the long exposure image. If expo_type='se', return the short exposure one.

  • supervisor.corono.get_psf(coro_index, expo_type='le') Return the coronagraph PSF. If expo_type='le' (default), return the long exposure PSF. If expo_type='se', return the short exposure one.

  • supervisor.corono.get_contrast(coro_index, expo_type='le', d_min=None, d_max=None, width=None, normalized_by_psf=True) Return azimuthal average, standard deviation, minimum and maximum of image intensity, at several angular distances from the optical axis. By default, image intensity is normalized by the maximum of the PSF.

  • supervisor.corono.reset(coro_index=None) Reset the integration of long exposure image and PSF.

  • supervisor.corono.compute_image(coro_index, comp_psf=True, accumulate=True) Compute the short exposure image, and accumulate it in the long exposure image. Might be useful if you need to overwrite the supervisor.next() method.

  • supervisor.corono.compute_psf(coro_index, accumulate) Compute the short exposure PSF, and accumulate it in the long exposure PSF. Again, might be useful if you need to overwrite the supervisor.next() method.

Parameter file

The coronagraphs are defined in the Compass parameter file through the configuration class config.Param_corono. To add one or more coronagraphs in the simulation, you need to set a list called p_coronos and filled with Param_corono() instances. Then you may choose the parameters y using the associated setters. For example :

p_corono0 = conf.Param_corono()
p_corono1 = conf.Param_corono()
p_coronos = [p_corono0, p_corono1]

p_corono0.set_type('SPHERE_APLC')  # type of coronograph
p_corono0.set_wavelength_0(1.6)    # [μm] wavelength

p_corono1.set_type('perfect')
p_corono1.set_wavelength_0(1.6)
p_corono1.set_dim_image(200)       # [pixel] size of the science image
p_corono1.set_image_sampling(3.5)  # [pixel] size of lambda/D in pixel

For each coronagraph, one of the required parameters is its type. You may choose between the SPHERE APLC, a perfect coronagraph or a user-defined coronagraph. Some parameters are common to every types, and some are specific. Those parameters are described in the following three sections.

SPHERE APLC

Type of coronagraph to set : p_corono.set_type('SPHERE_APLC')

Required parameters

  • p_corono.set_wavelength_0(float) Coronagraph wavelength in micron. This parameter is called λ hereafter.

Optional parameters

  • p_corono.set_dim_image(int) Size of the science image in pixel.

  • p_corono.set_image_sampling(float) Number of pixel per λ/D in the image plane. For instance, 2 is Shannon sampling. Default : auto computed value that matches SPHERE IRDIS pixel scale.

  • p_corono.set_delta_wav(float) Spectral bandwidth in micron. Default = 0.

  • p_corono.set_nb_wav(int) Number of simulated wavelengths in the spectral bandwidth. Default = 1. You need to set both delta_wav and nb_wav if you want polychromatic light.

  • p_corono.set_focal_plane_name(str) Name of the focal plane mask to use. Only the ALC masks are available for now. They are called SPHERE_APLC_fpm_ALC1, of diameter 145 mas, SPHERE_APLC_fpm_ALC2, of diameter 185 mas, and SPHERE_APLC_fpm_ALC3, of diameter 240 mas. Default is SPHERE_APLC_fpm_ALC2.

  • p_corono.set_fpm_sampling(float) Number of pixels per λ/D in the mask plane. Default is 20 (such high value has been chosen because a Babinet propagation method is used).

Perfect coronagraph

Type of coronagraph to set : p_corono.set_type('perfect')

Required parameters : wavelength_0, dim_image, image_sampling Optional parameters : delta_wav, nb_wav

User-defined coronagraph

Type of coronagraph to set : p_corono.set_type('custom')

Required parameters :

  • wavelength_0, dim_image, image_sampling

  • p_corono.set_apodizer_name(str) Apodizer keyword, or path to a fits file. Only the apodizer of SPHERE called APO1 is coded in Compass. It is accessible with the keyword SPHERE_APLC_apodizer_APO1. Otherwise, you may set your own apodizer with a path to a fits file of size (pupdiam, pupdiam). The integer pupdiam is the Compass pupil diameter in pixel.

  • p_corono.set_focal_plane_mask_name(str) Focal plane mask keyword, or path to a fits file. You may choose between a Lyot round mask called classical_Lyot or one of the keywords for the SPHERE ALC masks (which are round masks with hardcoded diameter). To use your own focal plane mask, set a path to a fits file of size (dim_fpm, dim_fpm). Your focal plane mask size dim_fpm in pixel is automatically detected by Compass during initialization. For polychromatic masks, you may use a 3D array of size (dim_fpm, dim_fpm, nb_wav), the third dimension corresponding to the simulated wavelengths.

  • p_corono.set_fpm_sampling(float) Number of pixel per λ/D in the mask plane. For the classical_Lyot focal plane mask, it is an optional parameter, with a default value equal to 20.

  • p_corono.set_lyot_fpm_radius(float) Radius of the mask in λ/D units. Exclusive to the classical_Lyot focal plane mask.

  • p_corono.set_lyot_stop_name(str) Lyot stop keyword, or path to a fits file. Only the Lyot stop of SPHERE is coded in Compass. It is accessible with the keyword SPHERE_APLC_Lyot_stop. Otherwise, you may set your own apodizer with a path to a fits file of size (pupdiam, pupdiam).

Optional parameters :

  • delta_wav, nb_wav
  • p_corono.set_babinet_trick(bool) True for enabling Babinet propagation method. Default : False. Forced to True for a classical_Lyot focal plane mask.

Example of use :

p_corono0 = conf.Param_corono()
p_coronos = [p_corono0]

p_corono0.set_type('custom')       # type of coronograph
p_corono0.set_wavelength_0(1.6)    # [μm] wavelength
p_corono0.set_dim_image(200)       # [pixel] size of the science image
p_corono0.set_image_sampling(3.5)  # [pixel] size of lambda/D in pixel

p_corono0.set_apodizer_name('/home/username/my_apodizer.fits') # your own apodizer
p_corono0.set_focal_plane_mask_name('classical_Lyot') # round mask
p_corono0.set_fpm_radius(2.3) # radius of the mask in lambda/D units
p_corono0.set_lyot_stop_name('SPHERE_APLC_Lyot_stop') # Lyot stop of SPHERE

Non settable parameters

Some parameters are automatically calculated by the simulation, but they are still acessible in the configuration module with the associated getter. For instance, the array of simulated wavelengths is available in supervisor.config.p_coronos[coro_index].get_wav_vec().

Other accessible parameters are :

  • supervisor.config.p_coronos[coro_index].get_apodizer() Return the apodizer array, of shape (pupdiam, pupdiam).
  • supervisor.config.p_coronos[coro_index].get_focal_plane_mask() Return the focal plane mask array. It is of shape (dim_fpm, dim_fpm, nb_wav), with the simulated wavelengths along the third dimension.
  • supervisor.config.p_coronos[coro_index].get_Lyot_stop() Return the Lyot stop array, of shape (pupdiam, pupdiam).

NCPA

Compass already has a function to add NCPA phase screens. It is in the target component :

  • supervisor.target.set_ncpa_tar(tar_index, ncpa) Set a NCPA phase screen, in microns. Has to be a 2D array of size (pupdiam, pupdiam). The parameter tar_index must be set to 0, as the coronagraph module gets the residual phase from the target 0.

Amplitude aberrations are available in the coronagraph, with the function :

  • supervisor.corono.set_electric_field_amplitude(coro_index, amplitude) Set the electric field amplitude before propagation through the coronagraph. The default amplitude is constant and equal to 1. Has to be a 3D array of size (pupdiam, pupdiam, nb_wav).

To simulate temporally evolving aberrations, you should update the screens at each iteration.

Known issues and possible improvements

  • Apodizer, focal plane mask and Lyot stop arrays are real and cannot be complex.

  • The wavelength array is defined as nλ wavelengths evenly distributed in $$\left[ \lambda_0 - \frac{\Delta \lambda}{2}, \lambda_0 + \frac{\Delta \lambda}{2}]\right]$$ However, these wavelengths simulate a bandwidth slightly larger than Δλ. It would be a better approximation to set the lower and upper bounds of the wavelength array at $$\lambda_0 - \frac{\Delta \lambda}{2} + \frac{\Delta \lambda}{2 n_{\lambda}}\verb! and ! \lambda_0 + \frac{\Delta \lambda}{2} - \frac{\Delta \lambda}{2 n_{\lambda}} \verb! respectively!.$$

  • Only the residual phase from the target number 0 is send to the coronagraphs. It might be relevant to account for each target, especially if we want to add planets in the field of view.

  • For the SPHERE APLC coronagraph, if the image sampling is not provided, a value is autocomputed to match the IRDIS pixel scale of 12.25 mas. The formula used is $$\verb!image_sampling! = \frac{\lambda_0 / D}{\verb!irdis_pixel_scale!} $$ with $$D = D_{\mathrm{telescope}} = 8 m$$ But the Lyot stop diameter should be used : $$D = D_{\mathrm{Lyot}} \simeq 0.96 D_{\mathrm{telescope}}$$

  • The Lyot stop of SPHERE does not feature the dead actuator patches.