Native Python API reference

The native Python API uses NumPy arrays throughout. Build and install the libswd extension before running numerical examples. HDF5 support also requires h5py.

For differentiable tensor computations without compiled extensions, see the PyTorch API reference and PyTorch backend.

Solver workspace

class specd.SpecWorkSpace(wavetype: str = None, has_att: bool = False)[source]

Bases: object

compute_dispersion(frequencies_hz: ndarray, azimuths_deg=0.0, include_group: bool = True)[source]

Compute a frequency/azimuth grid as a CSR dispersion table.

Mode counts may vary between solve points. Rows use frequency-major, azimuth-minor order and remain ordinary NumPy arrays.

compute_egn(freq: float, ang_in_deg=0.0, only_phase=False) → ndarray[source]

compute eigenvalues/eigenvectors

Parameters:
  • freq (float) – current frequency

  • ang_in_deg (float) – phase velocity azimuthal angle, in deg

  • only_phase (bool) – if False, only compute eigenvalues (phase velocities) if True, phase velocities and eigenfunctions will be computed

Returns:

c – phase velocities

Return type:

np.ndarray

get_egnfunc(imode: int, return_displ: bool, return_left=False)[source]

get eigenfunctions at current frequency/mode

Parameters:
  • imode (int) – mode number

  • return_left (bool) – if true, return left eigenvectors else return right eigenvectors

  • return_displ (bool) – if true, return displacement polarization amplitudes instead of eigenvectors. For VTI Rayleigh/Scholte waves, the horizontal and vertical amplitudes retain a real convention; the physical pi/2 phase offset of the vertical component is implicit. For example, the corresponding eigenvector is [u,v^{ar},chi^{ar}].

get_group_kl(imode: int)[source]

compute group velocity sensitivity kernels for mode {imode}

Parameters:

imode (int) – compute kernels at imode, imode elong [0,max_mode)

Returns:

  • frekl_c (np.ndarray) – group velocity kernels, shape(nkers,self._nz)

  • frekl_q (np.ndarray) – group velocity Q kernels,shape(nkers,self._nz), only returns when self._has_att = True

get_kernel_names()[source]

get names for Frechet derivative

Returns:

kl_name – list of kernel names

Return type:

list[str]

get_phase_kl(imode: int)[source]

compute phase velocity sensitivity kernels for mode {imode}

Parameters:

imode (int) – compute kernels at imode, imode elong [0,max_mode)

Returns:

  • frekl_c (np.ndarray) – phase velocity kernels, shape(nkers,self._nz)

  • frekl_q (np.ndarray) – phase velocity Q kernels,shape(nkers,self._nz), only returns when self._has_att = True

get_znodes()[source]

get mesh coordiantes, shape(nspec*NGLL+NGRL)

group_velocity()[source]

compute group velocites for each model at current frequency

Returns:

u – group velocities at current frequency. For general anisotropy, shape is (2, nmodes) with x and y components by row.

Return type:

float/complex

Note

before calling this routine, use_qz should be True in self.compute_egn

initialize(wavetype: str, z: ndarray, rho: ndarray, vph=None, vpv=None, vsh=None, vsv=None, eta=None, Qa=None, Qc=None, Qn=None, Ql=None, c21=None, Qani=None, qfunc_id=1, scale_rho=0.0, scale_v=0.0, scale_z=0.0, disp=False, reference_frequency=1.0)[source]

initialize working space for SEM

Parameters:
  • wavetype (str) – wavetype, one of [‘love’,’rayl’,’aniso’]

  • z (np.ndarray) – depth vector, should include discontinuities at half sapce

  • rho (np.ndarray) – density, shape_like(z)

  • vph/vpv/vsh/vsv (np.ndarray) – VTI parameters, shape_like(z)

  • Qa/Qc/Qn/Ql (np.ndarray) – VTI constant quality factors, shape_like(z)

  • c21 (np.ndarray) – 21 elastic tensor, shape(21,nz)

  • nQani (int) – no. of Q models for fully anisotropy

  • Qnai (np.ndarray) – quality factors, shape(nQnai,nz)

  • disp (bool) – if True print model information

  • reference_frequency (float) – frequency in Hz at which the input storage moduli (and therefore the real input velocities) are defined; default is 1 Hz

Note

The input parameters should be carefully chose by user. For Love wave, only vsh/vsv/Qsh/Qsv can be enabled, and for Rayleigh wave, only vph/vpv/vsv can ve enabled, and other params are for full anisotropy

CSR dispersion containers

class specd.ComplexCSR(indptr: ndarray, mode_index: ndarray, values: ndarray, component_names: Tuple[str, ...])[source]

Bases: object

Complex CSR rows indexed by solve point and local mode number.

component_names: Tuple[str, ...]
classmethod from_rows(rows: Sequence[ndarray], component_names: Sequence[str], mode_rows: Sequence[ndarray] | None = None) → ComplexCSR[source]

Pack variable-length NumPy rows into a CSR container.

