Skip to content

Commit e29f062

Browse files
authored
Merge pull request #35 from HPCSys-Lab/variable-density-with-higher-space-orders
variable density with multiple space order
2 parents 5021320 + ff6cab8 commit e29f062

File tree

8 files changed

+212
-44
lines changed

8 files changed

+212
-44
lines changed

examples/acoustic_2D_density.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from simwave import (
2+
SpaceModel, TimeModel, RickerWavelet, Solver, Compiler,
3+
Receiver, Source, plot_wavefield, plot_shotrecord, plot_velocity_model
4+
)
5+
import numpy as np
6+
7+
8+
# set compiler options
9+
# available language options: c (sequential) or cpu_openmp (parallel CPU)
10+
compiler = Compiler(
11+
cc='gcc',
12+
language='cpu_openmp',
13+
cflags='-O3 -fPIC -ffast-math -Wall -std=c99 -shared'
14+
)
15+
16+
# Velocity model
17+
vel = np.zeros(shape=(512, 512), dtype=np.float32)
18+
vel[:] = 1500.0
19+
vel[100:] = 2000.0
20+
21+
# Density model
22+
density = np.zeros(shape=(512, 512), dtype=np.float32)
23+
density[:] = 10
24+
25+
# create the space model
26+
space_model = SpaceModel(
27+
bounding_box=(0, 5120, 0, 5120),
28+
grid_spacing=(10, 10),
29+
velocity_model=vel,
30+
density_model=density,
31+
space_order=2,
32+
dtype=np.float32
33+
)
34+
35+
# config boundary conditions
36+
# (none, null_dirichlet or null_neumann)
37+
space_model.config_boundary(
38+
damping_length=0,
39+
boundary_condition=(
40+
"null_neumann", "null_dirichlet",
41+
"none", "null_dirichlet"
42+
),
43+
damping_polynomial_degree=3,
44+
damping_alpha=0.001
45+
)
46+
47+
# create the time model
48+
time_model = TimeModel(
49+
space_model=space_model,
50+
tf=1.0
51+
)
52+
53+
# create the set of sources
54+
source = Source(
55+
space_model,
56+
coordinates=[(2560, 2560)],
57+
window_radius=1
58+
)
59+
60+
# crete the set of receivers
61+
receiver = Receiver(
62+
space_model=space_model,
63+
coordinates=[(2560, i) for i in range(0, 5120, 10)],
64+
window_radius=1
65+
)
66+
67+
# create a ricker wavelet with 10hz of peak frequency
68+
ricker = RickerWavelet(10.0, time_model)
69+
70+
# create the solver
71+
solver = Solver(
72+
space_model=space_model,
73+
time_model=time_model,
74+
sources=source,
75+
receivers=receiver,
76+
wavelet=ricker,
77+
saving_stride=0,
78+
compiler=compiler
79+
)
80+
81+
# run the forward
82+
u_full, recv = solver.forward()
83+
84+
print("u_full shape:", u_full.shape)
85+
plot_velocity_model(space_model.velocity_model)
86+
plot_wavefield(u_full[-1])
87+
plot_shotrecord(recv)

simwave/kernel/backend/c_code/forward/variable_density/2d/wave.c

