def traceSector(Rin,Rout,F,N,span=pi/12,d=.605,t=.775,gap=25.,\ inc=1.5*pi/180,l=95.): """Trace Arcus sector """ #Trace parameters R = np.arange(Rin, Rout, t) #Vector of shell radii tg = .25 * np.arctan((R + d / 2) / F) #Primary graze angles L = d / tan(tg) #Primary length #L = 4*F*d/R #Vector of mirror lengths M = np.size(R) #Number of shells #Trace rays through SPO modules traceSPO(R, L, F, N, M, span=span, d=d, t=t) #Determine outermost radius of grating array PT.transform(0, 0, -(L.max() + gap + 95.), 0, 0, 0) PT.flat() outerrad = np.max(sqrt(PT.x**2 + PT.y**2)) hubdist = sqrt(outerrad**2 + (1e4 - (L.max() + gap + 95.))**2) angle = np.arctan(outerrad / (1e4 - (L.max() + gap + 95.))) #Trace grating array gratArray(outerrad, hubdist, angle, inc, l=l) return
def CDAbeam(num, div, pitch, roll, cda): ## PT.transform(*cda) PT.pointsource(div, num) PT.transform(0, 0, 0, pitch, 0, 0) PT.transform(0, 0, 0, 0, 0, roll) PT.itransform(*cda) return
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
def traceWSShell(num,theta,r0,z0,phigh,plow,shigh,slow,\ energy,rough,chaseFocus=False,bestFocus=False): """Trace a WS mirror pair with 10 m focal length and mirror axial cutoffs defined by phigh,plow """ #Define annulus of source rays a,p,d,e = con.woltparam(r0,z0) r1 = PT.wsPrimRad(plow,1.,r0,z0)#np.tan(a/2.)*(plow-10000.) + r0 r2 = PT.wsPrimRad(phigh,1.,r0,z0)#np.tan(a/2.)*(phigh-10000.) + r0 rays = PT.annulus(r1,r2,num) PT.transform(rays,0,0,0,np.pi,0,0) PT.transform(rays,0,0,z0,0,0,0) #Trace to primary PT.wsPrimary(rays,r0,z0,1.) #Handle vignetting ind = np.logical_and(rays[3]<phigh,rays[3]>plow) rays = PT.vignette(rays,ind=ind) #Vignette rays hitting backside of mirror dot = rays[4]*rays[7]+rays[5]*rays[8]+rays[6]*rays[9] ind = dot < 0. rays = PT.vignette(rays,ind=ind) #If all rays are vignetted, return if np.size(rays[1]) < 1: return 0.,0.,0. #Apply pointing error rays = [rays[0],rays[1],rays[2],rays[3],\ rays[4]+np.sin(theta),rays[5],-np.sqrt(1-np.sin(theta)**2),\ rays[7],rays[8],rays[9]] ## PT.l = PT.l + np.sin(theta) ## PT.n = -np.sqrt(1 - PT.l**2) #Reflect PT.reflect() #Compute mean incidence angle for reflectivity ang = np.abs(np.mean(np.arcsin(dot))) #radians refl1 = CXCreflIr(ang,energy,rough) #Total rays entering primary aperture N1 = np.size(rays[1]) #Trace to secondary PT.wsSecondary(r0,z0,1.) #Vignette anything outside the physical range of the mirror ind = np.logical_and(rays[3]>slow,rays[3]<shigh) rays = PT.vignette(rays,ind=ind) #Vignette anything hitting the backside dot = rays[4]*rays[7]+rays[5]*rays[8]+rays[6]*rays[9] ind = dot < 0. rays = PT.vignette(rays,ind=ind) if np.size(rays[1]) < 1: return 0.,0.,0. PT.reflect() #Compute mean incidence angle for reflectivity ang = np.abs(np.mean(np.arcsin(dot))) #radians refl2 = CXCreflIr(ang,energy,rough) #Trace to focal plane rays = PT.flat(rays) ## #Find Chase focus ## delta = 0. ## if chaseFocus or bestFocus: ## cx,cy = PT.centroid() ## r = np.sqrt(cx**2+cy**2) ## delta = .0625*(1.+1)*(r**2*(phigh-plow)/10000.**2)\ ## *(1/np.tan(a))**2 ## PT.transform(0,0,delta,0,0,0) ## PT.flat() ## ## #Find best focus ## delta2 = 0. ## delta3 = 0. ## if bestFocus: ## try: ## tran.focusI(rays,weights= ## except: ## pdb.set_trace() ## PT.flat() return refl1*refl2,rays
def sphericalNodes(rin,z0,fov,Nshells,N): """This function will iteratively scan node positions about a sphere around the focus. Node will start in obvious vignetting position. Extreme rays will be traced including FoV. Node will be nudged outward until vignetting no longer occurs. Node will then be moved by the designated mechanical gap. Then the next node is traced in the same fashion. Assumptions: 50 mm symmetric gap """ #Bookkeeping parameters f = np.sqrt(rin**2+z0**2) fov = fov/60.*np.pi/180. #fov to radians zlist = [] rlist = [] for i in range(Nshells): #Starting radius for next shell node rstart = PT.wsPrimRad(z0+225.,1.,rin,z0) #Reduce rstart until vignetting is reached flag = 0 while flag==0: zstart = np.sqrt(f**2-rstart**2) #Set up rays r1 = PT.wsPrimRad(zstart+25.,1.,rstart,zstart) r2 = PT.wsPrimRad(zstart+225.,1.,rstart,zstart) PT.pointsource(0.,N) PT.z = np.repeat(10500.,N) PT.x = np.linspace(r1,r2,N) PT.n = np.repeat(-1.,N) #Perform trace and add FoV deflections to rays PT.wsPrimary(rstart,zstart,1.) PT.l = np.repeat(np.sin(fov),N) PT.n = -np.sqrt(1 - PT.l**2) #Verify that rays do not hit prior primary PT.wsPrimary(rin,z0,1.) if np.sum(PT.z<z0+225.) != 0: #Ray has hit print 'Ray hits prior primary!' flag = 1 #Verify that rays do not hit prior secondary PT.wsPrimary(rstart,zstart,1.) PT.reflect() PT.wsSecondary(rstart,zstart,1.) PT.reflect() PT.wsSecondary(rin,z0,1.) if np.sum(PT.z > z0-225.) != 0: print 'Ray hits prior secondary!' flag = 1 #Look at other deflection PT.pointsource(0.,N) PT.z = np.repeat(10500.,N) PT.x = np.linspace(r1,r2,N) PT.n = np.repeat(-1.,N) #Perform trace and add FoV deflections to rays PT.wsPrimary(rstart,zstart,1.) PT.l = np.repeat(-np.sin(fov),N) PT.n = -np.sqrt(1 - PT.l**2) #Verify that rays do not hit prior primary PT.wsPrimary(rin,z0,1.) if np.sum(PT.z<z0+225.) != 0: #Ray has hit print 'Ray hits prior primary!' flag = 1 #Verify that rays do not hit prior secondary PT.wsPrimary(rstart,zstart,1.) PT.reflect() PT.wsSecondary(rstart,zstart,1.) PT.reflect() PT.wsSecondary(rin,z0,1.) if np.sum(PT.z > z0-225.) != 0: print 'Ray hits prior secondary!' flag = 1 if flag==0: rstart = rstart - .01 #Take off 10 microns ## sys.stdout.write(str(rstart)+'\n') ## sys.stdout.flush() #Vignetting has been reached, append rstart and zstart #to list of node positions rlist.append(rstart) zlist.append(zstart) rin = rstart z0 = zstart return rlist,zlist
def SXperformance(theta,energy,rough,bestsurface=False,optsurface=False): """Go through a SMART-X prescription file and compute area weighted performance for a flat focal plane """ #Load in rx data ## rx = np.transpose(np.genfromtxt('/home/rallured/Dropbox/AXRO/WSTracing/' ## 'mirror-design-260sh-200mmlong-040mmthick' ## '-3mdiam-10mfl-10arcmin-fov-planarIntersept032713.csv',\ ## delimiter=',')) 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')) therm = np.transpose(np.genfromtxt('/home/rallured/Dropbox/AXRO/' 'WSTracing/thermal_shield_transmission_102711.txt')) f = np.sqrt(rx[1][-1]**2+10000.**2) z = np.sqrt(f**2-rx[1]**2) #spherical ## z = np.repeat(10000.,np.size(rx[1])) ## ind = rx[0] > 210. ## rx = rx[:,ind] Ns = np.shape(rx)[1] #Loop through and compute a resolution and a weight for each shell hpdTelescope = np.zeros(np.size(theta)) rmsTelescope = np.zeros(np.size(theta)) delta = np.zeros(np.size(theta)) cent = np.zeros(np.size(theta)) platefrac = np.zeros(np.size(theta)) #fig = plt.figure() for t in theta[:]: xi = np.array([]) yi = np.array([]) l = np.array([]) m = np.array([]) n = np.array([]) weights = np.array([]) #plt.clf() tstart = time.time() plate = np.zeros(Ns) for s in np.arange(0,Ns): if geo[1][s] > 0.: sys.stdout.write('Shell: %03i \r' % s) sys.stdout.flush() r,rays = traceWSShell(1000,t,rx[1][s],z[s],z[s]+225.,z[s]+25.,\ z[s]-25.,z[s]-225.,energy,rough) r = r*geo[1][s]*rx[9][s] #Reflectivity*area*alignmentbars*vign #Account for thermal shield in shells 220-321 if s > 219: r = r * therm[1][np.abs(energy/1000.-therm[0]).argmin()] r = np.repeat(r,np.size(rays[1])) weights = np.append(weights,r) PT.conic(1107.799202,-1.) xi = np.append(xi,rays[1]) yi = np.append(yi,rays[2]) l = np.append(l,rays[4]) m = np.append(m,rays[5]) n = np.append(n,rays[6]) if s%10==0: plt.plot(rays[1][:100],rays[2][:100],'.') plate[s] = anal.centroid(rays,weights=r)[0] print time.time()-tstart #Have list of photon positions and weights #Need to compute centroid and then FoM #Normalize weights weights = weights/np.sum(weights) xi = np.array(xi,order='F') yi = np.array(yi,order='F') zi = np.zeros(np.size(xi)).astype('float') li = np.array(l,order='F') mi = np.array(m,order='F') ni = np.array(n,order='F') uxi = np.zeros(np.size(xi)).astype('float') uyi = np.zeros(np.size(xi)).astype('float') uzi = np.zeros(np.size(xi)).astype('float') rays = [np.zeros(np.size(xi)).astype('float'),\ xi,yi,zi,\ li,mi,ni,\ uxi,uyi,uzi] if bestsurface: rays = tran.transform(rays,0,0,.25,0,0,0) surf.focusI(rays,weights=weights) if optsurface: PT.conic(1107.799202,-1.) #Emprically found best surface 1128.058314 #Compute FoM rmsTelescope[t==theta] = PT.rmsCentroid(weights=weights)/10000. hpdTelescope[t==theta] = PT.hpd(weights=weights)/10000. cx,cy = PT.centroid() cent[t==theta] = cx ind = geo[1] > 0. platefrac[t==theta] = np.std(plate[ind]/1e4)/rmsTelescope[t==theta] print hpdTelescope[t==theta],rmsTelescope[t==theta] return hpdTelescope,rmsTelescope,delta,cent,plate
def traceChaseParam(num, psi, theta, alpha, L1, z0, bestFocus=False, chaseFocus=False): """Trace a WS mirror pair using the parameters in Eq. 13 of Chase & VanSpeybroeck Return the RMS radius of the focus Can specify whether to find the best focus or not """ #Define annulus of source rays r0 = np.tan(4 * alpha) * z0 alphap = 2 * alpha / (1 + 1 / psi) r1 = PT.wsPrimRad(z0 + L1, 1., r0, z0) #np.tan(alphap/2.)*L1 + r0 PT.annulus(r0, r1, num) PT.transform(0, 0, 0, np.pi, 0, 0) PT.transform(0, 0, -10000., 0, 0, 0) pdb.set_trace() #Trace to primary PT.wsPrimary(r0, z0, psi) #Handle vignetting PT.vignette() ind = np.logical_and(PT.z < z0 + L1, PT.z > z0) PT.vignette(ind=ind) ## pdb.set_trace() #Apply pointing error PT.l = PT.l + np.sin(theta) PT.n = -np.sqrt(1 - PT.l**2) #Anything hitting backside goes away dot = PT.l * PT.ux + PT.m * PT.uy + PT.n * PT.uz ind = dot < 0. PT.vignette(ind=ind) if np.size(PT.x) < 1: return 0., 0., 0. #Reflect PT.reflect() N1 = np.size(PT.x) #Trace to secondary PT.wsSecondary(r0, z0, psi) #Vignette anything that did not converge PT.vignette() #Vignette anything hitting the backside dot = PT.l * PT.ux + PT.m * PT.uy + PT.n * PT.uz ind = dot < 0. PT.vignette(ind=ind) ## #Vignette anything outside the physical range of the mirror ## ind = np.logical_and(PT.z>z0-L1,PT.z<z0) ## PT.vignette(ind=ind) if np.size(PT.x) < 1: return 0., 0., 0. PT.reflect() #Trace to focal plane PT.flat() cx, cy = PT.centroid() r = np.sqrt(cx**2 + cy**2) #Find best focus delta = 0. if chaseFocus or bestFocus: delta = .0625 * (psi + 1) * (r**2 * L1 / z0**2) * (1 / np.tan(alpha))**2 PT.transform(0, 0, delta, 0, 0, 0) PT.flat() delta2 = 0. delta3 = 0. if bestFocus: try: delta2 = PT.findimageplane(20., 100) PT.transform(0, 0, delta2, 0, 0, 0) delta3 = PT.findimageplane(1., 100) PT.transform(0, 0, delta3, 0, 0, 0) except: pdb.set_trace() PT.flat() return PT.rmsCentroid() / z0, delta + delta2 + delta3, r
def traceArcus(N,span=20.,d=.605,t=.775,gap=50.,\ inc=1.5*pi/180,l=95.,bestFocus=bestfoc,order=0,\ blazeYaw=yaw,wave=1.,marg=marg,findMargin=False,\ analyzeLine=True,offX=0.,offY=0.,calcCentroid=False,\ vis=False): """Trace Arcus sector """ sys.stdout.write(str(wave) + '\t' + str(order) + '\r') sys.stdout.flush() if wave is not 'uniform': #Compute efficiency and determine whether to proceed geff = gratEff(order) #Add in grating efficiency and CCD QE #geff and ccdQE need to be arrays if wave is array g = geff(wave) det = ccdQE(wave) if g * det == 0.: return 0, 0 g = g.reshape(np.size(g)) #Assign random wavelength to each ray if wave == 'uniform': rays,weights,minfoc,lmax,wave,coords = defineSPOaperture(N,wave,\ offX=offX,offY=offY,\ vis=vis) else: rays,weights,minfoc,lmax,coords = defineSPOaperture(N,wave,offX=offX,\ offY=offY,\ vis=vis) #Trace rays through SPO modules ## rays = plotting.pload('/home/rallured/Dropbox/Arcus/' ## 'Raytrace/Performance/160516_SPORays.pkl') ## weights = pyfits.getdata('/home/rallured/Dropbox/Arcus/' ## 'Raytrace/Performance/160516_Weights.fits') ## minfoc = 11972.53195 ## lmax = 115.97497 ## pdb.set_trace() #Determine outermost radius of grating array #outerrad should be fixed outerrad = outerradNom #np.max(sqrt(rays[1]**2+rays[2]**2)) foc = tran.applyTPos(0, 0, 0, coords, inverse=True) hubdist = sqrt(outerrad**2 + foc[2]**2) angle = np.arctan(outerrad / (minfoc - (lmax + gap + 95.))) thetag = angle - 1.5 * pi / 180. ## print 'Outerrad: %f\nHubdist: %f\nLmax: %f\nOuter Focus: %f\n' % \ ## (outerrad,hubdist,L.max(),focVec[-1]) #Trace grating array - need to add in grating efficiency and #CCD quantum efficiency if bestFocus is None: return gratArray(rays,outerrad,hubdist,angle,inc,l=l,\ weights=weights,order=-3,blazeYaw=blazeYaw,\ wave=2.4,coords=coords) ## return traceSector(Rin,Rout,F,N,span=span,d=d,t=t,gap=gap,\ ## inc=inc,l=l,bestFocus=bestFocus,order=order,\ ## blazeYaw=blazeYaw,wave=wave,marg=marg) gratArray(rays,outerrad,hubdist,angle,inc,l=l,bestFocus=bestFocus,\ weights=weights,order=order,blazeYaw=blazeYaw,wave=wave,\ offX=offX,vis=vis,coords=coords) #Grating vignetting weights = weights * (1 - abs(offX) / inc) if np.size(wave) == 1: #Account for grating efficiency weights = weights * g * det #Vignette rays with no weight (evanescence) ## rays = tran.vignette(rays,weights>0.) ## if len(rays[1])==0: ## return 0.,0. #Go to focal plane tran.transform(rays, 0, 0, bestFocus, 0, 0, 0, coords=coords) surf.flat(rays) if vis is True: pyfits.writeto('FocalPlanePos.fits',\ np.array([rays[1],rays[2],rays[3]]),\ clobber=True) pyfits.writeto('Wavelengths.fits',\ wave,clobber=True) if analyzeLine is False: return rays, weights #Get rid of outliers ind = np.abs(rays[2] - np.average(rays[2])) < 10. rays = PT.vignette(rays, ind=ind) weights = weights[ind] if calcCentroid is True: cent = anal.centroid(rays, weights=weights) if cent[0] < 100 or cent[1] < 100: pdb.set_trace() return anal.centroid(rays, weights=weights) #Get rid of rays that made it through ## ind = rays[1] > 0 ## rays = PT.vignette(rays,ind=ind) ## weights = weights[ind] #If no rays made it through if np.size(rays[1]) == 0: return 0, 0, 0, 0 #Look at resolution of this line try: cy = np.average(rays[2], weights=weights) except: pdb.set_trace() if findMargin is True: #Compute FWHM after Gaussian convolution fwhms = np.linspace(1, 3, 201) / 60.**2 * pi / 180 * 12e3 tot = np.array([convolveLSF(rays,.001,m,weights=weights)\ for m in fwhms/2.35]) #Convert to arcsec, return std of margin convolution marg = fwhms[np.argmin( np.abs(tot / 12e3 * 180 / pi * 60**2 - 3.))] / 2.35 return marg, rays fwhm = convolveLSF(rays, .001, marg, weights=weights) resolution = cy / fwhm weights = weights**.799 * .83 * .8 * .9 #Grat plates, azimuthal ribs, packing area = np.sum(weights) #print resolution #print area #print sqrt((cy/3000)**2 - lsf**2)/F * 180/pi*60**2 ## print 'Order: %i, Wave: %.2f\n'%(order,wave) return resolution, area, np.nanmean(rays[1]), np.nanmean(rays[2]),fwhm,\ rays,weights
def traceSPO(R, L, F, N, M, span=pi / 12, d=.605, t=.775): """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 tx = np.zeros(M * N) ty = np.zeros(M * N) tz = np.zeros(M * N) tl = np.zeros(M * N) tm = np.zeros(M * N) tn = np.zeros(M * N) tux = np.zeros(M * N) tuy = np.zeros(M * N) tuz = np.zeros(M * N) #Loop through shell radii and collect rays for i in range(M): #Set up source annulus PT.subannulus(R[i], R[i] + d, span, N) #Transform rays to be above xy plane PT.n = -PT.n PT.transform(0, 0, -100., 0, 0, 0) #Trace to primary PT.spoPrimary(R[i], F) PT.reflect() #Vignette ind = np.logical_and(PT.z <= L[i], PT.z >= 0.) if np.sum(ind) < N: pdb.set_trace() PT.vignette(np.logical_and(PT.z <= L[i], PT.z >= 0.)) #Trace to secondary PT.spoSecondary(R[i], F) PT.reflect() #Vignette ind = np.logical_and(PT.z <= 0., PT.z >= -L[i]) if np.sum(ind) < N: pdb.set_trace() PT.vignette(ind) #Collect rays try: tx[i * N:(i + 1) * N] = PT.x ty[i * N:(i + 1) * N] = PT.y tz[i * N:(i + 1) * N] = PT.z tl[i * N:(i + 1) * N] = PT.l tm[i * N:(i + 1) * N] = PT.m tn[i * N:(i + 1) * N] = PT.n tux[i * N:(i + 1) * N] = PT.ux tuy[i * N:(i + 1) * N] = PT.uy tuz[i * N:(i + 1) * N] = PT.uz except: pdb.set_trace() #Set to PT rays try: PT.x = tx PT.y = ty PT.z = tz PT.l = tl PT.m = tm PT.n = tn PT.ux = tux PT.uy = tuy PT.uz = tuz except: pdb.set_trace() return
import traces.PyTrace as PT import time tstart = time.time() PT.circularbeam(200., 512 * 512) print time.time() - tstart gpus = PT.transferToGPU() print time.time() - tstart PT.radgratC[512, 512](12.e3, 160. / 12.e3, 1, 1., *gpus[:6]) PT.radgratC[512, 512](12.e3, 160. / 12.e3, 1, 1., *gpus[:6]) PT.radgratC[512, 512](12.e3, 160. / 12.e3, 1, 1., *gpus[:6]) PT.radgratC[512, 512](12.e3, 160. / 12.e3, 1, 1., *gpus[:6]) PT.returnFromGPU(*gpus) print time.time() - tstart ##PT.circularbeam(200.,512*512) ##print time.time()-tstart ##PT.radgrat(12.e3,160./12.e3,1,1.) ##PT.radgrat(12.e3,160./12.e3,1,1.) ##PT.radgrat(12.e3,160./12.e3,1,1.) ##PT.radgrat(12.e3,160./12.e3,1,1.) ##print time.time()-tstart
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 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 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 arc(inc, yaw, hubdist, wave, order, dpermm): """Return x and y positions of diffraction arc as a function of wavelength for a given order""" #Set up source ray PT.circularbeam(0., 1) #Transform to grating frame PT.transform(0, 0, 0, pi / 2 + inc, 0, 0) PT.transform(0, 0, 0, 0, 0, yaw) PT.flat() #Apply grating PT.reflect() PT.radgrat(hubdist, dpermm, order, wave) #Go to focus PT.transform(0, 0, 0, 0, 0, -yaw) PT.transform(0, hubdist, 0, 0, 0, 0) PT.transform(0, 0, 0, pi / 2, 0, 0) PT.flat() #Get ray positions return PT.x[0], PT.y[0]
def traceSPO(R,L,focVec,N,M,spanv,wave,d=.605,t=.775,offX=0.,offY=0.,\ vis=None,ang=None,coords=None,scatter=False): """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 = PT.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) #Add scatter if scatter is True: theta = np.arctan2(rays[2], rays[1]) inplane = np.random.normal(scale=10. / 2.35 * 5e-6, size=N) outplane = np.random.normal(scale=1.5 / 2.35 * 5e-6, size=N) rays[4] = rays[4] + inplane * np.cos(theta) + outplane * np.sin( theta) rays[5] = rays[5] + inplane * np.sin(theta) + outplane * np.cos( theta) rays[6] = -np.sqrt(1. - rays[5]**2 - rays[4]**2) #Compute reflectivity inc = PT.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 traceBeam(gratAlign,order=1.,wave=2.48,blaze=30.): """Traces a beam to grating, applies misalignment, then traces to focal plane and returns mean x,y position x refers to spectral direction """ #Compute yaw to achieve Littrow configuration phi0 = arccos(sin(1.5*pi/180)/cos(blaze*pi/180)) yaw = -tan(sin(blaze*pi/180)/tan(phi0)) ## yaw = yaw - pi/2 ## pdb.set_trace() #Set up beam rays = PT.pointsource(0.,10) #multiple rays to avoid Python complaints #Rotate to nominal grating reference frame PT.transform(rays,0,0,0,pi/2+1.5*pi/180,0,0) #Apply misalignment PT.transform(rays,*gratAlign) #Trace grating PT.flat(rays) PT.transform(rays,0,0,0,0,0,yaw) #-1.73211678*pi/180 PT.radgrat(rays,11500.,160./11500.,order,wave) PT.itransform(rays,0,0,0,0,0,yaw) #Reverse misalignment PT.itransform(rays,*gratAlign) #Trace to focal plane PT.transform(rays,0,11500.,0,0,0,0) PT.transform(rays,0,0,0,pi/2,0,0) PT.flat(rays) #Return mean positions return mean(rays[1]),mean(rays[2])
def gratArray(outerrad, hubdist, angle, inc, l=95.): """Trace rays leaving SPO petal to the fanned grating array. Start with outermost radius and rotate grating array about the hub. Define outermost grating position by max ray radius at desired axial height. Rays have been traced to bottom of outermost grating. """ #Put origin at bottom of outermost grating PT.transform(outerrad, 0, 0, 0, 0, 0) #Go to proper incidence angle of grating PT.transform(0, 0, 0, 0, 0, -pi / 2) PT.transform(0, 0, 0, -pi / 2 - angle + inc, 0, 0) #Go to hub PT.transform(0, hubdist, 0, 0, 0, 0) #Trace out gratings until no rays hit a grating #Flat #Indices #Reflect #Apply Grating #Next PT.flat() ind = np.logical_and(PT.y < -hubdist, PT.y > -l - hubdist) ang = l * sin(inc) / hubdist i = 0 while np.sum(ind) > 0: i = i + 1 PT.reflect(ind=ind) PT.radgrat(0., 160. / hubdist, 0, 1., ind=ind) PT.transform(0, 0, 0, ang, 0, 0) PT.flat() ind = np.logical_and(PT.y < -hubdist, PT.y > -l - hubdist) sys.stdout.write('%i \r' % i) sys.stdout.flush() pdb.set_trace()
def traceWSShell(num,theta,r0,z0,phigh,plow,shigh,slow,\ chaseFocus=False,bestFocus=False): """Trace a WS mirror pair with 10 m focal length and mirror axial cutoffs defined by phigh,plow """ #Define annulus of source rays a, p, d, e = con.woltparam(r0, z0) r1 = PT.wsPrimRad(plow, 1., r0, z0) #np.tan(a/2.)*(plow-10000.) + r0 r2 = PT.wsPrimRad(phigh, 1., r0, z0) #np.tan(a/2.)*(phigh-10000.) + r0 ## r2 = np.mean([r1,r2]) PT.annulus(r1, r2, num) PT.transform(0, 0, 0, np.pi, 0, 0) PT.transform(0, 0, z0, 0, 0, 0) ## pdb.set_trace() #Trace to primary PT.wsPrimary(r0, z0, 1.) #Handle vignetting PT.vignette() ind = np.logical_and(PT.z < phigh, PT.z > plow) PT.vignette(ind=ind) #Vignette rays hitting backside of mirror dot = PT.l * PT.ux + PT.m * PT.uy + PT.n * PT.uz ind = dot < 0. PT.vignette(ind=ind) #If all rays are vignetted, return if np.size(PT.x) < 1: return 0., 0., 0. #Apply pointing error PT.l = PT.l + np.sin(theta) PT.n = -np.sqrt(1 - PT.l**2) #Reflect PT.reflect() #Compute mean incidence angle for reflectivity ## ang = np.abs(np.mean(np.arcsin(dot))) #radians ## refl1 = CXCreflIr(ang,energy,rough) #Total rays entering primary aperture N1 = np.size(PT.x) #Trace to secondary PT.wsSecondary(r0, z0, 1.) #Vignette anything that did not converge PT.vignette() #Vignette anything outside the physical range of the mirror ind = np.logical_and(PT.z > slow, PT.z < shigh) PT.vignette(ind=ind) #Vignette anything hitting the backside dot = PT.l * PT.ux + PT.m * PT.uy + PT.n * PT.uz ind = dot < 0. PT.vignette(ind=ind) if np.size(PT.x) < 1: return 0., 0., 0. PT.reflect() #Compute mean incidence angle for reflectivity ## ang = np.abs(np.mean(np.arcsin(dot))) #radians ## refl2 = CXCreflIr(ang,energy,rough) #Trace to focal plane PT.flat() #Find Chase focus delta = 0. if chaseFocus or bestFocus: cx, cy = PT.centroid() r = np.sqrt(cx**2 + cy**2) delta = .0625*(1.+1)*(r**2*(phigh-plow)/10000.**2)\ *(1/np.tan(a))**2 PT.transform(0, 0, delta, 0, 0, 0) PT.flat() #Find best focus delta2 = 0. delta3 = 0. if bestFocus: try: delta2 = PT.findimageplane(20., 100) PT.transform(0, 0, delta2, 0, 0, 0) delta3 = PT.findimageplane(1., 100) PT.transform(0, 0, delta3, 0, 0, 0) except: pdb.set_trace() PT.flat() #return refl1*refl2 return PT.hpd(), PT.rmsCentroid(), delta
def setupSource(wave,N,radius=450.,focal=8000.,scatter=50e-6,\ gwidth=25.,glength=32.,pitch=0.,yaw=0.,roll=0.): """Set up converging beam with some scatter. Idea is to place a grating at radius and focal length with an incidence angle of 1.5 degrees """ #Setup rays over grating surface PT.x = np.random.uniform(low=-gwidth / 2, high=gwidth / 2, size=N) PT.y = np.random.uniform(low=-glength / 2, high=glength / 2, size=N) PT.z = np.repeat(0., N) PT.l = np.zeros(N) PT.m = np.zeros(N) PT.n = np.zeros(N) PT.ux = np.zeros(N) PT.uy = np.zeros(N) PT.uz = np.repeat(1., N) #Transform to nominal focus to set ray cosines PT.transform(0, 0, 0, -88.5 * np.pi / 180, 0, 0) PT.transform(0, radius, -focal, 0, 0, 0) rad = np.sqrt(PT.x**2 + PT.y**2 + PT.z**2) PT.l = -PT.x / rad PT.m = -PT.y / rad PT.n = -PT.z / rad #Add scatter PT.l = PT.l + scatter / 10. * np.random.normal(size=N) PT.m = PT.m + scatter * np.random.normal(size=N) PT.n = -np.sqrt(1. - PT.l**2 - PT.m**2) #Go back to plane of of grating PT.transform(0, -radius, focal, 0, 0, 0) PT.transform(0, 0, 0, 88.5 * np.pi / 180, 0, np.pi) #Place grating and diffract hubdist = np.sqrt(radius**2 + focal**2) * np.cos(1.5 * np.pi / 180) PT.flat() PT.reflect() PT.transform(0, 0, 0, pitch, roll, yaw) PT.radgrat(hubdist, 160. / hubdist, 1, wave) PT.itransform(0, 0, 0, pitch, roll, yaw) #Go to focal plane PT.transform(0, 0, 0, np.pi / 2, 0, 0) PT.transform(0, 0, -hubdist, 0, 0, 0) PT.transform(0, 0, 27.27727728 - .04904905, 0, 0, 0) PT.flat() #plt.plot(PT.x,PT.y,'.') return PT.centroid()
def traceSector(Rin,Rout,F,N,span=20.,d=.605,t=.775,gap=50.,\ inc=1.5*pi/180,l=95.,bestFocus=None,order=0,\ blazeYaw=0.,wave=1.,marg=0.,findMargin=False,\ analyzeLine=True,offX=0.,offY=0.): """Trace Arcus sector """ #Trace parameters R = np.arange(Rin, Rout, t) #Vector of shell radii tg = .25 * np.arctan((R + d / 2) / F) #Primary graze angles L = d / tan(tg) #Primary length #L = 4*F*d/R #Vector of mirror lengths M = np.size(R) #Number of shells #Create focal length vector to implement spherical principle surface #This should be changed based on nominal focal lengths of #modules from cosine. focConst = F**2 #+Rin**2 focVec = sqrt(focConst - R**2) #Weight vector for shell radii weights = np.zeros(M * N) spanv = np.zeros(M) for i in range(M): #Full angular span of each shell spanv[i] = 2 * np.arcsin(span / 2 / R[i]) #Geometric area in each shell - 10^4 is unit conversion weights[i * N:(i + 1) * N] = ((R[i] + d)**2 - R[i]**2) * spanv[i] / 2 / 10000. #Assign random wavelength to each ray if wave == 'uniform': wave = np.random.uniform(3.6, 3.6 * 2, size=M * N) #Trace rays through SPO modules rays,refl = traceSPO(R,L,focVec,N,M,spanv,wave,d=d,t=t,\ offX=offX,offY=offY) #Can call traceSPO repeatedly for each individual module #Then send rays through grating array #Refl needs to be array if wave is array weights = weights * refl #Determine outermost radius of grating array PT.transform(rays, 0, 0, focVec[-1] - (L.max() + gap + 95.), 0, 0, 0) PT.flat(rays) #outerrad should be fixed outerrad = np.max(sqrt(rays[1]**2 + rays[2]**2)) hubdist = sqrt(outerrad**2 + (focVec[-1] - (L.max() + gap + 95.))**2) angle = np.arctan(outerrad / (focVec[-1] - (L.max() + gap + 95.))) thetag = angle - 1.5 * pi / 180. ## print 'Outerrad: %f\nHubdist: %f\nLmax: %f\nOuter Focus: %f\n' % \ ## (outerrad,hubdist,L.max(),focVec[-1]) pdb.set_trace() #Trace grating array - need to add in grating efficiency and #CCD quantum efficiency if bestFocus is None: return gratArray(rays,outerrad,hubdist,angle,inc,l=l,\ weights=weights,order=-3,blazeYaw=blazeYaw,\ wave=2.4) ## return traceSector(Rin,Rout,F,N,span=span,d=d,t=t,gap=gap,\ ## inc=inc,l=l,bestFocus=bestFocus,order=order,\ ## blazeYaw=blazeYaw,wave=wave,marg=marg) gratArray(rays,outerrad,hubdist,angle,inc,l=l,bestFocus=bestFocus,\ weights=weights,order=order,blazeYaw=blazeYaw,wave=wave) #Account for grating efficiency geff = gratEff(order) #Add in grating efficiency and CCD QE #geff and ccdQE need to be arrays if wave is array g = geff(wave) g = g.reshape(np.size(g)) weights = weights * g * ccdQE(wave) #Go to focal plane tran.transform(rays, 0, 0, bestFocus, 0, 0, 0) surf.flat(rays) if analyzeLine is False: return rays, weights, wave #Get rid of rays that made it through ## ind = rays[1] > 0 ## rays = PT.vignette(rays,ind=ind) ## weights = weights[ind] #Get rid of outliers ind = np.abs(rays[2] - np.average(rays[2])) < 10. rays = PT.vignette(rays, ind=ind) weights = weights[ind] #If no rays made it through if np.size(rays[1]) == 0: return 0, 0, 0, 0 #Look at resolution of this line try: cy = np.average(rays[2], weights=weights) except: pdb.set_trace() if findMargin is True: #Compute FWHM after Gaussian convolution fwhms = np.linspace(1, 3, 201) / 60.**2 * pi / 180 * 12e3 tot = np.array([convolveLSF(rays,.001,m,weights=weights)\ for m in fwhms/2.35]) #Convert to arcsec, return std of margin convolution marg = fwhms[np.argmin( np.abs(tot / 12e3 * 180 / pi * 60**2 - 3.))] / 2.35 return marg, rays fwhm = convolveLSF(rays, .001, marg, weights=weights) resolution = cy / fwhm area = np.sum( weights ) * .799 * .83 * .8 * .9 #Grat plates, azimuthal ribs, usable area #print resolution #print area #print sqrt((cy/3000)**2 - lsf**2)/F * 180/pi*60**2 print 'Done' return resolution, area, np.nanmean(rays[1]), np.nanmean(rays[2]),\ rays,weights