Exemple #1
0
    def getError(self):
        #Test function
        phi = lambda x: np.cos(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1])
        j_funX = lambda x: -np.pi * np.sin(np.pi * x[:, 0]) * np.cos(np.pi *
                                                                     x[:, 1])
        j_funY = lambda x: -np.pi * np.cos(np.pi * x[:, 0]) * np.sin(np.pi *
                                                                     x[:, 1])
        q_fun = lambda x: -2 * (np.pi**2) * phi(x)

        xc_ana = phi(self.M.gridCC)
        q_ana = q_fun(self.M.gridCC)
        jX_ana = j_funX(self.M.gridFx)
        jY_ana = j_funY(self.M.gridFy)
        j_ana = np.r_[jX_ana, jY_ana]

        #TODO: Check where our boundary conditions are CCx or Nx
        # fxm,fxp,fym,fyp = self.M.faceBoundaryInd
        # gBFx = self.M.gridFx[(fxm|fxp),:]
        # gBFy = self.M.gridFy[(fym|fyp),:]
        fxm, fxp, fym, fyp = self.M.cellBoundaryInd
        gBFx = self.M.gridCC[(fxm | fxp), :]
        gBFy = self.M.gridCC[(fym | fyp), :]

        bc = phi(np.r_[gBFx, gBFy])

        # P = sp.csr_matrix(([-1,1],([0,self.M.nF-1],[0,1])), shape=(self.M.nF, 2))

        P, Pin, Pout = self.M.getBCProjWF('dirichlet')

        Mc = self.M.getFaceInnerProduct()
        McI = utils.sdInv(self.M.getFaceInnerProduct())
        G = -self.M.faceDiv.T * utils.sdiag(self.M.vol)
        D = self.M.faceDiv
        j = McI * (G * xc_ana + P * bc)
        q = D * j

        # self.M.plotImage(j, 'FxFy', show_it=True)

        # Rearrange if we know q to solve for x
        A = D * McI * G
        rhs = q_ana - D * McI * P * bc

        if self.myTest == 'j':
            err = np.linalg.norm((j - j_ana), np.inf)
        elif self.myTest == 'q':
            err = np.linalg.norm((q - q_ana), np.inf)
        elif self.myTest == 'xc':
            xc = Solver(A) * (rhs)
            err = np.linalg.norm((xc - xc_ana), np.inf)
        elif self.myTest == 'xcJ':
            xc = Solver(A) * (rhs)
            j = McI * (G * xc + P * bc)
            err = np.linalg.norm((j - j_ana), np.inf)

        return err
Exemple #2
0
    def getError(self):
        # Test function
        phi = lambda x: np.cos(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1])
        j_funX = lambda x: -np.pi * np.sin(np.pi * x[:, 0]) * np.cos(np.pi *
                                                                     x[:, 1])
        j_funY = lambda x: -np.pi * np.cos(np.pi * x[:, 0]) * np.sin(np.pi *
                                                                     x[:, 1])
        q_fun = lambda x: -2 * (np.pi**2) * phi(x)

        mesh = self.M
        phi_ana = phi(mesh.cell_centers)
        q_ana = q_fun(mesh.cell_centers)

        phi_bc = phi(mesh.boundary_faces)

        MfI = mesh.get_face_inner_product(invert_matrix=True)
        M_bf = mesh.boundary_face_scalar_integral

        V = utils.sdiag(mesh.cell_volumes)
        G = -mesh.face_divergence.T * V
        D = mesh.face_divergence

        # Sinc the xc_bc is a known, move it to the RHS!
        A = V @ D @ MfI @ G
        rhs = V @ q_ana - V @ D @ MfI @ M_bf @ phi_bc

        phi_test = Solver(A) * rhs
        if self._meshType == "rotateCurv":
            err = np.linalg.norm(mesh.cell_volumes * (phi_test - phi_ana))
        else:
            err = np.linalg.norm(phi_test - phi_ana) / np.sqrt(mesh.n_cells)

        return err
