Example #1
0
    def __init__(self,
                 electric_field,
                 wavelength=1,
                 input_stokes_vector=None,
                 pad_factor=1):
        shape = electric_field.shaped.shape
        assert shape[0] == shape[1], "simulation region must be square!"
        assert shape[
            0] % 2 == 0, "simulation region must be an even number of pixels across!"

        res = shape[0]

        new_field = np.pad(electric_field.shaped,
                           int(res * (pad_factor - 1) / 2)).flatten()

        self.radius = electric_field.grid[-1, 0]
        self.total_radius = self.radius * pad_factor
        self.pad_factor = pad_factor
        self.beam_res = res
        self.res = pad_factor * res

        padded_electric_field = hc.Field(
            new_field,
            hc.make_pupil_grid(pad_factor * res, 2 * pad_factor * self.radius))

        super().__init__(padded_electric_field, wavelength,
                         input_stokes_vector)
Example #2
0
 def remove_pad(wf, pad):
     res = wf.electric_field.shaped.shape[0]
     radius = wf.electric_field.grid[-1, 0]
     beamres = int(res / pad)
     padpix = int((pad - 1) * beamres / 2)
     field = wf.electric_field.shaped[padpix:-padpix, padpix:-padpix]
     grid = hc.make_pupil_grid(beamres, 2 * radius)
     return hc.Wavefront(hc.Field(field.flatten(), grid),
                         wavelength=wf.wavelength)
Example #3
0
 def __init__(self, num_act_across, x, diam):
     # TODO: implement actuator masking and count for total actuators
     self.M = len(x)
     self.diam = diam  # TODO: unused
     self.pupil_grid = hcipy.make_pupil_grid(self.M)
     self.num_act_across = num_act_across
     self.actuator_spacing = 1. / num_act_across
     self.influence_functions = hcipy.make_gaussian_influence_functions(
         self.pupil_grid, self.num_act_across, self.actuator_spacing)
     self.dm = hcipy.DeformableMirror(self.influence_functions)
     self.influence_function_matrix = self.dm.influence_functions.transformation_matrix
     self.command = np.zeros((num_act_across, num_act_across),
                             dtype=np.float64)
def run_loyt():
    from hcipy import make_pupil_grid, make_focal_grid, FraunhoferPropagator, circular_aperture, evaluate_supersampled, imshow_field, imsave_field, Field, LyotCoronagraph, Wavefront
    import numpy as np
    import matplotlib.pyplot as plt

    pupil_grid = make_pupil_grid(256)
    focal_grid = make_focal_grid(pupil_grid, 8, 32)
    prop = FraunhoferPropagator(pupil_grid, focal_grid)

    aperture = circular_aperture(1)
    aperture = evaluate_supersampled(aperture, pupil_grid, 8)

    mask = 1 - circular_aperture(3)(focal_grid)
    stop = circular_aperture(0.7)(pupil_grid)
    coro = LyotCoronagraph(pupil_grid, mask, stop)

    wf = Wavefront(aperture)
    lyot = coro(wf)

    img = prop(lyot)
    img_ref = prop(wf)

    output_path = get_output_path("miscellaneous")

    fig = plt.figure()
    imshow_field(np.log10(img.power / img_ref.power.max()), vmin=-6, vmax=0)
    plt.xlim(-25, 25)
    plt.ylim(-25, 25)
    cbar = plt.colorbar()
    cbar.set_label(r"$^{10}\log(contrast)$")
    plt.ylabel(r"$\lambda/D$")
    plt.xlabel(r"$\lambda/D$")
    fig.savefig(output_path + "lyot_psf")

    fig = plt.figure()
    imshow_field(np.log10(img_ref.power / img_ref.power.max()),
                 vmin=-6,
                 vmax=0)
    plt.xlim(-25, 25)
    plt.ylim(-25, 25)
    cbar = plt.colorbar()
    cbar.set_label(r"$^{10}\log(contrast)$")
    plt.ylabel(r"$\lambda/D$")
    plt.xlabel(r"$\lambda/D$")
    fig.savefig(output_path + "normal_psf")
def run_loyt():
    from hcipy import make_pupil_grid, make_focal_grid, FraunhoferPropagator, circular_aperture, evaluate_supersampled, imshow_field, imsave_field, Field, LyotCoronagraph, Wavefront
    import numpy as np
    import matplotlib.pyplot as plt

    pupil_grid = make_pupil_grid(256)
    focal_grid = make_focal_grid(pupil_grid, 8, 32)
    prop = FraunhoferPropagator(pupil_grid, focal_grid)

    aperture = circular_aperture(1)
    aperture = evaluate_supersampled(aperture, pupil_grid, 8)

    mask = 1 - circular_aperture(3)(focal_grid)
    stop = circular_aperture(0.7)(pupil_grid)
    coro = LyotCoronagraph(pupil_grid, mask, stop)

    wf = Wavefront(aperture)
    lyot = coro(wf)

    img = prop(lyot)
    img_ref = prop(wf)

    output_path = get_output_path("miscellaneous")

    fig = plt.figure()
    imshow_field(np.log10(img.power / img_ref.power.max()), vmin=-6, vmax=0)
    plt.xlim(-25,25)
    plt.ylim(-25,25)
    cbar = plt.colorbar()
    cbar.set_label(r"$^{10}\log(contrast)$")
    plt.ylabel(r"$\lambda/D$")
    plt.xlabel(r"$\lambda/D$")
    fig.savefig(output_path+"lyot_psf")

    fig = plt.figure()
    imshow_field(np.log10(img_ref.power / img_ref.power.max()), vmin=-6, vmax=0)
    plt.xlim(-25,25)
    plt.ylim(-25,25)
    cbar = plt.colorbar()
    cbar.set_label(r"$^{10}\log(contrast)$")
    plt.ylabel(r"$\lambda/D$")
    plt.xlabel(r"$\lambda/D$")
    fig.savefig(output_path+"normal_psf")
Example #6
0
    def _setup_grids(self):
        """ Set up the grids to compute the segmented mirror surface into.
        This is relatively slow, but we only need to do this once for
        each size of input grids.
        """
        npix = self.aperture.shaped.shape[0]
        if npix == self._last_npix:
            return
        else:
            self._last_npix = npix

        x, y = self.input_grid.coords

        self._seg_mask = np.zeros_like(x)
        self._seg_x = np.zeros_like(x)
        self._seg_y = np.zeros_like(y)
        self._seg_indices = dict()

        pupil_grid = hcipy.make_pupil_grid(dims=npix, diameter=PUP_DIAMETER)
        aper_num, seg_positions = get_atlast_aperture(
            normalized=False,
            segment_transmissions=np.arange(1, self.segnum + 1))
        aper_num = hcipy.evaluate_supersampled(aper_num, pupil_grid, 2)

        self._seg_mask = np.copy(aper_num)

        for i in self.segmentlist:
            wseg = np.where(self._seg_mask == i)
            self._seg_indices[i] = wseg

            cenx, ceny = self.seg_pos.points[i - 1]

            self._seg_x[wseg] = x[wseg] - cenx
            self._seg_y[wseg] = y[wseg] - ceny

            # Set gaps to zero
            bad_gaps_x = np.where(
                np.abs(self._seg_x) > 0.1 * PUP_DIAMETER
            )  #*PUP_DIAMETER generalizes it for any size pupil field
            self._seg_x[bad_gaps_x] = 0
            bad_gaps_y = np.where(np.abs(self._seg_y) > 0.1 * PUP_DIAMETER)
            self._seg_y[bad_gaps_y] = 0
