Example #1
0
    def test_compute_normal_2d( self ):
        pts = np.array( [ [ 0., 2., -1. ],
                          [ 0., 4.,  2. ],
                          [ 0., 0.,  0. ] ] )
        normal = cg.compute_normal( pts )
        normal_test = np.array([0.,0.,1.])
        pt = pts[:,0]

        assert np.allclose( np.linalg.norm( normal ), 1. )
        assert np.allclose( [ np.dot( normal, p - pt ) \
                              for p in pts[:,1:].T ],
                            np.zeros( pts.shape[1] - 1 )  )
        assert np.allclose( normal, normal_test )
Example #2
0
    def test_compute_normal_3d( self ):
        pts = np.array( [ [  2.,  0.,  1.,  1. ],
                          [  1., -2., -1.,  1. ],
                          [ -1.,  0.,  2., -8. ] ] )
        normal_test = np.array( [7., -5., -1.] )
        normal_test = normal_test / np.linalg.norm( normal_test )
        normal = cg.compute_normal( pts )
        pt = pts[:,0]

        assert np.allclose( np.linalg.norm( normal ), 1. )
        assert np.allclose( [ np.dot( normal, p - pt ) \
                              for p in pts[:,1:].T ],
                            np.zeros( pts.shape[1] - 1 )  )
        assert np.allclose( normal, normal_test ) or \
               np.allclose( normal, -1. * normal_test )
Example #3
0
def plot_over_line(gb, pts, name, tol):

    values = np.zeros(pts.shape[1])
    is_found = np.zeros(pts.shape[1], dtype=np.bool)

    for g, d in gb:
        if g.dim < gb.dim_max():
            continue

        if not cg.is_planar(np.hstack((g.nodes, pts)), tol=1e-4):
            continue

        faces_cells, _, _ = sps.find(g.cell_faces)
        nodes_faces, _, _ = sps.find(g.face_nodes)

        normal = cg.compute_normal(g.nodes)
        for c in np.arange(g.num_cells):
            loc = slice(g.cell_faces.indptr[c], g.cell_faces.indptr[c + 1])
            pts_id_c = np.array([
                nodes_faces[g.face_nodes.indptr[f]:g.face_nodes.indptr[f + 1]]
                for f in faces_cells[loc]
            ]).T
            pts_id_c = sort_points.sort_point_pairs(pts_id_c)[0, :]
            pts_c = g.nodes[:, pts_id_c]

            mask = np.where(np.logical_not(is_found))[0]
            if mask.size == 0:
                break
            check = np.zeros(mask.size, dtype=np.bool)
            last = False
            for i, pt in enumerate(pts[:, mask].T):
                check[i] = cg.is_point_in_cell(pts_c, pt)
                if last and not check[i]:
                    break
            is_found[mask] = check
            values[mask[check]] = d[name][c]

    return values
