Exemple #1
0
def littrow():
    """
    Trace rectangular beam into OPG in Littrow.
    400 nm groove period
    8.4 m groove convergence
    """
    #Set up beam
    rays = sources.rectArray(50., 50., 1e2)

    #Trace to Littrow and diffract
    tran.transform(rays, 0, 0, 0, 0, 52.28 * np.pi / 180, 0)
    surf.flat(rays)
    tran.transform(rays, 0, 8400., 0, 0, 0, 0)
    tran.radgrat(rays, 400. / 8400., 1, 632.8)

    #Steer out beam tilt
    tran.steerX(rays)
    tran.steerY(rays)

    #Bring rays to common plane
    surf.flat(rays)

    #Get wavefront
    r = anal.wavefront(rays, 200, 200)

    return r
Exemple #2
0
def trace_gwat(gwat_xous=gwat_xous,
               gwat_facets=gwat_facets,
               order=order,
               wave=wave,
               N=10**5,
               diff_focus_zloc=None):
    # Tracing from the source through the SPO MMs.
    gwat_rays = gwatf.make_gwat_source(N, wave, gwathw.source_dist,
                                       gwathw.clock_angles)
    spomm_rays = ArcSPO.SPOPetalTrace(gwat_rays, gwat_xous)

    # I'm now doing this rather than what's embedded in the facet calculation. Is it bad? Time will tell.
    # Computing the SPO focus characteristics, the focal length, and the effective radius.
    focused_spo_rays, dz = gwatf.bring_rays_to_disp_focus(spomm_rays)
    xFocus, yFocus, zFocus = array(
        [mean(focused_spo_rays.x),
         mean(focused_spo_rays.y), -dz])

    # Now creating a saved version of the SPO MM rays (spomm_rays) and readying a set of rays
    # referenced to the SPO focus for tracing.
    system_spo_rays = copy.deepcopy(spomm_rays)
    prays = system_spo_rays.yield_prays()
    tran.transform(prays, xFocus, yFocus, -zFocus, 0., 0., 0.)
    system_spo_rays.set_prays(prays)

    # Setting the GWAT order in accordance with this function for "order selection".
    gwatf.set_gwat_order(order, facets=gwat_facets)

    # And now tracing the rays through the adjusted CAT petal.
    grat_rays = ArcCAT.CATPetalTrace(system_spo_rays, gwat_facets)

    ## Focusing the diffracted rays.
    #meas_rays = copy.deepcopy(grat_rays)
    #prays = meas_rays.yield_prays()
    #surf.focusX(prays)
    #meas_rays.set_prays(prays)

    # Cleaning up and naming everything appropriately.
    system_spo_rays = system_spo_rays
    system_grat_rays = grat_rays
    system_spo_focused_rays, spo_dz = gwatf.bring_rays_to_disp_focus(
        system_spo_rays)

    if diff_focus_zloc is None:
        system_diff_rays, diff_focus_zloc = gwatf.bring_rays_to_disp_focus(
            system_grat_rays)
        prays = system_diff_rays.yield_prays()
        tran.transform(prays, 0., 0., -diff_focus_zloc, 0., 0., 0)
        system_diff_rays.set_prays(prays)
    else:
        system_diff_rays = copy.deepcopy(system_grat_rays)
        prays = system_diff_rays.yield_prays()
        tran.transform(prays, 0., 0., diff_focus_zloc, 0., 0., 0)
        surf.flat(prays)
        tran.transform(prays, 0., 0., -diff_focus_zloc, 0., 0., 0)
        system_diff_rays.set_prays(prays)

    return system_spo_rays, system_grat_rays, system_spo_focused_rays, system_diff_rays, diff_focus_zloc
