def altaz2hadec(alt,az) : """ Convert Altitude, Azimuth to HA, Dec at Kitt Peak elevation Args: alt: float or 1D np.array altitude in degrees az: float or 1D np.array azimuth in degrees Returns: ha, dec ha: float or 1D np.array Hour Angle in degrees dec: float or 1D np.array Hour Angle in degrees """ salt,calt = sincosd(alt) saz,caz = sincosd(az) slat,clat = sincosd(LATITUDE) ha = arctan2d( -saz*calt, -caz*slat*calt+salt*clat) dec = arcsind(slat*salt+clat*calt*caz) return ha,dec
def xy2hadec(x,y,tel_ha,tel_dec) : """ Convert tangent plane x,y to HA,Dec given a telescope pointing tel_ha, tel_dec Args: x: float or 1D np.array with tangent plane coord. y: float or 1D np.array with tangent plane coord. tel_ha: float; telescope pointing Hour Angle in degrees tel_dec: float; telescope pointing Dec in degrees Returns: HA, Dec float or 1D np.array in degrees """ sh,ch = sincosd(tel_ha) sd,cd = sincosd(tel_dec) rh=np.array([[ch,-sh,0],[sh,ch,0],[0,0,1]]) rd=np.array([[sd,0,cd],[0,1,0],[-cd,0,sd]]) z = np.sqrt(1-x**2-y**2) xyz = rh.dot(rd.dot(np.array([-y,x,z]))) return getLONLAT(xyz)
def hadec2xy(ha,dec,tel_ha,tel_dec) : """ Convert HA,Dec to tangent plane x,y given a telescope pointing tel_ha, tel_dec Args: ha: float or 1D np.array Hour Angle in degrees dec: float or 1D np.array Hour Angle in degrees (same size as ha) tel_ha: float; telescope pointing Hour Angle in degrees tel_dec: float; telescope pointing Dec in degrees Returns: x y float or 1D np.array """ xyz = getXYZ(ha,dec) sh,ch = sincosd(tel_ha) sd,cd = sincosd(tel_dec) rh=np.array([[ch,sh,0],[-sh,ch,0],[0,0,1]]) # rotation about HA axis rd=np.array([[sd,0,-cd],[0,1,0],[+cd,0,sd]]) # rotation about Dec axis tmp = rd.dot(rh.dot(xyz)) x=tmp[1] y=-tmp[0] return x,y
def hadec2altaz(ha,dec) : """ Convert HA,Dec to Altitude , Azimuth at Kitt Peak elevation Args: ha: float or 1D np.array hour angle in degrees dec: float or 1D np.array declination in degrees Returns: alt, az alt: float or 1D np.array altitude in degrees az: float or 1D np.array azimuth in degrees """ sha,cha = sincosd(ha) sdec,cdec = sincosd(dec) slat,clat = sincosd(LATITUDE) x = - cha * cdec * slat + sdec * clat y = - sha * cdec z = cha * cdec * clat + sdec * slat r = np.hypot(x, y) az = arctan2d(y,x) alt = arctan2d(z,r) return alt,az
def fiberassign_radec2xy_cs5(ra, dec, tile_ra, tile_dec, tile_mjd, tile_ha, tile_fieldrot, adc1=None, adc2=None, to_platemaker=True): """Computes X Y focal plane coordinates of targets in CS5 coordinate system. Args: ra : 1D numpy.array with target RA in degrees (need an array of points to compute the field rotation) dec : 1D numpy.array with target Dec in degrees, same size as ra tile_ra : float, RA of tile center in degrees, such that after pointing and ADC shift corrections, this corresponds to X=0,Y=0 tile_dec : float, Dec of tile center in degrees, such that after pointing and ADC shift corrections, this corresponds to X=0,Y=0 tile_mjd : float, days, used for precession (does not need to be super accurate) tile_ha : float, hour angle of observation, in degrees tile_fieldrot : float, design/requested field rotation, in degrees adc1 : optional, float, ADC1 angle in degrees: by default it is computed based on the HA and Dec. adc2 : optional, float, ADC2 angle in degrees: by default it is computed based on the HA and Dec. to_platemaker : assume output coordinates are in platemaker system and use dm2pm transform Returns xfp,yfp, focal plane coordinates in mm in CS5, 1D numpy arrays of same size as ra,dec """ assert (ra.size == dec.size) # LST from HA lst = tile_ha + tile_ra if ((adc1 is None) and (adc2 is not None)) or ((adc1 is not None) and (adc2 is None)): raise ValueError("either set both adc angles or none") if adc1 is None: adc1, adc2 = pm_get_adc_angles(tile_ha, tile_dec) # start with pointing = tile center tel_ra = tile_ra + 0. tel_dec = tile_dec + 0. # tune telescope pointing given ADC angle # in order to fp coordinates of tile RA and DEC, it's not zero because of the ADC angles for _ in range(2): xtan, ytan = radec2tan(np.array([tile_ra]), np.array([tile_dec]), tel_ra, tel_dec, tile_mjd, lst, hexrot_deg=0) xfp_0, yfp_0 = tan2fp(xtan, ytan, adc1, adc2) #mm #print("Temp tile center in FP coordinates = {},{} mm".format(xfp_0[0],yfp_0[0])) # numeric derivative eps = 1. / 3600. # xtan, ytan = radec2tan(np.array([tile_ra + eps]), np.array([tile_dec]), tel_ra, tel_dec, tile_mjd, lst, hexrot_deg=0) xfp_dra, yfp_dra = tan2fp(xtan, ytan, adc1, adc2) #mm xtan, ytan = radec2tan(np.array([tile_ra]), np.array([tile_dec + eps]), tel_ra, tel_dec, tile_mjd, lst, hexrot_deg=0) xfp_ddec, yfp_ddec = tan2fp(xtan, ytan, adc1, adc2) #mm dxdra = (xfp_dra[0] - xfp_0[0]) / eps dydra = (yfp_dra[0] - yfp_0[0]) / eps dxddec = (xfp_ddec[0] - xfp_0[0]) / eps dyddec = (yfp_ddec[0] - yfp_0[0]) / eps J = [[dxdra, dxddec], [dydra, dyddec]] # solve linear system to get tile RA Dec at center of fov Jinv = np.linalg.inv(J) X = Jinv.dot([xfp_0[0], yfp_0[0]]) dra = X[0] ddec = X[1] # apply offset to telescope pointing tel_ra += dra tel_dec += ddec # verify xtan, ytan = radec2tan(np.array([tile_ra]), np.array([tile_dec]), tel_ra, tel_dec, tile_mjd, lst, hexrot_deg=0) xfp_0, yfp_0 = tan2fp(xtan, ytan, adc1, adc2) #mm print("Tile center in FP coordinates = {},{} mm".format( xfp_0[0], yfp_0[0])) # now compute coordinates of all targets xtan, ytan = radec2tan(ra, dec, tel_ra, tel_dec, tile_mjd, lst, hexrot_deg=0) tmp_xfp, tmp_yfp = tan2fp(xtan, ytan, adc1, adc2) if to_platemaker: # apply tranformation from desimeter to platemater dm2pm = DM2PM.read(dm2pm_filename()) tmp_xfp, tmp_yfp = dm2pm.dm2pm(tmp_xfp, tmp_yfp) # measure field rotation tmp_fieldrot = _measure_fieldrot_deg(-ra, dec, -tile_ra, tile_dec, tmp_xfp, tmp_yfp) # apply field rotation to match request drot = tile_fieldrot - tmp_fieldrot s, c = sincosd(drot) xfp = c * tmp_xfp - s * tmp_yfp yfp = s * tmp_xfp + c * tmp_yfp # verify realised_fieldrot = _measure_fieldrot_deg(-ra, dec, -tile_ra, tile_dec, xfp, yfp) print("Requested fieldrot={:3.1f} arcsec delta={:3.1f} arcsec".format( tile_fieldrot * 3600., (tile_fieldrot - realised_fieldrot) * 3600.)) return xfp, yfp
def vecZ(zdeg): # For positive zdeg=+az: +x=>+y; +y=>-x. s,c = sincosd(zdeg) return np.array([[c,-s,0], [+s,c,0], [0,0,1]])
def vecY(ydeg): # For positive ydeg=-elev: +z=>+x; +x=>-z. # do not overlook this minus sign: positive ydeg pitches downward. s,c = sincosd(ydeg) return np.array([[c,0,+s], [0,1,0], [-s,0,c]])
def vecX(xdeg): # For positive xdeg=cwRoll: +y=>+z; +z=>-y. s,c = sincosd(xdeg) return np.array([[1,0,0], [0,c,-s], [0,+s,c]])
def tan2radec(x_tan,y_tan,tel_ra,tel_dec,mjd,lst_deg,hexrot_deg, precession = True, aberration = True, polar_misalignment = True, use_astropy = False) : """ Convert ICRS coordinates to tangent plane coordinates Args: xtan: float or 1D np.array with tangent plane coordinates ytan: float or 1D np.array with tangent plane coordinates tel_ra: float, in degrees, telescope pointing RA tel_dec: float, in degrees, telescope pointing Dec mjd: float, Modified Julian Date of observation, in days lst_deg: float, local sidereal time, in degrees hexrot_deg: float, hexapod rotation angle, in degrees Returns RA,Dec in ICRS system (hopefully) Optional arguments: aberration: boolean; compute aberration if True polar_misalignment: boolean; compute polar misalignment if True use_astropy: boolean; use astropy coordinates for precession and aberration if True """ # undo hexapod rotation shex,chex = sincosd(hexrot_deg) x = chex*x_tan+shex*y_tan y = -shex*x_tan+chex*y_tan # need to apply precession ... etc to telescope pointing to interpret the x,y if precession : tel_ra,tel_dec = apply_precession_from_icrs(tel_ra, tel_dec, mjd, use_astropy) if aberration : tel_ra,tel_dec = apply_aberration(tel_ra,tel_dec,mjd, use_astropy) tel_ha = lst_deg - tel_ra if polar_misalignment : polar_misalignment_matrix = compute_polar_misalignment_rotation_matrix(me_arcsec=ME_ARCSEC,ma_arcsec=MA_ARCSEC) tel_ha,tel_dec = getLONLAT(polar_misalignment_matrix.dot(getXYZ(tel_ha,tel_dec))) # we need to apply refraction for the telescope pointing to interpret the x,y tel_alt,tel_az = hadec2altaz(tel_ha,tel_dec) # apply refraction refracted_tel_alt = apply_refraction(tel_alt) # back to ha,dec refracted_tel_ha,refracted_tel_dec = altaz2hadec(refracted_tel_alt,tel_az) # now convert x,y to ha,dec refracted_ha,refracted_dec = xy2hadec(x,y,refracted_tel_ha,refracted_tel_dec) # alt,az alt,az = hadec2altaz(refracted_ha,refracted_dec) # undo refraction alt = undo_refraction(alt) # back to ha,dec ha,dec = altaz2hadec(alt,az) # now polar mis-alignment if polar_misalignment : # inverse matrix polar_misalignment_matrix = compute_polar_misalignment_rotation_matrix(me_arcsec=-ME_ARCSEC,ma_arcsec=-MA_ARCSEC) ha,dec = getLONLAT(polar_misalignment_matrix.dot(getXYZ(ha,dec))) # ra ra = lst_deg - ha if aberration : ra,dec = undo_aberration(ra,dec,mjd, use_astropy) if precession : ra,dec = undo_precession_from_icrs(ra, dec, mjd, use_astropy) return ra,dec
def radec2tan(ra,dec,tel_ra,tel_dec,mjd,lst_deg,hexrot_deg, precession = True, aberration = True, polar_misalignment = True, use_astropy = False) : """ Convert ICRS coordinates to tangent plane coordinates Args: ra: float or 1D np.array with RA in degrees dec: float or 1D np.array with RA in degrees tel_ra: float, in degrees, telescope pointing RA tel_dec: float, in degrees, telescope pointing Dec mjd: float, Modified Julian Date of observation, in days lst_deg: float, local sidereal time, in degrees hexrot_deg: float, hexapod rotation angle, in degrees Returns x_tan,y_tan , tangent plane coordinates: x_tan = sin(theta)*cos(phi) : float on np.array (same shape as input ra,dec) y_tan = sin(theta)*sin(phi) : float on np.array (same shape as input ra,dec) where theta,phi are polar coordinates. theta=0 for along the telescope pointing. phi=0 for a star with the same Dec as the telescope pointing but a larger HA (or smaller RA). Optional arguments: aberration: boolean; compute aberration if True polar_misalignment: boolean; compute polar misalignment if True use_astropy: boolean; use astropy coordinates for precession and aberration if True """ if precession : ra,dec = apply_precession_from_icrs(ra, dec, mjd, use_astropy) tel_ra,tel_dec = apply_precession_from_icrs(tel_ra, tel_dec, mjd, use_astropy) if aberration : ra,dec = apply_aberration(ra,dec,mjd, use_astropy) tel_ra,tel_dec = apply_aberration(tel_ra,tel_dec,mjd, use_astropy) # ha,dec ha = lst_deg - ra tel_ha = lst_deg - tel_ra if polar_misalignment : # rotate polar_misalignment_matrix = compute_polar_misalignment_rotation_matrix(me_arcsec=ME_ARCSEC,ma_arcsec=MA_ARCSEC) ha,dec = getLONLAT(polar_misalignment_matrix.dot(getXYZ(ha,dec))) tel_ha,tel_dec = getLONLAT(polar_misalignment_matrix.dot(getXYZ(tel_ha,tel_dec))) # alt,az alt,az = hadec2altaz(ha,dec) tel_alt,tel_az = hadec2altaz(tel_ha,tel_dec) # apply refraction alt = apply_refraction(alt) tel_alt = apply_refraction(tel_alt) # convert back to ha,dec ha,dec = altaz2hadec(alt,az) tel_ha,tel_dec = altaz2hadec(tel_alt,tel_az) # tangent plane x,y = hadec2xy(ha,dec,tel_ha,tel_dec) # hexapod rotation shex,chex = sincosd(hexrot_deg) return chex*x-shex*y , +shex*x+chex*y