Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import numpy as np 

2import healpy as hp 

3from .healpixSlicer import HealpixSlicer 

4import warnings 

5from functools import wraps 

6import lsst.sims.utils as simsUtils 

7import matplotlib.path as mplPath 

8from lsst.sims.maf.utils.mafUtils import gnomonic_project_toxy 

9 

10 

11__all__ = ['HealpixComCamSlicer'] 

12 

13 

14# The names of the chips in the central raft, aka, ComCam 

15center_raft_chips = ['R:2,2 S:0,0', 'R:2,2 S:0,1', 'R:2,2 S:0,2', 

16 'R:2,2 S:1,0', 'R:2,2 S:1,1', 'R:2,2 S:1,2', 

17 'R:2,2 S:2,0', 'R:2,2 S:2,1', 'R:2,2 S:2,2'] 

18 

19 

20class HealpixComCamSlicer(HealpixSlicer): 

21 """Slicer that uses the ComCam footprint to decide if observations overlap a healpixel center 

22 """ 

23 

24 def __init__(self, nside=128, lonCol='fieldRA', 

25 latCol='fieldDec', latLonDeg=True, verbose=True, badval=hp.UNSEEN, 

26 useCache=True, leafsize=100, 

27 useCamera=False, rotSkyPosColName='rotSkyPos', 

28 mjdColName='observationStartMJD', chipNames=center_raft_chips, side_length=0.7): 

29 """ 

30 Parameters 

31 ---------- 

32 side_length : float (0.7) 

33 How large is a side of the raft (degrees) 

34 """ 

35 radius = side_length/2.*np.sqrt(2.) 

36 super(HealpixComCamSlicer, self).__init__(nside=nside, lonCol=lonCol, latCol=latCol, 

37 latLonDeg=latLonDeg, 

38 verbose=verbose, badval=badval, useCache=useCache, 

39 leafsize=leafsize, radius=radius, useCamera=useCamera, 

40 rotSkyPosColName=rotSkyPosColName, 

41 mjdColName=mjdColName, chipNames=chipNames) 

42 self.side_length = np.radians(side_length) 

43 self.corners_x = np.array([-self.side_length/2., -self.side_length/2., self.side_length/2., 

44 self.side_length/2.]) 

45 self.corners_y = np.array([self.side_length/2., -self.side_length/2., -self.side_length/2., 

46 self.side_length/2.]) 

47 # Need the rotation even if not using the camera 

48 self.columnsNeeded.append(rotSkyPosColName) 

49 self.columnsNeeded = list(set(self.columnsNeeded)) 

50 

51 # The 3D search radius for things inside the raft 

52 self.side_radius = simsUtils.xyz_angular_radius(side_length/2.) 

53 

54 def setupSlicer(self, simData, maps=None): 

55 """Use simData[self.lonCol] and simData[self.latCol] (in radians) to set up KDTree. 

56 

57 Parameters 

58 ----------- 

59 simData : numpy.recarray 

60 The simulated data, including the location of each pointing. 

61 maps : list of lsst.sims.maf.maps objects, optional 

62 List of maps (such as dust extinction) that will run to build up additional metadata at each 

63 slicePoint. This additional metadata is available to metrics via the slicePoint dictionary. 

64 Default None. 

65 """ 

66 if maps is not None: 

67 if self.cacheSize != 0 and len(maps) > 0: 

68 warnings.warn('Warning: Loading maps but cache on.' 

69 'Should probably set useCache=False in slicer.') 

70 self._runMaps(maps) 

71 self._setRad(self.radius) 

72 if self.useCamera: 

73 self._setupLSSTCamera() 

74 self._presliceFootprint(simData) 

75 else: 

76 if self.latLonDeg: 

77 self._buildTree(np.radians(simData[self.lonCol]), 

78 np.radians(simData[self.latCol]), self.leafsize) 

79 else: 

80 self._buildTree(simData[self.lonCol], simData[self.latCol], self.leafsize) 