Exemple #3
0
def littrow():
    """
    Trace rectangular beam into OPG in Littrow.
    400 nm groove period
    8.4 m groove convergence
    """
    #Set up beam
    rays = sources.rectArray(50., 50., 1e2)

    #Trace to Littrow and diffract
    tran.transform(rays, 0, 0, 0, 0, 52.28 * np.pi / 180, 0)
    surf.flat(rays)
    tran.transform(rays, 0, 8400., 0, 0, 0, 0)
    tran.radgrat(rays, 400. / 8400., 1, 632.8)

    #Steer out beam tilt
    tran.steerX(rays)
    tran.steerY(rays)

    #Bring rays to common plane
    surf.flat(rays)

    #Interpolate slopes to regular grid
    y, dx, dy = anal.interpolateVec(rays, 5, 200, 200)
    x, dx, dy = anal.interpolateVec(rays, 4, 200, 200)

    #Prepare arrays for integration
    #Reconstruct requires nans be replaced by 100
    #Fortran functions require arrays to be packed in
    #fortran contiguous mode
    x = man.padRect(x)
    y = man.padRect(y)
    phase = np.zeros(np.shape(x), order='F')
    phase[np.isnan(x)] = 100.
    x[np.isnan(x)] = 100.
    y[np.isnan(y)] = 100.
    y = np.array(y, order='F')
    x = np.array(x, order='F')

    #Reconstruct and remove border
    phase = reconstruct.reconstruct(x, y, 1e-12, dx, phase)
    phase[phase == 100] = np.nan
    x[x == 100] = np.nan
    y[y == 100] = np.nan

    return man.stripnans(phase), man.stripnans(x), man.stripnans(y)
def get_corner_throughput_frac(module_width=150 * u.mm):
    '''
    Returns percentage of incident photons from optic that will not
    interact with gratings in the OGRE grating array and will instead
    make it to the central CCD.

    Parameters
    ----------
    module_width : Quantity
        Total width of OGRE grating module, centered at x=0.

    Returns
    -------
    throughput_frac : float
        Fraction of photons that do not interact with the OGRE
        grating array.
    '''

    # Define rays.
    rays = ogre.create_rays()

    # Pass through optic.
    rays = ogre.ogre_mirror_module(rays, scatter='bg')

    # Move to center of OGRE grating module.
    z_cen = np.mean(np.concatenate((ogre.zg_cen_left, ogre.zg_cen_right)))
    trans.transform(rays, 0, 0, z_cen, 0, 0, 0)
    surfaces.flat(rays)

    # Find starting fraction.
    start_frac = len(rays[1])

    # How many get through.
    ind = np.where(abs(rays[1]) > module_width.to('mm').value / 2)[0]

    return len(ind) / float(start_frac)
Exemple #5
0
def traceSingleRay(rtrace,zexit,R0,Z0,zeta,rpos=False):
    """
    Trace single ray through WS shell and return
    ray at a given exit aperture z position
    """
    #Set up ray
    ray = sources.pointsource(0.,1)
    ray[6] = -ray[6]
    ray[1][0] = rtrace
    tran.transform(ray,0,0,-Z0,0,0,0)

    #Trace to shell
    surf.wsPrimary(ray,R0,Z0,zeta)
    tran.reflect(ray)
    surf.wsSecondary(ray,R0,Z0,zeta)
    tran.reflect(ray)
    if rpos is True:
        return ray[1][0],ray[3][0]

    #Go to exit aperture
    tran.transform(ray,0,0,zexit,0,0,0)
    surf.flat(ray)
    
    return ray
# Go to center of grating.
conv_length = L / np.cos(gammy)
trans.transform(rays, 0, 0, conv_length, 0, 0, 0, coords=glob_coords)

# Add incidence angle.
trans.transform(rays, 0, 0, 0, gammy, 0, 0, coords=glob_coords)

# Get +y in groove direction.
trans.transform(rays, 0, 0, 0, -np.pi / 2, 0, 0, coords=glob_coords)
trans.transform(rays, 0, 0, 0, 0, 0, np.pi, coords=glob_coords)

# Add yaw.
trans.transform(rays, 0, 0, 0, 0, 0, yaw, coords=glob_coords)

# Project rays onto grating surface.
surfaces.flat(rays)

