Esempio n. 1
0
def SubaruPupil(wf):
    """
    adds Subaru pupil mask to the optical train

    :param wf: 2D proper wavefront
    :return: acts upon wfo, applies a spatial mask of s=circular secondary obscuration and possibly spider legs
    """
    # dprint('Applying Subaru Pupil')

    # M2 shadow
    proper.prop_circular_obscuration(wf, 14 / 46, NORM=True)
    # Legs
    proper.prop_rectangular_obscuration(wf,
                                        1.2,
                                        2 / 46,
                                        .5,
                                        -.375,
                                        ROTATION=-50,
                                        NORM=True)
    proper.prop_rectangular_obscuration(wf,
                                        1.2,
                                        2 / 46,
                                        .5,
                                        .375,
                                        ROTATION=50,
                                        NORM=True)
    proper.prop_rectangular_obscuration(wf,
                                        1.2,
                                        2 / 46,
                                        -.5,
                                        -.375,
                                        ROTATION=50,
                                        NORM=True)
    proper.prop_rectangular_obscuration(wf,
                                        1.2,
                                        2 / 46,
                                        -.5,
                                        .375,
                                        ROTATION=-50,
                                        NORM=True)
    proper.prop_rectangular_obscuration(wf,
                                        1,
                                        1 / 46,
                                        .05,
                                        .45,
                                        ROTATION=-50,
                                        NORM=True)
    # Misc Spots
    proper.prop_circular_obscuration(wf, .075, -.1, 0.6, NORM=True)
    proper.prop_circular_obscuration(wf, .075, .5, -.375, NORM=True)
