Example #1
0
    def initialize_proper(self):
        # Initialize the Wavefront in Proper
        for iw, wavelength in enumerate(self.wsamples):
            # Scale beam ratio by wavelength for polychromatic imaging
            # see Proper manual pg 37
            # Proper is devised such that you get a Nyquist sampled image in the focal plane. If you optical system
            #  goes directly from pupil plane to focal plane, then you need to scale the beam ratio such that sampling
            #  in the focal plane is constant. You can check this with check_sampling, which returns the value from
            #  prop_get_sampling. If the optical system does not go directly from pupil-to-object plane at each optical
            #  plane, the beam ratio does not need to be scaled by wavelength, because of some optics wizardry that
            #  I don't fully understand. KD 2019
            if sp.focused_sys:
                beam_ratio = sp.beam_ratio
            else:
                beam_ratio = sp.beam_ratio * ap.wvl_range[0] / wavelength
                # dprint(f"iw={iw}, w={w}, beam ratio is {self.beam_ratios[iw]}")

            # Initialize the wavefront at entrance pupil
            wfp = proper.prop_begin(tp.entrance_d, wavelength, sp.grid_size,
                                    beam_ratio)

            wfs = [wfp]
            names = ['star']

            # Initiate wavefronts for companion(s)
            if ap.companion:
                for ix in range(len(ap.contrast)):
                    wfc = proper.prop_begin(tp.entrance_d, wavelength,
                                            sp.grid_size, beam_ratio)
                    wfs.append(wfc)
                    names.append('companion_%i' % ix)

            for io, (name, wf) in enumerate(zip(names, wfs)):
                self.wf_collection[iw, io] = Wavefront(wf, wavelength, name,
                                                       beam_ratio, iw, io)
Example #2
0
    def initialize_proper(self, set_up_beam=False):
        """

        Initialize the Wavefronts in Proper

        :param set_up_beam: bool applies prop_circular_aperture and prop_define_entrance before spectral scaling
            instead of during prescription wher it normally goes

        returns wf_colllection attribute array of wavefronts
        """
        for iw, wavelength in enumerate(self.wsamples):
            # Scale beam ratio by wavelength for polychromatic imaging
            # see Proper manual pg 37
            # Proper is devised such that you get a Nyquist sampled image in the focal plane. If you optical system
            #  goes directly from pupil plane to focal plane, then you need to scale the beam ratio such that sampling
            #  in the focal plane is constant. You can check this with check_sampling, which returns the value from
            #  prop_get_sampling. If the optical system does not go directly from pupil-to-object plane at each optical
            #  plane, the beam ratio does not need to be scaled by wavelength, because of some optics wizardry that
            #  I don't fully understand. KD 2019
            if sp.focused_sys:
                beam_ratio = sp.beam_ratio
            else:
                beam_ratio = sp.beam_ratio * ap.wvl_range[0] / wavelength
                # dprint(f"iw={iw}, w={w}, beam ratio is {self.beam_ratios[iw]}")

            # Initialize the wavefront at entrance pupil
            wfp = proper.prop_begin(tp.entrance_d, wavelength, sp.grid_size, beam_ratio)
            if set_up_beam:
                proper.prop_circular_aperture(wfp, radius = tp.entrance_d / 2)
                proper.prop_define_entrance(wfp)  # normalizes the intensity
            wfp.wfarr = np.multiply(wfp.wfarr, np.sqrt(self.spectra[0][iw]), out=wfp.wfarr, casting='unsafe')

            wfs = [wfp]
            names = ['star']

            # Initiate wavefronts for companion(s)
            if ap.companion:
                for ix in range(len(ap.contrast)):
                    wfc = proper.prop_begin(tp.entrance_d, wavelength, sp.grid_size, beam_ratio)
                    if set_up_beam:
                        proper.prop_circular_aperture(wfc, radius=tp.entrance_d / 2)
                        proper.prop_define_entrance(wfc)  # normalizes the intensity
                    wfc.wfarr = np.multiply(wfc.wfarr, np.sqrt(self.spectra[ix][iw]), out=wfc.wfarr, casting='unsafe')
                    wfs.append(wfc)
                    names.append('companion_%i' % ix)

            for io, (name, wf) in enumerate(zip(names, wfs)):
                self.wf_collection[iw, io] = Wavefront(wf, wavelength, name, beam_ratio, iw, io)
Example #3
0
def get_wf(wavelength, gridsize, PASSVALUE={}):
    diam = PASSVALUE.get('diam', 0.3)  # telescope diameter in meters
    m1_fl = PASSVALUE.get('m1_fl', 0.5717255)  # primary focal length (m)
    #beam_ratio     = PASSVALUE.get('beam_ratio',0.99)             # initial beam width/grid width
    tilt_x = PASSVALUE.get('tilt_x', 0.)  # Tilt angle along x (arc seconds)
    tilt_y = PASSVALUE.get('tilt_y', 0.)  # Tilt angle along y (arc seconds)

    beam_ratio = 0.99
    # Define the wavefront
    wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio)

    # Point off-axis
    prop_tilt(wfo, tilt_x, tilt_y)

    # Input aperture
    proper.prop_circular_aperture(wfo, diam / 2.)

    # Define entrance
    proper.prop_define_entrance(wfo)

    proper.prop_lens(wfo, m1_fl, "primary")

    opd1_func = PASSVALUE['opd_func']

    def build_m1_opd():
        return gen_opdmap(opd1_func, proper.prop_get_gridsize(wfo),
                          proper.prop_get_sampling(wfo))

    wfo.wfarr *= build_phase_map(
        wfo, load_cacheable_grid(opd1_func.__name__, wfo, build_m1_opd, False))

    wf = proper.prop_get_wavefront(wfo)

    return wf
Example #4
0
def generate_maps2():
    import random
    print 'Generating optic aberration maps using Proper'
    wfo = proper.prop_begin(tp.diam, 1., tp.grid_size, tp.beam_ratio)
    # rms_error = 5e-6#500.e-9       # RMS wavefront error in meters
    # c_freq = 0.005             # correlation frequency (cycles/meter)
    # high_power = 1.          # high frewquency falloff (r^-high_power)
    rms_error = 2.5e-3  # 500.e-9       # RMS wavefront error in meters
    c_freq = 0.000005  # correlation frequency (cycles/meter)
    high_power = 1.  # high frewquency falloff (r^-high_power)

    # tp.abertime = [0.5,2,10] # characteristic time for each aberation in secs
    tp.abertime = [
        100
    ]  # if beyond numframes then abertime will be auto set to duration of simulation
    abercubes = []
    aber_cube = np.zeros((ap.numframes, tp.grid_size, tp.grid_size))
    print 'here'

    perms = np.random.rand(ap.numframes, tp.grid_size, tp.grid_size) - 0.5
    perms *= 1e-7

    phase = 2 * np.pi * np.random.uniform(size=(tp.grid_size,
                                                tp.grid_size)) - np.pi
    aber_cube[0] = proper.prop_psd_errormap(
        wfo,
        rms_error,
        c_freq,
        high_power,
        MAP="prim_map",
        PHASE_HISTORY=phase)  # FILE=td.aberdir+'/telzPrimary_Map.fits')
    print 'lol'
    # quicklook_im(aber_cube[0], logAmp=False)

    for a in range(1, ap.numframes):
        # quicklook_im(aber_cube[a], logAmp=False)
        perms = np.random.rand(tp.grid_size, tp.grid_size) - 0.5
        perms *= 0.05
        phase += perms
        # print phase[:5,:5]
        aber_cube[a] = proper.prop_psd_errormap(wfo,
                                                rms_error,
                                                c_freq,
                                                high_power,
                                                MAP="prim_map",
                                                PHASE_HISTORY=phase)

    plt.plot(aber_cube[:, 20, 20])
    plt.show()

    for a in range(0, ap.numframes - 1, 100):
        quicklook_im(aber_cube[a], logAmp=False)

    if not os.path.isdir(iop.aberdir):
        os.mkdir(iop.aberdir)
    for f in range(0, ap.numframes, 1):
        # print 'saving frame #', f
        if f % 100 == 0: misc.progressBar(value=f, endvalue=ap.numframes)
        rawImageIO.saveFITS(aber_cube[f],
                            '%stelz%f.fits' % (iop.aberdir, f * cp.frame_time))
Example #5
0
def psd_spatial_zernike(cube_name, pup, zpols, nzer, ncube):
    spsd_name = cube_name[:-5] + '_%s' + '_%s.fits'%nzer
    try:
        spsd = fits.getdata(spsd_name%'spsd')
        print('getdata ' + spsd_name%'spsd')
    except FileNotFoundError:
        print('writeto ' + spsd_name%'spsd')
        cube = fits.getdata(cube_name)[:ncube]
        nimg = cube.shape[-1]
        pup = resize_cube(pup, nimg)
        zpols = zpols[:ncube,:nzer]
        wf = proper.prop_begin(1, 1, nimg, 1) # initial wavefront
        LSFs = np.empty((nzer, ncube, nimg, nimg))
        HSFs = np.empty((nzer, ncube, nimg, nimg))
        HSFs_rms = []
        for z in np.arange(nzer) + 1:
            verbose = True if z == 1 else False
            LSF, HSF = multiCPU(remove_zernike, posargs=[deepcopy(wf), pup],
                        posvars=[cube, zpols[:,:z]], case='remove zernike', 
                        nout=2, verbose=verbose)
            LSFs[z-1], HSFs[z-1] = LSF, HSF
            HSFs_rms.append(get_rms(HSF, verbose=verbose))
            print(z, end=', ')
        spsd = [rms**2 for rms in HSFs_rms]
        spsd = [spsd[0]] + spsd
        fits.writeto(spsd_name%'spsd', np.float32(spsd))
        fits.writeto(spsd_name%'LSFs', np.float32(LSFs))
        fits.writeto(spsd_name%'HSFs', np.float32(HSFs))
    return spsd
Example #6
0
def piston_refbeam(wf, iter, w):
    beam_ratio = 0.7 * tp.band[0] / w * 1e-9
    wf_ref = proper.prop_begin(tp.diam, w, tp.grid_size, beam_ratio)
    proper.prop_define_entrance(wf_ref)
    phase_mod = iter % 4 * w / 4  #np.pi/2
    obj_map = np.ones((tp.grid_size, tp.grid_size)) * phase_mod
    proper.prop_add_phase(wf_ref, obj_map)
    wf_ref.wfarr = wf.wfarr + wf_ref.wfarr
    Imap = proper.prop_shift_center(np.abs(wf_ref.wfarr)**2)
    return Imap
Example #7
0
def falco_gen_annular_FPM(pixresFPM,
                          rhoInner,
                          rhoOuter,
                          FPMampFac,
                          centering,
                          rot180=False):
    dxiUL = 1.0 / pixresFPM  # lambda_c/D per pixel. "UL" for unitless

    if np.isinf(rhoOuter):
        if centering == "interpixel":
            # number of points across the inner diameter of the FPM.
            Narray = utils.ceil_even((2 * rhoInner / dxiUL))
        else:
            # number of points across the inner diameter of the FPM. Another half pixel added for pixel-centered masks.
            Narray = utils.ceil_even(2 * (rhoInner / dxiUL + 0.5))
    else:
        if centering == "interpixel":
            # number of points across the outer diameter of the FPM.
            Narray = utils.ceil_even(2 * rhoOuter / dxiUL)
        else:
            # number of points across the outer diameter of the FPM. Another half pixel added for pixel-centered masks.
            Narray = utils.ceil_even(2 * (rhoOuter / dxiUL + 0.5))

    xshift = 0  # translation in x of FPM (in lambda_c/D)
    yshift = 0  # translation in y of FPM (in lambda_c/D)

    Darray = Narray * dxiUL  # width of array in lambda_c/D
    diam = Darray
    wl_dummy = 1e-6  # wavelength (m); Dummy value--no propagation here, so not used.

    if centering == "interpixel":
        cshift = -diam / 2 / Narray
    elif rot180:
        cshift = -diam / Narray
    else:
        cshift = 0

    wf = proper.prop_begin(diam, wl_dummy, Narray, 1.0)

    if not np.isinf(rhoOuter):
        # Outer opaque ring of FPM
        cx_OD = 0 + cshift + xshift
        cy_OD = 0 + cshift + yshift
        proper.prop_circular_aperture(wf, rhoOuter, cx_OD, cy_OD)

    # Inner spot of FPM (Amplitude transmission can be nonzero)
    ra_ID = (rhoInner)
    cx_ID = 0 + cshift + xshift
    cy_ID = 0 + cshift + yshift
    innerSpot = proper.prop_ellipse(
        wf, rhoInner, rhoInner, cx_ID, cy_ID,
        DARK=True) * (1 - FPMampFac) + FPMampFac

    mask = np.fft.ifftshift(np.abs(wf.wfarr))  # undo PROPER's fftshift
    return mask * innerSpot  # Include the inner FPM spot
Example #8
0
def _init_proper(Dmask, dx, centering):
    assert (centering in ("pixel", "interpixel"))

    # number of points across output array:
    if centering == "pixel":
        # Sometimes requires two more pixels when pixel centered. Same size as width when interpixel centered.
        Narray = 2 * np.ceil(0.5 * (Dmask / dx + 0.5))
    else:
        Narray = 2 * np.ceil(
            0.5 *
            (Dmask / dx + 0.0))  # Same size as width when interpixel centered.

    wl_dummy = 1e-6  # % wavelength (m); Dummy value--no propagation here, so not used.
    return proper.prop_begin(Narray * dx, wl_dummy, Narray, 1.0)
