import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from devito import *
from examples.seismic.source import RickerSource, WaveletSource, TimeAxis
from examples.seismic import ModelViscoacoustic, plot_image, setup_geometry, plot_velocity
11 - Implementation of a Devito viscoacoustic equations
This tutorial is contributed by SENAI CIMATEC (2020)
This tutorial is based on:
Linear inversion in layered viscoacoustic media using a time‐domain method (1994)
Joakim O. Blanch and William W. Symes
SEG Technical Program Expanded Abstracts
https://doi.org/10.1190/1.1822695
True-amplitude prestack depth migration (2007)
Feng Deng and George A. McMechan
GEOPHYSICS Technical Papers
https://doi.org/10.1190/1.2714334
Attenuation compensation for least-squares reverse time migration using the viscoacoustic-wave equation (2014)
Gaurav Dutta and Gerard T. Schuster
GEOPHYSICS Technical Papers
https://doi.org/10.1190/geo2013-0414.1
Multiscale viscoacoustic waveform inversion with the second generation wavelet transform and adaptive time–space domain finite-difference method (2014)
Zhiming Ren, Yang Liu,and Qunshan Zhang
Geophysical Journal International, Volume 197, Issue 2, 1 May 2014, Pages 948–974
https://doi.org/10.1093/gji/ggu024
Viscoacoustic prestack reverse time migration based on the optimal time-space domain high-order finite-difference method (2014)
Yan Zhao, Yang Liu, and Zhi-Ming Ren
Appl. Geophys. 11, 50–62.
https://doi.org/10.1007/s11770-014-0414-8
A stable and efficient approach of Q reverse time migration (2018)
Yan Zhao, Ningbo Mao, and Zhiming Ren
GEOPHYSICS Technical Papers
https://doi.org/10.1190/geo2018-0022.1
Introduction
The conversion of mechanical energy to heat, occurs during the propagation of seismic waves on the subsurface, due to the viscosity of the rocks. The presence of oil and gas in these rocks causes seismic attenuations. Thus, associated effects, such as dispersion and dissipation, can significantly affect the amplitudes, as well as the phase of the seismic pulse. However, in the seismic exploration, the subsurface has still been considered as an ideal elastic/acoustic medium, that is, disregarding its mitigating effect. In practice, the propagation of seismic waves on the subsurface is in many ways different from propagation in an ideal solid.
For example, some subsurface rocks have anisotropic properties, are heterogeneous, porous and so on. The acoustic/elastic wave equation is not sensitive enough to describe propagation in these more complicated mediums. Generally, the viscosity of materials in the subsurface causes energy dissipation and consequently a decrease in amplitude, in addition to modifying the frequency content of the waves. This phenomenon of energy dissipation of the wave is called seismic absorption or attenuation.
The goal of this tutorial is to perform a seismic modeling taking into account the viscosity of the medium, so that it is possible to more accurately simulate the seismic data and consequently build images with better resolution in the processing of this data, in addition to extracting more detailed information on rocky materials through seismic inversion.
This tutorial follow three main viscoacoustic approaches in time-space domain:
Blanch and Symes (1995) / Dutta and Schuster (2014)
Ren et al. (2014)
Deng and McMechan (2007)
Table of symbols
Symbol | Description |
---|---|
\(f\) | Frequency |
\(f_o\) | Reference frequency |
\(\omega\) | Angular frenquency |
\(\omega_0\) | Angular Reference Frequency |
\(v\) | Velocity model |
\(v_0\) | Reference velocity at \(\omega_0\) |
\(\kappa\) | Bulk modulus |
\(g\) | Absorption coefficient |
\(\tau\) | Relaxation time |
\(\tau_\sigma\) | Stress relaxation parameter |
\(\tau_\epsilon\) | Strain relaxation parameter |
\(Q\) | Quality factor |
\(\eta\) | Viscosity |
\(\rho\) | Density |
\(\nabla\) | Nabla operator |
\(P({\bf x},t)\) | Pressure field |
\(r({\bf x},t)\) | Memory variable |
\({\bf v}({\bf x},t)\) | Particle velocity |
\(S({\bf x}_s,t)\) | Source |
Seismic modelling with Devito
Before start with the viscoacoustic approaches we will describe a setup of seismic modelling with Devito in a simple 2D case. We will create a physical model of our domain and define a single source and an according set of receivers to model for the forward model. But first, we initialize some basic utilities.
= 300
nx = 300
nz
# Define a physical size
= (nx, nz)
shape = (20., 20.)
spacing = (0., 0.)
origin = 3
nlayers = 50
nbl = 8
space_order = np.float32
dtype
# Model physical parameters:
= np.zeros(shape)
vp = np.zeros(shape)
qp = np.zeros(shape)
rho
# Define a velocity profile. The velocity is in km/s
= 1.5
vp_top = 3.5
vp_bottom
# Define a velocity profile in km/s
= np.empty(shape, dtype=dtype)
v = vp_top # Top velocity (background)
v[:] = np.linspace(vp_top, vp_bottom, nlayers)
vp_i for i in range(1, nlayers):
*int(shape[-1] / nlayers):] = vp_i[i] # Bottom velocity
v[..., i
= 3.516*((v[:]*1000.)**2.2)*10**(-6) # Li's empirical formula
qp[:]
= 0.31*(v[:]*1000.)**0.25 # Gardner's relation rho[:]
#NBVAL_IGNORE_OUTPUT
= ModelViscoacoustic(space_order=space_order, vp=v, qp=qp, b=1/rho,
model =origin, shape=shape, spacing=spacing,
origin=nbl) nbl
Operator `initdamp` ran in 0.01 s
Operator `pad_vp` ran in 0.01 s
Operator `pad_b` ran in 0.02 s
Operator `pad_qp` ran in 0.01 s
#NBVAL_IGNORE_OUTPUT
= model.shape[0]/model.shape[1]
aspect_ratio
= {'cmap': 'jet', 'extent': [model.origin[0], model.origin[0] + model.domain_size[0],
plt_options_model 1] + model.domain_size[1], model.origin[1]]}
model.origin[= plt.subplots(nrows=1, ncols=3, figsize=(15, 5))
fig, ax
= [slice(model.nbl, -model.nbl), slice(model.nbl, -model.nbl)]
slices
= ax[0].imshow(np.transpose(model.vp.data[slices]), vmin=1.5, vmax=3.5, **plt_options_model)
img1 =ax[0])
fig.colorbar(img1, ax0].set_title(r"V (km/s)", fontsize=20)
ax[0].set_xlabel('X (m)', fontsize=20)
ax[0].set_ylabel('Depth (m)', fontsize=20)
ax[0].set_aspect('auto')
ax[
= ax[1].imshow(np.transpose(qp), vmin=15, vmax=220, **plt_options_model)
img2 =ax[1])
fig.colorbar(img2, ax1].set_title("Q", fontsize=20)
ax[1].set_xlabel('X (m)', fontsize=20)
ax[1].set_ylabel('Depth (m)', fontsize=20)
ax[1].set_aspect('auto')
ax[
= ax[2].imshow(np.transpose(rho), vmin=1.9, vmax=2.4, **plt_options_model)
img3 =ax[2])
fig.colorbar(img3, ax2].set_title(r"Density $\rho$ (g/cm^3)", fontsize=20)
ax[2].set_xlabel('X (m)', fontsize=20)
ax[2].set_ylabel('Depth (m)', fontsize=20)
ax[2].set_aspect('auto')
ax[
plt.tight_layout()
= 0.005 # peak/dominant frequency
f0 = model.b
b = 1./b
rho
# velocity model
= model.vp
vp = vp * vp * rho
lam
= (sp.sqrt(1.+1./model.qp**2)-1./model.qp)/f0
t_s = 1./(f0**2*t_s)
t_ep = (t_ep/t_s) - 1.
tt
= model.grid.stepping_dim.spacing
s = model.damp damp
# Time step in ms and time range:
= 0., 2000.
t0, tn = model.critical_dt
dt = TimeAxis(start=t0, stop=tn, step=dt) time_range
from examples.seismic import Receiver
def src_rec(p, model):
= RickerSource(name='src', grid=model.grid, f0=f0, time_range=time_range)
src 0, :] = np.array(model.domain_size) * .5
src.coordinates.data[0, -1] = 8.
src.coordinates.data[
# Create symbol for receivers
= Receiver(name='rec', grid=model.grid, npoint=shape[0], time_range=time_range)
rec
# Prescribe even spacing for receivers along the x-axis
0] = np.linspace(0, model.domain_size[0], num=shape[0])
rec.coordinates.data[:, 1] = 8.
rec.coordinates.data[:,
= src.inject(field=p.forward, expr=(s*src))
src_term = rec.interpolate(expr=p)
rec_term
return src_term + rec_term, src, rec
Auxiliary functions for plotting data:
def plot_receiver(rec):
= rec.resample(num=1001)
rec_plot = np.diag(np.linspace(1.0, 2.5, 1001)**2.0)
scale_for_plot # Pressure (txx + tzz) data at sea surface
= [rec_plot.coordinates.data[0, 0], rec_plot.coordinates.data[-1, 0], 1e-3*tn, t0]
extent = rec_plot.coordinates.data[-1, 0]/(1e-3*tn)/.5
aspect
=(10, 10))
plt.figure(figsize=-.01, vmax=.01, cmap="seismic",
plt.imshow(np.dot(scale_for_plot, rec_plot.data), vmin='lanczos', extent=extent, aspect=aspect)
interpolation"Time (s)", fontsize=20)
plt.ylabel("Receiver position (m)", fontsize=20) plt.xlabel(
def plot_v_and_p(model, v, p):
= [slice(model.nbl, -model.nbl), slice(model.nbl, -model.nbl)]
slices = .5*1e-3
scale
= {'extent': [model.origin[0] , model.origin[0] + model.domain_size[0],
plt_options_model 1] + model.domain_size[1], model.origin[1]]}
model.origin[
= plt.subplots(nrows=1, ncols=3, figsize=(15, 7))
fig, ax
0].imshow(np.transpose(v[0].data[0][slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[0].imshow(np.transpose(model.vp.data[slices]), vmin=1.5, vmax=3.5, cmap="jet", alpha=.5, **plt_options_model)
ax[0].set_aspect('auto')
ax[0].set_xlabel('X (m)', fontsize=20)
ax[0].set_ylabel('Depth (m)', fontsize=20)
ax[0].set_title(r"$v_{x}$", fontsize=20)
ax[
1].imshow(np.transpose(v[1].data[0][slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[1].imshow(np.transpose(model.vp.data[slices]), vmin=1.5, vmax=3.5, cmap="jet", alpha=.5, **plt_options_model)
ax[1].set_aspect('auto')
ax[1].set_xlabel('X (m)', fontsize=20)
ax[1].set_title(r"$v_{z}$", fontsize=20)
ax[
2].imshow(np.transpose(p.data[0][slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[2].imshow(np.transpose(model.vp.data[slices]), vmin=1.5, vmax=3.5, cmap="jet", alpha=.5, **plt_options_model)
ax[2].set_aspect('auto')
ax[2].set_xlabel('X (m)', fontsize=20)
ax[2].set_title(r"$P$", fontsize=20) ax[
Equation based on standard linear solid (SLS) rheological model
The equations of motion for a viscoacoustic medium can be written as:
\[\begin{equation} \left\{ \begin{array}{lcl} \frac{\partial P}{\partial t} + \kappa (\tau + 1)(\nabla \cdot {\bf v}) + r = S({\bf x}_{s}, t) \\ \frac{\partial {\bf v}}{\partial t} + \frac{1}{\rho}\nabla{P} = 0 \\ \frac{\partial r}{\partial t} + \frac{1}{\tau_{\sigma}} [r + \tau \kappa (\nabla \cdot {\bf v})] = 0. \end{array} \right. \end{equation}\]
Where \(\tau = \tau_{\epsilon}/\tau_{\sigma} -1\) represents the magnitude of \(Q\). \(\tau_{\epsilon}\) and \(\tau_{\sigma}\) are, respectively, the stress and strain relaxation parameters, given by:
\[\begin{equation} \tau_\sigma = \frac{\sqrt{Q^2+1}-1}{2 \pi f_0 Q} \end{equation}\] and \[\begin{equation} \tau_\epsilon= \frac{\sqrt{Q^2+1}+1}{2\pi f_0 Q} \end{equation}\]
# Stencil created from Blanch and Symes (1995) / Dutta and Schuster (2014)
def SLS(model, p, r, v):
# Bulk modulus
= rho * (vp * vp)
bm
# Define PDE to v
= v.dt + b * grad(p)
pde_v = Eq(v.forward, damp * solve(pde_v, v.forward))
u_v
# Define PDE to r
= r.dt + (1. / t_s) * (r + tt * bm * div(v.forward))
pde_r = Eq(r.forward, damp * solve(pde_r, r.forward))
u_r
# Define PDE to p
= p.dt + bm * (tt + 1.) * div(v.forward) + r.forward
pde_p = Eq(p.forward, damp * solve(pde_p, p.forward))
u_p
return [u_v, u_r, u_p]
# Seismic Modelling from Blanch and Symes (1995) / Dutta and Schuster (2014) viscoacoustic wave equation.
def modelling_SLS(model):
# Create symbols for particle velocity, pressure field, memory variable, source and receivers
= VectorTimeFunction(name="v", grid=model.grid, time_order=1, space_order=space_order)
v
= TimeFunction(name="p", grid=model.grid, time_order=1, space_order=space_order,
p =NODE)
staggered
= TimeFunction(name="r", grid=model.grid, time_order=1, space_order=space_order,
r =NODE)
staggered
# define the source injection and create interpolation expression for receivers
= src_rec(p, model)
src_rec_expr, src, rec
= SLS(model, p, r, v)
eqn
= Operator(eqn + src_rec_expr, subs=model.spacing_map)
op
=time_range.num-1, dt=dt, src=src, rec=rec)
op(time
return rec, v, p
#NBVAL_IGNORE_OUTPUT
= modelling_SLS(model) rec, v, p
Operator `Kernel` ran in 2.72 s
#NBVAL_IGNORE_OUTPUT
plot_receiver(rec)
assert np.isclose(np.linalg.norm(rec.data), 16, rtol=10)
#NBVAL_IGNORE_OUTPUT
plot_v_and_p(model, v, p)
assert np.isclose(norm(v[0]), 1.87797, atol=1e-3, rtol=0)
Equation based on Kelvin-Voigt (KV) rheological model
The viscoacoustic wave equation in time domain is written as:
\[\begin{equation} \frac{\partial^{2}P}{\partial{t^2}} - v^{2}\nabla^{2}{P} - \eta\nabla^{2}\left(\frac{\partial P}{\partial t}\right) = S({\bf x}_{s}, t), \end{equation}\]
where \(\eta = \frac{v^2}{\omega_{0}Q}\) represents the viscosity of medium.
Considering the variable density \(\rho\), the equation can be rewritten as:
\[\begin{equation} \frac{\partial^{2}P}{\partial{t^2}} - \kappa \nabla \cdot \frac{1}{\rho} \nabla{P} - \eta \rho \nabla \cdot \frac{1}{\rho} \nabla \left(\frac{\partial{P}}{\partial{t}}\right) = S({\bf x}_{s}, t). \end{equation}\]
The equation can be written using a first order formulation, given by:
\[\begin{equation} \left\{ \begin{array}{ll} \frac{\partial P}{\partial t} + \kappa \nabla \cdot {\bf v} - \eta \rho \nabla \cdot \frac{1}{\rho} \nabla{P} = S({\bf x}_{s}, t) \\ \frac{\partial {\bf v}}{\partial t} + \frac{1}{\rho} \nabla{P} = 0 \end{array} \right. \end{equation}\]
# Stencil created from Ren et al. (2014) viscoacoustic wave equation.
def KV(model, p, v):
# Angular frequency
= 2. * np.pi * f0
w
# Define PDE to v
= v.dt + b * grad(p)
pde_v = Eq(v.forward, damp * solve(pde_v, v.forward))
u_v
# Define PDE to p
= p.dt + lam * div(v.forward) - (lam / (w * model.qp)) * div(b * grad(p, shift=.5), shift=-.5)
pde_p
= Eq(p.forward, damp * solve(pde_p, p.forward))
u_p
return [u_v, u_p]
# Seismic Modelling from Ren et al. (2014) viscoacoustic wave equation.
def modelling_KV(model):
# Create symbols for particle velocity, pressure field, source and receivers
= VectorTimeFunction(name="v", grid=model.grid, time_order=1, space_order=space_order)
v
= TimeFunction(name="p", grid=model.grid, time_order=1, space_order=space_order,
p =NODE)
staggered
# define the source injection and create interpolation expression for receivers
= src_rec(p, model)
src_rec_expr, src, rec
= KV(model, p, v)
eqn
= Operator(eqn + src_rec_expr, subs=model.spacing_map)
op
=time_range.num-1, dt=dt, src=src, rec=rec)
op(time
return rec, v, p
#NBVAL_IGNORE_OUTPUT
= modelling_KV(model) rec, v, p
Operator `Kernel` ran in 2.02 s
#NBVAL_IGNORE_OUTPUT
plot_receiver(rec)
assert np.isclose(np.linalg.norm(rec.data), 15, rtol=10)
#NBVAL_IGNORE_OUTPUT
plot_v_and_p(model, v, p)
assert np.isclose(norm(v[0]), 1.0639238, atol=1e-3, rtol=0)
Equation based on Maxwell rheological model
The viscoacoustic wave equation for the propagating pressure \(P\) in the time-space domain:
\[\begin{equation} \frac{1}{v^2}\frac{\partial^{2}P}{\partial{t^2}} - \nabla^{2}P + \frac{g}{v}\frac{\partial P}{\partial{t}} = S({\bf x}_{s}, t), \end{equation}\]
where \(g\) is the absorption coefficient, given by:
\[\begin{equation} g = \frac{2\pi f_{0}}{vQ}, \end{equation}\]
The equation can be written using a first order formulation, given by:
\[\begin{equation} \left\{ \begin{array}{lcl} \frac{\partial P}{\partial t} + \kappa (\nabla \cdot {\bf v}) + \frac{2\pi f_{0}}{Q}P= S({\bf x}_{s}, t) \\ \frac{\partial {\bf v}}{\partial t} + \frac{1}{\rho}\nabla{P} = 0 \\ \end{array} \right. \end{equation}\]
# Stencil created from Deng and McMechan (2007) viscoacoustic wave equation.
def Maxwell(model, p, v):
# Angular frequency
= 2. * np.pi * f0
w
# Define PDE to v
= v.dt + b * grad(p)
pde_v = Eq(v.forward, damp * solve(pde_v, v.forward))
u_v
# Define PDE to p
= p.dt + lam * div(v.forward) + (w / model.qp) * p
pde_p = Eq(p.forward, damp * solve(pde_p, p.forward))
u_p
return [u_v, u_p]
# Seismic Modelling from Deng and McMechan (2007) viscoacoustic wave equation.
def modelling_Maxwell(model):
# Create symbols for particle velocity, pressure field, source and receivers
= VectorTimeFunction(name="v", grid=model.grid, time_order=1, space_order=space_order)
v
= TimeFunction(name="p", grid=model.grid, time_order=1, space_order=space_order,
p =NODE)
staggered
# define the source injection and create interpolation expression for receivers
= src_rec(p, model)
src_rec_expr, src, rec
= Maxwell(model, p, v)
eqn
= Operator(eqn + src_rec_expr, subs=model.spacing_map)
op
=time_range.num-1, dt=dt, src=src, rec=rec)
op(time
return rec, v, p
#NBVAL_IGNORE_OUTPUT
= modelling_Maxwell(model) rec, v, p
Operator `Kernel` ran in 0.77 s
#NBVAL_IGNORE_OUTPUT
plot_receiver(rec)
assert np.isclose(np.linalg.norm(rec.data), 16, rtol=10)
#NBVAL_IGNORE_OUTPUT
plot_v_and_p(model, v, p)
assert np.isclose(norm(v[0]), 1.1323929, atol=1e-3, rtol=0)
More references
[1] https://academic.oup.com/gji/article/197/2/948/616510
[2] https://link.springer.com/article/10.1007/s11770-014-0414-8
[3] https://janth.home.xs4all.nl/Software/fdelmodcManual.pdf