Exemple #3
0
    def getError(self):
        # Test function
        def phi_fun(x):
            return np.cos(np.pi * x)

        def j_fun(x):
            return np.pi * np.sin(np.pi * x)

        def phi_deriv(x):
            return -j_fun(x)

        def q_fun(x):
            return (np.pi**2) * np.cos(np.pi * x)

        xc_ana = phi_fun(self.M.gridCC)
        q_ana = q_fun(self.M.gridCC)
        j_ana = j_fun(self.M.gridFx)

        # Get boundary locations
        vecN = self.M.vectorNx
        vecC = self.M.vectorCCx

        # Setup Mixed B.C (alpha, beta, gamma)
        alpha_xm, alpha_xp = 1., 1.
        beta_xm, beta_xp = 1., 1.
        alpha = np.r_[alpha_xm, alpha_xp]
        beta = np.r_[beta_xm, beta_xp]
        vecN = self.M.vectorNx
        vecC = self.M.vectorCCx
        phi_bc = phi_fun(vecN[[0, -1]])
        phi_deriv_bc = phi_deriv(vecN[[0, -1]])
        gamma = alpha * phi_bc + beta * phi_deriv_bc
        x_BC, y_BC = getxBCyBC_CC(self.M, alpha, beta, gamma)

        sigma = np.ones(self.M.nC)
        Mfrho = self.M.getFaceInnerProduct(1. / sigma)
        MfrhoI = self.M.getFaceInnerProduct(1. / sigma, invMat=True)
        V = discretize.utils.sdiag(self.M.vol)
        Div = V * self.M.faceDiv
        P_BC, B = self.M.getBCProjWF_simple()
        q = q_fun(self.M.gridCC)
        M = B * self.M.aveCC2F
        G = Div.T - P_BC * discretize.utils.sdiag(y_BC) * M
        # Mrhoj = D.T V phi + P_BC*discretize.utils.sdiag(y_BC)*M phi - P_BC*x_BC
        rhs = V * q + Div * MfrhoI * P_BC * x_BC
        A = Div * MfrhoI * G

        if self.myTest == 'xc':
            # TODO: fix the null space
            Ainv = Solver(A)
            xc = Ainv * rhs
            err = np.linalg.norm((xc - xc_ana), np.inf)
        else:
            NotImplementedError
        return err
Exemple #4
0
    def getError(self):
        # Test function
        phi = lambda x: np.sin(np.pi * x[:, 0]) * np.sin(np.pi * x[:, 1])
        j_funX = lambda x: np.pi * np.cos(np.pi * x[:, 0]) * np.sin(np.pi *
                                                                    x[:, 1])
        j_funY = lambda x: np.pi * np.sin(np.pi * x[:, 0]) * np.cos(np.pi *
                                                                    x[:, 1])
        q_fun = lambda x: -2 * (np.pi**2) * phi(x)

        mesh = self.M
        phi_ana = phi(mesh.cell_centers)
        q_ana = q_fun(mesh.cell_centers)

        phi_bc = phi(mesh.boundary_faces)
        jx_bc = j_funX(mesh.boundary_faces)
        jy_bc = j_funY(mesh.boundary_faces)
        j_bc = np.c_[jx_bc, jy_bc]

        j_bc_dot_n = np.sum(j_bc * mesh.boundary_face_outward_normals, axis=-1)

        MfI = mesh.get_face_inner_product(invert_matrix=True)

        V = utils.sdiag(mesh.cell_volumes)
        G = mesh.face_divergence.T * V
        D = mesh.face_divergence

        # construct matrix with robin operator
        # get indices of x0 boundary and y0 boundary
        n_bounary_faces = len(j_bc_dot_n)
        dirichlet_locs = np.any(mesh.boundary_faces == 0.0, axis=1)

        alpha = np.zeros(n_bounary_faces)
        alpha[dirichlet_locs] = 1.0

        beta = np.zeros(n_bounary_faces)
        beta[~dirichlet_locs] = 1.0

        gamma = alpha * phi_bc + beta * j_bc_dot_n

        B_bc, b_bc = mesh.cell_gradient_weak_form_robin(alpha=alpha,
                                                        beta=beta,
                                                        gamma=gamma)

        A = V @ D @ MfI @ (-G + B_bc)
        rhs = V @ q_ana - V @ D @ MfI @ b_bc

        phi_test = Solver(A) * rhs

        if self._meshType == "rotateCurv":
            err = np.linalg.norm(mesh.cell_volumes * (phi_test - phi_ana))
        else:
            err = np.linalg.norm((phi_test - phi_ana)) / np.sqrt(mesh.n_cells)

        return err
