Esempio n. 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
Esempio n. 2
0
def wolterprimarynode(rays,r0,z0,psi=1.):
    """Place Wolter node at current origin,
    focus at (-r0,0,-z0)
    """
    tran.transform(rays,-r0,0,-z0,0,0,0)
    wolterprimary(rays,r0,z0,psi)
    tran.itransform(rays,-r0,0,-z0,0,0,0)
    return
Esempio n. 3
0
def focus(rays,fn,weights=None,nr=None,coords=None):
    dz1 = fn(rays,weights=weights)
    tran.transform(rays,0,0,dz1,0,0,0,coords=coords)
    flat(rays,nr=nr)
    dz2 = fn(rays,weights=weights)
    tran.transform(rays,0,0,dz2,0,0,0,coords=coords)
    flat(rays,nr=nr)
    
    return dz1+dz2
Esempio n. 4
0
def plotNodeSpacing(rsec,smax,pmin,fun,nodegap,L=200.,pbeam=True):
    """
    Plot mirror positions and beam extent for each mirror node
    """
    plt.figure('Nodes')
    plt.clf()
    for i in range(len(smax)):
        for r in rsec[i]:
            #Mirror parameters
            z = np.sqrt(1e4**2-r**2)
            psi = np.polyval(fun[i],r)
            psi = np.max([.01,psi])
            #Plot mirrors
            rp1 = wsPrimrad(pmin[i]+L,r,z,psi)
            rp2 = wsPrimrad(pmin[i],r,z,psi)
            rs1 = wsSecrad(smax[i],r,z,psi)
            rs2 = wsSecrad(smax[i]-L,r,z,psi)
            plt.plot([rp1,rp2],[pmin[i]+L,pmin[i]],'k')
            plt.plot([rs1,rs2],[smax[i],smax[i]-L],'k')

            if np.where(r==rsec[i])[0] == 136:
                pdb.set_trace()

            if pbeam is True:
                #Plot beam
                #Set up ray
                ray = sources.pointsource(0.,1)
                ray[6] = -ray[6]
                ray[1][0] = rp1
                tran.transform(ray,0,0,-1e4,0,0,0)

                #Trace to shell
                surf.wsPrimary(ray,r,z,psi)
                tran.reflect(ray)
                surf.wsSecondary(ray,r,z,psi)
                tran.reflect(ray)
                rb1 = ray[1][0]
                z1 = ray[3][0]

                #Set up ray
                ray = sources.pointsource(0.,1)
                ray[6] = -ray[6]
                ray[1][0] = rp2
                tran.transform(ray,0,0,-1e4,0,0,0)

                #Trace to shell
                surf.wsPrimary(ray,r,z,psi)
                tran.reflect(ray)
                surf.wsSecondary(ray,r,z,psi)
                tran.reflect(ray)
                rb2 = ray[1][0]
                z2 = ray[3][0]

                plt.plot([rp1,rp1,rb1,0],[1e4+500.,pmin[i]+L,z1,0],'b--')
                plt.plot([rp2,rp2,rb2,0],[1e4+500.,pmin[i],z2,0],'b--')
    return None
Esempio n. 5
0
def make_xou_source(clock_angle, wave, N, source_dist):
    prays = source.subannulus(700, 740, 0.10, N, zhat=-1.)
    tran.transform(prays, 0., 0., 0., 0., 0., clock_angle - pi / 2)
    tran.pointTo(prays, 0., mean([705, 745]), source_dist, reverse=1)
    if type(wave) == float:
        wavedist = zeros(N) + wave
    else:
        wavedist = wave.draw_waves(N)
    xou_rays = ArcRays.ArcusRays(prays, wavedist)
    return xou_rays
Esempio n. 6
0
def tanSphere(rays,rad,nr=None):
    """
    Wrapper for spherical surface placed tangent to XY plane
    Positive radius of curvature curves toward the +Z direction
    """
    #Go to center of curvature
    tran.transform(rays,0,0,rad,0,0,0)
    #Place sphere
    sphere(rays,rad,nr=nr)
    #Go back to tangent plane
    tran.transform(rays,0,0,-rad,0,0,0)
    return
