Exemple #1
0
 def test_basis_input(self):
     """Test the coboundary operator with some basis as inputs."""
     p_x, p_y = 2, 2
     func_space_0 = FunctionSpace(self.mesh,
                                  '0-lobatto', (p_x, p_y),
                                  is_inner=False)
     func_space_1 = FunctionSpace(self.mesh,
                                  '1-lobatto', (p_x, p_y),
                                  is_inner=False)
     func_space_2 = FunctionSpace(self.mesh,
                                  '2-lobatto', (p_x, p_y),
                                  is_inner=False)
     basis_0_ref = BasisForm(func_space_0)
     basis_1_ref = BasisForm(func_space_1)
     basis_0_ref.quad_grid = 'lobatto'
     basis_1_ref.quad_grid = 'gauss'
     basis_2_ref = BasisForm(func_space_2)
     basis_2_ref.quad_grid = 'lobatto'
     e_21_ref = d_21_lobatto_outer((p_x, p_y))
     e_10_ref = d_10_lobatto_outer((p_x, p_y))
     basis_1, e_10 = d(basis_0_ref)
     basis_1.quad_grid = 'gauss'
     basis_2, e_21 = d(basis_1_ref)
     basis_2.quad_grid = 'lobatto'
     M_1 = inner(basis_1, basis_1)
     M_1_ref = inner(basis_1_ref, basis_1_ref)
     npt.assert_array_almost_equal(M_1_ref, M_1)
     M_2 = inner(basis_2, basis_2)
     M_2_ref = inner(basis_2_ref, basis_2_ref)
     npt.assert_array_almost_equal(M_2_ref, M_2)
     npt.assert_array_equal(e_21_ref, e_21)
     npt.assert_array_equal(e_10_ref, e_10)
Exemple #2
0
    def test_basis_inner(self):
        """Test inner product with basis functions."""
        p_x, p_y = 2, 2
        func_space_0 = FunctionSpace(self.mesh, '0-lobatto', (p_x, p_y))
        func_space_1 = FunctionSpace(self.mesh, '1-lobatto', (p_x, p_y))
        basis_0 = BasisForm(func_space_0)
        basis_1 = BasisForm(func_space_1)
        basis_1.quad_grid = 'lobatto'
        basis_0.quad_grid = 'lobatto'
        M_1 = inner(basis_1, basis_1)
        e_10 = d(func_space_0)
        inner_prod_ref = np.tensordot(e_10, M_1, axes=((0), (0)))

        #
        inner_prod = inner(d(basis_0), basis_1)
        npt.assert_array_almost_equal(inner_prod_ref, inner_prod)
        #
        inner_prod_1_ref = np.rollaxis(
            np.tensordot(M_1, e_10, axes=((0), (0))), 2)

        inner_prod_1 = inner(basis_1, d(basis_0))
        npt.assert_array_almost_equal(inner_prod_1_ref, inner_prod_1)

        #
        inner_prod_2_ref = np.tensordot(e_10,
                                        np.tensordot(e_10,
                                                     M_1,
                                                     axes=((0), (0))),
                                        axes=((0), (1)))
        inner_prod_2 = inner(d(basis_0), d(basis_0))

        #
        npt.assert_array_almost_equal(inner_prod_2_ref, inner_prod_2)
Exemple #3
0
    def test_assemble_incidence_matrices(self):
        p_dual = (self.p[0] - 1, self.p[1] - 1)
        func_space_lob_0 = FunctionSpace(self.mesh, '0-lobatto', self.p)
        func_space_extgauss_0 = FunctionSpace(self.mesh, '0-ext_gauss', p_dual)

        func_space_lob_1 = NextSpace(func_space_lob_0)
        func_space_extgauss_1 = FunctionSpace(self.mesh, '1-ext_gauss', p_dual)

        func_space_lob_2 = FunctionSpace(self.mesh, '2-lobatto', self.p)
        func_space_extgauss_2 = FunctionSpace(self.mesh, '2-ext_gauss', p_dual)

        e10_lob = d(func_space_lob_0)
        e21_lob = d(func_space_lob_1)
        e10_ext = d(func_space_extgauss_0)
        # e21_ext = d(func_space_extgauss_1)
        #
        e10_lob_assembled_ref = assemble_slow(
            self.mesh, e10_lob, func_space_lob_1.dof_map.dof_map, func_space_lob_0.dof_map.dof_map, mode='replace')

        e21_lob_assembled_ref = assemble_slow(
            self.mesh, e21_lob, func_space_lob_2.dof_map.dof_map,
            func_space_lob_1.dof_map.dof_map, mode='replace')

        e10_ext_assembled_ref = assemble_slow(
            self.mesh, e10_ext, func_space_extgauss_1.dof_map.dof_map,
            func_space_extgauss_0.dof_map.dof_map, mode='replace')

        # e21_ext_assembled_ref = assemble_slow(
        #     self.mesh, e21_ext, func_space_extgauss_2.dof_map.dof_map,
        #     func_space_extgauss_1.dof_map.dof_map, mode='replace')

        e10_lob_assembled = assemble(e10_lob, (func_space_lob_1, func_space_lob_0)).toarray()
        e21_lob_assembled = assemble(e21_lob, (func_space_lob_2, func_space_lob_1)).toarray()
        e10_ext_assembled = assemble(e10_ext, (func_space_extgauss_1,
                                               func_space_extgauss_0)).toarray()
        # e21_ext_assembled = assemble(e21_ext, func_space_extgauss_2,
        #                              func_space_extgauss_1).toarray()

        npt.assert_array_almost_equal(e10_lob_assembled_ref, e10_lob_assembled)
        npt.assert_array_almost_equal(e21_lob_assembled_ref, e21_lob_assembled)
        npt.assert_array_almost_equal(e10_ext_assembled_ref, e10_ext_assembled)
        # npt.assert_array_almost_equal(e21_ext_assembled_ref, e21_ext_assembled)

        e10_internal = d(func_space_extgauss_0)[:func_space_extgauss_1.num_internal_local_dof]

        e10_internal_assembled_ref = assemble_slow(
            self.mesh, e10_internal, func_space_extgauss_1.dof_map.dof_map_internal, func_space_extgauss_0.dof_map.dof_map)
        e10_internal_assembled = assemble(
            e10_internal, (func_space_extgauss_1, func_space_extgauss_0)).toarray()

        npt.assert_array_almost_equal(e10_internal_assembled_ref, e10_internal_assembled)
Exemple #4
0
    def test_visulization_lobato_e10_inner(self):
        def pfun(x, y):
            return np.sin(np.pi * x) * np.sin(np.pi * y)

        p = (20, 20)
        n = (2, 2)
        mesh = CrazyMesh(2, n, ((-1, 1), (-1, 1)), 0.2)
        xi = eta = np.linspace(-1, 1, 100)

        func_space = FunctionSpace(mesh, '0-lobatto', p)
        form_0 = Form(func_space)
        form_0.discretize(pfun)
        form_0.reconstruct(xi, eta)
        (x, y), data = form_0.export_to_plot()
        plt.contourf(x, y, data)
        plt.title('reduced lobatto 0-form')
        plt.colorbar()
        plt.show()

        form_1 = d(form_0)

        form_1.reconstruct(xi, eta)
        (x, y), data_dx, data_dy = form_1.export_to_plot()

        plt.contourf(x, y, data_dx)
        plt.title('lobatto 1-form dx')
        plt.colorbar()
        # plt.show()

        plt.contourf(x, y, data_dy)
        plt.title('lobatto 1-form dy')
        plt.colorbar()
        # plt.show()
        print(np.min(data_dy))
Exemple #5
0
    def test_visulalization_extended_gauss_e10_inner(self):
        def pfun(x, y):
            return np.sin(np.pi * x) * np.sin(np.pi * y)

        p = (10, 10)
        n = (20, 20)

        mesh = CrazyMesh(2, n, ((-1, 1), (-1, 1)), 0.3)
        func_space_extGau = FunctionSpace(mesh, '0-ext_gauss', p)

        form_0_extG = Form(func_space_extGau)
        form_0_extG.discretize(self.pfun)

        xi = eta = np.linspace(-1, 1, 10)
        form_0_extG.reconstruct(xi, eta)
        (x, y), data = form_0_extG.export_to_plot()
        plt.contourf(x, y, data)
        plt.title('reduced extended_gauss 0-form')
        plt.colorbar()
        plt.show()

        form_1 = d(form_0_extG)
        form_1.reconstruct(xi, eta)
        (x, y), data_dx, data_dy = form_1.export_to_plot()
        ufun_x, ufun_y = self.ufun()
        plt.contourf(x, y, data_dx)
        plt.title('extended_gauss 1-form dx')
        plt.colorbar()
        plt.show()
        #
        plt.contourf(x, y, data_dy)
        plt.title('extended_gauss 1-form dy')
        plt.colorbar()
        plt.show()
        print(np.min(data_dy))
