def test_fuse_boxes2(): """ Test of fusion function. It makes union of three face-adjacent boxes. Possibly it can make union of two non-intersecting boxes. """ mesh_name = "box_fuse_2" gen = gmsh.GeometryOCC(mesh_name, verbose=True) # create inner box box_1 = gen.box([20, 20, 20]) box_2 = gen.box([20, 20, 20]) box_3 = gen.box([20, 20, 20]) box_2.translate([0, 20, 0]) box_3.translate([0, 40, 0]) # make union of two non-intersecting boxes # box_fused = box_1.fuse(box_3) box_fused = box_1.fuse(box_2, box_3) assert box_fused.regions[0] == gmsh.Region.default_region[3] box_fused.set_region("box") # box_fused.mesh_step(1) all_obj = [box_fused] mesh_all = [*all_obj] gen.make_mesh(mesh_all) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2)
def test_greet_no_volume(): """ Problem: Does not generate volume mesh. select_by_intersect probably fails, in comparison to simple cut(*tunnel_f) The cutting of the tunnels is a dead end, however, we do not understand the behaviour above. """ mesh_name = "greet_no_volume" gen = gmsh.GeometryOCC(mesh_name, verbose=True) geom = geometry() # create inner box box_inner = gen.box(geom['inner_box']["size"]) # create tunnel box_size = np.array(geom['outer_box']["size"]) tunnel_start = np.array(geom['tunnel_1']["start"]) tunnel_mid = np.array(geom['tunnel_1']["end"]) tunnel_end = np.array(geom['tunnel_2']["end"]) side_y = gen.rectangle([box_size[0], box_size[2]]).rotate([-1, 0, 0], np.pi / 2) tunnel_split = dict(start=side_y.copy().translate([0, tunnel_start[1], 0]), mid=side_y.copy().translate([0, tunnel_mid[1], 0]), end=side_y.copy().translate([0, tunnel_end[1], 0])) tunnel_1_c, tunnel_box_1 = create_cylinder(gen, geom['tunnel_1'], 0.2) tunnel_1_x = tunnel_1_c.copy().intersect(tunnel_box_1) tunnel_2_c, tunnel_box_2 = create_cylinder(gen, geom['tunnel_2'], 0.2) tunnel_2_x = tunnel_2_c.copy().intersect(tunnel_box_2) splits = [tunnel_split["start"].copy(), tunnel_split["end"].copy()] frag = gen.fragment(box_inner.copy(), tunnel_1_c, tunnel_2_c, *splits) tunnel_1_f = frag[1].select_by_intersect(tunnel_1_x) tunnel_2_f = frag[2].select_by_intersect(tunnel_2_x) tunnel_f = [tunnel_1_f, tunnel_2_f] box_inner_cut = box_inner.cut(*tunnel_f) box_inner_reg = frag[0].select_by_intersect(box_inner_cut) # box_inner_reg = box_inner.cut(tunnel_box_1) box_inner_reg.mesh_step(4.0) box_all = [] b_box_inner = box_inner_reg.get_boundary() b_tunnel = b_box_inner.select_by_intersect(*tunnel_f) box_all.append( b_tunnel.modify_regions("." + geom['inner_box']["name"] + "_tunnel")) box_all.extend([box_inner_reg]) b_tunnel.mesh_step(1.0) mesh_all = [*box_all] print("Generating mesh...") gen.make_mesh(mesh_all) print("Generating mesh...[finished]") print("Writing mesh...") gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2) print("Writing mesh...[finished]")
def mesh_from_brep(brep_file, mesh_file, project_conf, inv_par): if project_conf.method == GenieMethod.ERT: data = pg.DataContainerERT("input_snapped.dat", removeInvalid=False) else: data = pg.DataContainer("input_snapped.dat", sensorTokens='s g', removeInvalid=False) el_pos = [] for i in range(len(data.sensorPositions())): pos = data.sensorPosition(i) pos = np.array([pos[0], pos[1], pos[2]]) el_pos.append(pos) model = gmsh.GeometryOCC("model_name") compound = model.import_shapes(brep_file, highestDimOnly=False) points = [model.point(pos).tags[0] for pos in el_pos] dist = field.distance_nodes(points) f_distance = field.threshold(dist, lower_bound=(inv_par.elementSize_d, inv_par.elementSize_d), upper_bound=(inv_par.elementSize_D, inv_par.elementSize_H)) model.set_mesh_step_field(f_distance) model.mesh_options.CharacteristicLengthMin = 0.1 model.mesh_options.CharacteristicLengthMax = 100 model.make_mesh([compound]) model.write_mesh(mesh_file, gmsh.MeshFormat.msh2)
def test_exceptions(): """ Test exceptions. Using the broken remove_duplicate_entities() function for testing. """ mesh_name = "square_mesh" gen = gmsh.GeometryOCC(mesh_name, verbose=True, gmsh_exceptions=True) square = gen.rectangle([2, 2], [5, 0, 0]) with pytest.raises(gmsh_exceptions.FragmentationError, match=r".* duplicate .*"): gen.remove_duplicate_entities() gen.gmsh_exceptions = False # we cannot check warning type due to inline creation of the warning type in gmsh_exceptions.make_warning with pytest.warns(Warning, match=r".* duplicate .*"): gen.remove_duplicate_entities()
def test_extrude_rect(): """ Test extrusion of an rectangle. """ mesh_name = "extrude_rect" gen = gmsh.GeometryOCC(mesh_name, verbose=True) rect = gen.rectangle([2,5]) prism_extrude = rect.extrude([1, 3, 4]) prism = prism_extrude[3] prism.set_region("prism").mesh_step(0.5) mesh_all = [prism] # gen.write_brep(mesh_name) gen.make_mesh(mesh_all) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2)
def test_extrude_circle(): """ Test extrusion of an circle. """ mesh_name = "extrude_circle" gen = gmsh.GeometryOCC(mesh_name, verbose=True) circ = gen.disc(center=[2,5,1], rx=3, ry=3) circ_extrude = circ.extrude([2, 2, 2]) tube = circ_extrude[3] tube.set_region("tube").mesh_step(0.5) mesh_all = [tube] # gen.write_brep(mesh_name) gen.make_mesh(mesh_all) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2)
def test_revolve_square(): """ Test revolving a square. """ mesh_name = "revolve_square_mesh" gen = gmsh.GeometryOCC(mesh_name, verbose=True) square = gen.rectangle([2, 2], [5,0,0]) axis = [] center = [5, 10, 0] square_revolved = square.revolve(center=[5, 10, 0], axis=[1, 0, 0], angle=np.pi*3/4) obj = square_revolved[3].mesh_step(0.5) mesh_all = [obj] # gen.write_brep(mesh_name) gen.make_mesh(mesh_all) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2)
def test_cylinder_discrete(): """ Test creating discrete cylinder (prism with regular n-point base), extrusion. """ mesh_name = "cylinder_discrete_mesh" gen = gmsh.GeometryOCC(mesh_name, verbose=True) r = 2.5 start = np.array([-10, -5, -15]) end = np.array([5, 15, 10]) axis = end-start center = (end+start)/2 cyl = gen.cylinder_discrete(r,axis,center=center, n_points=12) cyl.mesh_step(1.0) mesh_all = [cyl] # gen.write_brep(mesh_name) gen.make_mesh(mesh_all) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2)
def test_fuse_boxes(): """ Test of fusion function. It makes union of two intersection boxes. """ mesh_name = "box_fuse" gen = gmsh.GeometryOCC(mesh_name, verbose=True) # create inner box box_1 = gen.box([20, 20, 20]) box_2 = gen.box([10, 10, 40]) box_fused = box_2.fuse(box_1) box_fused.set_region("box") # box_fused.mesh_step(1) all_obj = [box_fused] mesh_all = [*all_obj] gen.make_mesh(mesh_all) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2)
def test_extrude_polygon(): """ Test extrusion of an polygon. """ mesh_name = "extrude_polygon" gen = gmsh.GeometryOCC(mesh_name, verbose=True) # plane directional vectors vector u = np.array([1, 1, 0]) u = u / np.linalg.norm(u) v = np.array([0, 1, 1]) v = v / np.linalg.norm(v) #normal n = np.cross(u,v) n = n / np.linalg.norm(n) # add some points in the plane points= [] points.append(u) points.append(2 * u + 1 * v) points.append(5 * u + -2 * v) points.append(5 * u + 3 * v) points.append(4 * u + 5 * v) points.append(-2 * u + 3*v) points.append(v) # create polygon polygon = gen.make_polygon(points) # trying to set mesh step directly to nodes # polygon = gen.make_polygon(points, 0.2) prism_extrude = polygon.extrude(3*n) prism = prism_extrude[3] prism.set_region("prism").mesh_step_direct(0.5) mesh_all = [prism] # gen.write_brep(mesh_name) gen.make_mesh(mesh_all) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2)
def make_mesh(config_dict, fractures, mesh_name, mesh_file): geom = config_dict["geometry"] fracture_mesh_step = geom['fracture_mesh_step'] dimensions = geom["box_dimensions"] well_z0, well_z1 = geom["well_openning"] well_length = well_z1 - well_z0 well_r = geom["well_effective_radius"] well_dist = geom["well_distance"] print("load gmsh api") factory = gmsh.GeometryOCC(mesh_name, verbose=True) gopt = gmsh_options.Geometry() gopt.Tolerance = 0.0001 gopt.ToleranceBoolean = 0.001 # gopt.MatchMeshTolerance = 1e-1 # Main box box = factory.box(dimensions).set_region("box") side_z = factory.rectangle([dimensions[0], dimensions[1]]) side_y = factory.rectangle([dimensions[0], dimensions[2]]) side_x = factory.rectangle([dimensions[2], dimensions[1]]) sides = dict( side_z0=side_z.copy().translate([0, 0, -dimensions[2] / 2]), side_z1=side_z.copy().translate([0, 0, +dimensions[2] / 2]), side_y0=side_y.copy().translate([0, 0, -dimensions[1] / 2]).rotate([-1, 0, 0], np.pi / 2), side_y1=side_y.copy().translate([0, 0, +dimensions[1] / 2]).rotate([-1, 0, 0], np.pi / 2), side_x0=side_x.copy().translate([0, 0, -dimensions[0] / 2]).rotate([0, 1, 0], np.pi / 2), side_x1=side_x.copy().translate([0, 0, +dimensions[0] / 2]).rotate([0, 1, 0], np.pi / 2) ) for name, side in sides.items(): side.modify_regions(name) b_box = box.get_boundary().copy() # two vertical cut-off wells, just permeable part left_center = [-well_dist/2, 0, 0] right_center = [+well_dist/2, 0, 0] left_well = factory.cylinder(well_r, axis=[0, 0, well_z1 - well_z0]) \ .translate([0, 0, well_z0]).translate(left_center) right_well = factory.cylinder(well_r, axis=[0, 0, well_z1 - well_z0]) \ .translate([0, 0, well_z0]).translate(right_center) b_right_well = right_well.get_boundary() b_left_well = left_well.get_boundary() print("n fractures:", len(fractures)) fractures = create_fractures_rectangles(factory, fractures, factory.rectangle()) #fractures = create_fractures_polygons(factory, fractures) fractures_group = factory.group(*fractures) #fractures_group = fractures_group.remove_small_mass(fracture_mesh_step * fracture_mesh_step / 10) # drilled box and its boundary box_drilled = box.cut(left_well, right_well) # fractures, fragmented, fractures boundary print("cut fractures by box without wells") fractures_group = fractures_group.intersect(box_drilled.copy()) print("fragment fractures") box_fr, fractures_fr = factory.fragment(box_drilled, fractures_group) print("finish geometry") b_box_fr = box_fr.get_boundary() b_left_r = b_box_fr.select_by_intersect(b_left_well).set_region(".left_well") b_right_r = b_box_fr.select_by_intersect(b_right_well).set_region(".right_well") box_all = [] for name, side_tool in sides.items(): isec = b_box_fr.select_by_intersect(side_tool) box_all.append(isec.modify_regions("." + name)) box_all.extend([box_fr, b_left_r, b_right_r]) b_fractures = factory.group(*fractures_fr.get_boundary_per_region()) b_fractures_box = b_fractures.select_by_intersect(b_box).modify_regions("{}_box") b_fr_left_well = b_fractures.select_by_intersect(b_left_well).modify_regions("{}_left_well") b_fr_right_well = b_fractures.select_by_intersect(b_right_well).modify_regions("{}_right_well") b_fractures = factory.group(b_fr_left_well, b_fr_right_well, b_fractures_box) mesh_groups = [*box_all, fractures_fr, b_fractures] print(fracture_mesh_step) #fractures_fr.set_mesh_step(fracture_mesh_step) factory.keep_only(*mesh_groups) factory.remove_duplicate_entities() factory.write_brep() min_el_size = fracture_mesh_step / 10 fracture_el_size = np.max(dimensions) / 20 max_el_size = np.max(dimensions) / 8 fracture_el_size = gmsh_field.constant(fracture_mesh_step, 10000) frac_el_size_only = gmsh_field.restrict(fracture_el_size, fractures_fr, add_boundary=True) gmsh_field.set_mesh_step_field(frac_el_size_only) mesh = gmsh_options.Mesh() #mesh.Algorithm = options.Algorithm2d.MeshAdapt # produce some degenerated 2d elements on fracture boundaries ?? #mesh.Algorithm = options.Algorithm2d.Delaunay #mesh.Algorithm = options.Algorithm2d.FrontalDelaunay #mesh.Algorithm3D = options.Algorithm3d.Frontal #mesh.Algorithm3D = options.Algorithm3d.Delaunay mesh.ToleranceInitialDelaunay = 0.01 #mesh.ToleranceEdgeLength = fracture_mesh_step / 5 mesh.CharacteristicLengthFromPoints = True mesh.CharacteristicLengthFromCurvature = True mesh.CharacteristicLengthExtendFromBoundary = 2 mesh.CharacteristicLengthMin = min_el_size mesh.CharacteristicLengthMax = max_el_size mesh.MinimumCirclePoints = 6 mesh.MinimumCurvePoints = 2 #factory.make_mesh(mesh_groups, dim=2) factory.make_mesh(mesh_groups) factory.write_mesh(format=gmsh.MeshFormat.msh2) os.rename(mesh_name + ".msh2", mesh_file)
def apply_field(field, reference_fn, dim=2, tolerance=0.15, max_mismatch=5, mesh_name="field_mesh"): """ Create a mesh of dimension dim on a unit cube and compare element sizes to given reference funcion of coordinates. dim: Create mesh of that dimension. tolerance: maximum relative error of element sizes, actual size is max of edges, reference size is the field evaluated in the barycenter max_mismatch: maximum number of elements that could be over the tolerance """ model = gmsh.GeometryOCC(mesh_name) rec = model.rectangle([100, 100]) model.set_mesh_step_field(field) brep_fname = sandbox_fname(mesh_name, "brep") model.write_brep(brep_fname) model.mesh_options.CharacteristicLengthMin = 0.5 model.mesh_options.CharacteristicLengthMax = 100 model.make_mesh([rec], dim=dim) mesh_fname = sandbox_fname(mesh_name, "msh2") model.write_mesh(mesh_fname, gmsh.MeshFormat.msh2) # check ref_shape_edges = { 1: [(0, 1)], 2: [(0, 1), (0, 2), (1, 2)], 3: [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)], } node_tags, coords, param_coords = gmsh_model.mesh.getNodes( dim=-1, returnParametricCoord=False) coords = np.reshape(coords, (-1, 3)) node_indices = {tag: idx for idx, tag in enumerate(node_tags)} assert coords.shape[0] == len(node_tags) ele_types, ele_tags, ele_node_tags = gmsh_model.mesh.getElements(dim=dim) assert len(ele_types) == 1 and len(ele_tags) == 1 and len( ele_node_tags) == 1 ele_tags = ele_tags[0] ele_node_tags = np.reshape(ele_node_tags[0], (-1, dim + 1)) n_mismatch = 0 max_rel_error = 0 for ele_tag, ele_nodes in zip(ele_tags, ele_node_tags): i_nodes = [node_indices[n_tag] for n_tag in ele_nodes] vertices = coords[i_nodes, :] edges = [ vertices[i, :] - vertices[j, :] for i, j in ref_shape_edges[dim] ] ele_size = np.max(np.linalg.norm(edges, axis=1)) barycenter = np.average(vertices, axis=0) ref_ele_size = reference_fn(barycenter) rel_error = abs(ele_size - ref_ele_size) / ref_ele_size max_rel_error = max(max_rel_error, rel_error) #print(f"ele {ele_tag}, size: {ele_size}, ref size: {ref_ele_size}, {rel_error}") if rel_error > tolerance: print( f"Size mismatch, ele {ele_tag}, size: {ele_size}, ref size: {ref_ele_size}, rel_err: {rel_error}" ) n_mismatch += 1 assert n_mismatch <= max_mismatch print(f"n_mismatch: {n_mismatch}, max n mismatch: {max_mismatch}") print(f"max rel error: {max_rel_error}") del model
def test_empty_mesh(): """ Problem: Even though gmsh reports errors, it creates mesh with no elements. See seg fault problem below... The fragmentation of the tunnels is a dead end, however, we do not understand the behaviour above. """ mesh_name = "greet_empty_mesh" gen = gmsh.GeometryOCC(mesh_name, verbose=True) geom = geometry() # create inner box # box_inner = create_box(gen, geometry_dict['inner_box']) # create tunnel box_size = np.array(geom['outer_box']["size"]) tunnel_start = np.array(geom['tunnel_1']["start"]) tunnel_mid = np.array(geom['tunnel_1']["end"]) tunnel_end = np.array(geom['tunnel_2']["end"]) side_y = gen.rectangle([box_size[0], box_size[2]]).rotate([-1, 0, 0], np.pi / 2) tunnel_split = dict(start=side_y.copy().translate([0, tunnel_start[1], 0]), mid=side_y.copy().translate([0, tunnel_mid[1], 0]), end=side_y.copy().translate([0, tunnel_end[1], 0])) tunnel_1_c, tunnel_box_1 = create_cylinder(gen, geom['tunnel_1'], 0.2) tunnel_1_x = tunnel_1_c.copy().intersect(tunnel_box_1) tunnel_2_c, tunnel_box_2 = create_cylinder(gen, geom['tunnel_2'], 0.2) tunnel_2_x = tunnel_2_c.copy().intersect(tunnel_box_2) tunnel_1_s, tunnel_2_s, s1, s3 = gen.fragment( tunnel_1_c.copy(), tunnel_2_c.copy(), tunnel_split["start"].copy(), # tunnel_split["mid"].copy(), tunnel_split["end"].copy()) tunnel_1 = tunnel_1_s.select_by_intersect(tunnel_1_x) tunnel_2 = tunnel_2_s.select_by_intersect(tunnel_2_x) tunnel_1.set_region("t1") tunnel_2.set_region("t2") # box_inner_reg = box_inner.cut(*tunnel) # ENDS WITH SEG FAULT !!!!!!!!!!!!!!!!!!!!!!!!!!! # tunnel_1.mesh_step(1.5) # tunnel_2.mesh_step(1.5) # ends normally, but with empty mesh !!!!!!!!!!!!!!!!!!!!!!!!!!! tunnel_1_s.mesh_step(1.5) tunnel_2_s.mesh_step(1.5) mesh_all = [tunnel_1, tunnel_2] # gen.write_brep() print("Generating mesh...") gen.make_mesh(mesh_all) print("Generating mesh...[finished]") print("Writing mesh...") gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2) print("Writing mesh...[finished]")
def make_mesh(config_dict, fractures, mesh_name, mesh_file): geom = config_dict["geometry"] fracture_mesh_step = geom['fracture_mesh_step'] dimensions = geom["box_dimensions"] # well_z0, well_z1 = geom["well_openning"] # well_length = well_z1 - well_z0 # well_r = geom["well_effective_radius"] # well_dist = geom["well_distance"] mtr = geom["main_tunnel_radius"] mtw = geom["main_tunnel_width"] mtl = geom["main_tunnel_length"] st_r = geom["lateral_tunnel_radius"] stw = geom["lateral_tunnel_width"] stl = geom["lateral_tunnel_length"] # small_tunnel_passage_width = geom["lateral_tunnel_passage_width"] br = geom["borehole_radius"] bl = geom["borehole_length"] bd = geom["borehole_distance"] factory = gmsh.GeometryOCC(mesh_name, verbose=True) gopt = options.Geometry() gopt.Tolerance = 0.0001 gopt.ToleranceBoolean = 0.001 # gopt.MatchMeshTolerance = 1e-1 # Main box box = factory.box(dimensions).set_region("box") side_z = factory.rectangle([dimensions[0], dimensions[1]]) side_y = factory.rectangle([dimensions[0], dimensions[2]]) side_x = factory.rectangle([dimensions[2], dimensions[1]]) sides = dict( side_z0=side_z.copy().translate([0, 0, -dimensions[2] / 2]), side_z1=side_z.copy().translate([0, 0, +dimensions[2] / 2]), side_y0=side_y.copy().translate([0, 0, -dimensions[1] / 2]).rotate([-1, 0, 0], np.pi / 2), side_y1=side_y.copy().translate([0, 0, +dimensions[1] / 2]).rotate([-1, 0, 0], np.pi / 2), side_x0=side_x.copy().translate([0, 0, -dimensions[0] / 2]).rotate([0, 1, 0], np.pi / 2), side_x1=side_x.copy().translate([0, 0, +dimensions[0] / 2]).rotate([0, 1, 0], np.pi / 2) ) for name, side in sides.items(): side.modify_regions(name) b_box = box.get_boundary().copy() # # two vertical cut-off wells, just permeable part # left_center = [-well_dist/2, 0, 0] # right_center = [+well_dist/2, 0, 0] # main tunnel main_tunnel_block = factory.box([mtw, mtl, mtr]) y_shift = math.sqrt(mtr * mtr - 0.25 * mtw * mtw) - mtr / 2 main_tunnel_block_tmp = main_tunnel_block.copy().translate([0, 0, mtr]) main_tunnel_cylinder_tmp = factory.cylinder(mtr, axis=[0, mtl, 0]).translate([0, -mtl / 2, -y_shift]) main_tunnel_cylinder = main_tunnel_block_tmp.intersect(main_tunnel_cylinder_tmp) # lateral part of main tunnel y_shift_2 = math.sqrt(st_r * st_r - 0.25 * stw * stw) - st_r / 2 small_tunnel_block = factory.box([stl, stw, st_r]) small_tunnel_block_tmp = small_tunnel_block.copy().translate([0, 0, st_r]) small_tunnel_cylinder_tmp = factory.cylinder(st_r, axis=[stl, 0, 0])\ .translate([-stl / 2, 0, -y_shift_2]) small_tunnel_cylinder = small_tunnel_block_tmp.intersect(small_tunnel_cylinder_tmp) lateral_tunnel_part_1 = factory.group(small_tunnel_block, small_tunnel_cylinder) \ .translate([stl / 2, 0, 0]) lateral_tunnel_part_2 = lateral_tunnel_part_1.copy().translate([0, bd, 0]) lateral_tunnel_part_3 = lateral_tunnel_part_1.copy().translate([0, -bd, 0]) # lateral_tunnel_part = factory.group(lateral_tunnel_part_1, lateral_tunnel_part_2) # main tunnel with lateral parts right_well = main_tunnel_block.fuse(main_tunnel_cylinder, lateral_tunnel_part_1, lateral_tunnel_part_2,\ lateral_tunnel_part_3).translate([-bl/2, 0, 0]) # horizontal boreholes # right_well_1 = factory.cylinder(br, axis=[bl, 0, 0]).translate([stl, 0, 0]) # right_well_2 = right_well_1.copy().translate([0, 0, 20]) # # right_well = factory.group(right_well_1, right_well_2).translate([-30, 0, 0]) left_well_1 = factory.cylinder(br, axis=[bl, 0, 0]).translate([stl, 0, 0]) left_well_2 = left_well_1.copy().translate([0, bd, 0]) left_well_3 = left_well_1.copy().translate([0, -bd, 0]) left_well = left_well_1.fuse(left_well_2, left_well_3).translate([-bl/2, 0, 0]) b_right_well = right_well.get_boundary() b_left_well = left_well.get_boundary() print("n fractures:", len(fractures)) fractures = process.create_fractures_rectangles(factory, fractures, factory.rectangle()) # fractures = create_fractures_polygons(factory, fractures) fractures_group = factory.group(*fractures) # fractures_group = fractures_group.remove_small_mass(fracture_mesh_step * fracture_mesh_step / 10) # drilled box and its boundary box_drilled = box.cut(left_well, right_well) # fractures, fragmented, fractures boundary print("cut fractures by box without wells") fractures_group = fractures_group.intersect(box_drilled.copy()) print("fragment fractures") box_fr, fractures_fr = factory.fragment(box_drilled, fractures_group) print("finish geometry") b_box_fr = box_fr.get_boundary() b_left_r = b_box_fr.select_by_intersect(b_left_well).set_region(".boreholes") b_right_r = b_box_fr.select_by_intersect(b_right_well).set_region(".main_tunnel") box_all = [] for name, side_tool in sides.items(): isec = b_box_fr.select_by_intersect(side_tool) box_all.append(isec.modify_regions("." + name)) box_all.extend([box_fr, b_left_r, b_right_r]) b_fractures = factory.group(*fractures_fr.get_boundary_per_region()) b_fractures_box = b_fractures.select_by_intersect(b_box).modify_regions("{}_box") b_fr_left_well = b_fractures.select_by_intersect(b_left_well).modify_regions("{}_boreholes") b_fr_right_well = b_fractures.select_by_intersect(b_right_well).modify_regions("{}_main_tunnel") b_fractures = factory.group(b_fractures_box, b_fr_left_well, b_fr_right_well) mesh_groups = [*box_all, fractures_fr, b_fractures] print(fracture_mesh_step) # fractures_fr.set_mesh_step(fracture_mesh_step) factory.keep_only(*mesh_groups) factory.remove_duplicate_entities() factory.write_brep() min_el_size = fracture_mesh_step / 10 fracture_el_size = np.max(dimensions) / 20 max_el_size = np.max(dimensions) / 8 fracture_el_size = field.constant(fracture_mesh_step, 10000) frac_el_size_only = field.restrict(fracture_el_size, fractures_fr, add_boundary=True) field.set_mesh_step_field(frac_el_size_only) mesh = options.Mesh() # mesh.Algorithm = options.Algorithm2d.MeshAdapt # produce some degenerated 2d elements on fracture boundaries ?? # mesh.Algorithm = options.Algorithm2d.Delaunay # mesh.Algorithm = options.Algorithm2d.FrontalDelaunay # mesh.Algorithm3D = options.Algorithm3d.Frontal # mesh.Algorithm3D = options.Algorithm3d.Delaunay mesh.ToleranceInitialDelaunay = 0.01 # mesh.ToleranceEdgeLength = fracture_mesh_step / 5 mesh.CharacteristicLengthFromPoints = True mesh.CharacteristicLengthFromCurvature = True mesh.CharacteristicLengthExtendFromBoundary = 2 mesh.CharacteristicLengthMin = min_el_size mesh.CharacteristicLengthMax = max_el_size mesh.MinimumCirclePoints = 6 mesh.MinimumCurvePoints = 2 # factory.make_mesh(mesh_groups, dim=2) factory.make_mesh(mesh_groups) factory.write_mesh(format=gmsh.MeshFormat.msh2) os.rename(mesh_name + ".msh2", mesh_file)
def test_empty_mesh(): """ Problem: Even though gmsh reports errors, it creates mesh with no elements. See seg fault problem below... The fragmentation of the tunnels is a dead end, however, we do not understand the behaviour above. JB: I can not reproduce seg faults but the meshing problem comes from trying to mesh a rounded tip of the two tunnels intersection, that may leads to creating to overleaping surface elements on different surfaces. """ os.chdir(this_source_dir) mesh_name = "greet_empty_mesh" gen = gmsh.GeometryOCC(mesh_name, verbose=True) geom = geometry() # create inner box # box_inner = create_box(gen, geometry_dict['inner_box']) # create tunnel box_size = np.array(geom['outer_box']["size"]) tunnel_start = np.array(geom['tunnel_1']["start"]) tunnel_mid = np.array(geom['tunnel_1']["end"]) tunnel_end = np.array(geom['tunnel_2']["end"]) side_y = gen.rectangle([box_size[0], box_size[2]]).rotate([-1, 0, 0], np.pi / 2) tunnel_split = dict(start=side_y.copy().translate([0, tunnel_start[1], 0]), mid=side_y.copy().translate([0, tunnel_mid[1], 0]), end=side_y.copy().translate([0, tunnel_end[1], 0])) tunnel_1_c, tunnel_box_1 = create_cylinder(gen, geom['tunnel_1'], 0.2) tunnel_1_x = tunnel_1_c.copy().intersect(tunnel_box_1) tunnel_2_c, tunnel_box_2 = create_cylinder(gen, geom['tunnel_2'], 0.2) tunnel_2_x = tunnel_2_c.copy().intersect(tunnel_box_2) tunnel_1_s, tunnel_2_s, s1, s3 = gen.fragment( tunnel_1_c.copy(), tunnel_2_c.copy(), tunnel_split["start"].copy(), # tunnel_split["mid"].copy(), tunnel_split["end"].copy()) tunnel_1 = tunnel_1_s.select_by_intersect(tunnel_1_x) tunnel_2 = tunnel_2_s.select_by_intersect(tunnel_2_x) tunnel_1.set_region("t1") tunnel_2.set_region("t2") # box_inner_reg = box_inner.cut(*tunnel) # ENDS WITH SEG FAULT !!!!!!!!!!!!!!!!!!!!!!!!!!! # tunnel_1.mesh_step(1.5) # tunnel_2.mesh_step(1.5) # ends normally, but with empty mesh !!!!!!!!!!!!!!!!!!!!!!!!!!! tunnel_1_s.mesh_step(1.5) tunnel_2_s.mesh_step(1.5) mesh_all = [tunnel_1, tunnel_2] gen.write_brep() print("Generating mesh...") # Occasionally ends with error: # Exception: Invalid boundary mesh (overlapping facets) on surface 39 surface 40 # ... # Info : Tetrahedrizing 744 nodes... # Info : Done tetrahedrizing 752 nodes (Wall 0.0108547s, CPU 0.010854s) # Info : Reconstructing mesh... # Info : - Creating surface mesh # Info : Found two overlapping facets. # Info : 1st: [26, 25, 64] #39 # Info : 2nd: [26, 25, 64] #40 # ----------------------------- Captured stderr call ----------------------------- # Warning : 16 elements remain invalid in surface 11 # Warning : 18 elements remain invalid in surface 25 # Warning : 12 elements remain invalid in surface 41 # Warning : 18 elements remain invalid in surface 45 # Warning : 66 elements remain invalid in surface 25 # Warning : 32 elements remain invalid in surface 45 # Error : Invalid boundary mesh (overlapping facets) on surface 39 surface 40 # Sucessfull test run: # Info : Found volume 6 # Info : It. 0 - 0 nodes created - worst tet radius 1.14137 (nodes removed 0 0) # Info : 3D refinement terminated (2567 nodes total): # Info : - 0 Delaunay cavities modified for star shapeness # Info : - 0 nodes could not be inserted # Info : - 657 tetrahedra created in 0.000683932 sec. (960621 tets/s) # Info : Tetrahedrizing 585 nodes... # Info : Done tetrahedrizing 593 nodes (Wall 0.00824587s, CPU 0.008245s) # Info : Reconstructing mesh... # Info : - Creating surface mesh # Info : - Identifying boundary edges # Info : - Recovering boundary # Info : Done reconstructing mesh (Wall 0.0159928s, CPU 0.015992s) # local TOX run: # ... # Info : Found volume 6 # Info : It. 0 - 0 nodes created - worst tet radius 1.87415 (nodes removed 0 0) # Info : 3D refinement terminated (2553 nodes total): # Info : - 0 Delaunay cavities modified for star shapeness # Info : - 7 nodes could not be inserted # Info : - 64 tetrahedra created in 4.7456e-05 sec. (1348617 tets/s) # Info : Tetrahedrizing 1297 nodes... # Info : Done tetrahedrizing 1305 nodes (Wall 0.020723s, CPU 0.020724s) # Info : Reconstructing mesh... # Info : - Creating surface mesh # Info : Found two overlapping facets. # Info : 1st: [114, 113, 64] #39 # Info : 2nd: [114, 113, 64] #40 # ---------------------------------------------------------------------------------------------- Captured stderr call ----------------------------------------------------------------------------------------------- # Warning : 16 elements remain invalid in surface 11 # Warning : 18 elements remain invalid in surface 25 # Warning : 4 elements remain invalid in surface 41 # Warning : 24 elements remain invalid in surface 45 # Warning : 34 elements remain invalid in surface 25 # Warning : 6 elements remain invalid in surface 41 # Warning : 20 elements remain invalid in surface 45 # Error : Invalid boundary mesh (overlapping facets) on surface 39 surface 40 gen.make_mesh(mesh_all) print("Generating mesh...[finished]") print("Writing mesh...") gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2) print("Writing mesh...[finished]")
def test_fuse_tunnel_2(): """ Test shows, how to fuse two cylinders cross-secting each in a common plane under given angle. In contrast to previous test, we rotate the second tunnel around extremal point EP of the intersetion ellipse and then fuses both into final object. -> RESULT: not a good approach - the point EP is found correctly, however the cylinders stick out which can be seen both in brep and even better in resulting mesh with finer mesh step. """ os.chdir(this_source_dir) mesh_name = "fuse_tunnel_2" gen = gmsh.GeometryOCC(mesh_name, verbose=True) geom = geometry() # create tunnel tunnel_start = np.array(geom['tunnel_1']["start"]) tunnel_mid = np.array(geom['tunnel_1']["end"]) tunnel_end = np.array(geom['tunnel_2']["end"]) radius = float(geom['tunnel_1']["radius"]) assert radius == float(geom['tunnel_2']["radius"]) # # cutting box box_s = 20 # box = gen.box([box_s, box_s, box_s]) # # cutting plane between the cylinders plane = gen.rectangle([box_s, box_s]).rotate([1, 0, 0], np.pi / 2) # directional vectors of the cylinders # supposing equal radius v_t1 = tunnel_mid - tunnel_start v_t1 = v_t1 / np.linalg.norm(v_t1) # normalize v_t2 = tunnel_mid - tunnel_end v_t2 = v_t2 / np.linalg.norm(v_t2) # normalize # directional vectors of the cutting plane angle_12 = np.pi - np.arccos(np.dot(v_t1, v_t2)) d = radius / np.sin(angle_12) u = d * (v_t1 + v_t2 ) # points from the center to the extremal point of the ellipse E # distance we have to move both cylinder, so they meet at E with their corners delta = np.sqrt(np.dot(u, u) - radius * radius) # create prolongated tunnels for fusion tunnel_mid_1 = tunnel_mid + delta * v_t1 tunnel_mid_2 = tunnel_mid + delta * v_t2 tunnel_1 = gen.cylinder(radius, tunnel_mid_1 - tunnel_start, tunnel_start) tunnel_2 = gen.cylinder(radius, tunnel_mid_2 - tunnel_end, tunnel_end) # if needed, make the cutting ellipse plane v = np.cross(v_t1, v_t2) # normal of the cutting plane n = np.cross(u, v) n = n / np.linalg.norm(n) # normalize # angle between cutting plane and y-axis angle = np.arccos(np.dot([0, 0, 1], n)) - np.pi / 2 # rotate cutting box and plane plane.rotate(axis=[1, 0, 0], angle=angle) # move the cutting plane into the connecting point plane.translate(tunnel_mid) print("fuse...") # tunnel = tunnel_1.copy().fuse(tunnel_2.copy()) tunnel = tunnel_1.fuse(tunnel_2) # tunnel = tunnel_2_x.fuse(tunnel_1_x) mesh_step = 1.0 tunnel.set_region("tunnel").mesh_step(mesh_step) # tunnel_3 = gen.cylinder(radius, tunnel_mid - tunnel_start, tunnel_start) # tunnel_4 = gen.cylinder(radius, tunnel_mid - tunnel_end, tunnel_end) # tunnel_1.set_region("tunnel_1").mesh_step(mesh_step) # tunnel_2.set_region("tunnel_2").mesh_step(mesh_step) # tunnel_3.set_region("tunnel_3").mesh_step(mesh_step) # tunnel_4.set_region("tunnel_4").mesh_step(mesh_step) # mesh_all = [tunnel] # uncomment one of the following (and the corresponding above) to see auxilliary objects mesh_all = [tunnel, plane] # mesh_all = [plane, tunnel_1, tunnel_2] # mesh_all = [tunnel_1, tunnel_2, tunnel, plane, tunnel_3, tunnel_4] print("Generating mesh...") gen.keep_only(*mesh_all) gen.write_brep() gen.make_mesh(mesh_all) print("Generating mesh...[finished]") print("Writing mesh...") gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2) print("Writing mesh...[finished]")
def test_fuse_tunnel(): """ Test shows, how to fuse two cylinders cross-secting each in a common plane under given angle. It prolongates the cylinders, creates the common face in the middle, cuts the original cylinders and then fuses them into final object. """ os.chdir(this_source_dir) mesh_name = "fuse_tunnel" gen = gmsh.GeometryOCC(mesh_name, verbose=True) geom = geometry() # create tunnel tunnel_start = np.array(geom['tunnel_1']["start"]) tunnel_mid = np.array(geom['tunnel_1']["end"]) tunnel_end = np.array(geom['tunnel_2']["end"]) tunnel_1_c = create_cylinder(gen, geom['tunnel_1'], 0.2)[0] tunnel_2_c = create_cylinder(gen, geom['tunnel_2'], 0.2)[0] # cutting box box_s = 200 box = gen.box([box_s, box_s, box_s]) # cutting plane between the cylinders plane = gen.rectangle([box_s, box_s]).rotate([1, 0, 0], np.pi / 2) # directional vectors of the cylinders # supposing equal radius v_t1 = tunnel_mid - tunnel_start v_t1 = v_t1 / np.linalg.norm(v_t1) # normalize v_t2 = tunnel_mid - tunnel_end v_t2 = v_t2 / np.linalg.norm(v_t2) # normalize # directional vectors of the cutting plane u = v_t1 + v_t2 v = np.cross(v_t1, v_t2) # normal of the cutting plane n = np.cross(u, v) n = n / np.linalg.norm(n) # normalize # angle between cutting plane and y-axis angle = np.arccos(np.dot([0, 0, 1], n)) - np.pi / 2 # rotate cutting box and plane box.rotate(axis=[1, 0, 0], angle=angle) plane.rotate(axis=[1, 0, 0], angle=angle) # move the cutting plane into the connecting point plane.translate(tunnel_mid) # move box and cut the first cylinder box.translate(tunnel_mid) box.translate(-box_s / 2 * n) tunnel_1_x = tunnel_1_c.intersect(box) # move box and cut the second cylinder box.translate(+box_s * n) tunnel_2_x = tunnel_2_c.intersect(box) print("fuse...") tunnel = tunnel_1_x.fuse(tunnel_2_x) # tunnel = tunnel_2_x.fuse(tunnel_1_x) tunnel.set_region("tunnel").mesh_step(1.5) mesh_all = [tunnel] print("Generating mesh...") gen.keep_only(*mesh_all) gen.write_brep() gen.make_mesh(mesh_all) print("Generating mesh...[finished]") print("Writing mesh...") gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2) print("Writing mesh...[finished]")
def test_2D_tunnel_cut(): """ Generates a square mesh with an elliptic hole in its center. Test: - square and ellipse creation - cut and fragment functions - adding physical boundaries (select_by_intersect) - setting mesh_step to the tunnel boundary - reading the gmsh logger """ mesh_name = "2d_tunnel_cut" tunnel_mesh_step = 0.5 dimensions = [100, 100] tunnel_dims = np.array([4.375, 3.5]) / 2 tunnel_center = [0, 0, 0] # test gmsh loggger gen = gmsh.GeometryOCC(mesh_name, verbose=True) gmsh_logger = gen.get_logger() gmsh_logger.start() # Main box box = gen.rectangle(dimensions).set_region("box") side = gen.line([-dimensions[0] / 2, 0, 0], [dimensions[0] / 2, 0, 0]) sides = dict(bottom=side.copy().translate([0, -dimensions[1] / 2, 0]), top=side.copy().translate([0, +dimensions[1] / 2, 0]), left=side.copy().translate([0, +dimensions[0] / 2, 0]).rotate([0, 0, 1], np.pi / 2), right=side.copy().translate([0, -dimensions[0] / 2, 0]).rotate([0, 0, 1], np.pi / 2)) # ellipse of the tunnel cross-section tunnel_disc = gen.disc(tunnel_center, *tunnel_dims) tunnel_select = tunnel_disc.copy() box_drilled = box.cut(tunnel_disc) box_fr, tunnel_fr = gen.fragment(box_drilled, tunnel_disc) box_all = [] b_box_fr = box_fr.get_boundary() for name, side_tool in sides.items(): isec = b_box_fr.select_by_intersect(side_tool) box_all.append(isec.modify_regions("." + name)) b_tunnel_select = tunnel_select.get_boundary() b_tunnel = b_box_fr.select_by_intersect(b_tunnel_select) b_tunnel.modify_regions(".tunnel").mesh_step(tunnel_mesh_step) box_all.extend([box_fr, b_tunnel]) mesh_groups = [*box_all] gen.keep_only(*mesh_groups) # gen.write_brep() min_el_size = tunnel_mesh_step / 2 max_el_size = np.max(dimensions) / 10 gen.make_mesh(mesh_groups) gmsh_log_msgs = gmsh_logger.get() gmsh_logger.stop() def check_gmsh_log(lines): """ Search for "No elements in volume" message -> could not mesh the volume -> empty mesh. # PLC Error: A segment and a facet intersect at point (-119.217,65.5762,-40.8908). # Segment: [70,2070] #-1 (243) # Facet: [3147,9829,13819] #482 # Info : failed to recover constrained lines/triangles # Info : function failed # Info : function failed # Error : HXT 3D mesh failed # Error : No elements in volume 1 # Info : Done meshing 3D (Wall 0.257168s, CPU 0.256s) # Info : 13958 nodes 34061 elements # Error : ------------------------------ # Error : Mesh generation error summary # Error : 0 warnings # Error : 2 errors # Error : Check the full log for details # Error : ------------------------------ """ empty_volume_error = "No elements in volume" res = [line for line in lines if empty_volume_error in line] if len(res) != 0: raise Exception("GMSH error - No elements in volume") check_gmsh_log(gmsh_log_msgs) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2) # estimate number of the smallest elements around the tunnel tunnel_circuference = np.pi * np.sqrt( 2 * (tunnel_dims[0]**2 + tunnel_dims[1]**2)) n_expected = np.round(tunnel_circuference / tunnel_mesh_step) # get number of the smallest elements n_match = check_min_mesh_step(dim=2, step_size=tunnel_mesh_step, tolerance=0.05) assert n_match > n_expected
def generate_mesh(geom): # options.Geometry.Tolerance = 0.001 # options.Geometry.ToleranceBoolean = 1e-2 # options.Geometry.AutoCoherence = 2 # options.Geometry.OCCFixSmallEdges = True # options.Geometry.OCCFixSmallFaces = True # options.Geometry.OCCFixDegenerated = True # options.Geometry.OCCSewFaces = True # # # # options.Mesh.ToleranceInitialDelaunay = 0.01 # options.Mesh.CharacteristicLengthMin = 0.1 # options.Mesh.CharacteristicLengthMax = 2.0 # options.Mesh.AngleToleranceFacetOverlap = 0.8 gen = gmsh.GeometryOCC("greet_mesh_tunnel", verbose=True) # with open(os.path.join(script_dir, "geometry.yaml"), "r") as f: # geom = yaml.safe_load(f) # create tunnel box_size = np.array(geometry_dict['outer_box']["size"]) tunnel_start = np.array(geom['tunnel_1']["start"]) tunnel_mid = np.array(geom['tunnel_1']["end"]) tunnel_end = np.array(geom['tunnel_2']["end"]) tunnel = fuse_tunnels(gen, geom) # create inner box box_inner = create_box(gen, geometry_dict['inner_box']) # create outer box box_outer = create_box(gen, geometry_dict['outer_box']) # create fracture cut box cut_fracture_box = create_box(gen, geometry_dict['cut_fracture_box']) # create cut outer_box object for setting the correct region box_outer_cut = box_outer.copy().cut(box_inner) # cut tunnel from inner box box_inner_cut = box_inner.cut(*tunnel) # prepare auxiliary boundary objects to set boundary regions side_z = gen.rectangle([box_size[0], box_size[1]]) side_y = gen.rectangle([box_size[0], box_size[2]]) side_x = gen.rectangle([box_size[2], box_size[1]]) sides = dict( bottom=side_z.copy().translate([0, 0, -box_size[2] / 2]), top=side_z.copy().translate([0, 0, +box_size[2] / 2]), back=side_y.copy().translate([0, 0, -box_size[1] / 2]).rotate([-1, 0, 0], np.pi / 2), front=side_y.copy().translate([0, 0, +box_size[1] / 2]).rotate([-1, 0, 0], np.pi / 2), right=side_x.copy().translate([0, 0, -box_size[0] / 2]).rotate([0, 1, 0], np.pi / 2), left=side_x.copy().translate([0, 0, +box_size[0] / 2]).rotate([0, 1, 0], np.pi / 2) ) # translate and rotate all to final position objs_to_rotate = [box_outer_cut, box_inner_cut, cut_fracture_box, *tunnel, *sides.values()] outer_box_points = np.array(geometry_dict['outer_box']["nodes"]) barycenter = [np.average(outer_box_points[:, 0]), np.average(outer_box_points[:, 1]), np.average(outer_box_points[:, 2])] rot_x = float(geometry_dict['outer_box']["rot_x"]) rot_y = float(geometry_dict['outer_box']["rot_y"]) rot_z = float(geometry_dict['outer_box']["rot_z"]) for obj in objs_to_rotate: if rot_x != 0: obj.rotate([1, 0, 0], rot_x) if rot_y != 0: obj.rotate([0, 1, 0], rot_y) if rot_z != 0: obj.rotate([0, 0, 1], rot_z) obj.translate(barycenter) # I have no idea, why I have to do this separately.. box_outer.translate(barycenter) # create fractures fractures = [] fracture_names = [] for f in geometry_dict['fractures']: fract = create_plane(gen, f) # fract.set_region(f["name"]) fractures.append(fract.intersect(cut_fracture_box)) fracture_names.append(f["name"]) print("fragment start") frag = gen.fragment(box_outer, box_inner_cut, *[f.copy() for f in fractures]) fractures_f_group = gen.group(*[frag[i] for i in range(2, len(frag))]) # frag = gen.fragment(box_outer, box_inner_cut) print("fragment end") box_outer_reg = frag[0].select_by_intersect(box_outer_cut) box_outer_reg.set_region(geometry_dict['outer_box']["name"]) gen.set_mesh_step(box_outer_reg, 10.0) box_inner_reg = frag[1] box_inner_reg.set_region(geometry_dict['inner_box']["name"]) gen.set_mesh_step(box_inner_reg, 4.0) box_all = [box_outer_reg, box_inner_reg] # make boundaries print("Making boundaries...") b_box_outer = box_outer_reg.get_boundary() b_box_inner = box_inner_reg.get_boundary() for name, side_tool in sides.items(): isec_outer = b_box_outer.select_by_intersect(side_tool) isec_inner = b_box_inner.select_by_intersect(side_tool) isec_outer.set_region("." + geometry_dict['outer_box']["name"] + "_" + name) isec_inner.set_region("." + geometry_dict['inner_box']["name"] + "_" + name) box_all.append(isec_outer) box_all.append(isec_inner) b_box_inner = box_inner_reg.get_boundary() b_tunnel_parts = [] for i in range(len(tunnel)): b_tunnel_part = b_box_inner.select_by_intersect(tunnel[i]) b_tunnel_part.set_region(".tunnel" + "_" + str(i)) b_tunnel_parts.append(b_tunnel_part) gen.set_mesh_step(b_tunnel_part, 1.0) print("Making boundaries...[finished]") box_all.extend(b_tunnel_parts) print("Setting fractures regions...") # fracture regions fractures_reg = [] for frac, name in zip(fractures, fracture_names): frac_cut = frac.cut(*tunnel) frac_reg = fractures_f_group.select_by_intersect(frac_cut) frac_reg.set_region(name) gen.set_mesh_step(frac_reg, 2.0) fractures_reg.append(frac_reg) # set regions on the 1D curve cross-section of fractures and tunnel surface b_frac_reg = frac_reg.get_boundary() for i in range(len(b_tunnel_parts)): b_fract_tunnel = b_frac_reg.select_by_intersect(b_tunnel_parts[i]) if len(b_fract_tunnel.dim_tags) < 1: continue b_fract_tunnel.set_region("." + name + "_tunnel" + "_" + str(i)) box_all.append(b_fract_tunnel) box_all.extend(fractures_reg) print("Setting fractures regions...[finished]") # the tunnel must be removed before meshing | we do not know the reason for t in tunnel: gen.model.remove(t.dim_tags) # for sb in split_boxes: # gen.model.remove(sb.dim_tags) i=0 for b in box_all: print("i={0} ".format(i)) for r in b.regions: print("{0} ({1}) ".format(r.name, r.id)) for dt in b.dim_tags: print(dt) i = i+1 # mesh_all = [*tunnel] mesh_all = [*box_all] # mesh_all = [*split_boxes] print("Generating mesh...") gen.keep_only(*mesh_all) gen.write_brep() gen.make_mesh(mesh_all) print("Generating mesh...[finished]") print("Writing mesh...") mesh_name = "greet_mesh.msh2" gen.write_mesh(mesh_name, gmsh.MeshFormat.msh2) print("Writing mesh...[finished]")
def test_splitting(): """ In this test, we split the object (cylinder) into chosen number of parts. We should provide a function for this. Question is how to set the splitting plane, how to provide the axis in which we split the object. TODO: The main point is in the end, where we transform ObjectSet into list of ObjectSet, taking advantage of the simple problem.. We will have to use the symetric fragmentation and then select properly the parts... We should think of creating method for half-space defined by a plane.. """ mesh_name = "splitting" gen = gmsh.GeometryOCC(mesh_name, verbose=True) # tunnel_start = np.array([-50, -50, 10]) tunnel_start = np.array([0, 0, 0]) tunnel_end = np.array([50, 50, 10]) radius = 5 tunnel = gen.cylinder(radius, tunnel_end-tunnel_start, tunnel_start) # cutting box box_s = 50 # cutting plane between the cylinders split_plane = gen.rectangle([box_s, box_s]) # normal is in z-axis z = [0, 0, 1] # directional vector of the cylinder u_t = tunnel_end - tunnel_start u_t = u_t / np.linalg.norm(u_t) # normalize # axis of rotation axis = np.cross(z, u_t) axis = axis / np.linalg.norm(axis) # normalize angle = np.arccos(np.dot(u_t, z)) split_plane.rotate(axis=axis, angle=angle, center=[0, 0, 0]) splits = [] length_t = np.linalg.norm(tunnel_end-tunnel_start) n_parts = 5 # number of parts length_part = length_t / n_parts # length of a single part split_pos = tunnel_start + length_part*u_t for i in range(n_parts-1): split = split_plane.copy().translate(split_pos) splits.append(split) split_pos = split_pos + length_part*u_t # tunnel_f = tunnel.fragment(*splits) tunnel_f = tunnel.fragment(*[s.copy() for s in splits]) # split fragmented ObjectSet into list of ObjectSets by dimtags tunnel_parts = [] for dimtag, reg in tunnel_f.dimtagreg(): tunnel_parts.append(gmsh.ObjectSet(gen, [dimtag], [gmsh.Region.default_region[3]])) def center_comparison(obj): center, mass = obj.center_of_mass() return np.linalg.norm(center-tunnel_start) # for t in tunnel: # print(center_comparison(t)) tunnel_parts.sort(reverse=False, key=center_comparison) # test setting mesh step size i = 0 delta = 0.4 for t in tunnel_parts: print(gen.model.getMass(*(t.dim_tags[0]))) t.mesh_step(0.6+i*delta) i = i+1 gen.make_mesh([*tunnel_parts, *splits]) gen.write_mesh(mesh_name + ".msh2", gmsh.MeshFormat.msh2)