Coverage for python/lsst/sims/maf/stackers/moStackers.py : 45%

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 .baseStacker import BaseStacker
3import warnings
5__all__ = ['BaseMoStacker', 'MoMagStacker', 'CometMagVStacker', 'EclStacker']
8class BaseMoStacker(BaseStacker):
9 """Base class for moving object (SSobject) stackers. Relevant for MoSlicer ssObs (pd.dataframe).
11 Provided to add moving-object specific API for 'run' method of moving object stackers."""
12 def run(self, ssoObs, Href, Hval=None):
13 # Redefine this here, as the API does not match BaseStacker.
14 if Hval is None:
15 Hval = Href
16 if len(ssoObs) == 0:
17 return ssoObs
18 # Add the columns.
19 with warnings.catch_warnings():
20 warnings.simplefilter('ignore')
21 ssoObs, cols_present = self._addStackerCols(ssoObs)
22 # Here we don't really care about cols_present, because almost every time we will be readding
23 # columns anymore (for different H values).
24 return self._run(ssoObs, Href, Hval)
27class MoMagStacker(BaseMoStacker):
28 """Add columns relevant to SSobject apparent magnitudes and visibility to the slicer ssoObs
29 dataframe, given a particular Href and current Hval.
31 Specifically, this stacker adds magLimit, appMag, SNR, and vis.
32 magLimit indicates the appropriate limiting magnitude to consider for a particular object in a particular
33 observation, when combined with the losses due to detection (dmagDetect) or trailing (dmagTrail).
34 appMag adds the apparent magnitude in the filter of the current object, at the current Hval.
35 SNR adds the SNR of this object, given the magLimit.
36 vis adds a flag (0/1) indicating whether an object was visible (assuming a 5sigma threshhold including
37 some probabilistic determination of visibility).
39 Parameters
40 ----------
41 m5Col : str, opt
42 Name of the column describing the 5 sigma depth of each visit. Default fiveSigmaDepth.
43 lossCol : str, opt
44 Name of the column describing the magnitude losses,
45 due to trailing (dmagTrail) or detection (dmagDetect). Default dmagDetect.
46 gamma : float, opt
47 The 'gamma' value for calculating SNR. Default 0.038.
48 LSST range under normal conditions is about 0.037 to 0.039.
49 sigma : float, opt
50 The 'sigma' value for probabilistic prediction of whether or not an object is visible at 5sigma.
51 Default 0.12.
52 The probabilistic prediction of visibility is based on Fermi-Dirac completeness formula (see SDSS,
53 eqn 24, Stripe82 analysis: http://iopscience.iop.org/0004-637X/794/2/120/pdf/apj_794_2_120.pdf).
54 randomSeed: int or None, optional
55 If set, then used as the random seed for the numpy random number
56 generation for the dither offsets.
57 Default: None.
58 """
59 colsAdded = ['appMagV', 'appMag', 'SNR', 'vis']
61 def __init__(self, vMagCol='magV', colorCol='dmagColor',
62 lossCol='dmagDetect', m5Col='fiveSigmaDepth', gamma=0.038, sigma=0.12,
63 randomSeed=None):
64 self.vMagCol = vMagCol
65 self.colorCol = colorCol
66 self.m5Col = m5Col
67 self.lossCol = lossCol
68 self.gamma = gamma
69 self.sigma = sigma
70 self.randomSeed = randomSeed
71 self.colsReq = [self.m5Col, self.vMagCol, self.colorCol, self.lossCol]
72 self.units = ['mag', 'mag', 'SNR', '']
74 def _run(self, ssoObs, Href, Hval):
75 # Hval = current H value (useful if cloning over H range), Href = reference H value from orbit.
76 # Without cloning, Href = Hval.
77 ssoObs['appMagV'] = ssoObs[self.vMagCol] + ssoObs[self.lossCol] + Hval - Href
78 ssoObs['appMag'] = ssoObs[self.vMagCol] + ssoObs[self.colorCol] + ssoObs[self.lossCol] + Hval - Href
79 xval = np.power(10, 0.5 * (ssoObs['appMag'] - ssoObs[self.m5Col]))
80 ssoObs['SNR'] = 1.0 / np.sqrt((0.04 - self.gamma) * xval + self.gamma * xval * xval)
81 completeness = 1.0 / (1 + np.exp((ssoObs['appMag'] - ssoObs[self.m5Col])/self.sigma))
82 if not hasattr(self, '_rng'):
83 if self.randomSeed is not None:
84 self._rng = np.random.RandomState(self.randomSeed)
85 else:
86 self._rng = np.random.RandomState(734421)
88 probability = self._rng.random_sample(len(ssoObs['appMag']))
89 ssoObs['vis'] = np.where(probability <= completeness, 1, 0)
90 return ssoObs
93class CometMagVStacker(BaseMoStacker):
94 """Add an base V magnitude using a cometary magnitude model.
96 The cometV magnitude is intended to replace the 'magV' column coming from sims_movingObjects,
97 thus it does NOT take into account Hval, only Href. The full 'apparent magnitude' is calculated
98 with the MoMagStacker, configured for the appropriate 'vMagCol'.
100 m = M + 5 log10(Δ) + (5 + K) log10(rh)
102 Parameters
103 ----------
104 k : float, opt
105 Activity / intrinsic brightness dependence on heliocentric distance: rh**k.
106 Note the default here is k = 2.
107 rhCol : str, opt
108 The column name for the heliocentric distance. Default 'helio_dist'.
109 deltaCol : str, opt
110 The column name for the geocentric distance. Default 'geo_dist'.
111 """
112 colsAdded = ['cometV']
114 def __init__(self, k=2, rhCol='helio_dist', deltaCol='geo_dist'):
115 self.units = ['mag'] # new column units
116 self.k = k
117 self.rhCol = rhCol
118 self.deltaCol = deltaCol
119 self.colsReq = [self.rhCol, self.deltaCol] # names of required columns
121 def _run(self, ssObs, Href, Hval):
122 # comet apparent mag, use Href here and H-mag cloning will work later with MoMagStacker
123 ssObs['cometV'] = (Href + 5 * np.log10(ssObs[self.deltaCol])
124 + (5 + self.k) * np.log10(ssObs[self.rhCol]))
125 return ssObs
128class EclStacker(BaseMoStacker):
129 """
130 Add ecliptic latitude/longitude (ecLat/ecLon) to the slicer ssoObs (in degrees).
132 Parameters
133 -----------
134 raCol : str, opt
135 Name of the RA column to convert to ecliptic lat/long. Default 'ra'.
136 decCol : str, opt
137 Name of the Dec column to convert to ecliptic lat/long. Default 'dec'.
138 inDeg : bool, opt
139 Flag indicating whether RA/Dec are in degrees. Default True.
140 """
141 colsAdded = ['ecLat', 'ecLon']
143 def __init__(self, raCol='ra', decCol='dec', inDeg=True):
144 self.raCol = raCol
145 self.decCol = decCol
146 self.inDeg = inDeg
147 self.colsReq = [self.raCol, self.decCol]
148 self.units = ['deg', 'deg']
149 self.ecnode = 0.0
150 self.ecinc = np.radians(23.439291)
152 def _run(self, ssoObs, Href, Hval):
153 ra = ssoObs[self.raCol]
154 dec = ssoObs[self.decCol]
155 if self.inDeg:
156 ra = np.radians(ra)
157 dec = np.radians(dec)
158 x = np.cos(ra) * np.cos(dec)
159 y = np.sin(ra) * np.cos(dec)
160 z = np.sin(dec)
161 xp = x
162 yp = np.cos(self.ecinc)*y + np.sin(self.ecinc)*z
163 zp = -np.sin(self.ecinc)*y + np.cos(self.ecinc)*z
164 ssoObs['ecLat'] = np.degrees(np.arcsin(zp))
165 ssoObs['ecLon'] = np.degrees(np.arctan2(yp, xp))
166 ssoObs['ecLon'] = ssoObs['ecLon'] % 360
167 return ssoObs