Exemple #6
0
def multiple_element():
    mesh = CrazyMesh(2, (5, 7), ((-1, 1), (-1, 1)), curvature=0.3)
    p = 10, 10
    func_space_vort = FunctionSpace(mesh, '0-ext_gauss', (p[0] - 1, p[1] - 1), is_inner=False)
    func_space_outer_vel = FunctionSpace(
        mesh, '1-total_ext_gauss', (p[0], p[1]), is_inner=False)
    # func_space_outer_vel = FunctionSpace(
    #     mesh, '1-gauss', (p[0], p[1]), is_inner=False)
    func_space_inner_vel = FunctionSpace(mesh, '1-lobatto', p, is_inner=True)
    func_space_inner_vel.dof_map.continous_dof = True
    func_space_source = FunctionSpace(mesh, '2-lobatto', p, is_inner=True)

    basis_vort = BasisForm(func_space_vort)
    basis_vel_in = BasisForm(func_space_inner_vel)
    basis_vel_in.quad_grid = 'lobatto'
    basis_vel_out = BasisForm(func_space_outer_vel)
    basis_vel_out.quad_grid = 'lobatto'
    basis_2 = BasisForm(func_space_source)

    psi = Form(func_space_vort)
    u_in = Form(func_space_inner_vel)
    source = Form(func_space_source)
    source.discretize(ffun)

    M_1 = inner(basis_vel_in, basis_vel_in)
    E_21_in = d(func_space_inner_vel)
    W_02 = basis_2.wedged(basis_vort)
    W_02_E21 = np.transpose(W_02 @ E_21_in)

    M_1 = assemble(M_1, (func_space_inner_vel, func_space_inner_vel))
    print(np.shape(M_1))
    W_02_E21 = assemble(W_02_E21, (func_space_inner_vel, func_space_vort))
    print(np.shape(W_02_E21))
    W_02 = assemble(W_02, (func_space_source, func_space_vort))

    lhs = spr.bmat([[M_1, W_02_E21], [W_02_E21.transpose(), None]])
    print(np.shape(lhs))
    rhs = np.zeros(np.shape(lhs)[0])
    rhs[-func_space_source.num_dof:] = W_02 @ source.cochain

    solution = spr.linalg.spsolve(lhs.tocsc(), rhs)
    u_in.cochain = solution[:func_space_inner_vel.num_dof]
    cochian_psi = np.zeros(func_space_vort.num_dof)
    cochian_psi[:func_space_vort.num_internal_dof] = solution[-func_space_vort.num_internal_dof:]
    psi.cochain = cochian_psi

    xi = eta = np.linspace(-1, 1, 40)
    u_in.reconstruct(xi, eta)
    (x, y), u_x, u_y = u_in.export_to_plot()
    plt.contourf(x, y, u_x)
    plt.colorbar()
    plt.title("u_x inner")
    plt.show()
    psi.reconstruct(xi, eta)
    (x, y), psi_value = psi.export_to_plot()
    plt.contourf(x, y, psi_value)
    plt.title("psi outer"
              )
    plt.colorbar()
    plt.show()
    def test_multiple_elements(self):
        """Test the anysotropic case in multiple element."""
        p = (6, 6)
        is_inner = False
        crazy_mesh = CrazyMesh(2, (8, 5),  ((-1, 1), (-1, 1)), curvature=0.1)

        func_space_2_lobatto = FunctionSpace(crazy_mesh, '2-lobatto', p, is_inner)
        func_space_1_lobatto = FunctionSpace(crazy_mesh, '1-lobatto', p, is_inner)
        func_space_1_lobatto.dof_map.continous_dof = True

        def diffusion_11(x, y): return 4 * np.ones(np.shape(x))

        def diffusion_12(x, y): return 3 * np.ones(np.shape(x))

        def diffusion_22(x, y): return 5 * np.ones(np.shape(x))

        def source(x, y):
            return -36 * np.pi ** 2 * np.sin(2 * np.pi * x) * np.sin(2 * np.pi * y) + 24 * np.pi ** 2 * np.cos(2 * np.pi * x) * np.cos(2 * np.pi * y)

        # mesh function to inject the anisotropic tensor
        mesh_k = MeshFunction(crazy_mesh)
        mesh_k.continous_tensor = [diffusion_11, diffusion_12, diffusion_22]

        # definition of the basis functions
        basis_1 = BasisForm(func_space_1_lobatto)
        basis_1.quad_grid = 'gauss'
        basis_2 = BasisForm(func_space_2_lobatto)
        basis_2.quad_grid = 'gauss'

        # solution form
        phi_2 = Form(func_space_2_lobatto)
        phi_2.basis.quad_grid = 'gauss'

        form_source = Form(func_space_2_lobatto)
        form_source.discretize(source, ('gauss', 30))
        # find inner product
        M_1k = inner(basis_1, basis_1, mesh_k)
        N_2 = inner(d(basis_1), basis_2)
        M_2 = inner(basis_2, basis_2)
        # assemble
        M_1k = assemble(M_1k, func_space_1_lobatto)
        N_2 = assemble(N_2, (func_space_1_lobatto, func_space_2_lobatto))
        M_2 = assemble(M_2, func_space_2_lobatto)

        lhs = sparse.bmat([[M_1k, N_2], [N_2.transpose(), None]]).tocsc()
        rhs_source = (form_source.cochain @ M_2)[:, np.newaxis]
        rhs_zeros = np.zeros(lhs.shape[0] - np.size(rhs_source))[:, np.newaxis]
        rhs = np.vstack((rhs_zeros, rhs_source))

        solution = sparse.linalg.spsolve(lhs, rhs)
        phi_2.cochain = solution[-func_space_2_lobatto.num_dof:]

        # sample the solution
        xi = eta = np.linspace(-1, 1, 200)
        phi_2.reconstruct(xi, eta)
        (x, y), data = phi_2.export_to_plot()
        plt.contourf(x, y, data)
        plt.show()
        print("max value {0} \nmin value {1}" .format(np.max(data), np.min(data)))
        npt.assert_array_almost_equal(self.solution(x, y), data, decimal=2)
    def test_single_element(self):
        """Test the anysotropic case in a single element."""
        dim = 2
        elements_layout = (1, 1)
        bounds_domain = ((-1, 1), (-1, 1))
        curvature = 0.1

        p = (20, 20)
        is_inner = False

        crazy_mesh = CrazyMesh(dim, elements_layout, bounds_domain, curvature)

        func_space_2_lobatto = FunctionSpace(crazy_mesh, '2-lobatto', p, is_inner)
        func_space_1_lobatto = FunctionSpace(crazy_mesh, '1-lobatto', p, is_inner)

        def diffusion_11(x, y): return 4 * np.ones(np.shape(x))

        def diffusion_12(x, y): return 3 * np.ones(np.shape(x))

        def diffusion_22(x, y): return 5 * np.ones(np.shape(x))

        mesh_k = MeshFunction(crazy_mesh)
        mesh_k.continous_tensor = [diffusion_11, diffusion_12, diffusion_22]

        basis_1 = BasisForm(func_space_1_lobatto)
        basis_1.quad_grid = 'gauss'
        basis_2 = BasisForm(func_space_2_lobatto)
        basis_2.quad_grid = 'gauss'

        phi_2 = Form(func_space_2_lobatto)
        phi_2.basis.quad_grid = 'gauss'

        M_1k = inner(basis_1, basis_1, mesh_k)

        N_2 = inner(basis_2, d(basis_1))

        def source(x, y):
            return -36 * np.pi ** 2 * np.sin(2 * np.pi * x) * np.sin(2 * np.pi * y) + 24 * np.pi ** 2 * np.cos(2 * np.pi * x) * np.cos(2 * np.pi * y)

        form_source = Form(func_space_2_lobatto)
        form_source.discretize(source)

        M_2 = inner(basis_2, basis_2)

        lhs = np.vstack((np.hstack((M_1k[:, :, 0], N_2[:, :, 0])), np.hstack(
            (np.transpose(N_2[:, :, 0]), np.zeros((np.shape(N_2)[1], np.shape(N_2)[1]))))))

        rhs = np.zeros((np.shape(lhs)[0], 1))
        rhs[-np.shape(M_2)[0]:] = form_source.cochain @ M_2

        phi_2.cochain = np.linalg.solve(lhs, rhs)[-phi_2.basis.num_basis:].flatten()
        xi = eta = np.linspace(-1, 1, 200)
        phi_2.reconstruct(xi, eta)
        (x, y), data = phi_2.export_to_plot()
        print("max value {0} \nmin value {1}" .format(np.max(data), np.min(data)))
        npt.assert_array_almost_equal(self.solution(x, y), data, decimal=2)
Exemple #9
0
    def test_func_space_input(self):
        """Test function space input to coboudary operator.

        It should return the incidence matrix.
        """
        p_x, p_y = 3, 3
        func_space = FunctionSpace(self.mesh,
                                   '1-lobatto', (p_x, p_y),
                                   is_inner=False)
        e_21_lobatto_ref = d_21_lobatto_outer((p_x, p_y))
        e_21_lobatto = d(func_space)
        npt.assert_array_almost_equal(e_21_lobatto, e_21_lobatto_ref)
Exemple #10
0
    def test_form_input(self):
        p_x, p_y = 3, 3
        func_space = FunctionSpace(self.mesh,
                                   '1-lobatto', (p_x, p_y),
                                   is_inner=False)
        form_1_cochain = np.random.rand((func_space.num_dof))

        form_2_cochain_local_ref = d_21_lobatto_outer(
            (p_x, p_y)) @ cochain_to_local(func_space, form_1_cochain)
        func_space_2 = NextSpace(func_space)
        form_2_cochain_ref = cochain_to_global(func_space_2,
                                               form_2_cochain_local_ref)

        form_1 = Form(func_space, form_1_cochain)

        form_2 = d(form_1)
        npt.assert_array_almost_equal(form_2_cochain_ref, form_2.cochain)
Exemple #11
0
    def test_coboundary_lobatto_e10_inner(self):
        """Test of the coundary 0->1 for lobatto form inner oriented."""

        p = (20, 20)
        n = (6, 6)
        mesh = CrazyMesh(2, n, ((-1, 1), (-1, 1)), 0.1)
        xi = eta = np.linspace(-1, 1, 100)

        func_space = FunctionSpace(mesh, '0-lobatto', p)
        form_0 = Form(func_space)
        form_0.discretize(self.pfun)
        form_1 = d(form_0)
        form_1.reconstruct(xi, eta)
        (x, y), data_dx, data_dy = form_1.export_to_plot()

        ufun_x, ufun_y = self.ufun()
        npt.assert_array_almost_equal(ufun_x(x, y), data_dx)
        npt.assert_array_almost_equal(ufun_y(x, y), data_dy)
Exemple #12
0
    def test_coboundary_extended_gauss_e10_inner(self):
        def pfun(x, y):
            return np.sin(np.pi * x) * np.sin(np.pi * y)

        p = (10, 10)
        n = (20, 20)

        mesh = CrazyMesh(2, n, ((-1, 1), (-1, 1)), 0.3)
        func_space_extGau = FunctionSpace(mesh, '0-ext_gauss', p)

        form_0_extG = Form(func_space_extGau)
        form_0_extG.discretize(self.pfun)

        xi = eta = np.linspace(-1, 1, 10)
        form_0_extG.reconstruct(xi, eta)

        form_1 = d(form_0_extG)
        form_1.reconstruct(xi, eta)
        (x, y), data_dx, data_dy = form_1.export_to_plot()
        ufun_x, ufun_y = self.ufun()
        npt.assert_array_almost_equal(ufun_x(x, y), data_dx)
        npt.assert_array_almost_equal(ufun_y(x, y), data_dy)
        print(np.min(data_dy))
