Skip to content

SEM equations

The equation classes of sweep.sem.equations, all importable as sweep.sem.<Class>. A class is not constructed by hand: it is passed to PropSEM, which builds the mesh, interpolates the models onto its nodes and calls the class's build:

from sweep.sem import PropSEM, AcousticPotentialSEM2D

solver = PropSEM(AcousticPotentialSEM2D, shape=(141, 681), dh=25.0, dt=0.002)
seis = solver(wavelet, sources, receivers, models=[vp])

build(mesh, <models>, *, ...) is that call. Its positional arguments after the mesh are the models as element arrays (vp_e is vp at the GLL nodes of every element), in the order models= takes them, except rho on AcousticPotentialSEM2D, which PropSEM fills from density=. Its keywords are what PropSEM sets up from its own options, such as the free surface and the C-PML profile. The mesh family, the models, the CUDA kernels and the boundary-saving coverage of every class are in the SEM family table; sweep show <Class> prints the fields and the source and receiver types.

Registry

Equations are discovered, not listed: every class with field_specs in a module of sweep.sem.equations is one.

sweep.sem.equations.equation_classes

equation_classes() -> dict[str, type]

{class name: class} for every equation in this package.

sweep.sem.equations.summary

summary(cls) -> dict

What picks an equation, as data -- the columns of :func:describe.

mesh ("quad4", "quad9", "hex8" or "hex27"), ndim, topography (the mesh family admits one), cpml ("yes", "split" or "NO", see :func:describe), fields (the state, in order), sources and receivers (the fields a source drives and the receivers sample) and derived (the receiver components computed from those, such as p). sweep show prints it.

sweep.sem.equations.describe

describe() -> str

One line per equation: everything needed to pick one.

The columns exist because none of this is inferable from the class name. AcousticPotentialSEM2D has no "Deformed" in its name yet runs on a curved mesh and supports topography; ElasticVSSEM3D has none either and does not. And VS (velocity-stress) is a different FORMULATION, not a different mesh -- read it off the recorded fields: u_* is the 2nd-order displacement scheme, v_* the 1st-order velocity-stress one.

topo says the mesh family admits a topography; cpml says build() accepts an absorbing profile at all. An equation with cpml no is a reflecting box: PropSEM refuses an abcn for it.

Acoustic