Example #7
0
def build_DM(grid, diam=telescope_diameter):
    '''
    Generate a DM like how I've done
    '''
    num_acts = 21  #21 x 21 DM (a lot of actuators are outside the aperture)
    act_spacing = diam / num_acts
    influence_functions = hci.make_gaussian_influence_functions(
        grid, num_acts, act_spacing)
    DM = hci.DeformableMirror(influence_functions)
    n_modes = DM.num_actuators
    DM.flatten()

    grid_size = np.mean(grid.delta * grid.dims)
    dm_grid = hci.make_pupil_grid(num_acts, grid_size)
    fft_grid = hci.make_fft_grid(dm_grid)
    Fouriers = hci.make_fourier_basis(dm_grid, fft_grid)
    Fouriers = hci.ModeBasis([mode for mode in Fouriers.orthogonalized],
                             dm_grid)

    DM.actuators = Fouriers[0]
    return DM, dm_grid, Fouriers
Example #8
0
    def init_collimator(self, beam_radius, col_res=512):
        """the collimator can run on a higher res than regular pupil plane so that aliasing is prevented when also using PIAA"""

        self.col_args = (beam_radius, col_res)

        print("setting up collimator...")
        self.collimator_grid = hc.make_pupil_grid(col_res,
                                                  diameter=beam_radius * 2)
        self.propagator = hc.FraunhoferPropagator(
            self.collimator_grid,
            self.focal_grid,
            focal_length=self.fnum * 2 *
            beam_radius)  # what's the focal length after PIAA???

        def _inner_(wf):
            _power = wf.total_power

            reals, imags = wf.real, wf.imag
            reals = np.reshape(reals, (self.hi_pupil_res, self.hi_pupil_res))
            imags = np.reshape(imags, (self.hi_pupil_res, self.hi_pupil_res))

            if self.hi_pupil_res != col_res:
                reals = resize2(reals, (col_res, col_res)).flatten()
                imags = resize2(imags, (col_res, col_res)).flatten()
            else:
                reals = reals.flatten()
                imags = imags.flatten()

            new_wf = hc.Wavefront(
                hc.Field(reals + 1.j * imags, self.collimator_grid),
                wf.wavelength)
            # make sure power is conserved
            new_wf.total_power = _power
            return new_wf

        self.collimate = _inner_
        print("collimator setup complete")
print("generating: "+str(numb)+" psfs with:\n  fried parameter: "+str(fried_parameter)+"\n  sample time: "+str(time_between))

D_tel = 8.2 # meter
wavelength = 1e-6 # meter
oversampling = 8

# loading the files required for generating the vAPP.
amplitude_temp = read_fits(amplitude_file)
phase_temp     = read_fits(phase_file)

# number of pixels along one axis in the pupil
Npix = amplitude_temp.shape[0]

# generating the grids
pupil_grid = make_pupil_grid(Npix, D_tel)
focal_grid = make_focal_grid(pupil_grid, 4, 25, wavelength=wavelength)

#kolmogorov: verdeling voor sterkte special freq
spectral_noise_factory = SpectralNoiseFactoryFFT(kolmogorov_psd, pupil_grid, oversampling)
turbulence_layers = make_standard_multilayer_atmosphere(fried_parameter=fried_parameter, wavelength=wavelength)
# create phase screen
atmospheric_model = AtmosphericModel(spectral_noise_factory, turbulence_layers)

# Mapping from pupil plane to focal plane
prop = FraunhoferPropagator(pupil_grid, focal_grid)

# converting the amplitude and phase to fields
amplitude = Field(amplitude_temp.ravel(), pupil_grid)
phase     = Field(phase_temp.ravel(), pupil_grid)
Example #10
0
def seg_mirror_test():
    """
    Testing the integrated energy of images produced by HCIPy vs Poppy segmented DMs.

    This is now deprecated as I am using directly the hcipy SM, but specifically from an older commit:
    from hcipy.optics.segmented_mirror import SegmentedMirror
    """

    # Parameters
    which_tel = CONFIG_PASTIS.get('telescope', 'name')
    NPIX = CONFIG_PASTIS.getint('numerical', 'tel_size_px')
    PUP_DIAMETER = CONFIG_PASTIS.getfloat(which_tel, 'diameter')
    GAPSIZE = CONFIG_PASTIS.getfloat(which_tel, 'gaps')
    FLATTOFLAT = CONFIG_PASTIS.getfloat(which_tel, 'flat_to_flat')

    wvln = 638e-9
    lamD = 20
    samp = 4
    norm = False

    fac = 6.55

    # --------------------------------- #
    #aber_rad = 6.2
    aber_array = np.linspace(0, 2 * np.pi, 50, True)
    log.info('Aber in rad: \n{}'.format(aber_array))
    log.info('Aber in m: \n{}'.format(util.aber_to_opd(aber_array, wvln)))
    # --------------------------------- #

    ### HCIPy SM

    # HCIPy grids and propagator
    pupil_grid = hcipy.make_pupil_grid(dims=NPIX, diameter=PUP_DIAMETER)
    focal_grid = hcipy.make_focal_grid(pupil_grid, samp, lamD, wavelength=wvln)
    prop = hcipy.FraunhoferPropagator(pupil_grid, focal_grid)

    # Generate an aperture
    aper, seg_pos = get_atlast_aperture(normalized=norm)
    aper = hcipy.evaluate_supersampled(aper, pupil_grid, 1)

    # Instantiate the segmented mirror
    hsm = SegmentedMirror(aper, seg_pos)

    # Make a pupil plane wavefront from aperture
    wf = hcipy.Wavefront(aper, wavelength=wvln)

    ### Poppy SM

    psm = poppy.dms.HexSegmentedDeformableMirror(name='Poppy SM',
                                                 rings=3,
                                                 flattoflat=FLATTOFLAT * u.m,
                                                 gap=GAPSIZE * u.m,
                                                 center=False)

    ### Apply pistons
    hc_ims = []
    pop_ims = []
    for aber_rad in aber_array:

        # Flatten both SMs
        hsm.flatten()
        psm.flatten()

        # HCIPy
        for i in [19, 28]:
            hsm.set_segment(i, util.aber_to_opd(aber_rad, wvln) / 2, 0, 0)

        # Poppy
        for i in [34, 25]:
            psm.set_actuator(i,
                             util.aber_to_opd(aber_rad, wvln) * u.m, 0,
                             0)  # 34 in poppy is 19 in HCIPy

        ### Propagate to image plane
        ### HCIPy
        # Apply SM to pupil plane wf
        wf_fp_pistoned = hsm(wf)

        # Propagate from SM to image plane
        im_pistoned_hc = prop(wf_fp_pistoned)

        ### Poppy
        # Make an optical system with the Poppy SM and a detector
        osys = poppy.OpticalSystem()
        osys.add_pupil(psm)
        pxscle = 0.0031 * fac  # I'm tweaking pixelscale and fov_arcsec to match the HCIPy image
        fovarc = 0.05 * fac
        osys.add_detector(pixelscale=pxscle, fov_arcsec=fovarc, oversample=10)

        # Calculate the PSF
        psf = osys.calc_psf(wvln)

        # Get the PSF as an array
        im_pistoned_pop = psf[0].data

        hc_ims.append(im_pistoned_hc.intensity.shaped /
                      np.max(im_pistoned_hc.intensity))
        pop_ims.append(im_pistoned_pop / np.max(im_pistoned_pop))

    ### Trying to do it with numbers
    hc_ims = np.array(hc_ims)
    pop_ims = np.array(pop_ims)

    sum_hc = np.sum(hc_ims, axis=(1, 2))
    sum_pop = np.sum(
        pop_ims, axis=(1, 2)
    ) - 1.75  # the -1.75 is just there because I didn't bother about image normalization too much

    plt.suptitle('Image degradation of SMs')
    plt.plot(aber_array, sum_hc, label='HCIPy SM')
    plt.plot(aber_array, sum_pop, label='Poppy SM')
    plt.xlabel('rad')
    plt.ylabel('image sum')
    plt.legend()
    plt.show()
