Beispiel #1
0
def add_errors(wf,
               onaxis=True,
               phase_screen=None,
               amp_screen=None,
               tiptilt=None,
               misalign=[0, 0, 0, 0, 0, 0],
               ngrid=1024,
               verbose=False,
               **conf):

    # apply phase screen (scao residuals, ncpa, petal piston)
    if phase_screen is not None:
        assert phase_screen.ndim == 2, "phase_screen dim must be 2."
        proper.prop_add_phase(wf, pad_img(phase_screen, ngrid))

    # apply amplitude screen (Talbot effect)
    if amp_screen is not None:
        assert amp_screen.ndim == 2, "amp_screen dim must be 2."
        proper.prop_multiply(wf, pad_img(amp_screen, ngrid))

    # apply tip-tilt (Zernike 2,3)
    if tiptilt is not None:
        proper.prop_zernikes(wf, [2, 3], np.array(tiptilt, ndmin=1))

    # pupil-plane apodization (already preloaded if no RA misalign)
    if onaxis == False or ('RAVC' in conf['mode'] and misalign is not None):
        conf.update(ravc_misalign=misalign)
        wf = apodizer(wf, onaxis=onaxis, verbose=verbose, **conf)

    return wf
Beispiel #2
0
def wavefront_abberations(wfo,
                          npupil,
                          atm_screen,
                          NCPA,
                          Island_Piston,
                          TILT=[0, 0],
                          Debug='False',
                          Debug_print='False',
                          prefix='test'):

    lamda = proper.prop_get_wavelength(wfo)

    if (isinstance(atm_screen, (list, tuple, np.ndarray)) == True) and (
            atm_screen.ndim >= 2):  # when the atmosphere is present
        atmosphere(wfo, npupil, atm_screen, Debug_print, Debug)

    if (isinstance(NCPA, (list, tuple, np.ndarray))
            == True) and (NCPA.ndim >= 2):  # when the atmosphere is present
        NCPA_application(wfo, npupil, NCPA, Debug_print, Debug)

    if (all(v == 0
            for v in Island_Piston) == False):  # when the piston is present
        island_effect_piston(wfo, npupil, Island_Piston, Debug_print, Debug)

    if (TILT.any != 0.):  # when tip/tilt
        if (Debug_print == True):
            print("TILT: ", TILT)
            print("lamda: ", lamda)
        tiptilt = (np.multiply(
            TILT, lamda
        )) / 4  # translate the tip/tilt from lambda/D into RMS phase errors
        proper.prop_zernikes(wfo, [2, 3], tiptilt)  # 2-->xtilt, 3-->ytilt

    return wfo
Beispiel #3
0
def add_zern_ab(wf,
                zern_order=[2, 3, 4],
                zern_vals=np.array([175, -150, 200]) * 1.0e-9):
    """
    adds low-order aberrations from Zernike polynomials

    see Proper Manual pg 192 for full details
    see good example in Proper manual pg 51
    quote: These [polynomials] form an orthogonal set of aberrations that include:
     wavefront tilt, defocus, coma, astigmatism, spherical aberration, and others

    Orders are:
    1 Piston
    2 X tilt
    3 Y tilt
    4 Focus
    5 45º astigmatism
    6 0º astigmatism
    7 Y coma
    8 X coma
    9 Y clover (trefoil)
    10 X clover (trefoil)
    """
    if not tp.add_zern:
        pass
    else:
        proper.prop_zernikes(wf, zern_order, zern_vals)
Beispiel #4
0
def offset_companion(wf, id, atmos_map):
    # [x,y] = tp.grid_size/2 - np.array(ap.comp_loc)
    # disp = np.zeros((2))
    # for id, dim in enumerate([x,y]):
    #     angle = dim*tp.platescale/(1000.*3600.)
    #     print dim, angle,
    #     radius = proper.prop_get_beamradius(wf)
    #     print radius,
    #     disp[id] = np.tan(angle)*2*radius
    #     print disp[id]
    # proper.prop_zernikes(wf, [2, 3], disp)
    xloc = ap.lods[id][0]
    yloc = ap.lods[id][1]

    if tp.rot_rate:
        time = float(atmos_map[-19:-11])
        rotate_angle = tp.rot_rate * time
        rotate_angle = np.pi * rotate_angle / 180.
        rot_matrix = [[np.cos(rotate_angle), -np.sin(rotate_angle)],
                      [np.sin(rotate_angle),
                       np.cos(rotate_angle)]]
        # print rotate_angle, 'rotate', xloc, yloc
        xloc, yloc = np.matmul(rot_matrix, [xloc, yloc])

    proper.prop_zernikes(wf, [2, 3], np.array([xloc, yloc]) * 1e-6)
    wf.wfarr = wf.wfarr * np.sqrt(ap.contrast[id])
Beispiel #5
0
def add_zern_ab(wfo, f_lens):
    proper.prop_zernikes(wfo, [4, 11], np.array([500, 500]) * 1.0e-6)
    # [2,3], [0.5,0.5]*1.0e-6
    # FPWFS.quicklook_wf(wfo)
    proper.prop_lens(wfo, f_lens, "objective")

    #propagate through focus to pupil
    proper.prop_propagate(wfo, f_lens * 2, "telescope pupil imaging lens")
    proper.prop_lens(wfo, f_lens, "telescope pupil imaging lens")
    proper.prop_propagate(wfo, f_lens, "DM")
Beispiel #6
0
def add_single_speck(wfo, iter):
    # if iter <4:
    xloc = ap.lods[0][0]
    yloc = ap.lods[0][1]
    wf_temp = copy.deepcopy(wfo)
    wf_temp2 = copy.deepcopy(wfo)
    wf_temp3 = copy.deepcopy(wfo)
    # proper.prop_zernikes(wf_temp, [2], np.array([-1*xloc]) * 1e-6)
    proper.prop_zernikes(wf_temp, [4], np.array([-1 * xloc]) * 1e-6)
    # proper.prop_zernikes(wf_temp2, [2,3], np.array([-1*xloc, 0.5]) * 1e-6)
    # proper.prop_zernikes(wf_temp3, [2,3], np.array([-1*xloc, 1]) * 1e-6)
    wfo.wfarr += wf_temp.wfarr * 2.5
Beispiel #7
0
def offset_companion(wf, step=0):
    """
    offsets the companion wavefront using the 2nd and 3rd order Zernike Polynomials (X,Y tilt)
    companion(s) contrast and location(s) set in params

    We don't call this function via wfo.loop_collection because we need to know which object (io) we are on, which
    is not supported in the current format. This is the only acception to applying loop_collection

    Important: this function must be called AFTER any calls to proper.prop_define_entrance, which normalizes the
    intensity, because we scale the intensity of the planet relative to the star via the user-parameter ap.contrast.

    If you have a focused system, and do not scale the grid sampling of the system by wavelength, we account
    for that here (thus the if/else statements). This is because we shift the companion's location in the focal plane
    by proper.prop_zernikes, which scales the x/y tilt (zernike orders 2 and 3) by wavelength to account for the
    presumed resampling based on wavelength. We thus counteract that in the case of sp.focused_sys=True

    Wavelength/contrast scaling scales the contrast ratio between the star and planet as a function of wavelength.
    This ratio is given by ap.C_spec, and the scale ranges from 1/ap.C_spec to 1 as a function of ap.n_wvl_init. The
        gradient ap.C_spec should be chosen carefully to consider the number of wavelengths and spectral type of the
        star and planet in the simulation.

    :param wf: singe wavefront object from wfo.wf_collection, shape=(grid_sz, grid_sz)
    :return: nothing implicitly returned but the given wfo initiated in Wavefronts class has been altered to give the
        appropriate wavefront for a planet in the focal plane
    """
    if ap.companion is True and wf.name != 'star':
        cont_scaling = np.linspace(1. / ap.C_spec, 1, ap.n_wvl_init)

        # Shifting the Array
        if sp.focused_sys:
            # Scaling into lambda/D AND scaling by wavelength
            xloc = ap.companion_xy[wf.ib-1][0] * wf.lamda / tp.entrance_d \
                   * ap.wvl_range[0] / wf.lamda # * (-1)**(iw%2)
            yloc = ap.companion_xy[wf.ib-1][1] * wf.lamda / tp.entrance_d \
                    *  ap.wvl_range[0] / wf.lamda  # / (2*np.pi)   * (-1)**(iw%2)
        else:
            # Scaling Happens Naturally!
            xloc = ap.companion_xy[wf.ib-1][0]*1e-6
            yloc = ap.companion_xy[wf.ib-1][1]*1e-6

        if tp.rot_rate != 0 and step != 0:
            angle = np.deg2rad(tp.rot_rate * step * sp.sample_time)
            rot_matrix = [[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]]
            xloc, yloc = np.dot(rot_matrix, np.array([xloc,yloc]))
            dprint(tp.rot_rate, angle, rot_matrix, xloc, yloc)

        proper.prop_zernikes(wf, [2, 3], np.array([xloc, yloc]))  # zernike[2,3] = x,y tilt

        ##############################################
        # Wavelength/Contrast  Scaling the Companion
        ##############################################
        wf.wfarr *= np.sqrt(ap.contrast[wf.ib-1])
Beispiel #8
0
def prefocal_image(wavelength, gridsize, PASSVAL):
    diam = PASSVAL['diam']
    focal_length = PASSVAL['focal_length']
    beam_ratio = PASSVAL['beam_ratio']
    wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio)

    proper.prop_circular_aperture(wfo, diam/2)
    proper.prop_define_entrance(wfo)
    proper.prop_zernikes(wfo, [i+1 for i in range(len(PASSVAL['ZERN']))], PASSVAL['ZERN'])
    #print(proper.prop_get_phase(wfo)[gridsize//2,:])
    proper.prop_lens(wfo, focal_length)

    proper.prop_propagate(wfo, focal_length - PASSVAL['DEFOCUS'], TO_PLANE=False)
    (wfo, sampling) = proper.prop_end(wfo)

    return (wfo, sampling)