The potential form (SPECFEM's) is the FWI workhorse: shot batching, per-shot models and batched boundary saving on impl='c' are there. Its build takes a density model; PropSEM gives it the constant density=. The other four take vp alone, one per mesh family.

sweep.sem.AcousticPotentialSEM2D

AcousticPotentialSEM2D(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    rho_e: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    dirichlet: tuple[str, ...],
    dirichlet_idx: Tensor,
    cpml: Optional[CPMLProfile],
    domain: Optional[DomainMask],
    _mask_e: Tensor,
    _alive: Tensor,
    kappa_node: Tensor,
    mass_geo: Tensor,
    _inv_M_geo: Tensor,
    _D: Tensor,
    _inv_rho: Tensor,
    _w_J: Tensor,
    _ixx: Tensor,
    _ixz: Tensor,
    _iex: Tensor,
    _iez: Tensor,
)

Bases: sweep.sem.fields.DerivedInitState, sweep.sem.fields.DirichletNodes

SPECFEM-normalized variable-density acoustic (potential χ) on Quad9.

build classmethod

build(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    rho_e: Tensor,
    *,
    dirichlet: tuple[str, ...] = ("top",),
    domain: Optional[DomainMask] = None,
    cpml: Optional[CPMLProfile] = None
) -> AcousticPotentialSEM2D

domain restricts the fluid to its acoustic elements: the operators are assembled over those only, and χ on nodes outside them is a dead DOF pinned to exactly 0 (inv_M = 0). None = the whole mesh is fluid.

cpml enables the double-convolution absorbing bands (potential flavor — the flux (1/ρ)∇χ rides inside the directional operators).

sweep.sem.AcousticSEM2D

AcousticSEM2D(
    mesh: Quad4Mesh,
    vp_e: Tensor,
    vp_squared_node: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    dirichlet: tuple[str, ...],
    dirichlet_idx: Tensor,
    cpml: Optional[CPMLProfile],
    _D: Tensor,
    _w_jx_noc2: Tensor,
    _w_jz_noc2: Tensor,
    _w_jac: Tensor,
    _inv_half_dx: float,
    _inv_half_dz: float,
)

Bases: sweep.sem.fields.DerivedInitState, sweep.sem.fields.DirichletNodes

Cached factors + ops for 2-D acoustic SEM on a :class:Quad4Mesh.

build classmethod

build(
    mesh: Quad4Mesh,
    vp_e: Tensor,
    *,
    dirichlet: tuple[str, ...] = ("top",),
    cpml: Optional[CPMLProfile] = None
) -> AcousticSEM2D

sweep.sem.AcousticSEM2DDeformed

AcousticSEM2DDeformed(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    vp_squared_node: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    dirichlet: tuple[str, ...],
    dirichlet_idx: Tensor,
    cpml: Optional[CPMLProfile],
    _D: Tensor,
    _w_J: Tensor,
    _ixx: Tensor,
    _ixz: Tensor,
    _iex: Tensor,
    _iez: Tensor,
)

Bases: sweep.sem.fields.DerivedInitState, sweep.sem.fields.DirichletNodes

Cached factors + ops for 2-D acoustic SEM on a :class:Quad9Mesh.

build classmethod

build(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    *,
    dirichlet: tuple[str, ...] = ("top",),
    cpml: Optional[CPMLProfile] = None
) -> AcousticSEM2DDeformed

sweep.sem.AcousticSEM3D

AcousticSEM3D(
    mesh: Hex8Mesh,
    vp_e: Tensor,
    vp_squared_node: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    dirichlet: tuple[str, ...],
    dirichlet_idx: Tensor,
    cpml: Optional[CPML3DProfile],
    _D: Tensor,
    _w_jx_noc2: Tensor,
    _w_jy_noc2: Tensor,
    _w_jz_noc2: Tensor,
    _w_jac: Tensor,
    _inv_half_dx: float,
    _inv_half_dy: float,
    _inv_half_dz: float,
)

Bases: sweep.sem.fields.DerivedInitState, sweep.sem.fields.DirichletNodes

Cached factors + ops for 3-D acoustic SEM on a :class:Hex8Mesh.

build classmethod

build(
    mesh: Hex8Mesh,
    vp_e: Tensor,
    *,
    dirichlet: tuple[str, ...] = ("top",),
    cpml: Optional[CPML3DProfile] = None
) -> AcousticSEM3D

sweep.sem.AcousticSEM3DDeformed

AcousticSEM3DDeformed(
    mesh: Hex27Mesh,
    vp_e: Tensor,
    vp_squared_node: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    dirichlet: tuple,
    dirichlet_idx: Tensor,
    cpml: Optional[CPML3DProfile],
    _D: Tensor,
    _w_J: Tensor,
    _I: tuple,
)

Bases: sweep.sem.fields.DerivedInitState, sweep.sem.fields.DirichletNodes

Cached factors + ops for 3-D acoustic SEM on a :class:Hex27Mesh.

build classmethod

build(mesh: Hex27Mesh, vp_e, *, dirichlet=('top',), cpml=None)

Elastic, displacement form

Second-order in time (SPECFEM's Newmark scheme); the source and receiver fields are u_x, u_z (and u_y). ElasticSEM2D, ElasticSEM3D and ElasticSEM3DDeformed model no C-PML: PropSEM refuses an abcn for them.

sweep.sem.ElasticSEM2D

ElasticSEM2D(
    mesh: Quad4Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    _D: Tensor,
    _w_lam2mu_Jx: Tensor,
    _w_lam: Tensor,
    _w_lam2mu_Jz: Tensor,
    _w_mu_Jz: Tensor,
    _w_mu: Tensor,
    _w_mu_Jx: Tensor,
)

Bases: sweep.sem.fields.DerivedInitState

Cached SEM operators for 2-D isotropic elastic on a :class:Quad4Mesh.

build classmethod

build(mesh: Quad4Mesh, vp_e: Tensor, vs_e: Tensor, rho_e: Tensor) -> ElasticSEM2D

sweep.sem.ElasticSEM2DDeformed

ElasticSEM2DDeformed(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    cpml: Optional[ElasticCPMLProfile],
    _D: Tensor,
    _lam: Tensor,
    _mu: Tensor,
    _lam2mu: Tensor,
    _w_J: Tensor,
    _w_rho_J: Tensor,
    _ixx: Tensor,
    _ixz: Tensor,
    _iex: Tensor,
    _iez: Tensor,
    domain: Optional[DomainMask] = None,
    _mask_e: Optional[Tensor] = None,
    _alive: Optional[Tensor] = None,
)

Bases: sweep.sem.fields.DerivedInitState

Elastic SEM on a deformed Quad9 mesh.

build classmethod

build(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    *,
    cpml: Optional[ElasticCPMLProfile] = None,
    domain: Optional[DomainMask] = None
) -> ElasticSEM2DDeformed

domain restricts the solid to its elastic elements (fluid–solid coupling): the operators are assembled over those only and u outside them is a dead DOF pinned to exactly 0. None = the whole mesh.

sweep.sem.ElasticSEM3D

ElasticSEM3D(
    mesh: Hex8Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    _D: Tensor,
    _w3: Tensor,
    _lam: Tensor,
    _mu: Tensor,
    _lam2mu: Tensor,
    _Gxx: float,
    _Gyy: float,
    _Gzz: float,
    _Gxy: float,
    _Gxz: float,
    _Gyz: float,
)

Bases: sweep.sem.fields.DerivedInitState

Cached SEM operators for 3-D isotropic elastic on a :class:Hex8Mesh.

build classmethod

build(mesh: Hex8Mesh, vp_e: Tensor, vs_e: Tensor, rho_e: Tensor) -> ElasticSEM3D

sweep.sem.ElasticSEM3DDeformed

ElasticSEM3DDeformed(
    mesh: Hex27Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    mass: Tensor,
    _inv_M: Tensor,
    _D: Tensor,
    _lam: Tensor,
    _mu: Tensor,
    _lam2mu: Tensor,
    _w_J: Tensor,
    _I: tuple,
)

Bases: sweep.sem.fields.DerivedInitState

Cached factors + ops for 3-D isotropic elastic SEM on a Hex27 mesh.

build classmethod

build(mesh: Hex27Mesh, vp_e, vs_e, rho_e) -> ElasticSEM3DDeformed

Elastic, velocity-stress form

First-order in time; the source and receiver fields are v_x, v_z (and v_y). The stresses are element-local, so they take no receivers.

sweep.sem.ElasticVSSEM2DDeformed

ElasticVSSEM2DDeformed(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    mass_rho: Tensor,
    _inv_M: Tensor,
    cpml: Optional[SimpleElasticCPMLProfile],
    free_top: bool,
    top_elem_ids: Tensor,
    _tx_top: Tensor,
    _tz_top: Tensor,
    _D: Tensor,
    _lam: Tensor,
    _mu: Tensor,
    _lam2mu: Tensor,
    _w_J: Tensor,
    _ixx: Tensor,
    _ixz: Tensor,
    _iex: Tensor,
    _iez: Tensor,
)

Bases: sweep.sem.fields.DerivedInitState

1st-order velocity-stress elastic SEM on a deformed Quad9 mesh.

build classmethod

build(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    *,
    free_top: bool = False,
    cpml: Optional[SimpleElasticCPMLProfile] = None
) -> ElasticVSSEM2DDeformed

Build the equation operators.

free_top=False (default) → natural free-surface BC, weakly imposed by dropping the boundary integral. free_top=True → strong essential BC (σ·n=0 in local coords at the top row).

sweep.sem.ElasticVTISEM2DDeformed

ElasticVTISEM2DDeformed(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    mass_rho: Tensor,
    _inv_M: Tensor,
    cpml: Optional[SimpleElasticCPMLProfile],
    free_top: bool,
    top_elem_ids: Tensor,
    _tx_top: Tensor,
    _tz_top: Tensor,
    _D: Tensor,
    _lam: Tensor,
    _mu: Tensor,
    _lam2mu: Tensor,
    _w_J: Tensor,
    _ixx: Tensor,
    _ixz: Tensor,
    _iex: Tensor,
    _iez: Tensor,
)

Bases: sweep.sem.equations.elastic_vs_deformed.ElasticVSSEM2DDeformed

VTI velocity-stress elastic SEM (vertical symmetry axis).

build classmethod

build(
    mesh: Quad9Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    epsilon_e: Tensor,
    delta_e: Tensor,
    *,
    free_top: bool = False,
    cpml: Optional[SimpleElasticCPMLProfile] = None
) -> ElasticVTISEM2DDeformed

Build a VTI equation. vp_e / vs_e are the vertical P / S velocities; epsilon_e / delta_e are the Thomsen parameters (all (E, ngll, ngll) GLL-node tensors).

sweep.sem.ElasticVSSEM3D

ElasticVSSEM3D(
    mesh: Hex8Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    mass_rho: Tensor,
    _inv_M: Tensor,
    cpml: Optional[SimpleElasticCPML3DProfile],
    _D: Tensor,
    _lam: Tensor,
    _mu: Tensor,
    _lam2mu: Tensor,
    _w3: Tensor,
    _wHx: Tensor,
    _wHy: Tensor,
    _wHz: Tensor,
    _inv_half_dx: float,
    _inv_half_dy: float,
    _inv_half_dz: float,
)

Bases: sweep.sem.fields.DerivedInitState

1st-order velocity-stress elastic SEM on an axis-aligned Hex8 mesh.

build classmethod

build(
    mesh: Hex8Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    *,
    cpml: Optional[SimpleElasticCPML3DProfile] = None
) -> ElasticVSSEM3D

sweep.sem.ElasticVSSEM3DDeformed

ElasticVSSEM3DDeformed(
    mesh: Hex8Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    mass_rho: Tensor,
    _inv_M: Tensor,
    cpml: Optional[SimpleElasticCPML3DProfile],
    _D: Tensor,
    _lam: Tensor,
    _mu: Tensor,
    _lam2mu: Tensor,
    _w3: Tensor,
    _wHx: Tensor,
    _wHy: Tensor,
    _wHz: Tensor,
    _inv_half_dx: float,
    _inv_half_dy: float,
    _inv_half_dz: float,
    _inv_J: Optional[Tensor] = None,
    _w_jac: Optional[Tensor] = None,
)

Bases: sweep.sem.equations.elastic_vs3d.ElasticVSSEM3D

Velocity-stress elastic on Hex27, with the per-GLL Jacobian chain rule.

build classmethod

build(
    mesh: Hex27Mesh,
    vp_e: Tensor,
    vs_e: Tensor,
    rho_e: Tensor,
    *,
    cpml: Optional[SimpleElasticCPML3DProfile] = None
) -> ElasticVSSEM3DDeformed

Coupled fluid-solid

An acoustic potential in the water over an elastic solid, with a C-PML on each; records chi, u_x, u_z and the derived p, vx, vz.

sweep.sem.AcousticElasticSEM2D

AcousticElasticSEM2D(
    mesh: Quad9Mesh,
    ac: AcousticPotentialSEM2D,
    el: ElasticSEM2DDeformed,
    ifc: FluidSolidInterface,
    domain: DomainMask,
    mass: Tensor,
    cpml: Optional[object] = None,
)

Bases: sweep.sem.fields.DerivedInitState

Fluid–solid coupled SEM. State: (χ, χ_prev, u_x, u_z, u_x_prev, u_z_prev).

build classmethod

build(
    mesh: Quad9Mesh,
    vp_e,
    vs_e,
    rho_e,
    *,
    dirichlet: tuple[str, ...] = ("top",),
    domain: Optional[DomainMask] = None,
    cpml_ac=None,
    cpml_el=None
) -> AcousticElasticSEM2D

domain defaults to SPECFEM's rule: an element is acoustic iff vs==0. cpml_ac (acoustic :class:CPMLProfile) and cpml_el (:class:ElasticCPMLProfile) enable the absorbing bands — both or neither. The interface may cross an X-only or Z-only band (plain coupling term there, SPECFEM-style); a corner region touching the interface is rejected at build time.

Poroelastic (Biot)

The FD sweep.equations.Biot on the spectral-element mesh: solid velocity and pore pressure on the continuous nodes, Darcy flux and total stress in the elements, with the same eight coefficients [H, mu, C, M, rho, rho_f, m, b] and the same source and receiver names. See Poroelastic waves (Biot).

sweep.sem.BiotVSSEM2DDeformed

BiotVSSEM2DDeformed(
    mesh: Quad9Mesh,
    H_e: Tensor,
    mu_e: Tensor,
    C_e: Tensor,
    M_e: Tensor,
    rho_e: Tensor,
    rho_f_e: Tensor,
    m_e: Tensor,
    b_e: tuple,
    dirichlet: tuple,
    dirichlet_idx: Tensor,
    viscous_q: Optional[tuple],
    mass_rho: Tensor,
    _inv_M: Tensor,
    _inv_Mm: Tensor,
    _inv_Mp: Tensor,
    _inv_M1: Tensor,
    _lam_d: Tensor,
    _alpha: Tensor,
    _solid_e: Tensor,
    _fluid_e: Tensor,
    _qmask: Tensor,
    ifc: FluidSolidInterface,
    _tau: tuple,
    _slot_idx: Tensor,
    _kmax: int,
    _wm: Tensor,
    _wr: Tensor,
    _wb: tuple,
    _share: Tensor,
    cpml: Optional[SimpleElasticCPMLProfile],
    _D: Tensor,
    _w_J: Tensor,
    _ixx: Tensor,
    _ixz: Tensor,
    _iex: Tensor,
    _iez: Tensor,
    source_mode: str = "load",
    _drag: tuple = None,
)

1st-order velocity-stress Biot poroelastic SEM on a deformed Quad9 mesh.

build classmethod

build(
    mesh: Quad9Mesh,
    H_e: Tensor,
    mu_e: Tensor,
    C_e: Tensor,
    M_e: Tensor,
    rho_e: Tensor,
    rho_f_e: Tensor,
    m_e: Tensor,
    b_e: Tensor,
    *,
    dirichlet: tuple = (),
    cpml: Optional[SimpleElasticCPMLProfile] = None,
    viscous_q: Optional[tuple] = None
) -> BiotVSSEM2DDeformed

Build the operators from the eight Biot coefficients at the GLL nodes; dirichlet names the open-pore sides, viscous_q = (Q0, f0) turns on the viscous attenuation.

sweep.sem.BiotAnisoPermSEM2DDeformed

BiotAnisoPermSEM2DDeformed(
    mesh: Quad9Mesh,
    H_e: Tensor,
    mu_e: Tensor,
    C_e: Tensor,
    M_e: Tensor,
    rho_e: Tensor,
    rho_f_e: Tensor,
    m_e: Tensor,
    b_e: tuple,
    dirichlet: tuple,
    dirichlet_idx: Tensor,
    viscous_q: Optional[tuple],
    mass_rho: Tensor,
    _inv_M: Tensor,
    _inv_Mm: Tensor,
    _inv_Mp: Tensor,
    _inv_M1: Tensor,
    _lam_d: Tensor,
    _alpha: Tensor,
    _solid_e: Tensor,
    _fluid_e: Tensor,
    _qmask: Tensor,
    ifc: FluidSolidInterface,
    _tau: tuple,
    _slot_idx: Tensor,
    _kmax: int,
    _wm: Tensor,
    _wr: Tensor,
    _wb: tuple,
    _share: Tensor,
    cpml: Optional[SimpleElasticCPMLProfile],
    _D: Tensor,
    _w_J: Tensor,
    _ixx: Tensor,
    _ixz: Tensor,
    _iex: Tensor,
    _iez: Tensor,
    source_mode: str = "load",
    _drag: tuple = None,
)

Bases: sweep.sem.equations.biot_vs_deformed.BiotVSSEM2DDeformed

:class:BiotVSSEM2DDeformed with an anisotropic permeability: the drag eta kappa^-1 is the symmetric tensor [[b_xx, b_xz], [b_xz, b_zz]] (x right, z down), SPECFEM2D's kxx, kxz, kzz; build it with :func:sweep.equations.biot_params.biot_drag_tensor. The flux copies at a node then advance with both components coupled through the drag.

build classmethod

build(
    mesh: Quad9Mesh,
    H_e: Tensor,
    mu_e: Tensor,
    C_e: Tensor,
    M_e: Tensor,
    rho_e: Tensor,
    rho_f_e: Tensor,
    m_e: Tensor,
    b_xx_e: Tensor,
    b_xz_e: Tensor,
    b_zz_e: Tensor,
    *,
    dirichlet: tuple = (),
    cpml: Optional[SimpleElasticCPMLProfile] = None,
    viscous_q: Optional[tuple] = None
) -> BiotAnisoPermSEM2DDeformed

Build from the seven Biot coefficients and the three drag components at the GLL nodes.