23 """Mapper and cameraGeom definition for extremely simple mock data.
25 SimpleMapper inherits directly from Mapper, not CameraMapper. This means
26 we can avoid any problems with paf files at the expense of reimplementing
27 some parts of CameraMapper here. Jim is not sure this was the best
28 possible approach, but it gave him an opportunity to play around with
29 prototyping a future paf-free mapper class, and it does everything it
30 needs to do right now.
43 __all__ = (
"SimpleMapper",
"makeSimpleCamera",
"makeDataRepo")
47 """Base class of a hierarchy used by SimpleMapper to defined different kinds of types of objects
50 PersistenceType objects are never instantiated; only the type objects are used (we needed a
51 simple singleton struct that could be inherited, which is exactly what a Python type is).
61 """Method called by SimpleMapping to implement a map_ method."""
71 """Persistence type for things that don't actually use daf_persistence.
74 python =
"lsst.daf.base.PropertySet"
78 """Method called by SimpleMapping to implement a map_ method; overridden to not use the path."""
80 mapper=mapper, storage=storage)
84 """Persistence type of Exposure images.
87 python =
"lsst.afw.image.ExposureF"
89 storage =
"FitsStorage"
95 """Method called by SimpleMapping to implement a map_ method; overridden to support subimages."""
97 loc = super(ExposurePersistenceType, cls).
makeButlerLocation(path, dataId, mapper, suffix=
None,
105 "compression.algorithm":
"NONE",
106 "compression.columns": 0,
107 "compression.rows": 0,
108 "compression.quantizeLevel": 0.0,
109 "scaling.algorithm":
"NONE",
110 "scaling.bzero": 0.0,
111 "scaling.bscale": 0.0,
113 "scaling.quantizeLevel": 0.0,
114 "scaling.quantizePad": 0.0,
115 "scaling.fuzz":
False,
118 for prefix
in (
"image",
"mask",
"variance"):
119 for k, v
in options.items():
120 loc.additionalData.set(
"{}.{}".
format(prefix, k), v)
121 elif suffix ==
"_sub":
122 subId = dataId.copy()
123 bbox = subId.pop(
'bbox')
124 loc = super(ExposurePersistenceType, cls).
makeButlerLocation(path, subId, mapper, suffix=
None,
126 loc.additionalData.set(
'llcX', bbox.getMinX())
127 loc.additionalData.set(
'llcY', bbox.getMinY())
128 loc.additionalData.set(
'width', bbox.getWidth())
129 loc.additionalData.set(
'height', bbox.getHeight())
130 if 'imageOrigin' in dataId:
131 loc.additionalData.set(
'imageOrigin',
132 dataId[
'imageOrigin'])
137 python =
"lsst.skymap.BaseSkyMap"
138 storage =
"PickleStorage"
143 python =
"lsst.afw.table.BaseCatalog"
145 storage =
"FitsCatalogStorage"
150 python =
"lsst.afw.table.SimpleCatalog"
151 cpp =
"SimpleCatalog"
155 python =
"lsst.afw.table.SourceCatalog"
156 cpp =
"SourceCatalog"
160 python =
"lsst.afw.table.ExposureCatalog"
161 cpp =
"ExposureCatalog"
165 python =
"lsst.afw.detection.PeakCatalog"
170 """Mapping object used to implement SimpleMapper, similar in intent to lsst.daf.peristence.Mapping.
176 def __init__(self, persistence, template=None, keys=None):
178 if template
is not None:
183 def map(self, dataset, root, dataId, mapper, suffix=None, storage=None):
188 return self.
persistence.makeButlerLocation(path, dataId, suffix=suffix, mapper=mapper,
193 """Mapping for dataset types that are organized the same way as raw data (i.e. by CCD)."""
195 template =
"{dataset}-{visit:04d}-{ccd:01d}{ext}"
196 keys = dict(visit=int, ccd=int)
198 def query(self, dataset, index, level, format, dataId):
199 dictList = index[dataset][level]
200 results = [
list(d.values())
for d
in dictList[dataId.get(level,
None)]]
205 """Mapping for dataset types that are organized according to a SkyMap subdivision of the sky."""
207 template =
"{dataset}-{filter}-{tract:02d}-{patch}{ext}"
208 keys = dict(filter=str, tract=int, patch=str)
212 """Mapping for CoaddTempExp datasets."""
214 template =
"{dataset}-{tract:02d}-{patch}-{visit:04d}{ext}"
215 keys = dict(tract=int, patch=str, visit=int)
219 """Mapping for forced_src datasets."""
221 template =
"{dataset}-{tract:02d}-{visit:04d}-{ccd:01d}{ext}"
222 keys = dict(tract=int, ccd=int, visit=int)
226 """Metaclass for SimpleMapper that creates map_ and query_ methods for everything found in the
227 'mappings' class variable.
231 def _makeMapClosure(dataset, mapping, suffix=None):
232 def mapClosure(self, dataId, write=False):
233 return mapping.map(dataset, self.root, dataId, self, suffix=suffix, storage=self.storage)
237 def _makeQueryClosure(dataset, mapping):
238 def queryClosure(self, level, format, dataId):
239 return mapping.query(dataset, self.index, level, format, dataId)
243 type.__init__(cls, name, bases, dict_)
245 for dataset, mapping
in cls.mappings.
items():
246 setattr(cls,
"map_" + dataset, MapperMeta._makeMapClosure(dataset, mapping, suffix=
None))
247 for suffix
in mapping.persistence.suffixes:
248 setattr(cls,
"map_" + dataset + suffix,
249 MapperMeta._makeMapClosure(dataset, mapping, suffix=suffix))
250 if hasattr(mapping,
"query"):
251 setattr(cls,
"query_" + dataset, MapperMeta._makeQueryClosure(dataset, mapping))
252 cls.
keyDict.update(mapping.keys)
257 An extremely simple mapper for an imaginary camera for use in integration tests.
259 As SimpleMapper does not inherit from obs.base.CameraMapper, it does not
260 use a policy file to set mappings or a registry; all the information is here
261 (in the map_* and query_* methods).
263 The imaginary camera's raw data format has only 'visit' and 'ccd' keys, with
264 two CCDs per visit (by default).
270 forced_src_schema=
SimpleMapping(SourceCatalogPersistenceType,
271 template=
"{dataset}{ext}", keys={}),
272 truth=
SimpleMapping(SimpleCatalogPersistenceType, template=
"{dataset}-{tract:02d}{ext}",
273 keys={
"tract": int}),
274 simsrc=
RawMapping(SimpleCatalogPersistenceType, template=
"{dataset}-{tract:02d}{ext}",
275 keys={
"tract": int}),
276 observations=
SimpleMapping(ExposureCatalogPersistenceType, template=
"{dataset}-{tract:02d}{ext}",
277 keys={
"tract": int}),
278 ccdExposureId=
RawMapping(BypassPersistenceType),
280 deepCoaddId=
SkyMapping(BypassPersistenceType),
282 deepMergedCoaddId=
SkyMapping(BypassPersistenceType),
284 deepCoadd_skyMap=
SimpleMapping(SkyMapPersistenceType, template=
"{dataset}{ext}", keys={}),
285 deepCoadd=
SkyMapping(ExposurePersistenceType),
286 deepCoaddPsfMatched=
SkyMapping(ExposurePersistenceType),
287 deepCoadd_calexp=
SkyMapping(ExposurePersistenceType),
288 deepCoadd_calexp_background=
SkyMapping(CatalogPersistenceType),
289 deepCoadd_icSrc=
SkyMapping(SourceCatalogPersistenceType),
290 deepCoadd_icSrc_schema=
SimpleMapping(SourceCatalogPersistenceType,
291 template=
"{dataset}{ext}", keys={}),
292 deepCoadd_src=
SkyMapping(SourceCatalogPersistenceType),
293 deepCoadd_src_schema=
SimpleMapping(SourceCatalogPersistenceType,
294 template=
"{dataset}{ext}", keys={}),
295 deepCoadd_peak_schema=
SimpleMapping(PeakCatalogPersistenceType,
296 template=
"{dataset}{ext}", keys={}),
297 deepCoadd_ref=
SkyMapping(SourceCatalogPersistenceType),
298 deepCoadd_ref_schema=
SimpleMapping(SourceCatalogPersistenceType,
299 template=
"{dataset}{ext}", keys={}),
300 deepCoadd_det=
SkyMapping(SourceCatalogPersistenceType),
301 deepCoadd_det_schema=
SimpleMapping(SourceCatalogPersistenceType,
302 template=
"{dataset}{ext}", keys={}),
303 deepCoadd_mergeDet=
SkyMapping(SourceCatalogPersistenceType),
304 deepCoadd_mergeDet_schema=
SimpleMapping(SourceCatalogPersistenceType,
305 template=
"{dataset}{ext}", keys={}),
306 deepCoadd_deblendedFlux=
SkyMapping(SourceCatalogPersistenceType),
307 deepCoadd_deblendedFlux_schema=
SimpleMapping(SourceCatalogPersistenceType,
308 template=
"{dataset}{ext}", keys={}),
309 deepCoadd_deblendedModel=
SkyMapping(SourceCatalogPersistenceType),
310 deepCoadd_deblendedModel_schema=
SimpleMapping(SourceCatalogPersistenceType,
311 template=
"{dataset}{ext}", keys={}),
312 deepCoadd_meas=
SkyMapping(SourceCatalogPersistenceType),
313 deepCoadd_meas_schema=
SimpleMapping(SourceCatalogPersistenceType,
314 template=
"{dataset}{ext}", keys={}),
315 deepCoadd_forced_src=
SkyMapping(SourceCatalogPersistenceType),
316 deepCoadd_forced_src_schema=
SimpleMapping(SourceCatalogPersistenceType,
317 template=
"{dataset}{ext}", keys={}),
318 deepCoadd_mock=
SkyMapping(ExposurePersistenceType),
319 deepCoaddPsfMatched_mock=
SkyMapping(ExposurePersistenceType),
321 deepCoadd_directWarp_mock=
TempExpMapping(ExposurePersistenceType),
323 deepCoadd_psfMatchedWarp_mock=
TempExpMapping(ExposurePersistenceType),
332 self.
storage = lsst.daf.persistence.Storage.makeFromURI(root)
333 super(SimpleMapper, self).
__init__(**kwargs)
336 afwImageUtils.defineFilter(
'r', 619.42)
343 if datasetType
is None:
346 keyDict = self.
mappings[datasetType].keys
347 if level
is not None and level
in self.
levels:
348 keyDict = dict(keyDict)
349 for l
in self.
levels[level]:
355 filenames = os.listdir(self.
root)
356 rawRegex = re.compile(
r"(?P<dataset>\w+)-(?P<visit>\d+)-(?P<ccd>\d).*")
358 for filename
in filenames:
359 m = rawRegex.match(filename)
362 index = self.
index.setdefault(m.group(
'dataset'), dict(ccd={
None: []}, visit={
None: []}))
363 visit = int(m.group(
'visit'))
364 ccd = int(m.group(
'ccd'))
365 d1 = dict(visit=visit, ccd=ccd)
366 d2 = dict(visit=visit)
367 index[
'ccd'].setdefault(visit, []).
append(d1)
368 index[
'ccd'][
None].
append(d1)
369 index[
'visit'][visit] = [d2]
370 index[
'visit'][
None].
append(d1)
380 "lsst.afw.cameraGeom.Camera",
"Camera",
None, [], dataId, mapper=self, storage=self.
storage
384 detectorId = dataId[
"ccd"]
385 detector = self.
camera[detectorId]
386 item.setDetector(detector)
390 def _computeCcdExposureId(self, dataId):
391 return int(dataId[
"visit"]) * 10 + int(dataId[
"ccd"])
393 def _computeCoaddId(self, dataId):
396 tract = int(dataId[
'tract'])
397 if tract < 0
or tract >= 128:
398 raise RuntimeError(
'tract not in range [0,128)')
399 patchX, patchY = (int(c)
for c
in dataId[
'patch'].split(
','))
400 for p
in (patchX, patchY):
401 if p < 0
or p >= 2**13:
402 raise RuntimeError(
'patch component not in range [0, 8192)')
403 return (tract * 2**13 + patchX) * 2**13 + patchY
407 return dict(visit=(int(ccdExposureId) // 10), ccd=(int(ccdExposureId) % 10))
419 return 1 + 7 + 13*2 + 3
425 return 1 + 7 + 13*2 + 3
434 radialDistortion=0.925,
438 @param[in] nx: number of detectors in x
439 @param[in] ny: number of detectors in y
440 @param[in] sizeX: detector size in x (pixels)
441 @param[in] sizeY: detector size in y (pixels)
442 @param[in] gapX: gap between detectors in x (mm)
443 @param[in] gapY: gap between detectors in y (mm)
444 @param[in] pixelSize: pixel size (mm) (a float)
445 @param[in] plateScale: plate scale in arcsec/mm; 20.0 is for LSST
446 @param[in] radialDistortion: radial distortion, in mm/rad^2
447 (the r^3 coefficient of the radial distortion polynomial
448 that converts FIELD_ANGLE in radians to FOCAL_PLANE in mm);
449 0.925 is the value Dave Monet measured for lsstSim data
451 Each detector will have one amplifier (with no raw information).
454 radialDistortCoeffs = [0.0, 1.0/pScaleRad, 0.0, radialDistortion/pScaleRad]
463 cY = (iY - 0.5 * (nY - 1)) * (pixelSize * sizeY + gapY)
465 cX = (iX - 0.5 * (nX - 1)) * (pixelSize * sizeY + gapX)
467 detectorName =
"detector %d,%d" % (iX, iY)
469 detectorBuilder = cameraBuilder.add(detectorName, detectorId)
470 detectorBuilder.setSerial(detectorName +
" serial")
471 detectorBuilder.setBBox(ccdBBox)
477 ampBuilder.setName(ampName)
478 ampBuilder.setBBox(ccdBBox)
479 ampBuilder.setGain(1.0)
480 ampBuilder.setReadNoise(5.0)
482 detectorBuilder.append(ampBuilder)
486 cameraBuilder.setTransformFromFocalPlaneTo(lsst.afw.cameraGeom.FIELD_ANGLE, focalPlaneToFieldAngle)
487 return cameraBuilder.finish()
492 Create a data repository for SimpleMapper and return a butler for it.
494 Clobbers anything already in the given path.
496 if os.path.exists(root):
499 with open(os.path.join(root,
"_mapper"),
"w")
as f:
500 f.write(
"lsst.pipe.tasks.mocks.SimpleMapper\n")