+36-11
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// forward_2D_variable_density
1616
double forward(f_type *grid, f_type *velocity, f_type *density, f_type *damp,
1717
f_type *wavelet, size_t wavelet_size,
18-
f_type *coeff, size_t *boundary_conditions,
18+
f_type *coeff_order2, f_type *coeff_order1, size_t *boundary_conditions,
1919
size_t *src_points_interval, size_t src_points_interval_size,
2020
f_type *src_points_values, size_t src_points_values_size,
2121
size_t *rec_points_interval, size_t rec_points_interval_size,
@@ -96,20 +96,45 @@ double forward(f_type *grid, f_type *velocity, f_type *density, f_type *damp,
9696
// index of the current point in the grid
9797
size_t current = i * nx + j;
9898

99-
//neighbors in the horizontal direction
100-
f_type x1 = ((prev_snapshot[current + 1] - prev_snapshot[current]) * (density[current + 1] + density[current])) / density[current + 1];
101-
f_type x2 = ((prev_snapshot[current] - prev_snapshot[current - 1]) * (density[current] + density[current - 1])) / density[current - 1];
102-
f_type term_x = (x1 - x2) / (2 * dxSquared);
99+
// stencil code to update grid
100+
f_type value = 0.0;
103101

104-
//neighbors in the vertical direction
105-
f_type z1 = ((prev_snapshot[current + nx] - prev_snapshot[current]) * (density[current + nx] + density[current])) / density[current + nx];
106-
f_type z2 = ((prev_snapshot[current] - prev_snapshot[current - nx]) * (density[current] + density[current - nx])) / density[current - nx];
107-
f_type term_z = (z1 - z2) / (2 * dzSquared);
102+
// second derivative for pressure
103+
f_type sd_pressure_x = coeff_order2[0] * prev_snapshot[current];
104+
f_type sd_pressure_z = coeff_order2[0] * prev_snapshot[current];
108105

109-
//nominator with damp coefficient
106+
// first derivative for pressure
107+
f_type fd_pressure_x = 0.0;
108+
f_type fd_pressure_z = 0.0;
109+
110+
// first derivative for density
111+
f_type fd_density_x = 0.0;
112+
f_type fd_density_z = 0.0;
113+
114+
// radius of the stencil
115+
for(int ir = 1; ir <= stencil_radius; ir++){
116+
//neighbors in the horizontal direction
117+
sd_pressure_x += coeff_order2[ir] * (prev_snapshot[current + ir] + prev_snapshot[current - ir]);
118+
fd_pressure_x += coeff_order1[ir] * (prev_snapshot[current + ir] - prev_snapshot[current - ir]);
119+
fd_density_x += coeff_order1[ir] * (density[current + ir] - density[current - ir]);
120+
121+
//neighbors in the vertical direction
122+
sd_pressure_z += coeff_order2[ir] * (prev_snapshot[current + (ir * nx)] + prev_snapshot[current - (ir * nx)]);
123+
fd_pressure_z += coeff_order1[ir] * (prev_snapshot[current + (ir * nx)] - prev_snapshot[current - (ir * nx)]);
124+
fd_density_z += coeff_order1[ir] * (density[current + (ir * nx)] - density[current - (ir * nx)]);
125+
}
126+
127+
value += sd_pressure_x/dxSquared + sd_pressure_z/dzSquared;
128+
129+
f_type term_x = (fd_pressure_x * fd_density_x) / (2 * dxSquared);
130+
f_type term_z = (fd_pressure_z * fd_density_z) / (2 * dzSquared);
131+
132+
value -= (term_x + term_z) / density[current];
133+
134+
//denominator with damp coefficient
110135
f_type denominator = (1.0 + damp[current] * dt);
111136

112-
f_type value = dtSquared * velocity[current] * velocity[current] * (term_z + term_x) / denominator;
137+
value *= (dtSquared * velocity[current] * velocity[current]) / denominator;
113138

114139
next_snapshot[current] = 2.0 / denominator * prev_snapshot[current] - ((1.0 - damp[current] * dt) / denominator) * next_snapshot[current] + value;
115140
}

simwave/kernel/backend/c_code/forward/variable_density/3d/wave.c

+44-16
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// forward_3D_variable_density
1616
double forward(f_type *grid, f_type *velocity, f_type *density, f_type *damp,
1717
f_type *wavelet, size_t wavelet_size,
18-
f_type *coeff, size_t *boundary_conditions,
18+
f_type *coeff_order2, f_type *coeff_order1, size_t *boundary_conditions,
1919
size_t *src_points_interval, size_t src_points_interval_size,
2020
f_type *src_points_values, size_t src_points_values_size,
2121
size_t *rec_points_interval, size_t rec_points_interval_size,
@@ -101,28 +101,56 @@ double forward(f_type *grid, f_type *velocity, f_type *density, f_type *damp,
101101
// index of the current point in the grid
102102
size_t current = (i * nx + j) * ny + k;
103103

104-
//neighbors in the Y direction
105-
f_type y1 = ((prev_snapshot[current + 1] - prev_snapshot[current]) * (density[current + 1] + density[current])) / density[current + 1];
106-
f_type y2 = ((prev_snapshot[current] - prev_snapshot[current - 1]) * (density[current] + density[current - 1])) / density[current - 1];
107-
f_type term_y = (y1 - y2) / (2 * dySquared);
104+
// stencil code to update grid
105+
f_type value = 0.0;
108106

109-
//neighbors in the X direction
110-
f_type x1 = ((prev_snapshot[current + ny] - prev_snapshot[current]) * (density[current + ny] + density[current])) / density[current + ny];
111-
f_type x2 = ((prev_snapshot[current] - prev_snapshot[current - ny]) * (density[current] + density[current - ny])) / density[current - ny];
112-
f_type term_x = (x1 - x2) / (2 * dxSquared);
107+
// second derivative for pressure
108+
f_type sd_pressure_y = coeff_order2[0] * prev_snapshot[current];
109+
f_type sd_pressure_x = coeff_order2[0] * prev_snapshot[current];
110+
f_type sd_pressure_z = coeff_order2[0] * prev_snapshot[current];
113111

114-
//neighbors in the Z direction
115-
f_type z1 = ((prev_snapshot[current + (nx * ny)] - prev_snapshot[current]) * (density[current + (nx * ny)] + density[current])) / density[current + (nx * ny)];
116-
f_type z2 = ((prev_snapshot[current] - prev_snapshot[current - (nx * ny)]) * (density[current] + density[current - (nx * ny)])) / density[current - (nx * ny)];
117-
f_type term_z = (z1 - z2) / (2 * dzSquared);
112+
// first derivative for pressure
113+
f_type fd_pressure_y = 0.0;
114+
f_type fd_pressure_x = 0.0;
115+
f_type fd_pressure_z = 0.0;
118116

119-
//nominator with damp coefficient
117+
// first derivative for density
118+
f_type fd_density_y = 0.0;
119+
f_type fd_density_x = 0.0;
120+
f_type fd_density_z = 0.0;
121+
122+
// radius of the stencil
123+
for(int ir = 1; ir <= stencil_radius; ir++){
124+
//neighbors in the Y direction
125+
sd_pressure_y += coeff_order2[ir] * (prev_snapshot[current + ir] + prev_snapshot[current - ir]);
126+
fd_pressure_y += coeff_order1[ir] * (prev_snapshot[current + ir] - prev_snapshot[current - ir]);
127+
fd_density_y += coeff_order1[ir] * (density[current + ir] - density[current - ir]);
128+
129+
//neighbors in the X direction
130+
sd_pressure_x += coeff_order2[ir] * (prev_snapshot[current + (ir * ny)] + prev_snapshot[current - (ir * ny)]);
131+
fd_pressure_x += coeff_order1[ir] * (prev_snapshot[current + (ir * nx)] - prev_snapshot[current - (ir * nx)]);
132+
fd_density_x += coeff_order1[ir] * (density[current + (ir * nx)] - density[current - (ir * nx)]);
133+
134+
//neighbors in the Z direction
135+
sd_pressure_z += coeff_order2[ir] * (prev_snapshot[current + (ir * nx * ny)] + prev_snapshot[current - (ir * nx * ny)]);
136+
fd_pressure_z += coeff_order1[ir] * (prev_snapshot[current + (ir * nx * ny)] - prev_snapshot[current - (ir * nx * ny)]);
137+
fd_density_z += coeff_order1[ir] * (density[current + (ir * nx * ny)] - density[current - (ir * nx * ny)]);
138+
}
139+
140+
value += sd_pressure_y/dySquared + sd_pressure_x/dxSquared + sd_pressure_z/dzSquared;
141+
142+
f_type term_y = (fd_pressure_y * fd_density_y) / (2 * dySquared);
143+
f_type term_x = (fd_pressure_x * fd_density_x) / (2 * dxSquared);
144+
f_type term_z = (fd_pressure_z * fd_density_z) / (2 * dzSquared);
145+
146+
value -= (term_y + term_x + term_z) / density[current];
147+
148+
//denominator with damp coefficient
120149
f_type denominator = (1.0 + damp[current] * dt);
121150

122-
f_type value = dtSquared * velocity[current] * velocity[current] * (term_z + term_x + term_y) / denominator;
151+
value *= (dtSquared * velocity[current] * velocity[current]) / denominator;
123152

124153
next_snapshot[current] = 2.0 / denominator * prev_snapshot[current] - ((1.0 - damp[current] * dt) / denominator) * next_snapshot[current] + value;
125-
126154
}
127155
}
128156
}

