1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

4# ---|P------/S----------~Lg---------- 

5from __future__ import absolute_import, division, print_function 

6 

7import numpy as num 

8from pyrocko import model 

9from pyrocko.guts import Int, String, List 

10 

11from pyrocko.model.station import load_stations 

12from pyrocko.io import stationxml 

13from pyrocko.orthodrome import distance_accurate50m_numpy, \ 

14 geographic_midpoint_locations 

15 

16from .base import LocationGenerator 

17 

18guts_prefix = 'pf.scenario' 

19 

20 

21class StationGenerator(LocationGenerator): 

22 

23 def get_stations(self): 

24 raise NotImplementedError 

25 

26 def get_distance_range(self, sources): 

27 dists = [] 

28 for source in sources: 

29 for station in self.get_stations(): 

30 dists.append( 

31 source.distance_to(station)) 

32 

33 return num.min(dists), num.max(dists) 

34 

35 def ensure_data(self, engine, sources, path, tmin=None, tmax=None): 

36 return [] 

37 

38 def add_map_artists(self, engine, sources, automap): 

39 automap.add_stations(self.get_stations()) 

40 

41 

42class ImportStationGenerator(StationGenerator): 

43 

44 stations_paths = List.T( 

45 optional=True, 

46 help='List of files with station coordinates in Pyrocko format.') 

47 

48 stations_stationxml_paths = List.T( 

49 optional=True, 

50 help='List of files with station coordinates in StationXML format.') 

51 

52 pyrocko_stations = List.T( 

53 model.Station.T(), 

54 optional=True, 

55 help='List of Pyrocko stations') 

56 

57 def __init__(self, **kwargs): 

58 StationGenerator.__init__(self, **kwargs) 

59 self._stations = None 

60 

61 def has_stations(self): 

62 if not self.get_stations(): 

63 return False 

64 return True 

65 

66 def get_center_latlon(self): 

67 stations = self.get_stations() 

68 if not stations: 

69 return self._parent.get_center_latlon() 

70 

71 return geographic_midpoint_locations(self.get_stations()) 

72 

73 def get_radius(self): 

74 stations = self.get_stations() 

75 if not stations: 

76 return self._parent.get_radius() 

77 

78 clat, clon = self.get_center_latlon() 

79 radii = distance_accurate50m_numpy( 

80 clat, clon, 

81 [st.effective_lat for st in stations], 

82 [st.effective_lon for st in stations]) 

83 

84 return float(radii.max()) 

85 

86 def get_stations(self): 

87 if self._stations is None: 

88 

89 stations = [] 

90 

91 if self.stations_paths: 

92 for filename in self.stations_paths: 

93 stations.extend( 

94 load_stations(filename)) 

95 

96 if self.stations_stationxml_paths: 

97 for filename in self.stations_stationxml_paths: 

98 sxml = stationxml.load_xml(filename=filename) 

99 stations.extend( 

100 sxml.get_pyrocko_stations()) 

101 

102 if self.pyrocko_stations: 

103 stations.extend(self.pyrocko_stations) 

104 

105 self._stations = stations 

106 

107 return self._stations 

108 

109 def nsl(self, istation): 

110 stations = self.get_stations() 

111 return stations[istation].nsl() 

112 

113 def clear(self): 

114 self._stations = None 

115 

116 @property 

117 def nstations(self): 

118 return len(self.get_stations()) 

119 

120 

121class RandomStationGenerator(StationGenerator): 

122 

123 nstations = Int.T( 

124 default=10, 

125 help='Number of randomly distributed stations.') 

126 

127 network_name = String.T( 

128 default='CO', 

129 help='Network name') 

130 

131 channels = List.T( 

132 optional=True, 

133 default=['BHE', 'BHN', 'BHZ'], 

134 help='Seismic channels to generate. Default: BHN, BHE, BHZ') 

135 

136 def __init__(self, **kwargs): 

137 StationGenerator.__init__(self, **kwargs) 

138 self._stations = None 

139 

140 def clear(self): 

141 StationGenerator.clear(self) 

142 self._stations = None 

143 

144 def nsl(self, istation): 

145 return self.network_name, 'S%03i' % (istation + 1), '', 

146 

147 def get_stations(self): 

148 if self._stations is None: 

149 

150 if self.channels: 

151 channels = [model.station.Channel(c) for c in self.channels] 

152 else: 

153 channels = None 

154 

155 stations = [] 

156 for istation in range(self.nstations): 

157 lat, lon, north_shift, east_shift, depth = map( 

158 float, self.get_coordinates(istation)) 

159 

160 net, sta, loc = self.nsl(istation) 

161 station = model.Station( 

162 net, sta, loc, 

163 lat=lat, 

164 lon=lon, 

165 north_shift=north_shift, 

166 east_shift=east_shift, 

167 depth=depth, 

168 channels=channels) 

169 

170 stations.append(station) 

171 

172 self._stations = stations 

173 

174 return self._stations