Exemple #1
0
    def rhs_bound(self, g, data):
        """ Boundary component of the right hand side.

        TODO: Boundary effects of coupling terms.

        Parameters:
            g: grid, or subclass, with geometry fields computed.
            data: dictionary to store the data terms. Must have been through a
                call to discretize() to discretization of right hand side.
            state: np.ndarray, solution vector from previous time step.

        Returns:
            np.ndarray: Contribution to right hand side given the current
            state.

        """
        d = data["param"].get_bc_val("mechanics")
        p = data["param"].get_bc_val("flow")

        div_flow = fvutils.scalar_divergence(g)
        div_mech = fvutils.vector_divergence(g)

        p_bound = -div_flow * data["bound_flux"] * p - data["bound_div_d"] * d
        s_bound = -div_mech * data["bound_stress"] * d
        return np.hstack((s_bound, p_bound))
Exemple #2
0
    def matrix_rhs(self, matrix, g_h, g_l, data_h, data_l, data_edge, discretize=True):
        """
        Computes the coupling terms for the faces between cells in g_h and g_l
        using the two-point flux approximation.

        Parameters:
            g_h and g_l: grid structures of the higher and lower dimensional
                subdomains, respectively.
            data_h and data_l: the corresponding data dictionaries. Assumed
                to contain both permeability values ('perm') and apertures
                ('apertures') for each of the cells in the grids.

        Two hidden options (intended as "advanced" options that one should
        normally not care about):
            Half transmissibility calculation according to Ivar Aavatsmark, see
            folk.uib.no/fciia/elliptisk.pdf. Activated by adding the entry
            'Aavatsmark_transmissibilities': True   to the edge data.

            Aperture correction. The face centre is moved half an aperture
            away from the fracture for the matrix side transmissibility
            calculation. Activated by adding the entry
            'aperture_correction': True   to the edge data.

        Returns:
            cc: Discretization matrices for the coupling terms assembled
                in a csc.sparse matrix.
        """
        if discretize:
            self.discretize(g_h, g_l, data_h, data_l, data_edge)

        # assemble discretization matrix:
        _, cc = self.create_block_matrix([g_h, g_l, data_edge["mortar_grid"]])

        # Contribution from mortar variable to conservation in the higher domain
        # Acts as a boundary condition, treat with standard boundary discretization
        # cc[0, 2] = div_h *  bound_flux_h * face_areas_h *  hat_P.T
        div_h = fvutils.scalar_divergence(g_h)
        cc[0, 2] = div_h * data_edge["mortar_to_hat_bc"]
        # For the lower dimensional grid the mortar act as a source term. This
        # shows up in the equation as a jump operator: div u - ||lambda|| = 0
        # where ||.|| is the jump
        cc[1, 2] = -data_edge["jump"]  # * sps.diags(mg.cell_volumes)

        # Governing equation for the inter-dimensional flux law.
        # Equation on the form
        #   \lambda = \kappa (p_h - p_l). The trace of the pressure from
        # the higher dimension is composed of the cell center pressure,
        # and a contribution from the boundary flux, represented by the mortar flux
        # Cell center contribution, mapped to the mortar grid
        cc[2, 0] = data_edge["hat_P_to_mortar"]

        # Contribution from the lower dimensional pressure
        cc[2, 1] = -data_edge["check_P_to_mortar"]
        # Contribution from mortar
        # Should we have hat_P_pressure here?
        # cc[2, 2] += hat_P * bound_pressure_face_h * face_areas_h * hat_P.T
        cc[2, 2] = data_edge["mortar_weight"]

        return matrix + cc
Exemple #3
0
    def matrix_rhs(self, matrix, g_l, g_r, data_l, data_r, data_edge, discretize=True):
        """
        Computes the coupling terms for the faces between faces in g_l and
        faces in g_r using the two-point flux approximation.

        Parameters:
            g_l and g_r: grid structures of the two subdomains, respectively.
            data_l and data_r: the corresponding data dictionaries.

        Returns:
            cc: Discretization matrices for the coupling terms assembled
                in a csc.sparse matrix.
        """
        if discretize:
            self.discretize(g_l, g_r, data_l, data_r, data_edge)

        # calculate divergence
        div_l = fvutils.scalar_divergence(g_l)
        div_r = fvutils.scalar_divergence(g_r)

        # create block matrix

        # store discretization matrix
        if g_l != g_r:
            _, cc = self.create_block_matrix([g_l, g_r, data_edge["mortar_grid"]])
            # first the flux continuity
            cc[0, 2] = div_l * data_edge["mortar_to_hat_bc"]
            cc[1, 2] = div_r * data_edge["mortar_to_check_bc"]
            # then pressure continuity
            cc[2, 0] = data_edge["hat_P_to_mortar"]
            cc[2, 1] = -data_edge["check_P_to_mortar"]
            cc[2, 2] = data_edge["mortar_weight"]

        else:
            _, cc = self.create_block_matrix([g_l, data_edge["mortar_grid"]])
            # if the edge connect a node to itself the contribution
            # from the left and right are both at the same node
            cc[0, 1] = (
                div_l * data_edge["mortar_to_hat_bc"]
                + div_r * data_edge["mortar_to_check_bc"]
            )
            cc[1, 0] = data_edge["hat_P_to_mortar"] - data_edge["check_P_to_mortar"]
            cc[1, 1] = data_edge["mortar_weight"]

        return matrix + cc