# Move to coordinate system to hub location (required for radgrat).
trans.transform(rays, 0, -L, 0, 0, 0, 0, coords=glob_coords)

good_ind = np.where((rays[2] < 3300.) & (rays[2] > 3200.))[0]
rays = [r[good_ind] for r in deepcopy(rays)]

# Reflect rays.
trans.reflect(rays)

ys = np.array(rays[2]).copy()
zero_point = L + 50
ys -= zero_point
ys *= -1e6
def get_grating_throughput_frac(mid_width=5 * u.mm,
                                edge_support_width=5 * u.mm,
                                grat_thickness=ogre.grating_thickness,
                                rib_width=2 * u.mm,
                                rib_num=3,
                                module_width=150 * u.mm):
    '''
    Returns percentage of incident photons from optic that will interact
    with gratings in the OGRE grating array.

    Parameters
    ----------
    mid_width : Quantity
        Width between two grating stacks in grating module.
    edge_support_width : Quantity
        Width of left/right outside support in grating module.
    grat_thickness : Quantity
        Thickness of grating in OGRE grating stack.
    rib_width : Quantity
        Width of individual rib on wedged grating substrate.
    rib_num : Quantity
        Number of ribs on wedged grating substrate.
    module_width : Quantity
        Total width of OGRE grating module, centered at x=0.

    Returns
    -------
    throughput_frac : float
        Fraction of photons that interact with gratings in the OGRE
        grating array.
    '''

    # Create rays.
    rays = ogre.create_rays(n=1000000)

    # Pass them through the optic with Beckmann + Gaussian scatter.
    rays = ogre.ogre_mirror_module(rays, scatter='bg')

    # Move them to the mean grating center point.
    z_mean = (np.mean(ogre.zg_cen_left) + np.mean(ogre.zg_cen_right)) / 2
    trans.transform(rays, 0, 0, z_mean.to('mm').value, 0, 0, 0)
    surfaces.flat(rays)

    # Define starting number.
    start_num = len(rays[0])

    # Find photons that hit in between grating stacks.
    center_ind = np.where(np.abs(rays[1]) < mid_width.to('mm').value / 2)[0]

    # Find photons with x-positions g.t. maximal grating stack x-extent.
    outside_ind = np.where(
        np.abs(rays[1]) > (module_width / 2 -
                           edge_support_width).to('mm').value)[0]

    # Find photons that hit ribs.
    grating_width = module_width / 2 - edge_support_width - mid_width / 2

    # Find rib positions.
    rib_cen_positions = np.linspace(
        rib_width.to('mm').value / 2,
        (grating_width - rib_width / 2).to('mm').value,
        rib_num) * u.mm + mid_width / 2
    rib_ind = np.array([], dtype=int)
    for rc in rib_cen_positions:
        ri = np.where((np.abs(rays[1]) > (rc - rib_width / 2).to('mm').value)
                      & (np.abs(rays[1]) <
                         (rc + rib_width / 2).to('mm').value))[0]
        rib_ind = np.concatenate((rib_ind, ri))

    # Account grating thickness.
    thick_ind = np.array([], dtype=int)
    for r in ogre.rg_cen.to('mm').value:
        # Find which rays will hit grating thickness.
        ind = np.where((rays[2] < r)
                       & (rays[2] > r - grat_thickness.to('mm').value))[0]
        # Add to array list.
        thick_ind = np.concatenate((thick_ind, ind))

    # Combine all rays that will be occulted.
    occ_ind = np.concatenate((center_ind, outside_ind, rib_ind, thick_ind))

    # Remove occulted rays.
    rays = [np.delete(r, occ_ind) for r in rays]

    # What is ending number?
    end_num = len(rays[1])

    # print('Starting #: ' + str(start_num))
    # print('Ending #: ' + str(end_num))

    # Fraction of photons making it through?
    frac = float(end_num) / start_num

    return frac
