コード例 #1
0
ファイル: test_upwind.py プロジェクト: jontateixeira/porepy
    def test_upwind_2d_simplex_surf_discharge_negative(self):
        g = simplex.StructuredTriangleGrid([2, 1], [1, 1])
        R = cg.rot(-np.pi / 5., [1, 1, -1])
        g.nodes = np.dot(R, g.nodes)
        g.compute_geometry(is_embedded=True)

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, np.dot(R, [-1, 0, 0]))

        bf = g.tags['domain_boundary_faces'].nonzero()[0]
        bc = BoundaryCondition(g, bf, bf.size * ['neu'])
        param.set_bc(solver, bc)

        data = {'param': param, 'discharge': dis}
        M = solver.matrix_rhs(g, data)[0].todense()
        deltaT = solver.cfl(g, data)

        M_known = np.array([[1, 0, 0, -1],
                            [-1, 0, 0, 0],
                            [0, 0, 1, 0],
                            [0, 0, -1, 1]])
        deltaT_known = 1 / 6

        rtol = 1e-15
        atol = rtol
        assert np.allclose(M, M_known, rtol, atol)
        assert np.allclose(deltaT, deltaT_known, rtol, atol)
コード例 #2
0
ファイル: test_upwind.py プロジェクト: jontateixeira/porepy
    def test_upwind_1d_discharge_negative_bc_neu(self):
        g = structured.CartGrid(3, 1)
        g.compute_geometry()

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, [-2, 0, 0])

        bf = g.tags['domain_boundary_faces'].nonzero()[0]
        bc = BoundaryCondition(g, bf, bf.size * ['neu'])
        bc_val = np.array([2, 0, 0, -2]).ravel('F')
        param.set_bc(solver, bc)
        param.set_bc_val(solver, bc_val)

        data = {'param': param, 'discharge': dis}
        M, rhs = solver.matrix_rhs(g, data)
        deltaT = solver.cfl(g, data)

        M_known = np.array([[0, -2, 0],
                            [0, 2, -2],
                            [0, 0, 2]])
        rhs_known = np.array([-2, 0, 2])
        deltaT_known = 1 / 12

        rtol = 1e-15
        atol = rtol
        assert np.allclose(M.todense(), M_known, rtol, atol)
        assert np.allclose(rhs, rhs_known, rtol, atol)
        assert np.allclose(deltaT, deltaT_known, rtol, atol)
コード例 #3
0
    def test_upwind_2d_simplex_surf_discharge_positive(self):
        g = simplex.StructuredTriangleGrid([2, 1], [1, 1])
        R = cg.rot(np.pi / 2., [1, 1, 0])
        g.nodes = np.dot(R, g.nodes)
        g.compute_geometry()

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, np.dot(R, [1, 0, 0]))

        bf = g.tags["domain_boundary_faces"].nonzero()[0]
        bc = BoundaryCondition(g, bf, bf.size * ["neu"])
        param.set_bc(solver, bc)

        data = {"param": param, "discharge": dis}
        M = solver.matrix_rhs(g, data)[0].todense()
        deltaT = solver.cfl(g, data)

        M_known = np.array([[1, -1, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1],
                            [-1, 0, 0, 1]])
        deltaT_known = 1 / 6

        rtol = 1e-15
        atol = rtol
        self.assertTrue(np.allclose(M, M_known, rtol, atol))
        self.assertTrue(np.allclose(deltaT, deltaT_known, rtol, atol))
コード例 #4
0
    def test_upwind_2d_cart_surf_discharge_negative(self):
        g = structured.CartGrid([3, 2], [1, 1])
        R = cg.rot(np.pi/6., [1,1,0])
        g.nodes = np.dot(R, g.nodes)
        g.compute_geometry(is_embedded=True)

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, np.dot(R, [-1, 0, 0]))

        bf = g.get_boundary_faces()
        bc = BoundaryCondition(g, bf, bf.size * ['neu'])
        param.set_bc(solver, bc)

        data = {'param': param, 'discharge': dis}
        M = solver.matrix_rhs(g, data)[0].todense()
        deltaT = solver.cfl(g, data)

        M_known = 0.5 * np.array([[ 0,-1, 0, 0, 0, 0],
                                  [ 0, 1,-1, 0, 0, 0],
                                  [ 0, 0, 1, 0, 0, 0],
                                  [ 0, 0, 0, 0,-1, 0],
                                  [ 0, 0, 0, 0, 1,-1],
                                  [ 0, 0, 0, 0, 0, 1]])

        deltaT_known = 1/6

        rtol = 1e-15
        atol = rtol
        assert np.allclose(M, M_known, rtol, atol)
        assert np.allclose(deltaT, deltaT_known, rtol, atol)
