PINN as a PDE Solver


By Prof. Seungchul Lee
http://iai.postech.ac.kr/
Industrial AI Lab at POSTECH

Table of Contents

1. Lab 3: Euler Beam (Solid Mechanics)

1.1. Problem Setup

  • We will solve a Euler beam problem:



  • Problem properties
$$E = 1 \operatorname{pa}, \quad I = 1 \operatorname{kg\cdot m^2}, \quad q = 1 \operatorname{N/m}, \quad l = 1 \operatorname{m}$$


  • Partial differential equations & boundary conditions


$${\partial^4 y \over \partial x^4} + 1 = 0, \qquad \text{where} \quad x \in [0,1]$$

  • One Dirichlet boundary condition on the left boundary:


$$y(0) = 0$$

  • One Neumann boundary condition on the left boundary:


$$y'(0) = 0$$

  • Two boundary conditions on the right boundary:


$$y''(1) = 0, \quad y'''(1) = 0$$

  • The exact solution is


$$y(x) = -{1 \over 24}x^4 + {1 \over 6}x^3 - {1 \over 4}x^2$$

  • Make a neural network and loss functions like below :




1.2. Solve the Euler Beam problem

1.2.1. Import Library

In [2]:
import deepxde as dde
import numpy as np
Using backend: pytorch

1.2.2. Define PDE System

In [3]:
def dy(x, y):
    return dde.grad.jacobian(y, x)

def ddy(x, y):
    return dde.grad.hessian(y, x)

def dddy(x, y):
    return dde.grad.jacobian(ddy(x, y), x)

def pde(x, y):
    dy_xx = ddy(x, y)
    dy_xxxx = dde.grad.hessian(dy_xx, x)
    return dy_xxxx + 1

1.2.3. Define Boundary Condition

In [4]:
def boundary_left(x, on_boundary):
    return on_boundary and np.isclose(x[0], 0)

def boundary_right(x, on_boundary):
    return on_boundary and np.isclose(x[0], 1)

1.2.4. Define Geometry, Implement Boundary Condition

In [6]:
geom = dde.geometry.Interval(0, 1)

bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) # u(0) = 0
bc2 = dde.OperatorBC(geom, lambda x, y, _: dy(x, y), boundary_left) # u'(0) = 0
bc3 = dde.OperatorBC(geom, lambda x, y, _: ddy(x, y), boundary_right) # u''(1) = 0
bc4 = dde.OperatorBC(geom, lambda x, y, _: dddy(x, y), boundary_right) # u'''(1) = 0

# Reference solution to compute the error
def true_solution(x):
    return -(x ** 4) / 24 + x ** 3 / 6 - x ** 2 / 4

data = dde.data.PDE(geom, 
                    pde, 
                    [bc1, bc2, bc3, bc4], 
                    num_domain = 10, 
                    num_boundary = 2, 
                    solution = true_solution, 
                    num_test = 100)

1.2.5. Define Network and Hyper-parameters

In [7]:
layer_size = [1] + [20] * 3 + [1]
activation = "tanh"
initializer = "Glorot uniform"

net = dde.maps.FNN(layer_size, activation, initializer)
In [8]:
model = dde.Model(data, net)
model.compile("adam", lr = 0.001)
Compiling model...
'compile' took 0.000572 s

1.2.6. Train & Prediction

In [9]:
losshistory, train_state = model.train(epochs = 5000)
dde.saveplot(losshistory, train_state, issave = False, isplot = True)
Training model...

Step      Train loss                                            Test loss                                             Test metric
0         [1.86e+00, 0.00e+00, 7.93e-02, 2.05e-02, 3.95e-03]    [1.95e+00, 0.00e+00, 7.93e-02, 2.05e-02, 3.95e-03]    []  
1000      [6.72e-04, 4.35e-08, 1.01e-05, 8.14e-05, 1.21e-05]    [5.00e-04, 4.35e-08, 1.01e-05, 8.14e-05, 1.21e-05]    []  
2000      [1.77e-04, 3.46e-09, 7.84e-08, 1.33e-06, 1.19e-07]    [2.24e-04, 3.46e-09, 7.84e-08, 1.33e-06, 1.19e-07]    []  
3000      [7.86e-05, 7.03e-09, 4.48e-08, 2.85e-07, 1.72e-07]    [9.77e-05, 7.02e-09, 4.48e-08, 2.85e-07, 1.72e-07]    []  
4000      [5.91e-05, 5.70e-08, 3.42e-08, 9.71e-08, 1.26e-06]    [5.97e-05, 5.69e-08, 3.42e-08, 9.71e-08, 1.26e-06]    []  
5000      [1.62e-05, 7.57e-11, 3.54e-10, 7.34e-09, 1.05e-09]    [2.49e-05, 7.57e-11, 3.57e-10, 7.31e-09, 1.04e-09]    []  

