1 from __future__
import division
2 from builtins
import object
10 """Wrapper for getting a value from a metadata object by key.
11 @param[in] metadata metadata object to query for value
12 @param[in] key key to use for value lookup
13 @returns value associated with key, None if key does not exist
15 mdKeys = metadata.paramNames()
17 return metadata.get(key)
22 """Wrapper for setting a value in a metadata object. Deals with case
23 where the key already exists.
24 @param[in, out] metadata metadata object ot modify in place.
25 @param[in] key key to associate with value
26 @param[in] value value to assign in the metadata object
27 @param[in] clobber Clobber the value if the key already exisists?
29 mdKeys = metadata.paramNames()
30 if key
not in mdKeys
or (key
in mdKeys
and clobber):
31 metadata.set(key, value)
34 """ Class to hold mapping of header cards to attributes"""
35 def addEntry(self, keyname, attribute_name, default=None, transform=lambda x: x):
36 """Adds an entry to the registr
37 @param[in] keyname Key used to retrieve the header record
38 @param[in] attribute_name Name of the attribute to store the value in
39 @param[jn] default Default velue to store if the header card is not available
40 @param[in] transform Transform to apply to the header value before assigning it to the
43 self.__setitem__(attribute_name, {
'keyName':keyname,
45 'transform':transform})
48 """Sets the attributes on the give object given a metadata object.
49 @param[in, out] obj Object on which to operate in place
50 @param[in] metadata Metadata object used for applying the mapping
51 @param[in] doRaise Raise exceptions on calling methods on the input object that do not exist?
53 for key, attrDict
in self.items():
55 value =
getByKey(metadata, attrDict[
'keyName'])
57 self.
_applyVal(obj, value, key, attrDict[
'transform'])
61 value = attrDict[
'default']
62 self.
_applyVal(obj, value, key,
lambda x: x)
63 except Exception
as e:
67 warnings.warn(
'WARNING: Failed to set %s attribute with %s value: %s'%
70 def _applyVal(self, obj, value, attrName, transform):
71 raise NotImplementedError(
'Must be implemented in sub-class')
74 """ Class to hold mapping of header cards to AmpInfoTable attributes
75 The amp info is stored using setters, thus calling the attribute as a function.
77 def _applyVal(self, obj, value, attrName, transform):
78 getattr(obj, attrName)(transform(value))
81 """ Class to hold mapping of header cards to Detector attributes
82 Detector information is stored as attributes on a Config object.
84 def _applyVal(self, obj, value, attrName, transform):
85 obj.__setattr__(attrName, transform(value))
88 def __init__(self, detectorFileName, ampFileNameList, inAmpCoords=True, plateScale=1.,
89 radialCoeffs=(0., 1.), clobberMetadata=
False, doRaise=
True):
90 ''' @param[in] detectorFileName FITS file containing the detector description.
91 May use [] notation to specify an extension in an MEF.
92 @param[in] ampFileNameList List of FITS file names to use in building the amps.
93 May contain duplicate entries if the raw data are assembled.
94 @param[in] inAmpCoords Boolean, True if raw data are in amp coordinates, False if raw data
95 are assembled into pseudo detector pixel arrays
96 @param[in] plateScale Nominal platescale (arcsec/mm)
97 @param[in] radialCoeffs Radial distortion coefficients for a radial polynomial in normalized
99 @param[in] clobberMetadata Clobber metadata from input files if overridden in the _sanitizeMetadata method
100 @param[in] doRaise Raise exception if not all non-defaulted keywords are defined? Default is True.
110 for fileName
in ampFileNameList:
117 """This method is called for all metadata and gives an opportunity to add/modify
118 header information for use downstream.
119 Override this method if more than the default is needed.
120 @param[in, out] metadata Metadata to read/modify
121 @param[in] clobber Clobber keys that exist with default keys?
126 """Does the default sanitization of the header metadata.
127 @param[in,out] metadata Header metadata to extend/modify
128 @param[in] clobber Override values in existing header cards?
139 if dtm1
is not None and dtm2
is not None:
140 setByKey(metadata,
'FLIPX', dtm1 < 0, clobber)
141 setByKey(metadata,
'FLIPY', dtm2 < 0, clobber)
142 setByKey(metadata,
'RDCRNR', afwTable.LL, clobber)
144 setByKey(metadata,
'FLIPX',
False, clobber)
145 setByKey(metadata,
'FLIPY',
True, clobber)
147 setByKey(metadata,
'RDCRNR',
None, clobber)
152 if xext
is not None and yext
is not None:
153 setByKey(metadata,
'RAWBBOX',
'[%i:%i,%i:%i]'%(1, xext, 1, yext), clobber)
157 if dtv1
is not None and dtv2
is not None:
158 setByKey(metadata,
'XYOFF', [dtv1, dtv2], clobber)
162 if metadata.isArray(
'BIASSEC'):
163 keylist = [
'HOSCAN',
'PRESCAN',
'VOSCAN']
164 biassecs =
getByKey(metadata,
'BIASSEC')
165 for i, biassec
in enumerate(biassecs):
166 setByKey(metadata, keylist[i], biassec, clobber)
168 biassec =
getByKey(metadata,
'BIASSEC')
169 if biassec
is not None:
170 setByKey(metadata,
'HOSCAN', biassec, clobber)
173 """Make the default map from header information to amplifier information
174 @return The HeaderAmpMap object containing the mapping
178 mapList = [(
'EXTNAME',
'setName'),
179 (
'DETSEC',
'setBBox',
None, self.
_makeBbox),
180 (
'GAIN',
'setGain', 1.),
181 (
'RDNOISE',
'setReadNoise', 0.),
182 (
'SATURATE',
'setSaturation', 2<<15),
183 (
'RDCRNR',
'setReadoutCorner', afwTable.LL),
184 (
'LINCOEFF',
'setLinearityCoeffs', [0., 1.]),
185 (
'LINTYPE',
'setLinearityType',
'POLY'),
186 (
'RAWBBOX',
'setRawBBox',
None, self.
_makeBbox),
187 (
'DATASEC',
'setRawDataBBox',
None, self.
_makeBbox),
188 (
'FLIPX',
'setRawFlipX',
False),
189 (
'FLIPY',
'setRawFlipY',
False),
191 (
'HOSCAN',
'setRawHorizontalOverscanBBox', emptyBBox, self.
_makeBbox),
192 (
'VOSCAN',
'setRawVerticalOverscanBBox', emptyBBox, self.
_makeBbox),
193 (
'PRESCAN',
'setRawPrescanBBox', emptyBBox, self.
_makeBbox),
200 """Make the default map from header information to detector information
201 @return The HeaderDetectorMap object containing the mapping
204 mapList = [(
'CCDNAME',
'name',
'ccdName'),
210 (
'OBSTYPE',
'detectorType', afwCameraGeom.SCIENCE),
211 (
'SERSTR',
'serial',
'none'),
212 (
'XPOS',
'offset_x', 0.),
213 (
'YPOS',
'offset_y', 0.),
214 (
'XPIX',
'refpos_x', 0.),
215 (
'YPIX',
'refpos_y', 0.),
216 (
'YAWDEG',
'yawDeg', 0.),
217 (
'PITCHDEG',
'pitchDeg', 0.),
218 (
'ROLLDEG',
'rollDeg', 0.),
219 (
'XPIXSIZE',
'pixelSize_x', 1.),
220 (
'YPIXSIZE',
'pixelSize_y', 1.),
221 (
'TRNSPOSE',
'transposeDetector',
False),
228 """Helper function to make an extent from an array
229 @param[in] extArr Length 2 array to use in creating the Extent object
230 @return Extent2I constructed from the input list
235 """Helper funtion to make a bounding box from a string representing a FITS style bounding box
236 @param[in] boxString String describing the bounding box
237 @return Box2I for the bounding box
240 x1, x2, y1, y2 = [int(el)
for el
in re.split(
'[:,]', boxString.strip()[1:-1])]
249 return self.
_makeBbox(boxString).getMinX()
252 return self.
_makeBbox(boxString).getMaxX()
255 return self.
_makeBbox(boxString).getMinY()
258 return self.
_makeBbox(boxString).getMaxY()
261 """Helper function to get the radial transform given the radial polynomial coefficients given in
263 @param[in] radialCoeffs List of coefficients describing a polynomial radial distortion in
265 @return RadialXYTransform object describing the radial distortion
271 """Take all the information and build a Detector object. The Detector object is necessary for doing
272 things like assembly.
273 @return Detector object
278 schema = afwTable.AmpInfoTable.makeMinimalSchema()
281 record = ampInfo.addNew()
282 self.defaultAmpMap.setAttributes(record, ampMetadata, self.
doRaise)
283 record.setHasRawInfo(
True)
285 detConfig = afwCameraGeom.DetectorConfig()
291 """PLaceholder for subclasses to implement construction of a calib to associate with the exposure.
292 @return empty afwImage.Calib object
297 """Method for constructing an exposure object from an image and the information contained in this
298 class to construct the Detector and Calib objects.
299 @param[in] im Image used to construct the exposure
300 @param[in] mask Optional mask plane as a <askU
301 @param[in] variance Optional variance plance as an image of the same type as im
302 @param[out] Exposure object
305 mask = afwImage.MaskU(im.getDimensions())
315 exp.setDetector(detector)
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > * makeMaskedImage(typename Image< ImagePixelT >::Ptr image, typename Mask< MaskPixelT >::Ptr mask=typename Mask< MaskPixelT >::Ptr(), typename Image< VariancePixelT >::Ptr variance=typename Image< VariancePixelT >::Ptr())
A function to return a MaskedImage of the correct type (cf.
A custom container class for records, based on std::vector.
def _sanitizeHeaderMetadata
Describe an exposure's calibration.
An integer coordinate rectangle.
boost::shared_ptr< Wcs > makeWcs(coord::Coord const &crval, geom::Point2D const &crpix, double CD11, double CD12, double CD21, double CD22)
Create a Wcs object from crval, crpix, CD, using CD elements (useful from python) ...
boost::shared_ptr< daf::base::PropertyList > readMetadata(std::string const &fileName, int hdu=0, bool strip=false)
Return the metadata (header entries) from a FITS file.
Exposure< ImagePixelT, MaskPixelT, VariancePixelT >::Ptr makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, boost::shared_ptr< Wcs const > wcs=boost::shared_ptr< Wcs const >())
A function to return an Exposure of the correct type (cf.
double arcsecToRad(double x)
def _makeDefaultDetectorMap