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 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 fullShellPair(ang=2 * np.pi, secalign=[0, 0, 0, 0, 0, 0]): """ Trace a full shell optic with misalignments of the secondary with respect to primary. Allow azimuthal extent to be a variable. """ #Set up ray bundle rays = sources.subannulus(220., 220.6, ang, 100000, zhat=-1.) tran.transform(rays, 0, 0, -8400., 0, 0, 0) theta = np.arctan2(rays[2], rays[1]) #Trace through optics surf.wolterprimary(rays, 220., 8400.) tran.reflect(rays) tran.transform(rays, 0, 0, 8400., 0, 0, 0) tran.transform(rays, *secalign) tran.transform(rays, 0, 0, -8400., 0, 0, 0) surf.woltersecondary(rays, 220., 8400.) tran.reflect(rays) tran.transform(rays, 0, 0, 8400., 0, 0, 0) tran.itransform(rays, *secalign) #Go to focus tran.transform(rays, 0, 0, -8400., 0, 0, 0) surf.flat(rays) #Plot misalignment curves ## plt.plot(theta,rays[1],'.') ## plt.plot(theta,rays[2],'.') plt.plot(rays[1], rays[2], '.') return rays, theta
def traceThroughPrimary(rays,mask,primalign=np.zeros(6),\ detalign=np.zeros(6),primCoeffs=None,cenSig=0.): """ Trace rays through the primary mirror and then down to a focus. Need to simulate an initial misalignment and then applying an optimization algorithm to align primary to beam. Merit function should include the random error in spot centroiding primCoeffs is a list of coefficients, axial orders, and azimuthal orders Use global coordinate systems to determine sign conventions """ #Move to primary reference frame - rays 200 mm above node tran.transform(rays, 0, 0, -200., 0, 0, 0) glo = [tran.tr.identity_matrix()] * 4 #Move to mirror tangent point and apply misalignment tran.transform(rays, conic.primrad(8450., 220., 8400.), 0, 50, 0, 0, 0, coords=glo) tran.transform(rays, 0, 0, 0, *primalign[3:], coords=glo) tran.itransform(rays, conic.primrad(8450., 220., 8400.), 0, 50, 0, 0, 0, coords=glo) tran.transform(rays, 0, 0, -8400., 0, 0, 0, coords=glo) #Trace to Wolter surface if primCoeffs is None: surf.wolterprimary(rays, 220., 8400.) else: surf.primaryLL(rays,220.,8400.,8500.,8400.,100./220.,\ *primCoeffs) rays = tran.applyT(rays, glo, inverse=True) #Rays are now at primary in global coordinate system #(origin on optical axis and at nominal node height) #Now reflect and trace down to the detector tran.reflect(rays) tran.transform(rays, 0, 0, -conic.primfocus(220., 8400.), 0, 0, 0) #Apply detector misalignment tran.transform(rays, *detalign) surf.flat(rays) #Pick out spot centroids cen = [anal.centroid(rays, weights=mask == i) for i in range(mask[-1] + 1)] cen = np.transpose(np.array(cen)) #Add centroiding error if cenSig > 0: cen = cen + np.random.normal(scale=cenSig, size=np.shape(cen)) return cen
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 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 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