Example #9
0
def gen_norm_zern_maps(Nbeam, centering, indsZnoll):
    """
    Compute normalized 2-D maps of the specified Zernike modes.

    Parameters
    ----------
    Nbeam : int
        The number of pixels across the circle over which to compute the Zernike
    centering : str
        The centering of the array. Either 'pixel' or 'interpixel'.
    indsZnoll : numpy ndarray
        The iterable set of Zernike modes for which to compute maps.
    

    Returns
    -------
    ZmapCube : numpy ndarray
        A datacube in which each slice is a normalized Zernike mode.
    """
    if centering not in _VALID_CENTERING:
        raise ValueError(_CENTERING_ERR)
        
    # If a scalar integer, convert indsZnoll to an array so that it is indexable
    if not (type(indsZnoll) == np.ndarray):
        indsZnoll = np.array([indsZnoll])

    # Set array size as minimum width to contain the beam.
    if 'interpixel' in centering:
        Narray = falco.util.ceil_even(Nbeam)
    else:
        Narray = falco.util.ceil_even(Nbeam+1)

    # PROPER setup values
    Dbeam = 1.  # Diameter of aperture, normalized to itself
    wl = 1e-6  # wavelength (m); Dummy value--no propagation here, so not used.
    beam_diam_frac = Narray/Nbeam

    # Initialize wavefront structure in PROPER
    bm = proper.prop_begin(Dbeam, wl, Narray, beam_diam_frac)

    # Use modified PROPER function to generate the Zernike datacube
    Nzern = indsZnoll.size
    ZmapCube = np.zeros((Narray, Narray, Nzern))
    
    bm.centering = centering
    for iz in range(Nzern):
        ZmapCube[:, :, iz] = propcustom_zernikes(bm, np.array([indsZnoll[iz]]),
                np.array([1.]), NO_APPLY=True, CENTERING=centering)
        
    return ZmapCube
Example #10
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)
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)
def prescription_quad_tiltafter(wavelength, gridsize, 
                          PASSVALUE = {'diam': 0.3, 
                                       'm1_fl': 0.5717255, 
                                       'beam_ratio': 0.2, 
                                       'tilt_x': 0.0,
                                       'tilt_y': 0.0
                                      }):
    diam           = PASSVALUE['diam']           # telescope diameter in meters
    m1_fl          = PASSVALUE['m1_fl']          # primary focal length (m)
    beam_ratio     = PASSVALUE['beam_ratio']     # initial beam width/grid width
        
    tilt_x         = PASSVALUE['tilt_x']         # Tilt angle along x (arc seconds)
    tilt_y         = PASSVALUE['tilt_y']         # Tilt angle along y (arc seconds)
    
    # Define the wavefront
    wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio)
        
    # Input aperture
    proper.prop_circular_aperture(wfo, diam/2)
    
    # Define entrance
    proper.prop_define_entrance(wfo)

    # Primary mirror (treat as quadratic lens)
    proper.prop_lens(wfo, m1_fl, "primary")

    # Point off-axis
    prop_tilt(wfo, tilt_x, tilt_y)

    # Focus
    proper.prop_propagate(wfo, m1_fl, "focus", TO_PLANE=True)

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

    return (wfo, sampling)
Example #13
0
def gen_surf_from_act(dm, dx, N):
    """
    Function to compute the surface shape of a deformable mirror. Uses PROPER.

    Parameters
    ----------
    dm : ModelParameters
        Structure containing parameter values for the DM
    dx : float
        Pixel width [meters] at the DM plane
    N : int
        Number of points across the array to return at the DM plane

    Returns
    -------
    DMsurf : array_like
        2-D surface map of the DM

    """
    check.real_positive_scalar(dx, 'dx', TypeError)
    check.positive_scalar_integer(N, 'N', TypeError)
    # if type(dm) is not falco.config.Object:
    #     raise TypeError('Input "dm" must be of type falco.config.Object')

    # Set the order of operations
    flagXYZ = True
    if(hasattr(dm, 'flagZYX')):
        if(dm.flagZYX):
            flagXYZ = False

    # Adjust the centering of the output DM surface. The shift needs to be in
    # units of actuators, not meters, for prop_dm.m.
    Darray = dm.NdmPad*dm.dx
    Narray = dm.NdmPad
    if dm.centering == 'interpixel':
        cshift = -Darray/2./Narray/dm.dm_spacing
    elif dm.centering == 'pixel':
        cshift = 0

    pupil_ratio = 1  # beam diameter fraction
    wl_dummy = 1e-6  # dummy value needed to initialize PROPER (meters)

    bm = proper.prop_begin(N*dx, wl_dummy, N, pupil_ratio)

    # Apply various constraints to DM commands
    dm = enforce_constraints(dm)

    # Quantization of DM actuation steps based on least significant bit of the
    # DAC (digital-analog converter). In height, so called HminStep
    # If HminStep (minimum step in H) is defined, then quantize the DM voltages
    if(hasattr(dm, 'HminStep')):
        if not(hasattr(dm, 'HminStepMethod')):
            dm.HminStepMethod = 'round'
        # Discretize/Quantize the DM voltages (creates dm.Vquantized)
        dm = discretize_surf(dm, dm.HminStepMethod)
        heightMap = dm.VtoH*dm.Vquantized
    else:  # Quantization not desired; send raw, continuous voltages
        heightMap = dm.VtoH*dm.V

    if hasattr(dm, 'orientation'):
        if dm.orientation.lower() == 'rot0':
            pass  # no change
        elif dm.orientation.lower() == 'rot90':
            heightMap = np.rot90(heightMap, 1)
        elif dm.orientation.lower() == 'rot180':
            heightMap = np.rot90(heightMap, 2)
        elif dm.orientation.lower() == 'rot270':
            heightMap = np.rot90(heightMap, 3)
        elif dm.orientation.lower() == 'flipxrot0':
            heightMap = np.flipx(heightMap)
        elif dm.orientation.lower() == 'flipxrot90':
            heightMap = np.rot90(np.flipx(heightMap), 1)
        elif dm.orientation.lower() == 'flipxrot180':
            heightMap = np.rot90(np.flipx(heightMap), 2)
        elif dm.orientation.lower() == 'flipxrot270':
            heightMap = np.rot90(np.flipx(heightMap), 3)
        else:
            raise ValueError('invalid value of dm.orientation')

    # Generate the DM surface
    DMsurf = falco.dm.propcustom_dm(bm, heightMap, dm.xc-cshift, dm.yc-cshift,
    dm.dm_spacing, XTILT=dm.xtilt, YTILT=dm.ytilt, ZTILT=dm.zrot, XYZ=flagXYZ,
    inf_sign=dm.inf_sign, inf_fn=dm.inf_fn)

    return DMsurf
def prescription_rc_quad(wavelength, gridsize, PASSVALUE = {}):
    # Assign parameters from PASSVALUE struct or use defaults
    diam           = PASSVALUE.get('diam',0.3)                    # telescope diameter in meters
    m1_fl          = PASSVALUE.get('m1_fl',0.5717255)             # primary focal length (m)
    m1_hole_rad    = PASSVALUE.get('m1_hole_rad',0.035)           # Radius of hole in primary (m)
    m1_m2_sep      = PASSVALUE.get('m1_m2_sep',0.549337630333726) # primary to secondary separation (m)
    m2_fl          = PASSVALUE.get('m2_fl',-0.023378959)          # secondary focal length (m)
    bfl            = PASSVALUE.get('bfl',0.528110658881)          # nominal distance from secondary to focus (m)
    beam_ratio     = PASSVALUE.get('beam_ratio',0.2)              # initial beam width/grid width
    m2_rad         = PASSVALUE.get('m2_rad',0.059)                # Secondary half-diameter (m)
    m2_strut_width = PASSVALUE.get('m2_strut_width',0.01)         # Width of struts supporting M2 (m)
    m2_supports    = PASSVALUE.get('m2_supports',5)               # Number of support structs (assumed equally spaced)
    tilt_x         = PASSVALUE.get('tilt_x',0.)                   # Tilt angle along x (arc seconds)
    tilt_y         = PASSVALUE.get('tilt_y',0.)                   # Tilt angle along y (arc seconds)
    noabs          = PASSVALUE.get('noabs',False)                 # Output complex amplitude?
    use_caching    = PASSVALUE.get('use_caching',False)           # Use cached files if available?
    get_wf         = PASSVALUE.get('get_wf',False)                # Return wavefront

    # Can also specify a opd_func function with signature opd_func(r, phi)
    if 'phase_func' in PASSVALUE:
        print('DEPRECATED setting "phase_func": use "opd_func" instead')
        if 'opd_func' not in PASSVALUE:
            PASSVALUE['opd_func'] = PASSVALUE['phase_func']
    if 'phase_func_sec' in PASSVALUE:
        print('DEPRECATED setting "phase_func_sec": use "opd_func_sec" instead')
        if 'opd_func_sec' not in PASSVALUE:
            PASSVALUE['opd_func_sec'] = PASSVALUE['phase_func_sec']
    
    
    
    def build_m2_obs():
        # Input aperture
        grid = build_prop_circular_aperture(wfo, diam/2)

        # Secondary and structs obscuration
        grid *= build_prop_circular_obscuration(wfo, m2_rad) # secondary mirror obscuration
        # Spider struts/vanes, arranged evenly radiating out from secondary
        strut_length = diam/2 - m2_rad
        strut_step = 360/m2_supports
        strut_centre = m2_rad + strut_length/2
        for i in range(0, m2_supports):
            angle = i*strut_step
            radians = math.radians(angle) 
            xoff = math.cos(radians)*strut_centre
            yoff = math.sin(radians)*strut_centre
            grid *= build_prop_rectangular_obscuration(wfo, m2_strut_width,                                     strut_length,
                                                xoff, yoff,
                                                ROTATION = angle + 90)
        return grid
    
    
    
    
    
    
    # Define the wavefront
    wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio)

    # Point off-axis
    prop_tilt(wfo, tilt_x, tilt_y)
    
    wfo.wfarr *= load_cacheable_grid('m2_obs', wfo, build_m2_obs, use_caching)
    
    # Normalize wavefront
    proper.prop_define_entrance(wfo)
    
    #if get_wf:
      #  wf = proper.prop_get_wavefront(wfo)
     #   print('Got wavefront')
    
    proper.prop_propagate(wfo, m1_m2_sep, "primary")
    
    # Primary mirror
    if 'opd_func' in PASSVALUE:
        opd1_func = PASSVALUE['opd_func']        
        def build_m1_opd():
            return gen_opdmap(opd1_func, proper.prop_get_gridsize(wfo), proper.prop_get_sampling(wfo))
        wfo.wfarr *= build_phase_map(wfo, load_cacheable_grid(opd1_func.__name__, wfo, build_m1_opd, use_caching))
        
    if get_wf:
        wf = proper.prop_get_wavefront(wfo)
        print('Got wavefront')
        
    if 'm1_conic' in PASSVALUE:
        prop_conic(wfo, m1_fl, PASSVALUE['m1_conic'], "conic primary")
    else:
        proper.prop_lens(wfo, m1_fl, "primary")
        
    wfo.wfarr *= build_prop_circular_obscuration(wfo, m1_hole_rad)

    # Secondary mirror
    proper.prop_propagate(wfo, m1_m2_sep, "secondary")
    if 'opd_func_sec' in PASSVALUE:
        opd2_func = PASSVALUE['opd_func_sec']
        def build_m2_opd():
            return gen_opdmap(opd2_func, proper.prop_get_gridsize(wfo), proper.prop_get_sampling(wfo))
        wfo.wfarr *= build_phase_map(wfo, load_cacheable_grid(opd2_func.__name__, wfo, build_m2_opd, use_caching))
        
    if 'm1_conic' in PASSVALUE:
        prop_conic(wfo, m2_fl, PASSVALUE['m2_conic'], "conic secondary")
    else:
        proper.prop_lens(wfo, m2_fl, "secondary")
                
    def build_m2_ap():
        return build_prop_circular_aperture(wfo, m2_rad)
    wfo.wfarr *= load_cacheable_grid('m2_ap', wfo, build_m2_ap)

#    proper.prop_state(wfo)

    # Hole through primary
    if m1_m2_sep<bfl:
        proper.prop_propagate(wfo, m1_m2_sep, "M1 hole")
        def build_m1_hole():
            return build_prop_circular_aperture(wfo, m1_hole_rad) 
        wfo.wfarr *= load_cacheable_grid('m1_hole', wfo, build_m1_hole)


    # Focus - bfl can be varied between runs
    if m1_m2_sep<bfl:
        proper.prop_propagate(wfo, bfl-m1_m2_sep, "focus", TO_PLANE=True)
    else:
        proper.prop_propagate(wfo, bfl, "focus", TO_PLANE=True)

#     # End
#     return proper.prop_end(wfo, NOABS = noabs)

    # End
    (wfo, sampling) = proper.prop_end(wfo)
    if get_wf:
        return (wfo, wf, sampling)
    else:
        return (wfo, sampling)
Example #15
0
out = falco.setup.flesh_out_workspace(mp)


## Step 5

# Determine the region of the array corresponding to the DM surface for use in the fitting.
mp.dm1.V = np.ones((mp.dm1.Nact,mp.dm1.Nact))
testSurf =  falco.dm.gen_surf_from_act(mp.dm1, mp.dm1.compact.dx, mp.dm1.compact.NdmPad)
testArea = np.zeros(testSurf.shape)
testArea[testSurf >= 0.5*np.max(testSurf)] = 1

