Models, mechanisms, geometry and signals#
These utilities make axis, material, sampling and source conventions explicit. Model-building depths are generally kilometres, while the geographic Cartesian conversion functions take depths and offsets in metres. A six-component moment tensor uses NED; a rotated waveform vector uses ENU.
Only the objects listed here are included in the documented support surface. Additional helpers are catalogued in the advanced reference.
focal_mechanism#
- pygrnwang.focal_mechanism.check_convert_fm(focal_mechanism)[source]#
Convert a supported focal mechanism to six NED moment components.
- Parameters:
focal_mechanism (array_like) – Either [strike, dip, rake] in degrees; [M0, strike, dip, rake]; six NED components [Mnn, Mne, Mnd, Mee, Med, Mdd]; or [M0, six components]. Three angles imply unit moment; seven entries normalize the six-component shape to M0. Moments are in N m.
- Returns:
mt (list of float) – [Mnn, Mne, Mnd, Mee, Med, Mdd] in N m.
- Raises:
ValueError – The input length is not 3, 4, 6 or 7.
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions. A six-component input retains its magnitude. A seven-entry input uses the first value as M0 and normalizes the remaining shape; the shape must have nonzero scalar moment.
- pygrnwang.focal_mechanism.plane2mt(M0, strike, dip, rake)[source]#
Convert a double-couple mechanism to a NED moment tensor.
- Parameters:
M0 (float) – Scalar seismic moment in N m.
strike (float) – Strike angle in degrees clockwise from north.
dip (float) – Dip angle in degrees from horizontal.
rake (float) – Rake angle in degrees in the fault plane.
- Returns:
mt (numpy.ndarray) – Shape (6,), [Mnn, Mne, Mnd, Mee, Med, Mdd], in N m.
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions.
- pygrnwang.focal_mechanism.convert_mt_axis(mt, convert_flag)[source]#
Convert six moment components between NED and spherical RTP axes.
- Parameters:
mt (array_like) – Six NED moment components [Mnn, Mne, Mnd, Mee, Med, Mdd] in N m unless a coordinate flag specifies otherwise.
convert_flag (str) – Either ned2rtp or rtp2ned. RTP ordering is [Mrr, Mtt, Mpp, Mrt, Mrp, Mtp] with outward radial, colatitude and longitude axes.
- Returns:
converted (list or array_like) – Six components in the target ordering, retaining input physical units.
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions. An unrecognized flag currently returns the input unchanged; use only the documented flags.
- pygrnwang.focal_mechanism.tensor2full_tensor_matrix(mt, flag='ned')[source]#
Expand six symmetric tensor components into a full matrix.
- Parameters:
mt (array_like) – Six NED moment components [Mnn, Mne, Mnd, Mee, Med, Mdd] in N m unless a coordinate flag specifies otherwise.
flag (str, optional) – ned uses [Mnn, Mne, Mnd, Mee, Med, Mdd]; rtp uses [Mrr, Mtt, Mpp, Mrt, Mrp, Mtp]. Default: ‘ned’.
- Returns:
matrix (numpy.ndarray) – Shape (3, 3), with rows and columns in the selected axis order.
- Raises:
ValueError – flag is neither ned nor rtp.
- Return type:
ndarray
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions.
- pygrnwang.focal_mechanism.moment_from_moment_tensor(mt)[source]#
Compute scalar moment from the Frobenius norm of a NED tensor.
- Parameters:
mt (array_like) – Six NED moment components [Mnn, Mne, Mnd, Mee, Med, Mdd] in N m unless a coordinate flag specifies otherwise.
- Returns:
moment (float or numpy.ndarray) – sqrt((Mnn^2 + Mee^2 + Mdd^2 + 2*Mne^2 + 2*Mnd^2 + 2*Med^2)/2), in the input moment units. Component-first batches return one value per tensor.
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions.
- pygrnwang.focal_mechanism.cal_m0_from_mt(mt)[source]#
Compute scalar moment from the Frobenius norm of a NED tensor.
- Parameters:
mt (array_like) – Six NED moment components [Mnn, Mne, Mnd, Mee, Med, Mdd] in N m unless a coordinate flag specifies otherwise.
- Returns:
moment (float or numpy.ndarray) – sqrt((Mnn^2 + Mee^2 + Mdd^2 + 2*Mne^2 + 2*Mnd^2 + 2*Med^2)/2), in the input moment units. Component-first batches return one value per tensor.
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions.
- pygrnwang.focal_mechanism.mt2plane(mt)[source]#
Extract two nodal planes and principal axes from a NED moment tensor.
- Parameters:
mt (array_like) – Six NED moment components [Mnn, Mne, Mnd, Mee, Med, Mdd] in N m unless a coordinate flag specifies otherwise.
- Returns:
result (list) – [plane1, plane2, n1, d1, n2, d2, t, b, p, eigenvalues]. Each plane is [strike, dip, rake] in degrees; each vector has shape (3,) in NED. Eigenvalues retain the input moment units.
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions. For non-double-couple tensors, the planes describe the extracted orientation; they do not reconstruct arbitrary isotropic or CLVD contributions. Repeated eigenvalues make orientation nonunique.
- pygrnwang.focal_mechanism.plane2nd(strike, dip, rake)[source]#
Compute the fault normal and slip unit vectors in NED coordinates.
- Parameters:
strike (float) – Strike angle in degrees clockwise from north.
dip (float) – Dip angle in degrees from horizontal.
rake (float) – Rake angle in degrees in the fault plane.
- Returns:
n, d (numpy.ndarray) – Two shape-(3,) vectors; n is oriented upward (nonpositive down component).
- Return type:
Tuple[ndarray, ndarray]
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions.
- pygrnwang.focal_mechanism.plane2tbp(strike, dip, rake)[source]#
Compute tension, neutral and pressure axes for a double couple.
- Parameters:
strike (float) – Strike angle in degrees clockwise from north.
dip (float) – Dip angle in degrees from horizontal.
rake (float) – Rake angle in degrees in the fault plane.
- Returns:
t, b, p (numpy.ndarray) – Three shape-(3,) NED unit vectors, each oriented into the lower hemisphere.
- Return type:
Tuple[ndarray, ndarray, ndarray]
Notes
See the scientific conventions guide. NED means north, east, down; waveform output uses different axis conventions.
geo#
- pygrnwang.geo.rotate_2d_points(points, degree)[source]#
Rotate Cartesian point rows counterclockwise in their plane.
- Parameters:
points (numpy.ndarray) – Point coordinates with shape (N, 2), in any consistent length unit.
degree (float) – Counterclockwise rotation angle in degrees.
- Returns:
rotated (numpy.ndarray) – Shape (N, 2), retaining input coordinate units.
- Return type:
ndarray
- pygrnwang.geo.rotate_rtz_to_enz(az_in_deg, r, t, z)[source]#
Rotate radial, transverse, up components to east, north, up.
- Parameters:
az_in_deg (float) – Source-to-receiver azimuth in degrees clockwise from north.
r (float or numpy.ndarray) – Radial component, positive away from the source along the surface.
t (float or numpy.ndarray) – Transverse component, positive counterclockwise from radial when viewed from above.
z (float or numpy.ndarray) – Vertical component, positive up; use the same shape and unit as r and t.
- Returns:
enz (numpy.ndarray) – Shape (3,) for scalar components or (3, N) for time series.
Notes
E = R*sin(az) - T*cos(az); N = R*cos(az) + T*sin(az); U = Z. No vertical sign reversal is performed.
- pygrnwang.geo.create_rotate_z_mat(gamma)[source]#
Construct a Cartesian rotation matrix about the third axis.
- Parameters:
gamma (float) – Rotation angle in radians.
- Returns:
rotation (numpy.ndarray) – Shape (3, 3), [[cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1]].
- pygrnwang.geo.rotate_symmetric_tensor_series(tensor, gamma)[source]#
Transform symmetric tensor series with R.T @ tensor @ R.
- Parameters:
tensor (numpy.ndarray) – Shape (N, 6), each row [xx, xy, xz, yy, yz, zz]; off-diagonal strains are tensor components, not doubled engineering strains.
gamma (float) – Rotation angle in radians.
- Returns:
rotated (numpy.ndarray) – Shape (N, 6), in the same component ordering and units as tensor.
Notes
gamma is in radians; the function does not infer a physical NED/ENU convention.
- pygrnwang.geo.geo_2_r_earth(lat, lon, dep, r0=6371000)[source]#
Convert spherical geographic coordinates to Earth-centered Cartesian metres.
- Parameters:
lat (float) – Latitude in degrees.
lon (float) – Longitude in degrees.
dep (float) – Depth in metres, positive down.
r0 (float, optional) – Reference spherical Earth radius in metres. Default: 6371000.
- Returns:
position (numpy.ndarray) – Shape (3,), x/y/z in metres.
Notes
Uses a sphere, not an ellipsoid. Unlike Green-library depths, dep is in metres.
- pygrnwang.geo.r_earth_2_geo(r_earth, r0=6371000)[source]#
Convert Earth-centered Cartesian metres to spherical geographic coordinates.
- Parameters:
r_earth (array_like) – Earth-centered Cartesian position, shape (3,), in metres.
r0 (float, optional) – Reference spherical Earth radius in metres. Default: 6371000.
- Returns:
location (numpy.ndarray) – [latitude in degrees, longitude in degrees, depth in metres].
Notes
Uses a sphere; longitude is wrapped to the interval [-180, 180].
- pygrnwang.geo.convert_axis_delta_geo2ned(lat0, lon0, dep0, lat1, lon1, dep1)[source]#
Project an Earth-centered chord into the reference local NED frame.
- Parameters:
lat0 (float) – Reference latitude in degrees.
lon0 (float) – Reference longitude in degrees.
dep0 (float) – Reference depth in metres, positive down.
lat1 (float) – Target latitude in degrees.
lon1 (float) – Target longitude in degrees.
dep1 (float) – Target depth in metres, positive down.
- Returns:
offset (numpy.ndarray) – Shape (3,), north, east, down in metres.
Notes
This is a Cartesian chord projection on a spherical Earth, not a surface-distance formula.
- pygrnwang.geo.convert_axis_delta_ned2geo(lat0, lon0, dep0, r_ned)[source]#
Convert a local NED Cartesian offset to spherical geographic coordinates.
- Parameters:
lat0 (float) – Reference latitude in degrees.
lon0 (float) – Reference longitude in degrees.
dep0 (float) – Reference depth in metres, positive down.
r_ned (array_like) – Local Cartesian north, east, down displacement from the reference point, shape (3,), in metres.
- Returns:
location (numpy.ndarray) – [latitude in degrees, longitude in degrees, depth in metres].
signal_process#
- pygrnwang.signal_process.taper(data, taper_length=None, max_percentage=0.05)[source]#
Apply a Hann taper to both ends of a one-dimensional trace.
- Parameters:
data (numpy.ndarray) – One-dimensional uniformly sampled signal; input is not modified.
taper_length (int or None, optional) – Number of samples tapered at each end. None uses max(2, round(len(data)*max_percentage)); keep within the signal length. Default: None.
max_percentage (float, optional) – Fraction of trace length used at each tapered end when taper_length is None. Default: 0.05.
- Returns:
tapered (numpy.ndarray) – Same shape and units as the input.
- Raises:
ValueError – The taper does not fit the trace.
- Return type:
ndarray
Notes
The function copies the input. For very short traces, supply a compatible explicit taper_length.
- pygrnwang.signal_process.cal_sos(srate, freq_band, butter_order=4)[source]#
Design lowpass, highpass or bandpass Butterworth second-order sections.
- Parameters:
srate (float) – Positive output sampling rate in Hz.
freq_band (sequence of float or None) – Two cutoff frequencies [low, high] in Hz. None disables filtering in readers; a missing corner selects lowpass or highpass.
butter_order (int, optional) – Butterworth filter order. Default: 4.
- Returns:
sos (numpy.ndarray or None) – Shape (number_of_sections, 6); None means that no filtering is needed.
- Raises:
ValueError – Requested filter order or nonzero cutoff frequencies are invalid.
Notes
Supply a two-element freq_band. None or zero at a corner means no cutoff there. A high corner at or above Nyquist is ignored; a nonzero low corner then selects highpass.
- pygrnwang.signal_process.filter_butter(data, srate, freq_band, butter_order=4, zero_phase=False)[source]#
Filter an array along its last axis with a Butterworth filter.
- Parameters:
data (numpy.ndarray) – Signal array; filtering acts along the final axis. The input is copied.
srate (float) – Positive output sampling rate in Hz.
freq_band (sequence of float or None) – Two cutoff frequencies [low, high] in Hz. None disables filtering in readers; a missing corner selects lowpass or highpass.
butter_order (int, optional) – Butterworth filter order. Default: 4.
zero_phase (bool, optional) – True applies forward/backward filtering; False uses causal filtering. Default: False.
- Returns:
filtered (numpy.ndarray) – Same shape and units as data; a copy is returned even when filtering is disabled.
- Raises:
ValueError – Filter parameters are invalid or the trace is too short for zero-phase padding.
Notes
Unlike the reader wrappers, this function requires a two-element freq_band; use [None, None] to disable it. Forward/backward filtering requires enough samples for padding.
- pygrnwang.signal_process.resample(data, srate_old, srate_new, zero_phase=True)[source]#
Resample a one-dimensional signal with rate-dependent antialias handling.
- Parameters:
data (numpy.ndarray) – One-dimensional uniformly sampled signal; input is not modified.
srate_old (float) – Original positive sampling rate in Hz.
srate_new (float) – Desired positive sampling rate in Hz.
zero_phase (bool, optional) – True applies forward/backward filtering; False uses causal filtering. Default: True.
- Returns:
resampled (numpy.ndarray) – One-dimensional output at srate_new; length is determined by the selected SciPy method (polyphase uses a ceiling, FFT uses the requested rounded length).
- Raises:
ValueError – Rates or resulting filter parameters are invalid, or zero-phase padding cannot fit.
Notes
With zero_phase=True, integer sampling rates use polyphase resampling; other rates use FFT resampling followed by filtering. With zero_phase=False, integer downsampling uses causal FIR decimation. See the signal-processing guide.
- pygrnwang.signal_process.linear_interp(data, N_new)[source]#
Resample a trace by linear interpolation while preserving both endpoints.
- Parameters:
data (numpy.ndarray) – One-dimensional uniformly sampled signal; input is not modified.
N_new (int) – Number of output samples; must be positive.
- Returns:
interpolated (numpy.ndarray) – Shape (N_new,), retaining the signal units.
- Raises:
ValueError – The input is empty or N_new is invalid.
- Return type:
ndarray
Notes
This function supplies no antialias lowpass filter; use resample for sampled waveform rate changes.
utils#
- pygrnwang.utils.read_nd(path_nd, with_Q=False)[source]#
Read numeric rows from a named-discontinuity model.
- Parameters:
path_nd (str) – Path to a named-discontinuity text model with either four or six numeric columns as required by the operation.
with_Q (bool, optional) – True expects exactly six numeric columns; False expects four. The flag describes the file, it does not remove Q columns. Default: False.
- Returns:
model (numpy.ndarray) – Shape (N, 4) or (N, 6): depth km, Vp/Vs km/s, density g/cm3, and optional dimensionless Qp/Qs. Single-token discontinuity labels are skipped.
- Raises:
OSError – The model cannot be read.
ValueError – Numeric rows do not match the requested column layout.
- pygrnwang.utils.read_material_nd(model_name, depth)[source]#
Select the first material row at or below the requested depth.
- Parameters:
model_name (str) – TauP built-in model name or path to a custom model. Use a model consistent with the Green library.
depth (float) – Material lookup depth in km, positive down.
- Returns:
material (numpy.ndarray) – [depth km, Vp km/s, Vs km/s, density g/cm3]; below the model bottom, the final row is returned.
- Raises:
FileNotFoundError – model_name is neither ak135fc nor an existing model file.
Notes
This is a row selection, not interpolation. model_name accepts only the built-in ak135fc or a four-column no-Q ND file path; ak135 is not a material-lookup alias.
- pygrnwang.utils.read_layerd_material(path_layerd_dat, depth_in_km)[source]#
Read the material layer containing a depth from a thickness table.
- Parameters:
path_layerd_dat (str) – Text table of thickness (m), density, Vp, Vs, Qp, Qs; returned material values retain the file units.
depth_in_km (float) – Material lookup depth in km.
- Returns:
material (numpy.ndarray) – One row [thickness, density, Vp, Vs, Qp, Qs] in the file units; below the model bottom the final row is returned.
- Raises:
OSError – The table cannot be read.
- pygrnwang.utils.convert_earth_model_nd2inp(path_nd, path_output)[source]#
Convert ND numeric rows to numbered backend model input lines.
- Parameters:
path_nd (str) – Path to a named-discontinuity text model with either four or six numeric columns as required by the operation.
path_output (str) – Destination path for the converted model.
- Returns:
lines (list of str) – Numeric rows prefixed by a one-based row number and terminated by newlines.
- Raises:
OSError – The input model cannot be read.
Notes
path_output is retained for API compatibility but is not written by this function. Discontinuity labels are removed.
- pygrnwang.utils.convert_earth_model_nd2nd_without_Q(path_nd, path_output)[source]#
Write a four-column ND model by removing the final two Q columns.
- Parameters:
path_nd (str) – Path to a named-discontinuity text model with either four or six numeric columns as required by the operation.
path_output (str) – Destination path for the converted model.
- Returns:
lines (list of str) – The exact converted lines written to path_output, with labels retained.
- Raises:
OSError – Input or output cannot be accessed.
Notes
The input must have six numeric columns. Passing a four-column file removes real physical columns and is invalid.
- pygrnwang.utils.create_stf(tau, srate)[source]#
Sample a normalized squared half-sine source-rate function.
- Parameters:
tau (float) – Positive source duration in seconds.
srate (float) – Positive output sampling rate in Hz.
- Returns:
stf (numpy.ndarray) – Shape (round(tau*srate)+1,), samples of 2/tau * sin(pi*t/tau)^2, in 1/s. Its continuous integral over [0, tau] is one.
Notes
The discrete integral depends on sampling; normalize explicitly when exact discrete convolution normalization is required.
- pygrnwang.utils.cal_grid(v_min, v_max, delta)[source]#
Construct the regular grid shared by writers and readers.
- Parameters:
v_min (float) – First grid value in any consistent unit.
v_max (float) – Minimum required terminal value, in the same unit as v_min.
delta (float) – Positive grid spacing in the same unit as v_min.
- Returns:
grid (numpy.ndarray)
- Raises:
ZeroDivisionError – delta is zero.
ValueError – Non-finite grid parameters prevent calculation of the sample count.
Notes
create_nd_by_crust1_ak135#
- pygrnwang.create_nd_by_crust1_ak135.create_nd_by_crust1_ak135(lat, lon, path_crust1, path_ak135, path_output, no_low_velo_layer=False, layered_crust=True)[source]#
Join a location-specific CRUST1.0 crust to an AK135 mantle model.
- Parameters:
lat (float) – Latitude in degrees.
lon (float) – Longitude in degrees.
path_crust1 (str) – Directory containing crust1.vp, crust1.vs, crust1.rho and crust1.bnds.
path_ak135 (str) – Six-column no-water AK135 ND file with Qp and Qs in the last columns.
path_output (str) – Destination path for the converted model.
no_low_velo_layer (bool, optional) – Remove conflicting shallow mantle rows to avoid an artificial low-velocity join. Default: False.
layered_crust (bool, optional) – True repeats interface depths to encode constant-property CRUST1 layers; False uses linear interpolation between layer tops. Default: True.
- Returns:
model (numpy.ndarray) – Shape (N, 6): depth km, Vp/Vs km/s, density g/cm3, Qp/Qs. The corresponding ND file is also written to path_output.
- Raises:
OSError – A required model file is unavailable.
ValueError – The CRUST1 columns lack suitable crust/mantle rows or increasing layer depths.
Notes
Water and upper sediments are omitted. CRUST1 rows use Qp=927.34 and Qs=599.99. The mantle label is placed for TauP compatibility; verify that it represents the intended model discontinuity.
crust1#
- class pygrnwang.crust1.CrustModel(path_crust1)[source]#
Load the nine-layer CRUST1.0 global one-degree model.
- Parameters:
path_crust1 (str) – Directory containing crust1.vp, crust1.vs, crust1.rho and crust1.bnds.
- Returns:
model (CrustModel) – Model arrays vp, vs, rho and bnds with shape (180, 360, 9).
- Raises:
OSError – One of the four CRUST1 files cannot be read.
ValueError – The model files do not contain the expected grid size.
Notes
Vp/Vs are km/s, density is g/cm3, and layer boundary elevations are km relative to sea level. Only get_point is part of the supported query interface.
- CrustModel.get_point(lat, lon)[source]#
Select the CRUST1.0 grid cell at a geographic location.
- Parameters:
lat (float) – Latitude in degrees.
lon (float) – Longitude in degrees.
- Returns:
layers (dict) – Layer names map to [Vp km/s, Vs km/s, density g/cm3, thickness km, top elevation km]. Layers thinner than 0.01 km are omitted except mantle.
Notes
Grid selection is nearest enclosing one-degree cell, without spatial interpolation. Depth is the negative of elevation.