28from lsst.daf.butler.formatters.file
import FileFormatter
32 """Class to support bright object masks
34 N.b. I/O is done by providing a readFits method which fools the butler.
38 schema = afwTable.SimpleTable.makeMinimalSchema()
39 schema.addField(
"type", str,
"type of region (e.g. box, circle)", size=10)
40 schema.addField(
"radius",
"Angle",
"radius of mask (if type == circle")
41 schema.addField(
"height",
"Angle",
"height of mask (if type == box)")
42 schema.addField(
"width",
"Angle",
"width of mask (if type == box)")
43 schema.addField(
"angle",
"Angle",
"rotation of mask (if type == box)")
44 schema.addField(
"mag", float,
"object's magnitude")
46 self.
_catalog_catalog = afwTable.SimpleCatalog(schema)
47 self.
_catalog_catalog.table.setMetadata(dafBase.PropertyList())
66 """FitsCatalogStorage facade for `read`.
68 This method is intended
for use by the Gen2 Butler only.
73 Name of the file to read.
75 Provided
for compatibility
with the
"FitsCatalogStorage" read API
78 Provided
for compatibility
with the
"FitsCatalogStorage" read API
83 Having a `readFits` method makes the `ObjectCatalogMask`
class
85 needed to support reading by the Gen2 Butler
with no specialized code
87 ASCII ds9 region file, typically
with a
".reg" suffix.
89 return cls.
readread(fileName)
93 """Read a ds9 region file, returning a ObjectMaskCatalog object
95 The files should be structured as follows:
105 circle(RA, DEC, RADIUS)
106 box(RA, DEC, XSIZE, YSIZE, THETA)
109 The
", mag: XX.YY" is optional
111 The commented lines must be present,
with the relevant fields such
as
112 tract patch
and filter filled
in. The coordinate system must be listed
113 as above. Each patch
is specified
as a box
or circle,
with RA, DEC,
114 and dimensions specified
in decimal degrees (
with or without an
117 Only (axis-aligned) boxes
and circles are currently supported
as
121 log = logging.getLogger("lsst.ObjectMaskCatalog")
124 checkedWcsIsFk5 =
False
125 NaN = float(
"NaN")*geom.degrees
128 with open(fileName)
as fd:
129 for lineNo, line
in enumerate(fd.readlines(), 1):
132 if re.search(
r"^\s*#", line):
141 mat = re.search(
r"^\s*#\s*([a-zA-Z][a-zA-Z0-9_]+)\s*:\s*(.*)", line)
143 key, value = mat.group(1).lower(), mat.group(2)
147 brightObjects.table.getMetadata().set(key, value)
149 line = re.sub(
r"^\s*#.*",
"", line)
153 if re.search(
r"^\s*wcs\s*;\s*fk5\s*$", line, re.IGNORECASE):
154 checkedWcsIsFk5 =
True
159 mat = re.search(
r"^\s*(box|circle)"
161 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
163 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
165 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
168 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
171 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
175 r"#\s*ID:[\w\s]*(\d+)"
176 r"(?:\s*,?\s*mag:\s*([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?))?"
179 _type, ra, raUnit, dec, decUnit, \
180 param1, param1Unit, param2, param2Unit, param3, param3Unit, \
181 _id, mag = mat.groups()
195 angle = 0.0*geom.degrees
198 width =
convertToAngle(param1, param1Unit,
"width", fileName, lineNo)
199 height =
convertToAngle(param2, param2Unit,
"height", fileName, lineNo)
200 if param3
is not None:
201 angle =
convertToAngle(param3, param3Unit,
"angle", fileName, lineNo)
204 log.warning(
"Rotated boxes are not supported: \"%s\" at %s:%d",
205 line, fileName, lineNo)
207 elif _type ==
"circle":
208 radius =
convertToAngle(param1, param1Unit,
"radius", fileName, lineNo)
210 if not (param2
is None and param3
is None):
211 log.warning(
"Extra parameters for circle: \"%s\" at %s:%d",
212 line, fileName, lineNo)
215 rec = brightObjects.addNew()
223 rec[
"height"] = height
225 rec[
"radius"] = radius
227 log.warning(
"Unexpected line \"%s\" at %s:%d", line, fileName, lineNo)
231 raise RuntimeError(
"Saw %d formatting errors in %s" % (nFormatError, fileName))
233 if not checkedWcsIsFk5:
234 raise RuntimeError(
"Expected to see a line specifying an fk5 wcs in %s" % fileName)
237 brightObjects._catalog = brightObjects._catalog.copy(
True)
243 """Given a variable and its units, return an geom.Angle
245 what, fileName, and lineNo are used to generate helpful error messages
249 if varUnit
in (
"d",
"",
None):
256 raise RuntimeError(
"unsupported unit \"%s\" for %s at %s:%d" %
257 (varUnit, what, fileName, lineNo))
259 return var*geom.degrees
263 """Plugin for reading DS9 region file catalogs with Gen3 Butler.
267 def _readFile(self, path, pytype):
269 if not os.path.exists(path):
272 return pytype.read(path)
274 def _writeFile(self, inMemoryDataset, fileDescriptor):
276 raise NotImplementedError(
"Write not implemented.")
def __setitem__(self, i, v)
def readFits(cls, fileName, hdu=0, flags=0)
def convertToAngle(var, varUnit, what, fileName, lineNo)