Beispiel #9
0
def propagate_one(wf, phase_screen=None, tiptilt=None, misalign=None, 
        ngrid=1024, npupil=285, tag=None, onaxis=True, savefits=False, verbose=False, 
        **conf):
            
    """ 
    Propagate one single wavefront.
    An off-axis PSF can be obtained by switching onaxis to False,
    thereby decentering the focal plane mask (if any).
    """

    # update conf
    conf.update(ngrid=ngrid, npupil=npupil)
    
    # keep a copy of the input wavefront
    wf1 = deepcopy(wf)

    # apply phase screen (scao residuals, ncpa, petal piston)
    if phase_screen is not None:
        phase_screen = np.nan_to_num(phase_screen)
        phase_screen = pad_img(resize_img(phase_screen, npupil), ngrid)
        proper.prop_add_phase(wf1, phase_screen)
    # apply tip-tilt (Zernike 2,3)
    if tiptilt is not None:
        # translate the tip/tilt from lambda/D into RMS phase errors
        # RMS = x/2 = ((lam/D)*(D/2))/2 = lam/4
        tiptilt = np.array(tiptilt, ndmin=1)*conf['lam']/4
        proper.prop_zernikes(wf1, [2,3], tiptilt)
    # update RAVC misalignment
    conf.update(ravc_misalign=misalign)
    # pupil-plane apodization
    wf1, apo_amp, apo_phase = apodizer(wf1, get_amp=True, verbose=verbose, **conf)
    # focal-plane mask, only in 'on-axis' configuration
    if onaxis == True:
        wf1 = fp_mask(wf1, verbose=verbose, **conf)
    # Lyot-stop or APP
    wf1, ls_amp, ls_phase = lyot_stop(wf1, get_amp=True, verbose=verbose, **conf)
    # detector
    psf = detector(wf1, verbose=verbose, **conf)

    # save psf as fits file
    if savefits == True:
        tag = '' if tag is None else '%s_'%tag
        name = '%s%s_PSF'%(tag, {True: 'onaxis', False: 'offaxis'}[onaxis])
        save2fits(psf, name, **conf)

    return psf
Beispiel #10
0
def remove_zernike(wf, pup, allSF, zpols):
    proper.prop_add_phase(wf, allSF)
    LSF = proper.prop_zernikes(wf,
                               np.arange(len(zpols)) + 1,
                               zpols).astype('float32')
    LSF[pup == 0] = 0
    HSF = allSF.astype('float32') - LSF
    return LSF, HSF
def simple_telescope(wavelength, gridsize):
    diam = 1.0
    focal_ratio = 15.0
    focal_length = diam * focal_ratio
    beam_ratio = 0.5

    wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio)

    proper.prop_circular_aperture(wfo, diam / 2)
    proper.prop_zernikes(wfo, [5], [1e-6])
    proper.prop_define_entrance(wfo)
    proper.prop_lens(wfo, focal_length * 0.98)

    proper.prop_propagate(wfo, focal_length)

    (wfo, sampling) = proper.prop_end(wfo)

    return (wfo, sampling)
Beispiel #12
0
def wavefront_abberations(wfo, conf,atm_screen, TILT):

    diam = conf['DIAM']
    gridsize = conf['GRIDSIZE']
    pixelsize = conf['PIXEL_SCALE'] 
    wavelength = conf['WAVELENGTH']
    lamda = proper.prop_get_wavelength(wfo)
    Debug = conf['DEBUG']
    Debug_print = conf['DEBUG_PRINT'] 

    Island_Piston = np.array(conf['ISLAND_PISTON'])
#    atm_screen = fits.getdata(input_dir + '/' + atm_screen)
    beam_ratio = pixelsize*4.85e-9/(wavelength/diam)
    npupil = np.ceil(gridsize*beam_ratio) # compute the pupil size --> has to be ODD (proper puts the center in the up right pixel next to the grid center)

    if npupil % 2 == 0:
        npupil = npupil + 1

    if (isinstance(atm_screen, (list, tuple, np.ndarray)) == True) and (atm_screen.ndim >= 2): # when the atmosphere is present
        atmosphere(wfo, npupil, atm_screen, Debug_print, Debug)
    
    if (all(v == 0 for v in Island_Piston) == False): # when the piston is present
        island_effect_piston(wfo, npupil, Island_Piston, Debug_print, Debug)

    if conf['STATIC_NCPA'] == True:
        filename = conf['IMG_LM_SCAO']
        phase_screen = fits.getdata(conf['INPUT_DIR'] + filename)
        phase_screen = np.nan_to_num(phase_screen)
        phase_screen *= 10**-9          # scale the wavelenth to nm
        static_ncpa(wfo, npupil, phase_screen)
    
    if (TILT.any != 0.): # when tip/tilt
        if (Debug_print==True):
            print("TILT: ", TILT)
            print("lamda: ", lamda)
        tiptilt = (np.multiply(TILT, lamda))/4 # translate the tip/tilt from lambda/D into RMS phase errors
        proper.prop_zernikes(wfo, [2,3], tiptilt) # 2-->xtilt, 3-->ytilt
    
    return wfo
