Esempio n. 1
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
Esempio n. 2
0
def make_synth(config, spec_st, trace_spec=None):
    import math
    import numpy as np
    from copy import deepcopy
    from sourcespec.spectrum import Spectrum
    from sourcespec.ssp_spectral_model import spectral_model, objective_func
    from sourcespec.ssp_util import mag_to_moment, moment_to_mag
    fdelta = 0.01
    fmin = config.options.fmin
    fmax = config.options.fmax + fdelta

    residuals = list()
    n = 0
    for fc, mag, Mo, t_star, alpha in zip(config.options.fc,
                                          config.options.mag,
                                          config.options.Mo,
                                          config.options.t_star,
                                          config.options.alpha):
        spec = Spectrum()
        if trace_spec:
            spec.stats = deepcopy(trace_spec.stats)
        else:
            spec.stats.begin = fmin
            spec.stats.delta = fdelta
            spec.stats.npts = int((fmax - fmin) / fdelta)

        if math.isnan(Mo):
            Mo = mag_to_moment(mag)
        else:
            mag = moment_to_mag(Mo)

        spec.stats.station = 'S{:02d}'.format(n)
        n += 1
        spec.stats.instrtype = 'Synth'
        spec.stats.channel = spec.stats.channel[:-1] + 'S'
        spec.stats.par = {
            'Mw': mag,
            'fc': fc,
            't_star': t_star,
            'alpha': alpha
        }

        freq = spec.get_freq()
        freq_log = trace_spec.freq_log
        spec.freq_log = freq_log
        spec.data_mag = spectral_model(freq, mag, fc, t_star, alpha)
        spec.data = mag_to_moment(spec.data_mag)
        spec.data_log_mag = spectral_model(freq_log, mag, fc, t_star, alpha)
        spec.data_log = mag_to_moment(spec.data_log_mag)
        spec_st.append(spec)

        if trace_spec:
            objective_func2 = objective_func(freq, trace_spec.data_mag,
                                             np.ones_like(trace_spec.data_mag))
            print(Mo, mag, fc, t_star, alpha,
                  objective_func2((mag, fc, t_star, alpha)))
            residuals.append([
                Mo, mag, fc, t_star,
                objective_func2((mag, fc, t_star, alpha))
            ])
Esempio n. 3
0
def make_synth(config, spec_st, trace_spec=None):
    fdelta = 0.01
    fmin = config.options.fmin
    fmax = config.options.fmax + fdelta

    residuals = list()
    for fc, mag, Mo, t_star, alpha in zip(config.options.fc,
                                          config.options.mag,
                                          config.options.Mo,
                                          config.options.t_star,
                                          config.options.alpha):
        spec = Spectrum()
        if trace_spec:
            spec.stats = deepcopy(trace_spec.stats)
        else:
            spec.stats.begin = fmin
            spec.stats.delta = fdelta
            spec.stats.npts = int((fmax - fmin) / fdelta)

        if math.isnan(Mo):
            Mo = mag_to_moment(mag)
        else:
            mag = moment_to_mag(Mo)

        spec.stats.station = 'Mw: %.1f fc: %.2fHz t*: %.2fs alpha: %.2f' %\
            (mag, fc, t_star, alpha)
        spec.stats.instrtype = 'Synth'
        spec.stats.channel = spec.stats.channel[:-1] + 'S'
        spec.stats.par = {
            'Mw': mag,
            'fc': fc,
            't_star': t_star,
            'alpha': alpha
        }

        freq = spec.get_freq()
        spec.data_mag = spectral_model(freq, mag, fc, t_star, alpha)
        spec.data = mag_to_moment(spec.data_mag)
        spec_st.append(spec)

        if trace_spec:
            objective_func2 = objective_func(freq, trace_spec.data_mag,
                                             np.ones_like(trace_spec.data_mag))
            print(Mo, mag, fc, t_star, alpha,
                  objective_func2((mag, fc, t_star, alpha)))
            residuals.append([
                Mo, mag, fc, t_star,
                objective_func2((mag, fc, t_star, alpha))
            ])
