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 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 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 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 hartmannAngles(N, numholes): holecent = conicsolve.primrad(8475., 220., 8400.) #Radius of center of holes halfang = arcsin(50. / 220.) - .009 #Half angle of Hartmann mask holetheta = linspace(-halfang, halfang, numholes) #Vector of Hartmann angles thistheta = holetheta[N - 1] - pi / 2 return holecent, thistheta
def traceFromMask(N, numholes, cda, fold, retro, primary, foldrot=0., retrorot=0.): #Vignette at proper hole h = hartmannMask() ind = h == N PT.vignette(ind=ind) #Continue trace up to retro and back to CDA PT.transform(0, -123.41, 1156.48 - 651.57 - 134.18, 0, 0, 0) PT.flat() PT.transform(0, 0, 0, pi, 0, 0) PT.transform(*retro) PT.zernsurfrot(retrosag, retrofig, 378. / 2, -8.993 * pi / 180 + retrorot) PT.itransform(*retro) PT.reflect() PT.transform(0, 0, 0, -pi, 0, 0) PT.transform(0, 123.41, -1156.48 + 651.57 + 134.18, 0, 0, 0) PT.flat() h = hartmannMask() ind = h == N PT.vignette(ind=ind) PT.transform(0, 0, -134.18, 0, 0, 0) rt = conicsolve.primrad(8475., 220., 8400.) PT.transform(0, -rt, 75., 0, 0, 0) PT.transform(*primary) PT.transform(0, rt, -8475., 0, 0, 0) PT.wolterprimary(220., 8400.) ind = logical_and(PT.z < 8525., PT.z > 8425.) PT.vignette(ind=ind) PT.reflect() PT.transform(0, -rt, 8475., 0, 0, 0) PT.itransform(*primary) PT.transform(0, rt, -8475., 0, 0, 0) PT.transform(0,-85.12,8400.-651.57+85.12\ ,0,0,0) PT.transform(0, 0, 0, -pi / 4, 0, 0) PT.transform(0, 0, 0, 0, 0, pi) PT.flat() PT.transform(*fold) PT.zernsurfrot(foldsag, foldfig, 406. / 2, -174.659 * pi / 180 + foldrot) PT.itransform(*fold) PT.reflect() PT.transform(0, 0, 0, 0, 0, -pi) PT.transform(0, 0, 0, 3 * pi / 4, 0, 0) PT.transform(0,-85.12,-85.12-(conicsolve.primfocus(220.,8400.)-651.57)\ ,0,0,0) PT.transform(*cda) PT.flat() return
def sagVsRadius(rad, z0, z1, z2): """Compute axial sag needed as a function of radius of curvature Input is vector of radii and upper and lower axial length bounds """ sag = np.zeros(np.size(rad)) z = np.linspace(z1, z2, 1000) for r0 in rad: r = con.primrad(z, r0, z0) r = r - np.polyval(np.polyfit(z, r, 1), z) sag[r0 == rad] = np.max(r) - np.min(r) return sag
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 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 rxPlot(): #Get Rx rx = np.transpose(np.genfromtxt('/home/rallured/Dropbox/AXRO/WSTracing/' '150528_Pauls_Rx.csv',delimiter=',')) geo = np.transpose(np.genfromtxt('/home/rallured/Dropbox/AXRO/WSTracing/' 'geometric_transmission_102711.txt')) rx = rx[:,geo[1]>0] geo = geo[1][geo[1]>0] f = np.sqrt(rx[1][-1]**2+10000.**2) z = np.sqrt(f**2-rx[1]**2) #spherical #Make plot plt.figure('SX') plt.clf() for i in np.arange(0,len(geo),3): rp1 = con.primrad(z[i]+50.,rx[1][i],1e4) rp2 = con.primrad(z[i]+250.,rx[1][i],1e4) rh1 = con.secrad(z[i]-50.,rx[1][i],1e4) rh2 = con.secrad(z[i]-250.,rx[1][i],1e4) uplt.isoplot([rp1,rp2],[z[i]+50.-1e4,z[i]+250.-1e4],'b') uplt.isoplot([rh1,rh2],[z[i]-50.-1e4,z[i]-250.-1e4],'b') return rx,geo
def primMaskTrace(fold, primary, woltVignette=True, foldrot=0.): #Get Wolter parameters alpha, p, d, e = conicsolve.woltparam(220., 8400.) primfoc = conicsolve.primfocus(220., 8400.) #Trace to fold mirror #translate to center of fold mirror PT.transform(0., 85.12, primfoc - 651.57 + 85.12, 0, 0, 0) #rotate so surface normal points in correct direction PT.transform(0, 0, 0, -3 * pi / 4, 0, 0) PT.transform(0, 0, 0, 0, 0, pi) #trace to fold flat PT.flat() #Introduce fold misalignment PT.transform(*fold) PT.zernsurfrot(foldsag, foldfig, 406. / 2, -174.659 * pi / 180 + foldrot) PT.itransform(*fold) PT.reflect() PT.transform(0, 0, 0, 0, 0, -pi) PT.transform(0, 0, 0, pi / 4, 0, 0) #Translate to optical axis mid-plane, then down to image of #primary focus, place primary mirror and trace PT.transform(0, 85.12, 651.57 - 85.12, 0, 0, 0) PT.flat() ## pdb.set_trace() rt = conicsolve.primrad(8475., 220., 8400.) PT.transform(0, -rt, 75., 0, 0, 0) PT.transform(*primary) PT.transform(0, rt, -8475., 0, 0, 0) ## PT.wolterprimary(220.,8400.) PT.primaryLL(220., 8400., 8525., 8425., 30. * np.pi / 180., pcoeff, pax, paz) if woltVignette is True: ind = logical_and(PT.z < 8525., PT.z > 8425.) PT.vignette(ind=ind) PT.reflect() PT.transform(0, -rt, 8475., 0, 0, 0) PT.itransform(*primary) PT.transform(0, rt, -8475., 0, 0, 0) #Move back up to mask plane and trace flat PT.transform(0, 0, 8400. + 134.18, 0, 0, 0) PT.flat() ## pdb.set_trace() #Rays should now be at Hartmann mask plane return
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 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 fullFromMask(N, cda, fold, retro, prim, sec, foldrot=0., retrorot=0.): ## pdb.set_trace() #Vignette at proper hole h = hartmannMask() ind = h == N PT.vignette(ind=ind) #Continue trace up to retro and back to CDA PT.transform(0, -123.41, 1156.48 - 651.57 - 134.18, 0, 0, 0) PT.flat() PT.transform(0, 0, 0, pi, 0, 0) PT.transform(*retro) PT.zernsurfrot(retrosag, retrofig, 378. / 2, -8.993 * pi / 180 + retrorot) PT.itransform(*retro) PT.reflect() PT.transform(0, 0, 0, -pi, 0, 0) #Back to mask PT.transform(0, 123.41, -1156.48 + 651.57 + 134.18, 0, 0, 0) PT.flat() h = hartmannMask() ind = h == N PT.vignette(ind=ind) #Place Wolter surfaces PT.transform(0, 0, -134.18 - 8400., 0, 0, 0) PT.transform(0, -conicsolve.primrad(8425., 220., 8400.), 8425., 0, 0, 0) PT.transform(*prim) PT.itransform(0, -conicsolve.primrad(8425., 220., 8400.), 8425., 0, 0, 0) ## PT.wolterprimary(220.,8400.) PT.primaryLL(220., 8400., 8525., 8425., 30. * np.pi / 180., pcoeff, pax, paz) pdb.set_trace() ind = logical_and(PT.z < 8525., PT.z > 8425.) PT.vignette(ind=ind) PT.transform(0, -conicsolve.primrad(8425., 220., 8400.), 8425., 0, 0, 0) PT.itransform(*prim) PT.itransform(0, -conicsolve.primrad(8425., 220., 8400.), 8425., 0, 0, 0) PT.reflect() #Wolter secondary PT.transform(0, -conicsolve.secrad(8325., 220., 8400.), 8325., 0, 0, 0) PT.transform(*sec) PT.itransform(0, -conicsolve.secrad(8325., 220., 8400.), 8325., 0, 0, 0) PT.woltersecondary(220., 8400.) ind = logical_and(PT.z < 8375., PT.z > 8275.) PT.vignette(ind=ind) PT.reflect() PT.transform(0, -conicsolve.secrad(8325., 220., 8400.), 8325., 0, 0, 0) PT.itransform(*sec) PT.itransform(0, -conicsolve.secrad(8325., 220., 8400.), 8325., 0, 0, 0) ## PT.woltersecondary(220.,8400.) ## ind = logical_and(PT.z<8375.,PT.z>8275.) ## PT.vignette(ind=ind) ## PT.reflect() #Back to fold PT.transform(0,-85.12,8400.-651.57+85.12\ ,0,0,0) PT.transform(0, 0, 0, -pi / 4, 0, 0) PT.transform(0, 0, 0, 0, 0, pi) PT.flat() PT.transform(*fold) PT.zernsurfrot(foldsag, foldfig, 406. / 2, -174.659 * pi / 180 + foldrot) PT.itransform(*fold) PT.reflect() PT.transform(0, 0, 0, 0, 0, -pi) #Back to CDA PT.transform(0, 0, 0, 3 * pi / 4, 0, 0) PT.transform(0,-85.12,-85.12-8400.+651.57\ ,0,0,0) PT.transform(*cda) PT.flat() return
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 hartmannPosition(N): global holetheta holecent = conicsolve.primrad(8475., 220., 8400.) #Radius of center of holes thistheta = holetheta[N - 1] - pi / 2 return holecent * cos(thistheta), holecent * sin(thistheta)
def traceCyl(align): """Traces a cylindrical approximation to Wolter I geometry Assumes 1 m radius of curvature in accordance with OAB samples align is a 12 element array giving the transformations to be applied to each mirror Uses identical set of rays each run defined upon module import Adds a restraint such that any vignetting over 25% results in a huge merit function """ #Set up source np.random.seed(5) a, p, d, e = con.woltparam(1000., 10000.) r0 = con.primrad(10025., 1000., 10000.) r1 = con.primrad(10125., 1000., 10000.) dphi = 100. / 1000. PT.subannulus(r0, r1, dphi, 10**4) PT.transform(0, 0, 0, np.pi, 0, 0) PT.transform(0, 0, -10500., 0, 0, 0) #Trace primary cylinder: go to tangent point at center #of mirror and then rotate to cone angle, then move #to new cylinder axis and tracecyl rt = con.primrad(10075., 1000., 10000.) PT.transform(rt, 0, 0, 0, a, 0) PT.transform(*align[:6]) PT.transform(0, 0, 0, np.pi / 2, 0, 0) PT.transform(-1000., 0, 0, 0, 0, 0) PT.cyl(1000.) #Vignette rays missing physical surface ind = np.logical_and(abs(PT.z) < 50., abs(PT.y) < 50.) PT.vignette(ind=ind) #Reflect and reverse transformations PT.reflect() PT.transform(1000., 0, 0, 0, 0, 0) PT.itransform(0, 0, 0, np.pi / 2, 0, 0) PT.itransform(*align[:6]) PT.itransform(rt, 0, 0, 0, a, 0) #Trace secondary cylinder: same principle as before rt = con.secrad(9925., 1000., 10000.) PT.transform(0, 0, -150., 0, 0, 0) PT.transform(rt, 0, 0, 0, 3 * a, 0) PT.transform(*align[6:]) PT.transform(0, 0, 0, np.pi / 2, 0, 0) PT.transform(-1000., 0, 0, 0, 0, 0) PT.cyl(1000.) #Vignette rays missing physical surface ind = np.logical_and(abs(PT.z) < 50., abs(PT.y) < 50.) PT.vignette(ind=ind) #Reflect and reverse transformations PT.reflect() PT.transform(1000., 0, 0, 0, 0, 0) PT.itransform(0, 0, 0, np.pi / 2, 0, 0) PT.itransform(*align[6:]) PT.itransform(rt, 0, 0, 0, 3 * a, 0) #Go down to nominal focus PT.transform(0, 0, -9925., 0, 0, 0) PT.flat() #Compute merit function nom = PT.rmsCentroid() / 10**4 * 180. / np.pi * 60**2 nom = nom + max((9500. - np.size(PT.x)), 0.) return nom