コード例 #5
0
    def test_upwind_1d_discharge_negative_bc_dir(self):
        g = structured.CartGrid(3, 1)
        g.compute_geometry()

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, [-2, 0, 0])

        bf = g.tags["domain_boundary_faces"].nonzero()[0]
        bc = BoundaryCondition(g, bf, bf.size * ["dir"])
        bc_val = 3 * np.ones(g.num_faces).ravel("F")
        param.set_bc(solver, bc)
        param.set_bc_val(solver, bc_val)

        data = {"param": param, "discharge": dis}
        M, rhs = solver.matrix_rhs(g, data)
        deltaT = solver.cfl(g, data)

        M_known = np.array([[2, -2, 0], [0, 2, -2], [0, 0, 2]])
        rhs_known = np.array([0, 0, 6])
        deltaT_known = 1 / 12

        rtol = 1e-15
        atol = rtol
        self.assertTrue(np.allclose(M.todense(), M_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(deltaT, deltaT_known, rtol, atol))
コード例 #6
0
    def test_upwind_3d_cart_discharge_positive(self):
        g = structured.CartGrid([2, 2, 2], [1, 1, 1])
        g.compute_geometry()

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, [1, 0, 0])

        bf = g.tags["domain_boundary_faces"].nonzero()[0]
        bc = BoundaryCondition(g, bf, bf.size * ["neu"])
        param.set_bc(solver, bc)

        data = {"param": param, "discharge": dis}
        M = solver.matrix_rhs(g, data)[0].todense()
        deltaT = solver.cfl(g, data)

        M_known = 0.25 * np.array([
            [1, 0, 0, 0, 0, 0, 0, 0],
            [-1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, -1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, -1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0],
            [0, 0, 0, 0, 0, 0, -1, 0],
        ])

        deltaT_known = 1 / 4

        rtol = 1e-15
        atol = rtol
        self.assertTrue(np.allclose(M, M_known, rtol, atol))
        self.assertTrue(np.allclose(deltaT, deltaT_known, rtol, atol))
コード例 #7
0
    def test_upwind_example1(self, if_export=False):
        #######################
        # Simple 2d upwind problem with implicit Euler scheme in time
        #######################
        T = 1
        Nx, Ny = 10, 1
        g = structured.CartGrid([Nx, Ny], [1, 1])
        g.compute_geometry()

        advect = upwind.Upwind("transport")
        param = Parameters(g)
        dis = advect.discharge(g, [1, 0, 0])

        b_faces = g.get_all_boundary_faces()
        bc = BoundaryCondition(g, b_faces, ["dir"] * b_faces.size)
        bc_val = np.hstack(([1], np.zeros(g.num_faces - 1)))
        param.set_bc("transport", bc)
        param.set_bc_val("transport", bc_val)

        data = {"param": param, "discharge": dis}
        data["deltaT"] = advect.cfl(g, data)

        U, rhs = advect.matrix_rhs(g, data)
        M, _ = mass_matrix.MassMatrix().matrix_rhs(g, data)

        conc = np.zeros(g.num_cells)

        # Perform an LU factorization to speedup the solver
        IE_solver = sps.linalg.factorized((M + U).tocsc())

        # Loop over the time
        Nt = int(T / data["deltaT"])
        time = np.empty(Nt)
        folder = "example1"
        save = Exporter(g, "conc_IE", folder)
        for i in np.arange(Nt):

            # Update the solution
            # Backward and forward substitution to solve the system
            conc = IE_solver(M.dot(conc) + rhs)
            time[i] = data["deltaT"] * i
            if if_export:
                save.write_vtk({"conc": conc}, time_step=i)

        if if_export:
            save.write_pvd(time)

        known = np.array([
            0.99969927,
            0.99769441,
            0.99067741,
            0.97352474,
            0.94064879,
            0.88804726,
            0.81498958,
            0.72453722,
            0.62277832,
            0.51725056,
        ])
        assert np.allclose(conc, known)