Best model at step 5000:
  train loss: 1.62e-05
  test loss: 2.49e-05
  test metric: []

'train' took 115.460017 s

2. Lab 4: Navier-Stokes Equations (Fluid Mechanics)

  • Note: strongly recommend you to use GPU rather than CPU. (you can use CoLab GPU for free)
  • If you use Google Colab, please implement below codes
In [ ]:
# !pip install deepxde
In [2]:
import deepxde as dde
import numpy as np
import matplotlib.pyplot as plt
Using backend: pytorch

In [ ]:
# from deepxde.backend.set_default_backend import set_default_backend
# set_default_backend("pytorch")

2.1. Problem Setup

  • We will solve 2D Navier-Stokes Equations to find velocity profile in infinite parallel plates flow
    • Any fluid flowing in plates had to enter at some location. The region of flow near where the fluid enters the plates is termed the entrance region and is illustrated in below figure
    • The fluid typically enters the plates with a nearly uniform velocity profile
    • As the fluid moves through the plates, viscous effects cause it to stick to the plates wall (no-slip boundary condition)
    • Thus, a boundary layer is produced along the plates wall such that the initial velocity profile changes with distance along the plates, $x$, until the fluid reaches the end of the hydrodynamic entrance region (which is also called entrance length) beyond which the velocity profile does not vary with $x$





  • Problem properties


$$\rho = 1\operatorname{kg/m^3}, \quad \mu = 1\operatorname{N\cdot s/m^2}, \quad D = 2h = 1\operatorname{m}, \quad L = 2\operatorname{m}, \quad u_{in} = 1\operatorname{m/s}, \quad \nu = \frac{\mu}{\rho}$$


  • Hydraulic diameter is


$$\quad D_h = \lim\limits_{b\to\infty} {4(2bh) \over {2b+4h}} = 4h = 2\operatorname{m}$$

  • So, the Reynolds number of this system is


$$Re = \frac{\rho u_{in} D_h}{\mu} = 2 $$

  • 2D Navier-Stokes Equations & boundary conditions (for steady state)


$$ \begin{align*} u{\partial u \over \partial x} + v{\partial u \over \partial y} + {1 \over \rho}{\partial p \over \partial x} - \nu \ \left({\partial^2 u \over {\partial x^2}} + {\partial^2 u \over {\partial y^2}}\right) &= 0\\\\ u{\partial v \over \partial x} + v{\partial v \over \partial y} + {1 \over \rho}{\partial p \over \partial y} - \nu \ \left({\partial^2 v \over {\partial x^2}} + {\partial^2 v \over {\partial y^2}}\right) &= 0\\\\ {\partial u \over \partial x} + {\partial v \over \partial y} &= 0 \end{align*} $$


  • Two Dirichlet boundary conditions on the plate boundary (no-slip condition),


$$u(x,y) = 0, \quad v(x,y) = 0 \qquad \text{at} \quad y = \frac{D}{2} \ \; \text{or} \; -\frac{D}{2}$$

  • Two Dirichlet boundary conditions at the inlet boundary


$$u(-1,y) = u_{\text{in}}, \quad v(-1,y) = 0$$

  • Two Dirichlet boundary conditions at the outlet boundary


$$p(1,y) = 0, \quad v(1,y) = 0$$

  • Make a neural network and loss functions like below :




2.2. CFD Solution

  • CFD solution of this problem is illustrated in below figures
    • Velocity $u$ and velocity $v$, and pressure $p$, respectively
  • Solve this problem using PINN and then compare with CFD solutions







2.3. Solve the Navier-Stokes Equations

2.3.1. Define Parameters

In [3]:
# Properties
rho = 1
mu = 1
u_in = 1
D = 1
L = 2

2.3.2. Define PDE with Boundary & Initial Conditions