Esempio n. 7
0
def wsSecrad(z,r0,z0,psi=1.):
    """
    Determine radius of WS primary
    """
    #Set up ray
    ray = sources.pointsource(0.,1)
    tran.transform(ray,0,0,0,0,-np.pi/2,0)
    tran.transform(ray,-r0-2.,0,-z,0,0,0)

    surf.wsSecondary(ray,r0,z0,psi)

    return ray[1][0]
Esempio n. 8
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
Esempio n. 9
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)
Esempio n. 10
0
def ellipsoidPrimary(rays,R0,F,S,psi):
    """
    Trace rays to the primary of an ellipsoid-hyperboloid
    telescope.
    Call at focus, just like with Wolter-I
    """
    #Compute ellipsoid parameters
    P,a,b,e,f = con.ellipsoidFunction(S,psi,R0,F)
    R = b**2/a

    #Move to vertex
    tran.transform(rays,0,0,F+f-P-a,0,0,0)
    #Call conic
    conic(rays,R,-e**2)
    #Go back to focus
    tran.itransform(rays,0,0,F+f-P-a,0,0,0)

    return
Esempio n. 11
0
def testTransverseSecondary(r0, z0, zeta=1., offz=0., dx=0.):
    """
    Launch rays perpendicular to optical axis toward mirror.
    """
    #Set up source
    rays = sources.rectbeam(z0, r0, 1e4)
    tran.transform(rays, 0, 0, 0, 0, np.pi / 2, 0)
    tran.transform(rays, -r0 + dx, 0, -z0, 0, 0, 0)

    #Apply offaxis angle
    rays[6] = rays[6] + offz
    rays[4] = -np.sqrt(1 - rays[6]**2)

    #Trace to primary
    zi = np.copy(rays[3])
    yi = np.copy(rays[2])
    surf.wsSecondary(rays, r0, z0, zeta)

    return rays, yi, zi
Esempio n. 12
0
def testNormalSecondary(r0, z0, zeta=1., offx=0., dz=0.):
    """
    Launch a slit of rays toward the mirror from infinity.
    Return the 
    """
    #Set up source
    rays = sources.circularbeam(r0 * 2, 1e4)
    tran.transform(rays, 0, 0, -z0 + dz, 0, 0, 0)

    #Apply offaxis angle
    rays[4] = rays[4] + offx
    rays[6] = -np.sqrt(1 - rays[4]**2)

    #Trace to primary
    xi = np.copy(rays[1])
    yi = np.copy(rays[2])
    surf.wsSecondary(rays, r0, z0, zeta)

    return rays, xi, yi
Esempio n. 13
0
def onaxisMerit(pmin,smax,R0=220.,Z0=1e4,L=200.,psi=1.):
    """
    Trace rays for a given shell and determine amount of rays vignetted
    """
    #Set up aperture
    a0 = wsPrimrad(pmin,R0,Z0,psi)
    a1 = wsPrimrad(pmin+L,R0,Z0,psi)
    rays = sources.annulus(a0,a1,1e3)
    tran.transform(rays,0,0,-Z0,0,0,0)

    #Trace to primary
    surf.wsPrimary(rays,R0,Z0,psi)
    tran.reflect(rays)

    #Trace to secondary
    surf.wsSecondary(rays,R0,Z0,psi)

    #Determine fraction of rays vignetted
    try:
        return np.sum(np.logical_or(rays[3]<smax-L,rays[3]>smax)),np.mean(rays[3])
    except:
        pdb.set_trace()
Esempio n. 14
0
def traceZeta(pmin,R0=220.,Z0=1e4,psi=1.,offaxis=0.,L=200.,az=100.,pause=False):
    """
    Set initial aperture based on height of bottom of mirror
    above node (pmin). Assume 100 mm long mirrors.
    Then, trace to secondary and mark smin and smax for
    where the rays strike.
    Then trace out off axis field positions and determine
    RMS and HPD vs angle.
    """
    #Set up aperture
    a0 = wsPrimrad(pmin,R0,Z0,psi)
    a1 = wsPrimrad(pmin+L,R0,Z0,psi) 
    rays = sources.subannulus(a0,a1,az/R0,1e4)
    tran.transform(rays,0,0,-Z0,0,0,0)

    #Trace to primary and add off-axis angle
    surf.wsPrimary(rays,R0,Z0,psi)
    rays[4] = rays[4]+np.sin(offaxis)
    rays[6] = -np.sqrt(1.-rays[4]**2)
    tran.reflect(rays)

    #Trace to secondary
    surf.wsSecondary(rays,R0,Z0,psi)
    tran.reflect(rays)
    smax = np.nanmax(rays[3])
    smin = np.nanmin(rays[3])
    if pause is True:
        pdb.set_trace()

    #Go to focus
    f = surf.focusI(rays)

    #Compute merit functions
    hpd = anal.hpd(rays)
    rms = anal.rmsCentroid(rays)

    return smin,smax,f,hpd,rms
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)
Esempio n. 16
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
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
Esempio n. 18
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)
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
Esempio n. 20
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)
z_in = z0 + mirror_sep / 2
z_out = z_in + mirror_len