コード例 #8
0
    def test_upwind_1d_discharge_negative(self):
        g = structured.CartGrid(3, 1)
        g.compute_geometry()

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, [-2, 0, 0])

        bf = g.get_boundary_faces()
        bc = BoundaryCondition(g, bf, bf.size * ['neu'])
        param.set_bc(solver, bc)

        data = {'param': param, 'discharge': dis}
        M = solver.matrix_rhs(g, data)[0].todense()
        deltaT = solver.cfl(g, data)

        M_known = np.array([[0,-2, 0],
                            [0, 2,-2],
                            [0, 0, 2]])
        deltaT_known = 1/12

        rtol = 1e-15
        atol = rtol
        assert np.allclose(M, M_known, rtol, atol)
        assert np.allclose(deltaT, deltaT_known, rtol, atol)
コード例 #9
0
ファイル: test_upwind.py プロジェクト: jontateixeira/porepy
    def test_upwind_2d_cart_discharge_positive(self):
        g = structured.CartGrid([3, 2], [1, 1])
        g.compute_geometry()

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, [2, 0, 0])

        bf = g.tags['domain_boundary_faces'].nonzero()[0]
        bc = BoundaryCondition(g, bf, bf.size * ['neu'])
        param.set_bc(solver, bc)

        data = {'param': param, 'discharge': dis}
        M = solver.matrix_rhs(g, data)[0].todense()
        deltaT = solver.cfl(g, data)

        M_known = np.array([[1, 0, 0, 0, 0, 0],
                            [-1, 1, 0, 0, 0, 0],
                            [0, -1, 0, 0, 0, 0],
                            [0, 0, 0, 1, 0, 0],
                            [0, 0, 0, -1, 1, 0],
                            [0, 0, 0, 0, -1, 0]])

        deltaT_known = 1 / 12

        rtol = 1e-15
        atol = rtol
        assert np.allclose(M, M_known, rtol, atol)
        assert np.allclose(deltaT, deltaT_known, rtol, atol)
コード例 #10
0
    def test_upwind_2d_simplex_discharge_negative(self):
        g = simplex.StructuredTriangleGrid([2, 1], [1, 1])
        g.compute_geometry()

        solver = upwind.Upwind()
        param = Parameters(g)
        dis = solver.discharge(g, [-1, 0, 0])

        bf = g.get_boundary_faces()
        bc = BoundaryCondition(g, bf, bf.size * ['neu'])
        param.set_bc(solver, bc)

        data = {'param': param, 'discharge': dis}
        M = solver.matrix_rhs(g, data)[0].todense()
        deltaT = solver.cfl(g, data)

        M_known = np.array([[ 1, 0, 0,-1],
                            [-1, 0, 0, 0],
                            [ 0, 0, 1, 0],
                            [ 0, 0,-1, 1]])
        deltaT_known = 1/6

        rtol = 1e-15
        atol = rtol
        assert np.allclose(M, M_known, rtol, atol)
        assert np.allclose(deltaT, deltaT_known, rtol, atol)
コード例 #11
0
    def test_upwind_example0(self, if_export=False):
        #######################
        # Simple 2d upwind problem with explicit Euler scheme in time
        #######################
        T = 1
        Nx, Ny = 4, 1
        g = structured.CartGrid([Nx, Ny], [1, 1])
        g.compute_geometry()

        advect = upwind.Upwind("transport")
        param = Parameters(g)
        dis = advect.discharge(g, [1, 0, 0])

        b_faces = g.get_all_boundary_faces()
        bc = BoundaryCondition(g, b_faces, ['dir'] * b_faces.size)
        bc_val = np.hstack(([1], np.zeros(g.num_faces - 1)))
        param.set_bc("transport", bc)
        param.set_bc_val("transport", bc_val)

        data = {'param': param, 'discharge': dis}
        data['deltaT'] = advect.cfl(g, data)

        U, rhs = advect.matrix_rhs(g, data)
        OF = advect.outflow(g, data)
        M, _ = mass_matrix.MassMatrix().matrix_rhs(g, data)

        conc = np.zeros(g.num_cells)

        M_minus_U = M - U
        invM, _ = mass_matrix.InvMassMatrix().matrix_rhs(g, data)

        # Loop over the time
        Nt = int(T / data['deltaT'])
        time = np.empty(Nt)
        folder = 'example0'
        production = np.zeros(Nt)
        save = Exporter(g, "conc_EE", folder)
        for i in np.arange(Nt):

            # Update the solution
            production[i] = np.sum(OF.dot(conc))
            conc = invM.dot((M_minus_U).dot(conc) + rhs)
            time[i] = data['deltaT'] * i
            if if_export:
                save.write_vtk({"conc": conc}, time_step=i)

        if if_export:
            save.write_pvd(time)

        known = 1.09375
        assert np.sum(production) == known