simwave/kernel/backend/middleware.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,10 @@ def exec(self, operator, **kwargs):
7474
kwargs.update({'boundary_condition': bc})
7575

7676
# if density model is None, remove it
77+
# and remove first_order_fd_coefficients
7778
if kwargs.get('density_model') is None:
7879
kwargs.pop('density_model')
80+
kwargs.pop('first_order_fd_coefficients')
7981

8082
# get the grid shape
8183
grid_shape = kwargs.get('velocity_model').shape
@@ -168,7 +170,8 @@ def _keys_in_order(self):
168170
'damping_mask',
169171
'wavelet',
170172
'wavelet_size',
171-
'fd_coefficients',
173+
'second_order_fd_coefficients',
174+
'first_order_fd_coefficients',
172175
'boundary_condition',
173176
'src_points_interval',
174177
'src_points_interval_size',

simwave/kernel/frontend/fd.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
import findiff
33

44

5-
def half_coefficients(space_order):
5+
def half_coefficients(derivative_order, space_order):
66
"""
77
Return a list of right side finite differences coefficients
8-
according to the space order.
8+
according to the space order and derivative order.
99
1010
Parameters
1111
----------
@@ -18,7 +18,7 @@ def half_coefficients(space_order):
1818
List of FD coefficients.
1919
"""
2020
# all coefficients
21-
coeffs = coefficients(space_order)
21+
coeffs = coefficients(derivative_order, space_order)
2222