Beispiel #13
0
def wfirst_phaseb(lambda_m, output_dim0, PASSVALUE={'dummy': 0}):

    # "output_dim" is used to specify the output dimension in pixels at the final image plane.
    # Computational grid sizes are hardcoded for each coronagraph.
    # Based on Zemax prescription "WFIRST_CGI_DI_LOWFS_Sep24_2018.zmx" by Hong Tang.

    data_dir = wfirst_phaseb_proper.data_dir
    if 'PASSVALUE' in locals():
        if 'data_dir' in PASSVALUE: data_dir = PASSVALUE['data_dir']

    map_dir = data_dir + wfirst_phaseb_proper.map_dir
    polfile = data_dir + wfirst_phaseb_proper.polfile

    cor_type = 'hlc'  # coronagraph type ('hlc', 'spc', 'none')
    source_x_offset_mas = 0  # source offset in mas (tilt applied at primary)
    source_y_offset_mas = 0
    source_x_offset = 0  # source offset in lambda0_m/D radians (tilt applied at primary)
    source_y_offset = 0
    polaxis = 0  # polarization axis aberrations:
    #    -2 = -45d in, Y out
    #    -1 = -45d in, X out
    #     1 = +45d in, X out
    #     2 = +45d in, Y out
    #     5 = mean of modes -1 & +1 (X channel polarizer)
    #     6 = mean of modes -2 & +2 (Y channel polarizer)
    #    10 = mean of all modes (no polarization filtering)
    use_errors = 1  # use optical surface phase errors? 1 or 0
    zindex = np.array([0, 0])  # array of Zernike polynomial indices
    zval_m = np.array([0, 0])  # array of Zernike coefficients (meters RMS WFE)
    use_aperture = 0  # use apertures on all optics? 1 or 0
    cgi_x_shift_pupdiam = 0  # X,Y shear of wavefront at FSM (bulk displacement of CGI); normalized relative to pupil diameter
    cgi_y_shift_pupdiam = 0
    cgi_x_shift_m = 0  # X,Y shear of wavefront at FSM (bulk displacement of CGI) in meters
    cgi_y_shift_m = 0
    fsm_x_offset_mas = 0  # offset in focal plane caused by tilt of FSM in mas
    fsm_y_offset_mas = 0
    fsm_x_offset = 0  # offset in focal plane caused by tilt of FSM in lambda0/D
    fsm_y_offset = 0
    end_at_fsm = 0  # end propagation after propagating to FSM (no FSM errors)
    focm_z_shift_m = 0  # offset (meters) of focus correction mirror (+ increases path length)
    use_hlc_dm_patterns = 0  # use Dwight's HLC default DM wavefront patterns? 1 or 0
    use_dm1 = 0  # use DM1? 1 or 0
    use_dm2 = 0  # use DM2? 1 or 0
    dm_sampling_m = 0.9906e-3  # actuator spacing in meters
    dm1_xc_act = 23.5  # for 48x48 DM, wavefront centered at actuator intersections: (0,0) = 1st actuator center
    dm1_yc_act = 23.5
    dm1_xtilt_deg = 0  # tilt around X axis (deg)
    dm1_ytilt_deg = 5.7  # effective DM tilt in deg including 9.65 deg actual tilt and pupil ellipticity
    dm1_ztilt_deg = 0  # rotation of DM about optical axis (deg)
    dm2_xc_act = 23.5  # for 48x48 DM, wavefront centered at actuator intersections: (0,0) = 1st actuator center
    dm2_yc_act = 23.5
    dm2_xtilt_deg = 0  # tilt around X axis (deg)
    dm2_ytilt_deg = 5.7  # effective DM tilt in deg including 9.65 deg actual tilt and pupil ellipticity
    dm2_ztilt_deg = 0  # rotation of DM about optical axis (deg)
    use_pupil_mask = 1  # SPC only: use SPC pupil mask (0 or 1)
    mask_x_shift_pupdiam = 0  # X,Y shear of shaped pupil mask; normalized relative to pupil diameter
    mask_y_shift_pupdiam = 0
    mask_x_shift_m = 0  # X,Y shear of shaped pupil mask in meters
    mask_y_shift_m = 0
    use_fpm = 1  # use occulter? 1 or 0
    fpm_x_offset = 0  # FPM x,y offset in lambda0/D
    fpm_y_offset = 0
    fpm_x_offset_m = 0  # FPM x,y offset in meters
    fpm_y_offset_m = 0
    fpm_z_shift_m = 0  # occulter offset in meters along optical axis (+ = away from prior optics)
    pinhole_diam_m = 0  # FPM pinhole diameter in meters
    end_at_fpm_exit_pupil = 0  # return field at FPM exit pupil?
    output_field_rootname = ''  # rootname of FPM exit pupil field file (must set end_at_fpm_exit_pupil=1)
    use_lyot_stop = 1  # use Lyot stop? 1 or 0
    lyot_x_shift_pupdiam = 0  # X,Y shear of Lyot stop mask; normalized relative to pupil diameter
    lyot_y_shift_pupdiam = 0
    lyot_x_shift_m = 0  # X,Y shear of Lyot stop mask in meters
    lyot_y_shift_m = 0
    use_field_stop = 1  # use field stop (HLC)? 1 or 0
    field_stop_radius_lam0 = 0  # field stop radius in lambda0/D (HLC or SPC-wide mask only)
    field_stop_x_offset = 0  # field stop offset in lambda0/D
    field_stop_y_offset = 0
    field_stop_x_offset_m = 0  # field stop offset in meters
    field_stop_y_offset_m = 0
    use_pupil_lens = 0  # use pupil imaging lens? 0 or 1
    use_defocus_lens = 0  # use defocusing lens? Options are 1, 2, 3, 4, corresponding to +18.0, +9.0, -4.0, -8.0 waves P-V @ 550 nm
    defocus = 0  # instead of specific lens, defocus in waves P-V @ 550 nm (-8.7 to 42.0 waves)
    final_sampling_m = 0  # final sampling in meters (overrides final_sampling_lam0)
    final_sampling_lam0 = 0  # final sampling in lambda0/D
    output_dim = output_dim0  # dimension of output in pixels (overrides output_dim0)

    if 'PASSVALUE' in locals():
        if 'use_fpm' in PASSVALUE: use_fpm = PASSVALUE['use_fpm']
        if 'cor_type' in PASSVALUE: cor_type = PASSVALUE['cor_type']

    is_spc = False
    is_hlc = False

    if cor_type == 'hlc':
        is_hlc = True
        file_directory = data_dir + '/hlc_20190210/'  # must have trailing "/"
        prefix = file_directory + 'run461_'
        pupil_diam_pix = 309.0
        pupil_file = prefix + 'pupil_rotated.fits'
        lyot_stop_file = prefix + 'lyot.fits'
        lambda0_m = 0.575e-6
        lam_occ = [
            5.4625e-07, 5.49444444444e-07, 5.52638888889e-07, 5.534375e-07,
            5.55833333333e-07, 5.59027777778e-07, 5.60625e-07,
            5.62222222222e-07, 5.65416666667e-07, 5.678125e-07,
            5.68611111111e-07, 5.71805555556e-07, 5.75e-07, 5.78194444444e-07,
            5.81388888889e-07, 5.821875e-07, 5.84583333333e-07,
            5.87777777778e-07, 5.89375e-07, 5.90972222222e-07,
            5.94166666667e-07, 5.965625e-07, 5.97361111111e-07,
            6.00555555556e-07, 6.0375e-07
        ]
        lam_occs = [
            '5.4625e-07', '5.49444444444e-07', '5.52638888889e-07',
            '5.534375e-07', '5.55833333333e-07', '5.59027777778e-07',
            '5.60625e-07', '5.62222222222e-07', '5.65416666667e-07',
            '5.678125e-07', '5.68611111111e-07', '5.71805555556e-07',
            '5.75e-07', '5.78194444444e-07', '5.81388888889e-07',
            '5.821875e-07', '5.84583333333e-07', '5.87777777778e-07',
            '5.89375e-07', '5.90972222222e-07', '5.94166666667e-07',
            '5.965625e-07', '5.97361111111e-07', '6.00555555556e-07',
            '6.0375e-07'
        ]
        lam_occs = [
            prefix + 'occ_lam' + s + 'theta6.69polp_' for s in lam_occs
        ]
        # find nearest matching FPM wavelength
        wlam = (np.abs(lambda_m - np.array(lam_occ))).argmin()
        occulter_file_r = lam_occs[wlam] + 'real.fits'
        occulter_file_i = lam_occs[wlam] + 'imag.fits'
        n_default = 1024  # gridsize in non-critical areas
        if use_fpm == 1:
            n_to_fpm = 2048
        else:
            n_to_fpm = 1024
        n_from_lyotstop = 1024
        field_stop_radius_lam0 = 9.0
    elif cor_type == 'hlc_erkin':
        is_hlc = True
        file_directory = data_dir + '/hlc_20190206_v3/'  # must have trailing "/"
        prefix = file_directory + 'dsn17d_run2_pup310_fpm2048_'
        pupil_diam_pix = 310.0
        pupil_file = prefix + 'pupil.fits'
        lyot_stop_file = prefix + 'lyot.fits'
        lambda0_m = 0.575e-6
        lam_occ = [
            5.4625e-07, 5.4944e-07, 5.5264e-07, 5.5583e-07, 5.5903e-07,
            5.6222e-07, 5.6542e-07, 5.6861e-07, 5.7181e-07, 5.75e-07,
            5.7819e-07, 5.8139e-07, 5.8458e-07, 5.8778e-07, 5.9097e-07,
            5.9417e-07, 5.9736e-07, 6.0056e-07, 6.0375e-07
        ]
        lam_occs = [
            '5.4625e-07', '5.4944e-07', '5.5264e-07', '5.5583e-07',
            '5.5903e-07', '5.6222e-07', '5.6542e-07', '5.6861e-07',
            '5.7181e-07', '5.75e-07', '5.7819e-07', '5.8139e-07', '5.8458e-07',
            '5.8778e-07', '5.9097e-07', '5.9417e-07', '5.9736e-07',
            '6.0056e-07', '6.0375e-07'
        ]
        lam_occs = [
            prefix + 'occ_lam' + s + 'theta6.69pols_' for s in lam_occs
        ]
        # find nearest matching FPM wavelength
        wlam = (np.abs(lambda_m - np.array(lam_occ))).argmin()
        occulter_file_r = lam_occs[wlam] + 'real_rotated.fits'
        occulter_file_i = lam_occs[wlam] + 'imag_rotated.fits'
        n_default = 1024  # gridsize in non-critical areas
        if use_fpm == 1:
            n_to_fpm = 2048
        else:
            n_to_fpm = 1024
        n_from_lyotstop = 1024
        field_stop_radius_lam0 = 9.0
    elif cor_type == 'spc-ifs_short' or cor_type == 'spc-ifs_long' or cor_type == 'spc-spec_short' or cor_type == 'spc-spec_long':
        is_spc = True
        file_dir = data_dir + '/spc_20190130/'  # must have trailing "/"
        pupil_diam_pix = 1000.0
        pupil_file = file_dir + 'pupil_SPC-20190130_rotated.fits'
        pupil_mask_file = file_dir + 'SPM_SPC-20190130.fits'
        fpm_file = file_dir + 'fpm_0.05lamdivD.fits'
        fpm_sampling = 0.05  # sampling in fpm_sampling_lambda_m/D of FPM mask
        if cor_type == 'spc-ifs_short' or cor_type == 'spc-spec_short':
            fpm_sampling_lambda_m = 0.66e-6
            lambda0_m = 0.66e-6
        else:
            fpm_sampling_lambda_m = 0.73e-6
            lambda0_m = 0.73e-6  # FPM scaled for this central wavelength
        lyot_stop_file = file_dir + 'LS_SPC-20190130.fits'
        n_default = 2048  # gridsize in non-critical areas
        n_to_fpm = 2048  # gridsize to/from FPM
        n_mft = 1400  # gridsize to FPM (propagation to/from FPM handled by MFT)
        n_from_lyotstop = 4096
    elif cor_type == 'spc-wide':
        is_spc = True
        file_dir = data_dir + '/spc_20181220/'  # must have trailing "/"
        pupil_diam_pix = 1000.0
        pupil_file = file_dir + 'pupil_SPC-20181220_1k_rotated.fits'
        pupil_mask_file = file_dir + 'SPM_SPC-20181220_1000_rounded9_gray.fits'
        fpm_file = file_dir + 'fpm_0.05lamdivD.fits'
        fpm_sampling = 0.05  # sampling in lambda0/D of FPM mask
        fpm_sampling_lambda_m = 0.825e-6
        lambda0_m = 0.825e-6  # FPM scaled for this central wavelength
        lyot_stop_file = file_dir + 'LS_SPC-20181220_1k.fits'
        n_default = 2048  # gridsize in non-critical areas
        n_to_fpm = 2048  # gridsize to/from FPM
        n_mft = 1400
        n_from_lyotstop = 4096
    elif cor_type == 'none':
        file_directory = data_dir + '/hlc_20190210/'  # must have trailing "/"
        prefix = file_directory + 'run461_'
        pupil_diam_pix = 309.0
        pupil_file = prefix + 'pupil_rotated.fits'
        lambda0_m = 0.575e-6
        use_fpm = 0
        use_lyot_stop = 0
        use_field_stop = 0
        n_default = 1024
        n_to_fpm = 1024
        n_from_lyotstop = 1024
    else:
        raise Exception('ERROR: Unsupported cor_type: ' + cor_type)

    if 'PASSVALUE' in locals():
        if 'lam0' in PASSVALUE: lamba0_m = PASSVALUE['lam0'] * 1.0e-6
        if 'lambda0_m' in PASSVALUE: lambda0_m = PASSVALUE['lambda0_m']
        mas_per_lamD = lambda0_m * 360.0 * 3600.0 / (
            2 * np.pi * 2.363) * 1000  # mas per lambda0/D
        if 'source_x_offset' in PASSVALUE:
            source_x_offset = PASSVALUE['source_x_offset']
        if 'source_y_offset' in PASSVALUE:
            source_y_offset = PASSVALUE['source_y_offset']
        if 'source_x_offset_mas' in PASSVALUE:
            source_x_offset = PASSVALUE['source_x_offset_mas'] / mas_per_lamD
        if 'source_y_offset_mas' in PASSVALUE:
            source_y_offset = PASSVALUE['source_y_offset_mas'] / mas_per_lamD
        if 'use_errors' in PASSVALUE: use_errors = PASSVALUE['use_errors']
        if 'polaxis' in PASSVALUE: polaxis = PASSVALUE['polaxis']
        if 'zindex' in PASSVALUE: zindex = np.array(PASSVALUE['zindex'])
        if 'zval_m' in PASSVALUE: zval_m = np.array(PASSVALUE['zval_m'])
        if 'end_at_fsm' in PASSVALUE: end_at_fsm = PASSVALUE['end_at_fsm']
        if 'cgi_x_shift_pupdiam' in PASSVALUE:
            cgi_x_shift_pupdiam = PASSVALUE['cgi_x_shift_pupdiam']
        if 'cgi_y_shift_pupdiam' in PASSVALUE:
            cgi_y_shift_pupdiam = PASSVALUE['cgi_y_shift_pupdiam']
        if 'cgi_x_shift_m' in PASSVALUE:
            cgi_x_shift_m = PASSVALUE['cgi_x_shift_m']
        if 'cgi_y_shift_m' in PASSVALUE:
            cgi_y_shift_m = PASSVALUE['cgi_y_shift_m']
        if 'fsm_x_offset' in PASSVALUE:
            fsm_x_offset = PASSVALUE['fsm_x_offset']
        if 'fsm_y_offset' in PASSVALUE:
            fsm_y_offset = PASSVALUE['fsm_y_offset']
        if 'fsm_x_offset_mas' in PASSVALUE:
            fsm_x_offset = PASSVALUE['fsm_x_offset_mas'] / mas_per_lamD
        if 'fsm_y_offset_mas' in PASSVALUE:
            fsm_y_offset = PASSVALUE['fsm_y_offset_mas'] / mas_per_lamD
        if 'focm_z_shift_m' in PASSVALUE:
            focm_z_shift_m = PASSVALUE['focm_z_shift_m']
        if 'use_hlc_dm_patterns' in PASSVALUE:
            use_hlc_dm_patterns = PASSVALUE['use_hlc_dm_patterns']
        if 'use_dm1' in PASSVALUE: use_dm1 = PASSVALUE['use_dm1']
        if 'dm1_m' in PASSVALUE: dm1_m = PASSVALUE['dm1_m']
        if 'dm1_xc_act' in PASSVALUE: dm1_xc_act = PASSVALUE['dm1_xc_act']
        if 'dm1_yc_act' in PASSVALUE: dm1_yc_act = PASSVALUE['dm1_yc_act']
        if 'dm1_xtilt_deg' in PASSVALUE:
            dm1_xtilt_deg = PASSVALUE['dm1_xtilt_deg']
        if 'dm1_ytilt_deg' in PASSVALUE:
            dm1_ytilt_deg = PASSVALUE['dm1_ytilt_deg']
        if 'dm1_ztilt_deg' in PASSVALUE:
            dm1_ztilt_deg = PASSVALUE['dm1_ztilt_deg']
        if 'use_dm2' in PASSVALUE: use_dm2 = PASSVALUE['use_dm2']
        if 'dm2_m' in PASSVALUE: dm2_m = PASSVALUE['dm2_m']
        if 'dm2_xc_act' in PASSVALUE: dm2_xc_act = PASSVALUE['dm2_xc_act']
        if 'dm2_yc_act' in PASSVALUE: dm2_yc_act = PASSVALUE['dm2_yc_act']
        if 'dm2_xtilt_deg' in PASSVALUE:
            dm2_xtilt_deg = PASSVALUE['dm2_xtilt_deg']
        if 'dm2_ytilt_deg' in PASSVALUE:
            dm2_ytilt_deg = PASSVALUE['dm2_ytilt_deg']
        if 'dm2_ztilt_deg' in PASSVALUE:
            dm2_ztilt_deg = PASSVALUE['dm2_ztilt_deg']
        if 'use_pupil_mask' in PASSVALUE:
            use_pupil_mask = PASSVALUE['use_pupil_mask']
        if 'mask_x_shift_pupdiam' in PASSVALUE:
            mask_x_shift_pupdiam = PASSVALUE['mask_x_shift_pupdiam']
        if 'mask_y_shift_pupdiam' in PASSVALUE:
            mask_y_shift_pupdiam = PASSVALUE['mask_y_shift_pupdiam']
        if 'mask_x_shift_m' in PASSVALUE:
            mask_x_shift_m = PASSVALUE['mask_x_shift_m']
        if 'mask_y_shift_m' in PASSVALUE:
            mask_y_shift_m = PASSVALUE['mask_y_shift_m']
        if 'fpm_x_offset' in PASSVALUE:
            fpm_x_offset = PASSVALUE['fpm_x_offset']
        if 'fpm_y_offset' in PASSVALUE:
            fpm_y_offset = PASSVALUE['fpm_y_offset']
        if 'fpm_x_offset_m' in PASSVALUE:
            fpm_x_offset_m = PASSVALUE['fpm_x_offset_m']
        if 'fpm_y_offset_m' in PASSVALUE:
            fpm_y_offset_m = PASSVALUE['fpm_y_offset_m']
        if 'fpm_z_shift_m' in PASSVALUE:
            fpm_z_shift_m = PASSVALUE['fpm_z_shift_m']
        if 'pinhole_diam_m' in PASSVALUE:
            pinhole_diam_m = PASSVALUE['pinhole_diam_m']
        if 'end_at_fpm_exit_pupil' in PASSVALUE:
            end_at_fpm_exit_pupil = PASSVALUE['end_at_fpm_exit_pupil']
        if 'output_field_rootname' in PASSVALUE:
            output_field_rootname = PASSVALUE['output_field_rootname']
        if 'use_lyot_stop' in PASSVALUE:
            use_lyot_stop = PASSVALUE['use_lyot_stop']
        if 'lyot_x_shift_pupdiam' in PASSVALUE:
            lyot_x_shift_pupdiam = PASSVALUE['lyot_x_shift_pupdiam']
        if 'lyot_y_shift_pupdiam' in PASSVALUE:
            lyot_y_shift_pupdiam = PASSVALUE['lyot_y_shift_pupdiam']
        if 'lyot_x_shift_m' in PASSVALUE:
            lyot_x_shift_m = PASSVALUE['lyot_x_shift_m']
        if 'lyot_y_shift_m' in PASSVALUE:
            lyot_y_shift_m = PASSVALUE['lyot_y_shift_m']
        if 'use_field_stop' in PASSVALUE:
            use_field_stop = PASSVALUE['use_field_stop']
        if 'field_stop_x_offset' in PASSVALUE:
            field_stop_x_offset = PASSVALUE['field_stop_x_offset']
        if 'field_stop_y_offset' in PASSVALUE:
            field_stop_y_offset = PASSVALUE['field_stop_y_offset']
        if 'field_stop_x_offset_m' in PASSVALUE:
            field_stop_x_offset_m = PASSVALUE['field_stop_x_offset_m']
        if 'field_stop_y_offset_m' in PASSVALUE:
            field_stop_y_offset_m = PASSVALUE['field_stop_y_offset_m']
        if 'use_pupil_lens' in PASSVALUE:
            use_pupil_lens = PASSVALUE['use_pupil_lens']
        if 'use_defocus_lens' in PASSVALUE:
            use_defocus_lens = PASSVALUE['use_defocus_lens']
        if 'defocus' in PASSVALUE: defocus = PASSVALUE['defocus']
        if 'output_dim' in PASSVALUE: output_dim = PASSVALUE['output_dim']
        if 'final_sampling_m' in PASSVALUE:
            final_sampling_m = PASSVALUE['final_sampling_m']
        if 'final_sampling_lam0' in PASSVALUE:
            final_sampling_lam0 = PASSVALUE['final_sampling_lam0']

    diam = 2.3633372
    fl_pri = 2.83459423440 * 1.0013
    d_pri_sec = 2.285150515460035
    d_focus_sec = d_pri_sec - fl_pri
    fl_sec = -0.653933011 * 1.0004095
    d_sec_focus = 3.580188916677103
    diam_sec = 0.58166
    d_sec_fold1 = 2.993753476654728
    d_fold1_focus = 0.586435440022375
    diam_fold1 = 0.09
    d_fold1_m3 = 1.680935841598811
    fl_m3 = 0.430216463069001
    d_focus_m3 = 1.094500401576436
    d_m3_pupil = 0.469156807701977
    d_m3_focus = 0.708841602661368
    diam_m3 = 0.2
    d_m3_m4 = 0.943514749358944
    fl_m4 = 0.116239114833590
    d_focus_m4 = 0.234673014520402
    d_m4_pupil = 0.474357941656967
    d_m4_focus = 0.230324117970585
    diam_m4 = 0.07
    d_m4_m5 = 0.429145636743193
    d_m5_focus = 0.198821518772608
    fl_m5 = 0.198821518772608
    d_m5_pupil = 0.716529242882632
    diam_m5 = 0.07
    d_m5_fold2 = 0.351125431220770
    diam_fold2 = 0.06
    d_fold2_fsm = 0.365403811661862
    d_fsm_oap1 = 0.354826767220001
    fl_oap1 = 0.503331895563883
    diam_oap1 = 0.06
    d_oap1_focm = 0.768005607094041
    d_focm_oap2 = 0.314483210543378
    fl_oap2 = 0.579156922073536
    diam_oap2 = 0.06
    d_oap2_dm1 = 0.775775726154228
    d_dm1_dm2 = 1.0
    d_dm2_oap3 = 0.394833855161549
    fl_oap3 = 1.217276467668519
    diam_oap3 = 0.06
    d_oap3_fold3 = 0.505329955078121
    diam_fold3 = 0.06
    d_fold3_oap4 = 1.158897671642761
    fl_oap4 = 0.446951159052363
    diam_oap4 = 0.06
    d_oap4_pupilmask = 0.423013568764728
    d_pupilmask_oap5 = 0.408810648253099
    fl_oap5 = 0.548189351937178
    diam_oap5 = 0.06
    d_oap5_fpm = 0.548189083164429
    d_fpm_oap6 = 0.548189083164429
    fl_oap6 = 0.548189083164429
    diam_oap6 = 0.06
    d_oap6_lyotstop = 0.687567667550736
    d_lyotstop_oap7 = 0.401748843470518
    fl_oap7 = 0.708251083480054
    diam_oap7 = 0.06
    d_oap7_fieldstop = 0.708251083480054
    d_fieldstop_oap8 = 0.210985967281651
    fl_oap8 = 0.210985967281651
    diam_oap8 = 0.06
    d_oap8_pupil = 0.238185804200797
    d_oap8_filter = 0.368452268225530
    diam_filter = 0.01
    d_filter_lens = 0.170799548215162
    fl_lens = 0.246017378417573 + 0.050001306014153
    diam_lens = 0.01
    d_lens_fold4 = 0.246017378417573
    diam_fold4 = 0.02
    d_fold4_image = 0.050001578514650
    fl_pupillens = 0.149260576823040

    n = n_default  # start off with less padding

    wavefront = proper.prop_begin(diam, lambda_m, n, float(pupil_diam_pix) / n)
    pupil = proper.prop_fits_read(pupil_file)
    proper.prop_multiply(wavefront, trim(pupil, n))
    pupil = 0
    if polaxis != 0: polmap(wavefront, polfile, pupil_diam_pix, polaxis)
    proper.prop_define_entrance(wavefront)
    proper.prop_lens(wavefront, fl_pri)
    if source_x_offset != 0 or source_y_offset != 0:
        # compute tilted wavefront to offset source by xoffset,yoffset lambda0_m/D
        xtilt_lam = -source_x_offset * lambda0_m / lambda_m
        ytilt_lam = -source_y_offset * lambda0_m / lambda_m
        x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1))
        y = np.transpose(x)
        proper.prop_multiply(
            wavefront,
            np.exp(complex(0, 1) * np.pi * (xtilt_lam * x + ytilt_lam * y)))
        x = 0
        y = 0
    if zindex[0] != 0: proper.prop_zernikes(wavefront, zindex, zval_m)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_PRIMARY_phase_error_V1.0.fits',
                             WAVEFRONT=True)
        proper.prop_errormap(
            wavefront,
            map_dir +
            'wfirst_phaseb_GROUND_TO_ORBIT_4.2X_phase_error_V1.0.fits',
            WAVEFRONT=True)

    proper.prop_propagate(wavefront, d_pri_sec, 'secondary')
    proper.prop_lens(wavefront, fl_sec)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_SECONDARY_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_sec / 2.0)

    proper.prop_propagate(wavefront, d_sec_fold1, 'FOLD_1')
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_FOLD1_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_fold1 / 2.0)

    proper.prop_propagate(wavefront, d_fold1_m3, 'M3')
    proper.prop_lens(wavefront, fl_m3)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_M3_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_m3 / 2.0)

    proper.prop_propagate(wavefront, d_m3_m4, 'M4')
    proper.prop_lens(wavefront, fl_m4)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_M4_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_m4 / 2.0)

    proper.prop_propagate(wavefront, d_m4_m5, 'M5')
    proper.prop_lens(wavefront, fl_m5)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_M5_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_m5 / 2.0)

    proper.prop_propagate(wavefront, d_m5_fold2, 'FOLD_2')
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_FOLD2_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_fold2 / 2.0)

    proper.prop_propagate(wavefront, d_fold2_fsm, 'FSM')
    if end_at_fsm == 1:
        (wavefront, sampling_m) = proper.prop_end(wavefront, NOABS=True)
        wavefront = trim(wavefront, n)
        return wavefront, sampling_m
    if cgi_x_shift_pupdiam != 0 or cgi_y_shift_pupdiam != 0 or cgi_x_shift_m != 0 or cgi_y_shift_m != 0:  # bulk coronagraph pupil shear
        # FFT the field, apply a tilt, FFT back
        if cgi_x_shift_pupdiam != 0 or cgi_y_shift_pupdiam != 0:
            # offsets are normalized to pupil diameter
            xt = -cgi_x_shift_pupdiam * pupil_diam_pix * float(
                pupil_diam_pix) / n
            yt = -cgi_y_shift_pupdiam * pupil_diam_pix * float(
                pupil_diam_pix) / n
        else:
            # offsets are meters
            d_m = proper.prop_get_sampling(wavefront)
            xt = -cgi_x_shift_m / d_m * float(pupil_diam_pix) / n
            yt = -cgi_y_shift_m / d_m * float(pupil_diam_pix) / n
        x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1))
        y = np.transpose(x)
        tilt = complex(0, 1) * np.pi * (x * xt + y * yt)
        x = 0
        y = 0
        wavefront0 = proper.prop_get_wavefront(wavefront)
        wavefront0 = ffts(wavefront0, -1)
        wavefront0 *= np.exp(tilt)
        wavefront0 = ffts(wavefront0, 1)
        tilt = 0
        wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0)
        wavefront0 = 0
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_FSM_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_fsm / 2.0)
    if (fsm_x_offset != 0.0 or fsm_y_offset != 0.0):
        # compute tilted wavefront to offset source by fsm_x_offset,fsm_y_offset lambda0_m/D
        xtilt_lam = fsm_x_offset * lambda0_m / lambda_m
        ytilt_lam = fsm_y_offset * lambda0_m / lambda_m
        x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0), (n, 1))
        y = np.transpose(x)
        proper.prop_multiply(
            wavefront,
            np.exp(complex(0, 1) * np.pi * (xtilt_lam * x + ytilt_lam * y)))
        x = 0
        y = 0

    proper.prop_propagate(wavefront, d_fsm_oap1, 'OAP1')
    proper.prop_lens(wavefront, fl_oap1)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_OAP1_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_oap1 / 2.0)

    proper.prop_propagate(wavefront, d_oap1_focm + focm_z_shift_m, 'FOCM')
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_FOCM_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_focm / 2.0)

    proper.prop_propagate(wavefront, d_focm_oap2 + focm_z_shift_m, 'OAP2')
    proper.prop_lens(wavefront, fl_oap2)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_OAP2_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_oap2 / 2.0)

    proper.prop_propagate(wavefront, d_oap2_dm1, 'DM1')
    if use_dm1 != 0:
        proper.prop_dm(wavefront,
                       dm1_m,
                       dm1_xc_act,
                       dm1_yc_act,
                       dm_sampling_m,
                       XTILT=dm1_xtilt_deg,
                       YTILT=dm1_ytilt_deg,
                       ZTILT=dm1_ztilt_deg)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_DM1_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if is_hlc == True and use_hlc_dm_patterns == 1:
        dm1wfe = proper.prop_fits_read(prefix + 'dm1wfe.fits')
        proper.prop_add_phase(wavefront, trim(dm1wfe, n))
        dm1wfe = 0

    proper.prop_propagate(wavefront, d_dm1_dm2, 'DM2')
    if use_dm2 == 1:
        proper.prop_dm(wavefront,
                       dm2_m,
                       dm2_xc_act,
                       dm2_yc_act,
                       dm_sampling_m,
                       XTILT=dm2_xtilt_deg,
                       YTILT=dm2_ytilt_deg,
                       ZTILT=dm2_ztilt_deg)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_DM2_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if is_hlc == True:
        if use_hlc_dm_patterns == 1:
            dm2wfe = proper.prop_fits_read(prefix + 'dm2wfe.fits')
            proper.prop_add_phase(wavefront, trim(dm2wfe, n))
            dm2wfe = 0
        dm2mask = proper.prop_fits_read(prefix + 'dm2mask.fits')
        proper.prop_multiply(wavefront, trim(dm2mask, n))
        dm2mask = 0

    proper.prop_propagate(wavefront, d_dm2_oap3, 'OAP3')
    proper.prop_lens(wavefront, fl_oap3)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_OAP3_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_oap3 / 2.0)

    proper.prop_propagate(wavefront, d_oap3_fold3, 'FOLD_3')
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_FOLD3_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_fold3 / 2.0)

    proper.prop_propagate(wavefront, d_fold3_oap4, 'OAP4')
    proper.prop_lens(wavefront, fl_oap4)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_OAP4_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_oap4 / 2.0)

    proper.prop_propagate(wavefront, d_oap4_pupilmask,
                          'PUPIL_MASK')  # flat/reflective shaped pupil
    if is_spc == True and use_pupil_mask != 0:
        pupil_mask = proper.prop_fits_read(pupil_mask_file)
        pupil_mask = trim(pupil_mask, n)
        if mask_x_shift_pupdiam != 0 or mask_y_shift_pupdiam != 0 or mask_x_shift_m != 0 or mask_y_shift_m != 0:
            # shift SP mask by FFTing it, applying tilt, and FFTing back
            if mask_x_shift_pupdiam != 0 or mask_y_shift_pupdiam != 0:
                # offsets are normalized to pupil diameter
                xt = -mask_x_shift_pupdiam * pupil_diam_pix * float(
                    pupil_diam_pix) / n
                yt = -mask_y_shift_pupdiam * pupil_diam_pix * float(
                    pupil_diam_pix) / n
            else:
                d_m = proper.prop_get_sampling(wavefront)
                xt = -mask_x_shift_m / d_m * float(pupil_diam_pix) / n
                yt = -mask_y_shift_m / d_m * float(pupil_diam_pix) / n
            x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0),
                        (n, 1))
            y = np.transpose(x)
            tilt = complex(0, 1) * np.pi * (x * xt + y * yt)
            x = 0
            y = 0
            pupil_mask = ffts(pupil_mask, -1)
            pupil_mask *= np.exp(tilt)
            pupil_mask = ffts(pupil_mask, 1)
            pupil_mask = pupil_mask.real
            tilt = 0
        proper.prop_multiply(wavefront, pupil_mask)
        pupil_mask = 0
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_PUPILMASK_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    # while at a pupil, use more padding to provide 2x better sampling at FPM
    diam = 2 * proper.prop_get_beamradius(wavefront)
    (wavefront, dx) = proper.prop_end(wavefront, NOABS=True)
    n = n_to_fpm
    wavefront0 = trim(wavefront, n)
    wavefront = proper.prop_begin(diam, lambda_m, n, float(pupil_diam_pix) / n)
    wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0)
    wavefront0 = 0

    proper.prop_propagate(wavefront, d_pupilmask_oap5, 'OAP5')
    proper.prop_lens(wavefront, fl_oap5)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_OAP5_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_oap5 / 2.0)

    proper.prop_propagate(wavefront,
                          d_oap5_fpm + fpm_z_shift_m,
                          'FPM',
                          TO_PLANE=True)
    if use_fpm == 1:
        if fpm_x_offset != 0 or fpm_y_offset != 0 or fpm_x_offset_m != 0 or fpm_y_offset_m != 0:
            # To shift FPM, FFT field to pupil, apply tilt, FFT back to focus,
            # apply FPM, FFT to pupil, take out tilt, FFT back to focus
            if fpm_x_offset != 0 or fpm_y_offset != 0:
                # shifts are specified in lambda0/D
                x_offset_lamD = fpm_x_offset * lambda0_m / lambda_m
                y_offset_lamD = fpm_y_offset * lambda0_m / lambda_m
            else:
                d_m = proper.prop_get_sampling(wavefront)
                x_offset_lamD = fpm_x_offset_m / d_m * float(
                    pupil_diam_pix) / n
                y_offset_lamD = fpm_y_offset_m / d_m * float(
                    pupil_diam_pix) / n
            x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0),
                        (n, 1))
            y = np.transpose(x)
            tilt = complex(0,
                           1) * np.pi * (x * x_offset_lamD + y * y_offset_lamD)
            x = 0
            y = 0
            wavefront0 = proper.prop_get_wavefront(wavefront)
            wavefront0 = ffts(wavefront0, -1)
            wavefront0 *= np.exp(tilt)
            wavefront0 = ffts(wavefront0, 1)
            wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0)
            wavefront0 = 0
        if is_hlc == True:
            occ_r = proper.prop_fits_read(occulter_file_r)
            occ_i = proper.prop_fits_read(occulter_file_i)
            occ = np.array(occ_r + 1j * occ_i, dtype=np.complex128)
            proper.prop_multiply(wavefront, trim(occ, n))
            occ_r = 0
            occ_i = 0
            occ = 0
        elif is_spc == True:
            # super-sample FPM
            wavefront0 = proper.prop_get_wavefront(wavefront)
            wavefront0 = ffts(wavefront0, 1)  # to virtual pupil
            wavefront0 = trim(wavefront0, n_mft)
            fpm = proper.prop_fits_read(fpm_file)
            nfpm = fpm.shape[1]
            fpm_sampling_lam = fpm_sampling * fpm_sampling_lambda_m / lambda_m
            wavefront0 = mft2(wavefront0, fpm_sampling_lam, pupil_diam_pix,
                              nfpm, -1)  # MFT to highly-sampled focal plane
            wavefront0 *= fpm
            fpm = 0
            wavefront0 = mft2(wavefront0, fpm_sampling_lam, pupil_diam_pix, n,
                              +1)  # MFT to virtual pupil
            wavefront0 = ffts(wavefront0,
                              -1)  # back to normally-sampled focal plane
            wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0)
            wavefront0 = 0
        if fpm_x_offset != 0 or fpm_y_offset != 0 or fpm_x_offset_m != 0 or fpm_y_offset_m != 0:
            wavefront0 = proper.prop_get_wavefront(wavefront)
            wavefront0 = ffts(wavefront0, -1)
            wavefront0 *= np.exp(-tilt)
            wavefront0 = ffts(wavefront0, 1)
            wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0)
            wavefront0 = 0
            tilt = 0
    if pinhole_diam_m != 0:
        # "pinhole_diam_m" is pinhole diameter in meters
        dx_m = proper.prop_get_sampling(wavefront)
        dx_pinhole_diam_m = pinhole_diam_m / 101.0  # 101 samples across pinhole
        n_out = 105
        m_per_lamD = dx_m * n / float(
            pupil_diam_pix)  # current focal plane sampling in lambda_m/D
        dx_pinhole_lamD = dx_pinhole_diam_m / m_per_lamD  # pinhole sampling in lambda_m/D
        n_in = int(round(pupil_diam_pix * 1.2))
        wavefront0 = proper.prop_get_wavefront(wavefront)
        wavefront0 = ffts(wavefront0, +1)  # to virtual pupil
        wavefront0 = trim(wavefront0, n_in)
        m = dx_pinhole_lamD * n_in * float(n_out) / pupil_diam_pix
        wavefront0 = mft2(wavefront0, dx_pinhole_lamD, pupil_diam_pix, n_out,
                          -1)  # MFT to highly-sampled focal plane
        p = (radius(n_out) * dx_pinhole_diam_m) <= (pinhole_diam_m / 2.0)
        p = p.astype(np.int)
        wavefront0 *= p
        p = 0
        wavefront0 = mft2(wavefront0, dx_pinhole_lamD, pupil_diam_pix, n,
                          +1)  # MFT back to virtual pupil
        wavefront0 = ffts(wavefront0,
                          -1)  # back to normally-sampled focal plane
        wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0)
        wavefront0 = 0

    proper.prop_propagate(wavefront, d_fpm_oap6 - fpm_z_shift_m, 'OAP6')
    proper.prop_lens(wavefront, fl_oap6)
    if use_errors != 0 and end_at_fpm_exit_pupil == 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_OAP6_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_oap6 / 2.0)

    proper.prop_propagate(wavefront, d_oap6_lyotstop, 'LYOT_STOP')
    # while at a pupil, switch back to less padding
    diam = 2 * proper.prop_get_beamradius(wavefront)
    (wavefront, dx) = proper.prop_end(wavefront, NOABS=True)
    n = n_from_lyotstop
    wavefront = trim(wavefront, n)
    if output_field_rootname != '':
        lams = format(lambda_m * 1e6, "6.4f")
        pols = format(int(round(polaxis)))
        hdu = pyfits.PrimaryHDU()
        hdu.data = np.real(wavefront)
        hdu.writeto(output_field_rootname + '_' + lams + 'um_' + pols +
                    '_real.fits',
                    overwrite=True)
        hdu = pyfits.PrimaryHDU()
        hdu.data = np.imag(wavefront)
        hdu.writeto(output_field_rootname + '_' + lams + 'um_' + pols +
                    '_imag.fits',
                    overwrite=True)
    if end_at_fpm_exit_pupil == 1:
        return wavefront, dx
    wavefront0 = wavefront.copy()
    wavefront = 0
    wavefront = proper.prop_begin(diam, lambda_m, n, float(pupil_diam_pix) / n)
    wavefront.wfarr[:, :] = proper.prop_shift_center(wavefront0)
    wavefront0 = 0

    if use_lyot_stop != 0:
        lyot = proper.prop_fits_read(lyot_stop_file)
        lyot = trim(lyot, n)
        if lyot_x_shift_pupdiam != 0 or lyot_y_shift_pupdiam != 0 or lyot_x_shift_m != 0 or lyot_y_shift_m != 0:
            # apply shift to lyot stop by FFTing the stop, applying a tilt, and FFTing back
            if lyot_x_shift_pupdiam != 0 or lyot_y_shift_pupdiam != 0:
                # offsets are normalized to pupil diameter
                xt = -lyot_x_shift_pupdiam * pupil_diam_pix * float(
                    pupil_diam_pix) / n
                yt = -lyot_y_shift_pupdiam * pupil_diam_pix * float(
                    pupil_diam_pix) / n
            else:
                d_m = proper.prop_get_sampling(wavefront)
                xt = -lyot_x_shift_m / d_m * float(pupil_diam_pix) / n
                yt = -lyot_y_shift_m / d_m * float(pupil_diam_pix) / n
            x = np.tile((np.arange(n) - n // 2) / (pupil_diam_pix / 2.0),
                        (n, 1))
            y = np.transpose(x)
            tilt = complex(0, 1) * np.pi * (x * xt + y * yt)
            x = 0
            y = 0
            lyot = ffts(lyot, -1)
            lyot *= np.exp(tilt)
            lyot = ffts(lyot, 1)
            lyot = lyot.real
            tilt = 0
        proper.prop_multiply(wavefront, lyot)
        lyot = 0
    if use_pupil_lens != 0 or pinhole_diam_m != 0:
        proper.prop_circular_aperture(wavefront, 1.1, NORM=True)

    proper.prop_propagate(wavefront, d_lyotstop_oap7, 'OAP7')
    proper.prop_lens(wavefront, fl_oap7)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_OAP7_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_oap7 / 2.0)

    proper.prop_propagate(wavefront, d_oap7_fieldstop, 'FIELD_STOP')
    if use_field_stop != 0 and (cor_type == 'hlc' or cor_type == 'hlc_erkin'):
        sampling_lamD = float(
            pupil_diam_pix) / n  # sampling at focus in lambda_m/D
        stop_radius = field_stop_radius_lam0 / sampling_lamD * (
            lambda0_m / lambda_m) * proper.prop_get_sampling(wavefront)
        if field_stop_x_offset != 0 or field_stop_y_offset != 0:
            # convert offsets in lambda0/D to meters
            x_offset_lamD = field_stop_x_offset * lambda0_m / lambda_m
            y_offset_lamD = field_stop_y_offset * lambda0_m / lambda_m
            pupil_ratio = float(pupil_diam_pix) / n
            field_stop_x_offset_m = x_offset_lamD / pupil_ratio * proper.prop_get_sampling(
                wavefront)
            field_stop_y_offset_m = y_offset_lamD / pupil_ratio * proper.prop_get_sampling(
                wavefront)
        proper.prop_circular_aperture(wavefront, stop_radius,
                                      -field_stop_x_offset_m,
                                      -field_stop_y_offset_m)

    proper.prop_propagate(wavefront, d_fieldstop_oap8, 'OAP8')
    proper.prop_lens(wavefront, fl_oap8)
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_OAP8_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_oap8 / 2.0)

    proper.prop_propagate(wavefront, d_oap8_filter, 'filter')
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_FILTER_phase_error_V1.0.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_filter / 2.0)

    proper.prop_propagate(wavefront, d_filter_lens, 'LENS')
    if use_pupil_lens == 0 and use_defocus_lens == 0 and defocus == 0:
        # use imaging lens to create normal focus
        proper.prop_lens(wavefront, fl_lens)
        if use_errors != 0:
            proper.prop_errormap(wavefront,
                                 map_dir +
                                 'wfirst_phaseb_LENS_phase_error_V1.0.fits',
                                 WAVEFRONT=True)
    elif use_pupil_lens != 0:
        # use pupil imaging lens
        proper.prop_lens(wavefront, fl_pupillens)
        if use_errors != 0:
            proper.prop_errormap(
                wavefront,
                map_dir + 'wfirst_phaseb_PUPILLENS_phase_error_V1.0.fits',
                WAVEFRONT=True)
    else:
        # table is waves P-V @ 575 nm
        z4_pv_waves = np.array([
            -9.0545, -8.5543, -8.3550, -8.0300, -7.54500, -7.03350, -6.03300,
            -5.03300, -4.02000, -2.51980, 0.00000000, 3.028000, 4.95000,
            6.353600, 8.030000, 10.10500, 12.06000, 14.06000, 20.26000,
            28.34000, 40.77500, 56.65700
        ])
        fl_defocus_lens = np.array([
            5.09118, 1.89323, 1.54206, 1.21198, 0.914799, 0.743569, 0.567599,
            0.470213, 0.406973, 0.350755, 0.29601868, 0.260092, 0.24516,
            0.236606, 0.228181, 0.219748, 0.213278, 0.207816, 0.195536,
            0.185600, 0.176629, 0.169984
        ])
        # subtract ad-hoc function to make z4 vs f_length more accurately spline interpolatible
        f = fl_defocus_lens / 0.005
        f0 = 59.203738
        z4t = z4_pv_waves - (0.005 * (f0 - f - 40)) / f**2 / 0.575e-6
        if use_defocus_lens != 0:
            # use one of 4 defocusing lenses
            defocus = np.array([18.0, 9.0, -4.0, -8.0])  # waves P-V @ 575 nm
            f = interp1d(z4_pv_waves, z4t, kind='cubic')
            z4x = f(defocus)
            f = interp1d(z4t, fl_defocus_lens, kind='cubic')
            lens_fl = f(z4x)
            proper.prop_lens(wavefront, lens_fl[use_defocus_lens - 1])
            if use_errors != 0:
                proper.prop_errormap(wavefront,
                                     map_dir + 'wfirst_phaseb_DEFOCUSLENS' +
                                     str(use_defocus_lens) +
                                     '_phase_error_V1.0.fits',
                                     WAVEFRONT=True)
            defocus = defocus[use_defocus_lens - 1]
        else:
            # specify amount of defocus (P-V waves @ 575 nm)
            f = interp1d(z4_pv_waves, z4t, kind='cubic')
            z4x = f(defocus)
            f = interp1d(z4t, fl_defocus_lens, kind='cubic')
            lens_fl = f(z4x)
            proper.prop_lens(wavefront, lens_fl)
            if use_errors != 0:
                proper.prop_errormap(
                    wavefront,
                    map_dir +
                    'wfirst_phaseb_DEFOCUSLENS1_phase_error_V1.0.fits',
                    WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_lens / 2.0)

    proper.prop_propagate(wavefront, d_lens_fold4, 'FOLD_4')
    if use_errors != 0:
        proper.prop_errormap(wavefront,
                             map_dir +
                             'wfirst_phaseb_FOLD4_phase_error_V1.1.fits',
                             WAVEFRONT=True)
    if use_aperture != 0:
        proper.prop_circular_aperture(wavefront, diam_fold4 / 2.0)

    if defocus != 0 or use_defocus_lens != 0:
        if np.abs(defocus) <= 4:
            proper.prop_propagate(wavefront,
                                  d_fold4_image,
                                  'IMAGE',
                                  TO_PLANE=True)
        else:
            proper.prop_propagate(wavefront, d_fold4_image, 'IMAGE')
    else:
        proper.prop_propagate(wavefront, d_fold4_image, 'IMAGE')

    (wavefront, sampling_m) = proper.prop_end(wavefront, NOABS=True)

    if final_sampling_lam0 != 0 or final_sampling_m != 0:
        if final_sampling_m != 0:
            mag = sampling_m / final_sampling_m
            sampling_m = final_sampling_m
        else:
            mag = (float(pupil_diam_pix) /
                   n) / final_sampling_lam0 * (lambda_m / lambda0_m)
            sampling_m = sampling_m / mag
        wavefront = proper.prop_magnify(wavefront,
                                        mag,
                                        output_dim,
                                        AMP_CONSERVE=True)
    else:
        wavefront = trim(wavefront, output_dim)

    return wavefront, sampling_m
