Ejemplo n.º 1
0
    def solve(self, gb, method=None):
        key = "flow"
        if method is None:
            discretization = pp.Tpfa(key)
        elif method == "mpfa":
            discretization = pp.Mpfa(key)
        elif method == "mvem":
            discretization = pp.MVEM(key)
        assembler = test_utils.setup_flow_assembler(gb, discretization, key)
        assembler.discretize()
        A_flow, b_flow = assembler.assemble_matrix_rhs()
        p = sps.linalg.spsolve(A_flow, b_flow)
        assembler.distribute_variable(p)

        if method == "mvem":
            g2d = gb.grids_of_dimension(2)[0]
            p_n = np.zeros(gb.num_cells())
            for g, d in gb:
                if g.dim == 2:
                    p_n[:g2d.num_cells] = d[pp.STATE]["pressure"][g.num_faces:]
                else:
                    p_n[g2d.num_cells:] = d[pp.STATE]["pressure"][g.num_faces:]
                d[pp.STATE]["pressure"] = d[pp.STATE]["pressure"][g.num_faces:]
            p = p_n
        return p
Ejemplo n.º 2
0
    def solve(self):
        # consturct the matrices
        self.assembler.discretize()

        # in the case the fractures are scaled modify the problem
        if self.data.get("length_ratio", None) is not None:
            for g, d in self.gb:
                if g.dim == 1:
                    ratio = self.data["length_ratio"][g.frac_num]
                    d[pp.DISCRETIZATION_MATRICES][self.model]["flux"] *= ratio
                    d[pp.DISCRETIZATION_MATRICES][self.model]["bound_flux"] *= ratio
                    d[pp.DISCRETIZATION_MATRICES][self.model]["bound_pressure_face"] *= ratio
                    d[pp.DISCRETIZATION_MATRICES][self.model]["bound_pressure_cell"] *= ratio

        A, b = self.assembler.assemble_matrix_rhs()

        # solve the problem
        p = sps.linalg.spsolve(A, b)

        # distribute the variables
        self.assembler.distribute_variable(p)

        # split the variables
        for g, d in self.gb:
            d[pp.STATE][self.pressure] = d[pp.STATE][self.variable]
            d[pp.STATE][self.P0_flux] = np.zeros(g.num_cells)
            d[pp.PARAMETERS][self.model][self.flux] = np.zeros(g.num_faces)

        # reconstruct the Darcy flux
        pp.fvutils.compute_darcy_flux(self.gb, keyword=self.model, d_name=self.flux,
                                      p_name=self.pressure, lam_name=self.mortar)

        # split the darcy flux on each grid-bucket grid
        for _, d in self.gb:
            d[pp.STATE][self.flux] = d[pp.PARAMETERS][self.model][self.flux]

        for e, d in self.gb.edges():
            _, g_master = self.gb.nodes_of_edge(e)
            if g_master.dim == 1:
                ratio = self.data["length_ratio"][g_master.frac_num]
                d[pp.PARAMETERS][self.model][self.flux] *= ratio
            d[pp.STATE][self.mortar] = d[pp.PARAMETERS][self.model][self.flux]

        # export the P0 flux reconstruction
        pp.project_flux(self.gb, pp.MVEM(self.model), self.flux, self.P0_flux, self.mortar)

        # compute the module of the flow velocity and the azimuth
        for g, d in self.gb:
            P0_flux = d[pp.STATE][self.P0_flux]

            norm = np.sqrt(np.einsum("ij,ij->j", P0_flux, P0_flux))
            d[pp.STATE][self.norm_flux] = norm

            north = self.data["north"] / np.linalg.norm(self.data["north"])
            P0_flux_dir = np.divide(P0_flux, norm)

            azimuth = np.arctan2(P0_flux_dir[1, :], P0_flux_dir[0, :]) - \
                      np.arctan2(north[1], north[0]);

            d[pp.STATE][self.azimuth] = azimuth
Ejemplo n.º 3
0
def setup_discr_mvem(gb, key="flow"):
    """ Setup the discretization MVEM. """
    discr = pp.MVEM(key)
    p_trace = pp.CellDofFaceDofMap(key)
    interface = pp.FluxPressureContinuity(key, discr, p_trace)

    for g, d in gb:
        if g.dim == gb.dim_max():
            d[pp.PRIMARY_VARIABLES] = {key: {"cells": 1, "faces": 1}}
            d[pp.DISCRETIZATION] = {key: {"flux": discr}}
        else:
            d[pp.PRIMARY_VARIABLES] = {key: {"cells": 1}}
            d[pp.DISCRETIZATION] = {key: {"flux": p_trace}}

    for e, d in gb.edges():
        g_slave, g_master = gb.nodes_of_edge(e)
        d[pp.PRIMARY_VARIABLES] = {key: {"cells": 1}}
        d[pp.COUPLING_DISCRETIZATION] = {
            "flux": {
                g_slave: (key, "flux"),
                g_master: (key, "flux"),
                e: (key, interface),
            }
        }

    return pp.Assembler(gb), (discr, p_trace)