In [4]:
def boundary_wall(X, on_boundary):
    on_wall = np.logical_and(np.logical_or(np.isclose(X[1], -D/2), np.isclose(X[1], D/2)), on_boundary)
    return on_wall

def boundary_inlet(X, on_boundary):
    return on_boundary and np.isclose(X[0], -L/2)

def boundary_outlet(X, on_boundary):
    return on_boundary and np.isclose(X[0], L/2)
In [5]:
def pde(X, Y):
    du_x = dde.grad.jacobian(Y, X, i = 0, j = 0)
    du_y = dde.grad.jacobian(Y, X, i = 0, j = 1)
    dv_x = dde.grad.jacobian(Y, X, i = 1, j = 0)
    dv_y = dde.grad.jacobian(Y, X, i = 1, j = 1)
    dp_x = dde.grad.jacobian(Y, X, i = 2, j = 0)
    dp_y = dde.grad.jacobian(Y, X, i = 2, j = 1)
    du_xx = dde.grad.hessian(Y, X, i = 0, j = 0, component = 0)
    du_yy = dde.grad.hessian(Y, X, i = 1, j = 1, component = 0)
    dv_xx = dde.grad.hessian(Y, X, i = 0, j = 0, component = 1)
    dv_yy = dde.grad.hessian(Y, X, i = 1, j = 1, component = 1)
    
    pde_u = Y[:,0:1]*du_x + Y[:,1:2]*du_y + 1/rho * dp_x - (mu/rho)*(du_xx + du_yy)
    pde_v = Y[:,0:1]*dv_x + Y[:,1:2]*dv_y + 1/rho * dp_y - (mu/rho)*(dv_xx + dv_yy)
    pde_cont = du_x + dv_y

    return [pde_u, pde_v, pde_cont]

2.3.3. Define Geometry, Implement Boundary Condition

In [6]:
geom = dde.geometry.Rectangle(xmin=[-L/2, -D/2], xmax=[L/2, D/2])

bc_wall_u = dde.DirichletBC(geom, lambda X: 0., boundary_wall, component = 0)
bc_wall_v = dde.DirichletBC(geom, lambda X: 0., boundary_wall, component = 1)

bc_inlet_u = dde.DirichletBC(geom, lambda X: u_in, boundary_inlet, component = 0)
bc_inlet_v = dde.DirichletBC(geom, lambda X: 0., boundary_inlet, component = 1)

bc_outlet_p = dde.DirichletBC(geom, lambda X: 0., boundary_outlet, component = 2)
bc_outlet_v = dde.DirichletBC(geom, lambda X: 0., boundary_outlet, component = 1)
In [7]:
data = dde.data.PDE(geom, 
                    pde, 
                    [bc_wall_u, bc_wall_v, bc_inlet_u, bc_inlet_v, bc_outlet_p, bc_outlet_v], 
                    num_domain = 3000, 
                    num_boundary = 500, 
                    num_test = 1000,
                    train_distribution = 'LHS' )
Warning: 1000 points required, but 1035 points sampled.
In [8]:
plt.figure(figsize = (10,8))
plt.scatter(data.train_x_all[:,0], data.train_x_all[:,1], s = 0.5)
plt.xlabel('x-direction length')
plt.ylabel('Distance from the middle of plates (m)')
plt.show()

2.3.4. Define Network and Hyper-parameters

In [9]:
layer_size = [2] + [64] * 5 + [3]
activation = "tanh"
initializer = "Glorot uniform"

net = dde.maps.FNN(layer_size, activation, initializer)

model = dde.Model(data, net)
model.compile("adam", lr = 1e-3)
Compiling model...
'compile' took 0.001253 s

2.3.5. Train (Adam Optimizer)

In [10]:
losshistory, train_state = model.train(epochs = 10000)
dde.saveplot(losshistory, train_state, issave = False, isplot = True)
Training model...

