Coverage for python/lsst/sims/maf/slicers/opsimFieldSlicer.py : 12%

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.
3import numpy as np
4from functools import wraps
5import warnings
6from lsst.sims.maf.plots.spatialPlotters import OpsimHistogram, BaseSkyMap
8from .baseSpatialSlicer import BaseSpatialSlicer
10__all__ = ['OpsimFieldSlicer']
13class OpsimFieldSlicer(BaseSpatialSlicer):
14 """A spatial slicer that evaluates pointings based on matched IDs between the simData and fieldData.
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).
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.
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
79 def setupSlicer(self, simData, fieldData, maps=None):
80 """Set up opsim field slicer object.
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')
116 self.spatialExtent = [simData[self.simDataFieldIdColName].min(),
117 simData[self.simDataFieldIdColName].max()]
118 self.shape = self.nslice
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)
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