4 from astropy.io 
import fits
 
   10                galType='sersic', cosmosCat=None,
 
   11                drawMethod='no_pixel', trunc=10.0,
 
   12                transform=None, addShear=False,
 
   14                sersic_prec=0.01, addPoisson=False):
 
   16     Function called by task to make galaxy images 
   19         flux = calibrated total flux 
   20         gal = galaxy parameters in record (np.recarray) 
   21         psfImage = np.ndarray of psfImage 
   22         galType = type of galaxy we want to make, this has to agree 
   23                   with what's in the record array, options now are: 
   24                     'sersic' (single sersic), 
   25                     'dsersic' (double sersic), and 
   26                     'real' (for making galaxies from real HST images) 
   27                     'cosmos' (Using GalSim.COSMOSCatalog) 
   29     All the necessary keywords need to be in the fits catalog, 
   30     including maybe drawMethod and trunc... 
   32     if galType == 
'sersic':
 
   35                                 drawMethod=drawMethod,
 
   39                                 addPoisson=addPoisson)
 
   41     if galType == 
'dsersic':
 
   46                                       drawMethod=drawMethod,
 
   50                                       addPoisson=addPoisson)
 
   67                                 drawMethod=drawMethod,
 
   69                                 addPoisson=addPoisson)
 
   71     if galType == 
'cosmos':
 
   72         if cosmosCat 