Exemple #5
0
    def getError(self):
        # Test function
        phi = lambda x: np.cos(0.5 * np.pi * x)
        j_fun = lambda x: -0.5 * np.pi * np.sin(0.5 * np.pi * x)
        q_fun = lambda x: -0.25 * (np.pi**2) * np.cos(0.5 * np.pi * x)

        mesh = self.M
        xc_ana = phi(mesh.cell_centers)
        q_ana = q_fun(mesh.cell_centers)
        j_ana = j_fun(mesh.faces_x)

        phi_bc = phi(mesh.boundary_faces)
        j_bc = j_fun(mesh.boundary_faces)

        MfI = mesh.get_face_inner_product(invert_matrix=True)

        V = utils.sdiag(mesh.cell_volumes)
        G = mesh.face_divergence.T * V
        D = mesh.face_divergence

        # construct matrix with robin operator
        alpha = np.r_[1.0, 0.0]
        beta = np.r_[0.0, 1.0]
        gamma = alpha * phi_bc + beta * j_bc * mesh.boundary_face_outward_normals
        B_bc, b_bc = mesh.cell_gradient_weak_form_robin(alpha=alpha,
                                                        beta=beta,
                                                        gamma=gamma)

        A = V @ D @ MfI @ (-G + B_bc)
        rhs = V @ q_ana - V @ D @ MfI @ b_bc

        if self.myTest == "xc":
            xc = Solver(A) * rhs
            err = np.linalg.norm(xc - xc_ana) / np.sqrt(mesh.n_cells)
        elif self.myTest == "xcJ":
            xc = Solver(A) * rhs
            j = MfI @ ((-G + B_bc) @ xc + b_bc)
            err = np.linalg.norm(j - j_ana, np.inf)
        return err
Exemple #6
0
    def getError(self):
        #Test function
        phi = lambda x: np.cos(np.pi * x)
        j_fun = lambda x: -np.pi * np.sin(np.pi * x)
        q_fun = lambda x: -(np.pi**2) * np.cos(np.pi * x)

        xc_ana = phi(self.M.gridCC)
        q_ana = q_fun(self.M.gridCC)
        j_ana = j_fun(self.M.gridFx)

        #TODO: Check where our boundary conditions are CCx or Nx
        # vec = self.M.vectorNx
        vec = self.M.vectorCCx

        phi_bc = phi(vec[[0, -1]])
        j_bc = j_fun(vec[[0, -1]])

        P, Pin, Pout = self.M.getBCProjWF([['dirichlet', 'dirichlet']])

        Mc = self.M.getFaceInnerProduct()
        McI = utils.sdInv(self.M.getFaceInnerProduct())
        V = utils.sdiag(self.M.vol)
        G = -Pin.T * Pin * self.M.faceDiv.T * V
        D = self.M.faceDiv
        j = McI * (G * xc_ana + P * phi_bc)
        q = V * D * Pin.T * Pin * j + V * D * Pout.T * j_bc

        # Rearrange if we know q to solve for x
        A = V * D * Pin.T * Pin * McI * G
        rhs = V * q_ana - V * D * Pin.T * Pin * McI * P * phi_bc - V * D * Pout.T * j_bc
        # A = D*McI*G
        # rhs = q_ana - D*McI*P*phi_bc

        if self.myTest == 'j':
            err = np.linalg.norm((j - j_ana), np.inf)
        elif self.myTest == 'q':
            err = np.linalg.norm((q - V * q_ana), np.inf)
        elif self.myTest == 'xc':
            #TODO: fix the null space
            solver = SolverCG(A, maxiter=1000)
            xc = solver * (rhs)
            print('ACCURACY', np.linalg.norm(utils.mkvc(A * xc) - rhs))
            err = np.linalg.norm((xc - xc_ana), np.inf)
        elif self.myTest == 'xcJ':
            #TODO: fix the null space
            xc = Solver(A) * (rhs)
            print(np.linalg.norm(utils.mkvc(A * xc) - rhs))
            j = McI * (G * xc + P * phi_bc)
            err = np.linalg.norm((j - j_ana), np.inf)

        return err