Esempio n. 4
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
def _set_plot_params(config, spec_st, specnoise_st, ncols, plot_params):
    """Determine the number of plots and axes min and max."""
    nplots = 0
    moment_minmax = None
    freq_minmax = None
    if not config.plot_spectra_ignored:
        _spec_st = Stream(sp for sp in spec_st if not sp.stats.ignore)
    else:
        _spec_st = spec_st
    specids = set('.'.join(sp.id.split('.')[:-1]) for sp in _spec_st)
    for specid in specids:
        network, station, location = specid.split('.')
        spec_st_sel = _spec_st.select(
            network=network, station=station, location=location)
        if specnoise_st:
            specnoise_sel = specnoise_st.select(
                network=network, station=station, location=location)
            spec_st_sel += specnoise_sel
        for spec in spec_st_sel:
            moment_minmax, freq_minmax =\
                spec_minmax(spec.data, spec.get_freq(),
                            moment_minmax, freq_minmax)
        # 'code' is band+instrument code
        for code in set(x.stats.channel[:-1] for x in spec_st_sel):
            nplots += 1
    nlines = int(math.ceil(nplots/ncols))
    maxlines = config.plot_spectra_maxrows
    if nlines > maxlines:
        nlines = maxlines
    if plot_params.plot_type != 'weight':
        moment_minmax[1] *= 10
        mag_minmax = moment_to_mag(moment_minmax)
    else:
        mag_minmax = None
    plot_params.nlines = nlines
    plot_params.ncols = ncols
    plot_params.freq_minmax = freq_minmax
    plot_params.moment_minmax = moment_minmax
    plot_params.mag_minmax = mag_minmax
Esempio n. 6
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:
        msg = "'-C' option set, but 'residuals_filepath' not specified "
        msg += "in config file: ignoring station correction"
        logger.warning(msg)
        return spec_st
    with open(res_filepath, 'rb') as fp:
        residual = pickle.load(fp)

    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.data_mag -= corr.data_mag
            # interpolate the corrected data_mag to log frequencies
            f = interp1d(freq, spec.data_mag, fill_value='extrapolate')
            spec.data_log_mag = f(spec.freq_log)
            # convert mag to moment
            spec.data = mag_to_moment(spec.data_mag)
            spec.data_log = mag_to_moment(spec.data_log_mag)

            logger.info('%s corrected, frequency range is: %f %f' %
                        (spec.id, fmin, fmax))
    return spec_st
Esempio n. 7
0
def build_spectra(config, st, noise_weight=False):
    """
    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.
    """
    spec_st = Stream()
    specnoise_st = Stream()

    # sort by sampling rate: this limits the number of times on which
    # konno-ohmachi smoothing matrix is recomputed
    for trace in st.sort(keys=['sampling_rate', 'station']):
        try:
            _check_data_len(config, trace)
            trace_signal, trace_noise = _cut_signal_noise(config, trace)
            _check_noise_level(trace_signal, trace_noise)
        except (ValueError, RuntimeError):
            continue
        spec = _build_spectrum(config, trace_signal)
        if noise_weight:
            specnoise = _build_spectrum(config, trace_noise)
            weight = _build_weight(spec, specnoise)
            if config.spectral_sn_freq_range is not None:
                sn_fmin, sn_fmax = config.spectral_sn_freq_range
                freqs = weight.get_freq()
                idx = np.where((sn_fmin <= freqs)*(freqs <= sn_fmax))
            else:
                idx = range(len(weight.data_raw))
            spectral_snratio =\
                weight.data_raw[idx].sum()/len(weight.data_raw[idx])
            spec.stats.spectral_snratio = spectral_snratio
            logger.info('%s: spectral S/N: %.2f' %
                        (spec.get_id(), spectral_snratio))
            if config.spectral_sn_min:
                ssnmin = config.spectral_sn_min
                if spectral_snratio < ssnmin:
                    logger.warning('%s: spectral S/N smaller than %.2f: '
                                   'ignoring spectrum' %
                                   (spec.get_id(), ssnmin))
                    trace.stats.ignore = True
                    spec.stats.ignore = True
                    specnoise.stats.ignore = True
            specnoise_st.append(specnoise)
        spec_st.append(spec)

    # build H component and weight_st
    weight_st = _build_H_and_weight(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)

    # optionally, apply station correction
    if config.options.correction:
        spec_st = station_correction(spec_st, config)

    if noise_weight:
        for specnoise in specnoise_st:
            specnoise.data_mag = moment_to_mag(specnoise.data)
        return spec_st, specnoise_st, weight_st
    else:
        return spec_st
