Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/gui/snuffler/snufflings/cake_phase.py: 31%

124 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-10-06 15:01 +0000

1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6from ..snuffling import Snuffling, Param, Switch, Choice 

7from ..marker import PhaseMarker 

8from pyrocko import gf 

9from pyrocko import cake 

10import numpy as num 

11 

12 

13class CakePhase(Snuffling): 

14 

15 def help(self): 

16 return ''' 

17<html> 

18<head> 

19<style type="text/css"> 

20 body { margin-left:10px }; 

21</style> 

22</head> 

23<body> 

24<h1 align="center">Theoretical Phase Arrivals</h1> 

25<p> 

26This snuffling uses pyrocko's 

27<a href="http://emolch.github.io/pyrocko/v0.3/cake_doc.html">Cake</a> 

28module to calculate seismic rays for layered earth models. </p> 

29<p> 

30<b>Parameters:</b><br /> 

31 <b>&middot; Global shift</b> - Add time onset to phases. <br /> 

32 <b>&middot; Add Model</b> - Add a model to drop down menu. <br /> 

33 <b>&middot; Add Phase</b> - Add a phase definition. 

34 (GUI reset required)<br /> 

35</p> 

36<p> 

37Instructions and information on Cake's syntax of seismic rays can be 

38found in the 

39<a href="http://emolch.github.io/pyrocko/ 

40v0.3/cake_doc.html#cmdoption-cake--phase">Cake documentation</a>. 

41</p> 

42</body> 

43</html> 

44 ''' 

45 

46 def setup(self): 

47 self.set_name('Cake Phase') 

48 

49 # self._phase_names = ('PmP ~S ~P ~P(moho)s ~P(sill-top)s' 

50 # ' ~P(sill-bottom)s Pdiff').split() 

51 self._phase_names = ('~P Pg Sg pP p P Pdiff PKP PcP PcS PKIKP pPKIKP' 

52 ' SSP PPS SPP PSP SP PS ~PS ~SP Pn s S Sn PP PPP' 

53 ' ScS Sdiff SS SSS SKS SKIKS').split() 

54 

55 for iphase, name in enumerate(self._phase_names): 

56 self.add_parameter(Switch(name, 'wantphase_%i' % iphase, 

57 iphase == 0)) 

58 

59 model_names = cake.builtin_models() 

60 model_names = [ 

61 'Cake builtin: %s' % model_name for model_name in model_names] 

62 

63 self._engine = gf.LocalEngine(use_config=True) 

64 store_ids = self._engine.get_store_ids() 

65 

66 for store_id in store_ids: 

67 model_names.append('GF Store: %s' % store_id) 

68 

69 self._models = model_names 

70 

71 self.model_choice = Choice('Model', 'chosen_model', 

72 'ak135-f-continental.m', self._models) 

73 

74 self.add_parameter(self.model_choice) 

75 

76 self.add_parameter(Param('Global shift', 'tshift', 0., -20., 20.)) 

77 self.add_parameter(Switch('Use station depth', 

78 'use_station_depth', False)) 

79 self.add_trigger('Add Phase', self.add_phase_definition) 

80 self.add_trigger('Add Model', self.add_model_to_choice) 

81 self.add_trigger('Plot Model', self.plot_model) 

82 self.add_trigger('Plot Rays', self.plot_rays) 

83 

84 self._phases = {} 

85 self._model = None 

86 

87 def panel_visibility_changed(self, bool): 

88 pass 

89 

90 def wanted_phases(self): 

91 try: 

92 wanted = [] 

93 for iphase, name in enumerate(self._phase_names): 

94 if getattr(self, 'wantphase_%i' % iphase): 

95 if name in self._phases: 

96 phases = self._phases[name] 

97 else: 

98 if name.startswith('~'): 

99 phases = [cake.PhaseDef(name[1:])] 

100 else: 

101 phases = cake.PhaseDef.classic(name) 

102 

103 self._phases[name] = phases 

104 for pha in phases: 

105 pha.name = name 

106 

107 wanted.extend(phases) 

108 except (cake.UnknownClassicPhase, cake.PhaseDefParseError) as e: 

109 self.fail(str(e)) 

110 

111 return wanted 

112 

113 def call(self, plot_rays=False): 

114 

115 self.cleanup() 

116 wanted = self.wanted_phases() 