Exemple #7
0
    def getError(self):
        # Test function
        phi = lambda x: np.sin(np.pi * x)
        j_fun = lambda x: np.pi * np.cos(np.pi * x)
        q_fun = lambda x: -1 * (np.pi**2) * phi(x)

        mesh = self.M
        mesh.origin = [
            -0.25,
        ]

        phi_ana = phi(mesh.nodes)
        j_ana = j_fun(mesh.edges_x)
        q_ana = q_fun(mesh.nodes)

        phi_bc = phi(mesh.boundary_nodes)
        j_bc = j_fun(mesh.boundary_nodes)

        # construct matrix with robin operator
        beta = 1.0
        if self.boundary_type == "Robin":
            alpha = 1.0
        elif self.boundary_type == "Mixed":
            alpha = np.r_[1.0, 0.0]
        else:
            alpha = 0.0

        gamma = alpha * phi_bc + beta * j_bc * mesh.boundary_face_outward_normals

        Me = mesh.get_edge_inner_product()
        Mn = sp.diags(mesh.average_node_to_cell.T @ mesh.cell_volumes)
        G = mesh.nodal_gradient

        B_bc, b_bc = mesh.edge_divergence_weak_form_robin(alpha, beta, gamma)

        A = -G.T @ Me @ G + B_bc
        rhs = Mn @ q_ana - b_bc

        if self.boundary_type == "Nuemann":
            A[0, :] = 0.0
            A[0, 0] = 1.0
            rhs[0] = phi_ana[0]

        phi_test = Solver(A) * rhs

        err = np.linalg.norm(phi_test - phi_ana, np.inf)

        return err
Exemple #8
0
    def getError(self):
        # Create some functions to integrate
        fun = lambda x: np.sin(2*np.pi*x[:, 0])*np.sin(2*np.pi*x[:, 1])*np.sin(2*np.pi*x[:, 2])
        sol = lambda x: -3.*((2*np.pi)**2)*fun(x)

        self.M.setCellGradBC('dirichlet')

        D = self.M.faceDiv
        G = self.M.cellGrad
        if self.forward:
            sA = sol(self.M.gridCC)
            sN = D*G*fun(self.M.gridCC)
            err = np.linalg.norm((sA - sN), np.inf)
        else:
            fA = fun(self.M.gridCC)
            fN = Solver(D*G) * (sol(self.M.gridCC))
            err = np.linalg.norm((fA - fN), np.inf)
        return err
Exemple #9
0
    def getError(self):
        # Test function
        phi = lambda x: np.sin(np.pi * x[:, 0]) * np.sin(np.pi * x[:, 1])
        j_funX = lambda x: np.pi * np.cos(np.pi * x[:, 0]) * np.sin(np.pi *
                                                                    x[:, 1])
        j_funY = lambda x: np.pi * np.cos(np.pi * x[:, 1]) * np.sin(np.pi *
                                                                    x[:, 0])
        q_fun = lambda x: -2 * (np.pi**2) * phi(x)

        mesh = self.M
        if self._meshType == "rotateCurv":
            nodes_x, nodes_y = mesh.node_list
            nodes_x -= 0.25
            nodes_y -= 0.25
            mesh = discretize.CurvilinearMesh([nodes_x, nodes_y])
        else:
            mesh.origin = np.r_[-0.25, -0.25]

        phi_ana = phi(mesh.nodes)
        q_ana = q_fun(mesh.nodes)

        if self.boundary_type == "Nuemann":
            # Nuemann with J defined at boundary nodes
            jx_bc = j_funX(mesh.boundary_nodes)
            jy_bc = j_funY(mesh.boundary_nodes)
            j_bc = np.c_[jx_bc, jy_bc]

            M_bn = mesh.boundary_node_vector_integral

            B_bc = sp.csr_matrix((mesh.n_nodes, mesh.n_nodes))
            b_bc = M_bn @ (j_bc.reshape(-1, order='F'))
        else:
            phi_bc = phi(mesh.boundary_faces)
            jx_bc = j_funX(mesh.boundary_faces)
            jy_bc = j_funY(mesh.boundary_faces)
            j_bc = np.c_[jx_bc, jy_bc]

            j_bc_dot_n = np.sum(j_bc * mesh.boundary_face_outward_normals,
                                axis=-1)

            # construct matrix with robin operator
            if self.boundary_type == "Robin":
                alpha = 1.0
            else:
                # get indices of x0 boundary and y0 boundary
                n_boundary_faces = len(j_bc_dot_n)
                robin_locs = np.any(mesh.boundary_faces == -0.25, axis=1)

                alpha = np.zeros(n_boundary_faces)
                alpha[robin_locs] = 1.0

            beta = 1.0
            gamma = alpha * phi_bc + beta * j_bc_dot_n

            B_bc, b_bc = mesh.edge_divergence_weak_form_robin(
                alpha, beta, gamma)

        Me = mesh.get_edge_inner_product()
        Mn = sp.diags(mesh.average_node_to_cell.T @ mesh.cell_volumes)
        G = mesh.nodal_gradient

        A = -G.T @ Me @ G + B_bc
        rhs = Mn @ q_ana - b_bc

        if self.boundary_type == "Nuemann":
            A[0, :] = 0.0
            A[0, 0] = 1.0
            rhs[0] = phi_ana[0]

        phi_test = Solver(A) * rhs

        err = np.linalg.norm(phi_test - phi_ana, np.inf)
        return err
