Beispiel #1
0
def gb_coarse_fine_cell_mapping(
    gb: pp.GridBucket, gb_ref: pp.GridBucket, tol=1e-8
) -> None:
    """ Wrapper for coarse_fine_cell_mapping to construct mapping for grids in
    GridBucket.

    Adds a node_prop to each grid in gb. The key is 'coarse_fine_cell_mapping',
    and is the mapping generated by 'coarse_fine_cell_mapping(...)'.

    Note: No node prop is added to the reference grids in gb_ref.

    Parameters
    ----------
    gb : pp.GridBucket
        Coarse grid bucket
    gb_ref : pp.GridBucket
        Refined grid bucket
    tol : float, Optional
        Tolerance for point_in_poly* -methods
    """

    grids = gb.get_grids()
    grids_ref = gb_ref.get_grids()

    assert len(grids) == len(
        grids_ref
    ), "Weakly check that GridBuckets refer to same domains"
    assert np.allclose(
        np.append(*gb.bounding_box()), np.append(*gb_ref.bounding_box())
    ), "Weakly check that GridBuckets refer to same domains"

    # This method assumes a consistent node ordering between grids.
    # At least assign one.
    gb.assign_node_ordering(overwrite_existing=False)
    gb_ref.assign_node_ordering(overwrite_existing=False)

    # Add node prop on the coarse grid to map from coarse to fine cells.
    gb.add_node_props(keys="coarse_fine_cell_mapping")

    for i in np.arange(len(grids)):
        g, g_ref = grids[i], grids_ref[i]

        node_num = gb.node_props(g, "node_number")
        node_num_ref = gb_ref.node_props(g_ref, "node_number")
        assert node_num == node_num_ref, "Weakly check that grids refer to same domain."

        # Compute the mapping for this grid-pair,
        # and assign the result to the node of the coarse gb
        mapping = coarse_fine_cell_mapping(g, g_ref, point_in_poly_tol=tol)
        gb.set_node_prop(g, key="coarse_fine_cell_mapping", val=mapping)
def gb_coarse_fine_cell_mapping(
        gb: pp.GridBucket, gb_ref: pp.GridBucket, tol=1e-8
):
    """ Wrapper for coarse_fine_cell_mapping to construct mapping for grids in GridBucket.

    Parameters
    ----------
    gb : pp.GridBucket
        Coarse grid bucket
    gb_ref : pp.GridBucket
        Refined grid bucket
    tol : float, Optional
        Tolerance for point_in_poly* -methods

    Returns
    -------
    mapping : list of tuples with entries (pp.GridBucket, pp.GridBucket, sps.csc_matrix)
        The first entry is the coarse grid.
        The second entry is the refined grid.
        The third entry is the mapping from coarse to fine cells
    """

    grids = gb.get_grids()
    grids_ref = gb_ref.get_grids()

    assert len(grids) == len(grids_ref), "Weakly check that GridBuckets refer to same domains"
    assert np.array_equal(np.append(*gb.bounding_box()), np.append(*gb_ref.bounding_box())), \
        "Weakly check that GridBuckets refer to same domains"

    # This method assumes a consistent node ordering between grids. At least assign one.
    gb.assign_node_ordering(overwrite_existing=False)
    gb_ref.assign_node_ordering(overwrite_existing=False)

    n_grids = len(grids)
    # mappings = [None]*n_grids
    mappings = {'gb': gb, 'gb_ref': gb_ref}

    for i in np.arange(n_grids):
        g, g_ref = grids[i], grids_ref[i]
        node_num, node_num_ref = gb._nodes[g]['node_number'], gb_ref._nodes[g_ref]['node_number']

        assert node_num == node_num_ref, "Weakly check that grids refer to same domain."

        mapping = coarse_fine_cell_mapping(g, g_ref, tol=tol)

        mappings[(g, g_ref)] = {'node_number': node_num,
                                'data': gb.node_props(g),
                                'data_ref': gb_ref.node_props(g_ref)}

    return mappings
Beispiel #3
0
 def set_grid(self, gb: pp.GridBucket):
     """ Set a new grid
     """
     self.gb = gb
     self.Nd = gb.dim_max()
     self.n_frac = gb.get_grids(lambda _g: _g.dim == self.Nd - 1).size
     self.gb.add_node_props(keys="name")  # Add 'name' as node prop to all grids.
