Skip to content

Commit ba60420

Browse files
P wave type (version 2) (#9)
* Added 'rpp' configuration parameter for P-wave average radiation pattern coefficient. * Added support for P wave type in get_radiation_coefficient function. * Added support for P wave type in _add_hypo_dist_and_arrivals, _merge_stream and _check_sn_ratio functions. * Added support for P wave type in _plot_trace function. * Added support for P wave type in _compute_h, _displacement_to_moment functions. Added support for P wave type in _check_data_len and _cut_signal_noise functions. * Added support for P wave type in _spec_inversion function. * Added support for P wave type in _Q0_to_t_star function. * Simplified distinction between P and S in _displacement_to_moment function. Write hypocentral and station velocities to log in _displacement_to_moment function. * Add `P` option to `wave_type` in config file * Store `vp` in hypo object * `pre_p_time`-->`noise_pre_time`;`pre_s_time`-->`signal_pre_time` * Remove references to "S-wave" only Replace them with "P- or S-wave" or with "signal". * Improve velocity log messages Add statid; avoid duplicated messages. * `rps_from_focal_mechanism`-->`rp_from_focal_mechanism` * CHANGELOG for #9 * Update doc for P-wave inversion Co-authored-by: Claudio Satriano <[email protected]>
1 parent 459b0f8 commit ba60420

17 files changed

+188
-93
lines changed

CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SourceSpec
22

3-
Earthquake source parameters from S-wave displacement spectra
3+
Earthquake source parameters from P- or S-wave displacement spectra
44

55
(c) 2011-2022 Claudio Satriano <[email protected]>
66

@@ -14,6 +14,10 @@ Earthquake source parameters from S-wave displacement spectra
1414
- Config options `vp` and `vs` have been renamed to `vp_source`
1515
and `vs_source` (see issue [#5])
1616
- New, optional, config options `vp_stations` and `vs_stations`
17+
- Config options `pre_p_time` and `pre_s_time` have been renamed to
18+
`noise_pre_time` and `signal_pre_time`, respectively (see pull request [#9])
19+
- Config parameter `rps_from_focal_mechanism` renamed to
20+
`rp_from_focal_mechanism` (see pull request [#9])
1721
- Config parameters `PLOT_SHOW`, `PLOT_SAVE` and `PLOT_SAVE_FORMAT` are now
1822
lowercase (`plot_show`, `plot_save` and `plot_save_format`)
1923
- New, optional, general config parameters for specyfing author and agency
@@ -24,6 +28,7 @@ Earthquake source parameters from S-wave displacement spectra
2428
section called `TRACE AND METADATA PARAMETERS`
2529

2630
- Features:
31+
- Support for P-wave spectral inversion (see pull request [#9])
2732
- It is now possible to provide different vp and vs velocities, close to the
2833
source and close to the stations (see the new config options above and
2934
issue [#5])
@@ -310,3 +315,4 @@ Initial Python port.
310315
[#3]: https://github.com/SeismicSource/sourcespec/issues/3
311316
[#5]: https://github.com/SeismicSource/sourcespec/issues/5
312317
[#6]: https://github.com/SeismicSource/sourcespec/issues/6
318+
[#9]: https://github.com/SeismicSource/sourcespec/issues/9

CITATION.cff

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ authors:
44
- family-names: "Satriano"
55
given-names: "Claudio"
66
orcid: "https://orcid.org/0000-0002-3039-2530"
7-
title: "SourceSpec – Earthquake source parameters from S-wave displacement spectra"
7+
title: "SourceSpec – Earthquake source parameters from P- or S-wave displacement spectra"
88
doi: 10.5281/ZENODO.3688587
99
url: "https://sourcespec.seismicsource.org"

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# SourceSpec
44

5-
Earthquake source parameters from S-wave displacement spectra
5+
Earthquake source parameters from P- or S-wave displacement spectra
66

77
[![PyPI-badge]][PyPI-link]
88
[![license-badge]][license-link]
@@ -97,8 +97,9 @@ repository.
9797

9898
If you used SourceSpec for a scientific paper, please cite it as:
9999

100-
> Satriano, C. (2022). SourceSpec – Earthquake source parameters from S-wave
101-
> displacement spectra (X.Y). https://doi.org/10.5281/ZENODO.3688587
100+
> Satriano, C. (2022). SourceSpec – Earthquake source parameters from
101+
> P- or S-wave displacement spectra (X.Y).
102+
> https://doi.org/10.5281/ZENODO.3688587
102103
103104
Please replace `X.Y` with the SourceSpec version number you used.
104105

doc/index.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ SourceSpec documentation
99
SourceSpec is a collection of command line programs (written in Python) to
1010
determine earthquake source parameters (seismic moment :math:`M_0`, corner
1111
frequency :math:`f_c`) and the inelastic attenuation term (:math:`t^*`), from
12-
the modeling of waveform spectra.
12+
the modeling of waveform displacement spectra.
1313

1414
Other parameters (source radius :math:`r_0`, stress drop :math:`\Delta \sigma`)
15-
are computed from the inverted ones. The quality factor :math:`Q` is determined
16-
from :math:`t^*`.
15+
are computed from the inverted ones. The quality factor :math:`Q_0` is
16+
determined from :math:`t^*`.
1717

1818
As a bonus, local magnitude :math:`M_l` is computed as well.
1919

2020
SourceSpec is composed of the following programs:
2121

22-
* ``source_spec``: inverts the S-wave displacement spectra from station
22+
* ``source_spec``: inverts the P- or S-wave displacement spectra from station
2323
recordings of a single event.
2424
* ``ssp_residuals``: computes station residuals from ``source_spec`` output.
2525
* ``source_model``: direct spectral modelling.

doc/source_spec.rst

+11-10
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
SourceSpec
55
###########
66

7-
Earthquake source parameters from inversion of S-wave spectra.
7+
Earthquake source parameters from inversion of P- or S-wave spectra.
88

99
:copyright:
1010
2011-2022 Claudio Satriano <[email protected]>
@@ -15,7 +15,7 @@ Earthquake source parameters from inversion of S-wave spectra.
1515
Overview
1616
========
1717

18-
``source_spec`` inverts the S-wave displacement spectra from
18+
``source_spec`` inverts the P- or S-wave displacement spectra from
1919
station recordings of a single event.
2020

2121
Spectral model
@@ -31,7 +31,7 @@ propagation term (geometric and anelastic attenuation of body waves):
3131
\frac{1}{r}
3232
\times
3333
\frac{2 R_{\Theta\Phi}}
34-
{4 \pi \rho_h^{1/2} \rho_r^{1/2} \beta_h^{5/2} \beta_r^{1/2}}
34+
{4 \pi \rho_h^{1/2} \rho_r^{1/2} c_h^{5/2} c_r^{1/2}}
3535
\times
3636
M_O
3737
\times
@@ -43,11 +43,11 @@ where:
4343

4444
- :math:`r` is the hypocentral distance (:math:`\frac{1}{r}` is geometric
4545
attenuation);
46-
- :math:`R_{\Theta\Phi}` is the radiation pattern coefficient for S-waves
46+
- :math:`R_{\Theta\Phi}` is the radiation pattern coefficient for P- or S-waves
4747
(average or computed from focal mechanism, if available);
4848
- :math:`\rho_h` and :math:`\rho_r` are the medium densities at the hypocenter
4949
and at the receiver, respectively;
50-
- :math:`\beta_h` and :math:`\beta_r` are the S-wave velocities at the hypocenter
50+
- :math:`c_h` and :math:`c_r` are the P- or S-wave velocities at the hypocenter
5151
and at the receiver, respectively;
5252
- :math:`M_O` is the seismic moment;
5353
- :math:`f` is the frequency;
@@ -66,7 +66,7 @@ and convert them to seismic moment units:
6666
6767
M(f) \equiv
6868
r \times
69-
\frac{4 \pi \rho_h^{1/2} \rho_r^{1/2} \beta_h^{5/2} \beta_r^{1/2}}
69+
\frac{4 \pi \rho_h^{1/2} \rho_r^{1/2} c_h^{5/2} c_r^{1/2}}
7070
{2 R_{\Theta\Phi}}
7171
\times S(f) =
7272
M_O \times
@@ -120,14 +120,15 @@ where :math:`M_w \equiv \frac{2}{3} (\log_{10} M_0 - 9.1)`.
120120

121121
The parameters to determine are :math:`M_w`, :math:`f_c` and :math:`t^*`.
122122

123-
The retrieved attenuation parameter :math:`t^*` is then converted to the S-wave
124-
quality factor :math:`Q_0` using the following expression:
123+
The retrieved attenuation parameter :math:`t^*` is then converted to the P- or
124+
S-wave quality factor :math:`Q_0^{[P|S]}` using the following expression:
125125

126126
.. math::
127127
128-
Q_0 = \frac{tt_S(r)}{t^*}
128+
Q_0^{[P|S]} = \frac{tt_{[P|S]}(r)}{t^*}
129129
130-
where :math:`tt_S(r)` is the S-wave travel time from source to station.
130+
where :math:`tt_{[P|S]}(r)` is the P- or S-wave travel time from source to
131+
station.
131132

132133
Station-specific effects can be determined by running ``source_spec`` on several
133134
events and computing the average of station residuals between observed and

sourcespec/configspec.conf

+11-8
Original file line numberDiff line numberDiff line change
@@ -103,22 +103,23 @@ p_arrival_tolerance = float(default=4.0)
103103
s_arrival_tolerance = float(default=4.0)
104104

105105
# Start time (in seconds) of the noise window, respect to the P arrival time
106-
pre_p_time = float(default=6.0)
106+
noise_pre_time = float(default=6.0)
107107

108-
# Start time (in seconds) of the S-wave window, respect to the S arrival time
109-
pre_s_time = float(default=1.0)
108+
# Start time (in seconds) of the signal window, respect to the P or S arrival
109+
# times (see "wave_type" below)
110+
signal_pre_time = float(default=1.0)
110111

111-
# Length (in seconds) for both noise and S-wave windows
112+
# Length (in seconds) for both noise and signal windows
112113
win_length = float(default=5.0)
113114
# -------- TIME WINDOW PARAMETERS
114115

115116

116117
# SPECTRUM PARAMETERS --------
117-
# Wave type to analyse: 'S', 'SH' or 'SV'
118+
# Wave type to analyse: 'P', 'S', 'SH' or 'SV'
118119
# If 'SH' or 'SV' are selected, traces are rotated in the radial-transverse
119120
# system. Transverse component is used for 'SH', radial (and vertical)
120121
# components are used for 'SV'
121-
wave_type = option('S', 'SH', 'SV', default='S')
122+
wave_type = option('P', 'S', 'SH', 'SV', default='S')
122123

123124
# Integrate in time domain (default: integration in spectral domain)
124125
time_domain_int = boolean(default=False)
@@ -134,7 +135,7 @@ taper_halfwidth = float(0, 0.5, default=0.05)
134135
# this window length, so that the spectral
135136
# sampling is fixed to 1/spectral_win_length.
136137
# Comment out (or set to None) to use
137-
# S-wave window as spectral window length.
138+
# signal window as spectral window length.
138139
spectral_win_length = float(default=None)
139140

140141
# Spectral smoothing window width in frequency decades
@@ -217,10 +218,12 @@ vs_stations = float(default=None)
217218
NLL_model_dir = string(default=None)
218219
# Density (kg/m3):
219220
rho = float(default=2500)
221+
# P-wave average radiation pattern coefficient:
222+
rpp = float(default=0.52)
220223
# S-wave average radiation pattern coefficient:
221224
rps = float(default=0.62)
222225
# Radiation pattern from focal mechanism, if available
223-
rps_from_focal_mechanism = boolean(default=False)
226+
rp_from_focal_mechanism = boolean(default=False)
224227

225228
# Weighting type: 'noise', 'frequency' or 'no_weight'
226229
weighting = option('noise', 'frequency', 'no_weight', default='noise')

sourcespec/source_spec.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- coding: utf-8 -*-
22
# SPDX-License-Identifier: CECILL-2.1
33
"""
4-
Earthquake source parameters from inversion of S-wave spectra.
4+
Earthquake source parameters from inversion of P- or S-wave spectra.
55
66
:copyright:
77
2012 Claudio Satriano <[email protected]>

sourcespec/ssp_build_spectra.py

+41-15
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ def _compute_h(spec_st, code, wave_type='S'):
102102
# only use radial and, optionally, vertical component for SV
103103
if wave_type == 'SV' and channel[-1] == 'T':
104104
continue
105+
# only use vertical component for P
106+
if wave_type == 'P' and channel[-1] != 'Z':
107+
continue
105108
if spec_h is None:
106109
spec_h = spec.copy()
107110
spec_h.data = np.power(spec_h.data, 2)
@@ -118,10 +121,13 @@ def _compute_h(spec_st, code, wave_type='S'):
118121

119122
def _check_data_len(config, trace):
120123
traceId = trace.get_id()
121-
122124
trace_cut = trace.copy()
123-
t1 = trace.stats.arrivals['S1'][1]
124-
t2 = trace.stats.arrivals['S2'][1]
125+
if config.wave_type[0] == 'S':
126+
t1 = trace.stats.arrivals['S1'][1]
127+
t2 = trace.stats.arrivals['S2'][1]
128+
elif config.wave_type[0] == 'P':
129+
t1 = trace.stats.arrivals['P1'][1]
130+
t2 = trace.stats.arrivals['P2'][1]
125131
trace_cut.trim(starttime=t1, endtime=t2, pad=True, fill_value=0)
126132
npts = len(trace_cut.data)
127133
if npts == 0:
@@ -130,7 +136,7 @@ def _check_data_len(config, trace):
130136
raise RuntimeError(msg)
131137
nzeros = len(np.where(trace_cut.data == 0)[0])
132138
if nzeros > npts/4:
133-
msg = '{}: S-wave window is zero for more than 25%: skipping trace'
139+
msg = '{}: Signal window is zero for more than 25%: skipping trace'
134140
msg = msg.format(traceId)
135141
raise RuntimeError(msg)
136142

@@ -147,8 +153,12 @@ def _cut_signal_noise(config, trace):
147153
_time_integrate(config, trace_noise)
148154

149155
# trim...
150-
t1 = trace.stats.arrivals['S1'][1]
151-
t2 = trace.stats.arrivals['S2'][1]
156+
if config.wave_type[0] == 'S':
157+
t1 = trace.stats.arrivals['S1'][1]
158+
t2 = trace.stats.arrivals['S2'][1]
159+
elif config.wave_type[0] == 'P':
160+
t1 = trace.stats.arrivals['P1'][1]
161+
t2 = trace.stats.arrivals['P2'][1]
152162
trace_signal.trim(starttime=t1, endtime=t2, pad=True, fill_value=0)
153163
# Noise time window for weighting function:
154164
noise_t1 = trace.stats.arrivals['N1'][1]
@@ -188,21 +198,37 @@ def _check_noise_level(trace_signal, trace_noise):
188198
raise RuntimeError(msg)
189199

190200

201+
# store log messages to avoid duplicates
202+
velocity_log_messages = []
203+
204+
191205
def _displacement_to_moment(stats, config):
192206
"""
193207
Return the coefficient for converting displacement to seismic moment.
194208
195209
From Aki&Richards,1980
196210
"""
197-
vs_hypo = config.hypo.vs
198-
vs_station = get_vel(
211+
phase = config.wave_type[0]
212+
if phase == 'S':
213+
v_hypo = config.hypo.vs
214+
elif phase == 'P':
215+
v_hypo = config.hypo.vp
216+
v_station = get_vel(
199217
stats.coords.longitude, stats.coords.latitude, -stats.coords.elevation,
200-
'S', config)
201-
vs_hypo *= 1000.
202-
vs_station *= 1000.
203-
vs3 = vs_hypo**(5./2) * vs_station**(1./2)
204-
rps = get_radiation_pattern_coefficient(stats, config)
205-
coeff = 4 * math.pi * vs3 * config.rho / (2 * rps)
218+
phase, config)
219+
specid = '.'.join((
220+
stats.network, stats.station, stats.location, stats.channel))
221+
msg = '{}: V{}_hypo: {:.2f} km/s, V{}_station: {:.2f} km/s'.format(
222+
specid, phase.lower(), v_hypo, phase.lower(), v_station)
223+
global velocity_log_messages
224+
if msg not in velocity_log_messages:
225+
logger.info(msg)
226+
velocity_log_messages.append(msg)
227+
v_hypo *= 1000.
228+
v_station *= 1000.
229+
v3 = v_hypo**(5./2) * v_station**(1./2)
230+
rp = get_radiation_pattern_coefficient(stats, config)
231+
coeff = 4 * math.pi * v3 * config.rho / (2 * rp)
206232
return coeff
207233

208234

@@ -399,7 +425,7 @@ def build_spectra(config, st):
399425
"""
400426
Build spectra and the spec_st object.
401427
402-
Computes S-wave (displacement) spectra from
428+
Computes P- or S-wave (displacement) spectra from
403429
accelerometers and velocimeters, uncorrected for attenuation,
404430
corrected for instrumental constants, normalized by
405431
hypocentral distance.

sourcespec/ssp_data_types.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ def _check_minmax(self, minmax):
9393
return minmax
9494

9595
def _Qo_to_t_star(self):
96-
travel_time = self.spec.stats.travel_times['S']
96+
phase = self.config.wave_type[0]
97+
travel_time = self.spec.stats.travel_times[phase]
9798
t_star_bounds = travel_time/self.config.Qo_min_max
9899
return sorted(t_star_bounds)
99100

sourcespec/ssp_inversion.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ def _spec_inversion(config, spec, spec_weight):
274274

275275
# additional parameters, computed from fc, Mw and t_star
276276
vs = config.vs_source
277-
travel_time = spec.stats.travel_times['S']
277+
travel_time = spec.stats.travel_times[config.wave_type[0]]
278278
# seismic moment
279279
par['Mo'] = mag_to_moment(par['Mw'])
280280
# source radius in meters

sourcespec/ssp_parse_arguments.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ def _get_description(progname):
3838
if progname == 'source_spec':
3939
nargs = '+'
4040
description = 'Estimation of seismic source parameters from '
41-
description += 'inversion of S-wave spectra.'
41+
description += 'inversion of P- or S-wave displacement spectra.'
4242
epilog = ''
4343
elif progname == 'source_model':
4444
nargs = '*'
45-
description = 'Direct modeling of S-wave spectra.'
45+
description = 'Direct modeling of P- or S-wave displacement spectra.'
4646
epilog = 'Several values of moment magnitude, seismic moment, t-star\n'
4747
epilog += 'and alpha can be specified using a comma-separated list,'
4848
epilog += 'eg.:\n'

sourcespec/ssp_plot_traces.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,14 @@ def _plot_trace(config, trace, ntraces, tmax,
198198
ax.add_patch(rect)
199199
except KeyError:
200200
pass
201-
# S-wave window
202-
S1 = trace.stats.arrivals['S1'][1] - trace.stats.starttime
203-
S2 = trace.stats.arrivals['S2'][1] - trace.stats.starttime
204-
rect = patches.Rectangle((S1, 0), width=S2-S1, height=1,
201+
# Signal window
202+
if config.wave_type[0] == 'S':
203+
t1 = trace.stats.arrivals['S1'][1] - trace.stats.starttime
204+
t2 = trace.stats.arrivals['S2'][1] - trace.stats.starttime
205+
elif config.wave_type[0] == 'P':
206+
t1 = trace.stats.arrivals['P1'][1] - trace.stats.starttime
207+
t2 = trace.stats.arrivals['P2'][1] - trace.stats.starttime
208+
rect = patches.Rectangle((t1, 0), width=t2-t1, height=1,
205209
transform=trans, color='yellow',
206210
alpha=0.5, zorder=-1)
207211
ax.add_patch(rect)
@@ -236,7 +240,7 @@ def _add_labels(axes, plotn, ncols):
236240

237241
def _trim_traces(config, st):
238242
for trace in st:
239-
t1 = (trace.stats.arrivals['P'][1] - config.pre_p_time)
243+
t1 = (trace.stats.arrivals['P'][1] - config.noise_pre_time)
240244
t2 = (trace.stats.arrivals['S'][1] + 3 * config.win_length)
241245
trace.trim(starttime=t1, endtime=t2, pad=True, fill_value=0)
242246

0 commit comments

Comments
 (0)