81 

82 @wraps(self._sliceSimData) 

83 def _sliceSimData(islice): 

84 """Return indexes for relevant opsim data at slicepoint 

85 (slicepoint=lonCol/latCol value .. usually ra/dec).""" 

86 

87 # Build dict for slicePoint info 

88 slicePoint = {} 

89 if self.useCamera: 

90 indices = self.sliceLookup[islice] 

91 slicePoint['chipNames'] = self.chipNames[islice] 

92 else: 

93 sx, sy, sz = simsUtils._xyz_from_ra_dec(self.slicePoints['ra'][islice], 

94 self.slicePoints['dec'][islice]) 

95 # Anything within half the side length is good no matter what rotation angle 

96 # the camera is at 

97 indices = self.opsimtree.query_ball_point((sx, sy, sz), self.side_radius) 

98 # Now the larger radius. Need to make it an array for easy subscripting 

99 initial_indices = np.array(self.opsimtree.query_ball_point((sx, sy, sz), self.rad), dtype=int) 

100 # remove the indices we already know about 

101 initial_indices = initial_indices[np.in1d(initial_indices, indices, invert=True)] 

102 

103 if self.latLonDeg: 

104 lat = np.radians(simData[self.latCol][initial_indices]) 

105 lon = np.radians(simData[self.lonCol][initial_indices]) 

106 cos_rot = np.cos(np.radians(simData[self.rotSkyPosColName][initial_indices])) 

107 sin_rot = np.cos(np.radians(simData[self.rotSkyPosColName][initial_indices])) 

108 else: 

109 lat = simData[self.latCol][initial_indices] 

110 lon = simData[self.lonCol][initial_indices] 

111 cos_rot = np.cos(simData[self.rotSkyPosColName][initial_indices]) 

112 sin_rot = np.sin(simData[self.rotSkyPosColName][initial_indices]) 

113 # loop over the observations that might be overlapping the healpix, check each 

114 for i, ind in enumerate(initial_indices): 

115 # Rotate the camera 

116 x_rotated = self.corners_x*cos_rot[i] - self.corners_y*sin_rot[i] 

117 y_rotated = self.corners_x*sin_rot[i] + self.corners_y*cos_rot[i] 

118 # How far is the pointing center from the healpix center 

119 xshift, yshift = gnomonic_project_toxy(lon[i], lat[i], self.slicePoints['ra'][islice], 

120 self.slicePoints['dec'][islice]) 

121 

122 x_rotated += xshift 

123 y_rotated += yshift 

124 # Use matplotlib to make a polygon 

125 bbPath = mplPath.Path(np.array([[x_rotated[0], y_rotated[0]], 

126 [x_rotated[1], y_rotated[1]], 

127 [x_rotated[2], y_rotated[2]], 

128 [x_rotated[3], y_rotated[3]], 

129 [x_rotated[0], y_rotated[0]]])) 

130 # Check if the slicepoint is inside the image corners and append to list 

131 if bbPath.contains_point((0., 0.)): 

132 indices.append(ind) 

133 

134 # Loop through all the slicePoint keys. If the first dimension of slicepoint[key] has 

135 # the same shape as the slicer, assume it is information per slicepoint. 

136 # Otherwise, pass the whole slicePoint[key] information. Useful for stellar LF maps 

137 # where we want to pass only the relevant LF and the bins that go with it. 

138 

139 for key in self.slicePoints: 

140 if len(np.shape(self.slicePoints[key])) == 0: 

141 keyShape = 0 

142 else: 

143 keyShape = np.shape(self.slicePoints[key])[0] 

144 if (keyShape == self.nslice): 

145 slicePoint[key] = self.slicePoints[key][islice] 

146 else: 

147 slicePoint[key] = self.slicePoints[key] 

148 

149 return {'idxs': indices, 'slicePoint': slicePoint} 

150 setattr(self, '_sliceSimData', _sliceSimData)