def traceSource(N): """Trace rays from PANTER point source to position of SPO optics """ #Set up subannulus r0 = 737. F = 12e3 L = 4 * F * .605 / r0 tg = .25 * np.arctan(r0 / F) r1 = r0 + L * tg dphi = 50. / r0 / 2 rays = sources.subannulus(r0, r1, dphi, N) #Shift annulus to zero x coordinate tran.transform(rays, r0, 0, 0, 0, 0, 0) #Set ray cosines srcdist = 119471. raydist = sqrt(srcdist**2 + rays[1]**2 + rays[2]**2) l = rays[1] / raydist m = rays[2] / raydist n = -sqrt(1. - l**2 - m**2) rays = [ rays[0], rays[1], rays[2], rays[3], l, m, n, rays[7], rays[8], rays[9] ] #Go to optical axis tran.transform(rays, -r0, 0, 0, 0, 0, 0) return rays
def depthoffocus(rays, weights): tran.transform(rays, 0, 0, -20, 0, 0, 0) surf.flat(rays) lsf = [convolveLSF(rays, .001, marg, weights=weights)] for i in range(80): tran.transform(rays, 0, 0, .5, 0, 0, 0) surf.flat(rays) lsf.append(convolveLSF(rays, .001, marg, weights=weights)) return lsf
def distortTrace(cone1,sag1,roc1,cone2,sag2,roc2,despace=0.,secondaryTilt=0.,\ nominal=True): """ Trace rays through a Wolter mirror pair with low order distortions. Distortions can be applied to either primary or secondary or both. axial sag, azimuthal sag, and cone angle are included. """ #Define ray subannulus r1 = surf.con.primrad(8600., 1000., 8400.) ang = 260. / 1000. #arc length over radius is angular extent rays = sources.subannulus(1000., r1, ang, 10**3) tran.transform(rays, 0, 0, 0, np.pi, 0, 0) #Point in -z tran.transform(rays, 0, 0, -10000, 0, 0, 0) #Converge from above #Trace to primary surf.primaryLL(rays,1000.,8400.,8600,8400,ang,[cone1,sag1,roc1],\ [1,2,0],[0,0,2]) #Vignette rays missing ind = np.logical_and(rays[3] < 8600., rays[3] > 8400.) rays = tran.vignette(rays, ind) numin = float(len(rays[1])) #Reflect tran.reflect(rays) #Apply secondary misalignment tran.transform(rays, surf.con.secrad(8300., 1000., 8400.), 0, 8300, 0, 0, 0) tran.transform(rays, 0, 0, despace, 0, secondaryTilt, 0) tran.itransform(rays, surf.con.secrad(8300., 1000., 8400.), 0, 8300, 0, 0, 0) #Trace to secondary surf.secondaryLL(rays,1000.,8400.,8400.,8200.,ang,[cone2,sag2,roc2],\ [1,2,0],[0,0,2]) #Vignette rays missing ind = np.logical_and(rays[3] < 8400., rays[3] > 8200.) rays = tran.vignette(rays, ind) numout = float(len(rays[1])) #Reflect tran.reflect(rays) #Reverse secondary misalignment tran.transform(rays, surf.con.secrad(8300., 1000., 8400.), 0, 8300, 0, 0, 0) tran.itransform(rays, 0, 0, despace, 0, secondaryTilt, 0) tran.itransform(rays, surf.con.secrad(8300., 1000., 8400.), 0, 8300, 0, 0, 0) #Go to focus if nominal is True: surf.flat(rays) else: surf.focusI(rays) #Return merit function return rays #anal.hpd(rays)/8400.,numout/numin
def sourceToChamber(N, misalign=np.zeros(6)): """ Trace randomly sampled rays from the TruFocus X-ray source to the 1.22 m diameter entrance to the test chamber. A-B from Jeff K.'s memo is 89.61 Use oversized sub-apertured annulus, applying translations """ #Define some Wolter parameters r1 = conic.primrad(8600., 220., 8400.) dphi = 100. / 220. / 2 #Set up subannulus rays = sources.subannulus(220., r1, dphi * 1.25, N) #Set direction cosines srcdist = 89.61e3 + (1.5e3 - misalign[2]) raydist = sqrt(srcdist**2+\ (rays[1]-misalign[0])**2+\ (rays[2]-misalign[1])**2) l = (rays[1] - misalign[0]) / raydist m = (rays[2] - misalign[1]) / raydist n = -sqrt(1. - l**2 - m**2) rays = [ rays[0], rays[1], rays[2], rays[3], l, m, n, rays[7], rays[8], rays[9] ] #Go to mirror node and apply rotational misalignment tran.transform(rays, 220., 0, 0, misalign[3], misalign[4], misalign[5]) tran.transform(rays, -220., 0, 0, 0, 0, 0) #Place Wolter surfaces tran.transform(rays, 0, 0, -8400., 0, 0, 0) surf.wolterprimary(rays, 220., 8400.) tran.reflect(rays) #Vignette rays not landing in active mirror area indz = np.logical_and(rays[3] > 8426., rays[3] < 8526.) ind = np.logical_and(np.abs(rays[2]) < 50., indz) rays = tran.vignette(rays, ind=ind) #Place secondary surf.woltersecondary(rays, 220., 8400.) tran.reflect(rays) #Vignette rays not landing in active mirror area indz = np.logical_and(rays[3] > 8276., rays[3] < 8376.) ind = np.logical_and(np.abs(rays[2]) < 50., indz) rays = tran.vignette(rays, ind=ind) #Go back up to intersection plane tran.transform(rays, 0, 0, 8400, 0, 0, 0) #Reverse misalignments tran.itransform(rays, -220., 0, 0, 0, 0, 0) tran.itransform(rays, 0, 0, 0, misalign[3], misalign[4], misalign[5]) tran.itransform(rays, 220, 0, 0, 0, 0, 0) #Now back in nominal intersection coordinate system #Go to focus f = -9253.3858232 tran.transform(rays, 0, 0, f, 0, 0, 0) surf.flat(rays) return rays #anal.hpd(rays)/abs(f)*60**2*180/pi
def pairRaytrace(secondaryTilt, despace): """Trace the distorted mirror pair. Assume no gap for now. Vignette rays that land outside active mirror areas.""" #Define ray subannulus r1 = surf.con.primrad(8600., 1000., 8400.) ang = 260. / 1000. #arc length over radius is angular extent rays = sources.subannulus(1000., r1, ang, 10**3) tran.transform(rays, 0, 0, 0, np.pi, 0, 0) #Point in -z tran.transform(rays, 0, 0, -10000, 0, 0, 0) #Converge from above #Trace to primary surf.primaryLL(rays, 1000., 8400., 8600, 8400, ang, res[0], res[2], res[1]) #Vignette rays missing ind = np.logical_and(rays[3] < 8600., rays[3] > 8400.) rays = tran.vignette(rays, ind) numin = float(len(rays[1])) #Reflect tran.reflect(rays) #Bring to midplane of despaced secondary #Apply secondary misalignment tran.transform(rays, surf.con.secrad(8300., 1000., 8400.), 0, 8300, 0, 0, 0) tran.transform(rays, 0, 0, despace, 0, secondaryTilt, 0) tran.itransform(rays, surf.con.secrad(8300., 1000., 8400.), 0, 8300, 0, 0, 0) #Trace to secondary surf.secondaryLL(rays, 1000., 8400., 8400., 8200., ang, res2[0], res2[2], res2[1]) #Vignette rays missing ind = np.logical_and(rays[3] < 8400., rays[3] > 8200.) rays = tran.vignette(rays, ind) numout = float(len(rays[1])) #Reflect tran.reflect(rays) #Reverse secondary misalignment tran.transform(rays, surf.con.secrad(8300., 1000., 8400.), 0, 8300, 0, 0, 0) tran.itransform(rays, 0, 0, despace, 0, secondaryTilt, 0) tran.itransform(rays, surf.con.secrad(8300., 1000., 8400.), 0, 8300, 0, 0, 0) #Go to focus surf.focusI(rays) #Get centroid cx, cy = anal.centroid(rays) #Return merit function return anal.rmsCentroid( rays) / 8400. * 180 / np.pi * 60**2, numout / numin, cx, cy
def placeWolterPair(rays, misalign=np.zeros(6)): """ Place the X-ray test mirror pair in the beam path. Assume rays are at XY plane with -z mean direction Nominal position of intersection plane is 1.5 m past chamber entrance with mirror optical axis coincident with chamber optical axis. Can supply misalignment about X=0,Y=0 in intersection plane. """ #Go to nominal intersection plane tran.transform(rays, 0, 0, -1500., 0, 0, 0) #Apply misalignments tran.transform(rays, *misalign) #Go to focus and place primary tran.transform(rays, 0, 0, -8400, 0, 0, 0) pdb.set_trace() surf.wolterprimary(rays, 220., 8400.) tran.reflect(rays) pdb.set_trace() #Vignette rays not landing in active mirror area indz = np.logical_and(rays[3] > 8426., rays[3] < 8526.) ind = np.logical_and(np.abs(rays[2]) < 50., indz) rays = tran.vignette(rays, ind=ind) #Place secondary pdb.set_trace() surf.woltersecondary(rays, 220., 8400.) tran.reflect(rays) #Vignette rays not landing in active mirror area indz = np.logical_and(rays[3] > 8276., rays[3] < 8376.) ind = np.logical_and(np.abs(rays[2]) < 50., indz) rays = tran.vignette(rays, ind=ind) #Go back up to nominal intersection plane tran.transform(rays, 0, 0, 8400, 0, 0, 0) tran.itransform(rays, *misalign) return rays
def alignTolerances(num,azwidth=60.,axwidth=60.,f=None,catalign=np.zeros(6),\ returnrays=False): """ Set up perfect beam and insert CAT grating Mess with alignment and measure spot shift at focus """ #Set up converging beam rays = sources.convergingbeam2(12e3,-azwidth/2.,azwidth/2.,\ -axwidth/2.,axwidth/2.,num,0.) tran.transform(rays, 0, 0, 0, np.pi, 0, 0) tran.transform(rays, 0, 0, 12e3, 0, 0, 0) #Place CAT grating tran.transform(rays, *catalign) surf.flat(rays) tran.grat(rays, 200., 8, 1.) tran.itransform(rays, *catalign) #Go to focus if f is not None: try: tran.transform(rays, 0, 0, f, 0, 0, 0) surf.flat(rays) except: pdb.set_trace() cx, cy = anal.centroid(rays) if returnrays is True: return rays return cx, cy
def createWavefront(rad, num, coeff, rorder=None, aorder=None): """Bounce rays off of Zernike surface. Use flat to bring rays to a common plane, leaving the OPD as twice the figure error of the Zernike surface. """ #Create set of rays rays = sources.circularbeam(rad, num) #Reflect to Zernike surface surf.zernsurf(rays, coeff, rad, nr=1., rorder=rorder, aorder=aorder) tran.reflect(rays) tran.transform(rays, 0, 0, 0, np.pi, 0, 0) surf.flat(rays, nr=1.) #Wavefront now has the proper Zernike form, rays pointing in #+z direction return rays
def singleOptic(N, misalign=np.zeros(6)): """Trace single primary mirror from SLF finite source distance. """ #Define some Wolter parameters r1 = conic.primrad(8600., 220., 8400.) dphi = 100. / 220. / 2 #Set up subannulus rays = sources.subannulus(220., r1, dphi * 1.25, N) ## #Set direction cosines ## srcdist = 89.61e3+(1.5e3-misalign[2]) ## raydist = sqrt(srcdist**2+\ ## (rays[1]-misalign[0])**2+\ ## (rays[2]-misalign[1])**2) ## l = (rays[1]-misalign[0])/raydist ## m = (rays[2]-misalign[1])/raydist ## n = -sqrt(1. - l**2 - m**2) ## rays = [rays[0],rays[1],rays[2],rays[3],l,m,n,rays[7],rays[8],rays[9]] #Go to mirror node and apply rotational misalignment tran.transform(rays, 220., 0, 0, misalign[3], misalign[4], misalign[5]) tran.transform(rays, -220., 0, 0, 0, 0, 0) #Place Wolter surfaces tran.transform(rays, 0, 0, -8400., 0, 0, 0) surf.wolterprimary(rays, 220., 8400.) tran.reflect(rays) #Vignette rays not landing in active mirror area indz = np.logical_and(rays[3] > 8426., rays[3] < 8526.) ind = np.logical_and(np.abs(rays[2]) < 50., indz) rays = tran.vignette(rays, ind=ind) #Go to focus surf.flat(rays) f = surf.focusI(rays) - 8400. return rays #anal.hpd(rays)/abs(f)*180/pi*60**2,abs(f)
def singleOptic2(n,misalign=np.zeros(6),srcdist=89.61e3+1.5e3,az=100.,\ returnRays=False,f=None,\ plist=[[0],[0],[0]],\ ax=100.): """Alternative SLF finite source trace""" #Establish subannulus of rays r0 = conic.primrad(8426., 220., 8400.) r1 = conic.primrad(8426. + ax, 220., 8400.) rays = sources.subannulus(r0, r1, az / 220., n, zhat=-1.) #Transform to node position tran.transform(rays, 220, 0, 0, 0, 0, 0) #Set up finite source distance raydist = sqrt(srcdist**2 + rays[1]**2 + rays[2]**2) l = rays[1] / raydist m = rays[2] / raydist n = -sqrt(1. - l**2 - m**2) rays = [ raydist, rays[1], rays[2], rays[3], l, m, n, rays[7], rays[8], rays[9] ] #Align perfectly to beam tran.steerX(rays) #Apply misalignment tran.transform(rays, *misalign) #Place mirror tran.transform(rays, -220., 0, -8400., 0, 0, 0) ## surf.wolterprimarynode(rays,220,8400.) surf.primaryLL(rays, 220., 8400., 8426. + ax, 8426., az / 220., *plist) rays = tran.vignette(rays,ind=np.logical_and(rays[3]<8400.+ax,\ rays[3]>8400.)) tran.itransform(rays, -220., 0., -8400., 0, 0, 0) #Vignette rays not landing in active mirror area ind = np.logical_and(rays[3] > 26., rays[3] < (26. + ax)) ## ind = np.logical_and(np.abs(rays[2])<az/2.,indz) rays = tran.vignette(rays, ind=ind) #Reverse misalignment tran.itransform(rays, *misalign) #Reflect and go to surface tran.reflect(rays) if f is None: f = surf.focusI(rays) else: tran.transform(rays, 0, 0, f, 0, 0, 0) surf.flat(rays) #Get centroid cx, cy = anal.centroid(rays) if returnRays is True: return rays return anal.hpd(rays) / abs(f) * 180 / pi * 60**2, f, cx
def sourceAlignment(dx, dy, dz): """ Set up a trace of rays from the fiber source to the OAP. Determine wavefront error of collimated beam. """ #Source rays = sources.circularbeam(125. / 4, 10000) tran.pointTo(rays, dx, dy, -775. / 2 + dz, reverse=1) rays[0] = np.sqrt((rays[1] + dx)**2 + (rays[2] + dy)**2 + (775. / 2 + dz)**2) pdb.set_trace() #Go to focus tran.transform(rays, 0, 0, 0, np.pi / 2, 0, 0) tran.transform(rays, 0, -775. / 2, -775. / 2, 0, 0, 0) #Trace to parabola surf.conic(rays, 775., -1., nr=1.) tran.reflect(rays) #Restrict to 5" diameter ## ind = np.logical_and(rays[3]>387.5-62.5,rays[3]<387.5+62.5) ## tran.vignette(rays,ind=ind) #Reflect ## for i in range(7,10): ## rays[i] = -rays[i] tran.transform(rays, 0, 0, 775. / 2, 0, 0, 0) surf.flat(rays, nr=1.) pdb.set_trace() #Get OPD opd, dx0, dy0 = anal.interpolateVec(rays, 0, 200, 200) opd = man.remove2DLeg(opd, xo=1, yo=0) opd = man.remove2DLeg(opd, xo=0, yo=1) pv = ana.ptov(opd) plt.figure('OPD') plt.imshow(opd) plt.colorbar() wavesl = np.gradient(opd, dx0) resy = fit.legendre2d(wavesl[0], xo=2, yo=2) resx = fit.legendre2d(wavesl[1], xo=2, yo=2) resy[0][np.isnan(opd)] = np.nan resx[0][np.isnan(opd)] = np.nan plt.figure('Y') plt.imshow(resy[0] * 180 / np.pi * 60**2) plt.colorbar() plt.figure('X') plt.imshow(resx[0] * 180 / np.pi * 60**2) plt.colorbar() return pv * 1e6
def rayBundle(N, div, az, height, rad): """ Set up a diverging ray bundle on the 220 mm cylinder. """ #Establish rays rays = sources.pointsource(div, N) #Go to cylindrical axis tran.transform(rays, 0, 0, rad, 0, 0, 0) #Apply height offset tran.transform(rays, -height, 0, 0, 0, 0, 0) #Apply azimuthal offset tran.transform(rays, 0, 0, 0, -az, 0, 0) #Go back to tangent plane tran.transform(rays, 0, 0, -rad, 0, 0, 0) surf.flat(rays, nr=1.) return rays
def collectFocalPlaneRays(z): tra2 = np.dot(tr.translation_matrix([40,-100,0]),\ tr.rotation_matrix(pi/2,[0,0,1,0])) rot2 = tr.rotation_matrix(pi / 2, [0, 0, 1, 0]) tra3 = np.dot(tr.translation_matrix([1000,-1000,0]),\ tr.rotation_matrix(-pi/2,[0,0,1,0])) rot3 = tr.rotation_matrix(-pi / 2, [0, 0, 1, 0]) tra4 = np.dot(tr.translation_matrix([1020,920,0]),\ tr.rotation_matrix(pi,[0,0,1,0])) rot4 = tr.rotation_matrix(pi, [0, 0, 1, 0]) f = open( '/home/rallured/Dropbox/Arcus/Raytrace/FocalPlaneLayout/160412_Rays.pkl', 'r') rays = pickle.load(f) f.close() rays2 = np.copy(rays) rays2 = [rays2[0],rays2[1],-rays2[2],rays2[3],\ rays2[4],-rays2[5],rays2[6],\ rays2[7],rays2[8],rays2[9]] rays3 = np.copy(rays) rays3 = [rays3[0],rays3[1],-rays3[2],rays3[3],\ rays3[4],-rays3[5],rays3[6],\ rays3[7],rays3[8],rays3[9]] rays4 = np.copy(rays) tran.itransform(rays2, 40, -100, 0, 0, 0, pi / 2) tran.itransform(rays3, 1000, 1000, 0, 0, 0, -pi / 2) tran.itransform(rays4, 1020, 920, 0, 0, 0, pi) #Plot to make sure plt.plot(rays[1], rays[2], '.') plt.plot(rays2[1], rays2[2], '.') plt.plot(rays3[1], rays3[2], '.') plt.plot(rays4[1], rays4[2], '.') #Transform everything up r = [rays, rays2, rays3, rays4] [tran.transform(ri, 0, 0, z, 0, 0, 0) for ri in r] [surf.flat(ri) for ri in r] plt.figure() [plt.plot(ri[1], ri[2], '.') for ri in r]
def singleEllipse(n,misalign=np.zeros(6),srcdist=89.61e3+1.5e3,az=100.,\ returnRays=False,f=None,\ plist=[[0],[0],[0]],\ ax=100.,psi=psiE): """Alternative SLF finite source trace""" #Establish subannulus of rays r0 = conic.primrad(8426., 220., 8400.) r1 = conic.primrad(8426. + ax, 220., 8400.) rays = sources.subannulus(r0, r1, az / 220., n, zhat=-1.) tran.pointTo(rays, 0., 0., srcdist, reverse=1.) #Transform to node position tran.transform(rays, 220, 0, 0, 0, 0, 0) #Apply misalignment tran.transform(rays, *misalign) #Place mirror tran.transform(rays, -220., 0, -8400., 0, 0, 0) ## surf.wolterprimarynode(rays,220,8400.) surf.ellipsoidPrimaryLL(rays,220.,8400.,srcdist,psi,8426.+ax,8426.,\ az/220.,*plist) tran.itransform(rays, -220., 0., -8400., 0, 0, 0) #Vignette rays not landing in active mirror area ind = np.logical_and(rays[3] > 26., rays[3] < (26. + ax)) ## ind = np.logical_and(np.abs(rays[2])<az/2.,indz) rays = tran.vignette(rays, ind=ind) #Reverse misalignment tran.itransform(rays, *misalign) #Reflect and go to surface tran.reflect(rays) if f is None: f = surf.focusI(rays) else: tran.transform(rays, 0, 0, f, 0, 0, 0) surf.flat(rays) #Get centroid cx, cy = anal.centroid(rays) if returnRays is True: return rays return anal.hpd(rays) / abs(f) * 180 / pi * 60**2 #,f,cx
def traceSPO(N,rin=700.,rout=737.,azwidth=66.,srcdist=89.61e3+1.5e3,\ scatter=False): """ Trace a set of rays through an SPO module using a finite source distance. Ignore vignetting, we are only interested in aberrations. Set up a subannulus, apply finite source effect, and then simply translate to inner SPO radius and trace outward. Let x be the radial direction, y the azimuthal """ #Establish subannulus of rays rays = source.subannulus(rin,rout,azwidth/rin,N,zhat=-1.) #Transform to node position mx = np.mean([rin,rout]) tran.transform(rays,mx,0,0,0,0,0) #Set up finite source distance raydist = np.sqrt(srcdist**2+rays[1]**2+rays[2]**2) l = rays[1]/raydist m = rays[2]/raydist n = -np.sqrt(1.-l**2-m**2) rays = [raydist,rays[1],rays[2],rays[3],l,m,n,rays[7],rays[8],rays[9]] #Align perfectly to beam #tran.steerX(rays) tran.transform(rays,0,0,0,0,-np.mean(rays[4]),0) #Move to SPO optical axis and trace through shells tran.transform(rays,-mx,0,0,0,0,0) R = np.arange(rin,rout+.605,.605) rad = np.sqrt(rays[1]**2+rays[2]**2) for r in R: #Collect relevant rays ind = np.logical_and(rad>r,rad<r+.605) if np.sum(ind)==0: continue #Trace them through system surf.spoPrimary(rays,r,12e3,ind=ind) tran.reflect(rays,ind=ind) surf.spoSecondary(rays,r,12e3,ind=ind) tran.reflect(rays,ind=ind) #Rays are now at secondary surfaces, #Add scatter if scatter is True: rays[4] = rays[4] + np.random.normal(scale=15./2.35*5e-6,size=N) rays[5] = rays[5] + np.random.normal(scale=1.5/2.35*5e-6,size=N) rays[6] = -np.sqrt(1.-rays[5]**2-rays[4]**2) return rays
def perfectCyl1m(rays, align=np.zeros(6)): """ Trace rays from perfect cylinder with potential misalignment Assume rays are traced to tangent plane of nominal optic position +z points back toward CGH Leave with reference frame at tangent plane of nominal surface """ #Rotate reference frame so rays impinge toward -z tran.transform(rays, 0, 0, 0, 0, pi, 0) #Apply misalignment tran.transform(rays, *align) #Trace cylinder tran.transform(rays, 0, 0, 1000., 0, 0, 0) #Get cylindrical axis in +x direction tran.transform(rays, 0, 0, 0, 0, 0, pi / 2) surf.cyl(rays, 1000., nr=1.) tran.reflect(rays) tran.itransform(rays, 0, 0, 0, 0, 0, pi / 2) tran.itransform(rays, 0, 0, 1000., 0, 0, 0) #Go back to nominal tangent plane tran.itransform(rays, *align) surf.flat(rays, nr=1.) return
def createWavefront(rad,num,coeff,rorder=None,aorder=None,\ slitwidth=3.,masknum=15,trans=np.zeros(2)): """Bounce rays off of Zernike surface. Use flat to bring rays to a common plane, leaving the OPD as twice the figure error of the Zernike surface. Use subannulus so as not to waste rays in beginning of simulation Group rays for a given mask slit together using a Hartmann vector. Vignette everything else. Assume masknum slits 3 mm wide distributed evenly over the mirror aperture """ #Create set of rays r1 = conic.primrad(8500., 220., 8400.) #Loop through Hartmann mask maskcenters = np.linspace(-48.5 / 220., 48.5 / 220., masknum) for i in range(masknum): trays = sources.subannulus(220., r1, slitwidth / 220., round(num / masknum)) tran.transform(trays, 0, 0, 0, 0, 0, maskcenters[i]) try: rays = [np.concatenate([rays[ti], trays[ti]]) for ti in range(10)] mask = np.concatenate([mask, np.repeat(i, round(num / masknum))]) except: rays = trays mask = np.repeat(i, round(num / masknum)) tran.transform(rays, 220.3 + trans[0], trans[1], 0, 0, 0, 0) #Reflect to Zernike surface surf.zernsurf(rays, coeff, rad, nr=1., rorder=rorder, aorder=aorder) tran.reflect(rays) surf.flat(rays, nr=1.) tran.transform(rays, -220.3, 0, 0, 0, 0, 0) #Wavefront now has the proper Zernike form, rays pointing in #-z direction return rays, mask
def mirrorPair(N,srcdist=89.61e3+1.5e3,primalign=np.zeros(6),\ secalign=np.zeros(6),rrays=False,f=None,\ plist=[[0],[0],[0]],hlist=[[0],[0],[0]]): """ SLF finite source trace """ #Establish subannulus of rays rays = sources.subannulus(220., 221., 100. / 220., N, zhat=-1.) #Transform to node position tran.transform(rays, 220, 0, 0, 0, 0, 0) #Set up finite source distance raydist = sqrt(srcdist**2 + rays[1]**2 + rays[2]**2) rays[4] = rays[1] / raydist rays[5] = rays[2] / raydist rays[6] = -sqrt(1. - rays[4]**2 - rays[5]**2) #Place mirror pair coords = [tran.tr.identity_matrix()] * 4 tran.transform(rays,-220+conic.primrad(8450.,220.,8400.),0,50.,0,0,0,\ coords=coords) tran.transform(rays, *primalign, coords=coords) tran.transform(rays,-conic.primrad(8450.,220.,8400.),0,-8450.,0,0,0,\ coords=coords) ## surf.wolterprimary(rays,220.,8400.) surf.primaryLL(rays, 220., 8400., 8500., 8400., 100. / 220, *plist) rays = tran.vignette(rays,ind=np.logical_and(rays[3]<8500.,\ rays[3]>8400.)) tran.reflect(rays) #Place secondary in primary's reference frame tran.transform(rays,conic.secrad(8350.,220.,8400.),0,8350.,0,0,0,\ coords=coords) tran.transform(rays, *secalign, coords=coords) tran.itransform(rays,conic.secrad(8350.,220.,8400.),0,8350.,0,0,0,\ coords=coords) ## surf.woltersecondary(rays,220.,8400.) surf.secondaryLL(rays, 220., 8400., 1., 8400., 8300., 100. / 220, *hlist) rays = tran.vignette(rays,ind=np.logical_and(rays[3]<8400.,\ rays[3]>8300.)) tran.reflect(rays) #Go back to nominal node reference frame and down to focus rays = tran.applyT(rays, coords, inverse=True) if f is None: f = -surf.focusI(rays) print f else: tran.transform(rays, 0, 0, -f, 0, 0, 0) surf.flat(rays) if rrays is True: return rays return anal.hpd(rays)/f * 180/np.pi * 60.**2, \ airnp.mean(rays[1]), np.mean(rays[2])
def reproduceChevron(num,rin=220.,axlength=100.,azwidth=50.,F=8.4e3,\ hubdist=8e3,radapprox=False,order=1,wave=.83,f=None,\ autofocus=False,returnMet=False,yaw=0.,N=1,\ gratalign=np.zeros(6)): #Create Wolter beam rout = conic.primrad(F+axlength,rin,F) rays = source.subannulus(rin,rout,azwidth/rin,num,zhat=-1.) surf.wolterprimary(rays,rin,F) tran.reflect(rays) surf.woltersecondary(rays,rin,F) tran.reflect(rays) tran.transform(rays,0,0,0,0,0,np.pi/2) #Go to focus surf.focusI(rays) #Steer beam coords = [tran.tr.identity_matrix()]*4 tran.transform(rays,0,0,0,np.mean(rays[5]),-np.mean(rays[4]),0) pdb.set_trace() #Go up to grating tran.transform(rays,0,0,hubdist/np.cos(1.5*np.pi/180),0,0,0) #Go to incidence angle tran.transform(rays,0,0,0,91.5*np.pi/180,0,0) tran.transform(rays,0,0,0,0,0,yaw) #Apply grating misalignment tran.transform(rays,*gratalign) surf.flat(rays) #Get rid of rays outside grating ind = np.logical_and(np.abs(rays[2])<16,np.abs(rays[1])<25/2.) rays = tran.vignette(rays,ind=ind) plt.figure('grat') plt.clf() plt.plot(rays[1],rays[2],'.') plt.title('Beam Footprint') #Place grating if radapprox is False: tran.reflect(rays) tran.transform(rays,0,-hubdist,0,0,0,0) tran.radgrat(rays,160./hubdist,order,wave) tran.transform(rays,0,hubdist,0,0,0,0) else: tran.reflect(rays) gratedges = np.linspace(-16.,16.,N+1) for i in range(N): ind = np.logical_and(rays[2]>gratedges[i],\ rays[2]<gratedges[i+1]) d = (hubdist+np.mean(gratedges[i:i+2]))/hubdist*160. if np.sum(ind)>0: tran.grat(rays,d,-order,wave,ind=ind) #Go to focal plane tran.transform(rays,*gratalign) tran.transform(rays,0,0,0,0,0,-yaw) tran.transform(rays,0,0,0,-91.5*np.pi/180.,0,0) tran.transform(rays,0,0,0,0,0,np.pi/2) if f is not None: try: tran.transform(rays,0,0,-f,0,0,0) surf.flat(rays) except: pdb.set_trace() if autofocus is True: surf.focusY(rays) if returnMet is True: return anal.hpdY(rays)/F*180/np.pi*60**2 plt.figure('LSF') plt.clf() plt.plot(rays[1],rays[2],'.') plt.title('LSF') return rays
def traceToTestOptic220(N, app=75.): """Trace a set of rays from the point source to the nominal test optic location Return the rays at the plane tangent to the nominal source position. """ #Set up source div = app / 1935.033 rays = sources.pointsource(div, N) #Trace through collimator tran.transform(rays, 0, 0, 1935.033, 0, 0, 0) surf.flat(rays, nr=1.) lenses.collimator6(rays) #Trace to CGH tran.transform(rays, 0, 0, 100., 0, 0, 0) #Apply proper CGH misalignment pdb.set_trace() tran.transform(rays, 0, 0, 0, -1. * pi / 180, 0, 0) #Trace through CGH surf.flat(rays, nr=1.) tran.refract(rays, 1., nsil) tran.transform(rays, 0, 0, 6.35, 0, 0, 0) surf.flat(rays, nr=nsil) tran.refract(rays, nsil, 1.) surf.zernphase(rays, cghcoeff, 80., 632.82e-6) #Reverse CGH misalignment tran.itransform(rays, 0, 0, 0, -1. * pi / 180, 0, 0) #Go to line focus tran.transform(rays, 0, 0, 0, 0, 1. * pi / 180, 0) surf.flat(rays, nr=1.) tran.transform(rays, 0, 0, line, 0, 0, 0) surf.flat(rays, nr=1.) #Go to test optic tran.transform(rays, 0, 0, 220., 0, 0, 0) surf.flat(rays, nr=1.) #Rotate reference frame so rays impinge toward -z tran.transform(rays, 0, 0, 0, 0, pi, 0) return rays
def backToWFS220(rays): """ Trace rays from nominal test optic tangent plane back to WFS plane. This function can also be used with a point source to determine the Optimal focus positions of the field lenses. +z points toward CGH. """ #Back to CGH tran.transform(rays, 0, 0, 220 + line, 0, 0, 0) surf.flat(rays, nr=1.) #Trace back through CGH tran.transform(rays, 0, 0, 0, 0, 1. * pi / 180, 0) tran.transform(rays, 0, 0, 0, 1. * pi / 180, 0, 0) surf.flat(rays, nr=1.) surf.zernphase(rays, cghcoeff, 80., 632.82e-6) tran.refract(rays, 1., nsil) tran.transform(rays, 0, 0, 6.35, 0, 0, 0) surf.flat(rays, nr=nsil) tran.refract(rays, nsil, 1.) tran.itransform(rays, 0, 0, 0, 1. * pi / 180, 0, 0) #Go to collimator tran.transform(rays, 0, 0, 100, 0, 0, 0) surf.flat(rays, nr=1.) lenses.collimator6(rays, reverse=True) #Go to focus tran.transform(rays, 0, 0, 1934.99719 - 100., 0, 0, 0) surf.flat(rays, nr=1.) #Place to AC-508-250 lenses.AC508_250(rays, reverse=True) #Go to WFS location ## tran.transform(rays,0,0,foc,0,0,0) ## surf.flat(rays,nr=.1) tran.transform(rays, 0, 0, foc, 0, 0, 0) surf.flat(rays, nr=1.) #Go to cylindrical field lens tran.transform(rays, 0, 0, -cylz, 0, 0, 0) surf.flat(rays, nr=1.) tran.transform(rays, 0, 0, 0, 0, 0, pi / 2) lenses.LJ1516_L2(rays, reverse=False) tran.itransform(rays, 0, 0, 0, 0, 0, pi / 2) tran.itransform(rays, 0, 0, -cylz, 0, 0, 0) #Back to WFS surf.flat(rays, nr=1.) return anal.rmsY(rays)
def backToWFS1m(rays, cghalign=np.zeros(6)): """ Trace rays from nominal test optic tangent plane back to WFS plane. This function can also be used with a point source to determine the Optimal focus positions of the field lenses. +z points toward CGH. """ #Reverse x,z misalignments for i in [0, 2, 3, 5]: cghalign[i] = -cghalign[i] #Back to CGH tran.transform(rays, 0, 0, 1000 + line1m, 0, 0, 0) surf.flat(rays, nr=1.) #Trace back through CGH tran.transform(rays, *cghalign) surf.zernphase(rays, -cgh1m, 80., 632.82e-6) tran.refract(rays, 1., nsil) tran.transform(rays, 0, 0, 6.35, 0, 0, 0) surf.flat(rays, nr=nsil) tran.refract(rays, nsil, 1.) tran.itransform(rays, *cghalign) tran.transform(rays, 0, 0, 0, -10. * pi / 180, 0, 0) #Go to collimator tran.transform(rays, 0, 0, 100, 0, 0, 0) surf.flat(rays, nr=1.) lenses.collimator6(rays, reverse=True) #Go to focus tran.transform(rays, 0, 0, 1934.90059 - 100., 0, 0, 0) surf.flat(rays, nr=1.) #Place to AC-508-250 lenses.AC508_250(rays, reverse=True) #Go to WFS location ## tran.transform(rays,0,0,foc,0,0,0) ## surf.flat(rays,nr=.1) tran.transform(rays, 0, 0, foc1m, 0, 0, 0) #Go to cylindrical field lens tran.transform(rays, 0, 0, -cylz1m, 0, 0, 0) surf.flat(rays, nr=1.) tran.transform(rays, 0, 0, 0, 0, 0, pi / 2) lenses.LJ1144_L2(rays, reverse=False) tran.itransform(rays, 0, 0, 0, 0, 0, pi / 2) tran.itransform(rays, 0, 0, -cylz1m, 0, 0, 0) #Back to WFS surf.flat(rays, nr=1.) return anal.rmsY(rays)
def traceToTestOptic1m(N, app=75., coloffset=0., cghalign=np.zeros(6)): """Trace a set of rays from the point source to the nominal test optic location Return the rays at the plane tangent to the nominal source position. """ #Set up source div = app / 1935.033 rays = sources.pointsource(div, N) #Trace through collimator tran.transform(rays, 0, 0, 1935.033 + coloffset, 0, 0, 0) surf.flat(rays, nr=1.) lenses.collimator6(rays) ## tran.transform(rays,0,0,-coloffset,0,0,0) #Trace to CGH tran.transform(rays, 0, 0, 100., 0, 0, 0) #Apply proper CGH misalignment tran.transform(rays, 0, 0, 0, -10. * pi / 180, 0, 0) #Apply CGH misalignment tran.transform(rays, *cghalign) #Trace through CGH surf.flat(rays, nr=1.) tran.refract(rays, 1., nsil) tran.transform(rays, 0, 0, 6.35, 0, 0, 0) surf.flat(rays, nr=nsil) tran.refract(rays, nsil, 1.) surf.zernphase(rays, -cgh1m, 80., 632.82e-6) #Reverse CGH misalignment tran.itransform(rays, *cghalign) #Go to line focus line = surf.focusY(rays, nr=1.) #Go to test optic tran.transform(rays, 0, 0, 1000., 0, 0, 0) surf.flat(rays, nr=1.) #Go to 1m cylindrical radius of curvature px, py = anal.measurePower(rays, 200, 200) tran.transform(rays, 0, 0, 1000 + py, 0, 0, 0) surf.flat(rays, nr=1.) return rays, line
def traceWedge(rays, t=25., wang=1. * np.pi / 180, pang=45. * np.pi / 180): """ Make two copies of rays and trace through a wedged plate. Ignore multiple reflections. Interpolate one OPD onto the other, take difference modulo wavelength t = plate thickness (at narrow end) ang = wedge angle """ #Make copy rays2 = np.copy(rays) #Trace first set ref1 = [tran.tr.identity_matrix()] * 4 pdb.set_trace() tran.transform(rays, 0, 0, 300., pang, 0, 0, coords=ref1) surf.flat(rays, nr=1.) tran.reflect(rays) tran.transform(rays, 0, 0, 0, np.pi / 2 - pang, 0, 0, coords=ref1) tran.transform(rays, 0, 0, -300., 0, 0, 0, coords=ref1) ## tran.steerY(rays,coords=ref1) surf.flat(rays, nr=1.) #Trace second set ref2 = [tran.tr.identity_matrix()] * 4 pdb.set_trace() tran.transform(rays2, 0, 0, 300., pang, 0, 0, coords=ref2) surf.flat(rays2, nr=1.) #Refract into glass and reflect tran.refract(rays2, 1., nSiO2) tran.transform(rays2, 0, 0, t, 0, wang, 0, coords=ref2) surf.flat(rays2, nr=nSiO2) tran.reflect(rays2) #Refract out of glass ## tran.itransform(rays2,0,0,t,wang,0,0,coords=ref2) tran.transform(rays2, 0, 0, 0, 0, -wang, 0, coords=ref2) tran.transform(rays2, 0, 0, -t, 0, 0, 0, coords=ref2) surf.flat(rays2, nr=nSiO2) tran.refract(rays2, nSiO2, 1.) #Go to focal plane rays2 = tran.applyT(rays2, ref2, inverse=True) rays2 = tran.applyT(rays2, ref1) surf.flat(rays2, nr=1.) #Both sets of rays at same plane, should have shear and tilt #Interpolate OPDs onto common grid opd1,dx,dy = anal.interpolateVec(rays,0,200,200,\ xr=[rays[1].min(),rays[1].max()],\ yr=[rays2[2].min(),rays[2].max()]) opd2 = anal.interpolateVec(rays2,0,200,200,\ xr=[rays[1].min(),rays[1].max()],\ yr=[rays2[2].min(),rays[2].max()])[0] #Convert to complex phase opd1 = opd1 / .000635 * 2 * np.pi % (2 * np.pi) opd2 = opd2 / .000635 * 2 * np.pi % (2 * np.pi) opd1 = np.exp(1j * opd1) opd2 = np.exp(1j * opd2) #Compute intensity/interferogram return np.abs(opd1 + opd2)**2
def test(N,rin=700.,rout=737.,azwidth=66.,srcdist=89.61e3+1.5e3,\ hubdist=11832.911,yaw=0.,wave=6.,order=1,\ opgalign=[0,0,0,0,0,0],f=None,\ rrays=False,glob=False,rcen=False,\ groll=0.,gyaw=0.,gpitch=0.,\ scatter=False,coordin=None,\ radapprox=False): """ Trace through the SPO module, then place the OPG module at its nominal position, allowing for misalignments about the center of the OPG module. The module tolerances can be investigated by a coordinate transformation around the OPG module placement. """ #Trace through SPO module rays = traceSPO(N,rin=rin,rout=rout,azwidth=azwidth,srcdist=srcdist,\ scatter=scatter) #Find the nominal OPG module location using formalism #from Flanagan's SPIE paper #Go to focus, steer out X and Y, then go up a distance #defined using Flangan formula, this should leave you #at the center of the beam, therefore the center of the #OPG module if coordin is None: coords = [tran.tr.identity_matrix()]*4 tran.transform(rays,0,0,0,0,-np.mean(rays[4]),0,coords=coords) #tran.steerX(rays,coords=coords) #tran.steerY(rays,coords=coords) tran.transform(rays,0,0,0,pi-np.mean(rays[5]),0,0,coords=coords) f0 = surf.focusI(rays,coords=coords) tran.transform(rays,np.mean(rays[1]),np.mean(rays[2]),0,0,0,0,\ coords=coords) tran.transform(rays,0,0,0,0,pi,0,coords=coords) tran.transform(rays,0,0,11832.911*np.cos(1.5*np.pi/180),0,0,0,coords=coords) tran.transform(rays,0,0,0,0,1.5*np.pi/180,0,coords=coords) else: rays = tran.applyT(rays,coordin) coords = np.copy(coordin) surf.flat(rays) #Now at center of central grating, with -z pointing toward hub tran.transform(rays,*opgalign,coords=coords) rays,record = traceOPG(rays,hubdist=hubdist,yaw=yaw,wave=wave,order=order,\ gyaw=gyaw,groll=groll,gpitch=gpitch,\ radapprox=radapprox) tran.itransform(rays,*opgalign,coords=coords) #Should be at same reference frame, with rays now diffracted if np.sum(record)==0: pdb.set_trace() rays = tran.vignette(rays,ind=record>0) record = record[record>0] #Trace to detector and determine LSF rays = tran.applyT(rays,coords,inverse=True) #surf.focusI(rays) if f is not None: try: tran.transform(rays,0,0,-f,0,0,0) surf.flat(rays) except: pdb.set_trace() if rcen is True: return anal.centroid(rays) if rrays is True: if glob is True: tran.transform(rays,0,0,f,0,0,0) return rays,record #Return LSF in arcseconds return anal.hpdY(rays)/12e3*180/pi*60**2
def testRadApprox(num,order=1,wave=1.,radapprox=False,N=3,f=None,yaw=0.,\ azwidth=66.*.68,autofocus=False,returnMet=False,axwidth=2.5): """ """ #Set up converging source rays = source.convergingbeam2(12e3,-azwidth/2,azwidth/2,\ -axwidth/2,axwidth/2,num,0.) tran.transform(rays,0,0,12e3,0,0,0) tran.transform(rays,0,0,0,88.5*np.pi/180.,0,0) tran.transform(rays,0,0,0,0,0,yaw) surf.flat(rays) #Place grating if radapprox is False: tran.reflect(rays) tran.transform(rays,0,-12e3,0,0,0,0) tran.radgrat(rays,160./12e3,order,wave) tran.transform(rays,0,12e3,0,0,0,0) tran.transform(rays,0,0,0,0,0,-yaw) else: tran.reflect(rays) gratedges = np.linspace(-50.,50.,N+1) for i in range(N): ind = np.logical_and(rays[2]>gratedges[i],\ rays[2]<gratedges[i+1]) d = (12e3+np.mean(gratedges[i:i+2]))/12e3*160. if np.sum(ind)>0: tran.grat(rays,d,-order,wave,ind=ind) tran.transform(rays,0,0,0,0,0,-yaw) #Go to focal plane tran.transform(rays,0,0,0,-88.5*np.pi/180.,0,0) tran.transform(rays,0,0,0,0,0,np.pi/2) if f is not None: try: tran.transform(rays,0,0,-f,0,0,0) surf.flat(rays) except: pdb.set_trace() if autofocus is True: surf.focusY(rays) if returnMet is True: return anal.hpdY(rays)/12e3*180/np.pi*60**2 return rays
def tracePrimary(primCoeffs=None, primalign=np.zeros(6)): """ Trace rays from focus to primary, off retroreflector, then back to focus. Return spot centroids. """ #Set up source primfoc = conic.primfocus(220., 8400.) r1 = conic.primrad(8500., 220., 8400.) rays = sources.subannulus(220., r1, 100. / 220, 100000, zhat=1.) tran.pointTo(rays, 0., 0., -primfoc, reverse=1.) theta = np.arctan2(rays[2], rays[1]) #Trace to primary tran.transform(rays, *primalign) tran.transform(rays, 0., 0, -8400., 0, 0, 0) if primCoeffs is None: surf.wolterprimary(rays, 220., 8400.) else: surf.primaryLL(rays,220.,8400.,8500.,8400.,100./220.,\ *primCoeffs) tran.transform(rays, 0, 0, 8400., 0, 0, 0) tran.itransform(rays, *primalign) tran.reflect(rays) #Reflect and come back tran.transform(rays, 0, 0, 400., 0, 0, 0) surf.flat(rays) tran.reflect(rays) tran.transform(rays, 0, 0, -400., 0, 0, 0) #Trace to primary tran.transform(rays, *primalign) tran.transform(rays, 0., 0, -8400., 0, 0, 0) if primCoeffs is None: surf.wolterprimary(rays, 220., 8400.) else: surf.primaryLL(rays,220.,8400.,8500.,8400.,100./220.,\ *primCoeffs) ind = np.logical_and(rays[3] > 8400., rays[3] < 8500.) tran.vignette(rays, ind=ind) tran.transform(rays, 0, 0, 8400., 0, 0, 0) tran.itransform(rays, *primalign) tran.reflect(rays) #Go to primary focus tran.transform(rays, 0, 0, -primfoc, 0, 0, 0) surf.flat(rays) return rays, theta
def traceSPO(R,L,focVec,N,M,spanv,wave,d=.605,t=.775,offX=0.,offY=0.,\ vis=None,ang=None,coords=None): """Trace SPO surfaces sequentially. Collect rays from each SPO shell and set them to the PT rays at the end. Start at the inner radius, use the wafer and pore thicknesses to vignette and compute the next radius, loop while radius is less than Rout. """ #Ray bookkeeping arrays trays = [np.zeros(M * N) for n in range(10)] if vis is True: xp, yp, zp = [], [], [] xs, ys, zs = [], [], [] #Loop through shell radii and collect rays ref = np.zeros(M * N) for i in range(M): #Set up source annulus rays = sources.subannulus(R[i], R[i] + d, spanv[i], N, zhat=-1.) z, n = rays[3], rays[6] ## #Transform rays to be above xy plane ## tran.transform(rays,0,0,-100.,0,0,0,coords=coords) #Apply angular offset tran.transform(rays, 0, 0, 0, 0, 0, ang) #Get initial positions glob = None if vis is True: #Initial ray positions x0, y0, z0 = np.copy(rays[1]), np.copy(rays[2]), np.copy(rays[3]) ## ## #Establish 3d figure ## fig = plt.figure('vis') ## ax = fig.add_subplot(111,projection='3d') #Trace to primary surf.spoPrimary(rays, R[i], focVec[i]) #Export primary ray positions in global reference frame if vis is True: tran.transform(rays, 0, 0, -focVec[i], 0, 0, 0) xp = np.concatenate((xp, rays[1])) yp = np.concatenate((yp, rays[2])) zp = np.concatenate((zp, rays[3])) tran.transform(rays, 0, 0, focVec[i], 0, 0, 0) #Add offsets if they apply rays = [rays[0],rays[1],rays[2],rays[3],\ rays[4]+offX,rays[5]+offY,\ -np.sqrt(rays[6]**2-offX**2-offY**2),\ rays[7],rays[8],rays[9]] tran.reflect(rays) #Compute reflectivity inc = anal.grazeAngle(rays) #np.arcsin(l*ux+m*uy+n*uz) if np.size(wave) == 1: refl = sporef(inc * 180 / np.pi, 1239.8 / wave) else: refl = np.diag( sporef(inc * 180 / np.pi, 1239.8 / wave[i * N:(i + 1) * N])) #Trace to secondary surf.spoSecondary(rays, R[i], focVec[i]) tran.reflect(rays) #Compute reflectivity inc = anal.grazeAngle(rays) #inc = np.arcsin(l*ux+m*uy+n*uz) if np.size(wave) == 1: ref[i*N:(i+1)*N] = refl * sporef(inc*180/np.pi\ ,1239.8/wave) else: ref[i*N:(i+1)*N] = refl * np.diag(sporef(inc*180/np.pi\ ,1239.8/wave[i*N:(i+1)*N])) #Set plane to be at focus tran.transform(rays, 0, 0, -focVec[i], 0, 0, 0, coords=coords) #Collect rays try: for t in range(1, 7): temp = trays[t] temp[i * N:(i + 1) * N] = rays[t] except: pdb.set_trace() #Export secondary ray positions in global coordinate frame if vis is True: return trays, ref, [xp, yp, zp], [trays[1], trays[2], trays[3]] return trays, ref
def ellipsoidPair(N,srcdist=89.61e3+1.5e3,primalign=np.zeros(6),\ secalign=np.zeros(6),rrays=False,f=None,\ plist=[[0],[0],[0]],hlist=[[0],[0],[0]]): """ Trace an ellipsoid-hyperboloid telescope in SLF geometry. plist is [pcoeff,pax,paz] """ #Establish subannulus of rays r1 = conic.ellipsoidRad(srcdist, 1., 220., 8400., 8500.) rays = sources.subannulus(220., r1, 100. / 220., N, zhat=-1.) tran.pointTo(rays, 0, 0, srcdist, reverse=1.) ## #Transform to node position ## tran.transform(rays,220,0,0,0,0,0) ## #Set up finite source distance ## raydist = sqrt(srcdist**2+rays[1]**2+rays[2]**2) ## rays[4] = rays[1]/raydist ## rays[5] = rays[2]/raydist ## rays[6] = -sqrt(1.-rays[4]**2-rays[5]**2) #Place mirror pair coords = [tran.tr.identity_matrix()] * 4 prad = conic.ellipsoidRad(srcdist, 1., 220., 8400., 8450.) tran.transform(rays,prad,0,50.,0,0,0,\ coords=coords) tran.transform(rays, *primalign, coords=coords) tran.transform(rays,-prad,0,-8450.,0,0,0,\ coords=coords) surf.ellipsoidPrimaryLL(rays,220.,8400.,srcdist,1.,8500.,8400.,100./220,\ *plist) #Vignette any rays outside of active area rays = tran.vignette(rays,ind=np.logical_and(rays[3]<8500.,\ rays[3]>8400.)) ## surf.ellipsoidPrimary(rays,220.,8400.,srcdist,1.) tran.reflect(rays) #Place secondary in primary's reference frame srad = conic.ehSecRad(srcdist, 1., 220., 8400., 8350.) tran.transform(rays,srad,0,8350.,0,0,0,\ coords=coords) tran.transform(rays, *secalign, coords=coords) tran.itransform(rays,srad,0,8350.,0,0,0,\ coords=coords) ## surf.ellipsoidSecondary(rays,220.,8400.,srcdist,1.) surf.ellipsoidSecondaryLL(rays,220.,8400.,srcdist,1.,8400.,8300.,100./220,\ *hlist) rays = tran.vignette(rays,ind=np.logical_and(rays[3]<8400.,\ rays[3]>8300.)) ang = anal.grazeAngle(rays) tran.reflect(rays) #Go back to nominal node reference frame and down to focus rays = tran.applyT(rays, coords, inverse=True) if f is None: f = -surf.focusI(rays) print f else: tran.transform(rays, 0, 0, -f, 0, 0, 0) surf.flat(rays) if rrays is True: return rays return anal.hpd(rays) / f * 180 / np.pi * 60.**2
def traceOPG(rays,hubdist=11832.911,yaw=0.,order=1,wave=1.,ang=2.5/11832.911,\ gpitch=0.,gyaw=0.,groll=0.,\ radapprox=False): """ Trace the OPG module. Probably ignore vignetting again. Place perfect OPG surfaces at the correct angular distance to make this a reasonable approximation. Assume reference frame is in center of module with -z pointing toward hub - achieved with steerX/steerY and rotate inc before this function call Create vector to keep track of which grating each ray diffracts from. Separate LSFs can be identified using this vector. """ #Establish starting coordinate system coords = [tran.tr.identity_matrix()]*4 #Get -x pointing to hub #Question whether to rotate about z to swap x and y tran.transform(rays,0,0,0,0,0,-pi/2,coords=coords) tran.transform(rays,0,0,0,pi/2,0,0,coords=coords) #Go to hub, then rotate to extreme grating surface tran.transform(rays,0,0,0,0,0,yaw,coords=coords) #possible blaze tran.transform(rays,0,-11832.911,0,0,0,0,coords=coords) tran.transform(rays,0,0,0,-ang*7,0,0,coords=coords) #minus sign ambiguity #Loop through gratings, tracing rays left = np.repeat(True,len(rays[1])) record = np.zeros(len(rays[1])) for i in range(15): #If no rays left, we are done if np.sum(left) == 0: continue #Rays with small incidence angle removed indg = np.abs(np.arcsin(rays[6])) > .001 ind = np.logical_and(left,indg) if np.sum(ind)==0: tran.transform(rays,0,0,0,ang,0,0,coords=coords) continue #Trace rays to surface tyaw = np.random.uniform(low=-gyaw,high=gyaw) tpitch = np.random.uniform(low=-gpitch,high=gpitch) troll = np.random.uniform(low=-groll,high=groll) tran.transform(rays,0,11832.911,0,0,0,0,ind=ind) tran.transform(rays,0,0,0,tpitch,troll,tyaw,ind=ind) surf.flat(rays,ind=ind) tran.itransform(rays,0,0,0,tpitch,troll,tyaw,ind=ind) tran.itransform(rays,0,11832.911,0,0,0,0,ind=ind) #Identify relevant rays ind = np.logical_and(rays[2]>11832.911-96./2,rays[2]<11832.911+96./2) ind = np.logical_and(ind,left) #Remove these rays from the set that remain left = np.logical_and(left,np.invert(ind)) if np.sum(ind)==0: tran.transform(rays,0,0,0,ang,0,0,coords=coords) continue #Record which grating these rays diffracted from record[ind] = i+1 #Diffract this set of rays tran.reflect(rays,ind=ind) tran.transform(rays,0,11832.911-hubdist,0,0,0,0,coords=coords) if radapprox is False: tran.radgrat(rays,160./hubdist,order,wave,ind=ind) else: ind3 = np.logical_and(rays[2]<11832.911+48.,\ rays[2]>11832.911+48-9.282) ind4 = np.logical_and(ind3,ind) if np.sum(ind4)>0: tran.grat(rays,160.,order,wave,ind=ind4) ind3 = np.logical_and(rays[2]<11832.911+48.-9.282,\ rays[2]>11832.911+48-9.282-18.564) ind4 = np.logical_and(ind3,ind) if np.sum(ind4)>0: tran.grat(rays,159.75,order,wave,ind=ind4) ind3 = np.logical_and(rays[2]<11832.911+48.-9.282-18.564,\ rays[2]>11832.911+48-9.282-18.564*2) ind4 = np.logical_and(ind3,ind) if np.sum(ind4)>0: tran.grat(rays,159.5,order,wave,ind=ind4) ind3 = np.logical_and(rays[2]<11832.911+48.-9.282-18.564*2,\ rays[2]>11832.911+48-9.282-18.564*3) ind4 = np.logical_and(ind3,ind) if np.sum(ind4)>0: tran.grat(rays,159.25,order,wave,ind=ind4) ind3 = np.logical_and(rays[2]<11832.911+48.-9.282-18.564*3,\ rays[2]>11832.911+48-9.282-18.564*4) ind4 = np.logical_and(ind3,ind) if np.sum(ind4)>0: tran.grat(rays,159.,order,wave,ind=ind4) ind3 = np.logical_and(rays[2]<11832.911+48.-9.282-18.564*4,\ rays[2]>11832.911+48-9.282-18.564*4-12.462) ind4 = np.logical_and(ind3,ind) if np.sum(ind4)>0: tran.grat(rays,158.75,order,wave,ind=ind4) #pdb.set_trace() tran.transform(rays,0,hubdist-11832.911,0,0,0,0,coords=coords) #Rotate to next grating tran.transform(rays,0,0,0,ang,0,0,coords=coords) #Go back to original coordinate system rays = tran.applyT(rays,coords,inverse=True) return rays,record