Example #11
0
import hcipy as hci

import time as time_pkg  #just nice to have

################################################################
### SETUP
################################################################
wavelength_wfs = 842.0E-9  #meters
telescope_diameter = 10.0  #meters

#make pupil slightly larger than the telescope diameter to control edge effects
pupil_grid_diameter = 60 / 56 * telescope_diameter
num_pupil_pixels = 100  #100 pupil pixels across the pupil diameter

#pupil_grid is the fundamental "what apertures get evaluated on"
pupil_grid = hci.make_pupil_grid(num_pupil_pixels, pupil_grid_diameter)

Hz = 1e3

################################################################
### FUNCTIONS
################################################################


def make_keck_ap(grid):
    '''
    Iteratively step through the rings of keck to generate the primary mirror aperture.
    This currently ignores any spiders or gaps between mirrors.
    '''
    #Find the positions where there are mirrors
    centroid_pos = [[0, 0]]
Example #12
0
    def __init__(self, input_dir, apod_design, samp):
        self.nseg = 120
        self.wvln = 638e-9  # m
        self.diam = 15.  # m
        self.sampling = samp
        self.lam_over_d = self.wvln / self.diam
        self.apod_dict = {
            'small': {
                'pxsize':
                1000,
                'fpm_rad':
                3.5,
                'fpm_px':
                150,
                'iwa':
                3.4,
                'owa':
                12.,
                'fname':
                '0_LUVOIR_N1000_FPM350M0150_IWA0340_OWA01200_C10_BW10_Nlam5_LS_IDD0120_OD0982_no_ls_struts.fits'
            },
            'medium': {
                'pxsize':
                1000,
                'fpm_rad':
                6.82,
                'fpm_px':
                250,
                'iwa':
                6.72,
                'owa':
                23.72,
                'fname':
                '0_LUVOIR_N1000_FPM682M0250_IWA0672_OWA02372_C10_BW10_Nlam5_LS_IDD0120_OD0982_no_ls_struts.fits'
            },
            'large': {
                'pxsize':
                1000,
                'fpm_rad':
                13.38,
                'fpm_px':
                400,
                'iwa':
                13.28,
                'owa':
                46.88,
                'fname':
                '0_LUVOIR_N1000_FPM1338M0400_IWA1328_OWA04688_C10_BW10_Nlam5_LS_IDD0120_OD0982_no_ls_struts.fits'
            }
        }
        self.imlamD = 1.2 * self.apod_dict[apod_design]['owa']

        # Pupil plane optics
        aper_path = 'inputs/TelAp_LUVOIR_gap_pad01_bw_ovsamp04_N1000.fits'
        aper_ind_path = 'inputs/TelAp_LUVOIR_gap_pad01_bw_ovsamp04_N1000_indexed.fits'
        apod_path = os.path.join(input_dir, 'luvoir_stdt_baseline_bw10',
                                 apod_design + '_fpm', 'solutions',
                                 self.apod_dict[apod_design]['fname'])
        ls_fname = 'inputs/LS_LUVOIR_ID0120_OD0982_no_struts_gy_ovsamp4_N1000.fits'

        pup_read = hc.read_fits(os.path.join(input_dir, aper_path))
        aper_ind_read = hc.read_fits(os.path.join(input_dir, aper_ind_path))
        apod_read = hc.read_fits(os.path.join(input_dir, apod_path))
        ls_read = hc.read_fits(os.path.join(input_dir, ls_fname))

        pupil_grid = hc.make_pupil_grid(
            dims=self.apod_dict[apod_design]['pxsize'], diameter=self.diam)

        self.aperture = hc.Field(pup_read.ravel(), pupil_grid)
        self.aper_ind = hc.Field(aper_ind_read.ravel(), pupil_grid)
        self.apod = hc.Field(apod_read.ravel(), pupil_grid)
        self.ls = hc.Field(ls_read.ravel(), pupil_grid)

        # Load segment positions from fits header
        hdr = fits.getheader(os.path.join(input_dir, aper_ind_path))

        poslist = []
        for i in range(self.nseg):
            segname = 'SEG' + str(i + 1)
            xin = hdr[segname + '_X']
            yin = hdr[segname + '_Y']
            poslist.append((xin, yin))

        poslist = np.transpose(np.array(poslist))
        self.seg_pos = hc.CartesianGrid(poslist)

        # Focal plane mask
        samp_foc = self.apod_dict[apod_design]['fpm_px'] / (
            self.apod_dict[apod_design]['fpm_rad'] * 2)
        focal_grid_fpm = hc.make_focal_grid(
            pupil_grid=pupil_grid,
            q=samp_foc,
            num_airy=self.apod_dict[apod_design]['fpm_rad'],
            wavelength=self.wvln)
        self.fpm = 1 - hc.circular_aperture(
            2 * self.apod_dict[apod_design]['fpm_rad'] *
            self.lam_over_d)(focal_grid_fpm)

        # Final focal plane grid (detector)
        self.focal_det = hc.make_focal_grid(pupil_grid=pupil_grid,
                                            q=self.sampling,
                                            num_airy=self.imlamD,
                                            wavelength=self.wvln)

        luvoir_params = {
            'wavelength': self.wvln,
            'diameter': self.diam,
            'imlamD': self.imlamD,
            'fpm_rad': self.apod_dict[apod_design]['fpm_rad']
        }

        # Initialize the general segmented telescope with APLC class, includes the SM
        super().__init__(aper=self.aperture,
                         indexed_aperture=self.aper_ind,
                         seg_pos=self.seg_pos,
                         apod=self.apod,
                         lyotst=self.ls,
                         fpm=self.fpm,
                         focal_grid=self.focal_det,
                         params=luvoir_params)

        # Propagators
        self.coro = hc.LyotCoronagraph(pupil_grid, self.fpm, self.ls)
        self.prop = hc.FraunhoferPropagator(pupil_grid, self.focal_det)
        self.coro_no_ls = hc.LyotCoronagraph(pupil_grid, self.fpm)
