forked from xiaoguoguo626807/deepxde
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add documentation for diffusion-reaction demo (lululxvi#1012)
- Loading branch information
Showing
2 changed files
with
181 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
Diffusion-reaction equation | ||
=========================== | ||
|
||
Problem setup | ||
-------------- | ||
|
||
We will solve the following 1D diffusion-reaction equation: | ||
|
||
.. math:: \frac{\partial y}{\partial t} = d \frac{\partial^2 y}{\partial x^2} + e^{-t} (3\frac{\sin{2x}}{2} + \frac{8\sin{3x}}{3} + \frac{15\sin{4x}}{4} + \frac{63\sin{8x}}{8}) | ||
|
||
with the initial condition | ||
|
||
.. math:: y(x, 0) = \sin{x} + \frac{\sin{2x}}{2} + \frac{\sin{3x}}{3} + \frac{\sin{4x}}{4} + \frac{\sin{8x}}{8}, \quad x \in [-\pi, \pi] | ||
|
||
and the Dirichlet boundary condition | ||
|
||
.. math:: y(t, -\pi) = y(t, \pi) = 0, \quad t \in [0, 1] | ||
|
||
We also specify the following parameters for the equation: | ||
|
||
.. math:: d = 1 | ||
|
||
The exact solution is | ||
|
||
.. math:: y(x, t) = e^{-t}( \sin{x} + \frac{\sin{2x}}{2} + \frac{\sin{3x}}{3} + \frac{\sin{4x}}{4} + \frac{\sin{8x}}{8}) | ||
|
||
Implementation | ||
-------------- | ||
|
||
This description goes through the implementation of a solver for the above described diffusion-reaction equation step-by-step. | ||
|
||
First, DeepXDE, Numpy and Tensorflow libraries are imported: | ||
|
||
.. code-block:: python | ||
import DeepXDE as dde | ||
import numpy as np | ||
import tensorflow as tf | ||
Next, we express the PDE residual of the diffusion-reaction equation: | ||
|
||
.. code-block:: python | ||
def pde(x, y): | ||
dy_t = dde.grad.jacobian(y, x, i=0, j=1) | ||
dy_xx = dde.grad.hessian(y, x, i=0, j=0) | ||
d = 1 | ||
# Backend tensorflow.compact.v1 or tensorflow | ||
return ( | ||
dy_t | ||
- d * dy_xx | ||
- tf.exp(-x[:, 1:]) | ||
* ( | ||
3 * tf.sin(2 * x[:, 0:1]) / 2 | ||
+ 8 * tf.sin(3 * x[:, 0:1]) / 3 | ||
+ 15 * tf.sin(4 * x[:, 0:1]) / 4 | ||
+ 63 * tf.sin(8 * x[:, 0:1]) / 8 | ||
) | ||
) | ||
If the backend is Pytorch, the residual should look like this: | ||
|
||
.. code-block:: python | ||
def pde(x, y): | ||
dy_t = dde.grad.jacobian(y, x, i=0, j=1) | ||
dy_xx = dde.grad.hessian(y, x, i=0, j=0) | ||
d = 1 | ||
# Backend pytorch | ||
return ( | ||
dy_t | ||
- d * dy_xx | ||
- torch.exp(-x[:, 1:]) | ||
* ( | ||
3 * torch.sin(2 * x[:, 0:1]) / 2 | ||
+ 8 * torch.sin(3 * x[:, 0:1]) / 3 | ||
+ 15 * torch.sin(4 * x[:, 0:1]) / 4 | ||
+ 63 * torch.sin(8 * x[:, 0:1]) / 8 | ||
) | ||
) | ||
The first argument to ``pde`` is the 2 dimensional vector where the first component(``x[:, 0]``) is the :math:`x`-coordinate, and the second component(``x[:, 1]``) is the :math:`t`-coordinate. The second argument is the network output, i.e., the solution :math:`u(x)`, but here we use ``y`` as the name of the variable. | ||
|
||
Then we define the solution to the PDE: | ||
|
||
.. code-block:: python | ||
def func(x): | ||
return np.exp(-x[:, 1:]) * ( | ||
np.sin(x[:, 0:1]) | ||
+ np.sin(2 * x[:, 0:1]) / 2 | ||
+ np.sin(3 * x[:, 0:1]) / 3 | ||
+ np.sin(4 * x[:, 0:1]) / 4 | ||
+ np.sin(8 * x[:, 0:1]) / 8 | ||
) | ||
Now we can define a computational geometry and time domain. We can use a built-in class ``Interval`` and ``TimeDomain`` and we combine both the domains using ``GeometryXTime`` as follows | ||
|
||
.. code-block:: python | ||
geom = dde.geometry.Interval(-1, 1) | ||
timedomain = dde.geometry.TimeDomain(0, 0.99) | ||
geomtime = dde.geometry.GeometryXTime(geom, timedomain) | ||
Now, we have specified the geometry and the PDE residual. We then define the ``TimePDE`` problem as | ||
|
||
.. code-block:: python | ||
data = dde.data.TimePDE( | ||
geomtime, pde, [], num_domain=320, solution=func, num_test=80000 | ||
) | ||
The number 320 is the number of training residual points sampled inside the domain, and the number 80000 is the number of points sampled inside | ||
the domain for testing the PDE loss. | ||
|
||
Next, we choose the network. Here, we use a fully connected neural network of depth 7 (i.e., 6 hidden layers) and width 30: | ||
|
||
.. code-block:: python | ||
layer_size = [2] + [30] * 6 + [1] | ||
activation = "tanh" | ||
initializer = "Glorot uniform" | ||
net = dde.nn.FNN(layer_size, activation, initializer) | ||
Then we construct a function that satisfies both the initial and the boundary conditions to tansform the network output. | ||
In this case, :math:`t(\pi^2 - x^2)y + \sin{x} + \frac{\sin{2x}}{2} + \frac{\sin{3x}}{3} + \frac{\sin{4x}}{4} + \frac{\sin{8x}}{8}` is used. | ||
If :math:`t` is equal to 0, the initial condition is recovered. When :math:`x` is equal to :math:`-\pi` or :math:`\pi`, the boundary condition is recovered. | ||
Hence the initial and boundary conditions are both hard conditions. | ||
|
||
.. code-block:: python | ||
def output_transform(x, y): | ||
return ( | ||
x[:, 1:2] * (np.pi ** 2 - x[:, 0:1] ** 2) * y | ||
+ tf.sin(x[:, 0:1]) | ||
+ tf.sin(2 * x[:, 0:1]) / 2 | ||
+ tf.sin(3 * x[:, 0:1]) / 3 | ||
+ tf.sin(4 * x[:, 0:1]) / 4 | ||
+ tf.sin(8 * x[:, 0:1]) / 8 | ||
) | ||
net.apply_output_transform(output_transform) | ||
If the backend is Pytorch, the code should look like this: | ||
|
||
.. code-block:: python | ||
def output_transform(x, y): | ||
return ( | ||
x[:, 1:2] * (np.pi ** 2 - x[:, 0:1] ** 2) * y | ||
+ torch.sin(x[:, 0:1]) | ||
+ torch.sin(2 * x[:, 0:1]) / 2 | ||
+ torch.sin(3 * x[:, 0:1]) / 3 | ||
+ torch.sin(4 * x[:, 0:1]) / 4 | ||
+ torch.sin(8 * x[:, 0:1]) / 8 | ||
) | ||
net.apply_output_transform(output_transform) | ||
Now, we have the PDE problem and the network. We build a ``Model`` and choose the optimizer and learning rate. We then train the model for 20000 iterations. | ||
|
||
.. code-block:: python | ||
model = dde.Model(data, net) | ||
model.compile("adam", lr=1e-3, metrics=["l2 relative error"]) | ||
losshistory, train_state = model.train(iterations=20000) | ||
We also save and plot the best trained result and loss history. | ||
|
||
.. code-block:: python | ||
dde.saveplot(losshistory, train_state, issave=True, isplot=True) | ||
Complete code | ||
------------- | ||
|
||
.. literalinclude:: ../../../examples/pinn_forward/diffusion_reaction.py | ||
:language: python |