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

1# Class for opsim field based slicer. 

2 

3import numpy as np 

4from functools import wraps 

5import warnings 

6from lsst.sims.maf.plots.spatialPlotters import OpsimHistogram, BaseSkyMap 

7 

8from .baseSpatialSlicer import BaseSpatialSlicer 

9 

10__all__ = ['OpsimFieldSlicer'] 

11 

12 

13class OpsimFieldSlicer(BaseSpatialSlicer): 

14 """A spatial slicer that evaluates pointings based on matched IDs between the simData and fieldData. 

15 

16 Note that this slicer uses the fieldId of the simulated data fields to generate the spatial matches. 

17 Thus, it is not suitable for use in evaluating dithering or high resolution metrics 

18 (use the HealpixSlicer instead for those use-cases). 

19 

20 When the slicer is set up, it takes two arrays: fieldData and simData. FieldData is a numpy.recarray 

21 containing the information about the fields - this is the basis for slicing. 

22 The simData is a numpy.recarray that holds the information about the pointings - this is the data that 

23 is matched against the fieldData. 

24 

25 Parameters 

26 ---------- 

27 simDataFieldIDColName : str, optional 

28 Name of the column in simData for the fieldId 

29 Default fieldId. 

30 simDataFieldRaColName : str, optional 

31 Name of the column in simData for the RA. 

32 Default fieldRA. 

33 simDataFieldDecColName : str, optional 

34 Name of the column in simData for the fieldDec. 

35 Default fieldDec. 

36 latLongDeg : bool, optional 

37 Whether the RA/Dec values in *fieldData* are in degrees. 

38 If using a standard metricBundleGroup to run the metric, FieldData is fetched 

39 by utils.getFieldData, which always returns radians (so the default here is False). 

40 fieldIdColName : str, optional 

41 Name of the column in the fieldData for the fieldId (to match with simData). 

42 Default fieldId. 

43 fieldRaColName : str, optional 

44 Name of the column in the fieldData for the RA (used for plotting). 

45 Default fieldRA. 

46 fieldDecColName : str, optional 

47 Name of the column in the fieldData for the Dec (used for plotting). 

48 Default fieldDec. 

49 verbose : boolean, optional 

50 Flag to indicate whether or not to write additional information to stdout during runtime. 

51 Default True. 

52 badval : float, optional 

53 Bad value flag, relevant for plotting. Default -666. 

54 """ 

55 def __init__(self, simDataFieldIdColName='fieldId', 

56 simDataFieldRaColName='fieldRA', simDataFieldDecColName='fieldDec', latLonDeg=False, 

57 fieldIdColName='fieldId', fieldRaColName='fieldRA', fieldDecColName='fieldDec', 

58 verbose=True, badval=-666): 

59 super(OpsimFieldSlicer, self).__init__(verbose=verbose, badval=badval) 

60 self.fieldId = None 

61 self.simDataFieldIdColName = simDataFieldIdColName 

62 self.fieldIdColName = fieldIdColName 

63 self.fieldRaColName = fieldRaColName 

64 self.fieldDecColName = fieldDecColName 

65 self.latLonDeg = latLonDeg 

66 self.columnsNeeded = [simDataFieldIdColName, simDataFieldRaColName, simDataFieldDecColName] 

67 while '' in self.columnsNeeded: 

68 self.columnsNeeded.remove('') 

69 self.fieldColumnsNeeded = [fieldIdColName, fieldRaColName, fieldDecColName] 

70 self.slicer_init = {'simDataFieldIdColName': simDataFieldIdColName, 

71 'simDataFieldRaColName': simDataFieldRaColName, 

72 'simDataFieldDecColName': simDataFieldDecColName, 

73 'fieldIdColName': fieldIdColName, 

74 'fieldRaColName': fieldRaColName, 

75 'fieldDecColName': fieldDecColName, 'badval': badval} 

76 self.plotFuncs = [BaseSkyMap, OpsimHistogram] 

77 self.needsFields = True 

78 