def clean_vapp():
    import numpy as np
    import matplotlib.pyplot as plt 

    from hcipy import read_fits, make_pupil_grid, make_focal_grid, FraunhoferPropagator, circular_aperture, evaluate_supersampled, imshow_field, imsave_field, Field, LyotCoronagraph, Wavefront

    script_path = os.path.realpath(__file__).split("vApp_reduction",1)[0]
    full_path = script_path+"vApp_reduction/data/"
    amplitude_file = full_path+'SCExAO_vAPP_amplitude_resampled.fits'
    phase_file     = full_path+'SCExAO_vAPP_phase_resampled.fits'

    # loading the files required for generating the vAPP. 
    amplitude_temp = read_fits(amplitude_file)
    phase_temp     = read_fits(phase_file)

    # number of pixels along one axis in the pupil
    Npix = amplitude_temp.shape[0]

    # generating the grids 
    pupil_grid = make_pupil_grid(Npix)
    focal_grid = make_focal_grid(pupil_grid, 4, 25)

    # Mapping from pupil plane to focal plane
    propagator = FraunhoferPropagator(pupil_grid, focal_grid)

    # converting the amplitude and phase to fields 
    amplitude = Field(amplitude_temp.ravel(), pupil_grid)
    phase     = Field(phase_temp.ravel(), pupil_grid)

    # the wavefront for the three PSFs 
    pupil_wf_PSF_1 = Wavefront(amplitude * np.exp(1j * phase)) # coronagraphic PSF 1
    pupil_wf_PSF_2 = Wavefront(amplitude * np.exp(-1j * phase)) # coronagraphic PSF 2
    pupil_wf_PSF_3 = Wavefront(amplitude) # leakage

    # Propagating them to the focal plane 
    focal_wf_PSF_1 = propagator(pupil_wf_PSF_1)
    focal_wf_PSF_2 = propagator(pupil_wf_PSF_2)
    focal_wf_PSF_3 = propagator(pupil_wf_PSF_3)

    # setting the total power in the images 
    focal_wf_PSF_1.total_power = 1
    focal_wf_PSF_2.total_power = 1
    focal_wf_PSF_3.total_power = 1

    # the strenght of the leakage term
    leakage = 0.02

    # getting the power and scaling with leakage 
    PSF_1_pwr = focal_wf_PSF_1.power * (1 - leakage / 2)
    PSF_2_pwr = focal_wf_PSF_2.power * (1 - leakage / 2)
    PSF_3_pwr = focal_wf_PSF_3.power * leakage

    # generating the total PSF of the vAPP
    total_PSF = PSF_1_pwr + PSF_2_pwr + PSF_3_pwr

    # normalizing to sum = 1
    total_PSF /= np.sum(total_PSF)

    fig = plt.figure()
    imshow_field(np.log10(total_PSF / total_PSF.max()), vmin=-5, vmax=0)
    cbar = plt.colorbar()
    cbar.set_label(r"$^{10}\log(contrast)$")
    plt.ylabel(r"$\lambda/D$")
    plt.xlabel(r"$\lambda/D$")

    plt.show()
    output_path = get_output_path("miscellaneous")
    fig.savefig(output_path+"clean_vapp")
Example #14
0
    wvln = 638e-9

    print('Setting up optics...')
    print('Data folder: {}'.format(workdir))
    print('Coronagraph: {}'.format(apodizer_design))

    # Create SM
    # Read pupil and indexed pupil
    inputdir = '/Users/ilaginja/Documents/LabWork/ultra/LUVOIR_delivery_May2019/'
    aper_path = 'inputs/TelAp_LUVOIR_gap_pad01_bw_ovsamp04_N1000.fits'
    aper_ind_path = 'inputs/TelAp_LUVOIR_gap_pad01_bw_ovsamp04_N1000_indexed.fits'
    aper_read = hc.read_fits(os.path.join(inputdir, aper_path))
    aper_ind_read = hc.read_fits(os.path.join(inputdir, aper_ind_path))

    # Sample them on a pupil grid and make them hc.Fields
    pupil_grid = hc.make_pupil_grid(dims=aper_ind_read.shape[0], diameter=15)
    aper = hc.Field(aper_read.ravel(), pupil_grid)
    aper_ind = hc.Field(aper_ind_read.ravel(), pupil_grid)

    # Create the wavefront on the aperture
    wf_aper = hc.Wavefront(aper, wvln)

    # Load segment positions from fits header
    hdr = fits.getheader(os.path.join(inputdir, aper_ind_path))
    poslist = []
    for i in range(nseg):
        segname = 'SEG' + str(i + 1)
        xin = hdr[segname + '_X']
        yin = hdr[segname + '_Y']
        poslist.append((xin, yin))
    poslist = np.transpose(np.array(poslist))
def clean_vapp():
    import numpy as np
    import matplotlib.pyplot as plt

    from hcipy import read_fits, make_pupil_grid, make_focal_grid, FraunhoferPropagator, circular_aperture, evaluate_supersampled, imshow_field, imsave_field, Field, LyotCoronagraph, Wavefront

    script_path = os.path.realpath(__file__).split("vApp_reduction", 1)[0]
    full_path = script_path + "vApp_reduction/data/"
    amplitude_file = full_path + 'SCExAO_vAPP_amplitude_resampled.fits'
    phase_file = full_path + 'SCExAO_vAPP_phase_resampled.fits'

    # loading the files required for generating the vAPP.
    amplitude_temp = read_fits(amplitude_file)
    phase_temp = read_fits(phase_file)

    # number of pixels along one axis in the pupil
    Npix = amplitude_temp.shape[0]

    # generating the grids
    pupil_grid = make_pupil_grid(Npix)
    focal_grid = make_focal_grid(pupil_grid, 4, 25)

    # Mapping from pupil plane to focal plane
    propagator = FraunhoferPropagator(pupil_grid, focal_grid)

    # converting the amplitude and phase to fields
    amplitude = Field(amplitude_temp.ravel(), pupil_grid)
    phase = Field(phase_temp.ravel(), pupil_grid)

    # the wavefront for the three PSFs
    pupil_wf_PSF_1 = Wavefront(amplitude *
                               np.exp(1j * phase))  # coronagraphic PSF 1
    pupil_wf_PSF_2 = Wavefront(amplitude *
                               np.exp(-1j * phase))  # coronagraphic PSF 2
    pupil_wf_PSF_3 = Wavefront(amplitude)  # leakage

    # Propagating them to the focal plane
    focal_wf_PSF_1 = propagator(pupil_wf_PSF_1)
    focal_wf_PSF_2 = propagator(pupil_wf_PSF_2)
    focal_wf_PSF_3 = propagator(pupil_wf_PSF_3)

    # setting the total power in the images
    focal_wf_PSF_1.total_power = 1
    focal_wf_PSF_2.total_power = 1
    focal_wf_PSF_3.total_power = 1

    # the strenght of the leakage term
    leakage = 0.02

    # getting the power and scaling with leakage
    PSF_1_pwr = focal_wf_PSF_1.power * (1 - leakage / 2)
    PSF_2_pwr = focal_wf_PSF_2.power * (1 - leakage / 2)
    PSF_3_pwr = focal_wf_PSF_3.power * leakage

    # generating the total PSF of the vAPP
    total_PSF = PSF_1_pwr + PSF_2_pwr + PSF_3_pwr

    # normalizing to sum = 1
    total_PSF /= np.sum(total_PSF)

    fig = plt.figure()
    imshow_field(np.log10(total_PSF / total_PSF.max()), vmin=-5, vmax=0)

    cbar = plt.colorbar()
    cbar.set_label(r"$^{10}\log(contrast)$")
    plt.ylabel(r"$\lambda/D$")
    plt.xlabel(r"$\lambda/D$")

    plt.show()
    output_path = get_output_path("miscellaneous")
    fig.savefig(output_path + "clean_vapp")

    fig = plt.figure()
    imshow_field(np.log10(total_PSF / total_PSF.max()), vmin=-5, vmax=0)

    bbox_props = dict(boxstyle="circle,pad=0.3",
                      fill=False,
                      alpha=1,
                      fc=None,
                      ec="red",
                      lw=5)
    plt.text(10.3,
             10.7,
             " ",
             ha="center",
             va="center",
             rotation=45,
             size=110,
             bbox=bbox_props)
    plt.text(-10.3,
             -10.7,
             " ",
             ha="center",
             va="center",
             rotation=45,
             size=110,
             bbox=bbox_props)
    bbox_props = dict(boxstyle="circle,pad=0.3",
                      fill=False,
                      alpha=1,
                      fc=None,
                      ec="white",
                      lw=5)
    plt.text(0,
             0,
             " ",
             ha="center",
             va="center",
             rotation=45,
             size=55,
             bbox=bbox_props)
    plt.text(8,
             -15,
             " ",
             ha="center",
             va="center",
             rotation=45,
             size=55,
             bbox=bbox_props)
    plt.text(-8,
             15,
             " ",
             ha="center",
             va="center",
             rotation=45,
             size=55,
             bbox=bbox_props)

    cbar = plt.colorbar()
    cbar.set_label(r"$^{10}\log(contrast)$")
    plt.ylabel(r"$\lambda/D$")
    plt.xlabel(r"$\lambda/D$")

    plt.show()
    output_path = get_output_path("miscellaneous")
    fig.savefig(output_path + "clean_vapp_annotated")
