Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a linear elasticity example #1506

Merged
merged 30 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
422471a
Upload linear elasticity example
ww382 Oct 3, 2023
199c1f6
Update solution function
ww382 Oct 3, 2023
6e1437e
Fix format
ww382 Oct 3, 2023
10f604f
Update docs/demos/pinn_forward/elasticity.plate.rst
ww382 Oct 4, 2023
cd79874
Update docs/demos/pinn_forward/elasticity.plate.rst
ww382 Oct 4, 2023
f5a75ce
Update docs/demos/pinn_forward/elasticity.plate.rst
ww382 Oct 4, 2023
7e041d7
Update docs/demos/pinn_forward/elasticity.plate.rst
ww382 Oct 4, 2023
af3383f
Update docs/demos/pinn_forward/elasticity.plate.rst
ww382 Oct 4, 2023
e8a580e
Update docs/demos/pinn_forward/elasticity.plate.rst
ww382 Oct 4, 2023
f4799ec
Update elasticity.plate.rst format
ww382 Oct 4, 2023
f17f2a6
Update elasticity.plate.rst
ww382 Oct 4, 2023
42763d4
Merge branch 'lululxvi:master' into master
ww382 Oct 11, 2023
eef30d8
Update elasticity.plate.rst
ww382 Oct 11, 2023
2fa3c64
Update elasticity.plate.rst
ww382 Oct 11, 2023
0628fee
Update elasticity.plate.rst
ww382 Oct 11, 2023
dd426b1
Update elasticity.plate.rst
ww382 Oct 11, 2023
80d9119
Update elasticity.plate.rst
ww382 Oct 11, 2023
9b9613d
Delete .DS_Store
ww382 Oct 12, 2023
062feca
Update elasticity_plate_2d.py
ww382 Oct 13, 2023
0180dd1
Update elasticity_plate_2d.py
ww382 Oct 14, 2023
c8e91f0
Update elasticity_plate_2d.py
ww382 Oct 14, 2023
8ea354a
Update docs/demos/pinn_forward/elasticity.plate.rst
ww382 Oct 15, 2023
5d18bb9
Update docs/demos/pinn_forward/elasticity.plate.rst
ww382 Oct 15, 2023
cb7f0eb
Update elasticity.plate.rst
ww382 Oct 15, 2023
1a075b4
Update elasticity.plate.rst
ww382 Oct 15, 2023
0a1c89d
Update elasticity.plate.rst
ww382 Oct 15, 2023
8829737
Update elasticity.plate.rst
ww382 Oct 15, 2023
6059f67
Update elasticity.plate.rst
ww382 Oct 15, 2023
1aaf56b
Update filename
ww382 Oct 16, 2023
8471ed2
Update elasticity.plate.rst
ww382 Oct 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/demos/pinn_forward.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Time-independent PDEs
pinn_forward/poisson.Lshape
pinn_forward/laplace.disk
pinn_forward/eulerbeam
pinn_forward/elasticity.plate
pinn_forward/helmholtz.2d.dirichlet
pinn_forward/helmholtz.2d.dirichlet.hpo
pinn_forward/helmholtz.2d.neumann.hole
Expand Down
267 changes: 267 additions & 0 deletions docs/demos/pinn_forward/elasticity.plate.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
Linear elastostatic equation over a 2D square domain
==========

Problem setup
--------------

We will solve a 2D linear elasticity solid mechanic problem:

.. math:: \frac{\partial \sigma_{xx}}{\partial x} + \frac{\partial \sigma_{xy}}{\partial y} + f_x= 0, \quad
\frac{\partial \sigma_{xy}}{\partial x} + \frac{\partial \sigma_{yy}}{\partial y} + f_y= 0,

.. math:: x \in [0, 1], \quad y \in [0, 1],

where the linear elastic constitutive model is defined as

.. math:: \sigma_{xx} = (\lambda + 2\mu)\epsilon_{xx} + \lambda\epsilon_{yy}, \quad
\sigma_{yy} = (\lambda + 2\mu)\epsilon_{yy} + \lambda\epsilon_{xx}, \quad
\sigma_{xy} = 2\mu\epsilon_{xy},

with kinematic relation

.. math:: \epsilon_{xx} = \frac{\partial u_{x}}{\partial x}, \quad
\epsilon_{yy} = \frac{\partial u_{y}}{\partial y}, \quad
\epsilon_{xy} = \frac{1}{2}(\frac{\partial u_{x}}{\partial y} + \frac{\partial u_{y}}{\partial x}).

The 2D square domain is subjected to body forces:

.. math:: f_x = \lambda[4\pi^2cos(2\pi x)sin(\pi y) - \pi cos(\pi x)Qy^3] +
ww382 marked this conversation as resolved.
Show resolved Hide resolved
ww382 marked this conversation as resolved.
Show resolved Hide resolved

.. math:: \mu[9\pi^2cos(2\pi x)sin(\pi y) - \pi cos(\pi x)Qy^3],
ww382 marked this conversation as resolved.
Show resolved Hide resolved