#--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;

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
DM1Surf =  falco.dm.gen_surf_from_act(mp.dm1, mp.dm1.compact.dx, mp.dm1.compact.NdmPad)  
surfError = errorMap - DM1Surf;
Example #16
0
def scexao_model(lmda, grid_size, kwargs):
    """
    propagates instantaneous complex E-field thru Subaru from the DM through SCExAO

    uses PyPROPER3 to generate the complex E-field at the pupil plane, then propagates it through SCExAO 50x50 DM,
        then coronagraph, to the focal plane
    :returns spectral cube at instantaneous time in the focal_plane()
    """
    # print("Propagating Broadband Wavefront Through Subaru")

    # Initialize the Wavefront in Proper
    wfo = proper.prop_begin(entrance_d, lmda, grid_size, beam_ratio)

    # Defines aperture (baffle-before primary)
    proper.prop_circular_aperture(wfo, entrance_d / 2)
    proper.prop_define_entrance(wfo)  # normalizes abs intensity

    # Test Sampling
    if kwargs['verbose'] and kwargs['ix'] == 0:
        check1 = proper.prop_get_sampling(wfo)
        print(
            f"\n\tDM Pupil Plane\n"
            f"sampling at aperture is {check1 * 1e3:.4f} mm\n"
            f"Total Sim is {check1 * 1e3 * grid_size:.2f}x{check1 * 1e3 * grid_size:.2f} mm\n"
            f"Diameter of beam is {check1 * 1e3 * grid_size * beam_ratio:.4f} mm over {grid_size * beam_ratio} pix"
        )

    # SCExAO Reimaging 1
    proper.prop_lens(
        wfo, fl_SxOAPG)  # produces f#14 beam (approx exit beam of AO188)
    proper.prop_propagate(wfo, fl_SxOAPG * 2)  # move to second pupil
    if kwargs['verbose'] and kwargs['ix'] == 0:
        print(f"initial f# is {proper.prop_get_fratio(wfo):.2f}\n")

    ########################################
    # Import/Apply Actual DM Map
    # #######################################
    plot_flag = False
    if kwargs['verbose'] and kwargs['ix'] == 0:
        plot_flag = True

    dm_map = kwargs['map']
    errormap(wfo,
             dm_map,
             SAMPLING=dm_pitch,
             MIRROR_SURFACE=True,
             MASKING=True,
             BR=beam_ratio,
             PLOT=plot_flag)  # MICRONS=True

    if kwargs['verbose'] and kwargs['ix'] == 0:
        fig, subplot = plt.subplots(nrows=1, ncols=2, figsize=(12, 5))
        ax1, ax2 = subplot.flatten()
        fig.suptitle('SCExAO Model WFO after errormap',
                     fontweight='bold',
                     fontsize=14)
        ax1.imshow(proper.prop_get_amplitude(wfo), interpolation='none'
                   )  # np.abs(proper.prop_shift_center(wfo.wfarr))**2
        ax1.set_title('Amplitude')
        ax2.imshow(
            proper.prop_get_phase(wfo),
            interpolation=
            'none',  # np.angle(proper.prop_shift_center(wfo.wfarr))
            vmin=-1 * np.pi,
            vmax=1 * np.pi,
            cmap='hsv')  # , cmap='hsv'
        ax2.set_title('Phase')

    # ------------------------------------------------
    # SCExAO Reimaging 2
    proper.prop_lens(wfo, fl_SxOAPG)
    proper.prop_propagate(wfo,
                          fl_SxOAPG)  # focus at exit of DM telescope system
    proper.prop_lens(wfo, fl_SxOAPG)
    proper.prop_propagate(wfo,
                          fl_SxOAPG)  # focus at exit of DM telescope system

    # # Coronagraph
    SubaruPupil(wfo)  # focal plane mask
    # if kwargs['verbose'] and kwargs['ix']==0:
    #     fig, subplot = plt.subplots(nrows=1, ncols=2, figsize=(12, 5))
    #     ax1, ax2 = subplot.flatten()
    #     fig.suptitle('SCExAO Model WFO after FPM', fontweight='bold', fontsize=14)
    #     # ax.imshow(dm_map, interpolation='none')
    #     ax1.imshow(np.abs(proper.prop_shift_center(wfo.wfarr))**2, interpolation='none', norm=LogNorm(vmin=1e-7,vmax=1e-2))
    #     ax1.set_title('Amplitude')
    #     ax2.imshow(np.angle(proper.prop_shift_center(wfo.wfarr)), interpolation='none',
    #                vmin=-2*np.pi, vmax=2*np.pi, cmap='hsv')  # , cmap='hsv'
    #     ax2.set_title('Phase')
    proper.prop_propagate(wfo, fl_SxOAPG)
    proper.prop_lens(wfo, fl_SxOAPG)
    proper.prop_propagate(wfo, fl_SxOAPG)  # middle of 2f system
    proper.prop_circular_aperture(wfo, lyot_size, NORM=True)  # lyot stop
    proper.prop_propagate(wfo, fl_SxOAPG)  #
    proper.prop_lens(wfo, fl_SxOAPG)  # exit lens of gaussian telescope
    proper.prop_propagate(wfo, fl_SxOAPG)  # to focus

    # MEC Pickoff reimager.
    proper.prop_propagate(wfo, mec_parax_fl)  # to another pupil
    proper.prop_lens(
        wfo, mec_parax_fl)  # collimating lens, pupil size should be 8 mm
    proper.prop_propagate(wfo, mec1_fl +
                          .0142557)  # mec1_fl  .054  mec1_fl+.0101057
    # if kwargs['verbose'] and kwargs['ix']==0:
    #     current = proper.prop_get_beamradius(wfo)
    #     print(f'Beam Radius after SCExAO exit (at MEC foreoptics entrance) is {current*1e3:.3f} mm\n'
    #           f'current f# is {proper.prop_get_fratio(wfo):.2f}\n')

    # ##################################
    # MEC Optics Box
    # ###################################
    proper.prop_circular_aperture(wfo,
                                  0.00866)  # reading off the zemax diameter
    proper.prop_lens(wfo, mec1_fl)  # MEC lens 1
    proper.prop_propagate(wfo,
                          mec_l1_l2)  # there is a image plane at z=mec1_fl
    proper.prop_lens(wfo, mec2_fl)  # MEC lens 2 (tiny lens)
    proper.prop_propagate(wfo, mec_l2_l3)
    proper.prop_lens(wfo, mec3_fl)  # MEC lens 3
    proper.prop_propagate(wfo, mec3_fl,
                          TO_PLANE=False)  # , TO_PLANE=True mec_l3_focus

    # #######################################
    # Focal Plane
    # #######################################
    # Check Sampling in focal plane
    # shifts wfo from Fourier Space (origin==lower left corner) to object space (origin==center)
    # wf, samp = proper.prop_end(wfo, NoAbs=True)
    wf = proper.prop_shift_center(wfo.wfarr)
    wf = extract_center(wf, new_size=np.array(kwargs['psf_size']))
    samp = proper.prop_get_sampling(wfo)
    smp_asec = proper.prop_get_sampling_arcsec(wfo)

    if kwargs['verbose'] and kwargs['ix'] == 0:
        fig, subplot = plt.subplots(nrows=1, ncols=2, figsize=(12, 5))
        fig.subplots_adjust(left=0.08, hspace=.4, wspace=0.2)

        ax1, ax2 = subplot.flatten()
        fig.suptitle('SCExAO Model Focal Plane',
                     fontweight='bold',
                     fontsize=14)
        tic_spacing, tic_labels, axlabel = scale_lD(
            wfo, newsize=kwargs['psf_size'][0])
        tic_spacing[0] = tic_spacing[0] + 1  # hack for edge effects
        tic_spacing[-1] = tic_spacing[-1] - 1  # hack for edge effects

        im = ax1.imshow(
            np.abs(wf)**2,
            interpolation='none',
            norm=LogNorm(
                vmin=1e-7,
                vmax=1e-2))  # np.abs(proper.prop_shift_center(wfo.wfarr))**2
        ax1.set_xticks(tic_spacing)
        ax1.set_xticklabels(tic_labels)
        ax1.set_yticks(tic_spacing)
        ax1.set_yticklabels(tic_labels)
        ax1.set_ylabel(axlabel, fontsize=8)
        add_colorbar(im)

        im = ax2.imshow(np.angle(wf),
                        interpolation='none',
                        vmin=-np.pi,
                        vmax=np.pi,
                        cmap='hsv')
        ax2.set_xticks(tic_spacing)
        ax2.set_xticklabels(tic_labels)
        ax2.set_yticks(tic_spacing)
        ax2.set_yticklabels(tic_labels)
        ax2.set_ylabel(axlabel, fontsize=8)
        add_colorbar(im)

    if kwargs['verbose'] and kwargs['ix'] == 0:
        print(
            f"\nFocal Plane\n"
            f"sampling at focal plane is {samp*1e6:.1f} um ~= {smp_asec * 1e3:.4f} mas\n"
            f"\tfull FOV is {samp * kwargs['psf_size'][0] * 1e3:.2f} x {samp * kwargs['psf_size'][1] * 1e3:.2f} mm "
        )
        # s_rad = proper.prop_get_sampling_radians(wfo)
        # print(f"sampling at focal plane is {s_rad * 1e6:.6f} urad")
        print(f'final focal ratio is {proper.prop_get_fratio(wfo)}')

        print(f"Finished simulation")

    return wf, samp
