1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6from __future__ import absolute_import, print_function, division 

7 

8import sys 

9import logging 

10import os.path as op 

11from optparse import OptionParser 

12 

13from pyrocko import util, scenario, guts, gf 

14from pyrocko import __version__ 

15 

16 

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

18km = 1000. 

19 

20 

21def d2u(d): 

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

23 

24 

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

26 

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

28scenario. 

29 

30Colosseo is part of Pyrocko. Version %s. 

31''' % __version__ 

32 

33subcommand_descriptions = { 

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

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

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

37 'map': 'map the scenario arena' 

38} 

39 

40subcommand_usages = { 

41 'init': 'init <scenario_dir>', 

42 'fill': 'fill <scenario_dir>', 

43 'snuffle': 'snuffle <scenario_dir>', 

44 'map': '<scenario_dir>', 

45} 

46 

47subcommands = subcommand_descriptions.keys() 

48 

49program_name = 'colosseo' 

50 

51usage_tdata = d2u(subcommand_descriptions) 

52usage_tdata['program_name'] = program_name 

53usage_tdata['description'] = description 

54 

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

56 

57%(description)s 

58 

59Subcommands: 

60 

61 init %(init)s 

62 fill %(fill)s 

63 snuffle %(snuffle)s 

64 map %(map)s 

65 

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

67 

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

69 

70''' % usage_tdata 

71 

72 

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

74 if prelude: 

75 prelude = prelude + '\n' 

76 

77 if err: 

78 err = '\n' + err 

79 

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

81 

82 

83def none_or_float(x): 

84 if x == 'none': 

85 return None 

86 else: 

87 return float(x) 

88 

89 

90def add_common_options(parser): 

91 parser.add_option( 

92 '--loglevel', 

93 action='store', 

94 dest='loglevel', 

95 type='choice', 

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

97 default='info', 

98 help='set logger level to ' 

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

100 'Default is "%default".') 

101 

102 

103def process_common_options(options): 

104 util.setup_logging(program_name, options.loglevel) 

105 

106 

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

108 usage = subcommand_usages[command] 

109 descr = subcommand_descriptions[command] 

110 

111 if isinstance(usage, str): 

112 usage = [usage] 

113 

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

115 for s in usage[1:]: 

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

117 

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

119 

120 if details: 

121 description = description + ' %s' % details 

122 

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

124 

125 if setup: 

126 setup(parser) 

127 

128 add_common_options(parser) 

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

130 process_common_options(options) 

131 return parser, options, args 

132 

133 

134def get_scenario_yml(path): 

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

136 if op.exists(fn): 

137 return fn 

138 return False 

139 

140 

141def command_init(args): 

142 

143 def setup(parser): 

144 parser.add_option( 

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

146 help='overwrite existing files') 

147 parser.add_option( 

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

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

150 parser.add_option( 

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

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

153 

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

155 

156 if len(args) != 1: 

157 parser.print_help() 

158 sys.exit(1) 

159 

160 if options.location: 

161 try: 

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

163 except Exception: 

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

165 else: 

166 lat = lon = None 

167 

168 if options.radius is not None: 

169 radius = options.radius * km 

170 else: 

171 radius = None 

172 

173 project_dir = args[0] 

174 try: 

175 scenario.ScenarioGenerator.initialize( 

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

177 

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

179 util.ensuredir(gf_stores_path) 

180 

181 except scenario.CannotCreatePath as e: 

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

183 

184 except scenario.ScenarioError as e: 

185 die(str(e)) 

186 

187 

188def command_fill(args): 

189 

190 def setup(parser): 

191 parser.add_option( 

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

193 help='overwrite existing files') 

194 

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

196 

197 if len(args) == 0: 

198 args.append('.') 

199 

200 fn = get_scenario_yml(args[0]) 

201 

202 if not fn: 

203 parser.print_help() 

204 sys.exit(1) 

205 

206 project_dir = args[0] 

207 

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

209 

210 try: 

211 engine = get_engine([gf_stores_path]) 

212 

213 sc = guts.load(filename=fn) 

214 sc.init_modelling(engine) 

215 sc.ensure_gfstores(interactive=True) 

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

217 sc.ensure_data(path=project_dir) 

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

219 

220 except scenario.CannotCreatePath as e: 

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

222 

223 except scenario.ScenarioError as e: 

224 die(str(e)) 

225 

226 

227def command_map(args): 

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

229 

230 if len(args) == 0: 

231 args.append('.') 

232 

233 fn = get_scenario_yml(args[0]) 

234 

235 if not fn: 

236 parser.print_help() 

237 sys.exit(1) 

238 

239 project_dir = args[0] 

240 

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

242 engine = get_engine([gf_stores_path]) 

243 

244 try: 

245 sc = guts.load(filename=fn) 

246 sc.init_modelling(engine) 

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

248 

249 except scenario.ScenarioError as e: 

250 die(str(e)) 

251 

252 

253def command_snuffle(args): 

254 from pyrocko.gui.snuffler import snuffler 

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

256 

257 if len(args) == 0: 

258 args.append('.') 

259 

260 fn = get_scenario_yml(args[0]) 

261 

262 if not fn: 

263 parser.print_help() 

264 sys.exit(1) 

265 

266 project_dir = args[0] 

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

268 

269 engine = get_engine([gf_stores_path]) 

270 sc = guts.load(filename=fn) 

271 sc.init_modelling(engine) 

272 

273 return snuffler.snuffle( 

274 sc.get_pile(), 

275 stations=sc.get_stations(), 

276 events=sc.get_events()) 

277 

278 

279def main(args=None): 

280 if args is None: 

281 args = sys.argv[1:] 

282 

283 if len(args) < 1: 

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

285 

286 command = args.pop(0) 

287 

288 if command in subcommands: 

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

290 

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

292 if command == 'help' and args: 

293 acommand = args[0] 

294 if acommand in subcommands: 

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

296 

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

298 

299 else: 

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

301 

302 

303def get_engine(gf_store_superdirs): 

304 engine = gf.LocalEngine( 

305 store_superdirs=gf_store_superdirs, use_config=True) 

306 

307 logger.info( 

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

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

310 

311 return engine 

312 

313 

314if __name__ == '__main__': 

315 main()