Loading [MathJax]/extensions/tex2jax.js
LSST Applications g04a91732dc+cc8870d3f5,g07dc498a13+5aa0b8792f,g0fba68d861+80045be308,g1409bbee79+5aa0b8792f,g1a7e361dbc+5aa0b8792f,g1fd858c14a+f64bc332a9,g208c678f98+1ae86710ed,g35bb328faa+fcb1d3bbc8,g4d2262a081+47ad8a29a8,g4d39ba7253+9633a327c1,g4e0f332c67+5d362be553,g53246c7159+fcb1d3bbc8,g60b5630c4e+9633a327c1,g668ecb457e+25d63fd678,g78460c75b0+2f9a1b4bcd,g786e29fd12+cf7ec2a62a,g7b71ed6315+fcb1d3bbc8,g8852436030+8b64ca622a,g89139ef638+5aa0b8792f,g89e1512fd8+04325574d3,g8d6b6b353c+9633a327c1,g9125e01d80+fcb1d3bbc8,g989de1cb63+5aa0b8792f,g9f33ca652e+b196626af7,ga9baa6287d+9633a327c1,gaaedd4e678+5aa0b8792f,gabe3b4be73+1e0a283bba,gb1101e3267+71e32094df,gb58c049af0+f03b321e39,gb90eeb9370+2807b1ad02,gcf25f946ba+8b64ca622a,gd315a588df+a39986a76f,gd6cbbdb0b4+c8606af20c,gd9a9a58781+fcb1d3bbc8,gde0f65d7ad+4e42d81ab7,ge278dab8ac+932305ba37,ge82c20c137+76d20ab76d,gfe73954cf8+a1301e4c20,w.2025.11
LSST Data Management Base Package
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
wcs_wrapper.py
Go to the documentation of this file.
1from lsst.geom import Point2D
2
3import galsim
4import numpy as np
5
6
7class CelestialWcsWrapper(galsim.wcs.CelestialWCS):
8 """Wrap a `lsst.afw.geom.SkyWcs` in a GalSim WCS.
9
10 Parameters
11 ----------
12 pix_to_sky : `lsst.afw.geom.SkyWcs`
13 WCS to wrap.
14 origin : `galsim.PositionD`, optional
15 Origin in image coordinates.
16 """
17 def __init__(self, pix_to_sky, origin=None):
18 if origin is None:
19 # Use galsim._PositionD as it's faster than galsim.PositionD
20 origin = galsim._PositionD(0.0, 0.0)
21 self._pix_to_sky = pix_to_sky
22 self._origin = origin
23 self._color = None
24
25 @property
26 def origin(self):
27 """The image coordinate position to use as the origin.
28 """
29 return self._origin
30
31 def _radec(self, x, y, color=None):
32 x1 = np.atleast_1d(x)
33 y1 = np.atleast_1d(y)
34
35 ra, dec = self._pix_to_sky.pixelToSkyArray(x1, y1)
36
37 if np.ndim(x) == np.ndim(y) == 0:
38 return ra[0], dec[0]
39 else:
40 # Sanity checks that the inputs are the same shape.
41 assert np.ndim(x) == np.ndim(y)
42 assert x.shape == y.shape
43 return ra, dec
44
45 def _xy(self, ra, dec, color=None):
46 r1 = np.atleast_1d(ra)
47 d1 = np.atleast_1d(dec)
48
49 x, y = self._pix_to_sky.skyToPixelArray(r1, d1)
50
51 if np.ndim(ra) == np.ndim(dec) == 0:
52 return x[0], y[0]
53 else:
54 # Sanity checks that the inputs are the same shape.
55 assert np.ndim(ra) == np.ndim(dec)
56 assert ra.shape == dec.shape
57 return x, y
58
59 def _newOrigin(self, origin):
60 """Return a new CelestialWcsWrapper with new origin.
61
62 Parameters
63 ----------
64 origin : `galsim.PositionD`, optional
65 Origin in image coordinates.
66
67 Returns
68 -------
69 ret : `CelestialWcsWrapper`
70 Transformed WCS.
71 """
72 return CelestialWcsWrapper(self._pix_to_sky, origin=origin)
73
74
75class UVWcsWrapper(galsim.wcs.EuclideanWCS):
76 """Wrap a `lsst.afw.geom.TransformPoint2ToPoint2[2->2]` in a GalSim WCS.
77
78 Parameters
79 ----------
80 pix_to_field : `lsst.afw.geom.TransformPoint2ToPoint2[2->2]`
81 Transform to wrap. Most likely PIXELS -> FIELD_ANGLE, but other 2D ->
82 2D transforms should be possible.
83 origin : `galsim.PositionD`, optional
84 Origin in image coordinates.
85 world_origin : `galsim.PositionD`, optional
86 Origin in world coordinates.
87
88 Notes
89 -----
90
91 GalSim EuclideanWCS assumes
92 u = ufunc(x-x0, y-y0) + u0
93 v = vfunc(x-x0, y-y0) + v0
94 where u,v are world (likely field angles), and (x, y) are pixels.
95 GalSim also assumes that origin = x0, y0 and world_origin = u0, v0.
96 I might have naively thought that uv(origin) == world_origin, but
97 that appears to not be required. So we're just going to leave both
98 free.
99 """
100 _rad_to_arcsec = 206264.80624709636
101
102 def __init__(self, pix_to_field, origin=None, world_origin=None):
103 if origin is None:
104 # Use galsim._PositionD as it's faster than galsim.PositionD
105 origin = galsim._PositionD(0.0, 0.0)
106 if world_origin is None:
107 world_origin = galsim._PositionD(0.0, 0.0)
108 self._pix_to_field = pix_to_field
109 self._origin = origin
110 self._world_origin = world_origin
111 self._mapping = self._pix_to_field.getMapping()
112 self._color = None
113
114 @property
115 def origin(self):
116 """The image coordinate position to use as the origin.
117 """
118 return self._origin
119
120 @property
121 def world_origin(self):
122 """The world coordinate position to use as the origin.
123 """
124 return self._world_origin
125
126 def _xyTouv(self, x, y, color=None):
127 """Convert image coordinates to world coordinates.
128
129 Parameters
130 ----------
131 x, y : ndarray
132 Image coordinates.
133 color : ndarray
134 Color to use in transformation. Unused currently.
135
136 Returns
137 -------
138 u, v : ndarray
139 World coordinates.
140 """
141 x = x - self.x0
142 y = y - self.y0
143 u, v = self._mapping.applyForward(np.vstack((x, y)))
144 u *= self._rad_to_arcsec
145 v *= self._rad_to_arcsec
146 return u + self.u0, v + self.v0
147
148 def _uvToxy(self, u, v, color):
149 """Convert world coordinates to image coordinates.
150
151 Parameters
152 ----------
153 u, v : ndarray
154 World coordinates.
155 color : ndarray
156 Color to use in transformation. Unused currently.
157
158 Returns
159 -------
160 x, y : ndarray
161 Image coordinates.
162 """
163 u = (u - self.u0)/self._rad_to_arcsec
164 v = (v - self.v0)/self._rad_to_arcsec
165 x, y = self._mapping.applyInverse(np.vstack((u, v)))
166 return x + self.x0, y + self.y0
167
168 def _posToWorld(self, image_pos, color=None):
169 """Convert image coordinate to world coordinate.
170
171 Parameters
172 ----------
173 image_pos : galsim.PositionD
174 Image coordinate.
175 color : ndarray
176 Color to use in transformation. Unused currently.
177
178 Returns
179 -------
180 world_pos : galsim.PositionD
181 World coordinate.
182 """
183 # Use galsim._PositionD as it's faster than galsim.PositionD
184 return galsim._PositionD(*self._xyTouv(image_pos.x, image_pos.y, color))
185
186 def _local(self, image_pos, color=None):
187 """Compute local Jacobian WCS.
188
189 Parameters
190 ----------
191 image_pos : galsim.PositionD
192 Image position at which to compute local WCS.
193 color : ndarray
194 Color to use in transformation. Unused currently.
195
196 Returns
197 -------
198 local : galsim.JacobianWCS
199 Local linear approximation to WCS.
200 """
201 x0 = image_pos.x - self.x0
202 y0 = image_pos.y - self.y0
203
204 duvdxy = self._pix_to_field.getJacobian(Point2D(x0, y0))
205 return galsim.JacobianWCS(
206 *(duvdxy.ravel()*self._rad_to_arcsec)
207 )
208
209 def _newOrigin(self, origin, world_origin):
210 """Return a new UVWcsWrapper with new origins.
211
212 Parameters
213 ----------
214 origin : `galsim.PositionD`, optional
215 Origin in image coordinates.
216 world_origin : `galsim.PositionD`, optional
217 Origin in world coordinates.
218
219 Returns
220 -------
221 ret : `UVWcsWrapper`
222 Transformed WCS.
223 """
224 return UVWcsWrapper(self._pix_to_field, origin, world_origin)
__init__(self, pix_to_field, origin=None, world_origin=None)