Example #17
0
def run_system(empty_lamda, grid_size, PASSVALUE):  #'dm_disp':0
    passpara = PASSVALUE['params']
    ap.__dict__ = passpara[0].__dict__
    tp.__dict__ = passpara[1].__dict__
    iop.__dict__ = passpara[2].__dict__
    # params.ap = passpara[0]
    # params.tp = passpara[1]
    #
    # ap = params.ap
    # tp = params.tp

    # print 'line 23', tp.occulter_type
    # print 'propagating frame:', PASSVALUE['iter']
    wsamples = np.linspace(tp.band[0], tp.band[1], tp.nwsamp) / 1e9
    # print wsamples
    datacube = []
    # print proper.prop_get_sampling(wfp), proper.prop_get_nyquistsampling(wfp), proper.prop_get_fratio(wfp)
    # global phase_map, Imaps
    # Imaps = np.zeros((4,tp.grid_size,tp.grid_size))
    # phase_map = np.zeros((tp.grid_size, tp.grid_size))
    # wavefronts = np.empty((len(wsamples),1+len(ap.contrast)), dtype=object)
    for iw, w in enumerate(wsamples):
        # Define the wavefront
        beam_ratio = tp.beam_ratio * tp.band[0] / w * 1e-9
        wfp = proper.prop_begin(tp.diam, w, tp.grid_size, beam_ratio)

        wfs = [wfp]
        names = ['primary']
        if ap.companion:
            for id in range(len(ap.contrast)):
                wfc = proper.prop_begin(tp.diam, w, tp.grid_size, beam_ratio)
                wfs.append(wfc)
                names.append('companion_%i' % id)

        # proper.prop_circular_aperture(wfo, tp.diam / 2)
        # for iw, wf in enumerate([wfo, wfc]):
        wframes = np.zeros((tp.grid_size, tp.grid_size))
        for iwf, wf in zip(names, wfs):
            # wavefronts[iw,iwf] = wf
            proper.prop_circular_aperture(wf, tp.diam / 2)
            # quicklook_wf(wf, show=True)
            if tp.use_atmos:
                tdm.add_atmos(wf,
                              tp.f_lens,
                              w,
                              atmos_map=PASSVALUE['atmos_map'])

            if tp.rot_rate:
                tdm.rotate_atmos(wf, PASSVALUE['atmos_map'])

            # quicklook_wf(wf, show=True)
            # if tp.use_spiders:
            #     tdm.add_spiders(wf, tp.diam)

            if tp.use_hex:
                tdm.add_hex(wf)

            proper.prop_define_entrance(wf)  # normalizes the intensity

            if iwf[:9] == 'companion':
                tdm.offset_companion(wf, int(iwf[10:]), PASSVALUE['atmos_map'])
                # quicklook_wf(wf, show=True)
            if tp.use_apod:
                tdm.do_apod(wf, tp.grid_size, tp.beam_ratio, tp.apod_gaus)

            # quicklook_wf(wf, show=True)
            # obj_map = tdm.wfs_measurement(wfo)#, obj_map, tp.wfs_scale)
            proper.prop_propagate(wf, tp.f_lens)

            if tp.aber_params['CPA']:
                tdm.add_aber(wf,
                             tp.f_lens,
                             tp.aber_params,
                             tp.aber_vals,
                             PASSVALUE['iter'],
                             Loc='CPA')

            # if tp.CPA_type == 'test':
            #     tdm.add_single_speck(wf, PASSVALUE['iter'] )
            # if tp.CPA_type == 'Static':
            #     tdm.add_static(wf, tp.f_lens, loc = 'CPA')
            # if tp.CPA_type == 'Amp':
            #     tdm.add_static(wf, tp.f_lens, loc = 'CPA', type='Amp')
            # if tp.CPA_type == 'Quasi':
            #     tdm.add_quasi(wf, tp.f_lens, PASSVALUE['iter'])

            # rawImageIO.save_wf(wf, iop.datadir+'/beforeAO.pkl')
            # quicklook_wf(wf)
            # quicklook_im(obj_map, logAmp=False)

            proper.prop_propagate(wf, tp.f_lens)
            if tp.quick_ao:
                if iwf == 'primary':  # and PASSVALUE['iter'] == 0:
                    # quicklook_wf(wf, show=True)
                    r0 = float(PASSVALUE['atmos_map'][-10:-5])
                    # dprint((r0, 'r0'))
                    CPA_map = tdm.quick_wfs(wf, PASSVALUE['iter'],
                                            r0=r0)  # , obj_map, tp.wfs_scale)
                # dprint('quick_ao')
                # quicklook_wf(wf, show=True)
                if tp.use_ao:
                    tdm.quick_ao(wf, iwf, tp.f_lens, beam_ratio,
                                 PASSVALUE['iter'], CPA_map)
                # dprint('quick_ao')
                # quicklook_wf(wf, show=True)
            else:
                if tp.use_ao:
                    tdm.adaptive_optics(wf, iwf, iw, tp.f_lens, beam_ratio,
                                        PASSVALUE['iter'])

                if iwf == 'primary':  # and PASSVALUE['iter'] == 0:
                    # quicklook_wf(wf, show=True)
                    r0 = float(PASSVALUE['atmos_map'][-10:-5])
                    # dprint((r0, 'r0'))
                    # if iw == np.ceil(tp.nwsamp/2):
                    tdm.wfs_measurement(wf, PASSVALUE['iter'], iw,
                                        r0=r0)  #, obj_map, tp.wfs_scale)

            proper.prop_propagate(wf, tp.f_lens)

            # rawImageIO.save_wf(wf, iop.datadir+'/loopAO_8act.pkl')
            # if iwf == 'primary':
            #     quicklook_wf(wf, show=True)

            # if tp.active_modulate:
            #     tdm.modulate(wf, w, PASSVALUE['iter'])

            # if iwf == 'primary':
            #     quicklook_wf(wf, show=True)

            if tp.aber_params['NCPA']:
                tdm.add_aber(wf,
                             tp.f_lens,
                             tp.aber_params,
                             tp.aber_vals,
                             PASSVALUE['iter'],
                             Loc='NCPA')

            # if tp.NCPA_type == 'Static':
            #     tdm.add_static(wf, tp.f_lens, loc = 'NCPA')
            # if tp.NCPA_type == 'Wave':
            #     tdm.add_IFS_ab(wf, tp.f_lens, w)
            # if tp.NCPA_type == 'Quasi':
            #     tdm.add_quasi(wf, tp.f_lens, PASSVALUE['iter'])

            # quicklook_wf(wf, show=True)

            # if iwf == 'primary':
            #     NCPA_phasemap = proper.prop_get_phase(wf)
            #     quicklook_im(NCPA_phasemap, logAmp=False, show=False, colormap="jet", vmin=-3.14, vmax=3.14)
            # if iwf == 'primary':
            #     global obj_map
            #     r0 = float(PASSVALUE['atmos_map'][-10:-5])
            #     obj_map = tdm.wfs_measurement(wf, r0 = r0)#, obj_map, tp.wfs_scale)
            #     # quicklook_im(obj_map, logAmp=False)

            proper.prop_propagate(wf, tp.f_lens)

            # spiders are introduced here for now since the phase unwrapping seems to ignore them and hence so does the DM
            # Check out http://scikit-image.org/docs/dev/auto_examples/filters/plot_phase_unwrap.html for masking argument
            if tp.use_spiders:
                tdm.add_spiders(wf, tp.diam)

            tdm.prop_mid_optics(wf, tp.f_lens)

            # if iwf == 'primary':
            # if PASSVALUE['iter']>ap.numframes-2 or PASSVALUE['iter']==0:
            #     quicklook_wf(wf, show=True)
            # print proper.prop_get_sampling(wfp), proper.prop_get_sampling_arcsec(wfp), 'here'
            if tp.satelite_speck and iwf == 'primary':
                tdm.add_speckles(wf)

            # tp.variable = proper.prop_get_phase(wfo)[20,20]
            # print 'speck phase', tp.variable

            # import cPickle as pickle
            # dprint('just saved')
            # with open(iop.phase_ideal, 'wb') as handle:
            #     pickle.dump(proper.prop_get_phase(wf), handle, protocol=pickle.HIGHEST_PROTOCOL)
            # exit()

            if tp.active_null and iwf == 'primary':
                FPWFS.active_null(wf, PASSVALUE['iter'], w)
            # if tp.speckle_kill and iwf == 'primary':
            #     tdm.speckle_killer(wf)
            # tdm.speck_kill(wf)

            # iwf == 'primary':
            #     parent_bright = aper_phot(proper.prop_get_amplitude(wf),0,8)

            # if iwf == 'primary' and iop.saveIQ:
            #     save_pix_IQ(wf)
            #     complex_map = proper.prop_shift_center(wf.wfarr)
            #     complex_pix = complex_map[64, 64]
            #     print complex_pix
            #     if np.real(complex_pix) < 0.2:
            #         quicklook_IQ(wf)
            #
            # if iwf == 'primary':
            # #     print np.sum(proper.prop_get_amplitude(wf)), 'before', aper_phot(proper.prop_get_amplitude(wf),0,4)
            #     quicklook_wf(wf, show=True, logAmp=True)
            # if iwf == 'primary':
            #     quicklook_wf(wf, show=True)

            # if tp.active_modulate and PASSVALUE['iter'] >=8:
            #     coronagraph(wf, tp.f_lens, tp.occulter_type, tp.occult_loc, tp.diam)
            # if not tp.active_modulate:
            coronagraph(wf, tp.f_lens, tp.occulter_type, tp.occult_loc,
                        tp.diam)
            # dprint(proper.prop_get_sampling_arcsec(wf))
            # exit()
            #     tp.occult_factor = aper_phot(proper.prop_get_amplitude(wf),0,8)/parent_bright
            #     if PASSVALUE['iter'] % 10 == 0:
            #         with open(iop.logfile, 'a') as the_file:
            #               the_file.write('\n', tp.occult_factor)

            # quicklook_wf(wf, show=True)
            if tp.occulter_type != 'None' and iwf == 'primary':  #kludge for now until more sophisticated coronapraph has been installed
                wf.wfarr *= 0.1
            #     # print np.sum(proper.prop_get_amplitude(wf)), 'after', aper_phot(proper.prop_get_amplitude(wf), 0, 4)
            # quicklook_wf(wf, show=True)
            # print proper.prop_get_sampling(wfp), proper.prop_get_sampling_arcsec(wfp), 'here'
            # if iwf == 'primary':
            #     quicklook_wf(wf, show=True)
            if tp.use_zern_ab:
                tdm.add_zern_ab(wf, tp.f_lens)

            (wframe, sampling) = proper.prop_end(wf)
            # dprint((np.sum(wframe), 'sum'))
            # wframe = proper.prop_get_amplitude(wf)

            # planet = np.roll(np.roll(wframe, 20, 1), 20, 0) * 0.1  # [92,92]
            # if ap.companion:
            #     from scipy.ndimage.interpolation import shift
            #     companion = shift(wframe, shift=  np.array(ap.comp_loc[::-1])- np.array([tp.grid_size/2,tp.grid_size/2])) * ap.contrast
            #     # planet = np.roll(wframe, 15, 0) * 0.1  # [92,92]
            #
            #     wframe = (wframe + companion)

            # quicklook_im(wframe, logAmp=True)
            # '''test conserve=True on prop_magnify!'''

            # wframe = proper.prop_magnify(wframe, (w*1e9)/tp.band[0])
            # wframe = tdm.scale_wframe(wframe, w, iwf)
            # print np.shape(wframe)
            quicklook_im(wframe)
            # quicklook_im(wframe)

            # mid = int(len(wframe)/2)
            # wframe = wframe[mid - tp.grid_size/2 : mid +tp.grid_size/2, mid - tp.grid_size/2 : mid +tp.grid_size/2]
            # if max(mp.array_size) < tp.grid_size:
            #     # Photons seeded outside the array cannot have pixel phase uncertainty applied to them. Instead make both grids match in size
            #     wframe = rawImageIO.resize_image(wframe, newsize=(max(mp.array_size),max(mp.array_size)))
            # dprint(np.sum(wframe))
            # dprint(iwf)
            # if iwf == 'companion_0':
            wframes += wframe
            # if sp.show_wframe:
        # quicklook_im(wframes, logAmp=True, show=True)
        datacube.append(wframes)

    datacube = np.array(datacube)
    datacube = np.abs(datacube)
    # #normalize
    # datacube = np.transpose(np.transpose(datacube) / np.sum(datacube, axis=(1, 2)))/float(tp.nwsamp)

    # print 'Some pixels have negative values, possibly because of some Gaussian uncertainy you introduced. Taking abs for now.'

    # view_datacube(datacube)
    # # End

    # print type(wfo[0,0]), type(wfo)
    # #     proper.prop_savestate(wfo)
    # # else:
    # #     wfo = proper.prop_state(wfo)
    return (datacube, sampling)
Example #18
0
    def occulter(self, wf):

        n = int(proper.prop_get_gridsize(wf))
        ofst = 0  # no offset
        ramp_sign = 1  # sign of charge is positive
        ramp_oversamp = 11.  # vortex is oversampled for a better discretization

        # f_lens = tp.f_lens #conf['F_LENS']
        # diam = tp.diam#conf['DIAM']
        charge = 2  #conf['CHARGE']
        pixelsize = 5  #conf['PIXEL_SCALE']
        Debug_print = False  #conf['DEBUG_PRINT']

        coron_temp = os.path.join(iop.testdir, 'coron_maps/')
        if not os.path.exists(coron_temp):
            os.mkdir(coron_temp)

        if charge != 0:
            wavelength = proper.prop_get_wavelength(wf)
            gridsize = proper.prop_get_gridsize(wf)
            beam_ratio = pixelsize * 4.85e-9 / (wavelength / tp.entrance_d)
            # dprint((wavelength,gridsize,beam_ratio))
            calib = str(charge) + str('_') + str(int(
                beam_ratio * 100)) + str('_') + str(gridsize)
            my_file = str(coron_temp + 'zz_perf_' + calib + '_r.fits')

            if (os.path.isfile(my_file) == True):
                if (Debug_print == True):
                    print("Charge ", charge)
                vvc = self.readfield(
                    coron_temp,
                    'zz_vvc_' + calib)  # read the theoretical vortex field
                vvc = proper.prop_shift_center(vvc)
                scale_psf = wf._wfarr[0, 0]
                psf_num = self.readfield(coron_temp, 'zz_psf_' +
                                         calib)  # read the pre-vortex field
                psf0 = psf_num[0, 0]
                psf_num = psf_num / psf0 * scale_psf
                perf_num = self.readfield(
                    coron_temp,
                    'zz_perf_' + calib)  # read the perfect-result vortex field
                perf_num = perf_num / psf0 * scale_psf
                wf._wfarr = (
                    wf._wfarr - psf_num
                ) * vvc + perf_num  # the wavefront takes into account the real pupil with the perfect-result vortex field

            else:  # CAL==1: # create the vortex for a perfectly circular pupil
                if (Debug_print == True):
                    dprint(f"Vortex Charge= {charge}")

                f_lens = 200.0 * tp.entrance_d
                wf1 = proper.prop_begin(tp.entrance_d, wavelength, gridsize,
                                        beam_ratio)
                proper.prop_circular_aperture(wf1, tp.entrance_d / 2)
                proper.prop_define_entrance(wf1)
                proper.prop_propagate(wf1, f_lens,
                                      'inizio')  # propagate wavefront
                proper.prop_lens(
                    wf1, f_lens,
                    'focusing lens vortex')  # propagate through a lens
                proper.prop_propagate(wf1, f_lens, 'VC')  # propagate wavefront

                self.writefield(coron_temp, 'zz_psf_' + calib,
                                wf1.wfarr)  # write the pre-vortex field
                nramp = int(n * ramp_oversamp)  # oversamp
                # create the vortex by creating a matrix (theta) representing the ramp (created by atan 2 gradually varying matrix, x and y)
                y1 = np.ones((nramp, ), dtype=np.int)
                y2 = np.arange(0, nramp,
                               1.) - (nramp / 2) - int(ramp_oversamp) / 2
                y = np.outer(y2, y1)
                x = np.transpose(y)
                theta = np.arctan2(y, x)
                x = 0
                y = 0
                vvc_tmp = np.exp(1j * (ofst + ramp_sign * charge * theta))
                theta = 0
                vvc_real_resampled = cv2.resize(
                    vvc_tmp.real, (0, 0),
                    fx=1 / ramp_oversamp,
                    fy=1 / ramp_oversamp,
                    interpolation=cv2.INTER_LINEAR
                )  # scale the pupil to the pupil size of the simualtions
                vvc_imag_resampled = cv2.resize(
                    vvc_tmp.imag, (0, 0),
                    fx=1 / ramp_oversamp,
                    fy=1 / ramp_oversamp,
                    interpolation=cv2.INTER_LINEAR
                )  # scale the pupil to the pupil size of the simualtions
                vvc = np.array(vvc_real_resampled, dtype=complex)
                vvc.imag = vvc_imag_resampled
                vvcphase = np.arctan2(vvc.imag,
                                      vvc.real)  # create the vortex phase
                vvc_complex = np.array(np.zeros((n, n)), dtype=complex)
                vvc_complex.imag = vvcphase
                vvc = np.exp(vvc_complex)
                vvc_tmp = 0.
                self.writefield(coron_temp, 'zz_vvc_' + calib,
                                vvc)  # write the theoretical vortex field

                proper.prop_multiply(wf1, vvc)
                proper.prop_propagate(wf1, f_lens, 'OAP2')
                proper.prop_lens(wf1, f_lens)
                proper.prop_propagate(wf1, f_lens, 'forward to Lyot Stop')
                proper.prop_circular_obscuration(
                    wf1, 1.,
                    NORM=True)  # null the amplitude iside the Lyot Stop
                proper.prop_propagate(wf1, -f_lens)  # back-propagation
                proper.prop_lens(wf1, -f_lens)
                proper.prop_propagate(wf1, -f_lens)
                self.writefield(
                    coron_temp, 'zz_perf_' + calib,
                    wf1.wfarr)  # write the perfect-result vortex field

                vvc = self.readfield(coron_temp, 'zz_vvc_' + calib)
                vvc = proper.prop_shift_center(vvc)
                scale_psf = wf._wfarr[0, 0]
                psf_num = self.readfield(coron_temp, 'zz_psf_' +
                                         calib)  # read the pre-vortex field
                psf0 = psf_num[0, 0]
                psf_num = psf_num / psf0 * scale_psf
                perf_num = self.readfield(
                    coron_temp,
                    'zz_perf_' + calib)  # read the perfect-result vortex field
                perf_num = perf_num / psf0 * scale_psf
                wf._wfarr = (
                    wf._wfarr - psf_num
                ) * vvc + perf_num  # the wavefront takes into account the real pupil with the perfect-result vortex field

        return wf