.. math:: f_y = \lambda[-3sin(\pi x)Qy^2 + 2\pi^2sin(2\pi x) cos(\pi y)] +

.. math:: \mu[-6 sin(\pi x)Qy^2 + 2 \pi^2 sin(2\pi x)cos(\pi y) + \pi^2 sin(\pi x)Qy^4/4],

with displacement boundary conditions

.. math:: u_x(x, 0) = u_x(x, 1) = 0,
.. math:: u_y(0, y) = u_y(1, y) = u_y(x, 0) = 0,

and traction boundary conditions

.. math:: \sigma_{xx}(0, y)=0, \quad \sigma_{xx}(1, y)=0, \quad \sigma_{yy}(x, 1)=(\lambda + 2\mu)Qsin(\pi x).

We set parameters :math:`\lambda = 1,` :math:`\mu = 0.5,` and :math:`Q = 4.`

The exact solution is :math:`u_x(x, y) = cos(2\pi x)sin(\pi y)` and :math:`u_y(x, y) = sin(\pi x)Qy^4/4.`

Implementation
--------------

This description goes through the implementation of a solver for the above described linear elasticity problem step-by-step.

First, the DeepXDE, NumPy (``np``) and PyTorch (``torch``) modules are imported:

.. code-block:: python

import deepxde as dde
import numpy as np
from deepxde.backend import torch


We begin by defining the general parameters for the problem.

.. code-block:: python

lmbd = 1.0
mu = 0.5
Q = 4.0
pi = torch.pi

Next, we define a computational geometry. We can use a built-in class ``Rectangle`` as follows

.. code-block:: python

geom = dde.geometry.Rectangle([0, 0], [1, 1])


Next, we consider the left, right, top, and bottom boundary conditions. Two boundary conditions are applied on the left boundary. The location of the boundary conditions is defined by a simple Python function. The function should return ``True`` for those points satisfying :math:`x[0]=0` and ``False`` otherwise (Note that because of rounding-off errors, it is often wise to use ``dde.utils.isclose`` to test whether two floating point values are equivalent). In the functions below, the argument ``x`` to ``boundary`` is the network input and is a :math:`d`-dim vector, where :math:`d` is the dimension and :math:`d=1` in this case. Then a boolean ``on_boundary`` is used as the second argument. If the point ``x`` (the first argument) is on the boundary of the geometry, then ``on_boundary`` is ``True``, otherwise, ``on_boundary`` is ``False``.

.. code-block:: python

def boundary_left(x, on_boundary):
return on_boundary and dde.utils.isclose(x[0], 0.0)

Two boundary conditions are applied on the right boundary. Similar to ``boundary_left``, the location of these two boundary condition is defined in a similar way that the function should return ``True`` for those points satisfying :math:`x[0]=1` and ``False`` otherwise.

.. code-block:: python

def boundary_right(x, on_boundary):
return on_boundary and dde.utils.isclose(x[0], 1.0)

Two boundary conditions are applied on the top boundary.

.. code-block:: python

def boundary_top(x, on_boundary):
return on_boundary and dde.utils.isclose(x[1], 1.0)

Two boundary conditions are applied on the bottom boundary.

.. code-block:: python

def boundary_bottom(x, on_boundary):
return on_boundary and dde.utils.isclose(x[1], 0.0)

Next, for better comparsion, we define a function which is the exact solution to the problem.

.. code-block:: python

def func(x):
ux = np.cos(2 * np.pi * x[:, 0:1]) * np.sin(np.pi * x[:, 1:2])
uy = np.sin(pi * x[:, 0:1]) * Q * x[:, 1:2] ** 4 / 4

E_xx = -2 * np.pi * np.sin(2 * np.pi * x[:, 0:1]) * np.sin(np.pi * x[:, 1:2])
E_yy = np.sin(pi * x[:, 0:1]) * Q * x[:, 1:2] ** 3
E_xy = 0.5 * (
np.pi * np.cos(2 * np.pi * x[:, 0:1]) * np.cos(np.pi * x[:, 1:2])
+ np.pi * np.cos(np.pi * x[:, 0:1]) * Q * x[:, 1:2] ** 4 / 4
)

Sxx = E_xx * (2 * mu + lmbd) + E_yy * lmbd
Syy = E_yy * (2 * mu + lmbd) + E_xx * lmbd
Sxy = 2 * E_xy * mu

return np.hstack((ux, uy, Sxx, Syy, Sxy))

The displacement boundary conditions on the boundary are defined as follows.

.. code-block:: python

ux_top_bc = dde.icbc.DirichletBC(geom, lambda x: 0, boundary_top, component=0)
ux_bottom_bc = dde.icbc.DirichletBC(geom, lambda x: 0, boundary_bottom, component=0)
uy_left_bc = dde.icbc.DirichletBC(geom, lambda x: 0, boundary_left, component=1)
uy_bottom_bc = dde.icbc.DirichletBC(geom, lambda x: 0, boundary_bottom, component=1)
uy_right_bc = dde.icbc.DirichletBC(geom, lambda x: 0, boundary_right, component=1)

