Ejemplo n.º 1
0
 def test_completely_outside_lower(self):
     self.setup()
     f = self.f_1
     f.p[0] -= 2
     network = FractureNetwork([f])
     network.impose_external_boundary(self.domain)
     self.assertTrue(len(network._fractures) == (0 + 6))
Ejemplo n.º 2
0
 def test_outside_west_bottom(self):
     self.setup()
     f = self.f_1
     f.p[0] -= 0.5
     f.p[2] -= 1.5
     network = FractureNetwork([f])
     network.impose_external_boundary(self.domain)
     self.assertTrue(len(network._fractures) == (0 + 6))
Ejemplo n.º 3
0
def create(conforming, tol=1e-4):

    csv_folder = "./"
    csv_file = "example_4_outcrop.csv"
    pts, edges = importer.lines_from_csv(csv_folder + csv_file)

    # A tolerance of 1 seems to be sufficient to recover the T-intersections, but
    # I might have missed some, though, so take a look at the network and modify
    # if necessary.
    snap_pts = cg.snap_points_to_segments(pts, edges, tol=1)

    extrusion_kwargs = {}
    extrusion_kwargs["tol"] = tol
    extrusion_kwargs["exposure_angle"] = np.pi / 4.0 * np.ones(edges.shape[1])
    # Added an option not to include the points on the exposed surface. This
    # reduces cell refinement somewhat, but setting it True should also be okay
    extrusion_kwargs["outcrop_consistent"] = True

    fractures = extrusion.fractures_from_outcrop(snap_pts, edges,
                                                 **extrusion_kwargs)
    network = FractureNetwork(fractures, tol=tol)
    # network.to_vtk(folder_export+"network.vtu")
    bounding_box = {
        "xmin": -800,
        "xmax": 600,
        "ymin": 100,
        "ymax": 1500,
        "zmin": -100,
        "zmax": 1000,
    }
    network.impose_external_boundary(bounding_box,
                                     truncate_fractures=True,
                                     keep_box=False)

    mesh_kwargs = {}
    h = 30
    mesh_kwargs["mesh_size"] = {
        "mode": "weighted",  # 'distance'
        "value": h,
        "bound_value": h,
        "tol": tol,
    }

    if conforming:
        # Change h_ideal and h_min at will here, but I ran into trouble with h_min < 1.
        gb = meshing.dfn(network, conforming=True, h_ideal=100, h_min=5)
    else:
        # Switch conforming=True to get conforming meshes
        gb = meshing.dfn(network,
                         conforming=False,
                         **mesh_kwargs,
                         keep_geo=True)

    gb.remove_nodes(lambda g: g.dim == 0)
    gb.compute_geometry()
    gb.assign_node_ordering()

    return gb
Ejemplo n.º 4
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 = FractureNetwork([f])
     network.impose_external_boundary(self.domain)
     p_known = np.array([[0., 0.5, 0.5, 0], [5. / 6, 5. / 6, 1, 1],
                         [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))
Ejemplo n.º 5
0
 def test_incline_in_plane(self):
     self.setup()
     f = self.f_1
     f.p[0] -= 0.5
     f.p[2, :] = [0, -0.5, 0.5, 1]
     network = FractureNetwork([f])
     network.impose_external_boundary(self.domain)
     p_known = np.array([[0., 0.5, 0.5, 0], [0.5, 0.5, 0.5, 0.5],
                         [0., 0., 0.5, 0.75]])
     self.assertTrue(len(network._fractures) == (1 + 6))
     p_comp = network._fractures[0].p
     self.assertTrue(self._arrays_equal(p_known, p_comp))
Ejemplo n.º 6
0
 def test_intersect_two_same(self):
     self.setup()
     f = self.f_1
     f.p[0, :] = [-0.5, 1.5, 1.5, -0.5]
     f.p[2, :] = [0.2, 0.2, 0.8, 0.8]
     network = FractureNetwork([f])
     network.impose_external_boundary(self.domain)
     p_known = np.array([[0., 1, 1, 0], [0.5, 0.5, 0.5, 0.5],
                         [0.2, 0.2, 0.8, 0.8]])
     self.assertTrue(len(network._fractures) == (1 + 6))
     p_comp = network._fractures[0].p
     self.assertTrue(self._arrays_equal(p_known, p_comp))
 def test_intersect_one(self):
     self.setup()
     f = self.f_1
     f.p[0] -= 0.5
     f.p[2, :] = [0.2, 0.2, 0.8, 0.8]
     network = FractureNetwork([f])
     network.impose_external_boundary(self.domain)
     p_known = np.array([[0., 0.5, 0.5, 0], [0.5, 0.5, 0.5, 0.5],
                         [0.2, 0.2, 0.8, 0.8]])
     assert len(network._fractures) == (1 + 6)
     p_comp = network._fractures[0].p
     assert self._arrays_equal(p_known, p_comp)
Ejemplo n.º 8
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)
Ejemplo n.º 9
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)
Ejemplo n.º 10
0
def create_grid(**mesh_kwargs):
    """
    Create a grid bucket containing grids from gmsh.

    NOTE: The line setting 'path_to_gmsh' *must* be modified for this to work.

    Parameters concerning mesh size, domain size etc. may also be changed, see
    below.

    Returns:
        grid_bucket: A grid_bucket containing the full hierarchy of grids.

    """
    num_fracs = mesh_kwargs.get('num_fracs', 39)

    # If the
    # Don't change the path, or move the file
    data = _soultz_data()
    data = data[:num_fracs, :]

    # Data format of the data file is (frac_num, fracture center_xyz, major
    # axis, minor axis, dip direction, dip angle)
    centers = data[:, 1:4]
    major_axis = data[:, 4]
    minor_axis = data[:, 5]

    dip_direction = data[:, 6] / 180 * np.pi
    dip_angle = data[:, 7] / 180 * np.pi

    # We will define the fractures as elliptic fractures. For this we need
    # strike angle, rather than dip direction.
    strike_angle = dip_direction + np.pi / 2

    # Modifications of the fracture definition:
    # These are carried out to ease the gridding; without these, we will end up
    # with gridding polygons that have very close points. The result may be

    # Minor axis angle. This is specified as zero (the fractures are
    # interpreted as circles), but we rotate them in an attempt to avoid close
    # points in the fracture specification.
    # Also note that since the fractures are defined as circles, any
    # orientation of the approximating polygon is equally correct
    major_axis_angle = np.zeros(num_fracs)
    #   major_axis_angle[14] = 5 * np.pi / 180
    ##    major_axis_angle[24] = 5 * np.pi / 180
    #    major_axis_angle[26] = 5 * np.pi / 180
    ##    major_axis_angle[32-1] = 5 * np.pi / 180

    # Also modify some centers. This may potentially have some impact on the
    # properties of the fracture network, but they been selected as to not
    # modify the fracture network properties.
    #   centers[3, 2] += 30
    if num_fracs > 10:
        centers[11, 2] += 15


