Coverage for /usr/local/lib/python3.11/dist-packages/grond/apps/grond.py: 51%

742 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-10-26 16:25 +0000

1#!/usr/bin/env python 

2 

3from __future__ import print_function, absolute_import 

4 

5import sys 

6import os.path as op 

7import logging 

8from optparse import OptionParser, OptionValueError 

9import grond 

10from io import StringIO 

11 

12try: 

13 from pyrocko import util, marker 

14except ImportError: 

15 print('Pyrocko is required for Grond!' 

16 'Go to https://pyrocko.org/ for installation instructions.') 

17 

18 

19logger = logging.getLogger('grond.main') 

20km = 1e3 

21 

22 

23class Color: 

24 PURPLE = '\033[95m' 

25 CYAN = '\033[96m' 

26 DARKCYAN = '\033[36m' 

27 BLUE = '\033[94m' 

28 GREEN = '\033[92m' 

29 YELLOW = '\033[93m' 

30 RED = '\033[91m' 

31 BOLD = '\033[1m' 

32 UNDERLINE = '\033[4m' 

33 END = '\033[0m' 

34 

35 

36def d2u(d): 

37 if isinstance(d, dict): 

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

39 else: 

40 return d.replace('-', '_') 

41 

42 

43subcommand_descriptions = { 

44 'init': 'initialise new project structure or print configuration', 

45 'scenario': 'create a forward-modelled scenario project', 

46 'events': 'print available event names for given configuration', 

47 'check': 'check data and configuration', 

48 'go': 'run Grond optimisation', 

49 'continue': 'continue a Grond optimisation in case of an' 

50 ' interruption or more iterations are needed', 

51 'forward': 'run forward modelling', 

52 'harvest': 'manually run harvesting', 

53 'cluster': 'run cluster analysis on result ensemble', 

54 'plot': 'plot optimisation result', 

55 'movie': 'visualize optimiser evolution', 

56 'export': 'export results', 

57 'tag': 'add user-defined label to run directories', 

58 'report': 'create result report', 

59 'diff': 'compare two configs or other normalized Grond YAML files', 

60 'qc-polarization': 'check sensor orientations with polarization analysis', 

61 'upgrade-config': 'upgrade config file to the latest version of Grond', 

62 'version': 'print version number of Grond and its main dependencies', 

63} 

64 

65subcommand_usages = { 

66 'init': ( 

67 'init list [options]', 

68 'init <example> [options]', 

69 'init <example> <projectdir> [options]'), 

70 'scenario': 'scenario [options] <projectdir>', 

71 'events': 'events <configfile>', 

72 'check': 'check <configfile> <eventnames> ... [options]', 

73 'go': 'go <configfile> <eventnames> ... [options]', 

74 'continue': 'continue <configfile> <eventnames> ... [options]', 

75 'forward': ( 

76 'forward <rundir> [options]', 

77 'forward <configfile> <eventnames> ... [options]'), 

78 'harvest': 'harvest <rundir> [options]', 

79 'cluster': ( 

80 'cluster <method> <rundir> [options]', 

81 'cluster <clusteringconfigfile> <rundir> [options]'), 

82 'plot': ( 

83 'plot <plotnames> ( <rundir> | <configfile> <eventname> ) [options]', 

84 'plot all ( <rundir> | <configfile> <eventname> ) [options]', 

85 'plot <plotconfigfile> ( <rundir> | <configfile> <eventname> ) [options]', # noqa 

86 'plot list ( <rundir> | <configfile> <eventname> ) [options]', 

87 'plot config ( <rundir> | <configfile> <eventname> ) [options]'), 

88 'movie': 'movie <rundir> <xpar> <ypar> <filetemplate> [options]', 

89 'export': 'export (best|mean|ensemble|stats) <rundirs> ... [options]', 

90 'tag': ( 

91 'tag add <tag> <rundir>', 

92 'tag remove <tag> <rundir>', 

93 'tag list <rundir>'), 

94 'report': ( 

95 'report <rundir> ... [options]', 

96 'report <configfile> <eventnames> ...'), 

97 'diff': 'diff <left_path> <right_path>', 

98 'qc-polarization': 'qc-polarization <configfile> <eventname> ' 

99 '<target_group_path> [options]', 

100 'upgrade-config': 'upgrade-config <configfile>', 

101 'version': 'version', 

102} 

103 

104subcommands = subcommand_descriptions.keys() 

105 

106program_name = 'grond' 

107 

108usage_tdata = d2u(subcommand_descriptions) 

109usage_tdata['program_name'] = program_name 

110usage_tdata['version_number'] = grond.__version__ 

111 

112 

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

114 

115Grond is a probabilistic earthquake source inversion framework. 

116 

117This is Grond version %(version_number)s. 

118 

119Subcommands: 

120 

121 scenario %(scenario)s 

122 init %(init)s 

123 events %(events)s 

124 check %(check)s 

125 go %(go)s 

126 continue %(continue)s 

127 forward %(forward)s 

128 harvest %(harvest)s 

129 cluster %(cluster)s 

130 plot %(plot)s 

131 movie %(movie)s 

132 export %(export)s 

133 tag %(tag)s 

134 report %(report)s 

135 diff %(diff)s 

136 qc-polarization %(qc_polarization)s 

137 upgrade-config %(upgrade_config)s 

138 version %(version)s 

139 

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

141 

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

143 

144What do you want to bust today?! 

145''' % usage_tdata 

146 

147 

148class CLIHints(object): 

149 init = ''' 

150We created a folder structure in {project_dir}. 

151Check out the YAML configuration in {config} and start the optimisation by: 

152 

153 grond go {config} 

154''' 

155 scenario = ''' 

156To start the scenario's optimisation, change to folder 

157 

158 cd {project_dir} 

159 

160Check out the YAML configuration in {config} and start the optimisation by: 

161 

162 grond go {config} 

163''' 

164 report = ''' 

165To open the report in your web browser, run 

166 

167 grond report -s --open {config} 

168''' 

169 check = ''' 

170To start the optimisation, run 

171 

172 grond go {config} 

173''' 

174 go = ''' 

175To look at the results, run 

176 

177 grond report -so {rundir} 

