def g_u(x): """u的梯度(解析值) 为尽量减少计算与误差,直接代入梯度解析式计算梯度. Args: x: (theta,phi)^T. Returns: g: 梯度矢量. """ assert isinstance(x, Matrix), 'x不是Matrix' n = int(x.row / 2) g = Matrix(zero_mat(2 * n, 1)) for i in range(n): a = 0 b = 0 for j in range(n): if j != i: a -= (sin(x[i][0] - x[j][0]) + cos(x[i][0]) * sin(x[j][0]) * (1 - cos(x[i + n][0] - x[j + n][0]))) / (rij( x[i][0], x[j][0], x[i + n][0], x[j + n][0])**3) b -= (sin(x[i][0]) * sin(x[j][0]) * sin(x[i + n][0] - x[j + n][0])) / (rij( x[i][0], x[j][0], x[i + n][0], x[j + n][0])**3) g[i][0] = a g[i + n][0] = b return g
def fij(n, h, x0, y0): """ 线性方程组右侧列向量 input:剖分数n,步长h,x0,y0 output:Matrix fij """ n0 = (n - 1) * (n - 1) f = Matrix(zero_mat(n0, 1)) for i in range(1, n): for j in range(1, n): k = (i - 1) * (n - 1) + j - 1 f[k][0] = fxy(x0 + i * h, y0 + j * h) * h * h return f
def get_G(n): ''' 获取六边形电阻网络的导纳矩阵 进行星->三角变换后变为等边长三角形网络 取边上节点数为n,节点标号方式为从一个顶点开始,算作第一层,一次向上取第二层,第三层…… return Matrix ''' g = Matrix(zero_mat(int((n**2 + n) / 2), int((n**2 + n) / 2))) g[0][0] = 1 g[0][1] = -1 / 2 g[0][2] = -1 / 2 i = 1 for k in range(1, n - 1): g[i][i - k] = -1 / 2 g[i][i + 1] = -1 / 3 g[i][i + k + 1] = -1 / 2 g[i][i + k + 2] = -1 / 3 g[i][i] = 5 / 3 for j in range(1, k): s = i + j g[s][s - k - 1] = -1 / 3 g[s][s - k] = -1 / 3 g[s][s - 1] = -1 / 3 g[s][s + 1] = -1 / 3 g[s][s + k + 1] = -1 / 3 g[s][s + k + 2] = -1 / 3 g[s][s] = 2 s = i + k g[s][s - k - 1] = -1 / 2 g[s][s - 1] = -1 / 3 g[s][s + k + 1] = -1 / 3 g[s][s + k + 2] = -1 / 2 g[s][s] = 5 / 3 i = s + 1 g[i][i - n + 1] = -1 / 2 g[i][i + 1] = -1 / 2 g[i][i] = 1 for j in range(1, n - 1): s = i + j g[s][s - n] = -1 / 3 g[s][s - n + 1] = -1 / 3 g[s][s - 1] = -1 / 2 g[s][s + 1] = -1 / 2 g[s][s] = 5 / 3 s = i + n - 1 g[s][s - n] = -1 / 2 g[s][s - 1] = -1 / 2 g[s][s] = 1 # 带状矩阵,半宽为n return g
def get_G(n): ''' 获取三角形电阻网络的导纳矩阵 取边上节点数为n,节点标号方式为从一个顶点开始,算作第一层,一次向上取第二层,第三层…… return Matrix ''' g = Matrix(zero_mat(int((n**2 + n) / 2), int((n**2 + n) / 2))) g[0][0] = 2 g[0][1] = -1 g[0][2] = -1 i = 1 for k in range(1, n - 1): g[i][i - k] = -1 g[i][i + 1] = -1 g[i][i + k + 1] = -1 g[i][i + k + 2] = -1 g[i][i] = 4 for j in range(1, k): s = i + j g[s][s - k - 1] = -1 g[s][s - k] = -1 g[s][s - 1] = -1 g[s][s + 1] = -1 g[s][s + k + 1] = -1 g[s][s + k + 2] = -1 g[s][s] = 6 s = i + k g[s][s - k - 1] = -1 g[s][s - 1] = -1 g[s][s + k + 1] = -1 g[s][s + k + 2] = -1 g[s][s] = 4 i = s + 1 g[i][i - n + 1] = -1 g[i][i + 1] = -1 g[i][i] = 2 for j in range(1, n - 1): s = i + j g[s][s - n] = -1 g[s][s - n + 1] = -1 g[s][s - 1] = -1 g[s][s + 1] = -1 g[s][s] = 4 s = i + n - 1 g[s][s - n] = -1 g[s][s - 1] = -1 g[s][s] = 2 # 带状矩阵,半宽为n return g
def get_G(n, w): ''' 获取三角形交流网络的导纳矩阵 取边上节点数为n,节点标号方式为从右下一个顶点开始,算作第一层,一次向上取第二层,第三层…… return Matrix ''' g = Matrix(zero_mat(int((n**2 + n) / 2), int((n**2 + n) / 2))) g[0][0] = 1j * (w - 1 / w) g[0][1] = -1j * w g[0][2] = 1j / w i = 1 for k in range(1, n - 1): g[i][i - k] = -1j * w g[i][i + 1] = -1 g[i][i + k + 1] = -1j * w g[i][i + k + 2] = 1j / w g[i][i] = 1 + 1j * (2 * w - 1 / w) for j in range(1, k): s = i + j g[s][s - k - 1] = 1j / w g[s][s - k] = -1j * w g[s][s - 1] = -1 g[s][s + 1] = -1 g[s][s + k + 1] = -1j * w g[s][s + k + 2] = 1j / w g[s][s] = 2 + 2j * (w - 1 / w) s = i + k g[s][s - k - 1] = 1j / w g[s][s - 1] = -1 g[s][s + k + 1] = -1j * w g[s][s + k + 2] = 1j / w g[s][s] = 1 + 1j * (w - 2 / w) i = s + 1 g[i][i - n + 1] = -1j * w g[i][i + 1] = -1 g[i][i] = 1 + 1j * w for j in range(1, n - 1): s = i + j g[s][s - n] = 1j / w g[s][s - n + 1] = -1j * w g[s][s - 1] = -1 g[s][s + 1] = -1 g[s][s] = 2 + 1j * (w - 1 / w) s = i + n - 1 g[s][s - n] = 1j / w g[s][s - 1] = -1 g[s][s] = 1 - 1j / w # 带状矩阵,半宽为n return g
def initialize_x0(n): """初始化电子位置. cos(theta)和phi坐标在各自范围内随机取值. Args: n: 电子数. Returns: x0: 初始化的位置分布. """ x0 = Matrix(zero_mat(2 * n, 1)) for i in range(n): x0[i][0] = acos(random.uniform(-1, 1)) x0[i + n][0] = random.uniform(0, 2 * pi) return x0
def solve_R(g, a, b, n): ''' 直接法求解标号为a,b节点间的等效电阻R return R ''' assert a < b, "b>a不符合规范" # 删去g的第a行a列,使其成为非奇异矩阵 g.pop_col(a) g.pop_row(a) m = g.row # 对称正定矩阵Cholesky分解改进算法,G=LDL^T,带状矩阵优化 for i in range(m): if i < n: for j in range(i + 1): for k in range(j): g[i][j] = g[i][j] - g[i][k] * g[j][k] / g[k][k] else: for j in range(i - n, i + 1): for k in range(j): g[i][j] = g[i][j] - g[i][k] * g[j][k] / g[k][k] # 对电流I进行处理,I=LDI' # 求解 LDI'=I 得到 I',下三角前代算法 I = Matrix(zero_mat(m, 1)) I[b - 1][0] = 1 for i in range(m): assert g[i][i] != 0, "系数矩阵主元存在‘0’项" for j in range(i): I[i][0] = I[i][0] - g[i][j] / g[j][j] * I[j][0] I[i][0] = I[i][0] """ # 利用(TD)^(-1)特性方法失败 I = Matrix(zero_mat(m, 1)) I[b-1][0] = 1 for i in range(b, m): I[i][0] = -g[i][b - 1] / g[b - 1][b - 1] """ g = g.T() # 上三角矩阵回代得解 # 直接调用wheels通法 x = up_tri_msolve(g, I) return x[b - 1][0] """
def get_G(n): ''' 获取正方形电阻网络的导纳矩阵 节点标号方式为从左下起,由左向右,依次取完每行 return Matrix ''' g = Matrix(zero_mat(n**2, n**2)) for i in range(n**2): for j in range(n**2): if (abs(j - i) == 1) | (abs(j - i) == n): g[i][j] = -1 g[i][i] += 1 for i in range(1, n): g[i * n][i * n - 1] = 0 g[i * n][i * n] -= 1 g[i * n - 1][i * n] = 0 g[i * n - 1][i * n - 1] -= 1 return g
def coefficientmatrix(n): """ 系数矩阵生成, 已包含边界条件‘u=0’ input: 剖分数 n output:系数矩阵A """ n0 = (n - 1) * (n - 1) # 系数矩阵的维数 A = Matrix(zero_mat(n0, n0)) for i in range(0, n0): # 设置中央对角线 A[i][i] = 4 for j in range(0, n - 1): # 设置里面的两条斜对角线 for k in range(0, n - 2): kk = j * (n - 1) + k A[kk][kk + 1] = -1 A[kk + 1][kk] = -1 for k in range(0, n0 - n + 1): # 设置外面的两条斜对角线 A[k][k + n - 1] = -1 A[k + n - 1][k] = -1 return A
def initialize_x0(n): """初始化电子位置. cos(theta)和phi坐标在各自范围内均匀取值 Args: n: 电子数. Returns: x0: 初始化的位置分布. """ x0 = Matrix(zero_mat(2 * n, 1)) costheta = [1 - i * 2 / (n - 1) for i in range(n)] phi = [i * 2 * pi / n for i in range(n)] random.shuffle(costheta) random.shuffle(phi) for i in range(n): x0[i][0] = acos(costheta[i]) x0[i + n][0] = phi[i] return x0
def initialize_x0(n): """初始化电子位置. cos(theta)和phi坐标在各自范围内随机取值. Args: n: 电子数. Returns: x0: 初始化的位置分布. """ x0 = Matrix(zero_mat(2 * n, 1)) i = 0 for point in splot(n): if i >= n: break x0[i][0] = point[0] x0[i + n][0] = point[1] i += 1 return x0
def solve_R(g, a, b, n, M, e): ''' 迭代法求解标号为a,b节点间的等效电阻R return R ''' assert a < b, "b>a不符合规范" # 删去g的第a行a列,使其成为非奇异矩阵 g.pop_col(a) g.pop_row(a) m = g.row # 对电流I进行处理 I = Matrix(zero_mat(m, 1)) I[b - 1][0] = 1 """ # Jacobi迭代法收敛速度太慢 # Jacobi迭代法求解 gx=I x_0 = Matrix(zero_mat(m, 1)) for i in range(m): x_0[i][0] = 1 # 内置初始解向量 x = Matrix(zero_mat(m, 1)) # 另一组解向量初始化 M = 1000 # 内置最大迭代次数100 e = 1e-10 # 内置判停标准1e-10 for k in range(M): for i in range(m): x[i][0] = I[i][0] for j in range(m): x[i][0] = x[i][0] - g[i][j] * x_0[j][0] x[i][0] = x[i][0] / g[i][i] + x_0[i][0] if col_abs(x - x_0) < e: print("迭代次数: ", k+1) break elif k == M - 1: print("Not converged at given M=", M, " and e=", e) break x_0 = copy.deepcopy(x) """ # Gauss-Seidel迭代法 + 带状对称矩阵优化 x = Matrix(zero_mat(m, 1)) for i in range(m): x[i][0] = 1 # 内置初始解向量 x_0 = Matrix(zero_mat(m, 1)) # 另一组解向量初始化 for k in range(M): x_0 = copy.deepcopy(x) if m > 2 * n + 1: for i in range(m): x[i][0] = I[i][0] if i < n: for j in range(i): x[i][0] = x[i][0] - g[i][j] * x[j][0] for j in range(i + 1, i + n + 1): x[i][0] = x[i][0] - g[i][j] * x[j][0] x[i][0] = x[i][0] / g[i][i] elif i > m - n - 1: for j in range(i - n, i): x[i][0] = x[i][0] - g[i][j] * x[j][0] for j in range(i + 1, m): x[i][0] = x[i][0] - g[i][j] * x[j][0] x[i][0] = x[i][0] / g[i][i] else: for j in range(i - n, i): x[i][0] = x[i][0] - g[i][j] * x[j][0] for j in range(i + 1, i + n + 1): x[i][0] = x[i][0] - g[i][j] * x[j][0] x[i][0] = x[i][0] / g[i][i] # 逐次超松弛迭代法 x[i][0] = -0.9 * x_0[i][0] + 1.9 * x[i][0] else: for i in range(m): x[i][0] = I[i][0] for j in range(i): x[i][0] = x[i][0] - g[i][j] * x[j][0] for j in range(i + 1, m): x[i][0] = x[i][0] - g[i][j] * x[j][0] x[i][0] = x[i][0] / g[i][i] # 逐次超松弛迭代法 x[i][0] = -0.9 * x_0[i][0] + 1.9 * x[i][0] if col_abs(x - x_0) < e: print("迭代次数: ", k + 1) break elif k == M - 1: print("Not converged at given M=", M, " and e=", e) break return x[b - 1][0]
def uxy(x, y): """泊松方程真解""" return sin(pi * x) * sin(pi * y) a_x = 0. # x方向边界 b_x = 1. c_y = 0. # y方向边界 d_y = 1. for m in range(4, 8): n = 2**m # 剖分数 h = (b_x - a_x) / n # 步长 A0 = coefficientmatrix(n) # 计算系数矩阵 f_1d = Matrix(zero_mat((n - 1) * (n - 1), 1)) # 代求向量,初始化 b_matrix = fij(n, h, a_x, c_y) # 计算右端矩阵b f_1d = cg(A0, b_matrix, f_1d) # 共轭梯度法求解 uij = [] # 转换成二维矩阵 fT = f_1d.T().matrix[0] zero = [0 for i in range(n + 1)] uij.append(zero) for i in range(n - 1): uij.append([0] + fT[i * (n - 1):(i + 1) * (n - 1):] + [0]) uij.append(zero) El2 = e_l2(uij, n, h, a_x, c_y) # 计算误差 print('n=', n, ' 误差: ', El2) plt.figure()