Exemplo n.º 1
0
def test_conforming_two_fractures():
    f_1 = Fracture(
        np.array([[-1, -1, 0], [1, -1, 0], [1, 1, 0], [-1, 1, 0]]).T)
    f_2 = Fracture(
        np.array([[-1, 0, -1], [1, 0, -1], [1, 0, 1], [-1, 0, 1]]).T)
    network = FractureNetwork([f_1, f_2])
    gb = meshing.dfn(network, conforming=True)
Exemplo n.º 2
0
def test_non_conforming_three_fractures():
    f_1 = Fracture(
        np.array([[-1, -1, 0], [1, -1, 0], [1, 1, 0], [-1, 1, 0]]).T)
    f_2 = Fracture(
        np.array([[-1, 0, -1], [1, 0, -1], [1, 0, 1], [-1, 0, 1]]).T)
    f_3 = Fracture(
        np.array([[0, -1, -1], [0, 1, -1], [0, 1, 1], [0, -1, 1]]).T)
    network = FractureNetwork([f_1, f_2, f_3])
    gb = meshing.dfn(network, conforming=False)
Exemplo n.º 3
0
    def test_cut_fracture_no_intersection(self):
        p1 = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]).T
        f1 = Fracture(p1, check_convexity=False)

        p2 = np.array([[0.5, -0.5, 0.2], [0.5, 0.5, 0.2], [0.5, 0.5, 0.8],
                       [0.5, -0.5, 0.8]]).T
        p_known = p2.copy()
        f2 = Fracture(p2, check_convexity=False)

        ref_pt = np.array([[0], [1], [0]])
        extrusion.cut_fracture_by_plane(f2, f1, ref_pt)

        self.compare_arrays(p_known, f2.p)
Exemplo n.º 4
0
    def test_cut_fracture_one_inclined(self):
        p1 = np.array([[0, 1, -0.5], [1, 1, -0.5], [1, -1, 1.5], [0, -1,
                                                                  1.5]]).T
        f1 = Fracture(p1, check_convexity=False)

        p2 = np.array([[0.5, -0.5, 0.2], [0.5, 0.5, 0.2], [0.5, 0.5, 0.8],
                       [0.5, -1.5, 0.8]]).T
        p_known = np.array([[0.5, 0.3, 0.2], [0.5, 0.5, 0.2], [0.5, 0.5, 0.8],
                            [0.5, -0.3, 0.8]]).T
        f2 = Fracture(p2, check_convexity=False)

        ref_pt = np.array([[0], [1], [0]])
        extrusion.cut_fracture_by_plane(f2, f1, ref_pt)

        self.compare_arrays(p_known, f2.p)
Exemplo n.º 5
0
def rectangles_from_exposure(pt, edges, height=None, **kwargs):

    num_fracs = edges.shape[1]

    lengths = fracture_length(pt, edges)
    p0 = pt[:, edges[0]]
    p1 = pt[:, edges[1]]

    if height is None:
        height = lengths

    x0 = p0[0]
    x1 = p1[0]
    y0 = p0[1]
    y1 = p1[1]

    fracs = []

    for i in range(num_fracs):
        p = np.array(
            [
                [x0[i], y0[i], -height[i]],
                [x1[i], y1[i], -height[i]],
                [x1[i], y1[i], height[i]],
                [x0[i], y0[i], height[i]],
            ]
        ).T
        fracs.append(Fracture(p))
    return fracs
Exemplo n.º 6
0
    def test_fracture_rotation_90_deg(self):

        p = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]).T
        f = Fracture(p, check_convexity=False)

        p_rot_1_known = np.array([[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0,
                                                                    1]]).T
        exposure = np.array([[0], [0], [0]])
        extrusion.rotate_fracture(f, [1, 0, 0], np.pi / 2, exposure)
        self.compare_arrays(f.p, p_rot_1_known)

        p_rot_2_known = np.array([[0, 0.5, -0.5], [1, 0.5, -0.5],
                                  [1, 0.5, 0.5], [0, 0.5, 0.5]]).T
        exposure = np.array([[0], [0.5], [0]])
        f = Fracture(p, check_convexity=False)
        extrusion.rotate_fracture(f, [1, 0, 0], np.pi / 2, exposure)
        self.compare_arrays(f.p, p_rot_2_known)
Exemplo n.º 7
0
 def test_frac_rand(self):
     r = np.random.rand(4)
     x = np.array([0, 1, 1, 0])
     y = np.array([0, 0, 1, 1])
     z = (r[0] - r[1] * x - r[2] * y) / r[3]
     f = Fracture(np.vstack((x, y, z)), check_convexity=False)
     z_cc = (r[0] - 0.5 * r[1] - 0.5 * r[2]) / r[3]
     c_known = np.array([0.5, 0.5, z_cc]).reshape((3, 1))
     assert np.allclose(c_known, f.center)