Beispiel #4
0
def nd_sides_shearzone_injection_cell(
    params: FlowParameters, gb: pp.GridBucket, reset_frac_tags: bool = True,
) -> None:
    """ Tag the Nd cells surrounding a shear zone injection point

    Parameters
    ----------
    params : FlowParameters
        parameters that contain "source_scalar_borehole_shearzone"
        (with "shearzone", and "borehole") and "length_scale".
    gb : pp.GridBucket
        grid bucket
    reset_frac_tags : bool [Default: True]
        if set to False, keep injection tag in the shear zone.
    """
    # Shorthand
    shearzone = params.source_scalar_borehole_shearzone.get("shearzone")

    # First, tag the fracture cell, and get the tag
    shearzone_injection_cell(params, gb)
    fracture = gb.get_grids(lambda g: gb.node_props(g, "name") == shearzone)[0]
    tags = fracture.tags["well_cells"]
    # Second, map the cell to the Nd grid
    nd_grid: pp.Grid = gb.grids_of_dimension(gb.dim_max())[0]
    data_edge = gb.edge_props((fracture, nd_grid))
    mg: pp.MortarGrid = data_edge["mortar_grid"]

    slave_to_master_face = mg.mortar_to_master_int() * mg.slave_to_mortar_int()
    face_to_cell = nd_grid.cell_faces.T
    slave_to_master_cell = face_to_cell * slave_to_master_face
    nd_tags = np.abs(slave_to_master_cell) * tags

    # Set tags on the nd-grid
    nd_grid.tags["well_cells"] = nd_tags
    ndd = gb.node_props(nd_grid)
    pp.set_state(ndd, {"well": tags})

    if reset_frac_tags:
        # reset tags on the fracture
        zeros = np.zeros(fracture.num_cells)
        fracture.tags["well_cells"] = zeros
        d = gb.node_props(fracture)
        pp.set_state(d, {"well": zeros})
Beispiel #5
0
def center_of_shearzone_injection_cell(
    params: FlowParameters, gb: pp.GridBucket
) -> None:
    """ Tag the center cell of the given shear zone with 1 (injection)

    Parameters
    ----------
    params : FlowParameters
    gb : pp.GridBucket
    """

    # Shorthand
    shearzone = params.source_scalar_borehole_shearzone.get("shearzone")

    # Get the grid to inject to
    frac: pp.Grid = gb.get_grids(lambda g: gb.node_props(g, "name") == shearzone)[0]
    centers: np.ndarray = frac.cell_centers
    pts = np.atleast_2d(np.mean(centers, axis=1)).T

    # Tag injection grid with 1 in the injection cell
    _tag_injection_cell(gb, frac, pts, params.length_scale)
Beispiel #6
0
def shearzone_injection_cell(params: FlowParameters, gb: pp.GridBucket) -> None:
    """ Tag the borehole - shearzone intersection cell with 1 (injection)

    Parameters
    ----------
    params : FlowParameters
    gb : pp.GridBucket
    """
    # Shorthand
    shearzone = params.source_scalar_borehole_shearzone.get("shearzone")

    # Get intersection point
    pts = shearzone_borehole_intersection(params)

    # Get the grid to inject to
    injection_grid = gb.get_grids(lambda g: gb.node_props(g, "name") == shearzone)[0]
    assert (
        injection_grid.dim == gb.dim_max() - 1
    ), "Injection grid should be a Nd-1 fracture"

    # Tag injection grid with 1 in the injection cell
    _tag_injection_cell(gb, injection_grid, pts, params.length_scale)