Example #19
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
Example #20
0
def generate_maps(aber_vals, lens_diam, lens_name='lens', quasi_static=False):
    """
    generate PSD-defined aberration maps for a lens(mirror) using Proper

    Use Proper to generate an 2D aberration pattern across an optical element. The amplitude of the error per spatial
     frequency (cycles/m) across the surface is taken from a power spectral density (PSD) of statistical likelihoods
     for 'real' aberrations of physical optics.
    parameters defining the PSD function are specified in tp.aber_vals. These limit the range for the constants of the
     governing equation given by PSD = a/ [1+(k/b)^c]. This formula assumes the Terrestrial Planet Finder PSD, which is
     set to TRUE unless manually overridden line-by-line. As stated in the proper manual, this PSD function general
      under-predicts lower order aberrations, and thus Zernike polynomials can be added to get even more realistic
      surface maps.
    more information on a PSD error map can be found in the Proper manual on pgs 55-60

    Note: Functionality related to OOPP (out of pupil plane) optics has been removed. There is only one surface
    simulated for each optical surface

    :param aber_vals: dictionary? of values to use in the equation that generates the aberration map. The dictionary
        should contain 3 entries that get sent to proper.prop_psd_errormap. More information can be found on Proper
        Manual pg 56
    :param lens_diam: diameter of the lens/mirror to generate an aberration map for
    :param lens_name: name of the lens, for file naming
    :return: will create a FITs file in the folder specified by iop.quasi for each optic (and  timestep in the case
     of quasi-static aberrations)
    """
    # TODO add different timescale aberations
    if sp.verbose:
        dprint(
            f'Generating optic aberration maps using Proper at directory {iop.aberdir}'
        )
    if not os.path.isdir(iop.aberdir):
        # todo remove when all test scripts use the new format
        raise NotImplementedError
        print(
            'aberration maps should be created at the beginng, not on the fly')
        os.makedirs(iop.aberdir, exist_ok=True)

    # create blank lens wavefront for proper to add phase to
    wfo = proper.prop_begin(lens_diam, 1., sp.grid_size, sp.beam_ratio)
    aber_cube = np.zeros((1, sp.grid_size, sp.grid_size))

    # Randomly select a value from the range of values for each constant
    # rms_error = np.random.normal(aber_vals['a'][0], aber_vals['a'][1])
    # c_freq = np.random.normal(aber_vals['b'][0], aber_vals['b'][1])  # correlation frequency (cycles/meter)
    # high_power = np.random.normal(aber_vals['c'][0], aber_vals['c'][1])  # high frequency falloff (r^-high_power)

    rms_error, c_freq, high_power = aber_vals

    # perms = np.random.rand(sp.numframes, sp.grid_size, sp.grid_size)-0.5
    # perms *= 1e-7

    phase = 2 * np.pi * np.random.uniform(size=(sp.grid_size,
                                                sp.grid_size)) - np.pi
    aber_cube[0] = proper.prop_psd_errormap(wfo,
                                            rms_error,
                                            c_freq,
                                            high_power,
                                            TPF=True,
                                            PHASE_HISTORY=phase)
    # PHASE_HISTORY stuff is a kwarg Rupert added to a proper.prop_pds_errormap in proper_mod that helps
    #  ennable the small perturbations to the phase aberrations over time (quasi-static aberration evolution)
    #  however, this may not be implemented here, and the functionality may not be robust. It has yet to be
    #  verified in a robust manner. However, I am not sure it is being used....? KD 10-15-19
    # TODO verify this and add qusi-static functionality

    filename = f"{iop.aberdir}/t{0}_{lens_name}.fits"
    #dprint(f"filename = {filename}")
    if not os.path.isfile(filename):
        saveFITS(aber_cube[0], filename)

    if quasi_static:
        # todo implement monkey patch of proper.prop_psd_error that return phase too so it can be incremented with correlated gaussian noise
        # See commit 48c77c0babd5c6fcbc681b4fdd0d2db9cf540695 for original implementation of this code
        raise NotImplementedError