178''' 

179 

180 def __new__(cls, command, **kwargs): 

181 return '{c.BOLD}Hint{c.END}\n'.format(c=Color) +\ 

182 getattr(cls, command).format(**kwargs) 

183 

184 

185def main(args=None): 

186 if not args: 

187 args = sys.argv 

188 

189 args = list(args) 

190 if len(args) < 2: 

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

192 

193 args.pop(0) 

194 command = args.pop(0) 

195 

196 if command in subcommands: 

197 globals()['command_' + d2u(command)](args) 

198 

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

200 if command == 'help' and args: 

201 acommand = args[0] 

202 if acommand in subcommands: 

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

204 

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

206 

207 else: 

208 die('No such subcommand: %s' % command) 

209 

210 

211def add_common_options(parser): 

212 parser.add_option( 

213 '--loglevel', 

214 action='store', 

215 dest='loglevel', 

216 type='choice', 

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

218 help='set logger level to ' 

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

220 'Default is "info".') 

221 

222 parser.add_option( 

223 '--status', dest='status', 

224 type='choice', choices=['state', 'quiet'], 

225 help='status output selection (choices: state, quiet, default: ' 

226 'state)') 

227 

228 parser.add_option( 

229 '--parallel', dest='nparallel', type=int, 

230 help='set number of events to process in parallel, ' 

231 'if set to more than one, --status=quiet is implied.') 

232 

233 parser.add_option( 

234 '--threads', dest='nthreads', type=int, 

235 help='set number of threads per process (default: 1). ' 

236 'Set to 0 to use all available cores.') 

237 

238 parser.add_option( 

239 '--docs', 

240 dest='rst_docs', 

241 action='store_true') 

242 

243 

244def print_docs(command, parser): 

245 

246 from optparse import IndentedHelpFormatter 

247 

248 class DocsFormatter(IndentedHelpFormatter): 

249 

250 def format_heading(self, heading): 

251 return '%s\n%s\n\n' % (heading, '.'*len(heading)) 

252 

253 def format_usage(self, usage): 

254 lines = usage.splitlines() 

255 return self.format_heading('Usage') + \ 

256 '.. code-block:: none\n\n%s' % '\n'.join( 

257 ' '+line.strip() for line in lines) 

258 

259 def format_option(self, option): 

260 if not option.help: 

261 return '' 

262 

263 result = [] 

264 opts = self.option_strings[option] 

265 result.append('\n.. describe:: %s\n\n' % opts) 

266 

267 help_text = self.expand_default(option) 

268 result.append(' %s\n\n' % help_text) 

269 

270 return ''.join(result) 

271 

272 parser.formatter = DocsFormatter() 

273 parser.formatter.set_parser(parser) 

274 

275 def format_help(parser): 

276 formatter = parser.formatter 

277 result = [] 

278 

279 result.append(parser.format_description(formatter) + "\n") 

280 

281 if parser.usage: 

282 result.append(parser.get_usage() + "\n") 

283 

284 result.append('\n') 

285 

286 result.append(parser.format_option_help(formatter)) 

287 

288 result.append('\n') 

289 

290 result.append(parser.format_epilog(formatter)) 

291 return "".join(result) 

292 

293 print(command) 

294 print('-' * len(command)) 

295 print() 

296 print('.. program:: %s' % program_name) 

297 print() 

298 print('.. option:: %s' % command) 

299 print() 

300 print(format_help(parser)) 

301 

302 

303def process_common_options(command, parser, options): 

304 from grond.config import get_global_config 

305 

306 gconf = get_global_config() 

307 gconf.override_with_cli_arguments(options) 

308 

309 util.setup_logging(program_name, gconf.loglevel) 

310 if options.rst_docs: 

311 print_docs(command, parser) 

312 exit(0) 

313 

314 

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

316 usage = subcommand_usages[command] 

317 descr = subcommand_descriptions[command] 

318 

319 if isinstance(usage, str): 

320 usage = [usage] 

321 

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

323 for s in usage[1:]: 

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

325 

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

327 

328 if details: 

329 description = description + '\n\n%s' % details 

330 

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

332 

333 if setup: 

334 setup(parser) 

335 

336 add_common_options(parser) 

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

338 process_common_options(command, parser, options) 

339 return parser, options, args 

340 

341 

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

343 if prelude: 

344 prelude = prelude + '\n' 

345 

346 if err: 

347 err = '\n' + err 

348 

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

350 

351 

352def help_and_die(parser, message): 

353 sio = StringIO() 

354 parser.print_help(sio) 

355 die(message, prelude=sio.getvalue()) 

356 

357 

358def multiple_choice(option, opt_str, value, parser, choices): 

359 options = value.split(',') 

360 for opt in options: 

361 if opt not in choices: 

362 raise OptionValueError('Invalid option %s - valid options are: %s' 

363 % (opt, ', '.join(choices))) 

364 setattr(parser.values, option.dest, options) 

365 

366 

367def magnitude_range(option, opt_str, value, parser): 

368 mag_range = value.split('-') 

369 if len(mag_range) != 2: 

370 raise OptionValueError( 

371 'Invalid magnitude %s - valid range is e.g. 6-7.' % value) 

372 try: 

373 mag_range = tuple(map(float, mag_range)) 

374 except ValueError: 

375 raise OptionValueError('Magnitudes must be numbers.') 

376 

377 if mag_range[0] > mag_range[1]: 

378 raise OptionValueError('Minimum magnitude must be larger than' 

379 ' maximum magnitude.') 

380 setattr(parser.values, option.dest, mag_range) 

381 

382 

383def command_scenario(args): 

384 

385 STORE_STATIC = 'crust2_ib_static' 

386 STORE_WAVEFORMS = 'crust2_ib' 

387 

388 def setup(parser): 

389 parser.add_option( 

390 '--targets', action='callback', dest='targets', type=str, 

391 callback=multiple_choice, callback_kwargs={ 

392 'choices': ('waveforms', 'gnss', 'insar') 

393 }, 

394 default='waveforms', 

395 help='forward modelling targets for the scenario. Select from:' 

396 ' waveforms, gnss and insar. Multiple selection by ' 

397 '--targets=waveforms,gnss,insar' 

398 '(default: --targets=%default)') 

399 parser.add_option( 

400 '--problem', dest='problem', default='cmt', 

401 type='choice', choices=['cmt', 'rectangular', 'dynamic_rupture'], 

402 help='problem to generate: \'dc\' (double couple), ' 

403 '\'rectangular\' (rectangular finite fault) or ' 

404 '\'dynamic_rupture\' for a dynamic rupture scenario.' 

405 ' (default: \'%default\')') 

406 parser.add_option( 

407 '--magnitude-range', dest='magnitude_range', type=str, 

408 action='callback', callback=magnitude_range, default=[6.0, 7.0], 

409 help='Magnitude range min_mag-max_mag (default: %default)') 

410 parser.add_option( 

411 '--nstations', dest='nstations', type=int, default=20, 

412 help='number of seismic stations to create (default: %default)') 

413 parser.add_option( 

414 '--gnss_nstations', dest='gnss_nstations', type=int, default=20, 

415 help='number of GNSS campaign stations to create' 

416 ' (default: %default)') 

417 parser.add_option( 

418 '--nevents', dest='nevents', type=int, default=1, 

419 help='number of events to create (default: %default)') 

420 parser.add_option( 

421 '--lat', dest='lat', type=float, default=41.0, 

422 help='center latitude of the scenario (default: %default)') 

423 parser.add_option( 

424 '--lon', dest='lon', type=float, default=33.3, 

425 help='center latitude of the scenario (default: %default)') 

426 parser.add_option( 

427 '--radius', dest='radius', type=float, default=100., 

428 help='radius of the scenario in [km] (default: %default)') 

429 parser.add_option( 

430 '--source-radius', dest='source_radius', type=float, default=10., 

431 help='radius of the source area in [km] (default: %default)') 

432 parser.add_option( 

433 '--stations-paths', dest='stations_paths', type=str, default=None, 

434 help='paths to a Pyrocko station file, seperated by \',\'' 

435 '(default: %default)') 

436 parser.add_option( 

437 '--stationxml-paths', dest='stationxml_paths', type=str, 

438 default=None, 

439 help='paths to StationXML files, seperated by \',\'' 

440 '(default: %default)') 

441 parser.add_option( 

442 '--gf-waveforms', dest='store_waveforms', type=str, 

443 default=STORE_WAVEFORMS, 

444 help='Green\'s function store for waveform modelling, ' 

445 '(default: %default)') 

446 parser.add_option( 

447 '--gf-static', dest='store_statics', type=str, 

448 default=STORE_STATIC, 

449 help='Green\'s function store for static modelling, ' 

450 '(default: %default)') 

451 parser.add_option( 

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

453 help='overwrite existing project folder.') 

454 parser.add_option( 

455 '--gf-store-superdirs', 

456 dest='gf_store_superdirs', 

457 help='Comma-separated list of directories containing GF stores') 

458 parser.add_option( 

459 '--no-map', 

460 dest='make_map', 

461 default=True, 

462 action='store_false', 

463 help='suppress generation of map') 

464 parser.add_option( 

465 '--rebuild', 

466 dest='rebuild', action='store_true', default=False, 

467 help='Rebuild a manually configured grond scenario') 

468 

469 parser, options, args = cl_parse('scenario', args, setup) 

470 

471 gf_store_superdirs = None 

472 if options.gf_store_superdirs: 

473 gf_store_superdirs = options.gf_store_superdirs.split(',') 

474 

475 if len(args) == 1: 

476 project_dir = args[0] 

477 else: 

478 parser.print_help() 

479 sys.exit(1) 

480 

481 from grond import scenario as grond_scenario 

482 

483 try: 

484 scenario = grond_scenario.GrondScenario( 

485 project_dir, 

486 center_lat=options.lat, center_lon=options.lon, 

487 radius=options.radius*km) 

488 

489 scenario.rebuild = options.rebuild 

490 if options.rebuild: 

491 options.force = True 

492 

493 if 'waveforms' in options.targets: 

494 if options.stationxml_paths: 

495 options.stationxml_paths = [ 

496 op.abspath(path) for path in 

497 options.stationxml_paths.split(',')] 

498 

499 if options.stations_paths: 

500 options.stations_paths = [ 

501 op.abspath(path) for path in 

502 options.stations_paths.split(',')] 

503 

504 obs = grond_scenario.WaveformObservation( 

505 nstations=options.nstations, 

506 store_id=options.store_waveforms, 

507 stations_paths=options.stations_paths, 

508 stationxml_paths=options.stationxml_paths) 

509 scenario.add_observation(obs) 

510 

511 if 'insar' in options.targets: 

512 obs = grond_scenario.InSARObservation( 

513 store_id=options.store_statics) 

514 scenario.add_observation(obs) 

515 

516 if 'gnss' in options.targets: 

517 obs = grond_scenario.GNSSCampaignObservation( 

518 nstations=options.gnss_nstations, 

519 store_id=options.store_statics) 

520 scenario.add_observation(obs) 

521 

522 src_args = dict( 

523 nevents=options.nevents, 

524 magnitude_min=options.magnitude_range[0], 

525 magnitude_max=options.magnitude_range[1]) 

526 if options.problem == 'cmt': 

527 problem = grond_scenario.DCSourceProblem(**src_args) 

528 elif options.problem == 'rectangular': 

529 problem = grond_scenario.RectangularSourceProblem(**src_args) 

530 elif options.problem == 'dynamic_rupture': 

531 problem = grond_scenario.PseudoDynamicRuptureProblem(**src_args) 

532 scenario.set_problem(problem) 

533 

534 scenario.build( 

535 force=options.force, 

536 interactive=True, 

537 gf_store_superdirs=gf_store_superdirs, 

538 make_map=options.make_map) 

539 

540 logger.info(CLIHints('scenario', 

541 config=scenario.get_grond_config_path(), 

542 project_dir=project_dir)) 

543 

544 except grond.GrondError as e: 

545 die(str(e)) 

546 

547 

548def command_init(args): 

549 

550 from .cmd_init import GrondInit 

551 

552 grond_init = GrondInit() 

553 

554 def print_section(entries): 

555 if len(entries) == 0: 

556 return '\tNone available.' 

557 

558 padding = max([len(n) for n in entries.keys()]) 

559 rstr = [] 

560 lcat = None 

561 for name, desc in entries.items(): 

562 

563 cat = name.split('_')[0] 

564 if lcat is not None and lcat != cat: 

565 rstr.append('') 

566 lcat = cat 

567 

568 rstr.append(' {c.BOLD}{name:<{padding}}{c.END} : {desc}'.format( 

569 name=name, desc=desc, padding=padding, c=Color)) 

570 return '\n'.join(rstr) 

571 

572 help_text = '''Available configuration examples for Grond. 

