def triangle_grid_embedded(file_name): """Create triangular (2D) grid of a domain embedded in 3D space, without meshing the 3D volume. The resulting grid can be used in a DFN model. The grid will be fully conforming along intersections between fractures. This function produces a set of grids for fractures and lower-dimensional objects, but it does nothing to merge the grids. To create a GridBucket, use the function fracs.meshing.dfn instead, with the option conforming=True. To set the mesh size, use parameters mesh_size_frac and mesh_size_min, to represent the ideal and minimal mesh size sent to gmsh. For more details, see the gmsh manual on how to set mesh sizes. Parameters: file_name (str, optional): Filename for communication with gmsh. The config file for gmsh will be f_name.geo, with the grid output to f_name.msh. Defaults to dfn_network. Returns: list (length 3): For each dimension (2 -> 0), a list of all grids in that dimension. """ if file_name[-4:] == ".geo" or file_name[-4:] == ".msh": file_name = file_name[:-4] out_file = file_name + ".msh" pts, cells, cell_info, phys_names = _read_gmsh_file(out_file) g_2d = mesh_2_grid.create_2d_grids( pts, cells, is_embedded=True, phys_names=phys_names, cell_info=cell_info, ) g_1d, _ = mesh_2_grid.create_1d_grids(pts, cells, phys_names, cell_info) g_0d = mesh_2_grid.create_0d_grids(pts, cells, phys_names, cell_info) grids = [g_2d, g_1d, g_0d] logger.info("\n") for g_set in grids: if len(g_set) > 0: s = ("Created " + str(len(g_set)) + " " + str(g_set[0].dim) + "-d grids with ") num = 0 for g in g_set: num += g.num_cells s += str(num) + " cells" logger.info(s) logger.info("\n") return grids
def tetrahedral_grid_from_gmsh(file_name, constraints=None, **kwargs): """Generate a list of grids of dimensions {3, 2, 1, 0}, starting from a gmsh mesh. Parameters: file_name (str): Path to file of gmsh.msh specification. TODO: Line tag is unused. Maybe surface_tag replaces it?? Fix docs. This documentation is copied from mesh_2_grid.create_2d_grids(). constraints (np.array, optional): Array with lists of lines that should not become grids. The array items should match the INDEX in line_tag, see above. Returns: list of list of grids: grids in 2d, 1d and 0d. If no grids exist in a specified dimension, the inner list will be empty. """ start_time = time.time() # Verbosity level verbose = kwargs.get("verbose", 1) if file_name.endswith(".msh"): file_name = file_name[:-4] file_name = file_name + ".msh" pts, cells, cell_info, phys_names = _read_gmsh_file(file_name) # Call upon helper functions to create grids in various dimensions. # The constructors require somewhat different information, reflecting the # different nature of the grids. g_3d = mesh_2_grid.create_3d_grids(pts, cells) g_2d = mesh_2_grid.create_2d_grids( pts, cells, is_embedded=True, phys_names=phys_names, cell_info=cell_info, constraints=constraints, ) g_1d, _ = mesh_2_grid.create_1d_grids(pts, cells, phys_names, cell_info) g_0d = mesh_2_grid.create_0d_grids(pts, cells, phys_names, cell_info) grids = [g_3d, g_2d, g_1d, g_0d] if verbose > 0: logger.info("Grid creation completed. Elapsed time " + str(time.time() - start_time)) for g_set in grids: if len(g_set) > 0: s = ("Created " + str(len(g_set)) + " " + str(g_set[0].dim) + "-d grids with ") num = 0 for g in g_set: num += g.num_cells s += str(num) + " cells" logger.info(s) return grids
def line_grid_from_gmsh(file_name, constraints=None, **kwargs): """Generate a list of grids dimensions {1, 0}, starting from a gmsh mesh. Parameters: file_name (str): Path to file of gmsh.msh specification. constraints (np.array, optional): Index of fracture lines that are constraints in the meshing, but should not have a lower-dimensional mesh. Defaults to empty. Returns: list of list of grids: grids in 2d, 1d and 0d. If no grids exist in a specified dimension, the inner list will be empty. """ if constraints is None: constraints = np.empty(0, dtype=np.int) start_time = time.time() if file_name.endswith(".msh"): file_name = file_name[:-4] out_file = file_name + ".msh" pts, cells, cell_info, phys_names = _read_gmsh_file(out_file) # Constants used in the gmsh.geo-file const = constants.GmshConstants() # Create grids from gmsh mesh. logger.info("Create grids of various dimensions") g_1d, _ = mesh_2_grid.create_1d_grids( pts, cells, phys_names, cell_info, line_tag=const.PHYSICAL_NAME_FRACTURES, constraints=constraints, **kwargs, ) g_0d = mesh_2_grid.create_0d_grids(pts, cells, phys_names, cell_info) grids = [g_1d, g_0d] logger.info("Grid creation completed. Elapsed time " + str(time.time() - start_time)) for g_set in grids: if len(g_set) > 0: s = ("Created " + str(len(g_set)) + " " + str(g_set[0].dim) + "-d grids with ") num = 0 for g in g_set: num += g.num_cells s += str(num) + " cells" logger.info(s) return grids
def tetrahedral_grid_from_gmsh(file_name, network, **kwargs): start_time = time.time() # Verbosity level verbose = kwargs.get("verbose", 1) if file_name.endswith(".msh"): file_name = file_name[:-4] file_name = file_name + ".msh" pts, cells, _, cell_info, phys_names = gmsh_io.read(file_name) # Invert phys_names dictionary to map from physical tags to corresponding # physical names phys_names = {v[0]: k for k, v in phys_names.items()} # Call upon helper functions to create grids in various dimensions. # The constructors require somewhat different information, reflecting the # different nature of the grids. g_3d = mesh_2_grid.create_3d_grids(pts, cells) g_2d = mesh_2_grid.create_2d_grids( pts, cells, is_embedded=True, phys_names=phys_names, cell_info=cell_info, network=network, ) g_1d, _ = mesh_2_grid.create_1d_grids(pts, cells, phys_names, cell_info) g_0d = mesh_2_grid.create_0d_grids(pts, cells) grids = [g_3d, g_2d, g_1d, g_0d] if verbose > 0: print("\n") print("Grid creation completed. Elapsed time " + str(time.time() - start_time)) print("\n") for g_set in grids: if len(g_set) > 0: s = ( "Created " + str(len(g_set)) + " " + str(g_set[0].dim) + "-d grids with " ) num = 0 for g in g_set: num += g.num_cells s += str(num) + " cells" print(s) print("\n") return grids
def triangle_grid_from_gmsh(file_name, **kwargs): start_time = time.time() if file_name.endswith(".msh"): file_name = file_name[:-4] out_file = file_name + ".msh" # Verbosity level verbose = kwargs.get("verbose", 1) pts, cells, _, cell_info, phys_names = gmsh_io.read(out_file) # Invert phys_names dictionary to map from physical tags to corresponding # physical names. # As of meshio 1.10, the value of the physical name is defined as a numpy # array, with the first item being the tag, the second the dimension. phys_names = {v[0]: k for k, v in phys_names.items()} # Constants used in the gmsh.geo-file const = constants.GmshConstants() # Create grids from gmsh mesh. logger.info("Create grids of various dimensions") g_2d = mesh_2_grid.create_2d_grids(pts, cells, is_embedded=False) g_1d, _ = mesh_2_grid.create_1d_grids( pts, cells, phys_names, cell_info, line_tag=const.PHYSICAL_NAME_FRACTURES ) g_0d = mesh_2_grid.create_0d_grids(pts, cells) grids = [g_2d, g_1d, g_0d] logger.info( "Grid creation completed. Elapsed time " + str(time.time() - start_time) ) for g_set in grids: if len(g_set) > 0: s = ( "Created " + str(len(g_set)) + " " + str(g_set[0].dim) + "-d grids with " ) num = 0 for g in g_set: num += g.num_cells s += str(num) + " cells" logger.info(s) return grids
def triangle_grid_embedded(network, find_isect=True, f_name="dfn_network", mesh_size_frac=None, mesh_size_min=None, mesh_size_bound=None, **kwargs): """ Create triangular (2D) grid of a domain embedded in 3D space, without meshing the 3D volume. The resulting grid can be used in a DFN model. The grid will be fully conforming along intersections between fractures. This function produces a set of grids for fractures and lower-dimensional objects, but it does nothing to merge the grids. To create a GridBucket, use the function fracs.meshing.dfn instead, with the option conforming=True. To set the mesh size, use parameters mesh_size_frac and mesh_size_min, to represent the ideal and minimal mesh size sent to gmsh. For more details, see the gmsh manual on how to set mesh sizes. Parameters: network (FractureNetwork): To be meshed. find_isect (boolean, optional): If True (default), the network will search for intersections among fractures. Set False if network.find_intersections() already has been called. f_name (str, optional): Filename for communication with gmsh. The config file for gmsh will be f_name.geo, with the grid output to f_name.msh. Defaults to dfn_network. mesh_size_frac (double, optional): Target mesh size sent to gmsh. If not provided, gmsh will do its best to decide on the mesh size. mesh_size_min (double, optional): Minimal mesh size sent to gmsh. If not provided, gmsh will do its best to decide on the mesh size. **kwargs: Arguments sent to gmsh etc. Returns: list (length 3): For each dimension (2 -> 0), a list of all grids in that dimension. """ verbose = 1 if find_isect: network.find_intersections() # If fields mesh_size_frac and mesh_size_min are provided, try to estimate mesh sizes. if mesh_size_frac is not None and mesh_size_min is not None: if mesh_size_bound is None: mesh_size_bound = mesh_size_frac network.insert_auxiliary_points(mesh_size_frac, mesh_size_min, mesh_size_bound) # In this case we need to recompute intersection decomposition anyhow. network.split_intersections() if not hasattr(network, "decomposition"): network.split_intersections() else: logger.info("Use existing decomposition") pts, cells, cell_info, phys_names = _run_gmsh(f_name, network, in_3d=False, **kwargs) g_2d = mesh_2_grid.create_2d_grids( pts, cells, is_embedded=True, phys_names=phys_names, cell_info=cell_info, network=network, ) g_1d, _ = mesh_2_grid.create_1d_grids(pts, cells, phys_names, cell_info) g_0d = mesh_2_grid.create_0d_grids(pts, cells) grids = [g_2d, g_1d, g_0d] if verbose > 0: logger.info("\n") for g_set in grids: if len(g_set) > 0: s = ("Created " + str(len(g_set)) + " " + str(g_set[0].dim) + "-d grids with ") num = 0 for g in g_set: num += g.num_cells s += str(num) + " cells" logger.info(s) logger.info("\n") return grids
def tetrahedral_grid(fracs=None, box=None, network=None, subdomains=[], **kwargs): """ Create grids for a domain with possibly intersecting fractures in 3d. The function can be call through the wrapper function meshing.simplex_grid. Based on the specified fractures, the method computes fracture intersections if necessary, creates a gmsh input file, runs gmsh and reads the result, and then constructs grids in 3d (the whole domain), 2d (one for each individual fracture), 1d (along fracture intersections), and 0d (meeting between intersections). The fractures can be specified is terms of the keyword 'fracs' (either as numpy arrays or Fractures, see below), or as a ready-made FractureNetwork by the keyword 'network'. For fracs, the boundary of the domain must be specified as well, by 'box'. For a ready network, the boundary will be imposed if provided. For a network will use pre-computed intersection and decomposition if these are available (attributes 'intersections' and 'decomposition'). Parameters ---------- fracs (list, optional): List of either pre-defined fractures, or np.ndarrays, (each 3xn) of fracture vertexes. box (dictionary, optional). Domain specification. Should have keywords xmin, xmax, ymin, ymax, zmin, zmax. network (fractures.FractureNetwork, optional): A FractureNetwork containing fractures. subdomain (list, optional): List of planes partitioning the 3d domain into subdomains. The planes are defined in the same way as fracs. The fractures should be specified either by a combination of fracs and box, or by network (possibly combined with box). See above. **kwargs: To be explored. Returns ------- list (length 4): For each dimension (3 -> 0), a list of all grids in that dimension. Examples -------- frac1 = np.array([[1,1,4,4], [1,4,4,1], [2,2,2,2]]) frac2 = np.array([[2,2,2,2], [1,1,4,4], [1,4,4,1]]) fracs = [frac1, frac2] domain = {'xmin': 0, 'ymin': 0, 'zmin': 0, 'xmax': 5, 'ymax': 5, 'zmax': 5,} path_to_gmsh = .... # Set the sytem path to gmsh gb = tetrahedral_grid(fracs, domain, gmsh_path = path_to_gmsh) """ # Verbosity level verbose = kwargs.get('verbose', 1) # File name for communication with gmsh file_name = kwargs.pop('file_name', 'gmsh_frac_file') if network is None: frac_list = [] for f in fracs: # Input can be either numpy arrays or predifined fractures. As a # guide, we treat f as a fracture if it has an attribute p which is # a numpy array. # If f turns out not to be a fracture, strange errors will result # as the further program tries to access non-existing methods. # The correct treatment here would be several # isinstance-statements, but that became less than elegant. To # revisit. if hasattr(f, 'p') and isinstance(f.p, np.ndarray): frac_list.append(f) else: # Convert the fractures from numpy representation to our 3D # fracture data structure. frac_list.append(fractures.Fracture(f)) # Combine the fractures into a network network = fractures.FractureNetwork(frac_list, verbose=verbose, tol=kwargs.get('tol', 1e-4)) # Add any subdomain boundaries: network.add_subdomain_boundaries(subdomains) # Impose external boundary. If box is None, a domain size somewhat larger # than the network will be assigned. network.impose_external_boundary(box) # Find intersections and split them, preparing the way for dumping the # network to gmsh if not network.has_checked_intersections: network.find_intersections() else: print('Use existing intersections') start_time = time.time() # If fields h_ideal and h_min are provided, try to estimate mesh sizes. h_ideal = kwargs.get('h_ideal', None) h_min = kwargs.get('h_min', None) if h_ideal is not None and h_min is not None: network.insert_auxiliary_points(h_ideal, h_min) # In this case we need to recompute intersection decomposition anyhow. network.split_intersections() if not hasattr(network, 'decomposition'): network.split_intersections() else: print('Use existing decomposition') in_file = file_name + '.geo' out_file = file_name + '.msh' network.to_gmsh(in_file, **kwargs) gmsh_opts = kwargs.get('gmsh_opts', {}) gmsh_verbose = kwargs.get('gmsh_verbose', verbose) gmsh_opts['-v'] = gmsh_verbose gmsh_status = gmsh_interface.run_gmsh(in_file, out_file, dims=3, **gmsh_opts) if verbose > 0: start_time = time.time() if gmsh_status == 0: print('Gmsh processed file successfully') else: print('Gmsh failed with status ' + str(gmsh_status)) pts, cells, _, cell_info, phys_names = gmsh_io.read(out_file) # Invert phys_names dictionary to map from physical tags to corresponding # physical names phys_names = {v[0]: k for k, v in phys_names.items()} # Call upon helper functions to create grids in various dimensions. # The constructors require somewhat different information, reflecting the # different nature of the grids. g_3d = mesh_2_grid.create_3d_grids(pts, cells) g_2d = mesh_2_grid.create_2d_grids(pts, cells, is_embedded=True, phys_names=phys_names, cell_info=cell_info, network=network) g_1d, _ = mesh_2_grid.create_1d_grids(pts, cells, phys_names, cell_info) g_0d = mesh_2_grid.create_0d_grids(pts, cells) grids = [g_3d, g_2d, g_1d, g_0d] if verbose > 0: print('\n') print('Grid creation completed. Elapsed time ' + str(time.time() - start_time)) print('\n') for g_set in grids: if len(g_set) > 0: s = 'Created ' + str(len(g_set)) + ' ' + str(g_set[0].dim) + \ '-d grids with ' num = 0 for g in g_set: num += g.num_cells s += str(num) + ' cells' print(s) print('\n') return grids
def tetrahedral_grid_from_gmsh(network, file_name, **kwargs): """ Generate a list of grids of dimensions {3, 2, 1, 0}, starting from a gmsh mesh. Parameters: network (pp.FractureNetwork3d): The network used to generate the gmsh input file. file_name (str): Path to file of gmsh.msh specification. Returns: list of list of grids: grids in 2d, 1d and 0d. If no grids exist in a specified dimension, the inner list will be empty. """ start_time = time.time() # Verbosity level verbose = kwargs.get("verbose", 1) if file_name.endswith(".msh"): file_name = file_name[:-4] file_name = file_name + ".msh" mesh = meshio.read(file_name) pts = mesh.points cells = mesh.cells cell_info = mesh.cell_data # Invert phys_names dictionary to map from physical tags to corresponding # physical names phys_names = {v[0]: k for k, v in mesh.field_data.items()} # Call upon helper functions to create grids in various dimensions. # The constructors require somewhat different information, reflecting the # different nature of the grids. g_3d = mesh_2_grid.create_3d_grids(pts, cells) g_2d = mesh_2_grid.create_2d_grids( pts, cells, is_embedded=True, phys_names=phys_names, cell_info=cell_info, network=network, ) g_1d, _ = mesh_2_grid.create_1d_grids(pts, cells, phys_names, cell_info) g_0d = mesh_2_grid.create_0d_grids(pts, cells) grids = [g_3d, g_2d, g_1d, g_0d] if verbose > 0: logger.info("Grid creation completed. Elapsed time " + str(time.time() - start_time)) for g_set in grids: if len(g_set) > 0: s = ("Created " + str(len(g_set)) + " " + str(g_set[0].dim) + "-d grids with ") num = 0 for g in g_set: num += g.num_cells s += str(num) + " cells" logger.info(s) return grids
def triangle_grid_embedded(network, f_name, **kwargs): """ Create triangular (2D) grid of a domain embedded in 3D space, without meshing the 3D volume. The resulting grid can be used in a DFN model. The grid will be fully conforming along intersections between fractures. This function produces a set of grids for fractures and lower-dimensional objects, but it does nothing to merge the grids. To create a GridBucket, use the function fracs.meshing.dfn instead, with the option conforming=True. To set the mesh size, use parameters mesh_size_frac and mesh_size_min, to represent the ideal and minimal mesh size sent to gmsh. For more details, see the gmsh manual on how to set mesh sizes. Parameters: network (FractureNetwork): To be meshed. f_name (str, optional): Filename for communication with gmsh. The config file for gmsh will be f_name.geo, with the grid output to f_name.msh. Defaults to dfn_network. **kwargs: Arguments sent to gmsh etc. Returns: list (length 3): For each dimension (2 -> 0), a list of all grids in that dimension. """ out_file = _run_gmsh(f_name, in_3d=False, **kwargs) # The interface of meshio changed between versions 1 and 2. We make no # assumption on which version is installed here. if int(meshio.__version__[0]) < 2: pts, cells, _, cell_info, phys_names = meshio.gmsh_io.read(out_file) # Invert phys_names dictionary to map from physical tags to corresponding # physical names phys_names = {v[0]: k for k, v in phys_names.items()} else: mesh = meshio.read(out_file) pts = mesh.points cells = mesh.cells cell_info = mesh.cell_data phys_names = {v[0]: k for k, v in mesh.field_data.items()} g_2d = mesh_2_grid.create_2d_grids( pts, cells, is_embedded=True, phys_names=phys_names, cell_info=cell_info, network=network, ) g_1d, _ = mesh_2_grid.create_1d_grids(pts, cells, phys_names, cell_info) g_0d = mesh_2_grid.create_0d_grids(pts, cells) grids = [g_2d, g_1d, g_0d] logger.info("\n") for g_set in grids: if len(g_set) > 0: s = ("Created " + str(len(g_set)) + " " + str(g_set[0].dim) + "-d grids with ") num = 0 for g in g_set: num += g.num_cells s += str(num) + " cells" logger.info(s) logger.info("\n") return grids