├── LICENSE
├── README.md
├── main
└── PINN-elasticity.py
└── output
├── NN_Adam.pickle
├── NN_Adam_bfgs.pickle
├── loss.png
├── loss_history.pickle
├── sxx_PINN.png
├── sxx_anal.png
├── sxy_PINN.png
├── sxy_anal.png
├── syy_PINN.png
├── syy_anal.png
├── u_PINN.png
├── u_anal.png
├── v_PINN.png
└── v_anal.png
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Jing Hu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Physics-Informed-Neural-Networks for linear elasticity
2 | ### Jing Hu (UT Austin)
3 |
4 | In this project, the linear elasticity problem is solved with Physics Informed Neural Networks (PINN). The governing equations for isotropic linear elasticity are
5 |
6 |
7 |
8 | where
is the stress tensor,
is the strain tensor, u is the displacement vector, f is the body force vector,
and
are the Lamé parameters and Einstein summation applies. Now we consider the linear elasticity problem on a square domain
. We consider the following boundary conditions:
9 |
10 | Top wall
11 |
12 |
13 |
14 | Right wall
15 |
16 |
17 |
18 | Left wall
19 |
20 |
21 |
22 | Bottom wall
23 |
24 |
25 |
26 | where
is the traction prescribed on the boundaries and the Q is the load magnitude. We consider the following body force:
27 |
28 |
29 |
30 | The analytical solution to this problem is [
,
].
31 |
32 | In the numerical implementation, we output both displacements and stresses and adopt the following loss function to prescribe boundary conditions and enforce the governing equation.
33 |
34 |
35 |
36 | For model parameters:
,
and
, we have the following results
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | The decrease of the loss function is shown in the following figure.
49 |
50 |
51 |
52 | > **Note:** The implementations were developed and tested on colab with TensorFlow 1.9 and hardware accelerator chosen as GPU.
53 |
--------------------------------------------------------------------------------
/main/PINN-elasticity.py:
--------------------------------------------------------------------------------
1 | from google.colab import drive
2 | drive.mount('/content/drive')
3 |
4 | try:
5 | import mymodule
6 | except ImportError:
7 | !pip install pyDOE
8 |
9 | %tensorflow_version 1.9
10 | import numpy as np
11 | import time
12 | from pyDOE import lhs
13 | import matplotlib
14 | import matplotlib.pyplot as plt
15 | import pickle
16 | import scipy.io
17 | import random
18 | import tensorflow as tf
19 |
20 | device_name = tf.test.gpu_device_name()
21 | if device_name != '/device:GPU:0':
22 | raise SystemError('GPU device not found')
23 |
24 | random.seed(1234)
25 | np.random.seed(1234)
26 | tf.set_random_seed(1234)
27 |
28 | class PINN_elasticity:
29 | # Initialize the class
30 | def __init__(self, lamd, mu, Q, Collo, DirichletBCxy, NeumannBCxy, NeumannBCn, NeumannBCt, bodyf, uv_layers, trained_model = 0, uvDir='./drive/MyDrive/PINN/nnwb.pickle'):
31 |
32 | # Count for callback function
33 | self.count=0
34 |
35 | # Mat. properties
36 | self.lamd = lamd
37 | self.mu = mu
38 | self.Q = Q
39 |
40 | # Collocation point
41 | self.x_c = Collo[:, 0:1]
42 | self.y_c = Collo[:, 1:2]
43 |
44 | self.x_bodyf = bodyf[:, 0:1]
45 | self.y_bodyf = bodyf[:, 1:2]
46 |
47 | self.x_Dirichlet = DirichletBCxy[:, 0:1]
48 | self.y_Dirichlet = DirichletBCxy[:, 1:2]
49 |
50 | self.x_Neumann = NeumannBCxy[:, 0:1]
51 | self.y_Neumann = NeumannBCxy[:, 1:2]
52 |
53 | self.Neumann_n1 = NeumannBCn[:, 0:1]
54 | self.Neumann_n2 = NeumannBCn[:, 1:2]
55 |
56 | self.Neumann_t1 = NeumannBCt[:, 0:1]
57 | self.Neumann_t2 = NeumannBCt[:, 1:2]
58 |
59 | # Define layers
60 | self.uv_layers = uv_layers
61 |
62 | self.loss_rec = []
63 | self.loss_Dir = []
64 | self.loss_Neu = []
65 | self.loss_gov = []
66 |
67 | # Initialize NNs
68 | if trained_model == 0 :
69 | self.uv_weights, self.uv_biases = self.initialize_NN(self.uv_layers)
70 | else:
71 | print("Loading trained NN model...")
72 | self.uv_weights, self.uv_biases = self.load_NN(uvDir, self.uv_layers)
73 |
74 | # tf placeholders
75 | self.learning_rate = tf.placeholder(tf.float32, shape=[])
76 | self.x_tf = tf.placeholder(tf.float32, shape=[None, self.x_c.shape[1]])
77 | self.y_tf = tf.placeholder(tf.float32, shape=[None, self.y_c.shape[1]])
78 |
79 | self.x_bodyf_tf = tf.placeholder(tf.float32, shape=[None, self.x_bodyf.shape[1]])
80 | self.y_bodyf_tf = tf.placeholder(tf.float32, shape=[None, self.x_bodyf.shape[1]])
81 |
82 | self.x_Dirichlet_tf = tf.placeholder(tf.float32, shape=[None, self.x_Dirichlet.shape[1]])
83 | self.y_Dirichlet_tf = tf.placeholder(tf.float32, shape=[None, self.y_Dirichlet.shape[1]])
84 |
85 | self.x_Neumann_tf = tf.placeholder(tf.float32, shape=[None, self.x_Neumann.shape[1]])
86 | self.y_Neumann_tf = tf.placeholder(tf.float32, shape=[None, self.y_Neumann.shape[1]])
87 | self.n1_Neumann_tf = tf.placeholder(tf.float32, shape=[None, self.Neumann_n1.shape[1]])
88 | self.n2_Neumann_tf = tf.placeholder(tf.float32, shape=[None, self.Neumann_n2.shape[1]])
89 | self.Neumannt1_tf = tf.placeholder(tf.float32, shape=[None, self.Neumann_t1.shape[1]])
90 | self.Neumannt2_tf = tf.placeholder(tf.float32, shape=[None, self.Neumann_t2.shape[1]])
91 |
92 | self.x_c_tf = tf.placeholder(tf.float32, shape=[None, self.x_c.shape[1]])
93 | self.y_c_tf = tf.placeholder(tf.float32, shape=[None, self.y_c.shape[1]])
94 |
95 | # tf graphs
96 | self.u_pred, self.v_pred, self.s11_pred, self.s22_pred, self.s12_pred, _, _ = self.net_uv(self.x_c_tf, self.y_c_tf)
97 | # for minimization
98 | self.f_s11r_pred, self.f_s22r_pred, self.f_s12r_pred, self.f_s1_pred, self.f_s2_pred = self.net_f(self.x_c_tf, self.y_c_tf)
99 | # for Dirichlet BC minimization
100 | self.u_Dirichlet_pred, self.v_Dirichlet_pred, _, _, _, _, _ = self.net_uv(self.x_Dirichlet_tf, self.y_Dirichlet_tf)
101 | # for Neumann BC minimization
102 | self.x_Neumann_pred, self.y_Neumann_pred, _, _, _, self.Neumannt1_pred, self.Neumannt2_pred = self.net_uv(self.x_Neumann_tf, self.y_Neumann_tf, self.n1_Neumann_tf, self.n2_Neumann_tf)
103 |
104 | self.loss_f = tf.reduce_mean(tf.square(self.f_s11r_pred)) \
105 | + tf.reduce_mean(tf.square(self.f_s22r_pred))\
106 | + tf.reduce_mean(tf.square(self.f_s12r_pred))\
107 | + tf.reduce_mean(tf.square(self.x_bodyf_tf+self.f_s1_pred))\
108 | + tf.reduce_mean(tf.square(self.y_bodyf_tf+self.f_s2_pred))
109 |
110 | self.loss_Dirichlet = tf.reduce_mean(tf.square(self.u_Dirichlet_pred)) \
111 | + tf.reduce_mean(tf.square(self.v_Dirichlet_pred))
112 |
113 | self.loss_Neumann = tf.reduce_mean(tf.square(self.Neumannt1_tf-self.Neumannt1_pred))\
114 | + tf.reduce_mean(tf.square(self.Neumannt2_tf-self.Neumannt2_pred))
115 |
116 | self.loss = self.loss_f + self.loss_Dirichlet + self.loss_Neumann
117 |
118 | # Optimizer train_bfgs
119 | self.optimizer = tf.contrib.opt.ScipyOptimizerInterface(self.loss,
120 | var_list=self.uv_weights + self.uv_biases,
121 | method='L-BFGS-B',
122 | options={'maxiter': 100000,
123 | 'maxfun': 100000,
124 | 'maxcor': 50,
125 | 'maxls': 50,
126 | 'ftol ': 2e-8*np.finfo(float).eps})
127 |
128 | # Optimizer train_Adam
129 | self.optimizer_Adam = tf.train.AdamOptimizer(learning_rate = self.learning_rate)
130 | self.train_op_Adam = self.optimizer_Adam.minimize(self.loss,
131 | var_list=self.uv_weights + self.uv_biases)
132 |
133 | # tf session
134 | self.sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True,
135 | log_device_placement=True))
136 | init = tf.global_variables_initializer()
137 | self.sess.run(init)
138 |
139 | def initialize_NN(self, layers):
140 | weights = []
141 | biases = []
142 | num_layers = len(layers)
143 | for l in range(0, num_layers - 1):
144 | W = self.xavier_init(size=[layers[l], layers[l + 1]])
145 | b = tf.Variable(tf.zeros([1, layers[l + 1]], dtype=tf.float32), dtype=tf.float32)
146 | weights.append(W)
147 | biases.append(b)
148 | return weights, biases
149 |
150 | def xavier_init(self, size):
151 | in_dim = size[0]
152 | out_dim = size[1]
153 | xavier_stddev = np.sqrt(2 / (in_dim + out_dim))
154 | return tf.Variable(tf.truncated_normal([in_dim, out_dim], stddev=xavier_stddev, dtype=tf.float32), dtype=tf.float32)
155 |
156 | def save_NN(self, fileDir):
157 |
158 | uv_weights = self.sess.run(self.uv_weights)
159 | uv_biases = self.sess.run(self.uv_biases)
160 |
161 | with open(fileDir, 'wb') as f:
162 | pickle.dump([uv_weights, uv_biases], f)
163 | print(" - Save neural networks parameters on Google Drive successfully...")
164 |
165 | def load_NN(self, fileDir, layers):
166 | weights = []
167 | biases = []
168 | num_layers = len(layers)
169 | with open(fileDir, 'rb') as f:
170 | uv_weights, uv_biases = pickle.load(f)
171 |
172 | # Stored model must has the same # of layers
173 | assert num_layers == (len(uv_weights)+1)
174 |
175 | for num in range(0, num_layers - 1):
176 | W = tf.Variable(uv_weights[num], dtype=tf.float32)
177 | b = tf.Variable(uv_biases[num], dtype=tf.float32)
178 | weights.append(W)
179 | biases.append(b)
180 | print(" - Load NN parameters on Google Drive successfully...")
181 | return weights, biases
182 |
183 | def neural_net(self, X, weights, biases):
184 | num_layers = len(weights) + 1
185 | H = X
186 | # H = 2.0 * (X - self.lb) / (self.ub - self.lb) - 1.0
187 | for l in range(0, num_layers - 2):
188 | W = weights[l]
189 | b = biases[l]
190 | H = tf.tanh(tf.add(tf.matmul(H, W), b))
191 | W = weights[-1]
192 | b = biases[-1]
193 | Y = tf.add(tf.matmul(H, W), b)
194 | return Y
195 |
196 | def net_uv(self, x, y, n1=0, n2=0):
197 | temp = self.neural_net(tf.concat([x, y], 1), self.uv_weights, self.uv_biases)
198 | u = temp[:,0:1]
199 | v = temp[:,1:2]
200 | s11 = temp[:, 2:3]
201 | s22 = temp[:, 3:4]
202 | s12 = temp[:, 4:5]
203 |
204 | # tractions
205 | t1 = tf.math.multiply(s11,n1) + tf.math.multiply(s12,n2)
206 | t2 = tf.math.multiply(s12,n1) + tf.math.multiply(s22,n2)
207 |
208 | return u, v, s11, s22, s12, t1, t2
209 |
210 | def net_f(self, x, y):
211 |
212 | lamd=self.lamd
213 | mu=self.mu
214 | Q=self.Q
215 | Pi=np.pi
216 |
217 | u, v, s11, s22, s12, _, _ = self.net_uv(x, y)
218 |
219 | s11_1 = tf.gradients(s11, x)[0]
220 | s12_2 = tf.gradients(s12, y)[0]
221 | s22_2 = tf.gradients(s22, y)[0]
222 | s12_1 = tf.gradients(s12, x)[0]
223 |
224 | # Plane stress problem
225 | u_x = tf.gradients(u, x)[0]
226 | u_y = tf.gradients(u, y)[0]
227 |
228 | v_x = tf.gradients(v, x)[0]
229 | v_y = tf.gradients(v, y)[0]
230 |
231 | e_xx = u_x
232 | e_yy = v_y
233 | e_xy = (u_y + v_x)/2.0
234 | e_kk = e_xx + e_yy
235 |
236 | f_s11r = lamd*e_kk + 2*mu*e_xx - s11
237 | f_s22r = lamd*e_kk + 2*mu*e_yy - s22
238 | f_s12r = 2*mu*e_xy - s12
239 |
240 | f_s1r = s11_1 + s12_2
241 | f_s2r = s12_1 + s22_2
242 |
243 | return f_s11r, f_s22r, f_s12r, f_s1r, f_s2r
244 |
245 |
246 | def callback(self, loss_gov, loss_Neu, loss_Dir, loss):
247 | self.count = self.count+1
248 | self.loss_Neu.append(loss_Neu)
249 | self.loss_Dir.append(loss_Dir)
250 | self.loss_gov.append(loss_gov)
251 | self.loss_rec.append(loss)
252 |
253 | if self.count % 100 == 0:
254 | print('{} th iterations, loss_f: {}, loss_Neumann: {}, loss_Dirichlet: {}, loss_total: {}'.format(self.count, loss_gov, loss_Neu, loss_Dir, loss ))
255 |
256 | def train(self, iter, learning_rate):
257 |
258 | tf_dict = {self.x_c_tf: self.x_c, self.y_c_tf: self.y_c,
259 | self.x_bodyf_tf: self.x_bodyf, self.y_bodyf_tf: self.y_bodyf,
260 | self.x_Neumann_tf: self.x_Neumann, self.y_Neumann_tf: self.y_Neumann,
261 | self.Neumannt1_tf: self.Neumann_t1, self.Neumannt2_tf: self.Neumann_t2,
262 | self.n1_Neumann_tf: self.Neumann_n1, self.n2_Neumann_tf: self.Neumann_n2,
263 | self.x_Dirichlet_tf: self.x_Dirichlet, self.y_Dirichlet_tf: self.y_Dirichlet,
264 | self.learning_rate: learning_rate}
265 |
266 | for it in range(iter):
267 |
268 | self.sess.run(self.train_op_Adam, tf_dict)
269 |
270 | # Print
271 | if it % 100 == 0:
272 | loss_value = self.sess.run(self.loss, tf_dict)
273 | loss_valueF = self.sess.run(self.loss_f, tf_dict)
274 | loss_valueN = self.sess.run(self.loss_Neumann, tf_dict)
275 | loss_valueD = self.sess.run(self.loss_Dirichlet, tf_dict)
276 |
277 | print('It: %d, Loss: %.3e, LossF: %.3e, LossN: %.3e, LossD: %.3e' %
278 | (it, loss_value, loss_valueF, loss_valueN, loss_valueD))
279 |
280 | self.loss_Dir.append(self.sess.run(self.loss_Dirichlet, tf_dict))
281 | self.loss_Neu.append(self.sess.run(self.loss_Neumann, tf_dict))
282 | self.loss_gov.append(self.sess.run(self.loss_f, tf_dict))
283 | self.loss_rec.append(self.sess.run(self.loss, tf_dict))
284 |
285 | return self.loss_f, self.loss_Dirichlet, self.loss_Neumann, self.loss
286 |
287 | def train_bfgs(self):
288 |
289 | tf_dict = {self.x_c_tf: self.x_c, self.y_c_tf: self.y_c,
290 | self.x_bodyf_tf: self.x_bodyf, self.y_bodyf_tf: self.y_bodyf,
291 | self.x_Neumann_tf: self.x_Neumann, self.y_Neumann_tf: self.y_Neumann,
292 | self.Neumannt1_tf: self.Neumann_t1, self.Neumannt2_tf: self.Neumann_t2,
293 | self.n1_Neumann_tf: self.Neumann_n1, self.n2_Neumann_tf: self.Neumann_n2,
294 | self.x_Dirichlet_tf: self.x_Dirichlet, self.y_Dirichlet_tf: self.y_Dirichlet}
295 |
296 | self.optimizer.minimize(self.sess,
297 | feed_dict=tf_dict,
298 | fetches=[self.loss_f, self.loss_Neumann, self.loss_Dirichlet, self.loss],
299 | loss_callback=self.callback)
300 |
301 | def predict(self, x_star, y_star):
302 | u_star = self.sess.run(self.u_pred, {self.x_c_tf: x_star, self.y_c_tf: y_star})
303 | v_star = self.sess.run(self.v_pred, {self.x_c_tf: x_star, self.y_c_tf: y_star})
304 |
305 | s11_star = self.sess.run(self.s11_pred, {self.x_c_tf: x_star, self.y_c_tf: y_star})
306 | s22_star = self.sess.run(self.s22_pred, {self.x_c_tf: x_star, self.y_c_tf: y_star})
307 | s12_star = self.sess.run(self.s12_pred, {self.x_c_tf: x_star, self.y_c_tf: y_star})
308 | return u_star, v_star, s11_star, s22_star, s12_star
309 |
310 | def plot_loss(self,savepath="./drive/MyDrive/PINN"):
311 |
312 | fig = plt.figure()
313 | ax = fig.add_subplot(1,1,1)
314 | line1, = plt.plot(self.loss_rec, label="Total loss", linestyle='-')
315 | line2, = plt.plot(self.loss_Dir, label="Dirichlet", linestyle='-.')
316 | line3, = plt.plot(self.loss_Neu, label="Neumman", linestyle=':')
317 | line4, = plt.plot(self.loss_gov, label="Governing equation", linestyle='--')
318 | plt.xlabel("Iteration")
319 | plt.ylabel("Loss")
320 | plt.yscale('log')
321 | plt.legend()
322 | plt.savefig(savepath+'/loss.png', dpi=300)
323 | plt.show()
324 |
325 | def bodyf(lamd, mu, Q, x, y):
326 | # body force
327 | Pi = np.pi
328 | b1=lamd*(4*Pi**2*np.multiply(np.cos(2*Pi*x),np.sin(Pi*y))-Q*Pi*np.multiply(np.cos(Pi*x),np.power(y,3)))\
329 | +mu*(9.*Pi**2*np.multiply(np.cos(2*Pi*x),np.sin(Pi*y))-Q*Pi*np.multiply(np.cos(Pi*x),np.power(y,3)))
330 | b2=lamd*(-3*Q*np.multiply(np.sin(Pi*x),np.power(y,2))+2*Pi**2.*np.multiply(np.sin(2*Pi*x),np.cos(Pi*y)))\
331 | +mu*(-6.*Q*np.multiply(np.sin(Pi*x),np.power(y,2))+2*Pi**2.*np.multiply(np.sin(2*Pi*x),np.cos(Pi*y))\
332 | +Q*Pi**2.*np.multiply(np.sin(Pi*x),np.power(y,4))/4.)
333 | return b1, b2
334 |
335 | def analytical_soln(lamd, mu, Q, xx, yy):
336 | # analytical solution
337 | Pi = np.pi
338 | u = np.multiply(np.cos(2*Pi*xx),np.sin(Pi*yy))
339 | v = Q*np.multiply(np.sin(Pi*xx),np.power(yy,4))/4
340 | sxx = lamd*(Q*np.multiply(np.sin(np.pi*xx),np.power(yy,3))-2*Pi*np.multiply(np.sin(2*Pi*xx),np.sin(Pi*yy)))\
341 | -4*mu*Pi*np.multiply(np.sin(2*Pi*xx),np.sin(Pi*yy))
342 | syy = lamd*(Q*np.multiply(np.sin(np.pi*xx),np.power(yy,3))-2*Pi*np.multiply(np.sin(2*Pi*xx),np.sin(Pi*yy)))\
343 | +2*mu*Q*np.multiply(np.sin(Pi*xx),np.power(yy,3))
344 | sxy = mu*(np.multiply(np.cos(np.pi*xx),np.power(yy,4))*Pi*Q/4+Pi*np.multiply(np.cos(2*Pi*xx),np.cos(Pi*yy)))
345 |
346 | return u, v, sxx, syy, sxy
347 |
348 | def postProcess_field( field_anal, field_PINN, marksize = 2, alpha=0.8, marker='o',savepath="./drive/MyDrive/PINN"):
349 |
350 | xmin = 0
351 | xmax = 1
352 | ymin = 0
353 | ymax = 1
354 | [x_anal, y_anal, u_anal, v_anal, sxx_anal, syy_anal, sxy_anal ] = field_anal
355 | [x_PINN, y_PINN, u_PINN, v_PINN, sxx_PINN, syy_PINN, sxy_PINN ] = field_PINN
356 | normuv = matplotlib.colors.Normalize(vmin=-0.8, vmax=0.8)
357 | normsigma = matplotlib.colors.Normalize(vmin=-10, vmax=10)
358 |
359 | # plot PINN results
360 | fig11, ax11 = plt.subplots()
361 | ax11.set_aspect('equal')
362 | cp = ax11.scatter(x_PINN, y_PINN, c=u_PINN, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=-0.8, vmax=0.8)
363 | ax11.set_xticks([])
364 | ax11.set_yticks([])
365 | ax11.set_xlim([xmin, xmax])
366 | ax11.set_ylim([ymin, ymax])
367 | ax11.set_xlabel("x (m)")
368 | ax11.set_ylabel("y (m)")
369 | plt.title('PINN u $(m)$')
370 | fig11.colorbar(cp)
371 | plt.savefig(savepath+'/u_PINN.png', dpi=300)
372 | plt.show()
373 |
374 | fig21, ax21 = plt.subplots()
375 | ax21.set_aspect('equal')
376 | cp = ax21.scatter(x_PINN, y_PINN, c=v_PINN, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=0, vmax=0.8)
377 | ax21.set_xticks([])
378 | ax21.set_yticks([])
379 | ax21.set_xlim([xmin, xmax])
380 | ax21.set_ylim([ymin, ymax])
381 | ax21.set_xlabel("x (m)")
382 | ax21.set_ylabel("y (m)")
383 | plt.title('PINN v $(m)$')
384 | fig21.colorbar(cp)
385 | plt.savefig(savepath+'/v_PINN.png', dpi=300)
386 | plt.show()
387 |
388 | fig31, ax31 = plt.subplots()
389 | ax31.set_aspect('equal')
390 | cp = ax31.scatter(x_PINN, y_PINN, c=sxx_PINN, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=-10, vmax=10)
391 | ax31.set_xticks([])
392 | ax31.set_yticks([])
393 | ax31.set_xlim([xmin, xmax])
394 | ax31.set_ylim([ymin, ymax])
395 | ax31.set_xlabel("x (m)")
396 | ax31.set_ylabel("y (m)")
397 | plt.title('PINN $\sigma_{xx}\hspace{0.2}(N/m^2$)')
398 | fig31.colorbar(cp)
399 | plt.savefig(savepath+'/sxx_PINN.png', dpi=300)
400 | plt.show()
401 |
402 | fig41, ax41 = plt.subplots()
403 | ax41.set_aspect('equal')
404 | cp = ax41.scatter(x_PINN, y_PINN, c=syy_PINN, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=-6, vmax=8)
405 | ax41.set_xticks([])
406 | ax41.set_yticks([])
407 | ax41.set_xlim([xmin, xmax])
408 | ax41.set_ylim([ymin, ymax])
409 | ax41.set_xlabel("x (m)")
410 | ax41.set_ylabel("y (m)")
411 | plt.title('PINN $\sigma_{yy}\hspace{0.2}(N/m^2$)')
412 | fig41.colorbar(cp)
413 | plt.savefig(savepath+'/syy_PINN.png', dpi=300)
414 | plt.show()
415 |
416 | fig51, ax51 = plt.subplots()
417 | ax51.set_aspect('equal')
418 | cp = ax51.scatter(x_PINN, y_PINN, c=sxy_PINN, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=-3, vmax=3)
419 | ax51.set_xticks([])
420 | ax51.set_yticks([])
421 | ax51.set_xlim([xmin, xmax])
422 | ax51.set_ylim([ymin, ymax])
423 | ax51.set_xlabel("x (m)")
424 | ax51.set_ylabel("y (m)")
425 | plt.title('PINN $\sigma_{xy}\hspace{0.2}(N/m^2$)')
426 | fig51.colorbar(cp)
427 | plt.savefig(savepath+'/sxy_PINN.png', dpi=300)
428 | plt.show()
429 |
430 | # plot analytical results
431 | fig12, ax12 = plt.subplots()
432 | ax12.set_aspect('equal')
433 | cp = ax12.scatter(x_anal, y_anal, c=u_anal, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=-0.8, vmax=0.8)
434 | ax12.set_xticks([])
435 | ax12.set_yticks([])
436 | ax12.set_xlim([xmin, xmax])
437 | ax12.set_ylim([ymin, ymax])
438 | ax12.set_xlabel("x (m)")
439 | ax12.set_ylabel("y (m)")
440 | plt.title('Analytical u $(m)$')
441 | fig12.colorbar(cp)
442 | plt.savefig(savepath+'/u_anal.png', dpi=300)
443 | plt.show()
444 |
445 | fig22, ax22 = plt.subplots()
446 | ax22.set_aspect('equal')
447 | cp = ax22.scatter(x_anal, y_anal, c=v_anal, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=0, vmax=0.8)
448 | ax22.set_xticks([])
449 | ax22.set_yticks([])
450 | ax22.set_xlim([xmin, xmax])
451 | ax22.set_ylim([ymin, ymax])
452 | ax22.set_xlabel("x (m)")
453 | ax22.set_ylabel("y (m)")
454 | plt.title('Analytical v $(m)$')
455 | fig22.colorbar(cp)
456 | plt.savefig(savepath+'/v_anal.png', dpi=300)
457 | plt.show()
458 |
459 | fig32, ax32 = plt.subplots()
460 | ax32.set_aspect('equal')
461 | cp = ax32.scatter(x_anal, y_anal, c=sxx_anal, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=-10, vmax=10)
462 | ax32.set_xticks([])
463 | ax32.set_yticks([])
464 | ax32.set_xlim([xmin, xmax])
465 | ax32.set_ylim([ymin, ymax])
466 | ax32.set_xlabel("x (m)")
467 | ax32.set_ylabel("y (m)")
468 | plt.title('Analytical $\sigma_{xx}\hspace{0.2}(N/m^2$)')
469 | fig32.colorbar(cp)
470 | plt.savefig(savepath+'/sxx_anal.png', dpi=300)
471 | plt.show()
472 |
473 | fig42, ax42 = plt.subplots()
474 | ax42.set_aspect('equal')
475 | cp = ax42.scatter(x_anal, y_anal, c=syy_anal, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=-6, vmax=8)
476 | ax42.set_xticks([])
477 | ax42.set_yticks([])
478 | ax42.set_xlim([xmin, xmax])
479 | ax42.set_ylim([ymin, ymax])
480 | ax42.set_xlabel("x (m)")
481 | ax42.set_ylabel("y (m)")
482 | plt.title('Analytical $\sigma_{yy}\hspace{0.2}(N/m^2$)')
483 | fig42.colorbar(cp)
484 | plt.savefig(savepath+'/syy_anal.png', dpi=300)
485 | plt.show()
486 |
487 | fig52, ax52 = plt.subplots()
488 | ax52.set_aspect('equal')
489 | cp = ax52.scatter(x_anal, y_anal, c=sxy_anal, alpha=alpha-0.1, edgecolors='none', cmap='rainbow', marker=marker, s=int(marksize), vmin=-3, vmax=3)
490 | ax52.set_xticks([])
491 | ax52.set_yticks([])
492 | ax52.set_xlim([xmin, xmax])
493 | ax52.set_ylim([ymin, ymax])
494 | ax52.set_xlabel("x (m)")
495 | ax52.set_ylabel("y (m)")
496 | plt.title('Analytical $\sigma_{xy}\hspace{0.2}(N/m^2$)')
497 | fig52.colorbar(cp)
498 | plt.savefig(savepath+'/sxy_anal.png', dpi=300)
499 | plt.show()
500 |
501 | plt.close('all')
502 |
503 | if __name__ == "__main__":
504 |
505 | lamd = 1
506 | mu = 0.5
507 | Q = 4
508 |
509 | # Network configuration
510 | # output u,v,sigxx,sigyy,sigxy
511 | uv_layers = [2] + 10*[40] + [5]
512 |
513 | # number of domain training samples
514 | num_dom_train_samples = 200
515 | # number of boundary training samples
516 | num_b_train_samples = 300
517 |
518 | # collocation points in the domain
519 | XY_c1 = np.linspace(0.0, 1.0, num=num_dom_train_samples) # x = 0 ~ +1
520 | XY_c2 = np.linspace(0.0, 1.0, num=num_dom_train_samples) # y = 0 ~ +1
521 | XY_c1, XY_c2 = np.meshgrid(XY_c1, XY_c2)
522 | XY_c = np.vstack((XY_c1.flatten(),XY_c2.flatten())).T
523 |
524 | # Neumman BC
525 | xy_left = np.zeros((num_b_train_samples, 2))
526 | xy_left[..., 0] = np.zeros(num_b_train_samples) # x = 0
527 | xy_left[..., 1] = np.linspace(0.0, 1.0, num=num_b_train_samples) # y = 0 ~ +1
528 | n_left = np.zeros((num_b_train_samples, 2))
529 | n_left[..., 0] = -1.*np.ones(num_b_train_samples)
530 | n_left[..., 1] = np.zeros(num_b_train_samples)
531 | t_left = np.zeros((num_b_train_samples, 2))
532 | t_left[..., 0] = np.zeros(num_b_train_samples)
533 | t_left[..., 1] = -mu*np.pi*(np.cos(np.pi*xy_left[..., 1])+np.power(xy_left[..., 1],4)*Q/4)
534 |
535 | xy_top = np.zeros((num_b_train_samples, 2))
536 | xy_top[..., 0] = np.linspace(0.0, 1.0, num=num_b_train_samples) # x = 0 ~ +1
537 | xy_top[..., 1] = np.ones(num_b_train_samples) # y = 0
538 | n_top = np.zeros((num_b_train_samples, 2))
539 | n_top[..., 0] = np.zeros(num_b_train_samples)
540 | n_top[..., 1] = np.ones(num_b_train_samples)
541 | t_top = np.zeros((num_b_train_samples, 2))
542 | t_top[..., 0] = mu*np.pi*(-np.cos(2*np.pi*xy_top[..., 0])+np.cos(np.pi*xy_top[..., 0])*Q/4)
543 | t_top[..., 1] = (lamd+2*mu)*Q*np.sin(np.pi*xy_top[..., 0])
544 |
545 | xy_right = np.zeros((num_b_train_samples, 2))
546 | xy_right[..., 0] = np.ones(num_b_train_samples) # x = 1
547 | xy_right[..., 1] = np.linspace(0.0, 1.0, num=num_b_train_samples) # y = 0 ~ +1
548 | n_right = np.zeros((num_b_train_samples, 2))
549 | n_right[..., 0] = np.ones(num_b_train_samples)
550 | n_right[..., 1] = np.zeros(num_b_train_samples)
551 | t_right = np.zeros((num_b_train_samples, 2))
552 | t_right[..., 0] = np.zeros(num_b_train_samples)
553 | t_right[..., 1] = mu*np.pi*(np.cos(np.pi*xy_right[..., 1])-np.power(xy_right[..., 1],4)*Q/4)
554 |
555 | xy_NeumannBC = np.concatenate((xy_left, xy_top, xy_right), 0)
556 | n_NeumannBC = np.concatenate((n_left, n_top, n_right), 0)
557 | t_NeumannBC = np.concatenate((t_left, t_top, t_right), 0)
558 |
559 | # Dirichelet BC
560 | xy_bottom = np.zeros((num_b_train_samples, 2))
561 | xy_bottom[..., 0] = np.linspace(0.0, 1.0, num=num_b_train_samples) # x = 0 ~ +1
562 | xy_bottom[..., 1] = np.zeros(num_b_train_samples) # y = 1
563 | xy_DirichletBC = xy_bottom
564 |
565 | XY_c = np.concatenate((XY_c, xy_NeumannBC, xy_DirichletBC), 0)
566 |
567 | bf = np.zeros(XY_c.shape)
568 | bf[..., 0], bf[..., 1] = bodyf(lamd, mu, Q, XY_c[..., 0], XY_c[..., 1])
569 |
570 | # Visualize the collocation points
571 | fig, ax = plt.subplots()
572 | ax.set_aspect('equal')
573 | plt.scatter(XY_c[:,0:1], XY_c[:,1:2], marker='o', alpha=0.1 ,color='blue')
574 | plt.scatter(xy_NeumannBC[:,0:1], xy_NeumannBC[:,1:2], marker='o', alpha=0.2 , color='black')
575 | plt.scatter(xy_DirichletBC[:, 0:1], xy_DirichletBC[:, 1:2], marker='o', alpha=0.2, color='orange')
576 | plt.show()
577 |
578 | with tf.device('/device:GPU:0'):
579 | config = tf.ConfigProto()
580 | config.gpu_options.allow_growth = True
581 | session = tf.Session(config=config)
582 |
583 | # Train nn model or load trained model
584 | model = PINN_elasticity(lamd, mu, Q, XY_c, xy_DirichletBC, xy_NeumannBC, n_NeumannBC, t_NeumannBC, bf, uv_layers)
585 |
586 | start_time = time.time()
587 | loss_f, loss_Dirichlet, loss_Neumann, loss = model.train(iter=10000, learning_rate=1e-3)
588 | # postProcess_field( field_anal, field_PINN, marksize=2, alpha=0.8, marker='o',savepath="./drive/MyDrive/PINN")
589 |
590 | # Save neural network
591 | model.save_NN('./drive/MyDrive/PINN/NN_Adam.pickle')
592 |
593 | num_PINN = 200
594 | x_PINN = np.linspace(0, 1, num_PINN)
595 | y_PINN = np.linspace(0, 1, num_PINN)
596 | x_PINN, y_PINN = np.meshgrid(x_PINN, y_PINN)
597 | x_PINN = x_PINN.flatten()[:, None]
598 | y_PINN = y_PINN.flatten()[:, None]
599 | u_PINN, v_PINN, s11_PINN, s22_PINN, s12_PINN = model.predict(x_PINN, y_PINN)
600 | field_PINN = [x_PINN, y_PINN, u_PINN, v_PINN, s11_PINN, s22_PINN, s12_PINN]
601 |
602 | u_anal, v_anal, sigxx_anal, sigyy_anal, sigxy_anal = analytical_soln(lamd, mu, Q, x_PINN, y_PINN)
603 | field_anal = [x_PINN, y_PINN, u_anal, v_anal, sigxx_anal, sigyy_anal, sigxy_anal]
604 |
605 | model.train_bfgs()
606 | u_PINN, v_PINN, s11_PINN, s22_PINN, s12_PINN = model.predict(x_PINN, y_PINN)
607 | field_PINN = [x_PINN, y_PINN, u_PINN, v_PINN, s11_PINN, s22_PINN, s12_PINN]
608 | # Save neural network after bfgs training
609 | model.save_NN('./drive/MyDrive/PINN/NN_Adam_bfgs.pickle')
610 | print("--- %s seconds ---" % (time.time() - start_time))
611 |
612 | model.plot_loss()
613 |
614 | postProcess_field( field_anal, field_PINN, marksize=2, alpha=0.8, marker='o',savepath="./drive/MyDrive/PINN")
615 |
616 | # Save loss history
617 | with open('./drive/MyDrive/PINN/loss_history.pickle', 'wb') as f:
618 | pickle.dump([model.loss_rec, model.loss_Dir, model.loss_Neu, model.loss_gov], f)
--------------------------------------------------------------------------------
/output/NN_Adam.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/NN_Adam.pickle
--------------------------------------------------------------------------------
/output/NN_Adam_bfgs.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/NN_Adam_bfgs.pickle
--------------------------------------------------------------------------------
/output/loss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/loss.png
--------------------------------------------------------------------------------
/output/loss_history.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/loss_history.pickle
--------------------------------------------------------------------------------
/output/sxx_PINN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/sxx_PINN.png
--------------------------------------------------------------------------------
/output/sxx_anal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/sxx_anal.png
--------------------------------------------------------------------------------
/output/sxy_PINN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/sxy_PINN.png
--------------------------------------------------------------------------------
/output/sxy_anal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/sxy_anal.png
--------------------------------------------------------------------------------
/output/syy_PINN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/syy_PINN.png
--------------------------------------------------------------------------------
/output/syy_anal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/syy_anal.png
--------------------------------------------------------------------------------
/output/u_PINN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/u_PINN.png
--------------------------------------------------------------------------------
/output/u_anal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/u_anal.png
--------------------------------------------------------------------------------
/output/v_PINN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/v_PINN.png
--------------------------------------------------------------------------------
/output/v_anal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JINGHU-UT/PINN-elasticity/1b5d3a8d3aee3a2f65129ac7161b29378aaf5d50/output/v_anal.png
--------------------------------------------------------------------------------