r_in = conic.primrad(z_in, r0, z0)
r_out = conic.primrad(z_out, r0, z0)

# Define full angular width of subannulus.
dphi = np.radians(30.)

# # Define subannulus of rays.
rays = sources.subannulus(r_in, r_out, dphi, 1000000)

# rays = np.loadtxt('rays.txt')

# Rotate so that dispersion direction is in the x-dimension.
trans.transform(rays, 0, 0, 0, 0, 0, -np.pi / 2)

# Find centroid of rays and move rays down to center of beamline.
cen_optic = analyses.centroid(rays)

trans.transform(rays, 0, cen_optic[1], 0, 0, 0, 0)
trans.transform(rays, 0, -30, 0, 0, 0, 0)

# Change ray direction cosines to emanate from source (48 m away).
hyp = np.sqrt(L**2 + rays[1]**2 + rays[2]**2)
l = rays[1] / hyp
m = rays[2] / hyp
n = -np.sqrt(1. - l**2 - m**2)
rays = [rays[0], rays[1], rays[2], rays[3], l, m, n, rays[7], rays[8], rays[9]]

# Shift rays back up.
# Define Wolter-I parameters.
r0 = 165.  # Radius at the intersection plane of primary/secondary.
z0 = 3500.  #
mirror_len = 100.
mirror_sep = 5.

# Define inner & outer radii to create rays.
rp_front = conic.primrad(z0 + mirror_sep / 2 + mirror_len, r0, z0)
rp_back = conic.primrad(z0 + mirror_sep / 2, r0, z0)

# Define initial rays in subannulus.
rays = sources.subannulus(rp_back, rp_front, np.radians(30.), 100000)

# Transform rays to intersection plane of optic.
trans.transform(rays, 0, 0, -z0, 0, 0, 0)

# Rotate 90 degrees so that diffraction occurs in x-axis.
trans.transform(rays, 0, 0, 0, 0, 0, -np.radians(90.))

# Pass through primary.
surfaces.wolterprimary(rays, r0, z0)
trans.reflect(rays)

# # Add some scatter.
ogre.beckmann_scatter(rays, 0, 0, 1.48e-5)

# Pass through secondary.
surfaces.woltersecondary(rays, r0, z0)
trans.reflect(rays)
Esempio n. 23
0
z_in = z0 + mirror_sep / 2
z_out = z_in + mirror_length

r_in = conic.primrad(z_in, r_int[0], z0)
r_out = conic.primrad(z_out, r_int[-1], z0)

# Define full angular width of subannulus.
dphi = np.radians(30.)

# Define subannulus of rays.
rays = sources.subannulus(r_in, r_out, dphi, num)

np.save('originalpyxfrays.npy', rays)

# Rotate so that dispersion direction is in the x-dimension.
trans.transform(rays, 0, 0, 0, 0, 0, -np.pi / 2)

# Find centroid of rays and move rays down to center of beamline.
cen_optic = analyses.centroid(rays)

trans.transform(rays, 0, cen_optic[1], 0, 0, 0, 0)
trans.transform(rays, 0, -30, 0, 0, 0, 0)

# Change ray direction cosines to emanate from source (48 m away).
hyp = np.sqrt(L**2 + rays[1]**2 + rays[2]**2)
l = rays[1] / hyp
m = rays[2] / hyp
n = -np.sqrt(1. - l**2 - m**2)
rays = [rays[0], rays[1], rays[2], rays[3], l, m, n, rays[7], rays[8], rays[9]]

# Shift rays back up.