예제 #1
0
    def test_upwind_2d_cart_darcy_flux_positive(self):
        g = pp.CartGrid([3, 2], [1, 1])
        g.compute_geometry()

        solver = pp.Upwind()
        dis = solver.darcy_flux(g, [2, 0, 0])

        bf = g.tags["domain_boundary_faces"].nonzero()[0]
        bc = pp.BoundaryCondition(g, bf, bf.size * ["neu"])
        specified_parameters = {"bc": bc, "darcy_flux": dis}
        data = pp.initialize_default_data(g, {}, "transport", specified_parameters)

        solver.discretize(g, data)

        M = solver.assemble_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
        self.assertTrue(np.allclose(M, M_known, rtol, atol))
        self.assertTrue(np.allclose(deltaT, deltaT_known, rtol, atol))
예제 #2
0
    def test_upwind_1d_darcy_flux_negative_bc_neu(self):
        g = pp.CartGrid(3, 1)
        g.compute_geometry()

        solver = pp.Upwind()
        dis = solver.darcy_flux(g, [-2, 0, 0])

        bf = g.tags["domain_boundary_faces"].nonzero()[0]
        bc = pp.BoundaryCondition(g, bf, bf.size * ["neu"])
        bc_val = np.array([2, 0, 0, -2]).ravel("F")
        specified_parameters = {"bc": bc, "bc_values": bc_val, "darcy_flux": dis}
        data = pp.initialize_default_data(g, {}, "transport", specified_parameters)

        solver.discretize(g, data)

        M, rhs = solver.assemble_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
        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))
예제 #3
0
    def test_upwind_2d_simplex_surf_darcy_flux_negative(self):
        g = pp.StructuredTriangleGrid([2, 1], [1, 1])
        R = pp.map_geometry.rotation_matrix(-np.pi / 5.0, [1, 1, -1])
        g.nodes = np.dot(R, g.nodes)
        g.compute_geometry()

        solver = pp.Upwind()
        dis = solver.darcy_flux(g, np.dot(R, [-1, 0, 0]))

        bf = g.tags["domain_boundary_faces"].nonzero()[0]
        bc = pp.BoundaryCondition(g, bf, bf.size * ["neu"])
        specified_parameters = {"bc": bc, "darcy_flux": dis}
        data = pp.initialize_default_data(g, {}, "transport", specified_parameters)

        solver.discretize(g, data)

        M = solver.assemble_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
        self.assertTrue(np.allclose(M, M_known, rtol, atol))
        self.assertTrue(np.allclose(deltaT, deltaT_known, rtol, atol))
예제 #4
0
    def test_upwind_example_2(self, if_export=False):
        #######################
        # Simple 2d upwind problem with implicit Euler scheme in time
        #######################
        T = 1
        Nx, Ny = 10, 1
        g = pp.CartGrid([Nx, Ny], [1, 1])
        g.compute_geometry()

        advect = pp.Upwind("transport")
        dis = advect.darcy_flux(g, [1, 0, 0])

        b_faces = g.get_all_boundary_faces()
        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)
        time_step = advect.cfl(g, data)
        data[pp.PARAMETERS]["transport"]["time_step"] = time_step

        advect.discretize(g, data)
        U, rhs = advect.assemble_matrix_rhs(g, data)
        rhs = time_step * rhs
        U = time_step * U
        mass = pp.MassMatrix("transport")
        mass.discretize(g, data)
        M, _ = mass.assemble_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 / time_step)
        time = np.empty(Nt)
        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] = time_step * i

        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)
예제 #5
0
    def test_upwind_example_1(self, if_export=False):
        #######################
        # Simple 2d upwind problem with explicit Euler scheme in time
        #######################
        T = 1
        Nx, Ny = 4, 1
        g = pp.CartGrid([Nx, Ny], [1, 1])
        g.compute_geometry()

        advect = pp.Upwind("transport")
        dis = advect.darcy_flux(g, [1, 0, 0])

        b_faces = g.get_all_boundary_faces()
        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)
        time_step = advect.cfl(g, data)
        data[pp.PARAMETERS]["transport"]["time_step"] = time_step

        advect.discretize(g, data)

        U, rhs = advect.assemble_matrix_rhs(g, data)
        rhs = time_step * rhs
        U = time_step * U
        OF = advect.outflow(g, data)
        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)
        production = np.zeros(Nt)
        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] = time_step * i

        known = 1.09375
        assert np.sum(production) == known
예제 #6
0
    def __init__(self, keyword, grids):
        if isinstance(grids, list):
            self._grids = grids
        else:
            self._grids = [grids]
        self._discretization = pp.Upwind(keyword)
        self._name = "Upwind"
        self.keyword = keyword

        self.upwind: _MergedOperator
        self.rhs: _MergedOperator
        self.outflow_neumann: _MergedOperator
        _wrap_discretization(self, self._discretization, grids)