Ejemplo n.º 4
0
    def main(self, N):
        Nx = Ny = N

        # g = structured.CartGrid([Nx, Ny], [2, 2])
        g = pp.StructuredTriangleGrid([Nx, Ny], [1, 1])
        g.compute_geometry()
        # co.coarsen(g, 'by_volume')

        # Assign parameters
        data = self.add_data(g)

        # Choose and define the solvers
        solver_flow = pp.MVEM("flow")
        solver_flow.discretize(g, data)
        A_flow, b_flow = solver_flow.assemble_matrix_rhs(g, data)

        solver_source = pp.DualScalarSource("flow")
        solver_source.discretize(g, data)
        A_source, b_source = solver_source.assemble_matrix_rhs(g, data)

        up = sps.linalg.spsolve(A_flow + A_source, b_flow + b_source)

        u = solver_flow.extract_flux(g, up, data)
        p = solver_flow.extract_pressure(g, up, data)
        #    P0u = solver_flow.project_flux(g, u, data, keyword="flow")

        diam = np.amax(g.cell_diameters())
        return diam, self.error_p(g, p)
Ejemplo n.º 5
0
 def run_vem(self, gb):
     key = "flow"
     method = pp.MVEM(key)
     self._solve(gb, method, key)
     for g, d in gb:
         d[pp.STATE]["darcy_flux"] = d[pp.STATE]["pressure"][:g.num_faces]
         d[pp.STATE]["pressure"] = d[pp.STATE]["pressure"][g.num_faces:]
Ejemplo n.º 6
0
def homo_mvem(g):
    return {
        "scheme": pp.MVEM("flow"),
        "dof": {
            "cells": 1,
            "faces": 1
        },
        "label": "homo_mvem"
    }
Ejemplo n.º 7
0
    def run_vem(self, gb):
        solver_flow = pp.MVEM("flow")

        A_flow, b_flow = solver_flow.matrix_rhs(gb)

        up = sps.linalg.spsolve(A_flow, b_flow)
        solver_flow.split(gb, "up", up)
        solver_flow.extract_p(gb, "up", "pressure")
        self.verify_cv(gb)
Ejemplo n.º 8
0
def solve_vem(gb, folder, discr_3d=None):
    # Choose and define the solvers and coupler
    flow_discretization = pp.MVEM("flow")
    source_discretization = pp.DualScalarSource("flow")
    run_flow(gb,
             flow_discretization,
             source_discretization,
             folder,
             is_FV=False,
             discr_3d=discr_3d)
Ejemplo n.º 9
0
 def run_vem(self, gb):
     key = "flow"
     method = pp.MVEM(key)
     assembler = test_utils.setup_flow_assembler(gb, method, key)
     assembler.discretize()
     A_flow, b_flow = assembler.assemble_matrix_rhs()
     p = sps.linalg.spsolve(A_flow, b_flow)
     assembler.distribute_variable(p)
     for g, d in gb:
         d[pp.STATE]["pressure"] = d[pp.STATE]["pressure"][g.num_faces:]
Ejemplo n.º 10
0
    def set_param_flow(self, gb, no_flow=False, kn=1e3, method="mpfa"):
        # Set up flow field with uniform flow in y-direction
        kw = "flow"
        for g, d in gb:
            parameter_dictionary = {}

            perm = pp.SecondOrderTensor(kxx=np.ones(g.num_cells))
            parameter_dictionary["second_order_tensor"] = perm

            b_val = np.zeros(g.num_faces)
            if g.dim == 2:
                bound_faces = pp.face_on_side(g, ["ymin", "ymax"])
                if no_flow:
                    b_val[bound_faces[0]] = 1
                    b_val[bound_faces[1]] = 1
                bound_faces = np.hstack((bound_faces[0], bound_faces[1]))
                labels = np.array(["dir"] * bound_faces.size)
                parameter_dictionary["bc"] = pp.BoundaryCondition(
                    g, bound_faces, labels)

                y_max_faces = pp.face_on_side(g, "ymax")[0]
                b_val[y_max_faces] = 1
            else:
                parameter_dictionary["bc"] = pp.BoundaryCondition(g)
            parameter_dictionary["bc_values"] = b_val
            parameter_dictionary["mpfa_inverter"] = "python"

            d[pp.PARAMETERS] = pp.Parameters(g, [kw], [parameter_dictionary])
            d[pp.DISCRETIZATION_MATRICES] = {"flow": {}}

        gb.add_edge_props("kn")
        for e, d in gb.edges():
            mg = d["mortar_grid"]
            flow_dictionary = {
                "normal_diffusivity": 2 * kn * np.ones(mg.num_cells)
            }
            d[pp.PARAMETERS] = pp.Parameters(keywords=["flow"],
                                             dictionaries=[flow_dictionary])
            d[pp.DISCRETIZATION_MATRICES] = {"flow": {}}

        discretization_key = kw + "_" + pp.DISCRETIZATION

        for g, d in gb:
            # Choose discretization and define the solver
            if method == "mpfa":
                discr = pp.Mpfa(kw)
            elif method == "mvem":
                discr = pp.MVEM(kw)
            else:
                discr = pp.Tpfa(kw)

            d[discretization_key] = discr

        for _, d in gb.edges():
            d[discretization_key] = pp.RobinCoupling(kw, discr)
Ejemplo n.º 11
0
    def _matrix(self, g, perm, bc, vect):
        solver = pp.MVEM(keyword="flow")

        data = pp.initialize_default_data(
            g,
            {},
            "flow",
            {"second_order_tensor": perm, "bc": bc, "vector_source": vect},
        )
        solver.discretize(g, data)
        return solver.assemble_matrix_rhs(g, data)[1]
Ejemplo n.º 12
0
 def solve(self, method):
     key = "flow"
     gb = self.gb
     if method == "tpfa":
         discretization = pp.Tpfa(key)
     elif method == "mpfa":
         discretization = pp.Mpfa(key)
     elif method == "mvem":
         discretization = pp.MVEM(key)
     assembler = test_utils.setup_flow_assembler(gb, discretization, key)
     assembler.discretize()
     A_flow, b_flow = assembler.assemble_matrix_rhs()
     p = sps.linalg.spsolve(A_flow, b_flow)
     assembler.distribute_variable(p)
     return p
