Example #1
0
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()
Example #2
0
    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)
Example #3
0
    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()
Example #4
0
    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()
Example #5
0
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)
Example #6
0
 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()
Example #7
0
    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)
Example #8
0
    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)
Example #9
0
    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()
Example #10
0
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()
Example #11
0
    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')
Example #13
0
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]
Example #14
0
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)
Example #16
0
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
Example #17
0
#     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
Example #18
0
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
Example #19
0
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)
Example #21
0
#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)
Example #22
0
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