예제 #7
0
def advdiff(gb, param, model_flow):

    model = "transport"

    model_data_adv, model_data_diff = data.advdiff(gb, model, model_flow,
                                                   param)

    # discretization operator names
    adv_id = "advection"
    diff_id = "diffusion"

    # variable names
    variable = "scalar"
    mortar_adv = "lambda_" + variable + "_" + adv_id
    mortar_diff = "lambda_" + variable + "_" + diff_id

    # discretization operatr
    discr_adv = pp.Upwind(model_data_adv)
    discr_diff = pp.Tpfa(model_data_diff)

    coupling_adv = pp.UpwindCoupling(model_data_adv)
    coupling_diff = pp.RobinCoupling(model_data_diff, discr_diff)

    for g, d in gb:
        d[pp.PRIMARY_VARIABLES] = {variable: {"cells": 1}}
        d[pp.DISCRETIZATION] = {
            variable: {
                adv_id: discr_adv,
                diff_id: discr_diff
            }
        }

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

        d[pp.COUPLING_DISCRETIZATION] = {
            adv_id: {
                g_slave: (variable, adv_id),
                g_master: (variable, adv_id),
                e: (mortar_adv, coupling_adv)
            },
            diff_id: {
                g_slave: (variable, diff_id),
                g_master: (variable, diff_id),
                e: (mortar_diff, coupling_diff)
            }
        }

    # setup the advection-diffusion problem
    assembler = pp.Assembler()
    logger.info(
        "Assemble the advective and diffusive terms of the transport problem")
    A, b, block_dof, full_dof = assembler.assemble_matrix_rhs(gb)
    logger.info("done")

    # mass term
    mass_id = "mass"
    discr_mass = pp.MassMatrix(model_data_adv)

    for g, d in gb:
        d[pp.PRIMARY_VARIABLES] = {variable: {"cells": 1}}
        d[pp.DISCRETIZATION] = {variable: {mass_id: discr_mass}}

    gb.remove_edge_props(pp.COUPLING_DISCRETIZATION)

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

    logger.info("Assemble the mass term of the transport problem")
    M, _, _, _ = assembler.assemble_matrix_rhs(gb)
    logger.info("done")

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

    # time loop
    logger.info("Prepare the exporting")
    save = pp.Exporter(gb, "solution", folder=param["folder"])
    logger.info("done")
    variables = [variable, param["pressure"], param["P0_flux"]]

    x = np.ones(A.shape[0]) * param["initial_advdiff"]
    logger.info("Start the time loop with " + str(param["n_steps"]) + " steps")
    for i in np.arange(param["n_steps"]):
        #x = IE_solver(b + M.dot(x))
        logger.info("Solve the linear system for time step " + str(i))
        x = sps.linalg.spsolve(M + A, b + M.dot(x))
        logger.info("done")

        logger.info("Variable post-process")
        assembler.distribute_variable(gb, x, block_dof, full_dof)
        logger.info("done")

        logger.info("Export variable")
        save.write_vtk(variables, time_step=i)
        logger.info("done")

    save.write_pvd(np.arange(param["n_steps"]) * param["time_step"])
