def wolterprimarynode(rays,r0,z0,psi=1.): """Place Wolter node at current origin, focus at (-r0,0,-z0) """ tran.transform(rays,-r0,0,-z0,0,0,0) wolterprimary(rays,r0,z0,psi) tran.itransform(rays,-r0,0,-z0,0,0,0) return
def ellipsoidPrimary(rays,R0,F,S,psi): """ Trace rays to the primary of an ellipsoid-hyperboloid telescope. Call at focus, just like with Wolter-I """ #Compute ellipsoid parameters P,a,b,e,f = con.ellipsoidFunction(S,psi,R0,F) R = b**2/a #Move to vertex tran.transform(rays,0,0,F+f-P-a,0,0,0) #Call conic conic(rays,R,-e**2) #Go back to focus tran.itransform(rays,0,0,F+f-P-a,0,0,0) return
def ogre_simulation_one_channel(waves, orders, j=j, oa_misalign=oa_misalign, g_misalign=g_misalign, s_misalign=s_misalign, m_misalign=m_misalign, cen_width=5 * u.mm, rib_width=2 * u.mm, rib_num=3, edge_width=5. * u.mm, mod_width=150 * u.mm): ''' Simulate rays going through the OGRE spectrometer. This function will just simulate rays passing through the spectrometer with misalignments, but will not take throughput into consideration. A seperate function is needed to correct this output for throughput. Parameters ---------- waves : Quantity Array of wavelengths to simulate. Each wavelength in the array will be associated with one ray (100 wavelengths = 100 rays). orders : numpy.ndarray Diffraction orders associated with wavelengths passed. j : Quantity FWHM of the jitter throughout the observation. oa_misalign : g_misalign : s_misalign : m_misalign : Returns ------- rays : [opd, x, y, z, l, m, n, nx, ny, nz] Rays on the focal plane of the OGRE spectrometer. waves : Quantity Wavelengths corresponding to each simulated ray. orders : array Diffracted order of each simulated ray. ''' # Define initial rays. n = len(waves) rays = ogre.create_rays(10 * n) # Translate rays to center of optic assembly. rays[3] = np.ones(len(rays[1])) * oa_z_cen surfaces.flat(rays) # Misalign rays relative to optic assembly. trans.transform(rays, 0, 0, 0, oa_pitch, oa_yaw, 0) # Move rays to R_INT position. This is just a global offset. rays[3] = np.ones(len(rays[1])) * 3500. # Add jitter. xj = np.random.normal(0, j.to('rad').value, size=len(rays[4])) yj = np.random.normal(0, j.to('rad').value, size=len(rays[4])) rays[4] += xj rays[5] += yj rays[6] = np.sqrt(1 - rays[4]**2 - rays[5]**2) # Pass rays through optic. rays = ogre.ogre_mirror_module(rays, scatter='bg') # Randomly select indicies to keep based on count rate analysis. n_rays = len(rays[0]) rand_inds = np.random.choice(np.arange(n_rays, dtype=int), len(waves), replace=False) # Keep only those selected indicies. rays = [r[rand_inds] for r in rays] # Add random period error effect. rand_fact = np.random.normal(1, 0.000094, size=len(waves)) # Pass through grating moudle. rays, diff_ind = ogre.ogre_grating_module(rays, waves=waves * orders / rand_fact, g_misalign=g_misalign, s_misalign=s_misalign, m_misalign=m_misalign, return_diff_ind=True) # Keep only wavelength/orders that make it through grating module. waves = waves[diff_ind] orders = orders[diff_ind] # Occult rays that will hit ribs. rays, waves, orders = ogre.grating_rib_occultation(rays, waves=waves, orders=orders) # Transform coordinate system to be at center of rotation. trans.transform(rays, 0, 0, oa_z_cen, 0, 0, 0) # Propagate rays to misaligned plane, simulating center plane of optic assembly. surfaces.flat(rays) # Transform the rays back by the pitch angle to the optical axis coordinate system. trans.itransform(rays, 0, 0, 0, oa_pitch, oa_yaw, 0) # Put the rays back at the intersection plane of the ideal optic. rays[3] = np.ones(len(rays[3])) * oa_z_cen # Misalign in z-hat. trans.transform(rays, 0, 0, oa_z, 0, 0, 0) # Propagate to the focal plane. rays = ogre.ogre_focal_plane(rays, det_misalignments=[0, 0, 0, 0, 0, -det_z]) return rays, waves, orders