def _misfit_page(config): """Generate an HTML page with misfit plots.""" # Read template files template_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'html_report_template') misfit_html = os.path.join(template_dir, 'misfit.html') misfit_html_out = os.path.join(config.options.outdir, 'misfit.html') # Version and run completed ssp_version = get_versions()['version'] run_completed = '{} {}'.format( config.end_of_run.strftime('%Y-%m-%d %H:%M:%S'), config.end_of_run_tz) # event info hypo = config.hypo evid = hypo.evid # 1d conditional misfit plots misfit_plot_files = glob( os.path.join(config.options.outdir, 'misfit', '{}.cond_misfit_*.png'.format(evid))) one_d_misfit_table_rows = _misfit_table_rows(misfit_plot_files) # 2d conditional misfit plots: fc-Mw misfit_plot_files = glob( os.path.join(config.options.outdir, 'misfit', '{}.misfit_fc-Mw_*.png'.format(evid))) two_d_misfit_table_rows_fc_mw = _misfit_table_rows(misfit_plot_files) # 2d conditional misfit plots: fc-tstar misfit_plot_files = glob( os.path.join(config.options.outdir, 'misfit', '{}.misfit_fc-t_star_*.png'.format(evid))) two_d_misfit_table_rows_fc_tstar = _misfit_table_rows(misfit_plot_files) # 2d conditional misfit plots: tstar-Mw misfit_plot_files = glob( os.path.join(config.options.outdir, 'misfit', '{}.misfit_t_star-Mw_*.png'.format(evid))) two_d_misfit_table_rows_tstar_mw = _misfit_table_rows(misfit_plot_files) # Main HTML page replacements = { '{VERSION}': ssp_version, '{RUN_COMPLETED}': run_completed, '{EVENTID}': evid, '{1D_MISFIT_TABLE_ROWS}': one_d_misfit_table_rows, '{2D_MISFIT_TABLE_ROWS_FC_MW}': two_d_misfit_table_rows_fc_mw, '{2D_MISFIT_TABLE_ROWS_FC_TSTAR}': two_d_misfit_table_rows_fc_tstar, '{2D_MISFIT_TABLE_ROWS_TSTAR_MW}': two_d_misfit_table_rows_tstar_mw } misfit = open(misfit_html).read() misfit = _multireplace(misfit, replacements) with open(misfit_html_out, 'w') as fp: fp.write(misfit)
def _make_fig(config, nlines, ncols): if nlines <= 3: figsize = (16, 9) else: figsize = (16, 18) fig = plt.figure(figsize=figsize, dpi=300) # Create an invisible axis and use it for title and footer ax0 = fig.add_subplot(111, label='ax0') ax0.set_axis_off() # Add event information as a title hypo = config.hypo textstr = 'evid: {} lon: {:.3f} lat: {:.3f} depth: {:.1f} km' textstr = textstr.format( hypo.evid, hypo.longitude, hypo.latitude, hypo.depth) try: textstr += ' time: {}'.format( hypo.origin_time.format_iris_web_service()) except AttributeError: pass ax0.text(0., 1.06, textstr, fontsize=12, ha='left', va='top', transform=ax0.transAxes) if config.options.evname is not None: textstr = config.options.evname ax0.text(0., 1.1, textstr, fontsize=14, ha='left', va='top', transform=ax0.transAxes) # Add code information at the figure bottom textstr = 'SourceSpec v{} '.format(get_versions()['version']) ax0.text(1., -0.1, textstr, fontsize=10, ha='right', va='top', transform=ax0.transAxes) axes = [] for n in range(nlines*ncols): plotn = n+1 if plotn == 1: ax = fig.add_subplot(nlines, ncols, plotn) else: ax = fig.add_subplot(nlines, ncols, plotn, sharex=axes[0]) ax.grid(True, which='both', linestyle='solid', color='#DDDDDD', zorder=0) ax.set_axisbelow(True) ax.xaxis.set_tick_params(which='both', labelbottom=False) ax.yaxis.set_tick_params(which='both', labelleft=True) ax.tick_params(width=2) # FIXME: ticks are below grid lines! ax.tick_params(labelsize=8) ax.yaxis.offsetText.set_fontsize(8) yfmt = ScalarFormatter() yfmt.set_powerlimits((-1, 1)) ax.yaxis.set_major_formatter(yfmt) axes.append(ax) fig.subplots_adjust(hspace=.1, wspace=.20) return fig, axes
def _update_parser(parser, progname): if progname == 'source_spec': parser.add_argument( '-o', '--outdir', dest='outdir', action='store', default='sspec_out', help='save output to OUTDIR (default: sspec_out)', metavar='OUTDIR' ) elif progname == 'source_model': parser.add_argument( '-f', '--fmin', dest='fmin', action='store', type=float, default='0.01', help='minimum frequency (Hz, default 0.01)', metavar='FMIN' ) parser.add_argument( '-F', '--fmax', dest='fmax', action='store', type=float, default='50.0', help='maximum frequency (Hz, default 50.0)', metavar='FMAX' ) parser.add_argument( '-k', '--fc', dest='fc', action='store', default='10.0', help='(list of) corner frequency (Hz, default 10.0)', metavar='Fc' ) parser.add_argument( '-m', '--mag', dest='mag', action='store', default='2.0', help='(list of) moment magnitude (default 2.0)', metavar='Mw' ) parser.add_argument( '-M', '--moment', dest='Mo', action='store', default='NaN', help='(list of) seismic moment (N.m, default undefined)', metavar='Mo' ) parser.add_argument( '-*', '--tstar', dest='t_star', action='store', default='0.0', help='(list of) t-star (attenuation, default 0.0)', metavar='T-STAR' ) parser.add_argument( '-a', '--alpha', dest='alpha', action='store', default='1.0', help='(list of) alpha (exponent for frequency dependence\n' 'of attenuation, default 1.0)', metavar='1.0' ) parser.add_argument( '-C', '--combine', dest='combine', action='store_true', default=False, help='generate all the combinations of fc, mag, Mo, tstar, alpha' ) parser.add_argument( '-P', '--plot', dest='plot', action='store_true', default=False, help='plot results' ) parser.add_argument( '-v', '--version', action='version', version=get_versions()['version'] )
def _make_fig(config, plot_params): nlines = plot_params.nlines ncols = plot_params.ncols stack_plots = plot_params.stack_plots if nlines <= 3 or stack_plots: figsize = (16, 9) else: figsize = (16, 18) fig = plt.figure(figsize=figsize, dpi=300) # Create an invisible axis and use it for title and footer ax0 = fig.add_subplot(111, label='ax0') ax0.set_axis_off() # Add event information as a title hypo = config.hypo textstr = 'evid: {} lon: {:.3f} lat: {:.3f} depth: {:.1f} km' textstr = textstr.format( hypo.evid, hypo.longitude, hypo.latitude, hypo.depth) try: textstr += ' time: {}'.format( hypo.origin_time.format_iris_web_service()) except AttributeError: pass ax0.text(0., 1.06, textstr, fontsize=12, ha='left', va='top', transform=ax0.transAxes) if config.options.evname is not None: textstr = config.options.evname ax0.text(0., 1.1, textstr, fontsize=14, ha='left', va='top', transform=ax0.transAxes) # Add code information at the figure bottom textstr = 'SourceSpec v{} '.format(get_versions()['version']) if not stack_plots: textstr += '– {} {}\n'.format( config.end_of_run.strftime('%Y-%m-%d %H:%M:%S'), config.end_of_run_tz) ax0.text(1., -0.1, textstr, fontsize=10, ha='right', va='top', transform=ax0.transAxes) axes = [] for n in range(nlines*ncols): plotn = n+1 # ax1 has moment units (or weight) if plotn == 1: if stack_plots: ax = fig.add_subplot(1, 1, 1, label='ax') else: ax = fig.add_subplot(nlines, ncols, plotn) else: if not stack_plots: ax = fig.add_subplot( nlines, ncols, plotn, sharex=axes[0][0], sharey=axes[0][0]) ax.set_xlim(plot_params.freq_minmax) ax.set_ylim(plot_params.moment_minmax) ax.grid( True, which='both', linestyle='solid', color='#DDDDDD', zorder=0) ax.set_axisbelow(True) ax.xaxis.set_tick_params(which='both', labelbottom=False) ax.yaxis.set_tick_params(which='both', labelleft=False) ax.tick_params(width=2) # FIXME: ticks are below grid lines! # ax2 has magnitude units if plot_params.plot_type != 'weight': if ((stack_plots and plotn == 1) or not stack_plots): ax2 = ax.twinx() ax2.set_ylim(plot_params.mag_minmax) ax2.yaxis.set_tick_params( which='both', labelright=False, width=0) else: ax2 = None ax.has_station_text = False axes.append((ax, ax2)) fig.subplots_adjust(hspace=.025, wspace=.03) plot_params.figures.append(fig) plot_params.axes = axes plot_params.ax0 = ax0 plot_params.plotn = 0
def _plot_stations(config, lonlat_dist, st_ids, values, vmean, verr, vname): maxdist = np.max(lonlat_dist[:, 2]) ax, circle_texts = _make_basemap(config, maxdist) if config.options.evname is not None: textstr = '{} — '.format(config.options.evname) else: textstr = '' if vname == 'mag': verr_minus = verr_plus = verr textstr += 'Mw {:.2f} ± {:.2f}'.format(vmean, verr) elif vname == 'fc': verr_minus, verr_plus = verr textstr += 'fc {:.3f} [- {:.3f}, + {:.3f}] Hz'.format( vmean, verr_minus, verr_plus) ax.text(0., 1.22, textstr, fontsize=14, ha='left', va='top', transform=ax.transAxes) if vname == 'mag': vmax = np.max(np.abs(values - vmean)) vmin = -vmax vmax += vmean vmin += vmean if vmax == vmin: vmax = vmean + 0.5 vmin = vmean - 0.5 cbar_extend = 'neither' cmap = cm.Spectral_r elif vname == 'fc': vmin = np.min(values) vmax = np.max(values) cbar_extend = 'neither' # limit colorbar to ±3sigma if vmax > vmean + 3 * verr_plus: vmax = vmean + 3 * verr_plus cbar_extend = 'max' if vmin < vmean - 3 * verr_minus: vmin = vmean - 3 * verr_minus if cbar_extend == 'max': cbar_extend = 'both' else: cbar_extend = 'min' if vmax == vmin: vmax = vmean + 1 vmin = vmean - 1 midpoint = (vmean - vmin) / (vmax - vmin) cmap = _shiftedColorMap(cm.PRGn, midpoint=midpoint) # Corner case, when errorbars are larger than vmin or vmax if vmin > vmean - verr_minus: vmin = vmean - (verr_minus * 1.1) if vmax < vmean + verr_plus: vmax = vmean + (verr_plus * 1.1) norm = colors.Normalize(vmin=vmin, vmax=vmax) trans = ccrs.PlateCarree() lonlat = lonlat_dist[:, :2] ax.scatter(lonlat[:, 0], lonlat[:, 1], marker='^', s=100, color=cmap(norm(values)), edgecolor='k', zorder=99, transform=trans) if config.plot_station_names_on_map: texts = [] for ll, id in zip(lonlat, st_ids): id = '.'.join(id.split('.')[:2]) id = ' ' + id station_text_size = config.plot_station_text_size t = ax.text(ll[0], ll[1], id, size=station_text_size, weight='bold', va='center', zorder=999, transform=trans) t.set_path_effects([ PathEffects.Stroke(linewidth=0.8, foreground='white'), PathEffects.Normal() ]) texts.append(t) # Add a colorbar ax_divider = make_axes_locatable(ax) cax = ax_divider.append_axes('right', size='6%', pad='15%', axes_class=plt.Axes) sm = cm.ScalarMappable(cmap=cmap, norm=norm) sm.set_array([]) fig = ax.get_figure() fig.colorbar(sm, cax=cax, extend=cbar_extend) cax.get_yaxis().set_visible(True) cax.axhline(vmean, lw=2, color='black') linestyle = (0, (2, 1)) linewidth = 1.5 color = _contrast_color(cmap(norm(vmean - verr_minus))) cax.axhline(vmean - verr_minus, lw=linewidth, linestyle=linestyle, color=color) color = _contrast_color(cmap(norm(vmean + verr_plus))) cax.axhline(vmean + verr_plus, lw=linewidth, linestyle=linestyle, color=color) if vname == 'mag': cm_label = 'Magnitude' elif vname == 'fc': cm_label = 'Corner Frequency (Hz)' cax.set_ylabel(cm_label) # Add code information at the figure bottom textstr = 'SourceSpec v{} '.format(get_versions()['version']) textstr += '– {} {}\n'.format( config.end_of_run.strftime('%Y-%m-%d %H:%M:%S'), config.end_of_run_tz) cax.text(1., -0.1, textstr, fontsize=8, ha='right', va='top', transform=cax.transAxes) if config.plot_station_names_on_map: # first adjust text labels relatively to each other adjust_text(texts, ax=ax, maxshift=1e3) # then, try to stay away from circle texts adjust_text(texts, add_objects=circle_texts, ax=ax, maxshift=1e3) evid = config.hypo.evid figfile_base = os.path.join(config.options.outdir, evid) figfile_base += '.map_{}.'.format(vname) fmt = config.PLOT_SAVE_FORMAT if fmt == 'pdf_multipage': fmt = 'pdf' figfile = figfile_base + fmt if config.PLOT_SHOW: plt.show() if config.PLOT_SAVE: savefig(fig, figfile, fmt, quantize_colors=False, bbox_inches='tight') if vname == 'mag': logger.info('Station-magnitude map saved to: ' + figfile) elif vname == 'fc': logger.info('Station-corner_freq map saved to: ' + figfile)
def setup_logging(config, basename=None, progname='source_spec'): """ Set up the logging infrastructure. This function is typically called twice: the first time without basename and a second time with a basename (typically the eventid). When called the second time, the previous logfile is renamed using the given basename. """ global oldlogfile global logger global PYTHON_VERSION_STR global OBSPY_VERSION_STR global NUMPY_VERSION_STR global SCIPY_VERSION_STR global MATPLOTLIB_VERSION_STR global CARTOPY_VERSION_STR # Create outdir if not os.path.exists(config.options.outdir): os.makedirs(config.options.outdir) if basename: logfile = os.path.join(config.options.outdir, '%s.ssp.log' % basename) else: datestring = datetime.now().strftime('%Y%m%d_%H%M%S') logfile = os.path.join(config.options.outdir, '%s.ssp.log' % datestring) logger_root = logging.getLogger() if oldlogfile: hdlrs = logger_root.handlers[:] for hdlr in hdlrs: hdlr.flush() hdlr.close() logger_root.removeHandler(hdlr) # Copy old logfile to new shutil.copyfile(oldlogfile, logfile) # Remove old logfile from old and new dir os.remove(oldlogfile) oldlogfile = os.path.join( config.options.outdir, os.path.basename(oldlogfile)) os.remove(oldlogfile) filemode = 'a' else: filemode = 'w' # captureWarnings is not supported in old versions of python try: logging.captureWarnings(True) except Exception: pass logger_root.setLevel(logging.DEBUG) filehand = logging.FileHandler(filename=logfile, mode=filemode) filehand.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s %(name)-20s ' '%(levelname)-8s %(message)s') filehand.setFormatter(formatter) logger_root.addHandler(filehand) console = logging.StreamHandler() console.setLevel(logging.INFO) # Add logger color coding on all platforms but win32 if sys.platform != 'win32' and sys.stdout.isatty(): console.emit = _color_handler_emit(console.emit) logger_root.addHandler(console) logger = logging.getLogger(progname) # Only write these debug infos for a new logfile if not oldlogfile: logger.debug('source_spec START') logger.debug('SourceSpec version: ' + get_versions()['version']) uname = platform.uname() uname_str = '{} {} {}'.format(uname[0], uname[2], uname[4]) logger.debug('Platform: ' + uname_str) logger.debug('Python version: ' + PYTHON_VERSION_STR) logger.debug('ObsPy version: ' + OBSPY_VERSION_STR) logger.debug('NumPy version: ' + NUMPY_VERSION_STR) logger.debug('SciPy version: ' + SCIPY_VERSION_STR) logger.debug('Matplotlib version: ' + MATPLOTLIB_VERSION_STR) if CARTOPY_VERSION_STR is not None: logger.debug('Cartopy version: ' + CARTOPY_VERSION_STR) logger.debug('Running arguments:') logger.debug(' '.join(sys.argv)) oldlogfile = logfile # See if there are warnings to deliver for _ in range(len(config.warnings)): msg = config.warnings.pop(0) logger.warning(msg)
def html_report(config, sourcepar): """Generate an HTML report.""" # Read template files template_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'html_report_template') style_css = os.path.join(template_dir, 'style.css') index_html = os.path.join(template_dir, 'index.html') index_html_out = os.path.join(config.options.outdir, 'index.html') traces_plot_html = os.path.join(template_dir, 'traces_plot.html') spectra_plot_html = os.path.join(template_dir, 'spectra_plot.html') station_table_row_html = os.path.join(template_dir, 'station_table_row.html') quakeml_file_link_html = os.path.join(template_dir, 'quakeml_file_link.html') # Copy CSS to output dir shutil.copy(style_css, config.options.outdir) # Version and run completed ssp_version = get_versions()['version'] run_completed = '{} {}'.format( config.end_of_run.strftime('%Y-%m-%d %H:%M:%S'), config.end_of_run_tz) # Output files and maps hypo = config.hypo evid = hypo.evid config_file = '{}.ssp.conf'.format(evid) out_file = '{}.ssp.out'.format(evid) log_file = '{}.ssp.log'.format(evid) quakeml_file = '{}.xml'.format(evid) map_mag = '{}.map_mag.png'.format(evid) map_fc = '{}.map_fc.png'.format(evid) box_plots = '{}.boxplot.png'.format(evid) # Trace plot files traces_plot = open(traces_plot_html).read() traces_plot_files = glob( os.path.join(config.options.outdir, '*.traces.png')) traces_plot_files += glob( os.path.join(config.options.outdir, '*.traces.??.png')) traces_plots = '' traces_plot_id = '' for traces_plot_file in sorted(traces_plot_files): traces_plot_file = os.path.basename(traces_plot_file) traces_plots += traces_plot.replace('{TRACES_PLOT_ID}', traces_plot_id).replace( '{TRACES_PLOT_FILE}', traces_plot_file) traces_plot_id = ' id="print"' # Spectral plot files spectra_plot = open(spectra_plot_html).read() spectra_plot_files = glob(os.path.join(config.options.outdir, '*.ssp.png')) spectra_plot_files += glob( os.path.join(config.options.outdir, '*.ssp.??.png')) spectra_plots = '' spectra_plot_id = '' for spectra_plot_file in sorted(spectra_plot_files): spectra_plot_file = os.path.basename(spectra_plot_file) spectra_plots += spectra_plot.replace('{SPECTRA_PLOT_ID}', spectra_plot_id).replace( '{SPECTRA_PLOT_FILE}', spectra_plot_file) spectra_plot_id = ' id="print"' # Station table station_table_row = open(station_table_row_html).read() station_table_rows = '' stationpar = sourcepar.station_parameters for statId in sorted(stationpar.keys()): if statId in ['means', 'errors', 'means_weight', 'errors_weight']: continue par = stationpar[statId] id, type = statId.split() Mw_text, Mw_err_text = _value_and_err_text(par, 'Mw', '{:.3f}') fc_text, fc_err_text = _value_and_err_text(par, 'fc', '{:.3f}') t_star_text, t_star_err_text =\ _value_and_err_text(par, 't_star', '{:.3f}') Qo_text, Qo_err_text = _value_and_err_text(par, 'Qo', '{:.1f}') Mo_text, Mo_err_text = _value_and_err_text(par, 'Mo', '{:.3e}') bsd_text, bsd_err_text = _value_and_err_text(par, 'bsd', '{:.3e}') ra_text, ra_err_text = _value_and_err_text(par, 'ra', '{:.3f}') hyp_dist_text, _ = _value_and_err_text(par, 'hyp_dist', '{:.3f}') az_text, _ = _value_and_err_text(par, 'az', '{:.3f}') Er_text, _ = _value_and_err_text(par, 'Er', '{:.3e}') replacements = { '{STATION_ID}': id, '{STATION_TYPE}': type, '{STATION_MW}': Mw_text, '{STATION_MW_ERR}': Mw_err_text, '{STATION_FC}': fc_text, '{STATION_FC_ERR}': fc_err_text, '{STATION_TSTAR}': t_star_text, '{STATION_TSTAR_ERR}': t_star_err_text, '{STATION_Q0}': Qo_text, '{STATION_Q0_ERR}': Qo_err_text, '{STATION_M0}': Mo_text, '{STATION_M0_ERR}': Mo_err_text, '{STATION_BSD}': bsd_text, '{STATION_BSD_ERR}': bsd_err_text, '{STATION_RA}': ra_text, '{STATION_RA_ERR}': ra_err_text, '{STATION_DIST}': hyp_dist_text, '{STATION_AZ}': az_text, '{STATION_ER}': Er_text, } station_table_rows += _multireplace(station_table_row, replacements) # Main HTML page means = sourcepar.means errors = sourcepar.errors means_weight = sourcepar.means_weight errors_weight = sourcepar.errors_weight Mw_mean = means['Mw'] Mw_error = errors['Mw'] Mw_mean_weight = means_weight['Mw'] Mw_error_weight = errors_weight['Mw'] Mo_mean = means['Mo'] Mo_minus, Mo_plus = errors['Mo'] Mo_mean_weight = means_weight['Mo'] Mo_minus_weight, Mo_plus_weight = errors_weight['Mo'] fc_mean = means['fc'] fc_minus, fc_plus = errors['fc'] fc_mean_weight = means_weight['fc'] fc_minus_weight, fc_plus_weight = errors_weight['fc'] t_star_mean = means['t_star'] t_star_error = errors['t_star'] t_star_mean_weight = means_weight['t_star'] t_star_error_weight = errors_weight['t_star'] Qo_mean = means['Qo'] Qo_error = errors['Qo'] Qo_mean_weight = means_weight['Qo'] Qo_error_weight = errors_weight['Qo'] ra_mean = means['ra'] ra_minus, ra_plus = errors['ra'] ra_mean_weight = means_weight['ra'] ra_minus_weight, ra_plus_weight = errors_weight['ra'] bsd_mean = means['bsd'] bsd_minus, bsd_plus = errors['bsd'] bsd_mean_weight = means_weight['bsd'] bsd_minus_weight, bsd_plus_weight = errors_weight['bsd'] Er_mean = means['Er'] Er_minus, Er_plus = errors['Er'] replacements = { '{VERSION}': ssp_version, '{RUN_COMPLETED}': run_completed, '{EVENTID}': evid, '{EVENT_LONGITUDE}': '{:8.3f}'.format(hypo.longitude), '{EVENT_LATITUDE}': '{:7.3f}'.format(hypo.latitude), '{EVENT_DEPTH}': '{:5.1f}'.format(hypo.depth), '{ORIGIN_TIME}': '{}'.format(hypo.origin_time), '{MW}': '{:.2f}'.format(Mw_mean), '{MW_ERR}': '{:.2f}'.format(Mw_error), '{MW_WEIGHT}': '{:.2f}'.format(Mw_mean_weight), '{MW_WEIGHT_ERR}': '{:.2f}'.format(Mw_error_weight), '{M0}': '{:.3e}'.format(Mo_mean), '{M0_ERR_MINUS}': '{}'.format(_format_exponent(Mo_minus, Mo_mean)), '{M0_ERR_PLUS}': '{}'.format(_format_exponent(Mo_plus, Mo_mean)), '{M0_WEIGHT}': '{:.3e}'.format(Mo_mean_weight), '{M0_WEIGHT_ERR_MINUS}': '{}'.format(_format_exponent(Mo_minus_weight, Mo_mean_weight)), '{M0_WEIGHT_ERR_PLUS}': '{}'.format(_format_exponent(Mo_plus_weight, Mo_mean_weight)), '{FC}': '{:.3f}'.format(fc_mean), '{FC_ERR_MINUS}': '{:.3f}'.format(fc_minus), '{FC_ERR_PLUS}': '{:.3f}'.format(fc_plus), '{FC_WEIGHT}': '{:.3f}'.format(fc_mean_weight), '{FC_WEIGHT_ERR_MINUS}': '{:.3f}'.format(fc_minus_weight), '{FC_WEIGHT_ERR_PLUS}': '{:.3f}'.format(fc_plus_weight), '{TSTAR}': '{:.3f}'.format(t_star_mean), '{TSTAR_ERR}': '{:.3f}'.format(t_star_error), '{TSTAR_WEIGHT}': '{:.3f}'.format(t_star_mean_weight), '{TSTAR_WEIGHT_ERR}': '{:.3f}'.format(t_star_error_weight), '{Q0}': '{:.1f}'.format(Qo_mean), '{Q0_ERR}': '{:.1f}'.format(Qo_error), '{Q0_WEIGHT}': '{:.1f}'.format(Qo_mean_weight), '{Q0_WEIGHT_ERR}': '{:.1f}'.format(Qo_error_weight), '{RADIUS}': '{:.3f}'.format(ra_mean), '{RADIUS_ERR_MINUS}': '{:.3f}'.format(ra_minus), '{RADIUS_ERR_PLUS}': '{:.3f}'.format(ra_plus), '{RADIUS_WEIGHT}': '{:.3f}'.format(ra_mean_weight), '{RADIUS_WEIGHT_ERR_MINUS}': '{:.3f}'.format(ra_minus_weight), '{RADIUS_WEIGHT_ERR_PLUS}': '{:.3f}'.format(ra_plus_weight), '{BSD}': '{:.3e}'.format(bsd_mean), '{BSD_ERR_MINUS}': '{}'.format(_format_exponent(bsd_minus, bsd_mean)), '{BSD_ERR_PLUS}': '{}'.format(_format_exponent(bsd_plus, bsd_mean)), '{BSD_WEIGHT}': '{:.3e}'.format(bsd_mean_weight), '{BSD_WEIGHT_ERR_MINUS}': '{}'.format(_format_exponent(bsd_minus_weight, bsd_mean_weight)), '{BSD_WEIGHT_ERR_PLUS}': '{}'.format(_format_exponent(bsd_plus_weight, bsd_mean_weight)), '{ER}': '{:.3e}'.format(Er_mean), '{ER_ERR_MINUS}': '{}'.format(_format_exponent(Er_minus, Er_mean)), '{ER_ERR_PLUS}': '{}'.format(_format_exponent(Er_plus, Er_mean)), '{CONF_FILE_BNAME}': config_file, '{CONF_FILE}': config_file, '{OUT_FILE_BNAME}': out_file, '{OUT_FILE}': out_file, '{LOG_FILE_BNAME}': log_file, '{LOG_FILE}': log_file, '{MAP_MAG}': map_mag, '{MAP_FC}': map_fc, '{TRACES_PLOTS}': traces_plots, '{SPECTRA_PLOTS}': spectra_plots, '{BOX_PLOTS}': box_plots, '{STATION_TABLE_ROWS}': station_table_rows, } # Misfit plots (when using grid search) if os.path.exists(os.path.join(config.options.outdir, 'misfit')): misfit_plot_comment_begin = '' misfit_plot_comment_end = '' _misfit_page(config) else: misfit_plot_comment_begin = '<!--' misfit_plot_comment_end = '-->' replacements.update({ '{MISFIT_PLOT_COMMENT_BEGIN}': misfit_plot_comment_begin, '{MISFIT_PLOT_COMMENT_END}': misfit_plot_comment_end }) # QuakeML file (if produced) if os.path.exists(os.path.join(config.options.outdir, quakeml_file)): quakeml_file_link = open(quakeml_file_link_html).read() quakeml_file_link = quakeml_file_link\ .replace('{QUAKEML_FILE}', quakeml_file)\ .replace('{QUAKEML_FILE_BNAME}', quakeml_file) else: quakeml_file_link = '' replacements.update({'{QUAKEML_FILE_LINK}': quakeml_file_link}) index = open(index_html).read() index = _multireplace(index, replacements) with open(index_html_out, 'w') as fp: fp.write(index) logger.info('HTML report written to file: ' + index_html_out)
def write_qml(config, sourcepar): if not config.options.qml_file: return qml_file = config.options.qml_file cat = read_events(qml_file) evid = config.hypo.evid try: ev = [e for e in cat if evid in str(e.resource_id)][0] except Exception: logging.warning('Unable to find evid "{}" in QuakeML file. ' 'QuakeML output will not be written.'.format(evid)) origin = ev.preferred_origin() if origin is None: origin = ev.origins[0] origin_id = origin.resource_id origin_id_strip = origin_id.id.split('/')[-1] origin_id_strip = origin_id_strip.replace(config.smi_strip_from_origin_id, '') # Common parameters ssp_version = get_versions()['version'] method_id = config.smi_base + '/sourcespec/' + ssp_version cr_info = CreationInfo() cr_info.agency_id = config.agency_id if config.author is None: author = '{}@{}'.format(getuser(), gethostname()) else: author = config.author cr_info.author = author cr_info.creation_time = UTCDateTime() means = sourcepar.means_weight errors = sourcepar.errors_weight stationpar = sourcepar.station_parameters # Magnitude mag = Magnitude() _id = config.smi_magnitude_template.replace('$SMI_BASE', config.smi_base) _id = _id.replace('$ORIGIN_ID', origin_id_strip) mag.resource_id = ResourceIdentifier(id=_id) mag.method_id = ResourceIdentifier(id=method_id) mag.origin_id = origin_id mag.magnitude_type = 'Mw' mag.mag = means['Mw'] mag_err = QuantityError() mag_err.uncertainty = errors['Mw'] mag_err.confidence_level = 68.2 mag.mag_errors = mag_err mag.station_count = len([_s for _s in stationpar.keys()]) mag.evaluation_mode = 'automatic' mag.creation_info = cr_info # Seismic moment -- It has to be stored in a MomentTensor object # which, in turn, is part of a FocalMechanism object mt = MomentTensor() _id = config.smi_moment_tensor_template.replace('$SMI_BASE', config.smi_base) _id = _id.replace('$ORIGIN_ID', origin_id_strip) mt.resource_id = ResourceIdentifier(id=_id) mt.derived_origin_id = origin_id mt.moment_magnitude_id = mag.resource_id mt.scalar_moment = means['Mo'] mt_err = QuantityError() mt_err.lower_uncertainty = errors['Mo'][0] mt_err.upper_uncertainty = errors['Mo'][1] mt_err.confidence_level = 68.2 mt.scalar_moment_errors = mt_err mt.method_id = method_id mt.creation_info = cr_info # And here is the FocalMechanism object fm = FocalMechanism() _id = config.smi_focal_mechanism_template.replace('$SMI_BASE', config.smi_base) _id = _id.replace('$ORIGIN_ID', origin_id_strip) fm.resource_id = ResourceIdentifier(id=_id) fm.triggering_origin_id = origin_id fm.method_id = ResourceIdentifier(id=method_id) fm.moment_tensor = mt fm.creation_info = cr_info ev.focal_mechanisms.append(fm) # Station magnitudes for statId in sorted(stationpar.keys()): par = stationpar[statId] st_mag = StationMagnitude() seed_id = statId.split()[0] _id = config.smi_station_magnitude_template.replace( '$SMI_MAGNITUDE_TEMPLATE', config.smi_magnitude_template) _id = _id.replace('$ORIGIN_ID', origin_id_strip) _id = _id.replace('$SMI_BASE', config.smi_base) _id = _id.replace('$WAVEFORM_ID', seed_id) st_mag.resource_id = ResourceIdentifier(id=_id) st_mag.origin_id = origin_id st_mag.mag = par['Mw'] st_mag.station_magnitude_type = 'Mw' st_mag.method_id = mag.method_id st_mag.creation_info = cr_info st_mag.waveform_id = WaveformStreamID(seed_string=seed_id) st_mag.extra = SSPExtra() st_mag.extra.moment = SSPTag(par['Mo']) st_mag.extra.corner_frequency = SSPTag(par['fc']) st_mag.extra.t_star = SSPTag(par['t_star']) ev.station_magnitudes.append(st_mag) st_mag_contrib = StationMagnitudeContribution() st_mag_contrib.station_magnitude_id = st_mag.resource_id mag.station_magnitude_contributions.append(st_mag_contrib) ev.magnitudes.append(mag) # Write other average parameters as custom tags ev.extra = SSPExtra() ev.extra.corner_frequency = SSPContainerTag() ev.extra.corner_frequency.value.value = SSPTag(means['fc']) ev.extra.corner_frequency.value.lower_uncertainty =\ SSPTag(errors['fc'][0]) ev.extra.corner_frequency.value.upper_uncertainty =\ SSPTag(errors['fc'][1]) ev.extra.corner_frequency.value.confidence_level = SSPTag(68.2) ev.extra.t_star = SSPContainerTag() ev.extra.t_star.value.value = SSPTag(means['t_star']) ev.extra.t_star.value.uncertainty = SSPTag(errors['t_star']) ev.extra.t_star.value.confidence_level = SSPTag(68.2) ev.extra.source_radius = SSPContainerTag() ev.extra.source_radius.value.value = SSPTag(means['ra']) ev.extra.source_radius.value.lower_uncertainty =\ SSPTag(errors['ra'][0]) ev.extra.source_radius.value.upper_uncertainty =\ SSPTag(errors['ra'][1]) ev.extra.source_radius.value.confidence_level = SSPTag(68.2) ev.extra.stress_drop = SSPContainerTag() ev.extra.stress_drop.value.value = SSPTag(means['bsd']) ev.extra.stress_drop.value.lower_uncertainty =\ SSPTag(errors['bsd'][0]) ev.extra.stress_drop.value.upper_uncertainty =\ SSPTag(errors['bsd'][1]) ev.extra.stress_drop.value.confidence_level = SSPTag(68.2) if config.set_preferred_magnitude: ev.preferred_magnitude_id = mag.resource_id.id qml_file_out = os.path.join(config.options.outdir, evid + '.xml') ev.write(qml_file_out, format='QUAKEML') logging.info('QuakeML file written to: ' + qml_file_out)