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=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 poisson_fem_2d_neuman_test(self, p=1): pde = CosCosData() mesh = pde.init_mesh(n=2) for i in range(4): space = LagrangeFiniteElementSpace(mesh, p=p) A = space.stiff_matrix() b = space.source_vector(pde.source) uh = space.function() bc = BoundaryCondition(space, neuman=pde.neuman) bc.apply_neuman_bc(b) c = space.integral_basis() AD = bmat([[A, c.reshape(-1, 1)], [c, None]], format='csr') bb = np.r_[b, 0] x = spsolve(AD, bb) uh[:] = x[:-1] area = np.sum(space.integralalg.cellmeasure) ubar = space.integralalg.integral(pde.solution, barycenter=False) / area def solution(p): return pde.solution(p) - ubar error = space.integralalg.L2_error(solution, uh) print(error) mesh.uniform_refine()
def solve_poisson_robin(self, p=1, n=1, plot=True): pde = XYData() mesh = pde.init_mesh(n=n) node = mesh.node cell = mesh.entity("cell") name = 'RobinBCTest.mat' space = LagrangeFiniteElementSpace(mesh, p=p) A = space.stiff_matrix() F = space.source_vector(pde.source) # print(A.toarray()) # A, F = space.set_robin_bc(A, F, pde.robin) uh = space.function() #bc = BoundaryCondition(space, robin=pde.robin) A, b = space.set_robin_bc(A, F, pde.robin) uh[:] = spsolve(A, b).reshape(-1) error = space.integralalg.L2_error(pde.solution, uh) print(error) # print('A:', A.toarray()) # print('F:', F) if plot: fig = plt.figure() axes = fig.gca() mesh.add_plot(axes) mesh.find_node(axes, showindex=True) mesh.find_cell(axes, showindex=True) plt.show()
class ParabolicFEMModel(): def __init__(self, pde, mesh, p=1, q=6): from fealpy.functionspace import LagrangeFiniteElementSpace from fealpy.boundarycondition import BoundaryCondition self.space = LagrangeFiniteElementSpace(mesh, p) self.mesh = self.space.mesh self.pde = pde self.ftype = self.mesh.ftype self.itype = self.mesh.itype self.M = self.space.mass_matrix() self.A = self.space.stiff_matrix() def init_solution(self, timeline): NL = timeline.number_of_time_levels() gdof = self.space.number_of_global_dofs() uh = np.zeros((gdof, NL), dtype=self.mesh.ftype) uh[:, 0] = self.space.interpolation(lambda x: self.pde.solution(x, 0.0)) return uh def interpolation(self, u, timeline): NL = timeline.number_of_time_levels() gdof = self.space.number_of_global_dofs() ps = self.space.interpolation_points() uI = np.zeros((gdof, NL), dtype=self.mesh.ftype) times = timeline.all_time_levels() for i, t in enumerate(times): uI[..., i] = u(ps, t) return uI def get_current_left_matrix(self, timeline): dt = timeline.current_time_step_length() return self.M + 0.5 * dt * self.A def get_current_right_vector(self, uh, timeline): i = timeline.current dt = timeline.current_time_step_length() t0 = timeline.current_time_level() t1 = timeline.next_time_level() f = lambda x: self.pde.source(x, t0) + self.pde.source(x, t1) F = self.space.source_vector(f) return self.M @ uh[:, i] - 0.5 * dt * self.A @ uh[:, i] def apply_boundary_condition(self, A, b, timeline): t1 = timeline.next_time_level() bc = BoundaryCondition(self.space, neuamn=lambda x: self.pde.neuman(x, t1)) b = bc.apply_neuman_bc(b) return A, b def solve(self, uh, A, b, solver, timeline): i = timeline.current uh[:, i + 1] = solver(A, b)
def poisson_fem_2d_test(self, p=1): pde = CosCosData() mesh = pde.init_mesh(n=3) for i in range(4): space = LagrangeFiniteElementSpace(mesh, p=p) A = space.stiff_matrix() b = space.source_vector(pde.source) uh = space.function() bc = BoundaryCondition(space, dirichlet=pde.dirichlet) A, b = bc.apply_dirichlet_bc(A, b, uh) uh[:] = spsolve(A, b).reshape(-1) error = space.integralalg.L2_error(pde.solution, uh) print(error) mesh.uniform_refine()
def solve_poisson_robin(self, p=1, n=1, plot=True): pde = CosCosCosData() mesh = pde.init_mesh(n=n) space = LagrangeFiniteElementSpace(mesh, p=p) A = space.stiff_matrix() F = space.source_vector(pde.source) uh = space.function() bc = BoundaryCondition(space, robin=pde.robin) A, b = space.set_robin_bc(A, F, pde.robin) uh[:] = spsolve(A, b).reshape(-1) error = space.integralalg.L2_error(pde.solution, uh) print(error)
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 solve_poisson_robin(self, p=1, n=1, plot=True): pde = XYData() mesh = pde.init_mesh(n=1) space = LagrangeFiniteElementSpace(mesh, p=p) A = space.stiff_matrix() F = space.source_vector(pde.source) space.set_robin_bc(A, F, pde.robin) print('A:', A.toarray()) print('F:', F) if plot: fig = plt.figure() axes = fig.gca() mesh.add_plot(axes) mesh.find_node(axes, showindex=True) mesh.find_cell(axes, showindex=True) plt.show()
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)
from fealpy.mesh import MeshFactory from fealpy.functionspace import LagrangeFiniteElementSpace pde = SinCosData() mesh = MeshFactory.boxmesh2d(pde.box, nx=10, ny=10, meshtype='tri') uspace = LagrangeFiniteElementSpace(mesh, p=2) pspace = LagrangeFiniteElementSpace(mesh, p=1) pI = pspace.interpolation(pde.pressure) uI = uspace.interpolation(pde.velocity) # [[phi, 0], [0, phi]] # [[phi_x, phi_y], [0, 0]] [[0, 0], [phi_x, phi_y]] A = uspace.stiff_matrix() B = uspace.div_matrix(pspace) fig = plt.figure() axes = fig.gca() bc = np.array([1 / 3] * 3) point = mesh.bc_to_point(bc) p = pI.value(bc) u = uI.value(bc) mesh.add_plot(axes, cellcolor=p) axes.quiver(point[:, 0], point[:, 1], u[:, 0], u[:, 1]) #TODO: add color bar fig = plt.figure() axes = fig.gca(projection='3d') pI.add_plot(axes, cmap='rainbow')
domain = pde.domain() maxit = 4 errorType = [ '$|| u - u_h||_{\Omega,0}$', # L2 误差 '$||\\nabla u - \\nabla u_h||_{\Omega, 0}$' ] # H1 误差 errorMatrix = np.zeros((2, maxit), dtype=np.float) NDof = np.zeros(maxit, dtype=np.float) for i in range(maxit): print('Step:', i) space = LagrangeFiniteElementSpace(mesh, p=p) NDof[i] = space.number_of_global_dofs() uh = space.function() a = np.array([(10.0, -1.0), (-1.0, 2.0)], dtype=np.float64) A = space.stiff_matrix(c=a) @cartesian def r(p): x = p[..., 0] y = p[..., 1] return 1 + x**2 + y**2 M = space.mass_matrix(c=r) b = np.array([1.0, 1.0], dtype=np.float64) B = space.convection_matrix(c=b) @cartesian def f(p): x = p[..., 0] y = p[..., 1]
pde = CDRMODEL() domain = pde.domain() mf = MeshFactory() mesh = mf.boxmesh2d(domain, nx=n, ny=n, meshtype='tri') NDof = np.zeros(maxit, dtype=mesh.itype) errorMatrix = np.zeros((2, maxit), dtype=mesh.ftype) errorType = ['$|| u - u_h ||_0$', '$|| \\nabla u - \\nabla u_h||_0$'] for i in range(maxit): print('Step:', i) space = LagrangeFiniteElementSpace(mesh, p=p) NDof[i] = space.number_of_global_dofs() uh = space.function() A = space.stiff_matrix(c=pde.diffusion_coefficient) B = space.convection_matrix(c=pde.convection_coefficient_ndf) M = space.mass_matrix(c=pde.reaction_coefficient) F = space.source_vector(pde.source) A += B A += M bc = DirichletBC(space, pde.dirichlet) 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,
'$|| u - u_h||_{0}$', '$||\\nabla u - \\nabla u_h||_{0}$', '$||\\nabla u - G(\\nabla u_h)||_{0}$', '$||\\nabla u_h - G(\\nabla u_h)||_{0}$' ] NDof = np.zeros((maxit, ), dtype=np.int_) errorMatrix = np.zeros((len(errorType), maxit), dtype=np.float64) 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)
class FEMNavierStokesModel2d_channel: def __init__(self, pde, mesh, p, dt, T): self.p = p self.mesh = mesh self.dt = dt self.T = T self.itype = self.mesh.itype self.ftype = self.mesh.ftype self.pde = pde self.vspace = LagrangeFiniteElementSpace(mesh, p + 1) self.pspace = LagrangeFiniteElementSpace(mesh, p) self.vdof = self.vspace.dof self.pdof = self.pspace.dof self.cellmeasure = mesh.entity_measure('cell') self.integralalg = FEMeshIntegralAlg(self.mesh, p + 4, cellmeasure=self.cellmeasure) self.uh0 = self.vspace.function() self.uh1 = self.vspace.function() self.ph = self.pspace.function() @timer 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 def currt_error(self, ph, uh0, uh1, t): pde = self.pde def currt_pressure(p): return pde.pressure(p, t) p_l2err = self.pspace.integralalg.L2_error(currt_pressure, ph) # print('p_l2err = %e' % p_l2err) def currt_u0(p): return pde.velocity(p, t)[..., 0] u0_l2err = self.vspace.integralalg.L2_error(currt_u0, uh0) # print('u0_l2err = %e' % u0_l2err) def currt_u1(p): return pde.velocity(p, t)[..., 1] u1_l2err = self.vspace.integralalg.L2_error(currt_u1, uh1) # print('u1_l2err = %e' % u1_l2err) return p_l2err, u0_l2err, u1_l2err def uh_grad_value_at_faces(self, vh, f_bcs, cellidx, localidx): cell2dof = self.vdof.cell2dof f_gphi = self.vspace.edge_grad_basis(f_bcs, cellidx, localidx) # (NE,NQ,cldof,GD) # val.shape: (NQ,NE,GD) # vh.shape: (v_gdof,) # vh[cell2dof[cellidx]].shape: (Ncellidx,cldof) val = np.einsum('ik, ijkm->jim', vh[cell2dof[cellidx]], f_gphi) return val def NSNolinearTerm(self, uh0, uh1, bcs): vspace = self.vspace val0 = vspace.value(uh0, bcs) # val0.shape: (NQ,NC) val1 = vspace.value(uh1, bcs) # val1.shape: (NQ,NC) gval0 = vspace.grad_value(uh0, bcs) # gval0.shape: (NQ,NC,2) gval1 = vspace.grad_value(uh1, bcs) NSNolinear = np.empty(gval0.shape, dtype=self.ftype) # NSNolinear.shape: (NQ,NC,2) NSNolinear[..., 0] = val0 * gval0[..., 0] + val1 * gval0[..., 1] NSNolinear[..., 1] = val0 * gval1[..., 0] + val1 * gval1[..., 1] return NSNolinear def set_Dirichlet_edge(self, idxDirEdge=None): if idxDirEdge is not None: return idxDirEdge mesh = self.mesh node = mesh.node # (NV,2) edge2cell = mesh.ds.edge_to_cell() isBdEdge = (edge2cell[:, 0] == edge2cell[:, 1] ) # (NE,), the bool vars, to get the boundary edges idxBdEdge, = np.nonzero(isBdEdge) edge2node = mesh.ds.edge_to_node() # (NE,2) mid_coor = (node[edge2node[:, 0], :] + node[edge2node[:, 1], :]) / 2 # (NE,2) bd_mid = mid_coor[isBdEdge, :] isOutflow = np.abs(bd_mid[:, 0] - 1.0) < 1e-6 isDirEdge = ~isOutflow # here, we set all the boundary but the right edges are Dir edges idxDirEdge = idxBdEdge[isDirEdge] # (NE_Dir,) return idxDirEdge def set_outflow_edge(self, idxOutEdge=None): if idxOutEdge is not None: return idxOutEdge mesh = self.mesh node = mesh.node # (NV,2) edge2cell = mesh.ds.edge_to_cell() isBdEdge = (edge2cell[:, 0] == edge2cell[:, 1] ) # (NE,), the bool vars, to get the boundary edges idxBdEdge, = np.nonzero(isBdEdge) edge2node = mesh.ds.edge_to_node() # (NE,2) mid_coor = (node[edge2node[:, 0], :] + node[edge2node[:, 1], :]) / 2 # (NE,2) bd_mid = mid_coor[isBdEdge, :] isOutflow = np.abs(bd_mid[:, 0] - 1.0) < 1e-6 idxOutEdge = idxBdEdge[isOutflow] # (NE_Dir,) return idxOutEdge def set_velocity_inflow_dof(self): mesh = self.mesh node = mesh.node # (NV,2) edge2node = mesh.ds.edge_to_node() # (NE,2) idxDirEdge = self.set_Dirichlet_edge() dirIndicator = np.full(idxDirEdge.shape, False) mid_coor = (node[edge2node[:, 0], :] + node[edge2node[:, 1], :]) / 2 # (NE,2) bd_mid = mid_coor[idxDirEdge, :] # --- set inflow edges --- # inflow_x = 0.0 isInflow = np.abs(bd_mid[:, 0] - inflow_x) < 1e-6 localIdxInflow = np.nonzero(isInflow) idxInflow = idxDirEdge[isInflow] # --- set inflow dof --- # edge2dof = self.vdof.edge_to_dof() dir_dof = np.unique(edge2dof[idxDirEdge].flatten()) inflow_dof = np.unique(edge2dof[idxInflow].flatten()) dofLocalIdxInflow = np.searchsorted(dir_dof, inflow_dof) return dofLocalIdxInflow, localIdxInflow def set_Neumann_edge(self, idxNeuEdge=None): if idxNeuEdge is not None: return idxNeuEdge mesh = self.mesh edge2cell = mesh.ds.edge_to_cell() bdEdge = (edge2cell[:, 0] == edge2cell[:, 1] ) # the bool vars, to get the boundary edges isNeuEdge = bdEdge # here, we first set all the boundary edges are Neu edges issetNeuEdge = 'no' if issetNeuEdge == 'no': isNeuEdge = None idxNeuEdge, = np.nonzero(isNeuEdge) # (NE_Dir,) return idxNeuEdge
# plt.savefig('./test-' + str(i + 1) + '.png') # plt.close() space = LagrangeFiniteElementSpace(smesh, p=1) uh0 = space.interpolation(pde.init_value) for j in range(0, nt): # 下一个的时间层 t1 t1 = tmesh.next_time_level() print("t1=", t1) while True: # 下一层时间步的有限元解 uh1 = space.function() A = c * space.stiff_matrix() # 刚度矩阵 M = space.mass_matrix() # 质量矩阵 dt = tmesh.current_time_step_length() # 时间步长 G = M + dt * A # 隐式迭代矩阵 # t1 时间层的右端项 @cartesian def source(p): return pde.source(p, t1) F = space.source_vector(source) F *= dt F += M @ uh0 # t1 时间层的 Dirichlet 边界条件处理 @cartesian
class FEMCahnHilliardModel2d: def __init__(self, pde, mesh, p, dt): self.pde = pde self.p = p self.mesh = mesh self.timemesh, self.dt = self.pde.time_mesh(dt) self.itype = self.mesh.itype self.ftype = self.mesh.ftype self.pde = pde self.space = LagrangeFiniteElementSpace(mesh, p) self.dof = self.space.dof self.cellmeasure = mesh.entity_measure('cell') self.integralalg = FEMeshIntegralAlg(self.mesh, p + 4, cellmeasure=self.cellmeasure) self.uh = self.space.function() self.wh = self.space.function() self.StiffMatrix = self.space.stiff_matrix() self.MassMatrix = self.space.mass_matrix() def setCoefficient_T1stOrder(self, dt_minimum=None): pde = self.pde dt_min = self.dt if dt_minimum is None else dt_minimum m = pde.m epsilon = pde.epsilon s = np.sqrt(4 * epsilon / (m * dt_min)) alpha = 1. / (2 * epsilon) * (-s + np.sqrt(abs(s ** 2 - 4 * epsilon / (m * self.dt)))) return s, alpha def setCoefficient_T2ndOrder(self, dt_minimum=None): pde = self.pde dt_min = self.dt if dt_minimum is None else dt_minimum m = pde.m epsilon = pde.epsilon s = np.sqrt(4 * (3/2) * epsilon / (m * dt_min)) alpha = 1. / (2 * epsilon) * (-s + np.sqrt(abs(s ** 2 - 4 * (3/2) * epsilon / (m * self.dt)))) return s, alpha def uh_grad_value_at_faces(self, vh, f_bcs, cellidx, localidx): cell2dof = self.dof.cell2dof f_gphi = self.space.edge_grad_basis(f_bcs, cellidx, localidx) # (NE,NQ,cldof,GD) val = np.einsum('ik, ijkm->jim', vh[cell2dof[cellidx]], f_gphi) # (NQ,NE,GD) return val def grad_free_energy_at_faces(self, uh, f_bcs, idxBdEdge, cellidx, localidx): """ 1. Compute the grad of free energy at FACE Gauss-integration points (barycentric coordinates). 2. In this function, the free energy has NO coefficients. ------- :param uh: :param f_bcs: f_bcs.shape: (NQ,(GD-1)+1) :return: """ uh_val = self.space.value(uh, f_bcs)[..., idxBdEdge] # (NQ,NBE) guh_val = self.uh_grad_value_at_faces(uh, f_bcs, cellidx, localidx) # (NQ,NBE,GD) guh_val[..., 0] = 3 * uh_val ** 2 * guh_val[..., 0] - guh_val[..., 0] guh_val[..., 1] = 3 * uh_val ** 2 * guh_val[..., 1] - guh_val[..., 1] return guh_val # (NQ,NBE,2) def grad_free_energy_at_cells(self, uh, c_bcs): """ 1. Compute the grad of free energy at CELL Gauss-integration points (barycentric coordinates). 2. In this function, the free energy has NO coefficients. ------- :param uh: :param c_bcs: c_bcs.shape: (NQ,GD+1) :return: """ uh_val = self.space.value(uh, c_bcs) # (NQ,NC) guh_val = self.space.grad_value(uh, c_bcs) # (NQ,NC,2) guh_val[..., 0] = 3 * uh_val ** 2 * guh_val[..., 0] - guh_val[..., 0] guh_val[..., 1] = 3 * uh_val ** 2 * guh_val[..., 1] - guh_val[..., 1] return guh_val # (NQ,NC,2) @timer def CH_Solver_T1stOrder(self): pde = self.pde timemesh = self.timemesh NT = len(timemesh) dt = self.dt uh = self.uh wh = self.wh sm = self.StiffMatrix mm = self.MassMatrix space = self.space dof = self.dof face2dof = dof.face_to_dof() # (NE,fldof) cell2dof = dof.cell_to_dof() # (NC,cldof) dt_min = pde.dt_min if hasattr(pde, 'dt_min') else dt s, alpha = self.setCoefficient_T1stOrder(dt_minimum=dt_min) m = pde.m epsilon = pde.epsilon eta = pde.eta print(' # #################################### #') print(' Time 1st-order scheme') print(' # #################################### #') print(' # ------------ parameters ------------ #') print(' s = %.4e, alpha = %.4e, m = %.4e, epsilon = %.4e, eta = %.4e' % (s, alpha, m, epsilon, eta)) print(' t0 = %.4e, T = %.4e, dt = %.4e' % (timemesh[0], timemesh[-1], dt)) print(' ') idxNeuEdge = self.set_Neumann_edge() nBd = self.mesh.face_unit_normal(index=idxNeuEdge) # (NBE,2) NeuCellIdx = self.mesh.ds.edge2cell[idxNeuEdge, 0] NeuLocalIdx = self.mesh.ds.edge2cell[idxNeuEdge, 2] neu_face_measure = self.mesh.entity_measure('face', index=idxNeuEdge) # (Nneu,2) cell_measure = self.mesh.cell_area() 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=idxNeuEdge) # f_pp.shape: (NQ,NBE,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 phi_f = space.face_basis(f_bcs) # (NQ,1,fldof). 实际上这里可以直接用 pspace.basis(f_bcs), 两个函数的代码是相同的 phi_c = space.basis(c_bcs) # (NQ,NC,clodf) gphi_c = space.grad_basis(c_bcs) # (NQ,NC,cldof,GD) # # time-looping print(' # ------------ begin the time-looping ------------ #') for nt in range(NT-1): currt_t = timemesh[nt] next_t = currt_t + dt if nt % max([int(NT / 10), 1]) == 0: print(' currt_t = %.4e' % currt_t) if nt == 0: # the initial value setting u_c = pde.solution(c_pp, pde.t0) # (NQC,NC) gu_c = pde.gradient(c_pp, pde.t0) # (NQC,NC,2) u_f = pde.solution(f_pp, pde.t0) # (NQF,NBE) gu_f = pde.gradient(f_pp, pde.t0) # (NQF,NBE,2) grad_free_energy_c = epsilon / eta ** 2 * (3 * np.repeat(u_c[..., np.newaxis], 2, axis=2) ** 2 * gu_c - gu_c) grad_free_energy_f = epsilon / eta ** 2 * (3 * np.repeat(u_f[..., np.newaxis], 2, axis=2) ** 2 * gu_f - gu_f) uh_val = u_c # (NQ,NC) guh_val_c = gu_c # (NQ,NC,2) guh_val_f = gu_f # (NQ,NE,2) # gu_c_test = gu_c.copy() # gu_c_test[..., 0] = epsilon / eta ** 2 * (3 * u_c ** 2 * gu_c_test[..., 0] - gu_c_test[..., 0]) # gu_c_test[..., 1] = epsilon / eta ** 2 * (3 * u_c ** 2 * gu_c_test[..., 1] - gu_c_test[..., 1]) # gu_f_test = gu_f.copy() # gu_f_test[..., 0] = epsilon / eta ** 2 * (3 * u_f ** 2 * gu_f_test[..., 0] - gu_f_test[..., 0]) # gu_f_test[..., 1] = epsilon / eta ** 2 * (3 * u_f ** 2 * gu_f_test[..., 1] - gu_f_test[..., 1]) # print(np.allclose(gu_c_test, grad_free_energy_c)) # print(np.allclose(gu_f_test, grad_free_energy_f)) else: grad_free_energy_c = epsilon / eta ** 2 * self.grad_free_energy_at_cells(uh, c_bcs) # (NQ,NC,2) grad_free_energy_f = epsilon / eta ** 2 * self.grad_free_energy_at_faces(uh, f_bcs, idxNeuEdge, NeuCellIdx, NeuLocalIdx) # (NQ,NE,2) uh_val = space.value(uh, c_bcs) # (NQ,NC) guh_val_c = space.grad_value(uh, c_bcs) # (NQ,NC,2) guh_val_f = self.uh_grad_value_at_faces(uh, f_bcs, NeuCellIdx, NeuLocalIdx) # (NQ,NE,2) # # # ---------------------------------------- yc test --------------------------------------------------- # # # if nt == 0: # def init_solution(p): # return pde.solution(p, 0) # uh[:] = space.interpolation(init_solution) # grad_free_energy_c = epsilon / eta ** 2 * self.grad_free_energy_at_cells(uh, c_bcs) # (NQ,NC,2) # grad_free_energy_f = epsilon / eta ** 2 * self.grad_free_energy_at_faces(uh, f_bcs, idxNeuEdge, NeuCellIdx, # NeuLocalIdx) # (NQ,NE,2) # uh_val = space.value(uh, c_bcs) # (NQ,NC) # guh_val_c = space.grad_value(uh, c_bcs) # (NQ,NC,2) # guh_val_f = self.uh_grad_value_at_faces(uh, f_bcs, NeuCellIdx, NeuLocalIdx) # (NQ,NE,2) # # # --------------------------------------- end test ---------------------------------------------------- # # Neumann = pde.neumann(f_pp, next_t, nBd) # (NQ,NE) LaplaceNeumann = pde.laplace_neumann(f_pp, next_t, nBd) # (NQ,NE) f_val = pde.source(c_pp, next_t, m, epsilon, eta) # (NQ,NC) # # get the auxiliary equation Right-hand-side-Vector aux_rv = np.zeros((dof.number_of_global_dofs(),), dtype=self.ftype) # (Ndof,) # # aux_rhs_c_0: -1. / (epsilon * m * dt) * (uh^n,phi)_\Omega aux_rhs_c_0 = -1. / (epsilon * m) * (1/dt * np.einsum('i, ij, ijk, j->jk', c_ws, uh_val, phi_c, cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, f_val, phi_c, cell_measure)) # (NC,cldof) # # aux_rhs_c_1: -s / epsilon * (\nabla uh^n, \nabla phi)_\Omega aux_rhs_c_1 = -s / epsilon * ( np.einsum('i, ij, ijk, j->jk', c_ws, guh_val_c[..., 0], gphi_c[..., 0], cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, guh_val_c[..., 1], gphi_c[..., 1], cell_measure)) # (NC,cldof) # # aux_rhs_c_2: 1 / epsilon * (\nabla h(uh^n), \nabla phi)_\Omega aux_rhs_c_2 = 1. / epsilon * ( np.einsum('i, ij, ijk, j->jk', c_ws, grad_free_energy_c[..., 0], gphi_c[..., 0], cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, grad_free_energy_c[..., 1], gphi_c[..., 1], cell_measure)) # (NC,cldof) # # aux_rhs_f_0: (\nabla wh^{n+1}\cdot n, phi)_\Gamma, wh is the solution of auxiliary equation aux_rhs_f_0 = alpha * np.einsum('i, ij, ijn, j->jn', f_ws, Neumann, phi_f, neu_face_measure) \ + np.einsum('i, ij, ijn, j->jn', f_ws, LaplaceNeumann, phi_f, neu_face_measure) # (Nneu,fldof) # # aux_rhs_f_1: s / epsilon * (\nabla uh^n \cdot n, phi)_\Gamma aux_rhs_f_1 = s / epsilon * np.einsum('i, ijk, jk, ijn, j->jn', f_ws, guh_val_f, nBd, phi_f, neu_face_measure) # (Nneu,fldof) # # aux_rhs_f_2: -1 / epsilon * (\nabla h(uh^n) \cdot n, phi)_\Gamma aux_rhs_f_2 = -1. / epsilon * np.einsum('i, ijk, jk, ijn, j->jn', f_ws, grad_free_energy_f, nBd, phi_f, neu_face_measure) # (Nneu,fldof) np.add.at(aux_rv, cell2dof, aux_rhs_c_0 + aux_rhs_c_1 + aux_rhs_c_2) np.add.at(aux_rv, face2dof[idxNeuEdge, :], aux_rhs_f_0 + aux_rhs_f_1 + aux_rhs_f_2) # # update the solution of auxiliary equation wh[:] = spsolve(sm + (alpha + s / epsilon) * mm, aux_rv) # # update the original solution orig_rv = np.zeros((dof.number_of_global_dofs(),), dtype=self.ftype) # (Ndof,) wh_val = space.value(wh, c_bcs) # (NQ,NC) orig_rhs_c = - np.einsum('i, ij, ijk, j->jk', c_ws, wh_val, phi_c, cell_measure) # (NC,cldof) orig_rhs_f = np.einsum('i, ij, ijn, j->jn', f_ws, Neumann, phi_f, neu_face_measure) np.add.at(orig_rv, cell2dof, orig_rhs_c) np.add.at(orig_rv, face2dof[idxNeuEdge, :], orig_rhs_f) uh[:] = spsolve(sm - alpha * mm, orig_rv) # currt_l2err = self.currt_error(uh, next_t) # print('max(uh) = ', max(uh)) # if max(uh[:]) > 1e5: # break print(' # ------------ end the time-looping ------------ #\n') l2err, h1err = self.currt_error(uh, timemesh[-1]) print(' # ------------ the last errors ------------ #') print(' l2err = %.4e, h1err = %.4e' % (l2err, h1err)) return l2err, h1err def CH_Solver_T2ndOrder(self): pde = self.pde timemesh = self.timemesh NT = len(timemesh) space = self.space dt = self.dt uh = self.uh last_uh = space.function() wh = self.wh sm = self.StiffMatrix mm = self.MassMatrix dof = self.dof face2dof = dof.face_to_dof() # (NE,fldof) cell2dof = dof.cell_to_dof() # (NC,cldof) dt_min = pde.dt_min if hasattr(pde, 'dt_min') else dt s, alpha = self.setCoefficient_T2ndOrder(dt_minimum=dt_min) m = pde.m epsilon = pde.epsilon eta = pde.eta print(' # #################################### #') print(' Time 2nd-order scheme') print(' # #################################### #') print(' # ------------ parameters ------------ #') print(' s = %.4e, alpha = %.4e, m = %.4e, epsilon = %.4e, eta = %.4e' % (s, alpha, m, epsilon, eta)) print(' t0 = %.4e, T = %.4e, dt = %.4e' % (timemesh[0], timemesh[-1], dt)) print(' ') idxNeuEdge = self.set_Neumann_edge() nBd = self.mesh.face_unit_normal(index=idxNeuEdge) # (NBE,2) NeuCellIdx = self.mesh.ds.edge2cell[idxNeuEdge, 0] NeuLocalIdx = self.mesh.ds.edge2cell[idxNeuEdge, 2] neu_face_measure = self.mesh.entity_measure('face', index=idxNeuEdge) # (Nneu,2) cell_measure = self.mesh.cell_area() 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=idxNeuEdge) # f_pp.shape: (NQ,NBE,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 phi_f = space.face_basis(f_bcs) # (NQ,1,fldof). 实际上这里可以直接用 pspace.basis(f_bcs), 两个函数的代码是相同的 phi_c = space.basis(c_bcs) # (NQ,NC,clodf) gphi_c = space.grad_basis(c_bcs) # (NQ,NC,cldof,GD) # # time-looping print(' # ------------ begin the time-looping ------------ #') def init_solution(p): return pde.solution(p, 0) last_uh[:] = space.interpolation(init_solution) for nt in range(NT-1): currt_t = timemesh[nt] next_t = currt_t + dt if nt % max([int(NT/10), 1]) == 0: print(' currt_t = %.4e' % currt_t) if nt == 0: # the initial value setting s, alpha = self.setCoefficient_T1stOrder(dt_minimum=dt_min) u_c = pde.solution(c_pp, pde.t0) # (NQC,NC) gu_c = pde.gradient(c_pp, pde.t0) # (NQC,NC,2) u_f = pde.solution(f_pp, pde.t0) # (NQF,NBE) gu_f = pde.gradient(f_pp, pde.t0) # (NQF,NBE,2) grad_free_energy_c = epsilon / eta ** 2 * (3 * np.repeat(u_c[..., np.newaxis], 2, axis=2) ** 2 * gu_c - gu_c) grad_free_energy_f = epsilon / eta ** 2 * (3 * np.repeat(u_f[..., np.newaxis], 2, axis=2) ** 2 * gu_f - gu_f) uh_val = u_c # (NQ,NC) guh_val_c = gu_c # (NQ,NC,2) guh_val_f = gu_f # (NQ,NE,2) else: s, alpha = self.setCoefficient_T2ndOrder(dt_minimum=dt_min) grad_free_energy_c = epsilon / eta ** 2 * self.grad_free_energy_at_cells(2*uh - last_uh, c_bcs) # (NQ,NC,2) grad_free_energy_f = epsilon / eta ** 2 * self.grad_free_energy_at_faces(2*uh - last_uh, f_bcs, idxNeuEdge, NeuCellIdx, NeuLocalIdx) # (NQ,NE,2) uh_val = space.value(2 * uh - 1/2 * last_uh, c_bcs) # (NQ,NC) guh_val_c = space.grad_value(2*uh - last_uh, c_bcs) # (NQ,NC,2) guh_val_f = self.uh_grad_value_at_faces(2*uh - last_uh, f_bcs, NeuCellIdx, NeuLocalIdx) # (NQ,NE,2) last_uh[:] = uh[:] # update the last_uh Neumann = pde.neumann(f_pp, next_t, nBd) # (NQ,NE) LaplaceNeumann = pde.laplace_neumann(f_pp, next_t, nBd) # (NQ,NE) f_val = pde.source(c_pp, next_t, m, epsilon, eta) # (NQ,NC) # # get the auxiliary equation Right-hand-side-Vector aux_rv = np.zeros((dof.number_of_global_dofs(),), dtype=self.ftype) # (Ndof,) aux_rv_temp = np.zeros((dof.number_of_global_dofs(),), dtype=self.ftype) # # aux_rhs_c_0: -1. / (epsilon * m * dt) * (uh^n,phi)_\Omega aux_rhs_c_0 = -1. / (epsilon * m) * (1/dt * np.einsum('i, ij, ijk, j->jk', c_ws, uh_val, phi_c, cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, f_val, phi_c, cell_measure)) # (NC,cldof) # # aux_rhs_c_1: -s / epsilon * (\nabla uh^n, \nabla phi)_\Omega aux_rhs_c_1 = -s / epsilon * ( np.einsum('i, ij, ijk, j->jk', c_ws, guh_val_c[..., 0], gphi_c[..., 0], cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, guh_val_c[..., 1], gphi_c[..., 1], cell_measure)) # (NC,cldof) # # aux_rhs_c_2: 1 / epsilon * (\nabla h(uh^n), \nabla phi)_\Omega aux_rhs_c_2 = 1. / epsilon * ( np.einsum('i, ij, ijk, j->jk', c_ws, grad_free_energy_c[..., 0], gphi_c[..., 0], cell_measure) + np.einsum('i, ij, ijk, j->jk', c_ws, grad_free_energy_c[..., 1], gphi_c[..., 1], cell_measure)) # (NC,cldof) # # aux_rhs_f_0: (\nabla wh^{n+1}\cdot n, phi)_\Gamma, wh is the solution of auxiliary equation aux_rhs_f_0 = alpha * np.einsum('i, ij, ijn, j->jn', f_ws, Neumann, phi_f, neu_face_measure) \ + np.einsum('i, ij, ijn, j->jn', f_ws, LaplaceNeumann, phi_f, neu_face_measure) # (Nneu,fldof) # # aux_rhs_f_1: s / epsilon * (\nabla uh^n \cdot n, phi)_\Gamma aux_rhs_f_1 = s / epsilon * np.einsum('i, ijk, jk, ijn, j->jn', f_ws, guh_val_f, nBd, phi_f, neu_face_measure) # (Nneu,fldof) # # aux_rhs_f_2: -1 / epsilon * (\nabla h(uh^n) \cdot n, phi)_\Gamma aux_rhs_f_2 = -1. / epsilon * np.einsum('i, ijk, jk, ijn, j->jn', f_ws, grad_free_energy_f, nBd, phi_f, neu_face_measure) # (Nneu,fldof) np.add.at(aux_rv_temp, cell2dof, aux_rhs_c_0) np.add.at(aux_rv, cell2dof, aux_rhs_c_0 + aux_rhs_c_1 + aux_rhs_c_2) np.add.at(aux_rv, face2dof[idxNeuEdge, :], aux_rhs_f_0 + aux_rhs_f_1 + aux_rhs_f_2) # # update the solution of auxiliary equation wh[:] = spsolve(sm + (alpha + s / epsilon) * mm, aux_rv) # # update the original solution orig_rv = np.zeros((dof.number_of_global_dofs(),), dtype=self.ftype) # (Ndof,) wh_val = space.value(wh, c_bcs) # (NQ,NC) orig_rhs_c = - np.einsum('i, ij, ijk, j->jk', c_ws, wh_val, phi_c, cell_measure) # (NC,cldof) orig_rhs_f = np.einsum('i, ij, ijn, j->jn', f_ws, Neumann, phi_f, neu_face_measure) np.add.at(orig_rv, cell2dof, orig_rhs_c) np.add.at(orig_rv, face2dof[idxNeuEdge, :], orig_rhs_f) uh[:] = spsolve(sm - alpha * mm, orig_rv) print(' # ------------ end the time-looping ------------ #\n') l2err, h1err = self.currt_error(uh, timemesh[-1]) print(' # ------------ the last errors ------------ #') print(' l2err = %.4e, h1err = %.4e' % (l2err, h1err)) return l2err, h1err def currt_error(self, uh, t): pde = self.pde def currt_solution(p): return pde.solution(p, t) l2err = self.space.integralalg.L2_error(currt_solution, uh) def currt_grad_solution(p): return pde.gradient(p, t) h1err = self.space.integralalg.L2_error(currt_grad_solution, uh.grad_value) return l2err, h1err def set_Dirichlet_edge(self, idxDirEdge=None): if idxDirEdge is not None: return idxDirEdge mesh = self.mesh edge2cell = mesh.ds.edge_to_cell() isBdEdge = (edge2cell[:, 0] == edge2cell[:, 1]) # (NE,), the bool vars, to get the boundary edges isDirEdge = isBdEdge # here, we set all the boundary edges are Dir edges idxDirEdge, = np.nonzero(isDirEdge) # (NE_Dir,) return idxDirEdge def set_Neumann_edge(self, idxNeuEdge=None): if idxNeuEdge is not None: return idxNeuEdge mesh = self.mesh edge2cell = mesh.ds.edge_to_cell() bdEdge = (edge2cell[:, 0] == edge2cell[:, 1]) # the bool vars, to get the boundary edges isNeuEdge = bdEdge # here, we first set all the boundary edges are Neu edges idxNeuEdge, = np.nonzero(isNeuEdge) # (NE_Dir,) return idxNeuEdge
mu = float(sys.argv[3]) stype = sys.argv[4] pde = PolyModel3d(lam=lam, mu=mu) mesh = pde.init_mesh(n=n) NN = mesh.number_of_nodes() print("NN:", 3*NN) space = LagrangeFiniteElementSpace(mesh, p=1) bc = DirichletBC(space, pde.dirichlet) uh = space.function(dim=3) A = space.linear_elasticity_matrix(pde.lam, pde.mu, q=1) F = space.source_vector(pde.source, dim=3) A, F = bc.apply(A, F, uh) I = space.rigid_motion_matrix() S = space.stiff_matrix(2*pde.mu) S = bc.apply_on_matrix(S) solver = LinearElasticityLFEMFastSolver_1(A, S, I, stype=stype, drop_tol=1e-6, fill_factor=40) solver.solve(uh, F) error = space.integralalg.error(pde.displacement, uh) print(error)
N = len(F) print(N) start = timer() ilu = spilu(A.tocsc(), drop_tol=1e-6, fill_factor=40) end = timer() print('time:', end - start) 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) elif True: I = space.rigid_motion_matrix() P = space.stiff_matrix(c=2 * pde.mu) isBdDof = space.set_dirichlet_bc(uh, pde.dirichlet, threshold=pde.is_dirichlet_boundary) solver = LinearElasticityLFEMFastSolver(A, P, I, isBdDof) start = timer() uh[:] = solver.solve(uh, F) end = timer() print('time:', end - start, 'dof:', A.shape) elif False: A0 = space.stiff_matrix(c=2 * pde.mu) isBdDof = space.set_dirichlet_bc(uh, pde.dirichlet, threshold=pde.is_dirichlet_boundary) P = space.rigid_motion_matrix() solver = LinearElasticityLFEMFastSolver_2(A, A0, P, isBdDof)
#pde = PDE() pde = CosCosData() mesh = pde.init_mesh(n=3) errorType = [ '$|| u - u_h||_{\Omega,0}$', '$||\\nabla u - \\nabla u_h||_{\Omega, 0}$' ] 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() uh = space.function() A = space.stiff_matrix() F = space.source_vector(pde.source) bc = NeumannBC(space, pde.neumann) A, F = bc.apply( F, A=A) # Here is the case for pure Neumann bc, we also need modify A # bc.apply(F) # Not pure Neumann bc case uh[:] = spsolve(A, F)[:-1] # we add a addtional dof # Here can not work #ml = pyamg.ruge_stuben_solver(A) #x = ml.solve(F, tol=1e-12, accel='cg').reshape(-1) #uh[:] = x[-1] errorMatrix[0, i] = space.integralalg.L2_error(pde.solution, uh) errorMatrix[1, i] = space.integralalg.L2_error(pde.gradient, uh.grad_value)
class PoissonFEMModel(object): def __init__(self, pde, mesh, p, q=3): self.space = LagrangeFiniteElementSpace(mesh, p, q=q) self.mesh = self.space.mesh self.pde = pde self.uh = self.space.function() self.uI = self.space.interpolation(pde.solution) self.integrator = self.mesh.integrator(p + 2) def recover_estimate(self, rguh): qf = self.integrator bcs, ws = qf.quadpts, qf.weights val0 = rguh.value(bcs) val1 = self.uh.grad_value(bcs) l = np.sum((val1 - val0)**2, axis=-1) e = np.einsum('i, ij->j', ws, l) e *= self.space.cellmeasure return np.sqrt(e) def residual_estimate(self, uh=None): if uh is None: uh = self.uh mesh = self.mesh GD = mesh.geo_dimension() NC = mesh.number_of_cells() n = mesh.face_normal() bc = np.array([1 / (GD + 1)] * (GD + 1), dtype=mesh.ftype) grad = uh.grad_value(bc) ps = mesh.bc_to_point(bc) try: d = self.pde.diffusion_coefficient(ps) except AttributeError: d = np.ones(NC, dtype=mesh.ftype) if isinstance(d, float): grad *= d elif len(d) == GD: grad = np.einsum('m, im->im', d, grad) elif isinstance(d, np.ndarray): if len(d.shape) == 1: grad = np.einsum('i, im->im', d, grad) elif len(d.shape) == 2: grad = np.einsum('im, im->im', d, grad) elif len(d.shape) == 3: grad = np.einsum('imn, in->in', d, grad) if GD == 2: face2cell = mesh.ds.edge_to_cell() h = np.sqrt(np.sum(n**2, axis=-1)) elif GD == 3: face2cell = mesh.ds.face_to_cell() h = np.sum(n**2, axis=-1)**(1 / 4) J = h * np.sum( (grad[face2cell[:, 0]] - grad[face2cell[:, 1]]) * n, axis=-1)**2 NC = mesh.number_of_cells() eta = np.zeros(NC, dtype=mesh.ftype) np.add.at(eta, face2cell[:, 0], J) np.add.at(eta, face2cell[:, 1], J) return np.sqrt(eta) def get_left_matrix(self): return self.space.stiff_matrix() def get_right_vector(self): return self.space.source_vector(self.pde.source) def solve(self): bc = DirichletBC(self.space, self.pde.dirichlet) start = timer() A = self.get_left_matrix() b = self.get_right_vector() end = timer() self.A = A print("Construct linear system time:", end - start) AD, b = bc.apply(A, b) start = timer() self.uh[:] = spsolve(AD, b) end = timer() print("Solve time:", end - start) ls = {'A': AD, 'b': b, 'solution': self.uh.copy()} return ls # return the linear system def l2_error(self): e = self.uh - self.uI return np.sqrt(np.mean(e**2)) def uIuh_error(self): e = self.uh - self.uI return np.sqrt(e @ self.A @ e) def L2_error(self, uh=None): u = self.pde.solution if uh is None: uh = self.uh.value else: uh = uh.value L2 = self.space.integralalg.L2_error(u, uh) return L2 def H1_semi_error(self, uh=None): gu = self.pde.gradient if uh is None: guh = self.uh.grad_value else: guh = uh.grad_value H1 = self.space.integralalg.L2_error(gu, guh) return H1 def recover_error(self, rguh): gu = self.pde.gradient guh = rguh.value mesh = self.mesh re = self.space.integralalg.L2_error(gu, guh, mesh) return re