29 from astro_metadata_translator
import fix_header, DecamTranslator
34 from lsst.obs.base.utils
import createInitialSkyWcs, InitialSkyWcsError
36 from .makeDecamRawVisitInfo
import MakeDecamRawVisitInfo
37 from .decamFilters
import DECAM_FILTER_DEFINITIONS
38 from ._instrument
import DarkEnergyCamera
40 np.seterr(divide=
"ignore")
42 __all__ = [
"DecamMapper"]
46 packageName =
'obs_decam'
47 _gen3instrument = DarkEnergyCamera
49 MakeRawVisitInfoClass = MakeDecamRawVisitInfo
52 1:
'S29', 2:
'S30', 3:
'S31', 4:
'S25', 5:
'S26', 6:
'S27', 7:
'S28', 8:
'S20', 9:
'S21',
53 10:
'S22', 11:
'S23', 12:
'S24', 13:
'S14', 14:
'S15', 15:
'S16', 16:
'S17', 17:
'S18',
54 18:
'S19', 19:
'S8', 20:
'S9', 21:
'S10', 22:
'S11', 23:
'S12', 24:
'S13', 25:
'S1', 26:
'S2',
55 27:
'S3', 28:
'S4', 29:
'S5', 30:
'S6', 31:
'S7', 32:
'N1', 33:
'N2', 34:
'N3', 35:
'N4',
56 36:
'N5', 37:
'N6', 38:
'N7', 39:
'N8', 40:
'N9', 41:
'N10', 42:
'N11', 43:
'N12', 44:
'N13',
57 45:
'N14', 46:
'N15', 47:
'N16', 48:
'N17', 49:
'N18', 50:
'N19', 51:
'N20', 52:
'N21',
58 53:
'N22', 54:
'N23', 55:
'N24', 56:
'N25', 57:
'N26', 58:
'N27', 59:
'N28', 60:
'N29',
61 def __init__(self, inputPolicy=None, **kwargs):
62 policyFile = Policy.defaultPolicyFile(self.
packageNamepackageName,
"DecamMapper.yaml",
"policy")
63 policy =
Policy(policyFile)
65 super(DecamMapper, self).
__init__(policy, os.path.dirname(policyFile), **kwargs)
67 DECAM_FILTER_DEFINITIONS.defineFilters()
74 for datasetType
in (
"raw",
"instcal",
"dqmask",
"wtmap",
"cpIllumcor"):
75 self.mappings[datasetType].keyDict.update({
'ccdnum': int})
76 self.mappings[
"raw"].keyDict.update({
'object': str})
80 DecamMapper._nbit_tract = 10
81 DecamMapper._nbit_patch = 10
82 DecamMapper._nbit_filter = 4
83 DecamMapper._nbit_id = 64 - (DecamMapper._nbit_tract
84 + 2*DecamMapper._nbit_patch
85 + DecamMapper._nbit_filter)
87 def _extractDetectorName(self, dataId):
90 return DecamMapper.detectorNames[copyId[
'ccdnum']]
92 raise RuntimeError(
"No name found for dataId: %s"%(dataId))
94 def _transformId(self, dataId):
95 copyId = CameraMapper._transformId(self, dataId)
97 copyId.setdefault(
"ccdnum", copyId[
"ccd"])
106 def _computeCcdExposureId(self, dataId):
107 """Compute the 64-bit (long) identifier for a CCD exposure.
112 Data identifier with visit, ccd.
117 Integer identifier for a CCD exposure.
120 visit = copyId[
'visit']
121 ccdnum = copyId[
'ccdnum']
122 return int(
"%07d%02d" % (visit, ccdnum))
124 def _computeCoaddExposureId(self, dataId, singleFilter):
125 """Compute the 64-bit (long) identifier for a coadd.
130 Data identifier with tract and patch.
131 singleFilter : `bool`
132 True means the desired ID is for a single-filter coadd,
133 in which case the dataId must contain filter.
138 Unique integer identifier.
140 tract = int(dataId[
'tract'])
141 if tract < 0
or tract >= 2**DecamMapper._nbit_tract:
142 raise RuntimeError(
'tract not in range [0,%d)' % (2**DecamMapper._nbit_tract))
143 patchX, patchY = [int(x)
for x
in dataId[
'patch'].split(
',')]
144 for p
in (patchX, patchY):
145 if p < 0
or p >= 2**DecamMapper._nbit_patch:
146 raise RuntimeError(
'patch component not in range [0, %d)' % 2**DecamMapper._nbit_patch)
147 oid = (((tract << DecamMapper._nbit_patch) + patchX) << DecamMapper._nbit_patch) + patchY
149 return (oid << DecamMapper._nbit_filter) +
afwImage.Filter(dataId[
'filter']).getId()
156 return 64 - DecamMapper._nbit_id
162 return 64 - DecamMapper._nbit_id
165 return self.
bypass_deepCoaddIdbypass_deepCoaddId(datasetType, pythonType, location, dataId)
179 dqmArr = dqmask.getArray()
181 mArr = mask.getArray()
182 idxBad = np.where(dqmArr & 1)
183 idxSat = np.where(dqmArr & 2)
184 idxIntrp = np.where(dqmArr & 4)
185 idxCr = np.where(dqmArr & 16)
186 idxBleed = np.where(dqmArr & 64)
187 idxEdge = np.where(dqmArr & 512)
188 mArr[idxBad] |= mask.getPlaneBitMask(
"BAD")
189 mArr[idxSat] |= mask.getPlaneBitMask(
"SAT")
190 mArr[idxIntrp] |= mask.getPlaneBitMask(
"INTRP")
191 mArr[idxCr] |= mask.getPlaneBitMask(
"CR")
192 mArr[idxBleed] |= mask.getPlaneBitMask(
"SAT")
193 mArr[idxEdge] |= mask.getPlaneBitMask(
"EDGE")
197 wtmArr = wtmap.getArray()
198 idxUndefWeight = np.where(wtmArr <= 0)
200 wtmArr[idxUndefWeight] =
min(1e-14, np.min(wtmArr[np.where(wtmArr > 0)]))
202 varim = afwImage.ImageF(var)
207 instcalMap = self.map_instcal(dataId)
208 dqmaskMap = self.map_dqmask(dataId)
209 wtmapMap = self.map_wtmap(dataId)
210 instcalType = getattr(afwImage, instcalMap.getPythonType().split(
".")[-1])
211 dqmaskType = getattr(afwImage, dqmaskMap.getPythonType().split(
".")[-1])
212 wtmapType = getattr(afwImage, wtmapMap.getPythonType().split(
".")[-1])
213 instcal = instcalType(instcalMap.getLocationsWithRoot()[0])
214 dqmask = dqmaskType(dqmaskMap.getLocationsWithRoot()[0])
215 wtmap = wtmapType(wtmapMap.getLocationsWithRoot()[0])
220 mi = afwImage.MaskedImageF(afwImage.ImageF(instcal.getImage()), mask, variance)
222 fix_header(md, translator_class=DecamTranslator)
224 exp = afwImage.ExposureF(mi, wcs)
227 visitInfo = self.makeRawVisitInfo(md=md)
228 exp.getInfo().setVisitInfo(visitInfo)
230 exp.info.id = md[
'EXPID']
232 for kw
in (
'LTV1',
'LTV2'):
239 """Standardize a raw dataset by converting it to an Exposure.
241 Raw images are MEF files with one HDU for each detector.
245 item : `lsst.afw.image.DecoratedImage`
246 The image read by the butler.
252 result : `lsst.afw.image.Exposure`
253 The standardized Exposure.
255 return self._standardizeExposure(self.exposures[
'raw'], item, dataId,
256 trimmed=
False, setExposureId=
True)
258 def _createInitialSkyWcs(self, exposure):
263 self._createSkyWcsFromMetadata(exposure)
265 if exposure.getInfo().getVisitInfo()
is None:
266 msg =
"No VisitInfo; cannot access boresight information. Defaulting to metadata-based SkyWcs."
270 newSkyWcs = createInitialSkyWcs(exposure.getInfo().getVisitInfo(), exposure.getDetector(),
272 exposure.setWcs(newSkyWcs)
273 except InitialSkyWcsError
as e:
274 msg =
"Cannot create SkyWcs using VisitInfo and Detector, using metadata-based SkyWcs: %s"
275 self.log.
warn(msg, e)
276 self.log.
debug(
"Exception was: %s", traceback.TracebackException.from_exception(e))
277 if e.__context__
is not None:
278 self.log.
debug(
"Root-cause Exception was: %s",
279 traceback.TracebackException.from_exception(e.__context__))
283 rawPath = self.map_raw(dataId).getLocations()[0]
284 headerPath = re.sub(
r'[\[](\d+)[\]]$',
"[0]", rawPath)
286 fix_header(md0, translator_class=DecamTranslator)
287 visitInfo = self.makeRawVisitInfo(md0)
288 exp.getInfo().setVisitInfo(visitInfo)
289 return self._standardizeExposure(self.calibrations[
"dark"], exp, dataId, filter=
False)
293 return self._standardizeExposure(self.calibrations[
"bias"], exp, dataId, filter=
False)
297 return self._standardizeExposure(self.calibrations[
"flat"], exp, dataId, filter=
True)
301 return self._standardizeExposure(self.calibrations[
"illumcor"], exp, dataId, filter=
True)
303 def _standardizeCpMasterCal(self, datasetType, item, dataId, setFilter=False):
304 """Standardize a MasterCal image obtained from NOAO archive into Exposure
306 These MasterCal images are MEF files with one HDU for each detector.
307 Some WCS header, eg CTYPE1, exists only in the zeroth extensionr,
308 so info in the zeroth header need to be copied over to metadata.
313 Dataset type ("bias", "flat", or "illumcor").
314 item : `lsst.afw.image.DecoratedImage`
315 The image read by the butler.
319 Whether to set the filter in the Exposure.
323 result : `lsst.afw.image.Exposure`
324 The standardized Exposure.
327 md = item.getMetadata()
328 masterCalMap = getattr(self,
"map_" + datasetType)
329 masterCalPath = masterCalMap(dataId).getLocationsWithRoot()[0]
330 headerPath = re.sub(
r'[\[](\d+)[\]]$',
"[0]", masterCalPath)
332 fix_header(md0, translator_class=DecamTranslator)
333 for kw
in (
'CTYPE1',
'CTYPE2',
'CRVAL1',
'CRVAL2',
'CUNIT1',
'CUNIT2',
334 'CD1_1',
'CD1_2',
'CD2_1',
'CD2_2'):
335 if kw
in md0.paramNames()
and kw
not in md.paramNames():
336 md.add(kw, md0.getScalar(kw))
340 return self._standardizeExposure(self.calibrations[datasetType], exp, dataId, filter=setFilter)
350 return self._standardizeExposure(self.calibrations[
"fringe"], exp, dataId)
357 """Directory containing linearizers"""
358 packageName = cls.getPackageName()
360 return os.path.join(packageDir,
"decam",
"linearizer")
363 """Map a linearizer"""
365 location =
"%02d.fits" % (dataId[
"ccdnum"])
367 pythonType=
"lsst.ip.isr.LinearizeSquared",
369 storageName=
"PickleStorage",
370 locationList=[location],
378 """Directory containing crosstalk tables.
380 packageName = cls.getPackageName()
382 return os.path.join(packageDir,
"decam",
"crosstalk")
Represent a 2-dimensional array of bitmask pixels.
def bypass_deepMergedCoaddId(self, datasetType, pythonType, location, dataId)
def translate_wtmap(self, wtmap)
def bypass_deepMergedCoaddId_bits(self, *args, **kwargs)
def std_cpIllumcor(self, item, dataId)
def std_dark(self, item, dataId)
def std_fringe(self, item, dataId)
def bypass_dcrMergedCoaddId_bits(self, *args, **kwargs)
def bypass_dcrCoaddId_bits(self, *args, **kwargs)
def bypass_ccdExposureId(self, datasetType, pythonType, location, dataId)
def bypass_deepCoaddId(self, datasetType, pythonType, location, dataId)
def std_illumcor(self, item, dataId)
def bypass_dcrCoaddId(self, datasetType, pythonType, location, dataId)
def bypass_ccdExposureId_bits(self, datasetType, pythonType, location, dataId)
def bypass_dcrMergedCoaddId(self, datasetType, pythonType, location, dataId)
def std_raw(self, item, dataId)
def map_linearizer(self, dataId, write=False)
def _standardizeCpMasterCal(self, datasetType, item, dataId, setFilter=False)
def __init__(self, inputPolicy=None, **kwargs)
def _transformId(self, dataId)
def bypass_instcal(self, datasetType, pythonType, butlerLocation, dataId)
def std_bias(self, item, dataId)
def _computeCoaddExposureId(self, dataId, singleFilter)
def std_flat(self, item, dataId)
def _computeCcdExposureId(self, dataId)
def translate_dqmask(self, dqmask)
def std_cpBias(self, item, dataId)
def getLinearizerDir(cls)
def std_cpFlat(self, item, dataId)
def bypass_deepCoaddId_bits(self, *args, **kwargs)
std::shared_ptr< daf::base::PropertyList > readMetadata(std::string const &fileName, int hdu=DEFAULT_HDU, bool strip=false)
Read FITS header.
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
std::shared_ptr< PhotoCalib > makePhotoCalibFromCalibZeroPoint(double instFluxMag0, double instFluxMag0Err)
Construct a PhotoCalib from the deprecated Calib-style instFluxMag0/instFluxMag0Err values.
std::shared_ptr< Exposure< ImagePixelT, MaskPixelT, VariancePixelT > > makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, std::shared_ptr< geom::SkyWcs const > wcs=std::shared_ptr< geom::SkyWcs const >())
A function to return an Exposure of the correct type (cf.
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > * makeMaskedImage(typename std::shared_ptr< Image< ImagePixelT >> image, typename std::shared_ptr< Mask< MaskPixelT >> mask=Mask< MaskPixelT >(), typename std::shared_ptr< Image< VariancePixelT >> variance=Image< VariancePixelT >())
A function to return a MaskedImage of the correct type (cf.
std::string getPackageDir(std::string const &packageName)
return the root directory of a setup package