Ejemplo n.º 13
0
    def test_convergence_mvem_2d_iso_simplex_exact(self):

        p_ex = lambda pt: 2 * pt[0, :] - 3 * pt[1, :] - 9
        u_ex = np.array([-1, 4, 0])

        for i in np.arange(5):
            g = pp.StructuredTriangleGrid([3 + i] * 2, [1, 1])
            g.compute_geometry()

            kxx = np.ones(g.num_cells)
            perm = pp.SecondOrderTensor(kxx=kxx, kyy=kxx, kzz=1)
            bf = g.get_boundary_faces()
            bc = pp.BoundaryCondition(g, bf, bf.size * ["dir"])
            bc_val = np.zeros(g.num_faces)
            bc_val[bf] = p_ex(g.face_centers[:, bf])
            vect = np.vstack(
                (g.cell_volumes, g.cell_volumes, np.zeros(g.num_cells))
            ).ravel(order="F")

            solver = pp.MVEM(keyword="flow")

            specified_parameters = {
                "bc": bc,
                "bc_values": bc_val,
                "second_order_tensor": perm,
                "vector_source": vect,
            }
            data = pp.initialize_default_data(g, {}, "flow", specified_parameters)

            solver.discretize(g, data)
            M, rhs = solver.assemble_matrix_rhs(g, data)
            up = sps.linalg.spsolve(M, rhs)
            p = solver.extract_pressure(g, up, data)
            err = np.sum(np.abs(p - p_ex(g.cell_centers)))

            self.assertTrue(np.isclose(err, 0))

            _ = data[pp.DISCRETIZATION_MATRICES]["flow"][solver.vector_proj_key]
            u = solver.extract_flux(g, up, data)
            P0u = solver.project_flux(g, u, data)
            err = np.sum(
                np.abs(P0u - np.tile(u_ex, g.num_cells).reshape((3, -1), order="F"))
            )
            self.assertTrue(np.isclose(err, 0))
Ejemplo n.º 14
0
def hete2(g):
    if g.dim == 2:
        scheme = {
            "scheme": pp.MVEM("flow"),
            "dof": {
                "cells": 1,
                "faces": 1
            },
            "label": "hete2"
        }
    else:
        scheme = {
            "scheme": pp.Tpfa("flow"),
            "dof": {
                "cells": 1
            },
            "label": "hete2"
        }
    return scheme
Ejemplo n.º 15
0
    def extract(self, x):
        self.assembler.distribute_variable(x)

        for g, d in self.gb:
            d[pp.STATE][self.pressure] = d[pp.STATE][self.variable]
            d[pp.STATE]["cell_volumes"] = g.cell_volumes

        pp.fvutils.compute_darcy_flux(self.gb,
                                      keyword=self.model,
                                      d_name=self.flux,
                                      p_name=self.pressure,
                                      lam_name=self.mortar)

        for _, d in self.gb:
            d[pp.STATE][self.flux] = d[pp.PARAMETERS][self.model][self.flux]

        # export the P0 flux reconstruction
        pp.project_flux(self.gb, pp.MVEM(self.model), self.flux, self.P0_flux,
                        self.mortar)
Ejemplo n.º 16
0
    def solve(self, kf, description, is_coarse=False):
        gb, domain = pp.grid_buckets_2d.benchmark_regular(
            {"mesh_size_frac": 0.045}, is_coarse)
        # Assign parameters
        setup.add_data(gb, domain, kf)
        key = "flow"

        method = pp.MVEM(key)

        coupler = pp.RobinCoupling(key, method)

        for g, d in gb:
            d[pp.PRIMARY_VARIABLES] = {"pressure": {"cells": 1, "faces": 1}}
            d[pp.DISCRETIZATION] = {"pressure": {"diffusive": method}}
        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            d[pp.PRIMARY_VARIABLES] = {"mortar_solution": {"cells": 1}}
            d[pp.COUPLING_DISCRETIZATION] = {
                "lambda": {
                    g1: ("pressure", "diffusive"),
                    g2: ("pressure", "diffusive"),
                    e: ("mortar_solution", coupler),
                }
            }
            d[pp.DISCRETIZATION_MATRICES] = {"flow": {}}

        assembler = pp.Assembler(gb)

        # Discretize
        assembler.discretize()
        A, b = assembler.assemble_matrix_rhs()
        p = sps.linalg.spsolve(A, b)

        assembler.distribute_variable(p)

        for g, d in gb:
            d[pp.STATE]["darcy_flux"] = d[pp.STATE]["pressure"][:g.num_faces]
            d[pp.STATE]["pressure"] = d[pp.STATE]["pressure"][g.num_faces:]