Example #21
0
def pupil(diam,
          gridsize,
          spiders_width,
          spiders_angle,
          pixelsize,
          r_obstr,
          wavelength,
          pupil_file,
          missing_segments_number=0,
          Debug='False',
          Debug_print='False',
          prefix='test'):

    beam_ratio = pixelsize * 4.85e-9 / (wavelength / diam)
    wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio)
    n = int(gridsize)
    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 (Debug_print == True):
        print("npupil: ", npupil)
        print("lambda: ", wavelength)

    if (missing_segments_number == 0):
        if (isinstance(pupil_file, (list, tuple, np.ndarray)) == True):
            pupil = pupil_file
            pupil_pixels = (pupil.shape)[0]  ## fits file size
            scaling_factor = float(npupil) / float(
                pupil_pixels
            )  ## scaling factor between the fits file size and the pupil size of the simulation
            if (Debug_print == True):
                print("scaling_factor: ", scaling_factor)
            pupil_scale = cv2.resize(
                pupil.astype(np.float32), (0, 0),
                fx=scaling_factor,
                fy=scaling_factor,
                interpolation=cv2.INTER_LINEAR
            )  # scale the pupil to the pupil size of the simualtions
            if (Debug_print == True):
                print("pupil_resample", pupil_scale.shape)
            pupil_large = np.zeros(
                (n, n))  # define an array of n-0s, where to insert the pupuil
            if (Debug_print == True):
                print("n: ", n)
                print("npupil: ", npupil)
            pupil_large[
                int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 +
                int(npupil / 2),
                int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 +
                int(npupil / 2
                    )] = pupil_scale  # insert the scaled pupil into the 0s grid

        proper.prop_circular_aperture(
            wfo, diam / 2)  # create a wavefront with a circular pupil

        if (isinstance(pupil_file, (list, tuple, np.ndarray)) == True):
            proper.prop_multiply(wfo, pupil_large)  # multiply the saved pupil
        else:
            proper.prop_circular_obscuration(
                wfo, r_obstr, NORM=True
            )  # create a wavefront with a circular central obscuration
        if (spiders_width != 0):
            for iter in range(0, len(spiders_angle)):
                proper.prop_rectangular_obscuration(
                    wfo, spiders_width, 2 * diam,
                    ROTATION=spiders_angle[iter])  # define the spiders
    else:
        if (missing_segments_number == 1):
            pupil = fits.getdata(
                input_dir +
                '/ELT_2048_37m_11m_5mas_nospiders_1missing_cut.fits')
        if (missing_segments_number == 2):
            pupil = fits.getdata(
                input_dir +
                '/ELT_2048_37m_11m_5mas_nospiders_2missing_cut.fits')
        if (missing_segments_number == 4):
            pupil = fits.getdata(
                input_dir +
                '/ELT_2048_37m_11m_5mas_nospiders_4missing_cut.fits')
        if (missing_segments_number == 7):
            pupil = fits.getdata(
                input_dir +
                '/ELT_2048_37m_11m_5mas_nospiders_7missing_1_cut.fits')

        pupil_pixels = (pupil.shape)[0]  ## fits file size
        scaling_factor = float(npupil) / float(
            pupil_pixels
        )  ## scaling factor between the fits file size and the pupil size of the simulation
        if (Debug_print == True):
            print("scaling_factor: ", scaling_factor)
        pupil_scale = cv2.resize(
            pupil.astype(np.float32), (0, 0),
            fx=scaling_factor,
            fy=scaling_factor,
            interpolation=cv2.INTER_LINEAR
        )  # scale the pupil to the pupil size of the simualtions
        if (Debug_print == True):
            print("pupil_resample", pupil_scale.shape)
        pupil_large = np.zeros(
            (n, n))  # define an array of n-0s, where to insert the pupuil
        if (Debug_print == True):
            print("n: ", n)
            print("npupil: ", npupil)
        pupil_large[
            int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 +
            int(npupil / 2),
            int(n / 2) + 1 - int(npupil / 2) - 1:int(n / 2) + 1 +
            int(npupil /
                2)] = pupil_scale  # insert the scaled pupil into the 0s grid

        proper.prop_multiply(wfo, pupil_large)  # multiply the saved pupil
        if (spiders_width != 0):
            for iter in range(0, len(spiders_angle)):
                proper.prop_rectangular_obscuration(
                    wfo, spiders_width, 2 * diam,
                    ROTATION=spiders_angle[iter])  # define the spiders

    if (Debug == True):
        fits.writeto(
            out_dir + prefix + '_intial_pupil.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
    return (npupil, wfo)
Example #22
0
def create_pupil(nhr=2**10,
                 npupil=285,
                 pupil_img_size=40,
                 diam_ext=37,
                 diam_int=11,
                 spi_width=0.5,
                 spi_angles=[0, 60, 120],
                 seg_width=0,
                 seg_gap=0,
                 seg_rms=0,
                 seg_ny=[
                     10, 13, 16, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                     30, 31, 30, 31, 30, 31, 30, 31, 30, 29, 28, 27, 26, 25,
                     24, 23, 22, 19, 16, 13, 10
                 ],
                 seg_missing=[],
                 seed=123456,
                 **conf):
    ''' Create a pupil.
    
    Args:
        nhr: int
            high resolution grid
        npupil: int
            number of pixels of the pupil
        pupil_img_size: float
            pupil image (for PROPER) in m
        diam_ext: float
            outer circular aperture in m
        diam_int: float
            central obscuration in m
        spi_width: float
            spider width in m
        spi_angles: list of float
            spider angles in deg
        seg_width: float
            segment width in m
        seg_gap: float
            gap between segments in m
        seg_rms: float
            rms of the reflectivity of all segments
        seg_ny: list of int
            number of hexagonal segments per column (from left to right)
        seg_missing: list of tupples
            coordinates of missing segments
    
    '''

    # create a high res pupil with PROPER of even size (nhr)
    nhr_size = pupil_img_size * nhr / (nhr - 1)
    wf_tmp = proper.prop_begin(nhr_size, 1, nhr, diam_ext / nhr_size)
    if diam_ext > 0:
        proper.prop_circular_aperture(wf_tmp, 1, NORM=True)
    if diam_int > 0:
        proper.prop_circular_obscuration(wf_tmp,
                                         diam_int / diam_ext,
                                         NORM=True)
    if spi_width > 0:
        for angle in spi_angles:
            proper.prop_rectangular_obscuration(wf_tmp, spi_width/nhr_size, 2, \
                ROTATION=angle, NORM=True)
    pup = proper.prop_get_amplitude(wf_tmp)
    # crop the pupil to odd size (nhr-1), and resize to npupil
    pup = pup[1:, 1:]
    pup = resize_img(pup, npupil)
    # add segments
    if seg_width > 0:
        segments = np.zeros((nhr, nhr))
        # sampling in meters/pixel
        sampling = pupil_img_size / nhr
        # dist between center of two segments, side by side
        seg_d = seg_width * np.cos(np.pi / 6) + seg_gap
        # segment radius
        seg_r = seg_width / 2
        # segment radial distance wrt x and y axis
        seg_ny = np.array(seg_ny)
        seg_nx = len(seg_ny)
        seg_rx = np.arange(seg_nx) - (seg_nx - 1) / 2
        seg_ry = (seg_ny - 1) / 2
        # loop through segments
        np.random.seed(seed)
        for i in range(seg_nx):
            seg_x = seg_rx[i] * seg_d * np.cos(np.pi / 6)
            seg_y = -seg_ry[i] * seg_d
            for j in range(1, seg_ny[i] + 1):
                # removes secondary and if any missing segment is present
                if (np.sqrt(seg_x**2 + seg_y**2) <= 4.01*seg_d) \
                        or ((seg_rx[i], j) in seg_missing):
                    seg_y += seg_d
                else:
                    # creates one hexagonal segment at x, y position in meters
                    segment = create_hexagon(nhr, seg_r, seg_y, seg_x,
                                             sampling)
                    # multiply by segment reflectivity and add to segments
                    seg_refl = np.random.normal(1, seg_rms)
                    segments += segment * seg_refl
                    seg_y += seg_d
        # need to transpose, due to the orientation of hexagons in create_hexagon
        segments = segments.T
        # resize to npupil, and add to pupil
        segments = resize_img(segments, npupil)
        pup *= segments

    return pup
Example #23
0
def toliman_prescription_simple(wavelength, gridsize):
    # Values from Eduardo's RC Toliman system
    diam = 0.3  # telescope diameter in meters
    fl_pri = 0.5 * 1.143451  # primary focal length (m)
    # BN 20180208
    d_pri_sec = 0.549337630333726  # primary to secondary separation (m)
    #    d_pri_sec = 0.559337630333726            # primary to secondary separation (m)
    fl_sec = -0.5 * 0.0467579189727913  # secondary focal length (m)
    d_sec_to_focus = 0.528110658881  # nominal distance from secondary to focus (from eqn)
    #    d_sec_to_focus = 0.589999999989853       # nominal distance from secondary to focus
    beam_ratio = 0.2  # initial beam width/grid width

    m2_rad = 0.059  # Secondary half-diameter (m)
    m2_strut_width = 0.01  # Width of struts supporting M2 (m)
    m2_supports = 5

    # Define the wavefront
    wfo = proper.prop_begin(diam, wavelength, gridsize, beam_ratio)

    # Input aperture
    proper.prop_circular_aperture(wfo, diam / 2)
    # NOTE: could prop_propagate() here if some baffling included
    # Secondary and structs obscuration
    proper.prop_circular_obscuration(wfo,
                                     m2_rad)  # secondary mirror obscuration
    # Spider struts/vanes, arranged evenly radiating out from secondary
    strut_length = diam / 2 - m2_rad
    strut_step = 360 / m2_supports
    strut_centre = m2_rad + strut_length / 2
    for i in range(0, m2_supports):
        angle = i * strut_step
        radians = math.radians(angle)
        xoff = math.cos(radians) * strut_centre
        yoff = math.sin(radians) * strut_centre
        proper.prop_rectangular_obscuration(wfo,
                                            m2_strut_width,
                                            strut_length,
                                            xoff,
                                            yoff,
                                            ROTATION=angle + 90)

    # Define entrance
    proper.prop_define_entrance(wfo)

    # Primary mirror (treat as quadratic lens)
    proper.prop_lens(wfo, fl_pri, "primary")

    # Propagate the wavefront
    proper.prop_propagate(wfo, d_pri_sec, "secondary")

    # Secondary mirror (another quadratic lens)
    proper.prop_lens(wfo, fl_sec, "secondary")

    # NOTE: hole through primary?

    # Focus
    # BN 20180208 - Need TO_PLANE=True if you want an intermediate plane
    proper.prop_propagate(wfo, d_sec_to_focus, "focus", TO_PLANE=True)
    #    proper.prop_propagate(wfo, d_sec_to_focus, "focus", TO_PLANE = False)

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

    return (wfo, sampling)
Example #24
0
def generate_maps(aber_vals, lens_diam, lens_name='lens'):
    """
    generate PSD-defined aberration maps for a lens(mirror) using Proper

    Use Proper to generate an 2D aberration pattern across an optical element. The amplitude of the error per spatial
     frequency (cycles/m) across the surface is taken from a power spectral density (PSD) of statistical likelihoods
     for 'real' aberrations of physical optics.
    parameters defining the PSD function are specified in tp.aber_vals. These limit the range for the constants of the
     governing equation given by PSD = a/ [1+(k/b)^c]. This formula assumes the Terrestrial Planet Finder PSD, which is
     set to TRUE unless manually overridden line-by-line. As stated in the proper manual, this PSD function general
      under-predicts lower order aberrations, and thus Zernike polynomials can be added to get even more realistic
      surface maps.
    more information on a PSD error map can be found in the Proper manual on pgs 55-60

    Note: Functionality related to OOPP (out of pupil plane) optics has been removed. There is only one surface
    simulated for each optical surface

    :param aber_vals: dictionary? of values to use in the equation that generates the aberration map. The dictionary
        should contain 3 entries that get sent to proper.prop_psd_errormap. More information can be found on Proper
        Manual pg 56
    :param lens_diam: diameter of the lens/mirror to generate an aberration map for
    :param lens_name: name of the lens, for file naming
    :return: will create a FITs file in the folder specified by iop.quasi for each optic (and  timestep in the case
     of quasi-static aberrations)
    """
    # TODO add different timescale aberations
    dprint('Generating optic aberration maps using Proper')
    iop.aberdata = f"gridsz{sp.grid_size}_bmratio{sp.beam_ratio}_tsteps{sp.numframes}"
    iop.aberdir = os.path.join(iop.testdir, iop.aberroot, iop.aberdata)
    if not os.path.isdir(iop.aberdir):
        os.makedirs(iop.aberdir, exist_ok=True)
    dprint(f"Abberation directory = {iop.aberdir}")

    # create blank lens wavefront for proper to add phase to
    wfo = proper.prop_begin(lens_diam, 1., sp.grid_size, sp.beam_ratio)
    aber_cube = np.zeros((sp.numframes, sp.grid_size, sp.grid_size))

    # Randomly select a value from the range of values for each constant
    rms_error = np.random.normal(aber_vals['a'][0], aber_vals['a'][1])
    c_freq = np.random.normal(
        aber_vals['b'][0],
        aber_vals['b'][1])  # correlation frequency (cycles/meter)
    high_power = np.random.normal(
        aber_vals['c'][0],
        aber_vals['c'][1])  # high frequency falloff (r^-high_power)

    perms = np.random.rand(sp.numframes, sp.grid_size, sp.grid_size) - 0.5
    perms *= 1e-7

    phase = 2 * np.pi * np.random.uniform(size=(sp.grid_size,
                                                sp.grid_size)) - np.pi
    aber_cube[0] = proper.prop_psd_errormap(wfo,
                                            rms_error,
                                            c_freq,
                                            high_power,
                                            TPF=True,
                                            PHASE_HISTORY=phase)
    # PHASE_HISTORY stuff is a kwarg Rupert added to a proper.prop_pds_errormap in proper_mod that helps
    #  ennable the small perturbations to the phase aberrations over time (quasi-static aberration evolution)
    #  however, this may not be implemented here, and the functionality may not be robust. It has yet to be
    #  verified in a robust manner. However, I am not sure it is being used....? KD 10-15-19
    # TODO verify this and add qusi-static functionality

    filename = f"{iop.aberdir}/t{0}_{lens_name}.fits"
    #dprint(f"filename = {filename}")
    if not os.path.isfile(filename):
        saveFITS(aber_cube[0], filename)

    # I think this part does quasi-static aberrations, but not sure if the random error is correct. On 7-10-19
    for a in range(1, sp.numframes):
        perms = np.random.rand(sp.grid_size, sp.grid_size) - 0.5
        perms *= 0.05
        phase += perms
        aber_cube[a] = proper.prop_psd_errormap(wfo,
                                                rms_error,
                                                c_freq,
                                                high_power,
                                                MAP="prim_map",
                                                TPF=True,
                                                PHASE_HISTORY=phase)

        filename = f"{iop.aberdir}/t{a}_{lens_name}.fits"
        if not os.path.isfile(filename):
            saveFITS(aber_cube[0], filename)
Example #25
0
def vortex_init(vortex_calib='',
                dir_temp='',
                diam_ext=37,
                lam=3.8,
                ngrid=1024,
                beam_ratio=0.26,
                focal=660,
                vc_charge=2,
                verbose=False,
                **conf):
    '''
    
    Creates/writes vortex back-propagation fitsfiles, or loads them if files 
    already exist.
    The following parameters will be added to conf: 
        vortex_calib, psf_num, perf_num, vvc
    
    Returns: conf (updated and sorted)

    '''

    # update conf with local variables (remove unnecessary)
    conf.update(locals())
    [conf.pop(key) for key in ['conf', 'verbose'] if key in conf]

    # check if back-propagation params already loaded for this calib
    calib = 'vortex_%s_%s_%3.4f' % (vc_charge, ngrid, beam_ratio)
    if vortex_calib == calib:
        return conf

    else:
        # check for existing file
        filename = os.path.join(dir_temp, '%s.fits' % calib)
        if os.path.isfile(filename):
            if verbose is True:
                print('   loading vortex back-propagation params')
            data = fits.getdata(os.path.join(dir_temp, filename))
            # read the pre-vortex field
            psf_num = data[0] + 1j * data[1]
            # read the theoretical vortex field
            vvc = data[2] + 1j * data[3]
            # read the perfect-result vortex field
            perf_num = data[4] + 1j * data[5]

        # create files
        else:
            if verbose is True:
                print("   writing vortex back-propagation params")
            # create circular pupil
            wf_tmp = proper.prop_begin(diam_ext, lam, ngrid, beam_ratio)
            proper.prop_circular_aperture(wf_tmp, 1, NORM=True)
            # propagate to vortex
            lens(wf_tmp, focal)
            # pre-vortex field
            psf_num = deepcopy(wf_tmp.wfarr)
            # vortex phase ramp is oversampled for a better discretization
            ramp_oversamp = 11.
            nramp = int(ngrid * ramp_oversamp)
            start = -nramp / 2 - int(ramp_oversamp) / 2 + 0.5
            end = nramp / 2 - int(ramp_oversamp) / 2 + 0.5
            Vp = np.arange(start, end, 1.)
            # Pancharatnam Phase = arg<Vref,Vp> (horizontal input polarization)
            Vref = np.ones(Vp.shape)
            prod = np.outer(Vref, Vp)
            phiPan = np.angle(prod + 1j * prod.T)
            # vortex phase ramp exp(ilphi)
            ofst = 0
            ramp_sign = 1
            vvc_tmp = np.exp(1j * (ramp_sign * vc_charge * phiPan + ofst))
            vvc = np.array(impro.resize_img(vvc_tmp.real, ngrid),
                           dtype=complex)
            vvc.imag = impro.resize_img(vvc_tmp.imag, ngrid)
            phase_ramp = np.angle(vvc)
            # theoretical vortex field
            vvc_complex = np.array(np.zeros((ngrid, ngrid)), dtype=complex)
            vvc_complex.imag = phase_ramp
            vvc = np.exp(vvc_complex)
            # apply vortex
            proper.prop_multiply(wf_tmp, vvc)
            # null the amplitude inside the Lyot Stop, and back propagate
            lens(wf_tmp, focal)
            proper.prop_circular_obscuration(wf_tmp, 1., NORM=True)
            lens(wf_tmp, -focal)
            # perfect-result vortex field
            perf_num = deepcopy(wf_tmp.wfarr)
            # write all fields
            data = np.dstack((psf_num.real.T, psf_num.imag.T, vvc.real.T, vvc.imag.T,\
                perf_num.real.T, perf_num.imag.T)).T
            fits.writeto(os.path.join(dir_temp, filename),
                         np.float32(data),
                         overwrite=True)

        # shift the phase ramp
        vvc = proper.prop_shift_center(vvc)
        # add vortex back-propagation parameters at the end of conf
        conf = {k: v for k, v in sorted(conf.items())}
        conf.update(vortex_calib=calib,
                    psf_num=psf_num,
                    vvc=vvc,
                    perf_num=perf_num)

        if verbose is True:
            print('   vc_charge=%s, ngrid=%s, beam_ratio=%3.4f'%\
                (vc_charge, ngrid, beam_ratio))

        return conf
Example #26
0
def vortex(wfo, charge, f_lens, diam, pixelsize, Debug_print=False):

    n = int(proper.prop_get_gridsize(wfo))
    ofst = 0  # no offset
    ramp_sign = 1  #sign of charge is positive
    ramp_oversamp = 11.  # vortex is oversampled for a better discretization

    if charge != 0:
        wavelength = proper.prop_get_wavelength(wfo)
        gridsize = proper.prop_get_gridsize(wfo)
        beam_ratio = pixelsize * 4.85e-9 / (wavelength / diam)
        calib = str(charge) + str('_') + str(int(
            beam_ratio * 100)) + str('_') + str(gridsize)
        my_file = str(tmp_dir + 'zz_perf_' + calib + '_r.fits')

        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

        if (os.path.isfile(my_file) == True):
            if (Debug_print == True):
                print("Charge ", charge)
            vvc = readfield(tmp_dir, 'zz_vvc_' +
                            calib)  # read the theoretical vortex field
            vvc = proper.prop_shift_center(vvc)
            scale_psf = wfo._wfarr[0, 0]
            psf_num = readfield(tmp_dir,
                                'zz_psf_' + calib)  # read the pre-vortex field
            psf0 = psf_num[0, 0]
            psf_num = psf_num / psf0 * scale_psf
            perf_num = readfield(tmp_dir, 'zz_perf_' +
                                 calib)  # read the perfect-result vortex field
            perf_num = perf_num / psf0 * scale_psf
            wfo._wfarr = (
                wfo._wfarr - psf_num
            ) * vvc + perf_num  # the wavefront takes into account the real pupil with the perfect-result vortex field

        else:  # CAL==1: # create the vortex for a perfectly circular pupil
            if (Debug_print == True):
                print("Charge ", charge)

            wfo1 = proper.prop_begin(diam, wavelength, gridsize, beam_ratio)
            proper.prop_circular_aperture(wfo1, diam / 2)
            proper.prop_define_entrance(wfo1)
            proper.prop_propagate(wfo1, f_lens,
                                  'inizio')  # propagate wavefront
            proper.prop_lens(
                wfo1, f_lens,
                'focusing lens vortex')  # propagate through a lens
            proper.prop_propagate(wfo1, f_lens, 'VC')  # propagate wavefront

            writefield(tmp_dir, 'zz_psf_' + calib,
                       wfo1.wfarr)  # write the pre-vortex field
            nramp = int(n * ramp_oversamp)  #oversamp
            # create the vortex by creating a matrix (theta) representing the ramp (created by atan 2 gradually varying matrix, x and y)
            y1 = np.ones((nramp, ), dtype=np.int)
            y2 = np.arange(0, nramp, 1.) - (nramp / 2) - int(ramp_oversamp) / 2
            y = np.outer(y2, y1)
            x = np.transpose(y)
            theta = np.arctan2(y, x)
            x = 0
            y = 0
            vvc_tmp = np.exp(1j * (ofst + ramp_sign * charge * theta))
            theta = 0
            vvc_real_resampled = cv2.resize(
                vvc_tmp.real, (0, 0),
                fx=1 / ramp_oversamp,
                fy=1 / ramp_oversamp,
                interpolation=cv2.INTER_LINEAR
            )  # scale the pupil to the pupil size of the simualtions
            vvc_imag_resampled = cv2.resize(
                vvc_tmp.imag, (0, 0),
                fx=1 / ramp_oversamp,
                fy=1 / ramp_oversamp,
                interpolation=cv2.INTER_LINEAR
            )  # scale the pupil to the pupil size of the simualtions
            vvc = np.array(vvc_real_resampled, dtype=complex)
            vvc.imag = vvc_imag_resampled
            vvcphase = np.arctan2(vvc.imag,
                                  vvc.real)  # create the vortex phase
            vvc_complex = np.array(np.zeros((n, n)), dtype=complex)
            vvc_complex.imag = vvcphase
            vvc = np.exp(vvc_complex)
            vvc_tmp = 0.
            writefield(tmp_dir, 'zz_vvc_' + calib,
                       vvc)  # write the theoretical vortex field

            proper.prop_multiply(wfo1, vvc)
            proper.prop_propagate(wfo1, f_lens, 'OAP2')
            proper.prop_lens(wfo1, f_lens)
            proper.prop_propagate(wfo1, f_lens, 'forward to Lyot Stop')
            proper.prop_circular_obscuration(
                wfo1, 1., NORM=True)  # null the amplitude iside the Lyot Stop
            proper.prop_propagate(wfo1, -f_lens)  # back-propagation
            proper.prop_lens(wfo1, -f_lens)
            proper.prop_propagate(wfo1, -f_lens)
            writefield(tmp_dir, 'zz_perf_' + calib,
                       wfo1.wfarr)  # write the perfect-result vortex field

            vvc = readfield(tmp_dir, 'zz_vvc_' + calib)
            vvc = proper.prop_shift_center(vvc)
            scale_psf = wfo._wfarr[0, 0]
            psf_num = readfield(tmp_dir,
                                'zz_psf_' + calib)  # read the pre-vortex field
            psf0 = psf_num[0, 0]
            psf_num = psf_num / psf0 * scale_psf
            perf_num = readfield(tmp_dir, 'zz_perf_' +
                                 calib)  # read the perfect-result vortex field
            perf_num = perf_num / psf0 * scale_psf
            wfo._wfarr = (
                wfo._wfarr - psf_num
            ) * vvc + perf_num  # the wavefront takes into account the real pupil with the perfect-result vortex field

        proper.prop_propagate(wfo, f_lens, "propagate to pupil reimaging lens")
        proper.prop_lens(wfo, f_lens, "apply pupil reimaging lens")
        proper.prop_propagate(wfo, f_lens, "lyot stop")

    return wfo
Example #27
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
Example #28
0
def pupil(file_pupil='',
          lam=3.8e-6,
          ngrid=1024,
          npupil=285,
          pupil_img_size=40,
          diam_ext=37,
          diam_int=11,
          spi_width=0.5,
          spi_angles=[0, 60, 120],
          npetals=6,
          seg_width=0,
          seg_gap=0,
          seg_rms=0,
          seg_ny=[
              10, 13, 16, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 30, 31,
              30, 31, 30, 31, 30, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 19,
              16, 13, 10
          ],
          seg_missing=[],
          select_petal=None,
          savefits=False,
          verbose=False,
          **conf):
    ''' Create a wavefront object at the entrance pupil plane. 
    The pupil is either loaded from a fits file, or created using 
    pupil parameters.
    Can also select only one petal and mask the others.

    Args:
        dir_output (str):
            path to saved pupil file
        band (str):
            spectral band (e.g. 'L', 'M', 'N1', 'N2')
        mode (str):
            HCI mode: RAVC, CVC, APP, CLC
        file_pupil: str
            path to a pupil fits file
        lam: float
            wavelength in m
        ngrid: int
            number of pixels of the wavefront array
        npupil: int
            number of pixels of the pupil
        pupil_img_size: float
            pupil image (for PROPER) in m
        diam_ext: float
            outer circular aperture in m
        diam_int: float
            central obscuration in m
        spi_width: float
            spider width in m
        spi_angles: list of float
            spider angles in deg
        seg_width: float
            segment width in m
        seg_gap: float
            gap between segments in m
        seg_rms: float
            rms of the reflectivity of all segments
        seg_ny: list of int
            number of hexagonal segments per column (from left to right)
        seg_missing: list of tupples
            coordinates of missing segments
        npetals: int
            number of petals
        select_petal: int
            selected petal in range npetals, default to None
    
    '''

    # initialize wavefront using PROPER
    beam_ratio = npupil / ngrid * (diam_ext / pupil_img_size)
    wf = proper.prop_begin(pupil_img_size, lam, ngrid, beam_ratio)

    # load pupil file
    if os.path.isfile(file_pupil):
        if verbose is True:
            print("Load pupil from '%s'" % os.path.basename(file_pupil))
        #conf.update()
        pup = fits.getdata(file_pupil).astype(np.float32)
        # resize to npupil
        pup = resize_img(pup, npupil)
    # if no pupil file, create a pupil
    else:
        if verbose is True:
            print("Create pupil: spi_width=%s m, seg_width=%s m, seg_gap=%s m, seg_rms=%s"\
                %(spi_width, seg_width, seg_gap, seg_rms))
        conf.update(npupil=npupil,
                    pupil_img_size=pupil_img_size,
                    diam_ext=diam_ext,
                    diam_int=diam_int,
                    spi_width=spi_width,
                    spi_angles=spi_angles,
                    seg_width=seg_width,
                    seg_gap=seg_gap,
                    seg_ny=seg_ny,
                    seg_missing=seg_missing,
                    seg_rms=seg_rms)
        pup = create_pupil(**conf)

    # normalize the entrance pupil intensity (total flux = 1)
    I_pup = pup**2
    pup = np.sqrt(I_pup / np.sum(I_pup))
    # pad with zeros and add to wavefront
    proper.prop_multiply(wf, pad_img(pup, ngrid))

    # select one petal (optional)
    if select_petal in range(npetals) and npetals > 1:
        if verbose is True:
            print("   select_petal=%s" % select_petal)
        # petal start and end angles
        pet_angle = 2 * np.pi / npetals
        pet_start = pet_angle / 2 + (select_petal - 1) * pet_angle
        pet_end = pet_start + pet_angle
        # petal angles must be 0-2pi
        ti %= (2 * np.pi)
        pet_start %= (2 * np.pi)
        pet_end %= (2 * np.pi)
        # check if petal crosses 0 angle
        if pet_end - pet_start < 0:
            pet_start = (pet_start + np.pi) % (2 * np.pi) - np.pi
            pet_end = (pet_end + np.pi) % (2 * np.pi) - np.pi
            ti = (ti + np.pi) % (2 * np.pi) - np.pi
        # create petal and add to grid
        petal = ((ti >= pet_start) * (ti <= pet_end)).astype(int)
        petal = resize_img(petal, ngrid)
        proper.prop_multiply(wf, petal)

    # save pupil as fits file
    if savefits == True:
        save2fits(pup, 'pupil', **conf)

    if verbose is True:
        print('   diam=%s m, resize to %s pix, zero-pad to %s pix\n'\
            %(round(diam_ext, 2), npupil, ngrid))

    return wf
Example #29
0
def run_system(empty_lamda, grid_size, PASSVALUE):  # 'dm_disp':0
    passpara = PASSVALUE['params']
    ap.__dict__ = passpara[0].__dict__
    tp.__dict__ = passpara[1].__dict__
    iop.__dict__ = passpara[2].__dict__
    sp.__dict__ = passpara[3].__dict__
    # params.ap = passpara[0]
    # params.tp = passpara[1]
    #
    # ap = params.ap
    # tp = params.tp

    # print 'line 23', tp.occulter_type
    # print 'propagating frame:', PASSVALUE['iter']
    wsamples = np.linspace(tp.band[0], tp.band[1], tp.nwsamp) / 1e9
    # print wsamples
    datacube = []
    # print proper.prop_get_sampling(wfp), proper.prop_get_nyquistsampling(wfp), proper.prop_get_fratio(wfp)
    # global phase_map, Imaps
    # Imaps = np.zeros((4,tp.grid_size,tp.grid_size))
    # phase_map = np.zeros((tp.grid_size, tp.grid_size))

    if ap.companion:
        wf_array = np.empty((len(wsamples), 1 + len(ap.contrast)), dtype=object)
    else:
        wf_array = np.empty((len(wsamples), 1), dtype=object)
    beam_ratios = np.zeros_like((wsamples))
    for iw, w in enumerate(wsamples):
        # Define the wavefront
        beam_ratios[iw] = tp.beam_ratio * tp.band[0] / w * 1e-9
        wfp = proper.prop_begin(tp.diam, w, tp.grid_size, beam_ratios[iw])

        wfs = [wfp]
        names = ['primary']
        if ap.companion:
            for id in range(len(ap.contrast)):
                wfc = proper.prop_begin(tp.diam, w, tp.grid_size, beam_ratios[iw])
                wfs.append(wfc)
                names.append('companion_%i' % id)

        for io, (iwf, wf) in enumerate(zip(names, wfs)):
            wf_array[iw, io] = wf


    iter_func(wf_array, proper.prop_circular_aperture, **{'radius':tp.diam/2})
    if tp.use_atmos:
        tdm.add_atmos(wf_array, *(tp.f_lens, w, PASSVALUE['atmos_map']))
        # quicklook_wf(wf_array[0, 0])

    wf_array = tdm.abs_zeros(wf_array)
        # get_intensity(wf_array, sp, phase=True)



    if tp.rot_rate:
        iter_func(wf_array, tdm.rotate_atmos, *(PASSVALUE['atmos_map']))

    if tp.use_spiders:
        iter_func(wf_array, tdm.add_spiders, tp.diam)
        wf_array = tdm.abs_zeros(wf_array)
        if sp.get_ints: get_intensity(wf_array, sp, phase=True)
    #     tdm.add_spiders(wf, tp.diam)
    wf_array = tdm.abs_zeros(wf_array)

    # if tp.use_hex:
    #     tdm.add_hex(wf)
    iter_func(wf_array,proper.prop_define_entrance)  # normalizes the intensity

    if wf_array.shape[1] >=1:
        tdm.offset_companion(wf_array[:,1:], PASSVALUE['atmos_map'], )

    # tdm.offset_companion(wf_array, PASSVALUE['atmos_map'])

    # if tp.use_apod:
    #     tdm.do_apod(wf, tp.grid_size, tp.beam_ratio, tp.apod_gaus)
    #
    # iter_func(wf_array, proper.prop_propagate, tp.f_lens)

    if tp.aber_params['CPA']:

        tdm.add_aber(wf_array, tp.f_lens, tp.aber_params, tp.aber_vals, PASSVALUE['iter'], Loc='CPA')
        iter_func(wf_array, proper.prop_circular_aperture, **{'radius': tp.diam / 2})
        iter_func(wf_array, tdm.add_spiders, tp.diam, legs=False)
        wf_array = tdm.abs_zeros(wf_array)
        if sp.get_ints: get_intensity(wf_array, sp, phase=True)

    # iter_func(wf_array, proper.prop_propagate, tp.f_lens)
    # quicklook_wf(wf_array[0,0])
    # iter_func(wf_array, proper.prop_circular_aperture, **{'radius': tp.diam / 2})
    # iter_func(wf_array, tdm.add_spiders, tp.diam, legs=False)
    # # proper.prop_rectangular_obscuration(wf_array[0,0], 0.05 * 8, 8 * 1.3, ROTATION=20)
    # # proper.prop_rectangular_obscuration(wf_array[0,0], 8 * 1.3, 0.05 * 8, ROTATION=20)
    # quicklook_wf(wf_array[0, 0])

    if tp.quick_ao:
        r0 = float(PASSVALUE['atmos_map'][-10:-5])

        tdm.flat_outside(wf_array)
        CPA_maps = tdm.quick_wfs(wf_array[:,0], PASSVALUE['iter'], r0=r0)  # , obj_map, tp.wfs_scale)

        if tp.use_ao:
            tdm.quick_ao(wf_array, iwf, tp.f_lens, beam_ratios, PASSVALUE['iter'], CPA_maps)
            # iter_func(wf_array, proper.prop_circular_aperture, **{'radius': tp.diam / 2})
            # iter_func(wf_array, tdm.add_spiders, tp.diam, legs=False)
            wf_array = tdm.abs_zeros(wf_array)
            if sp.get_ints: get_intensity(wf_array, sp, phase=True)
            # dprint('quick_ao')

    else:
        print('This need to be updated to the parrallel implementation')
        exit()
        # if tp.use_ao:
        #     tdm.adaptive_optics(wf, iwf, iw, tp.f_lens, beam_ratio, PASSVALUE['iter'])
        #
        # if iwf == 'primary':  # and PASSVALUE['iter'] == 0:
        #     # quicklook_wf(wf, show=True)
        #     r0 = float(PASSVALUE['atmos_map'][-10:-5])
        #     # dprint((r0, 'r0'))
        #     # if iw == np.ceil(tp.nwsamp/2):
        #     tdm.wfs_measurement(wf, PASSVALUE['iter'], iw, r0=r0)  # , obj_map, tp.wfs_scale)
    #
    # iter_func(wf_array, proper.prop_propagate, tp.f_lens)
    # quicklook_wf(wf_array[0,0])
    # rawImageIO.save_wf(wf, iop.datadir+'/loopAO_8act.pkl')
    # if iwf == 'primary':
    #     quicklook_wf(wf, show=True)


    # if tp.active_modulate:
    #     tdm.modulate(wf, w, PASSVALUE['iter'])

    # if iwf == 'primary':
    #     quicklook_wf(wf, show=True)

    if tp.aber_params['NCPA']:
        tdm.add_aber(wf_array, tp.f_lens, tp.aber_params, tp.aber_vals, PASSVALUE['iter'], Loc='NCPA')
        iter_func(wf_array, proper.prop_circular_aperture, **{'radius': tp.diam / 2})
        iter_func(wf_array, tdm.add_spiders, tp.diam, legs=False)
        wf_array = tdm.abs_zeros(wf_array)
        if sp.get_ints: get_intensity(wf_array, sp, phase=True)

    if tp.use_zern_ab:
        iter_func(wf_array, tdm.add_zern_ab, tp.f_lens)

    #         # if iwf == 'primary':
    #         #     NCPA_phasemap = proper.prop_get_phase(wf)
    #         #     quicklook_im(NCPA_phasemap, logAmp=False, show=False, colormap="jet", vmin=-3.14, vmax=3.14)
    #         # if iwf == 'primary':
    #         #     global obj_map
    #         #     r0 = float(PASSVALUE['atmos_map'][-10:-5])
    #         #     obj_map = tdm.wfs_measurement(wf, r0 = r0)#, obj_map, tp.wfs_scale)
    #         #     # quicklook_im(obj_map, logAmp=False)
    #
    # iter_func(wf_array, proper.prop_propagate, 2*tp.f_lens)
    #
    # spiders are introduced here for now since the phase unwrapping seems to ignore them and hence so does the DM
    # Check out http://scikit-image.org/docs/dev/auto_examples/filters/plot_phase_unwrap.html for masking argument
    # if tp.use_spiders:
    #     iter_func(wf_array, tdm.add_spiders, tp.diam)
    #
    #         tdm.prop_mid_optics(wf, tp.f_lens)

    if tp.use_apod:
        from coronagraph import apodization
        iter_func(wf_array, apodization, True)


    iter_func(wf_array, tdm.prop_mid_optics, tp.f_lens)
    #
    #         # if iwf == 'primary':
    #         # if PASSVALUE['iter']>ap.numframes-2 or PASSVALUE['iter']==0:
    #         #     quicklook_wf(wf, show=True)
    # dprint((proper.prop_get_sampling(wf_array[0,0]), proper.prop_get_sampling_arcsec(wf_array[0,0]), 'here'))
    #         if tp.satelite_speck and iwf == 'primary':
    #             tdm.add_speckles(wf)
    #
    #         # tp.variable = proper.prop_get_phase(wfo)[20,20]
    #         # print 'speck phase', tp.variable
    #
    #         # import cPickle as pickle
    #         # dprint('just saved')
    #         # with open(iop.phase_ideal, 'wb') as handle:
    #         #     pickle.dump(proper.prop_get_phase(wf), handle, protocol=pickle.HIGHEST_PROTOCOL)
    #
    #         if tp.active_null and iwf == 'primary':
    #             FPWFS.active_null(wf, PASSVALUE['iter'], w)
    #             # if tp.speckle_kill and iwf == 'primary':
    #             #     tdm.speckle_killer(wf)
    #             # tdm.speck_kill(wf)
    #
    #         # iwf == 'primary':
    #         #     parent_bright = aper_phot(proper.prop_get_amplitude(wf),0,8)
    #
    #
    #         # if iwf == 'primary' and iop.saveIQ:
    #         #     save_pix_IQ(wf)
    #         #     complex_map = proper.prop_shift_center(wf.wfarr)
    #         #     complex_pix = complex_map[64, 64]
    #         #     print complex_pix
    #         #     if np.real(complex_pix) < 0.2:
    #         #         quicklook_IQ(wf)
    #         #
    #         # if iwf == 'primary':
    #         # #     print np.sum(proper.prop_get_amplitude(wf)), 'before', aper_phot(proper.prop_get_amplitude(wf),0,4)
    #         #     quicklook_wf(wf, show=True, logAmp=True)
    #         # if iwf == 'primary':
    #         #     quicklook_wf(wf, show=True)
    #
    #         # if tp.active_modulate and PASSVALUE['iter'] >=8:
    #         #     coronagraph(wf, tp.f_lens, tp.occulter_type, tp.occult_loc, tp.diam)
    #         # if not tp.active_modulate:
    if sp.get_ints: get_intensity(wf_array, sp, phase=False)
    # quicklook_wf(wf_array[0, 0], show=True)
    iter_func(wf_array, coronagraph, *(tp.f_lens, tp.occulter_type, tp.occult_loc, tp.diam))
    # if 'None' not in tp.occulter_type:  # kludge for now until more sophisticated coronagraph has been installed
    #     for iw in range(len(wf_array)):
    #         wf_array[iw,0].wfarr *= 0.1
    if sp.get_ints: get_intensity(wf_array, sp, phase=False)
    # dprint(wf_array.shape)
    # quicklook_wf(wf_array[0, 0], show=True)
    # quicklook_wf(wf_array[0, 1], show=True)
    # quicklook_wf(wf_array[1, 0], show=True)

    dprint(proper.prop_get_sampling_arcsec(wf_array[0,0]))
    # dprint(proper.prop_get_sampling_arcsec(wf_array[0,1]))

    #         # exit()
    #         #     tp.occult_factor = aper_phot(proper.prop_get_amplitude(wf),0,8)/parent_bright
    #         #     if PASSVALUE['iter'] % 10 == 0:
    #         #         with open(iop.logfile, 'a') as the_file:
    #         #               the_file.write('\n', tp.occult_factor)
    #
    #         # quicklook_wf(wf, show=True)
    #         if tp.occulter_type != 'None' and iwf == 'primary':  # kludge for now until more sophisticated coronapraph has been installed
    #             wf.wfarr *= 0.1
    #             #     # print np.sum(proper.prop_get_amplitude(wf)), 'after', aper_phot(proper.prop_get_amplitude(wf), 0, 4)
    #             # quicklook_wf(wf, show=True)
    #         # print proper.prop_get_sampling(wfp), proper.prop_get_sampling_arcsec(wfp), 'here'
    #         # if iwf == 'primary':
    #         #     quicklook_wf(wf, show=True)
    #         if tp.use_zern_ab:
    #             tdm.add_zern_ab(wf, tp.f_lens)
    #

    shape = wf_array.shape
    # comp_scaling = 10*np.arange(1,shape[0]+1)/shape[0]
    # dprint(comp_scaling)

    for iw in range(shape[0]):
        wframes = np.zeros((tp.grid_size, tp.grid_size))
        for io in range(shape[1]):
            (wframe, sampling) = proper.prop_end(wf_array[iw,io])
            # dprint((np.sum(wframe), 'sum'))
            # wframe = proper.prop_get_amplitude(wf)

            # planet = np.roll(np.roll(wframe, 20, 1), 20, 0) * 0.1  # [92,92]
            # if ap.companion:
            #     from scipy.ndimage.interpolation import shift
            #     companion = shift(wframe, shift=  np.array(ap.comp_loc[::-1])- np.array([tp.grid_size/2,tp.grid_size/2])) * ap.contrast
            #     # planet = np.roll(wframe, 15, 0) * 0.1  # [92,92]
            #
            #     wframe = (wframe + companion)

            # quicklook_im(wframe, logAmp=True)
            # '''test conserve=True on prop_magnify!'''

            # wframe = proper.prop_magnify(wframe, (w*1e9)/tp.band[0])
            # wframe = tdm.scale_wframe(wframe, w, iwf)
            # print np.shape(wframe)
            # quicklook_im(wframe, logAmp=True)
            # quicklook_im(wframe[57:201,59:199])

            # mid = int(len(wframe)/2)
            # wframe = wframe[mid - tp.grid_size/2 : mid +tp.grid_size/2, mid - tp.grid_size/2 : mid +tp.grid_size/2]
            # if max(mp.array_size) < tp.grid_size:
            #     # Photons seeded outside the array cannot have pixel phase uncertainty applied to them. Instead make both grids match in size
            #     wframe = rawImageIO.resize_image(wframe, newsize=(max(mp.array_size),max(mp.array_size)))
            # dprint(np.sum(wframe))
            # dprint(iwf)
            # if iwf == 'companion_0':

            # if io > 0:
            #     wframe *= comp_scaling[iw]

            wframes += wframe
            # if sp.show_wframe:
        # quicklook_im(wframes, logAmp=True, show=True)
        datacube.append(wframes)

    datacube = np.array(datacube)
    # if tp.pix_shift:
    #     datacube = np.roll(np.roll(datacube, tp.pix_shift[0], 1), tp.pix_shift[1], 2)
    datacube = np.abs(datacube)
    # #normalize
    # dprint(np.sum(datacube, axis=(1, 2)))

    # dprint((tp.interp_sample , tp.nwsamp>1 , tp.nwsamp<tp.w_bins))
    if tp.interp_sample and tp.nwsamp>1 and tp.nwsamp<tp.w_bins:
        # view_datacube(datacube, logAmp=True)
        wave_samps = np.linspace(0, 1, tp.nwsamp)
        f_out = interp1d(wave_samps, datacube, axis=0)
        new_heights = np.linspace(0, 1, tp.w_bins)
        datacube = f_out(new_heights)
        # dprint(datacube.shape)
        # view_datacube(datacube, logAmp=True)
        
    # datacube = np.transpose(np.transpose(datacube) / np.sum(datacube, axis=(1, 2)))/float(tp.nwsamp)

    # print 'Some pixels have negative values, possibly because of some Gaussian uncertainy you introduced. Taking abs for now.'


    # view_datacube(datacube)
    # # End

    # print type(wfo[0,0]), type(wfo)
    # #     proper.prop_savestate(wfo)
    # # else:
    # #     wfo = proper.prop_state(wfo)
    return (datacube, sampling)
Example #30
0
def pupil(pup=None,
          f_pupil='',
          lam=3.8e-6,
          ngrid=1024,
          npupil=285,
          pupil_img_size=40,
          diam_ext=37,
          diam_int=11,
          spi_width=0.5,
          spi_angles=[0, 60, 120],
          npetals=6,
          seg_width=0,
          seg_gap=0,
          seg_rms=0,
          seg_ny=[
              10, 13, 16, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 30, 31,
              30, 31, 30, 31, 30, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 19,
              16, 13, 10
          ],
          seg_missing=[],
          select_petal=None,
          norm_I=True,
          savefits=False,
          verbose=False,
          **conf):
    ''' Create a wavefront object at the entrance pupil plane. 
    The pupil is either loaded from a fits file, or created using 
    pupil parameters.
    Can also select only one petal and mask the others.

    Args:
        dir_output (str):
            path to saved pupil file
        band (str):
            spectral band (e.g. 'L', 'M', 'N1', 'N2')
        mode (str):
            HCI mode: RAVC, CVC, APP, CLC
        f_pupil: str
            path to a pupil fits file
        lam: float
            wavelength in m
        ngrid: int
            number of pixels of the wavefront array
        npupil: int
            number of pixels of the pupil
        pupil_img_size: float
            pupil image (for PROPER) in m
        diam_ext: float
            outer circular aperture in m
        diam_int: float
            central obscuration in m
        spi_width: float
            spider width in m
        spi_angles: list of float
            spider angles in deg
        seg_width: float
            segment width in m
        seg_gap: float
            gap between segments in m
        seg_rms: float
            rms of the reflectivity of all segments
        seg_ny: list of int
            number of hexagonal segments per column (from left to right)
        seg_missing: list of tupples
            coordinates of missing segments
        npetals: int
            number of petals
        select_petal: int
            selected petal in range npetals, default to None
    
    '''

    # initialize wavefront using PROPER
    beam_ratio = npupil / ngrid * (diam_ext / pupil_img_size)
    wf = proper.prop_begin(diam_ext, lam, ngrid, beam_ratio)

    # case 1: load pupil from data
    if pup is not None:
        if verbose is True:
            print("Load pupil data from 'pup'")
        pup = resize_img(pup, npupil)

    # case 2: load pupil from file
    elif os.path.isfile(f_pupil):
        if verbose is True:
            print("Load pupil from '%s'" % os.path.basename(f_pupil))
        pup = resize_img(fits.getdata(f_pupil), npupil)

    # case 3: create a pupil
    else:
        if verbose is True:
            print("Create pupil: spi_width=%s m, seg_width=%s m, seg_gap=%s m, seg_rms=%s"\
                %(spi_width, seg_width, seg_gap, seg_rms))
        conf.update(npupil=npupil,
                    pupil_img_size=pupil_img_size,
                    diam_ext=diam_ext,
                    diam_int=diam_int,
                    spi_width=spi_width,
                    spi_angles=spi_angles,
                    seg_width=seg_width,
                    seg_gap=seg_gap,
                    seg_ny=seg_ny,
                    seg_missing=seg_missing,
                    seg_rms=seg_rms)
        pup = create_pupil(**conf)

    # select one petal (optional)
    if select_petal in range(npetals) and npetals > 1:
        if verbose is True:
            print("   select_petal=%s" % select_petal)
        petal = create_petal(select_petal, npetals, npupil)
        pup *= petal

    # normalize the entrance pupil intensity (total flux = 1)
    if norm_I is True:
        I_pup = pup**2
        pup = np.sqrt(I_pup / np.sum(I_pup))
    # save pupil as fits file
    if savefits == True:
        save2fits(pup, 'pupil', **conf)

    # pad with zeros and add to wavefront
    proper.prop_multiply(wf, pad_img(pup, ngrid))

    return wf