def test_sky_to_tel(): """Test application of the attitude matrix""" # test with quantities ra = ra_deg * u.deg dec = dec_deg * u.deg pa = pa_deg * u.deg v2 = v2_arcsec * u.arcsec v3 = v3_arcsec * u.arcsec attitude = rotations.attitude_matrix(v2, v3, ra, dec, pa) ra_2, dec_2 = rotations.tel_to_sky( attitude, *rotations.sky_to_tel(attitude, ra, dec)) assert np.abs((ra - ra_2).to(u.milliarcsecond).value) < 1e-6 assert np.abs((dec - dec_2).to(u.milliarcsecond).value) < 1e-6 # test without quantities attitude = rotations.attitude_matrix(v2_arcsec, v3_arcsec, ra_deg, dec_deg, pa_deg) ra_2, dec_2 = rotations.tel_to_sky( attitude, *rotations.sky_to_tel(attitude, ra_deg, dec_deg)) assert np.abs(ra_deg - ra_2.to(u.deg).value) * u.deg.to( u.milliarcsecond) < 1e-6 assert np.abs(dec_deg - dec_2.to(u.deg).value) * u.deg.to( u.milliarcsecond) < 1e-6 # test array inputs n_side = 3 span = 2 * u.arcmin x_width = span.to(u.deg).value centre_deg = (ra_deg, dec_deg) ra_array_deg, dec_array_deg = tools.get_grid_coordinates( n_side, centre_deg, x_width) ra_array_2, dec_array_2 = rotations.tel_to_sky( attitude, *rotations.sky_to_tel(attitude, ra_array_deg * u.deg, dec_array_deg * u.deg)) assert np.all( np.abs(ra_array_deg * u.deg - ra_array_2) < 1e-6 * u.milliarcsecond) assert np.all( np.abs(dec_array_deg * u.deg - dec_array_2) < 1e-6 * u.milliarcsecond) ra_array_2, dec_array_2 = rotations.tel_to_sky( attitude, *rotations.sky_to_tel(attitude, ra_array_deg, dec_array_deg)) assert np.all( np.abs(ra_array_deg * u.deg - ra_array_2) < 1e-6 * u.milliarcsecond) assert np.all( np.abs(dec_array_deg * u.deg - dec_array_2) < 1e-6 * u.milliarcsecond)
def test_attitude_matrix(): """Compare original and new attitude matrix generator functions.""" ra = ra_deg * u.deg dec = dec_deg * u.deg pa = pa_deg * u.deg v2 = v2_arcsec * u.arcsec v3 = v3_arcsec * u.arcsec attitude = rotations.attitude(v2_arcsec, v3_arcsec, ra_deg, dec_deg, pa_deg) attitude_matrix = rotations.attitude_matrix(v2, v3, ra, dec, pa) assert np.all(attitude == attitude_matrix)
def lrsFieldSim(ra, dec, binComp=''): """ Produce a Grism Time Series field simulation for a target. Parameters ---------- ra : float The RA of the target. dec : float The Dec of the target. binComp : sequence The parameters of a binary companion. Returns ------- simuCube : np.ndarray The simulated data cube. Index 0 and 1 (axis=0) show the trace of the target for orders 1 and 2 (respectively). Index 2-362 show the trace of the target at every position angle (PA) of the instrument. """ #############################INSTRUMENT PARAMETERS###################### ######################################################################## # Instantiate a pySIAF object siaf = pysiaf.Siaf('MIRI') aper = siaf.apertures['MIRIM_SLITLESSPRISM'] full = siaf.apertures['MIRIM_FULL'] # Calling the variables deg2rad = np.pi / 180 subX, subY = aper.XSciSize, aper.YSciSize rad = 2.0 # arcmins pixel_scale = 0.11 # arsec/pixel V3PAs = np.arange(0, 360, 1) nPA = len(V3PAs) # Generate cube of field simulation at every degree of APA rotation simuCube = np.zeros([nPA + 1, subY, subX]) xSweet, ySweet = aper.reference_point('det') add_to_v3pa = aper.V3IdlYAngle # MIRI Full Frame dimensions rows, cols = full.corners('det') minrow, maxrow = rows.min(), rows.max() mincol, maxcol = cols.min(), cols.max() #############################STEP 1##################################### ######################################################################## # Converting to degrees targetcrd = crd.SkyCoord(ra=ra, dec=dec, unit=(u.hour, u.deg)) targetRA = targetcrd.ra.value targetDEC = targetcrd.dec.value # Querying for neighbors with 2MASS IRSA's fp_psc (point-source catalog) info = Irsa.query_region(targetcrd, catalog='fp_psc', spatial='Cone', radius=rad * u.arcmin) # Coordinates of all the stars in FOV, including target allRA = info['ra'].data.data allDEC = info['dec'].data.data # Initiating a dictionary to hold all relevant star information stars = {} stars['RA'], stars['DEC'] = allRA, allDEC #############################STEP 2##################################### ######################################################################## sindRA = (targetRA - stars['RA']) * np.cos(targetDEC) cosdRA = targetDEC - stars['DEC'] distance = np.sqrt(sindRA**2 + cosdRA**2) if np.min(distance) > 1.0 * (10**-4): coords = crd.SkyCoord(ra=ra, dec=dec, unit=(u.hour, u.deg)).to_string('decimal') ra, dec = coords.split(' ')[0], coords.split(' ')[1] raise Exception( 'Unable to detect a source with coordinates [RA: {}, DEC: {}] within IRSA`s 2MASS Point-Source Catalog. Please enter different coordinates or contact the JWST help desk.' .format(str(ra), str(dec))) targetIndex = np.argmin(distance) # Restoring model parameters modelParam = readsav(os.path.join(TRACES_PATH, 'NIRISS', 'modelsInfo.sav'), verbose=False) models = modelParam['models'] modelPadX = modelParam['modelpadx'] modelPadY = modelParam['modelpady'] dimXmod = modelParam['dimxmod'] dimYmod = modelParam['dimymod'] jhMod = modelParam['jhmod'] hkMod = modelParam['hkmod'] teffMod = modelParam['teffmod'] #############################STEP 3##################################### ######################################################################## # JHK bands of all stars in FOV, including target Jmag = info['j_m'].data.data Hmag = info['h_m'].data.data Kmag = info['k_m'].data.data # J-H band, H-K band. This will be used to derive the Teff J_Hobs = Jmag - Hmag H_Kobs = Hmag - Kmag # Add any missing companion if binComp != '': bb = binComp[0] / 3600 / np.cos(allDEC[targetIndex] * deg2rad) allRA = np.append(allRA, (allRA[targetIndex] + bb)) allDEC = np.append(allDEC, (allDEC[targetIndex] + binComp[1] / 3600)) Jmag = np.append(Jmag, binComp[2]) Hmag = np.append(Kmag, binComp[3]) Kmag = np.append(Kmag, binComp[4]) J_Hobs = Jmag - Hmag H_Kobs = Hmag - Kmag # Number of stars nStars = stars['RA'].size # Find/assign Teff of each star starsT = np.empty(nStars) for j in range(nStars): color_separation = (J_Hobs[j] - jhMod)**2 + (H_Kobs[j] - hkMod)**2 min_separation_ind = np.argmin(color_separation) starsT[j] = teffMod[min_separation_ind] # Record keeping stars['Temp'] = starsT stars['Jmag'] = Jmag #############################STEP 4##################################### ######################################################################## # Calculate corresponding V2/V3 (TEL) coordinates for Sweetspot v2targ, v3targ = aper.det_to_tel(xSweet, ySweet) for V3PA in range(0, nPA, 1): # Get APA from V3PA APA = V3PA + add_to_v3pa if APA > 360: APA = APA - 360 elif APA < 0: APA = APA + 360 print('Generating field at APA : {}'.format(str(APA))) # Get target's attitude matrix for each Position Angle attitude = rotations.attitude_matrix(v2targ, v3targ, targetRA, targetDEC, APA) xdet, ydet = [], [] xsci, ysci = [], [] for starRA, starDEC in zip(stars['RA'], stars['DEC']): # Get the TEL coordinates of each star w attitude matrix V2, V3 = rotations.sky_to_tel(attitude, starRA, starDEC) # Convert to arcsec and turn to a float V2, V3 = V2.to(u.arcsec).value, V3.to(u.arcsec).value XDET, YDET = aper.tel_to_det(V2, V3) XSCI, YSCI = aper.det_to_sci(XDET, YDET) xdet.append(XDET) ydet.append(YDET) xsci.append(XSCI) ysci.append(YSCI) # Record keeping stars['xdet'], stars['ydet'] = np.array(xdet), np.array(ydet) stars['xsci'], stars['ysci'] = np.array(xsci), np.array(ysci) sci_targx, sci_targy = stars['xsci'][targetIndex],\ stars['ysci'][targetIndex] #############################STEP 5##################################### ######################################################################## inFOV = [] for star in range(0, nStars): x, y = stars['xdet'][star], stars['ydet'][star] if (mincol < x) & (x < maxcol) & (minrow < y) & (y < maxrow): inFOV.append(star) inFOV = np.array(inFOV) #############################STEP 6##################################### ######################################################################## fitsFiles = glob.glob(os.path.join(TRACES_PATH, 'MIRI', 'LOW*.fits')) fitsFiles = np.sort(fitsFiles) for idx in inFOV: sci_dx = round(sci_targx - stars['xsci'][idx]) sci_dy = round(sci_targy - stars['ysci'][idx]) temp = stars['Temp'][idx] for file in fitsFiles: if str(temp) in file: trace = fits.getdata(file)[0] fluxscale = 10.0**(-0.4 * \ (stars['Jmag'][idx] - stars['Jmag'][targetIndex])) # Padding array pad_trace = np.pad(trace, pad_width=5000, mode='constant', constant_values=0) # Determine the highest pixel value of trace maxY, maxX = np.where(pad_trace == pad_trace.max()) peakY, peakX = maxY[0], maxX[0] # Use relative distances (sci_dx, sci_dy) to find target # xTarg,yTarg are essentially the "sweetspot" in the PADDED arr xTarg = peakX + sci_dx yTarg = peakY + sci_dy # Use the (xTarg, yTarg) coordinates to slice out subarray # remember X is columns, Y is rows dimX0, dimX1 = xTarg - sci_targx, xTarg + subX - sci_targx dimY0, dimY1 = yTarg - sci_targy, yTarg + subY - sci_targy if dimX0 < 0: dimX0 = 0 dimX1 = subX if dimY0 < 0: dimY0 = 0 dimY1 = subY traceX, traceY = np.shape(pad_trace)[1], np.shape(pad_trace)[0] if dimX1 > traceX: dimX1 = traceX dimX0 = traceX - subX if dimY1 > traceY: dimY1 = traceY dimY0 = traceY - subY if (dimX1 < 0) or (dimY1 < 0): continue # -1 because pySIAF is 1-indexed mx0, mx1 = int(dimX0) - 1, int(dimX1) - 1 my0, my1 = int(dimY0) - 1, int(dimY1) - 1 # Fleshing out index 0 of the simulation cube (trace of target) if (sci_dx == 0) & (sci_dy == 0): # this is the target tr = pad_trace[my0:my1, mx0:mx1] * fluxscale trX, trY = np.shape(tr)[1], np.shape(tr)[0] simuCube[0, 0:trY, 0:trX] = tr # Fleshing out indexes 1-361 of the simulation cube # (trace of neighboring stars at every position angle) else: tr = pad_trace[my0:my1, mx0:mx1] * fluxscale trX, trY = np.shape(tr)[1], np.shape(tr)[0] simuCube[V3PA + 1, 0:trY, 0:trX] += tr return simuCube