lsst.synpipe  15.0-3-g11fe1a0
positionGalSimFakes.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # encoding: utf-8
3 
4 from __future__ import print_function
5 from __future__ import absolute_import
6 from builtins import str
7 import os
8 import fcntl
9 
10 import numpy as np
11 import pyfits as fits
12 
13 import lsst.afw.image
14 import lsst.afw.geom
15 import lsst.afw.math
17 import lsst.pex.config as lsstConfig
18 
19 from lsst.pipe.tasks.fakes import BaseFakeSourcesConfig, BaseFakeSourcesTask
20 
21 from . import FakeSourceLib as fsl
22 from . import makeFakeGalaxy as makeFake
23 
24 
25 class PositionGalSimFakesConfig(BaseFakeSourcesConfig):
26  galList = lsstConfig.Field(dtype=str,
27  doc="catalog of galaxies to add")
28  maxMargin = lsstConfig.Field(dtype=int, default=600,
29  optional=True,
30  doc="Size of margin")
31  seed = lsstConfig.Field(dtype=int, default=1,
32  doc="Seed for random number generator")
33  addShear = lsstConfig.Field(dtype=bool, default=False,
34  doc='include shear in the galaxies')
35  addMask = lsstConfig.Field(dtype=bool, default=False,
36  doc='add FAKE mask plane')
37  sersic_prec = lsstConfig.Field(dtype=float, default=0.0,
38  doc='The desired precision for n')
39  cosStr = 'Use Galsim.COSMOSlog()'
40  serStr = 'Single sersic galaxies added'
41  dSerStr = 'Double sersic galaxies added'
42  realStr = 'Real HST galaxy images added'
43  galType = lsstConfig.ChoiceField(dtype=str, default='sersic',
44  allowed={'dsersic': dSerStr,
45  'sersic': serStr,
46  'real': realStr,
47  'cosmos': cosStr},
48  doc='type of GalSim galaxies to add')
49  exclusionLevel = lsstConfig.ChoiceField(dtype=str, default='none',
50  allowed={'none': "None",
51  'marginal': "Marginal",
52  'bad_stamp': "Bad Stamp",
53  'bad_fits': "Bad Fits"},
54  doc='Exclusion level')
55 
56 
57 class PositionGalSimFakesTask(BaseFakeSourcesTask):
58  ConfigClass = PositionGalSimFakesConfig
59 
60  def __init__(self, **kwargs):
61  BaseFakeSourcesTask.__init__(self, **kwargs)
62  print("RNG seed:", self.config.seed)
63  self.rng = lsst.afw.math.Random(seed=self.config.seed)
64  self.npRand = np.random.RandomState(self.config.seed)
65  self.galData = fits.open(self.config.galList)[1].data
66 
67  def run(self, exposure, background):
68  self.log.info("Adding fake galaxies at real positions")
69  PARENT = lsst.afw.image.PARENT
70  psf = exposure.getPsf()
71  md = exposure.getMetadata()
72  calib = exposure.getCalib()
73  expBBox = exposure.getBBox(PARENT)
74  wcs = exposure.getWcs()
75 
76  """Deal with the skipped ones."""
77  skipLog = 'runAddFake.skipped'
78  if not os.path.isfile(skipLog):
79  os.system('touch ' + skipLog)
80 
81  if self.config.galType is 'cosmos':
82  import galsim
83  exLevel = self.config.exclusionLevel
84  cosmosCat = galsim.COSMOSCatalog(exclusion_level=exLevel)
85  else:
86  cosmosCat = None
87 
88  for igal, gal in enumerate(self.galData):
89  try:
90  galident = gal["ID"]
91  except KeyError:
92  galident = igal + 1
93 
94  try:
95  flux = calib.getFlux(float(gal['mag']))
96  except KeyError:
97  raise KeyError("No mag column in %s" % self.config.galList)
98 
99  try:
100  galCoord = lsst.afw.geom.SpherePoint(gal['RA'], gal['DEC'], lsst.afw.geom.degrees)
101  except KeyError:
102  raise KeyError("No RA/DEC column in {} table".format(self.config.galList))
103 
104  skyToPixelMatrix = wcs.linearizeSkyToPixel(galCoord, lsst.afw.geom.degrees)
105  skyToPixelMatrix = skyToPixelMatrix.getLinear().getParameterVector() / 3600.0
106 
107  galXY = wcs.skyToPixel(galCoord)
108  bboxI = exposure.getBBox(PARENT)
109  bboxI.grow(self.config.maxMargin)
110  if not bboxI.contains(lsst.afw.geom.Point2I(galXY)):
111  # Will just skip this object
112  continue
113 
114  # Check the magnitude
115  if gal['mag'] <= 0:
116  self.log.info("Mag <= 0: Skipping %d" % galident)
117  self.log.info(" mag: %7.3d" % gal['mag'])
118  with open(skipLog, "a") as slog:
119  try:
120  fcntl.flock(slog, fcntl.LOCK_EX)
121  slog.write("%8d , negMag\n" % galident)
122  fcntl.flock(slog, fcntl.LOCK_UN)
123  except IOError:
124  continue
125  continue
126 
127  # This is extrapolating for the PSF, probably not a good idea
128  # Return an Image of the PSF, in a form suitable for convolution.
129  # The returned image is normalized to sum to unity.
130  try:
131  psfImage = psf.computeKernelImage(galXY)
132  except:
133  # There may not be any data at this point, and the object
134  # should be skipped
135  continue
136  try:
137  addShear = self.config.addShear
138  prec = self.config.sersic_prec
139  galType = self.config.galType
140  if self.config.galType is not 'cosmos':
141  galArray = makeFake.makeGalaxy(flux, gal,
142  psfImage.getArray(),
143  galType=galType,
144  cosmosCat=None,
145  calib=None,
146  addShear=addShear,
147  transform=skyToPixelMatrix)
148  else:
149  galArray = makeFake.makeGalaxy(flux, gal,
150  psfImage.getArray(),
151  cosmosCat=cosmosCat,
152  calib=calib,
153  galType=galType,
154  addShear=addShear,
155  sersic_prec=prec,
156  transform=skyToPixelMatrix)
157  except IndexError as ierr:
158  self.log.info("GalSim Index Error: Skipping %d" % galident)
159  self.log.info(ierr.message)
160  with open(skipLog, "a") as slog:
161  try:
162  fcntl.flock(slog, fcntl.LOCK_EX)
163  slog.write("%8d , galsimI\n" % galident)
164  fcntl.flock(slog, fcntl.LOCK_UN)
165  except IOError:
166  continue
167  continue
168  except KeyError as kerr:
169  self.log.info("GalSim Key Error: Skipping %d" % galident)
170  self.log.info(kerr.message)
171  with open(skipLog, "a") as slog:
172  try:
173  fcntl.flock(slog, fcntl.LOCK_EX)
174  slog.write("%8d , galsimK\n" % galident)
175  fcntl.flock(slog, fcntl.LOCK_UN)
176  except IOError:
177  continue
178  continue
179  except ValueError as verr:
180  self.log.info("GalSim Value Error: Skipping %d" % galident)
181  self.log.info(verr.message)
182  with open(skipLog, "a") as slog:
183  try:
184  fcntl.flock(slog, fcntl.LOCK_EX)
185  slog.write("%8d , galsimV\n" % galident)
186  fcntl.flock(slog, fcntl.LOCK_UN)
187  except IOError:
188  continue
189  continue
190  except RuntimeError as rerr:
191  self.log.info("GalSim Runtime Error: Skipping %d" % galident)
192  self.log.info(rerr.message)
193  with open(skipLog, "a") as slog:
194  try:
195  fcntl.flock(slog, fcntl.LOCK_EX)
196  slog.write("%8d , galsimR\n" % galident)
197  fcntl.flock(slog, fcntl.LOCK_UN)
198  except IOError:
199  continue
200  continue
201  except Exception as uerr:
202  self.log.info("Unexpected Error: Skipping %d" % galident)
203  self.log.info(uerr.message)
204  with open(skipLog, "a") as slog:
205  try:
206  fcntl.flock(slog, fcntl.LOCK_EX)
207  slog.write("%8d , Unexpected\n" % galident)
208  fcntl.flock(slog, fcntl.LOCK_UN)
209  except IOError:
210  continue
211  continue
212 
213  galImage = lsst.afw.image.ImageF(galArray.astype(np.float32))
214  galBBox = galImage.getBBox(PARENT)
215  galX0 = (galXY.getX() - galBBox.getWidth()/2.0 + 0.5)
216  galY0 = (galXY.getY() - galBBox.getHeight()/2.0 + 0.5)
217  galImage = lsst.afw.math.offsetImage(galImage,
218  galX0, galY0,
219  'lanczos3')
220  galBBox = galImage.getBBox(PARENT)
221 
222  # Check that we're within the larger exposure, otherwise crop
223  parentBox = galImage.getBBox(PARENT)
224  if expBBox.contains(parentBox) is False:
225  newBBox = galImage.getBBox(PARENT)
226  newBBox.clip(expBBox)
227  if newBBox.getArea() <= 0:
228  self.log.info("BBoxEdge Error: Skipping %d" % galident)
229  with open(skipLog, "a") as slog:
230  try:
231  fcntl.flock(slog, fcntl.LOCK_EX)
232  slog.write("%8d , bboxEdge\n" % galident)
233  fcntl.flock(slog, fcntl.LOCK_UN)
234  except IOError:
235  continue
236  continue
237  self.log.info("Cropping FAKE%d from %s to %s" % (galident,
238  str(galBBox), str(newBBox)))
239  galImage = galImage.Factory(galImage, newBBox,
240  PARENT)
241  galBBox = newBBox
242 
243  galMaskedImage = lsst.afw.image.MaskedImageF(galImage)
244 
245  # Put information of the added fake galaxies into the header
246  md.set("FAKE%s" % str(galident), "%.3f, %.3f" % (galXY.getX(),
247  galXY.getY()))
248  self.log.info("Adding fake %s at: %.1f,%.1f" % (str(galident),
249  galXY.getX(),
250  galXY.getY()))
251 
252  galMaskedImage.getMask().set(self.bitmask)
253  if not self.config.addMask:
254  try:
255  galMaskedImage.getMask().removeAndClearMaskPlane('FAKE',
256  True)
257  except Exception:
258  pass
259  try:
260  galMaskedImage.getMask().removeAndClearMaskPlane('CROSSTALK',
261  True)
262  except Exception:
263  pass
264  try:
265  galMaskedImage.getMask().removeAndClearMaskPlane('UNMASKEDNAN',
266  True)
267  except Exception:
268  pass
269 
270  maskedImage = exposure.getMaskedImage()
271  try:
272  maskedImage.getMask().removeAndClearMaskPlane('CROSSTALK',
273  True)
274  except Exception:
275  pass
276  try:
277  maskedImage.getMask().removeAndClearMaskPlane('UNMASKEDNAN',
278  True)
279  except Exception:
280  pass
281  if not self.config.addMask:
282  try:
283  maskedImage.getMask().removeAndClearMaskPlane('FAKE', True)
284  except Exception:
285  pass
286 
287  BBox = galMaskedImage.getBBox(PARENT)
288  subMaskedImage = maskedImage.Factory(exposure.getMaskedImage(),
289  BBox,
290  PARENT)
291  subMaskedImage += galMaskedImage
292 
293  """
294  #
295  galMaskedImage.getMask().set(self.bitmask)
296 
297  maskedImage = exposure.getMaskedImage()
298  try:
299  maskedImage.getMask().removeAndClearMaskPlane('CROSSTALK',
300  True)
301  except Exception:
302  pass
303  try:
304  maskedImage.getMask().removeAndClearMaskPlane('UNMASKEDNAN',
305  True)
306  except Exception:
307  pass
308  try:
309  maskedImage.getMask().removeAndClearMaskPlane('FAKE', True)
310  except Exception:
311  pass
312  """
std::shared_ptr< ImageT > offsetImage(ImageT const &image, float dx, float dy, std::string const &algorithmName="lanczos5", unsigned int buffer=0)