コード例 #12
0
def add_data_transport(gb):

    gb.add_node_props(['bc', 'bc_val', 'discharge', 'apertures'])
    for g, d in gb:
        b_faces = g.tags['domain_boundary_faces'].nonzero()[0]
        index = np.nonzero(
            abs(g.face_centers[:, b_faces]) == np.ones([3, b_faces.size]))[1]
        b_faces = b_faces[index]
        d['bc'] = bc.BoundaryCondition(g, b_faces, ['dir'] * b_faces.size)
        d['bc_val'] = {'dir': np.ones(b_faces.size)}
        d['apertures'] = np.ones(g.num_cells) * np.power(.01, float(g.dim < 3))
        d['discharge'] = upwind.Upwind().discharge(
            g, [1, 1, 2 * np.power(1000, g.dim < 2)], d['apertures'])

    gb.add_edge_prop('discharge')
    for e, d in gb.edges_props():
        g_h = gb.sorted_nodes_of_edge(e)[1]
        d['discharge'] = gb.node_prop(g_h, 'discharge')
コード例 #13
0
def add_data_transport(gb):

    gb.add_node_props(["bc", "bc_val", "discharge", "apertures"])
    for g, d in gb:
        b_faces = g.tags["domain_boundary_faces"].nonzero()[0]
        index = np.nonzero(
            abs(g.face_centers[:, b_faces]) == np.ones([3, b_faces.size]))[1]
        b_faces = b_faces[index]
        d["bc"] = bc.BoundaryCondition(g, b_faces, ["dir"] * b_faces.size)
        d["bc_val"] = {"dir": np.ones(b_faces.size)}
        d["apertures"] = np.ones(g.num_cells) * np.power(.01, float(g.dim < 3))
        d["discharge"] = upwind.Upwind().discharge(
            g, [1, 1, 2 * np.power(1000, g.dim < 2)], d["apertures"])

    gb.add_edge_prop("discharge")
    for e, d in gb.edges_props():
        g_h = gb.sorted_nodes_of_edge(e)[1]
        d["discharge"] = gb.node_prop(g_h, "discharge")