Step      Train loss                                                                                    Test loss                                                                                     Test metric
0         [1.36e-02, 1.14e-02, 1.23e-02, 3.27e-02, 2.08e-02, 4.74e-01, 3.36e-02, 2.12e-04, 3.34e-02]    [1.32e-02, 1.06e-02, 1.27e-02, 3.27e-02, 2.08e-02, 4.74e-01, 3.36e-02, 2.12e-04, 3.34e-02]    []  
1000      [8.79e-03, 2.10e-03, 8.93e-03, 3.53e-02, 1.25e-02, 4.34e-02, 3.47e-03, 1.32e-03, 2.22e-04]    [8.22e-03, 1.88e-03, 5.78e-03, 3.53e-02, 1.25e-02, 4.34e-02, 3.47e-03, 1.32e-03, 2.22e-04]    []  
2000      [9.00e-04, 7.68e-04, 4.90e-03, 2.79e-02, 9.76e-03, 3.36e-02, 8.79e-04, 1.41e-04, 1.47e-05]    [4.90e-04, 5.98e-04, 3.11e-03, 2.79e-02, 9.76e-03, 3.36e-02, 8.79e-04, 1.41e-04, 1.47e-05]    []  
3000      [1.21e-03, 6.45e-04, 3.68e-03, 2.39e-02, 8.76e-03, 2.53e-02, 2.16e-03, 2.96e-04, 6.19e-06]    [9.28e-04, 4.89e-04, 1.99e-03, 2.39e-02, 8.76e-03, 2.53e-02, 2.16e-03, 2.96e-04, 6.19e-06]    []  
4000      [1.96e-03, 6.68e-04, 2.98e-03, 2.17e-02, 7.76e-03, 2.23e-02, 3.56e-03, 5.31e-04, 8.66e-06]    [1.42e-03, 5.21e-04, 1.65e-03, 2.17e-02, 7.76e-03, 2.23e-02, 3.56e-03, 5.31e-04, 8.66e-06]    []  
5000      [1.28e-02, 1.16e-03, 3.46e-03, 2.08e-02, 7.46e-03, 1.85e-02, 5.02e-03, 2.94e-04, 6.17e-06]    [1.32e-02, 1.05e-03, 2.09e-03, 2.08e-02, 7.46e-03, 1.85e-02, 5.02e-03, 2.94e-04, 6.17e-06]    []  
6000      [4.54e-03, 1.32e-03, 2.50e-03, 1.97e-02, 7.01e-03, 1.73e-02, 5.92e-03, 1.66e-04, 5.71e-05]    [3.25e-03, 1.08e-03, 1.25e-03, 1.97e-02, 7.01e-03, 1.73e-02, 5.92e-03, 1.66e-04, 5.71e-05]    []  
7000      [1.15e-03, 2.79e-04, 2.32e-03, 1.94e-02, 6.54e-03, 1.65e-02, 6.24e-03, 2.18e-04, 1.68e-05]    [1.02e-03, 2.49e-04, 1.17e-03, 1.94e-02, 6.54e-03, 1.65e-02, 6.24e-03, 2.18e-04, 1.68e-05]    []  
8000      [2.10e-03, 3.82e-04, 2.22e-03, 1.92e-02, 6.08e-03, 1.60e-02, 6.38e-03, 7.45e-05, 1.67e-05]    [1.58e-03, 3.23e-04, 1.07e-03, 1.92e-02, 6.08e-03, 1.60e-02, 6.38e-03, 7.45e-05, 1.67e-05]    []  
9000      [1.48e-03, 5.50e-04, 2.10e-03, 1.90e-02, 5.79e-03, 1.54e-02, 6.54e-03, 1.36e-04, 1.90e-05]    [1.08e-03, 4.74e-04, 1.04e-03, 1.90e-02, 5.79e-03, 1.54e-02, 6.54e-03, 1.36e-04, 1.90e-05]    []  
10000     [2.67e-03, 2.86e-04, 1.91e-03, 1.88e-02, 5.48e-03, 1.49e-02, 6.63e-03, 1.22e-04, 8.98e-06]    [2.70e-03, 1.99e-04, 9.40e-04, 1.88e-02, 5.48e-03, 1.49e-02, 6.63e-03, 1.22e-04, 8.98e-06]    []  

Best model at step 10000:
  train loss: 5.09e-02
  test loss: 4.98e-02
  test metric: []

'train' took 436.061937 s

2.3.6. Plot Results (Adam Optimizer)

In [11]:
samples = geom.random_points(500000)
result = model.predict(samples)
color_legend = [[0, 1.5], [-0.3, 0.3], [0, 35]]
for idx in range(3):
    plt.figure(figsize = (20, 4))
    plt.scatter(samples[:, 0],
                samples[:, 1],
                c = result[:, idx],
                cmap = 'jet',
                s = 2)
    plt.colorbar()
    plt.clim(color_legend[idx])
    plt.xlim((0-L/2, L-L/2))
    plt.ylim((0-D/2, D-D/2))
    plt.tight_layout()
    plt.show()