573 

574{c.BOLD}Example Projects{c.END} 

575 

576 Deploy a full project structure into a directory. 

577 

578 usage: grond init <example> <projectdir> 

579 

580 where <example> is any of the following: 

581 

582{examples_list} 

583 

584{c.BOLD}Config Sections{c.END} 

585 

586 Print out configuration snippets for various components. 

587 

588 usage: grond init <section> 

589 

590 where <section> is any of the following: 

591 

592{sections_list} 

593'''.format(c=Color, 

594 examples_list=print_section(grond_init.get_examples()), 

595 sections_list=print_section(grond_init.get_sections())) 

596 

597 def setup(parser): 

598 parser.add_option( 

599 '--force', dest='force', action='store_true') 

600 

601 parser, options, args = cl_parse( 

602 'init', args, setup, 

603 'Use grond init list to show available examples.') 

604 

605 if len(args) not in (1, 2): 

606 help_and_die(parser, '1 or 2 arguments required') 

607 

608 if args[0] == 'list': 

609 print(help_text) 

610 return 

611 

612 if args[0].startswith('example_'): 

613 if len(args) == 1: 

614 config = grond_init.get_content_example(args[0]) 

615 if not config: 

616 help_and_die(parser, 'Unknown example: %s' % args[0]) 

617 

618 sys.stdout.write(config+'\n\n') 

619 

620 logger.info('Hint: To create a project, use: grond init <example> ' 

621 '<projectdir>') 

622 

623 elif op.exists(op.abspath(args[1])) and not options.force: 

624 help_and_die( 

625 parser, 

626 'Directory "%s" already exists! Use --force to overwrite.' 

627 % args[1]) 

628 else: 

629 try: 

630 grond_init.init_example(args[0], args[1], force=options.force) 

631 except OSError as e: 

632 print(str(e)) 

633 

634 else: 

635 sec = grond_init.get_content_snippet(args[0]) 

636 if not sec: 

637 help_and_die(parser, 'Unknown snippet: %s' % args[0]) 

638 

639 sys.stdout.write(sec) 

640 

641 

642def command_init_old(args): 

643 

644 from . import cmd_init as init 

645 

646 def setup(parser): 

647 parser.add_option( 

648 '--targets', action='callback', dest='targets', type=str, 

649 callback=multiple_choice, callback_kwargs={ 

650 'choices': ('waveforms', 'gnss', 'insar', 'all') 

651 }, 

652 default='waveforms', 

653 help='select from:' 

654 ' waveforms, gnss and insar. ' 

655 '(default: --targets=%default,' 

656 ' multiple selection by --targets=waveforms,gnss,insar)') 

657 parser.add_option( 

658 '--problem', dest='problem', 

659 type='choice', choices=['cmt', 'rectangular'], 

660 help='problem to generate: \'dc\' (double couple)' 

661 ' or\'rectangular\' (rectangular finite fault)' 

662 ' (default: \'%default\')') 

663 parser.add_option( 

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

665 help='overwrite existing project folder') 

666 

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

668 

669 try: 

670 project = init.GrondProject() 

671 

672 if 'all' in options.targets: 

673 targets = ['waveforms', 'gnss', 'insar'] 

674 else: 

675 targets = options.targets 

676 

677 if not options.problem: 

678 if 'insar' in targets or 'gnss' in targets: 

679 problem = 'rectangular' 

680 else: 

681 problem = 'cmt' 

682 else: 

683 problem = options.problem 

684 

685 if problem == 'rectangular': 

686 project.set_rectangular_source() 

687 elif problem == 'cmt': 

688 project.set_cmt_source() 

689 

690 if 'waveforms' in targets: 

691 project.add_waveforms() 

692 

693 if 'insar' in targets: 

694 project.add_insar() 

695 

696 if 'gnss' in targets: 

697 project.add_gnss() 

698 

699 if len(args) == 1: 

700 project_dir = args[0] 

701 project.build(project_dir, options.force) 

702 logger.info(CLIHints( 

703 'init', project_dir=project_dir, 

704 config=op.join(project_dir, 'config', 'config.gronf'))) 

705 else: 

706 sys.stdout.write(project.dump()) 

707 

708 except grond.GrondError as e: 

709 die(str(e)) 

710 

711 

712def command_events(args): 

713 def setup(parser): 

714 pass 

715 

716 parser, options, args = cl_parse('events', args, setup) 

717 if len(args) != 1: 

718 help_and_die(parser, 'missing arguments') 

719 

720 config_path = args[0] 

721 try: 

722 config = grond.read_config(config_path) 

723 

724 for event_name in grond.get_event_names(config): 

725 print(event_name) 

726 

727 except grond.GrondError as e: 

728 die(str(e)) 

729 

730 

731def command_check(args): 

732 

733 from grond.environment import Environment 

734 

735 def setup(parser): 

736 parser.add_option( 

737 '--target-ids', dest='target_string_ids', metavar='TARGET_IDS', 

738 help='process only selected targets. TARGET_IDS is a ' 

739 'comma-separated list of target IDs. Target IDs have the ' 

740 'form SUPERGROUP.GROUP.NETWORK.STATION.LOCATION.CHANNEL.') 

741 

742 parser.add_option( 

743 '--waveforms', dest='show_waveforms', action='store_true', 

744 help='show raw, restituted, projected, and processed waveforms') 

745 

746 parser.add_option( 

747 '--nrandom', dest='n_random_synthetics', metavar='N', type=int, 

748 default=10, 

749 help='set number of random synthetics to forward model (default: ' 

750 '10). If set to zero, create synthetics for the reference ' 

751 'solution.') 

752 

753 parser.add_option( 

754 '--save-stations-used', dest='stations_used_path', 

755 metavar='FILENAME', 

756 help='aggregate all stations used by the setup into a file') 

757 

758 parser, options, args = cl_parse('check', args, setup) 

759 if len(args) < 1: 

760 help_and_die(parser, 'missing arguments') 

761 

762 try: 

763 env = Environment(args) 

764 config = env.get_config() 

765 

766 target_string_ids = None 

767 if options.target_string_ids: 

768 target_string_ids = options.target_string_ids.split(',') 

769 

770 grond.check( 

771 config, 

772 event_names=env.get_selected_event_names(), 

773 target_string_ids=target_string_ids, 

774 show_waveforms=options.show_waveforms, 

775 n_random_synthetics=options.n_random_synthetics, 

776 stations_used_path=options.stations_used_path) 

777 

778 logger.info(CLIHints('check', config=env.get_config_path())) 

779 

780 except grond.GrondError as e: 

781 die(str(e)) 

782 

783 

784def command_go(args): 

785 

786 from grond.environment import Environment 

787 

788 def setup(parser): 

789 parser.add_option( 

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

791 help='overwrite existing run directory') 

792 parser.add_option( 

793 '--preserve', dest='preserve', action='store_true', 

794 help='preserve old rundir') 

795 

796 parser, options, args = cl_parse('go', args, setup) 

797 

798 try: 

799 env = Environment(args) 

800 

801 grond.go( 

802 env, 

803 force=options.force, 

804 preserve=options.preserve) 

805 

806 if len(env.get_selected_event_names()) == 1: 

807 logger.info(CLIHints( 

808 'go', rundir=env.get_rundir_path())) 

809 

810 except grond.GrondError as e: 

811 die(str(e)) 

812 

813 

814def command_continue(args): 

815 

816 from grond.environment import Environment 

817 

818 def setup(parser): 

819 parser.add_option( 

820 '--no-preserve', dest='no_preserve', action='store_true', 

821 help='do not preserve old rundir') 

822 parser.add_option( 

823 '--status', dest='status', default='state', 

824 type='choice', choices=['state', 'quiet'], 

825 help='status output selection (choices: state, quiet, default: ' 

826 'state)') 

827 parser.add_option( 

828 '--parallel', dest='nparallel', type=int, default=1, 

829 help='set number of events to process in parallel, ' 

830 'if set to more than one, --status=quiet is implied.') 

831 parser.add_option( 

832 '--threads', dest='nthreads', type=int, default=1, 

833 help='set number of threads per process (default: 1). ' 

834 'Set to 0 to use all available cores.') 

835 

836 parser, options, args = cl_parse('continue', args, setup) 

837 

838 try: 

839 env = Environment(args) 

840 

841 status = options.status 

842 if options.nparallel != 1: 

843 status = 'quiet' 

844 

845 grond.continue_run( 

846 env, 

847 preserve=~bool(options.no_preserve), 

848 status=status, 

849 nparallel=options.nparallel, 

850 nthreads=options.nthreads) 

851 

852 except grond.GrondError as e: 

853 die(str(e)) 

854 

855 

856def command_forward(args): 

857 

858 from grond.environment import Environment 

859 

860 def setup(parser): 

861 parser.add_option( 

862 '--show', dest='show', metavar='WHAT', 

863 default='filtered', 

864 choices=('filtered', 'processed'), 

865 help='select whether to show only "filtered" or fully "processed" ' 

866 '(i.e. tapered) waveforms (default "%default").') 

867 

868 parser, options, args = cl_parse('forward', args, setup) 

869 if len(args) < 1: 

870 help_and_die(parser, 'missing arguments') 

871 

872 try: 

873 env = Environment(args) 

874 grond.forward(env, show=options.show) 

875 except grond.GrondError as e: 

876 die(str(e)) 

877 

878 

879def command_harvest(args): 

880 def setup(parser): 

881 parser.add_option( 

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

883 help='overwrite existing harvest directory') 

884 parser.add_option( 

885 '--neach', dest='neach', type=int, default=10, 

886 help='take NEACH best samples from each chain (default: %default)') 

887 parser.add_option( 

888 '--weed', dest='weed', type=int, default=0, 

889 help='weed out bootstrap samples with bad global performance. ' 

890 '0: no weeding (default), ' 

891 '1: only bootstrap chains where all NEACH best samples ' 

892 'global misfit is less than the global average misfit of all ' 

893 'NEACH best in all chains plus one standard deviation are ' 

894 'included in the harvest ensemble, ' 

895 '2: same as 1 but additionally individual samples are ' 

896 'removed if their global misfit is greater than the global ' 

897 'average misfit of all NEACH best in all chains, ' 

898 '3: harvesting is done on the global chain only, bootstrap ' 

899 'chains are excluded') 

900 parser.add_option( 

901 '--export-fits', dest='export_fits', default='', 

902 help='additionally export details about the fit of individual ' 

903 'targets. "best" - export fits of best model, "mean" - ' 

904 'export fits of ensemble mean model, "ensemble" - export ' 

905 'fits of all models in harvest ensemble.') 

906 

907 parser, options, args = cl_parse('harvest', args, setup) 

908 if len(args) < 1: 

909 help_and_die(parser, 'no rundir') 

910 

911 export_fits = [] 

912 if options.export_fits.strip(): 

913 export_fits = [x.strip() for x in options.export_fits.split(',')] 

914 

915 for run_path in args: 

916 try: 

917 grond.harvest( 

918 run_path, 

919 force=options.force, 

920 nbest=options.neach, 

921 weed=options.weed, 

922 export_fits=export_fits) 

923 

924 except grond.DirectoryAlreadyExists as e: 

925 die(str(e) + '\n Use --force to overwrite.') 

926 

927 except grond.GrondError as e: 

928 die(str(e)) 

929 

930 

931def command_cluster(args): 

932 from grond import Clustering 

933 from grond.clustering import metrics, methods, read_config, write_config 

934 

935 def setup(parser): 

936 parser.add_option( 

937 '--metric', dest='metric', metavar='METRIC', 

938 default='kagan_angle', 

939 choices=metrics.metrics, 

940 help='metric to measure model distances. Choices: [%s]. Default: ' 

941 'kagan_angle' % ', '.join(metrics.metrics)) 

942 

943 parser.add_option( 

944 '--write-config', 

945 dest='write_config', 

946 metavar='FILE', 

947 help='write configuration (or default configuration) to FILE') 

948 

949 method = args[0] if args else '' 

950 try: 

951 parser, options, args = cl_parse( 

952 'cluster', args[1:], setup=Clustering.cli_setup(method, setup), 

953 details='Available clustering methods: [%s]. Use ' 

954 '"grond cluster <method> --help" to get list of method ' 

955 'dependent options.' % ', '.join(methods)) 

956 

957 if method not in Clustering.name_to_class and not op.exists(method): 

958 help_and_die( 

959 parser, 

960 'no such clustering method: %s' % method if method else 

961 'no clustering method specified') 

962 

963 if op.exists(method): 

964 clustering = read_config(method) 

965 else: 

966 clustering = Clustering.cli_instantiate(method, options) 

967 

968 if options.write_config: 

969 write_config(clustering, options.write_config) 

970 else: 

971 if len(args) != 1: 

972 help_and_die(parser, 'no rundir') 

973 run_path, = args 

974 

975 grond.cluster(run_path, clustering, metric=options.metric) 

976 

977 except grond.GrondError as e: 

978 die(str(e)) 

979 

980 

981def command_plot(args): 

982 

983 def setup(parser): 

984 parser.add_option( 

985 '--show', dest='show', action='store_true', 

986 help='show plot for interactive inspection') 

987 

988 details = '' 

989 

990 parser, options, args = cl_parse('plot', args, setup, details) 

991 

992 if not options.show: 

993 import matplotlib 

994 matplotlib.use('Agg') 

995 

996 from grond.environment import Environment 

997 

998 if len(args) not in (1, 2, 3): 

999 help_and_die(parser, '1, 2 or 3 arguments required') 

1000 

1001 if len(args) > 1: 

1002 env = Environment(args[1:]) 

1003 else: 

1004 env = None 

1005 

1006 from grond import plot 

1007 if args[0] == 'list': 

1008 

1009 def get_doc_title(doc): 

1010 for ln in doc.split('\n'): 

1011 ln = ln.strip() 

1012 if ln != '': 

1013 ln = ln.strip('.') 

1014 return ln 

1015 return 'Undocumented.' 

1016 

1017 if env: 

1018 plot_classes = env.get_plot_classes() 

1019 else: 

1020 plot_classes = plot.get_all_plot_classes() 

1021 

1022 plot_names, plot_doc = zip(*[(pc.name, pc.__doc__) 

1023 for pc in plot_classes]) 

1024 

1025 plot_descs = [get_doc_title(doc) for doc in plot_doc] 

1026 left_spaces = max([len(pn) for pn in plot_names]) 

1027 

1028 for name, desc in zip(plot_names, plot_descs): 

1029 print('{name:<{ls}} - {desc}'.format( 

1030 ls=left_spaces, name=name, desc=desc)) 

1031 

1032 elif args[0] == 'config': 

1033 plot_config_collection = plot.get_plot_config_collection(env) 

1034 print(plot_config_collection) 

1035 

1036 elif args[0] == 'all': 

1037 if env is None: 

1038 help_and_die(parser, 'two or three arguments required') 

1039 plot_names = plot.get_plot_names(env) 

1040 plot.make_plots(env, plot_names=plot_names, show=options.show) 

1041 

1042 elif op.exists(args[0]): 

1043 if env is None: 

1044 help_and_die(parser, 'two or three arguments required') 

1045 plots = plot.PlotConfigCollection.load(args[0]) 

1046 plot.make_plots(env, plots, show=options.show) 

1047 

1048 else: 

1049 if env is None: 

1050 help_and_die(parser, 'two or three arguments required') 

1051 plot_names = [name.strip() for name in args[0].split(',')] 

1052 plot.make_plots(env, plot_names=plot_names, show=options.show) 

1053 

1054 

1055def command_movie(args): 

1056 

1057 import matplotlib 

1058 matplotlib.use('Agg') 

1059 

1060 def setup(parser): 

1061 pass 

1062 

1063 parser, options, args = cl_parse('movie', args, setup) 

1064 

1065 if len(args) != 4: 

1066 help_and_die(parser, 'four arguments required') 

1067 

1068 run_path, xpar_name, ypar_name, movie_filename_template = args 

1069 

1070 from grond import plot 

1071 

1072 movie_filename = movie_filename_template % { 

1073 'xpar': xpar_name, 

1074 'ypar': ypar_name} 

1075 

1076 try: 

1077 plot.make_movie(run_path, xpar_name, ypar_name, movie_filename) 

1078 

1079 except grond.GrondError as e: 

1080 die(str(e)) 

1081 

1082 

1083def command_export(args): 

1084 

1085 def setup(parser): 

1086 parser.add_option( 

1087 '--type', dest='type', metavar='TYPE', 

1088 choices=('event', 'event-yaml', 'source', 'vector'), 

1089 help='select type of objects to be exported. Choices: ' 

1090 '"event" (default), "event-yaml", "source", "vector".') 

1091 

1092 parser.add_option( 

1093 '--parameters', dest='parameters', metavar='PLIST', 

1094 help='select parameters to be exported. PLIST is a ' 

1095 'comma-separated list where each entry has the form ' 

1096 '"<parameter>[.<measure>]". Available measures: "best", ' 

1097 '"mean", "std", "minimum", "percentile16", "median", ' 

1098 '"percentile84", "maximum".') 

1099 

1100 parser.add_option( 

1101 '--selection', dest='selection', metavar='EXPRESSION', 

1102 help='only export data for runs which match EXPRESSION. ' 

1103 'Example expression: "tags_contains:excellent,good"') 

1104 

1105 parser.add_option( 

1106 '--output', dest='filename', metavar='FILE', 

1107 help='write output to FILE') 

1108 

1109 parser.add_option( 

1110 '--effective-lat-lon', dest='effective_lat_lon', 

1111 action='store_true', 

1112 help='convert north_shift/east_shift offsets to true lat/lon ' 

1113 'coordinates (when outputting event objects).') 

1114 

1115 parser, options, args = cl_parse('export', args, setup) 

1116 if len(args) < 2: 

1117 help_and_die(parser, 'arguments required') 

1118 

1119 what = args[0] 

1120 

1121 dirnames = args[1:] 

1122 

1123 what_choices = ('best', 'mean', 'ensemble', 'stats') 

1124 

1125 if what not in what_choices: 

1126 help_and_die( 

1127 parser, 

1128 'invalid choice: %s (choose from %s)' % ( 

1129 repr(what), ', '.join(repr(x) for x in what_choices))) 

1130 

1131 if options.parameters: 

1132 pnames = options.parameters.split(',') 

1133 else: 

1134 pnames = None 

1135 

1136 try: 

1137 grond.export( 

1138 what, 

1139 dirnames, 

1140 filename=options.filename, 

1141 type=options.type, 

1142 pnames=pnames, 

1143 selection=options.selection, 

1144 effective_lat_lon=options.effective_lat_lon) 

1145 

1146 except grond.GrondError as e: 

1147 die(str(e)) 

1148 

1149 

1150def command_tag(args): 

1151 

1152 def setup(parser): 

1153 parser.add_option( 

1154 '-d', '--dir-names', 

1155 dest='show_dirnames', 

1156 action='store_true', 

1157 help='show directory names instead of run names') 

1158 

1159 parser, options, args = cl_parse('tag', args, setup) 

1160 if len(args) < 2: 

1161 help_and_die(parser, 'two or more arguments required') 

1162 

1163 action = args.pop(0) 

1164 

1165 if action not in ('add', 'remove', 'list'): 

1166 help_and_die(parser, 'invalid action: %s' % action) 

1167 

1168 if action in ('add', 'remove'): 

1169 if len(args) < 2: 

1170 help_and_die(parser, 'three or more arguments required') 

1171 

1172 tag = args.pop(0) 

1173 

1174 rundirs = args 

1175 

1176 if action == 'list': 

1177 rundirs = args 

1178 

1179 from grond.environment import Environment 

1180 

1181 errors = False 

1182 for rundir in rundirs: 

1183 try: 

1184 env = Environment([rundir]) 

1185 if options.show_dirnames: 

1186 name = rundir 

1187 else: 

1188 name = env.get_problem().name 

1189 

1190 info = env.get_run_info() 

1191 if action == 'add': 

1192 info.add_tag(tag) 

1193 env.set_run_info(info) 

1194 elif action == 'remove': 

1195 info.remove_tag(tag) 

1196 env.set_run_info(info) 

1197 elif action == 'list': 

1198 print('%-60s : %s' % ( 

1199 name, 

1200 ', '.join(info.tags))) 

1201 

1202 except grond.GrondError as e: 

1203 errors = True 

1204 logger.error(e) 

1205 

1206 if errors: 

1207 die('Errors occurred, see log messages above.') 

1208 

1209 

1210def make_report(env_args, event_name, conf, update_without_plotting): 

1211 from grond.environment import Environment 

1212 from grond.report import report 

1213 try: 

1214 env = Environment(env_args) 

1215 if event_name: 

1216 env.set_current_event_name(event_name) 

1217 

1218 report( 

1219 env, conf, 

1220 update_without_plotting=update_without_plotting, 

1221 make_index=False, 

1222 make_archive=False) 

1223 

1224 return True 

1225 

1226 except grond.GrondError as e: 

1227 logger.error(str(e)) 

1228 return False 

1229 

1230 

1231def command_report(args): 

1232 

1233 import matplotlib 

1234 matplotlib.use('Agg') 

1235 

1236 from pyrocko import parimap 

1237 

1238 from grond.environment import Environment 

1239 from grond.report import \ 

1240 report_index, report_archive, serve_ip, serve_report, read_config, \ 

1241 write_config, ReportConfig 

1242 

1243 def setup(parser): 

1244 parser.add_option( 

1245 '--index-only', 

1246 dest='index_only', 

1247 action='store_true', 

1248 help='create index only') 

1249 parser.add_option( 

1250 '--serve', '-s', 

1251 dest='serve', 

1252 action='store_true', 

1253 help='start http service') 

1254 parser.add_option( 

1255 '--serve-external', '-S', 

1256 dest='serve_external', 

1257 action='store_true', 

1258 help='shortcut for --serve --host=default --fixed-port') 

1259 parser.add_option( 

1260 '--host', 

1261 dest='host', 

1262 default='localhost', 

1263 help='<ip> to start the http server on. Special values for ' 

1264 '<ip>: "*" binds to all available interfaces, "default" ' 

1265 'to default external interface, "localhost" to "127.0.0.1".') 

1266 parser.add_option( 

1267 '--port', 

1268 dest='port', 

1269 type=int, 

1270 default=8383, 

1271 help='set default http server port. Will count up if port is ' 

1272 'already in use unless --fixed-port is given.') 

1273 parser.add_option( 

1274 '--fixed-port', 

1275 dest='fixed_port', 

1276 action='store_true', 

1277 help='fail if port is already in use') 

1278 parser.add_option( 

1279 '--open', '-o', 

1280 dest='open', 

1281 action='store_true', 

1282 help='open report in browser') 

1283 parser.add_option( 

1284 '--config', 

1285 dest='config', 

1286 metavar='FILE', 

1287 help='report configuration file to use') 

1288 parser.add_option( 

1289 '--write-config', 

1290 dest='write_config', 

1291 metavar='FILE', 

1292 help='write configuration (or default configuration) to FILE') 

1293 parser.add_option( 

1294 '--update-without-plotting', 

1295 dest='update_without_plotting', 

1296 action='store_true', 

1297 help='quick-and-dirty update parameter files without plotting') 

1298 parser.add_option( 

1299 '--no-archive', 

1300 dest='no_archive', 

1301 action='store_true', 

1302 help='don\'t create archive file.') 

1303 

1304 parser, options, args = cl_parse('report', args, setup) 

1305 

1306 s_conf = '' 

1307 if options.config: 

1308 try: 

1309 conf = read_config(options.config) 

1310 except grond.GrondError as e: 

1311 die(str(e)) 

1312 

1313 s_conf = ' --config="%s"' % options.config 

1314 else: 

1315 from grond import plot 

1316 conf = ReportConfig( 

1317 plot_config_collection=plot.get_plot_config_collection()) 

1318 conf.set_basepath('.') 

1319 

1320 if options.write_config: 

1321 try: 

1322 write_config(conf, options.write_config) 

1323 sys.exit(0) 

1324 

1325 except grond.GrondError as e: 

1326 die(str(e)) 

1327 

1328 # commandline options that can override config values 

1329 if options.no_archive: 

1330 conf.make_archive = False 

1331 

1332 if len(args) == 1 and op.exists(op.join(args[0], 'index.html')): 

1333 conf.report_base_path = conf.rel_path(args[0]) 

1334 s_conf = ' %s' % args[0] 

1335 args = [] 

1336 

1337 report_base_path = conf.expand_path(conf.report_base_path) 

1338 

1339 if options.index_only: 

1340 report_index(conf) 

1341 report_archive(conf) 

1342 args = [] 

1343 

1344 entries_generated = False 

1345 

1346 payload = [] 

1347 if args and all(op.isdir(rundir) for rundir in args): 

1348 rundirs = args 

1349 all_failed = True 

1350 for rundir in rundirs: 

1351 payload.append(( 

1352 [rundir], None, conf, options.update_without_plotting)) 

1353 

1354 elif args: 

1355 try: 

1356 env = Environment(args) 

1357 for event_name in env.get_selected_event_names(): 

1358 payload.append(( 

1359 args, event_name, conf, options.update_without_plotting)) 

1360 

1361 except grond.GrondError as e: 

1362 die(str(e)) 

1363 

1364 if payload: 

1365 entries_generated = [] 

1366 for result in parimap.parimap( 

1367 make_report, *zip(*payload), nprocs=options.nparallel): 

1368 

1369 entries_generated.append(result) 

1370 

1371 all_failed = not any(entries_generated) 

1372 entries_generated = any(entries_generated) 

1373 

1374 if all_failed: 

1375 die('no report entries generated') 

1376 

1377 report_index(conf) 

1378 report_archive(conf) 

1379 

1380 if options.serve or options.serve_external: 

1381 if options.serve_external: 

1382 host = 'default' 

1383 else: 

1384 host = options.host 

1385 

1386 addr = serve_ip(host), options.port 

1387 

1388 serve_report( 

1389 addr, 

1390 report_config=conf, 

1391 fixed_port=options.fixed_port or options.serve_external, 

1392 open=options.open) 

1393 

1394 elif options.open: 

1395 import webbrowser 

1396 url = 'file://%s/index.html' % op.abspath(report_base_path) 

1397 webbrowser.open(url) 

1398 

1399 else: 

1400 if not entries_generated and not options.index_only: 

1401 logger.info('Nothing to do, see: grond report --help') 

1402 

1403 if entries_generated and not (options.serve or options.serve_external): 

1404 logger.info(CLIHints('report', config=s_conf)) 

1405 

1406 

1407def command_qc_polarization(args): 

1408 

1409 def setup(parser): 

1410 parser.add_option( 

1411 '--time-factor-pre', dest='time_factor_pre', type=float, 

1412 metavar='NUMBER', 

1413 default=0.5, 

1414 help='set duration to extract before synthetic P phase arrival, ' 

1415 'relative to 1/fmin. fmin is taken from the selected target ' 

1416 'group in the config file (default=%default)') 

1417 parser.add_option( 

1418 '--time-factor-post', dest='time_factor_post', type=float, 

1419 metavar='NUMBER', 

1420 default=0.5, 

1421 help='set duration to extract after synthetic P phase arrival, ' 

1422 'relative to 1/fmin. fmin is taken from the selected target ' 

1423 'group in the config file (default=%default)') 

1424 parser.add_option( 

1425 '--distance-min', dest='distance_min', type=float, 

1426 metavar='NUMBER', 

1427 help='minimum event-station distance [m]') 

1428 parser.add_option( 

1429 '--distance-max', dest='distance_max', type=float, 

1430 metavar='NUMBER', 

1431 help='maximum event-station distance [m]') 

1432 parser.add_option( 

1433 '--depth-min', dest='depth_min', type=float, 

1434 metavar='NUMBER', 

1435 help='minimum station depth [m]') 

1436 parser.add_option( 

1437 '--depth-max', dest='depth_max', type=float, 

1438 metavar='NUMBER', 

1439 help='maximum station depth [m]') 

1440 parser.add_option( 

1441 '--picks', dest='picks_filename', 

1442 metavar='FILENAME', 

1443 help='add file with P picks in Snuffler marker format') 

1444 parser.add_option( 

1445 '--save', dest='output_filename', 

1446 metavar='FILENAME.FORMAT', 

1447 help='save output to file FILENAME.FORMAT') 

1448 parser.add_option( 

1449 '--dpi', dest='output_dpi', type=float, default=120., 

1450 metavar='NUMBER', 

1451 help='DPI setting for raster formats (default=120)') 

1452 

1453 parser, options, args = cl_parse('qc-polarization', args, setup) 

1454 if len(args) != 3: 

1455 help_and_die(parser, 'missing arguments') 

1456 

1457 if options.output_filename: 

1458 import matplotlib 

1459 matplotlib.use('Agg') 

1460 

1461 import grond.qc 

1462 

1463 config_path, event_name, target_group_path = args 

1464 

1465 try: 

1466 config = grond.read_config(config_path) 

1467 except grond.GrondError as e: 

1468 die(str(e)) 

1469 

1470 ds = config.get_dataset(event_name) 

1471 

1472 engine = config.engine_config.get_engine() 

1473 

1474 nsl_to_time = None 

1475 if options.picks_filename: 

1476 markers = marker.load_markers(options.picks_filename) 

1477 marker.associate_phases_to_events(markers) 

1478 

1479 nsl_to_time = {} 

1480 for m in markers: 

1481 if isinstance(m, marker.PhaseMarker): 

1482 ev = m.get_event() 

1483 if ev is not None and ev.name == event_name: 

1484 nsl_to_time[m.one_nslc()[:3]] = m.tmin 

1485 

1486 if not nsl_to_time: 

1487 help_and_die( 

1488 parser, 

1489 'no markers associated with event "%s" found in file "%s"' % ( 

1490 event_name, options.picks_filename)) 

1491 

1492 target_group_paths_avail = [] 

1493 for target_group in config.target_groups: 

1494 name = target_group.path 

1495 if name == target_group_path: 

1496 imc = target_group.misfit_config 

1497 fmin = imc.fmin 

1498 fmax = imc.fmax 

1499 ffactor = imc.ffactor 

1500 

1501 store = engine.get_store(target_group.store_id) 

1502 timing = '{cake:P|cake:p|cake:P\\|cake:p\\}' 

1503 

1504 grond.qc.polarization( 

1505 ds, store, timing, fmin=fmin, fmax=fmax, ffactor=ffactor, 

1506 time_factor_pre=options.time_factor_pre, 

1507 time_factor_post=options.time_factor_post, 

1508 distance_min=options.distance_min, 

1509 distance_max=options.distance_max, 

1510 depth_min=options.depth_min, 

1511 depth_max=options.depth_max, 

1512 nsl_to_time=nsl_to_time, 

1513 output_filename=options.output_filename, 

1514 output_dpi=options.output_dpi) 

1515 

1516 return 

1517 

1518 target_group_paths_avail.append(name) 

1519 

1520 die('no target group with path "%s" found. Available: %s' % ( 

1521 target_group_path, ', '.join(target_group_paths_avail))) 

1522 

1523 

1524def command_upgrade_config(args): 

1525 def setup(parser): 

1526 parser.add_option( 

1527 '--diff', dest='diff', action='store_true', 

1528 help='create diff between normalized old and new versions') 

1529 

1530 parser, options, args = cl_parse('upgrade-config', args, setup) 

1531 if len(args) != 1: 

1532 help_and_die(parser, 'missing argument <configfile>') 

1533 

1534 from grond import upgrade 

1535 upgrade.upgrade_config_file(args[0], diff=options.diff) 

1536 

1537 

1538def command_diff(args): 

1539 def setup(parser): 

1540 pass 

1541 

1542 parser, options, args = cl_parse('diff', args, setup) 

1543 if len(args) != 2: 

1544 help_and_die(parser, 'requires exactly two arguments') 

1545 

1546 from grond.config import diff_configs 

1547 diff_configs(*args) 

1548 

1549 

1550def command_version(args): 

1551 def setup(parser): 

1552 parser.add_option( 

1553 '--short', dest='short', action='store_true', 

1554 help='only print Grond\'s version number') 

1555 parser.add_option( 

1556 '--failsafe', dest='failsafe', action='store_true', 

1557 help='do not get irritated when some dependencies are missing') 

1558 

1559 parser, options, args = cl_parse('version', args, setup) 

1560 

1561 if options.short: 

1562 print(grond.__version__) 

1563 return 

1564 

1565 elif not options.failsafe: 

1566 from grond import info 

1567 print(info.version_info()) 

1568 return 

1569 

1570 print("grond: %s" % grond.__version__) 

1571 

1572 try: 

1573 import pyrocko 

1574 print('pyrocko: %s' % pyrocko.long_version) 

1575 except ImportError: 

1576 print('pyrocko: N/A') 

1577 

1578 try: 

1579 import numpy 

1580 print('numpy: %s' % numpy.__version__) 

1581 except ImportError: 

1582 print('numpy: N/A') 

1583 

1584 try: 

1585 import scipy 

1586 print('scipy: %s' % scipy.__version__) 

1587 except ImportError: 

1588 print('scipy: N/A') 

1589 

1590 try: 

1591 import matplotlib 

1592 print('matplotlib: %s' % matplotlib.__version__) 

1593 except ImportError: 

1594 print('matplotlib: N/A') 

1595 

1596 try: 

1597 from pyrocko.gui.qt_compat import Qt 

1598 print('PyQt: %s' % Qt.PYQT_VERSION_STR) 

1599 print('Qt: %s' % Qt.QT_VERSION_STR) 

1600 except ImportError: 

1601 print('PyQt: N/A') 

1602 print('Qt: N/A') 

1603 

1604 import sys 

1605 print('python: %s.%s.%s' % sys.version_info[:3]) 

1606 

1607 if not options.failsafe: 

1608 die('fell back to failsafe version printing') 

1609 

1610 

1611if __name__ == '__main__': 

1612 main()