Esempio n. 2
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
Esempio n. 3
0
def lyotstop(wf, conf, RAVC):
    input_dir = conf['INPUT_DIR']
    diam = conf['DIAM']
    npupil = conf['NPUPIL']
    spiders_angle = conf['SPIDERS_ANGLE']
    r_obstr = conf['R_OBSTR']
    Debug = conf['DEBUG']
    Debug_print = conf['DEBUG_PRINT']
    LS_amplitude_apodizer_file = conf['AMP_APODIZER']
    LS_misalignment = np.array(conf['LS_MIS_ALIGN'])
    if conf['PHASE_APODIZER_FILE'] == 0:
        LS_phase_apodizer_file = 0
    else:
        LS_phase_apodizer_file = fits.getdata(input_dir + '/' +
                                              conf['PHASE_APODIZER_FILE'])
    LS = conf['LYOT_STOP']
    LS_parameters = np.array(conf['LS_PARA'])
    n = proper.prop_get_gridsize(wf)
    if (RAVC == True):  # define the inner radius of the Lyot Stop
        t1_opt = 1. - 1. / 4 * (
            r_obstr**2 + r_obstr * (math.sqrt(r_obstr**2 + 8.))
        )  # define the apodizer transmission [Mawet2013]
        R1_opt = (r_obstr / math.sqrt(1. - t1_opt)
                  )  # define teh apodizer radius [Mawet2013]
        r_LS = R1_opt + LS_parameters[
            1]  # when a Ring apodizer is present, the inner LS has to have at least the value of the apodizer radius
    else:
        r_LS = r_obstr + LS_parameters[
            1]  # when no apodizer, the LS has to have at least the radius of the pupil central obstruction
    if LS == True:  # apply the LS
        if (Debug_print == True):
            print("LS parameters: ", LS_parameters)
        proper.prop_circular_aperture(wf,
                                      LS_parameters[0],
                                      LS_misalignment[0],
                                      LS_misalignment[1],
                                      NORM=True)
        proper.prop_circular_obscuration(wf,
                                         r_LS,
                                         LS_misalignment[0],
                                         LS_misalignment[1],
                                         NORM=True)
        if (LS_parameters[2] != 0):
            for iter in range(0, len(spiders_angle)):
                if (Debug_print == True):
                    print("LS_misalignment: ", LS_misalignment)
                proper.prop_rectangular_obscuration(
                    wf,
                    LS_parameters[2],
                    2 * diam,
                    LS_misalignment[0],
                    LS_misalignment[1],
                    ROTATION=spiders_angle[iter])  # define the spiders
        if (Debug == True):
            out_dir = str('./output_files/')
            fits.writeto(
                out_dir + '_Lyot_stop.fits',
                proper.prop_get_amplitude(wf)[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)

    if (isinstance(LS_phase_apodizer_file, (list, tuple, np.ndarray)) == True):
        xc_pixels = int(LS_misalignment[3] * npupil)
        yc_pixels = int(LS_misalignment[4] * npupil)
        apodizer_pixels = (LS_phase_apodizer_file.shape)[0]  ## fits file size
        scaling_factor = float(npupil) / float(
            apodizer_pixels
        )  ## scaling factor between the fits file size and the pupil size of the simulation

        #        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)
        apodizer_scale = cv2.resize(
            LS_phase_apodizer_file.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("apodizer_resample", apodizer_scale.shape)
        apodizer_large = np.zeros(
            (n, n))  # define an array of n-0s, where to insert the pupuil
        if (Debug_print == True):
            print("npupil: ", npupil)
        apodizer_large[
            int(n / 2) + 1 - int(npupil / 2) - 1 + xc_pixels:int(n / 2) + 1 +
            int(npupil / 2) + xc_pixels,
            int(n / 2) + 1 - int(npupil / 2) - 1 + yc_pixels:int(n / 2) + 1 +
            int(npupil / 2) +
            yc_pixels] = apodizer_scale  # insert the scaled pupil into the 0s grid
        phase_multiply = np.array(np.zeros((n, n)),
                                  dtype=complex)  # create a complex array
        phase_multiply.imag = apodizer_large  # define the imaginary part of the complex array as the atm screen
        apodizer = np.exp(phase_multiply)
        proper.prop_multiply(wf, apodizer)
        if (Debug == True):
            fits.writeto('LS_apodizer.fits',
                         proper.prop_get_phase(wf),
                         overwrite=True)

    if (isinstance(LS_amplitude_apodizer_file,
                   (list, tuple, np.ndarray)) == True):
        print('4th')
        xc_pixels = int(LS_misalignment[0] * npupil)
        yc_pixels = int(LS_misalignment[1] * npupil)
        apodizer_pixels = (
            LS_amplitude_apodizer_file.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)
            apodizer_scale = cv2.resize(
                amplitude_apodizer_file.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("apodizer_resample", apodizer_scale.shape)
        apodizer_large = np.zeros(
            (n, n))  # define an array of n-0s, where to insert the pupuil
        if (Debug_print == True):
            print("grid_size: ", n)
            print("npupil: ", npupil)
        apodizer_large[
            int(n / 2) + 1 - int(npupil / 2) - 1 + xc_pixels:int(n / 2) + 1 +
            int(npupil / 2) + xc_pixels,
            int(n / 2) + 1 - int(npupil / 2) - 1 + yc_pixels:int(n / 2) + 1 +
            int(npupil / 2) +
            yc_pixels] = apodizer_scale  # insert the scaled pupil into the 0s grid
        apodizer = apodizer_large
        proper.prop_multiply(wf, apodizer)
        if (Debug == True):
            fits.writeto('LS_apodizer.fits',
                         proper.prop_get_amplitude(wf),
                         overwrite=True)

    return wf
Esempio n. 4
0
def lyot_stop(wf,
              mode='RAVC',
              ravc_r=0.6,
              ls_dRext=0.03,
              ls_dRint=0.05,
              ls_dRspi=0.04,
              spi_width=0.5,
              spi_angles=[0, 60, 120],
              diam_ext=37,
              diam_int=11,
              diam_nominal=37,
              ls_misalign=None,
              ngrid=1024,
              npupil=285,
              f_lyot_stop='',
              verbose=False,
              **conf):
    """ Add a Lyot stop for a focal plane mask. Propagate to detector. """

    if mode in ['CVC', 'RAVC', 'CLC']:

        # load lyot stop from file if provided
        if os.path.isfile(f_lyot_stop):
            if verbose is True:
                print("   apply lyot stop from '%s'" %
                      os.path.basename(f_lyot_stop))
            # get amplitude and phase data
            ls_mask = fits.getdata(f_lyot_stop)
            # resize to npupil
            ls_mask = resize_img(ls_mask, npupil)
            # pad with zeros and add to wavefront
            proper.prop_multiply(wf, pad_img(ls_mask, ngrid))

        # if no lyot stop, create one
        else:
            # scale nominal values to pupil external diameter
            scaling = diam_nominal / diam_ext
            # LS parameters
            r_obstr = ravc_r if mode in ['RAVC'] else diam_int / diam_ext
            ls_int = r_obstr + ls_dRint * scaling
            ls_ext = 1 - ls_dRext * scaling
            ls_spi = spi_width / diam_ext + ls_dRspi * scaling
            # LS misalignments
            ls_misalign = [0, 0, 0, 0, 0, 0
                           ] if ls_misalign is None else list(ls_misalign)
            dx_amp, dy_amp, dz_amp = ls_misalign[0:3]
            dx_phase, dy_phase, dz_phase = ls_misalign[3:6]
            # create Lyot stop
            proper.prop_circular_aperture(wf,
                                          ls_ext,
                                          dx_amp,
                                          dy_amp,
                                          NORM=True)
            if diam_int > 0:
                proper.prop_circular_obscuration(wf,
                                                 ls_int,
                                                 dx_amp,
                                                 dy_amp,
                                                 NORM=True)
            if spi_width > 0:
                for angle in spi_angles:
                    proper.prop_rectangular_obscuration(wf, 2*ls_spi, 2, \
                            dx_amp, dy_amp, ROTATION=angle, NORM=True)
            if verbose is True:
                print('   apply Lyot stop: ls_int=%s, ls_ext=%s, ls_spi=%s'\
                    %(round(ls_int, 4), round(ls_ext, 4), round(ls_spi, 4)))

    # propagate to detector
    lens(wf, **conf)

    return wf
Esempio n. 5
0
    def lyotstop(self, wf, RAVC=None, APP=None, get_pupil='no', dnpup=50):
        """Add a Lyot stop, or an APP."""

        # load parameters
        npupil = 1  #conf['NPUPIL']
        pad = int((210 - npupil) / 2)

        # get LS misalignments
        LS_misalignment = (np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) *
                           npupil).astype(int)
        dx_amp, dy_amp, dz_amp = LS_misalignment[0:3]
        dx_phase, dy_phase, dz_phase = LS_misalignment[3:6]

        # case 1: Lyot stop (no APP)
        if APP is not True:

            # Lyot stop parameters: R_out, dR_in, spi_width
            # outer radius (absolute %), inner radius (relative %), spider width (m)
            (R_out, dR_in, spi_width) = [0.98, 0.03, 0]

            # Lyot stop inner radius at least as large as obstruction radius
            R_in = 0.15

            # case of a ring apodizer
            if RAVC is True:
                # define the apodizer transmission and apodizer radius [Mawet2013]
                # apodizer radius at least as large as obstruction radius
                T_ravc = 1 - (R_in**2 + R_in * np.sqrt(R_in**2 + 8)) / 4
                R_in /= np.sqrt(1 - T_ravc)

            # oversize Lyot stop inner radius
            R_in += dR_in

            # create Lyot stop
            proper.prop_circular_aperture(wf, R_out, dx_amp, dy_amp, NORM=True)
            if R_in > 0:
                proper.prop_circular_obscuration(wf,
                                                 R_in,
                                                 dx_amp,
                                                 dy_amp,
                                                 NORM=True)
            if spi_width > 0:
                for angle in [10]:
                    proper.prop_rectangular_obscuration(wf,
                                                        0.05 * 8,
                                                        8 * 1.3,
                                                        ROTATION=20)
                    proper.prop_rectangular_obscuration(wf,
                                                        8 * 1.3,
                                                        0.05 * 8,
                                                        ROTATION=20)
                    # proper.prop_rectangular_obscuration(wf, spi_width, 2 * 8, \
                    #                                     dx_amp, dy_amp, ROTATION=angle)

        # case 2: APP (no Lyot stop)
        else:
            # get amplitude and phase files
            APP_amp_file = os.path.join(conf['INPUT_DIR'],
                                        conf['APP_AMP_FILE'])
            APP_phase_file = os.path.join(conf['INPUT_DIR'],
                                          conf['APP_PHASE_FILE'])
            # get amplitude and phase data
            APP_amp = getdata(APP_amp_file) if os.path.isfile(APP_amp_file) \
                else np.ones((npupil, npupil))
            APP_phase = getdata(APP_phase_file) if os.path.isfile(APP_phase_file) \
                else np.zeros((npupil, npupil))
            # resize to npupil
            APP_amp = resize(APP_amp, (npupil, npupil),
                             preserve_range=True,
                             mode='reflect')
            APP_phase = resize(APP_phase, (npupil, npupil),
                               preserve_range=True,
                               mode='reflect')
            # pad with zeros to match PROPER gridsize
            APP_amp = np.pad(APP_amp, [(pad + 1 + dx_amp, pad - dx_amp), \
                                       (pad + 1 + dy_amp, pad - dy_amp)], mode='constant')
            APP_phase = np.pad(APP_phase, [(pad + 1 + dx_phase, pad - dx_phase), \
                                           (pad + 1 + dy_phase, pad - dy_phase)], mode='constant')
            # multiply the loaded APP
            proper.prop_multiply(wf, APP_amp * np.exp(1j * APP_phase))

        # get the pupil amplitude or phase for output
        if get_pupil.lower() in 'amplitude':
            return wf, proper.prop_get_amplitude(wf)[pad + 1 - dnpup:-pad +
                                                     dnpup, pad + 1 -
                                                     dnpup:-pad + dnpup]
        elif get_pupil.lower() in 'phase':
            return wf, proper.prop_get_phase(wf)[pad + 1 - dnpup:-pad + dnpup,
                                                 pad + 1 - dnpup:-pad + dnpup]
        else:
            return wf
Esempio n. 6
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
Esempio n. 7
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)
Esempio n. 8
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
Esempio n. 9
0
def falco_gen_pupil_WFIRSTcycle6_LS(Nbeam,
                                    Dbeam,
                                    ID,
                                    OD,
                                    strut_width,
                                    centering,
                                    rot180deg=False):
    strut_width = strut_width * Dbeam  # now in meters
    dx = Dbeam / Nbeam

    clock_deg = 0
    magfacD = 1
    xshift = 0
    yshift = 0
    pad_strut = 0
    Dmask = Dbeam  # % width of the beam (so can have zero padding if LS is undersized) (meters)
    diam = Dmask  # width of the mask (meters)
    # minimum even number of points across to fully contain the actual aperture (if interpixel centered)
    NapAcross = Dmask / dx

    wf = _init_proper(Dmask, dx, centering)

    # 0 shift for pixel-centered pupil, or -dx shift for inter-pixel centering
    if centering == "interpixel":
        cshift = -dx / 2
    elif rot180deg:
        cshift = -dx
    else:
        cshift = 0

    # DATA FROM THE VISIO FILE
    D0 = 8  # inches, pupil diameter in Visio file
    x0 = -26  # inches, pupil center in x in Visio file
    y0 = 20.25  # inches, pupil center in y in Visio file
    Dconv = diam / D0  # conversion factor from inches and Visio units to meters

    # PRIMARY MIRROR (OUTER DIAMETER)
    ra_OD = (Dbeam * OD / 2) * magfacD
    cx_OD = cshift + xshift
    cy_OD = cshift + yshift
    proper.prop_circular_aperture(wf, ra_OD, cx_OD, cy_OD)

    # SECONDARY MIRROR (INNER DIAMETER)
    ra_ID = (Dbeam * ID / 2) * magfacD
    cx_ID = cshift + xshift
    cy_ID = cshift + yshift
    proper.prop_circular_obscuration(wf, ra_ID, cx_ID, cy_ID)

    sx_s = magfacD * (3.6 * (diam / D0) + pad_strut)
    sy_s = magfacD * (strut_width + pad_strut)
    clock_rot = np.array(
        [[np.cos(np.radians(clock_deg)), -np.sin(np.radians(clock_deg))],
         [np.sin(np.radians(clock_deg)),
          np.cos(np.radians(clock_deg))]])

    def _get_strut_cxy(x, y):
        cx_s = (x - x0) * Dconv
        cy_s = (y - y0) * Dconv
        cxy = magfacD * clock_rot.dot([cx_s, cy_s]) + cshift
        return cxy + [xshift, yshift]

    # STRUT 1
    rot_s1 = 77.56 + clock_deg  # degrees
    cx_s1, cy_s1 = _get_strut_cxy(-24.8566, 22.2242)
    proper.prop_rectangular_obscuration(wf,
                                        sx_s,
                                        sy_s,
                                        cx_s1,
                                        cy_s1,
                                        ROTATION=rot_s1)

    # STRUT 2
    rot_s2 = -17.56 + clock_deg  # degrees
    cx_s2, cy_s2 = _get_strut_cxy(-23.7187, 20.2742)
    proper.prop_rectangular_obscuration(wf,
                                        sx_s,
                                        sy_s,
                                        cx_s2,
                                        cy_s2,
                                        ROTATION=rot_s2)

    # STRUT 3
    rot_s3 = -42.44 + clock_deg  # degrees
    cx_s3, cy_s3 = _get_strut_cxy(-24.8566, 18.2758)
    proper.prop_rectangular_obscuration(wf,
                                        sx_s,
                                        sy_s,
                                        cx_s3,
                                        cy_s3,
                                        ROTATION=rot_s3)

    # STRUT 4
    rot_s4 = 42.44 + clock_deg  # degrees
    cx_s4, cy_s4 = _get_strut_cxy(-27.1434, 18.2758)
    proper.prop_rectangular_obscuration(wf,
                                        sx_s,
                                        sy_s,
                                        cx_s4,
                                        cy_s4,
                                        ROTATION=rot_s4)

    # STRUT 5
    rot_s5 = 17.56 + clock_deg  # degrees
    cx_s5, cy_s5 = _get_strut_cxy(-28.2813, 20.2742)
    proper.prop_rectangular_obscuration(wf,
                                        sx_s,
                                        sy_s,
                                        cx_s5,
                                        cy_s5,
                                        ROTATION=rot_s5)

    # STRUT 6
    rot_s6 = 102.44 + clock_deg  # degrees
    cx_s6, cy_s6 = _get_strut_cxy(-27.1434, 22.2242)
    proper.prop_rectangular_obscuration(wf,
                                        sx_s,
                                        sy_s,
                                        cx_s6,
                                        cy_s6,
                                        ROTATION=rot_s6)

    mask = np.fft.ifftshift(np.abs(wf.wfarr))

    if rot180deg:
        mask = np.rot90(mask, 2)

    return mask
Esempio n. 10
0
def pupil(wfo, CAL, npupil, diam, r_obstr, spiders_width, spiders_angle,
          pupil_file, missing_segments_number, Debug, Debug_print):

    n = int(proper.prop_get_gridsize(wfo))

    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 CAL == 0:  # CAL=1 is for the back-propagation
            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:
        PACKAGE_PATH = os.path.abspath(os.path.join(__file__, os.pardir))
        if (missing_segments_number == 1):
            pupil = fits.getdata(
                PACKAGE_PATH +
                '/ELT_2048_37m_11m_5mas_nospiders_1missing_cut.fits')
        if (missing_segments_number == 2):
            pupil = fits.getdata(
                PACKAGE_PATH +
                '/ELT_2048_37m_11m_5mas_nospiders_2missing_cut.fits')
        if (missing_segments_number == 4):
            pupil = fits.getdata(
                PACKAGE_PATH +
                '/ELT_2048_37m_11m_5mas_nospiders_4missing_cut.fits')
        if (missing_segments_number == 7):
            pupil = fits.getdata(
                PACKAGE_PATH +
                '/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

        if CAL == 0:  # CAL=1 is for the back-propagation
            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

    return
Esempio n. 11
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
Esempio n. 12
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)
Esempio n. 13
0
def lyotstop(wf, 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 (RAVC==True): # define the inner radius of the Lyot Stop
        t1_opt = 1. - 1./4*(r_obstr**2 + r_obstr*(math.sqrt(r_obstr**2 + 8.))) # define the apodizer transmission [Mawet2013]
        R1_opt = (r_obstr/math.sqrt(1. - t1_opt)) # define teh apodizer radius [Mawet2013]
        r_LS = R1_opt + LS_parameters[1] # when a Ring apodizer is present, the inner LS has to have at least the value of the apodizer radius
    else:
        r_LS = r_obstr + LS_parameters[1] # when no apodizer, the LS has to have at least the radius of the pupil central obstruction
    if LS==True: # apply the LS
        if (Debug_print==True):
            print("LS parameters: ", LS_parameters)
        proper.prop_circular_aperture(wf, LS_parameters[0], LS_misalignment[0], LS_misalignment[1], NORM=True)
        proper.prop_circular_obscuration(wf, r_LS, LS_misalignment[0], LS_misalignment[1], NORM=True)
        if (LS_parameters[2]!=0):
            for iter in range(0,len(spiders_angle)):
                if (Debug_print==True):
                    print("LS_misalignment: ", LS_misalignment)
                proper.prop_rectangular_obscuration(wf, LS_parameters[2], 2*diam,LS_misalignment[0], LS_misalignment[1], ROTATION=spiders_angle[iter]) # define the spiders

    
    if (isinstance(LS_phase_apodizer_file, (list, tuple, np.ndarray)) == True):
        xc_pixels = int(LS_misalignment[3]*npupil)
        yc_pixels = int(LS_misalignment[4]*npupil)
        apodizer_pixels = (LS_phase_apodizer_file.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)
        apodizer_scale = cv2.resize(phase_apodizer_file.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 ("apodizer_resample", apodizer_scale.shape)
        apodizer_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)
        apodizer_large[int(n/2)+1-int(npupil/2)-1 + xc_pixels:int(n/2)+1+int(npupil/2)+ xc_pixels,int(n/2)+1-int(npupil/2)-1+ yc_pixels:int(n/2)+1+int(npupil/2)+ yc_pixels] =apodizer_scale # insert the scaled pupil into the 0s grid
        phase_multiply = np.array(np.zeros((n,n)), dtype=complex) # create a complex array
        phase_multiply.imag = apodizer_large # define the imaginary part of the complex array as the atm screen
        apodizer = np.exp(phase_multiply)
        proper.prop_multiply(wf, apodizer)
        if (Debug == True):
            fits.writeto(path + 'LS_apodizer.fits', proper.prop_get_phase(wf), overwrite=True)

    
    
    if (isinstance(LS_amplitude_apodizer_file, (list, tuple, np.ndarray)) == True):
        xc_pixels = int(LS_misalignment[0]*npupil)
        yc_pixels = int(LS_misalignment[1]*npupil)
        apodizer_pixels = (LS_amplitude_apodizer_file.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)
            apodizer_scale = cv2.resize(amplitude_apodizer_file.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 ("apodizer_resample", apodizer_scale.shape)
        apodizer_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)
        apodizer_large[int(n/2)+1-int(npupil/2)-1 + xc_pixels:int(n/2)+1+int(npupil/2)+ xc_pixels,int(n/2)+1-int(npupil/2)-1+ yc_pixels:int(n/2)+1+int(npupil/2)+ yc_pixels] =apodizer_scale # insert the scaled pupil into the 0s grid
        apodizer = apodizer_large
        proper.prop_multiply(wf, apodizer)
        if (Debug == True):
            fits.writeto(path + 'LS_apodizer.fits', proper.prop_get_amplitude(wf), overwrite=True)





    return
Esempio n. 14
0
def vortex(wfo, CAL, charge, f_lens, path, Debug_print):

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

    if charge != 0:
        if CAL == 1:  # create the vortex for a perfectly circular pupil
            if (Debug_print == True):
                print("CAL:1, charge ", charge)
            writefield(path, 'zz_psf', wfo.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_complex = np.array(np.zeros((nramp,nramp)), dtype=complex)
            #vvc_tmp_complex.imag = ofst + ramp_sign*charge*theta
            #vvc_tmp = np.exp(vvc_tmp_complex)
            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(path, 'zz_vvc',
                       vvc)  # write the theoretical vortex field
            wfo0 = wfo
            proper.prop_multiply(wfo, vvc)
            proper.prop_propagate(wfo, f_lens, 'OAP2')
            proper.prop_lens(wfo, f_lens)
            proper.prop_propagate(wfo, f_lens, 'forward to Lyot Stop')
            proper.prop_circular_obscuration(
                wfo, 1., NORM=True)  # null the amplitude iside the Lyot Stop
            proper.prop_propagate(wfo, -f_lens)  # back-propagation
            proper.prop_lens(wfo, -f_lens)
            proper.prop_propagate(wfo, -f_lens)
            writefield(path, 'zz_perf',
                       wfo.wfarr)  # write the perfect-result vortex field
            wfo = wfo0
        else:
            if (Debug_print == True):
                print("CAL:0, charge ", charge)
            vvc = readfield(path,
                            'zz_vvc')  # read the theoretical vortex field
            vvc = proper.prop_shift_center(vvc)
            scale_psf = wfo._wfarr[0, 0]
            psf_num = readfield(path, 'zz_psf')  # read the pre-vortex field
            psf0 = psf_num[0, 0]
            psf_num = psf_num / psf0 * scale_psf
            perf_num = readfield(
                path, 'zz_perf')  # 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

    return
Esempio n. 15
0
def prescription_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)
    beam_ratio = PASSVALUE.get('beam_ratio',
                               0.2)  # 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)
    noabs = PASSVALUE.get('noabs', False)  # Output complex amplitude?
    m1_hole_rad = PASSVALUE.get('m1_hole_rad', None)  # Inner hole diameter
    use_caching = PASSVALUE.get('use_caching',
                                False)  # Use cached files if available?
    get_wf = PASSVALUE.get('get_wf', False)  # Return wavefront
    """
    Prescription for a single quad lens system        
    """

    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']
    elif 'opd_func' not in PASSVALUE:
        print("no phase function")
    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']

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

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

    ###
    # Change to build ciruclar aperture??
    # Input aperture
    proper.prop_circular_aperture(wfo, diam / 2.)
    ###

    # Define entrance
    proper.prop_define_entrance(wfo)

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

    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_hole_rad is not None:
        proper.prop_circular_obscuration(wfo, m1_hole_rad)

    #if get_wf:
    #   wf = proper.prop_get_wavefront(wfo)
    #  print('Got wavefront')

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

    # End
    (wfo, sampling) = proper.prop_end(wfo)
    if get_wf:
        return (wfo, wf, sampling)
    else:
        return (wfo, sampling)
Esempio n. 16
0
def coronagraph(wfo, f_lens, occulter_type, occult_loc, diam):
    # proper.prop_lens(wfo, f_lens, "coronagraph imaging lens")
    # proper.prop_propagate(wfo, f_lens, "occulter")
    # quicklook_wf(wfo)
    # occulter sizes are specified here in units of lambda/diameter;
    # convert lambda/diam to radians then to meters

    lamda = proper.prop_get_wavelength(wfo)
    # print lamda
    occrad = 3  # occulter radius in lam/D
    occrad_rad = occrad * lamda / diam  # occulter radius in radians
    dx_m = proper.prop_get_sampling(wfo)
    dx_rad = proper.prop_get_sampling_radians(wfo)
    occrad_m = occrad_rad * dx_m / dx_rad  # occulter radius in meters
    # print occrad_m, occulter_type
    # print 'line 22.', occulter_type
    #plt.figure(figsize=(12,8))
    # quicklook_wf(wfo)
    if occulter_type == "Gaussian":
        r = proper.prop_radius(wfo)
        h = np.sqrt(-0.5 * occrad_m**2 / np.log(1 - np.sqrt(0.5)))  #*0.8
        gauss_spot = 1 - np.exp(-0.5 * (r / h)**2)
        # print occult_loc
        # gauss_spot = np.roll(gauss_spot,occult_loc,(0,1))
        gauss_spot = shift(gauss_spot, shift=occult_loc, mode='wrap')
        proper.prop_multiply(wfo, gauss_spot)
        # quicklook_wf(wfo)
        #plt.suptitle("Gaussian spot", fontsize = 18)
    elif occulter_type == "Solid":
        proper.prop_circular_obscuration(wfo, occrad_m * 4. / 3)
        #plt.suptitle("Solid spot", fontsize = 18)
        # quicklook_wf(wfo)
    elif occulter_type == "8th_Order":
        proper.prop_8th_order_mask(wfo, occrad * 3. / 4., CIRCULAR=True)
        # quicklook_wf(wfo)
    elif occulter_type == 'Vortex':
        # print('lol')
        # apodization(wfo, True)
        vortex(wfo)
        # lyotstop(wfo, True)

        #plt.suptitle("8th order band limited spot", fontsize = 18)
    # quicklook_wf(wfo, logAmp=False, show=True)
    # After occulter
    # plt.subplot(1,2,1)
    # plt.imshow(np.sqrt(proper.prop_get_amplitude(wfo)), origin = "lower", cmap = plt.cm.gray)
    # plt.text(200, 10, "After Occulter", color = "w")
    # plt.show()
    # quicklook_wf(wfo)

    proper.prop_propagate(wfo, f_lens, "pupil reimaging lens")
    # quicklook_wf(wfo)
    proper.prop_lens(wfo, f_lens, "pupil reimaging lens")
    # quicklook_wf(wfo)
    proper.prop_propagate(wfo, 2 * f_lens, "lyot stop")
    # quicklook_wf(wfo)

    # from numpy.fft import fft2, ifft2
    # wfo.wfarr = fft2(wfo.wfarr) #/ np.size(wfo.wfarr)
    # quicklook_wf(wfo)

    # plt.subplot(1,2,2)
    # plt.imshow(proper.prop_get_amplitude(wfo)**0.2, origin = "lower", cmap = plt.cm.gray)
    # plt.text(200, 10, "Before Lyot Stop", color = "w")
    # plt.show()
    # quicklook_wf(wfo,logAmp=False, show=True)

    if occulter_type == "Gaussian":
        # quicklook_wf(wfo)
        proper.prop_circular_aperture(wfo, 0.75, NORM=True)
    elif occulter_type == "Solid":
        # quicklook_wf(wfo)
        proper.prop_circular_aperture(wfo, 0.84, NORM=True)
    elif occulter_type == "8th_Order":
        # quicklook_wf(wfo)
        proper.prop_circular_aperture(wfo, 0.75, NORM=True)  #0.5
    elif occulter_type == "Vortex":
        # proper.prop_circular_aperture(wfo, 0.98, NORM = True) #0.5
        lyotstop(wfo, True)
        # quicklook_wf(wfo)
    elif occulter_type == "None (Lyot Stop)":
        proper.prop_circular_aperture(wfo, 0.8, NORM=True)

    proper.prop_propagate(wfo, f_lens, "reimaging lens")
    # errs = np.sqrt(proper.prop_get_amplitude(wfo))
    # # plt.figure()
    # # plt.imshow(errs)
    # # plt.show()
    # quicklook_wf(wfo)
    proper.prop_lens(wfo, f_lens, "reimaging lens")
    # quicklook_wf(wfo)
    proper.prop_propagate(wfo, f_lens, "final focus")
    # from numpy.fft import fft2, ifft2
    # wfo.wfarr = fft2(wfo.wfarr) / np.size(wfo.wfarr)
    # quicklook_wf(wfo)
    return