is None or calib 
is None:
 
   73             raise Exception(
"# No COSMOSCatalog() provided!")
 
   77                                 sersic_prec=sersic_prec,
 
   78                                 drawMethod=drawMethod,
 
   81                                 addPoisson=addPoisson)
 
   85     """Place holder for real galaxi.""" 
   93         cat_name = gal[
'cat_name']
 
   95         raise KeyError(
'Can not find the name of the catlog')
 
   97         cat_dir = gal[
'cat_dir']
 
  101     real_galaxy_catalog = galsim.RealGalaxyCatalog(cat_name,
 
  104     return real_galaxy_catalog, index
 
  109     Parse the input total flux [tflux] and parameter record array 
  110     [gal] into two parameter records for each component [comp1, comp2] 
  115         frac1 = float(gal[
'b2t'])
 
  117         raise KeyError(
"No b2t parameter is found in the record!!")
 
  120     if (frac1 <= 0) 
or (frac1 >= 1):
 
  121         raise Exception(
"b2t should be > 0 and <1 !!")
 
  122     flux1, flux2 = (tflux * frac1), (tflux * (1.0 - frac1))
 
  128         reff1, reff2 = float(gal[
"reff1"]), float(gal[
"reff2"])
 
  130         raise KeyError(
"reff1 or reff2 is found in the record!!")
 
  133         nser1, nser2 = float(gal[
"sersic_n1"]), float(gal[
"sersic_n2"])
 
  135         raise KeyError(
"sersic_n1 or sersic_n2 is found in the record!!")
 
  138         ba1, ba2 = float(gal[
"b_a1"]), float(gal[
"b_a2"])
 
  140         raise KeyError(
"b_a1 or b_a2 is found in the record!!")
 
  143         pa1, pa2 = float(gal[
"theta1"]), float(gal[
"theta2"])
 
  145         raise KeyError(
"theta1 or theta2 is found in the record!!")
 
  147     comp1 = np.array((galID, flux1, nser1, reff1, ba1, pa1),
 
  148                      dtype=[(
'ID', 
'int'),
 
  150                             (
'sersic_n', 
'float'),
 
  154     comp2 = np.array((galID, flux2, nser2, reff2, ba2, pa2),
 
  155                      dtype=[(
'ID', 
'int'),
 
  157                             (
'sersic_n', 
'float'),
 
  167     Convert an input 2-D array into a GalSim Image object 
  169     TODO : Check the scale here 
  170             According to the GalSim Doxygen 
  171             If provided, use this as the pixel scale for the Image; 
  172             this will override the pixel scale stored by the provided Image. 
  173             If scale is None, then take the provided image's pixel scale. 
  177         return galsim.InterpolatedImage(galsim.image.Image(imgArr),
 
  179                                         normalization=
"flux")
 
  181         return galsim.InterpolatedImage(galsim.image.Image(imgArr),
 
  188     "Draw" a GalSim Object into an GalSim Image using certain method, and with 
  191     TODO : Think about the scale here: 
  192       By default scale=None 
  193       According to GalSim Doxygen : 
  194       If provided, use this as the pixel scale for the image. If scale is None 
  195       and image != None, then take the provided image's pixel scale. 
  196       If scale is None and image == None, then use the Nyquist scale. 
  197       If scale <= 0 (regardless of image), then use the Nyquist scale. 
  202         imgTemp = galsim.image.Image(size, size)
 
  203         galImg = galObj.drawImage(imgTemp, scale=scale, method=method)
 
  205         galImg = galObj.drawImage(scale=scale, method=method)
 
  209         galImg.addNoise(galsim.PoissonNoise())
 
  218     Just do convolution using GalSim 
  220     Make sure the inputs are both GalSim GSObj 
  221     The galaxy model should be the first one, and the PSF object is the second 
  222     one; Returns a imgArr or GSObj 
  224     outObj = galsim.Convolve([galObj, psfObj])
 
  230                                  scale=scale, method=method)
 
  234 def galSimAdd(galObjList, size=0, scale=1.0, method="no_pixel",
 
  237     Just add a list of GSObjs together using GalSim 
  238     Make sure all elements in the input list are GSObjs 
  240     if len(galObjList) < 2:
 
  241         raise Exception(
"Should be more than one GSObjs to add !")
 
  243     outObj = galsim.Add(galObjList)
 
  254                    size=0, addPoisson=False):
 
  256     Generate a PNG image of the model 
  257     By default, the image will be named as 'fake_galaxy.png' 
  260     import matplotlib.pyplot 
as plt
 
  263         outPNG = 
'fake_galaxy' 
  265         outPNG = 
'fake_galaxy_%i' % galID
 
  266     if suffix 
is not None:
 
  267         outPNG = outPNG + 
'_' + suffix.strip() + 
'.png' 
  269     plt.figure(1, figsize=(8, 8))
 
  274                                           addPoisson=addPoisson,
 
  280                      psfImage=None, plotFake=False,
 
  281                      returnObj=True, sersic_prec=0.02,
 
  282                      drawMethod='no_pixel', scale=1.0,
 
  283                      transform=None, addShear=False,
 
  286     Generate fake galaxy using galSim.COSMOSCatalog objects. 
  289     indexUse = cosmosCat.orig_index
 
  290     paramCat = cosmosCat.param_cat
 
  291     objectUse = paramCat[indexUse]
 
  293     galFound = np.where(objectUse[
'IDENT'] == gal[
'COSMOS_ID'])[0]
 
  294     if len(galFound) == 0:
 
  295         warnings.warn(
"# Find no match for %d" % gal[
'COSMOS_ID'])
 
  296     elif len(galFound) > 1:
 
  297         warnings.warn(
"# Multiple match for %d" % gal[
'COSMOS_ID'])
 
  299     galIndex = galFound[0]
 
  300     cosObj = cosmosCat.makeGalaxy(index=galIndex,
 
  301                                   sersic_prec=sersic_prec,
 
  302                                   gal_type=
'parametric')
 
  303     hstFlux = cosObj.flux
 
  308             g1 = float(gal[
'g1'])
 
  309             g2 = float(gal[
'g2'])
 
  310             cosObj = cosObj.shear(g1=g1, g2=g2)
 
  312             warnings.warn(
"Can not find g1 or g2 in the input!\n",
 
  313                           " No shear has been added!")
 
  316     if transform 
is not None:
 
  317         cosObj = cosObj.transform(*tuple(transform.ravel()))
 
  321     The flux of the galaxy corresponds to a 1 second exposure time with the 
  322         Hubble Space Telescope. Users who wish to simulate F814W images with a 
  323         different telescope and an exposure time longer than 1 second should 
  324         multiply by that exposure time, and by the square of the ratio of the 
  325         effective diameter of their telescope compared to that of HST. 
  326         (Effective diameter may differ from the actual diameter if there is 
  327         significant obscuration.) 
  329     The catalog returns objects that are appropriate for HST in 1 second 
  330     exposures.  So for our  telescope we scale up by the relative area and 
  331     exposure time.  Note that what is important is the *effective* area after 
  332     taking into account obscuration.  For HST, the telescope diameter is 2.4 
  333     but there is obscuration (a linear factor of 0.33).  Here, we assume that 
  334     the telescope we're simulating effectively has no obscuration factor. 
  335     We're also ignoring the pi/4 factor since it appears in the numerator and 
  336     denominator, so we use area = diam^2. 
  339     hstEffArea = (2.4 ** 2) * (1.0 - 0.33 ** 2) 
  340     subaruEffArea = (8.2 ** 2) * (1.0 - 0.1 ** 2) 
  341     fluxScaling = (subaruEffArea / hstEffArea) 
  343     hstMag = -2.5 * np.log10(hstFlux) + 25.94
 
  345     hscFlux = calib.getFlux(hstMag)
 
  347     cosObj = cosObj.withFlux(float(hscFlux))
 
  350     if psfImage 
is not None:
 
  354         cosFinal = galsim.Convolve([cosObj, psfObj])
 
  367                                method=drawMethod, scale=scale,
 
  368                                addPoisson=addPoisson)
 
  372                      expAll=False, devAll=False, plotFake=False, trunc=0,
 
  373                      drawMethod="no_pixel", addPoisson=False, scale=1.0,
 
  374                      transform=None, addShear=False):
 
  376     Make a fake single Sersic galaxy using the galSim.Sersic function 
  378     Inputs: total flux of the galaxy, and a record array that stores the 
  379     necessary parameters [reffPix, nSersic, axisRatio, posAng] 
  381     Output: a 2-D image array of the galaxy model  OR 
  382             a GalSim object of the model 
  385         psfImage:     PSF image for convolution 
  386         trunc:        Flux of Sersic models will truncate at trunc * reffPix 
  387                       radius; trunc=0 means no truncation 
  388         drawMethod:   The method for drawImage: ['auto', 'fft', 'real_space'] 
  389         addPoisson:   Add Poisson noise 
  390         plotFake:     Generate a PNG figure of the model 
  391         expAll:       Input model will be seen as nSersic=1 
  392         devAll:       Input model will be seen as nSersic=4 
  393         returnObj:    If TRUE, will return the GSObj 
  395     reff = float(gal[
"reff"])
 
  396     posAng = float(gal[
"theta"])
 
  397     axisRatio = float(gal[
"b_a"])
 
  398     nSersic = float(gal[
"sersic_n"])
 
  406         raise ValueError(
"Sersic index is too large! Should be <= 6.0")
 
  408     if axisRatio <= 0.05:
 
  409         raise ValueError(
"Axis Ratio is too small! Should be >= 0.05")
 
  412     if nSersic == 1.0 
or expAll:
 
  414             serObj = galsim.Exponential(scale_radius=reff)
 
  416             serObj = galsim.Exponential(half_light_radius=reff)
 
  418             print(
" * Treated as a n=1 Exponential disk : %d" % (gal[
"ID"]))
 
  419     elif nSersic == 4.0 
or devAll:
 
  420         serObj = galsim.DeVaucouleurs(half_light_radius=reff, trunc=trunc)
 
  422             print(
" * Treated as a n=4 De Vaucouleurs model: %d" % (gal[
"ID"]))
 
  424         serObj = galsim.Sersic(nSersic, half_light_radius=reff)
 
  426         serObj = galsim.Sersic(nSersic, half_light_radius=reff,
 
  431         serObj = serObj.shear(q=axisRatio, beta=(0.0 * galsim.degrees))
 
  435     serObj = serObj.rotate((90.0 - posAng) * galsim.degrees)
 
  440             g1 = float(gal[
'g1'])
 
  441             g2 = float(gal[
'g2'])
 
  442             serObj = serObj.shear(g1=g1, g2=g2)
 
  444             warnings.warn(
"Can not find g1 or g2 in the input!\n",
 
  445                           " No shear has been added!")
 
  448     if transform 
is not None:
 
  449         serObj = serObj.transform(*tuple(transform.ravel()))
 
  452     serObj = serObj.withFlux(float(flux))
 
  455     if psfImage 
is not None:
 
  459         serFinal = galsim.Convolve([serObj, psfObj])
 
  472                                addPoisson=addPoisson)
 
  476                            returnObj=True, devExp=False,
 
  477                            plotFake=False, drawMethod='auto',
 
  478                            addPoisson=False, scale=1.0, transform=None,
 
  481     Make a fake double Sersic galaxy using the galSim.Sersic function 
  483     Inputs: total flux of the galaxy, and a record array that stores the 
  484     necessary parameters [reffPix, nSersic, axisRatio, posAng] 
  486     Output: a 2-D image array of the galaxy model  OR 
  487             a GalSim object of the model 
  490         psfImage:     PSF image for convolution 
  491         trunc:        Flux of Sersic models will truncate at trunc * reffPix 
  492                       radius; trunc=0 means no truncation 
  493         drawMethod:   The method for drawImage: ['auto', 'fft', 'real_space'] 
  494         addPoisson:   Add Poisson noise 
  495         plotFake:     Generate a PNG figure of the model 
  496         devexp:       The first component will be seen as a nSersic=4 bulge; 
  497                       And, the second one will be seen as a nSersic=1 disk 
  498         returnObj:    If TRUE, will return the GSObj 
  502     flux1 = float(comp1[
'mag'])
 
  503     flux2 = float(comp2[
'mag'])
 
  510                                      trunc=trunc, addShear=addShear)
 
  512                                      trunc=trunc, addShear=addShear)
 
  520     doubleSersic = 
galSimAdd([serModel1, serModel2])
 
  523     if transform 
is not None:
 
  524         doubleSersic = doubleSersic.transform(*tuple(transform.ravel()))
 
  527     if psfImage 
is not None:
 
  531         dserFinal = galsim.Convolve([doubleSersic, psfObj])
 
  533         dserFinal = doubleSersic
 
  547                                addPoisson=addPoisson)
 
  551                      random=False, returnObj=True, plotFake=False,
 
  552                      drawMethod='auto', addPoisson=False, scale=1.0,
 
  560     realObj = galsim.RealGalaxy(real_galaxy_catalog, index=index,
 
  562     index = realObj.index
 
  565     realObj = realObj.withFlux(flux)
 
  568     if transform 
is not None:
 
  569         realObj = realObj.transform(*tuple(transform.ravel()))
 
  572     if psfImage 
is not None:
 
  576         realFinal = galsim.Convolve([realObj, psfObj])
 
  578         realFinal = realFinal
 
  589                                addPoisson=addPoisson)
 
  592 def testMakeFake(galList, asciiTab=False, single=True, double=True, real=True):
 
  593     """Test the makeFake functions.""" 
  595     psfGaussian = galsim.Gaussian(fwhm=2.0)
 
  596     psfImage = psfGaussian.drawImage().array
 
  601             galData = np.loadtxt(galList, dtype=[(
'ID', 
'int'),
 
  603                                                  (
'sersic_n', 
'float'),
 
  608             galData = fits.open(galList)[1].data
 
  610         for igal, gal 
in enumerate(galData):
 
  612             flux = 10.0 ** ((27.0 - gal[
'mag']) / 2.5)
 
  614             print(
'\n---------------------------------')
 
  615             print(
" Input Flux : ", flux)
 
  616             print(
" Input Parameters : ", gal[
"sersic_n"], gal[
"reff"])
 
  617             print(
"                    ", gal[
"b_a"], gal[
"theta"])
 
  620                                         plotFake=
True, returnObj=
False,
 
  621                                         trunc=12.0, drawMethod=
"no_pixel")
 
  623             print(
" Output Flux : ", np.sum(galArray))
 
  624             print(
" Shape of the Output Array : ", galArray.shape)
 
  625             print(
'---------------------------------')
 
  630             raise Exception(
"For now, only FITS input is allowed !!")
 
  632             galData = fits.open(galList)[1].data
 
  634         for igal, gal 
in enumerate(galData):
 
  636             flux = 10.0 ** ((27.0 - gal[
'mag']) / 2.5)
 
  638             print(
'\n---------------------------------')
 
  639             print(
" Input Flux : ", flux)
 
  652             print(
" Flux for Component 1 : ", comp1[
'mag'])
 
  653             print(
" Flux for Component 2 : ", comp2[
'mag'])
 
  654             print(
" Comp 1 Parameters : %5.2f  %8.2f" % (comp1[
"sersic_n"],
 
  656             print(
"                     %5.2f  %8.2f" % (comp1[
"b_a"],
 
  658             print(
" Comp 2 Parameters : %5.2f  %8.2f" % (comp2[
"sersic_n"],
 
  660             print(
"                     %5.2f  %8.2f" % (comp2[
"b_a"],
 
  665                                                  trunc=12, returnObj=
False,
 
  666                                                  devExp=
True, plotFake=
True,
 
  667                                                  drawMethod=
'no_pixel')
 
  669             print(
" Output Flux : ", np.sum(doubleArray))
 
  670             print(
" Shape of the Output Array : ", doubleArray.shape)
 
  671             print(
'---------------------------------')
 
  676         psfReal = galsim.Gaussian(fwhm=0.2)
 
  677         psfRealImage = psfReal.drawImage().array
 
  681             raise Exception(
"For now, only FITS input is allowed !!")
 
  683             galData = fits.open(galList)[1].data
 
  685         for igal, gal 
in enumerate(galData):
 
  695             flux = 10.0 ** ((27.0 - gal[
'mag']) / 2.5)
 
  699                                          psfImage=psfRealImage,
 
  703                                          drawMethod=
'no_pixel')
 
  705             print(
'\n---------------------------------')
 
  706             print(
" Input Flux : ", flux)
 
  708             print(
" Output Flux : ", np.sum(realArray))
 
  709             print(
" Shape of the Output Array : ", realArray.shape)
 
  710             print(
'---------------------------------')