def buildWCS(self, config, base): """Build a local WCS from the given location in a DES focal plane, given a directory with the image files. By default, it will pick a random chipnum and image position, but these can be optionally specified. """ req = { "dir": str, # The directory with the files. We'll use 'des_data' here. "root": str, # The root name of the files. We'll use 'DECam_00154912' here. } opt = { "chipnum": int, # Which chip to use: 1-62. Default is to pick a random chip. "image_pos": galsim.PositionD, # The position in the chip. Default is random. "ext": str, # The file extension. Default is ".fits.fz" "bad_ccds": list, # A list of ccds to skip. Default is default_bad_ccds. } params, safe = galsim.config.GetAllParams(config, base, req=req, opt=opt) # These will already have been checked to be present, since they are in the req dict. dir = params['dir'] root = params['root'] rng = base['rng'] ud = galsim.UniformDeviate( rng) # Will give float values between 0 and 1. if 'chipnum' in params: chipnum = params['chipnum'] else: bad_ccds = params.get('bad_ccds', default_bad_ccds) chipnum = get_random_chipnum(ud, bad_ccds) ext = params.get('ext', '.fits.fz') # Build the full path of the file to use. file_name = os.path.join(dir, "%s_%02d%s" % (root, chipnum, ext)) # Read the full WCS as a regular FitsWCS. full_wcs = galsim.FitsWCS(file_name) # Determine where in the image we will get the local WCS if 'image_pos' in params: image_pos = params['image_pos'] else: x = ud( ) * 2048. + 0.5 # The pixel centers go from 1-2048, so edges are 0.5-2048.5 y = ud() * 4096. + 0.5 image_pos = galsim.PositionD(x, y) # Finally, return the local wcs at this location. local_wcs = full_wcs.local(image_pos) return local_wcs
def __init__(self, dir, root, ext='.fits.fz'): # Read all the wcs objects indexed by their chipnum self.all_wcs = {} for chipnum in range(1, 63): file_name = os.path.join(dir, "%s_%02d%s" % (root, chipnum, ext)) wcs = galsim.FitsWCS(file_name) self.all_wcs[chipnum] = wcs
def __init__(self, dir, root, ext='.fits.fz', bad_ccds=default_bad_ccds): self.bad_ccds = bad_ccds # Read all the wcs objects indexed by their chipnum self.all_wcs = {} for chipnum in range(1,63): # skip bad ccds if chipnum not in bad_ccds: file_name = os.path.join(dir, "%s_%02d%s"%(root,chipnum,ext)) wcs = galsim.FitsWCS(file_name) self.all_wcs[chipnum] = wcs
def __init__(self, dir, root, ext='.fits.fz'): # Read all the wcs objects indexed by their chipnum self.all_wcs = {} for chipnum in range(1,63): file_name = os.path.join(dir, "%s_%02d%s"%(root,chipnum,ext)) try: wcs = galsim.FitsWCS(file_name) except: continue self.all_wcs[chipnum] = wcs if len(self.all_wcs) == 0: raise RuntimeError("All input wcs files were missing or failed to load.")
def setup(self): self.object_mask = np.loadtxt("/home/samuroff/mask_template.txt") # WCS wcs_path = "/share/des/disc2/y1/OPS/coadd/20141118000051_DES0014-4414/coadd/DES0014-4414_r.fits.fz" orig_col = 1000 orig_row = 1000 image_pos = galsim.PositionD(orig_col, orig_row) self.wcs = galsim.FitsWCS(wcs_path) # im3shape config self.opt = p3s.Options( "/home/samuroff/shear_pipeline/end-to-end/end-to-end_code/config_files/im3shape/params_disc.ini" )
def analyse1(self, central_ellipticity, dneigh=20, central_flux=1912.0, psf_size=3.7, neighbour_flux=1912.0, neighbour_size=3.2): # Level 1 - loop over SNR #----------------------------------------------------------------------- self.m = {} self.m[1] = [] self.m[2] = [] self.snr = [] self.dneigh = 20 self.central_flux = 1912.0 self.psf_size = 3.7 self.neighbour_flux = 1912.0 self.neighbour_size = 3.2 print "Toy model has a central galaxy with shape ", central_ellipticity self.e1 = central_ellipticity[0] self.e2 = central_ellipticity[1] # Setup a dummy wcs # We load it here to avoid too much unncessary io # In fact it should provide a skeleton only, since we overwrite the Jacobian with an identity matrix wcs_path = "/share/des/disc2/y1/OPS/coadd/20141118000051_DES0014-4414/coadd/DES0014-4414_r.fits.fz" orig_col = 1000 orig_row = 1000 image_pos = galsim.PositionD(orig_col, orig_row) self.wcs = galsim.FitsWCS(wcs_path) self.opt = p3s.Options( "/home/samuroff/shear_pipeline/end-to-end/end-to-end_code/config_files/im3shape/params_disc.ini" ) self.binning = np.logspace(1, 3.5, 12) # Cycle over the central flux, as a proxy for SNR for i, proxy in enumerate(self.binning): print "Level 1 iteration: %d %f" % (i, proxy) self.do_position_loop(proxy) print "Done all loops"
def get_wcs(self, iobj, iexp): wcs_path = self.get_source_path(iobj, iexp) wcs_path = check_wcs(wcs_path) orig_col = self['orig_col'][iobj][iexp] orig_row = self['orig_row'][iobj][iexp] image_pos = galsim.PositionD(orig_col,orig_row) wcs = galsim.FitsWCS(wcs_path) ix = int(math.floor(image_pos.x )) iy = int(math.floor(image_pos.y )) # Offset of the galaxy centroid from the stamp centre offset = (image_pos - galsim.PositionD(ix,iy)) offset= galsim.PositionD(offset.x+0.5, offset.y+0.5) return wcs.local(image_pos), offset
def __init__(self, file_name, image_file_name=None, wcs=None, dir=None): if dir: if not isinstance(file_name, basestring): raise ValueError("Cannot provide dir and an HDU instance") import os file_name = os.path.join(dir, file_name) if image_file_name is not None: image_file_name = os.path.join(dir, image_file_name) self.file_name = file_name if image_file_name: if wcs is not None: raise AttributeError( "Cannot provide both image_file_name and wcs") self.wcs = galsim.FitsWCS(image_file_name) elif wcs: self.wcs = wcs else: self.wcs = None self.read()
def get_galsim_wcs(*, image_path, image_ext): """Read the WCS solution of an image into a galsim WCS object. Parameters ---------- image_path : str The path to the image. image_ext : int or str The extension with the WCS information. Returns ------- wcs : galsim WCS The WCS object. """ hd = fitsio.read_header( image_path, ext=image_ext) hd = {k.upper(): hd[k] for k in hd if k is not None} wcs = galsim.FitsWCS(header=hd) assert not isinstance(wcs, galsim.PixelScale) # this has been a problem return wcs
def get_fixed_gaussian_psf(options, psf_size, psf_e1, psf_e2, wcs=None): "This is slow - for test runs only." import galsim psf_box = (options.stamp_size + options.padding) * options.upsampling #Get the localized WCS information if wcs is None: wcs_path = "/share/des/disc2/y1/OPS/coadd/20141118000051_DES0014-4414/coadd/DES0014-4414_r.fits.fz" wcs = galsim.FitsWCS(wcs_path) orig_col = 1000 orig_row = 1000 image_pos = galsim.PositionD(orig_col, orig_row) local_wcs = wcs.local(image_pos) local_wcs._dudx = 1.0 / options.upsampling local_wcs._dudy = 0.0 / options.upsampling local_wcs._dvdx = 0.0 / options.upsampling local_wcs._dvdy = 1.0 / options.upsampling A = np.array([[local_wcs._dudx, local_wcs._dudy], [local_wcs._dvdx, local_wcs._dvdy]]) local_wcs._det = np.linalg.det(A) #Generate the PSF in sky coordinates pix = wcs.toWorld(galsim.Pixel(0.27), image_pos=image_pos) psf_sky = galsim.Convolve([galsim.Gaussian(fwhm=psf_size), pix]) psf_sky = galsim.Gaussian(fwhm=psf_size) pshear = galsim.Shear(g1=psf_e1, g2=psf_e2) psf_sky = psf_sky.shear(pshear) psf_stamp = psf_sky.drawImage(wcs=local_wcs, nx=psf_box, ny=psf_box, method='no_pixel') psf_stamp_array = psf_stamp.array.copy() assert psf_stamp_array.shape == (psf_box, psf_box) return psf_sky, psf_stamp.array.copy()
def skip_roman_wcs(): """Test the Roman WCS routines against ones provided by the Roman project office. """ # This test is out of date and is not run, but since it was a useful test, the code is kept here # as a reminder to reinstate it if/when we get an updated version of the WCS software from the # Roman project office for cycle 7+. Everything below this comment is the original code from # GalSim v1.4. ######################################################################################3 # The standard against which we will compare is the output of some software provided by Jeff # Kruk. The files used here were generated by Rachel on her Macbook using the script in # roman_files/make_standards.sh, and none of the parameters below can be changed without # modifying and rerunning that script. We use 4 sky positions and rotation angles (2 defined # using the focal plane array, 2 using the observatory coordinates), and in each case, use a # different SCA for our tests. We will simply read in the stored WCS and generate new ones, and # check that they have the right value of SCA center and pixel scale at the center, and that if # we offset by 500 pixels in some direction that gives the same sky position in each case. ra_test = [127., 307.4, -61.52, 0.0] dec_test = [-70., 50., 22.7, 0.0] pa_test = [160., 79., 23.4, -3.1] sca_test = [2, 13, 7, 18] import datetime ve = datetime.datetime(2025, 3, 20, 9, 2, 0) date_test = [ve, ve, ve, datetime.date(2025, 6, 20)] pa_is_fpa_test = [True, False, True, False] dist_arcsec = [] dist_2_arcsec = [] pix_area_ratio = [] for i_test in range(len(ra_test)): # Make the WCS for this test. world_pos = galsim.CelestialCoord(ra_test[i_test] * galsim.degrees, dec_test[i_test] * galsim.degrees) if i_test == 0: # Just for this case, we want to get the WCS for all SCAs. This will enable some # additional tests that we don't do for the other test case. gs_wcs_dict = galsim.roman.getWCS(PA=pa_test[i_test] * galsim.degrees, world_pos=world_pos, PA_is_FPA=pa_is_fpa_test[i_test], date=date_test[i_test]) np.testing.assert_equal( len(gs_wcs_dict), galsim.roman.n_sca, err_msg='WCS dict has wrong length: %d vs. %d' % (len(gs_wcs_dict), galsim.roman.n_sca)) else: # Use the SCAs keyword to just get the WCS for the SCA that we want. gs_wcs_dict = galsim.roman.getWCS(PA=pa_test[i_test] * galsim.degrees, world_pos=world_pos, PA_is_FPA=pa_is_fpa_test[i_test], SCAs=sca_test[i_test], date=date_test[i_test]) np.testing.assert_equal( len(gs_wcs_dict), 1, err_msg='WCS dict has wrong length: %d vs. %d' % (len(gs_wcs_dict), 1)) # Read in reference. test_file = 'test%d_sca_%02d.fits' % (i_test + 1, sca_test[i_test]) ref_wcs = galsim.FitsWCS(os.path.join('roman_files', test_file)) gs_wcs = gs_wcs_dict[sca_test[i_test]] # Check center position: im_cent_pos = galsim.PositionD(galsim.roman.n_pix / 2., galsim.roman.n_pix / 2) ref_cent_pos = ref_wcs.toWorld(im_cent_pos) gs_cent_pos = gs_wcs.toWorld(im_cent_pos) dist_arcsec.append( ref_cent_pos.distanceTo(gs_cent_pos) / galsim.arcsec) # Check pixel area rat = ref_wcs.pixelArea(image_pos=im_cent_pos) / gs_wcs.pixelArea( image_pos=im_cent_pos) pix_area_ratio.append(rat - 1.) # Check another position, just in case rotations are messed up. im_other_pos = galsim.PositionD(im_cent_pos.x + 500., im_cent_pos.y - 200.) ref_other_pos = ref_wcs.toWorld(im_other_pos) gs_other_pos = gs_wcs.toWorld(im_other_pos) dist_2_arcsec.append( ref_other_pos.distanceTo(gs_other_pos) / galsim.arcsec) if i_test == 0: # For just one of our tests cases, we'll do some additional tests. These will target # the findSCA() functionality. First, we'll choose an SCA and check that its center is # found to be in that SCA. found_sca = galsim.roman.findSCA(gs_wcs_dict, gs_cent_pos) np.testing.assert_equal( found_sca, sca_test[i_test], err_msg='Did not find SCA center position to be on that SCA!') # Then, we go to a place that should be off the side by a tiny bit, and check that it is # NOT on an SCA if we exclude borders, but IS on the SCA if we include borders. im_off_edge_pos = galsim.PositionD(-2., galsim.roman.n_pix / 2.) world_off_edge_pos = gs_wcs.toWorld(im_off_edge_pos) found_sca = galsim.roman.findSCA(gs_wcs_dict, world_off_edge_pos) assert found_sca is None found_sca = galsim.roman.findSCA(gs_wcs_dict, world_off_edge_pos, include_border=True) np.testing.assert_equal( found_sca, sca_test[i_test], err_msg='Did not find slightly off-edge position on the SCA' ' when including borders!') np.testing.assert_array_less( np.array(dist_arcsec), np.ones(len(ra_test)) * galsim.roman.pixel_scale / 100, err_msg= 'For at least one WCS, center offset from reference was > 0.01(pixel scale).' ) np.testing.assert_array_less( np.array(dist_2_arcsec), np.ones(len(ra_test)) * galsim.roman.pixel_scale / 100, err_msg= 'For at least one WCS, other offset from reference was > 0.01(pixel scale).' ) np.testing.assert_array_less( np.array(pix_area_ratio), np.ones(len(ra_test)) * 0.0001, err_msg= 'For at least one WCS, pixel areas differ from reference by >0.01%.')
def simImage(sourceDir,imFile,catFile,psfFile,outFile): """ Create a simulated image using PSFEx modelled PSFs and noise properties of the source image Input: sourceDir: input directory data imFile: imput image file name catFile: catalogue file (output from SeXtractor) psfFile: psf model (output from PSFEx) outFile: name of output file for image Output: writes to fits file. The catFile must contain the fields X_IMAGE, Y_IMAGE, FLUX_APER (or the code to be changed to equivalent for positions of sources and integrated flux). """ #load necessary stuff from files. #NOte that the MCS image files have two HDUs, one with #the WCS information, one with the image information. galHdr1 = galsim.FitsHeader(imFile, dir=sourceDir, hdu=0) galHdr2 = galsim.FitsHeader(imFile, dir=sourceDir, hdu=1) cat = galsim.Catalog(catFile, hdu=2, dir=sourceDir, file_type="FITS") psfex=des.DES_PSFEx(psfFile,imFile,dir=sourceDir) image=galsim.fits.read(imFile,sourceDir,hdu=1) #get setup the image. match the (currently trivial) WCS with the image, and #create a blank image wcs = galsim.FitsWCS(header=galHdr1) xSize=galHdr2['NAXIS1'] ySize=galHdr2['NAXIS2'] simImage = galsim.Image(xSize, ySize, wcs=wcs) #some definitions for extracting catalogue columsn xCol="X_IMAGE" yCol="Y_IMAGE" fluxCol="FLUX_APER" #get noise statistics. Read in the catalogue positions to estimate the centre #of the image in whatever rotation it has. This is so we get the noise statistics #from teh mask region, excludin the rest of the image. xVals=cat.data[xCol] yVals=cat.data[yCol] xMean=int(xVals.mean()) yMean=int(yVals.mean()) radius=1800 subIm=image.array[int(xMean-radius):int(xMean+radius),int(yMean-radius):int(yMean+radius)] im,a,b=sigmaclip(subIm.ravel(),5,5) skyLevel=im.mean() skySigma=im.std() gain = skyLevel / skySigma**2 #this definition from teh galsim tutorials nobj = cat.nobjects print('Catalog has ',nobj,' objects. Sky level is ',int(skyLevel),' Sky sigma is ',int(skySigma)) #now cycle over the catalogue. for k in range(nobj): #get position and flux x = cat.getFloat(k,xCol) y = cat.getFloat(k,yCol) flux = cat.getFloat(k,fluxCol)*5 #some position calculation for the galsim routines # + 0.5 to account for even-size postage stamps x=x+0.5 y=y+0.5 ix = int(math.floor(x+0.5)) iy = int(math.floor(y+0.5)) dx = x-ix dy = y-iy imagePos = galsim.PositionD(x,y) offset = galsim.PositionD(dx,dy) #calculate PSF for given position and flux psf=psfex.getPSF(imagePos).withFlux(flux) #make image stamp = psf.drawImage(wcs=wcs.local(imagePos), offset=offset, method='no_pixel') stamp.setCenter(ix,iy) #and place on image, taking into consideration edges bounds = stamp.bounds & simImage.bounds simImage[bounds] += stamp[bounds] #now that we've done all the spots, add noise #background sky level simImage += skyLevel #CCD noise random_seed = 1339201 rng=galsim.BaseDeviate(random_seed) noise = galsim.CCDNoise(rng, gain=gain) #poisonnian noise simImage.addNoise(noise) noise = galsim.PoissonNoise(rng, sky_level=skyLevel) simImage.addNoise(noise) #and dump to a file. Will overwrite existing file. simImage.write(outFile,clobber=True)
def test_flat(): """Test building a flat field image using the Silicon class. """ # Note: This test is based on a script devel/lsst/treering_flat.py if __name__ == '__main__': nx = 200 ny = 200 nflats = 20 niter = 50 toler = 0.01 else: nx = 50 ny = 50 nflats = 3 niter = 20 # Seem to really need 20 or more iterations to get covariances close. toler = 0.05 counts_total = 80.e3 counts_per_iter = counts_total / niter # Silicon sensor with tree rings seed = 31415 rng = galsim.UniformDeviate(seed) treering_func = galsim.SiliconSensor.simple_treerings(0.26, 47) treering_center = galsim.PositionD(0,0) sensor = galsim.SiliconSensor(rng=rng, treering_func=treering_func, treering_center=treering_center) # Use a non-trivial WCS to make sure that works properly. wcs = galsim.FitsWCS('fits_files/tnx.fits') # We add on a border of 2 pixels, since the outer row/col get a little messed up by photons # falling off the edge, but not coming on from the other direction. # We do 2 rows/cols rather than just 1 to be safe, since I think diffusion can probably go # 2 pixels, even though the deficit is only really evident on the outer pixel. nborder = 2 base_image = galsim.ImageF(nx+2*nborder, ny+2*nborder, wcs=wcs) base_image.wcs.makeSkyImage(base_image, sky_level=1.) # Rescale so that the mean sky level per pixel is skyCounts mean_pixel_area = base_image.array.mean() sky_level_per_iter = counts_per_iter / mean_pixel_area # in ADU/arcsec^2 now. base_image *= sky_level_per_iter # The base_image now has the right level to account for the WCS distortion, but not any sensor # effects. # This is the noise-free level that we want to add each iteration modulated by the sensor. noise = galsim.PoissonNoise(rng) flats = [] for n in range(nflats): print('n = ',n) # image is the image that we will build up in steps. image = galsim.ImageF(nx+2*nborder, ny+2*nborder, wcs=wcs) for i in range(niter): # temp is the additional flux we will add to the image in this iteration. # Start with the right area due to the sensor effects. temp = sensor.calculate_pixel_areas(image) temp /= temp.array.mean() # Multiply by the base image to get the right mean level and wcs effects temp *= base_image # Finally, add noise. What we have here so far is the expectation value in each pixel. # We need to realize this according to Poisson statistics with these means. temp.addNoise(noise) # Add this to the image we are building up. image += temp # Cut off the outer border where things don't work quite right. image = image.subImage(galsim.BoundsI(1+nborder,nx+nborder,1+nborder,ny+nborder)) flats.append(image.array) # These are somewhat noisy, so compute for all pairs and average them. mean = var = cov01 = cov10 = cov11a = cov11b = cov02 = cov20 = 0 n = len(flats) npairs = 0 for i in range(n): flati = flats[i] print('mean ',i,' = ',flati.mean()) mean += flati.mean() for j in range(i+1,n): flatj = flats[j] diff = flati - flatj var += diff.var()/2 cov01 += np.mean(diff[1:,:] * diff[:-1,:]) cov10 += np.mean(diff[:,1:] * diff[:,:-1]) cov11a += np.mean(diff[1:,1:] * diff[:-1,:-1]) cov11b += np.mean(diff[1:,:-1] * diff[:-1,1:]) cov02 += np.mean(diff[2:,:] * diff[:-2,:]) cov20 += np.mean(diff[:,2:] * diff[:,:-2]) npairs += 1 mean /= n var /= npairs cov01 /= npairs cov10 /= npairs cov11a /= npairs cov11b /= npairs cov02 /= npairs cov20 /= npairs print('var(diff)/2 = ',var, 0.93*counts_total) print('cov01 = ',cov01, 0.03*counts_total) # Note: I don't actually know if these are print('cov10 = ',cov10, 0.015*counts_total) # the right covariances... print('cov11a = ',cov11a, cov11a/counts_total) print('cov11b = ',cov11b, cov11b/counts_total) print('cov02 = ',cov02, cov02/counts_total) print('cov20 = ',cov20, cov20/counts_total) # Mean should be close to target counts np.testing.assert_allclose(mean, counts_total, rtol=toler) # Variance is a bit less than the mean due to B/F. np.testing.assert_allclose(var, 0.93 * counts_total, rtol=toler) # 01 and 10 covariances are significant. np.testing.assert_allclose(cov01, 0.03 * counts_total, rtol=30*toler) np.testing.assert_allclose(cov10, 0.015 * counts_total, rtol=60*toler) # The rest are small np.testing.assert_allclose(cov11a / counts_total, 0., atol=2*toler) np.testing.assert_allclose(cov11b / counts_total, 0., atol=2*toler) np.testing.assert_allclose(cov20 / counts_total, 0., atol=2*toler) np.testing.assert_allclose(cov02 / counts_total, 0., atol=2*toler)
def main(): pr = cProfile.Profile() pr.enable() rng = galsim.UniformDeviate(8675309) wcs = galsim.FitsWCS('../tests/des_data/DECam_00154912_12_header.fits') image = galsim.Image(xsize, ysize, wcs=wcs) bandpass = galsim.Bandpass('LSST_r.dat', wave_type='nm').thin(0.1) base_wavelength = bandpass.effective_wavelength angles = galsim.FRatioAngles(fratio, obscuration, rng) sensor = galsim.SiliconSensor(rng=rng, nrecalc=nrecalc) # Figure out the local_sidereal time from the observation location and time. lsst_lat = '-30:14:23.76' lsst_long = '-70:44:34.67' obs_time = '2012-11-24 03:37:25.023964' # From the header of the wcs file obs = astropy.time.Time(obs_time, scale='utc', location=(lsst_long + 'd', lsst_lat + 'd')) local_sidereal_time = obs.sidereal_time('apparent').value # Convert the ones we need below to galsim Angles. local_sidereal_time *= galsim.hours lsst_lat = galsim.Angle.from_dms(lsst_lat) times = [] mem = [] phot = [] t0 = time.clock() for iobj in range(nobjects): sys.stderr.write('.') psf = make_psf(rng) gal = make_gal(rng) obj = galsim.Convolve(psf, gal) sed = get_sed(rng) waves = galsim.WavelengthSampler(sed=sed, bandpass=bandpass, rng=rng) image_pos = get_pos(rng) sky_coord = wcs.toWorld(image_pos) bounds, offset = calculate_bounds(obj, image_pos, image) ha = local_sidereal_time - sky_coord.ra dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, obj_coord=sky_coord, HA=ha, latitude=lsst_lat) surface_ops = (waves, angles, dcr) obj.drawImage(method='phot', image=image[bounds], offset=offset, rng=rng, sensor=sensor, surface_ops=surface_ops) times.append(time.clock() - t0) mem.append(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) phot.append(obj.flux) image.write('phot.fits') phot = np.cumsum(phot) make_plots(times, mem, phot) pr.disable() ps = pstats.Stats(pr).sort_stats('time') ps.print_stats(20)
def test_meds(): """ Create two objects, each with three exposures. Save them to a MEDS file. Load the MEDS file. Compare the created objects with the one read by MEDS. """ # initialise empty MultiExposureObject list objlist = [] # we will be using 2 objects for testing, each with 3 cutouts n_obj_test = 2 n_cut_test = 3 # set the image size box_size = 32 # first obj img11 = galsim.Image(box_size, box_size, init_value=111) img12 = galsim.Image(box_size, box_size, init_value=112) img13 = galsim.Image(box_size, box_size, init_value=113) seg11 = galsim.Image(box_size, box_size, init_value=121) seg12 = galsim.Image(box_size, box_size, init_value=122) seg13 = galsim.Image(box_size, box_size, init_value=123) wth11 = galsim.Image(box_size, box_size, init_value=131) wth12 = galsim.Image(box_size, box_size, init_value=132) wth13 = galsim.Image(box_size, box_size, init_value=133) psf11 = galsim.Image(box_size, box_size, init_value=141) psf12 = galsim.Image(box_size, box_size, init_value=142) psf13 = galsim.Image(box_size, box_size, init_value=143) dudx = 11.1 dudy = 11.2 dvdx = 11.3 dvdy = 11.4 x0 = 11.5 y0 = 11.6 wcs11 = galsim.AffineTransform(dudx, dudy, dvdx, dvdy, galsim.PositionD(x0, y0)) dudx = 12.1 dudy = 12.2 dvdx = 12.3 dvdy = 12.4 wcs12 = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy) wcs13 = galsim.PixelScale(13) # create lists images = [img11, img12, img13] weight = [wth11, wth12, wth13] seg = [seg11, seg12, seg13] psf = [psf11, psf12, psf13] wcs = [wcs11, wcs12, wcs13] # create object obj1 = galsim.des.MultiExposureObject(images=images, weight=weight, seg=seg, psf=psf, wcs=wcs, id=1) # second obj img21 = galsim.Image(box_size, box_size, init_value=211) img22 = galsim.Image(box_size, box_size, init_value=212) img23 = galsim.Image(box_size, box_size, init_value=213) seg21 = galsim.Image(box_size, box_size, init_value=221) seg22 = galsim.Image(box_size, box_size, init_value=222) seg23 = galsim.Image(box_size, box_size, init_value=223) wth21 = galsim.Image(box_size, box_size, init_value=231) wth22 = galsim.Image(box_size, box_size, init_value=332) wth23 = galsim.Image(box_size, box_size, init_value=333) psf21 = galsim.Image(box_size, box_size, init_value=241) psf22 = galsim.Image(box_size, box_size, init_value=342) psf23 = galsim.Image(box_size, box_size, init_value=343) dudx = 21.1 dudy = 21.2 dvdx = 21.3 dvdy = 21.4 x0 = 21.5 y0 = 21.6 wcs21 = galsim.AffineTransform(dudx, dudy, dvdx, dvdy, galsim.PositionD(x0, y0)) dudx = 22.1 dudy = 22.2 dvdx = 22.3 dvdy = 22.4 wcs22 = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy) wcs23 = galsim.PixelScale(23) # create lists images = [img21, img22, img23] weight = [wth21, wth22, wth23] seg = [seg21, seg22, seg23] psf = [psf21, psf22, psf23] wcs = [wcs21, wcs22, wcs23] # create object # This time put the wcs in the image and get it there. img21.wcs = wcs21 img22.wcs = wcs22 img23.wcs = wcs23 obj2 = galsim.des.MultiExposureObject(images=images, weight=weight, seg=seg, psf=psf, id=2) obj3 = galsim.des.MultiExposureObject(images=images, id=3) # create an object list objlist = [obj1, obj2] # save objects to MEDS file filename_meds = 'output/test_meds.fits' galsim.des.WriteMEDS(objlist, filename_meds, clobber=True) bad1 = galsim.Image(32, 48, init_value=0) bad2 = galsim.Image(35, 35, init_value=0) bad3 = galsim.Image(48, 48, init_value=0) with assert_raises(TypeError): galsim.des.MultiExposureObject(images=img11) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[]) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[bad1]) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[bad2]) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[img11, bad3]) with assert_raises(TypeError): galsim.des.MultiExposureObject(images=images, weight=wth11) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=images, weight=[]) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[img11], weight=[bad3]) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[img11], psf=[bad1]) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[img11], psf=[bad2]) with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[img11, img12], psf=[bad2, psf12]) with assert_raises(TypeError): galsim.des.MultiExposureObject(images=images, wcs=wcs11) celestial_wcs = galsim.FitsWCS("DECam_00154912_12_header.fits", dir='des_data') with assert_raises(galsim.GalSimValueError): galsim.des.MultiExposureObject(images=[img11], wcs=[celestial_wcs]) # Check the one with no psf, weight, etc. filename_meds2 = 'output/test_meds_image_only.fits' galsim.des.WriteMEDS([obj3], filename_meds2, clobber=True) # Note that while there are no tests prior to this, the above still checks for # syntax errors in the meds creation software, so it's still worth running as part # of the normal unit tests. # But for the rest of the tests, we'll use the meds module to make sure our code # stays in sync with any changes there. try: import meds # Meds will import this, so check for this too. import fitsio except ImportError: print( 'Failed to import either meds or fitsio. Unable to do tests of meds file.' ) return # Run meds module's validate function try: meds.util.validate_meds(filename_meds) meds.util.validate_meds(filename_meds2) except AttributeError: print( 'Seems to be the wrong meds package. Unable to do tests of meds file.' ) return m = meds.MEDS(filename_meds) # Check the image_info extension: ref_info = meds.util.get_image_info_dtype(1) info = m.get_image_info() print('info = ', info) for name, dt in ref_info: dt = numpy.dtype(dt) print(name, dt, info.dtype[name], dt.char, info.dtype[name].char) assert name in info.dtype.names, "column %s not present in image_info extension" % name # I think S and U for this purpose are equivalent. # But I'm finding S in the reference, and U in info. c = info.dtype[name].char c = 'S' if c == 'U' else c assert dt.char == c, "column %s is the wrong type" % name # Check the basic structure of the object_data extension cat = m.get_cat() ref_data = meds.util.get_meds_output_dtype(1) for tup in ref_data: # Some of these tuples have 3 items, not 2. The last two are the full dtype tuple. name = tup[0] if len(tup) == 2: dt = tup[1] else: dt = tup[1:] dt = numpy.dtype(dt) print(name, dt, cat.dtype[name], dt.char, cat.dtype[name].char) assert name in cat.dtype.names, "column %s not present in object_data extension" % name assert dt.char == cat.dtype[ name].char, "column %s is the wrong type" % name # Check that we have the right number of objects. n_obj = len(cat) print('number of objects is %d' % n_obj) numpy.testing.assert_equal(n_obj, n_obj_test, err_msg="MEDS file has wrong number of objects") # loop over objects and exposures - test get_cutout for iobj in range(n_obj): # check ID is correct numpy.testing.assert_equal( cat['id'][iobj], iobj + 1, err_msg="MEDS file has wrong id for object %d" % iobj) # get number of cutouts and check if it's right n_cut = cat['ncutout'][iobj] numpy.testing.assert_equal( n_cut, n_cut_test, err_msg="MEDS file has wrong ncutout for object %d" % iobj) # loop over cutouts for icut in range(n_cut): # get the images etc to compare with originals img = m.get_cutout(iobj, icut, type='image') wth = m.get_cutout(iobj, icut, type='weight') seg = m.get_cutout(iobj, icut, type='seg') psf = m.get_psf(iobj, icut) wcs_meds = m.get_jacobian(iobj, icut) # Note: col == x, row == y. wcs_array_meds = numpy.array([ wcs_meds['dudcol'], wcs_meds['dudrow'], wcs_meds['dvdcol'], wcs_meds['dvdrow'], wcs_meds['col0'], wcs_meds['row0'] ]) # compare numpy.testing.assert_array_equal( img, objlist[iobj].images[icut].array, err_msg="MEDS cutout has wrong img for object %d" % iobj) numpy.testing.assert_array_equal( wth, objlist[iobj].weight[icut].array, err_msg="MEDS cutout has wrong wth for object %d" % iobj) numpy.testing.assert_array_equal( seg, objlist[iobj].seg[icut].array, err_msg="MEDS cutout has wrong seg for object %d" % iobj) numpy.testing.assert_array_equal( psf, objlist[iobj].psf[icut].array, err_msg="MEDS cutout has wrong psf for object %d" % iobj) wcs_orig = objlist[iobj].wcs[icut] wcs_array_orig = numpy.array([ wcs_orig.dudx, wcs_orig.dudy, wcs_orig.dvdx, wcs_orig.dvdy, wcs_orig.origin.x, wcs_orig.origin.y ]) numpy.testing.assert_array_equal( wcs_array_meds, wcs_array_orig, err_msg="MEDS cutout has wrong wcs for object %d" % iobj) # get the mosaic to compare with originals img = m.get_mosaic(iobj, type='image') wth = m.get_mosaic(iobj, type='weight') seg = m.get_mosaic(iobj, type='seg') # There is currently no get_mosaic option for the psfs. #psf = m.get_mosaic( iobj, type='psf') psf = numpy.concatenate( [m.get_psf(iobj, icut) for icut in range(n_cut)], axis=0) # get the concatenated images - create the true mosaic true_mosaic_img = numpy.concatenate( [x.array for x in objlist[iobj].images], axis=0) true_mosaic_wth = numpy.concatenate( [x.array for x in objlist[iobj].weight], axis=0) true_mosaic_seg = numpy.concatenate( [x.array for x in objlist[iobj].seg], axis=0) true_mosaic_psf = numpy.concatenate( [x.array for x in objlist[iobj].psf], axis=0) # compare numpy.testing.assert_array_equal( true_mosaic_img, img, err_msg="MEDS mosaic has wrong img for object %d" % iobj) numpy.testing.assert_array_equal( true_mosaic_wth, wth, err_msg="MEDS mosaic has wrong wth for object %d" % iobj) numpy.testing.assert_array_equal( true_mosaic_seg, seg, err_msg="MEDS mosaic has wrong seg for object %d" % iobj) numpy.testing.assert_array_equal( true_mosaic_psf, psf, err_msg="MEDS mosaic has wrong psf for object %d" % iobj)
# But here we build up to a much higher flux level where B/F is important. t0 = time.time() rng = galsim.UniformDeviate(seed) treering_func = galsim.SiliconSensor.simple_treerings( treering_amplitude, treering_period) niter = int(counts_total / counts_per_iter + 0.5) counts_per_iter = counts_total / niter # Recalculate in case not even multiple. print('Total counts = {} = {} * {}'.format(counts_total, niter, counts_per_iter)) # Not an LSST wcs, but just make sure this works properly with a non-trivial wcs. wcs = galsim.FitsWCS('../../tests/fits_files/tnx.fits') base_image = galsim.ImageF(nx + 2 * nborder, ny + 2 * nborder, wcs=wcs) print('image bounds = ', base_image.bounds) # nrecalc is actually irrelevant here, since a recalculation will be forced on each iteration. # Which is really the point. We need to set coundsPerIter appropriately so that the B/F effect # doesn't change *too* much between iterations. sensor = galsim.SiliconSensor(rng=rng, treering_func=treering_func, treering_center=treering_center) # We also need to account for the distortion of the wcs across the image. # This expects sky_level in ADU/arcsec^2, not ADU/pixel. base_image.wcs.makeSkyImage(base_image, sky_level=1.) base_image.write('wcs_area.fits')
def generate(self, dneigh=20, central_flux=1912.0, psf_size=3.7, neighbour_flux=1912.0, neighbour_size=3.2, vary="psf_e"): # PSF leakage toy model #----------------------------------------------------------------------- g_theta = {} theta = np.linspace(0, 2, 50) * np.pi self.g = {} self.g["e1"] = [] self.g["e2"] = [] ang = [] # Setup a dummy wcs # We load it here to avoid too much unncessary io # In fact it should provide a skeleton only, since we overwrite the Jacobian with an identity matrix wcs_path = "/share/des/disc2/y1/OPS/coadd/20141118000051_DES0014-4414/coadd/DES0014-4414_r.fits.fz" orig_col = 1000 orig_row = 1000 image_pos = galsim.PositionD(orig_col, orig_row) wcs = galsim.FitsWCS(wcs_path) opt = p3s.Options( "/home/samuroff/shear_pipeline/end-to-end/end-to-end_code/config_files/im3shape/params_disc.ini" ) binning = { "psf_e1": np.linspace(-0.2, 0.2, 12), "cent_e1": [-0.65, 0.65] } self.binning = binning[vary] # Cycle over psf ellipticities for e in self.binning: if vary == "psf_e1": pe = e ce = 0 elif vary == "cent_e1": pe = 0 ce = e g_theta["e1"] = [] g_theta["e2"] = [] ang = [] # For each psf ellipticity average over a ring of neighbour positions # For the moment we hardcode the other relevant parameters to their mean values from the simulation for i, t in enumerate(theta): x = dneigh * np.cos(t) y = dneigh * np.sin(t) gal, psf = setup_simple(boxsize=48, shear=(ce, 0.0), flux=central_flux, psf_ellipticity=(pe, 0.0), psf_size=psf_size, neighbour_ellipticity=(0.0, 0.0), neighbour=[x, y], neighbour_flux=neighbour_flux, neighbour_size=neighbour_size, wcs=wcs, opt=opt) res = run(gal, psf, opt=opt) g_theta["e1"].append(res.e1) gal, psf = setup_simple(boxsize=48, shear=(ce, 0.0), flux=central_flux, psf_ellipticity=(pe, 0.0), psf_size=psf_size, neighbour_ellipticity=(0.0, 0.0), neighbour=[np.inf, np.inf], neighbour_flux=neighbour_flux, neighbour_size=neighbour_size, wcs=wcs, opt=opt) res = run(gal, psf, opt=opt) g_theta["e2"].append(res.e1) ang.append(t) self.g["e1"].append(np.mean(g_theta["e1"])) self.g["e2"].append(np.mean(g_theta["e2"])) for k in self.g.keys(): self.g[k] = np.array(self.g[k])
def test_dcr(): """Test the dcr surface op """ # This tests that implementing DCR with the surface op is equivalent to using # ChromaticAtmosphere. # We use fairly extreme choices for the parameters to make the comparison easier, so # we can still get good discrimination of any errors with only 10^6 photons. zenith_angle = 45 * galsim.degrees # Larger angle has larger DCR. parallactic_angle = 129 * galsim.degrees # Something random, not near 0 or 180 pixel_scale = 0.03 # Small pixel scale means shifts are many pixels, rather than a fraction. alpha = -1.2 # The normal alpha is -0.2, so this is exaggerates the effect. bandpass = galsim.Bandpass('LSST_r.dat', 'nm') base_wavelength = bandpass.effective_wavelength base_wavelength += 500 # This exaggerates the effects fairly substantially. sed = galsim.SED('CWW_E_ext.sed', wave_type='ang', flux_type='flambda') flux = 1.e6 base_PSF = galsim.Kolmogorov(fwhm=0.3) # Use ChromaticAtmosphere im1 = galsim.ImageD(50, 50, scale=pixel_scale) star = galsim.DeltaFunction() * sed star = star.withFlux(flux, bandpass=bandpass) chrom_PSF = galsim.ChromaticAtmosphere(base_PSF, base_wavelength=base_wavelength, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, alpha=alpha) chrom = galsim.Convolve(star, chrom_PSF) chrom.drawImage(bandpass, image=im1) # Use PhotonDCR im2 = galsim.ImageD(50, 50, scale=pixel_scale) dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, alpha=alpha) achrom = base_PSF.withFlux(flux) rng = galsim.BaseDeviate(31415) wave_sampler = galsim.WavelengthSampler(sed, bandpass, rng) surface_ops = [wave_sampler, dcr] achrom.drawImage(image=im2, method='phot', rng=rng, surface_ops=surface_ops) im1 /= flux # Divide by flux, so comparison is on a relative basis. im2 /= flux printval(im2, im1, show=False) np.testing.assert_almost_equal( im2.array, im1.array, decimal=4, err_msg="PhotonDCR didn't match ChromaticAtmosphere") # Repeat with thinned bandpass and SED to check that thin still works well. im3 = galsim.ImageD(50, 50, scale=pixel_scale) thin = 0.1 # Even higher also works. But this is probably enough. thin_bandpass = bandpass.thin(thin) thin_sed = sed.thin(thin) print('len bp = %d => %d' % (len(bandpass.wave_list), len(thin_bandpass.wave_list))) print('len sed = %d => %d' % (len(sed.wave_list), len(thin_sed.wave_list))) wave_sampler = galsim.WavelengthSampler(thin_sed, thin_bandpass, rng) achrom.drawImage(image=im3, method='phot', rng=rng, surface_ops=surface_ops) im3 /= flux printval(im3, im1, show=False) np.testing.assert_almost_equal( im3.array, im1.array, decimal=4, err_msg="thinning factor %f led to 1.e-4 level inaccuracy" % thin) # Check scale_unit im4 = galsim.ImageD(50, 50, scale=pixel_scale / 60) dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, scale_unit='arcmin', alpha=alpha) surface_ops = [wave_sampler, dcr] achrom.dilate(1. / 60).drawImage(image=im4, method='phot', rng=rng, surface_ops=surface_ops) im4 /= flux printval(im4, im1, show=False) np.testing.assert_almost_equal( im4.array, im1.array, decimal=4, err_msg="PhotonDCR with scale_unit=arcmin, didn't match") # Check some other valid options # alpha = 0 means don't do any size scaling. # obj_coord, HA and latitude are another option for setting the angles # pressure, temp, and water pressure are settable. # Also use a non-trivial WCS. wcs = galsim.FitsWCS('des_data/DECam_00154912_12_header.fits') image = galsim.Image(50, 50, wcs=wcs) bandpass = galsim.Bandpass('LSST_r.dat', wave_type='nm').thin(0.1) base_wavelength = bandpass.effective_wavelength lsst_lat = galsim.Angle.from_dms('-30:14:23.76') lsst_long = galsim.Angle.from_dms('-70:44:34.67') local_sidereal_time = 3.14 * galsim.hours # Not pi. This is the time for this observation. im5 = galsim.ImageD(50, 50, wcs=wcs) obj_coord = wcs.toWorld(im5.true_center) base_PSF = galsim.Kolmogorov(fwhm=0.9) achrom = base_PSF.withFlux(flux) dcr = galsim.PhotonDCR( base_wavelength=bandpass.effective_wavelength, obj_coord=obj_coord, HA=local_sidereal_time - obj_coord.ra, latitude=lsst_lat, pressure=72, # default is 69.328 temperature=290, # default is 293.15 H2O_pressure=0.9) # default is 1.067 #alpha=0) # default is 0, so don't need to set it. surface_ops = [wave_sampler, dcr] achrom.drawImage(image=im5, method='phot', rng=rng, surface_ops=surface_ops) im6 = galsim.ImageD(50, 50, wcs=wcs) star = galsim.DeltaFunction() * sed star = star.withFlux(flux, bandpass=bandpass) chrom_PSF = galsim.ChromaticAtmosphere( base_PSF, base_wavelength=bandpass.effective_wavelength, obj_coord=obj_coord, HA=local_sidereal_time - obj_coord.ra, latitude=lsst_lat, pressure=72, temperature=290, H2O_pressure=0.9, alpha=0) chrom = galsim.Convolve(star, chrom_PSF) chrom.drawImage(bandpass, image=im6) im5 /= flux # Divide by flux, so comparison is on a relative basis. im6 /= flux printval(im5, im6, show=False) np.testing.assert_almost_equal( im5.array, im6.array, decimal=3, err_msg="PhotonDCR with alpha=0 didn't match") # Also check invalid parameters zenith_coord = galsim.CelestialCoord(13.54 * galsim.hours, lsst_lat) assert_raises( TypeError, galsim.PhotonDCR, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle) # base_wavelength is required assert_raises(TypeError, galsim.PhotonDCR, base_wavelength=500, parallactic_angle=parallactic_angle ) # zenith_angle (somehow) is required assert_raises( TypeError, galsim.PhotonDCR, 500, zenith_angle=34.4, parallactic_angle=parallactic_angle) # zenith_angle must be Angle assert_raises(TypeError, galsim.PhotonDCR, 500, zenith_angle=zenith_angle, parallactic_angle=34.5) # parallactic_angle must be Angle assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord, latitude=lsst_lat) # Missing HA assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord, HA=local_sidereal_time - obj_coord.ra) # Missing latitude assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord) # Need either zenith_coord, or (HA,lat) assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord, zenith_coord=zenith_coord, HA=local_sidereal_time - obj_coord.ra) # Can't have both HA and zenith_coord assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord, zenith_coord=zenith_coord, latitude=lsst_lat) # Can't have both lat and zenith_coord assert_raises(TypeError, galsim.PhotonDCR, 500, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, H20_pressure=1.) # invalid (misspelled) assert_raises(ValueError, galsim.PhotonDCR, 500, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, scale_unit='inches') # invalid scale_unit # Invalid to use dcr without some way of setting wavelengths. assert_raises(galsim.GalSimError, achrom.drawImage, im2, method='phot', surface_ops=[dcr])
config = desc.imsim.read_config() obs_md, phot_params, _ = desc.imsim.parsePhoSimInstanceFile(args.instcat, numRows=30) sensor_list = args.sensors.split('^') if args.sensors is not None \ else args.sensors rng = galsim.UniformDeviate(args.seed) niter = int(args.counts_total / args.counts_per_iter + 0.5) counts_per_iter = args.counts_total / niter logger = desc.imsim.get_logger(args.log_level, name='make_flats') visit = obs_md.OpsimMetaData['obshistID'] camera_wrapper = LSSTCameraWrapper() wcs = galsim.FitsWCS(args.wcs_file) if args.wcs_file is not None else None for det in camera_wrapper.camera: det_name = det.getName() if (det.getType() != cameraGeom.SCIENCE or (args.sensors is not None and det_name not in sensor_list)): continue logger.info("processing %s", det_name) gs_det = make_galsim_detector(camera_wrapper, det_name, phot_params, obs_md) desc.imsim.add_treering_info([gs_det]) my_flat = desc.imsim.make_flat(gs_det, counts_per_iter, niter, rng, logger=logger,
def test_withOrigin(): from test_wcs import Cubic # First EuclideantWCS types: wcs_list = [ galsim.OffsetWCS(0.3, galsim.PositionD(1, 1), galsim.PositionD(10, 23)), galsim.OffsetShearWCS(0.23, galsim.Shear(g1=0.1, g2=0.3), galsim.PositionD(12, 43)), galsim.AffineTransform(0.01, 0.26, -0.26, 0.02, galsim.PositionD(12, 43)), galsim.UVFunction(ufunc=lambda x, y: 0.2 * x, vfunc=lambda x, y: 0.2 * y), galsim.UVFunction(ufunc=lambda x, y: 0.2 * x, vfunc=lambda x, y: 0.2 * y, xfunc=lambda u, v: u / scale, yfunc=lambda u, v: v / scale), galsim.UVFunction(ufunc='0.2*x + 0.03*y', vfunc='0.01*x + 0.2*y'), ] color = 0.3 for wcs in wcs_list: # Original version of the shiftOrigin tests in do_nonlocal_wcs using deprecated name. new_origin = galsim.PositionI(123, 321) wcs3 = check_dep(wcs.withOrigin, new_origin) assert wcs != wcs3, name + ' is not != wcs.withOrigin(pos)' wcs4 = wcs.local(wcs.origin, color=color) assert wcs != wcs4, name + ' is not != wcs.local()' assert wcs4 != wcs, name + ' is not != wcs.local() (reverse)' world_origin = wcs.toWorld(wcs.origin, color=color) if wcs.isUniform(): if wcs.world_origin == galsim.PositionD(0, 0): wcs2 = wcs.local(wcs.origin, color=color).withOrigin(wcs.origin) assert wcs == wcs2, name + ' is not equal after wcs.local().withOrigin(origin)' wcs2 = wcs.local(wcs.origin, color=color).withOrigin(wcs.origin, wcs.world_origin) assert wcs == wcs2, name + ' not equal after wcs.local().withOrigin(origin,world_origin)' world_pos1 = wcs.toWorld(galsim.PositionD(0, 0), color=color) wcs3 = check_dep(wcs.withOrigin, new_origin) world_pos2 = wcs3.toWorld(new_origin, color=color) np.testing.assert_almost_equal( world_pos2.x, world_pos1.x, 7, 'withOrigin(new_origin) returned wrong world position') np.testing.assert_almost_equal( world_pos2.y, world_pos1.y, 7, 'withOrigin(new_origin) returned wrong world position') new_world_origin = galsim.PositionD(5352.7, 9234.3) wcs5 = check_dep(wcs.withOrigin, new_origin, new_world_origin, color=color) world_pos3 = wcs5.toWorld(new_origin, color=color) np.testing.assert_almost_equal( world_pos3.x, new_world_origin.x, 7, 'withOrigin(new_origin, new_world_origin) returned wrong position') np.testing.assert_almost_equal( world_pos3.y, new_world_origin.y, 7, 'withOrigin(new_origin, new_world_origin) returned wrong position') # Now some CelestialWCS types cubic_u = Cubic(2.9e-5, 2000., 'u') cubic_v = Cubic(-3.7e-5, 2000., 'v') center = galsim.CelestialCoord(23 * galsim.degrees, -13 * galsim.degrees) radec = lambda x, y: center.deproject_rad( cubic_u(x, y) * 0.2, cubic_v(x, y) * 0.2, projection='lambert') wcs_list = [ galsim.RaDecFunction(radec), galsim.AstropyWCS('1904-66_TAN.fits', dir='fits_files'), galsim.GSFitsWCS('tpv.fits', dir='fits_files'), galsim.FitsWCS('sipsample.fits', dir='fits_files'), ] for wcs in wcs_list: # Original version of the shiftOrigin tests in do_celestial_wcs using deprecated name. new_origin = galsim.PositionI(123, 321) wcs3 = wcs.shiftOrigin(new_origin) assert wcs != wcs3, name + ' is not != wcs.shiftOrigin(pos)' wcs4 = wcs.local(wcs.origin) assert wcs != wcs4, name + ' is not != wcs.local()' assert wcs4 != wcs, name + ' is not != wcs.local() (reverse)' world_pos1 = wcs.toWorld(galsim.PositionD(0, 0)) wcs3 = wcs.shiftOrigin(new_origin) world_pos2 = wcs3.toWorld(new_origin) np.testing.assert_almost_equal( world_pos2.distanceTo(world_pos1) / galsim.arcsec, 0, 7, 'shiftOrigin(new_origin) returned wrong world position')
def test_wfirst_wcs(): """Test the WFIRST WCS routines against those from software provided by WFIRST project office. """ # The standard against which we will compare is the output of some software provided by Jeff # Kruk. The files used here were generated by Rachel on her Macbook using the script in # wfirst_files/make_standards.sh, and none of the parameters below can be changed without # modifying and rerunning that script. We use 4 sky positions and rotation angles (2 defined # using the focal plane array, 2 using the observatory coordinates), and in each case, use a # different SCA for our tests. We will simply read in the stored WCS and generate new ones, and # check that they have the right value of SCA center and pixel scale at the center, and that if # we offset by 500 pixels in some direction that gives the same sky position in each case. ra_test = [127., 307.4, -61.52, 0.0] dec_test = [-70., 50., 22.7, 0.0] pa_test = [160., 79., 23.4, -3.1] sca_test = [2, 13, 7, 18] import datetime ve = datetime.datetime(2025, 3, 20, 9, 2, 0) date_test = [ve, ve, ve, datetime.date(2025, 6, 20)] pa_is_fpa_test = [True, False, True, False] dist_arcsec = [] dist_2_arcsec = [] pix_area_ratio = [] for i_test in range(len(ra_test)): # Make the WCS for this test. world_pos = galsim.CelestialCoord(ra_test[i_test] * galsim.degrees, dec_test[i_test] * galsim.degrees) if i_test == 0: # Just for this case, we want to get the WCS for all SCAs. This will enable some # additional tests that we don't do for the other test case. gs_wcs_dict = galsim.wfirst.getWCS( PA=pa_test[i_test] * galsim.degrees, world_pos=world_pos, PA_is_FPA=pa_is_fpa_test[i_test], date=date_test[i_test]) np.testing.assert_equal( len(gs_wcs_dict), galsim.wfirst.n_sca, err_msg='WCS dict has wrong length: %d vs. %d' % (len(gs_wcs_dict), galsim.wfirst.n_sca)) else: # Use the SCAs keyword to just get the WCS for the SCA that we want. gs_wcs_dict = galsim.wfirst.getWCS( PA=pa_test[i_test] * galsim.degrees, world_pos=world_pos, PA_is_FPA=pa_is_fpa_test[i_test], SCAs=sca_test[i_test], date=date_test[i_test]) np.testing.assert_equal( len(gs_wcs_dict), 1, err_msg='WCS dict has wrong length: %d vs. %d' % (len(gs_wcs_dict), 1)) # Read in reference. test_file = 'test%d_sca_%02d.fits' % (i_test + 1, sca_test[i_test]) ref_wcs = galsim.FitsWCS(os.path.join('wfirst_files', test_file)) gs_wcs = gs_wcs_dict[sca_test[i_test]] # Check center position: im_cent_pos = galsim.PositionD(galsim.wfirst.n_pix / 2., galsim.wfirst.n_pix / 2) ref_cent_pos = ref_wcs.toWorld(im_cent_pos) gs_cent_pos = gs_wcs.toWorld(im_cent_pos) dist_arcsec.append( ref_cent_pos.distanceTo(gs_cent_pos) / galsim.arcsec) # Check pixel area rat = ref_wcs.pixelArea(image_pos=im_cent_pos) / gs_wcs.pixelArea( image_pos=im_cent_pos) pix_area_ratio.append(rat - 1.) # Check another position, just in case rotations are messed up. im_other_pos = galsim.PositionD(im_cent_pos.x + 500., im_cent_pos.y - 200.) ref_other_pos = ref_wcs.toWorld(im_other_pos) gs_other_pos = gs_wcs.toWorld(im_other_pos) dist_2_arcsec.append( ref_other_pos.distanceTo(gs_other_pos) / galsim.arcsec) if i_test == 0: # For just one of our tests cases, we'll do some additional tests. These will target # the findSCA() functionality. First, we'll choose an SCA and check that its center is # found to be in that SCA. found_sca = galsim.wfirst.findSCA(gs_wcs_dict, gs_cent_pos) np.testing.assert_equal( found_sca, sca_test[i_test], err_msg='Did not find SCA center position to be on that SCA!') # Then, we go to a place that should be off the side by a tiny bit, and check that it is # NOT on an SCA if we exclude borders, but IS on the SCA if we include borders. im_off_edge_pos = galsim.PositionD(-2., galsim.wfirst.n_pix / 2.) world_off_edge_pos = gs_wcs.toWorld(im_off_edge_pos) found_sca = galsim.wfirst.findSCA(gs_wcs_dict, world_off_edge_pos) assert found_sca is None found_sca = galsim.wfirst.findSCA(gs_wcs_dict, world_off_edge_pos, include_border=True) np.testing.assert_equal( found_sca, sca_test[i_test], err_msg='Did not find slightly off-edge position on the SCA' ' when including borders!') np.testing.assert_array_less( np.array(dist_arcsec), np.ones(len(ra_test)) * galsim.wfirst.pixel_scale / 100, err_msg= 'For at least one WCS, center offset from reference was > 0.01(pixel scale).' ) np.testing.assert_array_less( np.array(dist_2_arcsec), np.ones(len(ra_test)) * galsim.wfirst.pixel_scale / 100, err_msg= 'For at least one WCS, other offset from reference was > 0.01(pixel scale).' ) np.testing.assert_array_less( np.array(pix_area_ratio), np.ones(len(ra_test)) * 0.0001, err_msg= 'For at least one WCS, pixel areas differ from reference by >0.01%.') # Check whether we're allowed to look at certain positions on certain dates. # Let's choose RA=90 degrees, dec=10 degrees. # We know that it's best to look about 90 degrees from the Sun. So on the vernal and autumnal # equinox, this should be a great place to look, but not midway in between. We'll use # approximate dates for these. pos = galsim.CelestialCoord(90. * galsim.degrees, 10. * galsim.degrees) import datetime assert galsim.wfirst.allowedPos(pos, datetime.date(2025, 3, 20)) assert galsim.wfirst.allowedPos(pos, datetime.date(2025, 9, 20)) assert not galsim.wfirst.allowedPos(pos, datetime.date(2025, 6, 20)) # Finally make sure it does something reasonable for the observatory position angle. # When the sun is at (0,0), and we look at (90,0), then +Z points towards the Sun and +Y points # North, giving a PA of 0 degrees. pos = galsim.CelestialCoord(90. * galsim.degrees, 0. * galsim.degrees) test_date = datetime.datetime(2025, 3, 20, 9, 2) pa = galsim.wfirst.bestPA(pos, test_date) np.testing.assert_almost_equal(pa.rad(), 0., decimal=3) # Now make it look at the same RA as the sun but quite different declination. It wants +Z # pointing North toward Sun, so we'll get a -90 degree angle for the PA. pos = galsim.CelestialCoord(0. * galsim.degrees, -70. * galsim.degrees) pa = galsim.wfirst.bestPA(pos, test_date) np.testing.assert_almost_equal(pa.rad(), -np.pi / 2, decimal=3)
def test_psf(): """Test the two kinds of PSF files we have in DES. """ data_dir = 'des_data' psfex_file = "DECam_00154912_12_psfcat.psf" fitpsf_file = "DECam_00154912_12_fitpsf.fits" wcs_file = "DECam_00154912_12_header.fits" wcs = galsim.FitsWCS(wcs_file, dir=data_dir) # We don't require that the files in example_data_dir have been downloaded. If they # haven't, then we just directly set the comparison values that we want here. example_data_dir = '../examples/des/des_data' cat_file = "DECam_00154912_12_cat.fits" image_file = "DECam_00154912_12.fits.fz" try: cat = galsim.Catalog(cat_file, hdu=2, dir=example_data_dir) size = numpy.array( [cat.getFloat(i, 'FLUX_RADIUS') for i in range(cat.nobjects)]) mag = numpy.array( [cat.getFloat(i, 'MAG_AUTO') for i in range(cat.nobjects)]) flags = numpy.array( [cat.getInt(i, 'FLAGS') for i in range(cat.nobjects)]) index = numpy.array(range(cat.nobjects)) xvals = numpy.array( [cat.getFloat(i, 'X_IMAGE') for i in range(cat.nobjects)]) yvals = numpy.array( [cat.getFloat(i, 'Y_IMAGE') for i in range(cat.nobjects)]) # Pick bright small objects as probable stars mask = (flags == 0) & (mag < 14) & (mag > 13) & (size > 2) & (size < 2.5) idx = numpy.argsort(size[mask]) # This choice of a star is fairly isolated from neighbors, isn't too near an edge or a tape # bump, and doesn't have any noticeable image artifacts in its vicinity. x = xvals[mask][idx][27] y = yvals[mask][idx][27] print('Using x,y = ', x, y) image_pos = galsim.PositionD(x, y) print('size, mag = ', size[mask][idx][27], mag[mask][idx][27]) data = galsim.fits.read(image_file, dir=example_data_dir) b = galsim.BoundsI(int(x) - 15, int(x) + 16, int(y) - 15, int(y) + 16) data_stamp = data[b] header = galsim.fits.FitsHeader(image_file, dir=example_data_dir) sky_level = header['SKYBRITE'] data_stamp -= sky_level raw_meas = data_stamp.FindAdaptiveMom() print('raw_meas = ', raw_meas) ref_size = raw_meas.moments_sigma ref_shape = raw_meas.observed_shape print('ref size: ', ref_size) print('ref shape: ', ref_shape) except IOError: x, y = 1195.64074707, 1276.63427734 image_pos = galsim.PositionD(x, y) b = galsim.BoundsI(int(x) - 15, int(x) + 16, int(y) - 15, int(y) + 16) ref_size = 1.80668628216 ref_shape = galsim.Shear(g1=0.022104322221, g2=-0.130925191715) # First the PSFEx model using the wcs_file to get the model is sky coordinates. psfex = galsim.des.DES_PSFEx(psfex_file, wcs_file, dir=data_dir) psf = psfex.getPSF(image_pos) # The getLocalWCS function should return a local WCS assert psfex.getLocalWCS(image_pos).isLocal() # Draw the postage stamp image # Note: the PSF already includes the pixel response, so draw with method 'no_pixel'. stamp = psf.drawImage(wcs=wcs.local(image_pos), bounds=b, method='no_pixel') print('wcs = ', wcs.local(image_pos)) meas = stamp.FindAdaptiveMom() print('meas = ', meas) print('pixel scale = ', stamp.wcs.minLinearScale(image_pos=image_pos)) print('cf sizes: ', ref_size, meas.moments_sigma) print('cf shapes: ', ref_shape, meas.observed_shape) # The agreement for a single star is not great of course, not even 2 decimals. # Divide by 2 to get agreement at 2 dp. numpy.testing.assert_almost_equal(meas.moments_sigma / 2, ref_size / 2, decimal=2, err_msg="PSFEx size doesn't match") numpy.testing.assert_almost_equal(meas.observed_shape.g1 / 2, ref_shape.g1 / 2, decimal=2, err_msg="PSFEx shape.g1 doesn't match") numpy.testing.assert_almost_equal(meas.observed_shape.g2 / 2, ref_shape.g2 / 2, decimal=2, err_msg="PSFEx shape.g2 doesn't match") # Repeat without the wcs_file argument, so the model is in chip coordinates. # Also check the functionality where the file is already open. with pyfits.open(os.path.join(data_dir, psfex_file)) as hdu_list: psfex = galsim.des.DES_PSFEx(hdu_list[1]) psf = psfex.getPSF(image_pos) # In this case, the getLocalWCS function won't return anything useful. assert psfex.getLocalWCS(image_pos) is None # Draw the postage stamp image. This time in image coords, so pixel_scale = 1.0. stamp = psf.drawImage(bounds=b, scale=1.0, method='no_pixel') meas = stamp.FindAdaptiveMom() numpy.testing.assert_almost_equal( meas.moments_sigma / 2, ref_size / 2, decimal=2, err_msg="no-wcs PSFEx size doesn't match") numpy.testing.assert_almost_equal( meas.observed_shape.g1 / 2, ref_shape.g1 / 2, decimal=2, err_msg="no-wcs PSFEx shape.g1 doesn't match") numpy.testing.assert_almost_equal( meas.observed_shape.g2 / 2, ref_shape.g2 / 2, decimal=2, err_msg="no-wcs PSFEx shape.g2 doesn't match") # Now the shapelet PSF model. This model is already in sky coordinates, so no wcs_file needed. fitpsf = galsim.des.DES_Shapelet(os.path.join(data_dir, fitpsf_file)) psf = fitpsf.getPSF(image_pos) # Draw the postage stamp image # Again, the PSF already includes the pixel response. stamp = psf.drawImage(wcs=wcs.local(image_pos), bounds=b, method='no_pixel') meas = stamp.FindAdaptiveMom() numpy.testing.assert_almost_equal( meas.moments_sigma / 2, ref_size / 2, decimal=2, err_msg="Shapelet PSF size doesn't match") numpy.testing.assert_almost_equal( meas.observed_shape.g1 / 2, ref_shape.g1 / 2, decimal=2, err_msg="Shapelet PSF shape.g1 doesn't match") numpy.testing.assert_almost_equal( meas.observed_shape.g2 / 2, ref_shape.g2 / 2, decimal=2, err_msg="Shapelet PSF shape.g2 doesn't match")
def test_psf_config(): """Test building the two PSF types using the config layer. """ data_dir = 'des_data' psfex_file = "DECam_00154912_12_psfcat.psf" fitpsf_file = "DECam_00154912_12_fitpsf.fits" wcs_file = "DECam_00154912_12_header.fits" image_pos = galsim.PositionD(123.45, 543.21) config = { 'input': { 'des_shapelet': { 'dir': data_dir, 'file_name': fitpsf_file }, 'des_psfex': [ { 'dir': data_dir, 'file_name': psfex_file }, { 'dir': data_dir, 'file_name': psfex_file, 'image_file_name': wcs_file }, ] }, 'psf1': { 'type': 'DES_Shapelet' }, 'psf2': { 'type': 'DES_PSFEx', 'num': 0 }, 'psf3': { 'type': 'DES_PSFEx', 'num': 1 }, 'psf4': { 'type': 'DES_Shapelet', 'image_pos': galsim.PositionD(567, 789), 'flux': 179, 'gsparams': { 'folding_threshold': 1.e-4 } }, 'psf5': { 'type': 'DES_PSFEx', 'image_pos': galsim.PositionD(789, 567), 'flux': 388, 'gsparams': { 'folding_threshold': 1.e-4 } }, # This would normally be set by the config processing. Set it manually here. 'image_pos': image_pos, } galsim.config.ProcessInput(config) psf1a = galsim.config.BuildGSObject(config, 'psf1')[0] fitpsf = galsim.des.DES_Shapelet(fitpsf_file, dir=data_dir) psf1b = fitpsf.getPSF(image_pos) gsobject_compare(psf1a, psf1b) psf2a = galsim.config.BuildGSObject(config, 'psf2')[0] psfex0 = galsim.des.DES_PSFEx(psfex_file, dir=data_dir) psf2b = psfex0.getPSF(image_pos) gsobject_compare(psf2a, psf2b) psf3a = galsim.config.BuildGSObject(config, 'psf3')[0] psfex1 = galsim.des.DES_PSFEx(psfex_file, wcs_file, dir=data_dir) psf3b = psfex1.getPSF(image_pos) gsobject_compare(psf3a, psf3b) gsparams = galsim.GSParams(folding_threshold=1.e-4) psf4a = galsim.config.BuildGSObject(config, 'psf4')[0] psf4b = fitpsf.getPSF(galsim.PositionD(567, 789), gsparams=gsparams).withFlux(179) gsobject_compare(psf4a, psf4b) # Insert a wcs for thes last one. config['wcs'] = galsim.FitsWCS(os.path.join(data_dir, wcs_file)) del config['input_objs'] galsim.config.ProcessInput(config) psfex2 = galsim.des.DES_PSFEx(psfex_file, dir=data_dir, wcs=config['wcs']) psf5a = galsim.config.BuildGSObject(config, 'psf5')[0] psf5b = psfex2.getPSF(galsim.PositionD(789, 567), gsparams=gsparams).withFlux(388) gsobject_compare(psf5a, psf5b)
def main(argv): root = 'DECam_00154912' data_dir = 'des_data' if not os.path.exists(data_dir): print('You will need to download some DES data to use this script.') print('Run the following commands from the directory GalSim/examples/des:') print() print(' wget http://www.sas.upenn.edu/~mjarvis/des_data.tar.gz') print(' tar xfz des_data.tar.gz') print() print('Then try running this script again. It should work now.') sys.exit() # Set which chips to run on first_chip = 1 last_chip = 62 #first_chip = 12 #last_chip = 12 # quick and dirty command line parsing. for var in argv: if var.startswith('first='): first_chip = int(var[6:]) if var.startswith('last='): last_chip = int(var[5:]) print('Processing chips %d .. %d'%(first_chip, last_chip)) out_dir = 'output' # The random seed, so the results are deterministic random_seed = 1339201 x_col = 'X_IMAGE' y_col = 'Y_IMAGE' flux_col = 'FLUX_AUTO' flag_col = 'FLAGS' xsize_key = 'NAXIS1' ysize_key = 'NAXIS2' sky_level_key = 'SKYBRITE' sky_sigma_key = 'SKYSIGMA' # Make output directory if not already present. if not os.path.isdir(out_dir): os.mkdir(out_dir) for chipnum in range(first_chip,last_chip+1): print('Start chip ',chipnum) # Setup the file names image_file = '%s_%02d.fits.fz'%(root,chipnum) cat_file = '%s_%02d_cat.fits'%(root,chipnum) psfex_file = '%s_%02d_psfcat.psf'%(root,chipnum) fitpsf_file = '%s_%02d_fitpsf.fits'%(root,chipnum) psfex_image_file = '%s_%02d_psfex_image.fits'%(root,chipnum) fitpsf_image_file = '%s_%02d_fitpsf_image.fits'%(root,chipnum) # Get some parameters about the image from the data image header information image_header = galsim.FitsHeader(image_file, dir=data_dir) xsize = image_header[xsize_key] ysize = image_header[ysize_key] sky_sigma = image_header[sky_sigma_key] # This is sqrt(variance) / pixel sky_level = image_header[sky_level_key] # This is in ADU / pixel gain = sky_level / sky_sigma**2 # an approximation, since gain is missing. # Read the WCS wcs = galsim.FitsWCS(header=image_header) # Setup the images: psfex_image = galsim.Image(xsize, ysize, wcs=wcs) fitpsf_image = galsim.Image(xsize, ysize, wcs=wcs) # Read the other input files cat = galsim.Catalog(cat_file, hdu=2, dir=data_dir) psfex = galsim.des.DES_PSFEx(psfex_file, image_file, dir=data_dir) fitpsf = galsim.des.DES_Shapelet(fitpsf_file, dir=data_dir) nobj = cat.nobjects print('Catalog has ',nobj,' objects') for k in range(nobj): sys.stdout.write('.') sys.stdout.flush() # Skip objects with a non-zero flag flag = cat.getInt(k,flag_col) if flag: continue # Get the position from the galaxy catalog x = cat.getFloat(k,x_col) y = cat.getFloat(k,y_col) image_pos = galsim.PositionD(x,y) #print ' pos = ',image_pos x += 0.5 # + 0.5 to account for even-size postage stamps y += 0.5 ix = int(math.floor(x+0.5)) # round to nearest pixel iy = int(math.floor(y+0.5)) dx = x-ix dy = y-iy offset = galsim.PositionD(dx,dy) # Also get the flux of the galaxy from the catalog flux = cat.getFloat(k,flux_col) #print ' flux = ',flux #print ' wcs = ',wcs.local(image_pos) # First do the PSFEx image: if True: # Define the PSF profile psf = psfex.getPSF(image_pos).withFlux(flux) #print ' psfex psf = ',psf # Draw the postage stamp image # Note: Use no_pixel method, since the PSFEx estimate of the PSF already includes # the pixel response. stamp = psf.drawImage(wcs=wcs.local(image_pos), offset=offset, method='no_pixel') # Recenter the stamp at the desired position: stamp.setCenter(ix,iy) # Find overlapping bounds bounds = stamp.bounds & psfex_image.bounds psfex_image[bounds] += stamp[bounds] # Next do the ShapeletPSF image: # If the position is not within the interpolation bounds, fitpsf will # raise an exception telling us to skip this object. Easier to check here. if fitpsf.bounds.includes(image_pos): # Define the PSF profile psf = fitpsf.getPSF(image_pos).withFlux(flux) #print ' fitpsf psf = ',psf # Draw the postage stamp image # Again, the PSF already includes the pixel response. stamp = psf.drawImage(wcs=wcs.local(image_pos), offset=offset, method='no_pixel') # Recenter the stamp at the desired position: stamp.setCenter(ix,iy) # Find overlapping bounds bounds = stamp.bounds & fitpsf_image.bounds fitpsf_image[bounds] += stamp[bounds] else: pass #print '...not in fitpsf.bounds' print() # Add background level psfex_image += sky_level fitpsf_image += sky_level # Add noise rng = galsim.BaseDeviate(random_seed) noise = galsim.CCDNoise(rng, gain=gain) psfex_image.addNoise(noise) # Reset the random seed to match the action of the yaml version # Note: the difference between seed and reset matters here. # reset would sever the connection between this rng instance and the one stored in noise. # seed changes the seed while keeping the connection between them. rng.seed(random_seed) fitpsf_image.addNoise(noise) # Now write the images to disk. psfex_image.write(psfex_image_file, dir=out_dir) fitpsf_image.write(fitpsf_image_file, dir=out_dir) print('Wrote images to %s and %s'%( os.path.join(out_dir,psfex_image_file), os.path.join(out_dir,fitpsf_image_file))) # Increment the random seed by the number of objects in the file random_seed += nobj
# We make new seg files now, so use out_dir for those paths as well. But don't copy the originals. seg_path = [ os.path.join(out_dir,os.path.basename(file)) for file in seg_path ] src_cols[0] = list(out_path[1:]) src_cols[1] = list(sky_path[1:]) src_cols[2] = list(seg_path[1:]) src_rows = zip(*src_cols) out_src_file = os.path.join(out_dir,os.path.basename(coadd_srclist)) with open(out_src_file,'w') as out_src: for row in src_rows: out_src.write('%s %s %s %s\n'%(row)) # Read the image files and make blank ones. # In principal, we could read the files and get the bounds from that, but # that's slow. So we just use the known bounds and use that for everything. se_bounds = galsim.BoundsI(1,2048,1,4096) image_wcs = [ galsim.FitsWCS(file_name) for file_name in image_path ] images = [ galsim.Image(wcs=wcs, bounds=se_bounds) for wcs in image_wcs ] # Except the first one (the coadd image) is different coadd_bounds = galsim.BoundsI(1,10000,1,10000) images[0] = galsim.Image(wcs=image_wcs[0], bounds=coadd_bounds) print 'Initialized the blank images' # Setup a PSF that varies according to a second order function across the image # Each chip will have its own PSF functions for size, e1, e2. # size = 0.9 arcsec + 0.2 arcsec * F_size(x,y) # e1 = 0.05 * F_e1(x,y) # e2 = 0.05 * F_e2(x,y) # where each F has the form: a + b T1(x) + c T1(y) + d T2(x) + e T1(x) T1(y) + f T2(y) # Similar for e1, e2. So need 18 parameters. Each parameter is chosen to # fall between -1 and 1, and the polynomial factors are Chebyshev polynomials # using the appropriate bounds (different for x,y) also vary between -1 and 1.
def read_image_header(img_file): """Read some information from the image header. Returns (date, time, filter, ccdnum, detpos, telra, teldec, ha, airmass, sky, sigsky, fwhm, tiling, hex, wcs) """ print 'Start read_image_header' print img_file import galsim import astropy.io.fits as pyfits if img_file.endswith('fz'): hdu = 1 else: hdu = 0 # fitsio is a bit faster here. 11 sec/exp rather than 12, so not a huge difference, but still. with pyfits.open(img_file) as pyf: #print pyf #print pyf[hdu] h = pyf[hdu].header #h = pyf[hdu].read_header() #print 'opened' # DATE-OBS looks like '2012-12-03T07:38:54.174780', so split on T. date = h['DATE-OBS'] date, time = date.strip().split('T', 1) # FILTER looks like 'z DECam SDSS c0004 9260.0 1520.0', so split on white space filter = h['FILTER'] filter = filter.split()[0] # CCDNUM is 1-62. DETPOS is a string such as 'S29 '. Strip off the whitespace. ccdnum = h['CCDNUM'] ccdnum = int(ccdnum) detpos = h['DETPOS'] detpos = detpos.strip() #print 'detpos = ',detpos # TELRA, TELDEC look like '-62:30:22.320'. Use GalSim to convert to decimal degrees. telra = h['TELRA'] teldec = h['TELDEC'] telra = galsim.HMS_Angle(telra) / galsim.degrees teldec = galsim.DMS_Angle(teldec) / galsim.degrees #print 'telra, teldec = ',telra,teldec # HA looks like '03:12:02.70''. Use GalSim to convert to decimal degrees. ha = h['HA'] ha = galsim.HMS_Angle(ha) / galsim.degrees # A few more items to grab from the header, but allow default values for these: airmass = float(h.get('AIRMASS', -999)) sky = float(h.get('SKYBRITE', -999)) sigsky = float(h.get('SKYSIGMA', -999)) fwhm = float(h.get('FWHM', -999)) tiling = int(h.get('TILING', 0)) hex = int(h.get('HEX', 0)) # Use Galsim to read WCS wcs = galsim.FitsWCS(header=h) #print 'wcs = ',wcs return (date, time, filter, ccdnum, detpos, telra, teldec, ha, airmass, sky, sigsky, fwhm, tiling, hex, wcs)
def analyse1( self, central_data, neighbour_data, nreal=1000 ): #, central_ellipticity, dneigh=20, central_flux=1912.0, psf_size=3.7, neighbour_flux=1912.0, neighbour_size=3.2, nrealisations=1000): # Level 1 - loop over SNR #----------------------------------------------------------------------- # Initialise the random number generator np.random.seed(self.random_seed) self.object_mask = np.loadtxt("mask_template.txt") m = {} m[1] = [] m[2] = [] c = {} c[1] = [] c[2] = [] snr = [] # Setup a dummy wcs # We load it here to avoid too much unncessary io # In fact it should provide a skeleton only, since we overwrite the Jacobian with an identity matrix wcs_path = "/share/des/disc2/y1/OPS/coadd/20141118000051_DES0014-4414/coadd/DES0014-4414_r.fits.fz" orig_col = 1000 orig_row = 1000 image_pos = galsim.PositionD(orig_col, orig_row) self.wcs = galsim.FitsWCS(wcs_path) self.opt = p3s.Options( "/home/samuroff/shear_pipeline/end-to-end/end-to-end_code/config_files/im3shape/params_disc.ini" ) self.binning = np.logspace(1, 2.8, 12) upper = self.binning[1:] lower = self.binning[:-1] # Cycle over the central flux, as a proxy for SNR for i, limits in enumerate(zip(lower, upper)): snr_min = limits[0] snr_max = limits[1] print "Level 1 iteration: %d SNR = %3.3f - %3.3f" % ( i + 1, snr_min, snr_max) # Selection function for this bin sel = (central_data.res["snr"] > snr_min) & (central_data.res["snr"] < snr_max) print "Will do %d realisations for this bin:" % nreal De1 = [] De2 = [] sn = [] g1 = [] g2 = [] for j in xrange(nreal): print "%d/%d" % (j + 1, nreal) self.generate_central_realisation(central_data, sel) self.generate_neighbour_realisation(neighbour_data, central_data, sel) # Draw this neighbour realisation repeatedly on a ring of angular positions snr, e1, e2 = self.do_position_loop() sn.append(snr) De1.append(e1) De2.append(e2) g1.append(self.g[0]) g2.append(self.g[1]) data = np.zeros(len(g1), dtype=[("e1", float), ("e2", float), ("true_g1", float), ("true_g2", float)]) data["e1"], data["e2"] = np.array(De1), np.array(De2) data["true_g1"], data["true_g2"] = np.array(g1), np.array(g2) bias = di.get_bias(data, nbins=5, names=["m11", "m22", "c11", "c22"], binning="equal_number", silent=True) print bias m[1].append(bias["m11"][0]) m[2].append(bias["m22"][0]) c[1].append(bias["c11"][0]) c[2].append(bias["c22"][0]) import pdb pdb.set_trace() print "Done all loops"
def setup_simple(boxsize=32, model="disc", upsample=1, size=2, flux=None, shear=(0, 0), neighbour=[np.inf, np.inf], neighbour_size=2.0, neighbour_flux=0.13, neighbour_ellipticity=(0, 0), psf_ellipticity=(0, 0), psf_size=0.1, wcs=None, opt=None): """Basic function to construct a test galaxy for exploring shape biases.""" if opt is None: opt = p3s.Options( "/home/samuroff/shear_pipeline/end-to-end/end-to-end_code/config_files/im3shape/params_disc.ini" ) opt.stamp_size = boxsize psfsize = (boxsize + opt._struct.contents.padding) * opt._struct.contents.upsampling upsampling = opt._struct.contents.upsampling large_boxsize = boxsize * 7 gal1 = get_model(size=size, type=model, g1=shear[0], g2=shear[1], flux=flux) pos1 = galsim.PositionD(0, 0) # Add a tiny nominal PSF psf, psf_image = get_fixed_gaussian_psf(opt, psf_size, psf_ellipticity[0], psf_ellipticity[1], wcs) #import pdb ; pdb.set_trace() #galsim.Gaussian(fwhm=psf_size*0.27) if wcs is None: wcs_path = "/share/des/disc2/y1/OPS/coadd/20141118000051_DES0014-4414/coadd/DES0014-4414_r.fits.fz" wcs = galsim.FitsWCS(wcs_path) orig_col = 1000 orig_row = 1000 image_pos = galsim.PositionD(orig_col, orig_row) local_wcs = wcs.local(image_pos) local_wcs._dudx = 1.0 local_wcs._dudy = 0.0 local_wcs._dvdx = 0.0 local_wcs._dvdy = 1.0 A = np.array([[local_wcs._dudx, local_wcs._dudy], [local_wcs._dvdx, local_wcs._dvdy]]) local_wcs._det = np.linalg.det(A) pix = wcs.toWorld(galsim.Pixel(0.27), image_pos=image_pos) obj1 = galsim.Convolve([gal1, psf, pix]) im1 = obj1.drawImage(wcs=local_wcs, nx=large_boxsize, ny=large_boxsize, method='no_pixel') im3 = obj1.drawImage(wcs=local_wcs, nx=large_boxsize, ny=large_boxsize, method='no_pixel') # And a neighbouring object if specified if np.isfinite(np.array(neighbour)).all(): print "drawing neighbour at (%d, %d)" % (int( neighbour[0]), int(neighbour[1])) gal2 = galsim.Sersic(n=1, half_light_radius=neighbour_size) gal2 = gal2.withFlux(neighbour_flux) nshear = galsim.Shear(g1=neighbour_ellipticity[0], g2=neighbour_ellipticity[1]) gal2 = gal2.shear(nshear) obj2 = galsim.Convolve([gal2, psf, pix]) pos2 = galsim.PositionD(x=neighbour[0], y=neighbour[1]) im2 = obj2.drawImage(wcs=local_wcs, nx=large_boxsize, ny=large_boxsize, method='no_pixel', offset=pos2) im3 += im2.array trim = (large_boxsize - boxsize) / 2. lim = galsim.BoundsI(xmin=trim, xmax=large_boxsize - trim - 1, ymin=trim, ymax=large_boxsize - trim - 1) del (wcs) gc.collect() return im3[lim].array, psf_image