lsst.pipe.tasks
g2c8cee2ce7+1ac6cedd78
Toggle main menu visibility
Loading...
Searching...
No Matches
python
lsst
pipe
tasks
objectMasks.py
Go to the documentation of this file.
1
# This file is part of pipe_tasks.
2
#
3
# Developed for the LSST Data Management System.
4
# This product includes software developed by the LSST Project
5
# (https://www.lsst.org).
6
# See the COPYRIGHT file at the top-level directory of this distribution
7
# for details of code ownership.
8
#
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation, either version 3 of the License, or
12
# (at your option) any later version.
13
#
14
# This program is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU General Public License for more details.
18
#
19
# You should have received a copy of the GNU General Public License
20
# along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22
__all__ = [
"ObjectMaskCatalog"
,
"RegionFileFormatter"
]
23
24
import
re
25
import
logging
26
import
lsst.daf.base
as
dafBase
27
import
lsst.geom
as
geom
28
import
lsst.afw.table
as
afwTable
29
from
typing
import
Any
30
from
lsst.daf.butler
import
FormatterV2, FormatterNotImplementedError
31
from
lsst.resources
import
ResourcePath
32
33
34
class
ObjectMaskCatalog
:
35
"""Class to support bright object masks
36
"""
37
38
def
__init__
(self):
39
schema = afwTable.SimpleTable.makeMinimalSchema()
40
schema.addField(
"type"
, str,
"type of region (e.g. box, circle)"
, size=10)
41
schema.addField(
"radius"
,
"Angle"
,
"radius of mask (if type == circle"
)
42
schema.addField(
"height"
,
"Angle"
,
"height of mask (if type == box)"
)
43
schema.addField(
"width"
,
"Angle"
,
"width of mask (if type == box)"
)
44
schema.addField(
"angle"
,
"Angle"
,
"rotation of mask (if type == box)"
)
45
schema.addField(
"mag"
, float,
"object's magnitude"
)
46
47
self.
_catalog
= afwTable.SimpleCatalog(schema)
48
self.
_catalog
.table.setMetadata(dafBase.PropertyList())
49
50
self.
table
= self.
_catalog
.table
51
self.
addNew
= self.
_catalog
.addNew
52
53
def
__len__
(self):
54
return
len(self.
_catalog
)
55
56
def
__iter__
(self):
57
return
iter(self.
_catalog
)
58
59
def
__getitem__
(self, i):
60
return
self.
_catalog
.
__getitem__
(i)
61
62
def
__setitem__
(self, i, v):
63
return
self.
_catalog
.
__setitem__
(i, v)
64
65
@classmethod
66
def
read
(cls, fileName):
67
"""Read a ds9 region file, returning a ObjectMaskCatalog object
68
69
The files should be structured as follows:
70
71
# Description of catalogue as a comment
72
# CATALOG: catalog-id-string
73
# TRACT: 0
74
# PATCH: 5,4
75
# FILTER: HSC-I
76
77
wcs; fk5
78
79
circle(RA, DEC, RADIUS) # ID: 1, mag: 12.34
80
box(RA, DEC, XSIZE, YSIZE, THETA) # ID: 2, mag: 23.45
81
...
82
83
The ", mag: XX.YY" is optional
84
85
The commented lines must be present, with the relevant fields such as
86
tract patch and filter filled in. The coordinate system must be listed
87
as above. Each patch is specified as a box or circle, with RA, DEC,
88
and dimensions specified in decimal degrees (with or without an
89
explicit "d").
90
91
Only (axis-aligned) boxes and circles are currently supported as
92
region definitions.
93
"""
94
95
log = logging.getLogger(
"lsst.ObjectMaskCatalog"
)
96
97
brightObjects = cls()
98
checkedWcsIsFk5 =
False
99
NaN = float(
"NaN"
)*geom.degrees
100
101
nFormatError = 0
# number of format errors seen
102
with
open(fileName)
as
fd:
103
for
lineNo, line
in
enumerate(fd.readlines(), 1):
104
line = line.rstrip()
105
106
if
re.search(
r"^\s*#"
, line):
107
#
108
# Parse any line of the form "# key : value" and put them into the metadata.
109
#
110
# The medatdata values must be defined as outlined in the above docstring
111
#
112
# The value of these three keys will be checked,
113
# so get them right!
114
#
115
mat = re.search(
r"^\s*#\s*([a-zA-Z][a-zA-Z0-9_]+)\s*:\s*(.*)"
, line)
116
if
mat:
117
key, value = mat.group(1).lower(), mat.group(2)
118
if
key ==
"tract"
:
119
value = int(value)
120
121
brightObjects.table.getMetadata().set(key, value)
122
123
line = re.sub(
r"^\s*#.*"
,
""
, line)
124
if
not
line:
125
continue
126
127
if
re.search(
r"^\s*wcs\s*;\s*fk5\s*$"
, line, re.IGNORECASE):
128
checkedWcsIsFk5 =
True
129
continue
130
131
# This regular expression parses the regions file for each region to be masked,
132
# with the format as specified in the above docstring.
133
mat = re.search(
r"^\s*(box|circle)"
134
r"(?:\s+|\s*\(\s*)"
# open paren or space
135
r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
# ra + units
136
r"(?:\s+|\s*,\s*)"
# sep
137
r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
# dec + units
138
r"(?:\s+|\s*,\s*)"
# sep
139
r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
# param1 + units
140
r"(?:"
# start optional 1
141
r"(?:\s+|\s*,\s*)"
# sep
142
r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
# param2 + units
143
r"(?:"
# start optional 2
144
r"(?:\s+|\s*,\s*)"
# sep
145
r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
# param3 + units
146
")?"
# end optional 2
147
")?"
# end optional 1
148
r"(?:\s*|\s*\)\s*)"
# close paren or space
149
r"#\s*ID:[\w\s]*(\d+)"
# start comment, ID
150
r"(?:\s*,?\s*mag:\s*([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?))?"
151
r"\s*$"
, line)
152
if
mat:
153
_type, ra, raUnit, dec, decUnit, \
154
param1, param1Unit, param2, param2Unit, param3, param3Unit, \
155
_id, mag = mat.groups()
156
157
_id = int(_id)
158
if
mag
is
None
:
159
mag = NaN
160
else
:
161
mag = float(mag)
162
163
ra =
convertToAngle
(ra, raUnit,
"ra"
, fileName, lineNo)
164
dec =
convertToAngle
(dec, decUnit,
"dec"
, fileName, lineNo)
165
166
radius = NaN
167
width = NaN
168
height = NaN
169
angle = 0.0*geom.degrees
170
171
if
_type ==
"box"
:
172
width =
convertToAngle
(param1, param1Unit,
"width"
, fileName, lineNo)
173
height =
convertToAngle
(param2, param2Unit,
"height"
, fileName, lineNo)
174
if
param3
is
not
None
:
175
angle =
convertToAngle
(param3, param3Unit,
"angle"
, fileName, lineNo)
176
177
if
angle != 0.0:
178
log.warning(
"Rotated boxes are not supported: \"%s\" at %s:%d"
,
179
line, fileName, lineNo)
180
nFormatError += 1
181
elif
_type ==
"circle"
:
182
radius =
convertToAngle
(param1, param1Unit,
"radius"
, fileName, lineNo)
183
184
if
not
(param2
is
None
and
param3
is
None
):
185
log.warning(
"Extra parameters for circle: \"%s\" at %s:%d"
,
186
line, fileName, lineNo)
187
nFormatError += 1
188
189
rec = brightObjects.addNew()
190
# N.b. rec["coord"] = Coord is not supported, so we have to use the setter
191
rec[
"type"
] = _type
192
rec[
"id"
] = _id
193
rec[
"mag"
] = mag
194
rec.setCoord(
geom.SpherePoint
(ra, dec))
195
196
rec[
"angle"
] = angle
197
rec[
"height"
] = height
198
rec[
"width"
] = width
199
rec[
"radius"
] = radius
200
else
:
201
log.warning(
"Unexpected line \"%s\" at %s:%d"
, line, fileName, lineNo)
202
nFormatError += 1
203
204
if
nFormatError > 0:
205
raise
RuntimeError(
"Saw %d formatting errors in %s"
% (nFormatError, fileName))
206
207
if
not
checkedWcsIsFk5:
208
raise
RuntimeError(
"Expected to see a line specifying an fk5 wcs in %s"
% fileName)
209
210
# This makes the deep copy contiguous in memory so that a ColumnView can be exposed to Numpy
211
brightObjects._catalog = brightObjects._catalog.copy(
True
)
212
213
return
brightObjects
214
215
216
def
convertToAngle
(var, varUnit, what, fileName, lineNo):
217
"""Given a variable and its units, return an geom.Angle
218
219
what, fileName, and lineNo are used to generate helpful error messages
220
"""
221
var = float(var)
222
223
if
varUnit
in
(
"d"
,
""
,
None
):
224
pass
225
elif
varUnit ==
"'"
:
226
var /= 60.0
227
elif
varUnit ==
'"'
:
228
var /= 3600.0
229
else
:
230
raise
RuntimeError(
"unsupported unit \"%s\" for %s at %s:%d"
%
231
(varUnit, what, fileName, lineNo))
232
233
return
var*geom.degrees
234
235
236
class
RegionFileFormatter
(FormatterV2):
237
"""Plugin for reading DS9 region file catalogs with Gen3 Butler.
238
"""
239
default_extension =
".reg"
240
can_read_from_local_file =
True
241
242
def
read_from_local_file
(
243
self, path: str, component: str |
None
=
None
, expected_size: int = -1
244
) -> Any:
245
# Docstring inherited.
246
pytype = self.file_descriptor.storageClass.pytype
247
return
pytype.read(path)
248
249
def
write_local_file
(self, in_memory_dataset: Any, uri: ResourcePath) ->
None
:
250
# Docstring inherited.
251
raise
FormatterNotImplementedError(
"Write not implemented."
)
lsst::geom::SpherePoint
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog
Definition
objectMasks.py:34
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog.__iter__
__iter__(self)
Definition
objectMasks.py:56
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog.read
read(cls, fileName)
Definition
objectMasks.py:66
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog.__getitem__
__getitem__(self, i)
Definition
objectMasks.py:59
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog.table
table
Definition
objectMasks.py:50
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog.__setitem__
__setitem__(self, i, v)
Definition
objectMasks.py:62
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog._catalog
_catalog
Definition
objectMasks.py:47
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog.addNew
addNew
Definition
objectMasks.py:51
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog.__len__
__len__(self)
Definition
objectMasks.py:53
lsst.pipe.tasks.objectMasks.ObjectMaskCatalog.__init__
__init__(self)
Definition
objectMasks.py:38
lsst.pipe.tasks.objectMasks.RegionFileFormatter
Definition
objectMasks.py:236
lsst.pipe.tasks.objectMasks.RegionFileFormatter.write_local_file
None write_local_file(self, Any in_memory_dataset, ResourcePath uri)
Definition
objectMasks.py:249
lsst.pipe.tasks.objectMasks.RegionFileFormatter.read_from_local_file
Any read_from_local_file(self, str path, str|None component=None, int expected_size=-1)
Definition
objectMasks.py:244
lsst::afw::table
lsst::daf::base
lsst::geom
lsst.pipe.tasks.objectMasks.convertToAngle
convertToAngle(var, varUnit, what, fileName, lineNo)
Definition
objectMasks.py:216
Generated on
for lsst.pipe.tasks by
1.17.0