Beispiel #14
0
def propagate_one(wf,
                  mode='RAVC',
                  phase_screen=None,
                  amp_screen=None,
                  tiptilt=None,
                  apo_misalign=None,
                  ls_misalign=None,
                  fp_offsets=None,
                  ngrid=1024,
                  npupil=285,
                  vc_chrom_leak=2e-3,
                  add_cl_det=False,
                  tag=None,
                  onaxis=True,
                  savefits=False,
                  verbose=False,
                  **conf):
    """
    Propagate one single wavefront.
    An off-axis PSF can be obtained by switching onaxis to False,
    thereby decentering the focal plane mask (if any).
    """

    if verbose == True:
        print('Create single %s-axis PSF' % {True: 'on', False: 'off'}[onaxis])

    # update conf
    conf.update(mode=mode,
                ngrid=ngrid,
                npupil=npupil,
                vc_chrom_leak=vc_chrom_leak,
                add_cl_det=add_cl_det,
                tag=tag,
                onaxis=onaxis)

    # keep a copy of the input wavefront
    wf1 = deepcopy(wf)

    # apply wavefront errors (SCAO residuals, NCPA, Talbot effect, ...)
    # and apodization (RAP, APP)
    wf1 = add_errors(wf1,
                     phase_screen=phase_screen,
                     amp_screen=amp_screen,
                     tiptilt=tiptilt,
                     apo_misalign=apo_misalign,
                     verbose=verbose,
                     **conf)

    # imaging a point source
    def point_source(wf1, verbose, conf):
        if onaxis == True:
            if add_cl_det is True and 'VC' in mode:  # add chromatic leakage (vortex only)
                cl = deepcopy(wf1)
                cl._wfarr = np.flip(cl._wfarr)  # 2 FFTs
                cl = lyot_stop(cl,
                               ls_misalign=ls_misalign,
                               verbose=verbose,
                               **conf)
                chrom_leak = cl._wfarr * np.sqrt(vc_chrom_leak)
            else:
                chrom_leak = 0
            wf1 = fp_mask(wf1, verbose=verbose,
                          **conf)  # focal-plane mask (onaxis only)
            wf1 = lyot_stop(wf1,
                            ls_misalign=ls_misalign,
                            verbose=verbose,
                            **conf)
            wf1._wfarr += chrom_leak
        else:
            wf1._wfarr = np.flip(wf1._wfarr)  # 2 FFTs
            wf1 = lyot_stop(wf1,
                            ls_misalign=ls_misalign,
                            verbose=verbose,
                            **conf)
        return detector(wf1, verbose=verbose, **conf)

    # imaging a point source
    if fp_offsets is None:
        psf = point_source(wf1, verbose, conf)
    # imaging a finite size star
    else:
        psf = 0
        for offset in fp_offsets:
            point = deepcopy(wf1)
            proper.prop_zernikes(point, [2, 3], np.array(offset, ndmin=1))
            psf += point_source(point, False, conf)
        psf /= len(fp_offsets)

    # save psf as fits file
    if savefits == True:
        tag = '' if tag is None else '%s_' % tag
        name = '%s%s_PSF' % (tag, {True: 'onaxis', False: 'offaxis'}[onaxis])
        save2fits(psf, name, **conf)

    return psf