Esempio n. 8
0
    freqs_min = [spec.get_freq().min() for spec in res]
    freqs_max = [spec.get_freq().max() for spec in res]
    freq_min = min(freqs_min)
    freq_max = max(freqs_max)

    spec_mean = Spectrum()
    spec_mean.stats.begin = freq_min
    spec_mean.stats.delta = res[0].stats.delta
    spec_mean.stats.station = res[0].stats.station
    spec_mean.data_mag = None
    for spec in res:
        spec_slice = spec.slice(freq_min,
                                freq_max,
                                pad=True,
                                fill_value=mag_to_moment(0))
        spec_slice.data_mag = moment_to_mag(spec_slice.data)
        norm = (spec_slice.data_mag != 0).astype(int)
        if spec_mean.data_mag is None:
            spec_mean.data_mag = spec_slice.data_mag
            norm_mean = norm
        else:
            spec_mean.data_mag += spec_slice.data_mag
            norm_mean += norm
    spec_mean.data_mag /= norm_mean
    spec_mean.data = mag_to_moment(spec_mean.data_mag)

    residual_mean.append(spec_mean)

    # plot traces
    if options.plot:
        stnm = spec_mean.stats.station
Esempio n. 9
0
def main():
    usage = 'usage: %prog [options] residuals_dir'

    parser = OptionParser(usage=usage)
    parser.add_option('-m',
                      '--min_spectra',
                      dest='min_spectra',
                      action='store',
                      default='20',
                      help='minimum number of spectra to '
                      'compute residuals (default=20)',
                      metavar='NUMBER')
    parser.add_option('-p',
                      '--plot',
                      dest='plot',
                      action='store_true',
                      default=False,
                      help='save residuals plots to file')
    (options, args) = parser.parse_args()

    if len(args) < 1:
        parser.print_usage(file=sys.stderr)
        sys.stderr.write("\tUse '-h' for help\n\n")
        sys.exit(1)

    resdir = args[0]
    min_spectra = int(options.min_spectra)
    outdir = 'sspec_residuals'

    residual_dict = defaultdict(Stream)
    for resfile in glob(os.path.join(resdir, '*-res*.pickle')):
        print(resfile)
        with open(resfile, 'rb') as fp:
            residual_st = pickle.load(fp)
        for spec in residual_st:
            residual_dict[spec.id].append(spec)

    if not os.path.exists(outdir):
        os.makedirs(outdir)

    residual_mean = Stream()
    for stat_id in sorted(residual_dict.keys()):
        if len(residual_dict[stat_id]) < min_spectra:
            continue
        print(stat_id)

        res = residual_dict[stat_id]

        freqs_min = [spec.get_freq().min() for spec in res]
        freqs_max = [spec.get_freq().max() for spec in res]
        freq_min = min(freqs_min)
        freq_max = max(freqs_max)

        spec_mean = Spectrum()
        spec_mean.stats.begin = freq_min
        spec_mean.stats.delta = res[0].stats.delta
        spec_mean.stats.station = res[0].stats.station
        spec_mean.data_mag = None
        for spec in res:
            spec_slice = spec.slice(freq_min,
                                    freq_max,
                                    pad=True,
                                    fill_value=mag_to_moment(0))
            spec_slice.data_mag = moment_to_mag(spec_slice.data)
            norm = (spec_slice.data_mag != 0).astype(int)
            if spec_mean.data_mag is None:
                spec_mean.data_mag = spec_slice.data_mag
                norm_mean = norm
            else:
                spec_mean.data_mag += spec_slice.data_mag
                norm_mean += norm
        spec_mean.data_mag /= norm_mean
        spec_mean.data = mag_to_moment(spec_mean.data_mag)

        residual_mean.append(spec_mean)

        # plot traces
        if options.plot:
            stnm = spec_mean.stats.station
            figurefile = os.path.join(outdir, stnm + '-res.png')
            fig = plt.figure(dpi=160)
            for spec in res:
                plt.semilogx(spec.get_freq(), spec.data_mag, 'b-')
            plt.semilogx(spec_mean.get_freq(), spec_mean.data_mag, 'r-')
            plt.xlabel('frequency (Hz)')
            plt.ylabel('residual amplitude (obs - synth) in magnitude units')
            plt.title('residuals : ' + stnm + ', ' + str(len(res)) +
                      ' records')
            fig.savefig(figurefile, bbox_inches='tight')
            plt.close()

    # writes the mean residuals (the stations corrections)
    with open(os.path.join(outdir, 'residual_mean.pickle'), 'wb') as fp:
        pickle.dump(residual_mean, fp)