117 

118 if not wanted: 

119 return 

120 

121 event, stations = self.get_active_event_and_stations() 

122 

123 if not stations: 

124 self.fail('No station information available.') 

125 

126 self.update_model() 

127 model = self._model[1] 

128 

129 depth = event.depth 

130 if depth is None: 

131 depth = 0.0 

132 

133 allrays = [] 

134 alldists = [] 

135 for station in stations: 

136 dist = event.distance_to(station) 

137 alldists.append(dist) 

138 

139 if self.use_station_depth: 

140 rdepth = station.depth 

141 else: 

142 rdepth = 0.0 

143 

144 multi_dists = [] 

145 nmax = 1 

146 for i in range(0, nmax): 

147 multi_dists.append(dist*cake.m2d + 360.*i) 

148 multi_dists.append((i+1)*360. - dist*cake.m2d) 

149 

150 rays = model.arrivals( 

151 phases=wanted, 

152 distances=multi_dists, 

153 zstart=depth, 

154 zstop=rdepth) 

155 

156 for ray in rays: 

157 time = ray.t 

158 name = ray.given_phase().name 

159 incidence_angle = ray.incidence_angle() 

160 takeoff_angle = ray.takeoff_angle() 

161 

162 time += event.time + self.tshift 

163 m = PhaseMarker([(station.network, station.station, '*', '*')], 

164 time, time, 2, 

165 phasename=name, 

166 event=event, 

167 incidence_angle=incidence_angle, 

168 takeoff_angle=takeoff_angle) 

169 self.add_marker(m) 

170 

171 allrays.extend(rays) 

172 

173 if plot_rays: 

174 fig = self.figure(name='Ray Paths') 

175 from pyrocko.plot import cake_plot 

176 cake_plot.my_rays_plot(model, None, allrays, depth, 0.0, 

177 num.array(alldists)*cake.m2d, 

178 axes=fig.gca()) 

179 

180 fig.canvas.draw() 

181 

182 def update_model(self): 

183 if not self._model or self._model[0] != self.chosen_model: 

184 if self.chosen_model.startswith('Cake builtin: '): 

185 load_model = cake.load_model( 

186 self.chosen_model.split(': ', 1)[1]) 

187 

188 elif self.chosen_model.startswith('GF Store: '): 

189 store_id = self.chosen_model.split(': ', 1)[1] 

190 

191 load_model = self._engine.get_store(store_id)\ 

192 .config.earthmodel_1d 

193 else: 

194 load_model = cake.load_model(self.chosen_model) 

195 

196 self._model = (self.chosen_model, load_model) 

197 

198 def update_model_choices(self): 

199 self.set_parameter_choices('chosen_model', self._models) 

200 

201 def add_model_to_choice(self): 

202 ''' 

203 Called from trigger 'Add Model'. 

204 

205 Adds another choice to the drop down 'Model' menu. 

206 ''' 

207 

208 in_model = self.input_filename('Load Model') 

209 if in_model not in self._models: 

210 self._models.append(in_model) 

211 self.update_model_choices() 

212 

213 self.set_parameter('chosen_model', in_model) 

214 self.call() 

215 

216 def add_phase_definition(self): 

217 ''' 

218 Called from trigger 'Add Phase Definition'. 

219 

220 Adds another phase option. 

221 Requires a reset of the GUI. 

222 ''' 

223 phase_def = str(self.input_dialog('Add New Phase', 

224 'Enter Phase Definition')) 

225 self._phase_names.append(phase_def) 

226 

227 self.add_parameter( 

228 Switch(phase_def, 

229 'wantphase_%s' % str(len(self._phase_names)-1), True)) 

230 self.reset_gui(reloaded=True) 

231 self.call() 

232 

233 def plot_model(self): 

234 self.update_model() 

235 

236 from pyrocko.plot import cake_plot 

237 

238 fig = self.figure(name='Model: %s' % self._model[0]) 

239 

240 cake_plot.my_model_plot(self._model[1], axes=fig.gca()) 

241 

242 fig.canvas.draw() 

243 

244 def plot_rays(self): 

245 self.call(plot_rays=True) 

246 

247 

248def __snufflings__(): 

249 ''' 

250 Returns a list of snufflings to be exported by this module. 

251 ''' 

252 

253 return [CakePhase()]