LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
pupil.py
Go to the documentation of this file.
1# This file is part of afw.
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__ = ['PupilFactory', 'Pupil']
23
24import numpy as np
25
26
27class Pupil:
28 """Pupil obscuration function.
29
30 Parameters
31 ----------
32 illuminated : `numpy.ndarray`, (Nx, Ny)
33 2D numpy array indicating which parts of the pupil plane are
34 illuminated.
35 size : `float`
36 Size of pupil plane array in meters. Note that this may be larger
37 than the actual diameter of the illuminated pupil to accommodate
38 zero-padding.
39 scale : `float`
40 Sampling interval of pupil plane array in meters.
41 """
42
43 def __init__(self, illuminated, size, scale):
44 self.illuminated = illuminated
45 self.size = size
46 self.scale = scale
47
48
50 """Pupil obscuration function factory for use with Fourier optics.
51
52 Parameters
53 ----------
54 visitInfo : `lsst.afw.image.VisitInfo`
55 Visit information for a particular exposure.
56 pupilSize : `float`
57 Size in meters of constructed Pupil array.
58 Note that this may be larger than the actual diameter of the
59 illuminated pupil to accommodate zero-padding.
60 npix : `int`
61 Constructed Pupils will be npix x npix.
62 """
63
64 def __init__(self, visitInfo, pupilSize, npix):
65 self.visitInfo = visitInfo
66 self.pupilSize = pupilSize
67 self.npix = npix
68 self.pupilScale = pupilSize/npix
69 u = (np.arange(npix, dtype=np.float64) - (npix - 1)/2) * self.pupilScale
70 self.u, self.v = np.meshgrid(u, u)
71
72 def getPupil(self, point):
73 """Calculate a Pupil at a given point in the focal plane.
74
75 Parameters
76 ----------
77 point : `lsst.geom.Point2D`
78 The focal plane coordinates.
79
80 Returns
81 -------
82 pupil : `Pupil`
83 The Pupil at ``point``.
84 """
85 raise NotImplementedError(
86 "PupilFactory not implemented for this camera")
87
88 @staticmethod
89 def _pointLineDistance(p0, p1, p2):
90 """Compute the right-angle distance between the points given by `p0`
91 and the line that passes through `p1` and `p2`.
92
93 Parameters
94 ----------
95 p0 : `tuple` of `numpy.ndarray`
96 2-tuple of numpy arrays (x, y focal plane coordinates)
97 p1 : ``pair`` of `float`
98 x,y focal plane coordinates
99 p2 : ``pair`` of `float`
100 x,y focal plane coordinates
101
102 Returns
103 -------
104 distances : `numpy.ndarray`
105 Numpy array of distances; shape congruent to p0[0].
106 """
107 x0, y0 = p0
108 x1, y1 = p1
109 x2, y2 = p2
110 dy21 = y2 - y1
111 dx21 = x2 - x1
112 return np.abs(dy21*x0 - dx21*y0 + x2*y1 - y2*x1)/np.hypot(dy21, dx21)
113
114 def _fullPupil(self):
115 """Make a fully-illuminated Pupil.
116
117 Returns
118 -------
119 pupil : `Pupil`
120 The illuminated pupil.
121 """
122 illuminated = np.ones(self.u.shape, dtype=bool)
123 return Pupil(illuminated, self.pupilSize, self.pupilScale)
124
125 def _cutCircleInterior(self, pupil, p0, r):
126 """Cut out the interior of a circular region from a Pupil.
127
128 Parameters
129 ----------
130 pupil : `Pupil`
131 Pupil to modify in place.
132 p0 : `pair`` of `float`
133 2-tuple indicating region center.
134 r : `float`
135 Circular region radius.
136 """
137 r2 = (self.u - p0[0])**2 + (self.v - p0[1])**2
138 pupil.illuminated[r2 < r**2] = False
139
140 def _cutCircleExterior(self, pupil, p0, r):
141 """Cut out the exterior of a circular region from a Pupil.
142
143 Parameters
144 ----------
145 pupil : `Pupil`
146 Pupil to modify in place
147 p0 : `pair`` of `float`
148 2-tuple indicating region center.
149 r : `float`
150 Circular region radius.
151 """
152 r2 = (self.u - p0[0])**2 + (self.v - p0[1])**2
153 pupil.illuminated[r2 > r**2] = False
154
155 def _cutRay(self, pupil, p0, angle, thickness):
156 """Cut out a ray from a Pupil.
157
158 Parameters
159 ----------
160 pupil : `Pupil`
161 Pupil to modify in place.
162 p0 : `pair`` of `float`
163 2-tuple indicating ray starting point.
164 angle : `pair` of `float`
165 Ray angle measured CCW from +x.
166 thickness : `float`
167 Thickness of cutout.
168 """
169 angleRad = angle.asRadians()
170 # the 1 is arbitrary, just need something to define another point on
171 # the line
172 p1 = (p0[0] + 1, p0[1] + np.tan(angleRad))
173 d = PupilFactory._pointLineDistance((self.u, self.v), p0, p1)
174 pupil.illuminated[(d < 0.5*thickness)
175 & ((self.u - p0[0])*np.cos(angleRad)
176 + (self.v - p0[1])*np.sin(angleRad) >= 0)] = False
177
178 def _centerPupil(self, pupil):
179 """Center the illuminated portion of the pupil in array.
180
181 Parameters
182 ----------
183 pupil : `Pupil`
184 Pupil to modify in place
185 """
186 def center(arr, axis):
187 smash = np.sum(arr, axis=axis)
188 w = np.where(smash)[0]
189 return int(0.5*(np.min(w)+np.max(w)))
190 ycenter = center(pupil.illuminated, 0)
191 xcenter = center(pupil.illuminated, 1)
192 ytarget = pupil.illuminated.shape[0]//2
193 xtarget = pupil.illuminated.shape[1]//2
194 pupil.illuminated = np.roll(np.roll(pupil.illuminated,
195 xtarget-xcenter,
196 axis=0),
197 ytarget-ycenter,
198 axis=1)
_cutRay(self, pupil, p0, angle, thickness)
Definition pupil.py:155
__init__(self, visitInfo, pupilSize, npix)
Definition pupil.py:64
_cutCircleExterior(self, pupil, p0, r)
Definition pupil.py:140
_cutCircleInterior(self, pupil, p0, r)
Definition pupil.py:125
__init__(self, illuminated, size, scale)
Definition pupil.py:43