2.3.7. Train More (L-BFGS Optimizer)

In [12]:
dde.optimizers.config.set_LBFGS_options()

model.compile("L-BFGS")
losshistory, train_state = model.train()
dde.saveplot(losshistory, train_state, issave = False, isplot = True)
Compiling model...
'compile' took 0.001089 s

Training model...

Step      Train loss                                                                                    Test loss                                                                                     Test metric
10000     [2.67e-03, 2.86e-04, 1.91e-03, 1.88e-02, 5.48e-03, 1.49e-02, 6.63e-03, 1.22e-04, 8.98e-06]    [2.70e-03, 1.99e-04, 9.40e-04, 1.88e-02, 5.48e-03, 1.49e-02, 6.63e-03, 1.22e-04, 8.98e-06]    []  
11000     [8.82e-04, 7.04e-04, 1.08e-03, 1.20e-02, 1.39e-03, 6.36e-03, 2.40e-03, 2.08e-05, 1.24e-05]    [6.93e-04, 5.51e-04, 6.05e-04, 1.20e-02, 1.39e-03, 6.36e-03, 2.40e-03, 2.08e-05, 1.24e-05]    []  
12000     [4.83e-04, 3.91e-04, 6.23e-04, 7.48e-03, 1.22e-03, 4.75e-03, 2.09e-03, 8.46e-06, 7.83e-06]    [4.03e-04, 3.01e-04, 5.41e-04, 7.48e-03, 1.22e-03, 4.75e-03, 2.09e-03, 8.46e-06, 7.83e-06]    []  
13000     [4.11e-04, 4.30e-04, 5.01e-04, 6.01e-03, 1.34e-03, 3.48e-03, 1.77e-03, 1.82e-05, 1.06e-05]    [3.50e-04, 2.84e-04, 4.50e-04, 6.01e-03, 1.34e-03, 3.48e-03, 1.77e-03, 1.82e-05, 1.06e-05]    []  
14000     [3.30e-04, 3.82e-04, 4.27e-04, 5.09e-03, 1.31e-03, 2.81e-03, 1.75e-03, 6.37e-06, 1.84e-05]    [5.26e-04, 4.04e-04, 3.25e-04, 5.09e-03, 1.31e-03, 2.81e-03, 1.75e-03, 6.37e-06, 1.84e-05]    []  
15000     [3.13e-04, 4.04e-04, 3.64e-04, 4.57e-03, 1.18e-03, 2.60e-03, 1.45e-03, 1.30e-06, 9.37e-06]    [6.25e-04, 3.28e-04, 3.15e-04, 4.57e-03, 1.18e-03, 2.60e-03, 1.45e-03, 1.30e-06, 9.37e-06]    []  
16000     [3.45e-04, 3.00e-04, 3.43e-04, 4.28e-03, 1.13e-03, 2.13e-03, 1.39e-03, 1.12e-06, 2.81e-06]    [7.88e-04, 3.17e-04, 3.06e-04, 4.28e-03, 1.13e-03, 2.13e-03, 1.39e-03, 1.12e-06, 2.81e-06]    []  
17000     [3.11e-04, 2.67e-04, 3.17e-04, 3.85e-03, 1.10e-03, 1.99e-03, 1.31e-03, 6.78e-06, 3.43e-06]    [7.36e-04, 4.03e-04, 2.62e-04, 3.85e-03, 1.10e-03, 1.99e-03, 1.31e-03, 6.78e-06, 3.43e-06]    []  
18000     [3.09e-04, 2.44e-04, 3.09e-04, 3.40e-03, 1.09e-03, 1.73e-03, 1.32e-03, 4.46e-06, 3.42e-06]    [6.15e-04, 4.01e-04, 2.35e-04, 3.40e-03, 1.09e-03, 1.73e-03, 1.32e-03, 4.46e-06, 3.42e-06]    []  
19000     [2.79e-04, 1.94e-04, 2.82e-04, 3.25e-03, 9.99e-04, 1.81e-03, 1.14e-03, 4.41e-06, 1.74e-06]    [5.24e-04, 3.57e-04, 1.86e-04, 3.25e-03, 9.99e-04, 1.81e-03, 1.14e-03, 4.41e-06, 1.74e-06]    []  
20000     [2.41e-04, 2.07e-04, 2.45e-04, 3.14e-03, 9.18e-04, 1.71e-03, 1.10e-03, 2.19e-06, 1.72e-06]    [5.28e-04, 4.60e-04, 1.54e-04, 3.14e-03, 9.18e-04, 1.71e-03, 1.10e-03, 2.19e-06, 1.72e-06]    []  
21000     [2.14e-04, 1.87e-04, 2.16e-04, 2.93e-03, 8.91e-04, 1.69e-03, 1.10e-03, 2.90e-06, 2.47e-06]    [4.42e-04, 4.05e-04, 1.01e-04, 2.93e-03, 8.91e-04, 1.69e-03, 1.10e-03, 2.90e-06, 2.47e-06]    []  
22000     [1.96e-04, 1.97e-04, 2.06e-04, 2.69e-03, 8.55e-04, 1.71e-03, 1.13e-03, 2.22e-06, 2.18e-06]    [4.48e-04, 7.71e-04, 9.12e-05, 2.69e-03, 8.55e-04, 1.71e-03, 1.13e-03, 2.22e-06, 2.18e-06]    []  
23000     [1.85e-04, 2.08e-04, 2.11e-04, 2.58e-03, 8.00e-04, 1.73e-03, 1.06e-03, 1.19e-06, 1.66e-06]    [4.62e-04, 6.14e-04, 9.59e-05, 2.58e-03, 8.00e-04, 1.73e-03, 1.06e-03, 1.19e-06, 1.66e-06]    []  
24000     [1.67e-04, 2.12e-04, 2.07e-04, 2.49e-03, 7.85e-04, 1.67e-03, 1.06e-03, 1.59e-06, 1.64e-06]    [7.40e-04, 3.91e-04, 9.83e-05, 2.49e-03, 7.85e-04, 1.67e-03, 1.06e-03, 1.59e-06, 1.64e-06]    []  
25000     [1.79e-04, 2.09e-04, 2.32e-04, 2.38e-03, 8.01e-04, 1.53e-03, 1.12e-03, 1.11e-06, 1.16e-06]    [9.13e-04, 2.38e-04, 1.11e-04, 2.38e-03, 8.01e-04, 1.53e-03, 1.12e-03, 1.11e-06, 1.16e-06]    []  

