def get_current_linear_system(self): V = self.V model = self.model t = self.currentTime S = self.stiffMatrix M = self.massMatrix k = model.diffusion_coefficient() bc = DirichletBC(self.V, lambda p: model.dirichlet(p, t), model.is_dirichlet_boundary) F = SourceForm(V, lambda p: model.source(p, t), 3).get_vector() dt = self.dt if self.method is 'FM': b = dt*(F - k*[email protected][-1]) + [email protected][-1] A, b = bc.apply(M, b) return A, b if self.method is 'BM': b = dt*F + [email protected][-1] A = M + dt*k*S A, b = bc.apply(A, b) return A, b if self.method is 'CN': b = dt*F + (M - 0.5*dt*k*S)@self.solution[-1] A = M + 0.5*dt*k*S A, b = bc.apply(A, b) return A, b
def apply_boundary_condition(self, A, b, timeline, sdc=False): if sdc is False: t1 = timeline.next_time_level() bc = DirichletBC(self.space, lambda x:self.pde.solution(x, t1), self.is_boundary_dof) A, b = bc.apply(A, b) return A, b else: bc = DirichletBC(self.space, lambda x:0, self.is_boundary_dof) A, b = bc.apply(A, b) return A, b
def solve_poisson_3d(self, n=2): from fealpy.pde.poisson_3d import CosCosCosData as PDE from fealpy.mesh import MeshFactory from fealpy.functionspace import LagrangeFiniteElementSpace from fealpy.boundarycondition import DirichletBC pde = PDE() mf = MeshFactory() m = 2**n box = [0, 1, 0, 1, 0, 1] mesh = mf.boxmesh3d(box, nx=m, ny=m, nz=m, meshtype='tet') space = LagrangeFiniteElementSpace(mesh, p=1) gdof = space.number_of_global_dofs() NC = mesh.number_of_cells() print('gdof:', gdof, 'NC:', NC) bc = DirichletBC(space, pde.dirichlet) uh = space.function() A = space.stiff_matrix() A = space.parallel_stiff_matrix(q=1) M = space.parallel_mass_matrix(q=2) M = space.mass_matrix() F = space.source_vector(pde.source) A, F = bc.apply(A, F, uh) solver = PETScSolver() solver.solve(A, F, uh) error = space.integralalg.L2_error(pde.solution, uh) print(error)
def test_poisson_fem_2d(): degree = 1 dim = 2 nrefine = 4 maxit = 4 from fealpy.pde.poisson_2d import CosCosData as PDE pde = PDE() mesh = pde.init_mesh(n=nrefine) errorMatrix = np.zeros((2, maxit), dtype=np.float64) NDof = np.zeros(maxit, dtype=np.int64) for i in range(maxit): space = LagrangeFiniteElementSpace(mesh, p=degree) NDof[i] = space.number_of_global_dofs() bc = DirichletBC(space, pde.dirichlet) uh = space.function() A = space.stiff_matrix() F = space.source_vector(pde.source) A, F = bc.apply(A, F, uh) uh[:] = spsolve(A, F).reshape(-1) errorMatrix[0, i] = space.integralalg.L2_error(pde.solution, uh) errorMatrix[1, i] = space.integralalg.L2_error(pde.gradient, uh.grad_value) if i < maxit-1: mesh.uniform_refine()
def solve_poisson_3d(self, n=5): from fealpy.pde.poisson_3d import CosCosCosData as PDE from fealpy.functionspace import LagrangeFiniteElementSpace from fealpy.boundarycondition import DirichletBC pde = PDE() mesh = pde.init_mesh(n=n) space = LagrangeFiniteElementSpace(mesh, p=1) bc = DirichletBC(space, pde.dirichlet) uh = space.function() A = space.stiff_matrix() F = space.source_vector(pde.source) A, F = bc.apply(A, F, uh) solver = PETScSolver() solver.solve(A, F, uh) error = space.integralalg.L2_error(pde.solution, uh) print(error)
def test_poisson(): p = 1 # 有限元空间次数, 可以增大 p, 看输出结果的变化 n = 4 # 初始网格加密次数 maxit = 4 # 最大迭代次数 pde = PDE() mesh = pde.init_mesh(n=n) errorMatrix = np.zeros((2, maxit), dtype=np.float) NDof = np.zeros(maxit, dtype=np.float) for i in range(maxit): space = LagrangeFiniteElementSpace(mesh, p=p) # 建立有限元空间 NDof[i] = space.number_of_global_dofs() # 有限元空间自由度的个数 bc = DirichletBC(space, pde.dirichlet) # DirichletBC 条件 uh = space.function() # 有限元函数 A = space.stiff_matrix() # 刚度矩阵 F = space.source_vector(pde.source) # 载荷向量 A, F = bc.apply(A, F, uh) # 处理边界条件 uh[:] = spsolve(A, F).reshape(-1) # 稀疏矩阵直接解法器 # ml = pyamg.ruge_stuben_solver(A) # 代数多重网格解法器 # uh[:] = ml.solve(F, tol=1e-12, accel='cg').reshape(-1) errorMatrix[0, i] = space.integralalg.L2_error( pde.solution, uh ) # 计算 L2 误差 errorMatrix[1, i] = space.integralalg.L2_error( pde.gradient, uh.grad_value ) # 计算 H1 误差 if i < maxit - 1: mesh.uniform_refine() # 一致加密网格 assert (errorMatrix < 1.0).all()
def Arctan(self, p=1, n=3): pde = ArctanData() node = np.array([[-1, -1], [1, -1], [1, 1], [-1, 1]], dtype=np.float_) cell = np.array([[0, 1, 2], [0, 2, 3]], dtype=np.int_) mesh = TriangleMesh(node, cell) mesh.uniform_refine(n=n) space = LagrangeFiniteElementSpace(mesh, p=p) uh = space.function() A = space.stiff_matrix() b = space.source_vector(pde.source) bc = DirichletBC(space, pde.dirichlet) A, b = bc.apply(A, b, uh) uh[:] = spsolve(A, b).reshape(-1) error0 = space.integralalg.L2_error(pde.solution, uh) error1 = space.integralalg.L2_error(pde.gradient, uh.grad_value) print(error0) print(error1)
def NS_VC_Solver(self): """ The Navier-Stokes Velocity-Correction scheme solver. """ pde = self.pde dt = self.dt uh0 = self.uh0 uh1 = self.uh1 ph = self.ph vspace = self.vspace pspace = self.pspace vdof = self.vdof pdof = self.pdof pface2dof = pdof.face_to_dof() # (NE,fldof) pcell2dof = pdof.cell_to_dof() # (NC,cldof) ucell2dof = vspace.cell_to_dof() # (NC,cldof) idxDirEdge = self.set_Dirichlet_edge() cellidxDir = self.mesh.ds.edge2cell[idxDirEdge, 0] localidxDir = self.mesh.ds.edge2cell[idxDirEdge, 2] Dir_face2dof = pface2dof[idxDirEdge, :] # (NDir,flodf) Dir_cell2dof = pcell2dof[cellidxDir, :] # (NDir,cldof) n_Dir = self.mesh.face_unit_normal(index=idxDirEdge) # (NDir,2) dir_face_measure = self.mesh.entity_measure( 'face', index=idxDirEdge) # (NDir,2) cell_measure = self.mesh.cell_area() dir_cell_measure = self.mesh.cell_area(cellidxDir) f_q = self.integralalg.faceintegrator f_bcs, f_ws = f_q.get_quadrature_points_and_weights( ) # f_bcs.shape: (NQ,(GD-1)+1) f_pp = self.mesh.bc_to_point( f_bcs, index=idxDirEdge ) # f_pp.shape: (NQ,NDir,GD) the physical Gauss points c_q = self.integralalg.cellintegrator c_bcs, c_ws = c_q.get_quadrature_points_and_weights( ) # c_bcs.shape: (NQ,GD+1) c_pp = self.mesh.bc_to_point( c_bcs) # c_pp.shape: (NQ_cell,NC,GD) the physical Gauss points last_uh0 = vspace.function() last_uh1 = vspace.function() next_ph = pspace.function() # # t^{n+1}: Pressure-Left-StiffMatrix plsm = self.pspace.stiff_matrix() basis_int = pspace.integral_basis() p_phi = pspace.face_basis( f_bcs) # (NQ,1,fldof). 实际上这里可以直接用 pspace.basis(f_bcs), 两个函数的代码是相同的 p_gphi_f = pspace.edge_grad_basis(f_bcs, cellidxDir, localidxDir) # (NDir,NQ,cldof,GD) p_gphi_c = pspace.grad_basis(c_bcs) # (NQ_cell,NC,ldof,GD) # # t^{n+1}: Velocity-Left-MassMatrix and -StiffMatrix ulmm = self.vspace.mass_matrix() ulsm = self.vspace.stiff_matrix() u_phi = vspace.basis(c_bcs) # (NQ,1,cldof) next_t = 0 dofLocalIdxInflow, localIdxInflow = self.set_velocity_inflow_dof() idxOutFlowEdge = self.set_outflow_edge() for nt in range(int(self.T / dt)): curr_t = nt * dt next_t = curr_t + dt # --------------------------------------- # 1st-step: get the p^{n+1} # --------------------------------------- # # Pressure-Right-Matrix if curr_t == 0.: # for Dirichlet-face-integration last_gu_val0 = pde.grad_velocity0(f_pp, 0) # grad_u0: (NQ,NDir,GD) last_gu_val1 = pde.grad_velocity1(f_pp, 0) # grad_u1: (NQ,NDir,GD) # for cell-integration last_u_val = pde.velocityInitialValue(c_pp) # (NQ,NC,GD) last_u_val0 = last_u_val[..., 0] # (NQ,NC) last_u_val1 = last_u_val[..., 1] # (NQ,NC) last_nolinear_val0 = pde.NS_nolinearTerm_0(c_pp, 0) # (NQ,NC) last_nolinear_val1 = pde.NS_nolinearTerm_1(c_pp, 0) # (NQ,NC) else: # for Dirichlet-face-integration # last_gu_val0 = vspace.grad_value(last_uh0, f_bcs) # grad_u0: (NQ,NDir,GD) # last_gu_val1 = vspace.grad_value(last_uh1, f_bcs) # grad_u1: (NQ,NDir,GD) last_gu_val0 = self.uh_grad_value_at_faces( last_uh0, f_bcs, cellidxDir, localidxDir) # grad_u0: (NQ,NDir,GD) last_gu_val1 = self.uh_grad_value_at_faces( last_uh1, f_bcs, cellidxDir, localidxDir) # grad_u0: (NQ,NDir,GD) # for cell-integration last_u_val0 = vspace.value(last_uh0, c_bcs) # (NQ,NC) last_u_val1 = vspace.value(last_uh1, c_bcs) last_nolinear_val = self.NSNolinearTerm( last_uh0, last_uh1, c_bcs) # last_nolinear_val.shape: (NQ,NC,GD) last_nolinear_val0 = last_nolinear_val[..., 0] # (NQ,NC) last_nolinear_val1 = last_nolinear_val[..., 1] # (NQ,NC) uDir_val = pde.dirichlet( f_pp, next_t, bd_threshold=localIdxInflow) # (NQ,NDir,GD) f_val = pde.source(c_pp, next_t) # (NQ,NC,GD) # # --- to update the pressure value --- # # # # to get the Pressure's Right-hand Vector prv = np.zeros((pdof.number_of_global_dofs(), ), dtype=self.ftype) # (Npdof,) # for Dirichlet faces integration dir_int0 = -1 / dt * np.einsum('i, ijk, jk, ijn, j->jn', f_ws, uDir_val, n_Dir, p_phi, dir_face_measure) # (NDir,fldof) dir_int1 = -pde.nu * ( np.einsum('i, j, ij, jin, j->jn', f_ws, n_Dir[:, 1], last_gu_val1[..., 0] - last_gu_val0[..., 1], p_gphi_f[..., 0], dir_face_measure) + np.einsum('i, j, ij, jin, j->jn', f_ws, -n_Dir[:, 0], last_gu_val1[..., 0] - last_gu_val0[..., 1], p_gphi_f[..., 1], dir_face_measure)) # (NDir,cldof) # for cell integration cell_int0 = 1 / dt * ( np.einsum('i, ij, ijk, j->jk', c_ws, last_u_val0, p_gphi_c[..., 0], cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, last_u_val1, p_gphi_c[..., 1], cell_measure)) # (NC,cldof) cell_int1 = -( np.einsum('i, ij, ijk, j->jk', c_ws, last_nolinear_val0, p_gphi_c[..., 0], cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, last_nolinear_val1, p_gphi_c[..., 1], cell_measure)) # (NC,cldof) cell_int2 = (np.einsum('i, ij, ijk, j->jk', c_ws, f_val[..., 0], p_gphi_c[..., 0], cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, f_val[..., 1], p_gphi_c[..., 1], cell_measure) ) # (NC,cldof) np.add.at(prv, Dir_face2dof, dir_int0) np.add.at(prv, Dir_cell2dof, dir_int1) np.add.at(prv, pcell2dof, cell_int0 + cell_int1 + cell_int2) # # Method I: The following code is right! Pressure satisfies \int_\Omega p = 0 # plsm_temp = bmat([[plsm, basis_int.reshape(-1, 1)], [basis_int, None]], format='csr') # prv = np.r_[prv, 0] # next_ph[:] = spsolve(plsm_temp, prv)[:-1] # we have added one addtional dof # # Method II: Using the Dirichlet boundary of pressure def dir_pressure(p): return pde.pressure_dirichlet(p, next_t) bc = DirichletBC(pspace, dir_pressure, threshold=idxOutFlowEdge) plsm_temp, prv = bc.apply(plsm.copy(), prv) next_ph[:] = spsolve(plsm_temp, prv).reshape(-1) # # --- to update the velocity value --- # # next_gradph = pspace.grad_value(next_ph, c_bcs) # (NQ,NC,2) # the velocity u's Left-Matrix ulm0 = 1 / dt * ulmm + pde.nu * ulsm ulm1 = 1 / dt * ulmm + pde.nu * ulsm # # to get the u's Right-hand Vector def dir_u0(p): return pde.dirichlet(p, next_t, bd_threshold=dofLocalIdxInflow)[..., 0] def dir_u1(p): return pde.dirichlet(p, next_t, bd_threshold=dofLocalIdxInflow)[..., 1] # for the first-component of velocity urv0 = np.zeros((vdof.number_of_global_dofs(), ), dtype=self.ftype) # (Nvdof,) urv0_temp = np.einsum('i, ij, ijk, j->jk', c_ws, last_u_val0 / dt - next_gradph[..., 0] - last_nolinear_val0 + f_val[..., 0], u_phi, cell_measure) # (NC,clodf) np.add.at(urv0, ucell2dof, urv0_temp) u0_bc = DirichletBC(vspace, dir_u0, threshold=idxDirEdge) ulm0, urv0 = u0_bc.apply(ulm0, urv0) last_uh0[:] = spsolve(ulm0, urv0).reshape(-1) # for the second-component of velocity urv1 = np.zeros((vdof.number_of_global_dofs(), ), dtype=self.ftype) # (Nvdof,) urv1_temp = np.einsum('i, ij, ijk, j->jk', c_ws, last_u_val1 / dt - next_gradph[..., 1] - last_nolinear_val1 + f_val[..., 1], u_phi, cell_measure) # (NC,clodf) np.add.at(urv1, ucell2dof, urv1_temp) u1_bc = DirichletBC(vspace, dir_u1, threshold=idxDirEdge) ulm1, urv1 = u1_bc.apply(ulm1, urv1) last_uh1[:] = spsolve(ulm1, urv1).reshape(-1) if nt % 100 == 0: print('# ------------ logging the circle info ------------ #') print('current t = ', curr_t) p_l2err, u0_l2err, u1_l2err = self.currt_error( next_ph, last_uh0, last_uh1, next_t) print('p_l2err = %e, u0_l2err = %e, u1_l2err = %e' % (p_l2err, u0_l2err, u1_l2err)) print( '# ------------------------------------------------- # \n') if np.isnan(p_l2err) | np.isnan(u0_l2err) | np.isnan(u1_l2err): print('Some error is nan: breaking the program') break # print('end of current time') # print('# ------------ the end error ------------ #') # p_l2err, u0_l2err, u1_l2err = self.currt_error(next_ph, last_uh0, last_uh1, next_t) # print('p_l2err = %e, u0_l2err = %e, u1_l2err = %e' % (p_l2err, u0_l2err, u1_l2err)) return last_uh0, last_uh1, next_ph
# 初始网格 fig = plt.figure() axes = fig.gca() mesh.add_plot(axes) for i in range(maxit): space = LagrangeFiniteElementSpace(mesh, p=p) # 建立有限元空间 NDof[i] = space.number_of_global_dofs() # 有限元空间自由度的个数 bc = DirichletBC(space, pde.dirichlet) # DirichletBC 条件 uh = space.function() # 有限元函数 A = space.stiff_matrix() # 刚度矩阵 F = space.source_vector(pde.source) # 载荷向量 A, F = bc.apply(A, F, uh) # 处理边界条件 uh[:] = spsolve(A, F).reshape(-1) # 稀疏矩阵直接解法器 #ml = pyamg.ruge_stuben_solver(A) # 代数多重网格解法器 #uh[:] = ml.solve(F, tol=1e-12, accel='cg').reshape(-1) errorMatrix[0, i] = space.integralalg.L2_error(pde.solution, uh) # 计算 L2 误差 errorMatrix[1, i] = space.integralalg.L2_error(pde.gradient, uh.grad_value) # 计算 H1 误差 if i < maxit - 1: mesh.uniform_refine() # 一致加密网格 # 画函数图像
mesh = pde.init_mesh(n=n) area = mesh.entity_measure('cell') space = LagrangeFiniteElementSpace(mesh, p=p) bc0 = DirichletBC(space, pde.dirichlet, threshold=pde.is_dirichlet_boundary) bc1 = NeumannBC(space, pde.neumann, threshold=pde.is_neumann_boundary) uh = space.function(dim=2) # (gdof, 2) and vector fem function uh[i, j] P = space.stiff_matrix(c=2 * pde.mu) A = space.linear_elasticity_matrix(pde.mu, pde.lam) # (2*gdof, 2*gdof) F = space.source_vector(pde.source, dim=2) F = bc1.apply(F) A, F = bc0.apply(A, F, uh) print(A.shape) if False: uh.T.flat[:] = spsolve(A, F) # (2, gdof ).flat elif False: N = len(F) print(N) ilu = spilu(A.tocsc(), drop_tol=1e-6, fill_factor=40) M = LinearOperator((N, N), lambda x: ilu.solve(x)) start = timer() uh.T.flat[:], info = cg(A, F, tol=1e-8, M=M) # solve with CG print(info) end = timer() print('time:', end - start)
def apply_boundary_condition(self, A, b, timeline): t1 = timeline.next_time_level() bc = DirichletBC(self.space, lambda x:self.pde.dirichlet(x, t1)) A, b = bc.apply(A, b) return A, b
# t1 时间层的右端项 @cartesian def source(p): return pde.source(p, t1) F = space.source_vector(source) F *= dt F += M @ uh0 # t1 时间层的 Dirichlet 边界条件处理 @cartesian def dirichlet(p): return pde.dirichlet(p, t1) bc = DirichletBC(space, dirichlet) GD, F = bc.apply(G, F, uh1) # 代数系统求解 uh1[:] = spsolve(GD, F) eta = space.recovery_estimate(uh1, method='area_harmonic') err = np.sqrt(np.sum(eta**2)) print('errrefine', err) if err < tol: break else: # 加密并插值 NN0 = smesh.number_of_nodes() edge = smesh.entity('edge') isMarkedCell = smesh.refine_marker(eta, rtheta, method='L2') smesh.refine_triangle_rg(isMarkedCell) i += 1
print("The {}-th computation:".format(i)) node = mesh.entity('node') cell = mesh.entity('cell') lmesh = LagrangeTriangleMesh(node, cell, p=p, surface=surface) space = IsoLagrangeFiniteElementSpace(lmesh, p=p) NDof[i] = space.number_of_global_dofs() print(NDof[i]) uh = space.function() A = space.stiff_matrix() F = space.source_vector(pde.source) # 封闭曲面,设置其第 0 个插值节点的值为真解值 bc = DirichletBC(space, pde.solution) A, F = bc.apply(A, F, uh, threshold=np.array([0])) uh[:] = spsolve(A, F).reshape(-1) uI = space.interpolation(pde.solution) errorMatrix[0, i] = space.integralalg.error(pde.solution, uh.value, linear=False) errorMatrix[1, i] = space.integralalg.error(pde.gradient, uh.grad_value, linear=False) errorMatrix[2, i] = space.integralalg.error(pde.solution, uI.value, linear=False) errorMatrix[3, i] = space.integralalg.error(pde.gradient, uI.grad_value, linear=False)
def decoupled_NS_Solver_T1stOrder(self, vel0, vel1, ph, uh, uh_last, next_t): """ The decoupled-Navier-Stokes-solver for the all system. :param vel0: The fist-component of velocity: stored the n-th(time) value, and to update the (n+1)-th value. :param vel1: The second-component of velocity: stored the n-th(time) value, and to update the (n+1)-th value. :param ph: The pressure: stored the n-th(time) value, and to update the (n+1)-th value. :param uh: The n-th(time) value of the solution of Cahn-Hilliard equation. :param uh_last: The (n-1)-th(time) value of the solution of Cahn-Hilliard equation. :param next_t: The next-time. :return: Updated vel0, vel1, ph. 注意: 本程序所参考的数值格式是按照 $D(u)=\nabla u + \nabla u^T$ 来写的, 如果要调整为 $D(u)=(\nabla u + \nabla u^T)/2$, 需要调整的地方太多了, 所以为了保证和数值格式的一致性, 应 `尽量避免` 使用 'self.stressC=0.5', 以保持程序也是严格按照 $D(u)=\nabla u + \nabla u^T$ 的形式给出. """ pde = self.pde # # variable coefficients settings m = pde.m rho0 = pde.rho0 rho1 = pde.rho1 nu0 = pde.nu0 nu1 = pde.nu1 rho_min = min(rho0, rho1) eta_max = max(nu0 / rho0, nu1 / rho1) J0 = -1. / 2 * (rho0 - rho1) * m nDir_NS = self.nDir_NS # (NDir,GD), here, the GD is 2 # # the pre-settings grad_vel0_f = self.uh_grad_value_at_faces(vel0, self.f_bcs, self.DirCellIdx_NS, self.DirLocalIdx_NS, space=self.vspace) # grad_vel0: (NQ,NDir,GD) grad_vel1_f = self.uh_grad_value_at_faces(vel1, self.f_bcs, self.DirCellIdx_NS, self.DirLocalIdx_NS, space=self.vspace) # grad_vel1: (NQ,NDir,GD) # for cell-integration grad_ph_val = self.space.grad_value(ph, self.c_bcs) # (NQ,NC,GD) uh_val = self.space.value(uh, self.c_bcs) # (NQ,NC) uh_val_f = self.space.value(uh, self.f_bcs)[..., self.DirEdgeIdx_NS] # (NQ,NDir) # |___ TODO: 为什么是 [..., self.DirCellIdx_NS] 而不是 [..., self.DirEdgeIdx_NS]?? 应该是个 bug ?? # |___ TODO: 2022-03-08 改为 [..., self.DirEdgeIdx_NS] grad_uh_val = self.space.grad_value(uh, self.c_bcs) # (NQ,NC,GD) vel0_val = self.vspace.value(vel0, self.c_bcs) # (NQ,NC) vel1_val = self.vspace.value(vel1, self.c_bcs) # (NQ,NC) grad_vel0_val = self.vspace.grad_value(vel0, self.c_bcs) # (NQ,NC,GD) grad_vel1_val = self.vspace.grad_value(vel1, self.c_bcs) # (NQ,NC,GD) nolinear_val = self.NSNolinearTerm(vel0, vel1, self.c_bcs) # nolinear_val.shape: (NQ,NC,GD) # nolinear_val0 = nolinear_val[..., 0] # (NQ,NC) # nolinear_val1 = nolinear_val[..., 1] # (NQ,NC) velDir_val = self.pde.dirichlet_NS(self.f_pp_Dir_NS, next_t) # (NQ,NDir,GD) f_val_NS = self.pde.source_NS(self.c_pp, next_t, self.pde.epsilon, self.pde.eta, m, rho0, rho1, nu0, nu1, self.stressC) # (NQ,NC,GD) # Neumann_0 = self.pde.neumann_0_NS(self.f_pp_Neu_NS, next_t, self.nNeu_NS) # (NQ,NE) # Neumann_1 = self.pde.neumann_1_NS(self.f_pp_Neu_NS, next_t, self.nNeu_NS) # (NQ,NE) # --- the CH_term: uh_val * (-epsilon*\nabla\Delta uh_val + \nabla free_energy) grad_free_energy_c = self.pde.epsilon / self.pde.eta ** 2 * self.grad_free_energy_at_cells(uh_last, self.c_bcs) # (NQ,NC,2) if self.p < 3: grad_x_laplace_uh = np.zeros(grad_free_energy_c[..., 0].shape) grad_y_laplace_uh = np.zeros(grad_free_energy_c[..., 0].shape) CH_term_val0 = uh_val * grad_free_energy_c[..., 0] # (NQ,NC) CH_term_val1 = uh_val * grad_free_energy_c[..., 1] # (NQ,NC) elif self.p == 3: phi_xxx, phi_yyy, phi_yxx, phi_xyy = self.cb.get_highorder_diff(self.c_bcs, order='3rd-order') # (NQ,NC,ldof) grad_x_laplace_uh = -self.pde.epsilon * np.einsum('ijk, jk->ij', phi_xxx + phi_xyy, uh[self.cell2dof]) # (NQ,NC) grad_y_laplace_uh = -self.pde.epsilon * np.einsum('ijk, jk->ij', phi_yxx + phi_yyy, uh[self.cell2dof]) # (NQ,NC) CH_term_val0 = uh_val * (grad_x_laplace_uh + grad_free_energy_c[..., 0]) # (NQ,NC) CH_term_val1 = uh_val * (grad_y_laplace_uh + grad_free_energy_c[..., 1]) # (NQ,NC) else: raise ValueError("The polynomial order p should be <= 3.") # --- update the variable coefficients rho_n = (rho0 + rho1) / 2. + (rho0 - rho1) / 2. * uh_val # (NQ,NC) rho_n_f = (rho0 + rho1) / 2. + (rho0 - rho1) / 2. * uh_val_f # (NQ,NDir) nu_n = (nu0 + nu1) / 2. + (nu0 - nu1) / 2. * uh_val # (NQ,NC) nu_n_f = (nu0 + nu1) / 2. + (nu0 - nu1) / 2. * uh_val_f # (NQ,NDir) J_n0 = J0 * (grad_x_laplace_uh + grad_free_energy_c[..., 0]) # (NQ,NC) J_n1 = J0 * (grad_y_laplace_uh + grad_free_energy_c[..., 1]) # (NQ,NC) # --- the auxiliary variable: G_VC stressC = self.stressC vel_stress_mat = [[stressC*2*grad_vel0_val[..., 0], stressC*(grad_vel0_val[..., 1] + grad_vel1_val[..., 0])], [stressC*(grad_vel0_val[..., 1] + grad_vel1_val[..., 0]), stressC*2*grad_vel1_val[..., 1]]] vel_grad_mat = [[grad_vel0_val[..., 0], grad_vel0_val[..., 1]], [grad_vel1_val[..., 0], grad_vel1_val[..., 1]]] rho_n_axis = rho_n[..., np.newaxis] G_VC = (-nolinear_val + (1. / rho_min - 1. / rho_n_axis) * grad_ph_val + 1. / rho_n_axis * self.vec_div_mat((nu0 - nu1) / 2. * grad_uh_val, vel_stress_mat) - 1. / rho_n_axis * np.array([CH_term_val0, CH_term_val1]).transpose((1, 2, 0)) - 1. / rho_n_axis * self.vec_div_mat([J_n0, J_n1], vel_grad_mat) + 1. / rho_n_axis * f_val_NS + 1./self.dt * np.array([vel0_val, vel1_val]).transpose((1, 2, 0))) # (NQ,NC,2) eta_n = nu_n / rho_n # (NQ,NC) eta_n_f = nu_n_f / rho_n_f # (NQ,NDir) eta_nx = ((nu0 - nu1) / 2. * rho_n - (rho0 - rho1) / 2. * nu_n) * grad_uh_val[..., 0] / rho_n ** 2 # (NQ,NC) eta_ny = ((nu0 - nu1) / 2. * rho_n - (rho0 - rho1) / 2. * nu_n) * grad_uh_val[..., 1] / rho_n ** 2 # (NQ,NC) curl_vel = stressC * (grad_vel1_val[..., 0] - grad_vel0_val[..., 1]) # (NQ,NC) curl_vel_f = stressC * (grad_vel1_f[..., 0] - grad_vel0_f[..., 1]) # (NQ,NDir) # for Dirichlet faces integration dir_int0 = -1 / self.dt * np.einsum('i, ijk, jk, ijn, j->jn', self.f_ws, velDir_val, nDir_NS, self.phi_f, self.DirEdgeMeasure_NS) # (NDir,fldof) dir_int1 = -(np.einsum('i, j, ij, jin, j->jn', self.f_ws, nDir_NS[:, 1], eta_n_f*curl_vel_f, self.gphi_f[..., 0], self.DirEdgeMeasure_NS) + np.einsum('i, j, ij, jin, j->jn', self.f_ws, -nDir_NS[:, 0], eta_n_f*curl_vel_f, self.gphi_f[..., 1], self.DirEdgeMeasure_NS)) # (NDir,cldof) # for cell integration cell_int0 = np.einsum('i, ijs, ijks, j->jk', self.c_ws, G_VC, self.gphi_c, self.cellmeasure) # (NC,cldof) cell_int1 = (np.einsum('i, ij, ijk, j->jk', self.c_ws, eta_ny * curl_vel, self.gphi_c[..., 0], self.cellmeasure) + np.einsum('i, ij, ijk, j->jk', self.c_ws, -eta_nx * curl_vel, self.gphi_c[..., 1], self.cellmeasure)) # (NC,cldof) # # --- 1. assemble the NS's pressure equation prv = np.zeros((self.dof.number_of_global_dofs(),), dtype=self.ftype) # (Npdof,) the Pressure's Right-hand Vector np.add.at(prv, self.face2dof[self.DirEdgeIdx_NS, :], dir_int0) np.add.at(prv, self.cell2dof[self.DirCellIdx_NS, :], dir_int1) np.add.at(prv, self.cell2dof, cell_int0 + cell_int1) # # --- 2. solve the NS's pressure equation plsm = 1. / rho_min * self.StiffMatrix # # Method I: The following code is right! Pressure satisfies \int_\Omega p = 0 basis_int = self.space.integral_basis() plsm_temp = bmat([[plsm, basis_int.reshape(-1, 1)], [basis_int, None]], format='csr') prv = np.r_[prv, 0] ph[:] = spsolve(plsm_temp, prv)[:-1] # we have added one additional dof # ph[:] = spsolve(plsm, prv) # # Method II: Using the Dirichlet boundary of pressure # def dir_pressure(p): # return self.pde.pressure_NS(p, next_t) # bc = DirichletBC(self.space, dir_pressure) # plsm_temp, prv = bc.apply(plsm.copy(), prv) # ph[:] = spsolve(plsm_temp, prv).reshape(-1) # # ------------------------------------ # # # # --- to update the velocity value --- # # # # ------------------------------------ # # grad_ph = self.space.grad_value(ph, self.c_bcs) # (NQ,NC,2) # # the Velocity-Left-Matrix vlm0 = 1 / self.dt * self.vel_MM + stressC * eta_max * self.vel_SM vlm1 = vlm0.copy() # # to get the u's Right-hand Vector def dir_u0(p): return self.pde.dirichlet_NS(p, next_t)[..., 0] def dir_u1(p): return self.pde.dirichlet_NS(p, next_t)[..., 1] # # --- assemble the first-component of Velocity-Right-Vector vrv0 = np.zeros((self.vdof.number_of_global_dofs(),), dtype=self.ftype) # (Nvdof,) vrv0_c_0 = np.einsum('i, ij, ijk, j->jk', self.c_ws, - 1. / rho_min * grad_ph[..., 0] + G_VC[..., 0], self.vphi_c, self.cellmeasure) # (NC,clodf) vrv0_c_1 = (np.einsum('i, ij, ijk, j->jk', self.c_ws, (eta_n - eta_max) * curl_vel, self.vgphi_c[..., 1], self.cellmeasure) + np.einsum('i, ij, ijk, j->jk', self.c_ws, eta_ny * curl_vel, self.vphi_c, self.cellmeasure)) # (NC,clodf) np.add.at(vrv0, self.vcell2dof, vrv0_c_0 + vrv0_c_1) v0_bc = DirichletBC(self.vspace, dir_u0, threshold=self.DirEdgeIdx_NS) vlm0, vrv0 = v0_bc.apply(vlm0, vrv0) vel0[:] = spsolve(vlm0, vrv0).reshape(-1) # # --- assemble the second-component of Velocity-Right-Vector vrv1 = np.zeros((self.vdof.number_of_global_dofs(),), dtype=self.ftype) # (Nvdof,) vrv1_c_0 = np.einsum('i, ij, ijk, j->jk', self.c_ws, - 1. / rho_min * grad_ph[..., 1] + G_VC[..., 1], self.vphi_c, self.cellmeasure) # (NC,clodf) vrv1_c_1 = (np.einsum('i, ij, ijk, j->jk', self.c_ws, (eta_n - eta_max) * curl_vel, -self.vgphi_c[..., 0], self.cellmeasure) + np.einsum('i, ij, ijk, j->jk', self.c_ws, - eta_nx * curl_vel, self.vphi_c, self.cellmeasure)) # (NC,clodf) np.add.at(vrv1, self.vcell2dof, vrv1_c_0 + vrv1_c_1) v1_bc = DirichletBC(self.vspace, dir_u1, threshold=self.DirEdgeIdx_NS) vlm1, vrv0 = v1_bc.apply(vlm1, vrv1) vel1[:] = spsolve(vlm1, vrv1).reshape(-1)
mesh.add_plot(plt) plt.savefig('./test-0.png') plt.close() for i in range(maxit): print('step:', i) space = LagrangeFiniteElementSpace(mesh, p=p) A = space.stiff_matrix(q=1) F = space.source_vector(pde.source) NDof[i] = space.number_of_global_dofs() bc = DirichletBC(space, pde.dirichlet) uh = space.function() A, F = bc.apply(A, F, uh) uh[:] = spsolve(A, F) errorMatrix[0, i] = space.integralalg.error(pde.solution, uh.value, power=2) errorMatrix[1, i] = space.integralalg.error(pde.gradient, uh.grad_value, power=2) errorMatrix[2, i] = space.integralalg.error(pde.gradient, rguh.value, power=2) eta = space.recovery_estimate(uh) errorMatrix[3, i] = np.sqrt(np.sum(eta**2)) if i < maxit - 1:
maxit = int(sys.argv[2]) start = timer() solver = MatlabSolver() end = timer() print("The matalb start time:", end - start) pde = CosCosData() mesh = pde.init_mesh(4) for i in range(maxit): space = LagrangeFiniteElementSpace(mesh, p=1) gdof = space.number_of_global_dofs() print("The num of dofs:", gdof) A = space.stiff_matrix() b = space.source_vector(pde.source) bc = DirichletBC(space, pde.dirichlet) AD, b = bc.apply(A, b) uh0 = solver.divide(AD, b) start = timer() uh1 = spsolve(AD, b) end = timer() print("The spsolver time:", end - start) print(np.sum(np.abs(uh0 - uh1))) #uh1 = solver.mumps_solver(A, b) #uh2 = solver.ifem_amg_solver(A, b) if i < maxit - 1: mesh.uniform_refine()
T1 = 1 N = 400 dt = (T1 - T0) / N print(dt) uh = FiniteElementFunction(V) uh[:] = model.init_value(V.interpolation_points()) uht = [uh] MD = BC.apply_on_matrix(M) for i in range(1, N + 1): t = T0 + i * dt AD = M + dt / 16 * A F = M @ uht[i - 1] + dt * b AD, F = BC.apply(AD, F) uh = FiniteElementFunction(V) uh[:] = spsolve(AD, F) # F = dt*(b - 1/16*A@uht[i-1]) + M@uht[i-1] # F = BC.apply_on_source_vector(F, M) # uh[:] = spsolve(MD, F) uht.append(uh) e = L2_error(lambda p: model.solution(p, t), uh) print(e) fig = plt.figure() axes = fig.gca() mesh.add_plot(axes) plt.show()