Exemple #10
0
def run(plotIt=True, n=60):

    np.random.seed(5)

    # Here we are going to rearrange the equations:

    # (phi_ - phi)/dt = A*(d2fdphi2*(phi_ - phi) + dfdphi - L*phi_)
    # (phi_ - phi)/dt = A*(d2fdphi2*phi_ - d2fdphi2*phi + dfdphi - L*phi_)
    # (phi_ - phi)/dt = A*d2fdphi2*phi_ + A*( - d2fdphi2*phi + dfdphi - L*phi_)
    # phi_ - phi = dt*A*d2fdphi2*phi_ + dt*A*(- d2fdphi2*phi + dfdphi - L*phi_)
    # phi_ - dt*A*d2fdphi2 * phi_ =  dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi
    # (I - dt*A*d2fdphi2) * phi_ =  dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi
    # (I - dt*A*d2fdphi2) * phi_ =  dt*A*dfdphi - dt*A*d2fdphi2*phi - dt*A*L*phi_ + phi
    # (dt*A*d2fdphi2 - I) * phi_ =  dt*A*d2fdphi2*phi + dt*A*L*phi_ - phi - dt*A*dfdphi
    # (dt*A*d2fdphi2 - I - dt*A*L) * phi_ =  (dt*A*d2fdphi2 - I)*phi - dt*A*dfdphi

    h = [(0.25, n)]
    M = discretize.TensorMesh([h, h])

    # Constants
    D = a = epsilon = 1.
    I = discretize.utils.speye(M.nC)

    # Operators
    A = D * M.faceDiv * M.cellGrad
    L = epsilon**2 * M.faceDiv * M.cellGrad

    duration = 75
    elapsed = 0.
    dexp = -5
    phi = np.random.normal(loc=0.5, scale=0.01, size=M.nC)
    ii, jj = 0, 0
    PHIS = []
    capture = np.logspace(-1, np.log10(duration), 8)
    while elapsed < duration:
        dt = min(100, np.exp(dexp))
        elapsed += dt
        dexp += 0.05

        dfdphi = a**2 * 2 * phi * (1 - phi) * (1 - 2 * phi)
        d2fdphi2 = discretize.utils.sdiag(a**2 * 2 * (1 - 6 * phi * (1 - phi)))

        MAT = (dt * A * d2fdphi2 - I - dt * A * L)
        rhs = (dt * A * d2fdphi2 - I) * phi - dt * A * dfdphi
        phi = Solver(MAT) * rhs

        if elapsed > capture[jj]:
            PHIS += [(elapsed, phi.copy())]
            jj += 1
        if ii % 10 == 0:
            print(ii, elapsed)
        ii += 1

    if plotIt:
        fig, axes = plt.subplots(2, 4, figsize=(14, 6))
        axes = np.array(axes).flatten().tolist()
        for ii, ax in zip(np.linspace(0, len(PHIS) - 1, len(axes)), axes):
            ii = int(ii)
            M.plotImage(PHIS[ii][1], ax=ax)
            ax.axis('off')
            ax.set_title('Elapsed Time: {0:4.1f}'.format(PHIS[ii][0]))
