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.