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 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 findGratingPosition(N, hubdist=11832.911, order=1, wave=4.4, disp=0.): """Place the SPO pair, find the focus, and then go back up to grating placement """ #Set up SPO rays = traceSource(N) placeSPO(rays) #SPO intersection plane is global coordinate system #Go to focus gratc = [tran.tr.identity_matrix()] * 4 surf.focusI(rays, coords=gratc) #Go back up to grating point tran.transform(rays, 0, 0, np.mean(-11828.856 * rays[6]), 0, 0, 0, coords=gratc) surf.flat(rays) #Place grating #Get to XY centroid of beam, now at center of grating tran.transform(rays, np.mean(rays[1]), 0, 0, 0, 0, 0, coords=gratc) gratc2 = np.copy(gratc) #Rotate to proper incidence angle tran.steerX(rays, coords=gratc2) tran.transform(rays, 0, 0, 0, 0, pi / 2 - 1.5 * pi / 180, 0, coords=gratc2) surf.flat(rays) tran.transform(rays, 0, 0, 0, 0, 0, pi / 2, coords=gratc2) #Go to hub and diffract #Add yaw yaw = grat.blazeYaw(1.5 * pi / 180, 2.4, 3, 160.) tran.transform(rays, 0, 0, 0, 0, 0, yaw, coords=gratc2) tran.transform(rays, 0, -hubdist + disp, 0, 0, 0, 0, coords=gratc2) tran.reflect(rays) tran.radgrat(rays, 160. / hubdist, order, wave) pdb.set_trace() #Go back to reference frame of grating rays = tran.applyT(rays, gratc2, inverse=True) #Back to global #rays = tran.applyT(rays,gratc) #forward to grating #Go to focus focusc = [tran.tr.identity_matrix()] * 4 surf.focusY(rays, coords=focusc) #Get rid of mean X and Y tran.transform(rays,np.mean(rays[1]),np.mean(rays[2]),0,0,0,0,\ coords=focusc) return rays,[gratc[1][i][-1] for i in range(3)],\ [focusc[1][i][-1] for i in range(3)]
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 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 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
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 gratArray(rays,outerrad,hubdist,angle,inc,l=95.,bestFocus=None,\ weights=None,order=0,blazeYaw=0.,wave=1.,offX=0.,\ coords=None,vis=False): """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. """ #Visualization bookkeeping xg, yg, zg = [np.zeros(len(rays[1]))] * 3 x, y = rays[1:3] #Dummy rays to ensure return of reference frame ## rays2 = sources.subannulus(220.,223.,10.*pi/180,100) #Put origin at bottom of outermost grating tran.transform(rays, outerrad, 0, 0, 0, 0, 0, coords=coords) ## PT.transform(rays2,outerrad,0,0,0,0,0) #Go to proper incidence angle of grating tran.transform(rays, 0, 0, 0, 0, 0, -pi / 2, coords=coords) tran.transform(rays, 0, 0, 0, -pi / 2 - angle + inc, 0, 0, coords=coords) ## PT.transform(rays2,0,0,0,0,0,-pi/2) ## PT.transform(rays2,0,0,0,-pi/2-angle+inc,0,0) #Go to hub tran.transform(rays, 0, 0, 0, 0, 0, blazeYaw, coords=coords) #Put in blaze tran.transform(rays, 0, hubdist, 0, 0, 0, 0, coords=coords) ## PT.transform(rays2,0,0,0,0,0,blazeYaw) #Put in blaze ## PT.transform(rays2,0,hubdist,0,0,0,0) #Trace out gratings until no rays hit a grating #Flat #Indices #Reflect #Apply Grating #Next #Edit to only flat rays with a substantial incidence angle indg = np.abs(np.arcsin(rays[6])) > .001 surf.flat(rays, ind=indg) rho = -sqrt(x**2 + y**2) * np.sign(y) ind = np.logical_and(rho > hubdist, rho < l + hubdist) ## pdb.set_trace() ind2 = np.copy(ind) #offx subtracted to prevent numerical vignetting...this #is accounted for with numerical factors, so don't want #any rays to be missed ang = l * sin(inc - offX) / hubdist * .95 i = 0 prev = np.copy(ind) #Loop condition needs to be rays not diffracted > 0 while np.sum(prev) < len(rays[1]): i = i + 1 if np.sum(ind2) > 0: tran.reflect(rays, ind=ind2) tran.radgrat(rays, 160. / hubdist, order, wave, ind=ind2) tran.transform(rays, 0, 0, 0, ang, 0, 0, coords=coords) ## PT.transform(rays2,0,0,0,ang,0,0) indg = np.abs(np.arcsin(rays[6])) > .001 indg = np.logical_and(np.invert(prev), indg) surf.flat(rays, ind=indg) ## pdb.set_trace() #Determine rays hitting new grating rho = -sqrt(x**2 + y**2) * np.sign(y) ind = np.logical_and(rho > hubdist, rho < l + hubdist) ind2 = np.logical_and(np.invert(prev), ind) #Remove previous rays prev = np.logical_or(prev, ind) #Add rays hitting new grating #sys.stdout.write('%i \r' % i) #sys.stdout.flush() tran.reflect(rays, ind=ind2) tran.radgrat(rays, 160. / hubdist, order, wave, ind=ind2) ## #Go to focal plane ## PT.transform(rays,0,-hubdist,0,0,0,0) ## PT.transform(rays,0,0,0,0,0,-blazeYaw) #Reverse blaze ## #Currently at bottom point of innermost grating ## pdb.set_trace() if vis is True: #Get hub position hub = tran.applyTPos(0, 0, 0, coords, inverse=True) pyfits.writeto('HubPos.fits', np.array(hub), clobber=True) #Get back to original outermost grating reference frame tran.transform(rays, 0, 0, 0, -ang * i, 0, 0, coords=coords) tran.transform(rays, 0, -hubdist, 0, 0, 0, 0, coords=coords) tran.transform(rays, 0, 0, 0, 0, 0, -blazeYaw, coords=coords) tran.transform(rays, 0, 0, 0, pi / 2 + angle - inc, 0, 0, coords=coords) tran.transform(rays, 0, 0, 0, 0, 0, pi / 2, coords=coords) tran.transform(rays, -outerrad, 0, 0, 0, 0, 0, coords=coords) ## PT.transform(rays2,0,0,0,-ang*i,0,0) ## PT.transform(rays2,0,-hubdist,0,0,0,0) ## PT.transform(rays2,0,0,0,0,0,-blazeYaw) ## PT.transform(rays2,0,0,0,pi/2+angle-inc,0,0) ## PT.transform(rays2,0,0,0,0,0,pi/2) ## PT.transform(rays2,-outerrad,0,0,0,0,0) #Export grating ray positions if vis is True: rays2 = tran.applyT(rays, coords, inverse=True) pyfits.writeto('GratingPos.fits',\ np.array([rays2[1],rays2[2],rays2[3]]),\ clobber=True) pdb.set_trace() #Should be there surf.flat(rays) ## PT.transform(rays,0,hubdist,0,0,0,0) ## PT.transform(rays,0,0,0,-ang*i+pi/2+angle-inc,0,0) ## PT.transform(rays,0,0,0,0,0,pi/2) ## PT.flat(rays) #Find focus if bestFocus is None: return surf.focusY(rays, weights=weights) ## ## #Focus already found, tracing diffracted line ## PT.transform(rays,0,0,bestFocus,0,0,0) ## PT.flat(rays) return None