예제 #8
0
def permeability_upscaling(network,
                           data,
                           mesh_args,
                           directions,
                           do_viz=True,
                           tracer_transport=False):
    """ Compute bulk permeabilities for a 2d domain with a fracture network.

    The function sets up a flow field in the specified directions, and calculates
    an upscaled permeability of corresponding to the calculated flow configuration.

    Parameters:
        network (pp.FractureNetwork2d): Network, with domain.
        data (dictionary): Data to be specified.
        mesh_args (dictionray): Parameters for meshing. See FractureNetwork2d.mesh()
            for details.
        directions (np.array): Directions to upscale permeabilities.
            Indicated by 0 (x-direction) and or 1 (y-direction).

    Returns:
        np.array, dim directions.size: Upscaled permeability in each of the directions.
        sim_info: Various information on the time spent on this simulation.

    """

    directions = np.asarray(directions)
    upscaled_perm = np.zeros(directions.size)

    sim_info = {}

    for di, direct in enumerate(directions):

        tic = time.time()
        filename = str(uuid.uuid4())
        gb = network.mesh(tol=network.tol,
                          mesh_args=mesh_args,
                          file_name=filename)

        toc = time.time()
        if di == 0:
            sim_info["num_cells_2d"] = gb.grids_of_dimension(2)[0].num_cells
            sim_info["time_for_meshing"] = toc - tic

        gb = _setup_simulation_flow(gb, data, direct)

        pressure_kw = "flow"

        mpfa = pp.Mpfa(pressure_kw)
        for g, d in gb:
            d[pp.PRIMARY_VARIABLES] = {"pressure": {"cells": 1}}
            d[pp.DISCRETIZATION] = {"pressure": {"diffusive": mpfa}}

        coupler = pp.RobinCoupling(pressure_kw, mpfa)
        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            d[pp.PRIMARY_VARIABLES] = {"mortar_darcy_flux": {"cells": 1}}
            d[pp.COUPLING_DISCRETIZATION] = {
                "lambda": {
                    g1: ("pressure", "diffusive"),
                    g2: ("pressure", "diffusive"),
                    e: ("mortar_darcy_flux", coupler),
                }
            }

        assembler = pp.Assembler(gb)
        assembler.discretize()
        # Discretize
        tic = time.time()
        A, b = assembler.assemble_matrix_rhs()
        if di == 0:
            toc = time.time()
            sim_info["Time_for_assembly"] = toc - tic
        tic = time.time()
        p = spla.spsolve(A, b)
        if di == 0:
            toc = time.time()
            sim_info["Time_for_pressure_solve"] = toc - tic

        assembler.distribute_variable(p)

        # Post processing to recover flux
        tot_pressure = 0
        tot_area = 0
        tot_inlet_flux = 0
        for g, d in gb:
            # Inlet faces of this grid
            inlet = d.get("inlet_faces", None)
            # If no inlet, no need to do anything
            if inlet is None or inlet.size == 0:
                continue

            # Compute flux field in the grid
            # Internal flux
            flux = (d[pp.DISCRETIZATION_MATRICES][pressure_kw]["flux"] *
                    d[pp.STATE]["pressure"])
            # Contribution from the boundary
            bound_flux_discr = d[
                pp.DISCRETIZATION_MATRICES][pressure_kw]["bound_flux"]
            flux += bound_flux_discr * d["parameters"][pressure_kw]["bc_values"]
            # Add contribution from all neighboring lower-dimensional interfaces
            for e, d_e in gb.edges_of_node(g):
                mg = d_e["mortar_grid"]
                if mg.dim == g.dim - 1:
                    flux += (bound_flux_discr * mg.mortar_to_master_int() *
                             d_e[pp.STATE]["mortar_darcy_flux"])

            # Add contribution to total inlet flux
            tot_inlet_flux += np.abs(flux[inlet]).sum()

            # Next, find the pressure at the inlet faces
            # The pressure is calculated as the values in the neighboring cells,
            # plus an offset from the incell-variations
            pressure_cell = (d[pp.DISCRETIZATION_MATRICES][pressure_kw]
                             ["bound_pressure_cell"] * d[pp.STATE]["pressure"])
            pressure_flux = (d[pp.DISCRETIZATION_MATRICES][pressure_kw]
                             ["bound_pressure_face"] *
                             d["parameters"][pressure_kw]["bc_values"])
            inlet_pressure = pressure_cell[inlet] + pressure_flux[inlet]
            # Scale the pressure at the face with the face length.
            # Also include an aperture scaling here: For the highest dimensional grid, this
            # will be as scaling with 1.
            aperture = d[pp.PARAMETERS][pressure_kw]["aperture"][0]
            tot_pressure += np.sum(inlet_pressure * g.face_areas[inlet] *
                                   aperture)
            # Add to the toal outlet area
            tot_area += g.face_areas[inlet].sum() * aperture
            # Also compute the cross sectional area of the domain
            if g.dim == gb.dim_max():
                # Extension of the domain in the active direction
                dx = g.nodes[direct].max() - g.nodes[direct].min()

        # Mean pressure at the inlet, which will also be mean pressure difference
        # over the domain
        mean_pressure = tot_pressure / tot_area

        # The upscaled permeability
        upscaled_perm[di] = (tot_inlet_flux / tot_area) * dx / mean_pressure
        # End of post processing for permeability upscaling

        if tracer_transport:

            _setup_simulation_tracer(gb, data, direct)

            tracer_variable = "temperature"

            temperature_kw = "transport"
            mortar_variable = "lambda_adv"

            # Identifier of the two terms of the equation
            adv = "advection"

            advection_term = "advection"
            mass_term = "mass"
            advection_coupling_term = "advection_coupling"

            adv_discr = pp.Upwind(temperature_kw)

            adv_coupling = pp.UpwindCoupling(temperature_kw)

            mass_discretization = pp.MassMatrix(temperature_kw)

            for g, d in gb:
                d[pp.PRIMARY_VARIABLES] = {tracer_variable: {"cells": 1}}
                d[pp.DISCRETIZATION] = {
                    tracer_variable: {
                        advection_term: adv_discr,
                        mass_term: mass_discretization,
                    }
                }

            for e, d in gb.edges():
                g1, g2 = gb.nodes_of_edge(e)
                d[pp.PRIMARY_VARIABLES] = {mortar_variable: {"cells": 1}}
                d[pp.COUPLING_DISCRETIZATION] = {
                    advection_coupling_term: {
                        g1: (tracer_variable, adv),
                        g2: (tracer_variable, adv),
                        e: (mortar_variable, adv_coupling),
                    }
                }

            pp.fvutils.compute_darcy_flux(gb,
                                          keyword_store=temperature_kw,
                                          lam_name="mortar_darcy_flux")

            A, b, block_dof, full_dof = assembler.assemble_matrix_rhs(
                gb,
                active_variables=[tracer_variable, mortar_variable],
                add_matrices=False,
            )

            advection_coupling_term += ("_" + mortar_variable + "_" +
                                        tracer_variable + "_" +
                                        tracer_variable)

            mass_term += "_" + tracer_variable
            advection_term += "_" + tracer_variable

            lhs = A[mass_term] + data["time_step"] * (
                A[advection_term] + A[advection_coupling_term])
            rhs_source_adv = data["time_step"] * (b[advection_term] +
                                                  b[advection_coupling_term])

            IEsolver = spla.factorized(lhs)

            save_every = 10
            n_steps = int(np.round(data["t_max"] / data["time_step"]))

            # Initial condition
            tracer = np.zeros(rhs_source_adv.size)
            assembler.distribute_variable(
                gb,
                tracer,
                block_dof,
                full_dof,
                variable_names=[tracer_variable, mortar_variable],
            )

            # Exporter
            exporter = pp.Exporter(gb, name=tracer_variable, folder="viz_tmp")
            export_fields = [tracer_variable]

            for i in range(n_steps):

                if np.isclose(i % save_every, 0):
                    # Export existing solution (final export is taken care of below)
                    assembler.distribute_variable(
                        gb,
                        tracer,
                        block_dof,
                        full_dof,
                        variable_names=[tracer_variable, mortar_variable],
                    )
                    exporter.write_vtk(export_fields,
                                       time_step=int(i // save_every))
                tracer = IEsolver(A[mass_term] * tracer + rhs_source_adv)

            exporter.write_vtk(export_fields,
                               time_step=(n_steps // save_every))
            time_steps = np.arange(0, data["t_max"] + data["time_step"],
                                   save_every * data["time_step"])
            exporter.write_pvd(time_steps)

    return upscaled_perm, sim_info
예제 #9
0
def transport(gb, data, solver_name, folder, callback=None, save_every=1):
    grid_variable = "tracer"
    mortar_variable = "mortar_tracer"
    kw = "transport"
    # Identifier of the discretization operator on each grid
    advection_term = "advection"
    source_term = "source"
    mass_term = "mass"

    # Identifier of the discretization operator between grids
    advection_coupling_term = "advection_coupling"

    # Discretization objects
    node_discretization = pp.Upwind(kw)
    source_discretization = pp.ScalarSource(kw)
    mass_discretization = pp.MassMatrix(kw)
    edge_discretization = pp.UpwindCoupling(kw)

    # Loop over the nodes in the GridBucket, define primary variables and discretization schemes
    for g, d in gb:
        # Assign primary variables on this grid. It has one degree of freedom per cell.
        d[pp.PRIMARY_VARIABLES] = {grid_variable: {"cells": 1, "faces": 0}}
        # Assign discretization operator for the variable.
        d[pp.DISCRETIZATION] = {
            grid_variable: {
                advection_term: node_discretization,
                source_term: source_discretization,
                mass_term: mass_discretization,
            }
        }

    # Loop over the edges in the GridBucket, define primary variables and discretizations
    for e, d in gb.edges():
        g1, g2 = gb.nodes_of_edge(e)
        # The mortar variable has one degree of freedom per cell in the mortar grid
        d[pp.PRIMARY_VARIABLES] = {mortar_variable: {"cells": 1}}

        d[pp.COUPLING_DISCRETIZATION] = {
            advection_coupling_term: {
                g1: (grid_variable, advection_term),
                g2: (grid_variable, advection_term),
                e: (mortar_variable, edge_discretization),
            }
        }
        d[pp.DISCRETIZATION_MATRICES] = {kw: {}}

    assembler = pp.Assembler()

    # Assemble the linear system, using the information stored in the GridBucket. By
    # not adding the matrices, we can arrange them at will to obtain the efficient
    # solver defined below, which LU factorizes the system only once for all time steps.
    A, b, block_dof, full_dof = assembler.assemble_matrix_rhs(
        gb,
        active_variables=[grid_variable, mortar_variable],
        add_matrices=False)

    advection_coupling_term += ("_" + mortar_variable + "_" + grid_variable +
                                "_" + grid_variable)
    mass_term += "_" + grid_variable
    advection_term += "_" + grid_variable
    source_term += "_" + grid_variable

    lhs = A[mass_term] + data["time_step"] * (A[advection_term] +
                                              A[advection_coupling_term])
    rhs_source_adv = b[source_term] + data["time_step"] * (
        b[advection_term] + b[advection_coupling_term])

    IEsolver = sps.linalg.factorized(lhs)
    n_steps = int(np.round(data["t_max"] / data["time_step"]))

    # Initial condition
    tracer = np.zeros(rhs_source_adv.size)
    assembler.distribute_variable(
        gb,
        tracer,
        block_dof,
        full_dof,
        variable_names=[grid_variable, mortar_variable])

    # Exporter
    exporter = pp.Exporter(gb, name="tracer", folder=folder)
    export_fields = ["tracer"]

    # Keep track of the outflow for each time step
    outflow = np.empty(0)

    # Time loop
    for i in range(n_steps):
        # Export existing solution (final export is taken care of below)
        assembler.distribute_variable(
            gb,
            tracer,
            block_dof,
            full_dof,
            variable_names=[grid_variable, mortar_variable],
        )
        if np.isclose(i % save_every, 0):
            exporter.write_vtk(export_fields, time_step=int(i // save_every))
        tracer = IEsolver(A[mass_term] * tracer + rhs_source_adv)

        outflow = compute_flow_rate(gb, grid_variable, outflow)
        if callback is not None:
            callback(gb)

    exporter.write_vtk(export_fields, time_step=(n_steps // save_every))
    time_steps = np.arange(0, data["t_max"] + data["time_step"],
                           save_every * data["time_step"])
    exporter.write_pvd(time_steps)
    return tracer, outflow, A, b, block_dof, full_dof
예제 #10
0
    def test_upwind_coupling_3d_2d_1d_0d(self):
        f1 = np.array([[0, 1, 1, 0], [0, 0, 1, 1], [0.5, 0.5, 0.5, 0.5]])
        f2 = np.array([[0.5, 0.5, 0.5, 0.5], [0, 1, 1, 0], [0, 0, 1, 1]])
        f3 = np.array([[0, 1, 1, 0], [0.5, 0.5, 0.5, 0.5], [0, 0, 1, 1]])

        gb = pp.meshing.cart_grid([f1, f2, f3], [2, 2, 2],
                                  **{"physdims": [1, 1, 1]})
        gb.compute_geometry()
        gb.assign_node_ordering()

        cell_centers1 = np.array([[0.25, 0.75, 0.25, 0.75],
                                  [0.25, 0.25, 0.75, 0.75],
                                  [0.5, 0.5, 0.5, 0.5]])
        cell_centers2 = np.array([[0.5, 0.5, 0.5, 0.5],
                                  [0.25, 0.25, 0.75, 0.75],
                                  [0.75, 0.25, 0.75, 0.25]])
        cell_centers3 = np.array([[0.25, 0.75, 0.25,
                                   0.75], [0.5, 0.5, 0.5, 0.5],
                                  [0.25, 0.25, 0.75, 0.75]])
        cell_centers4 = np.array([[0.5], [0.25], [0.5]])
        cell_centers5 = np.array([[0.5], [0.75], [0.5]])
        cell_centers6 = np.array([[0.75], [0.5], [0.5]])
        cell_centers7 = np.array([[0.25], [0.5], [0.5]])
        cell_centers8 = np.array([[0.5], [0.5], [0.25]])
        cell_centers9 = np.array([[0.5], [0.5], [0.75]])

        for g, d in gb:
            if np.allclose(g.cell_centers[:, 0], cell_centers1[:, 0]):
                d["node_number"] = 1
            elif np.allclose(g.cell_centers[:, 0], cell_centers2[:, 0]):
                d["node_number"] = 2
            elif np.allclose(g.cell_centers[:, 0], cell_centers3[:, 0]):
                d["node_number"] = 3
            elif np.allclose(g.cell_centers[:, 0], cell_centers4[:, 0]):
                d["node_number"] = 4
            elif np.allclose(g.cell_centers[:, 0], cell_centers5[:, 0]):
                d["node_number"] = 5
            elif np.allclose(g.cell_centers[:, 0], cell_centers6[:, 0]):
                d["node_number"] = 6
            elif np.allclose(g.cell_centers[:, 0], cell_centers7[:, 0]):
                d["node_number"] = 7
            elif np.allclose(g.cell_centers[:, 0], cell_centers8[:, 0]):
                d["node_number"] = 8
            elif np.allclose(g.cell_centers[:, 0], cell_centers9[:, 0]):
                d["node_number"] = 9
            else:
                pass

        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            n1 = gb.node_props(g1, "node_number")
            n2 = gb.node_props(g2, "node_number")
            if n1 == 1 and n2 == 0:
                d["edge_number"] = 0
            elif n1 == 2 and n2 == 0:
                d["edge_number"] = 1
            elif n1 == 3 and n2 == 0:
                d["edge_number"] = 2
            elif n1 == 4 and n2 == 1:
                d["edge_number"] = 3
            elif n1 == 5 and n2 == 1:
                d["edge_number"] = 4
            elif n1 == 6 and n2 == 1:
                d["edge_number"] = 5
            elif n1 == 7 and n2 == 1:
                d["edge_number"] = 6
            elif n1 == 4 and n2 == 2:
                d["edge_number"] = 7
            elif n1 == 5 and n2 == 2:
                d["edge_number"] = 8
            elif n1 == 8 and n2 == 2:
                d["edge_number"] = 9
            elif n1 == 9 and n2 == 2:
                d["edge_number"] = 10
            elif n1 == 6 and n2 == 3:
                d["edge_number"] = 11
            elif n1 == 7 and n2 == 3:
                d["edge_number"] = 12
            elif n1 == 8 and n2 == 3:
                d["edge_number"] = 13
            elif n1 == 9 and n2 == 3:
                d["edge_number"] = 14
            elif n1 == 10 and n2 == 4:
                d["edge_number"] = 15
            elif n1 == 10 and n2 == 5:
                d["edge_number"] = 16
            elif n1 == 10 and n2 == 6:
                d["edge_number"] = 17
            elif n1 == 10 and n2 == 7:
                d["edge_number"] = 18
            elif n1 == 10 and n2 == 8:
                d["edge_number"] = 19
            elif n1 == 10 and n2 == 9:
                d["edge_number"] = 20
            else:
                raise ValueError

        # define discretization
        key = "transport"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        variable = "T"
        assign_discretization(gb, upwind, upwind_coupling, variable)

        # assign parameters
        tol = 1e-3
        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:
            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            specified_parameters = {"aperture": aperture}
            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            if bound_faces.size != 0:

                bound_face_centers = g.face_centers[:, bound_faces]

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

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

                bc_val = np.zeros(g.num_faces)
                bc_dir = bound_faces[np.logical_or(left, right)]
                bc_val[bc_dir] = 1

                bound = pp.BoundaryCondition(g, bound_faces, labels)
                specified_parameters.update({"bc": bound, "bc_values": bc_val})

            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [1, 0, 0], a)
        assembler = pp.Assembler(gb)

        assembler.discretize()
        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"
        U, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)

        theta = np.linalg.solve(U.A, rhs)
        #        deltaT = solver.cfl(gb)
        (
            U_known,
            rhs_known,
        ) = (_helper_test_upwind_coupling.
             matrix_rhs_for_test_upwind_coupling_3d_2d_1d_0d())

        theta_known = np.array([
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1,
            1,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            -0.25,
            -0.25,
            -0.25,
            -0.25,
            0.25,
            0.25,
            0.25,
            0.25,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            -5.0e-03,
            5.0e-03,
            -5.0e-03,
            5.0e-03,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            -5e-03,
            5e-03,
            -5e-03,
            5e-03,
            0,
            0,
            -1e-04,
            1e-04,
            0,
            0,
        ])

        rtol = 1e-15
        atol = rtol
        self.assertTrue(np.allclose(U.todense(), U_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))
예제 #11
0
    def test_upwind_coupling_2d_1d_left_right(self):
        gb, _ = pp.grid_buckets_2d.single_horizontal([1, 2], simplex=False)

        tol = 1e-3
        # define discretization
        key = "transport"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        variable = "T"
        assign_discretization(gb, upwind, upwind_coupling, variable)

        # assign parameters

        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:

            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            specified_parameters = {"aperture": aperture}
            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            if bound_faces.size != 0:
                bound_face_centers = g.face_centers[:, bound_faces]

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

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

                bc_val = np.zeros(g.num_faces)
                bc_dir = bound_faces[np.logical_or(left, right)]
                bc_val[bc_dir] = 1

                bound = pp.BoundaryCondition(g, bound_faces, labels)
                specified_parameters.update({"bc": bound, "bc_values": bc_val})

            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [1, 0, 0], a)

        assembler = pp.Assembler(gb)
        assembler.discretize()

        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"

        U, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)
        theta = np.linalg.solve(U.A, rhs)
        #        deltaT = solver.cfl(gb)

        U_known = np.array([
            [0.5, 0.0, 0.0, 0.0, 1.0],
            [0.0, 0.5, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.01, -1.0, -1.0],
            [0.0, 0.0, 0.0, -1.0, 0.0],
            [0.0, 0.0, 0.0, 0.0, -1.0],
        ])

        rhs_known = np.array([0.5, 0.5, 1e-2, 0, 0])
        theta_known = np.array([1, 1, 1, 0, 0])

        rtol = 1e-15
        atol = rtol
        self.assertTrue(np.allclose(U.todense(), U_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))
예제 #12
0
    def test_upwind_coupling_2d_1d_left_right_cross(self):
        gb, _ = pp.grid_buckets_2d.two_intersecting([2, 2], simplex=False)

        # 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.5000000e-01],
            [0.50000000e00, 0.50000000e00],
            [-5.55111512e-17, 5.55111512e-17],
        ])
        cell_centers_2 = np.array([
            [0.50000000e00, 0.50000000e00],
            [7.50000000e-01, 2.5000000e-01],
            [-5.55111512e-17, 5.55111512e-17],
        ])

        for g, d in gb:
            if g.dim == 2:
                d["node_number"] = 0
            elif 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")
            elif g.dim == 0:
                d["node_number"] = 3
            else:
                raise ValueError

        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            n1 = gb.node_props(g1, "node_number")
            n2 = gb.node_props(g2, "node_number")
            if n1 == 1 and n2 == 0:
                d["edge_number"] = 0
            elif n1 == 2 and n2 == 0:
                d["edge_number"] = 1
            elif n1 == 3 and n2 == 1:
                d["edge_number"] = 2
            elif n1 == 3 and n2 == 2:
                d["edge_number"] = 3
            else:
                raise ValueError

        # define discretization
        key = "transport"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        variable = "T"
        assign_discretization(gb, upwind, upwind_coupling, variable)

        # define parameters
        tol = 1e-3
        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:
            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            specified_parameters = {"aperture": aperture}

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

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

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

                bc_val = np.zeros(g.num_faces)
                bc_dir = bound_faces[np.logical_or(left, right)]
                bc_val[bc_dir] = 1

                bound = pp.BoundaryCondition(g, bound_faces, labels)
                specified_parameters.update({"bc": bound, "bc_values": bc_val})
            else:
                bound = pp.BoundaryCondition(g, np.empty(0), np.empty(0))
                specified_parameters.update({"bc": bound})
            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [1, 0, 0], a)

        assembler = pp.Assembler(gb)
        assembler.discretize()

        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"
        U, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)
        theta = np.linalg.solve(U.A, rhs)
        #        deltaT = solver.cfl(gb)
        U_known = np.array([
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.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,
            ],
            [
                0.0,
                0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.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,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.5,
                0.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,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.01,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                1.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                -1.0,
                -1.0,
                -1.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.01,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -0.01,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
            ],
        ])

        theta_known = np.array([
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            0,
            0,
            0,
            0,
            -0.5,
            -0.5,
            0.5,
            0.5,
            0.01,
            -0.01,
            0,
            0,
        ])

        rhs_known = np.array([
            0.5,
            0.0,
            0.5,
            0.0,
            0.0,
            0.01,
            0.0,
            0.0,
            0.0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        ])

        rtol = 1e-15
        atol = rtol

        self.assertTrue(np.allclose(U.todense(), U_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))
