def _to_gmsh(self, in_file, ndim): # Create a writer of gmsh .geo-files p = self.decomposition["points"] edges = self.decomposition["edges"] intersections = self.decomposition["intersections"] mesh_size = self.decomposition["mesh_size"] domain = self.decomposition["domain"] # Find points that are both on a domain boundary, and on a fracture. # These will be decleared Physical const = constants.GmshConstants() point_on_fracture = edges[:2, edges[2] == const.FRACTURE_TAG].ravel() point_on_boundary = edges[:2, edges[2] == const.DOMAIN_BOUNDARY_TAG].ravel() fracture_boundary_points = np.intersect1d(point_on_fracture, point_on_boundary) self.decomposition[ "fracture_boundary_points"] = fracture_boundary_points gw = gmsh_interface.GmshWriter( p, edges, domain=domain, mesh_size=mesh_size, intersection_points=intersections, domain_boundary_points=self. decomposition["domain_boundary_points"], fracture_and_boundary_points=fracture_boundary_points, nd=ndim, ) gw.write_geo(in_file)
def line_grid_embedded(points, edges, domain, **kwargs): logger.info("Create 1d mesh embedded") # Unified description of points and lines for domain, and fractures constraints = np.empty(0, dtype=np.int) pts_all, lines, domain_pts = _merge_domain_fracs_2d( domain, points, edges, constraints) tol = kwargs.get("tol", 1e-4) pts_split, lines_split = _segment_2d_split(pts_all, lines, tol) # We find the end points that are shared by more than one intersection intersections = _find_intersection_points(lines_split) # Gridding size if "mesh_size_frac" in kwargs.keys(): # Tag points at the domain corners logger.info("Determine mesh size") tm = time.time() mesh_size, pts_split, lines_split = tools.determine_mesh_size( pts_split, None, lines_split, **kwargs) logger.info("Done. Elapsed time " + str(time.time() - tm)) else: mesh_size = None # gmsh options meshing_algorithm = kwargs.get("meshing_algorithm") # Create a writer of gmsh .geo-files gw = gmsh_interface.GmshWriter(pts_split, lines_split, mesh_size=mesh_size, intersection_points=intersections, meshing_algorithm=meshing_algorithm, nd=1) # File name for communication with gmsh file_name = kwargs.get("file_name", "gmsh_frac_file") kwargs.pop("file_name", str()) in_file = file_name + ".geo" gw.write_geo(in_file) _run_gmsh(file_name, **kwargs) return line_grid_from_gmsh(file_name, **kwargs)
def triangle_grid(fracs, domain, do_snap_to_grid=False, **kwargs): """ Generate a gmsh grid in a 2D domain with fractures. The function uses modified versions of pygmsh and mesh_io, both downloaded from github. To be added: Functionality for tuning gmsh, including grid size, refinements, etc. Parameters ---------- fracs: (dictionary) Two fields: points (2 x num_points) np.ndarray, edges (2 x num_lines) connections between points, defines fractures. box: (dictionary) keys xmin, xmax, ymin, ymax, [together bounding box for the domain] do_snap_to_grid (boolean, optional): If true, points are snapped to an underlying Cartesian grid with resolution tol before geometry computations are carried out. This used to be the standard, but indications are it is better not to do this. This keyword construct is a stop-gap measure to invoke the old functionality if desired. This option will most likely dissapear in the future. **kwargs: To be explored. Returns ------- list (length 3): For each dimension (2 -> 0), a list of all grids in that dimension. Examples p = np.array([[-1, 1, 0, 0], [0, 0, -1, 1]]) lines = np.array([[0, 2], [1, 3]]) char_h = 0.5 * np.ones(p.shape[1]) tags = np.array([1, 3]) fracs = {'points': p, 'edges': lines} box = {'xmin': -2, 'xmax': 2, 'ymin': -2, 'ymax': 2} g = triangle_grid(fracs, box) """ logger.info("Create 2d mesh") # Verbosity level verbose = kwargs.get("verbose", 1) # File name for communication with gmsh file_name = kwargs.get("file_name", "gmsh_frac_file") kwargs.pop("file_name", str()) tol = kwargs.get("tol", 1e-4) in_file = file_name + ".geo" out_file = file_name + ".msh" # Pick out fracture points, and their connections frac_pts = fracs["points"] frac_con = fracs["edges"] # Unified description of points and lines for domain, and fractures pts_all, lines, domain_pts = __merge_domain_fracs_2d( domain, frac_pts, frac_con) # Snap to underlying grid before comparing points if do_snap_to_grid: pts_all = cg.snap_to_grid(pts_all, tol) assert np.all(np.diff(lines[:2], axis=0) != 0) # Ensure unique description of points pts_all, _, old_2_new = unique_columns_tol(pts_all, tol=tol) lines[:2] = old_2_new[lines[:2]] to_remove = np.where(lines[0, :] == lines[1, :])[0] lines = np.delete(lines, to_remove, axis=1) # In some cases the fractures and boundaries impose the same constraint # twice, although it is not clear why. Avoid this by uniquifying the lines. # This may disturb the line tags in lines[2], but we should not be # dependent on those. li = np.sort(lines[:2], axis=0) _, new_2_old, old_2_new = unique_columns_tol(li, tol=tol) lines = lines[:, new_2_old] assert np.all(np.diff(lines[:2], axis=0) != 0) # We split all fracture intersections so that the new lines do not # intersect, except possible at the end points logger.info("Remove edge crossings") tm = time.time() pts_split, lines_split = cg.remove_edge_crossings(pts_all, lines, tol=tol, snap=do_snap_to_grid) logger.info("Done. Elapsed time " + str(time.time() - tm)) # Ensure unique description of points if do_snap_to_grid: pts_split = cg.snap_to_grid(pts_split, tol) pts_split, _, old_2_new = unique_columns_tol(pts_split, tol=tol) lines_split[:2] = old_2_new[lines_split[:2]] to_remove = np.where(lines[0, :] == lines[1, :])[0] lines = np.delete(lines, to_remove, axis=1) # Remove lines with the same start and end-point. # This can be caused by L-intersections, or possibly also if the two # endpoints are considered equal under tolerance tol. remove_line_ind = np.where(np.diff(lines_split[:2], axis=0)[0] == 0)[0] lines_split = np.delete(lines_split, remove_line_ind, axis=1) # TODO: This operation may leave points that are not referenced by any # lines. We should probably delete these. # We find the end points that are shared by more than one intersection intersections = __find_intersection_points(lines_split) # Gridding size if "mesh_size_frac" in kwargs.keys(): # Tag points at the domain corners logger.info("Determine mesh size") tm = time.time() boundary_pt_ind = ismember_rows(pts_split, domain_pts, sort=False)[0] mesh_size, pts_split, lines_split = tools.determine_mesh_size( pts_split, boundary_pt_ind, lines_split, **kwargs) logger.info("Done. Elapsed time " + str(time.time() - tm)) else: mesh_size = None # gmsh options meshing_algorithm = kwargs.get("meshing_algorithm") # Create a writer of gmsh .geo-files gw = gmsh_interface.GmshWriter( pts_split, lines_split, domain=domain, mesh_size=mesh_size, intersection_points=intersections, meshing_algorithm=meshing_algorithm, ) gw.write_geo(in_file) triangle_grid_run_gmsh(file_name, **kwargs) return triangle_grid_from_gmsh(file_name, **kwargs)
def triangle_grid(fracs, domain, **kwargs): """ Generate a gmsh grid in a 2D domain with fractures. The function uses modified versions of pygmsh and mesh_io, both downloaded from github. To be added: Functionality for tuning gmsh, including grid size, refinements, etc. Parameters ---------- fracs: (dictionary) Two fields: points (2 x num_points) np.ndarray, edges (2 x num_lines) connections between points, defines fractures. box: (dictionary) keys xmin, xmax, ymin, ymax, [together bounding box for the domain] **kwargs: To be explored. Returns ------- list (length 3): For each dimension (2 -> 0), a list of all grids in that dimension. Examples p = np.array([[-1, 1, 0, 0], [0, 0, -1, 1]]) lines = np.array([[0, 2], [1, 3]]) char_h = 0.5 * np.ones(p.shape[1]) tags = np.array([1, 3]) fracs = {'points': p, 'edges': lines} box = {'xmin': -2, 'xmax': 2, 'ymin': -2, 'ymax': 2} g = triangle_grid(fracs, box) """ # Verbosity level verbose = kwargs.get('verbose', 1) # File name for communication with gmsh file_name = kwargs.get('file_name', 'gmsh_frac_file') kwargs.pop('file_name', str()) tol = kwargs.get('tol', 1e-4) in_file = file_name + '.geo' out_file = file_name + '.msh' # Pick out fracture points, and their connections frac_pts = fracs['points'] frac_con = fracs['edges'] # Unified description of points and lines for domain, and fractures pts_all, lines = __merge_domain_fracs_2d(domain, frac_pts, frac_con) # Snap to underlying grid before comparing points pts_all = cg.snap_to_grid(pts_all, tol) assert np.all(np.diff(lines[:2], axis=0) != 0) # Ensure unique description of points pts_all, _, old_2_new = unique_columns_tol(pts_all, tol=tol) lines[:2] = old_2_new[lines[:2]] to_remove = np.where(lines[0, :] == lines[1, :])[0] lines = np.delete(lines, to_remove, axis=1) # In some cases the fractures and boundaries impose the same constraint # twice, although it is not clear why. Avoid this by uniquifying the lines. # This may disturb the line tags in lines[2], but we should not be # dependent on those. li = np.sort(lines[:2], axis=0) li_unique, new_2_old, old_2_new = unique_columns_tol(li) lines = lines[:, new_2_old] assert np.all(np.diff(lines[:2], axis=0) != 0) # We split all fracture intersections so that the new lines do not # intersect, except possible at the end points pts_split, lines_split = cg.remove_edge_crossings(pts_all, lines, tol=tol) # Ensure unique description of points pts_split = cg.snap_to_grid(pts_split, tol) pts_split, _, old_2_new = unique_columns_tol(pts_split, tol=tol) lines_split[:2] = old_2_new[lines_split[:2]] to_remove = np.where(lines[0, :] == lines[1, :])[0] lines = np.delete(lines, to_remove, axis=1) # Remove lines with the same start and end-point. # This can be caused by L-intersections, or possibly also if the two # endpoints are considered equal under tolerance tol. remove_line_ind = np.where(np.diff(lines_split[:2], axis=0)[0] == 0)[0] lines_split = np.delete(lines_split, remove_line_ind, axis=1) # TODO: This operation may leave points that are not referenced by any # lines. We should probably delete these. # We find the end points that is shared by more than one intersection intersections = __find_intersection_points(lines_split) # Gridding size if 'mesh_size' in kwargs.keys(): mesh_size, mesh_size_bound, pts_split, lines_split = \ utils.determine_mesh_size(pts_split, lines_split, **kwargs['mesh_size']) else: mesh_size = None mesh_size_bound = None # gmsh options meshing_algorithm = kwargs.get('meshing_algorithm') # Create a writer of gmsh .geo-files gw = gmsh_interface.GmshWriter(pts_split, lines_split, domain=domain, mesh_size=mesh_size, mesh_size_bound=mesh_size_bound, intersection_points=intersections, meshing_algorithm=meshing_algorithm) gw.write_geo(in_file) triangle_grid_run_gmsh(file_name, **kwargs) return triangle_grid_from_gmsh(file_name, **kwargs)
def triangle_grid(points, edges, domain, constraints=None, **kwargs): """ Generate a gmsh grid in a 2D domain with fractures. The function uses modified versions of pygmsh and mesh_io, both downloaded from github. To be added: Functionality for tuning gmsh, including grid size, refinements, etc. Parameters ---------- fracs: (dictionary) Two fields: points (2 x num_points) np.ndarray, edges (2 x num_lines) connections between points, defines fractures. box: (dictionary) keys xmin, xmax, ymin, ymax, [together bounding box for the domain] constraints (np.array, optional): Index of edges that only act as constraints in meshing, but do not generate lower-dimensional grids. **kwargs: To be explored. Returns ------- list (length 3): For each dimension (2 -> 0), a list of all grids in that dimension. Examples p = np.array([[-1, 1, 0, 0], [0, 0, -1, 1]]) lines = np.array([[0, 2], [1, 3]]) char_h = 0.5 * np.ones(p.shape[1]) tags = np.array([1, 3]) fracs = {'points': p, 'edges': lines} box = {'xmin': -2, 'xmax': 2, 'ymin': -2, 'ymax': 2} g = triangle_grid(fracs, box) """ logger.info("Create 2d mesh") # Unified description of points and lines for domain, and fractures pts_all, lines, domain_pts = _merge_domain_fracs_2d( domain, points, edges, constraints) assert np.all(np.diff(lines[:2], axis=0) != 0) tol = kwargs.get("tol", 1e-4) pts_split, lines_split = _segment_2d_split(pts_all, lines, tol) # We find the end points that are shared by more than one intersection intersections = _find_intersection_points(lines_split) # Gridding size if "mesh_size_frac" in kwargs.keys(): # Tag points at the domain corners logger.info("Determine mesh size") tm = time.time() boundary_pt_ind = ismember_rows(pts_split, domain_pts, sort=False)[0] mesh_size, pts_split, lines_split = tools.determine_mesh_size( pts_split, boundary_pt_ind, lines_split, **kwargs) logger.info("Done. Elapsed time " + str(time.time() - tm)) else: mesh_size = None # gmsh options meshing_algorithm = kwargs.get("meshing_algorithm") # Create a writer of gmsh .geo-files gw = gmsh_interface.GmshWriter( pts_split, lines_split, domain=domain, mesh_size=mesh_size, intersection_points=intersections, meshing_algorithm=meshing_algorithm, ) # File name for communication with gmsh file_name = kwargs.get("file_name", "gmsh_frac_file") kwargs.pop("file_name", str()) in_file = file_name + ".geo" gw.write_geo(in_file) _run_gmsh(file_name, **kwargs) return triangle_grid_from_gmsh(file_name, **kwargs)