Exemplo n.º 8
0
 def test_full_incline(self):
     self.setup()
     p = np.array([[-0.5, 0.5, 0.5, -0.5], [0.5, 0.5, 1.5, 1.5],
                   [-0.5, -0.5, 1, 1]])
     f = Fracture(p, check_convexity=False)
     network = pp.FractureNetwork3d([f])
     network.impose_external_boundary(self.domain)
     p_known = np.array([[0.0, 0.5, 0.5, 0], [5.0 / 6, 5.0 / 6, 1, 1],
                         [0.0, 0.0, 0.25, 0.25]])
     self.assertTrue(len(network._fractures) == (1 + 6))
     p_comp = network._fractures[0].p
     self.assertTrue(self._arrays_equal(p_known, p_comp))
 def setup(self):
     self.f_1 = Fracture(np.array([[0, 1, 1, 0], [.5, .5, .5, .5],
                                   [0, 0, 1, 1]]),
                         check_convexity=False)
     self.domain = {
         'xmin': 0,
         'xmax': 1,
         'ymin': 0,
         'ymax': 1,
         'zmin': 0,
         'zmax': 1
     }
Exemplo n.º 10
0
 def setup(self):
     self.f_1 = Fracture(
         np.array([[0, 1, 1, 0], [0.5, 0.5, 0.5, 0.5], [0, 0, 1, 1]]),
         check_convexity=False,
     )
     self.domain = {
         "xmin": 0,
         "xmax": 1,
         "ymin": 0,
         "ymax": 1,
         "zmin": 0,
         "zmax": 1
     }
Exemplo n.º 11
0
    def setup(self, num_fracs=1, remove_tags=False):

        domain = {
            "xmin": 0,
            "xmax": 1,
            "ymin": 0,
            "ymax": 1,
            "zmin": 0,
            "zmax": 1
        }

        if num_fracs == 0:
            fl = None

        elif num_fracs == 1:
            fl = [
                Fracture(
                    np.array([[0, 1, 1, 0], [0.5, 0.5, 0.5, 0.5], [0, 0, 1,
                                                                   1]]))
            ]
        elif num_fracs == 2:
            fl = [
                Fracture(
                    np.array([[0, 1, 1, 0], [0.5, 0.5, 0.5, 0.5], [0, 0, 1,
                                                                   1]])),
                Fracture(
                    np.array([[0.5, 0.5, 0.5, 0.5], [0, 1, 1, 0], [0, 0, 1,
                                                                   1]])),
            ]

        elif num_fracs == 3:
            fl = [
                Fracture(
                    np.array([[0, 1, 1, 0], [0.5, 0.5, 0.5, 0.5], [0, 0, 1,
                                                                   1]])),
                Fracture(
                    np.array([[0.5, 0.5, 0.5, 0.5], [0, 1, 1, 0], [0, 0, 1,
                                                                   1]])),
                Fracture(
                    np.array([[0, 1, 1, 0], [0, 0, 1, 1], [0.5, 0.5, 0.5,
                                                           0.5]])),
            ]

        gb = meshing.simplex_grid(fracs=fl,
                                  domain=domain,
                                  h_min=0.5,
                                  h_ideal=0.5,
                                  verbose=0)

        #        if remove_tags:
        #            internal_flag = FaceTag.FRACTURE
        #            [g.remove_face_tag_if_tag(FaceTag.BOUNDARY, internal_flag) for g, _ in gb]

        self.set_params(gb)

        return gb
Exemplo n.º 12
0
 def test_frac_4(self):
     # Fracture plane defined by x + y + z = 4
     f_1 = Fracture(np.array([[0, 1, 1, 0], [0, 0, 1, 1], [4, 3, 2, 3]]),
                    check_convexity=False)
     c_known = np.array([0.5, 0.5, 3]).reshape((3, 1))
     assert np.allclose(c_known, f_1.center)