def ogre_simulation_one_channel(waves,
                                orders,
                                j=j,
                                oa_misalign=oa_misalign,
                                g_misalign=g_misalign,
                                s_misalign=s_misalign,
                                m_misalign=m_misalign,
                                cen_width=5 * u.mm,
                                rib_width=2 * u.mm,
                                rib_num=3,
                                edge_width=5. * u.mm,
                                mod_width=150 * u.mm):
    '''
    Simulate rays going through the OGRE spectrometer. This function will
    just simulate rays passing through the spectrometer with
    misalignments, but will not take throughput into consideration. A
    seperate function is needed to correct this output for throughput.

    Parameters
    ----------
    waves : Quantity
        Array of wavelengths to simulate. Each wavelength in the array
        will be associated with one ray (100 wavelengths = 100 rays).
    orders : numpy.ndarray
        Diffraction orders associated with wavelengths passed.
    j : Quantity
        FWHM of the jitter throughout the observation.
    oa_misalign : 
    g_misalign : 
    s_misalign : 
    m_misalign : 

    Returns
    -------
    rays : [opd, x, y, z, l, m, n, nx, ny, nz]
        Rays on the focal plane of the OGRE spectrometer.
    waves : Quantity
        Wavelengths corresponding to each simulated ray.
    orders : array
        Diffracted order of each simulated ray.

    '''

    # Define initial rays.
    n = len(waves)
    rays = ogre.create_rays(10 * n)

    # Translate rays to center of optic assembly.
    rays[3] = np.ones(len(rays[1])) * oa_z_cen
    surfaces.flat(rays)

    # Misalign rays relative to optic assembly.
    trans.transform(rays, 0, 0, 0, oa_pitch, oa_yaw, 0)

    # Move rays to R_INT position. This is just a global offset.
    rays[3] = np.ones(len(rays[1])) * 3500.

    # Add jitter.
    xj = np.random.normal(0, j.to('rad').value, size=len(rays[4]))
    yj = np.random.normal(0, j.to('rad').value, size=len(rays[4]))

    rays[4] += xj
    rays[5] += yj
    rays[6] = np.sqrt(1 - rays[4]**2 - rays[5]**2)

    # Pass rays through optic.
    rays = ogre.ogre_mirror_module(rays, scatter='bg')

    # Randomly select indicies to keep based on count rate analysis.
    n_rays = len(rays[0])
    rand_inds = np.random.choice(np.arange(n_rays, dtype=int),
                                 len(waves),
                                 replace=False)

    # Keep only those selected indicies.
    rays = [r[rand_inds] for r in rays]

    # Add random period error effect.
    rand_fact = np.random.normal(1, 0.000094, size=len(waves))

    # Pass through grating moudle.
    rays, diff_ind = ogre.ogre_grating_module(rays,
                                              waves=waves * orders / rand_fact,
                                              g_misalign=g_misalign,
                                              s_misalign=s_misalign,
                                              m_misalign=m_misalign,
                                              return_diff_ind=True)

    # Keep only wavelength/orders that make it through grating module.
    waves = waves[diff_ind]
    orders = orders[diff_ind]

    # Occult rays that will hit ribs.
    rays, waves, orders = ogre.grating_rib_occultation(rays,
                                                       waves=waves,
                                                       orders=orders)

    # Transform coordinate system to be at center of rotation.
    trans.transform(rays, 0, 0, oa_z_cen, 0, 0, 0)

    # Propagate rays to misaligned plane, simulating center plane of optic assembly.
    surfaces.flat(rays)

    # Transform the rays back by the pitch angle to the optical axis coordinate system.
    trans.itransform(rays, 0, 0, 0, oa_pitch, oa_yaw, 0)

    # Put the rays back at the intersection plane of the ideal optic.
    rays[3] = np.ones(len(rays[3])) * oa_z_cen

    # Misalign in z-hat.
    trans.transform(rays, 0, 0, oa_z, 0, 0, 0)

    # Propagate to the focal plane.
    rays = ogre.ogre_focal_plane(rays,
                                 det_misalignments=[0, 0, 0, 0, 0, -det_z])

    return rays, waves, orders