Example #4
0
def cut_fracture_by_plane(
    main_frac, other_frac, reference_point, tol=1e-4, recompute_center=True, **kwargs
):
    """ Cut a fracture by a plane, and confine it to one side of the plane.

    Intended use is to confine abutting fractures (T-intersections) to one side
    of the fracture it hits. This is done by deleting points on the abutting
    fracture.

    Parameters:
        main_frac (Fracture): The fracture to be cut.
        other_frac (Fracture): The fracture that defines the confining plane.
        reference_point (np.array, nd): Point on the main frature that defines
            which side should be kept. Will typically be the other point of the
            exposed line.

    Returns:
        Fracture: A copy of the main fracture, cut by the other fracture.
        double: In cases where one interseciton point extends beyond the other
            fracture, this is the distance between the center of the other
            fracture and the intersection point. If both intersections are
            within the polygon, None will be returned.

    Raises:
        ValueError if the points in the other fracture is too close. This could
        probably be handled by a scaling of coordinates, it is tacitly assumed
        that we're working in something resembling the unit box.

    """
    reference_point = reference_point.reshape((-1, 1))
    if reference_point.size == 2:
        reference_point = np.vstack((reference_point, 0))

    # First determine extent of the main fracture
    main_min = main_frac.p.min(axis=1)
    main_max = main_frac.p.max(axis=1)

    # Equation for the plane through the other fracture, on the form
    #  n_x(x-c_x) + n_y(y-c_y) + n_z(z-c_z) = 0
    n = cg.compute_normal(other_frac.p).reshape((-1, 1))
    c = other_frac.center

    # max and min coordinates that extends outside the main fracture
    main_min -= 1
    main_max += 1

    # Define points in the plane of the second fracture with min and max
    # coordinates picked from the main fracture.
    # The below tricks with indices are needed to find a dimension with a
    # non-zero gradient of the plane, so that we can divide safely.
    # Implementation note: It might have been possible to do this with a
    # rotation to the natural plane of the other fracture, but it is not clear
    # this will really be simpler.

    # Not sure about the tolerance here
    # We should perhaps do a scaling of coordinates.
    non_zero = np.where(np.abs(n) > 1e-8)[0]
    if non_zero.size == 0:
        raise ValueError("Could not compute normal vector of other fracture")
    ind = np.setdiff1d(np.arange(3), non_zero[0])
    i0 = ind[0]
    i1 = ind[1]
    i2 = non_zero[0]

    p = np.zeros((3, 4))
    # A for-loop might have been possible here.
    p[i0, 0] = main_min[i0]
    p[i1, 0] = main_min[i1]
    p[i2, 0] = (
        c[i2]
        - (n[i0] * (main_min[i0] - c[i0]) + n[i1] * (main_min[i1] - c[i1])) / n[i2]
    )

    p[i0, 1] = main_max[i0]
    p[i1, 1] = main_min[i1]
    p[i2, 1] = (
        c[i2]
        - (n[i0] * (main_max[i0] - c[i0]) + n[i1] * (main_min[i1] - c[i1])) / n[i2]
    )

    p[i0, 2] = main_max[i0]
    p[i1, 2] = main_max[i1]
    p[i2, 2] = (
        c[i2]
        - (n[i0] * (main_max[i0] - c[i0]) + n[i1] * (main_max[i1] - c[i1])) / n[i2]
    )

    p[i0, 3] = main_min[i0]
    p[i1, 3] = main_max[i1]
    p[i2, 3] = (
        c[i2]
        - (n[i0] * (main_min[i0] - c[i0]) + n[i1] * (main_max[i1] - c[i1])) / n[i2]
    )

    # Create an auxiliary fracture that spans the same plane as the other
    # fracture, and with a larger extension than the main fracture.
    aux_frac = Fracture(p, check_convexity=False)

    isect_pt, _, _ = main_frac.intersects(aux_frac, tol)

    # The extension of the abutting fracture will cross the other fracture
    # with a certain angle to the vertical. If the other fracture is rotated
    # with a similar angle, point contact results.
    if isect_pt.size == 0:
        warnings.warn(
            """No intersection found in cutting of fractures. This is
                         likely caused by an unfortunate combination of
                         extrusion and rotation angles, which created fractures
                         that only intersect in a single point (the outcrop
                         plane. Will try to continue, but this may cause
                         trouble for meshing etc."""
        )
        return main_frac, None

    # Next step is to eliminate points in the main fracture that are on the
    # wrong side of the other fracture.
    v = main_frac.p - other_frac.center.reshape((-1, 1))
    sgn = np.sign(np.sum(v * n, axis=0))
    ref_v = reference_point - other_frac.center.reshape((-1, 1))
    right_sign = np.sign(np.sum(ref_v * n, axis=0))

    # Eliminate points that are on the other side.
    eliminate = np.where(sgn * right_sign < 0)[0]
    main_frac.remove_points(eliminate)

    # Add intersection points on the main fracture. One of these may already be
    # present, as the point of extrusion, but add_point will uniquify the point
    # cloud.
    # We add the points after elimination, to ensure that the points on the
    # plane are present in the final fracture.
    main_frac.add_points(isect_pt, check_convexity=False)

    if recompute_center:
        main_frac.compute_centroid()

    # If the main fracture is too large compared to the other, the cut line
    # will extend beyond the confining plane. In these cases, compute the
    # distance from the fracture center to the outside intersection point. This
    # can be used to extend the other fracture so as to avoid such strange
    # configurations.
    other_center = other_frac.center.reshape((-1, 1))
    other_p = other_frac.p
    rot = cg.project_plane_matrix(other_p - other_center)

    other_rot = rot.dot(other_p - other_center)[:2]
    isect_rot = rot.dot(isect_pt - other_center)[:2]

    is_inside = cg.is_inside_polygon(other_rot, isect_rot, tol, default=True)
    # At one point (the exposed point) must be in the polygon of the other
    # fracture.
    assert is_inside.any()

    if not is_inside.all():
        hit = np.logical_not(is_inside)
        r = np.sqrt(np.sum(isect_pt[:, hit] ** 2))
        return main_frac, r
    else:
        return main_frac, None