1from __future__ import print_function 

2# http://pyrocko.org - GPLv3 

3# 

4# The Pyrocko Developers, 21st Century 

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

6 

7import sys 

8import logging 

9import os.path as op 

10from optparse import OptionParser 

11 

12from pyrocko import util, scenario, guts, gf 

13from pyrocko import __version__ 

14 

15 

16logger = logging.getLogger('pyrocko.apps.colosseo') 

17km = 1000. 

18 

19 

20def d2u(d): 

21 return dict((k.replace('-', '_'), v) for (k, v) in d.items()) 

22 

23 

24description = '''This is Colosseo, an earthquake scenario generator. 

25 

26Create seismic waveforms, InSAR and GNSS offsets for a simulated earthquake 

27scenario. 

28 

29Colosseo is part of Pyrocko. Version %s. 

30''' % __version__ 

31 

32subcommand_descriptions = { 

33 'init': 'initialize a new, blank scenario', 

34 'fill': 'fill the scenario with modelled data', 

35 'snuffle': 'open Snuffler to inspect the waveform data', 

36 'map': 'map the scenario arena' 

37} 

38 

39subcommand_usages = { 

40 'init': 'init <scenario_dir>', 

41 'fill': 'fill <scenario_dir>', 

42 'snuffle': 'snuffle <scenario_dir>', 

43 'map': '<scenario_dir>', 

44} 

45 

46subcommands = subcommand_descriptions.keys() 

47 

48program_name = 'colosseo' 

49 

50usage_tdata = d2u(subcommand_descriptions) 

51usage_tdata['program_name'] = program_name 

52usage_tdata['description'] = description 

53 

54usage = '''%(program_name)s <subcommand> [options] [--] <arguments> ... 

55 

56%(description)s 

57 

58Subcommands: 

59 

60 init %(init)s 

61 fill %(fill)s 

62 snuffle %(snuffle)s 

63 map %(map)s 

64 

65To get further help and a list of available options for any subcommand run: 

66 

67 %(program_name)s <subcommand> --help 

68 

69''' % usage_tdata 

70 

71 

72def die(message, err='', prelude=''): 

73 if prelude: 

74 prelude = prelude + '\n' 

75 

76 if err: 

77 err = '\n' + err 

78 

79 sys.exit('%s%s failed: %s%s' % (prelude, program_name, message, err)) 

80 

81 

82def none_or_float(x): 

83 if x == 'none': 

84 return None 

85 else: 

86 return float(x) 

87 

88 

89def add_common_options(parser): 

90 parser.add_option( 

91 '--loglevel', 

92 action='store', 

93 dest='loglevel', 

94 type='choice', 

95 choices=('critical', 'error', 'warning', 'info', 'debug'), 

96 default='info', 

97 help='set logger level to ' 

98 '"critical", "error", "warning", "info", or "debug". ' 

99 'Default is "%default".') 

100 

101 

102def process_common_options(options): 

103 util.setup_logging(program_name, options.loglevel) 

104 

105 

106def cl_parse(command, args, setup=None, details=None): 

107 usage = subcommand_usages[command] 

108 descr = subcommand_descriptions[command] 

109 

110 if isinstance(usage, str): 

111 usage = [usage] 

112 

113 susage = '%s %s' % (program_name, usage[0]) 

114 for s in usage[1:]: 

115 susage += '\n%s%s %s' % (' '*7, program_name, s) 

116 

117 description = descr[0].upper() + descr[1:] + '.' 

118 

119 if details: 

120 description = description + ' %s' % details 

121 

122 parser = OptionParser(usage=susage, description=description) 

123 

124 if setup: 

125 setup(parser) 

126 

127 add_common_options(parser) 

128 (options, args) = parser.parse_args(args) 

129 process_common_options(options) 

130 return parser, options, args 

131 

132 

133def get_scenario_yml(path): 

134 fn = op.join(path, 'scenario.yml') 

135 if op.exists(fn): 

136 return fn 

137 return False 

138 

139 

140def command_init(args): 

141 

142 def setup(parser): 

143 parser.add_option( 

144 '--force', dest='force', action='store_true', 

145 help='overwrite existing files') 

146 parser.add_option( 

147 '--location', dest='location', metavar='LAT,LON', 

148 help='set scenario center location [deg]') 

149 parser.add_option( 

150 '--radius', dest='radius', metavar='RADIUS', type=float, 

151 help='set scenario center location [km]') 

152 

153 parser, options, args = cl_parse('init', args, setup=setup) 

154 

155 if len(args) != 1: 

156 parser.print_help() 

157 sys.exit(1) 

158 

159 if options.location: 