コード例 #14
0
    def atest_upwind_2d_1d_cross_with_elimination(self):
        """
        Simplest possible elimination scenario, one 0d-grid removed. Check on upwind
        matrix, rhs, solution and time step estimate. Full solution included
        (as comments) for comparison purposes if test breaks.
        """
        f1 = np.array([[0, 1], [.5, .5]])
        f2 = np.array([[.5, .5], [0, 1]])
        domain = {"xmin": 0, "ymin": 0, "xmax": 1, "ymax": 1}
        mesh_size = 0.4
        mesh_kwargs = {}
        mesh_kwargs["mesh_size"] = {
            "mode": "constant",
            "value": mesh_size,
            "bound_value": mesh_size,
        }
        gb = pp.meshing.cart_grid([f1, f2], [2, 2], **{"physdims": [1, 1]})
        # gb = pp.meshing.simplex_grid( [f1, f2],domain,**mesh_kwargs)
        gb.compute_geometry()
        gb.assign_node_ordering()

        # Enforce node orderning because of Python 3.5 and 2.7.
        # Don't do it in general.
        cell_centers_1 = np.array([
            [7.50000000e-01, 2.500000000e-01],
            [5.00000000e-01, 5.00000000e-01],
            [-5.55111512e-17, 5.55111512e-17],
        ])
        cell_centers_2 = np.array([
            [5.00000000e-01, 5.00000000e-01],
            [7.50000000e-01, 2.500000000e-01],
            [-5.55111512e-17, 5.55111512e-17],
        ])

        for g, d in gb:
            if g.dim == 1:
                if np.allclose(g.cell_centers, cell_centers_1):
                    d["node_number"] = 1
                elif np.allclose(g.cell_centers, cell_centers_2):
                    d["node_number"] = 2
                else:
                    raise ValueError("Grid not found")

        tol = 1e-3
        solver = pp.TpfaMixedDim()
        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:
            param = pp.Parameters(g)

            a_dim = np.power(a, gb.dim_max() - g.dim)
            aperture = np.ones(g.num_cells) * a_dim
            param.set_aperture(aperture)

            kxx = np.ones(g.num_cells) * np.power(1e3, g.dim < gb.dim_max())
            p = pp.SecondOrderTensor(3, kxx, kyy=kxx, kzz=kxx)
            param.set_tensor("flow", p)

            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            if bound_faces.size != 0:
                bound_face_centers = g.face_centers[:, bound_faces]

                right = bound_face_centers[0, :] > 1 - tol
                left = bound_face_centers[0, :] < tol

                labels = np.array(["neu"] * bound_faces.size)
                labels[right] = ["dir"]

                bc_val = np.zeros(g.num_faces)
                bc_dir = bound_faces[right]
                bc_neu = bound_faces[left]
                bc_val[bc_dir] = g.face_centers[0, bc_dir]
                bc_val[bc_neu] = -g.face_areas[bc_neu] * a_dim

                param.set_bc("flow",
                             pp.BoundaryCondition(g, bound_faces, labels))
                param.set_bc_val("flow", bc_val)
                # Transport
                bottom = bound_face_centers[1, :] < tol
                top = bound_face_centers[1, :] > 1 - tol

                labels = np.array(["neu"] * bound_faces.size)
                labels[np.logical_or(np.logical_or(left, right),
                                     np.logical_or(top, bottom))] = ["dir"]

                bc_val = np.zeros(g.num_faces)

                param.set_bc("transport",
                             pp.BoundaryCondition(g, bound_faces, labels))
                param.set_bc_val("transport", bc_val)
            else:
                param.set_bc("transport",
                             pp.BoundaryCondition(g, np.empty(0), np.empty(0)))
                param.set_bc("flow",
                             pp.BoundaryCondition(g, np.empty(0), np.empty(0)))
            # Transport:
            source = g.cell_volumes * a_dim
            param.set_source("transport", source)

            d["param"] = param

        gb.add_edge_props("param")
        for e, d in gb.edges():
            g_h = gb.nodes_of_edge(e)[1]
            d["param"] = pp.Parameters(g_h)

        A, rhs = solver.matrix_rhs(gb)
        # p = sps.linalg.spsolve(A,rhs)
        _, p_red, _, _ = condensation.solve_static_condensation(A,
                                                                rhs,
                                                                gb,
                                                                dim=0)
        dim_to_remove = 0
        gb_r, elimination_data = gb.duplicate_without_dimension(dim_to_remove)
        condensation.compute_elimination_fluxes(gb, gb_r, elimination_data)

        solver.split(gb_r, "pressure", p_red)

        # pp.fvutils.compute_discharges(gb)
        pp.fvutils.compute_discharges(gb_r)

        # ------Transport------#
        advection_discr = upwind.Upwind(physics="transport")
        advection_coupling_conditions = upwind.UpwindCoupling(advection_discr)
        advection_coupler = coupler.Coupler(advection_discr,
                                            advection_coupling_conditions)
        U_r, rhs_u_r = advection_coupler.matrix_rhs(gb_r)
        _, rhs_src_r = pp.IntegralMixedDim(
            physics="transport").matrix_rhs(gb_r)
        rhs_u_r = rhs_u_r + rhs_src_r
        deltaT = np.amin(
            gb_r.apply_function(advection_discr.cfl,
                                advection_coupling_conditions.cfl).data)

        theta_r = sps.linalg.spsolve(U_r, rhs_u_r)

        U_known, rhs_known, theta_known, deltaT_known = known_for_elimination()
        tol = 1e-7
        self.assertTrue(np.isclose(deltaT, deltaT_known, tol, tol))
        self.assertTrue((np.amax(np.absolute(U_r - U_known))) < tol)
        self.assertTrue((np.amax(np.absolute(rhs_u_r - rhs_known))) < tol)
        self.assertTrue((np.amax(np.absolute(theta_r - theta_known))) < tol)