2323
middle = len(coeffs) // 2
2424

@@ -28,13 +28,15 @@ def half_coefficients(space_order):
2828
return coeffs
2929

3030

31-
def coefficients(space_order):
31+
def coefficients(derivative_order, space_order):
3232
"""
3333
Return a list of finite differences coefficients according
34-
to the space order.
34+
to the space order and derivative order.
3535
3636
Parameters
3737
----------
38+
derivative_order : int
39+
Derivative order
3840
space_order : int
3941
Spatial order.
4042
@@ -45,7 +47,7 @@ def coefficients(space_order):
4547
"""
4648

4749
# fixed second derivative
48-
coeffs = findiff.coefficients(deriv=2, acc=space_order)
50+
coeffs = findiff.coefficients(deriv=derivative_order, acc=space_order)
4951

5052
return coeffs['center']['coefficients']
5153

@@ -77,7 +79,10 @@ def calculate_dt(dimension, space_order, grid_spacing, velocity_model):
7779
a1 = 4
7880

7981
# FD coeffs to the specific space order
80-
fd_coeffs = coefficients(space_order)
82+
fd_coeffs = coefficients(
83+
derivative_order=2,
84+
space_order=space_order
85+
)
8186

8287
a2 = dimension * np.sum(np.abs(fd_coeffs))
8388

simwave/kernel/frontend/model.py

+26-7
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,16 @@ def __init__(self, bounding_box, grid_spacing, velocity_model,
3838

3939
self._space_order = space_order
4040

41-
# space_order are limited to even number and limited up to 20
42-
if space_order % 2 != 0 or space_order < 2 or space_order > 20:
41+
# space_order are limited to even number
42+
if space_order % 2 != 0:
4343
raise ValueError(
44-
"Space order {} not supported".format(space_order)
44+
"Odd space order {} not supported".format(space_order)
45+
)
46+
47+
# space_order are limited from 2 to 20
48+
if not 2 <= space_order <= 20:
49+
raise ValueError(
50+
"Space order limited from 2 to 20."
4551
)
4652

4753
# get the space dimension according to the velocity model
@@ -205,10 +211,23 @@ def damping_alpha(self):
205211
except AttributeError:
206212
return 0.001
207213

208-
@property
209-
def fd_coefficients(self):
210-
"""Central and right side finite differences coefficients."""
211-
return self.dtype(fd.half_coefficients(self.space_order))
214+
def fd_coefficients(self, derivative_order):
215+
"""
216+
Central and right side finite differences coefficients.
217+
218+
Parameters
219+
----------
220+
derivative_order : int
221+
Derivative order.
222+
223+
Returns
224+
----------
225+
ndarray
226+
Central and right side FD coefficients.
227+
"""
228+
return self.dtype(
229+
fd.half_coefficients(derivative_order, self.space_order)
230+
)
212231

213232
def interpolate(self, data):
214233
"""

simwave/kernel/frontend/solver.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ def forward(self):
147147
damping_mask=self.space_model.damping_mask,
148148
wavelet=self.wavelet.values,
149149
wavelet_size=len(self.wavelet.values),
150-
fd_coefficients=self.space_model.fd_coefficients,
150+
second_order_fd_coefficients=self.space_model.fd_coefficients(2),
151+
first_order_fd_coefficients=self.space_model.fd_coefficients(1),
151152
boundary_condition=self.space_model.boundary_condition,
152153
src_points_interval=src_points,
153154
src_points_interval_size=len(src_points),

tests/test_space_model.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def test_fd_coefficients(self, time_order, space_order, coeffs):
153153
)
154154

155155
assert np.allclose(
156-
space_model.fd_coefficients,
156+
space_model.fd_coefficients(2),
157157
np.asarray(coeffs, dtype=space_model.dtype)
158158
)
159159

0 commit comments

Comments
 (0)