Ejemplo n.º 17
0
def flow(gb, param):

    model = "flow"

    model_data = data.flow(gb, model, param)

    # discretization operator name
    flux_id = "flux"

    # master variable name
    variable = "flux_pressure"
    mortar = "lambda_" + variable

    # post process variables
    pressure = "pressure"
    flux = "darcy_flux"  # it has to be this one
    P0_flux = "P0_flux"

    # save variable name for the advection-diffusion problem
    param["pressure"] = pressure
    param["flux"] = flux
    param["P0_flux"] = P0_flux
    param["mortar_flux"] = mortar

    # discretization operators
    discr = pp.MVEM(model_data)
    coupling = pp.RobinCoupling(model_data, discr)

    # define the dof and discretization for the grids
    for g, d in gb:
        d[pp.PRIMARY_VARIABLES] = {variable: {"cells": 1, "faces": 1}}
        d[pp.DISCRETIZATION] = {variable: {flux_id: discr}}

    # define the interface terms to couple the grids
    for e, d in gb.edges():
        g_slave, g_master = gb.nodes_of_edge(e)
        d[pp.PRIMARY_VARIABLES] = {mortar: {"cells": 1}}
        d[pp.COUPLING_DISCRETIZATION] = {
            variable: {
                g_slave: (variable, flux_id),
                g_master: (variable, flux_id),
                e: (mortar, coupling)
            }
        }

    # solution of the darcy problem
    assembler = pp.Assembler()

    logger.info("Assemble the flow problem")
    A, b, block_dof, full_dof = assembler.assemble_matrix_rhs(gb)
    logger.info("done")

    logger.info("Solve the linear system")
    up = sps.linalg.spsolve(A, b)
    logger.info("done")

    logger.info("Variable post-process")
    assembler.distribute_variable(gb, up, block_dof, full_dof)
    for g, d in gb:
        d[pressure] = discr.extract_pressure(g, d[variable])
        d[flux] = discr.extract_flux(g, d[variable])

    pp.project_flux(gb, discr, flux, P0_flux, mortar)
    logger.info("done")

    return model_data
Ejemplo n.º 18
0
    def test_upwind_example_3(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

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

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

        # Permeability
        perm = pp.SecondOrderTensor(kxx=np.ones(g.num_cells))

        # Boundaries
        b_faces = g.get_all_boundary_faces()
        bc = pp.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])
        specified_parameters = {
            "bc": bc,
            "bc_values": bc_val,
            "second_order_tensor": perm,
        }
        data = pp.initialize_default_data(g, {}, "flow", specified_parameters)
        solver = pp.MVEM("flow")
        solver.discretize(g, data)
        D_flow, b_flow = solver.assemble_matrix_rhs(g, data)

        solver_source = pp.DualScalarSource("flow")
        solver_source.discretize(g, data)
        D_source, b_source = solver_source.assemble_matrix_rhs(g, data)

        up = sps.linalg.spsolve(D_flow + D_source, b_flow + b_source)
        _, u = solver.extract_pressure(g, up, data), solver.extract_flux(g, up, data)

        # Darcy_Flux
        dis = u

        # Boundaries
        bc = pp.BoundaryCondition(g, b_faces, ["dir"] * b_faces.size)
        bc_val = np.hstack(([1], np.zeros(g.num_faces - 1)))
        specified_parameters = {"bc": bc, "bc_values": bc_val, "darcy_flux": dis}
        data = pp.initialize_default_data(g, {}, "transport", specified_parameters)

        # Advect solver
        advect = pp.Upwind("transport")
        advect.discretize(g, data)

        U, rhs = advect.assemble_matrix_rhs(g, data)
        time_step = advect.cfl(g, data)
        rhs = time_step * rhs
        U = time_step * U

        data[pp.PARAMETERS]["transport"]["time_step"] = time_step
        mass = pp.MassMatrix("transport")
        mass.discretize(g, data)
        M, _ = mass.assemble_matrix_rhs(g, data)

        conc = np.zeros(g.num_cells)
        M_minus_U = M - U
        inv_mass = pp.InvMassMatrix("transport")
        inv_mass.discretize(g, data)
        invM, _ = inv_mass.assemble_matrix_rhs(g, data)

        # Loop over the time
        Nt = int(T / time_step)
        time = np.empty(Nt)
        for i in np.arange(Nt):

            # Update the solution
            conc = invM.dot((M_minus_U).dot(conc) + rhs)
            time[i] = time_step * i

        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)
