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 

2import pandas as pd 

3 

4from .baseSlicer import BaseSlicer 

5from lsst.sims.maf.plots.moPlotters import MetricVsH, MetricVsOrbit 

6 

7from .orbits import Orbits 

8 

9__all__ = ['MoObjSlicer'] 

10 

11 

12class MoObjSlicer(BaseSlicer): 

13 """ Slice moving object _observations_, per object and optionally clone/per H value. 

14 

15 Iteration over the MoObjSlicer will go as: 

16 * iterate over each orbit; 

17 * if Hrange is not None, for each orbit, iterate over Hrange. 

18 

19 Parameters 

20 ---------- 

21 Hrange : numpy.ndarray or None 

22 The H values to clone the orbital parameters over. If Hrange is None, will not clone orbits. 

23 """ 

24 def __init__(self, Hrange=None, verbose=True, badval=0): 

25 super(MoObjSlicer, self).__init__(verbose=verbose, badval=badval) 

26 self.Hrange = Hrange 

27 self.slicer_init = {'Hrange': Hrange, 'badval': badval} 

28 # Set default plotFuncs. 

29 self.plotFuncs = [MetricVsH(), 

30 MetricVsOrbit(xaxis='q', yaxis='e'), 

31 MetricVsOrbit(xaxis='q', yaxis='inc')] 

32 

33 def setupSlicer(self, orbitFile, delim=None, skiprows=None, obsFile=None): 

34 """Set up the slicer and read orbitFile and obsFile from disk. 

35 

36 Sets self.orbits (with orbit parameters), self.allObs, and self.obs 

37 self.orbitFile and self.obsFile 

38 

39 Parameters 

40 ---------- 

41 orbitFile : str 

42 The file containing the orbit information. 

43 This is necessary, in order to be able to generate plots. 

44 obsFile : str, optional 

45 The file containing the observations of each object, optional. 

46 If not provided (default, None), then the slicer will not be able to 'slice', but can still plot. 

47 """ 

48 self.readOrbits(orbitFile, delim=delim, skiprows=skiprows) 

49 if obsFile is not None: 

50 self.readObs(obsFile) 

51 else: 

52 self.obsFile = None 

53 self.allObs = None 

54 self.obs = None 

55 # Add these filenames to the slicer init values, to preserve in output files. 

56 self.slicer_init['orbitFile'] = self.orbitFile 

57 self.slicer_init['obsFile'] = self.obsFile 

58 

59 def readOrbits(self, orbitFile, delim=None, skiprows=None): 

60 # Use sims_movingObjects to read orbit files. 

61 orb = Orbits() 

62 orb.readOrbits(orbitFile, delim=delim, skiprows=skiprows) 

63 self.orbitFile = orbitFile 

64 self.orbits = orb.orbits 

65 # Then go on as previously. Need to refactor this into 'setupSlicer' style. 

66 self.nSso = len(self.orbits) 

67 self.slicePoints = {} 

68 self.slicePoints['orbits'] = self.orbits 

69 # And set the slicer shape/size. 

70 if self.Hrange is not None: 

71 self.shape = [self.nSso, len(self.Hrange)] 

72 self.slicePoints['H'] = self.Hrange 

73 else: 

74 self.shape = [self.nSso, 1] 

75 self.slicePoints['H'] = self.orbits['H'] 

76 # Set the rest of the slicePoint information once 

77 self.nslice = self.shape[0] * self.shape[1] 

78 

79 def readObs(self, obsFile): 

80 """Read observations of the solar system objects (such as created by sims_movingObjects). 

81 

82 Parameters 

83 ---------- 

84 obsFile: str 

85 The file containing the observation information. 

86 """ 

87 # For now, just read all the observations (should be able to chunk this though). 

88 self.allObs = pd.read_csv(obsFile, delim_whitespace=True, comment='#') 

89 self.obsFile = obsFile 

90 # We may have to rename the first column from '#objId' to 'objId'. 

91 if self.allObs.columns.values[0].startswith('#'): 

92 newcols = self.allObs.columns.values 

93 newcols[0] = newcols[0].replace('#', '') 

94 self.allObs.columns = newcols 

95 if 'velocity' not in self.allObs.columns.values: 

96 self.allObs['velocity'] = np.sqrt(self.allObs['dradt']**2 + self.allObs['ddecdt']**2) 

97 if 'visitExpTime' not in self.allObs.columns.values: 

98 self.allObs['visitExpTime'] = np.zeros(len(self.allObs['objId']), float) + 30.0 

99 # If we created intermediate data products by pandas, we may have an inadvertent 'index' 

100 # column. Since this creates problems later, drop it here. 

101 if 'index' in self.allObs.columns.values: 

102 self.allObs.drop('index', axis=1, inplace=True) 

103 self.subsetObs() 

104 

105 def subsetObs(self, pandasConstraint=None): 

106 """ 

107 Choose a subset of all the observations, such as those in a particular time period. 

108 """ 

109 if pandasConstraint is None: 

110 self.obs = self.allObs 

111 else: 

112 self.obs = self.allObs.query(pandasConstraint) 

113 

114 def _sliceObs(self, idx): 

115 """Return the observations of a given ssoId. 

116 

117 For now this works for any ssoId; in the future, this might only work as ssoId is 

118 progressively iterated through the series of ssoIds (so we can 'chunk' the reading). 

119 

120 Parameters 

121 ---------- 

122 idx : integer 

123 The integer index of the particular SSO in the orbits dataframe. 

124 """ 

125 # Find the matching orbit. 

126 orb = self.orbits.iloc[idx] 

127 # Find the matching observations. 

128 if self.obs['objId'].dtype == 'object': 

129 obs = self.obs.query('objId == "%s"' %(orb['objId'])) 

130 else: 

131 obs = self.obs.query('objId == %d' %(orb['objId'])) 

132 # Return the values for H to consider for metric. 

133 if self.Hrange is not None: 

134 Hvals = self.Hrange 

135 else: 

136 Hvals = np.array([orb['H']], float) 

137 # Note that ssoObs / obs is a recarray not Dataframe! 

138 # But that the orbit IS a Dataframe. 

139 return {'obs': obs.to_records(), 

140 'orbit': orb, 

141 'Hvals': Hvals} 

142 

143 def __iter__(self): 

144 """ 

145 Iterate through each of the ssoIds. 

146 """ 

147 self.idx = 0 

148 return self 

149 

150 def __next__(self): 

151 """ 

152 Returns result of self._getObs when iterating over moSlicer. 

153 """ 

154 if self.idx >= self.nSso: 

155 raise StopIteration 

156 idx = self.idx 

157 self.idx += 1 

158 return self._sliceObs(idx) 

159 

160 def __getitem__(self, idx): 

161 # This may not be guaranteed to work if/when we implement chunking of the obsfile. 

162 return self._sliceObs(idx) 

163 

164 def __eq__(self, otherSlicer): 

165 """ 

166 Evaluate if two slicers are equal. 

167 """ 

168 result = False 

169 if isinstance(otherSlicer, MoObjSlicer): 

170 if otherSlicer.orbitFile == self.orbitFile: 

171 if otherSlicer.obsFile == self.obsFile: 

172 if np.all(otherSlicer.slicePoints['H'] == self.slicePoints['H']): 

173 result = True 

174 return result