예제 #13
0
    def test_upwind_2d_full_beta_bc_dir(self):

        f = np.array([[2, 2], [0, 2]])
        gb = pp.meshing.cart_grid([f], [4, 2])
        gb.assign_node_ordering()
        gb.compute_geometry()

        # define discretization
        key = "transport"
        variable = "T"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        assign_discretization(gb, upwind, upwind_coupling, variable)

        a = 1e-1
        for g, d in gb:
            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            specified_parameters = {"aperture": aperture}

            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            labels = np.array(["dir"] * bound_faces.size)
            bc_val = np.zeros(g.num_faces)
            bc_val[bound_faces] = 3

            bound = pp.BoundaryCondition(g, bound_faces, labels)
            specified_parameters.update({"bc": bound, "bc_values": bc_val})
            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [1, 1, 0], a)

        assembler = pp.Assembler(gb)
        assembler.discretize()

        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"

        M, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)
        theta = np.linalg.solve(M.A, rhs)
        M_known = np.array([
            [
                2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 1.0
            ],
            [
                0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, -1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                -1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0,
                -1.0,
                0.0,
                0.0,
                -1.0,
                1.0,
                0.0,
                0.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, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                -1.0,
                2.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.1,
                -0.1,
                -1.0,
                0.0,
                -1.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.1,
                0.0,
                -1.0,
                0.0,
                -1.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
            ],
            [
                0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                -1.0, 0.0
            ],
            [
                0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, -1.0
            ],
        ])

        rhs_known = np.array([
            6.0, 3.0, 3.0, 3.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0,
            0.0
        ])

        theta_known = np.array([
            3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, -3.0, -3.0, 3.0,
            3.0
        ])

        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(theta, theta_known, rtol, atol))