#    centers[8, 2] -= 10
#    centers[19, 2] -= 20
#    centers[22, 2] -= 10
#    centers[23, 1:3] -= 15
#    centers[24, 2] += 30
#    centers[25, 2] += 10
#    centers[29, 2] -= 30
#    centers[30, 2] += 30
#    centers[31, 2] += 30
#    centers[34, 2] -= 10
#    centers[38, 2] -= 10

# Create a set of fractures
    frac_list = []
    num_points = mesh_kwargs.get('num_points', 16)
    for fi in range(data.shape[0]):
        frac_new = EllipticFracture(centers[fi],
                                    major_axis[fi],
                                    minor_axis[fi],
                                    major_axis_angle[fi],
                                    strike_angle[fi],
                                    dip_angle[fi],
                                    num_points=num_points)
        frac_list.append(frac_new)

    # Create the network, dump to vtu
    network = FractureNetwork(frac_list, verbose=1, tol=1e-4)
    network.to_vtk('soultz_fractures_full.vtu')

    # Impose domain boundaries. These are set large enough to not be in
    # conflict with the network.
    # This may be changed if desirable.
    domain = {
        'xmin': -4000,
        'xmax': 4000,
        'ymin': -3000,
        'ymax': 3000,
        'zmin': 0,
        'zmax': 8000
    }
    domain = mesh_kwargs.get('domain', domain)
    network.impose_external_boundary(domain)

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

    # This may be changed, if desirable.
    if mesh_kwargs is None:
        mesh_size = {'mode': 'constant', 'value': 150, 'bound_value': 500}
        mesh_kwargs = {'mesh_size': mesh_size, 'file_name': 'soultz_fracs'}
    # Since we have a ready network (and may want to take this file into
    # jupyter and study the network before gridding), we abuse the workflow
    # slightly by calling simplex_tetrahedral directly, rather than to go the
    # way through meshing.simplex_grid (the latter is, for now, restricted to
    # specifying the grid by individual fractures, rather than networks).
    grids = simplex.tetrahedral_grid(network=network, **mesh_kwargs)

    # Convert the grids into a bucket
    meshing.tag_faces(grids)
    gb = meshing.assemble_in_bucket(grids)
    gb.compute_geometry()

    split_grid.split_fractures(gb)
    return gb
Ejemplo n.º 11
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
Ejemplo n.º 12
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
Ejemplo n.º 13
0
def elliptic_network_3d_from_csv(file_name,
                                 has_domain=True,
                                 tol=1e-4,
                                 degrees=False):
    """
    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 elliptic fractures:
      center_x, center_y, center_z, major_axis, minor_axis, major_axis_angle,
                 strike_angle, dip_angle, num_points.
     See EllipticFracture for information about the parameters

    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 data
            data = np.asarray(row, dtype=np.float)
            assert data.size % 9 == 0

            # Skip empty lines. Useful if the file ends with a blank line.
            if data.size == 0:
                continue
            centers = data[0:3]
            maj_ax = data[3]
            min_ax = data[4]
            maj_ax_ang = data[5] * (1 - degrees + degrees * np.pi / 180)
            strike_ang = data[6] * (1 - degrees + degrees * np.pi / 180)
            dip_ang = data[7] * (1 - degrees + degrees * np.pi / 180)
            num_points = data[8]

            frac_list.append(
                EllipticFracture(centers, maj_ax, min_ax, maj_ax_ang,
                                 strike_ang, dip_ang, num_points))
    # Create the network
    network = FractureNetwork(frac_list, tol=tol)

    if has_domain:
        return frac_list, network, domain
    else:
        return frac_list, network
Ejemplo n.º 14
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