Example #16
0
def analytical_model(zernike_pol, coef, cali=False):
    """

    :param zernike_pol:
    :param coef:
    :param cali: bool; True if we already have calibration coefficients to use. False if we still need to create them.
    :return:
    """

    #-# Parameters
    dataDir = os.path.join(CONFIG_INI.get('local', 'local_data_path'),
                           'active')
    telescope = CONFIG_INI.get('telescope', 'name')
    nb_seg = CONFIG_INI.getint(telescope, 'nb_subapertures')
    tel_size_m = CONFIG_INI.getfloat(telescope, 'diameter') * u.m
    real_size_seg = CONFIG_INI.getfloat(
        telescope, 'flat_to_flat'
    )  # in m, size in meters of an individual segment flatl to flat
    size_seg = CONFIG_INI.getint(
        'numerical',
        'size_seg')  # pixel size of an individual segment tip to tip
    wvln = CONFIG_INI.getint(telescope, 'lambda') * u.nm
    inner_wa = CONFIG_INI.getint(telescope, 'IWA')
    outer_wa = CONFIG_INI.getint(telescope, 'OWA')
    tel_size_px = CONFIG_INI.getint(
        'numerical', 'tel_size_px')  # pupil diameter of telescope in pixels
    im_size_pastis = CONFIG_INI.getint(
        'numerical', 'im_size_px_pastis')  # image array size in px
    sampling = CONFIG_INI.getfloat('numerical', 'sampling')  # sampling
    size_px_tel = tel_size_m / tel_size_px  # size of one pixel in pupil plane in m
    px_sq_to_rad = (size_px_tel * np.pi / tel_size_m) * u.rad
    zern_max = CONFIG_INI.getint('zernikes', 'max_zern')
    sz = CONFIG_INI.getint('numerical', 'im_size_lamD_hcipy')

    # Create Zernike mode object for easier handling
    zern_mode = util.ZernikeMode(zernike_pol)

    #-# Mean subtraction for piston
    if zernike_pol == 1:
        coef -= np.mean(coef)

    #-# Generic segment shapes

    if telescope == 'JWST':
        # Load pupil from file
        pupil = fits.getdata(
            os.path.join(dataDir, 'segmentation', 'pupil.fits'))

        # Put pupil in randomly picked, slightly larger image array
        pup_im = np.copy(pupil)  # remove if lines below this are active
        #pup_im = np.zeros([tel_size_px, tel_size_px])
        #lim = int((pup_im.shape[1] - pupil.shape[1])/2.)
        #pup_im[lim:-lim, lim:-lim] = pupil
        # test_seg = pupil[394:,197:315]    # this is just so that I can display an individual segment when the pupil is 512
        # test_seg = pupil[:203,392:631]    # ... when the pupil is 1024
        # one_seg = np.zeros_like(test_seg)
        # one_seg[:110, :] = test_seg[8:, :]    # this is the centered version of the individual segment for 512 px pupil

        # Creat a mini-segment (one individual segment from the segmented aperture)
        mini_seg_real = poppy.NgonAperture(
            name='mini', radius=real_size_seg
        )  # creating real mini segment shape with poppy
        #test = mini_seg_real.sample(wavelength=wvln, grid_size=flat_diam, return_scale=True)   # fix its sampling with wavelength
        mini_hdu = mini_seg_real.to_fits(wavelength=wvln,
                                         npix=size_seg)  # make it a fits file
        mini_seg = mini_hdu[
            0].data  # extract the image data from the fits file

    elif telescope == 'ATLAST':
        # Create mini-segment
        pupil_grid = hcipy.make_pupil_grid(dims=tel_size_px,
                                           diameter=real_size_seg)
        focal_grid = hcipy.make_focal_grid(
            pupil_grid, sampling, sz, wavelength=wvln.to(
                u.m).value)  # fov = lambda/D radius of total image
        prop = hcipy.FraunhoferPropagator(pupil_grid, focal_grid)

        mini_seg_real = hcipy.hexagonal_aperture(circum_diameter=real_size_seg,
                                                 angle=np.pi / 2)
        mini_seg_hc = hcipy.evaluate_supersampled(
            mini_seg_real, pupil_grid, 4
        )  # the supersampling number doesn't really matter in context with the other numbers
        mini_seg = mini_seg_hc.shaped  # make it a 2D array

        # Redefine size_seg if using HCIPy
        size_seg = mini_seg.shape[0]

        # Make stand-in pupil for DH array
        pupil = fits.getdata(
            os.path.join(dataDir, 'segmentation', 'pupil.fits'))
        pup_im = np.copy(pupil)

    #-# Generate a dark hole mask
    #TODO: simplify DH generation and usage
    dh_area = util.create_dark_hole(
        pup_im, inner_wa, outer_wa, sampling
    )  # this might become a problem if pupil size is not same like pastis image size. fine for now though.
    if telescope == 'ATLAST':
        dh_sz = util.zoom_cen(dh_area, sz * sampling)

    #-# Import information form segmentation script
    Projection_Matrix = fits.getdata(
        os.path.join(dataDir, 'segmentation', 'Projection_Matrix.fits'))
    vec_list = fits.getdata(
        os.path.join(dataDir, 'segmentation', 'vec_list.fits'))  # in pixels
    NR_pairs_list = fits.getdata(
        os.path.join(dataDir, 'segmentation', 'NR_pairs_list_int.fits'))

    # Figure out how many NRPs we're dealing with
    NR_pairs_nb = NR_pairs_list.shape[0]

    #-# Chose whether calibration factors to do the calibraiton with
    if cali:
        filename = 'calibration_' + zern_mode.name + '_' + zern_mode.convention + str(
            zern_mode.index)
        ck = fits.getdata(
            os.path.join(dataDir, 'calibration', filename + '.fits'))
    else:
        ck = np.ones(nb_seg)

    coef = coef * ck

    #-# Generic coefficients
    # the coefficients in front of the non redundant pairs, the A_q in eq. 13 in Leboulleux et al. 2018
    generic_coef = np.zeros(
        NR_pairs_nb
    ) * u.nm * u.nm  # setting it up with the correct units this will have

    for q in range(NR_pairs_nb):
        for i in range(nb_seg):
            for j in range(i + 1, nb_seg):
                if Projection_Matrix[i, j, 0] == q + 1:
                    generic_coef[q] += coef[i] * coef[j]

    #-# Constant sum and cosine sum - calculating eq. 13 from Leboulleux et al. 2018
    if telescope == 'JWST':
        i_line = np.linspace(-im_size_pastis / 2., im_size_pastis / 2.,
                             im_size_pastis)
        tab_i, tab_j = np.meshgrid(i_line, i_line)
        cos_u_mat = np.zeros(
            (int(im_size_pastis), int(im_size_pastis), NR_pairs_nb))
    elif telescope == 'ATLAST':
        i_line = np.linspace(-(2 * sz * sampling) / 2.,
                             (2 * sz * sampling) / 2., (2 * sz * sampling))
        tab_i, tab_j = np.meshgrid(i_line, i_line)
        cos_u_mat = np.zeros((int((2 * sz * sampling)), int(
            (2 * sz * sampling)), NR_pairs_nb))

    # Calculating the cosine terms from eq. 13.
    # The -1 with each NR_pairs_list is because the segment names are saved starting from 1, but Python starts
    # its indexing at zero, so we have to make it start at zero here too.
    for q in range(NR_pairs_nb):
        # cos(b_q <dot> u): b_q with 1 <= q <= NR_pairs_nb is the basis of NRPS, meaning the distance vectors between
        #                   two segments of one NRP. We can read these out from vec_list.
        #                   u is the position (vector) in the detector plane. Here, those are the grids tab_i and tab_j.
        # We need to calculate the dot product between all b_q and u, so in each iteration (for q), we simply add the
        # x and y component.
        cos_u_mat[:, :, q] = np.cos(
            px_sq_to_rad *
            (vec_list[NR_pairs_list[q, 0] - 1, NR_pairs_list[q, 1] - 1, 0] *
             tab_i) + px_sq_to_rad *
            (vec_list[NR_pairs_list[q, 0] - 1, NR_pairs_list[q, 1] - 1, 1] *
             tab_j)) * u.dimensionless_unscaled

    sum1 = np.sum(
        coef**2
    )  # sum of all a_{k,l} in eq. 13 - this works only for single Zernikes (l fixed), because np.sum would sum over l too, which would be wrong.
    if telescope == 'JWST':
        sum2 = np.zeros(
            (int(im_size_pastis), int(im_size_pastis))
        ) * u.nm * u.nm  # setting it up with the correct units this will have
    elif telescope == 'ATLAST':
        sum2 = np.zeros(
            (int(2 * sz * sampling), int(2 * sz * sampling))) * u.nm * u.nm

    for q in range(NR_pairs_nb):
        sum2 = sum2 + generic_coef[q] * cos_u_mat[:, :, q]

    #-# Local Zernike
    if telescope == 'JWST':
        # Generate a basis of Zernikes with the mini segment being the support
        isolated_zerns = zern.hexike_basis(nterms=zern_max,
                                           npix=size_seg,
                                           rho=None,
                                           theta=None,
                                           vertical=False,
                                           outside=0.0)

        # Calculate the Zernike that is currently being used and put it on one single subaperture, the result is Zer
        # Apply the currently used Zernike to the mini-segment.
        if zernike_pol == 1:
            Zer = np.copy(mini_seg)
        elif zernike_pol in range(2, zern_max - 2):
            Zer = np.copy(mini_seg)
            Zer = Zer * isolated_zerns[zernike_pol - 1]

        # Fourier Transform of the Zernike - the global envelope
        mf = mft.MatrixFourierTransform()
        ft_zern = mf.perform(Zer, im_size_pastis / sampling, im_size_pastis)

    elif telescope == 'ATLAST':
        isolated_zerns = hcipy.make_zernike_basis(num_modes=zern_max,
                                                  D=real_size_seg,
                                                  grid=pupil_grid,
                                                  radial_cutoff=False)
        Zer = hcipy.Wavefront(mini_seg_hc * isolated_zerns[zernike_pol - 1],
                              wavelength=wvln.to(u.m).value)

        # Fourier transform the Zernike
        ft_zern = prop(Zer)

    #-# Final image
    if telescope == 'JWST':
        # Generating the final image that will get passed on to the outer scope, I(u) in eq. 13
        intensity = np.abs(ft_zern)**2 * (sum1.value + 2. * sum2.value)
    elif telescope == 'ATLAST':
        intensity = ft_zern.intensity.shaped * (sum1.value + 2. * sum2.value)

    # PASTIS is only valid inside the dark hole, so we cut out only that part
    if telescope == 'JWST':
        tot_dh_im_size = sampling * (outer_wa + 3)
        intensity_zoom = util.zoom_cen(
            intensity, tot_dh_im_size
        )  # zoom box is (owa + 3*lambda/D) wide, in terms of lambda/D
        dh_area_zoom = util.zoom_cen(dh_area, tot_dh_im_size)

        dh_psf = dh_area_zoom * intensity_zoom

    elif telescope == 'ATLAST':
        dh_psf = dh_sz * intensity
    """
    # Create plots.
    plt.subplot(1, 3, 1)
    plt.imshow(pupil, origin='lower')
    plt.title('JWST pupil and diameter definition')
    plt.plot([46.5, 464.5], [101.5, 409.5], 'r-')   # show how the diagonal of the pupil is defined

    plt.subplot(1, 3, 2)
    plt.imshow(mini_seg, origin='lower')
    plt.title('JWST individual mini-segment')

    plt.subplot(1, 3, 3)
    plt.imshow(dh_psf, origin='lower')
    plt.title('JWST dark hole')
    plt.show()
    """

    # dh_psf is the image of the dark hole only, the pixels outside of it are zero
    # intensity is the entire final image
    return dh_psf, intensity