예제 #14
0
    def test_upwind_2d_beta_positive(self):

        f = np.array([[2, 2], [0, 2]])
        gb = pp.meshing.cart_grid([f], [4, 2])
        gb.assign_node_ordering()
        gb.compute_geometry()

        # define discretization
        key = "transport"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        variable = "T"
        assign_discretization(gb, upwind, upwind_coupling, variable)

        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:
            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            bf = g.tags["domain_boundary_faces"].nonzero()[0]
            bc = pp.BoundaryCondition(g, bf, bf.size * ["neu"])
            specified_parameters = {"aperture": aperture, "bc": bc}
            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [2, 0, 0], a)
        assembler = pp.Assembler(gb)
        assembler.discretize()

        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"

        M, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)

        # add generic mass matrix to solve system
        I_diag = np.zeros(M.shape[0])
        I_diag[:gb.num_cells()] = 1
        I = np.diag(I_diag)
        theta = np.linalg.solve(M + I, I_diag + rhs)
        M_known = np.array([
            [
                2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 1.0
            ],
            [
                0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, 0.0, 0.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                1.0, 0.0
            ],
            [
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -2.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -2.0,
                0.0,
                -1.0,
                0.0,
                0.0,
            ],
            [
                0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                -1.0, 0.0
            ],
            [
                0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, -1.0
            ],
        ])
        rhs_known = np.zeros(14)
        theta_known = np.array([
            0.33333333,
            0.55555556,
            0.80246914,
            2.60493827,
            0.33333333,
            0.55555556,
            0.80246914,
            2.60493827,
            0.7037037,
            0.7037037,
            -1.40740741,
            -1.40740741,
            1.11111111,
            1.11111111,
        ])

        rtol = 1e-8
        atol = rtol

        self.assertTrue(np.allclose(M.A, M_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))
