Source code for lsst.sims.maf.slicers.opsimFieldSlicer

# Class for opsim field based slicer.

import numpy as np
from functools import wraps
import warnings
from lsst.sims.maf.plots.spatialPlotters import OpsimHistogram, BaseSkyMap

from .baseSpatialSlicer import BaseSpatialSlicer

__all__ = ['OpsimFieldSlicer']


[docs]class OpsimFieldSlicer(BaseSpatialSlicer): """A spatial slicer that evaluates pointings based on matched IDs between the simData and fieldData. Note that this slicer uses the fieldId of the simulated data fields to generate the spatial matches. Thus, it is not suitable for use in evaluating dithering or high resolution metrics (use the HealpixSlicer instead for those use-cases). When the slicer is set up, it takes two arrays: fieldData and simData. FieldData is a numpy.recarray containing the information about the fields - this is the basis for slicing. The simData is a numpy.recarray that holds the information about the pointings - this is the data that is matched against the fieldData. Parameters ---------- simDataFieldIDColName : str, optional Name of the column in simData for the fieldId Default fieldId. simDataFieldRaColName : str, optional Name of the column in simData for the RA. Default fieldRA. simDataFieldDecColName : str, optional Name of the column in simData for the fieldDec. Default fieldDec. latLongDeg : bool, optional Whether the RA/Dec values in *fieldData* are in degrees. If using a standard metricBundleGroup to run the metric, FieldData is fetched by utils.getFieldData, which always returns radians (so the default here is False). fieldIdColName : str, optional Name of the column in the fieldData for the fieldId (to match with simData). Default fieldId. fieldRaColName : str, optional Name of the column in the fieldData for the RA (used for plotting). Default fieldRA. fieldDecColName : str, optional Name of the column in the fieldData for the Dec (used for plotting). Default fieldDec. verbose : boolean, optional Flag to indicate whether or not to write additional information to stdout during runtime. Default True. badval : float, optional Bad value flag, relevant for plotting. Default -666. """ def __init__(self, simDataFieldIdColName='fieldId', simDataFieldRaColName='fieldRA', simDataFieldDecColName='fieldDec', latLonDeg=False, fieldIdColName='fieldId', fieldRaColName='fieldRA', fieldDecColName='fieldDec', verbose=True, badval=-666): super(OpsimFieldSlicer, self).__init__(verbose=verbose, badval=badval) self.fieldId = None self.simDataFieldIdColName = simDataFieldIdColName self.fieldIdColName = fieldIdColName self.fieldRaColName = fieldRaColName self.fieldDecColName = fieldDecColName self.latLonDeg = latLonDeg self.columnsNeeded = [simDataFieldIdColName, simDataFieldRaColName, simDataFieldDecColName] while '' in self.columnsNeeded: self.columnsNeeded.remove('') self.fieldColumnsNeeded = [fieldIdColName, fieldRaColName, fieldDecColName] self.slicer_init = {'simDataFieldIdColName': simDataFieldIdColName, 'simDataFieldRaColName': simDataFieldRaColName, 'simDataFieldDecColName': simDataFieldDecColName, 'fieldIdColName': fieldIdColName, 'fieldRaColName': fieldRaColName, 'fieldDecColName': fieldDecColName, 'badval': badval} self.plotFuncs = [BaseSkyMap, OpsimHistogram] self.needsFields = True
[docs] def setupSlicer(self, simData, fieldData, maps=None): """Set up opsim field slicer object. Parameters ----------- simData : numpy.recarray Contains the simulation pointing history. fieldData : numpy.recarray Contains the field information (ID, Ra, Dec) about how to slice the simData. For example, only fields in the fieldData table will be matched against the simData. RA and Dec should be in degrees. maps : list of lsst.sims.maf.maps objects, optional Maps to run and provide additional metadata at each slicePoint. Default None. """ if hasattr(self, 'slicePoints'): warning_msg = 'Warning: this OpsimFieldSlicer was already set up once. ' warning_msg += 'Re-setting up an OpsimFieldSlicer can change the field information. ' warning_msg += 'Rerun metrics if this was intentional. ' warnings.warn(warning_msg) # Set basic properties for tracking field information, in sorted order. idxs = np.argsort(fieldData[self.fieldIdColName]) # Set needed values for slice metadata. self.slicePoints['sid'] = fieldData[self.fieldIdColName][idxs] if self.latLonDeg: self.slicePoints['ra'] = np.radians(fieldData[self.fieldRaColName][idxs]) self.slicePoints['dec'] = np.radians(fieldData[self.fieldDecColName][idxs]) else: self.slicePoints['ra'] = fieldData[self.fieldRaColName][idxs] self.slicePoints['dec'] = fieldData[self.fieldDecColName][idxs] self.nslice = len(self.slicePoints['sid']) self._runMaps(maps) # Set up data slicing. self.simIdxs = np.argsort(simData[self.simDataFieldIdColName]) simFieldsSorted = np.sort(simData[self.simDataFieldIdColName]) self.left = np.searchsorted(simFieldsSorted, self.slicePoints['sid'], 'left') self.right = np.searchsorted(simFieldsSorted, self.slicePoints['sid'], 'right') self.spatialExtent = [simData[self.simDataFieldIdColName].min(), simData[self.simDataFieldIdColName].max()] self.shape = self.nslice @wraps(self._sliceSimData) def _sliceSimData(islice): idxs = self.simIdxs[self.left[islice]:self.right[islice]] # Build dict for slicePoint info slicePoint = {} for key in self.slicePoints: if (np.shape(self.slicePoints[key])[0] == self.nslice) & \ (key != 'bins') & (key != 'binCol'): slicePoint[key] = self.slicePoints[key][islice] else: slicePoint[key] = self.slicePoints[key] return {'idxs': idxs, 'slicePoint': slicePoint} setattr(self, '_sliceSimData', _sliceSimData)
[docs] def __eq__(self, otherSlicer): """Evaluate if two grids are equivalent.""" result = False if isinstance(otherSlicer, OpsimFieldSlicer): if np.all(otherSlicer.shape == self.shape): # Check if one or both slicers have been setup if (self.slicePoints['ra'] is not None) or (otherSlicer.slicePoints['ra'] is not None): if (np.array_equal(self.slicePoints['ra'], otherSlicer.slicePoints['ra']) & np.array_equal(self.slicePoints['dec'], otherSlicer.slicePoints['dec']) & np.array_equal(self.slicePoints['sid'], otherSlicer.slicePoints['sid'])): result = True # If they have not been setup, check that they have same fields elif ((otherSlicer.fieldIdColName == self.fieldIdColName) & (otherSlicer.fieldRaColName == self.fieldRaColName) & (otherSlicer.fieldDecColName == self.fieldDecColName)): result = True return result