Coverage for python/lsst/sims/maf/metrics/crowdingMetric.py : 20%

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
2from scipy.interpolate import interp1d
3from lsst.sims.maf.metrics import BaseMetric
5# Modifying from Knut Olson's fork at:
6# https://github.com/knutago/sims_maf_contrib/blob/master/tutorials/CrowdingMetric.ipynb
8__all__ = ['CrowdingM5Metric', 'CrowdingMagUncertMetric']
11def _compCrowdError(magVector, lumFunc, seeing, singleMag=None):
12 """
13 Compute the photometric crowding error given the luminosity function and best seeing.
15 Parameters
16 ----------
17 magVector : np.array
18 Stellar magnitudes.
19 lumFunc : np.array
20 Stellar luminosity function.
21 seeing : float
22 The best seeing conditions. Assuming forced-photometry can use the best seeing conditions
23 to help with confusion errors.
24 singleMag : float (None)
25 If singleMag is None, the crowding error is calculated for each mag in magVector. If
26 singleMag is a float, the crowding error is interpolated to that single value.
28 Returns
29 -------
30 np.array
31 Magnitude uncertainties.
33 Equation from Olsen, Blum, & Rigaut 2003, AJ, 126, 452
34 """
35 lumAreaArcsec = 3600.0 ** 2
36 lumVector = 10 ** (-0.4 * magVector)
37 coeff = np.sqrt(np.pi / lumAreaArcsec) * seeing / 2.
38 myInt = (np.add.accumulate((lumVector ** 2 * lumFunc)[::-1]))[::-1]
39 temp = np.sqrt(myInt) / lumVector
40 if singleMag is not None:
41 interp = interp1d(magVector, temp)
42 temp = interp(singleMag)
43 crowdError = coeff * temp
44 return crowdError
47class CrowdingM5Metric(BaseMetric):
48 """Return the magnitude at which the photometric error exceeds crowding_error threshold.
49 """
50 def __init__(self, crowding_error=0.1, filtername='r', seeingCol='seeingFwhmGeom',
51 metricName=None, maps=['StellarDensityMap'], **kwargs):
52 """
53 Parameters
54 ----------
55 crowding_error : float, opt
56 The magnitude uncertainty from crowding in magnitudes. Default 0.1 mags.
57 filtername: str, opt
58 The bandpass in which to calculate the crowding limit. Default r.
59 seeingCol : str, opt
60 The name of the seeing column.
61 m5Col : str, opt
62 The name of the m5 depth column.
63 maps : list of str, opt
64 Names of maps required for the metric.
66 Returns
67 -------
68 float
69 The magnitude of a star which has a photometric error of `crowding_error`
70 """
72 cols = [seeingCol]
73 units = 'mag'
74 self.crowding_error = crowding_error
75 self.filtername = filtername
76 self.seeingCol = seeingCol
77 if 'metricName' is not None:
78 metricName = 'Crowding to Precision %.2f' % (crowding_error)
79 super().__init__(col=cols, maps=maps, units=units, metricName=metricName, **kwargs)
81 def run(self, dataSlice, slicePoint=None):
82 # Set magVector to the same length as starLumFunc (lower edge of mag bins)
83 magVector = slicePoint[f'starMapBins_{self.filtername}'][1:]
84 # Pull up density of stars at this point in the sky
85 lumFunc = slicePoint[f'starLumFunc_{self.filtername}']
86 # Calculate the crowding error using the best seeing value (in any filter?)
87 crowdError = _compCrowdError(magVector, lumFunc,
88 seeing=min(dataSlice[self.seeingCol]) )
89 # Locate at which point crowding error is greater than user-defined limit
90 aboveCrowd = np.where(crowdError >= self.crowding_error)[0]
92 if np.size(aboveCrowd) == 0:
93 return max(magVector)
94 else:
95 crowdMag = magVector[max(aboveCrowd[0]-1,0)]
96 return crowdMag
99class CrowdingMagUncertMetric(BaseMetric):
100 """
101 Given a stellar magnitude, calculate the mean uncertainty on the magnitude from crowding.
102 """
103 def __init__(self, rmag=20., seeingCol='seeingFwhmGeom', units='mag',
104 metricName=None, filtername='r', maps=['StellarDensityMap'], **kwargs):
105 """
106 Parameters
107 ----------
108 rmag : float
109 The magnitude of the star to consider.
111 Returns
112 -------
113 float
114 The uncertainty in magnitudes caused by crowding for a star of rmag.
115 """
117 self.filtername = filtername
118 self.seeingCol = seeingCol
119 self.rmag = rmag
120 if 'metricName' is not None:
121 metricName = 'CrowdingError at %.2f' % (rmag)
122 super().__init__(col=[seeingCol], maps=maps, units=units,
123 metricName=metricName, **kwargs)
125 def run(self, dataSlice, slicePoint=None):
126 magVector = slicePoint[f'starMapBins_{self.filtername}'][1:]
127 lumFunc = slicePoint[f'starLumFunc_{self.filtername}']
128 # Magnitude uncertainty given crowding
129 dmagCrowd = _compCrowdError(magVector, lumFunc,
130 dataSlice[self.seeingCol], singleMag=self.rmag)
131 result = np.mean(dmagCrowd)
132 return result