1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6import sys 

7import logging 

8import os.path as op 

9from optparse import OptionParser 

10 

11from pyrocko import util, scenario, guts, gf 

12from pyrocko import __version__ 

13 

14 

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

16km = 1000. 

17 

18 

19def d2u(d): 

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

21 

22 

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

24 

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

26scenario. 

27 

28Colosseo is part of Pyrocko. Version %s. 

29''' % __version__ 

30 

31subcommand_descriptions = { 

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

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

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

35 'map': 'map the scenario arena' 

36} 

37 

38subcommand_usages = { 

39 'init': 'init <scenario_dir>', 

40 'fill': 'fill <scenario_dir>', 

41 'snuffle': 'snuffle <scenario_dir>', 

42 'map': '<scenario_dir>', 

43} 

44 

45subcommands = subcommand_descriptions.keys() 

46 

47program_name = 'colosseo' 

48 

49usage_tdata = d2u(subcommand_descriptions) 

50usage_tdata['program_name'] = program_name 

51usage_tdata['description'] = description 

52 

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

54 

55%(description)s 

56 

57Subcommands: 

58 

59 init %(init)s 

60 fill %(fill)s 

61 snuffle %(snuffle)s 

62 map %(map)s 

63 

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

65 

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

67 

68''' % usage_tdata 

69 

70 

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

72 if prelude: 

73 prelude = prelude + '\n' 

74 

75 if err: 

76 err = '\n' + err 

77 

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

79 

80 

81def none_or_float(x): 

82 if x == 'none': 

83 return None 

84 else: 

85 return float(x) 

86 

87 

88def add_common_options(parser): 

89 parser.add_option( 

90 '--loglevel', 

91 action='store', 

92 dest='loglevel', 

93 type='choice', 

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

95 default='info', 

96 help='set logger level to ' 

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

98 'Default is "%default".') 

99 

100 

101def process_common_options(options): 

102 util.setup_logging(program_name, options.loglevel) 

103 

104 

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

106 usage = subcommand_usages[command] 

107 descr = subcommand_descriptions[command] 

108 

109 if isinstance(usage, str): 

110 usage = [usage] 

111 

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

113 for s in usage[1:]: 

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

115 

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

117 

118 if details: 

119 description = description + ' %s' % details 

120 

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

122 

123 if setup: 

124 setup(parser) 

125 

126 add_common_options(parser) 

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

128 process_common_options(options) 

129 return parser, options, args 

130 

131 

132def get_scenario_yml(path): 

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

134 if op.exists(fn): 

135 return fn 

136 return False 

137 

138 

139def command_init(args): 

140 

141 def setup(parser): 

142 parser.add_option( 

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

144 help='overwrite existing files') 

145 parser.add_option( 

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

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

148 parser.add_option( 

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

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

151 

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

153 

154 if len(args) != 1: 

155 parser.print_help() 

156 sys.exit(1) 

157 

158 if options.location: 

159 try: 

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

161 except Exception: 

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

163 else: 

164 lat = lon = None 

165 

166 if options.radius is not None: 

167 radius = options.radius * km 

168 else: 

169 radius = None 

170 

171 project_dir = args[0] 

172 try: 

173 scenario.ScenarioGenerator.initialize( 

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

175 

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

177 util.ensuredir(gf_stores_path) 

178 

179 except scenario.CannotCreatePath as e: 

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

181 

182 except scenario.ScenarioError as e: 

183 die(str(e)) 

184 

185 

186def command_fill(args): 

187 

188 def setup(parser): 

189 parser.add_option( 

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

191 help='overwrite existing files') 

192 

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

194 

195 if len(args) == 0: 

196 args.append('.') 

197 

198 fn = get_scenario_yml(args[0]) 

199 

200 if not fn: 

201 parser.print_help() 

202 sys.exit(1) 

203 

204 project_dir = args[0] 

205 

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

207 

208 try: 

209 engine = get_engine([gf_stores_path]) 

210 

211 sc = guts.load(filename=fn) 

212 sc.init_modelling(engine) 

213 sc.ensure_gfstores(interactive=True) 

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

215 sc.ensure_data(path=project_dir) 

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

217 

218 except scenario.CannotCreatePath as e: 

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

220 

221 except scenario.ScenarioError as e: 

222 die(str(e)) 

223 

224 

225def command_map(args): 

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

227 

228 if len(args) == 0: 

229 args.append('.') 

230 

231 fn = get_scenario_yml(args[0]) 

232 

233 if not fn: 

234 parser.print_help() 

235 sys.exit(1) 

236 

237 project_dir = args[0] 

238 

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

240 engine = get_engine([gf_stores_path]) 

241 

242 try: 

243 sc = guts.load(filename=fn) 

244 sc.init_modelling(engine) 

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

246 

247 except scenario.ScenarioError as e: 

248 die(str(e)) 

249 

250 

251def command_snuffle(args): 

252 from pyrocko.gui.snuffler import snuffler 

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

254 

255 if len(args) == 0: 

256 args.append('.') 

257 

258 fn = get_scenario_yml(args[0]) 

259 

260 if not fn: 

261 parser.print_help() 

262 sys.exit(1) 

263 

264 project_dir = args[0] 

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

266 

267 engine = get_engine([gf_stores_path]) 

268 sc = guts.load(filename=fn) 

269 sc.init_modelling(engine) 

270 

271 return snuffler.snuffle( 

272 sc.get_pile(), 

273 stations=sc.get_stations(), 

274 events=sc.get_events()) 

275 

276 

277def main(args=None): 

278 if args is None: 

279 args = sys.argv[1:] 

280 

281 if len(args) < 1: 

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

283 

284 command = args.pop(0) 

285 

286 if command in subcommands: 

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

288 

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

290 if command == 'help' and args: 

291 acommand = args[0] 

292 if acommand in subcommands: 

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

294 

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

296 

297 else: 

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

299 

300 

301def get_engine(gf_store_superdirs): 

302 engine = gf.LocalEngine( 

303 store_superdirs=gf_store_superdirs, use_config=True) 

304 

305 logger.info( 

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

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

308 

309 return engine 

310 

311 

312if __name__ == '__main__': 

313 main()