Example #17
0
        wf = prop_through_lens(wf, -z1g, IOR1)
        wf.total_power = 1
        return wf

    return _inner_, _inner_backwards


if __name__ == "__main__":
    plt.style.use("dark_background")

    radius = 0.013 / 2  #5
    sep = 0.12  #10
    IOR = 1.48  #acrylic at 1 um
    res = 600  #600 seems to be the critical value
    pad = 1
    pupil_grid = hc.make_pupil_grid(res, 2 * radius)

    r1, r2 = make_remapping_gauss_annulus(res, 0.23, 0, 3)
    z1, z2 = make_PIAA_lenses(r1 * radius, r2 * radius, IOR, IOR,
                              sep)  ## fix radius dependence here!

    apodizer = fresnel_apodizer(pupil_grid, sep, pad, r1, r2, z1, z2, IOR, IOR)

    keck_pupil_hires = np.array(fits.open("pupil_KECK_high_res.fits")[0].data,
                                dtype=np.float32)
    ap_arr = resize2(keck_pupil_hires, (res, res)).flatten()
    ap = hc.Field(ap_arr, pupil_grid)

    plt.imshow(ap.real.reshape((600, 600)))
    plt.show()
    wf = PaddedWavefront(ap, wavelength=1.e-6, pad_factor=pad)
Example #18
0
segment_flat_to_flat = (pupil_diameter - (2 * num_rings + 1) * gap_size) / (2 * num_rings + 1)
focal_length = 1 # m

# Parameters for the simulation
num_pix = 512
wavelength = 638e-9
num_airy = 20
sampling = 4
norm = False


# In[3]:


# HCIPy grids and propagator
pupil_grid = hcipy.make_pupil_grid(dims=num_pix, diameter=pupil_diameter)

focal_grid = hcipy.make_focal_grid(sampling, num_airy,
                                   pupil_diameter=pupil_diameter,
                                   reference_wavelength=wavelength,
                                   focal_length=focal_length)
focal_grid = focal_grid.shifted(focal_grid.delta / 2)

prop = hcipy.FraunhoferPropagator(pupil_grid, focal_grid, focal_length)


# In[4]:


