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