def solve_two_phase_flow_upwind(g):

    time = []
    sat_err = []
    pres_err = []
    maxflux = []
    
    xc = g.cell_centers

    # Permeability tensor
    k_xx = np.zeros(g.num_cells)
    k_xy = np.zeros(g.num_cells)
    k_yy = np.zeros(g.num_cells)

    k_xx[:] = perm_xx_f(xc[0], xc[1])
    k_yy[:] = perm_yy_f(xc[0], xc[1])
    k_xy[:] = perm_xy_f(xc[0], xc[1])

    perm = pp.SecondOrderTensor(k_xx, kyy=k_yy, kxy=k_xy)
    
    # Set type of boundary conditions
    xf = g.face_centers
    p_bound = np.zeros(g.num_faces)

    bnd_faces = g.get_all_boundary_faces()
    neu_faces = bnd_faces[:-1].copy()        
    dir_faces = np.array([g.num_faces-1])

    bot_faces = np.ravel(np.argwhere(g.face_centers[1] < 1e-10))
    top_faces = np.ravel(np.argwhere(g.face_centers[1] > domain[1] - 1e-10))
    left_faces = np.ravel(np.argwhere(g.face_centers[0] < 1e-10))
    right_faces = np.ravel(np.argwhere(g.face_centers[0] > domain[0] - 1e-10))
   
    bound_cond = pp.BoundaryCondition(g, dir_faces, ['dir'] * dir_faces.size)

    # set value of boundary condition
    p_bound[neu_faces] = 0
    p_bound[dir_faces] = p_f(xf[0, dir_faces], xf[1, dir_faces])

    # set rhs    
    rhs1 = np.zeros(g.num_cells)
    rhs2 = np.zeros(g.num_cells)

    specified_parameters = {"second_order_tensor": perm, "source": rhs1, "bc": bound_cond, "bc_values": p_bound}
    data = pp.initialize_default_data(g, {}, "flow", specified_parameters)
    
    # Set initial conditions
    s = np.zeros(g.num_cells)
    s = s_f(xc[0], xc[1])
    s_0 = s_f(xc[0], xc[1])
    #pp.plot_grid(g, s_0, figsize=(15, 12), alpha = 0.9, color_map=(0,1))
    V_start = np.sum(s*g.cell_volumes)

    fluxtot = np.zeros(g.num_faces)

    p_ex = p_f(xc[0], xc[1])
    s_ex = s_eq_f(xc[0], xc[1])

    time_steps_vec = []

    #save = pp.Exporter(g, 'twophase_gcmpfa8_time', folder='plots')
    #save.write_vtk({"s": s}, 0)

    # Gravity term
    # < K > * rho_alpha * g
    gforce = np.zeros((2, g.num_cells))
    gforce[0,:] = gx * np.ones(g.num_cells)
    gforce[1,:] = gy * np.ones(g.num_cells)
    gforce = gforce.ravel('F')

    g1 = rho1 * gforce
    g2 = rho2 * gforce

    flux_g1 = standard_discr(g, perm, g1)
    flux_g2 = standard_discr(g, perm, g2)
    
    # mpfa discretization
    flux, bound_flux, _, _  = pp.Mpfa("flow")._local_discr(
        g, perm, bound_cond, inverter="python"
    )
    div = pp.fvutils.scalar_divergence(g)

    # define iteration parameters
    t = .0
    k = 0
    i = 0

    time_steps_vec.append(t)
    time_step = 5  

    courant_max = 0.05
    
    while t < T:

        s_old = s.copy()

        # Increment time
        k += 1
        t += time_step

        # discretize gravity term
        kr1, kr2, f2, f1 = get_phase_mobility(g, s, fluxtot, flux_g1, flux_g2)
        fluxtot_g = kr1 * flux_g1 + kr2 * flux_g2
        p_bound[neu_faces] = fluxtot[neu_faces] - fluxtot_g[neu_faces]
        p_bound[bot_faces] *= -1
        p_bound[left_faces] *= -1

        a = div * (kr1 + kr2) * flux
        b = (rhs1 + rhs2) - div * bound_flux * p_bound - div * fluxtot_g

        p = sps.linalg.spsolve(a, b)
        
        fluxtot = (kr1 + kr2) * flux * p + bound_flux * p_bound + fluxtot_g
        assert np.all(abs(fluxtot[neu_faces]) < thresh)
        assert np.all(abs(fluxtot[dir_faces]) < 1.0e-16)

        if pert == 0:
            assert np.all(fluxtot < thresh)

        threshold_indices = abs(fluxtot) < thresh
        fluxtot[threshold_indices] = 0
        
        maxfluxtot = np.amax(np.absolute(fluxtot))
        maxflux.append(maxfluxtot)

        # update s
        q2 = f2 * (fluxtot + kr1 * (flux_g2 - flux_g1))
        q1 = f1 * (fluxtot + kr2 * (flux_g1 - flux_g2))
        q2[bnd_faces]=0
        q1[bnd_faces]=0
        assert np.allclose(q1+q2, fluxtot)

        # check courant number
        q2max = np.zeros(g.num_cells)
        q1max = np.zeros(g.num_cells)
        for j in range (0, g.num_cells):
            faces_of_cell = g.cell_faces.indices[g.cell_faces.indptr[j] : g.cell_faces.indptr[j+1]]
            for i in range (0, faces_of_cell.size):
                q2max[j] += np.absolute(q2[faces_of_cell[i]]) / g.cell_volumes[j]
                q1max[j] += np.absolute(q1[faces_of_cell[i]]) / g.cell_volumes[j]

        courant = 0.5 * max(np.amax(q2max), np.amax(q1max)) * time_step

        div_q2 = div * q2
        threshold_indices = abs(div_q2) < thresh
        div_q2[threshold_indices] = 0

        s = s + time_step / phi / g.cell_volumes * (rhs2 - div_q2)

        if not np.all(s >= 0.0):
            inds=np.argwhere(s<0.0)
            print(k, inds, s[inds])
            assert False
        if not np.all(s <= 1.0):
            inds=np.argwhere(s>1.0)
            #print(k, inds, s[inds])
            assert np.all(s[inds] < 1. + 1.0e-12)
            s[inds] = 1.
            #assert False
            

        mass_error = (np.sum(s*g.cell_volumes) - np.sum(s*g.cell_volumes)) / np.sum(s*g.cell_volumes)

        if abs(mass_error) > tol_mc:
            print('error in mass conservation')
            print(t, mass_error)
            break

        s_diff = s - s_ex
        s_err=np.sqrt(np.sum(g.cell_volumes * s_diff**2))/np.sqrt(np.sum(g.cell_volumes * s_ex**2))

        p_diff = p - p_ex
        p_err=np.sqrt(np.sum(g.cell_volumes * p_diff**2))/np.sqrt(np.sum(g.cell_volumes * p_ex**2))
        
        sat_err.append(s_err)
        pres_err.append(p_err)
        time.append(t)

        #time_steps.append(t)
        #save.write_vtk({"s": s}, time_step=k)

        if k % 100 == 0:
            print(t, mass_error, maxfluxtot, s_err, p_err)
            F = courant_max / courant
            if F > 1.:
                adjust_time_step = min(min(F, 1. + 0.1 * F), 1.2)
                time_step *= adjust_time_step
                print(time_step)

        #time_steps_vec.append(t)
        #i += 1
        """
        if k % 500 == 0 and t < 1.0e8:
            Q_n = fluxtot * g.face_normals
            solver_flow = pp.MVEM("flow")
            P0u = solver_flow.project_flux(g, fluxtot, data)
            #pp.plot_grid(g, p, P0u * 5e7, figsize=(15, 12))
            #pp.plot_grid(g, s_0, figsize=(15, 12), alpha = 0.9, color_map=(0,1))
            pp.plot_grid(g, s, vector_value=Q_n, figsize=(15, 12), vector_scale=1e7, alpha = 0.9, color_map=(0,1))
            #save.write_vtk({"s": s}, time_step=i)


        Q_n = fluxtot * g.face_normals
        pp.plot_grid(g, vector_value=Q_n, figsize=(15, 12), vector_scale=5e7)
        Q_1 = q1 * g.face_normals
        pp.plot_grid(g, vector_value=Q_1, figsize=(15, 12), vector_scale=5e7)
        Q_2 = q2 * g.face_normals
        pp.plot_grid(g, vector_value=Q_2, figsize=(15, 12), vector_scale=5e7)
        """

            
    #save.write_pvd(np.array(time_steps_vec))

    p_diff = p - p_ex
    s_diff = s - s_ex
    p_err=np.sqrt(np.sum(g.cell_volumes * p_diff**2))/np.sqrt(np.sum(g.cell_volumes * p_ex**2))
    s_err=np.sqrt(np.sum(g.cell_volumes * s_diff**2))/np.sqrt(np.sum(g.cell_volumes * s_ex**2))

    mass_error = (np.sum(s*g.cell_volumes) - np.sum(s*g.cell_volumes)) / np.sum(s*g.cell_volumes)
    print('error in mass conservation', mass_error)

    print('error in saturation ', s_err)
    print('error in pressure ', p_err)
    
    pp.plot_grid(g, s, figsize=(15, 12))
    pp.plot_grid(g, p, figsize=(15, 12))

    Q_n = fluxtot * g.face_normals
    solver_flow = pp.MVEM("flow")
    P0u = solver_flow.project_flux(g, fluxtot, data)
    #pp.plot_grid(g, p, P0u * 5e7, figsize=(15, 12))
    #pp.plot_grid(g, s_0, figsize=(15, 12), alpha = 0.9, color_map=(0,1))
    #pp.plot_grid(g, s, vector_value=Q_n, figsize=(15, 12), vector_scale=1e7, alpha = 0.9, color_map=(0,1))
    #save.write_vtk({"s": s}, time_step=i)

    #save.write_vtk({"p": p, 's_0' : s_0, 's_f' : s})

    return time, sat_err, pres_err, maxflux