Beispiel #15
0
def telescope(
    wavelength,
    gridsize,
    PASSVALUE={
        'prefix': 'prova',
        'path': os.path.abspath(os.path.join(__file__, os.pardir)),
        'charge': 0,
        'CAL': 0,
        'diam': 37.,
        'spiders_width': 0.60,
        'spiders_angle': [0., 60., 120.],
        'beam_ratio': 0.25,
        'f_lens': 658.6,
        'npupil': 243,
        'r_obstr': 0.3,
        'pupil_file': 0,
        'phase_apodizer_file': 0,
        'amplitude_apodizer_file': 0,
        'TILT': [0., 0.],
        'LS': False,
        'RAVC': False,
        'LS_phase_apodizer_file': 0,
        'LS_amplitude_apodizer_file': 0,
        'LS_parameters': [0.0, 0.0, 0.0],
        'atm_screen': 0,
        'missing_segments_number': 0,
        'apodizer_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        'LS_misalignment': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        'Island_Piston': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        'NCPA': 0,
        'Debug_print': False,
        'Debug': False
    }):

    ## call all the vues passed via passvalue
    prefix = PASSVALUE['prefix']
    path = PASSVALUE['path']
    charge = PASSVALUE['charge']
    CAL = PASSVALUE['CAL']
    diam = PASSVALUE['diam']
    spiders_width = PASSVALUE['spiders_width']
    spiders_angle = PASSVALUE['spiders_angle']
    beam_ratio = PASSVALUE['beam_ratio']
    f_lens = PASSVALUE['f_lens']
    npupil = PASSVALUE['npupil']
    r_obstr = PASSVALUE['r_obstr']
    pupil_file = PASSVALUE['pupil_file']
    phase_apodizer_file = PASSVALUE['phase_apodizer_file']
    amplitude_apodizer_file = PASSVALUE['amplitude_apodizer_file']
    TILT = PASSVALUE['TILT']
    LS = PASSVALUE['LS']
    RAVC = PASSVALUE['RAVC']
    LS_phase_apodizer_file = PASSVALUE['LS_phase_apodizer_file']
    LS_amplitude_apodizer_file = PASSVALUE['LS_amplitude_apodizer_file']
    LS_parameters = PASSVALUE['LS_parameters']
    atm_screen = PASSVALUE['atm_screen']
    missing_segments_number = PASSVALUE['missing_segments_number']
    apodizer_misalignment = PASSVALUE['apodizer_misalignment']
    LS_misalignment = PASSVALUE['LS_misalignment']
    Island_Piston = PASSVALUE['Island_Piston']
    NCPA = PASSVALUE['NCPA']
    Debug_print = PASSVALUE['Debug_print']
    Debug = PASSVALUE['Debug']

    TILT = np.array(TILT)
    apodizer_misalignment = np.array(apodizer_misalignment)
    LS_misalignment = np.array(LS_misalignment)
    Island_Piston = np.array(Island_Piston)

    ## call the size of the grid
    n = int(gridsize)

    wfo = proper.prop_begin(diam, wavelength, gridsize,
                            beam_ratio)  # define the simualtion pupil
    lamda = proper.prop_get_wavelength(
        wfo)  #save the wavelength value [m] into lamda

    if (Debug_print == True):
        print("lambda: ", lamda)

    pupil(wfo, CAL, npupil, diam, r_obstr, spiders_width, spiders_angle,
          pupil_file, missing_segments_number, Debug, Debug_print)

    if (Debug == True):
        fits.writeto(
            path + prefix + '_pupil_pre_define.fits',
            proper.prop_get_amplitude(wfo)[int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50),
                                           int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50)],
            overwrite=True)

    proper.prop_define_entrance(wfo)  #define the entrance wavefront

    #wfo.wfarr *= 1./np.amax(wfo._wfarr) # max(amplitude)=1

    if (isinstance(atm_screen, (list, tuple, np.ndarray)) == True) and (
            atm_screen.ndim >= 2):  # when the atmosphere is present
        print('atmosphere')
        atmosphere(wfo, npupil, atm_screen, Debug_print, Debug)

    if (isinstance(NCPA, (list, tuple, np.ndarray))
            == True) and (NCPA.ndim >= 2):  # when the atmosphere is present
        NCPA_application(wfo, npupil, NCPA, path, Debug_print, Debug)

    if (RAVC
            == True) or (isinstance(phase_apodizer_file,
                                    (list, tuple, np.ndarray))
                         == True) or (isinstance(amplitude_apodizer_file,
                                                 (list, tuple, np.ndarray))
                                      == True):  # when tha apodizer is present
        apodization(wfo, r_obstr, npupil, RAVC, phase_apodizer_file,
                    amplitude_apodizer_file, apodizer_misalignment,
                    Debug_print, Debug)

    if (all(v == 0
            for v in Island_Piston) == False):  # when the piston is present
        island_effect_piston(wfo, npupil, Island_Piston, path, Debug_print,
                             Debug)

    if (TILT.any != 0.):  # when tip/tilt
        if (Debug_print == True):
            print("TILT: ", TILT)
            print("lamda: ", lamda)
        tiptilt = (np.multiply(
            TILT, lamda
        )) / 4  # translate the tip/tilt from lambda/D into RMS phase errors
        proper.prop_zernikes(wfo, [2, 3], tiptilt)  # 2-->xtilt, 3-->ytilt

    if (Debug == True):
        if CAL == 1:
            fits.writeto(path + prefix + '_pupil_amplitude_CAL1.fits',
                         proper.prop_get_amplitude(wfo)
                         [int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                          int(npupil / 2 + 50),
                          int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                          int(npupil / 2 + 50)],
                         overwrite=True)
            fits.writeto(
                path + prefix + '_pupil_phase_CAL1.fits',
                proper.prop_get_phase(wfo)[int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50),
                                           int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50)],
                overwrite=True)
        else:
            fits.writeto(
                path + prefix + '_pupil_amplitude_CAL0_RA' + str(int(RAVC)) +
                '_charge' + str(charge) + '_ATM' + str(
                    int(
                        isinstance(atm_screen, (list, tuple,
                                                np.ndarray)) == True)) +
                '.fits',
                proper.prop_get_amplitude(
                    wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                         int(npupil / 2 + 50),
                         int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                         int(npupil / 2 + 50)],
                overwrite=True)
            fits.writeto(
                path + prefix + '_pupil_phase_CAL0_RA' + str(int(RAVC)) +
                '_charge' + str(charge) + '_ATM' + str(
                    int(
                        isinstance(atm_screen, (list, tuple,
                                                np.ndarray)) == True)) +
                '.fits',
                proper.prop_get_phase(wfo)[int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50),
                                           int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50)],
                overwrite=True)

    proper.prop_propagate(wfo, f_lens, 'inizio')  # propagate wavefront

    proper.prop_lens(wfo, f_lens,
                     'focusing lens vortex')  # propagate through a lens
    proper.prop_propagate(wfo, f_lens, 'VC')  # propagate wavefront

    vortex(wfo, CAL, charge, f_lens, path, Debug_print)

    if (Debug == True):
        if CAL == 1:
            fits.writeto(path + prefix + '_afterVortex_CAL1.fits',
                         proper.prop_get_amplitude(wfo)
                         [int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                          int(npupil / 2 + 50),
                          int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                          int(npupil / 2 + 50)],
                         overwrite=True)
            fits.writeto(
                path + prefix + '_afterVortex_CAL1_phase.fits',
                proper.prop_get_phase(wfo)[int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50),
                                           int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50)],
                overwrite=True)
        else:
            print(
                'ATM: ',
                str(
                    int(
                        isinstance(atm_screen, (list, tuple,
                                                np.ndarray)) == True)))
            if ((((int(
                    isinstance(atm_screen, (list, tuple,
                                            np.ndarray)) == True)))) == 1):
                print('atm_screen: ', atm_screen.shape)
                print(
                    'ATM: ',
                    int(
                        isinstance(atm_screen, (list, tuple,
                                                np.ndarray)) == True))
            fits.writeto(
                path + prefix + '_afterVortex_CAL0_RA' + str(int(RAVC)) +
                '_charge' + str(charge) + '_ATM' + str(
                    int(
                        isinstance(atm_screen, (list, tuple,
                                                np.ndarray)) == True)) +
                '.fits',
                proper.prop_get_amplitude(
                    wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                         int(npupil / 2 + 50),
                         int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                         int(npupil / 2 + 50)],
                overwrite=True)
            fits.writeto(
                path + prefix + '_afterVortex_phase_CAL0_RA' + str(int(RAVC)) +
                '_charge' + str(charge) + '_ATM' + str(
                    int(
                        isinstance(atm_screen, (list, tuple,
                                                np.ndarray)) == True)) +
                '.fits',
                proper.prop_get_phase(wfo)[int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50),
                                           int(n / 2) -
                                           int(npupil / 2 + 50):int(n / 2) +
                                           int(npupil / 2 + 50)],
                overwrite=True)

    proper.prop_propagate(wfo, f_lens,
                          'Lyot Collimetor')  # propagate wavefront

    proper.prop_lens(wfo, f_lens,
                     'Lyot Collimetor')  # propagate wavefront through  a lens
    proper.prop_propagate(wfo, f_lens, 'Lyot Stop')  # propagate wavefront

    if (Debug == True):
        if CAL == 1:
            fits.writeto(path + prefix + '_beforeLS_CAL1.fits',
                         proper.prop_get_amplitude(wfo)
                         [int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                          int(npupil / 2 + 50),
                          int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                          int(npupil / 2 + 50)],
                         overwrite=True)
        else:
            fits.writeto(
                path + prefix + '_beforeLS_CAL0_charge' + str(charge) +
                '_ATM' + str(
                    int(
                        isinstance(atm_screen, (list, tuple,
                                                np.ndarray)) == True)) +
                '.fits',
                proper.prop_get_amplitude(
                    wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                         int(npupil / 2 + 50),
                         int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                         int(npupil / 2 + 50)],
                overwrite=True)

    lyotstop(wfo, diam, r_obstr, npupil, RAVC, LS, LS_parameters,
             spiders_angle, LS_phase_apodizer_file, LS_amplitude_apodizer_file,
             LS_misalignment, path, Debug_print, Debug)

    if (Debug == True):
        if CAL == 1:
            fits.writeto(path + prefix + '_afterLS_CAL1.fits',
                         proper.prop_get_amplitude(wfo)
                         [int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                          int(npupil / 2 + 50),
                          int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                          int(npupil / 2 + 50)],
                         overwrite=True)
        else:
            fits.writeto(
                path + prefix + '_afterLS_CAL0_charge' + str(charge) + '_LS' +
                str(int(LS)) + '_RA' + str(int(RAVC)) + '_ATM' + str(
                    int(
                        isinstance(atm_screen, (list, tuple,
                                                np.ndarray)) == True)) +
                '.fits',
                proper.prop_get_amplitude(
                    wfo)[int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                         int(npupil / 2 + 50),
                         int(n / 2) - int(npupil / 2 + 50):int(n / 2) +
                         int(npupil / 2 + 50)],
                overwrite=True)

    proper.prop_propagate(wfo, f_lens)  # propagate wavefront

    proper.prop_lens(wfo, f_lens)  # propagate wavefront through a lens
    proper.prop_propagate(wfo, f_lens)  # propagate wavefront

    (wfo, sampling) = proper.prop_end(
        wfo, NOABS=True
    )  # conclude the simulation --> noabs= the wavefront array will be complex

    return (wfo, sampling)  # return the wavefront
