Note
Go to the end to download the full example code.
Acoustic Wave Equation modelling#
This example shows how to perform acoustic wave equation modelling
using the pylops.waveeqprocessing.AcousticWave2D
operator,
which brings the power of finite-difference modelling via the Devito
modelling engine to PyLops.
import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import gaussian_filter
import pylops
plt.close("all")
np.random.seed(0)
To begin with, we will create a simple layered velocity model. We will also define a background velocity model by smoothing the original velocity model which will be responsible of the kinematic of the wavefield modelled via Born modelling, and the perturbation velocity model which will lead to scattering effects and therefore guide the dynamic of the modelled wavefield.
# Velocity Model
nx, nz = 61, 40
dx, dz = 4, 4
x, z = np.arange(nx) * dx, np.arange(nz) * dz
vel = 1000 * np.ones((nx, nz))
vel[:, 15:] = 1200
vel[:, 35:] = 1600
# Smooth velocity model
v0 = gaussian_filter(vel, sigma=10)
# Born perturbation from m - m0
dv = vel ** (-2) - v0 ** (-2)
# Receivers
nr = 101
rx = np.linspace(0, x[-1], nr)
rz = 20 * np.ones(nr)
recs = np.vstack((rx, rz))
dr = recs[0, 1] - recs[0, 0]
# Sources
ns = 3
sx = np.linspace(0, x[-1], ns)
sz = 10 * np.ones(ns)
sources = np.vstack((sx, sz))
plt.figure(figsize=(10, 5))
im = plt.imshow(vel.T, cmap="summer", extent=(x[0], x[-1], z[-1], z[0]))
plt.scatter(recs[0], recs[1], marker="v", s=150, c="b", edgecolors="k")
plt.scatter(sources[0], sources[1], marker="*", s=150, c="r", edgecolors="k")
cb = plt.colorbar(im)
cb.set_label("[m/s]")
plt.axis("tight")
plt.xlabel("x [m]"), plt.ylabel("z [m]")
plt.title("Velocity")
plt.xlim(x[0], x[-1])
plt.tight_layout()
plt.figure(figsize=(10, 5))
im = plt.imshow(dv.T, cmap="seismic", extent=(x[0], x[-1], z[-1], z[0]))
plt.scatter(recs[0], recs[1], marker="v", s=150, c="b", edgecolors="k")
plt.scatter(sources[0], sources[1], marker="*", s=150, c="r", edgecolors="k")
cb = plt.colorbar(im)
cb.set_label("[m/s]")
plt.axis("tight")
plt.xlabel("x [m]"), plt.ylabel("z [m]")
plt.title("Velocity perturbation")
plt.xlim(x[0], x[-1])
plt.tight_layout()
Let us now define the Born modelling operator
And we use it to model our data
dobs = Aop @ dv
fig, axs = plt.subplots(1, 3, sharey=True, figsize=(10, 6))
fig.suptitle("FD modelling with Ricker", y=0.99)
for isrc in range(ns):
axs[isrc].imshow(
dobs[isrc].reshape(Aop.geometry.nrec, Aop.geometry.nt).T,
cmap="gray",
vmin=-1e-7,
vmax=1e-7,
extent=(
recs[0, 0],
recs[0, -1],
Aop.geometry.time_axis.time_values[-1] * 1e-3,
0,
),
)
axs[isrc].axis("tight")
axs[isrc].set_xlabel("rec [m]")
axs[0].set_ylabel("t [s]")
fig.tight_layout()
Finally, we are going to show how despite the
pylops.waveeqprocessing.AcousticWave2D
operator allows a user to
specify a limited number of source wavelets (this is directly borrowed from
Devito), a simple modification can be applied to pass any user defined wavelet.
We are going to do that with a Ormsby wavelet
# Extract Ricker wavelet
wav = Aop.geometry.src.data[:, 0]
wavc = np.argmax(wav)
# Define Ormsby wavelet
wavest = pylops.utils.wavelets.ormsby(
Aop.geometry.time_axis.time_values[:wavc] * 1e-3, f=[3, 20, 30, 45]
)[0]
# Update wavelet in operator and model new data
Aop.updatesrc(wavest)
dobs1 = Aop @ dv
fig, axs = plt.subplots(1, 3, sharey=True, figsize=(10, 6))
fig.suptitle("FD modelling with Ormsby", y=0.99)
for isrc in range(ns):
axs[isrc].imshow(
dobs1[isrc].reshape(Aop.geometry.nrec, Aop.geometry.nt).T,
cmap="gray",
vmin=-1e-7,
vmax=1e-7,
extent=(
recs[0, 0],
recs[0, -1],
Aop.geometry.time_axis.time_values[-1] * 1e-3,
0,
),
)
axs[isrc].axis("tight")
axs[isrc].set_xlabel("rec [m]")
axs[0].set_ylabel("t [s]")
fig.tight_layout()
fig, axs = plt.subplots(1, 2, figsize=(10, 3))
axs[0].plot(wav[: 2 * wavc], "k")
axs[0].plot(wavest, "r")
axs[1].plot(
dobs[isrc].reshape(Aop.geometry.nrec, Aop.geometry.nt)[nr // 2], "k", label="Ricker"
)
axs[1].plot(
dobs1[isrc].reshape(Aop.geometry.nrec, Aop.geometry.nt)[nr // 2],
"r",
label="Ormsby",
)
axs[1].legend()
fig.tight_layout()
Total running time of the script: (0 minutes 5.252 seconds)