4 from __future__
import print_function
15 galType='sersic', cosmosCat=None,
16 drawMethod='no_pixel', trunc=10.0,
17 transform=None, addShear=False,
19 sersic_prec=0.01, addPoisson=False):
21 Function called by task to make galaxy images 24 flux = calibrated total flux 25 gal = galaxy parameters in record (np.recarray) 26 psfImage = np.ndarray of psfImage 27 galType = type of galaxy we want to make, this has to agree 28 with what's in the record array, options now are: 29 'sersic' (single sersic), 30 'dsersic' (double sersic), and 31 'real' (for making galaxies from real HST images) 32 'cosmos' (Using GalSim.COSMOSCatalog) 34 All the necessary keywords need to be in the fits catalog, 35 including maybe drawMethod and trunc... 37 if galType
is 'sersic':
40 drawMethod=drawMethod,
44 addPoisson=addPoisson)
46 if galType
is 'dsersic':
51 drawMethod=drawMethod,
55 addPoisson=addPoisson)
72 drawMethod=drawMethod,
74 addPoisson=addPoisson)
76 if galType
is 'cosmos':
77 if cosmosCat
is None or calib
is None:
78 raise Exception(
"# No COSMOSCatalog() provided!")
82 sersic_prec=sersic_prec,
83 drawMethod=drawMethod,
86 addPoisson=addPoisson)
90 """Place holder for real galaxi.""" 98 cat_name = gal[
'cat_name']
100 raise KeyError(
'Can not find the name of the catlog')
102 cat_dir = gal[
'cat_dir']
106 real_galaxy_catalog = galsim.RealGalaxyCatalog(cat_name,
109 return real_galaxy_catalog, index
114 Parse the input total flux [tflux] and parameter record array 115 [gal] into two parameter records for each component [comp1, comp2] 120 frac1 =
float(gal[
'b2t'])
122 raise KeyError(
"No b2t parameter is found in the record!!")
125 if (frac1 <= 0)
or (frac1 >= 1):
126 raise Exception(
"b2t should be > 0 and <1 !!")
127 flux1, flux2 = (tflux * frac1), (tflux * (1.0 - frac1))
133 reff1, reff2 =
float(gal[
"reff1"]),
float(gal[
"reff2"])
135 raise KeyError(
"reff1 or reff2 is found in the record!!")
138 nser1, nser2 =
float(gal[
"sersic_n1"]),
float(gal[
"sersic_n2"])
140 raise KeyError(
"sersic_n1 or sersic_n2 is found in the record!!")
143 ba1, ba2 =
float(gal[
"b_a1"]),
float(gal[
"b_a2"])
145 raise KeyError(
"b_a1 or b_a2 is found in the record!!")
148 pa1, pa2 =
float(gal[
"theta1"]),
float(gal[
"theta2"])
150 raise KeyError(
"theta1 or theta2 is found in the record!!")
152 comp1 = np.array((galID, flux1, nser1, reff1, ba1, pa1),
153 dtype=[(
'ID',
'int'),
155 (
'sersic_n',
'float'),
159 comp2 = np.array((galID, flux2, nser2, reff2, ba2, pa2),
160 dtype=[(
'ID',
'int'),
162 (
'sersic_n',
'float'),
172 Convert an input 2-D array into a GalSim Image object 174 TODO : Check the scale here 175 According to the GalSim Doxygen 176 If provided, use this as the pixel scale for the Image; 177 this will override the pixel scale stored by the provided Image. 178 If scale is None, then take the provided image's pixel scale. 182 return galsim.InterpolatedImage(galsim.image.Image(imgArr),
184 normalization=
"flux")
186 return galsim.InterpolatedImage(galsim.image.Image(imgArr),
193 "Draw" a GalSim Object into an GalSim Image using certain method, and with 196 TODO : Think about the scale here: 197 By default scale=None 198 According to GalSim Doxygen : 199 If provided, use this as the pixel scale for the image. If scale is None 200 and image != None, then take the provided image's pixel scale. 201 If scale is None and image == None, then use the Nyquist scale. 202 If scale <= 0 (regardless of image), then use the Nyquist scale. 207 imgTemp = galsim.image.Image(size, size)
208 galImg = galObj.drawImage(imgTemp, scale=scale, method=method)
210 galImg = galObj.drawImage(scale=scale, method=method)
214 galImg.addNoise(galsim.PoissonNoise())
220 def galSimConvolve(galObj, psfObj, size=0, scale=1.0, method="no_pixel",
223 Just do convolution using GalSim 225 Make sure the inputs are both GalSim GSObj 226 The galaxy model should be the first one, and the PSF object is the second 227 one; Returns a imgArr or GSObj 229 outObj = galsim.Convolve([galObj, psfObj])
235 scale=scale, method=method)
239 def galSimAdd(galObjList, size=0, scale=1.0, method="no_pixel",
242 Just add a list of GSObjs together using GalSim 243 Make sure all elements in the input list are GSObjs 245 if len(galObjList) < 2:
246 raise Exception(
"Should be more than one GSObjs to add !")
248 outObj = galsim.Add(galObjList)
259 size=0, addPoisson=False):
261 Generate a PNG image of the model 262 By default, the image will be named as 'fake_galaxy.png' 265 import matplotlib.pyplot
as plt
268 outPNG =
'fake_galaxy' 270 outPNG =
'fake_galaxy_%i' % galID
271 if suffix
is not None:
272 outPNG = outPNG +
'_' + suffix.strip() +
'.png' 274 plt.figure(1, figsize=(8, 8))
279 addPoisson=addPoisson,
285 psfImage=None, plotFake=False,
286 returnObj=True, sersic_prec=0.02,
287 drawMethod='no_pixel', scale=1.0,
288 transform=None, addShear=False,
291 Generate fake galaxy using galSim.COSMOSCatalog objects. 294 indexUse = cosmosCat.orig_index
295 paramCat = cosmosCat.param_cat
296 objectUse = paramCat[indexUse]
298 galFound = np.where(objectUse[
'IDENT'] == gal[
'COSMOS_ID'])[0]
299 if len(galFound) == 0:
300 warnings.warn(
"# Find no match for %d" % gal[
'COSMOS_ID'])
301 elif len(galFound) > 1:
302 warnings.warn(
"# Multiple match for %d" % gal[
'COSMOS_ID'])
304 galIndex = galFound[0]
305 cosObj = cosmosCat.makeGalaxy(index=galIndex,
306 sersic_prec=sersic_prec,
307 gal_type=
'parametric')
308 hstFlux = cosObj.flux
313 g1 =
float(gal[
'g1'])
314 g2 =
float(gal[
'g2'])
315 cosObj = cosObj.shear(g1=g1, g2=g2)
317 warnings.warn(
"Can not find g1 or g2 in the input!\n",
318 " No shear has been added!")
321 if transform
is not None:
322 cosObj = cosObj.transform(*tuple(transform.ravel()))
326 The flux of the galaxy corresponds to a 1 second exposure time with the 327 Hubble Space Telescope. Users who wish to simulate F814W images with a 328 different telescope and an exposure time longer than 1 second should 329 multiply by that exposure time, and by the square of the ratio of the 330 effective diameter of their telescope compared to that of HST. 331 (Effective diameter may differ from the actual diameter if there is 332 significant obscuration.) 334 The catalog returns objects that are appropriate for HST in 1 second 335 exposures. So for our telescope we scale up by the relative area and 336 exposure time. Note that what is important is the *effective* area after 337 taking into account obscuration. For HST, the telescope diameter is 2.4 338 but there is obscuration (a linear factor of 0.33). Here, we assume that 339 the telescope we're simulating effectively has no obscuration factor. 340 We're also ignoring the pi/4 factor since it appears in the numerator and 341 denominator, so we use area = diam^2. 344 hstEffArea = (2.4 ** 2) * (1.0 - 0.33 ** 2) 345 subaruEffArea = (8.2 ** 2) * (1.0 - 0.1 ** 2) 346 fluxScaling = (subaruEffArea / hstEffArea) 348 hstMag = -2.5 * np.log10(hstFlux) + 25.94
350 hscFlux = calib.getFlux(hstMag)
352 cosObj = cosObj.withFlux(
float(hscFlux))
355 if psfImage
is not None:
359 cosFinal = galsim.Convolve([cosObj, psfObj])
372 method=drawMethod, scale=scale,
373 addPoisson=addPoisson)
376 def galSimFakeSersic(flux, gal, psfImage=None, scaleRad=False, returnObj=True,
377 expAll=False, devAll=False, plotFake=False, trunc=0,
378 drawMethod="no_pixel", addPoisson=False, scale=1.0,
379 transform=None, addShear=False):
381 Make a fake single Sersic galaxy using the galSim.Sersic function 383 Inputs: total flux of the galaxy, and a record array that stores the 384 necessary parameters [reffPix, nSersic, axisRatio, posAng] 386 Output: a 2-D image array of the galaxy model OR 387 a GalSim object of the model 390 psfImage: PSF image for convolution 391 trunc: Flux of Sersic models will truncate at trunc * reffPix 392 radius; trunc=0 means no truncation 393 drawMethod: The method for drawImage: ['auto', 'fft', 'real_space'] 394 addPoisson: Add Poisson noise 395 plotFake: Generate a PNG figure of the model 396 expAll: Input model will be seen as nSersic=1 397 devAll: Input model will be seen as nSersic=4 398 returnObj: If TRUE, will return the GSObj 400 reff =
float(gal[
"reff"])
401 posAng =
float(gal[
"theta"])
402 axisRatio =
float(gal[
"b_a"])
403 nSersic =
float(gal[
"sersic_n"])
411 raise ValueError(
"Sersic index is too large! Should be <= 6.0")
413 if axisRatio <= 0.05:
414 raise ValueError(
"Axis Ratio is too small! Should be >= 0.05")
417 if nSersic == 1.0
or expAll:
419 serObj = galsim.Exponential(scale_radius=reff)
421 serObj = galsim.Exponential(half_light_radius=reff)
423 print(
" * Treated as a n=1 Exponential disk : %d" % (gal[
"ID"]))
424 elif nSersic == 4.0
or devAll:
425 serObj = galsim.DeVaucouleurs(half_light_radius=reff, trunc=trunc)
427 print(
" * Treated as a n=4 De Vaucouleurs model: %d" % (gal[
"ID"]))
429 serObj = galsim.Sersic(nSersic, half_light_radius=reff)
431 serObj = galsim.Sersic(nSersic, half_light_radius=reff,
436 serObj = serObj.shear(q=axisRatio, beta=(0.0 * galsim.degrees))
440 serObj = serObj.rotate((90.0 - posAng) * galsim.degrees)
445 g1 =
float(gal[
'g1'])
446 g2 =
float(gal[
'g2'])
447 serObj = serObj.shear(g1=g1, g2=g2)
449 warnings.warn(
"Can not find g1 or g2 in the input!\n",
450 " No shear has been added!")
453 if transform
is not None:
454 serObj = serObj.transform(*tuple(transform.ravel()))
457 serObj = serObj.withFlux(
float(flux))
460 if psfImage
is not None:
464 serFinal = galsim.Convolve([serObj, psfObj])
477 addPoisson=addPoisson)
481 returnObj=True, devExp=False,
482 plotFake=False, drawMethod='auto',
483 addPoisson=False, scale=1.0, transform=None,
486 Make a fake double Sersic galaxy using the galSim.Sersic function 488 Inputs: total flux of the galaxy, and a record array that stores the 489 necessary parameters [reffPix, nSersic, axisRatio, posAng] 491 Output: a 2-D image array of the galaxy model OR 492 a GalSim object of the model 495 psfImage: PSF image for convolution 496 trunc: Flux of Sersic models will truncate at trunc * reffPix 497 radius; trunc=0 means no truncation 498 drawMethod: The method for drawImage: ['auto', 'fft', 'real_space'] 499 addPoisson: Add Poisson noise 500 plotFake: Generate a PNG figure of the model 501 devexp: The first component will be seen as a nSersic=4 bulge; 502 And, the second one will be seen as a nSersic=1 disk 503 returnObj: If TRUE, will return the GSObj 507 flux1 =
float(comp1[
'mag'])
508 flux2 =
float(comp2[
'mag'])
515 trunc=trunc, addShear=addShear)
517 trunc=trunc, addShear=addShear)
525 doubleSersic =
galSimAdd([serModel1, serModel2])
528 if transform
is not None:
529 doubleSersic = doubleSersic.transform(*tuple(transform.ravel()))
532 if psfImage
is not None:
536 dserFinal = galsim.Convolve([doubleSersic, psfObj])
538 dserFinal = doubleSersic
552 addPoisson=addPoisson)
556 random=False, returnObj=True, plotFake=False,
557 drawMethod='auto', addPoisson=False, scale=1.0,
565 realObj = galsim.RealGalaxy(real_galaxy_catalog, index=index,
567 index = realObj.index
570 realObj = realObj.withFlux(flux)
573 if transform
is not None:
574 realObj = realObj.transform(*tuple(transform.ravel()))
577 if psfImage
is not None:
581 realFinal = galsim.Convolve([realObj, psfObj])
583 realFinal = realFinal
594 addPoisson=addPoisson)
597 def testMakeFake(galList, asciiTab=False, single=True, double=True, real=True):
598 """Test the makeFake functions.""" 600 psfGaussian = galsim.Gaussian(fwhm=2.0)
601 psfImage = psfGaussian.drawImage().array
606 galData = np.loadtxt(galList, dtype=[(
'ID',
'int'),
608 (
'sersic_n',
'float'),
613 galData = fits.open(galList)[1].data
615 for igal, gal
in enumerate(galData):
617 flux = 10.0 ** ((27.0 - gal[
'mag']) / 2.5)
619 print(
'\n---------------------------------')
620 print(
" Input Flux : ", flux)
621 print(
" Input Parameters : ", gal[
"sersic_n"], gal[
"reff"])
622 print(
" ", gal[
"b_a"], gal[
"theta"])
625 plotFake=
True, returnObj=
False,
626 trunc=12.0, drawMethod=
"no_pixel")
628 print(
" Output Flux : ", np.sum(galArray))
629 print(
" Shape of the Output Array : ", galArray.shape)
630 print(
'---------------------------------')
635 raise Exception(
"For now, only FITS input is allowed !!")
637 galData = fits.open(galList)[1].data
639 for igal, gal
in enumerate(galData):
641 flux = 10.0 ** ((27.0 - gal[
'mag']) / 2.5)
643 print(
'\n---------------------------------')
644 print(
" Input Flux : ", flux)
657 print(
" Flux for Component 1 : ", comp1[
'mag'])
658 print(
" Flux for Component 2 : ", comp2[
'mag'])
659 print(
" Comp 1 Parameters : %5.2f %8.2f" % (comp1[
"sersic_n"],
661 print(
" %5.2f %8.2f" % (comp1[
"b_a"],
663 print(
" Comp 2 Parameters : %5.2f %8.2f" % (comp2[
"sersic_n"],
665 print(
" %5.2f %8.2f" % (comp2[
"b_a"],
670 trunc=12, returnObj=
False,
671 devExp=
True, plotFake=
True,
672 drawMethod=
'no_pixel')
674 print(
" Output Flux : ", np.sum(doubleArray))
675 print(
" Shape of the Output Array : ", doubleArray.shape)
676 print(
'---------------------------------')
681 psfReal = galsim.Gaussian(fwhm=0.2)
682 psfRealImage = psfReal.drawImage().array
686 raise Exception(
"For now, only FITS input is allowed !!")
688 galData = fits.open(galList)[1].data
690 for igal, gal
in enumerate(galData):
700 flux = 10.0 ** ((27.0 - gal[
'mag']) / 2.5)
704 psfImage=psfRealImage,
708 drawMethod=
'no_pixel')
710 print(
'\n---------------------------------')
711 print(
" Input Flux : ", flux)
713 print(
" Output Flux : ", np.sum(realArray))
714 print(
" Shape of the Output Array : ", realArray.shape)
715 print(
'---------------------------------')
def galSimConvolve(galObj, psfObj, size=0, scale=1.0, method="no_pixel", returnObj=False)
def galSimFakeSersic(flux, gal, psfImage=None, scaleRad=False, returnObj=True, expAll=False, devAll=False, plotFake=False, trunc=0, drawMethod="no_pixel", addPoisson=False, scale=1.0, transform=None, addShear=False)
def galSimFakeDoubleSersic(comp1, comp2, psfImage=None, trunc=0, returnObj=True, devExp=False, plotFake=False, drawMethod='auto', addPoisson=False, scale=1.0, transform=None, addShear=False)
def galSimAdd(galObjList, size=0, scale=1.0, method="no_pixel", returnArr=False)
def testMakeFake(galList, asciiTab=False, single=True, double=True, real=True)
def plotFakeGalaxy(galObj, galID=None, suffix=None, size=0, addPoisson=False)
def arrayToGSObj(imgArr, scale=1.0, norm=False)
def galSimDrawImage(galObj, size=0, scale=1.0, method="no_pixel", addPoisson=False)
def makeGalaxy(flux, gal, psfImage, galType='sersic', cosmosCat=None, drawMethod='no_pixel', trunc=10.0, transform=None, addShear=False, calib=None, sersic_prec=0.01, addPoisson=False)
def galSimFakeCosmos(cosmosCat, calib, gal, psfImage=None, plotFake=False, returnObj=True, sersic_prec=0.02, drawMethod='no_pixel', scale=1.0, transform=None, addShear=False, addPoisson=False)
def parseDoubleSersic(tflux, gal)
def galSimRealGalaxy(flux, real_galaxy_catalog, index=None, psfImage=None, random=False, returnObj=True, plotFake=False, drawMethod='auto', addPoisson=False, scale=1.0, transform=None)