def posang(l1, b1, l2, b2, system='galactic', units='degrees', **kwargs): """ Return the position angle between two points assuming a rectilinear coordinate system (I think; at the very least I am making no corrections for wcs). INPUT: longitude1, latitude1, longitude2, latitude2 Defaults to GALACTIC coordinates. **kwargs are passed to coords.Position """ pos1 = coords.Position([l1, b1], system=system, **kwargs) ra1, dec1 = pos1.j2000() pos2 = coords.Position([l2, b2], system=system, **kwargs) ra2, dec2 = pos2.j2000() radiff = (ra1 - ra2) / 180. * pi angle = arctan2( sin(radiff), cos(dec1 * pi / 180.) * tan(dec2 * pi / 180.) - sin(dec1 * pi / 180.) * cos(radiff)) if units == 'degrees': return angle / pi * 180 elif units == 'radians': return angle else: raise ValueError("Invalid units: %s" % units)
def coords_in_image(xc,yc,header,coordsys='celestial'): """ Determine whether the coordinates are within the boundaries of the image """ try: wcs = pywcs.WCS(header) except: # if the header isn't WCS compatible, we don't want it return False try: if coordsys=='celestial' and wcs.wcs.lngtyp=='GLON': xc,yc = coords.Position((xc,yc),system=coordsys).galactic() elif coordsys=='galactic' and wcs.wcs.lngtyp=='RA': xc,yc = coords.Position((xc,yc),system=coordsys).j2000() xp,yp = wcs.wcs_sky2pix(xc,yc,0) except: return False if xp > wcs.naxis1 or xp < 0: return False elif yp > wcs.naxis2 or yp < 0: return False else: return True
def gal2cel(regfile): """ Converts a region file from galactic to celestial coordinates including position angle reference from the center of the box (right now only works on box regions) Requires pyregion with the ShapeList.write() function implemented... not clear if that exists in 1.0 """ reg = pyregion.open(regfile) for R in reg: if R.name == 'box': x, y, dx, dy, angle = R.coord_list posn = coords.Position([x, y], system='galactic') ra, dec = posn.j2000() newang = posang.posang(x - dx, y, x + dx, y, system='galactic') coord_list = [ra, dec, dx, dy, angle - newang - 90] R.coord_format = 'fk5' R.coord_list = coord_list R.params = coord_list reg.write(regfile[:-4] + "_fk5.reg")
def coords_in_image(fitsfile,lon,lat,system='galactic'): """ Determine whether the coordinates are inside the image """ if not isinstance(fitsfile,pyfits.HDUList): fitsfile = pyfits.open(fitsfile) wcs = pywcs.WCS(flatten_header(fitsfile[0].header)) if 'RA' in wcs.wcs.ctype[0]: pos = coords.Position((lon,lat),system=system) lon,lat = pos.j2000() if 'GLON' in wcs.wcs.ctype[0]: pos = coords.Position((lon,lat),system=system) lon,lat = pos.galactic() x,y = wcs.wcs_sky2pix(lon,lat,0) #DEBUG print x,y,wcs.naxis1,wcs.naxis2 if (0 < x < wcs.naxis1) and (0 < y < wcs.naxis2): return True else: return False
def output_tab_delineated_spreadsheet(spreadsheet, print_column_headers=False): column_headers = [ key for key in match_table.columns.keys if 'index' not in key ] primary_header = column_headers[0] column_headers.insert(1, 'DEC') column_headers.insert(1, 'RA') row_strings = [] if print_column_headers: row_strings.append('\t'.join(column_headers)) spreadsheet_matched = match_table.where( np.in1d(match_table[primary_header], spreadsheet[primary_header.lstrip('WUVARS_2014_')])) RA_array = [] DEC_array = [] for (ra, dec) in zip(spreadsheet.RA, spreadsheet.DEC): pp = coords.Position((ra, dec), units='rad') ra_s, de_s = pp.hmsdms().split(' ') RA_array.append(ra_s[:-1]) DEC_array.append(' ' + de_s[:-2]) for i in range(len(spreadsheet_matched)): row_list = [str(spreadsheet_matched[primary_header][i])] row_list.extend([str(RA_array[i]), str(DEC_array[i])]) row_list.extend([ str(spreadsheet_matched[header][i]) for header in column_headers if (header != primary_header) and (len(header) > 3) ]) row_strings.append('\t'.join(row_list)) return_string = '\n'.join(row_strings) return return_string
def rotcrop_cube(x1, y1, x2, y2, cubename, outname, xwidth=25, ywidth=25, in_system='galactic', out_system='equatorial', clobber=True, newheader=None, xcen=None, ycen=None): """ Crop a data cube and then rotate it with montage """ cubefile = pyfits.open(cubename) if xcen is None and ycen is None: pos1 = coords.Position([x1,y1],system=in_system) pos2 = coords.Position([x2,y2],system=in_system) if cubefile[0].header.get('CTYPE1')[:2] == 'RA': x1,y1 = pos1.j2000() x2,y2 = pos2.j2000() coord_system = 'celestial' elif cubefile[0].header.get('CTYPE1')[:4] == 'GLON': x1,y1 = pos1.galactic() x2,y2 = pos2.galactic() coord_system = 'galactic' xcen = (x1+x2)/2.0 ycen = (y1+y2)/2.0 print xcen,ycen,xwidth,ywidth,coord_system else: coord_system = in_system sc = subcube(cubefile[0].data, xcen, xwidth, ycen, ywidth, widthunits='pixels', units="wcs", header=cubefile[0].header, return_HDU=True) # note: there should be no security risk here because pyfits' writeto # will not overwrite by default tempcube = tempfile.mktemp(suffix='.fits') sc.writeto(tempcube) pa = posang.posang(x1,y1,x2,y2,system=coord_system) - 90 if newheader is None: newheader = sc.header.copy() cd11 = newheader.get('CDELT1') if newheader.get('CDELT1') else newheader.get('CD1_1') cd22 = newheader.get('CDELT2') if newheader.get('CDELT2') else newheader.get('CD2_2') cd12 = newheader.get('CD1_2') if newheader.get('CD1_2') else 0.0 cd21 = newheader.get('CD2_1') if newheader.get('CD2_1') else 0.0 cdelt = numpy.sqrt(cd11**2+cd12**2) tempheader = tempfile.mktemp(suffix='.hdr') ycensign = "+" if numpy.sign(ycen) >= 0 else "-" montage.mHdr("%s %1s%s" % (xcen, ycensign, numpy.abs(ycen)), xwidth*cdelt, tempheader, system=out_system, height=ywidth*cdelt, pix_size=cdelt*3600.0, rotation=pa) os.system("sed -i bck '/END/d' %s" % (tempheader)) newheader2 = pyfits.Header() newheader2.fromTxtFile(tempheader) #newheader2.fromtextfile(tempheader) for key in ('CRPIX3','CRVAL3','CDELT3','CD3_3','CUNIT3','WCSTYPE3','CTYPE3'): if newheader.get(key): newheader2.update(key,newheader.get(key)) if newheader.get('CD3_3') and newheader2.get('CDELT3') is None: newheader2.update('CDELT3',newheader.get('CD3_3')) newheader2.toTxtFile(tempheader,clobber=True) #if newheader2.get('CDELT3') is None: # raise Exception("No CD3_3 or CDELT3 in header.") else: if isinstance(newheader,str): newheader2 = pyfits.Header() newheader2.fromTxtFile(newheader) tempheader = tempfile.mktemp(suffix='.hdr') newheader2.toTxtFile(tempheader,clobber=True) montage.wrappers.reproject_cube(tempcube,outname,header=tempheader,clobber=clobber) #print "\n",outname #os.system('imhead %s | grep CDELT' % outname) # AWFUL hack because montage removes CDELT3 tempcube = pyfits.open(outname) tempcube.header = newheader2 #if tempcube.header.get('CDELT3') is None: # raise Exception("No CD3_3 or CDELT3 in header.") #print tempcube.header.get('CDELT3') tempcube.writeto(outname,clobber=True) #print tempcube.get('CDELT3') #print "\n",outname #os.system('imhead %s | grep CDELT' % outname) #print "\nnewheader2" #print newheader2.ascard #print return
def aper_world2pix(ap,wcs,coordsys='galactic',wunit='arcsec'): """ Converts an elliptical aperture (x,y,width,height,PA) from WCS to pixel coordinates given an input wcs (an instance of the pywcs.WCS class). Must be a 2D WCS header. """ convopt = {'arcsec':3600,'arcmin':60,'degree':1} try: conv = convopt[wunit] except: raise Exception("Must specify wunit='arcsec','arcmin', or 'degree'") if len(wcs.wcs.cdelt) != 2: raise Exception("WCS header is not strictly 2-dimensional. Look for 3D keywords.") if '' in wcs.wcs.ctype: raise Exception("WCS header has no CTYPE.") pos = coords.Position((ap[0],ap[1]),system=coordsys) if wcs.wcs.ctype[0][:2] == 'RA': ra,dec = pos.j2000() corrfactor = cos(dec*dtor) elif wcs.wcs.ctype[0][:4] == 'GLON': ra,dec = pos.galactic() corrfactor=1 else: raise Exception("WCS CTYPE has no match.") # workaround for a broken wcs.wcs_sky2pix try: radif = (wcs.wcs.crval[0]-ra)*dtor gamma = acos(cos(dec*dtor)*cos(wcs.wcs.crval[1]*dtor)*cos(radif)+sin(dec*dtor)*sin(wcs.wcs.crval[1]*dtor)) / dtor theta = atan2( sin(radif) , ( tan(dec*dtor)*cos(wcs.wcs.crval[1]*dtor)-sin(wcs.wcs.crval[1]*dtor)*cos(radif) ) ) x = -gamma * sin(theta) / wcs.wcs.cd[0,0] + wcs.wcs.crpix[0] y = gamma * cos(theta) / wcs.wcs.cd[1,1] + wcs.wcs.crpix[1] except: radif = (wcs.wcs.crval[0]-ra)*dtor gamma = acos(cos(dec*dtor)*cos(wcs.wcs.crval[1]*dtor)*cos(radif)+sin(dec*dtor)*sin(wcs.wcs.crval[1]*dtor)) / dtor theta = atan2( sin(radif) , ( tan(dec*dtor)*cos(wcs.wcs.crval[1]*dtor)-sin(wcs.wcs.crval[1]*dtor)*cos(radif) ) ) x = -gamma * sin(theta) / wcs.wcs.cdelt[0] + wcs.wcs.crpix[0] y = gamma * cos(theta) / wcs.wcs.cdelt[1] + wcs.wcs.crpix[1] #print "DEBUG: x,y from math (vectors): ",x,y #x,y = wcs.wcs_sky2pix(ra,dec,0) # convert WCS coordinate to pixel coordinate (0 is origin, do not use fits convention) #print "DEBUG: x,y from wcs: ",x,y try: x=x[0] - 1 # change from FITS to python convention y=y[0] - 1 # change from FITS to python convention #print "DEBUG: x,y from math: ",x,y except: pass # cd is default, cdelt is backup if len(ap) > 3: try: width = ap[2] / conv / abs(wcs.wcs.cd[0,0]) # first is width, second is height in DS9 PA convention height = ap[3] / conv / abs(wcs.wcs.cd[0,0]) except: width = ap[2] / conv / abs(wcs.wcs.cdelt[0]) # first is width, second is height in DS9 PA convention height = ap[3] / conv / abs(wcs.wcs.cdelt[0]) apold = copy.copy(ap) if len(ap) == 5: PA = ap[4] ap = [x,y,width,height,PA] else: ap = [x,y,width,height] elif len(ap) == 3: try: width = ap[2] / conv / abs(wcs.wcs.cd[0,0]) # first is width, second is height in DS9 PA convention except: width = ap[2] / conv / abs(wcs.wcs.cdelt[0]) # first is width, second is height in DS9 PA convention apold = copy.copy(ap) ap = [x,y,width] return ap
pcd_ra = pc['m0']['value'] * 180 / np.pi if pcd_ra < 0: pcd_ra += 360 ms.done() pcd = [pcd_ra, pcd_dec] return pcd if __name__ == '__main__': import astrolib.coords as coords import pyfits # lens positions for RXJ0911, presumably we want to this to be the phase center of the data/input visibilities for Ripples!!!! p_list = [ coords.Position("09:11:27.56447 05:50:54.302").j2000(), coords.Position("09:11:27.51420 05:50:54.967").j2000() ] fits_cube = pyfits.open('calibrated.LSRK_cont_R05.image.fits') header = fits_cube[0].header ra_px, dec_px = coord2pix(p_list, header) print "RA, Dec: " print zip(ra_px, dec_px) x_cen, y_cen = offset_from_phs(header, ra_px[0], dec_px[0]) print("X, Y offset in px from ideal phase center: {:.2f}, {:.2f}").format( x_cen, y_cen) # for Ripples input get_PB_arcsec(header)
def cutout(filename, xc, yc, xw=25, yw=25, units='pixels', outfile=None, clobber=True, useMontage=False, coordsys='celestial', verbose=False): """ Inputs: file - .fits filename or pyfits HDUList (must be 2D) xc,yc - x and y coordinates in the fits files' coordinate system (CTYPE) xw,yw - x and y width (pixels or wcs) units - specify units to use: either pixels or wcs outfile - optional output file """ if isinstance(filename,str): file = pyfits.open(filename) opened=True elif isinstance(filename,pyfits.HDUList): file = filename opened=False else: raise Exception("cutout: Input file is wrong type (string or HDUList are acceptable).") head = file[0].header.copy() if head['NAXIS'] > 2: raise DimensionError("Too many (%i) dimensions!" % head['NAXIS']) cd1 = head.get('CDELT1') if head.get('CDELT1') else head.get('CD1_1') cd2 = head.get('CDELT2') if head.get('CDELT2') else head.get('CD2_2') if cd1 is None or cd2 is None: raise Exception("Missing CD or CDELT keywords in header") wcs = pywcs.WCS(head) if units == 'wcs': if coordsys=='celestial' and wcs.wcs.lngtyp=='GLON': xc,yc = coords.Position((xc,yc),system=coordsys).galactic() elif coordsys=='galactic' and wcs.wcs.lngtyp=='RA': xc,yc = coords.Position((xc,yc),system=coordsys).j2000() if useMontage and CanUseMontage: head['CRVAL1'] = xc head['CRVAL2'] = yc if units == 'pixels': head['CRPIX1'] = xw head['CRPIX2'] = yw head['NAXIS1'] = int(xw*2) head['NAXIS2'] = int(yw*2) elif units == 'wcs': cdelt = numpy.sqrt(cd1**2+cd2**2) head['CRPIX1'] = xw / cdelt head['CRPIX2'] = yw / cdelt head['NAXIS1'] = int(xw*2 / cdelt) head['NAXIS2'] = int(yw*2 / cdelt) head.toTxtFile('temp_montage.hdr',clobber=True) newfile = montage.wrappers.reproject_hdu(file[0],header='temp_montage.hdr',exact_size=True) os.remove('temp_montage.hdr') else: xx,yy = wcs.wcs_sky2pix(xc,yc,0) if units=='pixels': xmin,xmax = numpy.max([0,xx-xw]),numpy.min([head['NAXIS1'],xx+xw]) ymin,ymax = numpy.max([0,yy-yw]),numpy.min([head['NAXIS2'],yy+yw]) elif units=='wcs': xmin,xmax = numpy.max([0,xx-xw/numpy.abs(cd1)]),numpy.min([head['NAXIS1'],xx+xw/numpy.abs(cd1)]) ymin,ymax = numpy.max([0,yy-yw/numpy.abs(cd2)]),numpy.min([head['NAXIS2'],yy+yw/numpy.abs(cd2)]) else: raise Exception("Can't use units %s." % units) if xmax < 0 or ymax < 0: raise ValueError("Max Coordinate is outside of map: %f,%f." % (xmax,ymax)) if ymin >= head.get('NAXIS2') or xmin >= head.get('NAXIS1'): raise ValueError("Min Coordinate is outside of map: %f,%f." % (xmin,ymin)) head['CRPIX1']-=xmin head['CRPIX2']-=ymin head['NAXIS1']=int(xmax-xmin) head['NAXIS2']=int(ymax-ymin) if head.get('NAXIS1') == 0 or head.get('NAXIS2') == 0: raise ValueError("Map has a 0 dimension: %i,%i." % (head.get('NAXIS1'),head.get('NAXIS2'))) img = file[0].data[ymin:ymax,xmin:xmax] newfile = pyfits.PrimaryHDU(data=img,header=head) if verbose: print "Cut image %s with dims %s to %s. xrange: %f:%f, yrange: %f:%f" % (filename, file[0].data.shape,img.shape,xmin,xmax,ymin,ymax) if isinstance(outfile,str): newfile.writeto(outfile,clobber=clobber) if opened: file.close() return newfile
def kdist(l, b, vin, near=True,r0=8.4e3,v0=2.54e2,dynamical=False, kinematic=True,regular=False,rrgal=False,verbose=False, inverse=False,silent=False, returnvtan=False): """ NAME: KINDIST PURPOSE: To return the distance to an object given l,b,v CALLING SEQUENCE: dist = KDIST (L, B, V) INPUTS: L, B -- Galactic Longitude and Latitude (decimal degrees) V - Velocity w.r.t. LSR in km/s KEYWORD PARAMETERS: /NEAR, /FAR -- Report the near/far kinematic distances for Q1 and Q4 data. RO, VO -- Force values for galactocentric distance for sun and velocity of the LSR around the GC. Default to 8.4 kpc and 254 km/s (Reid et al., 2009) RGAL -- Named keyword containing galactocentric radius of sources. rrgal - return galactocentric distance in addition to distance from us /DYNAMICAL -- Use the dynamical definition of the LSR /KINEMATIC -- Use the kinematic definition of the LSR (default) /REGULAR -- Do not apply the rotation correction for High mass star forming regions. INVERSE -- If set, pass DISTANCE instead of velocity, and output is velocity returnvtan - if set, return the tanent velocity and ignore the input velocity OUTPUTS: DIST -- the kinematic distance in units of R0 (defaults to pc). MODIFICATION HISTORY: Fri Feb 27 00:47:18 2009, Erik <*****@*****.**> Adapted from kindist.pro Translated from IDL to Python by Adam Ginsburg ([email protected]) """ dtor = pi/180. if regular: vs = 0.0 else: vs=15.0 if kinematic or not(dynamical): solarmotion_ra = ((18+03/6e1+50.29/3.6e3)*15) solarmotion_dec = (30+0/6e1+16.8/3.6e3) solarmotion_mag = 20.0 else: solarmotion_ra = ((17+49/6e1+58.667/3.6e3)*15) solarmotion_dec = (28+7/6e1+3.96/3.6e3) solarmotion_mag = 16.55294 cg = coords.Position((l,b),system='galactic') solarmotion = coords.Position((solarmotion_ra,solarmotion_dec)) # ra,dec = cg.j2000() # gcirc, 2, solarmotion_ra, solarmotion_dec, ra, dec, theta theta = cg.angsep(solarmotion).arcsec() vhelio = vin-solarmotion_mag*cos(theta/206265.) # UVW from Dehnen and Binney bigu = 10.0 bigv = 5.23 bigw = 7.17 v = vhelio+(bigu*cos(l*dtor)+bigv*sin(l*dtor))*cos(b*dtor)+bigw*sin(b*dtor) # Compute tangent distance and velocity rtan = r0*(cos(l*dtor))/(cos(b*dtor)) vTEMP = (1/sin(l*dtor) - v0/(v0-vs)) * ((v0-vs)*sin(l*dtor)*cos(b*dtor)) vhelioTEMP = vTEMP - ((bigu*cos(l*dtor)+bigv*sin(l*dtor))*cos(b*dtor)+bigw*sin(b*dtor)) vtan = vhelioTEMP+solarmotion_mag*cos(theta/206265.) if returnvtan: return vtan # This is r/r0 null = (v0/(v0-vs)+v/((v0-vs)*sin(l*dtor)*cos(b*dtor)))**(-1) if inverse: radical = cos(l*dtor) - cos(b*dtor) * vin / r0 null = sqrt(1 - cos(l*dtor)**2 + radical**2) v = (1/null - v0/(v0-vs)) * ((v0-vs)*sin(l*dtor)*cos(b*dtor)) vhelio = v - ((bigu*cos(l*dtor)+bigv*sin(l*dtor))*cos(b*dtor)+bigw*sin(b*dtor)) vlsr = vhelio+solarmotion_mag*cos(theta/206265.) return vlsr else: if vin > vtan: if not silent: print "Velocity is greater than tangent velocity v=%f. Returning tangent distance." % vtan if rrgal: return rtan,null*r0 return rtan # The > 0 traps things near the tangent point and sets them to the # tangent distance. So quietly. Perhaps this should pitch a flag? radical = max(sqrt(((cos(l*dtor))**2-(1-null**2)) ),0) fardist = r0*(cos(l*dtor)+radical)/(cos(b*dtor)) neardist = r0*(cos(l*dtor)-radical)/(cos(b*dtor)) rgal = null*r0 ind = (abs(l-180) < 90) if ind.sum() > 1: neardist[ind] = fardist[ind] elif ind==True: neardist = fardist if not(near): dist = fardist else: dist = neardist if verbose: print "radical: %f null: %f vin: %f v: %f vhelio: %f rgal: %f neardist: %f fardist: %f" % (radical,null,vin,v,vhelio,rgal,neardist,fardist) if rrgal: return abs(dist),abs(rgal) return abs(dist)