예제 #15
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 advdiff(gb, discr, param, bc_flag):

    model = "transport"

    model_data_adv, model_data_diff, model_data_src = data_advdiff(
        gb, model, param, bc_flag
    )

    # discretization operator names
    adv_id = "advection"
    diff_id = "diffusion"
    src_id = "source"

    # variable names
    variable = "scalar"
    mortar_adv = "lambda_" + variable + "_" + adv_id
    mortar_diff = "lambda_" + variable + "_" + diff_id

    # save variable name for the post-process
    param["scalar"] = variable

    discr_adv = pp.Upwind(model_data_adv)
    discr_adv_interface = pp.CellDofFaceDofMap(model_data_adv)

    discr_diff = pp.Tpfa(model_data_diff)
    discr_diff_interface = pp.CellDofFaceDofMap(model_data_diff)

    coupling_adv = pp.UpwindCoupling(model_data_adv)
    coupling_diff = pp.FluxPressureContinuity(
        model_data_diff, discr_diff, discr_diff_interface
    )

    # mass term
    mass_id = "mass"
    discr_mass = pp.MassMatrix(model_data_adv)
    discr_mass_interface = pp.CellDofFaceDofMap(model_data_adv)

    discr_src = pp.ScalarSource(model_data_src)

    for g, d in gb:
        d[pp.PRIMARY_VARIABLES] = {variable: {"cells": 1}}
        if g.dim == gb.dim_max():
            d[pp.DISCRETIZATION] = {
                variable: {adv_id: discr_adv,
                diff_id: discr_diff,
                mass_id: discr_mass,
                src_id: discr_src}
            }
        else:
            d[pp.DISCRETIZATION] = {
                variable: {adv_id: discr_adv_interface,
                diff_id: discr_diff_interface,
                mass_id: discr_mass_interface}
            }

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

        d[pp.COUPLING_DISCRETIZATION] = {
            adv_id: {
                g_slave: (variable, adv_id),
                g_master: (variable, adv_id),
                e: (mortar_adv, coupling_adv),
            },
            diff_id: {
                g_slave: (variable, diff_id),
                g_master: (variable, diff_id),
                e: (mortar_diff, coupling_diff),
            },
        }

    # setup the advection-diffusion problem
    assembler = pp.Assembler(gb, active_variables=[variable, mortar_diff, mortar_adv])
    logger.info("Assemble the advective and diffusive terms of the transport problem")
    block_A, block_b = assembler.assemble_matrix_rhs(add_matrices=False)
    logger.info("done")

    # unpack the matrices just computed
    diff_name = diff_id + "_" + variable
    adv_name = adv_id + "_" + variable
    mass_name = mass_id + "_" + variable
    source_name = src_id + "_" + variable

    diff_coupling_name = diff_id + "_" + mortar_diff + "_" + variable + "_" + variable
    adv_coupling_name = adv_id + "_" + mortar_adv + "_" + variable + "_" + variable

    # need a sign for the convention of the conservation equation
    M = block_A[mass_name]
    A = block_A[diff_name] + block_A[diff_coupling_name] + \
        block_A[adv_name] + block_A[adv_coupling_name]
    b = block_b[diff_name] + block_b[diff_coupling_name] + \
        block_b[adv_name] + block_b[adv_coupling_name] + \
        block_b[source_name]

    M_t = M.copy() / param["time_step"] * param.get("mass_weight", 1)
    M_r = M.copy() * param.get("reaction", 0)

    # Perform an LU factorization to speedup the solver
    IE_solver = sps.linalg.factorized((M_t + A + M_r).tocsc())

    # time loop
    logger.info("Prepare the exporting")
    save = pp.Exporter(gb, "solution", folder=param["folder"])
    logger.info("done")

    variables = [variable, param["pressure"], "frac_num", "cell_volumes"]
    if discr["scheme"] is pp.MVEM or discr["scheme"] is pp.RT0:
        variables.append(param["P0_flux"])

    # assign the initial condition
    x = np.zeros(A.shape[0])
    assembler.distribute_variable(x)
    for g, d in gb:
        if g.dim == gb.dim_max():
            d[pp.STATE][variable] = param.get("init_trans", 0) * np.ones(g.num_cells)

    x = assembler.merge_variable(variable)

    outflow = np.zeros(param["n_steps"])

    logger.info("Start the time loop with " + str(param["n_steps"]) + " steps")
    for i in np.arange(param["n_steps"]):
        logger.info("Solve the linear system for time step " + str(i))
        x = IE_solver(b + M_t.dot(x))
        logger.info("done")

        logger.info("Variable post-process")
        assembler.distribute_variable(x)
        logger.info("done")

        logger.info("Export variable")
        save.write_vtk(variables, time_step=i)
        logger.info("done")

        logger.info("Compute the production")
        outflow[i] = compute_outflow(gb, param)
        logger.info("done")

    time = np.arange(param["n_steps"]) * param["time_step"]
    save.write_pvd(time)

    logger.info("Save outflow on file")
    file_out = param["folder"] + "/outflow.csv"
    data = np.vstack((time, outflow)).T
    np.savetxt(file_out, data, delimiter=",")
    logger.info("done")

    logger.info("Save dof on file")
    file_out = param["folder"] + "/dof_transport.csv"
    np.savetxt(file_out, get_dof(assembler), delimiter=",", fmt="%d")
    logger.info("done")