Exemplo n.º 13
0
def network_3d_from_csv(file_name, has_domain=True, tol=1e-4):
    """
    Create the fracture network from a set of 3d fractures stored in a csv file and
    domain. In the csv file, we assume the following structure
    - first line (optional) describes the domain as a rectangle with
      X_MIN, Y_MIN, Z_MIN, X_MAX, Y_MAX, Z_MAX
    - the other lines descibe the N fractures as a list of points
      P0_X, P0_Y, P0_Z, ...,PN_X, PN_Y, PN_Z

    Lines that start with a # are ignored.

    Parameters:
        file_name: name of the file
        has_domain: if the first line in the csv file specify the domain
        tol: (optional) tolerance for the methods

    Return:
        frac_list: the list of fractures
        network: the fracture network
        domain: (optional, returned if has_domain==True) the domain
    """

    # The first line of the csv file defines the bounding box for the domain

    frac_list = []
    # Extract the data from the csv file
    with open(file_name, 'r') as csv_file:
        spam_reader = csv.reader(csv_file, delimiter=',')

        # Read the domain first
        if has_domain:
            domain = np.asarray(next(spam_reader), dtype=np.float)
            assert domain.size == 6
            domain = {
                'xmin': domain[0],
                'xmax': domain[3],
                'ymin': domain[1],
                'ymax': domain[4],
                'zmin': domain[2],
                'zmax': domain[5]
            }

        for row in spam_reader:
            # If the line starts with a '#', we consider this a comment
            if row[0][0] == '#':
                continue

            # Read the points
            pts = np.asarray(row, dtype=np.float)
            assert pts.size % 3 == 0

            # Skip empty lines. Useful if the file ends with a blank line.
            if pts.size == 0:
                continue

            frac_list.append(Fracture(pts.reshape((3, -1), order='F')))

    # Create the network
    network = FractureNetwork(frac_list, tol=tol)

    if has_domain:
        return frac_list, network, domain
    else:
        return frac_list, network
Exemplo n.º 14
0
def network_3d_from_fab(f_name, return_all=False, tol=None):
    """ Read fractures from a .fab file, as specified by FracMan.

    The filter is based on the .fab-files available at the time of writing, and
    may not cover all options available.

    Parameters:
        f_name (str): Path to .fab file.

    Returns:
        network: the network of fractures
        tess_fracs (optional returned if return_all==True, list of np.ndarray):
            Each list element contains fracture
            cut by the domain boundary, represented by vertexes as a nd x n_pt
            array.
        tess_sgn (optional returned if return_all==True, np.ndarray):
            For each element in tess_frac, a +-1 defining
            which boundary the fracture is on.

    The function also reads in various other information of unknown usefulness,
    see implementation for details. This information is currently not returned.

    """
    def read_keyword(line):
        # Read a single keyword, on the form  key = val
        words = line.split('=')
        assert len(words) == 2
        key = words[0].strip()
        val = words[1].strip()
        return key, val

    def read_section(f, section_name):
        # Read a section of the file, surrounded by a BEGIN / END wrapping
        d = {}
        for line in f:
            if line.strip() == 'END ' + section_name.upper().strip():
                return d
            k, v = read_keyword(line)
            d[k] = v

    def read_fractures(f, is_tess=False):
        # Read the fracture
        fracs = []
        fracture_ids = []
        trans = []
        nd = 3
        for line in f:
            if not is_tess and line.strip() == 'END FRACTURE':
                return fracs, np.asarray(fracture_ids), np.asarray(trans)
            elif is_tess and line.strip() == 'END TESSFRACTURE':
                return fracs, np.asarray(fracture_ids), np.asarray(trans)
            if is_tess:
                ids, num_vert = line.split()
            else:
                ids, num_vert, t = line.split()[:3]

                trans.append(float(t))

            ids = int(ids)
            num_vert = int(num_vert)
            vert = np.zeros((num_vert, nd))
            for i in range(num_vert):
                data = f.readline().split()
                vert[i] = np.asarray(data[1:])

            # Transpose to nd x n_pt format
            vert = vert.T

            # Read line containing normal vector, but disregard result
            data = f.readline().split()
            if is_tess:
                trans.append(int(data[1]))
            fracs.append(vert)
            fracture_ids.append(ids)

    with open(f_name, 'r') as f:
        for line in f:
            if line.strip() == 'BEGIN FORMAT':
                # Read the format section, but disregard the information for
                # now
                formats = read_section(f, 'FORMAT')
            elif line.strip() == 'BEGIN PROPERTIES':
                # Read in properties section, but disregard information
                props = read_section(f, 'PROPERTIES')
            elif line.strip() == 'BEGIN SETS':
                # Read set section, but disregard information.
                sets = read_section(f, 'SETS')
            elif line.strip() == 'BEGIN FRACTURE':
                # Read fractures
                fracs, frac_ids, trans = read_fractures(f, is_tess=False)
            elif line.strip() == 'BEGIN TESSFRACTURE':
                # Read tess_fractures
                tess_fracs, tess_frac_ids, tess_sgn = \
                    read_fractures(f, is_tess=True)
            elif line.strip()[:5] == 'BEGIN':
                # Check for keywords not yet implemented.
                raise ValueError('Unknown section type ' + line)

    fractures = [Fracture(f) for f in fracs]
    if tol is not None:
        network = FractureNetwork(fractures, tol=tol)
    else:
        network = FractureNetwork(fractures)

    if return_all:
        return network, tess_fracs, tess_sgn
    else:
        return network
