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")
Exemple #3
0
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]]
    radials = [1, 2, 3]
    in_seg_len = 10 / 7  #meters from one flat edge of a mirror segment to the other
    ang_types = np.arange(30, 360, 60) + 120
    for rad in radials:
        cur_x = rad * in_seg_len * np.cos(30 * np.pi / 180)
        cur_y = rad * in_seg_len * np.sin(30 * np.pi / 180)
        for ang in ang_types:
            for iii in range(rad):
                cur_x += in_seg_len * np.cos(ang * np.pi / 180)
                cur_y += in_seg_len * np.sin(ang * np.pi / 180)

                centroid_pos.append([cur_x, cur_y])

    #Now put mirrors on each of those points
    out_seg_len = 20 * np.sqrt(
        3) / 21  #size of the circle enclosing the hexagons
    oversamp = 10

    keck_aperture = -5 * hci.evaluate_supersampled(hci.circular_aperture(2.4),
                                                   grid, oversamp)
    for cent in centroid_pos:
        aper = hci.hexagonal_aperture(out_seg_len,
                                      angle=np.pi / 6,
                                      center=cent)
        heck_aperture += hci.evaluate_supersampled(aper, grid, oversamp)
    keck_aperture[keck_aperture < 0] = 0
    keck_aperture[keck_aperture > 1] = 1

    #hci.imshow_field(keck_aperture)
    #plt.xlabel('x position(m)')
    #plt.ylabel('y position(m)')
    #plt.colorbar()
    #plt.show()
    return keck_aperture
def contrast_luvoir_num(apodizer_choice,
                        matrix_dir,
                        matrix_mode='luvoir',
                        rms=1 * u.nm):
    """
    Compute the contrast for a random SM mislignment on the LUVOIR simulator.
    :param matrix_dir: str, directory of saved matrix
    :param matrix_mode: str, analytical or numerical; currently only numerical supported
    :param rms: astropy quantity, rms wfe to be put randomly on the SM
    :return: 2x float, E2E and matrix contrast
    """

    # Keep track of time
    start_time = time.time()  # runtime currently is around ? min

    # Parameters
    nb_seg = CONFIG_INI.getint('LUVOIR', 'nb_subapertures')
    sampling = 4

    # Import numerical PASTIS matrix for HiCAT sim
    filename = 'PASTISmatrix_num_piston_Noll1'
    matrix_pastis = fits.getdata(os.path.join(matrix_dir, filename + '.fits'))

    # Create random aberration coefficients
    aber = np.random.random([nb_seg])  # piston values in input units
    print('PISTON ABERRATIONS:', aber)

    # Normalize to the RMS value I want
    rms_init = util.rms(aber)
    aber *= rms.value / rms_init
    calc_rms = util.rms(aber) * u.nm
    aber *= u.nm  # making sure the aberration has the correct units
    print("Calculated RMS:", calc_rms)

    # Remove global piston
    aber -= np.mean(aber)

    # Coronagraph parameters
    # The LUVOIR STDT delivery in May 2018 included three different apodizers
    # we can work with, so I will implement an easy way of making a choice between them.
    design = apodizer_choice
    optics_input = '/Users/ilaginja/Documents/LabWork/ultra/LUVOIR_delivery_May2019/'

    # Instantiate LUVOIR telescope with APLC
    luvoir = LuvoirAPLC(optics_input, design, sampling)

    ### BASELINE PSF - NO ABERRATIONS, NO CORONAGRAPH
    # and coro PSF without aberrations
    start_e2e = time.time()
    print('Generating baseline PSF from E2E - no coronagraph, no aberrations')
    print('Also generating coro PSF without aberrations')
    psf_perfect, ref = luvoir.calc_psf(ref=True)
    normp = np.max(ref)
    psf_coro = psf_perfect / normp

    print('Calculating E2E contrast...')
    # Put aberrations on segmented mirror
    for nseg in range(nb_seg):
        luvoir.set_segment(nseg + 1, aber[nseg].to(u.m).value / 2, 0, 0)

    psf_luvoir = luvoir.calc_psf()
    psf_luvoir /= normp

    # Create DH
    dh_outer = hc.circular_aperture(2 * luvoir.apod_dict[design]['owa'] *
                                    luvoir.lam_over_d)(luvoir.focal_det)
    dh_inner = hc.circular_aperture(2 * luvoir.apod_dict[design]['iwa'] *
                                    luvoir.lam_over_d)(luvoir.focal_det)
    dh_mask = (dh_outer - dh_inner).astype('bool')

    # Get the mean contrast
    dh_intensity = psf_luvoir * dh_mask
    contrast_luvoir = np.mean(dh_intensity[np.where(dh_intensity != 0)])
    end_e2e = time.time()

    ###
    # Calculate baseline contrast
    baseline_dh = psf_coro * dh_mask
    contrast_base = np.mean(baseline_dh[np.where(baseline_dh != 0)])
    print('Baseline contrast: {}'.format(contrast_base))

    ## MATRIX PASTIS
    print('Generating contrast from matrix-PASTIS')
    start_matrixpastis = time.time()
    # Get mean contrast from matrix PASTIS
    contrast_matrix = util.pastis_contrast(
        aber, matrix_pastis
    ) + contrast_base  # calculating contrast with PASTIS matrix model
    end_matrixpastis = time.time()

    ## Outputs
    print('\n--- CONTRASTS: ---')
    print('Mean contrast from E2E:', contrast_luvoir)
    print('Contrast from matrix PASTIS:', contrast_matrix)

    print('\n--- RUNTIMES: ---')
    print('E2E: ', end_e2e - start_e2e, 'sec =', (end_e2e - start_e2e) / 60,
          'min')
    print('Matrix PASTIS: ', end_matrixpastis - start_matrixpastis, 'sec =',
          (end_matrixpastis - start_matrixpastis) / 60, 'min')

    end_time = time.time()
    runtime = end_time - start_time
    print('Runtime for contrast_calculation_simple.py: {} sec = {} min'.format(
        runtime, runtime / 60))

    return contrast_luvoir, contrast_matrix
