22 """Functions to help create jointcal tests by generating fake data."""
24 __all__ = [
'createFakeCatalog',
'createTwoFakeCcdImages',
'getMeasuredStarsFromCatalog']
36 import lsst.jointcal.star
40 """Returns True if the necessary packages and files are available.
42 We need ``obs_cfht`` to load the test/data/cfht_minimal dataset, which
43 includes the metadata that is used to build the fake catalogs.
53 photoCalibMean1=1e-2, photoCalibMean2=1.2e-2,
54 fakeWcses=(
None,
None),
55 fakeVisitInfos=(
None,
None)):
56 """Return two fake ccdImages built on CFHT Megacam metadata.
58 If ``num1 == num2``, the catalogs will align on-sky so each source will
59 have a match in the other catalog.
61 This uses the butler dataset stored in `tests/data/cfht_minimal` to
62 bootstrap the metadata.
66 num1, num2 : `int`, optional
67 Number of sources to put in the first and second catalogs. Should be
68 a square, to have sqrt(num) centroids on a grid.
69 seed : `int`, optional
70 Seed value for np.random.
71 fakeCcdId : `int`, optional
72 Sensor identifier to use for both CcdImages. The wcs, bbox, photoCalib, etc.
73 will still be drawn from the CFHT ccd=12 files, as that is the only
74 testdata that is included in this simple test dataset.
75 photoCalibMean1, photoCalibMean2: `float`, optional
76 The mean photometric calibration to pass to each ccdImage construction.
77 Note: this value is 1/instFluxMag0, so it should be less than 1.
78 fakeWcses : `list` [`lsst.afw.geom.SkyWcs`], optional
79 The SkyWcses to use instead of the ones read from disk.
80 fakeWcses : `list` [`lsst.afw.image.VisitInfo`], optional
81 The VisitInfos to use instead of the ones read from disk.
85 struct : `lsst.pipe.base.Struct`
86 Result struct with components:
88 - `camera` : Camera representing these catalogs
89 (`lsst.afw.cameraGeom.Camera`).
90 - `catalogs` : Catalogs containing fake sources
91 (`list` of `lsst.afw.table.SourceCatalog`).
92 - `ccdImageList` : CcdImages containing the metadata and fake sources
93 (`list` of `lsst.jointcal.CcdImage`).
94 - `bbox` : Bounding Box of the image (`lsst.geom.Box2I`).
95 - 'fluxFieldName' : name of the instFlux field in the catalogs ('str').
98 msg =
"Necessary packages not available to run tests that use the cfht_minimal dataset."
99 raise unittest.SkipTest(msg)
105 fluxFieldName =
"SomeFlux"
109 inputDir = os.path.join(dataDir,
'tests/data/cfht_minimal')
113 camera = butler.get(
'camera', visit=visit1)
116 photoCalibMean=photoCalibMean1, photoCalibErr=1.0, fakeCcdId=fakeCcdId,
117 fakeWcs=fakeWcses[0], fakeVisitInfo=fakeVisitInfos[0])
119 photoCalibMean=photoCalibMean2, photoCalibErr=5.0, fakeCcdId=fakeCcdId,
120 fakeWcs=fakeWcses[1], fakeVisitInfo=fakeVisitInfos[1])
123 catalogs=[struct1.catalog, struct2.catalog],
124 ccdImageList=[struct1.ccdImage, struct2.ccdImage],
126 skyWcs=[struct1.skyWcs, struct2.skyWcs],
127 fluxFieldName=fluxFieldName)
131 photoCalibMean=1e-2, photoCalibErr=1.0, fakeCcdId=12,
132 fakeWcs=None, fakeVisitInfo=None):
133 """Create a fake CcdImage by making a fake catalog.
137 butler : `lsst.daf.persistence.Butler`
138 Butler to load metadata from.
140 Visit identifier to build a butler dataId.
142 Number of sources to put in the catalogs. Should be
143 a square, to have sqrt(num) centroids on a grid.
144 fluxFieldName : `str`
145 Name of the flux field to populate in the catalog, without `_instFlux`
146 (e.g. "slot_CalibFlux").
147 photoCalibMean : `float`, optional
148 Value to set for calibrationMean in the created PhotoCalib.
149 Note: this value is 1/instFluxMag0, so it should be less than 1.
150 photoCalibErr : `float`, optional
151 Value to set for calibrationErr in the created PhotoCalib.
152 fakeCcdId : `int`, optional
153 Use this as the ccdId in the returned CcdImage.
154 fakeWcs : `lsst.afw.geom.SkyWcs`, optional
155 A SkyWcs to use instead of one read from disk.
156 fakeVisitInfo : `lsst.afw.image.VisitInfo`, optional
157 A VisitInfo to use instead of one read from disk.
161 struct : `lsst.pipe.base.Struct`
162 Result struct with components:
164 - `catalog` : Catalogs containing fake sources
165 (`lsst.afw.table.SourceCatalog`).
166 - `ccdImage` : CcdImage containing the metadata and fake sources
167 (`lsst.jointcal.CcdImage`).
168 - `bbox` : Bounding Box of the image (`lsst.geom.Box2I`).
169 - `skyWcs` : SkyWcs of the image (`lsst.afw.geom.SkyWcs`).
173 dataId = dict(visit=visit, ccd=ccdId)
174 skyWcs = fakeWcs
if fakeWcs
is not None else butler.get(
'calexp_wcs', dataId=dataId)
175 visitInfo = fakeVisitInfo
if fakeVisitInfo
is not None else butler.get(
'calexp_visitInfo', dataId=dataId)
176 bbox = butler.get(
'calexp_bbox', dataId=dataId)
177 detector = butler.get(
'calexp_detector', dataId=dataId)
178 filt = butler.get(
"calexp_filter", dataId=dataId).getName()
182 ccdImage = lsst.jointcal.ccdImage.CcdImage(catalog, skyWcs, visitInfo, bbox, filt, photoCalib,
183 detector, visit, fakeCcdId, fluxFieldName)
189 """Return a fake minimally-useful catalog for jointcal.
194 Number of sources to put in the catalogs. Should be
195 a square, to have sqrt(num) centroids on a grid.
196 bbox : `lsst.geom.Box2I`
197 Bounding Box of the detector to populate.
198 fluxFieldName : `str`
199 Name of the flux field to populate in the catalog, without `_instFlux`
200 (e.g. "slot_CalibFlux").
201 skyWcs : `lsst.afw.geom.SkyWcs` or None, optional
202 If supplied, use this to fill in coordinates from centroids.
203 refCat : `bool`, optional
204 Return a ``SimpleCatalog`` so that it behaves like a reference catalog?
208 catalog : `lsst.afw.table.SourceCatalog`
209 A populated source catalog.
213 centroidKey = lsst.afw.table.Point2DKey.addFields(schema,
"centroid",
"centroid",
"pixels")
214 xErrKey = schema.addField(
"centroid_xErr", type=
"F")
215 yErrKey = schema.addField(
"centroid_yErr", type=
"F")
218 lsst.afw.table.CoordinateType.PIXEL)
220 schema.addField(fluxFieldName+
"_instFlux", type=
"D", doc=
"post-ISR instFlux")
221 schema.addField(fluxFieldName+
"_instFluxErr", type=
"D", doc=
"post-ISR instFlux stddev")
222 schema.addField(fluxFieldName+
"_flux", type=
"D", doc=
"source flux (nJy)")
223 schema.addField(fluxFieldName+
"_fluxErr", type=
"D", doc=
"flux stddev (nJy)")
224 schema.addField(fluxFieldName+
"_mag", type=
"D", doc=
"magnitude")
225 schema.addField(fluxFieldName+
"_magErr", type=
"D", doc=
"magnitude stddev")
227 centroidKey, xErrKey, yErrKey, shapeKey, fluxFieldName,
228 skyWcs=skyWcs, refCat=refCat)
232 centroidKey, xErrKey, yErrKey, shapeKey, fluxFieldName,
233 skyWcs=None, fluxErrFraction=0.05, refCat=False):
234 """Return a catalog populated with fake, but reasonable, sources.
236 Centroids are placed on a uniform grid, errors are normally distributed.
240 schema : `lsst.afw.table.Schema`
241 Pre-built schema to make the catalog from.
243 Number of sources to put in the catalog.
244 bbox : `lsst.geom.Box2I`
245 Bounding box of the ccd to put sources in.
246 centroidKey : `lsst.afw.table.Key`
247 Key for the centroid field to populate.
248 xErrKey : `lsst.afw.table.Key`
249 Key for the xErr field to populate.
250 yErrKey : `lsst.afw.table.Key`
251 Key for the yErr field to populate.
252 shapeKey : `lsst.afw.table.Key`
253 Key for the shape field to populate.
254 fluxFieldName : `str`
255 Name of the flux field to populate in the catalog, without `_instFlux`
256 (e.g. "slot_CalibFlux").
257 skyWcs : `lsst.afw.geom.SkyWcs` or None, optional
258 If supplied, use this to fill in coordinates from centroids.
259 fluxErrFraction : `float`, optional
260 Fraction of instFlux to use for the instFluxErr.
261 refCat : `bool`, optional
262 Return a ``SimpleCatalog`` so that it behaves like a reference catalog?
266 catalog : `lsst.afw.table.SourceCatalog`
270 table.defineCentroid(
'centroid')
271 table.defineShape(
'shape')
272 table.defineCalibFlux(fluxFieldName)
278 instFlux = np.random.random(num)*10000
279 instFluxErr = np.abs(instFlux * np.random.normal(fluxErrFraction, scale=0.1, size=num))
280 xx = np.linspace(bbox.getMinX(), bbox.getMaxX(), int(np.sqrt(num)))
281 yy = np.linspace(bbox.getMinY(), bbox.getMaxY(), int(np.sqrt(num)))
282 xv, yv = np.meshgrid(xx, yy)
283 vx = np.random.normal(scale=0.1, size=num)
284 vy = np.random.normal(scale=0.1, size=num)
291 for i, (x, y)
in enumerate(zip(xv.ravel(), yv.ravel())):
292 record = catalog.addNew()
297 if skyWcs
is not None:
300 catalog[xErrKey] = vx
301 catalog[yErrKey] = vy
302 catalog[fluxFieldName +
'_instFlux'] = instFlux
303 catalog[fluxFieldName +
'_instFluxErr'] = instFluxErr
309 """Return a list of measuredStars built from a catalog.
313 catalog : `lsst.afw.table.SourceCatalog`
314 The table to get sources from.
315 pixToFocal : `lsst.afw.geom.TransformPoint2ToPoint2`
316 Transform that goes from pixel to focal plane coordinates, to set the
317 MeasuredStar x/y focal points.
321 stars : `list` of `lsst.jointcal.MeasuredStar`
322 MeasuredStars built from the catalog sources.
325 for record
in catalog:
326 star = lsst.jointcal.star.MeasuredStar()
327 star.x = record.getX()
328 star.y = record.getY()
329 star.setInstFluxAndErr(record.getCalibInstFlux(), record.getCalibInstFluxErr())
332 pointFocal = pixToFocal.applyForward(point)
333 star.setXFocal(pointFocal.getX())
334 star.setYFocal(pointFocal.getY())