23"""Mapper and cameraGeom definition for extremely simple mock data.
25SimpleMapper inherits directly from Mapper, not CameraMapper. This means
26we can avoid any problems with paf files at the expense of reimplementing
27some parts of CameraMapper here. Jim
is not sure this was the best
28possible approach, but it gave him an opportunity to play around
with
29prototyping a future paf-free mapper
class,
and it does everything it
37import lsst.daf.persistence
38import lsst.afw.cameraGeom
40import lsst.afw.image as afwImage
41from lsst.daf.base import PropertySet
43__all__ = ("SimpleMapper", "makeSimpleCamera", "makeDataRepo")
46# None of the values aside from the "NONE"s matter, but
47# writing explicit meaningless values for all of them to appease
48# afw is the price we pay for trying to write a non-CameraMapper
49# Mapper. It'll all get better with Gen3 (TM).
50# Cache the values in a PropertySet since this code is called thousands
52_write_options = PropertySet.from_mapping({
53 "compression.algorithm":
"NONE",
54 "compression.columns": 0,
55 "compression.rows": 0,
56 "compression.quantizeLevel": 0.0,
57 "scaling.algorithm":
"NONE",
59 "scaling.bscale": 0.0,
61 "scaling.quantizeLevel": 0.0,
62 "scaling.quantizePad": 0.0,
63 "scaling.fuzz":
False,
69 """Base class of a hierarchy used by SimpleMapper to defined different kinds of types of objects
72 PersistenceType objects are never instantiated; only the type objects are used (we needed a
73 simple singleton struct that could be inherited, which is exactly what a Python type
is).
83 """Method called by SimpleMapping to implement a map_ method."""
84 return lsst.daf.persistence.ButlerLocation(cls.
pythonpython, cls.
cppcpp, cls.
storagestorage, [path], dataId,
93 """Persistence type for things that don't actually use daf_persistence.
96 python = "lsst.daf.base.PropertySet"
100 """Method called by SimpleMapping to implement a map_ method; overridden to not use the path."""
101 return lsst.daf.persistence.ButlerLocation(cls.
pythonpythonpython, cls.
cppcpp, cls.
storagestorage, [], dataId,
102 mapper=mapper, storage=storage)
106 """Persistence type of Exposure images.
109 python = "lsst.afw.image.ExposureF"
111 storage =
"FitsStorage"
117 """Method called by SimpleMapping to implement a map_ method; overridden to support subimages."""
119 loc = super(ExposurePersistenceType, cls).
makeButlerLocation(path, dataId, mapper, suffix=
None,
123 for prefix
in (
"image",
"mask",
"variance"):
124 loc.additionalData.setPropertySet(prefix, _write_options)
125 elif suffix ==
"_sub":
126 subId = dataId.copy()
127 bbox = subId.pop(
'bbox')
128 loc = super(ExposurePersistenceType, cls).
makeButlerLocation(path, subId, mapper, suffix=
None,
130 loc.additionalData.set(
'llcX', bbox.getMinX())
131 loc.additionalData.set(
'llcY', bbox.getMinY())
132 loc.additionalData.set(
'width', bbox.getWidth())
133 loc.additionalData.set(
'height', bbox.getHeight())
134 if 'imageOrigin' in dataId:
135 loc.additionalData.set(
'imageOrigin',
136 dataId[
'imageOrigin'])
141 python =
"lsst.skymap.BaseSkyMap"
142 storage =
"PickleStorage"
147 python =
"lsst.afw.table.BaseCatalog"
149 storage =
"FitsCatalogStorage"
154 python =
"lsst.afw.table.SimpleCatalog"
155 cpp =
"SimpleCatalog"
159 python =
"lsst.afw.table.SourceCatalog"
160 cpp =
"SourceCatalog"
164 python =
"lsst.afw.table.ExposureCatalog"
165 cpp =
"ExposureCatalog"
169 python =
"lsst.afw.detection.PeakCatalog"
174 """Mapping object used to implement SimpleMapper, similar in intent to lsst.daf.peristence.Mapping.
180 def __init__(self, persistence, template=None, keys=None):
182 if template
is not None:
187 def map(self, dataset, root, dataId, mapper, suffix=None, storage=None):
188 if self.
templatetemplate
is not None:
189 path = self.
templatetemplate.format(dataset=dataset, ext=self.
persistencepersistence.ext, **dataId)
192 return self.
persistencepersistence.makeButlerLocation(path, dataId, suffix=suffix, mapper=mapper,
197 """Mapping for dataset types that are organized the same way as raw data (i.e. by CCD)."""
199 template =
"{dataset}-{visit:04d}-{ccd:01d}{ext}"
200 keys = dict(visit=int, ccd=int)
202 def query(self, dataset, index, level, format, dataId):
203 dictList = index[dataset][level]
204 results = [list(d.values())
for d
in dictList[dataId.get(level,
None)]]
209 """Mapping for dataset types that are organized according to a SkyMap subdivision of the sky."""
211 template =
"{dataset}-{filter}-{tract:02d}-{patch}{ext}"
212 keys = dict(filter=str, tract=int, patch=str)
216 """Mapping for CoaddTempExp datasets."""
218 template =
"{dataset}-{tract:02d}-{patch}-{visit:04d}{ext}"
219 keys = dict(tract=int, patch=str, visit=int)
223 """Mapping for forced_src datasets."""
225 template =
"{dataset}-{tract:02d}-{visit:04d}-{ccd:01d}{ext}"
226 keys = dict(tract=int, ccd=int, visit=int)
230 """Metaclass for SimpleMapper that creates map_ and query_ methods for everything found in the
231 'mappings' class variable.
235 def _makeMapClosure(dataset, mapping, suffix=None):
236 def mapClosure(self, dataId, write=False):
237 return mapping.map(dataset, self.root, dataId, self, suffix=suffix, storage=self.storage)
241 def _makeQueryClosure(dataset, mapping):
242 def queryClosure(self, level, format, dataId):
243 return mapping.query(dataset, self.index, level, format, dataId)
247 type.__init__(cls, name, bases, dict_)
249 for dataset, mapping
in cls.mappings.items():
250 setattr(cls,
"map_" + dataset, MapperMeta._makeMapClosure(dataset, mapping, suffix=
None))
251 for suffix
in mapping.persistence.suffixes:
252 setattr(cls,
"map_" + dataset + suffix,
253 MapperMeta._makeMapClosure(dataset, mapping, suffix=suffix))
254 if hasattr(mapping,
"query"):
255 setattr(cls,
"query_" + dataset, MapperMeta._makeQueryClosure(dataset, mapping))
256 cls.
keyDictkeyDict.update(mapping.keys)
261 An extremely simple mapper for an imaginary camera
for use
in integration tests.
263 As SimpleMapper does
not inherit
from obs.base.CameraMapper, it does
not
264 use a policy file to set mappings
or a registry; all the information
is here
265 (
in the map_*
and query_* methods).
267 The imaginary camera
's raw data format has only 'visit
' and 'ccd
' keys, with
268 two CCDs per visit (by default).
274 forced_src_schema=SimpleMapping(SourceCatalogPersistenceType,
275 template="{dataset}{ext}", keys={}),
276 truth=
SimpleMapping(SimpleCatalogPersistenceType, template=
"{dataset}-{tract:02d}{ext}",
277 keys={
"tract": int}),
278 simsrc=
RawMapping(SimpleCatalogPersistenceType, template=
"{dataset}-{tract:02d}{ext}",
279 keys={
"tract": int}),
280 observations=
SimpleMapping(ExposureCatalogPersistenceType, template=
"{dataset}-{tract:02d}{ext}",
281 keys={
"tract": int}),
282 ccdExposureId=
RawMapping(BypassPersistenceType),
284 deepCoaddId=
SkyMapping(BypassPersistenceType),
287 deepMergedCoaddId=
SkyMapping(BypassPersistenceType),
289 deepCoadd_skyMap=
SimpleMapping(SkyMapPersistenceType, template=
"{dataset}{ext}", keys={}),
290 deepCoadd=
SkyMapping(ExposurePersistenceType),
291 deepCoadd_filterLabel=
SkyMapping(ExposurePersistenceType),
292 deepCoaddPsfMatched=
SkyMapping(ExposurePersistenceType),
293 deepCoadd_calexp=
SkyMapping(ExposurePersistenceType),
294 deepCoadd_calexp_background=
SkyMapping(CatalogPersistenceType),
295 deepCoadd_icSrc=
SkyMapping(SourceCatalogPersistenceType),
296 deepCoadd_icSrc_schema=
SimpleMapping(SourceCatalogPersistenceType,
297 template=
"{dataset}{ext}", keys={}),
298 deepCoadd_src=
SkyMapping(SourceCatalogPersistenceType),
299 deepCoadd_src_schema=
SimpleMapping(SourceCatalogPersistenceType,
300 template=
"{dataset}{ext}", keys={}),
301 deepCoadd_peak_schema=
SimpleMapping(PeakCatalogPersistenceType,
302 template=
"{dataset}{ext}", keys={}),
303 deepCoadd_ref=
SkyMapping(SourceCatalogPersistenceType),
304 deepCoadd_ref_schema=
SimpleMapping(SourceCatalogPersistenceType,
305 template=
"{dataset}{ext}", keys={}),
306 deepCoadd_det=
SkyMapping(SourceCatalogPersistenceType),
307 deepCoadd_det_schema=
SimpleMapping(SourceCatalogPersistenceType,
308 template=
"{dataset}{ext}", keys={}),
309 deepCoadd_mergeDet=
SkyMapping(SourceCatalogPersistenceType),
310 deepCoadd_mergeDet_schema=
SimpleMapping(SourceCatalogPersistenceType,
311 template=
"{dataset}{ext}", keys={}),
312 deepCoadd_deblendedFlux=
SkyMapping(SourceCatalogPersistenceType),
313 deepCoadd_deblendedFlux_schema=
SimpleMapping(SourceCatalogPersistenceType,
314 template=
"{dataset}{ext}", keys={}),
315 deepCoadd_deblendedModel=
SkyMapping(SourceCatalogPersistenceType),
316 deepCoadd_deblendedModel_schema=
SimpleMapping(SourceCatalogPersistenceType,
317 template=
"{dataset}{ext}", keys={}),
318 deepCoadd_meas=
SkyMapping(SourceCatalogPersistenceType),
319 deepCoadd_meas_schema=
SimpleMapping(SourceCatalogPersistenceType,
320 template=
"{dataset}{ext}", keys={}),
321 deepCoadd_forced_src=
SkyMapping(SourceCatalogPersistenceType),
322 deepCoadd_forced_src_schema=
SimpleMapping(SourceCatalogPersistenceType,
323 template=
"{dataset}{ext}", keys={}),
324 deepCoadd_mock=
SkyMapping(ExposurePersistenceType),
325 deepCoaddPsfMatched_mock=
SkyMapping(ExposurePersistenceType),
327 deepCoadd_directWarp_mock=
TempExpMapping(ExposurePersistenceType),
329 deepCoadd_psfMatchedWarp_mock=
TempExpMapping(ExposurePersistenceType),
338 self.
storagestorage = lsst.daf.persistence.Storage.makeFromURI(root)
339 super(SimpleMapper, self).
__init__(**kwargs)
347 self.
filterLabelfilterLabel = afwImage.FilterLabel(band=
"r", physical=
"r")
354 if datasetType
is None:
357 keyDict = self.
mappingsmappings[datasetType].keys
358 if level
is not None and level
in self.
levelslevels:
359 keyDict = dict(keyDict)
360 for lev
in self.
levelslevels[level]:
366 filenames = os.listdir(self.
rootroot)
367 rawRegex = re.compile(
r"(?P<dataset>\w+)-(?P<visit>\d+)-(?P<ccd>\d).*")
369 for filename
in filenames:
370 m = rawRegex.match(filename)
373 index = self.
indexindex.setdefault(m.group(
'dataset'), dict(ccd={
None: []}, visit={
None: []}))
374 visit = int(m.group(
'visit'))
375 ccd = int(m.group(
'ccd'))
376 d1 = dict(visit=visit, ccd=ccd)
377 d2 = dict(visit=visit)
378 index[
'ccd'].setdefault(visit, []).append(d1)
379 index[
'ccd'][
None].append(d1)
380 index[
'visit'][visit] = [d2]
381 index[
'visit'][
None].append(d1)
390 return lsst.daf.persistence.ButlerLocation(
391 "lsst.afw.cameraGeom.Camera",
"Camera",
None, [], dataId, mapper=self, storage=self.
storagestorage
395 detectorId = dataId[
"ccd"]
396 detector = self.
cameracamera[detectorId]
397 item.setDetector(detector)
401 def _computeCcdExposureId(self, dataId):
402 return int(dataId[
"visit"]) * 10 + int(dataId[
"ccd"])
404 def _computeCoaddId(self, dataId):
407 tract = int(dataId[
'tract'])
408 if tract < 0
or tract >= 128:
409 raise RuntimeError(
'tract not in range [0,128)')
410 patchX, patchY = (int(c)
for c
in dataId[
'patch'].split(
','))
411 for p
in (patchX, patchY):
412 if p < 0
or p >= 2**13:
413 raise RuntimeError(
'patch component not in range [0, 8192)')
414 return (tract * 2**13 + patchX) * 2**13 + patchY
418 return dict(visit=(int(ccdExposureId) // 10), ccd=(int(ccdExposureId) % 10))
430 return 1 + 7 + 13*2 + 3
439 return 1 + 7 + 13*2 + 3
442 """To return a useful filterLabel for MergeDetectionsTask."""
443 return afwImage.FilterLabel(band=self.
filterLabelfilterLabel.bandLabel)
452 radialDistortion=0.925,
456 @param[
in] nx: number of detectors
in x
457 @param[
in] ny: number of detectors
in y
458 @param[
in] sizeX: detector size
in x (pixels)
459 @param[
in] sizeY: detector size
in y (pixels)
460 @param[
in] gapX: gap between detectors
in x (mm)
461 @param[
in] gapY: gap between detectors
in y (mm)
462 @param[
in] pixelSize: pixel size (mm) (a float)
463 @param[
in] plateScale: plate scale
in arcsec/mm; 20.0
is for LSST
464 @param[
in] radialDistortion: radial distortion,
in mm/rad^2
465 (the r^3 coefficient of the radial distortion polynomial
466 that converts FIELD_ANGLE
in radians to FOCAL_PLANE
in mm);
467 0.925
is the value Dave Monet measured
for lsstSim data
469 Each detector will have one amplifier (
with no raw information).
472 radialDistortCoeffs = [0.0, 1.0/pScaleRad, 0.0, radialDistortion/pScaleRad]
481 cY = (iY - 0.5 * (nY - 1)) * (pixelSize * sizeY + gapY)
483 cX = (iX - 0.5 * (nX - 1)) * (pixelSize * sizeY + gapX)
485 detectorName =
"detector %d,%d" % (iX, iY)
487 detectorBuilder = cameraBuilder.add(detectorName, detectorId)
488 detectorBuilder.setSerial(detectorName +
" serial")
489 detectorBuilder.setBBox(ccdBBox)
495 ampBuilder.setName(ampName)
496 ampBuilder.setBBox(ccdBBox)
497 ampBuilder.setGain(1.0)
498 ampBuilder.setReadNoise(5.0)
500 detectorBuilder.append(ampBuilder)
504 cameraBuilder.setTransformFromFocalPlaneTo(lsst.afw.cameraGeom.FIELD_ANGLE, focalPlaneToFieldAngle)
505 return cameraBuilder.finish()
510 Create a data repository for SimpleMapper
and return a butler
for it.
512 Clobbers anything already
in the given path.
514 if os.path.exists(root):
517 with open(os.path.join(root,
"_mapper"),
"w")
as f:
518 f.write(
"lsst.pipe.tasks.mocks.SimpleMapper\n")
519 return lsst.daf.persistence.Butler(root=root)
def makeButlerLocation(cls, path, dataId, mapper, suffix=None, storage=None)
def makeButlerLocation(cls, path, dataId, mapper, suffix=None, storage=None)
def makeButlerLocation(cls, path, dataId, mapper, suffix=None, storage=None)
def canStandardize(self, datasetType)
def query(self, dataset, index, level, format, dataId)
def bypass_deepMergedCoaddId_bits(self, datasetType, pythonType, location, dataId)
def bypass_deepMergedCoaddId(self, datasetType, pythonType, location, dataId)
def getDefaultLevel(self)
def bypass_ccdExposureId(self, datasetType, pythonType, location, dataId)
def _computeCcdExposureId(self, dataId)
def bypass_deepCoadd_filterLabel(self, *args, **kwargs)
def bypass_deepCoadd_band(self, datasetType, pythonType, location, dataId)
def getKeys(self, datasetType, level)
def std_calexp(self, item, dataId)
def map_camera(self, dataId, write=False)
def __init__(self, root, **kwargs)
def bypass_camera(self, datasetType, pythonType, location, dataId)
def splitCcdExposureId(ccdExposureId)
def bypass_deepCoaddId_bits(self, datasetType, pythonType, location, dataId)
def bypass_ccdExposureId_bits(self, datasetType, pythonType, location, dataId)
def bypass_deepCoaddId(self, datasetType, pythonType, location, dataId)
def _computeCoaddId(self, dataId)
def map(self, dataset, root, dataId, mapper, suffix=None, storage=None)
def __init__(self, persistence, template=None, keys=None)
std::shared_ptr< TransformPoint2ToPoint2 > makeRadialTransform(std::vector< double > const &coeffs)
constexpr double arcsecToRad(double x) noexcept
def makeSimpleCamera(nX, nY, sizeX, sizeY, gapX, gapY, pixelSize=1.0, plateScale=20.0, radialDistortion=0.925)