LSST Applications  21.0.0+75b29a8a7f,21.0.0+e70536a077,21.0.0-1-ga51b5d4+62c747d40b,21.0.0-10-gbfb87ad6+3307648ee3,21.0.0-15-gedb9d5423+47cba9fc36,21.0.0-2-g103fe59+fdf0863a2a,21.0.0-2-g1367e85+d38a93257c,21.0.0-2-g45278ab+e70536a077,21.0.0-2-g5242d73+d38a93257c,21.0.0-2-g7f82c8f+e682ffb718,21.0.0-2-g8dde007+d179fbfa6a,21.0.0-2-g8f08a60+9402881886,21.0.0-2-ga326454+e682ffb718,21.0.0-2-ga63a54e+08647d4b1b,21.0.0-2-gde069b7+26c92b3210,21.0.0-2-gecfae73+0445ed2f95,21.0.0-2-gfc62afb+d38a93257c,21.0.0-27-gbbd0d29+ae871e0f33,21.0.0-28-g5fc5e037+feb0e9397b,21.0.0-3-g21c7a62+f4b9c0ff5c,21.0.0-3-g357aad2+57b0bddf0b,21.0.0-3-g4be5c26+d38a93257c,21.0.0-3-g65f322c+3f454acf5d,21.0.0-3-g7d9da8d+75b29a8a7f,21.0.0-3-gaa929c8+9e4ef6332c,21.0.0-3-ge02ed75+4b120a55c4,21.0.0-4-g3300ddd+e70536a077,21.0.0-4-g591bb35+4b120a55c4,21.0.0-4-gc004bbf+4911b9cd27,21.0.0-4-gccdca77+f94adcd104,21.0.0-4-ge8fba5a+2b3a696ff9,21.0.0-5-gb155db7+2c5429117a,21.0.0-5-gdf36809+637e4641ee,21.0.0-6-g00874e7+c9fd7f7160,21.0.0-6-g4e60332+4b120a55c4,21.0.0-7-gc8ca178+40eb9cf840,21.0.0-8-gfbe0b4b+9e4ef6332c,21.0.0-9-g2fd488a+d83b7cd606,w.2021.05
LSST Data Management Base Package
utils.py
Go to the documentation of this file.
1 # This file is part of obs_base.
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__ = ('InitialSkyWcsError', 'createInitialSkyWcs', 'createInitialSkyWcsFromBoresight', 'bboxFromIraf')
23 
24 import re
25 import lsst.geom as geom
26 
27 from . import Instrument
28 from lsst.afw.cameraGeom import PIXELS, FIELD_ANGLE
29 from lsst.afw.image import RotType
30 from lsst.afw.geom.skyWcs import makeSkyWcs
32 from lsst.utils import doImport
33 
34 
35 class InitialSkyWcsError(Exception):
36  """For handling failures when creating a SkyWcs from a camera geometry and
37  boresight.
38 
39  Typically used as a chained exception from a lower level exception.
40  """
41  pass
42 
43 
44 def createInitialSkyWcs(visitInfo, detector, flipX=False):
45  """Create a SkyWcs from the visit information and detector geometry.
46 
47  A typical usecase for this is to create the initial WCS for a newly-read
48  raw exposure.
49 
50 
51  Parameters
52  ----------
53  visitInfo : `lsst.afw.image.VisitInfo`
54  Where to get the telescope boresight and rotator angle from.
55  detector : `lsst.afw.cameraGeom.Detector`
56  Where to get the camera geomtry from.
57  flipX : `bool`, optional
58  If False, +X is along W, if True +X is along E.
59 
60  Returns
61  -------
62  skyWcs : `lsst.afw.geom.SkyWcs`
63  The new composed WCS.
64 
65  Raises
66  ------
67  InitialSkyWcsError
68  Raised if there is an error generating the SkyWcs, chained from the
69  lower-level exception if available.
70  """
71  if visitInfo.getRotType() != RotType.SKY:
72  msg = (f"Cannot create SkyWcs from camera geometry: rotator angle defined using "
73  f"RotType={visitInfo.getRotType()} instead of SKY.")
74  raise InitialSkyWcsError(msg)
75  orientation = visitInfo.getBoresightRotAngle()
76  boresight = visitInfo.getBoresightRaDec()
77  return createInitialSkyWcsFromBoresight(boresight, orientation, detector, flipX)
78 
79 
80 def createInitialSkyWcsFromBoresight(boresight, orientation, detector, flipX=False):
81  """Create a SkyWcs from the telescope boresight and detector geometry.
82 
83  A typical usecase for this is to create the initial WCS for a newly-read
84  raw exposure.
85 
86  Parameters
87  ----------
88  boresight : `lsst.geom.SpherePoint`
89  The ICRS boresight RA/Dec
90  orientation : `lsst.geom.Angle`
91  The rotation angle of the focal plane on the sky.
92  detector : `lsst.afw.cameraGeom.Detector`
93  Where to get the camera geomtry from.
94  flipX : `bool`, optional
95  If False, +X is along W, if True +X is along E.
96 
97  Returns
98  -------
99  skyWcs : `lsst.afw.geom.SkyWcs`
100  The new composed WCS.
101 
102  Raises
103  ------
104  InitialSkyWcsError
105  Raised if there is an error generating the SkyWcs, chained from the
106  lower-level exception if available.
107  """
108  try:
109  pixelsToFieldAngle = detector.getTransform(detector.makeCameraSys(PIXELS),
110  detector.makeCameraSys(FIELD_ANGLE))
112  raise InitialSkyWcsError("Cannot compute PIXELS to FIELD_ANGLE Transform.") from e
113  return makeSkyWcs(pixelsToFieldAngle, orientation, flipX, boresight)
114 
115 
116 def bboxFromIraf(irafBBoxStr):
117  """Return a Box2I corresponding to an IRAF-style BBOX
118 
119  [x0:x1,y0:y1] where x0 and x1 are the one-indexed start and end columns,
120  and correspondingly y0 and y1 are the start and end rows.
121  """
122 
123  mat = re.search(r"^\[([-\d]+):([-\d]+),([-\d]+):([-\d]+)\]$", irafBBoxStr)
124  if not mat:
125  raise RuntimeError("Unable to parse IRAF-style bbox \"%s\"" % irafBBoxStr)
126  x0, x1, y0, y1 = [int(_) for _ in mat.groups()]
127 
128  return geom.BoxI(geom.PointI(x0 - 1, y0 - 1), geom.PointI(x1 - 1, y1 - 1))
129 
130 
131 def getInstrument(instrumentName, registry=None):
132  """Return an instance of a named instrument.
133 
134  If the instrument name not is qualified (does not contain a '.') and a
135  butler registry is provided, this will attempt to load the instrument using
136  Instrument.fromName. Otherwise the instrument will be imported and
137  instantiated.
138 
139  Parameters
140  ----------
141  instrumentName : string
142  The name or fully-qualified class name of an instrument.
143  registry : `lsst.daf.butler.Registry`, optional
144  Butler registry to query to find information about the instrument, by
145  default None
146 
147  Returns
148  -------
149  Instrument subclass instance
150  The instantiated instrument.
151 
152  Raises
153  ------
154  RuntimeError
155  If the instrument can not be imported, instantiated, or obtained from
156  the registry.
157  TypeError
158  If the instrument is not a subclass of lsst.obs.base.Instrument.
159  """
160  if "." not in instrumentName and registry is not None:
161  try:
162  instr = Instrument.fromName(instrumentName, registry)
163  except Exception as err:
164  raise RuntimeError(
165  f"Could not get instrument from name: {instrumentName}. Failed with exception: {err}")
166  else:
167  try:
168  instr = doImport(instrumentName)
169  except Exception as err:
170  raise RuntimeError(f"Could not import instrument: {instrumentName}. Failed with exception: {err}")
171  instr = instr()
172  if not isinstance(instr, Instrument):
173  raise TypeError(f"{instrumentName} is not an Instrument subclass.")
174  return instr
175 
176 
177 # TODO remove the impl in pipe_base? (NB this combines setDottedAtr AND the
178 # handling in ConfigValueAction.__call__)
179 def setDottedAttr(item, name, value):
180  """Set an instance attribute (like `setattr` but accepting hierarchical
181  names such as ``foo.bar.baz``) If the attribute can not be set as a string,
182  will attempt to set the attribute with the result of eval'ing the value.
183 
184  Parameters
185  ----------
186  item : obj
187  Object whose attribute is to be set.
188  name : `str`
189  Name of attribute to set.
190  value : obj
191  New value for the attribute.
192 
193  Notes
194  -----
195  For example if name is ``foo.bar.baz`` then ``item.foo.bar.baz``
196  is set to the specified value.
197 
198  Raises
199  ------
200  AttributeError
201  If the item does not have a field specified by name that can be set.
202  RuntimeError
203  If the value can not be set as a string or rendered by eval, or if
204  there is an error setting the attribute with the rendered value.
205  """
206  subitem = item
207  subnameList = name.split(".")
208  for subname in subnameList[:-1]:
209  subitem = getattr(subitem, subname)
210  try:
211  setattr(subitem, subnameList[-1], value)
212  except AttributeError:
213  raise AttributeError(f"No field: {name!r}")
214  except Exception:
215  try:
216  v = eval(value, {})
217  except Exception:
218  raise RuntimeError(f"Cannot render {value!r} as a value for {name!r}")
219  try:
220  setattr(subitem, subnameList[-1], v)
221  except Exception as e:
222  raise RuntimeError(f"Cannot set config. {name}={value!r}: {e}")
223 
224 
225 def setDottedAttrs(item, attrs):
226  for name, value in attrs:
227  setDottedAttr(item, name, value)
An integer coordinate rectangle.
Definition: Box.h:55
Reports invalid arguments.
Definition: Runtime.h:66
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
Definition: SkyWcs.cc:526
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
def doImport(pythonType)
Definition: utils.py:104
def bboxFromIraf(irafBBoxStr)
Definition: utils.py:116
def getInstrument(instrumentName, registry=None)
Definition: utils.py:131
def createInitialSkyWcsFromBoresight(boresight, orientation, detector, flipX=False)
Definition: utils.py:80
def setDottedAttrs(item, attrs)
Definition: utils.py:225
def createInitialSkyWcs(visitInfo, detector, flipX=False)
Definition: utils.py:44
def setDottedAttr(item, name, value)
Definition: utils.py:179