コード例 #15
0
    # gb = meshing.cart_grid(f_set, [Nx, Nx, Nx])
    path_to_gmsh = '~/gmsh-2.16.0-Linux/bin/gmsh'

    gb = meshing.simplex_grid(f_set, domain, gmsh_path=path_to_gmsh)
    gb.assign_node_ordering()

    ################## Transport solver ##################

    print("Compute global matrix and rhs for the advection problem")
    gb_r, elimination_data = gb.duplicate_without_dimension(0)
    condensation.compute_elimination_fluxes(gb, gb_r, elimination_data)

    add_data_transport(gb)
    add_data_transport(gb_r)

    upwind_solver = upwind.Upwind()
    upwind_cc = upwind.UpwindCoupling(upwind_solver)
    coupler_solver = coupler.Coupler(upwind_solver, upwind_cc)
    U, rhs = coupler_solver.matrix_rhs(gb)
    U_r, rhs_r = coupler_solver.matrix_rhs(gb_r)

    deltaT = np.amin([upwind_solver.cfl(g, d) for g, d in gb])
    deltaT_r = np.amin([upwind_solver.cfl(g, d) for g, d in gb_r])

    T = deltaT * max(Nx, Ny) * 4

    gb.add_node_prop("deltaT", None, deltaT)
    gb_r.add_node_prop("deltaT", None, deltaT_r)

    mass_solver = mass_matrix.MassMatrix()
    coupler_solver = coupler.Coupler(mass_solver)
コード例 #16
0
    diffusion = second_order_tensor.SecondOrderTensorTensor(g.dim, kxx)

    f = np.ones(g.num_cells) * g.cell_volumes

    data = {'beta_n': beta_n, 'bc': bnd, 'bc_val': bnd_val, 'k': diffusion,
            'f': f}

    return data

#------------------------------------------------------------------------------#

# the f is considered twice, we guess that non-homogeneous Neumann as well.


Nx = Ny = 20
g = structured.CartGrid([Nx, Ny], [1, 1])
g.compute_geometry()

advection = upwind.Upwind()
diffusion = tpfa.Tpfa()

# Assign parameters
data = add_data(g, advection)

U, rhs_u = advection.matrix_rhs(g, data)
D, rhs_d = diffusion.matrix_rhs(g, data)

theta = sps.linalg.spsolve(D + U, rhs_u + rhs_d)