Exemplo n.º 15
0
def network_3d_from_csv(file_name, has_domain=True, tol=1e-4):
    """
    Create the fracture network from a set of 3d fractures stored in a csv file and
    domain. In the csv file, we assume the following structure
    - first line (optional) describes the domain as a rectangle with
      X_MIN, Y_MIN, Z_MIN, X_MAX, Y_MAX, Z_MAX
    - the other lines descibe the N fractures as a list of points
      P0_X, P0_Y, P0_Z, ...,PN_X, PN_Y, PN_Z

    Lines that start with a # are ignored.

    Parameters:
        file_name: name of the file
        has_domain: if the first line in the csv file specify the domain
        tol: (optional) tolerance for the methods

    Return:
        network: the fracture network

    """

    # The first line of the csv file defines the bounding box for the domain

    frac_list = []
    # Extract the data from the csv file
    with open(file_name, "r") as csv_file:
        spam_reader = csv.reader(csv_file, delimiter=",")

        # Read the domain first
        if has_domain:
            domain = np.asarray(next(spam_reader), dtype=np.float)
            domain = {
                "xmin": domain[0],
                "xmax": domain[3],
                "ymin": domain[1],
                "ymax": domain[4],
                "zmin": domain[2],
                "zmax": domain[5],
            }

        for row in spam_reader:
            # If the line starts with a '#', we consider this a comment
            if row[0][0] == "#":
                continue

            # Read the points
            pts = np.asarray(row, dtype=np.float)
            if not pts.size % 3 == 0:
                raise ValueError("Points are always 3d")

            # Skip empty lines. Useful if the file ends with a blank line.
            if pts.size == 0:
                continue

            frac_list.append(Fracture(pts.reshape((3, -1), order="F")))

    # Create the network
    if has_domain:
        return pp.FractureNetwork3d(frac_list, tol=tol, domain=domain)
    else:
        return pp.FractureNetwork3d(frac_list, tol=tol)
Exemplo n.º 16
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
Exemplo n.º 17
0
 def test_frac_1(self):
     f_1 = Fracture(np.array([[0, 2, 2, 0], [0, 2, 2, 0], [-1, -1, 1, 1]]),
                    check_convexity=False)
     c_known = np.array([1, 1, 0]).reshape((3, 1))
     assert np.allclose(c_known, f_1.center)
Exemplo n.º 18
0
def network_3d_from_csv(file_name, has_domain=True, tol=1e-4):
    """
    Create the fracture network from a set of 3d fractures stored in a csv file and
    domain. In the csv file, we assume the following structure
    - first line (optional) describes the domain as a rectangle with
      X_MIN, Y_MIN, Z_MIN, X_MAX, Y_MAX, Z_MAX
    - the other lines descibe the N fractures as a list of points
      P0_X, P0_Y, P0_Z, ...,PN_X, PN_Y, PN_Z

    Parameters:
        file_name: name of the file
        has_domain: if the first line in the csv file specify the domain
        tol: (optional) tolerance for the methods

    Return:
        frac_list: the list of fractures
        network: the fracture network
        domain: (optional, returned if has_domain==True) the domain
    """

    # The first line of the csv file defines the bounding box for the domain

    frac_list = []
    # Extract the data from the csv file
    with open(file_name, 'r') as csv_file:
        spam_reader = csv.reader(csv_file, delimiter=',')

        # Read the domain first
        if has_domain:
            domain = np.asarray(next(spam_reader), dtype=np.float)
            assert domain.size == 6
            domain = {
                'xmin': domain[0],
                'xmax': domain[3],
                'ymin': domain[1],
                'ymax': domain[4],
                'zmin': domain[2],
                'zmax': domain[5]
            }

        for row in spam_reader:
            # Read the points
            pts = np.asarray(row, dtype=np.float)
            assert pts.size % 3 == 0
            frac_list.append(Fracture(pts.reshape((3, -1), order='F')))

    # Create the network
    network = FractureNetwork(frac_list, tol=tol)

    # Cut the fractures due to the domain
    if has_domain:
        network.impose_external_boundary(domain)

    # Find intersections, and split these
    network.find_intersections()
    network.split_intersections()

    if has_domain:
        return frac_list, network, domain
    else:
        return frac_list, network