Skip to content

ElasticTTI2nd

sweep.equations.ElasticTTI2nd

ElasticTTI2nd(spatial_order=4, device='cpu', backend='torch', mpml_ratio=0.05)

Bases: sweep.equations.base.FirstOrderEquation

Displacement-based 2-D elastic TTI wave equation (Oh et al. 2020).

Second-order-in-time P-SV formulation rho u_tt = div(C~ : grad u) (GJI 223, eqs 11-12) with the hierarchical VTI parametrization of their eq. (19): horizontal P velocity vh, vertical S velocity vs, density, Thomsen epsilon, anellipticity eta and the tilt theta — all six differentiable. prepare_models builds the four VTI constants and Bond-rotates them (their eq. 10) into the six TTI entries consumed by the update, so autograd chains the stiffness gradients back to the physical parameters.

Differences from :class:ElasticTTI/:class:ElasticTTISG (first-order velocity-stress, 2-D-3C, 8 parameters): two displacement components only (no SH — no gamma/phi), vh/eta instead of vp0/delta, and a leapfrog second-order time stepping whose stiffness operator is discretely self-adjoint.

Models (constructor input order)

  • vh (m/s): Horizontal P-wave velocity (VTI frame).
  • vs (m/s): Vertical S-wave velocity.
  • rho (kg/m^3): Density.
  • epsilon: Thomsen epsilon.
  • eta: Anellipticity eta = (epsilon - delta) / (1 + 2 delta).
  • theta (rad): Tilt angle of the TI symmetry axis.

Wavefields

  • ux (aliases: displacement_x): Horizontal displacement; default receiver.
  • uz (aliases: displacement_z): Vertical displacement; default source and receiver.
  • ux_pre: Previous-step horizontal displacement (internal).
  • uz_pre: Previous-step vertical displacement (internal).
  • m_gxux: CPML memory for dux/dx (internal).
  • m_gzux: CPML memory for dux/dz (internal).
  • m_gxuz: CPML memory for duz/dx (internal).
  • m_gzuz: CPML memory for duz/dz (internal).
  • m_sxxx: CPML memory for dsxx/dx (internal).
  • m_sxzz: CPML memory for dsxz/dz (internal).
  • m_sxzx: CPML memory for dsxz/dx (internal).
  • m_szzz: CPML memory for dszz/dz (internal).

Defaults

  • source_type: ['uz']
  • receiver_type: ['ux', 'uz']
  • pml_type: 'cpmls'

Build the displacement-based 2-D elastic TTI operator.

Parameters:

  • spatial_order –

    FD accuracy order of the staggered first-derivative operator — e.g. spatial_order=4 is fourth-order accurate. Internally the half-stencil width is M = spatial_order // 2 (used for loop bounds and PML padding). Must be an even integer (2, 4, 6, 8, 10, …). Performance note (impl='c' on CUDA): the compiled kernels ship template specialisations only for spatial_order ∈ {2, 4, 6, 8}. Above 8 the dispatcher drops to a generic runtime path (order = -1 in src/sweep/csrc/cuda/equations/elastic_tti_2nd2d/forward.cu) which uses more registers and runs noticeably slower. The PyTorch eager path is unaffected. Defaults to 4.

  • device –

    Device for the operator's static gradient kernels. Use 'cuda' / a torch.device for GPU runs so the propagator can follow without a host↔device copy. Defaults to 'cpu'.

  • backend –

    Array / programming backend, 'torch' or 'jax'. When you later want impl='c', leave this on 'torch'. Defaults to 'torch'.

  • mpml_ratio –

    Multiaxial-PML mixing ratio (Li & Bou Matar 2010 eq. 23). Plain CPML is unstable for this second-order displacement system — see the module docstring — and this is the knob that fixes it: each damping profile receives this fraction of the other axis'. 0 restores the plain CPML and with it the late-time growth (envelope past the direct arrival at 9.6 s, NaN at 19.5 s on a uniform TTI medium). Larger values are safer but absorb worse: measured boundary artefact against a domain no reflection can reach is -56.3 dB at 0 (unstable), -53.2 dB at 0.05, -49.9 dB at 0.10, -44.5 dB at 0.25. Defaults to :data:DEFAULT_MPML_RATIO (0.05).

C_HAS_RECURSIVE_CKPT class-attribute

C_HAS_RECURSIVE_CKPT = False

bool(x) -> bool

Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.

C_NAME class-attribute

C_NAME = 'elastic_tti_2nd2d'

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.

prepare_models_for_c class-attribute

prepare_models_for_c = True

bool(x) -> bool

Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.

supports_free_surface class-attribute

supports_free_surface = False

bool(x) -> bool

Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.

init_abc

init_abc(type='cpml', **kwargs)

Build the CPML profiles, then mix them multiaxially.

The mix has to happen here rather than in step: that is exactly the property of the multiaxial layer that makes it cheap — the update never learns about it. The profiles come back as full 2-D fields even at mpml_ratio=0 so the compiled kernel has a single index path.

prepare_models

prepare_models(models)

(vh, vs, rho, epsilon, eta, theta) -> [rho] + 6 rotated stiffnesses.

VTI constants from Oh et al. (2020) eq. (19) — note C13 uses the NMO velocity vh^2/(1+2 eta) — then the closed-form 2-D Bond rotation of their eq. (10). Pure smooth tensor ops: autograd differentiates every physical parameter, including theta (no VTI-fallback masking needed — the polynomials are exact at theta = 0).