exporter.export_vtk(g, "advection_diffusion", {"theta": theta})
コード例 #17
0
    def test_upwind_example2(self, if_export=False):
        #######################
        # Simple 2d upwind problem with explicit Euler scheme in time coupled with
        # a Darcy problem
        #######################
        T = 2
        Nx, Ny = 10, 10
        folder = 'example2'

        def funp_ex(pt):
            return -np.sin(pt[0]) * np.sin(pt[1]) - pt[0]

        g = structured.CartGrid([Nx, Ny], [1, 1])
        g.compute_geometry()

        param = Parameters(g)

        # Permeability
        perm = tensor.SecondOrderTensor(g.dim, kxx=np.ones(g.num_cells))
        param.set_tensor("flow", perm)

        # Source term
        param.set_source("flow", np.zeros(g.num_cells))

        # Boundaries
        b_faces = g.get_all_boundary_faces()
        bc = BoundaryCondition(g, b_faces, ['dir'] * b_faces.size)
        bc_val = np.zeros(g.num_faces)
        bc_val[b_faces] = funp_ex(g.face_centers[:, b_faces])
        param.set_bc("flow", bc)
        param.set_bc_val("flow", bc_val)

        # Darcy solver
        data = {'param': param}
        solver = vem_dual.DualVEM("flow")
        D_flow, b_flow = solver.matrix_rhs(g, data)

        solver_source = vem_source.DualSource('flow')
        D_source, b_source = solver_source.matrix_rhs(g, data)

        up = sps.linalg.spsolve(D_flow + D_source, b_flow + b_source)

        p, u = solver.extract_p(g, up), solver.extract_u(g, up)
        P0u = solver.project_u(g, u, data)

        save = Exporter(g, "darcy", folder)

        if if_export:
            save.write_vtk({'pressure': p, "P0u": P0u})

        # Discharge
        dis = u

        # Boundaries
        bc = BoundaryCondition(g, b_faces, ['dir'] * b_faces.size)
        bc_val = np.hstack(([1], np.zeros(g.num_faces - 1)))
        param.set_bc("transport", bc)
        param.set_bc_val("transport", bc_val)

        data = {'param': param, 'discharge': dis}

        # Advect solver
        advect = upwind.Upwind("transport")

        U, rhs = advect.matrix_rhs(g, data)

        data['deltaT'] = advect.cfl(g, data)
        M, _ = mass_matrix.MassMatrix().matrix_rhs(g, data)

        conc = np.zeros(g.num_cells)
        M_minus_U = M - U
        invM, _ = mass_matrix.InvMassMatrix().matrix_rhs(g, data)

        # Loop over the time
        Nt = int(T / data['deltaT'])
        time = np.empty(Nt)
        save.change_name("conc_darcy")
        for i in np.arange(Nt):

            # Update the solution
            conc = invM.dot((M_minus_U).dot(conc) + rhs)
            time[i] = data['deltaT'] * i
            if if_export:
                save.write_vtk({"conc": conc}, time_step=i)

        if if_export:
            save.write_pvd(time)

        known = \
            np.array([9.63168200e-01,   8.64054875e-01,   7.25390695e-01,
                      5.72228235e-01,   4.25640080e-01,   2.99387331e-01,
                      1.99574336e-01,   1.26276876e-01,   7.59011550e-02,
                      4.33431230e-02,   3.30416807e-02,   1.13058617e-01,
                      2.05372538e-01,   2.78382057e-01,   3.14035373e-01,
                      3.09920132e-01,   2.75024694e-01,   2.23163145e-01,
                      1.67386939e-01,   1.16897527e-01,   1.06111312e-03,
                      1.11951850e-02,   3.87907727e-02,   8.38516119e-02,
                      1.36617802e-01,   1.82773271e-01,   2.10446545e-01,
                      2.14651936e-01,   1.97681518e-01,   1.66549151e-01,
                      3.20751341e-05,   9.85780113e-04,   6.07062715e-03,
                      1.99393042e-02,   4.53237556e-02,   8.00799828e-02,
                      1.17199623e-01,   1.47761481e-01,   1.64729339e-01,
                      1.65390555e-01,   9.18585872e-07,   8.08267622e-05,
                      8.47227168e-04,   4.08879583e-03,   1.26336029e-02,
                      2.88705048e-02,   5.27841497e-02,   8.10459333e-02,
                      1.07956484e-01,   1.27665318e-01,   2.51295298e-08,
                      6.29844122e-06,   1.09361990e-04,   7.56743783e-04,
                      3.11384414e-03,   9.04446601e-03,   2.03443897e-02,
                      3.75208816e-02,   5.89595194e-02,   8.11457277e-02,
                      6.63498510e-10,   4.73075468e-07,   1.33728945e-05,
                      1.30243418e-04,   7.01905707e-04,   2.55272292e-03,
                      6.96686157e-03,   1.52290448e-02,   2.78607282e-02,
                      4.40402650e-02,   1.71197497e-11,   3.47118057e-08,
                      1.57974045e-06,   2.13489614e-05,   1.48634295e-04,
                      6.68104990e-04,   2.18444135e-03,   5.58646819e-03,
                      1.17334966e-02,   2.09744728e-02,   4.37822313e-13,
                      2.52373622e-09,   1.83589660e-07,   3.40553325e-06,
                      3.02948532e-05,   1.66504215e-04,   6.45119867e-04,
                      1.90731440e-03,   4.53436628e-03,   8.99977737e-03,
                      1.12627412e-14,   1.84486857e-10,   2.13562387e-08,
                      5.39492977e-07,   6.08223906e-06,   4.05535296e-05,
                      1.84731221e-04,   6.25871542e-04,   1.66459389e-03,
                      3.59980231e-03])

        assert np.allclose(conc, known)