indptr: ndarray
mode_index: ndarray
property nentry: int
property nrow: int
row(row: int) → Tuple[ndarray, ndarray][source]

Return (mode_index, values) as zero-copy NumPy views.

validate(nrow: int, name: str = 'csr') → None[source]
values: ndarray
class specd.DispersionTable(frequency_hz: ndarray, azimuth_deg: ndarray, phase_velocity: ComplexCSR, group_velocity: ComplexCSR | None = None, velocity_units: str = 'km/s')[source]

Bases: object

CSR dispersion data on a frequency/azimuth grid.

azimuth_deg: ndarray
frequency_hz: ndarray
classmethod from_hdf5(path) → DispersionTable[source]

Read and validate a version-1 SpecSWD CSR HDF5 file.

classmethod from_rows(frequency_hz, phase_rows: Sequence[ndarray], *, azimuth_deg=(0.0,), phase_mode_rows: Sequence[ndarray] | None = None, group_rows: Sequence[ndarray] | None = None, group_components: Sequence[str] = ('radial',), group_mode_rows: Sequence[ndarray] | None = None, velocity_units: str = 'km/s') → DispersionTable[source]

Create a table directly from variable-length solver outputs.

group_row(frequency_index: int, azimuth_index: int = 0) → Tuple[ndarray, ndarray][source]
group_velocity: ComplexCSR | None = None
property nsolve: int
phase_row(frequency_index: int, azimuth_index: int = 0) → Tuple[ndarray, ndarray][source]
phase_velocity: ComplexCSR
solve_row(frequency_index: int, azimuth_index: int = 0) → int[source]

Map grid indices to the frequency-major CSR row.

to_hdf5(path) → None[source]

Write schema-versioned CSR data using HDF5 compound complex values.

validate() → None[source]
velocity_units: str = 'km/s'

Complete solver output

class specd.RaggedComplexField(indptr: ndarray, values: ndarray, component_names: Tuple[str, ...], units: str = 'normalized')[source]

Bases: object

Variable-length complex samples with a fixed component dimension.

component_names: Tuple[str, ...]
indptr: ndarray
property nrow: int
row(row: int) → ndarray[source]

Return one field as a zero-copy (npoint,ncomponent) view.

units: str = 'normalized'
validate(nrow: int | None = None) → None[source]
values: ndarray
class specd.KernelTable(parameter_names: Tuple[str, ...], velocity: ndarray, propagation_q_inverse: ndarray | None = None)[source]

Bases: object

Projected kernels with shape (nmode,nparameter,ndepth).

parameter_names: Tuple[str, ...]
propagation_q_inverse: ndarray | None = None
velocity: ndarray
class specd.SolverOutput(dispersion: DispersionTable, wave_type: int, attenuation: bool, kernel_type: int, kernel_observable: str, model_depth: ndarray, sem_depth_indptr: ndarray, sem_depth_values: ndarray, eigenfunctions: RaggedComplexField, elastic_kernels: KernelTable | None = None, acoustic_kernels: KernelTable | None = None)[source]

Bases: object

Complete command-line result backed only by NumPy containers.

acoustic_kernels: KernelTable | None = None
attenuation: bool
dispersion: DispersionTable
eigenfunctions: RaggedComplexField
elastic_kernels: KernelTable | None = None
classmethod from_hdf5(path) → SolverOutput[source]

Read complete output written by a C++ or Python solver.

kernel_observable: str
kernel_type: int
model_depth: ndarray
sem_depth_indptr: ndarray
sem_depth_row(solve_row: int) → ndarray[source]

Return the physical SEM depth coordinates for one solve row.

sem_depth_values: ndarray
to_hdf5(path) → None[source]

Write the complete version-1 solver output.

validate() → None[source]
wave_type: int

Constant-Q helpers

specd.constant_q_response(freq, quality_factor, reference_frequency=1.0)[source]

Return M(omega) / M0 for storage modulus M0 at the reference.

The response uses the positive-frequency convention of SpecSWD:

s = (1 + i/Q) * (freq/reference_frequency)**alpha, alpha = 2/pi * atan(1/Q).

specd.constant_q_response_derivatives(freq, quality_factor, reference_frequency=1.0)[source]

Return s, ds/domega, ds/d(Q^-1), and the mixed derivative.

Thomson-Haskell comparison solver

class specd.THSolver(thick: ndarray, vp: ndarray, vs: ndarray, rho: ndarray, spherical: bool = False)[source]

Bases: object

compute_swd(wavetype: str, mode: int, T: ndarray) → ndarray[source]

compute dispersion (phase/group) for a give wavetype

Parameters:
  • wavetype (str) – wave type, one of [‘Rc’,’Rg’,’Lc’,’Lg’]

  • mode (int) – which mode it will return, >=0

  • T (np.ndarray) – period, in s

Returns:

cg – phase velocity (for Rc,Lc) or group velocity (Rg,Lg)

Return type:

np.ndarray