Exemple #9
0
def traceXRS(rsec,smax,pmin,fun,nodegap,L=200.,Nshell=1e3,energy=1000.,\
             rough=1.,offaxis=0.,rrays=False):
    """
    Using output from defineRx, trace the nodes in a Lynx design.
    Provide number of sections, and the zeta as a function of radius
    interpolation function.
    Calculate node radii iteratively, providing appropriate gaps between
    nodes in order to limit off-axis vignetting.
    """
    gap = L*3e-3+0.4 #.4 mm glass thickness plus vignetting
    #Trace through all shells, computing reflectivity and geometric area
    #for each shell
    previousrho = []
    for i in range(len(smax)):
        #Variable to store radial position of bottom of previous
        #secondary mirror
        previousrho.append(0.)
        for r in rsec[i]:
            #Determine zeta for this shell...must be at least .01
            psi = np.polyval(fun[i],r)
            psi = np.max([.01,psi])
            #Set up aperture
            z = np.sqrt(1e4**2-r**2)
            a0 = wsPrimrad(pmin[i],r,z,psi=psi)
            a1 = wsPrimrad(pmin[i]+L,r,z,psi=psi) 
            rays = sources.annulus(a0,a1,Nshell)
            tran.transform(rays,0,0,-z,0,0,0)

            #Set up weights (cm^2)
            weights = np.repeat((a1**2-a0**2) * np.pi / 100. / Nshell,Nshell)

            #Trace to primary
            surf.wsPrimary(rays,r,z,psi)
            rays[4] = rays[4]+np.sin(offaxis)
            rays[6] = -np.sqrt(1.-rays[4]**2)
            tran.reflect(rays)
            ang = anal.grazeAngle(rays)
            weights = weights*\
                      pol.computeReflectivities(ang,energy,rough,1,cons)[0]

            #Trace to secondary
            surf.wsSecondary(rays,r,z,psi)
            tran.reflect(rays)
            ang = anal.grazeAngle(rays)
            weights = weights*\
                      pol.computeReflectivities(ang,energy,rough,1,cons)[0]

            #Handle vignetting
            ind = np.logical_and(rays[3]>smax[i]-L,rays[3]<smax[i])
            if sum(ind) == 0:
                pdb.set_trace()
            rays = tran.vignette(rays,ind=ind)
            weights = weights[ind]

            #Go to exit aperture and confirm rays don't
            #hit back of previous shell
            tran.transform(rays,0,0,smax[i]-L,0,0,0)
            surf.flat(rays)
            rho = np.sqrt(rays[1]**2+rays[2]**2)
            ind = rho > previousrho[-1]
            #if np.sum(ind)==0:
                #pdb.set_trace()
            if np.sum(~ind) > 100:
                print '%i rays hit back of shell' % np.sum(~ind)
                print r,psi
                #pdb.set_trace()
            rays = tran.vignette(rays,ind=ind)
            weights = weights[ind]
            previousrho.append(wsSecrad(smax[i]-L,r,z,psi=psi)+.4)

            #Go to focus
            if rrays is False:
                tran.transform(rays,0,0,-smax[i]+L,0,0,0)
                surf.flat(rays)

            #Accumulate master rays
            try:
                mrays = [np.concatenate([mrays[ti],rays[ti]]) for ti in range(10)]
                mweights = np.concatenate([mweights,weights])
            except:
                mrays = rays
                mweights = weights


    if rrays is True:
        return mrays,mweights,previousrho

    #Go to focus
    try:
        surf.focusI(rays,weights=weights)
    except:
        pdb.set_trace()

    return anal.hpd(mrays,weights=mweights)/1e4*180/np.pi*60**2,\
           anal.rmsCentroid(mrays,weights=mweights)/1e4*180/np.pi*60**2,\
           np.sum(mweights)
