1from __future__ import print_function
2# http://pyrocko.org - GPLv3
3#
4# The Pyrocko Developers, 21st Century
5# ---|P------/S----------~Lg----------
7import sys
8import logging
9import os.path as op
10from optparse import OptionParser
12from pyrocko import util, scenario, guts, gf
13from pyrocko import __version__
16logger = logging.getLogger('pyrocko.apps.colosseo')
17km = 1000.
20def d2u(d):
21 return dict((k.replace('-', '_'), v) for (k, v) in d.items())
24description = '''This is Colosseo, an earthquake scenario generator.
26Create seismic waveforms, InSAR and GNSS offsets for a simulated earthquake
27scenario.
29Colosseo is part of Pyrocko. Version %s.
30''' % __version__
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}
39subcommand_usages = {
40 'init': 'init <scenario_dir>',
41 'fill': 'fill <scenario_dir>',
42 'snuffle': 'snuffle <scenario_dir>',
43 'map': '<scenario_dir>',
44}
46subcommands = subcommand_descriptions.keys()
48program_name = 'colosseo'
50usage_tdata = d2u(subcommand_descriptions)
51usage_tdata['program_name'] = program_name
52usage_tdata['description'] = description
54usage = '''%(program_name)s <subcommand> [options] [--] <arguments> ...
56%(description)s
58Subcommands:
60 init %(init)s
61 fill %(fill)s
62 snuffle %(snuffle)s
63 map %(map)s
65To get further help and a list of available options for any subcommand run:
67 %(program_name)s <subcommand> --help
69''' % usage_tdata
72def die(message, err='', prelude=''):
73 if prelude:
74 prelude = prelude + '\n'
76 if err:
77 err = '\n' + err
79 sys.exit('%s%s failed: %s%s' % (prelude, program_name, message, err))
82def none_or_float(x):
83 if x == 'none':
84 return None
85 else:
86 return float(x)
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".')
102def process_common_options(options):
103 util.setup_logging(program_name, options.loglevel)
106def cl_parse(command, args, setup=None, details=None):
107 usage = subcommand_usages[command]
108 descr = subcommand_descriptions[command]
110 if isinstance(usage, str):
111 usage = [usage]
113 susage = '%s %s' % (program_name, usage[0])
114 for s in usage[1:]:
115 susage += '\n%s%s %s' % (' '*7, program_name, s)
117 description = descr[0].upper() + descr[1:] + '.'
119 if details:
120 description = description + ' %s' % details
122 parser = OptionParser(usage=susage, description=description)
124 if setup:
125 setup(parser)
127 add_common_options(parser)
128 (options, args) = parser.parse_args(args)
129 process_common_options(options)
130 return parser, options, args
133def get_scenario_yml(path):
134 fn = op.join(path, 'scenario.yml')
135 if op.exists(fn):
136 return fn
137 return False
140def command_init(args):
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]')
153 parser, options, args = cl_parse('init', args, setup=setup)
155 if len(args) != 1:
156 parser.print_help()
157 sys.exit(1)
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
167 if options.radius is not None:
168 radius = options.radius * km
169 else:
170 radius = None
172 project_dir = args[0]
173 try:
174 scenario.ScenarioGenerator.initialize(
175 project_dir, lat, lon, radius, force=options.force)
177 gf_stores_path = op.join(project_dir, 'gf_stores')
178 util.ensuredir(gf_stores_path)
180 except scenario.CannotCreatePath as e:
181 die(str(e) + ' Use --force to override.')
183 except scenario.ScenarioError as e:
184 die(str(e))
187def command_fill(args):
189 def setup(parser):
190 parser.add_option(
191 '--force', dest='force', action='store_true',
192 help='overwrite existing files')
194 parser, options, args = cl_parse('fill', args, setup=setup)
196 if len(args) == 0:
197 args.append('.')
199 fn = get_scenario_yml(args[0])
201 if not fn:
202 parser.print_help()
203 sys.exit(1)
205 project_dir = args[0]
207 gf_stores_path = op.join(project_dir, 'gf_stores')
209 try:
210 engine = get_engine([gf_stores_path])
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'))
219 except scenario.CannotCreatePath as e:
220 die(str(e) + ' Use --force to override.')
222 except scenario.ScenarioError as e:
223 die(str(e))
226def command_map(args):
227 parser, options, args = cl_parse('map', args)
229 if len(args) == 0:
230 args.append('.')
232 fn = get_scenario_yml(args[0])
234 if not fn:
235 parser.print_help()
236 sys.exit(1)
238 project_dir = args[0]
240 gf_stores_path = op.join(project_dir, 'gf_stores')
241 engine = get_engine([gf_stores_path])
243 try:
244 sc = guts.load(filename=fn)
245 sc.init_modelling(engine)
246 sc.make_map(op.join(project_dir, 'map.pdf'))
248 except scenario.ScenarioError as e:
249 die(str(e))
252def command_snuffle(args):
253 from pyrocko.gui import snuffler
254 parser, options, args = cl_parse('map', args)
256 if len(args) == 0:
257 args.append('.')
259 fn = get_scenario_yml(args[0])
261 if not fn:
262 parser.print_help()
263 sys.exit(1)
265 project_dir = args[0]
266 gf_stores_path = op.join(project_dir, 'gf_stores')
268 engine = get_engine([gf_stores_path])
269 sc = guts.load(filename=fn)
270 sc.init_modelling(engine)
272 return snuffler.snuffle(
273 sc.get_pile(),
274 stations=sc.get_stations(),
275 events=sc.get_events())
278def main(args=None):
279 if args is None:
280 args = sys.argv[1:]
282 if len(args) < 1:
283 sys.exit('Usage: %s' % usage)
285 command = args.pop(0)
287 if command in subcommands:
288 globals()['command_' + command](args)
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'])
296 sys.exit('Usage: %s' % usage)
298 else:
299 sys.exit('%s: error: no such subcommand: %s' % (program_name, command))
302def get_engine(gf_store_superdirs):
303 engine = gf.LocalEngine(
304 store_superdirs=gf_store_superdirs, use_config=True)
306 logger.info(
307 'Directories to be searched for GF stores:\n%s'
308 % '\n'.join(' ' + s for s in engine.store_superdirs))
310 return engine
313if __name__ == '__main__':
314 main()