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

1import numpy as np 

2from .baseStacker import BaseStacker 

3import warnings 

4 

5__all__ = ['BaseMoStacker', 'MoMagStacker', 'CometMagVStacker', 'EclStacker'] 

6 

7 

8class BaseMoStacker(BaseStacker): 

9 """Base class for moving object (SSobject) stackers. Relevant for MoSlicer ssObs (pd.dataframe). 

10 

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) 

25 

26 

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. 

30 

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). 

38 

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'] 

60 

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', ''] 

73 

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) 

87 

88 probability = self._rng.random_sample(len(ssoObs['appMag'])) 

89 ssoObs['vis'] = np.where(probability <= completeness, 1, 0) 

90 return ssoObs 

91 

92 

93class CometMagVStacker(BaseMoStacker): 

94 """Add an base V magnitude using a cometary magnitude model. 

95 

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'. 

99  

100 m = M + 5 log10(Δ) + (5 + K) log10(rh) 

101  

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'] 

113 

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 

120 

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 

126 

127 

128class EclStacker(BaseMoStacker): 

129 """ 

130 Add ecliptic latitude/longitude (ecLat/ecLon) to the slicer ssoObs (in degrees). 

131 

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'] 

142 

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) 

151 

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