Exemple #11
0
    def getError(self):
        # Test function
        def phi_fun(x):
            return (np.cos(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1]) *
                    np.cos(np.pi * x[:, 2]))

        def j_funX(x):
            return (np.pi * np.sin(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1]) *
                    np.cos(np.pi * x[:, 2]))

        def j_funY(x):
            return (np.pi * np.cos(np.pi * x[:, 0]) * np.sin(np.pi * x[:, 1]) *
                    np.cos(np.pi * x[:, 2]))

        def j_funZ(x):
            return (np.pi * np.cos(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1]) *
                    np.sin(np.pi * x[:, 2]))

        def phideriv_funX(x):
            return -j_funX(x)

        def phideriv_funY(x):
            return -j_funY(x)

        def phideriv_funZ(x):
            return -j_funZ(x)

        def q_fun(x):
            return 3 * (np.pi**2) * phi_fun(x)

        xc_ana = phi_fun(self.M.gridCC)
        q_ana = q_fun(self.M.gridCC)
        jX_ana = j_funX(self.M.gridFx)
        jY_ana = j_funY(self.M.gridFy)
        j_ana = np.r_[jX_ana, jY_ana, jY_ana]

        # Get boundary locations
        fxm, fxp, fym, fyp, fzm, fzp = self.M.faceBoundaryInd
        gBFxm = self.M.gridFx[fxm, :]
        gBFxp = self.M.gridFx[fxp, :]
        gBFym = self.M.gridFy[fym, :]
        gBFyp = self.M.gridFy[fyp, :]
        gBFzm = self.M.gridFz[fzm, :]
        gBFzp = self.M.gridFz[fzp, :]

        # Setup Mixed B.C (alpha, beta, gamma)
        alpha_xm = np.ones_like(gBFxm[:, 0])
        alpha_xp = np.ones_like(gBFxp[:, 0])
        beta_xm = np.ones_like(gBFxm[:, 0])
        beta_xp = np.ones_like(gBFxp[:, 0])
        alpha_ym = np.ones_like(gBFym[:, 1])
        alpha_yp = np.ones_like(gBFyp[:, 1])
        beta_ym = np.ones_like(gBFym[:, 1])
        beta_yp = np.ones_like(gBFyp[:, 1])
        alpha_zm = np.ones_like(gBFzm[:, 2])
        alpha_zp = np.ones_like(gBFzp[:, 2])
        beta_zm = np.ones_like(gBFzm[:, 2])
        beta_zp = np.ones_like(gBFzp[:, 2])

        phi_bc_xm, phi_bc_xp = phi_fun(gBFxm), phi_fun(gBFxp)
        phi_bc_ym, phi_bc_yp = phi_fun(gBFym), phi_fun(gBFyp)
        phi_bc_zm, phi_bc_zp = phi_fun(gBFzm), phi_fun(gBFzp)

        phiderivX_bc_xm = phideriv_funX(gBFxm)
        phiderivX_bc_xp = phideriv_funX(gBFxp)
        phiderivY_bc_ym = phideriv_funY(gBFym)
        phiderivY_bc_yp = phideriv_funY(gBFyp)
        phiderivY_bc_zm = phideriv_funZ(gBFzm)
        phiderivY_bc_zp = phideriv_funZ(gBFzp)

        def gamma_fun(alpha, beta, phi, phi_deriv):
            return alpha * phi + beta * phi_deriv

        gamma_xm = gamma_fun(alpha_xm, beta_xm, phi_bc_xm, phiderivX_bc_xm)
        gamma_xp = gamma_fun(alpha_xp, beta_xp, phi_bc_xp, phiderivX_bc_xp)
        gamma_ym = gamma_fun(alpha_ym, beta_ym, phi_bc_ym, phiderivY_bc_ym)
        gamma_yp = gamma_fun(alpha_yp, beta_yp, phi_bc_yp, phiderivY_bc_yp)
        gamma_zm = gamma_fun(alpha_zm, beta_zm, phi_bc_zm, phiderivY_bc_zm)
        gamma_zp = gamma_fun(alpha_zp, beta_zp, phi_bc_zp, phiderivY_bc_zp)

        alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
        beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
        gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]

        x_BC, y_BC = getxBCyBC_CC(self.M, alpha, beta, gamma)

        sigma = np.ones(self.M.nC)
        Mfrho = self.M.getFaceInnerProduct(1. / sigma)
        MfrhoI = self.M.getFaceInnerProduct(1. / sigma, invMat=True)
        V = discretize.utils.sdiag(self.M.vol)
        Div = V * self.M.faceDiv
        P_BC, B = self.M.getBCProjWF_simple()
        q = q_fun(self.M.gridCC)
        M = B * self.M.aveCC2F
        G = Div.T - P_BC * discretize.utils.sdiag(y_BC) * M
        rhs = V * q + Div * MfrhoI * P_BC * x_BC
        A = Div * MfrhoI * G

        if self.myTest == 'xc':
            # TODO: fix the null space
            Ainv = Solver(A)
            xc = Ainv * rhs
            err = np.linalg.norm((xc - xc_ana), np.inf)
        else:
            NotImplementedError
        return err