예제 #1
0
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)
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
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
예제 #6
0
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()
예제 #7
0
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)
예제 #8
0
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
예제 #9
0
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
예제 #10
0
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)
예제 #11
0
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
예제 #12
0
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
예제 #13
0
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
예제 #14
0
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
예제 #15
0
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)
예제 #16
0
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
예제 #17
0
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
예제 #18
0
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
예제 #19
0
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))
예제 #20
0
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()
예제 #21
0
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)
예제 #22
0
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
예제 #23
0
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
예제 #24
0
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