79 def setupSlicer(self, simData, fieldData, maps=None): 

80 """Set up opsim field slicer object. 

81 

82 Parameters 

83 ----------- 

84 simData : numpy.recarray 

85 Contains the simulation pointing history. 

86 fieldData : numpy.recarray 

87 Contains the field information (ID, Ra, Dec) about how to slice the simData. 

88 For example, only fields in the fieldData table will be matched against the simData. 

89 RA and Dec should be in degrees. 

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

91 Maps to run and provide additional metadata at each slicePoint. Default None. 

92 """ 

93 if hasattr(self, 'slicePoints'): 

94 warning_msg = 'Warning: this OpsimFieldSlicer was already set up once. ' 

95 warning_msg += 'Re-setting up an OpsimFieldSlicer can change the field information. ' 

96 warning_msg += 'Rerun metrics if this was intentional. ' 

97 warnings.warn(warning_msg) 

98 # Set basic properties for tracking field information, in sorted order. 

99 idxs = np.argsort(fieldData[self.fieldIdColName]) 

100 # Set needed values for slice metadata. 

101 self.slicePoints['sid'] = fieldData[self.fieldIdColName][idxs] 

102 if self.latLonDeg: 

103 self.slicePoints['ra'] = np.radians(fieldData[self.fieldRaColName][idxs]) 

104 self.slicePoints['dec'] = np.radians(fieldData[self.fieldDecColName][idxs]) 

105 else: 

106 self.slicePoints['ra'] = fieldData[self.fieldRaColName][idxs] 

107 self.slicePoints['dec'] = fieldData[self.fieldDecColName][idxs] 

108 self.nslice = len(self.slicePoints['sid']) 

109 self._runMaps(maps) 

110 # Set up data slicing. 

111 self.simIdxs = np.argsort(simData[self.simDataFieldIdColName]) 

112 simFieldsSorted = np.sort(simData[self.simDataFieldIdColName]) 

113 self.left = np.searchsorted(simFieldsSorted, self.slicePoints['sid'], 'left') 

114 self.right = np.searchsorted(simFieldsSorted, self.slicePoints['sid'], 'right') 

115 

116 self.spatialExtent = [simData[self.simDataFieldIdColName].min(), 

117 simData[self.simDataFieldIdColName].max()] 

118 self.shape = self.nslice 

119 

120 @wraps(self._sliceSimData) 

121 def _sliceSimData(islice): 

122 idxs = self.simIdxs[self.left[islice]:self.right[islice]] 

123 # Build dict for slicePoint info 

124 slicePoint = {} 

125 for key in self.slicePoints: 

126 if (np.shape(self.slicePoints[key])[0] == self.nslice) & \ 

127 (key is not 'bins') & (key is not 'binCol'): 

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

129 else: 

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

131 return {'idxs': idxs, 'slicePoint': slicePoint} 

132 setattr(self, '_sliceSimData', _sliceSimData) 

133 

134 def __eq__(self, otherSlicer): 

135 """Evaluate if two grids are equivalent.""" 

136 result = False 

137 if isinstance(otherSlicer, OpsimFieldSlicer): 

138 if np.all(otherSlicer.shape == self.shape): 

139 # Check if one or both slicers have been setup 

140 if (self.slicePoints['ra'] is not None) or (otherSlicer.slicePoints['ra'] is not None): 

141 if (np.array_equal(self.slicePoints['ra'], otherSlicer.slicePoints['ra']) & 

142 np.array_equal(self.slicePoints['dec'], otherSlicer.slicePoints['dec']) & 

143 np.array_equal(self.slicePoints['sid'], otherSlicer.slicePoints['sid'])): 

144 result = True 

145 # If they have not been setup, check that they have same fields 

146 elif ((otherSlicer.fieldIdColName == self.fieldIdColName) & 

147 (otherSlicer.fieldRaColName == self.fieldRaColName) & 

148 (otherSlicer.fieldDecColName == self.fieldDecColName)): 

149 result = True 

150 return result