# Define function from rad of phase to m OPD
def aber_to_opd(aber_rad, wavelength):
Example #19
0
    def __init__(self,
                 diameter,
                 fnum,
                 wavelength,
                 num_DM_acts=30,
                 wavelength_0=None,
                 obstr_frac=0.242):

        if wavelength_0 is None:
            wavelength_0 = wavelength

        self.reference_wavelength = wavelength_0

        self.diameter = diameter
        self.fnum = fnum
        self.num_acts = num_DM_acts
        self.obstr_frac = obstr_frac
        self.wavelength = wavelength

        ## setting up low and high res pupil grids. the low res grid is used for to only calibrate/control the DM

        num_pupil_pixels = self.low_pupil_res
        pupil_pixel_samps = self.low_pupil_res * 0.95  #the keck pupil fits seems be padded with zeros around border by ~5%

        self.pupil_plane_res = (num_pupil_pixels, num_pupil_pixels)

        pupil_grid_diam = diameter * num_pupil_pixels / pupil_pixel_samps
        self.pupil_grid_diam = pupil_grid_diam
        self.pupil_sample_rate = pupil_grid_diam / num_pupil_pixels

        self.pupil_grid = hc.make_pupil_grid(self.low_pupil_res,
                                             diameter=pupil_grid_diam)
        self.pupil_grid_hires = hc.make_pupil_grid(self.hi_pupil_res,
                                                   diameter=pupil_grid_diam)

        ## now set up the actual pupil fields

        keck_pupil_hires = np.array(
            fits.open("pupil_KECK_high_res.fits")[0].data, dtype=np.float32)
        ap_arr = resize2(keck_pupil_hires,
                         (self.low_pupil_res, self.low_pupil_res))
        ap_arr_hires = resize2(keck_pupil_hires,
                               (self.hi_pupil_res, self.hi_pupil_res))

        self.ap = hc.Field(ap_arr.flatten(), self.pupil_grid)
        self.ap_hires = hc.Field(ap_arr_hires.flatten(), self.pupil_grid_hires)

        ## we need to make two DMs, one sampled on the low res pupil grid and another on the hi res pupil grid

        act_spacing = diameter / num_DM_acts
        influence_funcs = hc.make_gaussian_influence_functions(
            self.pupil_grid, num_DM_acts, act_spacing)

        self.DM = hc.DeformableMirror(influence_funcs)

        influence_funcs_hires = hc.make_gaussian_influence_functions(
            self.pupil_grid_hires, num_DM_acts, act_spacing)
        self.DM_hires = hc.DeformableMirror(influence_funcs_hires)

        ## make the rest of our optics (besides PIAA/collimator)

        self.pwfs = hc.PyramidWavefrontSensorOptics(self.pupil_grid,
                                                    wavelength_0=wavelength_0)

        self.detector = hc.NoiselessDetector()
        self.dt = 1  #integration time in seconds (?)

        ## focal grid set up. linear resolution in pixels is 2 * q * num_airy
        self.focal_grid = hc.make_focal_grid(q=16 * 2,
                                             num_airy=16,
                                             f_number=fnum,
                                             reference_wavelength=wavelength_0)

        self.ref_image = None
        self.rmat = None

        ## pupil -> focal and focal -> pupil propagators

        self.propagator = hc.FraunhoferPropagator(self.pupil_grid,
                                                  self.focal_grid,
                                                  focal_length=diameter * fnum)
        self.propagator_backward = hc.FraunhoferPropagator(
            self.focal_grid, self.pupil_grid, focal_length=-diameter * fnum)

        ## misc other stuff that is useful to cache/save
        self.t_arr = None
        self.DMshapes = None
        self.psgen = None
        self.apodize = None
        self.apodize_backwards = None
        self.collimate = None
        self.collimator_grid = None

        self.current_phase_screen = None
        self.wf_pupil, self.wf_pupil_hires, self.wf_focal = None, None, None

        self.PIAA_args, self.col_args = None, None
Example #20
0
def get_atlast_aperture(normalized=False,
                        with_segment_gaps=True,
                        segment_transmissions=1,
                        write_to_disk=False,
                        outDir=None):
    """Make the ATLAST/HiCAT pupil mask.

    This function is a copy of make_hicat_aperture(), except that it also returns the segment positions.

    Parameters
    ----------
    normalized : boolean
        If this is True, the outer diameter will be scaled to 1. Otherwise, the
        diameter of the pupil will be 15.0 meters.
    with_segment_gaps : boolean
        Include the gaps between individual segments in the aperture.
    segment_transmissions : scalar or array_like
        The transmission for each of the segments. If this is a scalar, this transmission will
        be used for all segments.

    Returns
    -------
    Field generator
        The ATLAST aperture.
    CartesianGrid
        The segment positions.
    """
    pupil_diameter = PUP_DIAMETER
    segment_circum_diameter = 2 / np.sqrt(3) * pupil_diameter / 7
    num_rings = 3
    segment_gap = CONFIG_PASTIS.getfloat(which_tel, 'gaps')

    if not with_segment_gaps:
        segment_gap = 0

    if normalized:
        segment_circum_diameter /= pupil_diameter
        segment_gap /= pupil_diameter
        pupil_diameter = 1.0

    segment_positions = hcipy.make_hexagonal_grid(
        segment_circum_diameter / 2 * np.sqrt(3), num_rings)
    segment_positions = segment_positions.subset(lambda grid: ~(
        hcipy.circular_aperture(segment_circum_diameter)(grid) > 0))

    hexagon = hcipy.hexagonal_aperture(segment_circum_diameter - segment_gap)

    def segment(grid):
        return hexagon(grid.rotated(np.pi / 2))

    segmented_aperture = hcipy.make_segmented_aperture(segment,
                                                       segment_positions,
                                                       segment_transmissions)

    def func(grid):
        res = segmented_aperture(grid)

        return hcipy.Field(res, grid)

    # Save pupil to disk, as pdf and fits
    if write_to_disk:
        pupil_grid = hcipy.make_pupil_grid(dims=pupil_size,
                                           diameter=pupil_diameter)
        atlast = hcipy.evaluate_supersampled(func, pupil_grid, 8)

        hcipy.imshow_field(atlast)
        for i in range(36):
            plt.annotate(str(i + 1),
                         size='x-large',
                         xy=(segment_positions.x[i] - pupil_diameter * 0.03,
                             segment_positions.y[i] - pupil_diameter * 0.02))
            # -0.03/-0.02 is for shifting the numbers closer to the segment centers. Scaling that by pupil_diameter
            # keeps them in place.
        plt.savefig(os.path.join(outDir, 'ATLAST_pupil.pdf'))

        util.write_fits(atlast.shaped, os.path.join(outDir, 'pupil.fits'))

    return func, segment_positions