160 try: 

161 lat, lon = map(float, options.location.split(',')) 

162 except Exception: 

163 die('expected --location=LAT,LON') 

164 else: 

165 lat = lon = None 

166 

167 if options.radius is not None: 

168 radius = options.radius * km 

169 else: 

170 radius = None 

171 

172 project_dir = args[0] 

173 try: 

174 scenario.ScenarioGenerator.initialize( 

175 project_dir, lat, lon, radius, force=options.force) 

176 

177 gf_stores_path = op.join(project_dir, 'gf_stores') 

178 util.ensuredir(gf_stores_path) 

179 

180 except scenario.CannotCreatePath as e: 

181 die(str(e) + ' Use --force to override.') 

182 

183 except scenario.ScenarioError as e: 

184 die(str(e)) 

185 

186 

187def command_fill(args): 

188 

189 def setup(parser): 

190 parser.add_option( 

191 '--force', dest='force', action='store_true', 

192 help='overwrite existing files') 

193 

194 parser, options, args = cl_parse('fill', args, setup=setup) 

195 

196 if len(args) == 0: 

197 args.append('.') 

198 

199 fn = get_scenario_yml(args[0]) 

200 

201 if not fn: 

202 parser.print_help() 

203 sys.exit(1) 

204 

205 project_dir = args[0] 

206 

207 gf_stores_path = op.join(project_dir, 'gf_stores') 

208 

209 try: 

210 engine = get_engine([gf_stores_path]) 

211 

212 sc = guts.load(filename=fn) 

213 sc.init_modelling(engine) 

214 sc.ensure_gfstores(interactive=True) 

215 sc.prepare_data(path=project_dir, overwrite=options.force) 

216 sc.ensure_data(path=project_dir) 

217 sc.make_map(op.join(project_dir, 'map.pdf')) 

218 

219 except scenario.CannotCreatePath as e: 

220 die(str(e) + ' Use --force to override.') 

221 

222 except scenario.ScenarioError as e: 

223 die(str(e)) 

224 

225 

226def command_map(args): 

227 parser, options, args = cl_parse('map', args) 

228 

229 if len(args) == 0: 

230 args.append('.') 

231 

232 fn = get_scenario_yml(args[0]) 

233 

234 if not fn: 

235 parser.print_help() 

236 sys.exit(1) 

237 

238 project_dir = args[0] 

239 

240 gf_stores_path = op.join(project_dir, 'gf_stores') 

241 engine = get_engine([gf_stores_path]) 

242 

243 try: 

244 sc = guts.load(filename=fn) 

245 sc.init_modelling(engine) 

246 sc.make_map(op.join(project_dir, 'map.pdf')) 

247 

248 except scenario.ScenarioError as e: 

249 die(str(e)) 

250 

251 

252def command_snuffle(args): 

253 from pyrocko.gui import snuffler 

254 parser, options, args = cl_parse('map', args) 

255 

256 if len(args) == 0: 

257 args.append('.') 

258 

259 fn = get_scenario_yml(args[0]) 

260 

261 if not fn: 

262 parser.print_help() 

263 sys.exit(1) 

264 

265 project_dir = args[0] 

266 gf_stores_path = op.join(project_dir, 'gf_stores') 

267 

268 engine = get_engine([gf_stores_path]) 

269 sc = guts.load(filename=fn) 

270 sc.init_modelling(engine) 

271 

272 return snuffler.snuffle( 

273 sc.get_pile(), 

274 stations=sc.get_stations(), 

275 events=sc.get_events()) 

276 

277 

278def main(args=None): 

279 if args is None: 

280 args = sys.argv[1:] 

281 

282 if len(args) < 1: 

283 sys.exit('Usage: %s' % usage) 

284 

285 command = args.pop(0) 

286 

287 if command in subcommands: 

288 globals()['command_' + command](args) 

289 

290 elif command in ('--help', '-h', 'help'): 

291 if command == 'help' and args: 

292 acommand = args[0] 

293 if acommand in subcommands: 

294 globals()['command_' + acommand](['--help']) 

295 

296 sys.exit('Usage: %s' % usage) 

297 

298 else: 

299 sys.exit('%s: error: no such subcommand: %s' % (program_name, command)) 

300 

301 

302def get_engine(gf_store_superdirs): 

303 engine = gf.LocalEngine( 

304 store_superdirs=gf_store_superdirs, use_config=True) 

305 

306 logger.info( 

307 'Directories to be searched for GF stores:\n%s' 

308 % '\n'.join(' ' + s for s in engine.store_superdirs)) 

309 

310 return engine 

311 

312 

313if __name__ == '__main__': 

314 main()