H, W = 100, 100 pixscale = 0.262 ra, dec = 40., 10. psf_sigma = 1.4 # pixels v = psf_sigma**2 ps = pixscale / 3600. wcs = Tan(ra, dec, W / 2. + 0.5, H / 2. + 0.5, -ps, 0., 0., ps, float(W), float(H)) tim = tractor.Image(data=np.zeros((H, W), np.float32), inverr=np.ones((H, W), np.float32), psf=tractor.GaussianMixturePSF(1., 0., 0., v, v, 0.), wcs=tractor.ConstantFitsWcs(wcs)) src = RexGalaxy(tractor.RaDecPos(ra, dec), tractor.Flux(100.), LogRadius(0.)) tr = tractor.Tractor([tim], [src]) mod = tr.getModelImage(0) plt.clf() plt.imshow(mod, interpolation='nearest', origin='lower') plt.savefig('rex.png') # add noise with std 1. noisy = mod + np.random.normal(size=mod.shape) # make that the tim's data tim.data = noisy # reset the source params
def main(): # In LSST meas-deblend (on lsst6): # python examples/suprimePlot.py --data ~dstn/lsst/ACT-data -v 126969 -c 5 --data-range -100 300 --roi 0 500 0 500 --psf psf.fits --image img.fits --sources srcs.fits from optparse import OptionParser import sys parser = OptionParser(usage=('%prog <img> <psf> <srcs>')) parser.add_option('-v', '--verbose', dest='verbose', action='count', default=0, help='Make more verbose') opt, args = parser.parse_args() if len(args) != 3: parser.print_help() sys.exit(-1) if opt.verbose == 0: lvl = logging.INFO else: lvl = logging.DEBUG logging.basicConfig(level=lvl, format='%(message)s', stream=sys.stdout) imgfn, psffn, srcfn = args pimg = pyfits.open(imgfn) if len(pimg) != 4: print('Image must have 3 extensions') sys.exit(-1) img = pimg[1].data mask = pimg[2].data maskhdr = pimg[2].header var = pimg[3].data del pimg print('var', var.shape) #print var print('mask', mask.shape) #print mask print('img', img.shape) #print img mask = mask.astype(np.int16) for bit in range(16): on = ((mask & (1 << bit)) != 0) print('Bit', bit, 'has', np.sum(on), 'pixels set') ''' MP_BAD = 0 Bit 0 has 2500 pixels set MP_SAT = 1 Bit 1 has 5771 pixels set MP_INTRP= 2 Bit 2 has 11269 pixels set MP_CR = 3 Bit 3 has 136 pixels set MP_EDGE = 4 Bit 4 has 11856 pixels set HIERARCH MP_DETECTED = 5 Bit 5 has 37032 pixels set ''' print('Mask header:', maskhdr) maskplanes = {} print('Mask planes:') for card in maskhdr.ascardlist(): if not card.key.startswith('MP_'): continue print(card.value, card.key) maskplanes[card.key[3:]] = card.value print('Variance range:', var.min(), var.max()) print('Image median:', np.median(img.ravel())) invvar = 1. / var invvar[var == 0] = 0. invvar[var < 0] = 0. sig = np.sqrt(np.median(var)) H, W = img.shape for k, v in maskplanes.items(): plt.clf() I = ((mask & (1 << v)) != 0) rgb = np.zeros((H, W, 3)) clipimg = np.clip((img - (-3. * sig)) / (13. * sig), 0, 1) cimg = clipimg.copy() cimg[I] = 1 rgb[:, :, 0] = cimg cimg = clipimg.copy() cimg[I] = 0 rgb[:, :, 1] = cimg rgb[:, :, 2] = cimg plt.imshow(rgb, interpolation='nearest', origin='lower') plt.title(k) plt.savefig('mask-%s.png' % k.lower()) badmask = sum([(1 << maskplanes[k]) for k in ['BAD', 'SAT', 'INTRP', 'CR']]) # HACK -- left EDGE sucks badmask += (1 << maskplanes['EDGE']) #badmask = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) #badmask |= (1 << 4) print('Masking out: 0x%x' % badmask) invvar[(mask & badmask) != 0] = 0. assert (all(np.isfinite(img.ravel()))) assert (all(np.isfinite(invvar.ravel()))) psf = pyfits.open(psffn)[0].data print('psf', psf.shape) psf /= psf.sum() from tractor.emfit import em_fit_2d from tractor.fitpsf import em_init_params # Create Gaussian mixture model PSF approximation. S = psf.shape[0] # number of Gaussian components K = 3 w, mu, sig = em_init_params(K, None, None, None) II = psf.copy() II /= II.sum() # HIDEOUS HACK II = np.maximum(II, 0) print('Multi-Gaussian PSF fit...') xm, ym = -(S / 2), -(S / 2) em_fit_2d(II, xm, ym, w, mu, sig) print('w,mu,sig', w, mu, sig) mypsf = tractor.GaussianMixturePSF(w, mu, sig) P = mypsf.getPointSourcePatch(S / 2, S / 2) mn, mx = psf.min(), psf.max() ima = dict(interpolation='nearest', origin='lower', vmin=mn, vmax=mx) plt.clf() plt.subplot(1, 2, 1) plt.imshow(psf, **ima) plt.subplot(1, 2, 2) pimg = np.zeros_like(psf) P.addTo(pimg) plt.imshow(pimg, **ima) plt.savefig('psf.png') sig = np.sqrt(np.median(var)) plt.clf() plt.hist(img.ravel(), 100, range=(-3. * sig, 3. * sig)) plt.savefig('imghist.png') srcs = fits_table(srcfn) print('Initial:', len(srcs), 'sources') # Trim sources with x=0 or y=0 srcs = srcs[(srcs.x != 0) * (srcs.y != 0)] print('Trim on x,y:', len(srcs), 'sources left') # Zero out nans & infs for c in ['theta', 'a', 'b']: I = np.logical_not(np.isfinite(srcs.get(c))) srcs.get(c)[I] = 0. # Set sources with flux=NaN to something more sensible... I = np.logical_not(np.isfinite(srcs.flux)) srcs.flux[I] = 1. # Sort sources by flux. srcs = srcs[np.argsort(-srcs.flux)] # Trim sources that are way outside the image. margin = 8. * np.maximum(srcs.a, srcs.b) H, W = img.shape srcs = srcs[(srcs.x > -margin) * (srcs.y > -margin) * (srcs.x < (W + margin) * (srcs.y < (H + margin)))] print('Trim out-of-bounds:', len(srcs), 'sources left') wcs = tractor.FitsWcs(Sip(imgfn, 1)) #wcs = tractor.NullWCS() timg = tractor.Image(data=img, invvar=invvar, psf=mypsf, wcs=wcs, sky=tractor.ConstantSky(0.), photocal=tractor.NullPhotoCal(), name='image') inverr = timg.getInvError() assert (all(np.isfinite(inverr.ravel()))) tsrcs = [] for s in srcs: #pos = tractor.PixPos(s.x, s.y) pos = tractor.RaDecPos(s.ra, s.dec) if s.a > 0 and s.b > 0: eflux = tractor.Flux(s.flux / 2.) dflux = tractor.Flux(s.flux / 2.) re, ab, phi = s.a, s.b / s.a, 90. - s.theta eshape = gal.GalaxyShape(re, ab, phi) dshape = gal.GalaxyShape(re, ab, phi) print('Fluxes', eflux, dflux) tsrc = gal.CompositeGalaxy(pos, eflux, eshape, dflux, dshape) else: flux = tractor.Flux(s.flux) print('Flux', flux) tsrc = tractor.PointSource(pos, flux) tsrcs.append(tsrc) chug = tractor.Tractor([timg]) for src in tsrcs: if chug.getModelPatch(timg, src) is None: print('Dropping non-overlapping source:', src) continue chug.addSource(src) print('Kept a total of', len(chug.catalog), 'sources') ima = dict(interpolation='nearest', origin='lower', vmin=-3. * sig, vmax=10. * sig) chia = dict(interpolation='nearest', origin='lower', vmin=-5., vmax=5.) plt.clf() plt.imshow(img, **ima) plt.colorbar() plt.savefig('img.png') plt.clf() plt.imshow(invvar, interpolation='nearest', origin='lower') plt.colorbar() plt.savefig('invvar.png') mod = chug.getModelImages()[0] plt.clf() plt.imshow(mod, **ima) plt.colorbar() plt.savefig('mod-0.png') chi = chug.getChiImage(0) plt.clf() plt.imshow(chi, **chia) plt.colorbar() plt.savefig('chi-0.png') for step in range(5): cat = chug.getCatalog() for src in cat: if chug.getModelPatch(timg, src) is None: print('Dropping non-overlapping source:', src) chug.removeSource(src) print('Kept a total of', len(chug.catalog), 'sources') #cat = chug.getCatalog() #for i,src in enumerate([]): #for i,src in enumerate(chug.getCatalog()): #for i in range(len(cat)): i = 0 while i < len(cat): src = cat[i] #print 'Step', i #for j,s in enumerate(cat): # x,y = timg.getWcs().positionToPixel(s, s.getPosition()) # print ' ', # if j == i: # print '*', # print '(%6.1f, %6.1f)'%(x,y), s print('Optimizing source', i, 'of', len(cat)) x, y = timg.getWcs().positionToPixel(src.getPosition(), src) print('(%6.1f, %6.1f)' % (x, y), src) # pre = src.getModelPatch(timg) s1 = str(src) print('src1 ', s1) dlnp1, X, a = chug.optimizeCatalogFluxes(srcs=[src]) s2 = str(src) dlnp2, X, a = chug.optimizeCatalogAtFixedComplexityStep(srcs=[src], sky=False) s3 = str(src) #post = src.getModelPatch(timg) print('src1 ', s1) print('src2 ', s2) print('src3 ', s3) print('dlnp', dlnp1, dlnp2) if chug.getModelPatch(timg, src) is None: print('After optimizing, no overlap!') print('Removing source', src) chug.removeSource(src) i -= 1 i += 1 # plt.clf() # plt.subplot(2,2,1) # img = timg.getImage() # (x0,x1,y0,y1) = pre.getExtent() # plt.imshow(img, **ima) # ax = plt.axis() # plt.plot([x0,x0,x1,x1,x0], [y0,y1,y1,y0,y0], 'k-', lw=2) # plt.axis(ax) # plt.subplot(2,2,3) # plt.imshow(pre.getImage(), **ima) # plt.subplot(2,2,4) # plt.imshow(post.getImage(), **ima) # plt.savefig('prepost-s%i-s%03i.png' % (step, i)) # # mod = chug.getModelImages()[0] # plt.clf() # plt.imshow(mod, **ima) # plt.colorbar() # plt.savefig('mod-s%i-s%03i.png' % (step, i)) # chi = chug.getChiImage(0) # plt.clf() # plt.imshow(chi, **chia) # plt.colorbar() # plt.savefig('chi-s%i-s%03i.png' % (step, i)) #dlnp,x,a = chug.optimizeCatalogFluxes() #print 'fluxes: dlnp', dlnp #dlnp,x,a = chug.optimizeCatalogAtFixedComplexityStep() #print 'opt: dlnp', dlnp mod = chug.getModelImages()[0] plt.clf() plt.imshow(mod, **ima) plt.colorbar() plt.savefig('mod-%i.png' % (step + 1)) chi = chug.getChiImage(0) plt.clf() plt.imshow(chi, **chia) plt.colorbar() plt.savefig('chi-%i.png' % (step + 1)) return for step in range(5): chug.optimizeCatalogFluxes() mod = chug.getModelImages()[0] plt.clf() plt.imshow(mod, **ima) plt.colorbar() plt.savefig('mod-s%i.png' % step) chi = chug.getChiImage(0) plt.clf() plt.imshow(chi, **chia) plt.colorbar() plt.savefig('chi-s%i.png' % step)
def read_cfht_coadd(imgfn, weightfn, roi=None, radecroi=None, filtermap=None): ''' Given filenames for CFHT coadd image and weight files, produce a tractor.Image object. *roi*: (x0,x1, y0,y1): a region-of-interest in pixel space; returns the subimage [x0,x1), [y0,y1). *radecroi*: (ra0, ra1, dec0, dec1): a region-of-interest in RA,Dec space; returns the subimage bounding the given RA,Dec box [ra0,ra1], [dec0,dec1]. *filtermap*: dict, eg, { 'i.MP9701': 'i' }, to map from the FILTER header keyword to a standard filter name. ''' P = pyfits.open(imgfn) print 'Read', P[0].data.shape, 'image' img = P[0].data imgheader = P[0].header # WCS: the image file has a WCS header # we should be able to do: #twcs = tractor.FitsWcs(imgfn) # ARGH! Memory issues reading the file; HACK: copy header... f, tempfn = tempfile.mkstemp() os.close(f) pyfits.writeto(tempfn, None, header=imgheader, clobber=True) twcs = tractor.FitsWcs(tempfn) # Cut down to the region-of-interest, if given. if roi is not None: x0, x1, y0, y1 = roi elif radecroi is not None: ralo, rahi, declo, dechi = radecroi xy = [ twcs.positionToPixel(tractor.RaDecPos(r, d)) for r, d in [(ralo, declo), (ralo, dechi), (rahi, declo), (rahi, dechi)] ] xy = np.array(xy) x0, x1 = xy[:, 0].min(), xy[:, 0].max() y0, y1 = xy[:, 1].min(), xy[:, 1].max() print 'RA,Dec ROI', ralo, rahi, declo, dechi, 'becomes x,y ROI', x0, x1, y0, y1 # Clip to image size... H, W = data.shape x0 = max(0, min(x0, W - 1)) x1 = max(0, min(x1, W)) y0 = max(0, min(y0, H - 1)) y1 = max(0, min(y1, H)) print ' clipped to', x0, x1, y0, y1 else: H, W = img.shape x0, x1, y0, y1 = 0, W, 0, H if roi is not None or radecroi is not None: # Actually cut the pixels img = img[y0:y1, x0:x1].copy() # Also tell the WCS to apply an offset. twcs.setX0Y0(x0, y0) print 'Image:', img.shape # HACK, tell the WCS how big the image is... # (needed because of the previous HACK, copying the header) twcs.wcs.set_imagesize(x1 - x0, y1 - y0) print twcs # Argh, this doesn't work: the files are .fz compressed #P = pyfits.open(weightfn) #weight = P[1].data[y0:y1, x0:x1] # HACK: use "imcopy" to uncompress to a temp file! #print 'Writing to temp file', tempfn cmd = "imcopy '%s[%i:%i,%i:%i]' '!%s'" % (weightfn, x0 + 1, x1, y0 + 1, y1, tempfn) print 'running', cmd os.system(cmd) P = pyfits.open(tempfn) weight = P[0].data print 'Read', weight.shape, 'weight image' # PSF model: FAKE IT for now tpsf = tractor.GaussianMixturePSF(np.array([0.9, 0.1]), np.zeros((2, 2)), np.array([1, 2])) # SKY level: assume zero #sky = np.median(img) #print 'Image median value:', sky sky = 0. tsky = tractor.ConstantSky(sky) # Photometric calibration: the FITS header says: ''' FILTER = 'r.MP9601' / Filter PHOTZP = 30.000 / photometric zeropoint COMMENT AB magnitude = -2.5 * log10(flux) + PHOTZP COMMENT r.MP9601=r_SDSS-0.024*(g_SDSS-r_SDSS) ''' # Grab the filter name, and apply the filtermap (if given) filter = imgheader['FILTER'] if filtermap: filter = filtermap.get(filter, filter) zp = imgheader['PHOTZP'] # Simple photocal object photocal = tractor.MagsPhotoCal(filter, zp) # For plotting: find the approximate standard deviation #print 'Median weight:', np.median(weight) sigma1 = 1. / np.sqrt(np.median(weight)) zr = np.array([-3, 10]) * sigma1 + sky name = 'CFHT ' + imgheader.get('OBJECT', '') tim = tractor.Image(data=img, invvar=weight, psf=tpsf, wcs=twcs, sky=tsky, photocal=photocal, name=name, zr=zr) tim.extent = [x0, x1, y0, y1] return tim
FWHM = 1.0 # arcsec # Need it in pixels: FWHM = FWHM / (3600.0 * hdr['CDELT1']) print "PS1_IQ: WARNING: FWHM = NaN in header, setting to 1.0 arcsec =", FWHM, "pixels" return FWHM # ============================================================================ if __name__ == '__main__': if False: # Testing LensPlaneWCS: ra, dec = 310.0, 0.0 pos = tractor.RaDecPos(ra, dec) lenswcs = lenstractor.LensPlaneWCS(pos) print lenswcs dt = 1 / 360.0 print lenswcs.positionToPixel(tractor.RaDecPos(ra, dec)) print lenswcs.positionToPixel(tractor.RaDecPos(ra + dt, dec)) print lenswcs.positionToPixel(tractor.RaDecPos(ra - dt, dec)) print lenswcs.positionToPixel(tractor.RaDecPos(ra, dec + dt)) print lenswcs.positionToPixel(tractor.RaDecPos(ra, dec - dt)) # ============================================================================
psf = tractor.psf.PixelizedPSF(psf.array) # sky_level_pixel = sky_level * pixel_scale**2 sky_level_pixel = float(sky_levels_pixel[0]) # [counts / pixel] gmag = 23.0 ## gflux = exptime * 10.**((zpt - gmag) / 2.5) # [Total counts on the image]. gflux = 10**(-0.4 * (gmag - 22.5)) # [Nanomaggies]. gre = 0.40 # [arcsec]. ## https://github.com/dstndstn/tractor/blob/13d3239500c5af873935c81d079c928f4cdf0b1d/doc/galsim.rst ## _gflux = tractor.Fluxes(g=gflux, r=0.0, z=0.0) _gflux = tractor.NanoMaggies(**{'g': gflux, 'r': 0.0, 'z': 0.0}) src = RexGalaxy(tractor.RaDecPos(ra, dec), _gflux, LogRadius(gre)) wcs = Tan(ra, dec, W / 2. + 0.5, H / 2. + 0.5, -ps, 0., 0., ps, float(W), float(H)) wcs = tractor.ConstantFitsWcs(wcs) tims = [] for band in ['g', 'r', 'z']: ## photcal = tractor.LinearPhotoCal(1., band=band) photcal = tractor.MagsPhotoCal(band, zpt) csky_level_sig = photcal.brightnessToCounts(sky_level_sig) ## The rms of the noise in ADU. ## noise = galsim.PoissonNoise(rng, sky_level=sky_level_pixel)
def read_wise_level1b(basefn, radecroi=None, radecrad=None, filtermap=None, nanomaggies=False, mask_gz=False, unc_gz=False, sipwcs=False, constantInvvar=False, roi=None, zrsigs=[-3, 10], ): if filtermap is None: filtermap = {} intfn = basefn + '-int-1b.fits' maskfn = basefn + '-msk-1b.fits' if mask_gz: maskfn = maskfn + '.gz' uncfn = basefn + '-unc-1b.fits' if unc_gz: uncfn = uncfn + '.gz' logger.debug('intensity image %s' % intfn) logger.debug('mask image %s' % maskfn) logger.debug('uncertainty image %s' % uncfn) if sipwcs: wcs = Sip(intfn, 0) twcs = tractor.ConstantFitsWcs(wcs) else: twcs = tractor.ConstantFitsWcs(intfn) # Read enough of the image to get its size Fint = fitsio.FITS(intfn) H, W = Fint[0].get_info()['dims'] if radecrad is not None: r, d, rad = radecrad x, y = twcs.positionToPixel(tractor.RaDecPos(r, d)) pixrad = rad / (twcs.pixel_scale() / 3600.) print('Tractor WCS:', twcs) print('RA,Dec,rad', r, d, rad, 'becomes x,y,pixrad', x, y, pixrad) roi = (x - pixrad, x + pixrad + 1, y - pixrad, y + pixrad + 1) if radecroi is not None: ralo, rahi, declo, dechi = radecroi xy = [twcs.positionToPixel(tractor.RaDecPos(r, d)) for r, d in [(ralo, declo), (ralo, dechi), (rahi, declo), (rahi, dechi)]] xy = np.array(xy) x0, x1 = xy[:, 0].min(), xy[:, 0].max() y0, y1 = xy[:, 1].min(), xy[:, 1].max() print('RA,Dec ROI', ralo, rahi, declo, dechi, 'becomes x,y ROI', x0, x1, y0, y1) roi = (x0, x1 + 1, y0, y1 + 1) if roi is not None: x0, x1, y0, y1 = roi x0 = int(np.floor(x0)) x1 = int(np.ceil(x1)) y0 = int(np.floor(y0)) y1 = int(np.ceil(y1)) roi = (x0, x1, y0, y1) # Clip to image size... x0 = np.clip(x0, 0, W) x1 = np.clip(x1, 0, W) y0 = np.clip(y0, 0, H) y1 = np.clip(y1, 0, H) if x0 == x1 or y0 == y1: print('ROI is empty') return None assert(x0 < x1) assert(y0 < y1) #roi = (x0,x1,y0,y1) twcs.setX0Y0(x0, y0) else: x0, x1, y0, y1 = 0, W, 0, H roi = (x0, x1, y0, y1) ihdr = Fint[0].read_header() data = Fint[0][y0:y1, x0:x1] logger.debug('Read %s intensity' % (str(data.shape))) band = ihdr['BAND'] F = fitsio.FITS(uncfn) assert(F[0].get_info()['dims'] == [H, W]) unc = F[0][y0:y1, x0:x1] F = fitsio.FITS(maskfn) assert(F[0].get_info()['dims'] == [H, W]) mask = F[0][y0:y1, x0:x1] # HACK -- circular Gaussian PSF of fixed size... # in arcsec fwhms = {1: 6.1, 2: 6.4, 3: 6.5, 4: 12.0} # -> sigma in pixels sig = fwhms[band] / 2.35 / twcs.pixel_scale() # print 'PSF sigma', sig, 'pixels' tpsf = tractor.NCircularGaussianPSF([sig], [1.]) filter = 'w%i' % band if filtermap: filter = filtermap.get(filter, filter) zp = ihdr['MAGZP'] if nanomaggies: photocal = tractor.LinearPhotoCal(tractor.NanoMaggies.zeropointToScale(zp), band=filter) else: photocal = tractor.MagsPhotoCal(filter, zp) # print 'Image median:', np.median(data) # print 'unc median:', np.median(unc) sky = np.median(data) tsky = tractor.ConstantSky(sky) name = 'WISE ' + ihdr['FRSETID'] + ' W%i' % band # Mask bits, from # http://wise2.ipac.caltech.edu/docs/release/allsky/expsup/sec4_4a.html#maskdef # 0 from static mask: excessively noisy due to high dark current alone # 1 from static mask: generally noisy [includes bit 0] # 2 from static mask: dead or very low responsivity # 3 from static mask: low responsivity or low dark current # 4 from static mask: high responsivity or high dark current # 5 from static mask: saturated anywhere in ramp # 6 from static mask: high, uncertain, or unreliable non-linearity # 7 from static mask: known broken hardware pixel or excessively noisy responsivity estimate [may include bit 1] # 8 reserved # 9 broken pixel or negative slope fit value (downlink value = 32767) # 10 saturated in sample read 1 (down-link value = 32753) # 11 saturated in sample read 2 (down-link value = 32754) # 12 saturated in sample read 3 (down-link value = 32755) # 13 saturated in sample read 4 (down-link value = 32756) # 14 saturated in sample read 5 (down-link value = 32757) # 15 saturated in sample read 6 (down-link value = 32758) # 16 saturated in sample read 7 (down-link value = 32759) # 17 saturated in sample read 8 (down-link value = 32760) # 18 saturated in sample read 9 (down-link value = 32761) # 19 reserved # 20 reserved # 21 new/transient bad pixel from dynamic masking # 22 reserved # 23 reserved # 24 reserved # 25 reserved # 26 non-linearity correction unreliable # 27 contains cosmic-ray or outlier that cannot be classified (from temporal outlier rejection in multi-frame pipeline) # 28 contains positive or negative spike-outlier # 29 reserved # 30 reserved # 31 not used: sign bit goodmask = ((mask & sum([1 << bit for bit in [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 26, 27, 28]])) == 0) sigma1 = np.median(unc[goodmask]) zr = np.array(zrsigs) * sigma1 + sky # constant cinvvar = np.zeros_like(data) cinvvar[goodmask] = 1. / (sigma1**2) # varying vinvvar = np.zeros_like(data) vinvvar[goodmask] = 1. / (unc[goodmask])**2 bad = np.flatnonzero(np.logical_not(np.isfinite(vinvvar))) if len(bad): vinvvar.flat[bad] = 0. cinvvar.flat[bad] = 0. data.flat[bad] = sky if constantInvvar: invvar = cinvvar else: invvar = vinvvar # avoid NaNs data[np.logical_not(goodmask)] = sky mjd = ihdr['MJD_OBS'] time = TAITime(None, mjd=mjd) tim = tractor.Image(data=data, invvar=invvar, psf=tpsf, wcs=twcs, sky=tsky, photocal=photocal, time=time, name=name, zr=zr, domask=False) tim.extent = [x0, x1, y0, y1] tim.sigma1 = sigma1 #tim.roi = roi # FIXME tim.maskplane = mask tim.uncplane = unc tim.goodmask = goodmask # carry both around for retrofitting tim.vinvvar = vinvvar tim.cinvvar = cinvvar return tim
def read_wise_level3(basefn, radecroi=None, filtermap=None, nanomaggies=False): if filtermap is None: filtermap = {} intfn = basefn + '-int-3.fits' uncfn = basefn + '-unc-3.fits' print('intensity image', intfn) print('uncertainty image', uncfn) P = pyfits.open(intfn) ihdr = P[0].header data = P[0].data print('Read', data.shape, 'intensity') band = ihdr['BAND'] P = pyfits.open(uncfn) unc = P[0].data print('Read', unc.shape, 'uncertainty') ''' cov: BAND = 1 / wavelength band number WAVELEN = 3.368 / [microns] effective wavelength of band COADDID = '3342p000_ab41' / atlas-image identifier MAGZP = 20.5 / [mag] relative photometric zero point MEDINT = 4.0289044380188 / [DN] median of intensity pixels ''' ''' int: BUNIT = 'DN ' / image pixel units CTYPE1 = 'RA---SIN' / Projection type for axis 1 CTYPE2 = 'DEC--SIN' / Projection type for axis 2 CRPIX1 = 2048.000000 / Axis 1 reference pixel at CRVAL1,CRVAL2 CRPIX2 = 2048.000000 / Axis 2 reference pixel at CRVAL1,CRVAL2 CDELT1 = -0.0003819444391411 / Axis 1 scale at CRPIX1,CRPIX2 (deg/pix) CDELT2 = 0.0003819444391411 / Axis 2 scale at CRPIX1,CRPIX2 (deg/pix) CROTA2 = 0.000000 / Image twist: +axis2 W of N, J2000.0 (deg) ''' ''' unc: FILETYPE= '1-sigma uncertainty image' / product description ''' twcs = tractor.WcslibWcs(intfn) print('WCS', twcs) # twcs.debug() print('pixel scale', twcs.pixel_scale()) # HACK -- circular Gaussian PSF of fixed size... # in arcsec fwhms = {1: 6.1, 2: 6.4, 3: 6.5, 4: 12.0} # -> sigma in pixels sig = fwhms[band] / 2.35 / twcs.pixel_scale() print('PSF sigma', sig, 'pixels') tpsf = tractor.NCircularGaussianPSF([sig], [1.]) if radecroi is not None: ralo, rahi, declo, dechi = radecroi xy = [twcs.positionToPixel(tractor.RaDecPos(r, d)) for r, d in [(ralo, declo), (ralo, dechi), (rahi, declo), (rahi, dechi)]] xy = np.array(xy) x0, x1 = xy[:, 0].min(), xy[:, 0].max() y0, y1 = xy[:, 1].min(), xy[:, 1].max() print('RA,Dec ROI', ralo, rahi, declo, dechi, 'becomes x,y ROI', x0, x1, y0, y1) # Clip to image size... H, W = data.shape x0 = max(0, min(x0, W - 1)) x1 = max(0, min(x1, W)) y0 = max(0, min(y0, H - 1)) y1 = max(0, min(y1, H)) print(' clipped to', x0, x1, y0, y1) data = data[y0:y1, x0:x1] unc = unc[y0:y1, x0:x1] twcs.setX0Y0(x0, y0) print('Cut data to', data.shape) else: H, W = data.shape x0, x1, y0, y1 = 0, W, 0, H filt = 'w%i' % band if filtermap: filt = filtermap.get(filt, filt) zp = ihdr['MAGZP'] if nanomaggies: photocal = tractor.LinearPhotoCal(tractor.NanoMaggies.zeropointToScale(zp), band=filt) else: photocal = tractor.MagsPhotoCal(filt, zp) print('Image median:', np.median(data)) print('unc median:', np.median(unc)) sky = np.median(data) tsky = tractor.ConstantSky(sky) sigma1 = np.median(unc) zr = np.array([-3, 10]) * sigma1 + sky name = 'WISE ' + ihdr['COADDID'] + ' W%i' % band tim = tractor.Image(data=data, invvar=1. / (unc**2), psf=tpsf, wcs=twcs, sky=tsky, photocal=photocal, name=name, zr=zr, domask=False) tim.extent = [x0, x1, y0, y1] return tim