Exemple #13
0
def solver(p, n, c):
    px = py = p
    nx = ny = n
    print("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^")
    print("Start div grad solver @ p=", px)
    print("                      @ n=", nx)
    print("                      @ c=", c)
    mesh = CrazyMesh(2, (nx, ny), ((0, 1), (0, 1)), c)
    xi = eta = np.linspace(-1, 1, np.ceil(500 / (nx * ny)) + 1)

    # %% function spaces
    func_space_eg0 = FunctionSpace(mesh, '0-ext_gauss', (px, py))
    p0 = Form(func_space_eg0)
    p0_exact = Form(func_space_eg0)
    p0_exact.discretize(pfun)
    #p0_exact.reconstruct(xi, eta)
    #(x, y), data = p0_exact.export_to_plot()
    #plt.contourf(x, y, data)
    #plt.title('exact extended gauss 0-form, p0')
    #plt.colorbar()
    #plt.show()

    func_space_eg1 = FunctionSpace(mesh, '1-ext_gauss', (px, py))
    ui = Form(func_space_eg1)

    func_space_gl1 = FunctionSpace(mesh,
                                   '1-lobatto', (px + 1, py + 1),
                                   is_inner=False)
    uo = Form(func_space_gl1)

    func_space_gl2 = FunctionSpace(mesh,
                                   '2-lobatto', (px + 1, py + 1),
                                   is_inner=False)
    f2 = Form(func_space_gl2)
    f2.discretize(ffun, ('gauss', px + 5))
    #    f2.reconstruct(xi, eta)
    #    (x, y), data = f2.export_to_plot()
    #    plt.contourf(x, y, data)
    #    plt.title('exact lobatto 2-form, f2')
    #    plt.colorbar()
    #    plt.show()

    # %%
    E10 = d(func_space_eg0)[0:ui.basis.num_basis]
    #    E10 = d(func_space_eg0)
    H = hodge(func_space_gl1)
    E21 = d(func_space_gl1)

    #     print(np.shape(uo.function_space.dof_map.dof_map))
    #     print(np.shape(ui.function_space.dof_map.dof_map_internal))

    #    E10_assembled = assemble_(mesh, E10, ui.function_space.dof_map.dof_map_internal,
    #                             p0.function_space.dof_map.dof_map, mode='replace')
    E10_assembled = assemble(E10, (ui.function_space, p0.function_space))

    #    H_assembled = assemble_(mesh, H, uo.function_space.dof_map.dof_map,
    #                           ui.function_space.dof_map.dof_map_internal)

    #    E21_assembled = assemble_(mesh, E21, f2.function_space.dof_map.dof_map,
    #                             uo.function_space.dof_map.dof_map, mode='replace')
    E21_assembled = assemble(E21, (f2.function_space, uo.function_space))

    #print(E21_assembled)
    #    E10_assembled = assemble(E10, ui.function_space, p0.function_space)
    H_assembled = -assemble(H, ui.function_space, uo.function_space)
    #    E21_assembled = assemble(E21, f2.function_space, uo.function_space)

    # %% test the assembled matrices
    #    ui_cochian_internal = E10_assembled.dot(p0_exact.cochain)
    #    ui.cochain = np.concatenate((ui_cochian_internal, np.zeros(
    #        ui.function_space.num_dof - ui.basis.num_basis * ui.mesh.num_elements)), axis=0)
    #    ui.reconstruct(xi, eta)
    #    (x, y), data_dx, data_dy = ui.export_to_plot()
    ##    plt.contourf(x, y, data_dx)
    ##    plt.title('exact extended_gauss 1-form dx')
    ##    plt.colorbar()
    ##    plt.show()
    #
    #    plt.contourf(x, y, data_dy)
    #    plt.title('exact extended_gauss 1-form dy')
    #    plt.colorbar()
    #    plt.show()
    #
    #    uo.cochain = H_assembled.dot( ui_cochian_internal)
    #    uo.reconstruct(xi, eta)
    #    (x, y), data_dx, data_dy = uo.export_to_plot()
    #    plt.contourf(x, y, data_dx)
    #    plt.title('exact lobbat 1-form dx')
    #    plt.colorbar()
    #    plt.show()

    #    plt.contourf(x, y, data_dy)
    #    plt.title('exact lobbat 1-form dy')
    #    plt.colorbar()
    #    plt.show()

    # %%
    # system:
    #  |  H      E10 |   | uo |      | 0 |
    #  |             |   |    |      |   |
    #  |             | * |    |   =  |   |
    #  |             |   |    |      |   |
    #  |  E21     0  |   | p  |      | f |
    ui_num_dof_internal = ui.basis.num_basis * ui.mesh.num_elements

    #    LHS1 = np.hstack((np.eye(ui_num_dof_internal),
    #                      np.zeros((ui_num_dof_internal, uo.function_space.num_dof)),
    #                      -E10_assembled))
    #
    #    LHS2 = np.hstack((-H_assembled,
    #                      np.eye(uo.function_space.num_dof),
    #                      np.zeros((uo.function_space.num_dof, p0.function_space.num_dof))))
    #
    #    LHS3 = np.hstack((np.zeros((f2.function_space.num_dof, ui_num_dof_internal)),
    #                      E21_assembled,
    #                      np.zeros((f2.function_space.num_dof, p0.function_space.num_dof))))

    LHS1 = sparse.hstack((H_assembled, E10_assembled))

    LHS2 = sparse.hstack(
        (E21_assembled,
         sparse.csc_matrix(
             (f2.function_space.num_dof, p0.function_space.num_dof))))

    RHS1 = np.zeros(shape=(uo.function_space.num_dof, 1))
    RHS2 = f2.cochain.reshape((f2.function_space.num_dof, 1))

    # %%
    def dof_map_crazy_lobatto_edges(mesh, p):
        nx, ny = mesh.n_x, mesh.n_y
        global_numbering = np.zeros((nx * ny, 2 * p * (p + 1)), dtype=np.int32)
        local_numbering = np.array([int(i) for i in range(2 * p * (p + 1))])
        for i in range(nx):
            for j in range(ny):
                s = j + i * ny
                global_numbering[s, :] = local_numbering + 2 * p * (p + 1) * s
        interface_edge_pair = np.zeros(
            (((nx - 1) * ny + nx * (ny - 1)) * p, 2), dtype=np.int32)
        n = 0
        for i in range(nx - 1):
            for j in range(ny):
                s1 = j + i * ny
                s2 = j + (i + 1) * ny
                for m in range(p):
                    interface_edge_pair[n,
                                        0] = global_numbering[s1, p * (p + 1) +
                                                              p**2 + m]
                    interface_edge_pair[n,
                                        1] = global_numbering[s2,
                                                              p * (p + 1) + m]
                    n += 1
        for i in range(nx):
            for j in range(ny - 1):
                s1 = j + i * ny
                s2 = j + 1 + i * ny
                for m in range(p):
                    interface_edge_pair[n, 0] = global_numbering[s1, (m + 1) *
                                                                 (p + 1) - 1]
                    interface_edge_pair[n, 1] = global_numbering[s2,
                                                                 m * (p + 1)]
                    n += 1
        return interface_edge_pair

    interface_edge_pair = dof_map_crazy_lobatto_edges(mesh, px + 1)
    LItFuo = sparse.lil_matrix(
        (np.shape(interface_edge_pair)[0],
         uo.function_space.num_dof + p0.function_space.num_dof))
    RItFuo = np.zeros(shape=(np.shape(interface_edge_pair)[0], 1))
    for i in range(np.shape(interface_edge_pair)[0]):
        LItFuo[i, interface_edge_pair[i, 0]] = 1
        LItFuo[i, interface_edge_pair[i, 1]] = -1

    # %%
    def CrazyMesh_2d_extended_gauss0_general_boundary_nodes(
            mesh, p, gathering_matrix):
        p += 1
        nx = mesh.n_x
        ny = mesh.n_y

        Left = np.zeros(shape=(ny * p), dtype=np.int16)
        Right = np.zeros(shape=(ny * p), dtype=np.int16)
        Bottom = np.zeros(shape=(nx * p), dtype=np.int16)
        Top = np.zeros(shape=(nx * p), dtype=np.int16)

        for J in range(ny):
            eleidLeft = J
            Left[J * p:J * p + p] = gathering_matrix[eleidLeft, p**2:p**2 + p]

            eleidRight = (nx - 1) * ny + J
            Right[J * p:J * p + p] = gathering_matrix[eleidRight,
                                                      p**2 + p:p**2 + 2 * p]

        for I in range(nx):

            eleidBottom = I * ny
            Bottom[I * p:I * p + p] = gathering_matrix[eleidBottom, p**2 +
                                                       2 * p:p**2 + 3 * p]

            eleidTop = I * ny + ny - 1
            Top[I * p:I * p + p] = gathering_matrix[eleidTop,
                                                    p**2 + 3 * p:p**2 + 4 * p]

        return Left, Right, Bottom, Top

    Left, Right, Bottom, Top = CrazyMesh_2d_extended_gauss0_general_boundary_nodes(
        mesh, px, p0.function_space.dof_map.dof_map)
    Boundarypoint = np.hstack((Left, Right, Bottom, Top))
    #    LBCphi = np.zeros(shape=(np.size(Boundarypoint), ui_num_dof_internal +
    #                             uo.function_space.num_dof + p0.function_space.num_dof))
    LBCphi = sparse.lil_matrix(
        (np.size(Boundarypoint),
         uo.function_space.num_dof + p0.function_space.num_dof))
    RBCphi = np.zeros(shape=(np.size(Boundarypoint), 1))
    for i in range(np.size(Boundarypoint)):
        LBCphi[i, uo.function_space.num_dof + Boundarypoint[i]] = 1
        RBCphi[i] = p0_exact.cochain[Boundarypoint[i]]

    # %% LHS and RHS and solve it
    LHS = sparse.vstack((LHS1, LHS2, LItFuo, LBCphi))
    RHS = np.vstack((RHS1, RHS2, RItFuo, RBCphi))
    print("----------------------------------------------------")
    print("LHS shape:", np.shape(LHS))
    #
    LHS = sparse.csr_matrix(LHS)
    print("------ solve the square sparse system:......")
    Res = sparse.linalg.spsolve(LHS, RHS)
    #    Res = sparse.linalg.lsqr(LHS,RHS, atol=1e-20, btol=1e-20)[0]

    #    print("++++++ solve the singular square full system:......")
    #    Res = np.linalg.solve(LHS, RHS)

    # %% split into pieces
    uo.cochain = Res[:uo.function_space.num_dof].reshape(
        uo.function_space.num_dof)
    p0.cochain = Res[-p0.function_space.num_dof:].reshape(
        p0.function_space.num_dof)

    # %% view the result
    p0.reconstruct(xi, eta)
    (x, y), data = p0.export_to_plot()
    plt.contourf(x, y, data)
    plt.title('solution extended gauss 0-form, p0')
    plt.colorbar()
    plt.show()
    #
    #    uo.reconstruct(xi, eta)
    #    (x, y), data_dx, data_dy = uo.export_to_plot()
    #    plt.contourf(x, y, data_dx)
    #    plt.title('lobatto 1-form dx')
    #    plt.colorbar()
    #    plt.show()
    #
    #    plt.contourf(x, y, data_dy)
    #    plt.title('lobatto 1-form dy')
    #    plt.colorbar()
    #    plt.show()

    #f2.reconstruct(xi, eta)
    #(x, y), data = f2.export_to_plot()
    #plt.contourf(x, y, data)
    #plt.title('exact lobatto 2-form, f2')
    #plt.colorbar()
    #plt.show()

    # %% L2_error
    L2_error_p0 = p0.l_2_norm(pfun, ('gauss', px + 5))[0]

    L2_error_uo = uo.l_2_norm((uo_dx, uo_dy), ('lobatto', px + 5))[0]

    print("------ L2_error_p0 =", L2_error_p0)
    print("------ L2_error_uo =", L2_error_uo)
    return L2_error_p0, L2_error_uo
    print("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n")
