discretization.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. import numpy as np
  2. from numpy import sin, cos, pi
  3. from scipy.linalg import block_diag
  4. import matplotlib.pyplot as plt
  5. class hdpg1d(object):
  6. """
  7. 1d advection hdg solver outlined in 'an implicit HHDG method for
  8. confusion'. Test case: /tau = 1, convection only, linear and higher order.
  9. Please enter number of elements and polynomial order, i.e., HDG1d(10,2)
  10. """
  11. def __init__(self, n_ele, p):
  12. self.n_ele = n_ele
  13. self.p = p + 1
  14. self.tau_pos = 1e-6
  15. self.tau_neg = 1e-6
  16. self.c = 0
  17. self.kappa = 1e-6
  18. self.estError = []
  19. self.trueError = []
  20. def bc(self, case, t=None):
  21. # boundary condition
  22. if case == 0:
  23. # advection-diffusion
  24. bc = [0, 0]
  25. if case == 1:
  26. # simple convection
  27. # bc = np.sin(2*np.pi*t)
  28. # adjoint boundary
  29. bc = [0, 1]
  30. return bc
  31. def shape(self, x, p):
  32. """ evaluate shape functions at give locations"""
  33. # coeffient matrix
  34. A = np.array([np.linspace(-1, 1, p)]).T**np.arange(p)
  35. C = np.linalg.inv(A).T
  36. x = np.array([x]).T
  37. shp = C.dot((x**np.arange(p)).T)
  38. shpx = C[:, 1::1].dot((x**np.arange(p - 1) * np.arange(1, p)).T)
  39. return shp, shpx
  40. def forcing(self, x):
  41. # f = np.cos(2*np.pi*x)
  42. # f = 4*pi**2*sin(2*pi*x)
  43. f = 1
  44. return f
  45. def mesh(self, n_ele, index, x):
  46. """generate mesh"""
  47. # if n_ele < 1 or n_ele > self.n_ele:
  48. # raise RuntimeError('Bad Element number')
  49. in_value = np.zeros(len(index))
  50. for i in np.arange(len(index)):
  51. in_value[i] = (x[index[i]] + x[index[i] - 1]) / 2
  52. x_c = np.sort(np.insert(x, 0, in_value))
  53. x_i = np.linspace(x_c[n_ele - 1], x_c[n_ele], num=self.p)
  54. dx = x_c[n_ele] - x_c[n_ele - 1]
  55. return x_i, dx, x_c
  56. def exact(self, x):
  57. """solve the problem in an enriched space to simulate exact soltuion"""
  58. self.n_ele = 1000
  59. self.p = 3
  60. x = np.linspace(0, 1, self.n_ele + 1)
  61. self.exactSol = self.solve_local([], x)
  62. def matrix_gen(self, index, x):
  63. n_ele = self.n_ele
  64. # # space size
  65. # dx = 1/n_ele
  66. # order of polynomial shape functions
  67. p = self.p
  68. # order of gauss quadrature
  69. gorder = 2 * p
  70. # shape function and gauss quadrature
  71. xi, wi = np.polynomial.legendre.leggauss(gorder)
  72. shp, shpx = self.shape(xi, p)
  73. # ---------------------------------------------------------------------
  74. # advection constant
  75. con = self.c
  76. # diffusion constant
  77. kappa = self.kappa
  78. # number of nodes (solution U)
  79. n_ele = self.n_ele + len(index)
  80. # elemental forcing vector
  81. F = np.zeros(p * n_ele)
  82. for i in range(1, n_ele + 1):
  83. x_i, dx_i, _ = self.mesh(i, index, x)
  84. f = dx_i / 2 * \
  85. shp.dot(wi * self.forcing(x[0] + 1 / 2 * (1 + xi) * dx_i))
  86. F[(i - 1) * p:(i - 1) * p + p] = f
  87. # elemental m (for convection only)
  88. # m = dx/2*shp.dot(np.diag(wi).dot(shp.T))
  89. # add boundary
  90. F[0] += (con + self.tau_pos) * self.bc(0)[0]
  91. F[-1] += (-con + self.tau_neg) * self.bc(0)[1]
  92. # elemental d
  93. # d = con*(-shpx.T*np.ones((gorder,p))).T.dot(np.diag(wi).dot(shp.T))
  94. d = shp.dot(np.diag(wi).dot(shp.T))
  95. # d[0, 0] += self.tau_pos
  96. # d[-1, -1] += self.tau_neg
  97. # elemental a
  98. a = 1 / kappa * shp.dot(np.diag(wi).dot(shp.T))
  99. # elemental b
  100. b = (shpx.T * np.ones((gorder, p))).T.dot(np.diag(wi).dot(shp.T))
  101. # elemental h
  102. h = np.zeros((2, 2))
  103. h[0, 0], h[-1, -1] = -con - self.tau_pos, con - self.tau_neg
  104. # mappinng matrix
  105. map_h = np.zeros((2, n_ele), dtype=int)
  106. map_h[:, 0] = np.arange(2)
  107. for i in np.arange(1, n_ele):
  108. map_h[:, i] = np.arange(
  109. map_h[2 - 1, i - 1], map_h[2 - 1, i - 1] + 2)
  110. # assemble H and eliminate boundaries
  111. H = np.zeros((n_ele + 1, n_ele + 1))
  112. for i in range(n_ele):
  113. for j in range(2):
  114. m = map_h[j, i]
  115. for k in range(2):
  116. n = map_h[k, i]
  117. H[m, n] += h[j, k]
  118. H = H[1:n_ele][:, 1:n_ele]
  119. # elemental g
  120. g = np.zeros((2, p))
  121. g[0, 0], g[-1, -1] = self.tau_pos, self.tau_neg
  122. # mapping matrix
  123. map_g_x = map_h
  124. map_g_y = np.arange(p * n_ele, dtype=int).reshape(n_ele, p).T
  125. # assemble global G
  126. G = np.zeros((n_ele + 1, p * n_ele))
  127. for i in range(n_ele):
  128. for j in range(2):
  129. m = map_g_x[j, i]
  130. for k in range(p):
  131. n = map_g_y[k, i]
  132. G[m, n] += g[j, k]
  133. G = G[1:n_ele, :]
  134. # elemental e
  135. e = np.zeros((p, 2))
  136. e[0, 0], e[-1, -1] = -con - self.tau_pos, con - self.tau_neg
  137. # mapping matrix
  138. map_e_x = np.arange(p * n_ele, dtype=int).reshape(n_ele, p).T
  139. map_e_y = map_h
  140. # assemble global E
  141. E = np.zeros((p * n_ele, n_ele + 1))
  142. for i in range(n_ele):
  143. for j in range(p):
  144. m = map_e_x[j, i]
  145. for k in range(2):
  146. n = map_e_y[k, i]
  147. E[m, n] += e[j, k]
  148. E = E[:, 1:n_ele]
  149. # L, easy in 1d
  150. L = np.zeros(n_ele - 1)
  151. # elemental c
  152. c = np.zeros((p, 2))
  153. c[0, 0], c[-1, -1] = -1, 1
  154. # assemble global C
  155. C = np.zeros((p * n_ele, n_ele + 1))
  156. for i in range(n_ele):
  157. for j in range(p):
  158. m = map_e_x[j, i]
  159. for k in range(2):
  160. n = map_e_y[k, i]
  161. C[m, n] += c[j, k]
  162. C = C[:, 1:n_ele]
  163. # L, easy in 1d
  164. L = np.zeros(n_ele - 1)
  165. # R, easy in 1d
  166. R = np.zeros(p * n_ele)
  167. R[0] = self.bc(0)[0]
  168. R[-1] = -self.bc(0)[1]
  169. return d, m, E, G, H, F, L, a, b, C, R
  170. def solve_local(self, index, x):
  171. """ solve the 1d advection equation wit local HDG"""
  172. d, _, E, G, H, F, L, a, b, C, R = self.matrix_gen(index, x)
  173. # find dx
  174. dx = np.zeros(self.n_ele + len(index))
  175. for i in range(1, self.n_ele + len(index) + 1):
  176. x_i, dx_i, x_n = self.mesh(i, index, x)
  177. dx[i - 1] = dx_i
  178. # assemble global D
  179. bb = np.zeros((self.p, self.p))
  180. bb[0, 0] = self.tau_pos
  181. bb[-1, -1] = self.tau_neg
  182. D = np.repeat(dx, self.p) / 2 * block_diag(*[d] * (
  183. self.n_ele + len(index))) + block_diag(*[bb] * (self.n_ele + len(index)))
  184. # assemble global A
  185. A = np.repeat(dx, self.p) / 2 * block_diag(*
  186. [a] * (self.n_ele + len(index)))
  187. # assemble global B
  188. B = block_diag(*[b] * (self.n_ele + len(index)))
  189. # solve U and \lambda
  190. K = -np.concatenate((C.T, G), axis=1).dot(np.linalg.inv(
  191. np.bmat([[A, -B], [B.T, D]])).dot(np.concatenate((C, E)))) + H
  192. F_hat = np.array([L]).T - np.concatenate((C.T, G), axis=1).dot(np.linalg.inv(
  193. np.bmat([[A, -B], [B.T, D]]))).dot(np.array([np.concatenate((R, F))]).T)
  194. lamba = np.linalg.solve(K, F_hat)
  195. U = np.linalg.inv(np.bmat([[A, -B], [B.T, D]])).dot(
  196. np.array([np.concatenate((R, F))]).T - np.concatenate((C, E)).dot(lamba))
  197. return U, lamba
  198. def solve_adjoint(self, index, x, u, u_hat):
  199. self.p = self.p + 1
  200. d, _, E, G, H, F, L, a, b, C, R = self.matrix_gen(index, x)
  201. # add boundary
  202. F = np.zeros(len(F))
  203. R[-1] = -self.bc(1)[1]
  204. # find dx
  205. dx = np.zeros(self.n_ele + len(index))
  206. for i in range(1, self.n_ele + len(index) + 1):
  207. x_i, dx_i, x_n = self.mesh(i, index, x)
  208. dx[i - 1] = dx_i
  209. # assemble global D
  210. bb = np.zeros((self.p, self.p))
  211. bb[0, 0] = self.tau_pos
  212. bb[-1, -1] = self.tau_neg
  213. D = np.repeat(dx, self.p) / 2 * block_diag(*[d] * (
  214. self.n_ele + len(index))) + block_diag(*[bb] * (self.n_ele + len(index)))
  215. # assemble global A
  216. A = np.repeat(dx, self.p) / 2 * block_diag(*
  217. [a] * (self.n_ele + len(index)))
  218. # assemble global B
  219. B = block_diag(*[b] * (self.n_ele + len(index)))
  220. # # assemble global matrix LHS
  221. LHS = np.bmat([[A, -B, C], [B.T, D, E], [C.T, G, H]])
  222. # solve U and \lambda
  223. U = np.linalg.solve(LHS.T, np.concatenate((R, F, L)))
  224. return U[0:2 * self.p * (self.n_ele + len(index))], U[2 * self.p * (self.n_ele + len(index)):len(U)]
  225. def diffusion(self):
  226. """solve 1d convection with local HDG"""
  227. # begin and end time
  228. t, T = 0, 1
  229. # time marching step for diffusion equation
  230. dt = 1e-3
  231. d, m, E, G, H, F, L, a, b, C, R = self.matrix_gen()
  232. # add time derivatives to the space derivatives (both are
  233. # elmental-wise)
  234. d = d + 1 / dt * m
  235. # assemble global D
  236. D = block_diag(*[d] * self.n_ele)
  237. # assemble global A
  238. A = block_diag(*[a] * self.n_ele)
  239. # assemble global B
  240. B = block_diag(*[b] * self.n_ele)
  241. # initial condition
  242. X = np.zeros(self.p * self.n_ele)
  243. for i in range(1, self.n_ele + 1):
  244. x = self.mesh(i)
  245. X[(i - 1) * self.p:(i - 1) * self.p + self.p] = x
  246. U = np.concatenate((pi * cos(pi * X), sin(pi * X)))
  247. # assemble M
  248. M = block_diag(*[1 / dt * m] * self.n_ele)
  249. # time marching
  250. while t < T:
  251. # add boundary conditions
  252. F_dynamic = F + \
  253. M.dot(U[self.n_ele * self.p:2 * self.n_ele * self.p])
  254. # assemble global matrix LHS
  255. LHS = np.bmat([[A, -B, C], [B.T, D, E], [C.T, G, H]])
  256. # solve U and \lambda
  257. U = np.linalg.solve(LHS, np.concatenate((R, F_dynamic, L)))
  258. # plot solutions
  259. plt.clf()
  260. plt.plot(X, U[self.n_ele * self.p:2 * self.n_ele * self.p], '-r.')
  261. plt.plot(X, sin(pi * X) * np.exp(-pi**2 * t))
  262. plt.ylim([0, 1])
  263. plt.grid()
  264. plt.pause(1e-3)
  265. plt.close()
  266. print("Diffusion equation du/dt - du^2/d^2x = 0 with u_exact ="
  267. ' 6sin(pi*x)*exp(-pi^2*t).')
  268. plt.figure(1)
  269. plt.plot(X, U[self.n_ele * self.p:2 * self.n_ele * self.p], '-r.')
  270. plt.plot(X, sin(pi * X) * np.exp(-pi**2 * T))
  271. plt.xlabel('x')
  272. plt.ylabel('y')
  273. plt.legend(('Numberical', 'Exact'), loc='upper left')
  274. plt.title('Simple Diffusion Equation Solution at t = {}'.format(T))
  275. plt.grid()
  276. plt.savefig('diffusion', bbox_inches='tight')
  277. plt.show(block=False)
  278. return U
  279. def residual(self, U, hat_U, z, hat_z, dx, index, x_c):
  280. n_ele = self.n_ele
  281. # order of polynomial shape functions
  282. p = self.p
  283. p_l = p - 1
  284. # order of gauss quadrature
  285. gorder = 2 * p
  286. # shape function and gauss quadrature
  287. xi, wi = np.polynomial.legendre.leggauss(gorder)
  288. shp, shpx = self.shape(xi, p)
  289. shp_l, shpx_l = self.shape(xi, p_l)
  290. # ---------------------------------------------------------------------
  291. # advection constant
  292. con = self.c
  293. # diffusion constant
  294. kappa = self.kappa
  295. z_q, z_u, z_hat = np.zeros(self.p * self.n_ele), \
  296. np.zeros(self.p * self.n_ele), np.zeros(self.n_ele - 1)
  297. q, u, lamba = np.zeros(p_l * self.n_ele), \
  298. np.zeros(p_l * self.n_ele), np.zeros(self.n_ele - 1)
  299. for i in np.arange(self.p * self.n_ele):
  300. z_q[i] = z[i]
  301. z_u[i] = z[i + self.p * self.n_ele]
  302. for i in np.arange(p_l * self.n_ele):
  303. q[i] = U[i]
  304. u[i] = U[i + p_l * self.n_ele]
  305. for i in np.arange(self.n_ele - 1):
  306. z_hat[i] = hat_z[i]
  307. # add boundary condtions to U_hat
  308. U_hat = np.zeros(self.n_ele + 1)
  309. for i, x in enumerate(hat_U):
  310. U_hat[i + 1] = x
  311. U_hat[0] = self.bc(0)[0]
  312. U_hat[-1] = self.bc(0)[1]
  313. # L, easy in 1d
  314. L = np.zeros(n_ele + 1)
  315. # R, easy in 1d
  316. RR = np.zeros(p * n_ele)
  317. # elemental forcing vector
  318. F = np.zeros(p * n_ele)
  319. for i in range(1, n_ele + 1):
  320. f = dx[i - 1] / 2 * \
  321. shp.dot(
  322. wi * self.forcing(x_c[0] + 1 / 2 * (1 + xi) * dx[i - 1]))
  323. F[(i - 1) * p:(i - 1) * p + p] = f
  324. # elemental h
  325. h = np.zeros((2, 2))
  326. h[0, 0], h[-1, -1] = -con - self.tau_pos, con - self.tau_neg
  327. # mappinng matrix
  328. map_h = np.zeros((2, n_ele), dtype=int)
  329. map_h[:, 0] = np.arange(2)
  330. for i in np.arange(1, n_ele):
  331. map_h[:, i] = np.arange(
  332. map_h[2 - 1, i - 1], map_h[2 - 1, i - 1] + 2)
  333. # assemble H and eliminate boundaries
  334. H = np.zeros((n_ele + 1, n_ele + 1))
  335. for i in range(n_ele):
  336. for j in range(2):
  337. m = map_h[j, i]
  338. for k in range(2):
  339. n = map_h[k, i]
  340. H[m, n] += h[j, k]
  341. H = H[1:n_ele][:, 1:n_ele]
  342. # elemental g
  343. g = np.zeros((2, p_l))
  344. g[0, 0], g[-1, -1] = self.tau_pos, self.tau_neg
  345. # mapping matrix
  346. map_g_x = map_h
  347. map_g_y = np.arange(p_l * n_ele, dtype=int).reshape(n_ele, p_l).T
  348. # assemble global G
  349. G = np.zeros((n_ele + 1, p_l * n_ele))
  350. for i in range(n_ele):
  351. for j in range(2):
  352. m = map_g_x[j, i]
  353. for k in range(p_l):
  354. n = map_g_y[k, i]
  355. G[m, n] += g[j, k]
  356. G = G[1:n_ele, :]
  357. # elemental c
  358. c = np.zeros((p_l, 2))
  359. c[0, 0], c[-1, -1] = -1, 1
  360. # mapping matrix
  361. map_e_x = np.arange(p_l * n_ele, dtype=int).reshape(n_ele, p_l).T
  362. map_e_y = map_h
  363. # assemble global C
  364. C = np.zeros((p_l * n_ele, n_ele + 1))
  365. for i in range(n_ele):
  366. for j in range(p_l):
  367. m = map_e_x[j, i]
  368. for k in range(2):
  369. n = map_e_y[k, i]
  370. C[m, n] += c[j, k]
  371. C = C[:, 1:n_ele]
  372. # L, easy in 1d
  373. L = np.zeros(n_ele - 1)
  374. # residual vector
  375. R = np.zeros(self.n_ele)
  376. for i in np.arange(self.n_ele):
  377. a = dx[i] / 2 * 1 / kappa * \
  378. ((shp.T).T).dot(np.diag(wi).dot(shp_l.T))
  379. b = ((shpx.T) * np.ones((gorder, p))
  380. ).T.dot(np.diag(wi).dot(shp_l.T))
  381. b_t = ((shpx_l.T) * np.ones((gorder, p_l))
  382. ).T.dot(np.diag(wi).dot(shp.T))
  383. d = dx[i] / 2 * shp.dot(np.diag(wi).dot(shp_l.T))
  384. d[0, 0] += self.tau_pos
  385. d[-1, -1] += self.tau_neg
  386. h = np.zeros((2, 2))
  387. h[0, 0], h[-1, -1] = -con - self.tau_pos, con - self.tau_neg
  388. g = np.zeros((2, p_l))
  389. g[0, 0], g[-1, -1] = self.tau_pos, self.tau_neg
  390. e = np.zeros((p, 2))
  391. e[0, 0], e[-1, -1] = -con - self.tau_pos, con - self.tau_neg
  392. c = np.zeros((p, 2))
  393. c[0, 0], c[-1, -1] = -1, 1
  394. m = np.zeros((2, p_l))
  395. m[0, 0], m[-1, -1] = -1, 1
  396. # local error
  397. R[i] = (np.concatenate((a.dot(q[p_l * i:p_l * i + p_l]) + -b.dot(u[p_l * i:p_l * i + p_l]) + c.dot(U_hat[i:i + 2]),
  398. b_t.T.dot(q[p_l * i:p_l * i + p_l]) + d.dot(u[p_l * i:p_l * i + p_l]) + e.dot(U_hat[i:i + 2]))) - np.concatenate((RR[p * i:p * i + p], F[p * i:p * i + p]))).dot(1 - np.concatenate((z_q[p * i:p * i + p], z_u[p * i:p * i + p])))
  399. com_index = np.argsort(np.abs(R))
  400. # select \theta% elements with the large error
  401. theta = 0.15
  402. refine_index = com_index[int(self.n_ele * (1 - theta)):len(R)]
  403. self.p = self.p - 1
  404. # global error
  405. R_g = (C.T.dot(q) + G.dot(u) + H.dot(U_hat[1:-1])).dot(1 - z_hat)
  406. return np.abs(np.sum(R) + np.sum(R_g)), refine_index + 1
  407. def adaptive(self):
  408. x = np.linspace(0, 1, self.n_ele + 1)
  409. index = []
  410. U, hat_U = self.solve_local(index, x)
  411. U_adjoint, hat_adjoint = self.solve_adjoint(index, x, U, hat_U)
  412. X = np.zeros(self.p * self.n_ele)
  413. dx = np.zeros(self.n_ele + len(index))
  414. for i in range(1, self.n_ele + 1):
  415. x_i, dx_i, x_n = self.mesh(i, index, x)
  416. X[(i - 1) * self.p:(i - 1) * self.p + self.p] = x_i
  417. dx[i - 1] = dx_i
  418. numAdaptive = 28
  419. trueError = np.zeros((2, numAdaptive))
  420. estError = np.zeros((2, numAdaptive))
  421. for i in np.arange(numAdaptive):
  422. est_error, index = self.residual(
  423. U, hat_U, U_adjoint, hat_adjoint, dx, index, x)
  424. index = index.tolist()
  425. U, hat_U = self.solve_local(index, x)
  426. U_adjoint, hat_adjoint = self.solve_adjoint(index, x, U, hat_U)
  427. self.p = self.p - 1
  428. X = np.zeros(self.p * (self.n_ele + len(index)))
  429. dx = np.zeros(self.n_ele + len(index))
  430. for j in range(1, self.n_ele + len(index) + 1):
  431. x_i, dx_i, x_n = self.mesh(j, index, x)
  432. X[(j - 1) * self.p:(j - 1) * self.p + self.p] = x_i
  433. dx[j - 1] = dx_i
  434. x = x_n
  435. estError[0, i] = self.n_ele
  436. estError[1, i] = est_error
  437. self.n_ele = self.n_ele + len(index)
  438. # U_1d = np.zeros(len(U))
  439. # for j in np.arange(len(U)):
  440. # U_1d[j] = U[j]
  441. # Unum = np.array([])
  442. # Xnum = np.array([])
  443. # Qnum = np.array([])
  444. # for j in range(1, self.n_ele + 1):
  445. # # Gauss quadrature
  446. # gorder = 10 * self.p
  447. # xi, wi = np.polynomial.legendre.leggauss(gorder)
  448. # shp, shpx = self.shape(xi, self.p)
  449. # Xnum = np.hstack((Xnum, (X[(j - 1) * self.p + self.p - 1] + X[(j - 1) * self.p]) / 2 + (
  450. # X[(j - 1) * self.p + self.p - 1] - X[(j - 1) * self.p]) / 2 * xi))
  451. # Unum = np.hstack(
  452. # (Unum, shp.T.dot(U_1d[int(len(U) / 2) + (j - 1) * self.p:int(len(U) / 2) + j * self.p])))
  453. # Qnum = np.hstack(
  454. # (Qnum, shp.T.dot(U_1d[int((j - 1) * self.p):j * self.p])))
  455. # if i in [0, 4, 9, 19]:
  456. # plt.plot(Xnum, Unum, '-', color='C3')
  457. # plt.plot(X, U[int(len(U) / 2):len(U)], 'C3.')
  458. # plt.xlabel('$x$', fontsize=17)
  459. # plt.ylabel('$u$', fontsize=17)
  460. # plt.axis([-0.05, 1.05, 0, 1.3])
  461. # plt.grid()
  462. # # plt.savefig('u_test_{}.pdf'.format(i+1))
  463. # plt.show()
  464. # plt.clf()
  465. trueError[0, i] = self.n_ele
  466. trueError[1, i] = np.abs(
  467. U[self.n_ele * self.p - 1] - np.sqrt(self.kappa))
  468. self.p = self.p + 1
  469. self.trueError = trueError
  470. self.estError = estError