Ejemplo n.º 20
0
    def matrix_rhs(self, g, data):
        """
        Return the matrix and righ-hand side for a discretization of a second
        order elliptic equation using hybrid dual virtual element method.
        The name of data in the input dictionary (data) are:
        perm : tensor.SecondOrderTensor
            Permeability defined cell-wise. If not given a identity permeability
            is assumed and a warning arised.
        source : array (self.g.num_cells)
            Scalar source term defined cell-wise. If not given a zero source
            term is assumed and a warning arised.
        bc : boundary conditions (optional)
        bc_val : dictionary (optional)
            Values of the boundary conditions. The dictionary has at most the
            following keys: 'dir' and 'neu', for Dirichlet and Neumann boundary
            conditions, respectively.

        Parameters
        ----------
        g : grid, or a subclass, with geometry fields computed.
        data: dictionary to store the data.

        Return
        ------
        matrix: sparse csr (g.num_faces+g_num_cells, g.num_faces+g_num_cells)
            Saddle point matrix obtained from the discretization.
        rhs: array (g.num_faces+g_num_cells)
            Right-hand side which contains the boundary conditions and the scalar
            source term.

        Examples
        --------
        b_faces_neu = ... # id of the Neumann faces
        b_faces_dir = ... # id of the Dirichlet faces
        bnd = bc.BoundaryCondition(g, np.hstack((b_faces_dir, b_faces_neu)),
                                ['dir']*b_faces_dir.size + ['neu']*b_faces_neu.size)
        bnd_val = {'dir': fun_dir(g.face_centers[:, b_faces_dir]),
                   'neu': fun_neu(f.face_centers[:, b_faces_neu])}

        data = {'perm': perm, 'source': f, 'bc': bnd, 'bc_val': bnd_val}

        H, rhs = hybrid.matrix_rhs(g, data)
        l = sps.linalg.spsolve(H, rhs)
        u, p = hybrid.compute_up(g, l, data)
        P0u = dual.project_u(g, perm, u)

        """
        # pylint: disable=invalid-name

        # If a 0-d grid is given then we return an identity matrix
        if g.dim == 0:
            return sps.identity(self.ndof(g), format="csr"), np.zeros(1)

        parameter_dictionary = data[pp.PARAMETERS][self.keyword]
        k = parameter_dictionary["second_order_tensor"]
        f = parameter_dictionary["source"]
        bc = parameter_dictionary["bc"]
        bc_val = parameter_dictionary["bc_values"]
        a = parameter_dictionary["aperture"]

        faces, _, sgn = sps.find(g.cell_faces)

        # Map the domain to a reference geometry (i.e. equivalent to compute
        # surface coordinates in 1d and 2d)
        c_centers, f_normals, f_centers, _, _, _ = pp.map_geometry.map_grid(g)

        # Weight for the stabilization term
        diams = g.cell_diameters()
        weight = np.power(diams, 2 - g.dim)

        # Allocate the data to store matrix entries, that's the most efficient
        # way to create a sparse matrix.
        size = np.sum(
            np.square(g.cell_faces.indptr[1:] - g.cell_faces.indptr[:-1]))
        row = np.empty(size, dtype=np.int)
        col = np.empty(size, dtype=np.int)
        data = np.empty(size)
        rhs = np.zeros(g.num_faces)

        idx = 0
        # Use a dummy keyword to trick the constructor of dualVEM.
        massHdiv = pp.MVEM("dummy").massHdiv

        # define the function to compute the inverse of the permeability matrix
        if g.dim == 1:
            inv_matrix = DualElliptic._inv_matrix_1d
        elif g.dim == 2:
            inv_matrix = DualElliptic._inv_matrix_2d
        elif g.dim == 3:
            inv_matrix = DualElliptic._inv_matrix_3d

        for c in np.arange(g.num_cells):
            # For the current cell retrieve its faces
            loc = slice(g.cell_faces.indptr[c], g.cell_faces.indptr[c + 1])
            faces_loc = faces[loc]
            ndof = faces_loc.size

            # Retrieve permeability and normals assumed outward to the cell.
            sgn_loc = sgn[loc].reshape((-1, 1))
            normals = np.multiply(np.tile(sgn_loc.T, (g.dim, 1)),
                                  f_normals[:, faces_loc])

            # Compute the H_div-mass local matrix
            A = massHdiv(
                k.values[0:g.dim, 0:g.dim, c],
                inv_matrix(k.values[0:g.dim, 0:g.dim, c]),
                c_centers[:, c],
                a[c] * g.cell_volumes[c],
                f_centers[:, faces_loc],
                a[c] * normals,
                np.ones(ndof),
                diams[c],
                weight[c],
            )[0]
            # Compute the Div local matrix
            B = -np.ones((ndof, 1))
            # Compute the hybrid local matrix
            C = np.eye(ndof, ndof)

            # Perform the static condensation to compute the hybrid local matrix
            invA = np.linalg.inv(A)
            S = 1 / np.dot(B.T, np.dot(invA, B))
            L = np.dot(np.dot(invA, np.dot(B, np.dot(S, B.T))), invA)
            L = np.dot(np.dot(C.T, L - invA), C)

            # Compute the local hybrid right using the static condensation
            rhs[faces_loc] += np.dot(C.T,
                                     np.dot(invA,
                                            np.dot(B, np.dot(S, f[c]))))[:, 0]

            # Save values for hybrid matrix
            indices = np.tile(faces_loc, (faces_loc.size, 1))
            loc_idx = slice(idx, idx + indices.size)
            row[loc_idx] = indices.T.ravel()
            col[loc_idx] = indices.ravel()
            data[loc_idx] = L.ravel()
            idx += indices.size

        # construct the global matrices
        H = sps.coo_matrix((data, (row, col))).tocsr()

        # Apply the boundary conditions
        if bc is not None:

            if np.any(bc.is_dir):
                norm = sps.linalg.norm(H, np.inf)
                is_dir = np.where(bc.is_dir)[0]

                H[is_dir, :] *= 0
                H[is_dir, is_dir] = norm
                rhs[is_dir] = norm * bc_val[is_dir]

            if np.any(bc.is_neu):
                faces, _, sgn = sps.find(g.cell_faces)
                sgn = sgn[np.unique(faces, return_index=True)[1]]

                is_neu = np.where(bc.is_neu)[0]
                rhs[is_neu] += sgn[is_neu] * bc_val[is_neu] * g.face_areas[
                    is_neu]

        return H, rhs