def solver(p, n, c):
    print("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^")
    print("Start curl curl solver @ p=", p)
    print("                       @ n=", n)
    print("                       @ c=", c)
    px = py = p
    nx = n
    ny = n
    mesh = CrazyMesh(2, (nx, ny), ((-1, 1), (-1, 1)), c)
    xi = eta = np.linspace(-1, 1, np.ceil(500 / (nx * ny)) + 1)
    # %% exact p(0)
    func_space_gl0 = FunctionSpace(mesh,
                                   '0-lobatto', (px + 1, py + 1),
                                   is_inner=False)
    p0_exact = Form(func_space_gl0)
    p0_exact.discretize(pfun)
    p0_exact.reconstruct(xi, eta)
    (x, y), data = p0_exact.export_to_plot()
    plt.contourf(x, y, data)
    plt.title('exact lobatto 0-form, p0')
    plt.colorbar()
    plt.show()

    # %% p(0)
    func_space_gl0 = FunctionSpace(mesh,
                                   '0-lobatto', (px + 1, py + 1),
                                   is_inner=False)
    p0 = Form(func_space_gl0)

    # %%
    func_space_gl1 = FunctionSpace(mesh,
                                   '1-lobatto', (px + 1, py + 1),
                                   is_inner=False)
    uo = Form(func_space_gl1)

    # %%
    func_space_eg1 = FunctionSpace(mesh, '1-ext_gauss', (px, py))
    ui = Form(func_space_eg1)

    # %%
    func_space_eg2 = FunctionSpace(mesh, '2-ext_gauss', (px, py))
    f2 = Form(func_space_eg2)
    f2_exact = Form(func_space_eg2)
    f2_exact.discretize(ffun)
    #    f2_exact.reconstruct(xi, eta)
    #    (x, y), data = f2_exact.export_to_plot()
    #    plt.contourf(x, y, data)
    #    plt.title('exact extended-gauss 2-form, f2')
    #    plt.colorbar()
    #    plt.show()

    # %%
    E10 = d(func_space_gl0)
    #    E10_assembled = assemble(mesh, E10, uo.function_space.dof_map.dof_map,p0.function_space.dof_map.dof_map, mode='replace')
    E10_assembled = assemble(E10, (uo.function_space, p0.function_space))

    H = hodge(func_space_gl1)
    #    H_assembled   = assemble(mesh, H  , ui.function_space.dof_map.dof_map_internal, uo.function_space.dof_map.dof_map)
    H_assembled = assemble(H, (ui.function_space, uo.function_space))
    #H_assembled   = np.linalg.inv(H_assembled)

    E21 = d(func_space_eg1)
    #    E21_assembled = assemble(mesh, E21, f2.function_space.dof_map.dof_map, ui.function_space.dof_map.dof_map, mode = 'replace')
    E21_assembled = assemble(E21, (f2.function_space, ui.function_space))
    # %%
    #    uo.cochain = E10_assembled.dot(p0_exact.cochain)
    #    uo.reconstruct(xi, eta)
    #    (x, y), data_dx, data_dy = uo.export_to_plot()
    #    plt.contourf(x, y, data_dx)
    #    plt.title('exact lobatto 1-form dx')
    #    plt.colorbar()
    #    plt.show()
    #    print('uo_dx max:', np.max(data_dx))
    #    print('uo_dx min:', np.min(data_dx))
    #
    #    plt.contourf(x, y, data_dy)
    #    plt.title('exact lobatto 1-form dy')
    #    plt.colorbar()
    #    plt.show()
    #    print('uo_dy max:', np.max(data_dy))
    #    print('uo_dy min:', np.min(data_dy))
    #
    #    ui_internal_cochain = H_assembled.dot(uo.cochain)
    #    ui.cochain = np.concatenate((ui_internal_cochain, np.zeros(
    #        ui.function_space.num_dof - ui.basis.num_basis * ui.mesh.num_elements)), axis=0)
    #    ui.reconstruct(xi, eta)
    #    (x, y), data_dx, data_dy = ui.export_to_plot()
    #    plt.contourf(x, y, data_dx)
    #    plt.title('ext_gauss 1-form dx')
    #    plt.colorbar()
    #    plt.show()
    #    print('ui_dx max:', np.max(data_dx))
    #    print('ui_dy min:', np.min(data_dx))
    #
    #    plt.contourf(x, y, data_dy)
    #    plt.title('ext_gauss 1-form dy')
    #    plt.colorbar()
    #    plt.show()
    #    print('ui_dy max:', np.max(data_dy))
    #    print('ui_dy min:', np.min(data_dy))
    #    def UBC(mesh, s, p, position):
    #        def pullbackedfun_dx(xi, eta):
    #            x, y = mesh.mapping(xi, eta, s)
    #            return ui_dx(x, y)
    #
    #        def pullbackedfun_dy(xi, eta):
    #            x, y = mesh.mapping(xi, eta, s)
    #            return ui_dy(x, y)
    #
    #        def fun2bint_dxi(xi, eta):
    #            return pullbackedfun_dx(xi, eta) * mesh.dx_dxi(xi, eta, s)  + pullbackedfun_dy(xi, eta) * mesh.dy_dxi(xi, eta, s)
    #
    #        def fun2bint_deta(xi, eta):
    #            return pullbackedfun_dx(xi, eta) * mesh.dx_deta(xi, eta, s) + pullbackedfun_dy(xi, eta) * mesh.dy_deta(xi, eta, s)
    #
    #        UBC_s = np.zeros(shape = (p+1))
    #        extended_gauss_nodes, _ = extended_gauss_quad(p-1)
    #        if position == 'Left':
    #            for i in range(p+1):
    #    #            print("hello, Left world")
    #                def fun2bint_deta_BC(eta):
    #                    return fun2bint_deta(-1, eta)
    #                UBC_s[i] = quad(fun2bint_deta_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
    #        elif position == 'Right':
    #            for i in range(p+1):
    #    #            print("hello, Right world")
    #                def fun2bint_deta_BC(eta):
    #                    return fun2bint_deta(+1, eta)
    #                UBC_s[i] = quad(fun2bint_deta_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
    #        elif position == 'Bottom':
    #            for i in range(p+1):
    #    #            print("hello, Bottom world")
    #                def fun2bint_dxi_BC(xi):
    #                    return fun2bint_dxi(xi, -1)
    #                UBC_s[i] = quad(fun2bint_dxi_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
    #        elif position == 'Top':
    #            for i in range(p+1):
    #    #            print("hello, Top world")
    #                def fun2bint_dxi_BC(xi):
    #                    return fun2bint_dxi(xi, +1)
    #                UBC_s[i] = quad(fun2bint_dxi_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
    #        return UBC_s
    #
    #    def extended_gauss1_general_boundary_edges(mesh, p, gathering_matrix):
    #        p+=1
    #        nx = mesh.n_x
    #        ny = mesh.n_y
    #
    #        Left   = np.zeros( shape = (ny*(p+1)), dtype=np.int32 )
    #        Right  = np.zeros( shape = (ny*(p+1)), dtype=np.int32 )
    #        Bottom = np.zeros( shape = (nx*(p+1)), dtype=np.int32 )
    #        Top    = np.zeros( shape = (nx*(p+1)), dtype=np.int32 )
    #
    #        M = 2 * p * (p+1)
    #        N = p+1
    #
    #        UBC_L = UBC_R = UBC_B = UBC_T = 0
    #
    #        for J in range(ny):
    #            eleidLeft  = J
    #            Left[  J*N : J*N + N ] = gathering_matrix[ eleidLeft , M +2*N : M +3*N ]
    #            UBC_s=UBC(mesh, eleidLeft, p, "Left")
    #            if UBC_L is 0:
    #                UBC_L= UBC_s
    #            else:
    #                UBC_L = np.hstack((UBC_L, UBC_s))
    #
    #            eleidRight = (nx-1)*ny + J
    #            Right[ J*N : J*N + N ] = gathering_matrix[ eleidRight, M +3*N : M +4*N ]
    #            UBC_s=UBC(mesh, eleidRight, p, "Right")
    #            if UBC_R is 0:
    #                UBC_R= UBC_s
    #            else:
    #                UBC_R = np.hstack((UBC_R, UBC_s))
    #
    #        for I in range(nx):
    #            eleidBottom = I*ny
    #            Bottom[ I*N : I*N + N ] = gathering_matrix[ eleidBottom, M     : M +   N ]
    #            UBC_s=UBC(mesh, eleidBottom, p, "Bottom")
    #            if UBC_B is 0:
    #                UBC_B= UBC_s
    #            else:
    #                UBC_B = np.hstack((UBC_B, UBC_s))
    #
    #            eleidTop = I*ny + ny -1
    #            Top[ I*N : I*N + N ]    = gathering_matrix[ eleidTop   , M + N : M + 2*N ]
    #            UBC_s=UBC(mesh, eleidTop, p, "Top")
    #            if UBC_T is 0:
    #                UBC_T= UBC_s
    #            else:
    #                UBC_T = np.hstack((UBC_T, UBC_s))
    #
    #        return np.vstack((Left, UBC_L)), np.vstack((Right, UBC_R)), np.vstack((Bottom, UBC_B)), np.vstack((Top, UBC_T))
    #
    #    Left, Right, Bottom, Top = extended_gauss1_general_boundary_edges(mesh, px, ui.function_space.dof_map.dof_map)
    #    Boundaryedgs = np.hstack( (Left, Right, Bottom, Top) )
    #    for i in range(np.shape(Boundaryedgs)[1]):
    #        ui.cochain[int(Boundaryedgs[0, i])] =Boundaryedgs[1, i]
    #
    #    f2.cochain = E21_assembled.dot(ui.cochain)
    #    f2.reconstruct(xi, eta)
    #    (x, y), data = f2.export_to_plot()
    #    plt.contourf(x, y, data)
    #    plt.title('exact extended-gauss 2-form, f2')
    #    plt.colorbar()
    #    plt.show()
    # %%
    # system:
    #  |  I     -H       0  |   | ui |      | 0 |
    #  |                    |   |    |      |   |
    #  |  0      I     -E10 | * | uo |   =  | 0 |
    #  |                    |   |    |      |   |
    #  | E21     0       0  |   | p  |      | f |
    ui_num_dof_internal = ui.basis.num_basis * ui.mesh.num_elements
    ui_num_dof_external = ui.function_space.num_dof - ui_num_dof_internal

    #    LHS1 = np.hstack((   np.eye(ui_num_dof_internal) ,
    #                         np.zeros((ui_num_dof_internal, ui_num_dof_external)),
    #                        -H_assembled ,
    #                         np.zeros((ui_num_dof_internal, p0.function_space.num_dof))   ))
    LHS1 = sparse.hstack(
        (sparse.eye(ui_num_dof_internal),
         sparse.csc_matrix(
             (ui_num_dof_internal, ui_num_dof_external)), -H_assembled,
         sparse.csc_matrix((ui_num_dof_internal, p0.function_space.num_dof))))

    #    LHS2 = np.hstack((  np.zeros((uo.function_space.num_dof, ui.function_space.num_dof )) ,
    #                        np.eye(uo.function_space.num_dof) ,
    #                       -E10_assembled    ))
    LHS2 = sparse.hstack(
        (sparse.csc_matrix(
            (uo.function_space.num_dof, ui.function_space.num_dof)),
         sparse.eye(uo.function_space.num_dof), -E10_assembled))

    #    LHS3 = np.hstack((  E21_assembled ,
    #                        np.zeros((f2.function_space.num_dof, uo.function_space.num_dof )) ,
    #                        np.zeros((f2.function_space.num_dof, f2.function_space.num_dof ))    ))
    LHS3 = sparse.hstack(
        (E21_assembled,
         sparse.csc_matrix(
             (f2.function_space.num_dof, uo.function_space.num_dof)),
         sparse.csc_matrix(
             (f2.function_space.num_dof, f2.function_space.num_dof))))

    RHS1 = np.zeros((ui_num_dof_internal, 1))
    RHS2 = np.zeros((uo.function_space.num_dof, 1))
    RHS3 = f2_exact.cochain.reshape((f2_exact.function_space.num_dof, 1))

    # %% boundary edges
    #    def UBC(mesh, s, p, position):
    #        def pullbackedfun_dx(xi, eta):
    #            x, y = mesh.mapping(xi, eta, s)
    #            return ufun_u(x, y)
    #
    #        def pullbackedfun_dy(xi, eta):
    #            x, y = mesh.mapping(xi, eta, s)
    #            return ufun_v(x, y)
    #
    #        def fun2bint_dxi(xi, eta):
    #            return pullbackedfun_dx(xi, eta) * mesh.dx_dxi(xi, eta, s)  + pullbackedfun_dy(xi, eta) * mesh.dy_dxi(xi, eta, s)
    #
    #        def fun2bint_deta(xi, eta):
    #            return pullbackedfun_dx(xi, eta) * mesh.dx_deta(xi, eta, s) + pullbackedfun_dy(xi, eta) * mesh.dy_deta(xi, eta, s)
    #
    #        UBC_s = np.zeros(shape = (p+1))
    #        extended_gauss_nodes, _ = extended_gauss_quad(p-1)
    #        if position == 'Left':
    #            for i in range(p+1):
    #    #            print("hello, Left world")
    #                def fun2bint_deta_BC(eta):
    #                    return fun2bint_deta(-1, eta)
    #                UBC_s[i] = quad(fun2bint_deta_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
    #        elif position == 'Right':
    #            for i in range(p+1):
    #    #            print("hello, Right world")
    #                def fun2bint_deta_BC(eta):
    #                    return fun2bint_deta(+1, eta)
    #                UBC_s[i] = quad(fun2bint_deta_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
    #        elif position == 'Bottom':
    #            for i in range(p+1):
    #    #            print("hello, Bottom world")
    #                def fun2bint_dxi_BC(xi):
    #                    return fun2bint_dxi(xi, -1)
    #                UBC_s[i] = quad(fun2bint_dxi_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
    #        elif position == 'Top':
    #            for i in range(p+1):
    #    #            print("hello, Top world")
    #                def fun2bint_dxi_BC(xi):
    #                    return fun2bint_dxi(xi, +1)
    #                UBC_s[i] = quad(fun2bint_dxi_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
    #        return UBC_s
    #
    #    def extended_gauss1_general_boundary_edges(mesh, p, gathering_matrix):
    #        p+=1
    #        nx = mesh.n_x
    #        ny = mesh.n_y
    #
    #        Left   = np.zeros( shape = (ny*(p+1)), dtype=np.int32 )
    #        Right  = np.zeros( shape = (ny*(p+1)), dtype=np.int32 )
    #        Bottom = np.zeros( shape = (nx*(p+1)), dtype=np.int32 )
    #        Top    = np.zeros( shape = (nx*(p+1)), dtype=np.int32 )
    #
    #        M = 2 * p * (p+1)
    #        N = p+1
    #
    #        UBC_L = UBC_R = UBC_B = UBC_T = 0
    #
    #        for J in range(ny):
    #            eleidLeft  = J
    #            Left[  J*N : J*N + N ] = gathering_matrix[ eleidLeft , M +2*N : M +3*N ]
    #            UBC_s=UBC(mesh, eleidLeft, p, "Left")
    #            if UBC_L is 0:
    #                UBC_L= UBC_s
    #            else:
    #                UBC_L = np.hstack((UBC_L, UBC_s))
    #
    #            eleidRight = (nx-1)*ny + J
    #            Right[ J*N : J*N + N ] = gathering_matrix[ eleidRight, M +3*N : M +4*N ]
    #            UBC_s=UBC(mesh, eleidRight, p, "Right")
    #            if UBC_R is 0:
    #                UBC_R= UBC_s
    #            else:
    #                UBC_R = np.hstack((UBC_R, UBC_s))
    #
    #        for I in range(nx):
    #            eleidBottom = I*ny
    #            Bottom[ I*N : I*N + N ] = gathering_matrix[ eleidBottom, M     : M +   N ]
    #            UBC_s=UBC(mesh, eleidBottom, p, "Bottom")
    #            if UBC_B is 0:
    #                UBC_B= UBC_s
    #            else:
    #                UBC_B = np.hstack((UBC_B, UBC_s))
    #
    #            eleidTop = I*ny + ny -1
    #            Top[ I*N : I*N + N ]    = gathering_matrix[ eleidTop   , M + N : M + 2*N ]
    #            UBC_s=UBC(mesh, eleidTop, p, "Top")
    #            if UBC_T is 0:
    #                UBC_T= UBC_s
    #            else:
    #                UBC_T = np.hstack((UBC_T, UBC_s))
    #
    #        return np.vstack((Left, UBC_L)), np.vstack((Right, UBC_R)), np.vstack((Bottom, UBC_B)), np.vstack((Top, UBC_T))
    #
    #    Left, Right, Bottom, Top = extended_gauss1_general_boundary_edges(mesh, px, ui.function_space.dof_map.dof_map)
    #    Boundaryedgs = np.hstack( (Left, Right, Bottom, Top) )
    #
    ##    LBC = np.zeros( shape = ( np.shape(Boundaryedgs)[1], ui.function_space.num_dof+ uo.function_space.num_dof + p0.function_space.num_dof ) )
    #    LBC = sparse.lil_matrix( ( np.shape(Boundaryedgs)[1], ui.function_space.num_dof+ uo.function_space.num_dof + p0.function_space.num_dof ) )
    #
    #    RBC = np.zeros( shape = ( np.shape(Boundaryedgs)[1], 1) )
    #    for i in range(np.shape(Boundaryedgs)[1]):
    #        if i == 0 :
    #            LBC[0, ui.function_space.num_dof+ uo.function_space.num_dof] = 1
    #            RBC[0] = p0_exact.cochain[0]
    #        else:
    #            LBC[i, int(Boundaryedgs[0, i])] =1
    #            RBC[i] = Boundaryedgs[1, i]

    # %%
    def PBC(p, nx, ny, gathering_matrix, gathering_matrix_edge):
        p += 1

        Left = np.zeros(shape=(ny * (p + 1), 4), dtype=np.int32)
        Right = np.zeros(shape=(ny * (p + 1), 4), dtype=np.int32)
        Bottom = np.zeros(shape=(nx * (p + 1), 4), dtype=np.int32)
        Top = np.zeros(shape=(nx * (p + 1), 4), dtype=np.int32)

        N = p + 1
        P = 2 * p * (p + 1)
        Q = (p + 1)

        for J in range(ny):
            eleidLeft = J
            Left[J * N:J * N + N, 0] = gathering_matrix[eleidLeft, :N]
            if eleidLeft == 0:  # left-bottom corner element
                Left[0, 0] = -1  # left - bottom corner point
                Left[0, 1] = gathering_matrix_edge[0, P + 2 * Q]
                Left[0, 2] = gathering_matrix_edge[0, P]
            if eleidLeft == ny - 1:  # left-top corner element
                Left[-1, 0] = -3  # left _- top corner point
                Left[-1, 1] = gathering_matrix_edge[eleidLeft, P + Q]
                Left[-1, 2] = gathering_matrix_edge[eleidLeft, P + 3 * Q - 1]
            if eleidLeft >= 0 and eleidLeft < ny - 1:
                Left[J * N + N - 1, 0] = -2  # left
                Left[J * N + N - 1, 1] = gathering_matrix_edge[eleidLeft,
                                                               P + 3 * Q - 1]
                Left[J * N + N - 1, 2] = gathering_matrix_edge[eleidLeft,
                                                               P + Q]
                Left[J * N + N - 1, 3] = gathering_matrix_edge[eleidLeft + 1,
                                                               P + 2 * Q]

            eleidRight = (nx - 1) * ny + J
            Right[J * N:J * N + N, 0] = gathering_matrix[eleidRight, -N:]
            if eleidRight == nx * ny - ny:  # right bottom element
                Right[0, 0] = -4
                Right[0, 1] = gathering_matrix_edge[eleidRight, P + Q - 1]
                Right[0, 2] = gathering_matrix_edge[eleidRight, P + 3 * Q]
            if eleidRight == nx * ny - 1:  # right top element
                Right[-1, 0] = -5
                Right[-1, 1] = gathering_matrix_edge[eleidRight, P + 2 * Q - 1]
                Right[-1, 2] = gathering_matrix_edge[eleidRight, -1]
            if eleidRight >= nx * ny - ny and eleidRight < nx * ny - 1:  # right elements
                Right[J * N + N - 1, 0] = -6
                Right[J * N + N - 1, 1] = gathering_matrix_edge[eleidRight, -1]
                Right[J * N + N - 1, 2] = gathering_matrix_edge[eleidRight,
                                                                P + 2 * Q - 1]
                Right[J * N + N - 1, 3] = gathering_matrix_edge[eleidRight + 1,
                                                                P + 3 * Q]

        for I in range(nx):
            eleidBottom = I * ny
            Bottom[I * N:I * N + N, 0] = gathering_matrix[eleidBottom,
                                                          0:N**2:N]
            if eleidBottom >= 0 and eleidBottom < nx * ny - ny:  # bottom elements
                Bottom[I * N + N - 1, 0] = -7
                Bottom[I * N + N - 1, 1] = gathering_matrix_edge[eleidBottom,
                                                                 P + Q - 1]
                Bottom[I * N + N - 1, 2] = gathering_matrix_edge[eleidBottom,
                                                                 P + 3 * Q]
                Bottom[I * N + N - 1,
                       3] = gathering_matrix_edge[eleidBottom + ny, P]

            eleidTop = I * ny + ny - 1
            Top[I * N:I * N + N, 0] = gathering_matrix[eleidTop, N - 1:N**2:N]

            if eleidTop >= 0 and eleidTop < nx * ny - 1:  # bottom elements
                Top[I * N + N - 1, 0] = -8
                Top[I * N + N - 1, 1] = gathering_matrix_edge[eleidTop,
                                                              P + 2 * Q - 1]
                Top[I * N + N - 1, 2] = gathering_matrix_edge[eleidTop, -1]
                Top[I * N + N - 1, 3] = gathering_matrix_edge[eleidTop + ny,
                                                              P + Q]

        return Left, Right, Bottom, Top

    Left, Right, Bottom, Top = PBC(p, nx, ny,
                                   p0_exact.function_space.dof_map.dof_map,
                                   ui.function_space.dof_map.dof_map)

    Boundarypoints = np.vstack((Left, Right, Bottom, Top))

    LBC = sparse.lil_matrix(
        (np.shape(Boundarypoints)[0], ui.function_space.num_dof +
         uo.function_space.num_dof + p0.function_space.num_dof))
    RBC = np.zeros(shape=(np.shape(Boundarypoints)[0], 1))
    for i in range(np.shape(Boundarypoints)[0]):
        if Boundarypoints[i, 0] == -1:
            LBC[i, Boundarypoints[i, 1]] = +1
            LBC[i, Boundarypoints[i, 2]] = +1
            RBC[i] = 0
        elif Boundarypoints[i, 0] == -2:
            LBC[i, Boundarypoints[i, 1]] = -2
            LBC[i, Boundarypoints[i, 2]] = +1
            LBC[i, Boundarypoints[i, 3]] = +1
            RBC[i] = 0
        elif Boundarypoints[i, 0] == -3:
            LBC[i, Boundarypoints[i, 1]] = +1
            LBC[i, Boundarypoints[i, 2]] = -1
            RBC[i] = 0
        elif Boundarypoints[i, 0] == -4:
            LBC[i, Boundarypoints[i, 1]] = +1
            LBC[i, Boundarypoints[i, 2]] = -1
            RBC[i] = 0
        elif Boundarypoints[i, 0] == -5:
            LBC[i, Boundarypoints[i, 1]] = +1
            LBC[i, Boundarypoints[i, 2]] = +1
            RBC[i] = 0
        elif Boundarypoints[i, 0] == -6:
            LBC[i, Boundarypoints[i, 1]] = +1
            LBC[i, Boundarypoints[i, 2]] = +1
            LBC[i, Boundarypoints[i, 3]] = -2
            RBC[i] = 0
        elif Boundarypoints[i, 0] == -7:
            LBC[i, Boundarypoints[i, 1]] = -2
            LBC[i, Boundarypoints[i, 2]] = +1
            LBC[i, Boundarypoints[i, 3]] = +1
            RBC[i] = 0
        elif Boundarypoints[i, 0] == -8:
            LBC[i, Boundarypoints[i, 1]] = +1
            LBC[i, Boundarypoints[i, 2]] = +1
            LBC[i, Boundarypoints[i, 3]] = -2
            RBC[i] = 0
        else:
            LBC[i, ui.function_space.num_dof + uo.function_space.num_dof +
                int(Boundarypoints[i, 0])] = 1
            RBC[i] = p0_exact.cochain[Boundarypoints[i, 0]]

    # %%
    def dof_map_crazy_lobatto_point_pair(mesh, p, global_numbering,
                                         global_numbering_edges):
        nx, ny = mesh.n_x, mesh.n_y

        N = p + 1

        interface_point_pair = np.zeros(
            (((nx - 1) * ny + nx * (ny - 1)) * N, 4), dtype=np.int32)

        n = 0

        P = 2 * p * (p + 1)
        Q = (p + 1)

        for i in range(nx - 1):
            for j in range(ny):
                s1 = j + i * ny
                s2 = j + (i + 1) * ny
                #            print(s1, s2)
                for m in range(N):
                    interface_point_pair[n, 0] = global_numbering[s1,
                                                                  N * p + m]
                    interface_point_pair[n, 1] = global_numbering[s2, m]

                    if j < ny - 1 and m == N - 1:
                        s3 = s2 + 1
                        interface_point_pair[n,
                                             0] = global_numbering_edges[s1,
                                                                         P +
                                                                         2 *
                                                                         Q - 1]
                        interface_point_pair[n, 1] = global_numbering_edges[s1,
                                                                            -1]
                        interface_point_pair[n,
                                             2] = global_numbering_edges[s2,
                                                                         P + Q]
                        interface_point_pair[n,
                                             3] = global_numbering_edges[s3,
                                                                         P +
                                                                         2 * Q]
                    n += 1
        for i in range(nx):
            for j in range(ny - 1):
                s1 = j + i * ny
                s2 = j + 1 + i * ny
                #            print(s1, s2)
                for m in range(N):
                    interface_point_pair[n,
                                         0] = global_numbering[s1,
                                                               (m + 1) * N - 1]
                    interface_point_pair[n, 1] = global_numbering[s2, m * N]
                    n += 1
        return interface_point_pair

    interface_point_pair = dof_map_crazy_lobatto_point_pair(
        mesh, px + 1, p0.function_space.dof_map.dof_map,
        ui.function_space.dof_map.dof_map)
    #    Lintface = np.zeros( shape = ( np.shape( interface_point_pair )[0], ui.function_space.num_dof+ uo.function_space.num_dof + p0.function_space.num_dof ) )
    Lintface = sparse.lil_matrix(
        (np.shape(interface_point_pair)[0], ui.function_space.num_dof +
         uo.function_space.num_dof + p0.function_space.num_dof))
    #Rintface = np.zeros( shape = ( np.shape( interface_point_pair )[0]-(nx-1)*(ny-1), 1) )
    Rintface = np.zeros(shape=(np.shape(interface_point_pair)[0], 1))
    for i in range(np.shape(interface_point_pair)[0]):
        if interface_point_pair[i, 2] != 0 and interface_point_pair[i, 3] != 0:
            Lintface[i, interface_point_pair[i, 0]] = 1
            Lintface[i, interface_point_pair[i, 1]] = 1
            Lintface[i, interface_point_pair[i, 2]] = -1
            Lintface[i, interface_point_pair[i, 3]] = -1
        else:
            Lintface[i, ui.function_space.num_dof + uo.function_space.num_dof +
                     interface_point_pair[i, 0]] = 1
            Lintface[i, ui.function_space.num_dof + uo.function_space.num_dof +
                     interface_point_pair[i, 1]] = -1