Example #21
0
def gen_atmos(plot=False, debug=True):
    """
    generates atmospheric phase distortions using hcipy (updated from original using CAOS)

    read more on HCIpy here: https://hcipy.readthedocs.io/en/latest/index.html
    In hcipy, the atmosphere evolves as a function of time, specified by the user. User can thus specify the
    timescale of evolution through both velocity of layer and time per step in the obs_sequence, in loop for
    medis_main.gen_timeseries().

    :param plot: turn plotting on or off
    :return:

    todo add simple mp.Pool.map code to make maps in parrallel
    """
    if tp.use_atmos is False:
        pass  # only make new atmosphere map if using the atmosphere
    else:

        if sp.verbose: dprint("Making New Atmosphere Model")
        # Saving Parameters
        # np.savetxt(iop.atmosconfig, ['Grid Size', 'Wvl Range', 'Number of Frames', 'Layer Strength', 'Outer Scale', 'Velocity', 'Scale Height', cp.model])
        # np.savetxt(iop.atmosconfig, ['ap.grid_size', 'ap.wvl_range', 'ap.numframes', 'atmp.cn_sq', 'atmp.L0', 'atmp.vel', 'atmp.h', 'cp.model'])
        # np.savetxt(iop.atmosconfig, [ap.grid_size, ap.wvl_range, ap.numframes, atmp.cn_sq, atmp.L0, atmp.vel, atmp.h, cp.model], fmt='%s')

        wsamples = np.linspace(ap.wvl_range[0], ap.wvl_range[1], ap.n_wvl_init)
        wavefronts = []

        ##################################
        # Initiate HCIpy Atmosphere Type
        ##################################
        pupil_grid = hcipy.make_pupil_grid(sp.grid_size, tp.entrance_d)
        if atmp.model == 'single':
            layers = [
                hcipy.InfiniteAtmosphericLayer(pupil_grid, atmp.cn_sq, atmp.L0,
                                               atmp.vel, atmp.h, 2)
            ]
        elif atmp.model == 'hcipy_standard':
            # Make multi-layer atmosphere
            # layers = hcipy.make_standard_atmospheric_layers(pupil_grid, atmp.L0)
            heights = np.array([500, 1000, 2000, 4000, 8000, 16000])
            velocities = np.array([10, 10, 10, 10, 10, 10])
            Cn_squared = np.array(
                [0.2283, 0.0883, 0.0666, 0.1458, 0.3350, 0.1350]) * 3.5e-12

            layers = []
            for h, v, cn in zip(heights, velocities, Cn_squared):
                layers.append(
                    hcipy.InfiniteAtmosphericLayer(pupil_grid, cn, atmp.L0, v,
                                                   h, 2))

        elif atmp.model == 'evolving':
            raise NotImplementedError
        atmos = hcipy.MultiLayerAtmosphere(layers, scintilation=False)

        for wavelength in wsamples:
            wavefronts.append(
                hcipy.Wavefront(
                    hcipy.Field(np.ones(pupil_grid.size), pupil_grid),
                    wavelength))

        if atmp.correlated_sampling:
            # Damage Detection and Localization from Dense Network of Strain Sensors

            # fancy sampling goes here
            normal = corrsequence(sp.numframes,
                                  atmp.tau / sp.sample_time)[1] * atmp.std
            uniform = (special.erf(normal / np.sqrt(2)) + 1)

            times = np.cumsum(uniform) * sp.sample_time

            if debug:
                import matplotlib.pylab as plt
                plt.plot(normal)
                plt.figure()
                plt.plot(uniform)
                plt.figure()
                plt.hist(uniform)
                plt.figure()
                plt.plot(
                    np.arange(0, sp.numframes * sp.sample_time,
                              sp.sample_time))
                plt.plot(times)
                plt.show()
        else:
            times = np.arange(0, sp.numframes * sp.sample_time, sp.sample_time)

        ###########################################
        # Evolving Wavefront using HCIpy tools
        ###########################################
        for it, t in enumerate(times):
            atmos.evolve_until(t)
            for iw, wf in enumerate(wavefronts):
                wf2 = atmos.forward(wf)

                filename = get_filename(
                    it, wsamples[iw],
                    (iop.atmosdir, sp.sample_time, atmp.model))
                if sp.verbose: dprint(f"atmos file = {filename}")
                hdu = fits.ImageHDU(
                    wf2.phase.reshape(sp.grid_size, sp.grid_size))
                hdu.header['PIXSIZE'] = tp.entrance_d / sp.grid_size
                hdu.writeto(filename, overwrite=True)

                if plot and iw == 0:
                    import matplotlib.pyplot as plt
                    from medis.twilight_colormaps import sunlight
                    plt.figure()
                    plt.title(
                        f"Atmosphere Phase Map t={t} lambda={eformat(wsamples[iw], 3, 2)}"
                    )
                    hcipy.imshow_field(wf2.phase, cmap=sunlight)
                    plt.colorbar()
                    plt.show(block=True)
Example #22
0
def gen_atmos(plot=False):
    """
    generates atmospheric phase distortions using hcipy (updated from original using CAOS)

    read more on HCIpy here: https://hcipy.readthedocs.io/en/latest/index.html
    In hcipy, the atmosphere evolves as a function of time, specified by the user. User can thus specify the
    timescale of evolution through both velocity of layer and time per step in the obs_sequence, in loop for
    medis_main.gen_timeseries().

    :param plot: turn plotting on or off
    :return:
    """
    dprint("Making New Atmosphere Model")
    # Saving Parameters
    # np.savetxt(iop.atmosconfig, ['Grid Size', 'Wvl Range', 'Number of Frames', 'Layer Strength', 'Outer Scale', 'Velocity', 'Scale Height', cp.model])
    # np.savetxt(iop.atmosconfig, ['ap.grid_size', 'ap.wvl_range', 'ap.numframes', 'atmp.cn_sq', 'atmp.L0', 'atmp.vel', 'atmp.h', 'cp.model'])
    # np.savetxt(iop.atmosconfig, [ap.grid_size, ap.wvl_range, ap.numframes, atmp.cn_sq, atmp.L0, atmp.vel, atmp.h, cp.model], fmt='%s')

    wsamples = np.linspace(ap.wvl_range[0], ap.wvl_range[1], ap.n_wvl_init)
    wavefronts = []

    ##################################
    # Initiate HCIpy Atmosphere Type
    ##################################
    pupil_grid = hcipy.make_pupil_grid(sp.grid_size, tp.entrance_d)
    if atmp.model == 'single':
        layers = [
            hcipy.InfiniteAtmosphericLayer(pupil_grid, atmp.cn_sq, atmp.L0,
                                           atmp.vel, atmp.h, 2)
        ]
    elif atmp.model == 'hcipy_standard':
        # Make multi-layer atmosphere
        layers = hcipy.make_standard_atmospheric_layers(
            pupil_grid, atmp.outer_scale)
    elif atmp.model == 'evolving':
        raise NotImplementedError
    atmos = hcipy.MultiLayerAtmosphere(layers, scintilation=False)

    for wavelength in wsamples:
        wavefronts.append(
            hcipy.Wavefront(hcipy.Field(np.ones(pupil_grid.size), pupil_grid),
                            wavelength))

    ###########################################
    # Evolving Wavefront using HCIpy tools
    ###########################################
    for it, t in enumerate(
            np.arange(0, sp.numframes * sp.sample_time, sp.sample_time)):
        atmos.evolve_until(t)
        for iw, wf in enumerate(wavefronts):
            wf2 = atmos.forward(wf)

            filename = get_filename(it, wsamples[iw])
            dprint(f"atmos file = {filename}")
            hdu = fits.ImageHDU(wf2.phase.reshape(sp.grid_size, sp.grid_size))
            hdu.header['PIXSIZE'] = tp.entrance_d / sp.grid_size
            hdu.writeto(filename, overwrite=True)

            if plot and iw == 0:
                import matplotlib.pyplot as plt
                from medis.twilight_colormaps import sunlight
                plt.figure()
                plt.title(
                    f"Atmosphere Phase Map t={t} lambda={eformat(wsamples[iw], 3, 2)}"
                )
                hcipy.imshow_field(wf2.phase, cmap=sunlight)
                plt.colorbar()
                plt.show(block=True)
print("generating: " + str(numb) + " psfs with:\n  fried parameter: " +
      str(fried_parameter) + "\n  sample time: " + str(time_between))

D_tel = 8.2  # meter
wavelength = 1e-6  # meter
oversampling = 8

# loading the files required for generating the vAPP.
amplitude_temp = read_fits(amplitude_file)
phase_temp = read_fits(phase_file)

# number of pixels along one axis in the pupil
Npix = amplitude_temp.shape[0]

# generating the grids
pupil_grid = make_pupil_grid(Npix, D_tel)
focal_grid = make_focal_grid(pupil_grid, 4, 25, wavelength=wavelength)

#kolmogorov: verdeling voor sterkte special freq
spectral_noise_factory = SpectralNoiseFactoryFFT(kolmogorov_psd, pupil_grid,
                                                 oversampling)
turbulence_layers = make_standard_multilayer_atmosphere(
    fried_parameter=fried_parameter, wavelength=wavelength)
# create phase screen
atmospheric_model = AtmosphericModel(spectral_noise_factory, turbulence_layers)

# Mapping from pupil plane to focal plane
prop = FraunhoferPropagator(pupil_grid, focal_grid)

# converting the amplitude and phase to fields
amplitude = Field(amplitude_temp.ravel(), pupil_grid)