def num_matrix_luvoir(design):
    """
    Generate a numerical PASTIS matrix for a LUVOIR A coronagraph.

    All inputs are read from the (local) configfile and saved to the specified output directory.
    The LUVOIR STDT delivery in May 2018 included three different apodizers
    we can work with, so I will implement an easy way of making a choice between them.
    small, medium and large
    """

    # Keep track of time
    start_time = time.time()  # runtime is currently around 150 minutes
    print('Building numerical matrix for LUVOIR\n')

    ### Parameters

    # System parameters
    resDir = os.path.join(CONFIG_INI.get('local', 'local_data_path'), 'active',
                          'matrix_numerical')
    zern_number = CONFIG_INI.getint('calibration', 'zernike')
    zern_mode = util.ZernikeMode(
        zern_number)  # Create Zernike mode object for easier handling

    # General telescope parameters
    nb_seg = CONFIG_INI.getint('LUVOIR', 'nb_subapertures')
    wvln = CONFIG_INI.getfloat('LUVOIR', 'lambda') * 1e-9  # m
    diam = CONFIG_INI.getfloat('LUVOIR', 'diameter')  # m
    nm_aber = CONFIG_INI.getfloat('calibration',
                                  'single_aberration') * 1e-9  # m

    # Image system parameters
    im_lamD = 30  # image size in lambda/D
    sampling = 4

    # Print some of the defined parameters
    print('LUVOIR apodizer design: {}'.format(design))
    print()
    print('Wavelength: {} m'.format(wvln))
    print('Telescope diameter: {} m'.format(diam))
    print('Number of segments: {}'.format(nb_seg))
    print()
    print('Image size: {} lambda/D'.format(im_lamD))
    print('Sampling: {} px per lambda/D'.format(sampling))

    ### Setting up the paths

    # If subfolder "matrix_numerical" doesn't exist yet, create it.
    if not os.path.isdir(resDir):
        os.mkdir(resDir)

    # If subfolder "OTE_images" doesn't exist yet, create it.
    if not os.path.isdir(os.path.join(resDir, 'OTE_images')):
        os.mkdir(os.path.join(resDir, 'OTE_images'))

    # If subfolder "psfs" doesn't exist yet, create it.
    if not os.path.isdir(os.path.join(resDir, 'psfs')):
        os.mkdir(os.path.join(resDir, 'psfs'))

    ### Instantiate Luvoir telescope with chosen apodizer design
    optics_input = '/Users/ilaginja/Documents/LabWork/ultra/LUVOIR_delivery_May2019/'
    luvoir = LuvoirAPLC(optics_input, design, sampling)

    ### Dark hole mask
    dh_outer = hc.circular_aperture(2 * luvoir.apod_dict[design]['owa'] *
                                    luvoir.lam_over_d)(luvoir.focal_det)
    dh_inner = hc.circular_aperture(2 * luvoir.apod_dict[design]['iwa'] *
                                    luvoir.lam_over_d)(luvoir.focal_det)
    dh_mask = (dh_outer - dh_inner).astype('bool')

    ### Reference images for contrast normalization and coronagraph floor
    unaberrated_coro_psf, ref = luvoir.calc_psf(ref=True,
                                                display_intermediate=False,
                                                return_intermediate=False)
    norm = np.max(ref)

    dh_intensity = unaberrated_coro_psf / norm * dh_mask
    contrast_floor = np.mean(dh_intensity[np.where(dh_intensity != 0)])
    print(contrast_floor)

    ### Generating the PASTIS matrix and a list for all contrasts
    matrix_direct = np.zeros([nb_seg, nb_seg])  # Generate empty matrix
    all_psfs = []
    all_contrasts = []

    print('nm_aber: {} m'.format(nm_aber))

    for i in range(nb_seg):
        for j in range(nb_seg):

            print('\nSTEP: {}-{} / {}-{}'.format(i + 1, j + 1, nb_seg, nb_seg))

            # Put aberration on correct segments. If i=j, apply only once!
            luvoir.flatten()
            luvoir.set_segment(i + 1, nm_aber / 2, 0, 0)
            if i != j:
                luvoir.set_segment(j + 1, nm_aber / 2, 0, 0)

            print('Calculating coro image...')
            image, inter = luvoir.calc_psf(ref=False,
                                           display_intermediate=False,
                                           return_intermediate='intensity')
            # Normalize PSF by reference image
            psf = image / norm

            # Save image to disk
            filename_psf = 'psf_' + zern_mode.name + '_' + zern_mode.convention + str(
                zern_mode.index) + '_segs_' + str(i + 1) + '-' + str(j + 1)
            hc.write_fits(psf,
                          os.path.join(resDir, 'psfs', filename_psf + '.fits'))
            all_psfs.append(psf)

            # Save OPD images for testing (are these actually surface images, not OPD?)
            opd_name = 'opd_' + zern_mode.name + '_' + zern_mode.convention + str(
                zern_mode.index) + '_segs_' + str(i + 1) + '-' + str(j + 1)
            plt.clf()
            hc.imshow_field(inter['seg_mirror'],
                            mask=luvoir.aperture,
                            cmap='RdBu')
            plt.savefig(os.path.join(resDir, 'OTE_images', opd_name + '.pdf'))

            print('Calculating mean contrast in dark hole')
            dh_intensity = psf * dh_mask
            contrast = np.mean(dh_intensity[np.where(dh_intensity != 0)])
            print('contrast:', contrast)
            all_contrasts.append(contrast)

            # Fill according entry in the matrix and subtract baseline contrast
            matrix_direct[i, j] = contrast - contrast_floor

    # Transform saved lists to arrays
    all_psfs = np.array(all_psfs)
    all_contrasts = np.array(all_contrasts)

    # Filling the off-axis elements
    matrix_two_N = np.copy(
        matrix_direct
    )  # This is just an intermediary copy so that I don't mix things up.
    matrix_pastis = np.copy(
        matrix_direct)  # This will be the final PASTIS matrix.

    for i in range(nb_seg):
        for j in range(nb_seg):
            if i != j:
                matrix_off_val = (matrix_two_N[i, j] - matrix_two_N[i, i] -
                                  matrix_two_N[j, j]) / 2.
                matrix_pastis[i, j] = matrix_off_val
                print('Off-axis for i{}-j{}: {}'.format(
                    i + 1, j + 1, matrix_off_val))

    # Normalize matrix for the input aberration - the whole code is set up to be normalized to 1 nm, and even if
    # the units entered are in m for the sake of HCIPy, everything else is assuming the baseline is 1nm, so the
    # normalization can be taken out if we're working with exactly 1 nm for the aberration, even if entered in meters.
    #matrix_pastis /= np.square(nm_aber)

    # Save matrix to file
    filename_matrix = 'PASTISmatrix_num_' + zern_mode.name + '_' + zern_mode.convention + str(
        zern_mode.index)
    hc.write_fits(matrix_pastis, os.path.join(resDir,
                                              filename_matrix + '.fits'))
    print('Matrix saved to:', os.path.join(resDir, filename_matrix + '.fits'))

    # Save the PSF image *cube* as well (as opposed to each one individually)
    hc.write_fits(
        all_psfs,
        os.path.join(resDir, 'psfs', 'psf_cube' + '.fits'),
    )
    np.savetxt(os.path.join(resDir, 'contrasts.txt'), all_contrasts, fmt='%e')

    # Tell us how long it took to finish.
    end_time = time.time()
    print('Runtime for matrix_building.py:', end_time - start_time, 'sec =',
          (end_time - start_time) / 60, 'min')
    print('Data saved to {}'.format(resDir))