Exemple #10
0
def tracePerfectXRS(L=200.,nodegap=50.,Nshell=1e3,energy=1000.,\
                    rough=1.,offaxis=0.,rrays=False,rnodes=False):
    """
    Trace rays through a perfect Lynx design where all the shells
    are on the spherical principle surface, with zeta equal to unity.
    """
    #Construct node positions
    rad = np.array([200.])
    z = np.sqrt(1e4**2-rad[-1]**2)
    #Gap is projected radial shell plus thickness plus vignetting gap
    rout = wsPrimrad(z+L+nodegap/2.,rad[-1],z)
    gap = L*3e-3 + 0.4
    #Establish radius vector
    rad = np.array([])
    for sec in range(3):
        rout = 0.
        #First node position
        rad = np.append(rad,200.+(1300./3)*sec)
        #rguess = np.linspace(
        while rout+gap < 200.+(1300./3)*(sec+1)-10.: #Need to adjust this condition
            #Compute parameters for current node
            z = np.sqrt(1e4**2-rad[-1]**2)
            rout = wsPrimrad(z+L+nodegap/2.,rad[-1],z)
            rad = np.append(rad,rout+gap)
        rad = rad[:-1]

    if rnodes is True:
        return rad

    #Use radial nodes and trace Lynx, keeping track of effective area
    previousrho = 0.
    for r in rad:
        #Set up aperture
        z = np.sqrt(1e4**2-r**2)
        a0 = wsPrimrad(z+nodegap/2.,r,z)
        a1 = wsPrimrad(z+nodegap/2.+L,r,z) 
        rays = sources.annulus(a0,a1,Nshell)
        tran.transform(rays,0,0,-z,0,0,0)

        #Set up weights (cm^2)
        weights = np.repeat((a1**2-a0**2) * np.pi / 100. / Nshell,Nshell)

        #Trace to primary
        surf.wsPrimary(rays,r,z,1.)
        rays[4] = rays[4]+np.sin(offaxis)
        rays[6] = -np.sqrt(1.-rays[4]**2)
        tran.reflect(rays)
        ang = anal.grazeAngle(rays)
        weights = weights*\
                  pol.computeReflectivities(ang,energy,rough,1,cons)[0]

        #Trace to secondary
        surf.wsSecondary(rays,r,z,1.)
        tran.reflect(rays)
        ang = anal.grazeAngle(rays)
        weights = weights*\
                  pol.computeReflectivities(ang,energy,rough,1,cons)[0]

        #Handle vignetting
        ind = np.logical_and(rays[3]>z-nodegap/2.-L,rays[3]<z-nodegap/2.)
        if sum(ind) == 0:
            pdb.set_trace()
        rays = tran.vignette(rays,ind=ind)
        weights = weights[ind]

        #Go to exit aperture and confirm rays don't - EDIT HERE!
        #hit back of previous shell
        tran.transform(rays,0,0,z-nodegap/2-L,0,0,0)
        surf.flat(rays)
        rho = np.sqrt(rays[1]**2+rays[2]**2)
        ind = rho > previousrho
        #if np.sum(ind)==0:
            #pdb.set_trace()
        if np.sum(~ind) > 100:
            print '%i rays hit back of shell' % np.sum(~ind)
            print r
            #pdb.set_trace()
        rays = tran.vignette(rays,ind=ind)
        weights = weights[ind]
        previousrho = wsSecrad(z-nodegap/2-L,r,z)+.4

        #Go to focus
        try:
            surf.focusI(rays,weights=weights)
        except:
            pdb.set_trace()

        #Accumulate master rays
        try:
            mrays = [np.concatenate([mrays[ti],rays[ti]]) for ti in range(10)]
            mweights = np.concatenate([mweights,weights])
        except:
            mrays = rays
            mweights = weights

    if rrays is True:
        return mrays,mweights

    return anal.hpd(mrays,weights=mweights)/1e4*180/np.pi*60**2,\
           anal.rmsCentroid(mrays,weights=mweights)/1e4*180/np.pi*60**2,\
           np.sum(mweights)