27 from lsst.daf.butler.formatters.fileFormatter
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")
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
76 defined in `lsst.daf.persistence`, and ignored here.
78 Provided for compatibility with the "FitsCatalogStorage" read API
79 defined in `lsst.daf.persistence`, and ignored here.
83 Having a `readFits` method makes the `ObjectCatalogMask` class
84 duck-type compatible with `lsst.afw.table` catalogs, to the extent
85 needed to support reading by the Gen2 Butler with no specialized code
86 in `lsst.daf.persistence`. The on-disk type should actually be an
87 ASCII ds9 region file, typically with a ".reg" suffix.
89 return cls.
read(fileName)
93 """Read a ds9 region file, returning a ObjectMaskCatalog object
95 The files should be structured as follows:
97 # Description of catalogue as a comment
98 # CATALOG: catalog-id-string
105 circle(RA, DEC, RADIUS) # ID: 1, mag: 12.34
106 box(RA, DEC, XSIZE, YSIZE, THETA) # ID: 2, mag: 23.45
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 = Log.getLogger(
"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.warn(
"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.warn(
"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.warn(
"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.")