| 1 |  |  | from astropy.io import fits | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | from astropy.wcs import WCS | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | from astropy.wcs.utils import proj_plane_pixel_area | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | import numpy as np | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | from util import cartesian | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | from hawc_hal.sphere_dist import sphere_dist | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | _fits_header = """ | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | NAXIS   =                    2 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | NAXIS1  =                   %i | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | NAXIS2  =                   %i | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | CTYPE1  = 'RA---AIT' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  | CRPIX1  =                   %i | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  | CRVAL1  =                   %s | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  | CDELT1  =                  -%f | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  | CUNIT1  = 'deg     ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  | CTYPE2  = 'DEC--AIT' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  | CRPIX2  =                   %i | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  | CRVAL2  =                   %s | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  | CDELT2  =                   %f | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  | CUNIT2  = 'deg     ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  | COORDSYS= '%s' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  | """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  | def _get_header(ra, dec, pixel_size, coordsys, h, w): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                            
                                                                                            
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |     assert 0 <= ra <= 360 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |     header = fits.Header.fromstring(_fits_header % (h, w, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |                                                     h / 2, ra, pixel_size, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |                                                     w / 2, dec, pixel_size, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |                                                     coordsys), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |                                     sep='\n') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     return header | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  | def _get_all_ra_dec(input_wcs, h, w): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |     # An array of all the possible permutation of (i,j) for i=0..999 and j=0..999 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |     xx = np.arange(0.5, h + 0.5, 1, dtype=np.int16) | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |     yy = np.arange(0.5, w + 0.5, 1, dtype=np.int16) | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |     _ij_grid = cartesian((xx, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |                           yy)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |     # Convert pixel coordinates to world coordinates | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |     world = input_wcs.all_pix2world(_ij_grid, 0, ra_dec_order=True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |     return world[:, 0], world[:, 1] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  | class FlatSkyProjection(object): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     def __init__(self, ra_center, dec_center, pixel_size_deg, npix_height, npix_width): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |         assert npix_height % 2 == 0, "Number of height pixels must be even" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         assert npix_width % 2 == 0, "Number of width pixels must be even" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         if isinstance(npix_height, float): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |             assert npix_height.is_integer(), "This is a bug" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         if isinstance(npix_width, float): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |             assert npix_width.is_integer(), "This is a bug" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |         self._npix_height = int(npix_height) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |         self._npix_width = int(npix_width) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |         assert 0 <= ra_center <= 360.0, "Right Ascension must be between 0 and 360" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |         assert -90.0 <= dec_center <= 90.0, "Declination must be between -90.0 and 90.0" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |         self._ra_center = float(ra_center) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |         self._dec_center = float(dec_center) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |         self._pixel_size_deg = float(pixel_size_deg) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |         # Build projection, i.e., a World Coordinate System object | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |         self._wcs = WCS(_get_header(ra_center, dec_center, pixel_size_deg, 'icrs', npix_height, npix_width)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |         # Pre-compute all R.A., Decs | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |         self._ras, self._decs = _get_all_ra_dec(self._wcs, npix_height, npix_width) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |         # Make sure we have the right amount of coordinates | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |         assert self._ras.shape[0] == self._decs.shape[0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |         assert self._ras.shape[0] == npix_width * npix_height | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |         # Pre-compute pixel area | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |         self._pixel_area = proj_plane_pixel_area(self._wcs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |         # Pre-compute an oversampled version to be used for PSF integration | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |         # if oversample and pixel_size_deg > 0.025: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |         # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |         #     self._oversampled, self._oversample_factor = self._oversample(new_pixel_size=0.025) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |         # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |         # else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |         # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |         #     self._oversampled = self | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |         #     self._oversample_factor = 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |         # Cache for angular distances from a point (see get_spherical_distances_from) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |         self._distance_cache = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |     # def _oversample(self, new_pixel_size): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |     #     """Return a new instance oversampled by the provided factor""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |     #     # Compute the oversampling factor (as a float because we need it for the division down) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |     #     factor = float(np.ceil(self._pixel_size_deg / new_pixel_size)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |     #     if factor <= 1: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |     #         # The projection is already with a smaller pixel size than the oversampled version | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |     #         # No need to oversample | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |     #         return self, 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |     #     else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |     #         new_fp = FlatSkyProjection(self._ra_center, self._dec_center, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |     #                                    self._pixel_size_deg / factor, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |     #                                    self._npix_height * factor, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |     #                                    self._npix_width * factor, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |     #                                    oversample=False) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |     #         return new_fp, int(factor) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |     # @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |     # def oversampled(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |     #     return self._oversampled | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 135 |  |  |     # | 
            
                                                                        
                            
            
                                    
            
            
                | 136 |  |  |     # @property | 
            
                                                                        
                            
            
                                    
            
            
                | 137 |  |  |     # def oversample_factor(self): | 
            
                                                                        
                            
            
                                    
            
            
                | 138 |  |  |     #     return self._oversample_factor | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |     def ras(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |         :return: Right Ascension for all pixels | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |         return self._ras | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |     def decs(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |         :return: Declination for all pixels | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |         return self._decs | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |     def ra_center(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |         :return: R.A. for the center of the projection | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |         return self._ra_center | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |     def dec_center(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |         :return: Declination for the center of the projection | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |         return self._dec_center | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |     def pixel_size(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  |         :return: size (in deg) of the pixel | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |         return self._pixel_size_deg | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  |     def wcs(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  |         :return: World Coordinate System instance describing the projection | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |         return self._wcs | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |     def npix_height(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |         :return: height of the projection in pixels | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 |  |  |         return self._npix_height | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 189 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 190 |  |  |     def npix_width(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 191 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 192 |  |  |         :return: width of the projection in pixels | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |         return self._npix_width | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  |     def project_plane_pixel_area(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  |         :return: area of the pixels (remember, this is an equal-area projection so all pixels are equal) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 |  |  |         return self._pixel_area | 
            
                                                                                                            
                            
            
                                    
            
            
                | 202 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 203 |  |  |     # def get_spherical_distances_from(self, ra, dec, cutout_radius): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 204 |  |  |     #     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 205 |  |  |     #     Returns the distances for all points in this grid from the given point | 
            
                                                                                                            
                            
            
                                    
            
            
                | 206 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 207 |  |  |     #     :param ra: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 208 |  |  |     #     :param dec: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 209 |  |  |     #     :param cutout_radius: do not consider elements beyond this radius (NOTE: we use a planar approximation on | 
            
                                                                                                            
                            
            
                                    
            
            
                | 210 |  |  |     #     purpose, to make things fast, so the cut is not precise) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 211 |  |  |     #     :return: (angular distances of selected points from (ra, dec), selection indexes) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 212 |  |  |     #     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 213 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 214 |  |  |     #     # This is typically used sequentially on different energy bins, so we cache the result and re-use it | 
            
                                                                                                            
                            
            
                                    
            
            
                | 215 |  |  |     #     # if we already computed it | 
            
                                                                                                            
                            
            
                                    
            
            
                | 216 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 217 |  |  |     #     key = (ra, dec, cutout_radius, self.ras.shape[0], self.decs.shape[0]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 218 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 219 |  |  |     #     if key not in self._distance_cache: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 220 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 221 |  |  |     #         # In order to gain speed, we use a planar approximation (instead of using the harversine formula we assume | 
            
                                                                                                            
                            
            
                                    
            
            
                | 222 |  |  |     #         # plane geometry). This gets more and more unprecise the large the cutout radius, but we do not care here | 
            
                                                                                                            
                            
            
                                    
            
            
                | 223 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 224 |  |  |     #         selection_idx = (((ra - self.ras)**2 + (dec - self.decs)**2) <= (1.2*cutout_radius)**2)  # type: np.ndarray | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 225 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 226 |  |  |     #         ds = sphere_dist(ra, dec, self.ras[selection_idx], self.decs[selection_idx]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 227 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 228 |  |  |     #         # Refine selection by putting to False all elements in the mask at a distance larger than the cutout | 
            
                                                                                                            
                            
            
                                    
            
            
                | 229 |  |  |     #         # radius | 
            
                                                                                                            
                            
            
                                    
            
            
                | 230 |  |  |     #         fine_selection_idx = (ds <= cutout_radius) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 231 |  |  |     #         selection_idx[selection_idx.nonzero()[0][~fine_selection_idx]] = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 232 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 233 |  |  |     #         # This is to make sure we only keep cached the last result, and the dictionary does not grow indefinitely | 
            
                                                                                                            
                            
            
                                    
            
            
                | 234 |  |  |     #         self._distance_cache = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 235 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 236 |  |  |     #         self._distance_cache[key] = (ds[fine_selection_idx], selection_idx) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 237 |  |  |     # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 238 |  |  |     #     return self._distance_cache[key] | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 239 |  |  |  | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                        
            
                                    
            
            
                | 240 |  |  |  | 
            
                        
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.