├── Icon.png ├── FAU_MoD_Internship_Report__PINN.pdf ├── degenerate_wave.m ├── README.md ├── second_case_damage.py ├── first_case_no_damage.py ├── control.py ├── test_loss_time.py ├── third_case_double_damage.py ├── Wave_equation.py ├── train_error_val_error_time.py ├── wave_equation_otherBC.py ├── Inverse_problem.py ├── all_together_loss_time.py └── changing_nodes_test_loss.py /Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DCN-FAU-AvH/PINNs_wave_equation/HEAD/Icon.png -------------------------------------------------------------------------------- /FAU_MoD_Internship_Report__PINN.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DCN-FAU-AvH/PINNs_wave_equation/HEAD/FAU_MoD_Internship_Report__PINN.pdf -------------------------------------------------------------------------------- /degenerate_wave.m: -------------------------------------------------------------------------------- 1 | clear all 2 | close all 3 | clc 4 | 5 | alpha = 0; 6 | a =@(x) 4*(2*norm(x-0.5))^alpha; % stiffness 7 | u0 = @(x) sin(pi*x/2); % initial condition 8 | 9 | L = 1; 10 | N = 100; 11 | x = linspace(0,L); 12 | dx = x(2) - x(1); 13 | 14 | A = sparse(N,N); 15 | A(1,1) = -2*a(x(1)); A(1,2) = 2*a(x(1)); 16 | for ii = 2:N-1 17 | A(ii,ii-1) = 1*a(x(ii)); 18 | A(ii,ii) = -2*a(x(ii)); 19 | A(ii,ii+1) = 1*a(x(ii)); 20 | end 21 | A(N,N-1) = 2*a(x(N)); A(N,N) = -2*a(x(N)); 22 | A = A/dx^2; 23 | 24 | T = 2; 25 | NT = 400; 26 | time = linspace(0,T,NT); 27 | dt = time(2) - time(1); 28 | 29 | U = zeros(N,NT); 30 | U(:,1) = u0(x); % zero velocity initial condition 31 | U(:,2) = u0(x); 32 | 33 | cdofs = [1]; % nodes with Dirichlet BCs 34 | fdofs = setdiff(1:N, cdofs); 35 | 36 | for ii = 3:NT 37 | U(fdofs,ii) = 2*U(fdofs,ii-1) - U(fdofs,ii-2) + dt^2*A(fdofs,fdofs)*U(fdofs,ii-1); 38 | end 39 | 40 | figure 41 | surf(time,fliplr(x),U) 42 | xlabel 'time' 43 | ylabel 'x' 44 | ax = gca; 45 | ax.YTick = [0, 0.5, 1]; 46 | ax.YTickLabel = {'1', '0.5', '0'}; 47 | zlabel 'solution' 48 | shading interp 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Approximating the 1D wave equation using Physics Informed Neural Networks (PINNs) 2 | 3 | An implementation of Physics-Informed Neural Networks (PINNs) to solve various forward and inverse problems for the 1 dimensional wave equation. 4 | 5 |

6 | 7 |

