|
|
@@ -1,621 +0,0 @@
|
|
|
-import numpy as np
|
|
|
-from numpy import sin, cos, pi
|
|
|
-from scipy.linalg import block_diag
|
|
|
-import matplotlib.pyplot as plt
|
|
|
-from matplotlib import rc
|
|
|
-plt.rc('text', usetex=True)
|
|
|
-plt.rc('font', family='serif')
|
|
|
-
|
|
|
-
|
|
|
-class HDPG1d(object):
|
|
|
- """
|
|
|
- 1d advection hdg solver outlined in 'an implicit HHDG method for
|
|
|
- confusion'. Test case: /tau = 1, convection only, linear and higher order.
|
|
|
- Please enter number of elements and polynomial order, i.e., HDG1d(10,2)
|
|
|
- """
|
|
|
- # stablization parameter
|
|
|
- tau_pos = 1e-6
|
|
|
- tau_neg = 1e-6
|
|
|
- # advection constant
|
|
|
- c = 0
|
|
|
- # diffusion constant
|
|
|
- kappa = 1e-6
|
|
|
-
|
|
|
- def __init__(self, n_ele, p):
|
|
|
- self.n_ele = n_ele
|
|
|
- # number of the shape functions (thus porder + 1)
|
|
|
- self.p = p + 1
|
|
|
-
|
|
|
- def bc(self, case, t=None):
|
|
|
- # boundary condition
|
|
|
- if case == 0:
|
|
|
- # advection-diffusion
|
|
|
- bc = [0, 0]
|
|
|
- if case == 1:
|
|
|
- # simple convection
|
|
|
- # bc = np.sin(2*np.pi*t)
|
|
|
- # adjoint boundary
|
|
|
- bc = [0, 1]
|
|
|
- return bc
|
|
|
-
|
|
|
- def shape(self, x, p):
|
|
|
- """ evaluate shape functions at give locations"""
|
|
|
- # coeffient matrix
|
|
|
- A = np.array([np.linspace(-1, 1, p)]).T**np.arange(p)
|
|
|
- C = np.linalg.inv(A).T
|
|
|
- x = np.array([x]).T
|
|
|
- shp = C.dot((x**np.arange(p)).T)
|
|
|
- shpx = C[:, 1::1].dot((x**np.arange(p - 1) * np.arange(1, p)).T)
|
|
|
- return shp, shpx
|
|
|
-
|
|
|
- def forcing(self, x):
|
|
|
- # f = np.cos(2*np.pi*x)
|
|
|
- # f = 4*pi**2*sin(2*pi*x)
|
|
|
- f = 1
|
|
|
- return f
|
|
|
-
|
|
|
- def mesh(self, n_ele, index, x):
|
|
|
- """generate mesh"""
|
|
|
- # if n_ele < 1 or n_ele > self.n_ele:
|
|
|
- # raise RuntimeError('Bad Element number')
|
|
|
- in_value = np.zeros(len(index))
|
|
|
- for i in np.arange(len(index)):
|
|
|
- in_value[i] = (x[index[i]] + x[index[i] - 1]) / 2
|
|
|
-
|
|
|
- x_c = np.sort(np.insert(x, 0, in_value))
|
|
|
-
|
|
|
- x_i = np.linspace(x_c[n_ele - 1], x_c[n_ele], num=self.p)
|
|
|
- dx = x_c[n_ele] - x_c[n_ele - 1]
|
|
|
- return x_i, dx, x_c
|
|
|
-
|
|
|
- def uexact(self, x):
|
|
|
- # Ue = self.bc(0) + np.sin(2*pi*x)
|
|
|
- Ue = (np.exp(1 / self.kappa * (x - 1)) - 1) / \
|
|
|
- (np.exp(-1 / self.kappa) - 1)
|
|
|
- return Ue
|
|
|
-
|
|
|
- def matrix_gen(self, index, x):
|
|
|
- n_ele = self.n_ele
|
|
|
- # # space size
|
|
|
- # dx = 1/n_ele
|
|
|
-
|
|
|
- # order of polynomial shape functions
|
|
|
- p = self.p
|
|
|
-
|
|
|
- # order of gauss quadrature
|
|
|
- gorder = 2 * p
|
|
|
- # shape function and gauss quadrature
|
|
|
- xi, wi = np.polynomial.legendre.leggauss(gorder)
|
|
|
- shp, shpx = self.shape(xi, p)
|
|
|
- # ---------------------------------------------------------------------
|
|
|
- # advection constant
|
|
|
- con = self.c
|
|
|
-
|
|
|
- # diffusion constant
|
|
|
- kappa = self.kappa
|
|
|
-
|
|
|
- # number of nodes (solution U)
|
|
|
- n_ele = self.n_ele + len(index)
|
|
|
- # elemental forcing vector
|
|
|
- F = np.zeros(p * n_ele)
|
|
|
- for i in range(1, n_ele + 1):
|
|
|
- x_i, dx_i, _ = self.mesh(i, index, x)
|
|
|
- f = dx_i / 2 * \
|
|
|
- shp.dot(wi * self.forcing(x[0] + 1 / 2 * (1 + xi) * dx_i))
|
|
|
- F[(i - 1) * p:(i - 1) * p + p] = f
|
|
|
- # elemental m (for convection only)
|
|
|
- # m = dx/2*shp.dot(np.diag(wi).dot(shp.T))
|
|
|
- # add boundary
|
|
|
- F[0] += (con + self.tau_pos) * self.bc(0)[0]
|
|
|
- F[-1] += (-con + self.tau_neg) * self.bc(0)[1]
|
|
|
-
|
|
|
- # elemental d
|
|
|
- # d = con*(-shpx.T*np.ones((gorder,p))).T.dot(np.diag(wi).dot(shp.T))
|
|
|
- d = shp.dot(np.diag(wi).dot(shp.T))
|
|
|
- # d[0, 0] += self.tau_pos
|
|
|
- # d[-1, -1] += self.tau_neg
|
|
|
-
|
|
|
- # elemental a
|
|
|
- a = 1 / kappa * shp.dot(np.diag(wi).dot(shp.T))
|
|
|
-
|
|
|
- # elemental b
|
|
|
- b = (shpx.T * np.ones((gorder, p))).T.dot(np.diag(wi).dot(shp.T))
|
|
|
-
|
|
|
- # elemental h
|
|
|
- h = np.zeros((2, 2))
|
|
|
- h[0, 0], h[-1, -1] = -con - self.tau_pos, con - self.tau_neg
|
|
|
- # mappinng matrix
|
|
|
- map_h = np.zeros((2, n_ele), dtype=int)
|
|
|
- map_h[:, 0] = np.arange(2)
|
|
|
- for i in np.arange(1, n_ele):
|
|
|
- map_h[:, i] = np.arange(
|
|
|
- map_h[2 - 1, i - 1], map_h[2 - 1, i - 1] + 2)
|
|
|
- # assemble H and eliminate boundaries
|
|
|
- H = np.zeros((n_ele + 1, n_ele + 1))
|
|
|
- for i in range(n_ele):
|
|
|
- for j in range(2):
|
|
|
- m = map_h[j, i]
|
|
|
- for k in range(2):
|
|
|
- n = map_h[k, i]
|
|
|
- H[m, n] += h[j, k]
|
|
|
- H = H[1:n_ele][:, 1:n_ele]
|
|
|
-
|
|
|
- # elemental g
|
|
|
- g = np.zeros((2, p))
|
|
|
- g[0, 0], g[-1, -1] = self.tau_pos, self.tau_neg
|
|
|
- # mapping matrix
|
|
|
- map_g_x = map_h
|
|
|
- map_g_y = np.arange(p * n_ele, dtype=int).reshape(n_ele, p).T
|
|
|
- # assemble global G
|
|
|
- G = np.zeros((n_ele + 1, p * n_ele))
|
|
|
- for i in range(n_ele):
|
|
|
- for j in range(2):
|
|
|
- m = map_g_x[j, i]
|
|
|
- for k in range(p):
|
|
|
- n = map_g_y[k, i]
|
|
|
- G[m, n] += g[j, k]
|
|
|
- G = G[1:n_ele, :]
|
|
|
-
|
|
|
- # elemental e
|
|
|
- e = np.zeros((p, 2))
|
|
|
- e[0, 0], e[-1, -1] = -con - self.tau_pos, con - self.tau_neg
|
|
|
- # mapping matrix
|
|
|
- map_e_x = np.arange(p * n_ele, dtype=int).reshape(n_ele, p).T
|
|
|
- map_e_y = map_h
|
|
|
- # assemble global E
|
|
|
- E = np.zeros((p * n_ele, n_ele + 1))
|
|
|
- for i in range(n_ele):
|
|
|
- for j in range(p):
|
|
|
- m = map_e_x[j, i]
|
|
|
- for k in range(2):
|
|
|
- n = map_e_y[k, i]
|
|
|
- E[m, n] += e[j, k]
|
|
|
- E = E[:, 1:n_ele]
|
|
|
-
|
|
|
- # L, easy in 1d
|
|
|
- L = np.zeros(n_ele - 1)
|
|
|
-
|
|
|
- # elemental c
|
|
|
- c = np.zeros((p, 2))
|
|
|
- c[0, 0], c[-1, -1] = -1, 1
|
|
|
-
|
|
|
- # assemble global C
|
|
|
- C = np.zeros((p * n_ele, n_ele + 1))
|
|
|
- for i in range(n_ele):
|
|
|
- for j in range(p):
|
|
|
- m = map_e_x[j, i]
|
|
|
- for k in range(2):
|
|
|
- n = map_e_y[k, i]
|
|
|
- C[m, n] += c[j, k]
|
|
|
- C = C[:, 1:n_ele]
|
|
|
- # L, easy in 1d
|
|
|
- L = np.zeros(n_ele - 1)
|
|
|
-
|
|
|
- # R, easy in 1d
|
|
|
- R = np.zeros(p * n_ele)
|
|
|
- R[0] = self.bc(0)[0]
|
|
|
- R[-1] = -self.bc(0)[1]
|
|
|
- return d, m, E, G, H, F, L, a, b, C, R
|
|
|
-
|
|
|
- def solve_local(self, index, x):
|
|
|
- """ solve the 1d advection equation wit local HDG"""
|
|
|
- d, _, E, G, H, F, L, a, b, C, R = self.matrix_gen(index, x)
|
|
|
- # find dx
|
|
|
- dx = np.zeros(self.n_ele + len(index))
|
|
|
-
|
|
|
- for i in range(1, self.n_ele + len(index) + 1):
|
|
|
- x_i, dx_i, x_n = self.mesh(i, index, x)
|
|
|
- dx[i - 1] = dx_i
|
|
|
-
|
|
|
- # assemble global D
|
|
|
- bb = np.zeros((self.p, self.p))
|
|
|
- bb[0, 0] = self.tau_pos
|
|
|
- bb[-1, -1] = self.tau_neg
|
|
|
- D = np.repeat(dx, self.p) / 2 * block_diag(*[d] * (
|
|
|
- self.n_ele + len(index))) + block_diag(*[bb] * (self.n_ele + len(index)))
|
|
|
- # assemble global A
|
|
|
- A = np.repeat(dx, self.p) / 2 * block_diag(*
|
|
|
- [a] * (self.n_ele + len(index)))
|
|
|
-
|
|
|
- # assemble global B
|
|
|
- B = block_diag(*[b] * (self.n_ele + len(index)))
|
|
|
- # solve U and \lambda
|
|
|
- K = -np.concatenate((C.T, G), axis=1).dot(np.linalg.inv(
|
|
|
- np.bmat([[A, -B], [B.T, D]])).dot(np.concatenate((C, E)))) + H
|
|
|
- F_hat = np.array([L]).T - np.concatenate((C.T, G), axis=1).dot(np.linalg.inv(
|
|
|
- np.bmat([[A, -B], [B.T, D]]))).dot(np.array([np.concatenate((R, F))]).T)
|
|
|
- lamba = np.linalg.solve(K, F_hat)
|
|
|
- U = np.linalg.inv(np.bmat([[A, -B], [B.T, D]])).dot(
|
|
|
- np.array([np.concatenate((R, F))]).T - np.concatenate((C, E)).dot(lamba))
|
|
|
- return U, lamba
|
|
|
-
|
|
|
- def solve_adjoint(self, index, x, u, u_hat):
|
|
|
- self.p = self.p + 1
|
|
|
- d, _, E, G, H, F, L, a, b, C, R = self.matrix_gen(index, x)
|
|
|
-
|
|
|
- # add boundary
|
|
|
- F = np.zeros(len(F))
|
|
|
- R[-1] = -self.bc(1)[1]
|
|
|
-
|
|
|
- # find dx
|
|
|
- dx = np.zeros(self.n_ele + len(index))
|
|
|
- for i in range(1, self.n_ele + len(index) + 1):
|
|
|
- x_i, dx_i, x_n = self.mesh(i, index, x)
|
|
|
- dx[i - 1] = dx_i
|
|
|
- # assemble global D
|
|
|
- bb = np.zeros((self.p, self.p))
|
|
|
- bb[0, 0] = self.tau_pos
|
|
|
- bb[-1, -1] = self.tau_neg
|
|
|
- D = np.repeat(dx, self.p) / 2 * block_diag(*[d] * (
|
|
|
- self.n_ele + len(index))) + block_diag(*[bb] * (self.n_ele + len(index)))
|
|
|
-
|
|
|
- # assemble global A
|
|
|
- A = np.repeat(dx, self.p) / 2 * block_diag(*
|
|
|
- [a] * (self.n_ele + len(index)))
|
|
|
-
|
|
|
- # assemble global B
|
|
|
- B = block_diag(*[b] * (self.n_ele + len(index)))
|
|
|
-
|
|
|
- # # assemble global matrix LHS
|
|
|
- LHS = np.bmat([[A, -B, C], [B.T, D, E], [C.T, G, H]])
|
|
|
-
|
|
|
- # solve U and \lambda
|
|
|
- U = np.linalg.solve(LHS.T, np.concatenate((R, F, L)))
|
|
|
-
|
|
|
- return U[0:2 * self.p * (self.n_ele + len(index))], U[2 * self.p * (self.n_ele + len(index)):len(U)]
|
|
|
-
|
|
|
- def diffusion(self):
|
|
|
- """solve 1d convection with local HDG"""
|
|
|
-
|
|
|
- # begin and end time
|
|
|
- t, T = 0, 1
|
|
|
-
|
|
|
- # time marching step for diffusion equation
|
|
|
- dt = 1e-3
|
|
|
-
|
|
|
- d, m, E, G, H, F, L, a, b, C, R = self.matrix_gen()
|
|
|
- # add time derivatives to the space derivatives (both are
|
|
|
- # elmental-wise)
|
|
|
- d = d + 1 / dt * m
|
|
|
- # assemble global D
|
|
|
- D = block_diag(*[d] * self.n_ele)
|
|
|
- # assemble global A
|
|
|
- A = block_diag(*[a] * self.n_ele)
|
|
|
- # assemble global B
|
|
|
- B = block_diag(*[b] * self.n_ele)
|
|
|
-
|
|
|
- # initial condition
|
|
|
- X = np.zeros(self.p * self.n_ele)
|
|
|
- for i in range(1, self.n_ele + 1):
|
|
|
- x = self.mesh(i)
|
|
|
- X[(i - 1) * self.p:(i - 1) * self.p + self.p] = x
|
|
|
- U = np.concatenate((pi * cos(pi * X), sin(pi * X)))
|
|
|
-
|
|
|
- # assemble M
|
|
|
- M = block_diag(*[1 / dt * m] * self.n_ele)
|
|
|
-
|
|
|
- # time marching
|
|
|
- while t < T:
|
|
|
- # add boundary conditions
|
|
|
- F_dynamic = F + \
|
|
|
- M.dot(U[self.n_ele * self.p:2 * self.n_ele * self.p])
|
|
|
-
|
|
|
- # assemble global matrix LHS
|
|
|
- LHS = np.bmat([[A, -B, C], [B.T, D, E], [C.T, G, H]])
|
|
|
-
|
|
|
- # solve U and \lambda
|
|
|
- U = np.linalg.solve(LHS, np.concatenate((R, F_dynamic, L)))
|
|
|
-
|
|
|
- # plot solutions
|
|
|
- plt.clf()
|
|
|
- plt.plot(X, U[self.n_ele * self.p:2 * self.n_ele * self.p], '-r.')
|
|
|
- plt.plot(X, sin(pi * X) * np.exp(-pi**2 * t))
|
|
|
- plt.ylim([0, 1])
|
|
|
- plt.grid()
|
|
|
- plt.pause(1e-3)
|
|
|
-
|
|
|
- plt.close()
|
|
|
- print("Diffusion equation du/dt - du^2/d^2x = 0 with u_exact ="
|
|
|
- ' 6sin(pi*x)*exp(-pi^2*t).')
|
|
|
- plt.figure(1)
|
|
|
- plt.plot(X, U[self.n_ele * self.p:2 * self.n_ele * self.p], '-r.')
|
|
|
- plt.plot(X, sin(pi * X) * np.exp(-pi**2 * T))
|
|
|
- plt.xlabel('x')
|
|
|
- plt.ylabel('y')
|
|
|
- plt.legend(('Numberical', 'Exact'), loc='upper left')
|
|
|
- plt.title('Simple Diffusion Equation Solution at t = {}'.format(T))
|
|
|
- plt.grid()
|
|
|
- plt.savefig('diffusion', bbox_inches='tight')
|
|
|
- plt.show(block=False)
|
|
|
- return U
|
|
|
-
|
|
|
- def errorL2(self):
|
|
|
- # evaluate error
|
|
|
- errorL2 = 0.
|
|
|
- # solve and track solving time
|
|
|
- x = np.linspace(0, 1, self.n_ele + 1)
|
|
|
- U, _ = self.solve_local([], x)
|
|
|
- errorL2 = np.abs(U[self.p * self.n_ele - 1] - np.sqrt(self.kappa))
|
|
|
- return errorL2
|
|
|
-
|
|
|
- def conv(self):
|
|
|
- p = np.arange(2, 6)
|
|
|
- n_ele = 2**np.arange(1, 9)
|
|
|
- legend = []
|
|
|
- errorL2 = np.zeros((n_ele.size, p.size))
|
|
|
- for i in range(p.size):
|
|
|
- self.p = p[i]
|
|
|
- for j, n in enumerate(n_ele):
|
|
|
- self.n_ele = n
|
|
|
- print(self.errorL2())
|
|
|
- errorL2[j, i] = self.errorL2()
|
|
|
- legend.append('p = {}'.format(p[i] - 1))
|
|
|
- # loglog plot
|
|
|
- plt.figure(3)
|
|
|
- plt.loglog(n_ele, errorL2, '-o')
|
|
|
- plt.legend((legend))
|
|
|
- plt.xlabel('Number of nodes')
|
|
|
- plt.ylabel('L2 norm(log)')
|
|
|
- plt.title('Convergence rate(log)')
|
|
|
- plt.grid()
|
|
|
- plt.savefig('con_rate_uni.pdf', bbox_inches='tight')
|
|
|
-
|
|
|
- # output then save the convergence rates
|
|
|
- rate = np.log(errorL2[0:-1, :] /
|
|
|
- errorL2[1:errorL2.size, :]) / np.log(2)
|
|
|
- for i in range(p.size):
|
|
|
- print('p = {}, convergence rate = {:.4f}'.format(
|
|
|
- p[i] - 1, rate[-1, i]))
|
|
|
- np.savetxt('Con_rate.csv', rate, fmt='%10.4f',
|
|
|
- delimiter=',', newline='\n')
|
|
|
- return n_ele, errorL2
|
|
|
-
|
|
|
- def residual(self, U, hat_U, z, hat_z, dx, index, x_c):
|
|
|
- n_ele = self.n_ele
|
|
|
-
|
|
|
- # order of polynomial shape functions
|
|
|
- p = self.p
|
|
|
-
|
|
|
- p_l = p - 1
|
|
|
- # order of gauss quadrature
|
|
|
- gorder = 2 * p
|
|
|
- # shape function and gauss quadrature
|
|
|
- xi, wi = np.polynomial.legendre.leggauss(gorder)
|
|
|
- shp, shpx = self.shape(xi, p)
|
|
|
- shp_l, shpx_l = self.shape(xi, p_l)
|
|
|
- # ---------------------------------------------------------------------
|
|
|
- # advection constant
|
|
|
- con = self.c
|
|
|
-
|
|
|
- # diffusion constant
|
|
|
- kappa = self.kappa
|
|
|
-
|
|
|
- z_q, z_u, z_hat = np.zeros(self.p * self.n_ele), \
|
|
|
- np.zeros(self.p * self.n_ele), np.zeros(self.n_ele - 1)
|
|
|
-
|
|
|
- q, u, lamba = np.zeros(p_l * self.n_ele), \
|
|
|
- np.zeros(p_l * self.n_ele), np.zeros(self.n_ele - 1)
|
|
|
-
|
|
|
- for i in np.arange(self.p * self.n_ele):
|
|
|
- z_q[i] = z[i]
|
|
|
- z_u[i] = z[i + self.p * self.n_ele]
|
|
|
-
|
|
|
- for i in np.arange(p_l * self.n_ele):
|
|
|
- q[i] = U[i]
|
|
|
- u[i] = U[i + p_l * self.n_ele]
|
|
|
-
|
|
|
- for i in np.arange(self.n_ele - 1):
|
|
|
- z_hat[i] = hat_z[i]
|
|
|
-
|
|
|
- # add boundary condtions to U_hat
|
|
|
- U_hat = np.zeros(self.n_ele + 1)
|
|
|
- for i, x in enumerate(hat_U):
|
|
|
- U_hat[i + 1] = x
|
|
|
- U_hat[0] = self.bc(0)[0]
|
|
|
- U_hat[-1] = self.bc(0)[1]
|
|
|
-
|
|
|
- # L, easy in 1d
|
|
|
- L = np.zeros(n_ele + 1)
|
|
|
-
|
|
|
- # R, easy in 1d
|
|
|
- RR = np.zeros(p * n_ele)
|
|
|
-
|
|
|
- # elemental forcing vector
|
|
|
- F = np.zeros(p * n_ele)
|
|
|
- for i in range(1, n_ele + 1):
|
|
|
- f = dx[i - 1] / 2 * \
|
|
|
- shp.dot(
|
|
|
- wi * self.forcing(x_c[0] + 1 / 2 * (1 + xi) * dx[i - 1]))
|
|
|
- F[(i - 1) * p:(i - 1) * p + p] = f
|
|
|
-
|
|
|
- # elemental h
|
|
|
- h = np.zeros((2, 2))
|
|
|
- h[0, 0], h[-1, -1] = -con - self.tau_pos, con - self.tau_neg
|
|
|
- # mappinng matrix
|
|
|
- map_h = np.zeros((2, n_ele), dtype=int)
|
|
|
- map_h[:, 0] = np.arange(2)
|
|
|
- for i in np.arange(1, n_ele):
|
|
|
- map_h[:, i] = np.arange(
|
|
|
- map_h[2 - 1, i - 1], map_h[2 - 1, i - 1] + 2)
|
|
|
- # assemble H and eliminate boundaries
|
|
|
- H = np.zeros((n_ele + 1, n_ele + 1))
|
|
|
- for i in range(n_ele):
|
|
|
- for j in range(2):
|
|
|
- m = map_h[j, i]
|
|
|
- for k in range(2):
|
|
|
- n = map_h[k, i]
|
|
|
- H[m, n] += h[j, k]
|
|
|
- H = H[1:n_ele][:, 1:n_ele]
|
|
|
-
|
|
|
- # elemental g
|
|
|
- g = np.zeros((2, p_l))
|
|
|
- g[0, 0], g[-1, -1] = self.tau_pos, self.tau_neg
|
|
|
- # mapping matrix
|
|
|
- map_g_x = map_h
|
|
|
- map_g_y = np.arange(p_l * n_ele, dtype=int).reshape(n_ele, p_l).T
|
|
|
- # assemble global G
|
|
|
- G = np.zeros((n_ele + 1, p_l * n_ele))
|
|
|
- for i in range(n_ele):
|
|
|
- for j in range(2):
|
|
|
- m = map_g_x[j, i]
|
|
|
- for k in range(p_l):
|
|
|
- n = map_g_y[k, i]
|
|
|
- G[m, n] += g[j, k]
|
|
|
- G = G[1:n_ele, :]
|
|
|
-
|
|
|
- # elemental c
|
|
|
- c = np.zeros((p_l, 2))
|
|
|
- c[0, 0], c[-1, -1] = -1, 1
|
|
|
-
|
|
|
- # mapping matrix
|
|
|
- map_e_x = np.arange(p_l * n_ele, dtype=int).reshape(n_ele, p_l).T
|
|
|
- map_e_y = map_h
|
|
|
-
|
|
|
- # assemble global C
|
|
|
- C = np.zeros((p_l * n_ele, n_ele + 1))
|
|
|
- for i in range(n_ele):
|
|
|
- for j in range(p_l):
|
|
|
- m = map_e_x[j, i]
|
|
|
- for k in range(2):
|
|
|
- n = map_e_y[k, i]
|
|
|
- C[m, n] += c[j, k]
|
|
|
- C = C[:, 1:n_ele]
|
|
|
-
|
|
|
- # L, easy in 1d
|
|
|
- L = np.zeros(n_ele - 1)
|
|
|
-
|
|
|
- # residual vector
|
|
|
- R = np.zeros(self.n_ele)
|
|
|
- for i in np.arange(self.n_ele):
|
|
|
- a = dx[i] / 2 * 1 / kappa * \
|
|
|
- ((shp.T).T).dot(np.diag(wi).dot(shp_l.T))
|
|
|
-
|
|
|
- b = ((shpx.T) * np.ones((gorder, p))
|
|
|
- ).T.dot(np.diag(wi).dot(shp_l.T))
|
|
|
-
|
|
|
- b_t = ((shpx_l.T) * np.ones((gorder, p_l))
|
|
|
- ).T.dot(np.diag(wi).dot(shp.T))
|
|
|
-
|
|
|
- d = dx[i] / 2 * shp.dot(np.diag(wi).dot(shp_l.T))
|
|
|
- d[0, 0] += self.tau_pos
|
|
|
- d[-1, -1] += self.tau_neg
|
|
|
-
|
|
|
- h = np.zeros((2, 2))
|
|
|
- h[0, 0], h[-1, -1] = -con - self.tau_pos, con - self.tau_neg
|
|
|
-
|
|
|
- g = np.zeros((2, p_l))
|
|
|
- g[0, 0], g[-1, -1] = self.tau_pos, self.tau_neg
|
|
|
-
|
|
|
- e = np.zeros((p, 2))
|
|
|
- e[0, 0], e[-1, -1] = -con - self.tau_pos, con - self.tau_neg
|
|
|
-
|
|
|
- c = np.zeros((p, 2))
|
|
|
- c[0, 0], c[-1, -1] = -1, 1
|
|
|
-
|
|
|
- m = np.zeros((2, p_l))
|
|
|
- m[0, 0], m[-1, -1] = -1, 1
|
|
|
- # local error
|
|
|
- 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]),
|
|
|
- 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])))
|
|
|
-
|
|
|
- com_index = np.argsort(np.abs(R))
|
|
|
- # select \theta% elements with the large error
|
|
|
- theta = 0.15
|
|
|
- refine_index = com_index[int(self.n_ele * (1 - theta)):len(R)]
|
|
|
- self.p = self.p - 1
|
|
|
-
|
|
|
- # global error
|
|
|
- R_g = (C.T.dot(q) + G.dot(u) + H.dot(U_hat[1:-1])).dot(1 - z_hat)
|
|
|
- return np.abs(np.sum(R) + np.sum(R_g)), refine_index + 1
|
|
|
-
|
|
|
- def adaptive(self):
|
|
|
- x = np.linspace(0, 1, self.n_ele + 1)
|
|
|
- index = []
|
|
|
- U, hat_U = self.solve_local(index, x)
|
|
|
- U_adjoint, hat_adjoint = self.solve_adjoint(index, x, U, hat_U)
|
|
|
- X = np.zeros(self.p * self.n_ele)
|
|
|
- dx = np.zeros(self.n_ele + len(index))
|
|
|
- for i in range(1, self.n_ele + 1):
|
|
|
- x_i, dx_i, x_n = self.mesh(i, index, x)
|
|
|
- X[(i - 1) * self.p:(i - 1) * self.p + self.p] = x_i
|
|
|
- dx[i - 1] = dx_i
|
|
|
-
|
|
|
- numAdaptive = 28
|
|
|
- trueError = np.zeros((2, numAdaptive))
|
|
|
- estError = np.zeros((2, numAdaptive))
|
|
|
- for i in np.arange(numAdaptive):
|
|
|
- est_error, index = self.residual(
|
|
|
- U, hat_U, U_adjoint, hat_adjoint, dx, index, x)
|
|
|
- index = index.tolist()
|
|
|
- U, hat_U = self.solve_local(index, x)
|
|
|
- U_adjoint, hat_adjoint = self.solve_adjoint(index, x, U, hat_U)
|
|
|
- self.p = self.p - 1
|
|
|
- X = np.zeros(self.p * (self.n_ele + len(index)))
|
|
|
- dx = np.zeros(self.n_ele + len(index))
|
|
|
- for j in range(1, self.n_ele + len(index) + 1):
|
|
|
- x_i, dx_i, x_n = self.mesh(j, index, x)
|
|
|
- X[(j - 1) * self.p:(j - 1) * self.p + self.p] = x_i
|
|
|
- dx[j - 1] = dx_i
|
|
|
- x = x_n
|
|
|
- estError[0, i] = self.n_ele
|
|
|
- estError[1, i] = est_error
|
|
|
-
|
|
|
- self.n_ele = self.n_ele + len(index)
|
|
|
-
|
|
|
- # U_1d = np.zeros(len(U))
|
|
|
- # for j in np.arange(len(U)):
|
|
|
- # U_1d[j] = U[j]
|
|
|
- # Unum = np.array([])
|
|
|
- # Xnum = np.array([])
|
|
|
- # Qnum = np.array([])
|
|
|
- # for j in range(1, self.n_ele + 1):
|
|
|
- # # Gauss quadrature
|
|
|
- # gorder = 10 * self.p
|
|
|
- # xi, wi = np.polynomial.legendre.leggauss(gorder)
|
|
|
- # shp, shpx = self.shape(xi, self.p)
|
|
|
- # Xnum = np.hstack((Xnum, (X[(j - 1) * self.p + self.p - 1] + X[(j - 1) * self.p]) / 2 + (
|
|
|
- # X[(j - 1) * self.p + self.p - 1] - X[(j - 1) * self.p]) / 2 * xi))
|
|
|
- # Unum = np.hstack(
|
|
|
- # (Unum, shp.T.dot(U_1d[int(len(U) / 2) + (j - 1) * self.p:int(len(U) / 2) + j * self.p])))
|
|
|
- # Qnum = np.hstack(
|
|
|
- # (Qnum, shp.T.dot(U_1d[int((j - 1) * self.p):j * self.p])))
|
|
|
- # if i in [0, 4, 9, 19]:
|
|
|
- # plt.plot(Xnum, Unum, '-', color='C3')
|
|
|
- # plt.plot(X, U[int(len(U) / 2):len(U)], 'C3.')
|
|
|
- # plt.xlabel('$x$', fontsize=17)
|
|
|
- # plt.ylabel('$u$', fontsize=17)
|
|
|
- # plt.axis([-0.05, 1.05, 0, 1.3])
|
|
|
- # plt.grid()
|
|
|
- # # plt.savefig('u_test_{}.pdf'.format(i+1))
|
|
|
- # plt.show()
|
|
|
- # plt.clf()
|
|
|
- trueError[0, i] = self.n_ele
|
|
|
- trueError[1, i] = U[self.n_ele * self.p - 1] - np.sqrt(self.kappa)
|
|
|
- self.p = self.p + 1
|
|
|
- return trueError, estError
|
|
|
-
|
|
|
-
|
|
|
-# test = HDPG1d(2, 2)
|
|
|
-
|
|
|
-# _, trueError, estError = test.adaptive()
|
|
|
-# p = np.arange(3, 4)
|
|
|
-# n_ele = 2**np.arange(1, 8)
|
|
|
-# legend = []
|
|
|
-# errorL2 = np.zeros((n_ele.size, p.size))
|
|
|
-# for i in range(p.size):
|
|
|
-# test.p = p[i]
|
|
|
-# for j, n in enumerate(n_ele):
|
|
|
-# test.n_ele = n
|
|
|
-# print(test.errorL2())
|
|
|
-# errorL2[j, i] = test.errorL2()
|
|
|
-
|
|
|
-# plt.loglog(trueError[0, 0:-1], np.abs(trueError[1, 0:-1]), '-ro')
|
|
|
-# plt.axis([1, 250, 1e-13, 1e-2])
|
|
|
-# plt.loglog(n_ele, errorL2, '-o')
|
|
|
-# plt.loglog(estError[0, :], estError[1, :], '--', color='#1f77b4')
|
|
|
-# plt.xlabel('Number of elements', fontsize=17)
|
|
|
-# plt.ylabel('Error', fontsize=17)
|
|
|
-# plt.grid()
|
|
|
-# plt.legend(('Adaptive', 'Uniform', 'Estimator'), loc=3, fontsize=15)
|
|
|
-# # plt.savefig('conv{}p{}_4_test.pdf'.format(15, test.p))
|
|
|
-# plt.show()
|