from devito import *
from examples.seismic.source import RickerSource, Receiver, TimeAxis
from examples.seismic import plot_image, demo_model
import numpy as np
import matplotlib.pyplot as plt
from sympy import init_printing, latex
='mathjax')
init_printing(use_latex
# Some ploting setup
'text', usetex=True)
plt.rc('font', family='serif')
plt.rc('xtick', labelsize=20)
plt.rc('ytick', labelsize=20) plt.rc(
06 - Elastic wave equation implementation on a staggered grid
This second elastic tutorial extends the previous constant parameter implementation to varying parameters (Lame parameters) and takes advantage of the Tensorial capabilities of Devito to write the elastic wave equation following its mathematical definition. The staggering is automated via the TensorFunction API.
Explosive source
We will first attempt to replicate the explosive source test case described in [1], Figure 4. We start by defining the source signature \(g(t)\), the derivative of a Gaussian pulse, given by Eq 4:
\[g(t) = -2 \alpha(t - t_0)e^{-\alpha(t-t_0)^2}\]
#NBVAL_IGNORE_OUTPUT
# Initial grid: 3km x 3km, with spacing 10m
= 5
nlayers = 8
so = demo_model(preset='layers-elastic', nlayers=nlayers, shape=(301, 301), spacing=(10., 10.),
model =so) space_order
Operator `initdamp` ran in 0.01 s
#NBVAL_SKIP
= 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=3, ncols=1, figsize=(15, 15))
fig, ax
= [slice(model.nbl, -model.nbl), slice(model.nbl, -model.nbl)]
slices
= ax[0].imshow(np.transpose(model.lam.data[slices]), vmin=1.5**2, vmax=4.0**2, **plt_options_model)
img1 =ax[0])
fig.colorbar(img1, ax0].set_title(r"First Lam\'e parameter $\lambda$", 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(model.mu.data[slices]), vmin=0, vmax=15, **plt_options_model)
img2 =ax[1])
fig.colorbar(img2, ax1].set_title(r"Shear modulus $\mu$", 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(1/np.transpose(model.b.data[slices]), vmin=1.0, vmax=3.0, **plt_options_model)
img3 =ax[2])
fig.colorbar(img3, ax2].set_title(r"Density $\rho$", 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()
# Timestep size from Eq. 7 with V_p=6000. and dx=100
= 0., 2000.
t0, tn = model.critical_dt
dt = TimeAxis(start=t0, stop=tn, step=dt)
time_range
= RickerSource(name='src', grid=model.grid, f0=0.015, time_range=time_range)
src = [1500., 10.] src.coordinates.data[:]
#NBVAL_SKIP
src.show()
Vectorial form
While conventional litterature writes the elastic wave-equation as a set of scalar PDEs, the higher level representation comes from Hooke’s law and the equation of motion and writes as:
\[\begin{cases} &\frac{dv}{dt} = \nabla . \tau \\ &\frac{d \tau}{dt} = \lambda tr(\nabla v) \mathbf{I} + \mu (\nabla v + (\nabla v)^T) \end{cases}\]and as \(tr(\nabla v)\) is the divergence of \(v\) we can reqrite it as
\[\begin{cases} &\frac{dv}{dt} = \nabla . \tau \\ &\frac{d \tau}{dt} = \lambda \text{diag}(\nabla . v) + \mu (\nabla v + (\nabla v)^T) \end{cases}\]where \(v\) is a vector valued function:
\(v(t, x, y) = (v_x(t, x, y), v_y(t, x, y)\)
and the stress \(\tau\) is a symmetric tensor valued function:
\(\tau(t, x, y) = \begin{bmatrix}\tau_{xx}(t, x, y) & \tau_{xy}(t, x, y)\\\tau_{xy}t, x, y) & \tau_{yy}(t, x, y)\end{bmatrix}\)
We show in the following how to setup the elastic wave-equation form Devito’s high-level tensorial types.
# Now we create the velocity and pressure fields
= model.grid.dimensions
x, z = model.grid.stepping_dim
t = model.grid.time_dim
time = time.spacing
s
= VectorTimeFunction(name='v', grid=model.grid, space_order=so, time_order=1)
v = TensorTimeFunction(name='t', grid=model.grid, space_order=so, time_order=1) tau
# The source injection term
= src.inject(field=tau.forward[0, 0], expr=s*src)
src_xx = src.inject(field=tau.forward[1, 1], expr=s*src)
src_zz
# The receiver
= 301
nrec = Receiver(name="rec", grid=model.grid, npoint=nrec, time_range=time_range)
rec 0] = np.linspace(0., model.domain_size[0], num=nrec)
rec.coordinates.data[:, -1] = 5.
rec.coordinates.data[:,
= Receiver(name="rec2", grid=model.grid, npoint=nrec, time_range=time_range)
rec2 0] = np.linspace(0., model.domain_size[0], num=nrec)
rec2.coordinates.data[:, -1] = 3000.0/nlayers
rec2.coordinates.data[:,
= Receiver(name="rec3", grid=model.grid, npoint=nrec, time_range=time_range)
rec3 0] = np.linspace(0., model.domain_size[0], num=nrec)
rec3.coordinates.data[:, -1] = 3000.0/nlayers
rec3.coordinates.data[:,
= rec.interpolate(expr=tau[0, 0] + tau[1, 1])
rec_term += rec2.interpolate(expr=v[1])
rec_term += rec3.interpolate(expr=v[0]) rec_term
#NBVAL_SKIP
from examples.seismic import plot_velocity
=src.coordinates.data,
plot_velocity(model, source=rec.coordinates.data[::10, :])
receiver=src.coordinates.data,
plot_velocity(model, source=rec2.coordinates.data[::10, :]) receiver
# Now let's try and create the staggered updates
# Lame parameters
= model.lam, model.mu, model.b
l, mu, ro
# First order elastic wave equation
= v.dt - ro * div(tau)
pde_v = tau.dt - l * diag(div(v.forward)) - mu * (grad(v.forward) + grad(v.forward).transpose(inner=False))
pde_tau # Time update
= Eq(v.forward, model.damp * solve(pde_v, v.forward))
u_v = Eq(tau.forward, model.damp * solve(pde_tau, tau.forward))
u_t
= Operator([u_v] + [u_t] + src_xx + src_zz + rec_term) op
v.time_order
\(\displaystyle 1\)
0]).evaluate ro._eval_at(v[
\(\displaystyle 0.5 b(x, y) + 0.5 b(x + h_x, y)\)
We can now see that both the particle velocities and stress equations are vectorial and tensorial equations. Devito takes care of the discretization and staggered grids automatically for these types of object.
u_v
\(\displaystyle \left[\begin{matrix}v_x(t + dt, x + h_x/2, y)\\v_y(t + dt, x, y + h_y/2)\end{matrix}\right] = \left[\begin{matrix}dt \left(\left(\frac{\partial}{\partial x} t_xx(t, x, y) + \frac{\partial}{\partial y} t_xy(t, x + h_x/2, y + h_y/2)\right) b(x, y) + \frac{v_x(t, x + h_x/2, y)}{dt}\right) damp(x, y)\\dt \left(\left(\frac{\partial}{\partial x} t_xy(t, x + h_x/2, y + h_y/2) + \frac{\partial}{\partial y} t_yy(t, x, y)\right) b(x, y) + \frac{v_y(t, x, y + h_y/2)}{dt}\right) damp(x, y)\end{matrix}\right]\)
u_t
\(\displaystyle \left[\begin{matrix}t_xx(t + dt, x, y) & t_xy(t + dt, x + h_x/2, y + h_y/2)\\t_xy(t + dt, x + h_x/2, y + h_y/2) & t_yy(t + dt, x, y)\end{matrix}\right] = \left[\begin{matrix}dt \left(\left(\frac{\partial}{\partial x} v_x(t + dt, x + h_x/2, y) + \frac{\partial}{\partial y} v_y(t + dt, x, y + h_y/2)\right) lam(x, y) + 2 mu(x, y) \frac{\partial}{\partial x} v_x(t + dt, x + h_x/2, y) + \frac{t_xx(t, x, y)}{dt}\right) damp(x, y) & dt \left(\left(\frac{\partial}{\partial y} v_x(t + dt, x + h_x/2, y) + \frac{\partial}{\partial x} v_y(t + dt, x, y + h_y/2)\right) mu(x, y) + \frac{t_xy(t, x + h_x/2, y + h_y/2)}{dt}\right) damp(x, y)\\dt \left(\left(\frac{\partial}{\partial y} v_x(t + dt, x + h_x/2, y) + \frac{\partial}{\partial x} v_y(t + dt, x, y + h_y/2)\right) mu(x, y) + \frac{t_xy(t, x + h_x/2, y + h_y/2)}{dt}\right) damp(x, y) & dt \left(\left(\frac{\partial}{\partial x} v_x(t + dt, x + h_x/2, y) + \frac{\partial}{\partial y} v_y(t + dt, x, y + h_y/2)\right) lam(x, y) + 2 mu(x, y) \frac{\partial}{\partial y} v_y(t + dt, x, y + h_y/2) + \frac{t_yy(t, x, y)}{dt}\right) damp(x, y)\end{matrix}\right]\)
#NBVAL_IGNORE_OUTPUT
# Partial ru for 1.2sec to plot the wavefield
=model.critical_dt, time_M=int(1000/model.critical_dt)) op(dt
Operator `Kernel` ran in 0.23 s
PerformanceSummary([(PerfKey(name='section0', rank=None),
PerfEntry(time=0.20279700000000003, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section1', rank=None),
PerfEntry(time=0.005569999999999994, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section2', rank=None),
PerfEntry(time=0.006224000000000026, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section3', rank=None),
PerfEntry(time=0.006004000000000021, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section4', rank=None),
PerfEntry(time=0.00578600000000002, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])
#NBVAL_SKIP
= .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=2, ncols=2, figsize=(15, 15))
fig, ax
0, 0].imshow(np.transpose(v[0].data[0][slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[0, 0].imshow(np.transpose(model.lam.data[slices]), vmin=2.5, vmax=15.0, cmap="jet", alpha=.5, **plt_options_model)
ax[0, 0].set_aspect('auto')
ax[0, 0].set_xlabel('X (m)', fontsize=20)
ax[0, 0].set_ylabel('Depth (m)', fontsize=20)
ax[0, 0].set_title(r"$v_{x}$", fontsize=20)
ax[
0, 1].imshow(np.transpose(v[1].data[0][slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[0, 1].imshow(np.transpose(model.lam.data[slices]), vmin=2.5, vmax=15.0, cmap="jet", alpha=.5, **plt_options_model)
ax[0, 1].set_aspect('auto')
ax[0, 1].set_title(r"$v_{z}$", fontsize=20)
ax[0, 1].set_xlabel('X (m)', fontsize=20)
ax[0, 1].set_ylabel('Depth (m)', fontsize=20)
ax[
1, 0].imshow(np.transpose(tau[0,0].data[0][slices]+tau[1,1].data[0][slices]),
ax[=-10*scale, vmax=10*scale, cmap="RdGy", **plt_options_model)
vmin1, 0].imshow(np.transpose(model.lam.data[slices]), vmin=2.5, vmax=15.0, cmap="jet",
ax[=.5, **plt_options_model)
alpha1, 0].set_aspect('auto')
ax[1, 0].set_title(r"$\tau_{xx} + \tau_{zz}$", fontsize=20)
ax[1, 0].set_xlabel('X (m)', fontsize=20)
ax[1, 0].set_ylabel('Depth (m)', fontsize=20)
ax[
1, 1].imshow(np.transpose(tau[0,1].data[0][slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[1, 1].imshow(np.transpose(model.lam.data[slices]), vmin=2.5, vmax=15.0, cmap="jet", alpha=.5, **plt_options_model)
ax[1, 1].set_aspect('auto')
ax[1, 1].set_title(r"$\tau_{xy}$", fontsize=20)
ax[1, 1].set_xlabel('X (m)', fontsize=20)
ax[1, 1].set_ylabel('Depth (m)', fontsize=20)
ax[
plt.tight_layout()
model._physical_parameters
{'b', 'damp', 'lam', 'mu'}
#NBVAL_IGNORE_OUTPUT
# Full run for the data
=model.critical_dt, time_m=int(1000/model.critical_dt)) op(dt
Operator `Kernel` ran in 0.23 s
PerformanceSummary([(PerfKey(name='section0', rank=None),
PerfEntry(time=0.20478399999999966, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section1', rank=None),
PerfEntry(time=0.005923000000000004, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section2', rank=None),
PerfEntry(time=0.00643000000000003, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section3', rank=None),
PerfEntry(time=0.006100000000000016, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section4', rank=None),
PerfEntry(time=0.006256000000000025, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])
# Data on a standard 2ms tim axis
= rec.resample(num=1001)
rec_plot = rec2.resample(num=1001)
rec2_plot = rec3.resample(num=1001) rec3_plot
= np.diag(np.linspace(1.0, 2.5, 1001)**2.0) scale_for_plot
#NBVAL_SKIP
# 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
=(15, 15))
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(
Text(0.5, 0, 'Receiver position (m)')
#NBVAL_SKIP
# OBC data of vx/vz
=(15, 15))
plt.figure(figsize121)
plt.subplot(=-1e-3, vmax=1e-3, cmap="seismic",
plt.imshow(rec2_plot.data, vmin='lanczos', extent=extent, aspect=aspect)
interpolation"Time (s)", fontsize=20)
plt.ylabel("Receiver position (m)", fontsize=20)
plt.xlabel(122)
plt.subplot(=-1e-3, vmax=1e-3, cmap="seismic",
plt.imshow(rec3_plot.data, vmin='lanczos', extent=extent, aspect=aspect)
interpolation"Time (s)", fontsize=20)
plt.ylabel("Receiver position (m)", fontsize=20) plt.xlabel(
Text(0.5, 0, 'Receiver position (m)')
assert np.isclose(norm(rec), 22.68, atol=0, rtol=1e-3)
assert np.isclose(norm(rec2), 1.8299, atol=0, rtol=1e-3)
assert np.isclose(norm(rec3), 3.8671, atol=0, rtol=1e-3)
Second order in time
Now that looks pretty! But let’s do it again with a 2nd order in time
= 8
so = VectorTimeFunction(name='v2', grid=model.grid, space_order=so, time_order=2)
v2 = TensorFunction(name='t0', grid=model.grid, space_order=so)
tau0 # The source injection term
= src.inject(field=tau0[0, 0], expr=src.dt)
src_xx = src.inject(field=tau0[1, 1], expr=src.dt)
src_zz
= model.grid.time_dim.spacing
s
# Second order elastic wave equation
= v2.dt2 - ro * div(tau0) + (1 - model.damp) * v2.dt
pde_v2
# Time update
= Eq(v2.forward, solve(pde_v2, v2.forward))
u_v # The stress equation isn't time dependent so we don't need solve.
= Eq(tau0, model.damp * (l * diag(div(v2.forward)) + mu * (grad(v2.forward) + grad(v2.forward).transpose(inner=False))))
u_t
= rec2.interpolate(expr=v2[0])
rec_term2 += rec3.interpolate(expr=v2[1])
rec_term2 = Operator([u_v] + [u_t] + src_xx + src_zz + rec_term2) op
#NBVAL_IGNORE_OUTPUT
# Partial ru for 1.2sec to plot the wavefield
=model.critical_dt, time_M=int(1000/model.critical_dt)) op(dt
Operator `Kernel` ran in 0.26 s
PerformanceSummary([(PerfKey(name='section0', rank=None),
PerfEntry(time=0.22333499999999995, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section1', rank=None),
PerfEntry(time=0.008422999999999998, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section2', rank=None),
PerfEntry(time=0.009065000000000017, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section3', rank=None),
PerfEntry(time=0.009086000000000014, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])
#NBVAL_SKIP
= 1e-4
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=2, ncols=2, figsize=(15, 15))
fig, ax
0, 0].imshow(np.transpose(v2[0].data[0][slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[0, 0].imshow(np.transpose(model.lam.data[slices]), vmin=2.5, vmax=15.0, cmap="jet", alpha=.5, **plt_options_model)
ax[0, 0].set_aspect('auto')
ax[0, 0].set_xlabel('X (m)', fontsize=20)
ax[0, 0].set_ylabel('Depth (m)', fontsize=20)
ax[0, 0].set_title(r"$v_{x}$", fontsize=20)
ax[
0, 1].imshow(np.transpose(v2[1].data[0][slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[0, 1].imshow(np.transpose(model.lam.data[slices]), vmin=2.5, vmax=15.0, cmap="jet", alpha=.5, **plt_options_model)
ax[0, 1].set_aspect('auto')
ax[0, 1].set_title(r"$v_{z}$", fontsize=20)
ax[0, 1].set_xlabel('X (m)', fontsize=20)
ax[0, 1].set_ylabel('Depth (m)', fontsize=20)
ax[
1, 0].imshow(np.transpose(tau0[0,0].data[slices]+tau0[1,1].data[slices]),
ax[=-10*scale, vmax=10*scale, cmap="RdGy", **plt_options_model)
vmin1, 0].imshow(np.transpose(model.lam.data[slices]), vmin=2.5, vmax=15.0, cmap="jet",
ax[=.5, **plt_options_model)
alpha1, 0].set_aspect('auto')
ax[1, 0].set_title(r"$\tau_{xx} + \tau_{zz}$", fontsize=20)
ax[1, 0].set_xlabel('X (m)', fontsize=20)
ax[1, 0].set_ylabel('Depth (m)', fontsize=20)
ax[
1, 1].imshow(np.transpose(tau0[0,1].data[slices]), vmin=-scale, vmax=scale, cmap="RdGy", **plt_options_model)
ax[1, 1].imshow(np.transpose(model.lam.data[slices]), vmin=2.5, vmax=15.0, cmap="jet", alpha=.5, **plt_options_model)
ax[1, 1].set_aspect('auto')
ax[1, 1].set_title(r"$\tau_{xy}$", fontsize=20)
ax[1, 1].set_xlabel('X (m)', fontsize=20)
ax[1, 1].set_ylabel('Depth (m)', fontsize=20)
ax[
plt.tight_layout()
#NBVAL_IGNORE_OUTPUT
=model.critical_dt, time_m=int(1000/model.critical_dt)) op(dt
Operator `Kernel` ran in 0.22 s
PerformanceSummary([(PerfKey(name='section0', rank=None),
PerfEntry(time=0.19835300000000017, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section1', rank=None),
PerfEntry(time=0.005520999999999994, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section2', rank=None),
PerfEntry(time=0.005916000000000023, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section3', rank=None),
PerfEntry(time=0.006079000000000015, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])
= rec2.resample(num=1001)
rec2_plot2 = rec3.resample(num=1001) rec3_plot2
#NBVAL_SKIP
# OBC data of vx/vz
=(15, 15))
plt.figure(figsize121)
plt.subplot(=-1e-3, vmax=1e-3, cmap="seismic",
plt.imshow(rec2_plot2.data, vmin='lanczos', extent=extent, aspect=aspect)
interpolation"Time (s)", fontsize=20)
plt.ylabel("Receiver position (m)", fontsize=20)
plt.xlabel(122)
plt.subplot(=-1e-3, vmax=1e-3, cmap="seismic",
plt.imshow(rec3_plot2.data, vmin='lanczos', extent=extent, aspect=aspect)
interpolation"Time (s)", fontsize=20)
plt.ylabel("Receiver position (m)", fontsize=20) plt.xlabel(
Text(0.5, 0, 'Receiver position (m)')
assert np.isclose(norm(rec2), .407183, atol=0, rtol=1e-3)
assert np.isclose(norm(rec3), .209852, atol=0, rtol=1e-3)
Rotated staggered grid
Now let’s use the rotated staggered grid to avoid dispersion and instabilities. This method is usually used for TTI elastic modeling but we show it here for a simplified isotropic case
Simple example of RSFD
We first show the stencil generated by the RSFD method compared to the standard staggered grid method
= model.grid.dimensions[0]
x = Function(name='f', grid=model.grid, space_order=2, staggered=NODE)
f = f.dx, f.dx45 dfdx, dfdxrsfd
dfdx.evaluate
\(\displaystyle \frac{f(x, y)}{h_{x}} - \frac{f(x - h_x, y)}{h_{x}}\)
dfdxrsfd.evaluate
\(\displaystyle \left(- \frac{f(x - h_x, y - h_y)}{4 h_{x}} + \frac{f(x + h_x, y + h_y)}{4 h_{x}}\right) + \left(- \frac{f(x - h_x, y + h_y)}{4 h_{x}} + \frac{f(x + h_x, y - h_y)}{4 h_{x}}\right)\)
Elastic modeling
from devito import div45, grad45
= [[NODE for _ in range(model.grid.dim)] for _ in range(model.grid.dim)]
all_node = [model.grid.dimensions for _ in range(model.grid.dim)]
all_vert
= 8
so = VectorTimeFunction(name='vr', grid=model.grid, space_order=so, time_order=1, staggered=all_vert)
v_rsfd = TensorTimeFunction(name='tr', grid=model.grid, space_order=so, time_order=1, staggered=all_node)
tau_rsfd
# The source injection term
= src.inject(field=v_rsfd.forward.diagonal(), expr=s*src)
src_xx
# First order elastic wave equation
= v_rsfd.dt - ro * div45(tau_rsfd)
pde_v = tau_rsfd.dt - l * diag(div45(v_rsfd.forward)) - mu * (grad45(v_rsfd.forward) + grad45(v_rsfd.forward).transpose(inner=False))
pde_tau # Time update
= Eq(v_rsfd.forward, model.damp * solve(pde_v, v_rsfd.forward))
u_v = Eq(tau_rsfd.forward, model.damp * solve(pde_tau, tau_rsfd.forward))
u_t
# Receiver
= rec.interpolate(expr=tau_rsfd[0, 0] + tau_rsfd[1, 1])
rec_term += rec2.interpolate(expr=v_rsfd[1])
rec_term += rec3.interpolate(expr=v_rsfd[0])
rec_term
= Operator([u_v] + [u_t] + src_xx + rec_term) op
#NBVAL_IGNORE_OUTPUT
=model.critical_dt) op(dt
Operator `Kernel` ran in 0.71 s
PerformanceSummary([(PerfKey(name='section0', rank=None),
PerfEntry(time=0.6343909999999997, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section1', rank=None),
PerfEntry(time=0.017495000000000028, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section2', rank=None),
PerfEntry(time=0.018152000000000022, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section3', rank=None),
PerfEntry(time=0.017839, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),
(PerfKey(name='section4', rank=None),
PerfEntry(time=0.017724000000000007, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])
= rec.resample(num=1001)
rec_plot2 = rec2.resample(num=1001)
rec2_plot2 = rec3.resample(num=1001) rec3_plot2
#NBVAL_SKIP
# 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
=(15, 15))
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(
Text(0.5, 0, 'Receiver position (m)')
#NBVAL_SKIP
# OBC data of vx/vz
=(15, 15))
plt.figure(figsize121)
plt.subplot(=-1e-3, vmax=1e-3, cmap="seismic",
plt.imshow(rec2_plot.data, vmin='lanczos', extent=extent, aspect=aspect)
interpolation"Time (s)", fontsize=20)
plt.ylabel("Receiver position (m)", fontsize=20)
plt.xlabel(122)
plt.subplot(=-1e-3, vmax=1e-3, cmap="seismic",
plt.imshow(rec3_plot.data, vmin='lanczos', extent=extent, aspect=aspect)
interpolation"Time (s)", fontsize=20)
plt.ylabel("Receiver position (m)", fontsize=20) plt.xlabel(
Text(0.5, 0, 'Receiver position (m)')
assert np.isclose(norm(rec), 29.83, atol=0, rtol=1e-3)
assert np.isclose(norm(rec2), 3.4437, atol=0, rtol=1e-3)
assert np.isclose(norm(rec3), 4.5632, atol=0, rtol=1e-3)