8 | 9 | ## Detailed explanation 10 | 11 | [Wave_equation.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/Wave_equation.py) solves the 1d wave equation 12 | 13 | [Wave_equation_otherBC](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/Wave_equation_otherBC.py) solves the 1d wave equation with Neumann boundary conditions 14 | 15 | [test_loss_time.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/test_loss_time.py) shows the test error-computational time dependency for a specific structure of neural network 16 | 17 | [train_error_val_error_time.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/train_error_val_error_time.py) displays the train error/validation error/computational time-size of training set dependencies 18 | 19 | [all_together_loss_time.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/all_together_loss_time.py) shows the test error-computational time dependency for different structures of neural networks. 20 | 21 | [changing_nodes_test_loss.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/changing_nodes_test_loss.py) shows the test error-computational time dependency for neural network structures with different numbers of nodes. 22 | 23 | [inverse_problem.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/inverse_problem.py) solves the inverse problem of the 1d wave equation 24 | 25 | [first_case_no_damage.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/first_case_no_damage.py) solves the degenerating 1d wave equation when $a(x)=4$ 26 | 27 | [second_case_damage.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/second_case_damage.py) solves the degenerating 1d wave equation when $a(x)=8|x-0.5|$ 28 | 29 | [third_case_double_damage.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/third_case_double_damage.py) solves the degenerating 1d wave equation when $a(x)=16|x-0.5|^2$ 30 | 31 | [control.py](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/control.py) solves the null controllability problem of the 1d wave equation. 32 | 33 | [degenerate_wave.m](https://github.com/DCN-FAU-AvH/PINNs_wave_equation/blob/main/degenerate_wave.m) solves a wave equation $u_{tt}(t,x) + a(x) u_{xx}(t,x) = 0$ on $x \in (0,1)$ in which the stiffness is $a(x) = 4(2|x-\frac{1}{2}|)^\alpha$ by finite differences. (used for comparison) 34 | -------------------------------------------------------------------------------- /second_case_damage.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from itertools import product 3 | import deepxde as dde 4 | import math 5 | import pathlib 6 | import os 7 | import tensorflow as tf 8 | import matplotlib.pyplot as plt 9 | OUTPUT_DIRECTORY = pathlib.Path.cwd() / "results" / "linear_wave" 10 | if not OUTPUT_DIRECTORY.exists(): 11 | os.makedirs(OUTPUT_DIRECTORY, exist_ok=True) 12 | 13 | 14 | 15 | #first case a(x)=1 16 | 17 | #def a(x,y): 18 | # if x<0.5: 19 | # return 0.5-x 20 | # else: 21 | # return x-0.5 22 | 23 | 24 | 25 | def pde(x, y): # wave equation 26 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 27 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 28 | 29 | return dy_tt - 8*abs(0.5-x[:,0:1])*dy_xx 30 | 31 | 32 | def initial_pos(x): # initial position 33 | 34 | return np.sin((np.pi * x[:, 0:1])/2) 35 | 36 | 37 | def initial_velo(x): # initial velocity 38 | 39 | return 0.0 40 | 41 | 42 | def boundary_left(x, on_boundary): # boundary x=0 43 | is_on_boundary_left = on_boundary and np.isclose(x[0], 0) 44 | 45 | return is_on_boundary_left 46 | 47 | def boundary_right(x, on_boundary): # boundary x=1 48 | is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 49 | 50 | return is_on_boundary_right 51 | 52 | def boundary_bottom(x, on_boundary): # boundary t=0 53 | is_on_boundary_bottom = ( 54 | on_boundary 55 | and np.isclose(x[1], 0) 56 | and not np.isclose(x[0], 0) 57 | and not np.isclose(x[0], 1) 58 | ) 59 | 60 | return is_on_boundary_bottom 61 | 62 | 63 | def boundary_upper(x, on_boundary): # boundary t=2 64 | is_on_boundary_upper = ( 65 | on_boundary 66 | and np.isclose(x[1], 2) 67 | and not np.isclose(x[0], 0) 68 | and not np.isclose(x[0], 1) 69 | ) 70 | 71 | return is_on_boundary_upper 72 | 73 | 74 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 2]) 75 | 76 | 77 | #bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 78 | bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 79 | #bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 80 | bc2 = dde.NeumannBC(geom, lambda x: 0, boundary_right) #correct 81 | bc3 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 82 | 83 | bc4 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 84 | 85 | 86 | 87 | 88 | data = dde.data.PDE( 89 | geom, 90 | pde, 91 | [bc1, bc2, bc3, bc4], 92 | num_domain=2000, 93 | num_boundary=1000, train_distribution="uniform" 94 | ) 95 | print("The training set is {}".format(data.train_x_all.T)) 96 | net = dde.maps.FNN([2] + [50] * 4 + [1], "tanh", "Glorot uniform") #the input layer has size 2, there are 4 hidden layers of size 50 and one output layer of size 1 97 | 98 | #Activation function is tanh; the weights are initially chosen to be uniformly distributed according to Glorat distribution 99 | 100 | model = dde.Model(data, net) 101 | 102 | model.compile("adam", lr=0.001) 103 | 104 | model.train(epochs=7000) 105 | 106 | model.compile("L-BFGS-B") 107 | 108 | losshistory, train_state = model.train() 109 | 110 | dde.saveplot( 111 | losshistory, train_state, issave=True, isplot=True, output_dir=OUTPUT_DIRECTORY 112 | ) 113 | 114 | 115 | 116 | #Post-processing: error analysis and figures 117 | 118 | 119 | X = np.linspace(0, 1, 2000) 120 | t = np.linspace(0, 2, 4000) 121 | 122 | X_repeated = np.repeat(X, t.shape[0]) 123 | t_tiled = np.tile(t, X.shape[0]) 124 | XX = np.vstack((X_repeated, t_tiled)).T 125 | 126 | state_predict = model.predict(XX).T 127 | state_predict_M = state_predict.reshape((2000, 4000)).T 128 | 129 | Xx, Tt = np.meshgrid(np.linspace(0, 1, 2000), np.linspace(0, 2, 4000)) 130 | 131 | fig = plt.figure() # plot of predicted state 132 | ax = plt.axes(projection="3d") 133 | surf = ax.plot_surface( 134 | Xx, Tt, state_predict_M, cmap="hsv_r", linewidth=0, antialiased=False 135 | ) 136 | 137 | ax.set_title(r"PINN state: $a(x)=8|x-\frac{1}{2}|$") 138 | ax.set_xlabel("$x$") 139 | ax.set_ylabel("$t$") 140 | fig.colorbar(surf, shrink=0.6, aspect=10) 141 | 142 | plt.show() 143 | 144 | 145 | -------------------------------------------------------------------------------- /first_case_no_damage.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from matplotlib import cm 3 | import numpy as np 4 | from itertools import product 5 | import deepxde as dde 6 | import math 7 | import pathlib 8 | import os 9 | 10 | OUTPUT_DIRECTORY = pathlib.Path.cwd() / "results" / "linear_wave" 11 | if not OUTPUT_DIRECTORY.exists(): 12 | os.makedirs(OUTPUT_DIRECTORY, exist_ok=True) 13 | 14 | 15 | 16 | #first case a(x)=1 17 | 18 | 19 | 20 | def pde(x, y): # wave equation 21 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 22 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 23 | 24 | return dy_tt - 4*dy_xx 25 | 26 | 27 | def initial_pos(x): # initial position 28 | 29 | return np.sin((np.pi * x[:, 0:1])/2) 30 | 31 | 32 | def initial_velo(x): # initial velocity 33 | 34 | return 0.0 35 | 36 | 37 | def boundary_left(x, on_boundary): # boundary x=0 38 | is_on_boundary_left = on_boundary and np.isclose(x[0], 0) 39 | 40 | return is_on_boundary_left 41 | 42 | def boundary_right(x, on_boundary): # boundary x=1 43 | is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 44 | 45 | return is_on_boundary_right 46 | 47 | def boundary_bottom(x, on_boundary): # boundary t=0 48 | is_on_boundary_bottom = ( 49 | on_boundary 50 | and np.isclose(x[1], 0) 51 | and not np.isclose(x[0], 0) 52 | and not np.isclose(x[0], 1) 53 | ) 54 | 55 | return is_on_boundary_bottom 56 | 57 | 58 | def boundary_upper(x, on_boundary): # boundary t=2 59 | is_on_boundary_upper = ( 60 | on_boundary 61 | and np.isclose(x[1], 2) 62 | and not np.isclose(x[0], 0) 63 | and not np.isclose(x[0], 1) 64 | ) 65 | 66 | return is_on_boundary_upper 67 | 68 | 69 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 2]) 70 | 71 | 72 | #bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 73 | bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 74 | #bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 75 | bc2 = dde.NeumannBC(geom, lambda x: 0, boundary_right) #correct 76 | bc3 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 77 | 78 | bc4 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 79 | 80 | 81 | 82 | 83 | data = dde.data.PDE( 84 | geom, 85 | pde, 86 | [bc1, bc2, bc3, bc4], 87 | num_domain=800, 88 | num_boundary=600, train_distribution="uniform") 89 | #print("The training set is {}".format(data.train_x_all.T)) 90 | net = dde.maps.FNN([2] + [50] * 4 + [1], "tanh", "Glorot uniform") #the input layer has size 2, there are 4 hidden layers of size 50 and one output layer of size 1 91 | 92 | #Activation function is tanh; the weights are initially chosen to be uniformly distributed according to Glorat distribution 93 | 94 | model = dde.Model(data, net) 95 | 96 | model.compile("adam", lr=0.001) 97 | 98 | model.train(epochs=7000) 99 | 100 | model.compile("L-BFGS-B") 101 | 102 | losshistory, train_state = model.train() 103 | 104 | dde.saveplot( 105 | losshistory, train_state, issave=True, isplot=True, output_dir=OUTPUT_DIRECTORY 106 | ) 107 | 108 | 109 | 110 | #Post-processing: error analysis and figures 111 | 112 | xx=np.linspace(0,1,100) 113 | tt=np.linspace(0,2,200) 114 | 115 | 116 | 117 | X = np.linspace(0, 1, 1000) 118 | t = np.linspace(0, 2, 2000) 119 | 120 | X_repeated = np.repeat(X, t.shape[0]) 121 | t_tiled = np.tile(t, X.shape[0]) 122 | XX = np.vstack((X_repeated, t_tiled)).T 123 | 124 | state_predict = model.predict(XX).T 125 | state_predict_M = state_predict.reshape((1000, 2000)).T 126 | 127 | Xx, Tt = np.meshgrid(np.linspace(0, 1, 1000), np.linspace(0, 2, 2000)) 128 | 129 | fig = plt.figure() # plot of predicted state 130 | ax = plt.axes(projection="3d") 131 | surf = ax.plot_surface( 132 | Xx, Tt, state_predict_M, cmap="hsv_r", linewidth=0, antialiased=False 133 | ) 134 | 135 | ax.set_title("PINN state: a(x)=4") 136 | ax.set_xlabel("$x$") 137 | ax.set_ylabel("$t$") 138 | fig.colorbar(surf, shrink=0.6, aspect=10) 139 | 140 | plt.show() 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /control.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from matplotlib import cm 3 | import numpy as np 4 | from itertools import product 5 | import deepxde as dde 6 | import math 7 | import pathlib 8 | import os 9 | 10 | OUTPUT_DIRECTORY = pathlib.Path.cwd() / "results" / "linear_wave" 11 | if not OUTPUT_DIRECTORY.exists(): 12 | os.makedirs(OUTPUT_DIRECTORY, exist_ok=True) 13 | 14 | 15 | def pde(x, y): # wave equation 16 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 17 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 18 | 19 | return dy_tt - 4*dy_xx 20 | 21 | 22 | def initial_pos(x): # initial position 23 | 24 | return np.sin(np.pi * x[:, 0:1]) 25 | 26 | 27 | def initial_velo(x): # initial velocity 28 | 29 | return 0.0 30 | 31 | 32 | def boundary_left(x, on_boundary): # boundary x=0 33 | is_on_boundary_left =on_boundary and np.isclose(x[0], 0) 34 | return is_on_boundary_left 35 | 36 | #def boundary_right(x, on_boundary): # boundary x=1 37 | # is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 38 | 39 | # return is_on_boundary_right 40 | 41 | def boundary_bottom(x, on_boundary): # boundary t=0 42 | is_on_boundary_bottom = ( 43 | on_boundary 44 | and np.isclose(x[1], 0) 45 | and not np.isclose(x[0], 0) 46 | and not np.isclose(x[0], 1) 47 | ) 48 | 49 | return is_on_boundary_bottom 50 | 51 | 52 | def boundary_upper(x, on_boundary): # boundary t=4 53 | is_on_boundary_upper = ( 54 | on_boundary 55 | and np.isclose(x[1], 4) and not np.isclose(x[0], 0) and not np.isclose(x[0], 1) 56 | 57 | ) 58 | 59 | return is_on_boundary_upper 60 | 61 | 62 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 4]) 63 | 64 | 65 | bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 66 | 67 | #bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 68 | 69 | bc2 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 70 | 71 | bc3 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 72 | 73 | 74 | 75 | bc4 = dde.DirichletBC(geom, lambda x: 0, boundary_upper) #correct 76 | 77 | bc5 = dde.NeumannBC(geom, initial_velo, boundary_upper) #correct 78 | 79 | 80 | data = dde.data.PDE( 81 | geom, 82 | pde, 83 | [bc1, bc2, bc3, bc4, bc5], 84 | num_domain=1000, 85 | num_boundary=700, 86 | ) 87 | print("The training set is {}".format(data.train_x_all.T)) 88 | net = dde.maps.FNN([2] + [50] * 4 + [1], "tanh", "Glorot uniform") #the input layer has size 2, there are 4 hidden layers of size 50 and one output layer of size 1 89 | 90 | #Activation function is tanh; the weights are initially chosen to be uniformly distributed according to Glorat distribution 91 | 92 | model = dde.Model(data, net) 93 | 94 | model.compile("adam", lr=0.001) 95 | 96 | model.train(epochs=10000) 97 | 98 | model.compile("L-BFGS-B") 99 | 100 | losshistory, train_state = model.train() 101 | 102 | dde.saveplot( 103 | losshistory, train_state, issave=True, isplot=True, output_dir=OUTPUT_DIRECTORY 104 | ) 105 | 106 | 107 | X = np.linspace(0, 1, 600) 108 | t = np.linspace(0, 4, 2400) 109 | 110 | X_repeated = np.repeat(X, t.shape[0]) 111 | t_tiled = np.tile(t, X.shape[0]) 112 | XX = np.vstack((X_repeated, t_tiled)).T 113 | 114 | state_predict = model.predict(XX).T 115 | state_predict_M = state_predict.reshape((600, 2400)).T 116 | 117 | Xx, Tt = np.meshgrid(np.linspace(0, 1, 600), np.linspace(0, 4, 2400)) 118 | 119 | fig = plt.figure() # plot of predicted state 120 | ax = plt.axes(projection="3d") 121 | surf = ax.plot_surface( 122 | Xx, Tt, state_predict_M, cmap="hsv_r", linewidth=0, antialiased=False 123 | ) 124 | 125 | ax.set_title("PINN state ") 126 | ax.set_xlabel("$x$") 127 | ax.set_ylabel("$t$") 128 | fig.colorbar(surf, shrink=0.6, aspect=10) 129 | 130 | plt.show() 131 | 132 | 133 | 134 | tt = np.linspace(0, 4, 40000) 135 | xx1 = np.ones_like(tt) 136 | X1 = np.vstack((xx1, tt)).T 137 | 138 | 139 | control_predict_1 = np.ravel(model.predict(X1)) # predicted control1 140 | control_predict_1[0]=0 141 | 142 | 143 | 144 | fig=plt.figure() 145 | plt.plot(tt, control_predict_1, label="Control function u(t)", color="r") 146 | plt.xlabel("t") 147 | plt.ylabel("u(t)") 148 | plt.legend() 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /test_loss_time.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from matplotlib import cm 3 | import numpy as np 4 | from itertools import product 5 | import deepxde as dde 6 | import math 7 | import pathlib 8 | import os 9 | import time 10 | #import tf.keras.callbacks.EarlyStopping 11 | import tensorflow as tf 12 | from toolz import partition 13 | OUTPUT_DIRECTORY = pathlib.Path.cwd() / "results" / "wave_equation" 14 | if not OUTPUT_DIRECTORY.exists(): 15 | os.makedirs(OUTPUT_DIRECTORY, exist_ok=True) 16 | 17 | 18 | def pde(x, y): # wave equation 19 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 20 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 21 | 22 | return dy_tt - 4*dy_xx 23 | 24 | 25 | def initial_pos(x): # initial position 26 | 27 | return np.sin(np.pi * x[:, 0:1]) 28 | 29 | 30 | def initial_velo(x): # initial velocity 31 | 32 | return 0.0 33 | 34 | 35 | def boundary_left(x, on_boundary): # boundary x=0 36 | is_on_boundary_left = on_boundary and np.isclose(x[0], 0) 37 | 38 | return is_on_boundary_left 39 | 40 | def boundary_right(x, on_boundary): # boundary x=1 41 | is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 42 | 43 | return is_on_boundary_right 44 | 45 | def boundary_bottom(x, on_boundary): # boundary t=0 46 | is_on_boundary_bottom = ( 47 | on_boundary 48 | and np.isclose(x[1], 0) 49 | and not np.isclose(x[0], 0) 50 | and not np.isclose(x[0], 1) 51 | ) 52 | 53 | return is_on_boundary_bottom 54 | 55 | 56 | def boundary_upper(x, on_boundary): # boundary t=2 57 | is_on_boundary_upper = ( 58 | on_boundary 59 | and np.isclose(x[1], 2) 60 | and not np.isclose(x[0], 0) 61 | and not np.isclose(x[0], 1) 62 | ) 63 | 64 | return is_on_boundary_upper 65 | 66 | def func(x): 67 | return np.sin(np.pi * x[:, 0:1]) * np.cos(2*np.pi*x[:, 1:]) 68 | 69 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 2]) 70 | 71 | 72 | bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 73 | 74 | bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 75 | 76 | bc3 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 77 | 78 | bc4 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 79 | 80 | 81 | 82 | 83 | data = dde.data.TimePDE( 84 | geom, 85 | pde, 86 | [bc1, bc2, bc3, bc4], 87 | num_domain=200, 88 | num_boundary=100, solution=func, num_test=250 89 | ) 90 | print("The training set is {}".format(data.train_x_all.T)) 91 | net = dde.maps.FNN([2] + [50] * 4 + [1], "tanh", "Glorot uniform") #the input layer has size 2, there are 4 hidden layers of size 50 and one output layer of size 1 92 | 93 | #Activation function is tanh; the weights are initially chosen to be uniformly distributed according to Glorat distribution 94 | 95 | #callback=dde.callbacks.EarlyStopping(min_delta=0.001, patience=1000, monitor='loss_test') 96 | 97 | model = dde.Model(data, net) 98 | 99 | model.compile("adam", lr=0.001) 100 | 101 | class TimeHistory(dde.callbacks.Callback): 102 | #def __init__(self): 103 | #self.times = [] 104 | def on_train_begin(self): 105 | self.times = [] 106 | # self.time0=[] #everything started 107 | # self.timef=[] #everything ended 108 | def on_epoch_begin(self): 109 | self.epoch_time_start = time.process_time() 110 | # self.time0.append(self.epoch_time_start) 111 | def on_epoch_end(self): 112 | self.times.append(time.process_time() - self.epoch_time_start) 113 | # self.epoch_time_end = time.process_time() 114 | # self.timef.append(self.epoch_time_end) 115 | 116 | 117 | time_callback = TimeHistory() 118 | history=model.train(callbacks=[time_callback], epochs=10000) 119 | def fun(x): 120 | x=np.array(x) 121 | return np.sum(x) 122 | #print(len(time_callback.times)) 123 | chunks_1 = list(partition(1000, time_callback.times)) 124 | #print(time_callback.times) 125 | time_epochs=list(map(fun, chunks_1)) 126 | print("Time epochs {}".format(time_epochs)) 127 | model.compile("L-BFGS-B") 128 | print("Time epochs {}".format(time_epochs)) 129 | 130 | 131 | 132 | losshistory, train_state = model.train() 133 | 134 | 135 | 136 | 137 | dde.saveplot( 138 | losshistory, train_state, issave=True, isplot=True, output_dir=OUTPUT_DIRECTORY 139 | ) 140 | print("Loss history gives {}".format(losshistory.loss_train)) 141 | 142 | 143 | print("Loss history gives {}".format(losshistory.metrics_test)) 144 | 145 | 146 | a=list(map(np.sum, losshistory.loss_test))[0:10] 147 | print("Total loss is {}".format(a)) 148 | 149 | 150 | 151 | 152 | print("This are the times {}".format(time_epochs)) 153 | print("This are the test losses {}".format(losshistory.loss_test[0:10])) 154 | 155 | time_taken=[] 156 | b=0 157 | for i in range(len(time_epochs)): 158 | b=b+time_epochs[i] 159 | time_taken.append(b) 160 | 161 | 162 | plt.plot(time_taken, a) 163 | plt.xlabel("Computational time (s)") 164 | plt.ylabel("Test error") 165 | plt.title("Test error vs. Computational time") 166 | 167 | print("Comp. time: {}".format(time_taken)) 168 | print("Error: {}".format(a)) -------------------------------------------------------------------------------- /third_case_double_damage.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from itertools import product 3 | import deepxde as dde 4 | import math 5 | import pathlib 6 | import os 7 | import tensorflow as tf 8 | import matplotlib.pyplot as plt 9 | OUTPUT_DIRECTORY = pathlib.Path.cwd() / "results" / "linear_wave" 10 | if not OUTPUT_DIRECTORY.exists(): 11 | os.makedirs(OUTPUT_DIRECTORY, exist_ok=True) 12 | 13 | 14 | 15 | #first case a(x)=1 16 | 17 | #def a(x,y): 18 | # if x<0.5: 19 | # return 0.5-x 20 | # else: 21 | # return x-0.5 22 | 23 | 24 | 25 | def pde(x, y): # wave equation 26 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 27 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 28 | 29 | return dy_tt - 16*abs(0.5-x[:,0:1])**2*dy_xx 30 | 31 | 32 | def initial_pos(x): # initial position 33 | 34 | return np.sin((np.pi * x[:, 0:1])/2) 35 | 36 | 37 | def initial_velo(x): # initial velocity 38 | 39 | return 0.0 40 | 41 | 42 | def boundary_left(x, on_boundary): # boundary x=0 43 | is_on_boundary_left = on_boundary and np.isclose(x[0], 0) 44 | 45 | return is_on_boundary_left 46 | 47 | def boundary_right(x, on_boundary): # boundary x=1 48 | is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 49 | 50 | return is_on_boundary_right 51 | 52 | def boundary_bottom(x, on_boundary): # boundary t=0 53 | is_on_boundary_bottom = ( 54 | on_boundary 55 | and np.isclose(x[1], 0) 56 | and not np.isclose(x[0], 0) 57 | and not np.isclose(x[0], 1) 58 | ) 59 | 60 | return is_on_boundary_bottom 61 | 62 | 63 | def boundary_upper(x, on_boundary): # boundary t=2 64 | is_on_boundary_upper = ( 65 | on_boundary 66 | and np.isclose(x[1], 2) 67 | and not np.isclose(x[0], 0) 68 | and not np.isclose(x[0], 1) 69 | ) 70 | 71 | return is_on_boundary_upper 72 | 73 | 74 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 2]) 75 | 76 | 77 | #bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 78 | bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 79 | #bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 80 | bc2 = dde.NeumannBC(geom, lambda x: 0, boundary_right) #correct 81 | bc3 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 82 | 83 | bc4 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 84 | 85 | 86 | 87 | 88 | data = dde.data.PDE( 89 | geom, 90 | pde, 91 | [bc1, bc2, bc3, bc4], 92 | num_domain=400, 93 | num_boundary=800, 94 | ) 95 | print("The training set is {}".format(data.train_x_all.T)) 96 | net = dde.maps.FNN([2] + [50] * 4 + [1], "tanh", "Glorot uniform") #the input layer has size 2, there are 4 hidden layers of size 50 and one output layer of size 1 97 | 98 | #Activation function is tanh; the weights are initially chosen to be uniformly distributed according to Glorat distribution 99 | 100 | model = dde.Model(data, net) 101 | 102 | model.compile("adam", lr=0.001) 103 | 104 | model.train(epochs=7000) 105 | 106 | model.compile("L-BFGS-B") 107 | 108 | losshistory, train_state = model.train() 109 | 110 | dde.saveplot( 111 | losshistory, train_state, issave=True, isplot=True, output_dir=OUTPUT_DIRECTORY 112 | ) 113 | 114 | 115 | 116 | #Post-processing: error analysis and figures 117 | 118 | xx=np.linspace(0,1,1000) 119 | tt=np.linspace(0,2,2000) 120 | #X_repeated = np.repeat(xx, tt.shape[0]) 121 | #t_tiled = np.tile(tt, xx.shape[0]) 122 | #X=np.vstack((X_repeated, t_tiled)).T 123 | list_all_data=list(product(*[list(xx), list(tt)], repeat=1)) 124 | #print("List all data is {}".format(list_all_data)) 125 | #X=[np.asarray(list_all_data[k]) for k in range(len(list_all_data))] 126 | #X=np.asarray(X) 127 | print("List {}".format(list_all_data)) 128 | training_set=[(data.train_x_all.T[0][k], data.train_x_all.T[1][k]) for k in range(len(data.train_x_all.T[0]))] 129 | 130 | gen_error_set=set(list_all_data)-set(training_set) 131 | l1=list(gen_error_set) 132 | print("li is {}".format(l1)) 133 | validating_set=[np.asarray(l1[k]) for k in range(len(l1))] 134 | print("Dania {}".format(validating_set)) 135 | validating_set=np.asarray(validating_set) 136 | print("Dania 2 {}".format(validating_set)) 137 | #print("Validating set {}".format(validating_set)) 138 | predicted_solution = np.ravel(model.predict(validating_set)) 139 | print("Pred solution {}".format(predicted_solution)) 140 | 141 | X = np.linspace(0, 1, 1000) 142 | t = np.linspace(0, 2, 2000) 143 | 144 | 145 | X_repeated = np.repeat(X, t.shape[0]) 146 | t_tiled = np.tile(t, X.shape[0]) 147 | XX = np.vstack((X_repeated, t_tiled)).T 148 | 149 | state_predict = model.predict(XX).T 150 | state_predict_M = state_predict.reshape((1000, 2000)).T 151 | 152 | Xx, Tt = np.meshgrid(np.linspace(0, 1, 1000), np.linspace(0, 2, 2000)) 153 | 154 | fig = plt.figure() # plot of predicted state 155 | ax = plt.axes(projection="3d") 156 | surf = ax.plot_surface( 157 | Xx, Tt, state_predict_M, cmap="hsv_r", linewidth=0, antialiased=False 158 | ) 159 | 160 | ax.set_title(r"PINN state: $a(x)=16|x-\frac{1}{2}|^{2}$") 161 | ax.set_xlabel("$x$") 162 | ax.set_ylabel("$t$") 163 | fig.colorbar(surf, shrink=0.6, aspect=10) 164 | 165 | plt.show() 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /Wave_equation.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from matplotlib import cm 3 | import numpy as np 4 | from itertools import product 5 | import deepxde as dde 6 | import math 7 | import pathlib 8 | import os 9 | 10 | 11 | 12 | OUTPUT_DIRECTORY = pathlib.Path.cwd() / "results" / "wave_equation" 13 | if not OUTPUT_DIRECTORY.exists(): 14 | os.makedirs(OUTPUT_DIRECTORY, exist_ok=True) 15 | 16 | 17 | def pde(x, y): # wave equation 18 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 19 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 20 | 21 | return dy_tt - 4*dy_xx 22 | 23 | 24 | def initial_pos(x): # initial position 25 | 26 | return np.sin(np.pi * x[:, 0:1]) 27 | 28 | 29 | def initial_velo(x): # initial velocity 30 | 31 | return 0.0 32 | 33 | 34 | def boundary_left(x, on_boundary): # boundary x=0 35 | is_on_boundary_left = on_boundary and np.isclose(x[0], 0) 36 | 37 | return is_on_boundary_left 38 | 39 | def boundary_right(x, on_boundary): # boundary x=1 40 | is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 41 | 42 | return is_on_boundary_right 43 | 44 | def boundary_bottom(x, on_boundary): # boundary t=0 45 | is_on_boundary_bottom = ( 46 | on_boundary 47 | and np.isclose(x[1], 0) 48 | and not np.isclose(x[0], 0) 49 | and not np.isclose(x[0], 1) 50 | ) 51 | 52 | return is_on_boundary_bottom 53 | 54 | 55 | def boundary_upper(x, on_boundary): # boundary t=2 56 | is_on_boundary_upper = ( 57 | on_boundary 58 | and np.isclose(x[1], 2) 59 | and not np.isclose(x[0], 0) 60 | and not np.isclose(x[0], 1) 61 | ) 62 | 63 | return is_on_boundary_upper 64 | 65 | def func(x): 66 | return np.sin(np.pi * x[:, 0:1]) * np.cos(2*np.pi*x[:, 1:]) 67 | 68 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 2]) 69 | 70 | 71 | bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 72 | 73 | bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 74 | 75 | bc3 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 76 | 77 | bc4 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 78 | 79 | 80 | 81 | 82 | data = dde.data.TimePDE( 83 | geom, 84 | pde, 85 | [bc1, bc2, bc3, bc4], 86 | num_domain=100, 87 | num_boundary=50, solution=func 88 | ) 89 | print("The training set is {}".format(data.train_x_all.T)) 90 | net = dde.maps.FNN([2] + [50] * 4 + [1], "tanh", "Glorot uniform") #the input layer has size 2, there are 4 hidden layers of size 50 and one output layer of size 1 91 | 92 | #Activation function is tanh; the weights are initially chosen to be uniformly distributed according to Glorat distribution 93 | 94 | 95 | model = dde.Model(data, net) 96 | 97 | model.compile("adam", lr=0.001) 98 | 99 | model.train(epochs=8000) 100 | 101 | model.compile("L-BFGS-B") 102 | 103 | losshistory, train_state = model.train() 104 | 105 | dde.saveplot( 106 | losshistory, train_state, issave=True, isplot=True, output_dir=OUTPUT_DIRECTORY 107 | ) 108 | 109 | 110 | 111 | #Post-processing: error analysis and figures 112 | 113 | xx=np.linspace(0,1,100) 114 | tt=np.linspace(0,2,200) 115 | 116 | list_all_data=list(product(*[list(xx), list(tt)], repeat=1)) 117 | 118 | 119 | training_set=[(data.train_x_all.T[0][k], data.train_x_all.T[1][k]) for k in range(len(data.train_x_all.T[0]))] 120 | 121 | 122 | def exact_function(x): 123 | return math.sin(math.pi*x[0])*math.cos(2*math.pi*x[1]) 124 | 125 | 126 | 127 | X = np.linspace(0, 1, 100) 128 | t = np.linspace(0, 2, 200) 129 | 130 | X_repeated = np.repeat(X, t.shape[0]) 131 | t_tiled = np.tile(t, X.shape[0]) 132 | XX = np.vstack((X_repeated, t_tiled)).T 133 | 134 | state_predict = model.predict(XX).T 135 | state_predict_M = state_predict.reshape((100, 200)).T 136 | 137 | Xx, Tt = np.meshgrid(np.linspace(0, 1, 100), np.linspace(0, 2, 200)) 138 | 139 | fig = plt.figure() # plot of predicted state 140 | ax = plt.axes(projection="3d") 141 | surf = ax.plot_surface( 142 | Xx, Tt, state_predict_M, cmap="hsv_r", linewidth=0, antialiased=False 143 | ) 144 | 145 | ax.set_title("PINN state ") 146 | ax.set_xlabel("$x$") 147 | ax.set_ylabel("$t$") 148 | fig.colorbar(surf, shrink=0.6, aspect=10) 149 | 150 | plt.show() 151 | 152 | 153 | def explicit_state(x,t): 154 | return np.sin(math.pi*x)*np.cos(2*math.pi*t) 155 | 156 | 157 | state_exact = explicit_state(Xx, Tt) # computation of exact state 158 | 159 | fig = plt.figure() # plot of exact state 160 | ax = plt.axes(projection="3d") 161 | surf2 = ax.plot_surface( 162 | Xx, Tt, state_exact, cmap="hsv_r", linewidth=0, antialiased=False 163 | ) 164 | 165 | ax.set_title("Exact state ") 166 | ax.set_xlabel("$x$") 167 | ax.set_ylabel("$t$") 168 | 169 | fig.colorbar(surf2, shrink=0.6, aspect=10) 170 | 171 | plt.show() 172 | 173 | 174 | 175 | fig = plt.figure() # plot of the difference between exact and PINN state 176 | ax = plt.axes(projection="3d") 177 | surf2 = ax.plot_surface( 178 | Xx, Tt, state_exact-state_predict_M, cmap="hsv_r", 179 | linewidth=0, antialiased=False 180 | ) 181 | 182 | ax.set_title("Difference of the exact and PINN state") 183 | ax.set_xlabel("$x$") 184 | ax.set_ylabel("$t$") 185 | 186 | fig.colorbar(surf2, shrink=0.6, aspect=10) 187 | 188 | plt.show() 189 | 190 | 191 | #Plot the training set and validation set 192 | fig = plt.figure() 193 | 194 | plt.plot(data.train_x_all.T[0], data.train_x_all.T[1],"o") 195 | #plt.plot(validating_set.T[0], validating_set.T[1], "r", label="Validation set") 196 | plt.xlabel("x") 197 | plt.ylabel("t") 198 | plt.title("Training set") 199 | #plt.legend() 200 | 201 | 202 | -------------------------------------------------------------------------------- /train_error_val_error_time.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | t0=time.process_time() 4 | import matplotlib.pyplot as plt 5 | from matplotlib import cm 6 | import numpy as np 7 | from itertools import product 8 | import deepxde as dde 9 | import math 10 | import pathlib 11 | import os 12 | 13 | OUTPUT_DIRECTORY = pathlib.Path.cwd() / "results" / "linear_wave" 14 | if not OUTPUT_DIRECTORY.exists(): 15 | os.makedirs(OUTPUT_DIRECTORY, exist_ok=True) 16 | 17 | 18 | def pde(x, y): # wave equation 19 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 20 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 21 | 22 | return dy_tt - 4*dy_xx 23 | 24 | 25 | def initial_pos(x): # initial position 26 | 27 | return np.sin(np.pi * x[:, 0:1]) 28 | 29 | 30 | def initial_velo(x): # initial velocity 31 | 32 | return 0.0 33 | 34 | 35 | def boundary_left(x, on_boundary): # boundary x=0 36 | is_on_boundary_left = on_boundary and np.isclose(x[0], 0) 37 | 38 | return is_on_boundary_left 39 | 40 | def boundary_right(x, on_boundary): # boundary x=1 41 | is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 42 | 43 | return is_on_boundary_right 44 | 45 | def boundary_bottom(x, on_boundary): # boundary t=0 46 | is_on_boundary_bottom = ( 47 | on_boundary 48 | and np.isclose(x[1], 0) 49 | and not np.isclose(x[0], 0) 50 | and not np.isclose(x[0], 1) 51 | ) 52 | 53 | return is_on_boundary_bottom 54 | 55 | 56 | def boundary_upper(x, on_boundary): # boundary t=2 57 | is_on_boundary_upper = ( 58 | on_boundary 59 | and np.isclose(x[1], 2) 60 | and not np.isclose(x[0], 0) 61 | and not np.isclose(x[0], 1) 62 | ) 63 | 64 | return is_on_boundary_upper 65 | 66 | def func(x): 67 | return np.sin(np.pi * x[:, 0:1]) * np.cos(2*np.pi*x[:, 1:]) 68 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 2]) 69 | 70 | 71 | bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 72 | 73 | bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 74 | 75 | bc3 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 76 | 77 | bc4 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 78 | 79 | 80 | 81 | data=[] 82 | models=[] 83 | net = dde.maps.FNN([2] + [50] * 4 + [1],"tanh", "Glorot uniform") 84 | xx=np.linspace(0,1,600) 85 | tt=np.linspace(0,2,600) 86 | list_all_data=list(product(*[list(xx), list(tt)], repeat=1)) 87 | gen_err=[] 88 | train_err=[] 89 | training_set_all=[] 90 | compiling_time=[] 91 | def exact_function(x): 92 | return math.sin(math.pi*x[0])*math.cos(2*math.pi*x[1]) 93 | 94 | 95 | 96 | for k in range(6): 97 | observe_x_1_val=np.vstack((np.linspace(0, 1, num=199-10*k), np.full((199-10*k), 2))).T 98 | observe_x_1 = np.vstack((np.linspace(0, 1, num=1+10*k), np.full((1+10*k), 2))).T 99 | observe_x_2_val=np.vstack((np.linspace(0, 1, num=199-10*k), np.full((199-10*k), 0))).T 100 | observe_x_2 = np.vstack((np.linspace(0, 1, num=1+10*k), np.full((1+10*k), 0))).T 101 | observe_x_3_val=np.vstack((np.full((199-10*k), 0),np.linspace(0, 2, num=199-10*k))).T 102 | observe_x_3 = np.vstack((np.full((1+10*k), 0),np.linspace(0, 2, num=1+10*k))).T 103 | observe_x_4_val=np.vstack((np.full((199-10*k), 1),np.linspace(0, 2, num=199-10*k))).T 104 | observe_x_4 = np.vstack((np.full((1+10*k), 1),np.linspace(0, 2, num=1+10*k))).T 105 | observe_x_5_val=np.vstack((np.full((199-10*k), 0.5),np.linspace(0, 2, num=199-10*k))).T 106 | observe_x_5=np.vstack((np.full((1+10*k), 0.5),np.linspace(0, 2, num=1+10*k))).T 107 | observe_x_6_val=np.vstack((np.linspace(0, 1, num=199-10*k), np.full((199-10*k), 1))).T 108 | observe_x_6=np.vstack((np.linspace(0, 1, num=1+10*k), np.full((1+10*k), 1))).T 109 | 110 | observe_x=np.array(list(observe_x_1)+list(observe_x_2)+list(observe_x_3)+list(observe_x_4)+list(observe_x_6)+list(observe_x_5)) 111 | # print(observe_x) 112 | observe_final_val=np.array(list(observe_x_1_val)+list(observe_x_2_val)+list(observe_x_3_val)+list(observe_x_4_val)+list(observe_x_5_val)+list(observe_x_6_val)) 113 | #print(len(observe_final_val) 114 | # observe_final_val1=[(observe_final_val.T[0][i], observe_final_val.T[1][i]) for i in range(len(observe_final_val.T[0])) 115 | 116 | observe_final_val1=[(observe_final_val.T[0][i], observe_final_val.T[1][i]) for i in range(len(observe_final_val.T[0]))] 117 | # print(observe_final_val1) 118 | training_set=[(observe_x.T[0][i], observe_x.T[1][i]) for i in range(len(observe_x.T[0]))] 119 | # print(training_set) 120 | gen_err_set=set(observe_final_val1)-set(training_set) 121 | # print(gen_err_set) 122 | l1=list(gen_err_set) 123 | validating_set=[np.asarray(l1[i]) for i in range(len(l1))] 124 | #print(validating_set) 125 | observe_y=dde.icbc.PointSetBC(observe_x, func(observe_x), component=0) 126 | data = dde.data.PDE(geom, pde, [bc1, bc2, bc3, bc4, observe_y], num_domain=0, num_boundary=0,anchors=observe_x,num_test=1000, solution=func) 127 | model = dde.Model(data, net) 128 | #models.append(model) 129 | model.compile("adam", lr=0.001, loss_weights=[1,1,1,1,1,1]) 130 | model.train(epochs=6000) 131 | model.compile("L-BFGS-B", loss_weights=[1,1,1,1,1,1]) 132 | losshistory, train_state=model.train() 133 | 134 | predicted_solution = np.ravel(model.predict(validating_set)) 135 | exact_solution=np.asarray(list(map(exact_function, validating_set))) 136 | # gen_error = (1/len(predicted_solution))*np.linalg.norm(predicted_solution - exact_solution) 137 | gen_error = (1/len(predicted_solution))*np.sum(predicted_solution**2 + exact_solution**2-2*predicted_solution*exact_solution) 138 | gen_err.append(gen_error) 139 | training_error=np.sum(np.array(losshistory.loss_train[-1])) 140 | train_err.append(training_error) 141 | compiling_time.append(time.process_time()-t0) 142 | 143 | 144 | no_samples=[6+k*60 for k in range(6)] 145 | 146 | fig = plt.figure() 147 | plt.plot(no_samples, gen_err, color="red",marker="o", linestyle="-") 148 | #plot.plot(x, y, color="red", marker="o", linestyle="--") 149 | plt.xlabel("No. training samples") 150 | plt.ylabel("Validation error") 151 | plt.title("Validation error vs. no of training samples") 152 | plt.show() 153 | plt.savefig("Generr.png") 154 | 155 | 156 | fig = plt.figure() # plot of predicted state 157 | plt.plot(no_samples, train_err, marker="o", linestyle="-") 158 | plt.xlabel("No. training samples") 159 | plt.ylabel("Training error") 160 | plt.title("Training error vs. no of training samples") 161 | plt.show() 162 | plt.savefig("Trainerr.png") 163 | 164 | 165 | 166 | fig = plt.figure() # plot of predicted state 167 | plt.plot(no_samples, compiling_time, color="green",marker="o", linestyle="-") 168 | plt.xlabel("No. training samples") 169 | plt.ylabel("Computational time") 170 | plt.title("Computational time vs. no of training samples") 171 | plt.show() 172 | plt.savefig("Time.png") 173 | 174 | -------------------------------------------------------------------------------- /wave_equation_otherBC.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from matplotlib import cm 3 | import numpy as np 4 | from itertools import product 5 | import deepxde as dde 6 | import math 7 | import pathlib 8 | import os 9 | 10 | OUTPUT_DIRECTORY = pathlib.Path.cwd() / "results" / "linear_wave" 11 | if not OUTPUT_DIRECTORY.exists(): 12 | os.makedirs(OUTPUT_DIRECTORY, exist_ok=True) 13 | 14 | 15 | def pde(x, y): # wave equation 16 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 17 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 18 | 19 | return dy_tt - 4*dy_xx 20 | 21 | 22 | def initial_pos(x): # initial position 23 | 24 | return np.sin(np.pi * x[:, 0:1]) 25 | 26 | 27 | def initial_velo(x): # initial velocity 28 | 29 | return 0.0 30 | 31 | 32 | def boundary_left(x, on_boundary): # boundary x=0 33 | is_on_boundary_left = on_boundary and np.isclose(x[0], 0) 34 | 35 | return is_on_boundary_left 36 | 37 | def boundary_right(x, on_boundary): # boundary x=1 38 | is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 39 | 40 | return is_on_boundary_right 41 | 42 | def boundary_bottom(x, on_boundary): # boundary t=0 43 | is_on_boundary_bottom = ( 44 | on_boundary 45 | and np.isclose(x[1], 0) 46 | and not np.isclose(x[0], 0) 47 | and not np.isclose(x[0], 1) 48 | ) 49 | 50 | return is_on_boundary_bottom 51 | 52 | 53 | def boundary_upper(x, on_boundary): # boundary t=2 54 | is_on_boundary_upper = ( 55 | on_boundary 56 | and np.isclose(x[1], 2) 57 | and not np.isclose(x[0], 0) 58 | and not np.isclose(x[0], 1) 59 | ) 60 | 61 | return is_on_boundary_upper 62 | 63 | 64 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 2]) 65 | 66 | 67 | #bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 68 | bc1 = dde.NeumannBC(geom, lambda x: 0, boundary_left) #correct 69 | #bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 70 | bc2 = dde.NeumannBC(geom, lambda x: 0, boundary_right) #correct 71 | bc3 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 72 | 73 | bc4 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 74 | 75 | 76 | 77 | 78 | data = dde.data.PDE( 79 | geom, 80 | pde, 81 | [bc1, bc2, bc3, bc4], 82 | num_domain=200, 83 | num_boundary=100, 84 | ) 85 | print("The training set is {}".format(data.train_x_all.T)) 86 | net = dde.maps.FNN([2] + [50] * 4 + [1], "tanh", "Glorot uniform") #the input layer has size 2, there are 4 hidden layers of size 50 and one output layer of size 1 87 | 88 | #Activation function is tanh; the weights are initially chosen to be uniformly distributed according to Glorat distribution 89 | 90 | model = dde.Model(data, net) 91 | 92 | model.compile("adam", lr=0.001) 93 | 94 | model.train(epochs=7000) 95 | 96 | model.compile("L-BFGS-B") 97 | 98 | losshistory, train_state = model.train() 99 | 100 | dde.saveplot( 101 | losshistory, train_state, issave=True, isplot=True, output_dir=OUTPUT_DIRECTORY 102 | ) 103 | 104 | 105 | 106 | #Post-processing: error analysis and figures 107 | 108 | xx=np.linspace(0,1,100) 109 | tt=np.linspace(0,2,200) 110 | #X_repeated = np.repeat(xx, tt.shape[0]) 111 | #t_tiled = np.tile(tt, xx.shape[0]) 112 | #X=np.vstack((X_repeated, t_tiled)).T 113 | list_all_data=list(product(*[list(xx), list(tt)], repeat=1)) 114 | #print("List all data is {}".format(list_all_data)) 115 | #X=[np.asarray(list_all_data[k]) for k in range(len(list_all_data))] 116 | #X=np.asarray(X) 117 | print("List {}".format(list_all_data)) 118 | training_set=[(data.train_x_all.T[0][k], data.train_x_all.T[1][k]) for k in range(len(data.train_x_all.T[0]))] 119 | 120 | gen_error_set=set(list_all_data)-set(training_set) 121 | l1=list(gen_error_set) 122 | print("li is {}".format(l1)) 123 | validating_set=[np.asarray(l1[k]) for k in range(len(l1))] 124 | print("Dania {}".format(validating_set)) 125 | validating_set=np.asarray(validating_set) 126 | print("Dania 2 {}".format(validating_set)) 127 | #print("Validating set {}".format(validating_set)) 128 | predicted_solution = np.ravel(model.predict(validating_set)) 129 | print("Pred solution {}".format(predicted_solution)) 130 | def exact_function(x): 131 | return math.sin(math.pi*x[0])*math.cos(2*math.pi*x[1]) 132 | 133 | #Generalization error: 134 | exact_solution=np.asarray(list(map(exact_function, validating_set))) 135 | print("Exact solution {}".format(exact_solution)) 136 | gen_error = (1/len(predicted_solution))*np.linalg.norm(predicted_solution - exact_solution) 137 | print("Generalization error is {}".format(gen_error)) 138 | relative_error = np.linalg.norm(predicted_solution - exact_solution) / np.linalg.norm(exact_solution) 139 | print("Relative error is {}".format(relative_error)) 140 | #Training error: 141 | exact_solution_training=np.asarray(list(map(exact_function, data.train_x_all))) 142 | predicted_solution_training=np.ravel(model.predict(data.train_x_all)) 143 | training_error=(1/len(predicted_solution_training))*np.linalg.norm(predicted_solution_training- exact_solution_training) 144 | X = np.linspace(0, 1, 100) 145 | t = np.linspace(0, 2, 200) 146 | 147 | X_repeated = np.repeat(X, t.shape[0]) 148 | t_tiled = np.tile(t, X.shape[0]) 149 | XX = np.vstack((X_repeated, t_tiled)).T 150 | 151 | state_predict = model.predict(XX).T 152 | state_predict_M = state_predict.reshape((100, 200)).T 153 | 154 | Xx, Tt = np.meshgrid(np.linspace(0, 1, 100), np.linspace(0, 2, 200)) 155 | 156 | fig = plt.figure() # plot of predicted state 157 | ax = plt.axes(projection="3d") 158 | surf = ax.plot_surface( 159 | Xx, Tt, state_predict_M, cmap="hsv_r", linewidth=0, antialiased=False 160 | ) 161 | 162 | ax.set_title("PINN state ") 163 | ax.set_xlabel("$x$") 164 | ax.set_ylabel("$t$") 165 | fig.colorbar(surf, shrink=0.6, aspect=10) 166 | 167 | plt.show() 168 | 169 | 170 | def explicit_state(x,t): 171 | return np.sin(math.pi*x)*np.cos(2*math.pi*t) 172 | 173 | 174 | state_exact = explicit_state(Xx, Tt) # computation of exact state 175 | 176 | fig = plt.figure() # plot of exact state 177 | ax = plt.axes(projection="3d") 178 | surf2 = ax.plot_surface( 179 | Xx, Tt, state_exact, cmap="hsv_r", linewidth=0, antialiased=False 180 | ) 181 | 182 | ax.set_title("Exact state ") 183 | ax.set_xlabel("$x$") 184 | ax.set_ylabel("$t$") 185 | 186 | fig.colorbar(surf2, shrink=0.6, aspect=10) 187 | 188 | plt.show() 189 | 190 | 191 | 192 | fig = plt.figure() # plot of the difference between exact and PINN state 193 | ax = plt.axes(projection="3d") 194 | surf2 = ax.plot_surface( 195 | Xx, Tt, state_exact-state_predict_M, cmap="hsv_r", 196 | linewidth=0, antialiased=False 197 | ) 198 | 199 | ax.set_title("Difference of the exact and PINN state") 200 | ax.set_xlabel("$x$") 201 | ax.set_ylabel("$t$") 202 | 203 | fig.colorbar(surf2, shrink=0.6, aspect=10) 204 | 205 | plt.show() 206 | 207 | 208 | #Plot the training set and validation set 209 | fig = plt.figure() 210 | 211 | plt.plot(data.train_x_all.T[0], data.train_x_all.T[1],"o") 212 | #plt.plot(validating_set.T[0], validating_set.T[1], "r", label="Validation set") 213 | plt.xlabel("x") 214 | plt.ylabel("t") 215 | plt.title("Training set") 216 | #plt.legend() 217 | 218 | 219 | print("Training set {}".format(data.train_x_all)) 220 | #print("Validation set {}".format(validating_set)) 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /Inverse_problem.py: -------------------------------------------------------------------------------- 1 | import deepxde as dde 2 | import numpy as np 3 | # Backend tensorflow.compat.v1 or tensorflow 4 | from deepxde.backend import tf 5 | # Backend pytorch 6 | # import torch 7 | # Backend paddle 8 | # import paddle 9 | import matplotlib.pyplot as plt 10 | Ctrue=4.0 11 | C = dde.Variable(0.05) 12 | 13 | def pde(x, y): # wave equation 14 | dy_tt = dde.grad.hessian(y, x, i=1, j=1) 15 | dy_xx = dde.grad.hessian(y, x, i=0, j=0) 16 | return dy_tt - C*dy_xx 17 | 18 | def initial_pos(x): # initial position 19 | return np.sin(np.pi * x[:, 0:1]) 20 | 21 | def initial_velo(x): # initial velocity 22 | return 0.0 23 | 24 | 25 | def boundary_left(x, on_boundary): # boundary x=0 26 | is_on_boundary_left = on_boundary and np.isclose(x[0], 0) 27 | return is_on_boundary_left 28 | 29 | def boundary_right(x, on_boundary): # boundary x=1 30 | is_on_boundary_right = on_boundary and np.isclose(x[0], 1) 31 | return is_on_boundary_right 32 | 33 | def boundary_bottom(x, on_boundary): # boundary t=0 34 | is_on_boundary_bottom = ( 35 | on_boundary 36 | and np.isclose(x[1], 0) 37 | and not np.isclose(x[0], 0) 38 | and not np.isclose(x[0], 1) 39 | ) 40 | 41 | return is_on_boundary_bottom 42 | 43 | 44 | def boundary_upper(x, on_boundary): # boundary t=2 45 | is_on_boundary_upper = ( 46 | on_boundary 47 | and np.isclose(x[1], 2) 48 | and not np.isclose(x[0], 0) 49 | and not np.isclose(x[0], 1) 50 | ) 51 | 52 | return is_on_boundary_upper 53 | 54 | def func(x): 55 | return np.sin(np.pi * x[:, 0:1]) * np.cos(2*np.pi*x[:, 1:]) 56 | 57 | #geom = dde.geometry.Interval(0, 1) 58 | #timedomain = dde.geometry.TimeDomain(0, 2) 59 | #geomtime = dde.geometry.GeometryXTime(geom, timedomain) 60 | 61 | geom = dde.geometry.Rectangle(xmin=[0, 0], xmax=[1, 2]) 62 | 63 | 64 | bc1 = dde.DirichletBC(geom, lambda x: 0, boundary_left) #correct 65 | 66 | bc2 = dde.DirichletBC(geom, lambda x: 0, boundary_right) #correct 67 | 68 | bc3 = dde.DirichletBC(geom, initial_pos, boundary_bottom) #correct 69 | 70 | bc4 = dde.NeumannBC(geom, initial_velo, boundary_bottom) #correct 71 | 72 | 73 | observe_x_1 = np.vstack((np.linspace(0, 1, num=200), np.full((200), 2))).T 74 | observe_x_2 = np.vstack((np.linspace(0, 1, num=200), np.full((200), 0))).T 75 | observe_x_3 = np.vstack((np.full((200), 0),np.linspace(0, 2, num=200))).T 76 | observe_x_4 = np.vstack((np.full((200), 1),np.linspace(0, 2, num=200))).T 77 | 78 | 79 | observe_x_initial = np.random.uniform((0, 0), (1, 2), (1000, 2)) 80 | observe_x_5=np.array([a for a in observe_x_initial if 0