def testwave(): """ Verify wavefront reconstruction is occurring properly Coefficients can be altered in zernsurf and then resulting wavefront can be examined for the appropriate structure. """ #Set up Zernike wave rays = sources.circularbeam(1., 10000) surf.zernsurf(rays, [0, 0, 0, .00, .001], 1.) tran.reflect(rays) r = anal.wavefront(rays, 200, 200) return r
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
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()
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 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
# 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) # Go to optic focus. surfaces.focusX(rays) # Define grating parameters. d = 160. # Groove period @ 3300 mm [nm] L = 3250. # Center of grating [mm] d *= L / 3300 # Find groove period at center of grating.
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)
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)
# Create new ray object with only these rays. ind_rays = [r[ind] for r in rays] # Propagate these photons to primary mirror. surfaces.wolterprimary(ind_rays, r_int[i], z0) # Find which photons interact with this mirror. ind = np.where((ind_rays[3] > (z0 + mirror_sep / 2)) & (ind_rays[3] < (z0 + mirror_sep / 2 + mirror_length)))[0] # Keep only the photons which interact with the actual size # of the mirror ind_rays = [r[ind] for r in ind_rays] # Reflect photons off of primary. trans.reflect(ind_rays) # # Add Beckmann + Gaussian scatter. # # ogre.beckmann_scatter(ind_rays, 0, 0, 2e-5) # ind_rays[4] = ind_rays[4] + np.random.normal(scale=1e-7, size=len(ind_rays[4])) # ind_rays[5] = ind_rays[5] + np.random.normal(scale=1e-6, size=len(ind_rays[5])) # ind_rays[6] = -np.sqrt(1. - ind_rays[5]**2 - ind_rays[4]**2) # Propagate photons to the secondary mirror. surfaces.woltersecondary(ind_rays, r_int[i], z0) # Find which photons will interact with hyperboloid. ind = np.where((ind_rays[3] < (z0 - mirror_sep / 2)) & (ind_rays[3] > (z0 - mirror_sep / 2 - mirror_length)))[0] # keep only photons which interact with mirror.