Exemple #6
0
    # Instantiate SM
    sm = SegmentedMirror(aper_ind, seg_pos)

    # Instantiate LUVOIR
    optics_input = '/Users/ilaginja/Documents/LabWork/ultra/LUVOIR_delivery_May2019/'
    luvoir = LuvoirAPLC(optics_input, apodizer_design, sampling)

    # Generate reference PSF and coronagraph baseline
    luvoir.flatten()
    psf_unaber, ref = luvoir.calc_psf(ref=True, display_intermediate=False)
    norm = ref.max()
    #plt.show()
    # Make dark hole mask
    dh_outer = hc.circular_aperture(
        2 * luvoir.apod_dict[apodizer_design]['owa'] * luvoir.lam_over_d)(
            luvoir.focal_det)
    dh_inner = hc.circular_aperture(
        2 * luvoir.apod_dict[apodizer_design]['iwa'] * luvoir.lam_over_d)(
            luvoir.focal_det)
    dh_mask = (dh_outer - dh_inner).astype('bool')

    # plt.figure()
    # plt.subplot(1, 3, 1)
    # hc.imshow_field(dh_mask)
    # plt.subplot(1, 3, 2)
    # hc.imshow_field(psf_unaber, norm=LogNorm(), mask=dh_mask)
    # plt.subplot(1, 3, 3)
    # hc.imshow_field(psf_unaber, norm=LogNorm())
    # plt.show()
