Exemplo n.º 1
0
def score_matrix3(aberrations, show=False):
    
    # Make segmented mirror
    aper, segments = hcipy.make_hexagonal_segmented_aperture(num_rings,
                                                         segment_flat_to_flat,
                                                         gap_size,
                                                         starting_ring=1,
                                                         return_segments=True)

    aper = hcipy.evaluate_supersampled(aper, pupil_grid, 1)
    segments = hcipy.evaluate_supersampled(segments, pupil_grid, 1)
    
    # Instantiate the segmented mirror
    hsm = hcipy.SegmentedDeformableMirror(segments)

    # Make a pupil plane wavefront from aperture
    wf = hcipy.Wavefront(aper, wavelength)
    
    hsm.flatten()
    
    # Get poke segments
    for i in range(0,len(aberrations)):
        if float(aberrations[i]) != 0:
            hsm.set_segment_actuators(i, aber_to_opd(aber_rad, wavelength) / (1/float(aberrations[i])), 0, 0)
    
    if show:
        plt.figure(figsize=(8,8))
        plt.title('OPD for HCIPy SM')
        hcipy.imshow_field(hsm.surface * 2, mask=aper, cmap='RdBu_r', vmin=-5e-7, vmax=5e-7)
        plt.colorbar()
        plt.show()
    
    ### PROPAGATE AND SCORE ###
    wf_fp_pistoned = hsm(wf)

    # Propagate from SM to image plane
    im_pistoned_hc = prop(wf_fp_pistoned)
    norm_hc = np.max(im_pistoned_hc.intensity)
    
    if show:
        # Display intensity in image plane

        hcipy.imshow_field(np.log10(im_pistoned_hc.intensity / norm_hc), cmap='inferno', vmin=-9)
        plt.title('Image plane after SM')
        plt.colorbar()
        plt.show()
        
        hcipy.imshow_field(np.log10((im_pistoned_hc.intensity / norm_hc)*(annulus)), cmap='inferno', vmin=-9)
        plt.title('Annular image plane region')
        plt.colorbar()
        plt.show()
        
    interested_field = (im_pistoned_hc.intensity / norm_hc)*(1-annulus)
    score = float(hcipy.Field.sum(interested_field)/hcipy.Field.sum(im_pistoned_hc.intensity / norm_hc))*100
    
    return score
Exemplo n.º 2
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
Exemplo n.º 3
0
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")
Exemplo n.º 4
0
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")
Exemplo n.º 5
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
Exemplo n.º 6
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()
Exemplo n.º 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
Exemplo n.º 8
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