1 from __future__
import absolute_import, division, print_function
2 from builtins
import object
4 import lsst.daf.base
as dafBase
5 import lsst.afw.coord
as afwCoord
6 import lsst.afw.geom
as afwGeom
7 import lsst.afw.table
as afwTable
8 from lsst.log
import Log
12 """Class to support bright object masks
14 N.b. I/O is done by providing a readFits method which fools the butler.
18 schema = afwTable.SimpleTable.makeMinimalSchema()
19 schema.addField(
"type", str,
"type of region (e.g. box, circle)", size=10)
20 schema.addField(
"radius",
"Angle",
"radius of mask (if type == circle")
21 schema.addField(
"height",
"Angle",
"height of mask (if type == box)")
22 schema.addField(
"width",
"Angle",
"width of mask (if type == box)")
23 schema.addField(
"angle",
"Angle",
"rotation of mask (if type == box)")
24 schema.addField(
"mag", float,
"object's magnitude")
26 self.
_catalog = afwTable.SimpleCatalog(schema)
27 self._catalog.table.setMetadata(dafBase.PropertyList())
29 self.
table = self._catalog.table
39 return self._catalog.__getitem__(i)
42 return self._catalog.__setitem__(i, v)
46 """Read a ds9 region file, returning a ObjectMaskCatalog object
48 This method is called "readFits" to fool the butler. The corresponding mapper entry looks like
50 template: "deepCoadd/BrightObjectMasks/%(tract)d/BrightObjectMask-%(tract)d-%(patch)s-%(filter)s.reg"
51 python: "lsst.obs.subaru.objectMasks.ObjectMaskCatalog"
52 persistable: "PurePythonClass"
53 storage: "FitsCatalogStorage"
55 and this is the only way I know to get it to read a random file type, in this case a ds9 region file.
57 This method expects to find files named as BrightObjectMask-%(tract)d-%(patch)s-%(filter)s.reg
58 The files should be structured as follows:
60 # Description of catalogue as a comment
61 # CATALOG: catalog-id-string
68 circle(RA, DEC, RADIUS) # ID: 1, mag: 12.34
69 box(RA, DEC, XSIZE, YSIZE, THETA) # ID: 2, mag: 23.45
72 The ", mag: XX.YY" is optional
74 The commented lines must be present, with the relevant fields such as tract patch and filter filled
75 in. The coordinate system must be listed as above. Each patch is specified as a box or circle, with
76 RA, DEC, and dimensions specified in decimal degrees (with or without an explicit "d").
78 Only (axis-aligned) boxes and circles are currently supported as region definitions.
81 log = Log.getLogger(
"ObjectMaskCatalog")
84 checkedWcsIsFk5 =
False
85 NaN = float(
"NaN")*afwGeom.degrees
88 with open(fileName)
as fd:
89 for lineNo, line
in enumerate(fd.readlines(), 1):
92 if re.search(
r"^\s*#", line):
101 mat = re.search(
r"^\s*#\s*([a-zA-Z][a-zA-Z0-9_]+)\s*:\s*(.*)", line)
103 key, value = mat.group(1).lower(), mat.group(2)
107 brightObjects.table.getMetadata().set(key, value)
109 line = re.sub(
r"^\s*#.*",
"", line)
113 if re.search(
r"^\s*wcs\s*;\s*fk5\s*$", line, re.IGNORECASE):
114 checkedWcsIsFk5 =
True
119 mat = re.search(
r"^\s*(box|circle)"
121 "(\d+(?:\.\d*)?([d]*))" "(?:\s+|\s*,\s*)"
122 "([+-]?\d+(?:\.\d*)?)([d]*)" "(?:\s+|\s*,\s*)"
123 "([+-]?\d+(?:\.\d*)?)([d]*)" "(?:\s+|\s*,\s*)?"
124 "(?:([+-]?\d+(?:\.\d*)?)([d]*)"
126 "([+-]?\d+(?:\.\d*)?)([d]*)"
130 "(?:\s*,\s*mag:\s*(\d+\.\d*))?"
133 _type, ra, raUnit, dec, decUnit, \
134 param1, param1Unit, param2, param2Unit, param3, param3Unit, \
135 _id, mag = mat.groups()
152 width =
convertToAngle(param1, param1Unit,
"width", fileName, lineNo)
153 height =
convertToAngle(param2, param2Unit,
"height", fileName, lineNo)
154 angle =
convertToAngle(param3, param3Unit,
"angle", fileName, lineNo)
157 log.warn(
"Rotated boxes are not supported: \"%s\" at %s:%d" % (
158 line, fileName, lineNo))
160 elif _type ==
"circle":
161 radius =
convertToAngle(param1, param1Unit,
"radius", fileName, lineNo)
163 if not (param2
is None and param3
is None):
164 log.warn(
"Extra parameters for circle: \"%s\" at %s:%d" % (
165 line, fileName, lineNo))
168 rec = brightObjects.addNew()
173 rec.setCoord(afwCoord.Fk5Coord(ra, dec))
176 rec[
"height"] = height
178 rec[
"radius"] = radius
180 log.warn(
"Unexpected line \"%s\" at %s:%d" % (line, fileName, lineNo))
184 raise RuntimeError(
"Saw %d formatting errors in %s" % (nFormatError, fileName))
186 if not checkedWcsIsFk5:
187 raise RuntimeError(
"Expected to see a line specifying an fk5 wcs in %s" % fileName)
190 brightObjects._catalog = brightObjects._catalog.copy(
True)
196 """Given a variable and its units, return an afwGeom.Angle
198 what, fileName, and lineNo are used to generate helpful error messages
202 if varUnit
in (
"d",
"",
None):
209 raise RuntimeError(
"unsupported unit \"%s\" for %s at %s:%d" %
210 (varUnit, what, fileName, lineNo))
212 return var*afwGeom.degrees