13 """Wrapper for getting a value from a metadata object by key. 14 @param[in] metadata metadata object to query for value 15 @param[in] key key to use for value lookup 16 @returns value associated with key, None if key does not exist 18 mdKeys = metadata.paramNames()
20 return metadata.getScalar(key)
26 """Wrapper for setting a value in a metadata object. Deals with case 27 where the key already exists. 28 @param[in, out] metadata metadata object ot modify in place. 29 @param[in] key key to associate with value 30 @param[in] value value to assign in the metadata object 31 @param[in] clobber Clobber the value if the key already exisists? 33 mdKeys = metadata.paramNames()
34 if key
not in mdKeys
or (key
in mdKeys
and clobber):
35 metadata.set(key, value)
39 """ Class to hold mapping of header cards to attributes""" 41 def addEntry(self, keyname, attribute_name, default=None, transform=lambda x: x):
42 """Adds an entry to the registr 43 @param[in] keyname Key used to retrieve the header record 44 @param[in] attribute_name Name of the attribute to store the value in 45 @param[jn] default Default velue to store if the header card is not available 46 @param[in] transform Transform to apply to the header value before assigning it to the 49 self.__setitem__(attribute_name, {
'keyName': keyname,
51 'transform': transform})
54 """Sets the attributes on the give object given a metadata object. 55 @param[in, out] obj Object on which to operate in place 56 @param[in] metadata Metadata object used for applying the mapping 57 @param[in] doRaise Raise exceptions on calling methods on the 58 input object that do not exist? 60 for key, attrDict
in self.items():
62 value =
getByKey(metadata, attrDict[
'keyName'])
66 self.
_applyVal(obj, value, key, attrDict[
'transform'])
70 value = attrDict[
'default']
72 self.
_applyVal(obj, value, key,
lambda x: x)
73 except Exception
as e:
77 warnings.warn(
'WARNING: Failed to set %s attribute with %s value: %s' %
80 def _applyVal(self, obj, value, attrName, transform):
81 raise NotImplementedError(
'Must be implemented in sub-class')
85 """ Class to hold mapping of header cards to AmpInfoTable attributes 86 The amp info is stored using setters, thus calling the attribute as a function. 89 def _applyVal(self, obj, value, attrName, transform):
94 """ Class to hold mapping of header cards to Detector attributes 95 Detector information is stored as attributes on a Config object. 98 def _applyVal(self, obj, value, attrName, transform):
99 obj.__setattr__(attrName,
transform(value))
103 def __init__(self, detectorFileName, ampFileNameList, inAmpCoords=True, plateScale=1.,
104 radialCoeffs=(0., 1.), clobberMetadata=
False, doRaise=
True):
105 ''' @param[in] detectorFileName FITS file containing the detector description. 106 May use [] notation to specify an extension in an MEF. 107 @param[in] ampFileNameList List of FITS file names to use in building the amps. 108 May contain duplicate entries if the raw data are assembled. 109 @param[in] inAmpCoords Boolean, True if raw data are in amp coordinates, False if raw data 110 are assembled into pseudo detector pixel arrays 111 @param[in] plateScale Nominal platescale (arcsec/mm) 112 @param[in] radialCoeffs Radial distortion coefficients for a radial polynomial in normalized 114 @param[in] clobberMetadata Clobber metadata from input files if 115 overridden in the _sanitizeMetadata method 116 @param[in] doRaise Raise exception if not all non-defaulted 117 keywords are defined? Default is True. 128 for fileName
in ampFileNameList:
135 def _sanitizeHeaderMetadata(self, metadata, clobber):
136 """This method is called for all metadata and gives an opportunity to add/modify 137 header information for use downstream. 138 Override this method if more than the default is needed. 139 @param[in, out] metadata Metadata to read/modify 140 @param[in] clobber Clobber keys that exist with default keys? 144 def _defaultSanitization(self, metadata, clobber):
145 """Does the default sanitization of the header metadata. 146 @param[in,out] metadata Header metadata to extend/modify 147 @param[in] clobber Override values in existing header cards? 158 if dtm1
is not None and dtm2
is not None:
159 setByKey(metadata,
'FLIPX', dtm1 < 0, clobber)
160 setByKey(metadata,
'FLIPY', dtm2 < 0, clobber)
162 afwTable.ReadoutCorner.LL), clobber)
164 setByKey(metadata,
'FLIPX',
False, clobber)
165 setByKey(metadata,
'FLIPY',
True, clobber)
168 setByKey(metadata,
'RDCRNR',
None, clobber)
173 if xext
is not None and yext
is not None:
174 setByKey(metadata,
'RAWBBOX',
'[%i:%i,%i:%i]'%(
175 1, xext, 1, yext), clobber)
179 if dtv1
is not None and dtv2
is not None:
180 setByKey(metadata,
'XYOFF', [dtv1, dtv2], clobber)
184 if metadata.isArray(
'BIASSEC'):
185 keylist = [
'HOSCAN',
'PRESCAN',
'VOSCAN']
186 biassecs =
getByKey(metadata,
'BIASSEC')
187 for i, biassec
in enumerate(biassecs):
188 setByKey(metadata, keylist[i], biassec, clobber)
190 biassec =
getByKey(metadata,
'BIASSEC')
191 if biassec
is not None:
192 setByKey(metadata,
'HOSCAN', biassec, clobber)
194 def _makeDefaultAmpMap(self):
195 """Make the default map from header information to amplifier information 196 @return The HeaderAmpMap object containing the mapping 200 mapList = [(
'EXTNAME',
'setName'),
201 (
'DETSEC',
'setBBox',
None, self.
_makeBbox),
202 (
'GAIN',
'setGain', 1.),
203 (
'RDNOISE',
'setReadNoise', 0.),
204 (
'SATURATE',
'setSaturation', 2 << 15),
205 (
'RDCRNR',
'setReadoutCorner',
int(
206 afwTable.ReadoutCorner.LL), afwTable.ReadoutCorner),
207 (
'LINCOEFF',
'setLinearityCoeffs', [0., 1.]),
208 (
'LINTYPE',
'setLinearityType',
'POLY'),
209 (
'RAWBBOX',
'setRawBBox',
None, self.
_makeBbox),
210 (
'DATASEC',
'setRawDataBBox',
None, self.
_makeBbox),
211 (
'FLIPX',
'setRawFlipX',
False),
212 (
'FLIPY',
'setRawFlipY',
False),
214 (
'HOSCAN',
'setRawHorizontalOverscanBBox',
216 (
'VOSCAN',
'setRawVerticalOverscanBBox',
218 (
'PRESCAN',
'setRawPrescanBBox', emptyBBox, self.
_makeBbox),
224 def _makeDefaultDetectorMap(self):
225 """Make the default map from header information to detector information 226 @return The HeaderDetectorMap object containing the mapping 229 mapList = [(
'CCDNAME',
'name',
'ccdName'),
237 (
'OBSTYPE',
'detectorType',
int(
238 afwCameraGeom.DetectorType.SCIENCE)),
239 (
'SERSTR',
'serial',
'none'),
240 (
'XPOS',
'offset_x', 0.),
241 (
'YPOS',
'offset_y', 0.),
242 (
'XPIX',
'refpos_x', 0.),
243 (
'YPIX',
'refpos_y', 0.),
244 (
'YAWDEG',
'yawDeg', 0.),
245 (
'PITCHDEG',
'pitchDeg', 0.),
246 (
'ROLLDEG',
'rollDeg', 0.),
247 (
'XPIXSIZE',
'pixelSize_x', 1.),
248 (
'YPIXSIZE',
'pixelSize_y', 1.),
249 (
'TRNSPOSE',
'transposeDetector',
False),
255 def _makeExt(self, extArr):
256 """Helper function to make an extent from an array 257 @param[in] extArr Length 2 array to use in creating the Extent object 258 @return Extent2I constructed from the input list 262 def _makeBbox(self, boxString):
263 """Helper funtion to make a bounding box from a string representing a FITS style bounding box 264 @param[in] boxString String describing the bounding box 265 @return Box2I for the bounding box 268 x1, x2, y1, y2 = [
int(el)
for el
in re.split(
269 '[:,]', boxString.strip()[1:-1])]
276 def _getBboxX0(self, boxString):
277 return self.
_makeBbox(boxString).getMinX()
279 def _getBboxX1(self, boxString):
280 return self.
_makeBbox(boxString).getMaxX()
282 def _getBboxY0(self, boxString):
283 return self.
_makeBbox(boxString).getMinY()
285 def _getBboxY1(self, boxString):
286 return self.
_makeBbox(boxString).getMaxY()
288 def _makeRadialTransform(self, radialCoeffs):
289 """Helper function to get the radial transform given the radial polynomial coefficients given in 291 @param[in] radialCoeffs List of coefficients describing a polynomial radial distortion in 293 @return Transform object describing the radial distortion 299 """Take all the information and build a Detector object. The Detector object is necessary for doing 300 things like assembly. 301 @return Detector object 306 schema = afwTable.AmpInfoTable.makeMinimalSchema()
309 record = ampInfo.addNew()
311 record.setHasRawInfo(
True)
313 detConfig = afwCameraGeom.DetectorConfig()
316 self.
detector = afwCameraGeom.makeDetector(
321 """PLaceholder for subclasses to implement construction of a calib to associate with the exposure. 322 @return empty afwImage.Calib object 327 """Method for constructing an exposure object from an image and the information contained in this 328 class to construct the Detector and Calib objects. 329 @param[in] im Image used to construct the exposure 330 @param[in] mask Optional mask plane as a <askU 331 @param[in] variance Optional variance plance as an image of the same type as im 332 @param[out] Exposure object 344 exp.setDetector(detector)
def makeExposure(self, im, mask=None, variance=None)
def _makeRadialTransform(self, radialCoeffs)
def _getBboxY1(self, boxString)
def _makeDefaultAmpMap(self)
def _makeDefaultDetectorMap(self)
def _makeBbox(self, boxString)
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.
Describe an exposure's calibration.
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.
def _defaultSanitization(self, metadata, clobber)
def _getBboxY0(self, boxString)
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.
def _sanitizeHeaderMetadata(self, metadata, clobber)
Represent a 2-dimensional array of bitmask pixels.
def getByKey(metadata, key)
std::shared_ptr< TransformPoint2ToPoint2 > makeRadialTransform(std::vector< double > const &forwardCoeffs, std::vector< double > const &inverseCoeffs)
A purely radial polynomial distortion.
def _getBboxX0(self, boxString)
def _makeExt(self, extArr)
def _getBboxX1(self, boxString)
constexpr double arcsecToRad(double x) noexcept
An integer coordinate rectangle.
def __init__(self, detectorFileName, ampFileNameList, inAmpCoords=True, plateScale=1., radialCoeffs=(0., 1.), clobberMetadata=False, doRaise=True)
def setByKey(metadata, key, value, clobber)