#    Lintface = sparse.csr_matrix(Lintface)
# %%
#Lintface=Lintface[~np.all(Lintface == 0, axis=1)]

    LHS = sparse.vstack((LHS1, LHS2, LHS3, Lintface, LBC))
    RHS = np.vstack((RHS1, RHS2, RHS3, Rintface, RBC))
    #rrefLHS = np.array(Matrix(LHS).rref()[0]).astype(None)
    #print(rrefLHS)
    print("----------------------------------------------------")
    print("LHS shape:", np.shape(LHS))

    print("------ solve the square sparse system:......")
    LHS = sparse.csr_matrix(LHS)
    Res = sparse.linalg.spsolve(LHS, RHS)
    #
    #    print("------ solve the singular square sparse system:......")
    #    solution = sparse.linalg.lsqr(LHS,RHS, atol=1e-20, btol=1e-20)
    #    Res = solution[0].reshape((np.size(solution[0]),1))
    #    residual = np.sum(np.abs(LHS.dot(Res) - RHS))
    #    print("------ least square solution error =",residual)

    #    print("++++++ solve the singular square full system:......")
    #    solution= np.linalg.lstsq(LHS,RHS)

    # %% eigen values and eigen vector
    #    w, v = sp.linalg.eig(LHS.todense())

    # %%
    ui.cochain = Res[0:ui.function_space.num_dof].reshape(
        ui.function_space.num_dof)
    uo.cochain = Res[ui.function_space.
                     num_dof:-p0.function_space.num_dof].reshape(
                         uo.function_space.num_dof)
    p0.cochain = Res[-p0.function_space.num_dof:].reshape(
        p0.function_space.num_dof)

    # %% view the result
    p0.reconstruct(xi, eta)
    (x, y), data = p0.export_to_plot()
    plt.contourf(x, y, data)
    plt.title('solution lobatto 0-form, p0')
    plt.colorbar()
    plt.show()
    print('p0 max:', np.max(data))
    print('p0 min:', np.min(data))

    uo.reconstruct(xi, eta)
    (x, y), data_dx, data_dy = uo.export_to_plot()
    plt.contourf(x, y, data_dx)
    plt.title('solution lobatto 1-form dx')
    plt.colorbar()
    plt.show()
    print('uo max:', np.max(data_dx))
    print('uo min:', np.min(data_dx))

    plt.contourf(x, y, data_dy)
    plt.title('solution lobatto 1-form dy')
    plt.colorbar()
    plt.show()
    print('uo max:', np.max(data_dy))
    print('uo min:', np.min(data_dy))
    #    #
    ui.reconstruct(xi, eta)
    (x, y), data_dx, data_dy = ui.export_to_plot()
    plt.contourf(x, y, data_dx)
    plt.title('solution extended_gauss 1-form dx')
    plt.colorbar()
    plt.show()
    print('ui max:', np.max(data_dx))
    print('ui min:', np.min(data_dx))

    plt.contourf(x, y, data_dy)
    plt.title('solution extended_gauss 1-form dy')
    plt.colorbar()
    plt.show()
    print('ui max:', np.max(data_dy))
    print('ui min:', np.min(data_dy))

    f2_exact.reconstruct(xi, eta)
    (x, y), data = f2_exact.export_to_plot()
    plt.contourf(x, y, data)
    plt.title('exact extended-gauss 2-form, f2')
    plt.colorbar()
    plt.show()

    # %% error
    L2_error_p0 = p0.l_2_norm(pfun, ('gauss', 10))[0]
    print("------ L2_error_psi0 =", L2_error_p0)

    L2_error_ui = ui.l_2_norm((ui_dx, ui_dy), ('gauss', 5))[0]
    print("------ L2_error_ui =", L2_error_ui)
    print("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n")
    # %% return
    return L2_error_p0, L2_error_ui
