1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6from __future__ import absolute_import, print_function, division
8import sys
9import logging
10import os.path as op
11from optparse import OptionParser
13from pyrocko import util, scenario, guts, gf
14from pyrocko import __version__
17logger = logging.getLogger('pyrocko.apps.colosseo')
18km = 1000.
21def d2u(d):
22 return dict((k.replace('-', '_'), v) for (k, v) in d.items())
25description = '''This is Colosseo, an earthquake scenario generator.
27Create seismic waveforms, InSAR and GNSS offsets for a simulated earthquake
28scenario.
30Colosseo is part of Pyrocko. Version %s.
31''' % __version__
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}
40subcommand_usages = {
41 'init': 'init <scenario_dir>',
42 'fill': 'fill <scenario_dir>',
43 'snuffle': 'snuffle <scenario_dir>',
44 'map': '<scenario_dir>',
45}
47subcommands = subcommand_descriptions.keys()
49program_name = 'colosseo'
51usage_tdata = d2u(subcommand_descriptions)
52usage_tdata['program_name'] = program_name
53usage_tdata['description'] = description
55usage = '''%(program_name)s <subcommand> [options] [--] <arguments> ...
57%(description)s
59Subcommands:
61 init %(init)s
62 fill %(fill)s
63 snuffle %(snuffle)s
64 map %(map)s
66To get further help and a list of available options for any subcommand run:
68 %(program_name)s <subcommand> --help
70''' % usage_tdata
73def die(message, err='', prelude=''):
74 if prelude:
75 prelude = prelude + '\n'
77 if err:
78 err = '\n' + err
80 sys.exit('%s%s failed: %s%s' % (prelude, program_name, message, err))
83def none_or_float(x):
84 if x == 'none':
85 return None
86 else:
87 return float(x)
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".')
103def process_common_options(options):
104 util.setup_logging(program_name, options.loglevel)
107def cl_parse(command, args, setup=None, details=None):
108 usage = subcommand_usages[command]
109 descr = subcommand_descriptions[command]
111 if isinstance(usage, str):
112 usage = [usage]
114 susage = '%s %s' % (program_name, usage[0])
115 for s in usage[1:]:
116 susage += '\n%s%s %s' % (' '*7, program_name, s)
118 description = descr[0].upper() + descr[1:] + '.'
120 if details:
121 description = description + ' %s' % details
123 parser = OptionParser(usage=susage, description=description)
125 if setup:
126 setup(parser)
128 add_common_options(parser)
129 (options, args) = parser.parse_args(args)
130 process_common_options(options)
131 return parser, options, args
134def get_scenario_yml(path):
135 fn = op.join(path, 'scenario.yml')
136 if op.exists(fn):
137 return fn
138 return False
141def command_init(args):
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]')
154 parser, options, args = cl_parse('init', args, setup=setup)
156 if len(args) != 1:
157 parser.print_help()
158 sys.exit(1)
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
168 if options.radius is not None:
169 radius = options.radius * km
170 else:
171 radius = None
173 project_dir = args[0]
174 try:
175 scenario.ScenarioGenerator.initialize(
176 project_dir, lat, lon, radius, force=options.force)
178 gf_stores_path = op.join(project_dir, 'gf_stores')
179 util.ensuredir(gf_stores_path)
181 except scenario.CannotCreatePath as e:
182 die(str(e) + ' Use --force to override.')
184 except scenario.ScenarioError as e:
185 die(str(e))
188def command_fill(args):
190 def setup(parser):
191 parser.add_option(
192 '--force', dest='force', action='store_true',
193 help='overwrite existing files')
195 parser, options, args = cl_parse('fill', args, setup=setup)
197 if len(args) == 0:
198 args.append('.')
200 fn = get_scenario_yml(args[0])
202 if not fn:
203 parser.print_help()
204 sys.exit(1)
206 project_dir = args[0]
208 gf_stores_path = op.join(project_dir, 'gf_stores')
210 try:
211 engine = get_engine([gf_stores_path])
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'))
220 except scenario.CannotCreatePath as e:
221 die(str(e) + ' Use --force to override.')
223 except scenario.ScenarioError as e:
224 die(str(e))
227def command_map(args):
228 parser, options, args = cl_parse('map', args)
230 if len(args) == 0:
231 args.append('.')
233 fn = get_scenario_yml(args[0])
235 if not fn:
236 parser.print_help()
237 sys.exit(1)
239 project_dir = args[0]
241 gf_stores_path = op.join(project_dir, 'gf_stores')
242 engine = get_engine([gf_stores_path])
244 try:
245 sc = guts.load(filename=fn)
246 sc.init_modelling(engine)
247 sc.make_map(op.join(project_dir, 'map.pdf'))
249 except scenario.ScenarioError as e:
250 die(str(e))
253def command_snuffle(args):
254 from pyrocko.gui.snuffler import snuffler
255 parser, options, args = cl_parse('map', args)
257 if len(args) == 0:
258 args.append('.')
260 fn = get_scenario_yml(args[0])
262 if not fn:
263 parser.print_help()
264 sys.exit(1)
266 project_dir = args[0]
267 gf_stores_path = op.join(project_dir, 'gf_stores')
269 engine = get_engine([gf_stores_path])
270 sc = guts.load(filename=fn)
271 sc.init_modelling(engine)
273 return snuffler.snuffle(
274 sc.get_pile(),
275 stations=sc.get_stations(),
276 events=sc.get_events())
279def main(args=None):
280 if args is None:
281 args = sys.argv[1:]
283 if len(args) < 1:
284 sys.exit('Usage: %s' % usage)
286 command = args.pop(0)
288 if command in subcommands:
289 globals()['command_' + command](args)
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'])
297 sys.exit('Usage: %s' % usage)
299 else:
300 sys.exit('%s: error: no such subcommand: %s' % (program_name, command))
303def get_engine(gf_store_superdirs):
304 engine = gf.LocalEngine(
305 store_superdirs=gf_store_superdirs, use_config=True)
307 logger.info(
308 'Directories to be searched for GF stores:\n%s'
309 % '\n'.join(' ' + s for s in engine.store_superdirs))
311 return engine
314if __name__ == '__main__':
315 main()