Ejemplo n.º 21
0
    def test_convergence_mvem_2d_iso_simplex(self):

        a = 8 * np.pi ** 2
        rhs_ex = lambda pt: np.multiply(
            np.sin(2 * np.pi * pt[0, :]), np.sin(2 * np.pi * pt[1, :])
        )
        p_ex = lambda pt: rhs_ex(pt) / a
        u_ex_0 = (
            lambda pt: np.multiply(
                -np.cos(2 * np.pi * pt[0, :]), np.sin(2 * np.pi * pt[1, :])
            )
            * 2
            * np.pi
            / a
            + 1
        )
        u_ex_1 = (
            lambda pt: np.multiply(
                -np.sin(2 * np.pi * pt[0, :]), np.cos(2 * np.pi * pt[1, :])
            )
            * 2
            * np.pi
            / a
        )

        p_errs_known = np.array(
            [
                0.007347293666843033,
                0.004057878042430692,
                0.002576479539795832,
                0.0017817307824819935,
                0.0013057660031758425,
            ]
        )

        u_errs_known = np.array(
            [
                0.024425617686195774,
                0.016806807988931565,
                0.012859109258624922,
                0.010445238111710832,
                0.00881184436169123,
            ]
        )

        for i, p_err_known, u_err_known in zip(
            np.arange(5), p_errs_known, u_errs_known
        ):
            g = pp.StructuredTriangleGrid([3 + i] * 2, [1, 1])
            g.compute_geometry()

            kxx = np.ones(g.num_cells)
            perm = pp.SecondOrderTensor(kxx=kxx, kyy=kxx, kzz=1)
            bf = g.get_boundary_faces()
            bc = pp.BoundaryCondition(g, bf, bf.size * ["dir"])
            bc_val = np.zeros(g.num_faces)
            bc_val[bf] = p_ex(g.face_centers[:, bf])
            # Minus sign to move to rhs
            source = np.multiply(g.cell_volumes, rhs_ex(g.cell_centers))
            vect = np.vstack(
                (g.cell_volumes, np.zeros(g.num_cells), np.zeros(g.num_cells))
            ).ravel(order="F")

            solver = pp.MVEM(keyword="flow")
            solver_rhs = pp.DualScalarSource(keyword="flow")

            specified_parameters = {
                "bc": bc,
                "bc_values": bc_val,
                "second_order_tensor": perm,
                "source": source,
                "vector_source": vect,
            }
            data = pp.initialize_default_data(g, {}, "flow", specified_parameters)

            solver.discretize(g, data)
            solver_rhs.discretize(g, data)

            M, rhs_bc = solver.assemble_matrix_rhs(g, data)
            _, rhs = solver_rhs.assemble_matrix_rhs(g, data)

            up = sps.linalg.spsolve(M, rhs_bc + rhs)
            p = solver.extract_pressure(g, up, data)
            err = np.sqrt(
                np.sum(
                    np.multiply(g.cell_volumes, np.power(p - p_ex(g.cell_centers), 2))
                )
            )
            self.assertTrue(np.isclose(err, p_err_known))

            _ = data[pp.DISCRETIZATION_MATRICES]["flow"][solver.vector_proj_key]
            u = solver.extract_flux(g, up, data)
            P0u = solver.project_flux(g, u, data)
            uu_ex_0 = u_ex_0(g.cell_centers)
            uu_ex_1 = u_ex_1(g.cell_centers)
            uu_ex_2 = np.zeros(g.num_cells)
            uu_ex = np.vstack((uu_ex_0, uu_ex_1, uu_ex_2))
            err = np.sqrt(
                np.sum(
                    np.multiply(
                        g.cell_volumes, np.sum(np.power(P0u - uu_ex, 2), axis=0)
                    )
                )
            )
            self.assertTrue(np.isclose(err, u_err_known))