def solver(p,n,c):
    # %% define
    px = py = p
    nx = n
    ny = n
    mesh = CrazyMesh(2, (nx, ny), ((-1, 1), (-1, 1)), c)
    xi = eta = np.linspace(-1, 1, np.ceil(1000 / (nx * ny)) + 1)
    
    
    # %% exact p(0)
    func_space_gl0 = FunctionSpace(mesh, '0-lobatto', (px + 1, py + 1), is_inner=False)
#    p0_exact = Form(func_space_gl0)
#    p0_exact.discretize(pfun)
#    p0_exact.reconstruct(xi, eta)
#    (x, y), data = p0_exact.export_to_plot()
#    plt.contourf(x, y, data)
#    plt.title('exact lobatto 0-form, p0')
#    plt.colorbar()
#    plt.show()
    
    # %% p(0)
    func_space_gl0 = FunctionSpace(mesh, '0-lobatto', (px + 1, py + 1), is_inner=False)
    p0 = Form(func_space_gl0)
    
    # %%
    func_space_gl1 = FunctionSpace(mesh, '1-lobatto', (px + 1, py + 1), is_inner=False)
    uo = Form(func_space_gl1)
    
    # %%
    func_space_eg1 = FunctionSpace(mesh, '1-ext_gauss', (px, py))
    ui = Form(func_space_eg1)
    
    # %%
    func_space_eg2 = FunctionSpace(mesh, '2-ext_gauss', (px, py))
    f2 = Form(func_space_eg2)
    f2_exact = Form(func_space_eg2)
    f2_exact.discretize(ffun)