Similarly, the traction boundary conditions are defined as,

.. code-block:: python

sxx_left_bc = dde.icbc.DirichletBC(geom, lambda x: 0, boundary_left, component=2)
sxx_right_bc = dde.icbc.DirichletBC(geom, lambda x: 0, boundary_right, component=2)
syy_top_bc = dde.icbc.DirichletBC(
geom,
lambda x: (2 * mu + lmbd) * Q * np.sin(pi * x[:, 0:1]),
boundary_top,
component=3,
)

Next, we define the body forces,
ww382 marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: python

def fx(x):
return (
-lmbd
* (
4 * pi**2 * torch.cos(2 * pi * x[:, 0:1]) * torch.sin(pi * x[:, 1:2])
- Q * x[:, 1:2] ** 3 * pi * torch.cos(pi * x[:, 0:1])
)
- mu
* (
pi**2 * torch.cos(2 * pi * x[:, 0:1]) * torch.sin(pi * x[:, 1:2])
- Q * x[:, 1:2] ** 3 * pi * torch.cos(pi * x[:, 0:1])
)
- 8 * mu * pi**2 * torch.cos(2 * pi * x[:, 0:1]) * torch.sin(pi * x[:, 1:2])
)


def fy(x):
return (
lmbd
* (
3 * Q * x[:, 1:2] ** 2 * torch.sin(pi * x[:, 0:1])
- 2 * pi**2 * torch.cos(pi * x[:, 1:2]) * torch.sin(2 * pi * x[:, 0:1])
)
- mu
* (
2 * pi**2 * torch.cos(pi * x[:, 1:2]) * torch.sin(2 * pi * x[:, 0:1])
+ (Q * x[:, 1:2] ** 4 * pi**2 * torch.sin(pi * x[:, 0:1])) / 4
)
+ 6 * Q * mu * x[:, 1:2] ** 2 * torch.sin(pi * x[:, 0:1])
)

Next, we express the PDE residuals of the momentum equation and the constitutive law.

.. code-block:: python

def pde(x, f):
E_xx = dde.grad.jacobian(f, x, i=0, j=0)
E_yy = dde.grad.jacobian(f, x, i=1, j=1)
E_xy = 0.5 * (dde.grad.jacobian(f, x, i=0, j=1) + dde.grad.jacobian(f, x, i=1, j=0))

S_xx = E_xx * (2 * mu + lmbd) + E_yy * lmbd
S_yy = E_yy * (2 * mu + lmbd) + E_xx * lmbd
S_xy = E_xy * 2 * mu

Sxx_x = dde.grad.jacobian(f, x, i=2, j=0)
Syy_y = dde.grad.jacobian(f, x, i=3, j=1)
Sxy_x = dde.grad.jacobian(f, x, i=4, j=0)
Sxy_y = dde.grad.jacobian(f, x, i=4, j=1)

momentum_x = Sxx_x + Sxy_y - fx(x)
momentum_y = Sxy_x + Syy_y - fy(x)

stress_x = S_xx - f[:, 2:3]
stress_y = S_yy - f[:, 3:4]
stress_xy = S_xy - f[:, 4:5]

return [momentum_x, momentum_y, stress_x, stress_y, stress_xy]

The first argument to ``pde`` is the network input, i.e., the :math:`x` and `y` -coordinate. The second argument is the network output, i.e., the solution :math:`u_x(x, y)`, but here we use ``f`` as the name of the variable.


Now, we have specified the geometry, PDE residuals, and boundary conditions. We then define the PDE problem as

.. code-block:: python

data = dde.data.PDE(
geom,
pde,
[
ux_top_bc,
ux_bottom_bc,
uy_left_bc,
uy_bottom_bc,
uy_right_bc,
sxx_left_bc,
sxx_right_bc,
syy_top_bc,
],
num_domain=500,
num_boundary=500,
solution=func,
num_test=100,
)

The number 500 is the number of training residual points sampled inside the domain, and the number 500 is the number of training points sampled on the boundary. The argument ``solution=func`` is the reference solution to compute the error of our solution, and can be ignored if we don't have a reference solution. We use 100 residual points for testing the PDE residual.

Next, we choose the network. Here, we use 5 fully connected independent neural network of depth 5 (i.e., 4 hidden layers) and width 40:

.. code-block:: python

layers = [2, [40] * 5, [40] * 5, [40] * 5, [40] * 5, 5]
activation = "tanh"
initializer = "Glorot uniform"
net = dde.nn.PFNN(layers, activation, initializer)

Now, we have the PDE problem and the network. We build a ``Model`` and choose the optimizer and learning rate:

.. code-block:: python

model = dde.Model(data, net)
model.compile("adam", lr=0.001)

We then train the model for 5000 iterations:

.. code-block:: python

losshistory, train_state = model.train(epochs=5000)

Complete code
--------------

.. literalinclude:: ../../../examples/pinn_forward/elasticity_plate_2d.py
:language: python
Loading