Exemple #7
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
Exemple #8
0
    def calc_psf(self,
                 ref=False,
                 display_intermediate=False,
                 return_intermediate=None):
        """Calculate the PSF of the segmented telescope, normalized to contrast units.

        Parameters:
        ----------
        ref : bool
            Keyword for additionally returning the refrence PSF without the FPM.
        display_intermediate : bool
            Keyword for display of all planes.
        return_intermediate : string
            Either 'intensity', return the intensity in all planes; except phase on the SM (first plane)
            or 'efield', return the E-fields in all planes. Default none.
        Returns:
        --------
        wf_im_coro.intensity : Field
            Coronagraphic image, normalized to contrast units by max of reference image (even when ref
            not returned).
        wf_im_ref.intensity : Field, optional
            Reference image without FPM.
        intermediates : dict of Fields, optional
            Intermediate plane intensity images; except for full wavefront on segmented mirror.
        wf_im_coro : Wavefront
            Wavefront in last focal plane.
        wf_im_ref : Wavefront, optional
            Wavefront of reference image without FPM.
        intermediates : dict of Wavefronts, optional
            Intermediate plane E-fields; except intensity in focal plane after FPM.
        """

        # Create fake FPM for plotting
        fpm_plot = 1 - hc.circular_aperture(2 * self.fpm_rad * self.lamDrad)(
            self.focal_det)

        # Create apodozer as hc.Apodizer() object to be able to propagate through it
        apod_prop = hc.Apodizer(self.apodizer)

        # Calculate all wavefronts of the full propagation
        wf_sm = self.sm(self.wf_aper)
        wf_apod = apod_prop(wf_sm)
        wf_lyot = self.coro(wf_apod)
        wf_im_coro = self.prop(wf_lyot)

        # Wavefronts in extra planes
        wf_before_fpm = self.prop(wf_apod)
        int_after_fpm = np.log10(
            wf_before_fpm.intensity / wf_before_fpm.intensity.max()
        ) * fpm_plot  # this is the intensity straight
        wf_before_lyot = self.coro_no_ls(wf_apod)

        # Wavefronts of the reference propagation
        wf_ref_pup = hc.Wavefront(self.apodizer * self.lyotstop,
                                  wavelength=self.wvln)
        wf_im_ref = self.prop(wf_ref_pup)

        # Display intermediate planes
        if display_intermediate:

            plt.figure(figsize=(15, 15))

            plt.subplot(331)
            hc.imshow_field(wf_sm.phase, mask=self.aper, cmap='RdBu')
            plt.title('Seg aperture phase')

            plt.subplot(332)
            hc.imshow_field(wf_apod.intensity, cmap='inferno')
            plt.title('Apodizer')

            plt.subplot(333)
            hc.imshow_field(wf_before_fpm.intensity /
                            wf_before_fpm.intensity.max(),
                            norm=LogNorm(),
                            cmap='inferno')
            plt.title('Before FPM')

            plt.subplot(334)
            hc.imshow_field(int_after_fpm / wf_before_fpm.intensity.max(),
                            cmap='inferno')
            plt.title('After FPM')

            plt.subplot(335)
            hc.imshow_field(wf_before_lyot.intensity /
                            wf_before_lyot.intensity.max(),
                            norm=LogNorm(vmin=1e-3, vmax=1),
                            cmap='inferno')
            plt.title('Before Lyot stop')

            plt.subplot(336)
            hc.imshow_field(wf_lyot.intensity / wf_lyot.intensity.max(),
                            norm=LogNorm(vmin=1e-3, vmax=1),
                            cmap='inferno',
                            mask=self.lyotstop)
            plt.title('After Lyot stop')

            plt.subplot(337)
            hc.imshow_field(wf_im_coro.intensity / wf_im_ref.intensity.max(),
                            norm=LogNorm(vmin=1e-10, vmax=1e-3),
                            cmap='inferno')
            plt.title('Final image')
            plt.colorbar()

        if return_intermediate == 'intensity':

            # Return the intensity in all planes; except phase on the SM (first plane)
            intermediates = {
                'seg_mirror':
                wf_sm.phase,
                'apod':
                wf_apod.intensity,
                'before_fpm':
                wf_before_fpm.intensity / wf_before_fpm.intensity.max(),
                'after_fpm':
                int_after_fpm / wf_before_fpm.intensity.max(),
                'before_lyot':
                wf_before_lyot.intensity / wf_before_lyot.intensity.max(),
                'after_lyot':
                wf_lyot.intensity / wf_lyot.intensity.max()
            }

            if ref:
                return wf_im_coro.intensity, wf_im_ref.intensity, intermediates
            else:
                return wf_im_coro.intensity, intermediates

        if return_intermediate == 'efield':

            # Return the E-fields in all planes; except intensity in focal plane after FPM
            intermediates = {
                'seg_mirror': wf_sm,
                'apod': wf_apod,
                'before_fpm': wf_before_fpm,
                'after_fpm': int_after_fpm,
                'before_lyot': wf_before_lyot,
                'after_lyot': wf_lyot
            }

            if ref:
                return wf_im_coro, wf_im_ref, intermediates
            else:
                return wf_im_coro, intermediates

        if ref:
            return wf_im_coro.intensity, wf_im_ref.intensity

        return wf_im_coro.intensity
Exemple #9
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)