#    f2_exact.reconstruct(xi, eta)
#    (x, y), data = f2_exact.export_to_plot()
#    plt.contourf(x, y, data)
#    plt.title('exact extended-gauss 2-form, f2')
#    plt.colorbar()
#    plt.show()
    
    # %%
    E10 = d(func_space_gl0)
    E10_assembled = assemble(mesh, E10, uo.function_space.dof_map.dof_map,
                             p0.function_space.dof_map.dof_map, mode='replace')
    
    
    H = hodge(func_space_gl1)
    H_assembled   = assemble(mesh, H  , ui.function_space.dof_map.dof_map_internal, uo.function_space.dof_map.dof_map)
    #H_assembled   = np.linalg.inv(H_assembled)
    
    
    E21 = d(func_space_eg1)
    E21_assembled = assemble(mesh, E21, f2.function_space.dof_map.dof_map, ui.function_space.dof_map.dof_map, mode = 'replace')
    
    # %%
    #uo.cochain = E10_assembled.dot(p0_exact.cochain)
    #uo.reconstruct(xi, eta)
    #(x, y), data_dx, data_dy = uo.export_to_plot()
    #plt.contourf(x, y, data_dx)
    #plt.title('test lobatto outer 1-form dx')
    #plt.colorbar()
    #plt.show()
    #
    #plt.contourf(x, y, data_dy)
    #plt.title('test lobatto outer 1-form dy')
    #plt.colorbar()
    #plt.show()
    #
    #cochain_internal = H_assembled.dot(uo.cochain)
    #ui.cochain = np.concatenate((cochain_internal, np.zeros(ui.function_space.num_dof - ui.basis.num_basis * ui.mesh.num_elements )), axis=0)
    #ui.reconstruct(xi, eta)
    #(x, y), data_dx, data_dy = ui.export_to_plot()
    #plt.contourf(x, y, data_dx)
    #plt.title('test extended gauss inner 1-form dx')
    #plt.colorbar()
    #plt.show()
    #
    #plt.contourf(x, y, data_dy)
    #plt.title('test extended gauss inner 1-form dy')
    #plt.colorbar()
    #plt.show()
    # %%
    # system:
    #  |  I     H*E10   |   | ui |      | 0 |
    #  |                |   |    |  =   |   |
    #  | E21     0      |   | p  |      | f |
    ui_num_dof_internal = ui.basis.num_basis * ui.mesh.num_elements
    ui_num_dof_external = ui.function_space.num_dof - ui_num_dof_internal
    
    LHS1 = np.hstack((   np.eye(ui_num_dof_internal) , 
                         np.zeros((ui_num_dof_internal, ui_num_dof_external)),
                        -H_assembled.dot(E10_assembled)    ))
    
    LHS3 = np.hstack((  E21_assembled , 
                        np.zeros((f2.function_space.num_dof, p0.function_space.num_dof ))    ))

    
    RHS1 = np.zeros((ui_num_dof_internal, 1 ))
    RHS3 = f2_exact.cochain.reshape( (f2_exact.function_space.num_dof,1) )
    
    LHS3[-1,:]  = 0
    LHS3[-1,-1] = 1
    RHS3[-1,0]  = 0
    # %% boundary edges
    def UBC(mesh, s, p, position):
        def pullbackedfun_dx(xi, eta):
            x, y = mesh.mapping(xi, eta, s)
            return ufun_u(x, y)
    
        def pullbackedfun_dy(xi, eta):
            x, y = mesh.mapping(xi, eta, s)
            return ufun_v(x, y)
    
        def fun2bint_dxi(xi, eta):
            return pullbackedfun_dx(xi, eta) * mesh.dx_dxi(xi, eta, s)  + pullbackedfun_dy(xi, eta) * mesh.dy_dxi(xi, eta, s)
    
        def fun2bint_deta(xi, eta):
            return pullbackedfun_dx(xi, eta) * mesh.dx_deta(xi, eta, s) + pullbackedfun_dy(xi, eta) * mesh.dy_deta(xi, eta, s)
        
        UBC_s = np.zeros(shape = (p+1))
        extended_gauss_nodes, _ = extended_gauss_quad(p-1)
        if position == 'Left':
            for i in range(p+1):
    #            print("hello, Left world")
                def fun2bint_deta_BC(eta):
                    return fun2bint_deta(-1, eta)
                UBC_s[i] = quad(fun2bint_deta_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
        elif position == 'Right':
            for i in range(p+1):
    #            print("hello, Right world")
                def fun2bint_deta_BC(eta):
                    return fun2bint_deta(+1, eta)
                UBC_s[i] = quad(fun2bint_deta_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
        elif position == 'Bottom':
            for i in range(p+1):
    #            print("hello, Bottom world")
                def fun2bint_dxi_BC(xi):
                    return fun2bint_dxi(xi, -1)
                UBC_s[i] = quad(fun2bint_dxi_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
        elif position == 'Top':
            for i in range(p+1):
    #            print("hello, Top world")
                def fun2bint_dxi_BC(xi):
                    return fun2bint_dxi(xi, +1)
                UBC_s[i] = quad(fun2bint_dxi_BC, extended_gauss_nodes[i], extended_gauss_nodes[i+1] )[0]
        return UBC_s
    
    def extended_gauss1_general_boundary_edges(mesh, p, gathering_matrix):
        p+=1
        nx = mesh.n_x
        ny = mesh.n_y
    
        Left   = np.zeros( shape = (ny*(p+1)), dtype=np.int32 )
        Right  = np.zeros( shape = (ny*(p+1)), dtype=np.int32 )
        Bottom = np.zeros( shape = (nx*(p+1)), dtype=np.int32 )
        Top    = np.zeros( shape = (nx*(p+1)), dtype=np.int32 )
        
        M = 2 * p * (p+1)
        N = p+1
        
        UBC_L = UBC_R = UBC_B = UBC_T = 0
        
        for J in range(ny):
            eleidLeft  = J
            Left[  J*N : J*N + N ] = gathering_matrix[ eleidLeft , M +2*N : M +3*N ]
            UBC_s=UBC(mesh, eleidLeft, p, "Left")
            if UBC_L is 0:
                UBC_L= UBC_s
            else:
                UBC_L = np.hstack((UBC_L, UBC_s))
            
            eleidRight = (nx-1)*ny + J 
            Right[ J*N : J*N + N ] = gathering_matrix[ eleidRight, M +3*N : M +4*N ]
            UBC_s=UBC(mesh, eleidRight, p, "Right")
            if UBC_R is 0:
                UBC_R= UBC_s
            else:
                UBC_R = np.hstack((UBC_R, UBC_s))
    
        for I in range(nx):
    
            eleidBottom = I*ny
            Bottom[ I*N : I*N + N ] = gathering_matrix[ eleidBottom, M     : M +   N ]
            UBC_s=UBC(mesh, eleidBottom, p, "Bottom")
            if UBC_B is 0:
                UBC_B= UBC_s
            else:
                UBC_B = np.hstack((UBC_B, UBC_s))
            
            eleidTop = I*ny + ny -1
            Top[ I*N : I*N + N ]    = gathering_matrix[ eleidTop   , M + N : M + 2*N ] 
            UBC_s=UBC(mesh, eleidTop, p, "Top")
            if UBC_T is 0:
                UBC_T= UBC_s
            else:
                UBC_T = np.hstack((UBC_T, UBC_s))
    
        return np.vstack((Left, UBC_L)), np.vstack((Right, UBC_R)), np.vstack((Bottom, UBC_B)), np.vstack((Top, UBC_T))
    
    Left, Right, Bottom, Top = extended_gauss1_general_boundary_edges(mesh, px, ui.function_space.dof_map.dof_map)
    Boundaryedgs = np.hstack( (Left, Right, Bottom, Top) )
    
    LBC = np.zeros( shape = ( np.shape(Boundaryedgs)[1], ui.function_space.num_dof + p0.function_space.num_dof ) )
    RBC = np.zeros( shape = ( np.shape(Boundaryedgs)[1], 1) )
    for i in range(np.shape(Boundaryedgs)[1]):
        LBC[i, int(Boundaryedgs[0, i])] =1
        RBC[i] = Boundaryedgs[1, i]
    #ui.cochain = np.concatenate((cochain_internal, Bottom[1,:], Top[1,:], Left[1,:], Right[1,:]))
    #f2.cochain = E21_assembled.dot(ui.cochain)
    #f2.discretize(ffun)
    #f2.reconstruct(xi, eta)
    #(x, y), data = f2.export_to_plot()
    #plt.contourf(x, y, data)
    #plt.title('test extended-gauss 2-form, f2')
    #plt.colorbar()
    #plt.show()
    
    #size_Left = np.size( Left ) /2
    # %% 
    def dof_map_crazy_lobatto_point_pair(mesh, p, global_numbering):
        nx, ny = mesh.n_x, mesh.n_y
        
        N = p+1
        
        interface_point_pair = np.zeros( ( ( (nx - 1) * ny + nx * (ny - 1) ) * N, 2 ), dtype=np.int32 )
        
        n = 0
        
        for i in range(nx - 1):
            for j in range(ny):
                s1 = j + i * ny
                s2 = j + (i + 1) * ny
    #            print(s1, s2)
                for m in range(N):
                    interface_point_pair[n, 0] = global_numbering[s1, N * p + m]
                    interface_point_pair[n, 1] = global_numbering[s2,         m]
                    
    #                if j < ny-1 and m == N-1:
    #                    interface_point_pair[n, 0] = interface_point_pair[n, 1] = 0
                    n += 1
        for i in range(nx):
            for j in range(ny - 1):
                s1 = j + i * ny
                s2 = j + 1 + i * ny
    #            print(s1, s2)
                for m in range(N):
                    interface_point_pair[n, 0] = global_numbering[s1, (m+1)*N -1]
                    interface_point_pair[n, 1] = global_numbering[s2, m*N]
                    n += 1
        return interface_point_pair
    interface_point_pair = dof_map_crazy_lobatto_point_pair(mesh, px+1, p0.function_space.dof_map.dof_map)
    
    Lintface = np.zeros( shape = ( np.shape( interface_point_pair )[0], ui.function_space.num_dof + p0.function_space.num_dof ) ) 
    #Rintface = np.zeros( shape = ( np.shape( interface_point_pair )[0]-(nx-1)*(ny-1), 1) )
    Rintface = np.zeros( shape = ( np.shape( interface_point_pair )[0], 1) )
    for i in range( np.shape( interface_point_pair )[0] ):
        if interface_point_pair[i, 0] == interface_point_pair[i, 1] == 0:
            pass
        else:
            Lintface[i, ui.function_space.num_dof + interface_point_pair[i, 0]] =  1
            Lintface[i, ui.function_space.num_dof + interface_point_pair[i, 1]] = -1
    
    # %% 
    #Lintface=Lintface[~np.all(Lintface == 0, axis=1)]
    LHS = np.vstack( (LHS1, LHS3, Lintface, LBC) )
    RHS = np.vstack( (RHS1, RHS3, Rintface, RBC) )
    #rrefLHS = np.array(Matrix(LHS).rref()[0]).astype(None)
    #print(rrefLHS)
#    solution= np.linalg.lstsq(LHS,RHS)
    
    sLHS = sparse.csr_matrix(LHS)
    solution = sparse.linalg.lsqr(sLHS,RHS)

    Res = solution[0].reshape((np.size(solution[0]),1))
    residual = np.sum(np.abs(LHS.dot(Res) - RHS))
    print("residual=",residual)
    
    # %%
    ui.cochain = Res[0:ui.function_space.num_dof].reshape(ui.function_space.num_dof)
    p0.cochain = Res[-p0.function_space.num_dof:].reshape(p0.function_space.num_dof)
    
    # %% view the result
    p0.reconstruct(xi, eta)
    (x, y), data = p0.export_to_plot()
    plt.contourf(x, y, data)
    plt.title('solution lobatto 0-form, p0')
    plt.colorbar()
    plt.show()
    print('p0 max:', np.max(data))
    print('p0 min:', np.min(data))
#    #
    ui.reconstruct(xi, eta)
    (x, y), data_dx, data_dy = ui.export_to_plot()
    plt.contourf(x, y, data_dx)
    plt.title('solution extended_gauss 1-form dx')
    plt.colorbar()
    plt.show()
    print('ui max:', np.max(data_dx))
    print('ui min:', np.min(data_dx))
    
    plt.contourf(x, y, data_dy)
    plt.title('solution extended_gauss 1-form dy')
    plt.colorbar()
    plt.show()
    print('ui max:', np.max(data_dy))
    print('ui min:', np.min(data_dy))
    
    L2_error_p0 = p0.l_2_norm(pfun, ('gauss', 40))[0]
    print(L2_error_p0)
    
    L2_error_ui = ui.l_2_norm((ufun_u, ufun_v), ('lobatto', 40))[0]
    print(L2_error_ui)
    
    return L2_error_p0, L2_error_ui
Exemple #16
0
def single_element():
    mesh = CrazyMesh(2, (1, 1), ((-1, 1), (-1, 1)), curvature=0.1)
    p = 20, 20

    func_space_vort = FunctionSpace(mesh, '0-ext_gauss', (p[0] - 1, p[1] - 1), is_inner=False)
    func_space_outer_vel = FunctionSpace(
        mesh, '1-ext_gauss', (p[0] - 2, p[1] - 2), is_inner=False)
    func_space_inner_vel = FunctionSpace(mesh, '1-lobatto', p, is_inner=True)
    func_space_source = FunctionSpace(mesh, '2-lobatto', p, is_inner=True)

    basis_vort = BasisForm(func_space_vort)
    basis_vel_in = BasisForm(func_space_inner_vel)
    basis_vel_out = BasisForm(func_space_outer_vel)
    basis_2 = BasisForm(func_space_source)

    psi = Form(func_space_vort)
    u_in = Form(func_space_inner_vel)
    source = Form(func_space_source)
    source.discretize(ffun)

    M_1 = inner(basis_vel_in, basis_vel_in)
    W_11 = basis_vel_out.wedged(basis_vel_in)
    E_10_ext = d(func_space_vort)
    E_21_in = d(func_space_inner_vel)
    W_02 = basis_vort.wedged(basis_2)
    print("shapes : \n \
    M_1 : {0} \n \
    W_11 : {1} \n \
    E_10 : {2} \n \
    E_21_in : {3} \n \
    W_02 : {4} \n" .format(np.shape(M_1), np.shape(W_11), np.shape(E_10_ext), np.shape(E_21_in), np.shape(W_02)))
    # one element
    # print(func_space_inner_vel.num_dof, func_space_vort.num_dof)
    lhs_0 = np.hstack((M_1[:, :, 0], np.transpose(W_02 @ E_21_in)))
    col_size_0 = np.shape(lhs_0)[1]
    eW = W_02 @ E_21_in
    col_zeros = col_size_0 - np.shape(eW)[1]
    lhs_1 = np.hstack((eW, np.zeros(
        (func_space_source.num_dof, col_zeros))))
    lhs = np.vstack((lhs_0, lhs_1))

    rhs_source = (source.cochain @ W_02)[:, np.newaxis]
    rhs_zeros = np.zeros((np.shape(lhs)[0] - func_space_source.num_dof, 1))
    rhs = np.vstack((rhs_zeros, rhs_source))
    print(np.shape(lhs))
    solution = np.linalg.solve(lhs, rhs).flatten()
    print(np.shape(solution))
    print(func_space_vort.num_dof)
    u_in.cochain = solution[:func_space_inner_vel.num_dof]

    psi_zeros = np.zeros((func_space_vort.num_dof - func_space_vort.num_internal_local_dof))
    psi.cochain = np.append(solution[func_space_inner_vel.num_dof:],
                            np.zeros((func_space_vort.num_dof - func_space_vort.num_internal_local_dof)))
    xi = eta = np.linspace(-1, 1, 40)
    u_in.reconstruct(xi, eta)
    (x, y), u_x, u_y = u_in.export_to_plot()
    plt.contourf(x, y, u_x)
    plt.colorbar()
    plt.title("u_x inner")
    plt.show()
    psi.reconstruct(xi, eta)
    (x, y), psi_value = psi.export_to_plot()
    plt.contourf(x, y, psi_value)
    plt.title("psi outer"
              )
    plt.colorbar()
    plt.show()
# # solution = sparse.linalg.spsolve(lhs, rhs)
# # phi_2.cochain = solution[-func_space_2_lobatto.num_dof:]
# #
# # # sample the solution
# # xi = eta = np.linspace(-1, 1, 200)
# # phi_2.reconstruct(xi, eta)
# # (x, y), data = phi_2.export_to_plot()
# # plt.contourf(x, y, data)
# # plt.show()
#
#
# # solve for unknowns


M_1k = inner(basis_1, basis_1, anisotropic_tensor)
N_2 = inner(basis_2, d(basis_1))
M_2 = inner(basis_2, basis_2)
# assemble inner products
M_1k = assemble(M_1k, func_space_1_lobatto)
N_2 = assemble(N_2, (func_space_2_lobatto, func_space_1_lobatto))
M_2 = assemble(M_2, func_space_2_lobatto)

lhs = sparse.bmat([[M_1k, N_2.transpose()], [N_2, None]]).tolil()
rhs_source = (form_source.cochain @ M_2)[:, np.newaxis]
rhs_zeros = np.zeros(lhs.shape[0] - np.size(rhs_source))[:, np.newaxis]
rhs = np.vstack((rhs_zeros, rhs_source))
# print(func_space_1_lobatto.dof_map.dof_map_boundary)
bottom, top, left, right = func_space_1_lobatto.dof_map.dof_map_boundary
# flux = 0
lhs[bottom] = 0
lhs[bottom, bottom] = 1
#H11_assembled = -assemble(H11, ui.function_space,uo.function_space)

#ui_num_dof_internal = ui.basis.num_basis * ui.mesh.num_elements
p0_num_dof_internal = p0.basis.num_basis * ui.mesh.num_elements
# %% LHS 11
Mnm1 = inner(uo.basis, uo.basis)
Mnm1_assembled = assemble(Mnm1, uo.function_space, uo.function_space)

# %% LHS 21
W0n = f2.basis.wedged(p0.basis)
W0n_assembled = assemble_(mesh,
                          W0n,
                          p0.function_space.dof_map.dof_map_internal,
                          f2.function_space.dof_map.dof_map,
                          mode='add')
E21 = d(func_space_gl1)

#E21_assembled = assemble_(mesh, E21, f2.function_space.dof_map.dof_map,
#                          uo.function_space.dof_map.dof_map, mode='replace')

LHS21_local = W0n.dot(E21)
LHS12_local = LHS21_local.T

LHS12_add = sparse.lil_matrix((np.shape(LHS21_local)[1], (px + 1) * 4))
Wb = integral1d_(1, ('lobatto_edge', px + 1), ('gauss_node', px + 1),
                 ('gauss', px + 5))
P = (p + 1) * (p + 2)
Q = (p + 1)**2
M = p + 1
for i in range(p + 1):
    for j in range(p + 1):
def multiple_element_v1():
    mesh = CrazyMesh(2, (1, 1), ((-1, 1), (-1, 1)), curvature=0.0)
    p = 4, 4
    func_space_vort = FunctionSpace(mesh, '0-lobatto', p, is_inner=False)
    func_space_outer_vel = FunctionSpace(
        mesh, '1-lobatto', p, is_inner=False)
    func_space_outer_vel.dof_map.continous_dof = True
    # func_space_outer_vel = FunctionSpace(
    #     mesh, '1-gauss', (p[0], p[1]), is_inner=False)
    func_space_inner_vel = FunctionSpace(
        mesh, '1-gauss', (p[0], p[1]), is_inner=True)
    print('dof gauss :', func_space_inner_vel.num_dof)
    func_space_inner_vel.dof_map.continous_dof = False
    func_space_source = FunctionSpace(mesh, '2-gauss', (p[0] + 1, p[1] + 1), is_inner=True)
    print("dof source :", func_space_source.num_dof)

    basis_vort = BasisForm(func_space_vort)
    basis_vel_in = BasisForm(func_space_inner_vel)
    basis_vel_in.quad_grid = 'lobatto'
    basis_vel_out = BasisForm(func_space_outer_vel)
    basis_vel_out.quad_grid = 'lobatto'
    basis_2 = BasisForm(func_space_source)

    psi = Form(func_space_vort)
    u_in = Form(func_space_inner_vel)
    source = Form(func_space_source)
    source.discretize(ffun)

    M_1 = inner(basis_vel_in, basis_vel_in)
    # E_21_in = d(func_space_inner_vel)
    W_02 = basis_2.wedged(basis_vort)
    W_11 = basis_vel_in.wedged(basis_vel_out)
    E_10_out = d(func_space_vort)
    print(np.shape(W_11), np.shape(E_10_out))
    W_E = W_11 @ E_10_out
    W_11_inv = basis_vel_out.wedged(basis_vel_in)
    E_W = np.transpose(E_10_out) @ W_11_inv
    print("shape ew : ", np.shape(W_E))
    print(np.shape(W_02))

    M_1 = assemble(M_1, (func_space_inner_vel, func_space_inner_vel))
    print(func_space_source.num_local_dof)
    W_E = assemble(W_E, (func_space_outer_vel, func_space_vort))
    E_W = assemble(E_W, (func_space_vort, func_space_outer_vel))
    W_02 = assemble(W_02, (func_space_vort, func_space_source))

    lhs = spr.bmat([[M_1, W_E], [W_E.transpose(), None]])
    rhs = np.zeros(np.shape(lhs)[0])
    rhs[-func_space_source.num_dof:] = W_02 @ source.cochain

    solution = spr.linalg.spsolve(lhs.tocsc(), rhs)
    u_in.cochain = solution[:func_space_inner_vel.num_dof]
    psi.cochain = solution[-func_space_vort.num_dof:]

    xi = eta = np.linspace(-1, 1, 40)
    u_in.reconstruct(xi, eta)
    (x, y), u_x, u_y = u_in.export_to_plot()
    plt.contourf(x, y, u_x)
    plt.colorbar()
    plt.title("u_x inner")
    plt.show()
    psi.reconstruct(xi, eta)
    (x, y), psi_value = psi.export_to_plot()
    plt.contourf(x, y, psi_value)
    plt.title("psi outer")
    plt.colorbar()
    plt.show()