Loading [MathJax]/extensions/tex2jax.js
LSST Applications g04a91732dc+a3f7a6a005,g07dc498a13+5ab4d22ec3,g0fba68d861+870ee37b31,g1409bbee79+5ab4d22ec3,g1a7e361dbc+5ab4d22ec3,g1fd858c14a+11200c7927,g20f46db602+25d63fd678,g35bb328faa+fcb1d3bbc8,g4d2262a081+cc8af5cafb,g4d39ba7253+6b9d64fe03,g4e0f332c67+5d362be553,g53246c7159+fcb1d3bbc8,g60b5630c4e+6b9d64fe03,g78460c75b0+2f9a1b4bcd,g786e29fd12+cf7ec2a62a,g7b71ed6315+fcb1d3bbc8,g8048e755c2+a1301e4c20,g8852436030+a750987b4a,g89139ef638+5ab4d22ec3,g89e1512fd8+a86d53a4aa,g8d6b6b353c+6b9d64fe03,g9125e01d80+fcb1d3bbc8,g989de1cb63+5ab4d22ec3,g9f33ca652e+38ca901d1a,ga9baa6287d+6b9d64fe03,gaaedd4e678+5ab4d22ec3,gabe3b4be73+1e0a283bba,gb1101e3267+aa269f591c,gb58c049af0+f03b321e39,gb90eeb9370+af74afe682,gc741bbaa4f+7f5db660ea,gcf25f946ba+a750987b4a,gd315a588df+b78635c672,gd6cbbdb0b4+c8606af20c,gd9a9a58781+fcb1d3bbc8,gde0f65d7ad+5839af1903,ge278dab8ac+932305ba37,ge82c20c137+76d20ab76d,w.2025.11
LSST Data Management Base Package
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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