22 __all__ = [
'PupilFactory', 
'Pupil']
 
   28     """Pupil obscuration function. 
   32     illuminated : `numpy.ndarray`, (Nx, Ny) 
   33         2D numpy array indicating which parts of the pupil plane are 
   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 
   40         Sampling interval of pupil plane array in meters. 
   50     """Pupil obscuration function factory for use with Fourier optics. 
   54     visitInfo : `lsst.afw.image.VisitInfo` 
   55         Visit information for a particular exposure. 
   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. 
   61         Constructed Pupils will be npix x npix. 
   64     def __init__(self, visitInfo, pupilSize, npix):
 
   69         u = (np.arange(npix, dtype=np.float64) - (npix - 1)/2) * self.
pupilScale 
   70         self.u, self.
v = np.meshgrid(u, u)
 
   73         """Calculate a Pupil at a given point in the focal plane. 
   77         point : `lsst.geom.Point2D` 
   78           The focal plane coordinates. 
   83             The Pupil at ``point``. 
   85         raise NotImplementedError(
 
   86             "PupilFactory not implemented for this camera")
 
   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`. 
   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 
  104         distances : `numpy.ndarray` 
  105             Numpy array of distances; shape congruent to p0[0]. 
  112         return np.abs(dy21*x0 - dx21*y0 + x2*y1 - y2*x1)/np.hypot(dy21, dx21)
 
  114     def _fullPupil(self):
 
  115         """Make a fully-illuminated Pupil. 
  120             The illuminated pupil. 
  122         illuminated = np.ones(self.u.shape, dtype=np.bool)
 
  125     def _cutCircleInterior(self, pupil, p0, r):
 
  126         """Cut out the interior of a circular region from a Pupil. 
  131             Pupil to modify in place. 
  132         p0 : `pair`` of `float` 
  133             2-tuple indicating region center. 
  135             Circular region radius. 
  137         r2 = (self.u - p0[0])**2 + (self.
v - p0[1])**2
 
  138         pupil.illuminated[r2 < r**2] = 
False 
  140     def _cutCircleExterior(self, pupil, p0, r):
 
  141         """Cut out the exterior of a circular region from a Pupil. 
  146             Pupil to modify in place 
  147         p0 : `pair`` of `float` 
  148             2-tuple indicating region center. 
  150             Circular region radius. 
  152         r2 = (self.u - p0[0])**2 + (self.
v - p0[1])**2
 
  153         pupil.illuminated[r2 > r**2] = 
False 
  155     def _cutRay(self, pupil, p0, angle, thickness):
 
  156         """Cut out a ray from a 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. 
  169         angleRad = angle.asRadians()
 
  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 
  178     def _centerPupil(self, pupil):
 
  179         """Center the illuminated portion of the pupil in array. 
  184             Pupil to modify in place 
  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,