Beispiel #16
0
def propagate_one(wf,
                  phase_screen=None,
                  amp_screen=None,
                  tiptilt=None,
                  misalign=[0, 0, 0, 0, 0, 0],
                  ngrid=1024,
                  npupil=285,
                  vc_chrom_leak=2e-3,
                  add_cl_det=False,
                  fp_offsets=None,
                  tag=None,
                  onaxis=True,
                  savefits=False,
                  verbose=False,
                  **conf):
    """ 
    Propagate one single wavefront.
    An off-axis PSF can be obtained by switching onaxis to False,
    thereby decentering the focal plane mask (if any).
    """

    if verbose == True:
        print('Create single %s-axis PSF' % {True: 'on', False: 'off'}[onaxis])

    # update conf
    conf.update(ngrid=ngrid, npupil=npupil, vc_chrom_leak=vc_chrom_leak, \
            add_cl_det=add_cl_det, tag=tag, onaxis=onaxis)

    # keep a copy of the input wavefront
    wf1 = deepcopy(wf)

    # apply phase screen (scao residuals, ncpa, petal piston)
    wf1 = add_errors(wf1, phase_screen=phase_screen, amp_screen=amp_screen, \
        tiptilt=tiptilt, misalign=misalign, verbose=verbose, **conf)

    # imaging a point source
    def point_source(wf1, verbose, conf):
        if onaxis == True:  # focal-plane mask, only in 'on-axis' configuration
            if add_cl_det is True:
                cl = deepcopy(wf1)
                cl._wfarr = np.flip(cl._wfarr)  # 2 FFTs
                cl = lyot_stop(cl, verbose=verbose, **conf)
            wf1 = fp_mask(wf1, verbose=verbose, **conf)
            wf1 = lyot_stop(wf1, verbose=verbose, **conf)
            if add_cl_det is True:
                wf1._wfarr += cl._wfarr * np.sqrt(vc_chrom_leak)
        else:
            wf1._wfarr = np.flip(wf1._wfarr)  # 2 FFTs
            wf1 = lyot_stop(wf1, verbose=verbose, **conf)
        return detector(wf1, verbose=verbose, **conf)

    # imaging a point source
    if fp_offsets is None:
        psf = point_source(wf1, verbose, conf)
    # imaging a finite size star
    else:
        psf = 0
        for offset in fp_offsets:
            point = deepcopy(wf1)
            proper.prop_zernikes(point, [2, 3], np.array(offset, ndmin=1))
            psf += point_source(point, False, conf)
        psf /= len(fp_offsets)

    # save psf as fits file
    if savefits == True:
        tag = '' if tag is None else '%s_' % tag
        name = '%s%s_PSF' % (tag, {True: 'onaxis', False: 'offaxis'}[onaxis])
        save2fits(psf, name, **conf)

    return psf
Beispiel #17
0
#--PROPER initialization
pupil_ratio = 1  # beam diameter fraction
wl_dummy = 1e-6  # dummy value needed to initialize wavelength in PROPER (meters)
wavefront = proper.prop_begin(mp.dm1.compact.NdmPad * mp.dm1.dx, wl_dummy,
                              mp.dm1.compact.NdmPad, pupil_ratio)
# PSD Error Map Generation using PROPER

#amp = 9.6e-19; b = 4.0;
#c = 3.0;
#errorMap = proper.prop_psd_errormap( wavefront, amp, b, c, TPF=True )
#errorMap = errorMap*testArea;

zSet = np.arange(3, 12)
zCoef = 1e-9 * np.random.rand(len(zSet))
errorMap = proper.prop_zernikes(wavefront, zSet, zCoef)
errorMap = errorMap * testArea

if (flagPlotDebug):
    plt.figure(1)
    plt.imshow(testArea)
    plt.colorbar()
    plt.pause(0.1)
    plt.figure(2)
    plt.imshow(errorMap)
    plt.colorbar()
    plt.pause(0.1)

#--Fit the surface
Vout = falco.dm.fit_surf_to_act(mp.dm1, errorMap) / mp.dm1.VtoH
mp.dm1.V = Vout