This notebook implements, for a given initial density profile, a solver for the 2D diffusion equation using an explicit finite difference scheme with 'do-nothing' conditions on the boundaries (and hence will not provide a reasonable solution once the profile has diffused to a boundary).
In [1]:
# Some imports we will need below
import numpy as np
from devito import *
import matplotlib.pyplot as plt
%matplotlib inline
In [2]:
nx, ny = 100, 100
grid = Grid(shape=(nx, ny))
To represent the density, we use a TimeFunction
-- a scalar, discrete function encapsulating space- and time-varying data. We also use a Constant
for the diffusion coefficient.
In [3]:
u = TimeFunction(name='u', grid=grid, space_order=2, save=200)
c = Constant(name='c')
The 2D diffusion equation is expressed as:
In [4]:
eqn = Eq(u.dt, c * u.laplace)
From this diffusion equation we derive our time-marching method -- at each timestep, we compute u
at timestep t+1
, which in the Devito language is represented by u.forward
. Hence:
In [5]:
step = Eq(u.forward, solve(eqn, u.forward))
OK, it's time to let Devito generate code for our solver!
In [6]:
op = Operator([step])
Before executing the Operator
we must first specify the initial density profile. Here, we place a "ring" with a constant density value in the center of the domain.
In [7]:
xx, yy = np.meshgrid(np.linspace(0., 1., nx, dtype=np.float32),
np.linspace(0., 1., ny, dtype=np.float32))
r = (xx - .5)**2. + (yy - .5)**2.
# Inserting the ring
u.data[0, np.logical_and(.05 <= r, r <= .1)] = 1.
We're now ready to execute the Operator
. We run it with a diffusion coefficient of 0.5 and for a carefully chosen dt
. Unless specified otherwise, the simulation runs for 199 timesteps as specified in the definition of u
(i.e. the function was defined with save=200
the initial data + 199 new timesteps).
In [8]:
stats = op.apply(dt=5e-05, c=0.5)
In [9]:
plt.rcParams['figure.figsize'] = (20, 20)
for i in range(1, 6):
plt.subplot(1, 6, i)
plt.imshow(u.data[(i-1)*40])
plt.show()
In [10]:
# Instead of `platform=nvidiaX`, you may run your Python code with the environment variable `DEVITO_PLATFORM=nvidiaX`
op = Operator([step], platform='nvidiaX')
That's it! We can now run it exactly as before
In [11]:
# Uncomment and run only if Devito was installed with GPU support.
# stats = op.apply(dt=5e-05, c=0.5)
We should see a big performance difference between the two runs. We can also inspect op
to see what Devito has generated to run on the GPU
In [12]:
print(op)