Ejemplo n.º 22
0
    def test_convergence_mvem_2d_ani_simplex(self):

        rhs_ex = lambda pt: 14
        p_ex = (
            lambda pt: 2 * np.power(pt[0, :], 2)
            - 6 * np.power(pt[1, :], 2)
            + np.multiply(pt[0, :], pt[1, :])
        )
        u_ex_0 = lambda pt: -9 * pt[0, :] + 10 * pt[1, :] + 4
        u_ex_1 = lambda pt: -6 * pt[0, :] + 23 * pt[1, :] + 5

        p_errs_known = np.array(
            [
                0.2411784823808065,
                0.13572349427526526,
                0.08688469978140642,
                0.060345813825004285,
                0.044340156291519606,
            ]
        )
        u_errs_known = np.array(
            [
                1.7264059760345327,
                1.3416423116340397,
                1.0925566034251672,
                0.9198698104736416,
                0.7936243780450764,
            ]
        )

        for i, p_err_known, u_err_known in zip(
            np.arange(5), p_errs_known, u_errs_known
        ):
            g = pp.StructuredTriangleGrid([3 + i] * 2, [1, 1])
            g.compute_geometry()

            kxx = 2 * np.ones(g.num_cells)
            kxy = np.ones(g.num_cells)
            perm = pp.SecondOrderTensor(kxx=kxx, kyy=kxx, kxy=kxy, kzz=1)
            bf = g.get_boundary_faces()
            bc = pp.BoundaryCondition(g, bf, bf.size * ["dir"])
            bc_val = np.zeros(g.num_faces)
            bc_val[bf] = p_ex(g.face_centers[:, bf])
            # Minus sign to move to rhs
            source = np.multiply(g.cell_volumes, rhs_ex(g.cell_centers))
            vect = np.vstack(
                (g.cell_volumes, 2 * g.cell_volumes, np.zeros(g.num_cells))
            ).ravel(order="F")

            solver = pp.MVEM(keyword="flow")
            solver_rhs = pp.DualScalarSource(keyword="flow")

            specified_parameters = {
                "bc": bc,
                "bc_values": bc_val,
                "second_order_tensor": perm,
                "source": source,
                "vector_source": vect,
            }
            data = pp.initialize_default_data(g, {}, "flow", specified_parameters)

            solver.discretize(g, data)
            solver_rhs.discretize(g, data)
            M, rhs_bc = solver.assemble_matrix_rhs(g, data)
            _, rhs = solver_rhs.assemble_matrix_rhs(g, data)

            up = sps.linalg.spsolve(M, rhs_bc + rhs)
            p = solver.extract_pressure(g, up, data)
            err = np.sqrt(
                np.sum(
                    np.multiply(g.cell_volumes, np.power(p - p_ex(g.cell_centers), 2))
                )
            )
            self.assertTrue(np.isclose(err, p_err_known))

            P = data[pp.DISCRETIZATION_MATRICES]["flow"][solver.vector_proj_key]
            u = solver.extract_flux(g, up, data)
            P0u = solver.project_flux(g, u, data)
            uu_ex_0 = u_ex_0(g.cell_centers)
            uu_ex_1 = u_ex_1(g.cell_centers)
            uu_ex_2 = np.zeros(g.num_cells)
            uu_ex = np.vstack((uu_ex_0, uu_ex_1, uu_ex_2))
            err = np.sqrt(
                np.sum(
                    np.multiply(
                        g.cell_volumes, np.sum(np.power(P0u - uu_ex, 2), axis=0)
                    )
                )
            )
            self.assertTrue(np.isclose(err, u_err_known))