1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6import sys
7import logging
8import os.path as op
9from optparse import OptionParser
11from pyrocko import util, scenario, guts, gf
12from pyrocko import __version__
15logger = logging.getLogger('pyrocko.apps.colosseo')
16km = 1000.
19def d2u(d):
20 return dict((k.replace('-', '_'), v) for (k, v) in d.items())
23description = '''This is Colosseo, an earthquake scenario generator.
25Create seismic waveforms, InSAR and GNSS offsets for a simulated earthquake
26scenario.
28Colosseo is part of Pyrocko. Version %s.
29''' % __version__
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}
38subcommand_usages = {
39 'init': 'init <scenario_dir>',
40 'fill': 'fill <scenario_dir>',
41 'snuffle': 'snuffle <scenario_dir>',
42 'map': '<scenario_dir>',
43}
45subcommands = subcommand_descriptions.keys()
47program_name = 'colosseo'
49usage_tdata = d2u(subcommand_descriptions)
50usage_tdata['program_name'] = program_name
51usage_tdata['description'] = description
53usage = '''%(program_name)s <subcommand> [options] [--] <arguments> ...
55%(description)s
57Subcommands:
59 init %(init)s
60 fill %(fill)s
61 snuffle %(snuffle)s
62 map %(map)s
64To get further help and a list of available options for any subcommand run:
66 %(program_name)s <subcommand> --help
68''' % usage_tdata
71def die(message, err='', prelude=''):
72 if prelude:
73 prelude = prelude + '\n'
75 if err:
76 err = '\n' + err
78 sys.exit('%s%s failed: %s%s' % (prelude, program_name, message, err))
81def none_or_float(x):
82 if x == 'none':
83 return None
84 else:
85 return float(x)
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".')
101def process_common_options(options):
102 util.setup_logging(program_name, options.loglevel)
105def cl_parse(command, args, setup=None, details=None):
106 usage = subcommand_usages[command]
107 descr = subcommand_descriptions[command]
109 if isinstance(usage, str):
110 usage = [usage]
112 susage = '%s %s' % (program_name, usage[0])
113 for s in usage[1:]:
114 susage += '\n%s%s %s' % (' '*7, program_name, s)
116 description = descr[0].upper() + descr[1:] + '.'
118 if details:
119 description = description + ' %s' % details
121 parser = OptionParser(usage=susage, description=description)
123 if setup:
124 setup(parser)
126 add_common_options(parser)
127 (options, args) = parser.parse_args(args)
128 process_common_options(options)
129 return parser, options, args
132def get_scenario_yml(path):
133 fn = op.join(path, 'scenario.yml')
134 if op.exists(fn):
135 return fn
136 return False
139def command_init(args):
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]')
152 parser, options, args = cl_parse('init', args, setup=setup)
154 if len(args) != 1:
155 parser.print_help()
156 sys.exit(1)
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
166 if options.radius is not None:
167 radius = options.radius * km
168 else:
169 radius = None
171 project_dir = args[0]
172 try:
173 scenario.ScenarioGenerator.initialize(
174 project_dir, lat, lon, radius, force=options.force)
176 gf_stores_path = op.join(project_dir, 'gf_stores')
177 util.ensuredir(gf_stores_path)
179 except scenario.CannotCreatePath as e:
180 die(str(e) + ' Use --force to override.')
182 except scenario.ScenarioError as e:
183 die(str(e))
186def command_fill(args):
188 def setup(parser):
189 parser.add_option(
190 '--force', dest='force', action='store_true',
191 help='overwrite existing files')
193 parser, options, args = cl_parse('fill', args, setup=setup)
195 if len(args) == 0:
196 args.append('.')
198 fn = get_scenario_yml(args[0])
200 if not fn:
201 parser.print_help()
202 sys.exit(1)
204 project_dir = args[0]
206 gf_stores_path = op.join(project_dir, 'gf_stores')
208 try:
209 engine = get_engine([gf_stores_path])
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'))
218 except scenario.CannotCreatePath as e:
219 die(str(e) + ' Use --force to override.')
221 except scenario.ScenarioError as e:
222 die(str(e))
225def command_map(args):
226 parser, options, args = cl_parse('map', args)
228 if len(args) == 0:
229 args.append('.')
231 fn = get_scenario_yml(args[0])
233 if not fn:
234 parser.print_help()
235 sys.exit(1)
237 project_dir = args[0]
239 gf_stores_path = op.join(project_dir, 'gf_stores')
240 engine = get_engine([gf_stores_path])
242 try:
243 sc = guts.load(filename=fn)
244 sc.init_modelling(engine)
245 sc.make_map(op.join(project_dir, 'map.pdf'))
247 except scenario.ScenarioError as e:
248 die(str(e))
251def command_snuffle(args):
252 from pyrocko.gui.snuffler import snuffler
253 parser, options, args = cl_parse('map', args)
255 if len(args) == 0:
256 args.append('.')
258 fn = get_scenario_yml(args[0])
260 if not fn:
261 parser.print_help()
262 sys.exit(1)
264 project_dir = args[0]
265 gf_stores_path = op.join(project_dir, 'gf_stores')
267 engine = get_engine([gf_stores_path])
268 sc = guts.load(filename=fn)
269 sc.init_modelling(engine)
271 return snuffler.snuffle(
272 sc.get_pile(),
273 stations=sc.get_stations(),
274 events=sc.get_events())
277def main(args=None):
278 if args is None:
279 args = sys.argv[1:]
281 if len(args) < 1:
282 sys.exit('Usage: %s' % usage)
284 command = args.pop(0)
286 if command in subcommands:
287 globals()['command_' + command](args)
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'])
295 sys.exit('Usage: %s' % usage)
297 else:
298 sys.exit('%s: error: no such subcommand: %s' % (program_name, command))
301def get_engine(gf_store_superdirs):
302 engine = gf.LocalEngine(
303 store_superdirs=gf_store_superdirs, use_config=True)
305 logger.info(
306 'Directories to be searched for GF stores:\n%s'
307 % '\n'.join(' ' + s for s in engine.store_superdirs))
309 return engine
312if __name__ == '__main__':
313 main()