Exemple #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)
Exemple #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)
Exemple #3
0
def full_modes_from_file(datadir):
    """
    Read all modes into an array of hcipy.Fields and an array of 2D arrays.
    :param datadir: string, path to overall data directory containing matrix and results folder
    :return: all_modes as array of Fields, mode_cube as array of 2D arrays (hcipy vs matplotlib)
    """

    mode_cube = hc.read_fits(
        os.path.join(datadir, 'results', 'modes', 'fits', 'cube_modes.fits'))
    all_modes = hc.Field(mode_cube.ravel())

    return all_modes, mode_cube
Exemple #4
0
    def apply_coef(self):
        """ Apply the DM shape from its own segment coefficients to make segmented mirror surface.
        """
        self._setup_grids()

        keep_surf = np.zeros_like(self._seg_x)
        for i in self.segmentlist:
            wseg = self._seg_indices[i]
            keep_surf[wseg] = (self._coef[i - 1, 0] +
                               self._coef[i - 1, 1] * self._seg_x[wseg] +
                               self._coef[i - 1, 2] * self._seg_y[wseg])
        return hcipy.Field(keep_surf, self.input_grid)
def make_FPM(focal_grid, N=focal_number):
    
    array = np.array([[0.0]*N]*N)
    
    for i in range(0,N):
        for j in range (0, N):
            x = abs(int(N/2) - i)
            y = abs(int(N/2) - j)
            r = np.sqrt(x**2 + y**2)
            if r < 3.5*N/16 and r > 2*N/16:
                array[i][j] = 1.0
    
    array_flat = array.flatten()
    return hcipy.Field(array_flat, focal_grid)
Exemple #6
0
def read_atm(fname, grid, aper, Hz=Hz):
    atm_frames = np.load(fname)
    #The resultant numpy array is 2D where axis=0 is the time step and axis=1 is the
    # spatial info of the phase that got flattened by HCIPy. If you want to avoid using
    # the hci.Field and pupil stuff, you get the correct shaping by calling
    # np.reshape(atm_frames[tstep], (100,100)) #(num_pupil_pixels,num_pup_pix)

    phase_frames = []
    #wf_frames = []
    times = np.arange(1, atm_frames.shape[0] + 1) / Hz
    for ind in range(atm_frames.shape[0]):
        phase = hci.Field(atm_frames[ind], grid)
        phase_frames.append(phase)
        #wf_frames.append(make_wf(phase, aper))

    return times, phase_frames  #,wf_frames
Exemple #7
0
def coupling_vs_r_pupilplane_single(tele: AOtele.AOtele, pupilfields, rcore,
                                    ncore, nclad, wl0):
    k0 = 2 * np.pi / wl0

    fieldshape = pupilfields[0].shape

    #need to generate the available modes
    V = LPmodes.get_V(k0, rcore, ncore, nclad)
    modes = LPmodes.get_modes(V)
    lpfields = []

    for mode in modes:
        if mode[0] == 0:
            lpfields.append(
                normalize(
                    LPmodes.lpfield(xg, yg, mode[0], mode[1], rcore, wl0,
                                    ncore, nclad)))

        else:
            lpfields.append(
                normalize(
                    LPmodes.lpfield(xg, yg, mode[0], mode[1], rcore, wl0,
                                    ncore, nclad, "cos")))
            lpfields.append(
                normalize(
                    LPmodes.lpfield(xg, yg, mode[0], mode[1], rcore, wl0,
                                    ncore, nclad, "sin")))

    lppupilfields = []

    #then backpropagate
    for field in lpfields:
        wf = hc.Wavefront(hc.Field(field.flatten(), tele.focalgrid),
                          wavelength=wl0 * 1.e-6)
        pupil_wf = tele.back_propagate(wf, True)
        lppupilfields.append(pupil_wf.electric_field.reshape(fieldshape))

    lppupilfields = np.array(lppupilfields)
    pupilfields = np.array(pupilfields)

    #compute total overlap
    powers = np.sum(pupilfields * lppupilfields, axes=(1, 2))

    return np.mean(powers), np.stddev(powers)
Exemple #8
0
        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
Exemple #9
0
def field_from_array(arr, *axes):
    grid = hcipy_grid_from_axes(*axes)
    return hcipy.Field(arr.ravel(), grid)
Exemple #10
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
Exemple #11
0
    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))
    seg_pos = hc.CartesianGrid(poslist)
Exemple #12
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)
Exemple #13
0
    def func(grid):
        res = segmented_aperture(grid)

        return hcipy.Field(res, grid)
Exemple #14
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)
Exemple #15
0
    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)
    wf.total_power = 1 * pad * pad

    wf = apodizer(wf)

    #hc.imshow_field(wf.electric_field)
    #plt.show()

    p = wf.power.reshape(pad * res, pad * res)
    fig, ax = plt.subplots(figsize=(4, 4))
    ax.axis("off")
    plt.xlim(-radius, radius)
Exemple #16
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)