Beispiel #7
0
def grid_error(
    gb: pp.GridBucket,
    gb_ref: pp.GridBucket,
    variable: List[str],
    variable_dof: List[int],
) -> dict:
    """ Compute grid errors a grid bucket and refined reference grid bucket

    Assumes that the coarse grid bucket has a node property
    'coarse_fine_cell_mapping' assigned on each grid, which
    maps from coarse to fine cells according to the method
    'coarse_fine_cell_mapping(...)'.

    Parameters
    ----------
    gb, gb_ref : pp.GridBucket
        Coarse and fine grid buckets, respectively
    variable : List[str]
        which variables to compute error over
    variable_dof : List[int]
        Degrees of freedom for each variable in the list 'variable'.

    Returns
    -------
    errors : dict
        Dictionary with top level keys as node_number,
        within which for each variable, the error is
        reported.
    """

    if not isinstance(variable, list):
        variable = [variable]
    if not isinstance(variable_dof, list):
        variable_dof = [variable_dof]
    assert len(variable) == len(variable_dof), (
        "Each variable must have associated "
        "with it a number of degrees of freedom.")
    n_variables = len(variable)

    errors = {}

    grids = gb.get_grids()
    grids_ref = gb_ref.get_grids()
    n_grids = len(grids)

    for i in np.arange(n_grids):
        g, g_ref = grids[i], grids_ref[i]
        mapping = gb.node_props(g, "coarse_fine_cell_mapping")

        # Get states
        data = gb.node_props(g)
        data_ref = gb_ref.node_props(g_ref)
        states = data[pp.STATE]
        states_ref = data_ref[pp.STATE]

        node_number = data["node_number"]

        # Initialize errors
        errors[node_number] = {}

        for var_idx in range(0, n_variables):
            var = variable[var_idx]
            var_dof = variable_dof[var_idx]

            # Check if the variable exists on both
            # the grid and reference grid
            state_keys = set(states.keys())
            state_ref_keys = set(states_ref.keys())
            check_keys = state_keys.intersection(state_ref_keys)
            if var not in check_keys:
                logger.info(f"{var} not present on grid number "
                            f"{node_number} of dim {g.dim}.")
                continue

            # Compute errors relative to the reference grid
            # TODO: Should the solution be divided by
            #  g.cell_volumes or similar?
            # TODO: If scaling is used, consider that
            #  - or use the export-ready variables,
            #   'u_exp', 'p_exp', etc.
            sol = (states[var].reshape((var_dof, -1),
                                       order="F").T)  # (num_cells x var_dof)
            mapped_sol: np.ndarray = mapping.dot(
                sol)  # (num_cells x variable_dof)
            sol_ref = (states_ref[var].reshape(
                (var_dof, -1), order="F").T)  # (num_cells x var_dof)

            # axis=0 gives component-wise norm.
            absolute_error = np.linalg.norm(mapped_sol - sol_ref, axis=0)
            norm_ref = np.linalg.norm(sol_ref, axis=0)

            if np.any(norm_ref < 1e-10):
                logger.info(f"Relative error not reportable. "
                            f"Norm of reference solution is {norm_ref}. "
                            f"Reporting absolute error")
                error = absolute_error
                is_relative = False
            else:
                error = absolute_error / norm_ref
                is_relative = True

            errors[node_number][var] = {
                "error": error,
                "is_relative": is_relative,
            }

    return errors
Beispiel #8
0
def gb_refinement(
    gb: pp.GridBucket, gb_ref: pp.GridBucket, tol: float = 1e-8, mode: str = "nested"
):
    """Wrapper for coarse_fine_cell_mapping to construct mapping for grids in
    GridBucket.

    Adds a node_prop to each grid in gb. The key is 'coarse_fine_cell_mapping',
    and is the mapping generated by 'coarse_fine_cell_mapping(...)'.

    Currently, only nested refinement is supported; more general cases are also
    possible.

    Note: No node prop is added to the reference grids in gb_ref.

    Parameters
    ----------
    gb : pp.GridBucket
        Coarse grid bucket
    gb_ref : pp.GridBucket
        Refined grid bucket
    tol : float, Optional
        Tolerance for point_in_poly* -methods
    mode : str, Optional
        Refinement mode. Defaults to 'nested', corresponds to refinement by splitting.

    Acknowledgement: The code was contributed by Haakon Ervik.

    """

    grids = gb.get_grids()
    grids_ref = gb_ref.get_grids()

    assert len(grids) == len(
        grids_ref
    ), "Weakly check that GridBuckets refer to same domains"
    assert np.allclose(
        np.append(*gb.bounding_box()), np.append(*gb_ref.bounding_box())
    ), "Weakly check that GridBuckets refer to same domains"

    # This method assumes a consistent node ordering between grids. At least assign one.
    gb.assign_node_ordering(overwrite_existing=False)
    gb_ref.assign_node_ordering(overwrite_existing=False)

    # Add node prop on the coarse grid to map from coarse to fine cells.
    gb.add_node_props(keys="coarse_fine_cell_mapping")

    for i in np.arange(len(grids)):
        g, g_ref = grids[i], grids_ref[i]

        node_num, node_num_ref = (
            gb._nodes[g]["node_number"],
            gb_ref._nodes[g_ref]["node_number"],
        )
        assert node_num == node_num_ref, "Weakly check that grids refer to same domain."

        # Compute the mapping for this grid-pair,
        # and assign the result to the node of the coarse gb
        if mode == "nested":
            mapping = structured_refinement(g, g_ref, point_in_poly_tol=tol)
        else:
            raise NotImplementedError("Unknown refinement mode")

        gb.set_node_prop(grid=g, key="coarse_fine_cell_mapping", val=mapping)