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))
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))
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
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))
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))
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)
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
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