def get_higal_peak_info(self, wavelength): """Obtain the position and column density at the peak of the (wavelength) HiGAL map""" datapath = self.get_cube_path( "n2hp") #We assume that the WCS is the same for all lines d, h = pyfits.getdata(datapath, header=True) malt90_WCS = astWCS.WCS(h, mode="pyfits") hipath = self.get_herschel_path("500") dd_500, hh_500 = pyfits.getdata(hipath, header=True) herschel_WCS_500 = astWCS.WCS(hh_500, mode="pyfits") maximum = 0 bestxx = 10 bestyy = 10 for xx in range(8, 16): for yy in range(8, 16): #print(xx,yy,dd[yy,xx]) if dd_500[yy, xx] > maximum: maximum = dd_500[yy, xx] bestxx = xx bestyy = yy #print(bestxx,bestyy) radec = herschel_WCS_500.pix2wcs(bestxx, bestyy) xy = malt90_WCS.wcs2pix(radec[0], radec[1]) #xy = [14,12] #print(xy) n2hp = self.get_moment_at_location("n2hp", "mom0", xy[1], xy[0]) hcop = self.get_moment_at_location("hcop", "mom0", xy[1], xy[0]) ratio = hcop / n2hp print(ratio) hipath = self.get_herschel_path("250") dd_250, hh_250 = pyfits.getdata(hipath, header=True) herschel_WCS_250 = astWCS.WCS(hh_250, mode="pyfits") xy_250 = herschel_WCS_250.wcs2pix(radec[0], radec[1]) S_500 = maximum S_250 = dd_250[ yy, xx] #This is a very simplistic (i.e. wrong) 250 micron flux S_500 = S_500 #Convert to common units S_250 = S_250 dust_T = 10. column = 1000. #kappa_500 = herschel_utilities.get_kappa(500) #dust_T = herschel_utilities.find_temperature(S_250/(18.1**2),S_500/(36.9**2)) #column = herschel_utilities.find_column(dust_T,kappa_500,S_500*1000.,36.9,0.5) #1000 takes Jy/beam to mJy/beam #print(dust_T) #print(column) #print(S_500) info = {"dust_T": dust_T, "column": column, "xy": xy, "S_500": S_500} return (info)
def Add_Srces(Input, fl): """ Take stock of confused sources, find their locations """ f = open('MODEL_all.xml','r') dat = f.readlines() f.close() nm = [] for line in dat: if ('source name' in line): nm.append( line.split('name="')[1].split('"')[0] ) check_cut = 18 check = [] for name in nm: if ( len(name) == check_cut ): check.append( name ) mdl = [] if ( len( check ) > 0 ): for nm in check: for i in np.arange( len(dat) ): if ( nm in dat[i] ): mdl = dat[i:i+11] GLON = [] GLAT = [] for j in np.arange( len(mdl) ): for line in mdl[j]: if ('RA' in line): RA = float(line.split('value="')[1].split('"')[0]) elif ('DEC' in line): DE = float(line.split('value="')[1].split('"')[0]) (lon,lat) = astCoords.convertCoords("J2000","GALACTIC",RA,DE,2000) GLON.append(lon) GLAT.append(lat) # Go through clouds. Check to see if CO clouds are close to any confused # sources. RAadd = [] DEadd = [] dirc = os.listdir('../Clouds_2sig') for nm in dirc: if (nm[:2] == 'CO'): close = 0 cld = pyfits.open('../Clouds_2sig/' + nm ) cldwcs = astWCS.WCS('../Clouds_2sig' + nm ) if ( cld[0].data.max() > 3 ): (xx,yy) = np.where( cld[0].data == cld[0].data.max() ) cld[0].data[ cld[0].data > 0 ] = 1 for j in np.arange( len(GLON) ): (gln,glt) = cldwcs.wcs2pix(GLON[j],GLAT[j]) if (np.sqrt( (xx-gln)**2 + (yy-glt)**2) < 15): close += 1 if ( (close == 0) and (cld[0].data.sum() > 50) ): (l,b) = cldwcs.pix2wcs(xx,yy) (RA1,DE1) = astCoords.convertCoords("GALACTIC","J2000",l,b,2000) RAadd.append(RA1) DEadd.append(DE1)
def get_center_ra_dec(key): shovekey = 'neat_wcs_%s' % md5_storage_hash(key) if shovekey not in store: print "get_center_ra_dec: couldn't find matching key in store" return None wcs = astWCS.WCS(StringIO(store[shovekey])) return wcs.getCentreWCSCoords()
def addAutoTileDefinitions(self, DS9RegionFileName=None, cacheFileName=None): """Runs the autotiler to add automatic tile definitions into the parameters dictionary in-place. Args: DS9RegionFileName (str, optional): Path to DS9 regions file to be written. cacheFileName (str, optional): Path to output a cached .yml file which will can be read instead on repeated runs (for speed). """ if cacheFileName is not None and os.path.exists(cacheFileName): with open(cacheFileName, "r") as stream: self.parDict['tileDefinitions'] = yaml.safe_load(stream) return None if 'tileDefinitions' in self.parDict.keys() and type( self.parDict['tileDefinitions']) == dict: # If we're not given a survey mask, we'll make one up from the map image itself if 'mask' in self.parDict['tileDefinitions'].keys( ) and self.parDict['tileDefinitions']['mask'] is not None: surveyMaskPath = self.parDict['tileDefinitions']['mask'] maskProvided = True else: surveyMaskPath = self.parDict['unfilteredMaps'][0][ 'mapFileName'] maskProvided = False if maskProvided == True: surveyMask, wcs = maps.chunkLoadMask( surveyMaskPath) # memory efficient else: with pyfits.open(surveyMaskPath, do_not_scale_image_data=True) as img: for ext in img: if ext.data is not None: break surveyMask = np.array(ext.data, dtype=np.uint8) wcs = astWCS.WCS(ext.header, mode='pyfits') # One day we will write a routine to deal with the multi-plane thing sensibly... # But today is not that day if surveyMask.ndim == 3: surveyMask = surveyMask[0, :] assert (surveyMask.ndim == 2) surveyMask[surveyMask != 0] = 1 del img self.parDict['tileDefinitions'] = maps.autotiler( surveyMask, wcs, self.parDict['tileDefinitions']['targetTileWidthDeg'], self.parDict['tileDefinitions']['targetTileHeightDeg']) print("... breaking map into %d tiles" % (len(self.parDict['tileDefinitions']))) if DS9RegionFileName is not None: maps.saveTilesDS9RegionsFile(self.parDict, DS9RegionFileName) if cacheFileName is not None: stream = yaml.dump(self.parDict['tileDefinitions']) with open(cacheFileName, "w") as outFile: outFile.write(stream)
def CO_Cldkill(): """ Take CO map and remove cloud of interest (center of ROI). """ co = pyfits.open('CO_temp.fits') coWCS = astWCS.WCS(co[0].header, mode="pyfits") co[0].data = np.transpose(co[0].data) ny = co[0].header['NAXIS2'] nx = co[0].header['NAXIS1'] comsk = np.zeros((ny, nx)) comsk[co[0].data > 0] = 1 co[0].data *= comsk maxx = np.where(co[0].data == co[0].data.max())[0][0] maxy = np.where(co[0].data == co[0].data.max())[1][0] cldmsk = np.zeros((ny, nx)) cldmsk[maxx, maxy] = 1 while True: diff_temp = comsk - cldmsk cldmsk = ndimage.binary_dilation(cldmsk) cldmsk *= comsk diff = comsk - cldmsk if ((diff - diff_temp).sum() == 0): break co[0].data -= cldmsk * co[0].data co[0].data = np.transpose(co[0].data) co.writeto('CO_temp_nocld.fits')
def derive_ota_outlines(otalist): """ For each OTA (extension) in the pased list, derive the sky-position of all 4 corners. """ from astLib import astWCS all_corners = [] for ext in range(len(otalist)): if (not is_image_extension(otalist[ext])): continue #type(otalist[ext]) == pyfits.hdu.image.ImageHDU): wcs = astWCS.WCS(otalist[ext].header, mode='pyfits') corner_coords = [] corner_coords.append(wcs.pix2wcs( 0, 0)) corner_coords.append(wcs.pix2wcs(otalist[ext].header['NAXIS1'], 0)) corner_coords.append(wcs.pix2wcs(otalist[ext].header['NAXIS1'], otalist[ext].header['NAXIS2'])) corner_coords.append(wcs.pix2wcs( 0, otalist[ext].header['NAXIS2'])) all_corners.append(corner_coords) return all_corners
def wcs_pix2wcs_2(xy, wcs_polynomials, debug=False): # Now create a fits header and save all WCS keywords hdr = pyfits.core.Header() wcs_wcspoly_to_header(wcs_polynomials, hdr) # print hdr hdr['NAXIS'] = 2 hdr['NAXIS1'] = 4096 hdr['NAXIS2'] = 4096 hdr['CTYPE1'] = "RA---TPV" hdr['CTYPE2'] = "DEC--TPV" hdr['EQUINOX'] = 2000.0 wcs = astWCS.WCS(hdr, mode="pyfits") #print wcs.getCentreWCSCoords() #print "x=\n",xy[:,0] #print "y=\n",xy[:,1] #print "runnign the wcs.pix2wcs ..." radec = wcs.pix2wcs(xy[:,0], xy[:,1]) #print radec radec = numpy.array(radec) #print radec #print radec.shape return radec
def filterBright2MASSByDistance(self, radius, magThreshold, band): """Rejects stars that are a certain distance from bright 2MASS stars that are known by the user to be saturated. This might be the candidate star itself. I propose that 13th magnitude is a good cut-off for a star that you'd want to be close to. Need to check this... :param radius: exclusion zone of bright 2MASS stars around the PSF candidate, in pixels. :param band: can either be "J" or "Ks" """ radius = radius**2. # work in squared distances if band == "J": magKey = "jmag" elif band == "Ks": magKey = "kmag" else: magKey = None brightRA = [] brightDec = [] # Get 2MASS stars and magnitudes in the native frame of the input image if self.psc is None: self._get2MASS() # Find stars brighter than threshold n2MASS = len(self.psc['ra']) for i in xrange(n2MASS): if self.psc[magKey][i] < magThreshold: # convert this to image frame with pointToImageFrame... brightRA.append(self.psc['ra'][i]) brightDec.append(self.psc['dec'][i]) nBrights = len(brightRA) brightX = numpy.zeros(nBrights) brightY = numpy.zeros(nBrights) inputFITS = pyfits.open(self.inputImagePath) header = inputFITS[0].header wcs = astWCS.WCS(header, mode='pyfits') for i in xrange(nBrights): x, y = wcs.wcs2pix(brightRA[i], brightDec[i]) brightX[i] = x brightY[i] = y # Ask candidate if it is within radius pixels of a bright star for star in self.candidates: x = int(self.apCatalog.stars[star]['x']) y = int(self.apCatalog.stars[star]['y']) dist = (x - brightX)**2. + (y - brightY)**2. # print "The closest bright star is %.2f pixels" % dist.min() if len(numpy.where(dist < radius)[0]) > 0: # there are bright stars nearby; need to delete this candidate # print "There is a bright 2MASS star on/near %i" % star # print self.candidates.index(star) self.candidates.remove(star) print "There are %i candidates on 2MASS filter" % len(self.candidates)
def get_size(h): """Establish a reasonable size for the output image.""" guess_one = abs(h["NAXIS1"] * h["CDELT1"]) WCS = aw.WCS(h, mode="pyfits") guess_two = WCS.getFullSizeSkyDeg() #print(guess_one) #print(guess_two) return (guess_one)
def createTile(currentLevel, maxLevel, i, j, outDirectory, plateName, special=False): # Create the associated tile description t = skyTile.SkyImageTile() t.level = currentLevel t.i = i t.j = j t.imageUrl = "x%.2d/" % (2 ** currentLevel) + "x%.2d_%.2d_%.2d.jpg" % (2 ** currentLevel, i, j) if currentLevel == 0: t.credits = "Copyright (C) 2008, STScI Digitized Sky Survey" t.infoUrl = "http://stdatu.stsci.edu/cgi-bin/dss_form" # t.maxBrightness = 10 # Create the matching sky polygons, return if there is no relevant polygons if special is True: pl = [[[0, 0], [300, 0], [300, 300], [0, 300]]] else: pl = getIntersectPoly(plateName, currentLevel, i, j) if pl is None or not pl: return None # Get the WCS from the input FITS header file for the tile wcs = astWCS.WCS(plateName + "/" + levels[currentLevel] + "/" + plateName + "_%.2d_%.2d_" % (i, j) + levels[ currentLevel] + ".hhh") naxis1 = wcs.header.get('NAXIS1') naxis2 = wcs.header.get('NAXIS2') t.skyConvexPolygons = [] for idx, poly in enumerate(pl): p = [wcs.pix2wcs(v[0] + 0.5, v[1] + 0.5) for iv, v in enumerate(poly)] t.skyConvexPolygons.append(p) t.textureCoords = [] for idx, poly in enumerate(pl): p = [(float(v[0]) / naxis1, float(v[1]) / naxis2) for iv, v in enumerate(poly)] t.textureCoords.append(p) v10 = wcs.pix2wcs(1, 0) v01 = wcs.pix2wcs(0, 1) v00 = wcs.pix2wcs(0, 0) t.minResolution = max(abs(v10[0] - v00[0]) * math.cos(v00[1] * math.pi / 180.), abs(v01[1] - v00[1])) if (currentLevel >= maxLevel): return t # Recursively creates the 4 sub-tiles sub = createTile(currentLevel + 1, maxLevel, i * 2, j * 2, outDirectory, plateName) if sub != None: t.subTiles.append(sub) sub = createTile(currentLevel + 1, maxLevel, i * 2 + 1, j * 2, outDirectory, plateName) if sub != None: t.subTiles.append(sub) sub = createTile(currentLevel + 1, maxLevel, i * 2 + 1, j * 2 + 1, outDirectory, plateName) if sub != None: t.subTiles.append(sub) sub = createTile(currentLevel + 1, maxLevel, i * 2, j * 2 + 1, outDirectory, plateName) if sub != None: t.subTiles.append(sub) return t
def get_pixel_offset(image_key1, image_key2, reference_ra, reference_dec): """ Returns an (X, Y) tuple of pixel offsets to transform key1 to key2. reference_ra and reference_dec must appear in both images. """ shove_key1 = 'neat_wcs_%s' % md5_storage_hash(image_key1) shove_key2 = 'neat_wcs_%s' % md5_storage_hash(image_key2) if shove_key1 not in store or shove_key2 not in store: print "get_pixel_offset: couldn't find matching keys in store - are you sure they've been processed?" return None wcs1 = astWCS.WCS(StringIO(store[shove_key1])) x1, y1 = wcs1.wcs2pix(reference_ra, reference_dec) wcs2 = astWCS.WCS(StringIO(store[shove_key2])) x2, y2 = wcs2.wcs2pix(reference_ra, reference_dec) return x2 - x1, y2 - y1
def resampleToTanProjection(imageData, imageWCS, outputPixDimensions=[600, 600]): """Resamples an image and WCS to a tangent plane projection. Purely for plotting purposes (e.g., ensuring RA, dec. coordinate axes perpendicular). @type imageData: numpy array @param imageData: image data array @type imageWCS: astWCS.WCS @param imageWCS: astWCS.WCS object @type outputPixDimensions: list @param outputPixDimensions: [width, height] of output image in pixels @rtype: dictionary @return: image data (numpy array), updated astWCS WCS object for image, in format {'data', 'wcs'}. """ RADeg, decDeg = imageWCS.getCentreWCSCoords() xPixelScale = imageWCS.getXPixelSizeDeg() yPixelScale = imageWCS.getYPixelSizeDeg() xSizeDeg, ySizeDeg = imageWCS.getFullSizeSkyDeg() xSizePix = int(round(outputPixDimensions[0])) ySizePix = int(round(outputPixDimensions[1])) xRefPix = xSizePix / 2.0 yRefPix = ySizePix / 2.0 xOutPixScale = xSizeDeg / xSizePix yOutPixScale = ySizeDeg / ySizePix cardList = pyfits.CardList() cardList.append(pyfits.Card('NAXIS', 2)) cardList.append(pyfits.Card('NAXIS1', xSizePix)) cardList.append(pyfits.Card('NAXIS2', ySizePix)) cardList.append(pyfits.Card('CTYPE1', 'RA---TAN')) cardList.append(pyfits.Card('CTYPE2', 'DEC--TAN')) cardList.append(pyfits.Card('CRVAL1', RADeg)) cardList.append(pyfits.Card('CRVAL2', decDeg)) cardList.append(pyfits.Card('CRPIX1', xRefPix + 1)) cardList.append(pyfits.Card('CRPIX2', yRefPix + 1)) cardList.append(pyfits.Card('CDELT1', -xOutPixScale)) cardList.append(pyfits.Card( 'CDELT2', xOutPixScale)) # Makes more sense to use same pix scale cardList.append(pyfits.Card('CUNIT1', 'DEG')) cardList.append(pyfits.Card('CUNIT2', 'DEG')) newHead = pyfits.Header(cards=cardList) newWCS = astWCS.WCS(newHead, mode='pyfits') newImage = numpy.zeros([ySizePix, xSizePix]) tanImage = resampleToWCS(newImage, newWCS, imageData, imageWCS, highAccuracy=True, onlyOverlapping=False) return tanImage
def get_center_position(h, input_sys, output_sys): """Get position at center of map, convert to other system.""" WCS = aw.WCS(h, mode="pyfits") xcen = int(h["NAXIS1"] / 2.) ycen = int(h["NAXIS2"] / 2.) original_coords = WCS.pix2wcs(xcen, ycen) modified_coords = ac.convertCoords(input_sys, output_sys, original_coords[0], original_coords[1], 2000.) modified_coords = original_coords return (modified_coords[0], modified_coords[1])
def NewSrc_Detect(Input,fl): """ Rummage through the latest model map created too see if there are any missed sources (large positive residuals) or if the model serverely overpredicted the emission, usually the result of fixing a strong source. """ cmap = pyfits.open(fl['CMAP']) (nx,ny) = (cmap[0].header['NAXIS1'],cmap[0].header['NAXIS2']) cmap[0].data = np.transpose( cmap[0].data ) try: mdl = pyfits.open(fl['outmap1_%s'%fl['mode'].lower()]) mdl[0].data = np.transpose( mdl[0].data ) except: # print "Error loading model map. Refit." return "None" resi = cmap[0].data - mdl[0].data res = pyfits.PrimaryHDU( resi ) res.header = cmap[0].header res.writeto('resid_%s.fits'%fl['mode']) resi_smooth = ndimage.gaussian_filter(resi, sigma=2) # Choose a 4-sigma cutoff. The smoothed residual map should be # distributed like a normal curve if everything is modeled # well... What about holes? Those should fit out? resi_smooth[ resi_smooth < 5*resi_smooth.std() ] = 0 if ( resi_smooth.max() == 0 ): # If nothing stands out, exit return "None" f = open('mdl1_%s.xml'%fl['mode'],'r') dat = f.readlines() f.close() del dat[-1] cnt = 1 WCS = astWCS.WCS(fl['CMAP']) while (resi_smooth.std() > 0.0): maxx = np.where( resi_smooth == resi_smooth.max() )[0][0] maxy = np.where( resi_smooth == resi_smooth.max() )[1][0] (glon,glat) = WCS.pix2wcs( maxx, maxy ) dat = Diffuse_ptsrc(Input,fl,dat,glon,glat,cnt) for ind in np.arange( nx*ny ): if ( np.linalg.norm( np.array( (maxx,maxy) ) - np.array( (ind%nx,ind/nx) ) ) < 10 ): resi_smooth[ ind%nx,ind/nx ] = 0 cnt += 1 dat.append('</source_library>') # os.system('mv mdl1_int1.xml MODEL_int1.xml') g = open('mdl1_int1.xml','w') g.writelines(dat) g.close() return "Done"
def applyTaper(infits,directions,fwhms,invert,outfits): # Apply a 2D Gaussian taper to an image # infits = input fits file # centre = [(ra1,dec1),(ra2,dec2), ... ] in degrees # fwhms = [fwhm1,fwhm2, ... ] list of FWHMs of Gaussians (degrees) # invert = True to multiply by inverse Gaussian # outfits = output fits file # gi('applyTaper: Processing image '+infits) input_hdu = pyfits.open(infits)[0] hdr = input_hdu.header WCS = astWCS.WCS(hdr,mode='pyfits') if len(input_hdu.data.shape) == 2: image = numpy.array(input_hdu.data[:,:]) elif len(input_hdu.data.shape) == 3: image = numpy.array(input_hdu.data[0,:,:]) else: image = numpy.array(input_hdu.data[0,0,:,:]) raDelta = hdr.get('CDELT1') decDelta = hdr.get('CDELT2') pixscale = abs(min(raDelta,decDelta)) imX = image.shape[1] imY = image.shape[0] finalTaper = numpy.zeros((imY,imX)) for centre in directions: gi('applyTaper: Direction '+str(centre)) if len(directions) == len(fwhms): fwhm = fwhms[directions.index(centre)] gi('applyTaper: FWHM '+str(fwhm)) else: fwhm = fwhms[0] ri('applyTaper: Length mismatch between directions and fwhms, using fwhms[0] '+str(fwhm)) fwhm = fwhm/pixscale # fwhm now in pixel units sig_x = fwhm/2.3548 sig_y = sig_x centre = WCS.wcs2pix(centre[0],centre[1]) x0 = centre[0] y0 = centre[1] bx = numpy.arange(0,image.shape[1],1,float) by = bx[0:image.shape[0],numpy.newaxis] xPart = ((bx-x0)**2.0)/(2.0*(sig_x**2.0)) yPart = ((by-y0)**2.0)/(2.0*(sig_y**2.0)) taperImage = (numpy.exp(-1.0*(xPart+yPart))) gi('applyTaper: intermediate taper min,max '+str(numpy.min(taperImage))+','+str(numpy.max(taperImage))) finalTaper += taperImage if invert: finalTaper = 1.0 - finalTaper gi('applyTaper: final taper min,max '+str(numpy.min(finalTaper))+','+str(numpy.max(finalTaper))) opimage = image*finalTaper gi('applyTaper: Writing image '+outfits) os.system('cp '+infits+' '+outfits) flushFits(opimage,outfits) return outfits
def create_cutout(hdulist, ra, dec, fov): for i, ext in enumerate(hdulist): data = ext.data if (type(data) != numpy.ndarray): continue if (data.ndim != 2): continue wcs = astWCS.WCS(ext.header, mode='pyfits') xy = wcs.sky2pix(ra, dec) print xy
def sample_background_using_ds9_regions(hdu, sky_regions): wcs = astWCS.WCS(hdu.header, mode='pyfits') pixelscale = wcs.getPixelSizeDeg() * 3600. data = hdu.data center_xy = wcs.wcs2pix(sky_regions[:, 0], sky_regions[:, 1]) # print center_xy center_xy = numpy.array(center_xy) cx = center_xy[:, 0] cy = center_xy[:, 1] width = sky_regions[:, 2] / 2. / pixelscale height = sky_regions[:, 3] / 2. / pixelscale in_ota = ((cx + width) > 0) & ((cx - width) < data.shape[1]) & \ ((cy + height) > 0) & ((cy - height) < data.shape[0]) cx = cx[in_ota] cy = cy[in_ota] w = width[in_ota] h = height[in_ota] if (cx.size <= 0): # no boxes in this OTA return None left = numpy.floor(cx - w).astype(numpy.int) right = numpy.ceil(cx + w).astype(numpy.int) top = numpy.ceil(cy + h).astype(numpy.int) bottom = numpy.floor(cy - h).astype(numpy.int) left[left < 0] = 0 bottom[bottom < 0] = 0 results = [] for box in range(cx.shape[0]): cutout = data[bottom[box]:top[box], left[box]:right[box]] median = bottleneck.nanmedian(cutout.astype(numpy.float32)) if (numpy.isfinite(median)): results.append([cx[box], cy[box], median]) #print results if (len(results) <= 0): return None return numpy.array(results)
def load_header(self, header, fobj=None): self.header = {} self.header.update(header.items()) self.fix_bad_headers() # reconstruct a pyfits header hdr = pyfits.Header(header.items()) try: self.wcs = astWCS.WCS(hdr, mode='pyfits') self.coordsys = self.choose_coord_system(self.header) except Exception as e: self.logger.error("Error making WCS object: %s" % (str(e))) self.wcs = None
def normaliseRGB(num, source, base_dir): """ This is to normalise the g, r, and i WCSClipped images and to make a rgb composite image of the three band together. Args: num(integer): Number identifying the particular processed negative folder and files is being used. source(string): This is the tilename of the original images from DES. base_dir(string): The root directory in which the normalised images and the rgb compostie images are saved, this is defaulted to 'DES/DES_Processed'. Saves: norm_image(numpy array): This is the wcs clipped images normalised, and saved under 'DES/DES_Processed/num/source/ rgb(png): This is a rgb composite image created and saved under 'DES/DES_Processed/num_source/'. """ paths = { 'iBandPath': glob.glob('%s/%s_%s/i_WCSClipped.fits' % (base_dir, num, source))[0], 'rBandPath': glob.glob('%s/%s_%s/r_WCSClipped.fits' % (base_dir, num, source))[0], 'gBandPath': glob.glob('%s/%s_%s/g_WCSClipped.fits' % (base_dir, num, source))[0] } rgb_dict = {} wcs = None for band in ['g', 'r', 'i']: with fits.open(paths[band + 'BandPath']) as image: im = image[0].data norm_image = (im - im.mean()) / np.std(im) if wcs is None: wcs = astWCS.WCS(image[0].header, mode='pyfits') astImages.saveFITS( '%s/%s_%s/%s_norm.fits' % (base_dir, num, source, band), norm_image, wcs) rgb_dict[band] = norm_image min_cut, max_cut = -1, 3 cut_levels = [[min_cut, max_cut], [min_cut, max_cut], [min_cut, max_cut]] plt.figure(figsize=(10, 10)) astPlots.ImagePlot([rgb_dict['i'], rgb_dict['r'], rgb_dict['g']], wcs, cutLevels=cut_levels, axesLabels=None, axesFontSize=26.0, axes=[0, 0, 1, 1]) plt.savefig('%s/%s_%s/rgb.png' % (base_dir, num, source))
def _get2MASS(self): """Sets the self.psc catalog with 2MASS stars in the input image frame. """ inputFITS = pyfits.open(self.inputImagePath) header = inputFITS[0].header wcs = astWCS.WCS(header, mode='pyfits') alphaNW, deltaNW = wcs.pix2wcs(2048, 2048) alphaSW, deltaSW = wcs.pix2wcs(2048, 1) alphaSE, deltaSE = wcs.pix2wcs(1, 1) alphaNE, deltaNE = wcs.pix2wcs(1, 2048) raMin = min(alphaNW, alphaSW, alphaNE, alphaNW) raMax = max(alphaNW, alphaSW, alphaNE, alphaNW) decMin = min(deltaNW, deltaSW, deltaNE, deltaNW) decMax = max(deltaNW, deltaSW, deltaNE, deltaNW) catalog2MASS = owl.twomicron.Catalog2MASS() self.psc = catalog2MASS.getStarsInArea(raMin, raMax, decMin, decMax) inputFITS.close()
def setUpWCSDict(self): """ Sets-up WCS info, needed for fetching images. This is slow (~30 sec) if the survey is large, so don't do this lightly. """ # Add some extra columns to speed up searching self.tileTab = atpy.Table().read(self.WCSTabPath) self.tileTab.add_column( atpy.Column(np.zeros(len(self.tileTab)), 'RAMin')) self.tileTab.add_column( atpy.Column(np.zeros(len(self.tileTab)), 'RAMax')) self.tileTab.add_column( atpy.Column(np.zeros(len(self.tileTab)), 'decMin')) self.tileTab.add_column( atpy.Column(np.zeros(len(self.tileTab)), 'decMax')) self.WCSDict = {} keyWordsToGet = [ 'NAXIS', 'NAXIS1', 'NAXIS2', 'CTYPE1', 'CTYPE2', 'CRVAL1', 'CRVAL2', 'CRPIX1', 'CRPIX2', 'CD1_1', 'CD1_2', 'CD2_1', 'CD2_2', 'CDELT1', 'CDELT2', 'CUNIT1', 'CUNIT2' ] for row in self.tileTab: newHead = pyfits.Header() for key in keyWordsToGet: if key in self.tileTab.keys(): newHead[key] = row[key] # Defaults if missing (needed for e.g. DES) if 'NAXIS' not in newHead.keys(): newHead['NAXIS'] = 2 if 'CUNIT1' not in newHead.keys(): newHead['CUNIT1'] = 'DEG' if 'CUNIT2' not in newHead.keys(): newHead['CUNIT2'] = 'DEG' self.WCSDict[row['TILENAME']] = astWCS.WCS(newHead.copy(), mode='pyfits') ra0, dec0 = self.WCSDict[row['TILENAME']].pix2wcs(0, 0) ra1, dec1 = self.WCSDict[row['TILENAME']].pix2wcs( row['NAXIS1'], row['NAXIS2']) if ra1 > ra0: ra1 = -(360 - ra1) row['RAMin'] = min([ra0, ra1]) row['RAMax'] = max([ra0, ra1]) row['decMin'] = min([dec0, dec1]) row['decMax'] = max([dec0, dec1])
def load_header(self, header, fobj=None): self.header = {} self.header.update(header.items()) self.fix_bad_headers() try: # reconstruct a pyfits header hdr = pyfits.Header(header.items()) self.logger.debug("Trying to make astLib wcs object") self.wcs = astWCS.WCS(hdr, mode='pyfits') self.coordsys = self.get_coord_system_name(self.header) self.logger.debug("Coordinate system is: %s" % (self.coordsys)) except Exception as e: self.logger.error("Error making WCS object: %s" % (str(e))) self.wcs = None
def _checkWCSConsistency(self): # Check consistency of WCS across maps mapKeys = [ 'mapFileName', 'weightsFileName', 'pointSourceMask', 'surveyMask' ] refWCS = None for mapDict in self.parDict['unfilteredMaps']: for key in mapKeys: if key in mapDict.keys() and mapDict[key] is not None: with pyfits.open(mapDict[key]) as img: wcs = None for ext in img: if ext is not None: wcs = astWCS.WCS(img[ext].header, mode='pyfits') if wcs is None: raise Exception("Map %s doesn't have a WCS." % (mapDict[key])) if refWCS is None: refWCS = wcs else: try: assert (refWCS.getCentreWCSCoords() == wcs.getCentreWCSCoords()) assert (refWCS.getImageMinMaxWCSCoords() == wcs.getImageMinMaxWCSCoords()) assert (refWCS.header['NAXIS1'] == wcs.header['NAXIS1']) assert (refWCS.header['NAXIS2'] == wcs.header['NAXIS2']) assert (refWCS.getXPixelSizeDeg() == wcs.getXPixelSizeDeg()) assert (refWCS.getYPixelSizeDeg() == wcs.getYPixelSizeDeg()) except: raise Exception( "WCS of %s is not consistent with other maps (all maps must have the same WCS)." % (mapDict[key]))
def maskimage(infits, directions, size): backup = True if backup: backupfits = infits + '.backup' if not os.path.isfile(backupfits): gi('Making backup: ' + backupfits) os.system('cp ' + infits + ' ' + backupfits) else: ri(backupfits + ' already exists, will not overwrite') gi('Reading: ' + infits) input_hdu = pyfits.open(infits)[0] hdr = input_hdu.header WCS = astWCS.WCS(hdr, mode='pyfits') deg2pix = 1.0 / hdr.get('CDELT2') # declination increment if len(input_hdu.data.shape) == 2: image = numpy.array(input_hdu.data[:, :]) elif len(input_hdu.data.shape) == 3: image = numpy.array(input_hdu.data[0, :, :]) else: image = numpy.array(input_hdu.data[0, 0, :, :]) dx = dy = extent * deg2pix / 2.0 for ra, dec in directions: gi('Direction: ' + str(ra) + ' ' + str(dec)) xpix, ypix = WCS.wcs2pix(ra, dec) x0 = xpix - dx x1 = xpix + dx y0 = ypix - dy y1 = ypix + dy x0 = int(x0) x1 = int(x1) y0 = int(y0) y1 = int(y1) gi('Masking: ' + str(x0) + ' ' + str(x1) + ' ' + str(y0) + ' ' + str(y1)) image[y0:y1, x0:x1] = 0.0 flushFits(image, infits)
def extract_psf(fn, ra, dec, cutout_size=700, superscale=2., normalize_zp=30., magnitude=0., rotate=True): hdu = pyfits.open(fn) hdu.writeto("dump2.fits", clobber=True) data = hdu[1].data #pyfits.PrimaryHDU(data=data).writeto("dump.fits", clobber=True) #os._exit(0) #return data wcs = astWCS.WCS(hdu[1].header, mode='pyfits') xy = wcs.wcs2pix(ra, dec) print xy # resulting pixels are 0-based (not 1, as usual FITS coords) skylevel = hdu[0].header['SKYLEVEL'] #cutout_size = 700 x1 = int(xy[0] - cutout_size) x2 = int(xy[0] + cutout_size) y1 = int(xy[1] - cutout_size) y2 = int(xy[1] + cutout_size) print x1, x2, y1, y2 cutout = data[y1:y2, x1:x2] #return cutout # make bad pixel masks, and grow a bit cutout[cutout > 50000] = numpy.NaN #return cutout bpm = numpy.zeros(cutout.shape) bpm[numpy.isnan(cutout)] = 1. bpm_conv = scipy.ndimage.filters.convolve(input=bpm, weights=numpy.ones((5, 5)), output=None, mode='reflect', cval=0.0) bpm = bpm_conv #return bpm cutout[numpy.isnan(cutout)] = 0. cutout -= skylevel # rotator angle rotator_angle = hdu[0].header['ROTSTART'] if (rotator_angle > 180.): rotator_angle -= 360. if (rotator_angle < -180.): rotator_angle += 360. elevation = numpy.degrees(float(hdu[0].header['ELMAP'])) print rotator_angle, -1 * rotator_angle, elevation derotate_angle = -1. * (rotator_angle - elevation) # rotated = scipy.ndimage.interpolation.rotate( # input=cutout, # angle=-1*rotator_angle, # order=3, # ) # bpm_rotated = scipy.ndimage.interpolation.rotate( # input=bpm, # angle=-1*rotator_angle, # order=3, # ) print "running geometric_transform" output_shape = (3 * cutout_size, 3 * cutout_size) setup = { 'in_center_x': cutout.shape[1] / 2., 'in_center_y': cutout.shape[0] / 2., 'sin_rot': numpy.sin(numpy.radians(derotate_angle)), 'cos_rot': numpy.cos(numpy.radians(derotate_angle)), 'out_center_x': output_shape[1] / 2., 'out_center_y': output_shape[0] / 2., 'scale': superscale, } out = scipy.ndimage.interpolation.geometric_transform( input=cutout, mapping=rotate_me, output_shape=output_shape, order=1, mode='constant', cval=numpy.NaN, prefilter=False, extra_keywords=setup) print "done!" out_bpm = scipy.ndimage.interpolation.geometric_transform( input=bpm, mapping=rotate_me, output_shape=output_shape, order=1, mode='constant', cval=numpy.NaN, prefilter=False, extra_keywords=setup) print "done!" out[out_bpm > 0.1] = numpy.NaN # rotated[bpm_rotated > 0.1] = numpy.NaN # pyfits.PrimaryHDU(data=cutout, header=hdu[0].header).writeto("psf.fits", clobber=True) # pyfits.PrimaryHDU(data=rotated, header=hdu[0].header).writeto("psf_rotated.fits", clobber=True) # pyfits.PrimaryHDU(data=bpm_rotated, header=hdu[0].header).writeto("psf_rotated_bpm.fits", clobber=True) # pyfits.PrimaryHDU(data=out, header=hdu[0].header).writeto("psf_geom.fits", clobber=True) # # Figure out an appropriate scaling factor to normalize PSF extractions # magzero = hdu[0].header['PHOTZP_X'] scale = numpy.power(10., -0.4 * (magzero - normalize_zp - magnitude)) out *= scale print "#####", fn, magzero, normalize_zp, scale return out
hdulist = pyfits.open(filename) for extension in range(1, len(hdulist)): loopcounter = 0 extname = hdulist[extension].header['EXTNAME'] if (extname[0:3] != "OTA"): continue ota = int(extname[3:5]) catfile = "matchcat_%02d.dat" % ota cat = numpy.loadtxt(catfile) wcs = astWCS.WCS(hdulist[extension].header, mode="pyfits") pinit = get_init_value(wcs) radec_ref = cat[:,2:4] radec_comp = odi2wcs(cat[:,0:2], wcs) d2 = (radec_ref - radec_comp) / (0.11/3600.) d_radec = numpy.sqrt(numpy.sum(d2**2, axis=1)) cat = cat[d_radec < 30] errfunc = lambda p, wcs, cat: ferr(p, wcs, cat) #ferr(pinit, wcs, cat) out = scipy.optimize.leastsq(errfunc, pinit, args=(wcs, cat)) #, full_output=1)
def scale_subtract_background_model(in_filename, ic_file, out_filename, per_ota=True, remove_gradient=None, reuse_samples=False, twod_model=True, logger=None): if (logger is None): logger = logging.getLogger("ScaleSubtractBG") if (type(in_filename) == str): imghdu = pyfits.open(in_filename) else: imghdu = in_filename if (type(ic_file) is str): ic_hdu = pyfits.open(ic_file) else: ic_hdu = ic_file # now go over each OTA, and find sky-measurement boxes # ext_skylevels = imghdu['SKYLEVEL'] final_grid_sky = {} pixel_sampling = 500 _y, _x = numpy.indices((9, 9)) grid_x = _x * pixel_sampling grid_y = _y * pixel_sampling # if (debug): print(grid_x) logger.info("Finding optimal scaling for background model") n_sky_samples = 500 smoothing_length = 8. # 8 arcmin all_ratios = None all_sky_samples = None all_model_samples = None ota_ratios = {} for ext in imghdu: if (not is_image_extension(ext)): continue # also check if we have this extension in the IC frame try: ic_ext = ic_hdu[ext.name] except: continue logger.debug("Working on %s" % (ext.name)) wcs = astWCS.WCS(ext.header, mode='pyfits') sky_samples = numpy.array( podi_fitskybackground.sample_background(data=ext.data, wcs=wcs, starcat=None, min_found=n_sky_samples, boxwidth=30, min_box_spacing=3)) logger.debug(sky_samples.shape) # now repeat measurements in the IC data ic_samples = numpy.array( podi_fitskybackground.sample_background( data=ic_ext.data, box_center=sky_samples[:, 2:4], wcs=None, starcat=None, )) logger.debug(ic_samples.shape) ratio = sky_samples[:, 4] / ic_samples[:, 4] logger.debug( "%s %s %s" % (ratio.shape, numpy.nanmedian(ratio), numpy.nanstd(ratio))) all_ratios = ratio if all_ratios is None else numpy.append( all_ratios, ratio) if (all_sky_samples is None): all_sky_samples = sky_samples all_model_samples = ic_samples else: all_sky_samples = numpy.append(all_sky_samples, sky_samples, axis=0) all_model_samples = numpy.append(all_model_samples, ic_samples, axis=0) if (per_ota): ota_ratios[ext.name] = ratio # also calculate the corners for the final grid final_grid_sky[ext.name] = numpy.array(wcs.pix2wcs(grid_x.ravel(), grid_y.ravel()))\ .reshape((grid_x.shape[0], grid_x.shape[1], 2)) #print(final_grid_sky[ext.name]) #numpy.savetxt("gridraw", final_grid_sky[ext.name].reshape((-1,2))) #break if (debug): numpy.savetxt("ratios.dmp", all_ratios) numpy.savetxt("bgsamples.sky", all_sky_samples) all_model_samples[:, 0:2] = all_sky_samples[:, 0:2] numpy.savetxt("bgsamples.model", all_model_samples) numpy.savetxt("all_sky.dmp", all_sky_samples) numpy.savetxt("all_models.dmp", all_model_samples) all_model_samples[:, 0:2] = all_sky_samples[:, 0:2] # # now correct data # logger.info("Subtracting background model") bgsub_samples = None per_ota = False if (per_ota): for extname in ota_ratios: scaling = numpy.nanmedian(ota_ratios[extname]) imghdu[extname].data -= ic_hdu[extname].data * scaling logger.debug("Scaling model by %f for %s" % (scaling, extname)) else: global_ratio = numpy.nanmedian(all_ratios) logger.info("Using global sky scaling = %f" % (global_ratio)) for ext in imghdu: if (not is_image_extension(ext) or not ext.name in ic_hdu): continue ext.data -= ic_hdu[ext.name].data * global_ratio logger.debug("Scaling model by %f for %s" % (global_ratio, ext.name)) all_sky_samples[:, 4] -= global_ratio * all_model_samples[:, 4] if (debug): numpy.savetxt("all_sky_sub.dmp", all_sky_samples) print(all_sky_samples[:10, 4]) if (twod_model): logger.info("Running 2-d model") # print(final_grid_sky) projected_sky = all_sky_samples.copy() median_declination = numpy.median(projected_sky[:, 1]) median_ra = numpy.median(projected_sky[:, 0]) cos_declination = numpy.cos(numpy.radians(median_declination)) # projected_sky[:,0] *= cos_declination projected_sky[:, 0] = (projected_sky[:, 0] - median_ra) * numpy.cos( numpy.radians(projected_sky[:, 1])) + median_ra if (debug): numpy.savetxt("all_sky_proj.dmp", projected_sky) coord_tree = scipy.spatial.cKDTree(projected_sky[:, 0:2]) max_samples_return = 1500 gridded_sky = [] skyframe = [pyfits.PrimaryHDU(header=imghdu[0].header)] for extname in final_grid_sky: radec_grid = final_grid_sky[extname] # numpy.savetxt("grid_%s" % (extname), radec_grid.reshape((-1,2))) logger.info("Calculating background model for %s" % (extname)) # equally deproject all grid boxes radec_grid = final_grid_sky[extname] grid_ra = radec_grid[:, :, 0] grid_dec = radec_grid[:, :, 1] grid_ra = (grid_ra - median_ra) * numpy.cos( numpy.radians(grid_dec)) + median_ra # radec_grid[:,0] = (radec_grid[:,0] - median_ra) * numpy.cos(numpy.radians(radec_grid[:,1])) + median_ra # print(extname, radec_grid[:3,:3,:]) # numpy.savetxt("grid_%s" % (extname), numpy.array([ # grid_ra.flatten(), grid_dec.flatten()]).T) local_sky_array = numpy.zeros(grid_x.shape) for x, y in itertools.product(range(radec_grid.shape[0]), range(radec_grid.shape[1])): gra, gdec = grid_ra[y, x], grid_dec[y, x] #radec_grid[y,x] # print(gra,gdec) d, i = coord_tree.query([gra, gdec], distance_upper_bound=smoothing_length / 60., k=max_samples_return, p=2) valid_indices = numpy.isfinite(d) idx = i[valid_indices] local_sky_samples = projected_sky[idx] local_sky = numpy.nanmedian(local_sky_samples[:, 4]) # TODO: outlier rejection gridded_sky.append( [gra, gdec, local_sky, local_sky_samples.shape[0]]) local_sky_array[x, y] = local_sky # numpy.savetxt("grid_%s" % (extname), radec_grid.reshape((-1,2))) logger.info("Expanding %s to full-res" % (extname)) fullframe = podi_photflat.expand_to_fullres( local_sky_array, blocksize=pixel_sampling, mag2flux=False) skyframe.append( pyfits.ImageHDU(header=imghdu[extname].header, data=fullframe)) imghdu[extname].data -= fullframe # print("\n"*3) gridded_sky = numpy.array(gridded_sky) if (debug): numpy.savetxt("sky.grid", gridded_sky) #logger.info("Saving skyframe") sky_hdu = pyfits.HDUList(skyframe) #sky_hdu.writeto("skyframe.fits", overwrite=True) # # save output # if (out_filename is not None): logger.info("Saving sky-model output to %s" % (out_filename)) imghdu.writeto(out_filename, overwrite=True) if (twod_model): return imghdu, sky_hdu return imghdu
def scamp_header_to_minifits(filename, minifits_outputname, reference_fits, reference_extension="OTA33.SCI", distortion_level=4, recenter_odi=True): if (not os.path.isfile(filename)): return None headfile = open(filename, "r") lines = headfile.readlines() values = {} values_list = [] comments = {} comments_list = [] extlist = [] primhdu = pyfits.PrimaryHDU() extlist.append(primhdu) for line in lines: #print line key, value, comment = line[0:8].strip(), line[9:30].strip( ), line[32:].strip() if (key in ( "HISTORY", "COMMENT", )): # Don't know what to do with those, so skip'em continue elif (key in ( "FGROUPNO", "FLXSCALE", "MAGZEROP", "ASTINST", "PHOTIRMS", "PHOTINST", "PHOTLINK", )): # These are some scamp-specific headers, let's not copy them continue elif (key in ( "CRVAL1", "CRVAL2", "CRPIX1", "CRPIX2", "CD1_1", "CD1_2", "CD2_1", "CD2_2", "EQUINOX", ) or (key[0:2] == "PV" and key[3] == "_")): value = float(value) elif (key in ("RADECSYS", "CTYPE1", "CTYPE2", "CUNIT1", "CUNIT2")): # Strip the unnecessary quotes and spaces from the end value = value[1:-1].strip() elif (key == "END"): # This concludes one extension, add it to list and start new # list for the next OTA values_list.append(values) comments_list.append(comments) values = {} comments = {} continue values[key] = value comments[key] = comment refhdu = pyfits.open(reference_fits) # Count how many image extensions exist in the reference frame n_imageext = 0 ota_names = [] for i in range(len(refhdu)): if (is_image_extension(refhdu[i])): n_imageext += 1 ota_names.append(refhdu[i].name) # try: # extname = refhdu[i].header['EXTNAME'] # if (extname[0:3] == "OTA" and extname[-3:] == "SCI"): # n_imageext += 1 # except: # pass if (len(values_list) != n_imageext): stdout_write( "Illegal scamp solution or wrong reference fits (%d vs %d)!\n" % (len(values_list), len(refhdu) - 1)) return -1 # Now copy all scamp headers into the minifits # With this data at hand, work out the shift we need to apply to the scamp solution print("Creating the minfits headers") for ota in range(len(values_list)): # Create a new Image extension to hold the header hdu = pyfits.ImageHDU(name=ota_names[ota]) # Copy all headers to the new HDU for key in values_list[ota]: hdu.header[key] = (values_list[ota][key], comments_list[ota][key]) for key in ['NAXIS', 'NAXIS1', 'NAXIS2']: hdu.header[key] = refhdu[ota_names[ota]].header[key] # And add the HDU to the list that will form the minifits extlist.append(hdu) # # Work out the position of the origin - # take the center between the 33/34/43/44 OTAs as optical center # tmp_hdulist = pyfits.HDUList(extlist) if (recenter_odi): center_pos = { 'OTA33.SCI': [4096, 4096], 'OTA34.SCI': [4096, 0], 'OTA43.SCI': [0, 4096], 'OTA44.SCI': [0, 0], } centers = [] for ota in center_pos: xy = center_pos[ota] ext = tmp_hdulist[ota] print(xy, ext.header) wcs = astWCS.WCS(ext.header, mode='pyfits') ra_dec = wcs.pix2wcs(xy[0], xy[1]) print(ra_dec) centers.append(ra_dec) centers = numpy.array(centers) numpy.savetxt(sys.stdout, centers) optical_center = numpy.mean(centers, axis=0) print(optical_center) print(numpy.std(centers, axis=0)) print(numpy.std(centers, axis=0) * 3600.) else: wcs = astWCS.WCS(refhdu[reference_extension].header, mode='pyfits') optical_center = numpy.array(wcs.getCentreWCSCoords()) # # Now modify and re-fit the WCS with the correct reference point # n_stars = 5000 tmp_hdulist.info() output_hdulist = [pyfits.PrimaryHDU()] for ota in tmp_hdulist[1:]: print(ota.name) # create a number of random points scattered throughout the image xy = numpy.random.random((n_stars, 2)) xy *= [ota.header['NAXIS1'], ota.header['NAXIS2']] print(xy.shape) print(xy[:5]) wcs = astWCS.WCS(ota.header, mode='pyfits') ra_dec = numpy.array(wcs.pix2wcs(xy[:, 0], xy[:, 1])) # Now create the catalog we need to re-compute the distortion parameters # Columns of catalog to be compatible with optimize_wcs_solution # 3/4: x/y # last 2 columns: reference ra/dec catalog = numpy.zeros((n_stars, 6)) catalog[:, 0:2] = ra_dec[:, :] catalog[:, 2:4] = xy[:, :] catalog[:, 4:6] = ra_dec[:, :] new_hdu = pyfits.ImageHDU(header=ota.header, name=ota.name) # define the new optical axis new_hdu.header['CRVAL1'] = optical_center[0] new_hdu.header['CRVAL2'] = optical_center[1] # reset some of the headers we do not need for key in ['PV1_0', 'PV1_2', 'PV2_0', 'PV2_2']: new_hdu.header[key] = 0. for key in ['PV1_1', 'PV2_1']: new_hdu.header[key] = 1. # set image size - otherwise WCS transformation won't work for key in ['NAXIS', 'NAXIS1', 'NAXIS2']: new_hdu.header[key] = ota.header[key] header_keywords = [ 'CRPIX1', 'CRPIX2', #'CRVAL1', 'CRVAL2', 'CD1_1', 'CD1_2', 'CD2_1', 'CD2_2', ] if (distortion_level >= 2): header_keywords.extend([ 'PV1_4', 'PV1_5', 'PV1_6', 'PV2_4', 'PV2_5', 'PV2_6', ]) if (distortion_level >= 3): header_keywords.extend([ 'PV1_7', 'PV1_8', 'PV1_9', 'PV1_10', 'PV2_7', 'PV2_8', 'PV2_9', 'PV2_10', ]) if (distortion_level >= 4): header_keywords.extend([ 'PV1_12', 'PV1_13', 'PV1_14', 'PV1_15', 'PV1_16', 'PV2_12', 'PV2_13', 'PV2_14', 'PV2_15', 'PV2_16', ]) if (distortion_level >= 5): header_keywords.extend([ 'PV1_17', 'PV1_18', 'PV1_19', 'PV1_20', 'PV1_21', 'PV1_22', 'PV2_17', 'PV2_18', 'PV2_19', 'PV2_20', 'PV2_21', 'PV2_22', ]) #print header_keywords #print new_hdu.header print("re-fitting & optimizing WCS solution for OTA %s" % (ota.name)) dev_ccmatch.optimize_wcs_solution(catalog, new_hdu.header, header_keywords) # Now re-compute the Ra/Dec positions using the new WCS system wcs_out = astWCS.WCS(new_hdu.header, mode='pyfits') radec_new = numpy.array(wcs_out.pix2wcs(xy[:, 0] - 1, xy[:, 1] - 1)) catalog[:, 0:2] = radec_new[:, :] numpy.savetxt("recomputed.%s" % (ota.name), catalog) # compute RMS value of old-new d_radec = catalog[:, 0:2] - catalog[:, 4:6] rms_radec = numpy.std(d_radec, axis=0) * 3600 print("RMS of fit: %f/%f arcsec" % (rms_radec[0], rms_radec[1])) # Finally, delete the CRVAL header keywords and prepare the new ImageHDU for key in ['CRVAL1', 'CRVAL2']: new_hdu.header[key] = 0. # fix the RADESYS header new_hdu.header['RADESYS'] = 'ICRS' output_hdulist.append(new_hdu) # break # Create a proper HDUList from the list of new HDUs minifits_hdulist = pyfits.HDUList(output_hdulist) # return -1 # Now go through both the minifits and the reference and assign the extname keywords # print "Correcting CRVALs for reference position" # ota33_found = False # for ext in range(1, len(refhdu)): # if (not is_image_extension(refhdu[ext])): # continue # extname = refhdu[ext].header['EXTNAME'] # if (extname == reference_extension): ota33_found = True # extlist[ext].name = extname # # Create a proper HDUList from the list of new HDUs # minifits_hdulist = pyfits.HDUList(extlist) # Next (and almost finally) we need to change the CRVAL keywords to account for the # offsets in pointing center and the center assumed by scamp # Adjust the solution for the known shift in CRPIX position # In pODI: True pointing of telescope is ~ at pixel 4200,4200 of OTA 3,3 # From scamp: Typically somewhere around 2000,2000 in OTA 3,3 # NB: 0.11 / 3600. is the pixel scale in degrees/pixel, ignoring rotation and distortion # if (ota33_found): # dx_crpix = 4200 - minifits_hdulist[reference_extension].header["CRPIX1"] # dy_crpix = 4200 - minifits_hdulist[reference_extension].header["CRPIX2"] # d_ra = dx_crpix * 0.11 / 3600. # d_dec = dy_crpix * 0.11 / 3600. # else: # d_ra, d_dec = 0, 0 # # # fix potential problems with d_ra > 360 or d_ra < 0 # d_ra = d_ra - math.floor(d_ra/360.)*360 # # for ext in range(1, len(minifits_hdulist)): # minifits_hdulist[ext].header['CRVAL1'] = d_ra # minifits_hdulist[ext].header['CRVAL2'] = d_dec # Last step: write the minifits to file minifits_hdulist.writeto(minifits_outputname, overwrite=True) # That's it, all done! return 0
def compute_angular_misalignment(header, l=256): # # Make copy so we don't accidently change the input header # ext = pyfits.ImageHDU(header=header) # # Get valid WCS system # ext.header['NAXIS'] = 2 ext.header['NAXIS1'] = l ext.header['NAXIS2'] = l ext.header['CRVAL1'] = 0.0 ext.header['CRVAL2'] = 0.0 wcs = astWCS.WCS(ext.header, mode='pyfits') # compute zero-point radec_0_0 = numpy.array(wcs.pix2wcs(0, 0)) wcs.header['CRVAL1'] -= radec_0_0[0] if (wcs.header['CRVAL1'] < 0): wcs.header['CRVAL1'] += 360. wcs.header['CRVAL2'] -= radec_0_0[1] wcs.header[ 'CRVAL1'] += 10. # add some offset to RA to avoid problems around RA=0=360 wcs.updateFromHeader() # # compute points at origin and along both axes # radec_0_0 = numpy.array(wcs.pix2wcs(0, 0)) #print radec_0_0-[10.,0] radec_0_100 = numpy.array(wcs.pix2wcs(0, l)) - radec_0_0 radec_100_0 = numpy.array(wcs.pix2wcs(l, 0)) - radec_0_0 radec_100_100 = numpy.array(wcs.pix2wcs(l, l)) - radec_0_0 # # convert vectors into angles # #print radec_100_0, radec_0_100 angle_100_0 = numpy.degrees(numpy.arctan2(radec_100_0[0], radec_100_0[1])) angle_0_100 = numpy.degrees(numpy.arctan2(radec_0_100[0], radec_0_100[1])) angle_100_100 = numpy.degrees( numpy.arctan2(radec_100_100[0], radec_100_100[1])) #print angle_100_100 - 45. # # Then from the difference between perfect alignment compute misalignment # d = 90. - angle_100_0 #print "\n",angle_100_0, angle_0_100, angle_100_0 - angle_0_100, d, 0.5*(d-angle_0_100) angle_error = 0.5 * (d - angle_0_100) angle_error = angle_100_100 - 45. rot = wcs.getRotationDeg() if (rot > 180): rot -= 360. #print rot #print "Angle_Misalignment (%s) = %f deg" % (ext.name, angle_error) return angle_error
headers = ['CRPIX1', 'CRPIX2', 'CD1_1', 'CD1_2', 'CD2_1', 'CD2_2'] # # open ds9 # print "Establishing XPA connection and starting ds9" pyds9.ds9_xpans() ds9 = pyds9.DS9(target="hst_realign", start="-scale zscale -zoom 0.5", wait=25) files_to_delete = [] ext = hdulist[args.extname] backup_hdr = ext.header.copy() wcs = astWCS.WCS(ext.header, mode="pyfits") cos_dec = numpy.cos(numpy.radians(ext.header['CRVAL2'])) datafile = "tmp_%s.cat" % (args.extname) print "***************************************\n" * 2 print "Working on EXT %s\n" % (ext.name) print "***************************************\n" * 2 # center_ra, center_dec = wcs.getCentreWCSCoords() # print center_ra, center_dec # # display image in ds9 # pass # # # save current extension as separate file tmp_file = "tmp_%s.fits" % (ext.name) fits.PrimaryHDU(data=ext.data, header=ext.header).writeto(tmp_file,