Pure-qP VTI / TTI: forward, adjoint and Born equations¶
AcousticVTI / AcousticTTI implement the decoupled pure-qP equation with the
"new acoustic approximation" of Liang, Cao, Sun and Yin (2023, Geophysics
88(1), WA335, doi:10.1190/geo2022-0292.1).
AcousticVTILSRTM / AcousticTTILSRTM are their Born (LSRTM) equations. This
page writes down the three operators the code implements: the forward step, its
adjoint (the FWI gradient) and the Born equation. A worked example, RTM and LSRTM
of a tilted anisotropic bed, is the notebook
LSRTM · pure-qP VTI / TTI.
Forward¶
Setting the qSV phase velocity to zero in every direction (rather than only along the symmetry axis, as Alkhalifah's acoustic approximation does) gives a dispersion relation without qSV branch. In the wavenumber domain (paper eqs 12-14)
\(S_k\) depends only on the direction of the wavenumber, so this operator is linear in \(P\). In TTI media (appendix A, eq. A-7), with \(c = \cos\theta\), \(s = \sin\theta\) and \(S_k\) evaluated in the rotated frame \(k_x' = k_x c - k_z s\), \(k_z' = k_x s + k_z c\):
The space-domain scheme (eqs 15-23) replaces the wavenumber direction by the gradient direction of the wavefield, \(\mathbf{n} = \nabla P/|\nabla P|\):
(\(S_n\) is homogeneous of degree 0, so \(\nabla P\) can stand in for \(\mathbf n\);
the \(10^{-26}\) keeps it finite where \(\nabla P = 0\)). With the second-order CPML
of Acoustic written out per axis, one step of the code is
(and the same along \(z\)), \(m = D_z(p_x)\) for the tilted mixed derivative, and
\(A = 1+2\varepsilon,\ C = 1,\ E = 0\) (VTI) or \(A = (1+2\varepsilon)c^2 + s^2,\ C = (1+2\varepsilon)s^2 + c^2,\ E = 2\varepsilon\sin2\theta\) (TTI), with \(S_n\) evaluated on the CPML-corrected \((p_x, p_z)\).
Stability. The step is explicit, and the paper's appendix B gives its condition for VTI (eqs. B-8 to B-10):
with \(S_m\) the \(S\) of the Nyquist corner and \(c_{2m}\) the second-derivative
coefficients. For TTI the rotation mixes the two axes, so both take the
operator's largest coefficient, \(1+2\varepsilon+\max(S,0)\) -- over the
directions \(S\) peaks at \((\delta-\varepsilon)/(\sqrt{1+2\varepsilon}+1+\delta)\) --
a bound from the safe side. PropTorch evaluates the condition on every cell
before a forward and warns once when dt breaks it
(sweep.equations.qP_vti.qp_stability_ratio); the run is not stopped.
Adjoint (FWI gradient) and s_gradient¶
Through \(S_n(\nabla P)\) the discrete step is nonlinear in \(P\). Its exact derivative is the transpose of the step linearised about the forward state of the same step. Write \(g = V^2\Delta t^2\lambda^{n+1}\) and \(Q_{x,z} = (L^{\rm pml}_x + L^{\rm pml}_z)\,\partial S_n/\partial p_{x,z}\). The adjoint of the bracket is
and it flows through the CPML exactly as the acoustic adjoint does:
with \(L^{\top} = L\) (symmetric taps) and \(D^{\top} = -D\). The model gradients of step \(n\) are \(\lambda^{n+1}\) times the derivative of the bracket, e.g. for VTI
(\(R\) the bracket; TTI adds the \(\theta\) derivatives of \(A\), \(C\), \(E\) and of \(S_n\) through the rotation).
That exact gradient is ill-conditioned. \(\partial S_n/\partial p \sim 1/|\nabla P|\) and \(Q \sim |\Sigma|/|\nabla P|\) does not shrink with the amplitude (\(S_n\) is homogeneous of degree 0), so the adjoint carries O(1) coefficients set by the direction of weak parts of the wavefield, which fp32 rounding decides. Measured on the canonical gradient test (48 x 56, \(\varepsilon > \delta\)): eager fp32 and eager fp64 differ by 2-3 %, two eager fp32 runs on one GPU do not agree bit for bit, and a 20 m/s finite-difference check of the fp64 gradient is off by 21 % (5 % at 5 m/s). With \(\varepsilon = \delta\) (\(S_n \equiv 0\)) the same comparison agrees to \(10^{-7}\). This, not the CPML, is why eager boundary saving was refused for these equations: any reconstruction round-off moves the gradient by several percent.
s_gradient picks the adjoint (AcousticVTI, AcousticTTI and the Born pair;
the forward is identical in all three):
s_gradient |
adjoint propagation | model gradient | conditioning |
|---|---|---|---|
'adjoint' (default) |
the qP operator with \(S_n\) of the adjoint field's own gradient: the adjoint of the wavenumber-domain eq. 14 is the same operator, so back-propagated residuals travel with their own anisotropic kinematics | \(S_n\), \(S_\varepsilon\), \(S_\delta\), \(S_\theta\) of the forward field | nonlinear in \(\lambda\): fp32 floor \(\sim\)3e-3 (model gradients), \(\sim\)3e-2 (wavelet) |
'frozen' |
transpose of the step with \(S_n\) held at the forward field (no \(Q\)) | same | linear in \(\lambda\): rounding only, \(\le\)1e-4 |
'exact' |
the exact transpose above (with \(Q\)) | same | percent-level floor; memory=Full() only |
'frozen' carries the adjoint with the incident wave's direction, and where
the forward field has passed and is weak (\(S_n \to 0\)) elliptically. For the
Born pair it is worse: at \(m_p = 0\) the scattered field is zero, so 'frozen'
and 'exact' back-propagate the residual elliptically (\(\delta\) lost) in the
first LSRTM iteration. Hence the default.
impl='c'¶
qp_vti2d / qp_tti2d (and qp_vti_lsrtm2d / qp_tti_lsrtm2d) run the same
discretisation. The adjoint step is two launches: the state-dependent
coefficients, the CPML adjoints of the own cell and the fused model gradient,
then the transposed stencils. Because the backward needs the forward state of
step \(n+1\) at reverse step \(n\) (in 'frozen' / 'exact' the adjoint
coefficients themselves, in every mode the imaging terms near the CPML):
memory=Full()stores \((P, \psi_x, \psi_z, \zeta_x, \zeta_z)\) per step (5 grids; the Born pair: the scattered state and the background update, 6);memory=BoundarySaving(...)stores the same five fields on the whole CPML frame -- the absorbing pad plus \(M+1\) cells of the physical box, all four faces, corners included (cuda_layout.boundary_frame) -- and rebuilds \(P\) in the deep interior by reverse stepping; fp32 / fp16 / bf16 on gpu, cpu or disk (int8 is refused, see below). In'adjoint'and'frozen'mode it reproduces the full-storage gradient to \(\le\)2e-4 (fp32);'exact'is refused.- No checkpointing, no domain decomposition, no free surface.
Measured against eager on V100 (canonical 48 x 56 and 72 x 90 / 420 steps,
orders 4 and 8, \(\varepsilon \gtrless \delta\), VTI and TTI): records 1e-6-2e-4
(the same as eager on CPU against eager on GPU); 'frozen' gradients
1e-5-1e-3 in full and fp32 boundary saving (the strict element-wise criterion
of backend_gradient_matrix.py holds wherever eager-cpu against eager-gpu
holds); 'adjoint' gradients within eager's own gpu/cpu spread. int8 boundary
storage is refused: \(S_n\) depends on the direction of \(\nabla P\) only, so the
quantised frame turns into direction errors of the rebuilt field, and the
gradients move by 8-15 % away from the source.
Born equation (LSRTM)¶
Perturb the model, \(V \to V + \delta V\) (likewise \(\varepsilon, \delta, \theta\)), and the wavefield, \(P = P_0 + \delta P\), in the linear wavenumber-domain equation above. Writing it as \(P_{tt} = V^2\mathcal L[\varepsilon,\delta,\theta]\,P\), the first-order terms give
For velocity LSRTM with the reflectivity \(m_p = 2\,\delta V/V\) (as
AcousticLSRTM):
the scattered field obeys the same qP operator as the background, driven by \(m_p\) times the background's \(V^2\mathcal L P_0\) (\(= \partial_t^2 P_0\) away from the source). In VTI, \(\delta_\varepsilon\mathcal L = 2\partial_{xx} + \partial_\varepsilon S_k(\partial_{xx}+\partial_{zz})\) and \(\delta_\delta\mathcal L = \partial_\delta S_k(\partial_{xx}+\partial_{zz})\) give the extra scattering sources of a multi-parameter Born, not implemented here.
In the space domain each field evaluates the anisotropy operator on its own gradient: \(S_n(\nabla P_0)\) in the background step and in the scattering source, \(S_n(\nabla\delta P)\) in the scattered step:
\(\mathcal L_h[Q]\) being the bracket of the forward step with \(S_n(\nabla Q)\) and
the CPML memories of \(Q\). This is what AcousticVTILSRTM / AcousticTTILSRTM
step (qP_lsrtm.py; source on h1, receivers on sh1).
Why not linearise the space-domain step instead. Linearising \(\mathcal L_h[P_0 + \delta P]\) in \(\delta P\) gives \(\mathcal L_h[P_0] + J(P_0)\,\delta P\) with
It carries the scattered wave with the incident wave's direction
\(S_n(\nabla P_0)\), plus a correction of size \(|\Sigma_0|/|\nabla P_0| \sim k\) that
does not shrink with the incident amplitude (\(S_n\) is homogeneous of degree 0).
Behind the incident wavefront \(\nabla P_0 \to 0\), \(S_n(\nabla P_0) \to 0\) and \(J\)
propagates \(\delta P\) through an elliptical medium (\(\delta\) disappears). The
scattered wave of the true (nonlinear) space-domain model has the opposite
behaviour, \(S_n(\nabla(P_0 + \delta P)) \approx S_n(\nabla\delta P)\) wherever it
dominates. \(J\) is still the exact derivative of the discrete forward map, so it
is what the FWI gradient of AcousticVTI / AcousticTTI transposes; it is just
not a scattering propagator.
The Born map above is homogeneous of degree one in \(m_p\) (scaling \(m_p\) scales
the data) but, through \(S_n(\nabla\delta P)\), not exactly additive. With
\(\lambda_s\) the adjoint of the scattered field (propagated as s_gradient
says; by default with its own \(S_n\)),
impl='c' returns this reflectivity gradient only (the LSRTM case: background
models and wavelet without gradient); asking it for the background models' or
the wavelet's gradient raises, since those need the background adjoint --
impl='eager' returns them all.