Best model at step 25000:
  train loss: 6.45e-03
  test loss: 7.10e-03
  test metric: []

'train' took 869.018719 s

2.3.8. Plot Results (Adam + L-BFGS)

In [13]:
samples = geom.random_points(500000)
result = model.predict(samples)
color_legend = [[0, 1.5], [-0.3, 0.3], [0, 35]]
for idx in range(3):
    plt.figure(figsize = (20, 4))
    plt.scatter(samples[:, 0],
                samples[:, 1],
                c = result[:, idx],
                cmap = 'jet',
                s = 2)
    plt.colorbar()
    plt.clim(color_legend[idx])
    plt.xlim((0-L/2, L-L/2))
    plt.ylim((0-D/2, D-D/2))
    plt.tight_layout()
    plt.show()

2.3.9. Validation: Plot Velocity Profile at the End of the Plate

  • Fully developed velocity profile at the infinite parallel plates flow are known as


$$u(y) = {3V_{avg} \over 2} \left[ 1- \left( \frac{y}{h} \right)^2 \right]$$




In [14]:
# Analytic solution
x = np.ones([1000,1])
y = np.linspace(-0.5, 0.5, 1000).reshape(1000,1)
outlet = np.hstack([x, y])

analytic_solution = u_in * 1.5 * (1 - ((y)/(D/2))**2)

PINN_solution = model.predict(outlet)
In [15]:
plt.figure(figsize = (10,8))
plt.plot(y, PINN_solution[:, 0], c = 'tomato', linewidth = 3, label = 'PINN solution')
plt.plot(y, analytic_solution, c = 'k', linestyle = '--', label = 'Analytic solution')
plt.xticks(np.linspace(-0.5, 0.5, 5), fontsize = 15)
plt.yticks(np.linspace(0, 1.5, 11), fontsize = 15)
plt.legend(fontsize = 12)
plt.xlabel('Distance from the middle of plates (m)', fontsize = 15)
plt.ylabel('Velocity ($u$)', fontsize = 15)
plt.show()
In [1]:
%%javascript
$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')