Summary
examples/seismic/model.py documents the Thomsen parameters as
epsilon : Thomsen epsilon parameter (0<epsilon<1).
delta : Thomsen delta parameter (0<delta<1), delta<epsilon.
(model.py:265 on main, also in 4.8.22), but nothing checks delta<epsilon, and the pseudoacoustic TTI kernel in examples/seismic/tti/operators.py (kernel_centered, the Zhang, Zhang & Zhang 2011 form) is exponentially unstable whenever it is violated. A user who sets delta > epsilon anywhere in the model — a physically valid regime (negative anellipticity shales) — gets a blow-up with no diagnostic pointing at the cause.
Why it is unstable
This is not a discretisation or CFL problem; it is a property of the pseudoacoustic (V_Sz = 0) approximation itself. Bube et al. (2012, Geophysics 77(5) T171–T186, doi:10.1190/geo2011-0250.1) show that for every 2×2 second-order-in-time pseudoacoustic system the dispersion relation ω⁴ − Bω² + C = 0 has C = 2 V_Pz⁴ (ε−δ) k_h² k_z², so for ε < δ one ω² root is negative and the corresponding mode grows exponentially. Reducing dt does not help.
For kernel_centered specifically, with a = Gh and b = Gzz the symbols of the rotated operators (both ≤ 0), the 2×2 coupling matrix [[ (1+2ε)a, √(1+2δ) b ], [ √(1+2δ) a, b ]] has determinant 2(ε−δ)·a·b, which changes sign exactly at ε = δ.
Measured
Von Neumann analysis of the exact kernel_centered discrete operator (space_order=8, 2-D, constant coefficients, dt well inside the isotropic CFL limit), stability decided from the coupling matrix's eigenvalues:
|
ε ≥ δ |
ε < δ |
| unstable cases / total, over 400 random (ε, δ, θ) tuples |
0 / 299 |
101 / 101 |
Point examples: ε=0.24, δ=0.10 → stable; ε=0.05, δ=0.10 → max Re(λ) = +2.3e4 → diverges.
All shipped presets satisfy the condition (constant-tti: ε=0.3, δ=0.2; layers-tti: ε=0.1·, δ=0.05·), so the test suite never exercises it.
Suggestion
Either of:
- In
Model.__init__ (or wherever epsilon/delta are attached), warn when np.any(delta > epsilon), naming the condition and citing Bube et al. 2012 — a warning rather than an error, since users may deliberately build a positive-V_S model (e.g. Fuck, Casasanta & Nauta 2024, doi:10.3997/2214-4609.2024101515) and the check should not block them.
- Note in the
kernel_centered docstring that it is the V_Sz = 0 pseudoacoustic form and is unstable for ε < δ; the self-adjoint, energy-conserving construction of Bube, Washbourne, Ergas & Nemeth (2016, doi:10.1190/segam2016-13878451.1) is the form that is stable by construction, at the cost of a finite V_S.
Happy to open a PR for (1) if that shape is acceptable.
Summary
examples/seismic/model.pydocuments the Thomsen parameters as(
model.py:265onmain, also in 4.8.22), but nothing checksdelta<epsilon, and the pseudoacoustic TTI kernel inexamples/seismic/tti/operators.py(kernel_centered, the Zhang, Zhang & Zhang 2011 form) is exponentially unstable whenever it is violated. A user who setsdelta > epsilonanywhere in the model — a physically valid regime (negative anellipticity shales) — gets a blow-up with no diagnostic pointing at the cause.Why it is unstable
This is not a discretisation or CFL problem; it is a property of the pseudoacoustic (
V_Sz = 0) approximation itself. Bube et al. (2012, Geophysics 77(5) T171–T186, doi:10.1190/geo2011-0250.1) show that for every 2×2 second-order-in-time pseudoacoustic system the dispersion relationω⁴ − Bω² + C = 0hasC = 2 V_Pz⁴ (ε−δ) k_h² k_z², so forε < δoneω²root is negative and the corresponding mode grows exponentially. Reducingdtdoes not help.For
kernel_centeredspecifically, witha = Ghandb = Gzzthe symbols of the rotated operators (both ≤ 0), the 2×2 coupling matrix[[ (1+2ε)a, √(1+2δ) b ], [ √(1+2δ) a, b ]]has determinant2(ε−δ)·a·b, which changes sign exactly atε = δ.Measured
Von Neumann analysis of the exact
kernel_centereddiscrete operator (space_order=8, 2-D, constant coefficients,dtwell inside the isotropic CFL limit), stability decided from the coupling matrix's eigenvalues:Point examples: ε=0.24, δ=0.10 → stable; ε=0.05, δ=0.10 → max Re(λ) = +2.3e4 → diverges.
All shipped presets satisfy the condition (
constant-tti: ε=0.3, δ=0.2;layers-tti: ε=0.1·, δ=0.05·), so the test suite never exercises it.Suggestion
Either of:
Model.__init__(or whereverepsilon/deltaare attached), warn whennp.any(delta > epsilon), naming the condition and citing Bube et al. 2012 — a warning rather than an error, since users may deliberately build a positive-V_Smodel (e.g. Fuck, Casasanta & Nauta 2024, doi:10.3997/2214-4609.2024101515) and the check should not block them.kernel_centereddocstring that it is theV_Sz = 0pseudoacoustic form and is unstable forε < δ; the self-adjoint, energy-conserving construction of Bube, Washbourne, Ergas & Nemeth (2016, doi:10.1190/segam2016-13878451.1) is the form that is stable by construction, at the cost of a finiteV_S.Happy to open a PR for (1) if that shape is acceptable.