Exemple #4
0
    def matrix_rhs(self, g, data, discretize=True):
        """
        Return the matrix and right-hand side for a discretization of a second
        order elliptic equation using a FV method with a multi-point flux
        approximation.

        The name of data in the input dictionary (data) are:
        k : second_order_tensor
            Permeability defined cell-wise.
        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. For details on necessary keywords,
            see method discretize()
        discretize (boolean, optional): Whether to discetize prior to matrix
            assembly. If False, data should already contain discretization.
            Defaults to True.

        Return
        ------
        matrix: sparse csr (g_num_cells, g_num_cells)
            Discretization matrix.
        rhs: array (g_num_cells)
            Right-hand side which contains the boundary conditions and the scalar
            source term.

        """
        if discretize:
            self.discretize(g, data)

        div = fvutils.scalar_divergence(g)
        flux = data['flux']
        M = div * flux

        bound_flux = data['bound_flux']

        param = data['param']

        bc_val = param.get_bc_val(self)

        return M, self.rhs(g, bound_flux, bc_val)
Exemple #5
0
    def matrix_rhs(self, g, data, discretize=True):
        """
        Return the matrix and right-hand side for a discretization of a second
        order elliptic equation using a FV method with a multi-point flux
        approximation.

        The data should contain a parameter class under the field "param".
        The following parameters will be accessed:
        get_tensor : SecondOrderTensor. Permeability defined cell-wise.
        get_bc : boundary conditions
        get_bc_val : boundary values
        get_robin_weight : float. Weight for pressure in Robin condition

        Parameters
        ----------
        g : grid, or a subclass, with geometry fields computed.
        data: dictionary to store the data. For details on necessary keywords,
            see method discretize()
        discretize (boolean, optional): Whether to discetize prior to matrix
            assembly. If False, data should already contain discretization.
            Defaults to True.

        Return
        ------
        matrix: sparse csr (g_num_cells, g_num_cells)
            Discretization matrix.
        rhs: array (g_num_cells)
            Right-hand side which contains the boundary conditions and the scalar
            source term.

        """
        if discretize:
            self.discretize(g, data)

        div = fvutils.scalar_divergence(g)
        flux = data["flux"]
        M = div * flux

        bound_flux = data["bound_flux"]

        param = data["param"]

        bc_val = param.get_bc_val(self)

        return M, self.rhs(g, bound_flux, bc_val)
Exemple #6
0
    def assemble_matrix(self, g, data):
        """ Assemble the poro-elastic system matrix.

        The discretization is presumed stored in the data dictionary.

        Parameters:
            g (grid): Grid for disrcetization
            data (dictionary): Data for discretization, as well as matrices
                with discretization of the sub-parts of the system.

        Returns:
            scipy.sparse.bmat: Block matrix with the combined MPSA/MPFA
                discretization.

        """
        div_flow = fvutils.scalar_divergence(g)
        div_mech = fvutils.vector_divergence(g)
        param = data["param"]

        fluid_viscosity = param.fluid_viscosity
        biot_alpha = param.biot_alpha

        # Put together linear system
        A_flow = div_flow * data["flux"] / fluid_viscosity
        A_mech = div_mech * data["stress"]

        # Time step size
        dt = data["dt"]

        d_scaling = data.get("displacement_scaling", 1)
        # Matrix for left hand side
        A_biot = sps.bmat([
            [A_mech, data["grad_p"] * biot_alpha],
            [
                data["div_d"] * biot_alpha * d_scaling,
                data["compr_discr"] + dt * A_flow + data["stabilization"],
            ],
        ]).tocsr()

        return A_biot
Exemple #7
0
    def matrix_rhs(self, g, data, faces=None, discretize=True):
        """
        Return the matrix and right-hand side for a discretization of a second
        order elliptic equation using a FV method with a two-point flux approximation.

        To set a source see the source.Integral discretization class

        Parameters
        ----------
        g : grid, or a subclass, with geometry fields computed.
        data: dictionary to store the data. For details on necessary keywords,
            see method discretize()
        discretize (boolean, optional): Whether to discetize prior to matrix
            assembly. If False, data should already contain discretization.
            Defaults to True.

        Return
        ------
        matrix: sparse csr (g_num_cells, g_num_cells)
            Discretization matrix.
        rhs: array (g_num_cells)
            Right-hand side which contains the boundary conditions and the scalar
            source term.

        """
        div = fvutils.scalar_divergence(g)
        if discretize:
            self.discretize(g, data)
        flux = data['flux']
        M = div * flux

        bound_flux = data['bound_flux']
        param = data['param']
        bc_val = param.get_bc_val(self)

        return M, self.rhs(g, bound_flux, bc_val)