def main(): config = configure('source_model') if len(config.options.trace_path) > 0: st = read_traces(config) # Deconvolve, filter, cut traces: proc_st = process_traces(config, st) # Build spectra (amplitude in magnitude units) spec_st = build_spectra(config, proc_st) if len(spec_st) == 0: ssp_exit() # We keep just horizontal component: spec_st = Stream( [x for x in spec_st.traces if (x.stats.channel[-1] == 'H')]) for trace_spec in spec_st: orientation = trace_spec.stats.channel[-1] if orientation != 'H': continue make_synth(config, spec_st, trace_spec) else: spec_st = Stream() make_synth(config, spec_st) if config.options.plot: config.PLOT_SHOW = True else: config.PLOT_SHOW = False config.PLOT_SAVE = False plot_traces(config, proc_st, ncols=2, block=False) plot_spectra(config, spec_st, ncols=1, stack_plots=True)
def _wave_arrival_nll(trace, phase, NLL_time_dir): """Arrival time using a NLL grid.""" if trace.stats.hypo.origin_time is None: return if NLL_time_dir is None: return try: from nllgrid import NLLGrid except ImportError: logger.error('Error: the "nllgrid" python module is required ' 'for "NLL_time_dir".') ssp_exit() grdfile = '*.{}.{}.time.hdr'.format(phase, trace.stats.station) grdfile = os.path.join(NLL_time_dir, grdfile) try: grdfile = glob(grdfile)[0] except IndexError: return grd = NLLGrid(grdfile) if grd.type != 'TIME': return hypo_x, hypo_y = grd.project(trace.stats.hypo.longitude, trace.stats.hypo.latitude) hypo_z = trace.stats.hypo.depth tt = grd.get_value(hypo_x, hypo_y, hypo_z) return trace.stats.hypo.origin_time + tt
def build_spectra(config, st): """ Build spectra and the spec_st object. Computes S-wave (displacement) spectra from accelerometers and velocimeters, uncorrected for attenuation, corrected for instrumental constants, normalized by hypocentral distance. """ logger.info('Building spectra...') spec_st = Stream() specnoise_st = Stream() # sort by trace id for trace in sorted(st, key=lambda tr: tr.id): try: _check_data_len(config, trace) trace_signal, trace_noise = _cut_signal_noise(config, trace) _check_noise_level(trace_signal, trace_noise) spec = _build_spectrum(config, trace_signal) specnoise = _build_spectrum(config, trace_noise) _check_spectral_sn_ratio(config, spec, specnoise) except RuntimeError as msg: # RuntimeError is for skipped spectra logger.warning(msg) continue except ValueError as msg: # ValueError is for ignored spectra, which are still stored logger.warning(msg) trace.stats.ignore = True spec.stats.ignore = True specnoise.stats.ignore = True spec_st.append(spec) specnoise_st.append(specnoise) if not spec_st: logger.error('No spectra left! Exiting.') ssp_exit() # build H component _build_H(spec_st, specnoise_st, config.wave_type) # convert the spectral amplitudes to moment magnitude for spec in spec_st: spec.data_mag = moment_to_mag(spec.data) spec.data_log_mag = moment_to_mag(spec.data_log) # apply station correction if a residual file is specified in config spec_st = station_correction(spec_st, config) # build the weight spectrum weight_st = _build_weight_st(config, spec_st, specnoise_st) logger.info('Building spectra: done') if config.weighting == 'noise': for specnoise in specnoise_st: specnoise.data_mag = moment_to_mag(specnoise.data) return spec_st, specnoise_st, weight_st else: return spec_st
def _read_dataless(path): if path is None: return None # Try to read the file as StationXML if not os.path.isdir(path): try: inv = read_inventory(path) return inv except TypeError: pass except IOError as err: logger.error(err) ssp_exit() logger.info('Reading dataless...') dataless = dict() if os.path.isdir(path): listing = os.listdir(path) for filename in listing: fullpath = os.path.join(path, filename) try: dataless[filename] = Parser(fullpath) except Exception: continue # TODO: manage the case in which "path" is a file name logger.info('Reading dataless: done') return dataless
def _read_metadata(path): if path is None: return None logger.info('Reading station metadata...') metadata = None # Try to read the file as StationXML if os.path.isdir(path): _path = os.path.join(path, '*') else: _path = path try: metadata = read_inventory(_path) except Exception: pass except IOError as err: logger.error(err) ssp_exit() if metadata is None: metadata = dict() if os.path.isdir(path): listing = os.listdir(path) for filename in listing: fullpath = os.path.join(path, filename) try: metadata[filename] = Parser(fullpath) except Exception: continue # TODO: manage the case in which "path" is a file name logger.info('Reading station metadata: done') return metadata
def main(): # Setup stage config = configure() setup_logging(config) st = read_traces(config) setup_logging(config, config.hypo.evid) # Save config to out dir save_config(config) # Deconvolve, filter, cut traces: proc_st = process_traces(config, st) # Build spectra (amplitude in magnitude units) spec_st, specnoise_st, weight_st =\ build_spectra(config, proc_st, noise_weight=True) plotter = init_plotting(config) ntr = len(set(t.id[:-1] for t in proc_st)) ncols = 4 if ntr > 6 else 3 plot_traces(config, proc_st, ncols=ncols, async_plotter=plotter) # Spectral inversion sourcepar, sourcepar_err =\ spectral_inversion(config, spec_st, weight_st) # Local magnitude if config.compute_local_magnitude: local_magnitude(config, st, proc_st, sourcepar, sourcepar_err) # Save output sourcepar_mean = write_output(config, sourcepar, sourcepar_err) # Save residuals spectral_residuals(config, spec_st, sourcepar_mean) # Plotting nspec = len(set(s.id[:-1] for s in spec_st)) ncols = 4 if nspec > 6 else 3 plot_spectra(config, spec_st, specnoise_st, plottype='regular', ncols=ncols, async_plotter=plotter) plot_spectra(config, weight_st, plottype='weight', ncols=ncols, async_plotter=plotter) if config.plot_station_map: # We import here, cause we check for Cartopy at runtime from sourcespec.ssp_plot_stations import plot_stations plot_stations(config, sourcepar) ssp_exit()
def _log_db_write_error(db_err, db_file): msg = 'Unable to insert values: {}'.format(db_err) logger.error(msg) msg = 'Maybe your sqlite database has an old format.' logger.info(msg) msg = 'Try to remove or rename your database file.' logger.info(msg) msg = '(Current database file: {})'.format(db_file) logger.info(msg) ssp_exit(1)
def process_traces(config, st): """Remove mean, deconvolve and ignore unwanted components.""" out_st = Stream() for id in sorted(set(tr.id for tr in st)): # We still use a stream, since the trace can have # gaps or overlaps st_sel = st.select(id=id) network, station, location, channel = id.split('.') # build a list of all possible ids, from station only # to full net.sta.loc.chan ss = [ station, ] ss.append('.'.join((network, station))) ss.append('.'.join((network, station, location))) ss.append('.'.join((network, station, location, channel))) if config.use_stations is not None: combined = ("(" + ")|(".join(config.use_stations) + ")").replace( '.', '\.') if not any(re.match(combined, s) for s in ss): logger.warning('%s: ignored from config file' % id) continue if config.ignore_stations is not None: combined = ("(" + ")|(".join(config.ignore_stations) + ")").replace('.', '\.') if any(re.match(combined, s) for s in ss): logger.warning('%s: ignored from config file' % id) continue try: _add_hypo_dist_and_arrivals(config, st_sel) trace = _merge_stream(config, st_sel) trace.stats.ignore = False trace_process = _process_trace(config, trace) out_st.append(trace_process) except (ValueError, RuntimeError): continue if len(out_st) == 0: logger.error('No traces left! Exiting.') ssp_exit() # Rotate traces, if SH or SV is requested if config.wave_type in ['SH', 'SV']: for id in sorted(set(tr.id[:-1] for tr in out_st)): net, sta, loc, chan = id.split('.') st_sel = out_st.select(network=net, station=sta, location=loc, channel=chan + '?') t0 = max(tr.stats.starttime for tr in st_sel) t1 = min(tr.stats.endtime for tr in st_sel) st_sel.trim(t0, t1) st_sel.rotate('NE->RT') return out_st
def _parse_hypocenter(hypo_file): if hypo_file is None: return None hypo = AttribDict() hypo.latitude = None hypo.longitude = None hypo.depth = None hypo.origin_time = None hypo.evid = None if isinstance(hypo_file, str): try: with open(hypo_file) as fp: # Corinth hypocenter file format: # TODO: check file format line = fp.readline() # Skip the first line if it contains # characters in the first 10 digits: if any(c.isalpha() for c in line[0:10]): line = fp.readline() except IOError as err: logger.error(err) ssp_exit(1) timestr = line[0:17] # There are two possible formats for the timestring. # We try both of them try: dt = datetime.strptime(timestr, '%y%m%d %H %M%S.%f') except ValueError: dt = datetime.strptime(timestr, '%y%m%d %H%M %S.%f') hypo.origin_time = UTCDateTime(dt) lat = float(line[17:20]) lat_deg = float(line[21:26]) hypo.latitude = lat + lat_deg / 60 lon = float(line[26:30]) lon_deg = float(line[31:36]) hypo.longitude = lon + lon_deg / 60 hypo.depth = float(line[36:42]) evid = os.path.basename(hypo_file) evid = evid.replace('.phs', '').replace('.h', '').replace('.hyp', '') hypo.evid = evid else: # FIXME: put a condition here! ev = hypo_file # FIXME: improve this! hypo.latitude = ev.latitude hypo.longitude = ev.longitude hypo.depth = ev.depth hypo.origin_time = ev.utcdate hypo.evid = ev.event_id return hypo
def main(): # Lazy-import modules for speed from sourcespec.ssp_parse_arguments import parse_args options = parse_args(progname='source_model') from sourcespec.ssp_setup import configure, ssp_exit config = configure(options, progname='source_model') from sourcespec.ssp_read_traces import read_traces from sourcespec.ssp_process_traces import process_traces from sourcespec.ssp_build_spectra import build_spectra from obspy.core import Stream # We don't use weighting in source_model config.weighting = None if len(config.options.trace_path) > 0: st = read_traces(config) # Deconvolve, filter, cut traces: proc_st = process_traces(config, st) # Build spectra (amplitude in magnitude units) spec_st = build_spectra(config, proc_st) if len(spec_st) == 0: ssp_exit() # We keep just horizontal component: spec_st = Stream( [x for x in spec_st.traces if (x.stats.channel[-1] == 'H')]) for trace_spec in spec_st: orientation = trace_spec.stats.channel[-1] if orientation != 'H': continue make_synth(config, spec_st, trace_spec) else: spec_st = Stream() make_synth(config, spec_st) if config.options.plot: config.PLOT_SHOW = True else: config.PLOT_SHOW = False config.PLOT_SAVE = False from sourcespec.ssp_plot_spectra import plot_spectra from sourcespec.ssp_plot_traces import plot_traces plot_traces(config, proc_st, ncols=2, block=False) plot_spectra(config, spec_st, ncols=1, stack_plots=True)
def _correct_traceid(trace, traceid_file): if traceid_file is None: return try: correct_traceids = _get_correct_traceids(traceid_file) except Exception: msg = ('traceid mapping file "{}" not found ' 'or not in json format'.format(traceid_file)) logger.error(msg) ssp_exit(1) try: traceid = correct_traceids[trace.get_id()] net, sta, loc, chan = traceid.split('.') trace.stats.network = net trace.stats.station = sta trace.stats.location = loc trace.stats.channel = chan except KeyError: pass
def _compute_sensitivity(trace, config): # Securize the string before calling eval() # see https://stackoverflow.com/a/25437733/2021880 inp = re.sub(r'\.(?![0-9])', '', config.sensitivity) # Check if string contains letters, meaning that # it must contain SAC header fields and trace must be in SAC format namespace = None if re.search(r'[a-zA-Z]', inp): try: namespace = trace.stats.sac except Exception: raise Exception( '{}: trace must be in SAC format'.format(trace.id)) try: sensitivity = eval(inp, {}, namespace) except NameError as msg: hdr_field = str(msg).split()[1] logger.error('SAC header field {} does not exist'.format(hdr_field)) ssp_exit(1) return sensitivity
def station_correction(spec_st, config): """ Correct spectra using station-average residuals. Residuals are obtained from a previous run. """ res_filepath = config.residuals_filepath if res_filepath is None: return spec_st try: with open(res_filepath, 'rb') as fp: residual = pickle.load(fp) except Exception as msg: logger.error(msg) ssp_exit(1) for spec in [spec for spec in spec_st if (spec.stats.channel[-1] == 'H')]: station = spec.stats.station if station in set(x.stats.station for x in residual): # apply correction corr = residual.select(station=station)[0] freq = spec.get_freq() fmin = freq.min() fmax = freq.max() corr = corr.slice(fmin, fmax) corr.data_mag = moment_to_mag(corr.data) spec_corr = spec.copy() # uncorrected spectrum will have component name 'h' spec.stats.channel = spec.stats.channel[:-1] + 'h' spec_corr.data_mag -= corr.data_mag # interpolate the corrected data_mag to log frequencies f = interp1d(freq, spec_corr.data_mag, fill_value='extrapolate') spec_corr.data_log_mag = f(spec_corr.freq_log) # convert mag to moment spec_corr.data = mag_to_moment(spec_corr.data_mag) spec_corr.data_log = mag_to_moment(spec_corr.data_log_mag) spec_st.append(spec_corr) logger.info( '{} corrected, frequency range is: {:.2f} {:.2f} Hz'.format( spec_corr.id, fmin, fmax)) return spec_st
def get_vel(lon, lat, depth, wave, NLL_model_dir): if NLL_model_dir is None: return try: from nllgrid import NLLGrid except ImportError: logger.error('Error: the "nllgrid" python module is required ' 'for "NLL_model_dir".') ssp_exit() grdfile = '*.{}.mod.hdr'.format(wave) grdfile = os.path.join(NLL_model_dir, grdfile) try: grdfile = glob(grdfile)[0] except IndexError: return grd = NLLGrid(grdfile) x, y = grd.project(lon, lat) if grd.type == 'SLOW_LEN': slow_len = grd.get_value(lon, lat, depth) return grd.dx / slow_len return
def _parse_hypo_file(hypo_file): picks = None err_msgs = [] try: hypo = _parse_hypo71_hypocenter(hypo_file) return hypo, picks except Exception as err: msg = '{}: Not a hypo71 hypocenter file'.format(hypo_file) err_msgs.append(msg) msg = 'Parsing error: ' + str(err) err_msgs.append(msg) try: hypo, picks = _parse_hypo2000_file(hypo_file) return hypo, picks except Exception as err: msg = '{}: Not a hypo2000 hypocenter file'.format(hypo_file) err_msgs.append(msg) msg = 'Parsing error: ' + str(err) err_msgs.append(msg) # If we arrive here, the file was not recognized as valid for msg in err_msgs: logger.error(msg) ssp_exit(1)
def process_traces(config, st): """Remove mean, deconvolve and ignore unwanted components.""" logger.info('Processing traces...') out_st = Stream() for id in sorted(set(tr.id for tr in st)): # We still use a stream, since the trace can have gaps or overlaps st_sel = st.select(id=id) try: _skip_ignored(config, id) _add_hypo_dist_and_arrivals(config, st_sel) trace = _merge_stream(config, st_sel) trace.stats.ignore = False trace_process = _process_trace(config, trace) out_st.append(trace_process) except (ValueError, RuntimeError) as msg: logger.warning(msg) continue if len(out_st) == 0: logger.error('No traces left! Exiting.') ssp_exit() # Rotate traces, if SH or SV is requested if config.wave_type in ['SH', 'SV']: for id in sorted(set(tr.id[:-1] for tr in out_st)): net, sta, loc, chan = id.split('.') st_sel = out_st.select(network=net, station=sta, location=loc, channel=chan + '?') t0 = max(tr.stats.starttime for tr in st_sel) t1 = min(tr.stats.endtime for tr in st_sel) st_sel.trim(t0, t1) st_sel.rotate('NE->RT') logger.info('Processing traces: done') return out_st
def _parse_qml(qml_file, evid=None): if qml_file is None: return None, None hypo = AttribDict() hypo.latitude = None hypo.longitude = None hypo.depth = None hypo.origin_time = None hypo.evid = None try: cat = read_events(qml_file) except Exception as err: logger.error(err) ssp_exit(1) if evid is not None: ev = [e for e in cat if evid in str(e.resource_id)][0] else: # just take the first event ev = cat[0] # See if there is a preferred origin... origin = ev.preferred_origin() # ...or just use the first one if origin is None: origin = ev.origins[0] hypo.origin_time = origin.time hypo.latitude = origin.latitude hypo.longitude = origin.longitude hypo.depth = origin.depth / 1000. hypo.evid = ev.resource_id.id.split('/')[-1] picks = [] for pck in ev.picks: pick = Pick() pick.station = pck.waveform_id.station_code pick.network = pck.waveform_id.network_code pick.channel = pck.waveform_id.channel_code if pck.waveform_id.location_code is not None: pick.location = pck.waveform_id.location_code else: pick.location = '' if pck.onset == 'emergent': pick.flag = 'E' elif pck.onset == 'impulsive': pick.flag = 'I' try: pick.phase = pck.phase_hint[0:1] except Exception: # ignore picks with no phase hint continue if pck.polarity == 'positive': pick.polarity = 'U' elif pck.polarity == 'negative': pick.polarity = 'D' pick.time = pck.time picks.append(pick) return hypo, picks
def write_output(config, sourcepar, sourcepar_err): """Write results to a plain text file and/or to a SQLite database file.""" if len(sourcepar) == 0: logger.info('No source parameter calculated') ssp_exit() means = dict() errors = dict() means_weight = dict() errors_weight = dict() # Compute average source parameters # Mw Mw_values = np.array([x['Mw'] for x in sourcepar.values()]) Mw_err = np.array([x['Mw'] for x in sourcepar_err.values()]) means['Mw'], errors['Mw'] = _avg_and_std(Mw_values) means_weight['Mw'], errors_weight['Mw'] = \ _avg_and_std(Mw_values, errors=Mw_err) # Mo (N.m) means['Mo'], errors['Mo'] = _M0_avg_and_std(means['Mw'], errors['Mw']) means_weight['Mo'], errors_weight['Mo'] = \ _M0_avg_and_std(means_weight['Mw'], errors_weight['Mw']) # fc , hertz fc_values = np.array([x['fc'] for x in sourcepar.values()]) fc_err = np.array([x['fc'] for x in sourcepar_err.values()]) means['fc'], errors['fc'] = _avg_and_std(fc_values, logarithmic=True) means_weight['fc'], errors_weight['fc'] = \ _avg_and_std(fc_values, errors=fc_err, logarithmic=True) # t_star t_star_values = np.array([x['t_star'] for x in sourcepar.values()]) t_star_err = np.array([x['t_star'] for x in sourcepar_err.values()]) means['t_star'], errors['t_star'] = _avg_and_std(t_star_values) means_weight['t_star'], errors_weight['t_star'] = \ _avg_and_std(t_star_values, errors=t_star_err) # ra, radius (meters) vs_m = config.hypo.vs * 1000 ra_values = 0.37 * vs_m / fc_values means['ra'], errors['ra'] = _avg_and_std(ra_values, logarithmic=True) # bsd, Brune stress drop (MPa) Mo_values = mag_to_moment(Mw_values) bsd_values = 0.4375 * Mo_values / np.power(ra_values, 3) * 1e-6 means['bsd'], errors['bsd'] = _avg_and_std(bsd_values, logarithmic=True) # Ml # build Ml_values: use np.nan for missing values Ml_values = np.array([x.get('Ml', np.nan) for x in sourcepar.values()]) Ml_values = Ml_values[~np.isnan(Ml_values)] if Ml_values.size: means['Ml'], errors['Ml'] = _avg_and_std(Ml_values) else: means['Ml'] = None errors['Ml'] = None # Er Er_values = np.array([x['Er'] for x in sourcepar.values()]) means['Er'], errors['Er'] = _avg_and_std(Er_values, logarithmic=True) sourcepar['means'] = means sourcepar['errors'] = errors sourcepar['means_weight'] = means_weight sourcepar['errors_weight'] = errors_weight # Write to parfile _write_parfile(config, sourcepar, sourcepar_err) # Write to database, if requested _write_db(config, sourcepar) # Write to hypo file, if requested _write_hypo(config, sourcepar) params_name = ('Mw', 'fc', 't_star') sourcepar_mean = dict( zip(params_name, [means['Mw'], means['fc'], means['t_star']])) logger.info('params_mean: {}'.format(sourcepar_mean)) sourcepar_mean_weight = dict( zip(params_name, [means_weight['Mw'], means_weight['fc'], means_weight['t_star']])) logger.info('params_mean_weighted: {}'.format(sourcepar_mean_weight)) return sourcepar_mean
def compute_averages(config, sourcepar): """Compute average source parameters, find outliers""" if len(sourcepar.station_parameters) == 0: logger.info('No source parameter calculated') ssp_exit() means = dict() errors = dict() means_weight = dict() errors_weight = dict() nIQR = config.nIQR # Mw sourcepar.find_outliers('Mw', n=nIQR) Mw_values = sourcepar.value_array('Mw', filter_outliers=True) Mw_err = sourcepar.error_array('Mw', filter_outliers=True) means['Mw'], errors['Mw'] = _avg_and_std(Mw_values) means_weight['Mw'], errors_weight['Mw'] = _avg_and_std(Mw_values, Mw_err) # Mo (N.m) means['Mo'], errors['Mo'] = _M0_avg_and_std(means['Mw'], errors['Mw']) means_weight['Mo'], errors_weight['Mo'] = \ _M0_avg_and_std(means_weight['Mw'], errors_weight['Mw']) # fc (Hz) sourcepar.find_outliers('fc', n=nIQR) fc_values = sourcepar.value_array('fc', filter_outliers=True) fc_err = sourcepar.error_array('fc', filter_outliers=True) means['fc'], errors['fc'] = _avg_and_std(fc_values, logarithmic=True) means_weight['fc'], errors_weight['fc'] =\ _avg_and_std(fc_values, fc_err, logarithmic=True) # t_star (s) sourcepar.find_outliers('t_star', n=nIQR) t_star_values = sourcepar.value_array('t_star', filter_outliers=True) t_star_err = sourcepar.error_array('t_star', filter_outliers=True) means['t_star'], errors['t_star'] = _avg_and_std(t_star_values) means_weight['t_star'], errors_weight['t_star'] =\ _avg_and_std(t_star_values, t_star_err) # ra, radius (meters) sourcepar.find_outliers('ra', n=nIQR) ra_values = sourcepar.value_array('ra', filter_outliers=True) ra_err = sourcepar.error_array('ra', filter_outliers=True) means['ra'], errors['ra'] = _avg_and_std(ra_values, logarithmic=True) means_weight['ra'], errors_weight['ra'] =\ _avg_and_std(ra_values, ra_err, logarithmic=True) # bsd, Brune stress drop (MPa) sourcepar.find_outliers('bsd', n=nIQR) bsd_values = sourcepar.value_array('bsd', filter_outliers=True) bsd_err = sourcepar.error_array('bsd', filter_outliers=True) means['bsd'], errors['bsd'] = _avg_and_std(bsd_values, logarithmic=True) means_weight['bsd'], errors_weight['bsd'] =\ _avg_and_std(bsd_values, bsd_err, logarithmic=True) # Quality factor sourcepar.find_outliers('Qo', n=nIQR) Qo_values = sourcepar.value_array('Qo', filter_outliers=True) Qo_err = sourcepar.error_array('Qo', filter_outliers=True) Qo_values[np.isinf(Qo_values)] = np.nan means['Qo'], errors['Qo'] = _avg_and_std(Qo_values) cond_err = np.logical_or(np.isinf(Qo_err[:, 0]), np.isinf(Qo_err[:, 1])) Qo_values[cond_err] = np.nan Qo_err[cond_err] = np.nan means_weight['Qo'], errors_weight['Qo'] = _avg_and_std(Qo_values, Qo_err) # Ml sourcepar.find_outliers('Ml', n=nIQR) Ml_values = sourcepar.value_array('Ml', filter_outliers=True) means['Ml'], errors['Ml'] = _avg_and_std(Ml_values) # Er (N.m) sourcepar.find_outliers('Er', n=nIQR) Er_values = sourcepar.value_array('Er', filter_outliers=True) means['Er'], errors['Er'] = _avg_and_std(Er_values, logarithmic=True) sourcepar.means = means sourcepar.errors = errors sourcepar.means_weight = means_weight sourcepar.errors_weight = errors_weight params_name = ('Mw', 'fc', 't_star') sourcepar_mean = dict( zip(params_name, [means['Mw'], means['fc'], means['t_star']])) logger.info('params_mean: {}'.format(sourcepar_mean)) sourcepar_mean_weight = dict( zip(params_name, [means_weight['Mw'], means_weight['fc'], means_weight['t_star']])) logger.info('params_mean_weighted: {}'.format(sourcepar_mean_weight))
def main(): # Lazy-import modules for speed from sourcespec.ssp_parse_arguments import parse_args options = parse_args(progname='source_spec') # Setup stage from sourcespec.ssp_setup import (configure, move_outdir, remove_old_outdir, setup_logging, save_config, ssp_exit) config = configure(options, progname='source_spec') setup_logging(config) from sourcespec.ssp_read_traces import read_traces st = read_traces(config) # Now that we have an evid, we can rename the outdir and the log file move_outdir(config) setup_logging(config, config.hypo.evid) remove_old_outdir(config) # Save config to out dir save_config(config) # Deconvolve, filter, cut traces: from sourcespec.ssp_process_traces import process_traces proc_st = process_traces(config, st) # Build spectra (amplitude in magnitude units) from sourcespec.ssp_build_spectra import build_spectra spec_st, specnoise_st, weight_st = build_spectra(config, proc_st) from sourcespec.ssp_plot_traces import plot_traces plot_traces(config, proc_st) # Spectral inversion from sourcespec.ssp_inversion import spectral_inversion sourcepar = spectral_inversion(config, spec_st, weight_st) # Local magnitude if config.compute_local_magnitude: from sourcespec.ssp_local_magnitude import local_magnitude local_magnitude(config, st, proc_st, sourcepar) # Compute averages, find outliers from sourcespec.ssp_averages import compute_averages compute_averages(config, sourcepar) # Save output from sourcespec.ssp_output import write_output write_output(config, sourcepar) # Save residuals from sourcespec.ssp_residuals import spectral_residuals spectral_residuals(config, spec_st, sourcepar) # Plotting from sourcespec.ssp_plot_spectra import plot_spectra plot_spectra(config, spec_st, specnoise_st, plot_type='regular') plot_spectra(config, weight_st, plot_type='weight') from sourcespec.ssp_plot_params_stats import box_plots box_plots(config, sourcepar) if config.plot_station_map: # We import here, cause we check for Cartopy at runtime from sourcespec.ssp_plot_stations import plot_stations plot_stations(config, sourcepar) if config.html_report: from sourcespec.ssp_html_report import html_report html_report(config, sourcepar) ssp_exit()
def _write_db(config, sourcepar): try: database_file = config.database_file except KeyError: database_file = None if not database_file: return hypo = config.hypo evid = hypo.evid # Open SQLite database conn = sqlite3.connect(database_file, timeout=60) c = conn.cursor() # Init Station table c.execute('create table if not exists Stations ' '(stid, evid,' 'Mo, Mo_err_minus, Mo_err_plus,' 'Mw, Mw_err_minus, Mw_err_plus,' 'fc, fc_err_minus, fc_err_plus,' 't_star, t_star_err_minus, t_star_err_plus,' 'Qo, Qo_err_minus, Qo_err_plus,' 'bsd, bsd_err_minus, bsd_err_plus,' 'ra, ra_err_minus, ra_err_plus,' 'dist, azimuth, Er);') # Write station source parameters to database nobs = 0 stationpar = sourcepar.station_parameters for statId in sorted(stationpar.keys()): nobs += 1 par = stationpar[statId] # Remove existing line, if present t = (statId, evid) c.execute('delete from Stations where stid=? and evid=?;', t) # Insert new line t = (statId, evid, par['Mo'], *par['Mo_err'], par['Mw'], *par['Mw_err'], par['fc'], *par['fc_err'], par['t_star'], *par['t_star_err'], par['Qo'], *par['Qo_err'], par['bsd'], *par['bsd_err'], par['ra'], *par['ra_err'], par['hyp_dist'], par['az'], par['Er']) # Create a string like ?,?,?,? values = ','.join('?' * len(t)) try: c.execute('insert into Stations values(' + values + ');', t) except Exception as msg: _log_db_write_error(msg, database_file) ssp_exit(1) # Commit changes conn.commit() # Init Event table c.execute('create table if not exists Events ' '(evid, orig_time, lon, lat, depth, nobs,' 'Mo, Mo_err_minus, Mo_err_plus,' 'Mo_wavg, Mo_wavg_err_minus, Mo_wavg_err_plus,' 'Mw, Mw_err, Mw_wavg, Mw_wavg_err,' 'fc, fc_err_minus, fc_err_plus,' 'fc_wavg, fc_wavg_err_minus, fc_wavg_err_plus,' 't_star, t_star_err,' 't_star_wavg, t_star_wavg_err,' 'Qo, Qo_err,' 'Qo_wavg, Qo_wavg_err,' 'ra, ra_err_minus, ra_err_plus,' 'ra_wavg, ra_wavg_err_minus, ra_wavg_err_plus,' 'bsd, bsd_err_minus, bsd_err_plus,' 'bsd_wavg, bsd_wavg_err_minus, bsd_wavg_err_plus,' 'Er, Er_err_minus, Er_err_plus,' 'Ml, Ml_err);') means = sourcepar.means means_weight = sourcepar.means_weight errors = sourcepar.errors errors_weight = sourcepar.errors_weight # Remove event from Event table, if present t = (evid, ) c.execute('delete from Events where evid=?;', t) t = (evid, str(hypo.origin_time), float(hypo.longitude), float(hypo.latitude), float( hypo.depth), nobs, means['Mo'], *errors['Mo'], means_weight['Mo'], *errors_weight['Mo'], means['Mw'], errors['Mw'], means_weight['Mw'], errors_weight['Mw'], means['fc'], *errors['fc'], means_weight['fc'], *errors_weight['fc'], means['t_star'], errors['t_star'], means_weight['t_star'], errors_weight['t_star'], means['Qo'], errors['Qo'], means_weight['Qo'], errors_weight['Qo'], means['ra'], *errors['ra'], means_weight['ra'], *errors_weight['ra'], means['bsd'], *errors['bsd'], means_weight['bsd'], *errors_weight['bsd'], means['Er'], *errors['Er'], means['Ml'], errors['Ml']) # Create a string like ?,?,?,? values = ','.join('?' * len(t)) try: c.execute('insert into Events values(' + values + ');', t) except Exception as msg: _log_db_write_error(msg, database_file) ssp_exit(1) # Commit changes and close database conn.commit() conn.close() logger.info('Output written to database: ' + database_file)
def _parse_picks(config): # we need to lazy-import here, so that OBSPY_VERSION is defined from sourcespec.ssp_setup import OBSPY_VERSION pick_file = config.options.pick_file if pick_file is None: return None try: fp = open(pick_file) if not _is_hypo_format(fp): raise Exception('%s: Not a phase file' % pick_file) lines = fp.readlines() fp.close() except Exception as err: logger.error(err) ssp_exit(1) picks = [] for line in lines: # remove newline line = line.replace('\n', '') # skip separator and empty lines stripped_line = line.strip() if stripped_line == '10' or stripped_line == '': continue # Check if it is a pick line # 6th character should be alpha (phase name: P or S) # other character should be digits (date/time) if not (line[5].isalpha() and line[9].isdigit() and line[20].isdigit()): continue pick = Pick() pick.station = line[0:4].strip() pick.station = \ _correct_station_name(pick.station, config.traceids) pick.flag = line[4:5] pick.phase = line[5:6] pick.polarity = line[6:7] try: pick.quality = int(line[7:8]) except ValueError: # If we cannot read pick quality, # we give the pick the lowest quality pick.quality = 4 timestr = line[9:24] dt = datetime.strptime(timestr, '%y%m%d%H%M%S.%f') pick.time = UTCDateTime(dt) picks.append(pick) try: stime = line[31:36] except Exception: continue if stime.strip() == '': continue pick2 = Pick() pick2.station = pick.station pick2.flag = line[36:37] pick2.phase = line[37:38] pick2.polarity = line[38:39] try: pick2.quality = int(line[39:40]) except ValueError: # If we cannot read pick quality, # we give the pick the lowest quality pick2.quality = 4 # pick2.time has the same date, hour and minutes # than pick.time # We therefore make a copy of pick.time, # and set seconds and microseconds to 0 if OBSPY_VERSION > (1, 1, 1): # UTCDateTime objects will become immutable in future # versions of ObsPy pick2.time = pick.time.replace(second=0, microsecond=0) else: # For old versions, UTCDateTime objects are mutable pick2.time = UTCDateTime(pick.time) pick2.time.second = 0 pick2.time.microsecond = 0 # finally we add stime pick2.time += float(stime) picks.append(pick2) return picks
def read_traces(config): """Read traces, store waveforms and metadata.""" # read dataless dataless = _read_dataless(config.dataless) # read PAZ (normally this is an alternative to dataless) paz = _read_paz(config.paz) # parse hypocenter file _set_hypo_file_path(config) hypo = _parse_hypocenter(config.options.hypo_file) # parse pick file _set_pick_file_path(config) picks = _parse_picks(config) # parse QML file if hypo is None: hypo, picks = _parse_qml(config.options.qml_file, config.options.evid) # finally, read traces # traces can be defined in a pickle catalog (Antilles format)... if config.pickle_catalog: sys.path.append(config.pickle_classpath) with open(config.pickle_catalog, 'rb') as fp: catalog = pickle.load(fp) event = [ev for ev in catalog if ev.event_id == config.options.evid][0] hypo = _parse_hypocenter(event) st = Stream() for trace in event.traces: if config.options.station is not None: if not trace.station == config.options.station: continue try: tmpst = read(trace.trace_file, fsize=False) except Exception as err: logger.error(err) continue for trace in tmpst.traces: st.append(trace) trace.stats.format = config.trace_format _add_paz_and_coords(trace, dataless, paz) _add_hypocenter(trace, hypo) _add_picks(trace, picks) # FIXME: actually add picks! # _add_instrtype(trace) trace.stats.instrtype = 'acc' # FIXME # ...or in standard files (CRL and ISNet) else: logger.info('Reading traces...') # phase 1: build a file list # ph 1.1: create a temporary dir and run '_build_filelist()' # to move files to it and extract all tar archives tmpdir = tempfile.mkdtemp() filelist = [] for trace_path in config.options.trace_path: _build_filelist(trace_path, filelist, tmpdir) # ph 1.2: rerun '_build_filelist()' in tmpdir to add to the # filelist all the extraceted files listing = os.listdir(tmpdir) for filename in listing: fullpath = os.path.join(tmpdir, filename) _build_filelist(fullpath, filelist, None) # phase 2: build a stream object from the file list orientation_codes = config.vertical_channel_codes +\ config.horizontal_channel_codes_1 +\ config.horizontal_channel_codes_2 st = Stream() for filename in sorted(filelist): try: tmpst = read(filename, fsize=False) except Exception: logger.warning('%s: Unable to read file as a trace: ' 'skipping' % filename) continue for trace in tmpst.traces: orientation = trace.stats.channel[-1] if orientation not in orientation_codes: logger.warning('%s: Unknown channel orientation: "%s": ' 'skipping trace' % (trace.id, orientation)) continue if config.options.station is not None: if not trace.stats.station == config.options.station: continue trace.stats.format = config.trace_format _correct_traceid(trace, config.traceids) try: _add_paz_and_coords(trace, dataless, paz) _add_instrtype(trace, config) _add_hypocenter(trace, hypo) _add_picks(trace, picks) except Exception as err: logger.warning(err) continue st.append(trace) shutil.rmtree(tmpdir) logger.info('Reading traces: done') if len(st.traces) == 0: logger.info('No trace loaded') ssp_exit() _complete_picks(st) # if hypo is still None, get it from first trace if hypo is None: try: hypo = st[0].stats.hypo except AttributeError: logger.error('No hypocenter information found') ssp_exit() # add vs to hypo _hypo_vel(hypo, config) # add hypo to config file config.hypo = hypo st.sort() return st
def _parse_hypo71_picks(config): pick_file = config.options.pick_file if pick_file is None: return None try: _is_hypo71_picks(pick_file) except Exception as err: logger.error(err) ssp_exit(1) picks = [] for line in open(pick_file): # remove newline line = line.replace('\n', '') # skip separator and empty lines stripped_line = line.strip() if stripped_line == '10' or stripped_line == '': continue # Check if it is a pick line # 6th character should be alpha (phase name: P or S) # other character should be digits (date/time) if not (line[5].isalpha() and line[9].isdigit() and line[20].isdigit()): continue pick = Pick() pick.station = line[0:4].strip() pick.station = \ _correct_station_name(pick.station, config.traceid_mapping_file) pick.flag = line[4:5] pick.phase = line[5:6] pick.polarity = line[6:7] try: pick.quality = int(line[7:8]) except ValueError: # If we cannot read pick quality, # we give the pick the lowest quality pick.quality = 4 timestr = line[9:24] dt = datetime.strptime(timestr, '%y%m%d%H%M%S.%f') pick.time = UTCDateTime(dt) picks.append(pick) try: stime = line[31:36] except Exception: continue if stime.strip() == '': continue pick2 = Pick() pick2.station = pick.station pick2.flag = line[36:37] pick2.phase = line[37:38] pick2.polarity = line[38:39] try: pick2.quality = int(line[39:40]) except ValueError: # If we cannot read pick quality, # we give the pick the lowest quality pick2.quality = 4 # pick2.time has the same date, hour and minutes # than pick.time # We therefore make a copy of pick.time, # and set seconds and microseconds to 0 pick2.time = pick.time.replace(second=0, microsecond=0) # finally we add stime pick2.time += float(stime) picks.append(pick2) return picks