def make_cylinder_mesh(radius=0.5, height=1, radial_subdivisions=10, height_subdivisions=1, max_volume=None, periodic=False, boundary_tagger=(lambda fvi, el, fn, all_v: [])): from meshpy.tet import MeshInfo, build from meshpy.geometry import make_cylinder points, facets, facet_holestarts, facet_markers = \ make_cylinder(radius, height, radial_subdivisions, height_subdivisions) assert len(facets) == len(facet_markers) if periodic: return _make_z_periodic_mesh( points, facets, facet_holestarts, facet_markers, height=height, max_volume=max_volume, boundary_tagger=boundary_tagger) else: mesh_info = MeshInfo() mesh_info.set_points(points) mesh_info.set_facets_ex(facets, facet_holestarts, facet_markers) generated_mesh = build(mesh_info, max_volume=max_volume) from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Tetrahedron vertices = numpy.asarray(generated_mesh.points, dtype=float, order="C") return make_conformal_mesh_ext( vertices, [Tetrahedron(i, el_idx, vertices) for i, el_idx in enumerate(generated_mesh.elements)], boundary_tagger)
def make_1d_mesh(points, left_tag=None, right_tag=None, periodic=False, boundary_tagger=None, volume_tagger=None): def my_boundary_tagger(fvi, el, fn, all_v): if el.face_normals[fn][0] < 0: return [left_tag] else: return [right_tag] kwargs = {} if volume_tagger is not None: kwargs["volume_tagger"] = volume_tagger if periodic: left_tag = "x_minus" right_tag = "x_plus" kwargs["periodicity"] = [(left_tag, right_tag)] if boundary_tagger is not None: raise ValueError("cannot have both periodicity and a custom " "boundary tagger") boundary_tagger = my_boundary_tagger else: boundary_tagger = boundary_tagger or my_boundary_tagger from hedge.mesh import make_conformal_mesh_ext vertices = numpy.asarray(points, order="C").reshape((len(points), 1)) from hedge.mesh.element import Interval return make_conformal_mesh_ext( vertices, [Interval(i, (i, i+1), vertices) for i in xrange(len(points)-1)], boundary_tagger=boundary_tagger, **kwargs)
def make_disk_mesh(r=0.5, faces=50, max_area=4e-3, boundary_tagger=(lambda fvi, el, fn, all_v: [])): from math import cos, sin, pi def needs_refinement(vertices, area): return area > max_area points = [(r*cos(angle), r*sin(angle)) for angle in numpy.linspace(0, 2*pi, faces, endpoint=False)] import meshpy.triangle as triangle mesh_info = triangle.MeshInfo() mesh_info.set_points(points) mesh_info.set_facets( list(_round_trip_connect(0, faces-1)), faces*[1] ) generated_mesh = triangle.build(mesh_info, refinement_func=needs_refinement) from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Triangle vertices = numpy.asarray(generated_mesh.points, dtype=float, order="C") return make_conformal_mesh_ext( vertices, [Triangle(i, el_idx, vertices) for i, el_idx in enumerate(generated_mesh.elements)], boundary_tagger)
def make_mesh(a, b, pml_width=0.25, **kwargs): from meshpy.geometry import GeometryBuilder, make_circle geob = GeometryBuilder() circle_centers = [(-1.5, 0), (1.5, 0)] for cent in circle_centers: geob.add_geometry(*make_circle(1, cent)) geob.wrap_in_box(1) geob.wrap_in_box(pml_width) mesh_mod = geob.mesher_module() mi = mesh_mod.MeshInfo() geob.set(mi) mi.set_holes(circle_centers) built_mi = mesh_mod.build(mi, **kwargs) def boundary_tagger(fvi, el, fn, points): return [] from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Triangle pts = np.asarray(built_mi.points, dtype=np.float64) return make_conformal_mesh_ext( pts, [Triangle(i, el, pts) for i, el in enumerate(built_mi.elements)], boundary_tagger)
def finish_2d_rect_mesh(points, facets, facet_markers, marker2tag, refine_func, periodicity, boundary_tagger): """Semi-internal bottom-half routine for generation of rectangular 2D meshes.""" import meshpy.triangle as triangle mesh_info = triangle.MeshInfo() mesh_info.set_points(points) mesh_info.set_facets(facets, facet_markers) #triangle.write_gnuplot_mesh("mesh.dat", mesh_info, True) if periodicity is None: periodicity = (False, False) axes = ["x", "y"] mesh_periodicity = [] periodic_tags = set() for i, axis in enumerate(axes): if periodicity[i]: minus_tag = "minus_"+axis plus_tag = "plus_"+axis mesh_periodicity.append((minus_tag, plus_tag)) periodic_tags.add(minus_tag) periodic_tags.add(plus_tag) else: mesh_periodicity.append(None) generated_mesh = triangle.build(mesh_info, refinement_func=refine_func, allow_boundary_steiner=not (periodicity[0] or periodicity[1])) fmlookup = MeshPyFaceMarkerLookup(generated_mesh) def wrapped_boundary_tagger(fvi, el, fn, all_v): btag = marker2tag[fmlookup(fvi)] if btag in periodic_tags: return [btag] else: return [btag] + boundary_tagger(fvi, el, fn, all_v) vertices = numpy.asarray(generated_mesh.points, dtype=float, order="C") from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Triangle return make_conformal_mesh_ext( vertices, [Triangle(i, el_idx, vertices) for i, el_idx in enumerate(generated_mesh.elements)], wrapped_boundary_tagger, periodicity=mesh_periodicity)
def _make_z_periodic_mesh(points, facets, facet_holestarts, facet_markers, height, max_volume, boundary_tagger): from meshpy.tet import MeshInfo, build from meshpy.geometry import Marker mesh_info = MeshInfo() mesh_info.set_points(points) mesh_info.set_facets_ex(facets, facet_holestarts, facet_markers) mesh_info.pbc_groups.resize(1) pbcg = mesh_info.pbc_groups[0] pbcg.facet_marker_1 = Marker.MINUS_Z pbcg.facet_marker_2 = Marker.PLUS_Z pbcg.set_transform(translation=[0, 0, height]) def zper_boundary_tagger(fvi, el, fn, all_v): # we only ask about *boundaries* # we should not try to have the user tag # the (periodicity-induced) interior faces face_marker = fvi2fm[frozenset(fvi)] if face_marker == Marker.MINUS_Z: return ["minus_z"] if face_marker == Marker.PLUS_Z: return ["plus_z"] result = boundary_tagger(fvi, el, fn, all_v) if face_marker == Marker.SHELL: result.append("shell") return result generated_mesh = build(mesh_info, max_volume=max_volume) fvi2fm = generated_mesh.face_vertex_indices_to_face_marker from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Tetrahedron vertices = numpy.asarray(generated_mesh.points, dtype=float, order="C") return make_conformal_mesh_ext( vertices, [Tetrahedron(i, el_idx, vertices) for i, el_idx in enumerate(generated_mesh.elements)], zper_boundary_tagger, periodicity=[None, None, ("minus_z", "plus_z")])
def make_ball_mesh(r=0.5, subdivisions=10, max_volume=None, boundary_tagger=(lambda fvi, el, fn, all_v: [])): from meshpy.tet import MeshInfo, build from meshpy.geometry import make_ball points, facets, facet_holestarts, facet_markers = \ make_ball(r, subdivisions) mesh_info = MeshInfo() mesh_info.set_points(points) mesh_info.set_facets_ex(facets, facet_holestarts, facet_markers) generated_mesh = build(mesh_info, max_volume=max_volume) vertices = numpy.asarray(generated_mesh.points, dtype=float, order="C") from hedge.mesh.element import Tetrahedron from hedge.mesh import make_conformal_mesh_ext return make_conformal_mesh_ext( vertices, [Tetrahedron(i, el_idx, vertices) for i, el_idx in enumerate(generated_mesh.elements)], boundary_tagger)
def make_extrusion_with_fine_core(rz, inner_r, max_volume_inner=1e-4, max_volume_outer=5e-2, radial_subdiv=20): min_z = min(rz_pt[1] for rz_pt in rz) max_z = max(rz_pt[1] for rz_pt in rz) from meshpy.tet import MeshInfo, build from meshpy.geometry import generate_surface_of_revolution MINUS_Z_MARKER = 1 PLUS_Z_MARKER = 2 inner_points, inner_facets, inner_holes, inner_markers = \ generate_surface_of_revolution( [ (0, min_z), (inner_r, min_z), (inner_r, max_z), (0, max_z), ], ring_markers=[ MINUS_Z_MARKER, 0, PLUS_Z_MARKER ], radial_subdiv=radial_subdiv, ) inner_point_indices = tuple(range(len(inner_points))) outer_points, outer_facets, outer_holes, outer_markers = \ generate_surface_of_revolution( [(inner_r,min_z)] + rz + [(inner_r, max_z)], ring_markers=[MINUS_Z_MARKER] + [0]*(len(rz)-1) + [PLUS_Z_MARKER], point_idx_offset=len(inner_points), radial_subdiv=radial_subdiv, ring_point_indices= [ inner_point_indices[:radial_subdiv] ] + [None]*len(rz) + [inner_point_indices[radial_subdiv:]] ) mesh_info = MeshInfo() mesh_info.set_points(inner_points + outer_points) mesh_info.set_facets_ex( inner_facets + outer_facets, inner_holes + outer_holes, inner_markers + outer_markers, ) # set regional max. volume mesh_info.regions.resize(2) mesh_info.regions[0] = [0, 0, (max_z + min_z) / 2, 0, max_volume_inner] mesh_info.regions[1] = [ inner_r + (rz[0][0] - inner_r) / 2, 0, (max_z + min_z) / 2, 0, max_volume_outer ] # add periodicity mesh_info.pbc_groups.resize(1) pbcg = mesh_info.pbc_groups[0] pbcg.facet_marker_1 = MINUS_Z_MARKER pbcg.facet_marker_2 = PLUS_Z_MARKER pbcg.set_transform(translation=[0, 0, max_z - min_z]) mesh = build(mesh_info, verbose=True, volume_constraints=True) #print "%d elements" % len(mesh.elements) #mesh.write_vtk("gun.vtk") fvi2fm = mesh.face_vertex_indices_to_face_marker def zper_boundary_tagger(fvi, el, fn, points): face_marker = fvi2fm[frozenset(fvi)] if face_marker == MINUS_Z_MARKER: return ["minus_z"] elif face_marker == PLUS_Z_MARKER: return ["plus_z"] else: return ["shell"] vertices = numpy.asarray(mesh.points, dtype=float, order="C") from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Tetrahedron return make_conformal_mesh_ext( vertices, [ Tetrahedron(i, el_idx, vertices) for i, el_idx in enumerate(mesh.elements) ], zper_boundary_tagger, periodicity=[None, None, ("minus_z", "plus_z")])
def make_extrusion_with_fine_core(rz, inner_r, max_volume_inner=1e-4, max_volume_outer=5e-2, radial_subdiv=20): min_z = min(rz_pt[1] for rz_pt in rz) max_z = max(rz_pt[1] for rz_pt in rz) from meshpy.tet import MeshInfo, build from meshpy.geometry import generate_surface_of_revolution MINUS_Z_MARKER = 1 PLUS_Z_MARKER = 2 inner_points, inner_facets, inner_holes, inner_markers = \ generate_surface_of_revolution( [ (0, min_z), (inner_r, min_z), (inner_r, max_z), (0, max_z), ], ring_markers=[ MINUS_Z_MARKER, 0, PLUS_Z_MARKER ], radial_subdiv=radial_subdiv, ) inner_point_indices = tuple(range(len(inner_points))) outer_points, outer_facets, outer_holes, outer_markers = \ generate_surface_of_revolution( [(inner_r,min_z)] + rz + [(inner_r, max_z)], ring_markers=[MINUS_Z_MARKER] + [0]*(len(rz)-1) + [PLUS_Z_MARKER], point_idx_offset=len(inner_points), radial_subdiv=radial_subdiv, ring_point_indices= [ inner_point_indices[:radial_subdiv] ] + [None]*len(rz) + [inner_point_indices[radial_subdiv:]] ) mesh_info = MeshInfo() mesh_info.set_points(inner_points + outer_points) mesh_info.set_facets_ex( inner_facets + outer_facets, inner_holes + outer_holes, inner_markers + outer_markers, ) # set regional max. volume mesh_info.regions.resize(2) mesh_info.regions[0] = [0, 0, (max_z+min_z)/2, 0, max_volume_inner] mesh_info.regions[1] = [inner_r+(rz[0][0]-inner_r)/2, 0, (max_z+min_z)/2, 0, max_volume_outer] # add periodicity mesh_info.pbc_groups.resize(1) pbcg = mesh_info.pbc_groups[0] pbcg.facet_marker_1 = MINUS_Z_MARKER pbcg.facet_marker_2 = PLUS_Z_MARKER pbcg.set_transform(translation=[0,0,max_z-min_z]) mesh = build(mesh_info, verbose=True, volume_constraints=True) #print "%d elements" % len(mesh.elements) #mesh.write_vtk("gun.vtk") fvi2fm = mesh.face_vertex_indices_to_face_marker def zper_boundary_tagger(fvi, el, fn, points): face_marker = fvi2fm[frozenset(fvi)] if face_marker == MINUS_Z_MARKER: return ["minus_z"] elif face_marker == PLUS_Z_MARKER: return ["plus_z"] else: return ["shell"] vertices = numpy.asarray(mesh.points, dtype=float, order="C") from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Tetrahedron return make_conformal_mesh_ext( vertices, [Tetrahedron(i, el_idx, vertices) for i, el_idx in enumerate(mesh.elements)], zper_boundary_tagger, periodicity=[None, None, ("minus_z", "plus_z")])
def build_mesh(self, periodicity, allow_internal_boundaries, tag_mapper, boundary_tagger=None): # figure out dimensionalities vol_dim = max( el.el_type.dimensions for key, el in self.gmsh_vertex_nrs_to_element.iteritems()) vol_elements = [ el for key, el in self.gmsh_vertex_nrs_to_element.iteritems() if el.el_type.dimensions == vol_dim ] # build hedge-compatible elements from hedge.mesh.element import TO_CURVED_CLASS hedge_vertices = [] hedge_elements = [] gmsh_node_nr_to_hedge_vertex_nr = {} hedge_el_to_gmsh_element = {} def get_vertex_nr(gmsh_node_nr): try: return gmsh_node_nr_to_hedge_vertex_nr[gmsh_node_nr] except KeyError: hedge_vertex_nr = len(hedge_vertices) hedge_vertices.append(self.nodes[gmsh_node_nr]) gmsh_node_nr_to_hedge_vertex_nr[gmsh_node_nr] = hedge_vertex_nr return hedge_vertex_nr for el_nr, gmsh_el in enumerate(vol_elements): el_map = LocalToGlobalMap( [self.nodes[ni] for ni in gmsh_el.node_indices], gmsh_el.el_type) is_affine = el_map.is_affine() el_class = gmsh_el.el_type.geometry if not is_affine: try: el_class = TO_CURVED_CLASS[el_class] except KeyError: raise NotImplementedError( "unsupported curved gmsh element type %s" % el_class) vertex_indices = [ get_vertex_nr(gmsh_node_nr) for gmsh_node_nr in gmsh_el.gmsh_vertex_indices ] if is_affine: hedge_el = el_class(el_nr, vertex_indices, hedge_vertices) else: hedge_el = el_class(el_nr, vertex_indices, el_map) hedge_elements.append(hedge_el) hedge_el_to_gmsh_element[hedge_el] = gmsh_el from pytools import reverse_dictionary hedge_vertex_nr_to_gmsh_node_nr = reverse_dictionary( gmsh_node_nr_to_hedge_vertex_nr) del vol_elements def volume_tagger(el, all_v): return [ self.tag_name_map[tag_nr, el.dimensions] for tag_nr in hedge_el_to_gmsh_element[el].tag_numbers if (tag_nr, el.dimensions) in self.tag_name_map ] if boundary_tagger is None: def boundary_tagger(fvi, el, fn, all_v): gmsh_vertex_nrs = frozenset( hedge_vertex_nr_to_gmsh_node_nr[face_vertex_index] for face_vertex_index in fvi) try: gmsh_element = self.gmsh_vertex_nrs_to_element[ gmsh_vertex_nrs] except KeyError: return [] else: x = [ self.tag_name_map[tag_nr, el.dimensions - 1] for tag_nr in gmsh_element.tag_numbers if (tag_nr, el.dimensions - 1) in self.tag_name_map ] if len(x) > 1: from pudb import set_trace set_trace() return x vertex_array = np.array(hedge_vertices, dtype=np.float64) pt_dim = vertex_array.shape[-1] if pt_dim != vol_dim: from warnings import warn warn("Found %d-dimensional mesh embedded in %d-dimensional space. " "Hedge only supports meshes of zero codimension (for now). " "Maybe you want to set force_dimension=%d?" % (vol_dim, pt_dim, vol_dim)) from hedge.mesh import make_conformal_mesh_ext return make_conformal_mesh_ext( vertex_array, hedge_elements, boundary_tagger=boundary_tagger, volume_tagger=volume_tagger, periodicity=periodicity, allow_internal_boundaries=allow_internal_boundaries)
def build_mesh(self): # figure out dimensionalities node_dim = single_valued(len(node) for node in nodes) vol_dim = max(el.el_type.dimensions for key, el in gmsh_vertex_nrs_to_element.iteritems()) bdry_dim = vol_dim - 1 vol_elements = [el for key, el in gmsh_vertex_nrs_to_element.iteritems() if el.el_type.dimensions == vol_dim] bdry_elements = [el for key, el in gmsh_vertex_nrs_to_element.iteritems() if el.el_type.dimensions == bdry_dim] # build hedge-compatible elements from hedge.mesh.element import TO_CURVED_CLASS hedge_vertices = [] hedge_elements = [] gmsh_node_nr_to_hedge_vertex_nr = {} hedge_el_to_gmsh_element = {} def get_vertex_nr(gmsh_node_nr): try: return gmsh_node_nr_to_hedge_vertex_nr[gmsh_node_nr] except KeyError: hedge_vertex_nr = len(hedge_vertices) hedge_vertices.append(nodes[gmsh_node_nr]) gmsh_node_nr_to_hedge_vertex_nr[gmsh_node_nr] = hedge_vertex_nr return hedge_vertex_nr for el_nr, gmsh_el in enumerate(vol_elements): el_map = LocalToGlobalMap([nodes[ni] for ni in gmsh_el.node_indices], gmsh_el.el_type) is_affine = el_map.is_affine() el_class = gmsh_el.el_type.geometry if not is_affine: try: el_class = TO_CURVED_CLASS[el_class] except KeyError: raise GmshFileFormatError("unsupported curved element type %s" % el_class) vertex_indices = [get_vertex_nr(gmsh_node_nr) for gmsh_node_nr in gmsh_el.gmsh_vertex_indices] if is_affine: hedge_el = el_class(el_nr, vertex_indices, hedge_vertices) else: hedge_el = el_class(el_nr, vertex_indices, el_map) hedge_elements.append(hedge_el) hedge_el_to_gmsh_element[hedge_el] = gmsh_el from pytools import reverse_dictionary hedge_vertex_nr_to_gmsh_node_nr = reverse_dictionary(gmsh_node_nr_to_hedge_vertex_nr) del vol_elements def volume_tagger(el, all_v): return [ tag_name_map[tag_nr, el.dimensions] for tag_nr in hedge_el_to_gmsh_element[el].tag_numbers if (tag_nr, el.dimensions) in tag_name_map ] def boundary_tagger(fvi, el, fn, all_v): gmsh_vertex_nrs = frozenset(hedge_vertex_nr_to_gmsh_node_nr[face_vertex_index] for face_vertex_index in fvi) try: gmsh_element = gmsh_vertex_nrs_to_element[gmsh_vertex_nrs] except KeyError: return [] else: x = [ tag_name_map[tag_nr, el.dimensions - 1] for tag_nr in gmsh_element.tag_numbers if (tag_nr, el.dimensions - 1) in tag_name_map ] if len(x) > 1: from pudb import set_trace set_trace() return x vertex_array = np.array(hedge_vertices, dtype=np.float64) pt_dim = vertex_array.shape[-1] if pt_dim != vol_dim: from warnings import warn warn( "Found %d-dimensional mesh embedded in %d-dimensional space. " "Hedge only supports meshes of zero codimension (for now). " "Maybe you want to set force_dimension=%d?" % (vol_dim, pt_dim, vol_dim) ) from hedge.mesh import make_conformal_mesh_ext return make_conformal_mesh_ext( vertex_array, hedge_elements, boundary_tagger=boundary_tagger, volume_tagger=volume_tagger, periodicity=periodicity, allow_internal_boundaries=allow_internal_boundaries, )
def make_squaremesh(): def round_trip_connect(seq): result = [] for i in range(len(seq)): result.append((i, (i+1)%len(seq))) return result def needs_refinement(vertices, area): x = sum(numpy.array(v) for v in vertices)/3 max_area_volume = 0.7e-2 + 0.03*(0.05*x[1]**2 + 0.3*min(x[0]+1,0)**2) max_area_corners = 1e-3 + 0.001*max( la.norm(x-corner)**4 for corner in obstacle_corners) return bool(area > 2.5*min(max_area_volume, max_area_corners)) from meshpy.geometry import make_box points, facets, _, _ = make_box((-0.5,-0.5), (0.5,0.5)) obstacle_corners = points[:] from meshpy.geometry import GeometryBuilder, Marker profile_marker = Marker.FIRST_USER_MARKER builder = GeometryBuilder() builder.add_geometry(points=points, facets=facets, facet_markers=profile_marker) points, facets, _, facet_markers = make_box((-16, -22), (25, 22)) builder.add_geometry(points=points, facets=facets, facet_markers=facet_markers) from meshpy.triangle import MeshInfo, build mi = MeshInfo() builder.set(mi) mi.set_holes([(0,0)]) mesh = build(mi, refinement_func=needs_refinement, allow_boundary_steiner=True, generate_faces=True) print "%d elements" % len(mesh.elements) from meshpy.triangle import write_gnuplot_mesh write_gnuplot_mesh("mesh.dat", mesh) fvi2fm = mesh.face_vertex_indices_to_face_marker face_marker_to_tag = { profile_marker: "noslip", Marker.MINUS_X: "inflow", Marker.PLUS_X: "outflow", Marker.MINUS_Y: "inflow", Marker.PLUS_Y: "inflow" } def bdry_tagger(fvi, el, fn, all_v): face_marker = fvi2fm[fvi] return [face_marker_to_tag[face_marker]] from hedge.mesh import make_conformal_mesh_ext vertices = numpy.asarray(mesh.points, dtype=float, order="C") from hedge.mesh.element import Triangle return make_conformal_mesh_ext( vertices, [Triangle(i, el_idx, vertices) for i, el_idx in enumerate(mesh.elements)], bdry_tagger)
def make_nacamesh(): def round_trip_connect(seq): result = [] for i in range(len(seq)): result.append((i, (i + 1) % len(seq))) return result pt_back = numpy.array([1, 0]) # def max_area(pt): # max_area_front = 1e-2*la.norm(pt)**2 + 1e-5 # max_area_back = 1e-2*la.norm(pt-pt_back)**2 + 1e-4 # return min(max_area_front, max_area_back) def max_area(pt): x = pt[0] if x < 0: return 1e-2 * la.norm(pt) ** 2 + 1e-5 elif x > 1: return 1e-2 * la.norm(pt - pt_back) ** 2 + 1e-5 else: return 1e-2 * pt[1] ** 2 + 1e-5 def needs_refinement(vertices, area): barycenter = sum(numpy.array(v) for v in vertices) / 3 return bool(area > max_area(barycenter)) from meshpy.naca import get_naca_points points = get_naca_points(naca_digits="2412", number_of_points=80) from meshpy.geometry import GeometryBuilder, Marker from meshpy.triangle import write_gnuplot_mesh profile_marker = Marker.FIRST_USER_MARKER builder = GeometryBuilder() builder.add_geometry(points=points, facets=round_trip_connect(points), facet_markers=profile_marker) builder.wrap_in_box(4, (10, 8)) from meshpy.triangle import MeshInfo, build mi = MeshInfo() builder.set(mi) mi.set_holes([builder.center()]) mesh = build( mi, refinement_func=needs_refinement, # allow_boundary_steiner=False, generate_faces=True, ) write_gnuplot_mesh("mesh.dat", mesh) print "%d elements" % len(mesh.elements) fvi2fm = mesh.face_vertex_indices_to_face_marker face_marker_to_tag = { profile_marker: "noslip", Marker.MINUS_X: "inflow", Marker.PLUS_X: "outflow", Marker.MINUS_Y: "inflow", Marker.PLUS_Y: "inflow" # Marker.MINUS_Y: "minus_y", # Marker.PLUS_Y: "plus_y" } def bdry_tagger(fvi, el, fn, all_v): face_marker = fvi2fm[fvi] return [face_marker_to_tag[face_marker]] from hedge.mesh import make_conformal_mesh_ext vertices = numpy.asarray(mesh.points, order="C") from hedge.mesh.element import Triangle return make_conformal_mesh_ext( vertices, [Triangle(i, el_idx, vertices) for i, el_idx in enumerate(mesh.elements)], bdry_tagger, # periodicity=[None, ("minus_y", "plus_y")] )
def parse_gmsh(line_iterable, force_dimension=None, periodicity=None, allow_internal_boundaries=False, tag_mapper=lambda tag: tag): """ :param force_dimension: if not None, truncate point coordinates to this many dimensions. """ feeder = LineFeeder(line_iterable) element_type_map = GMSH_ELEMENT_TYPE_TO_INFO_MAP # collect the mesh information nodes = [] elements = [] # maps (tag_number, dimension) -> tag_name tag_name_map = {} gmsh_vertex_nrs_to_element = {} class ElementInfo(Record): pass while feeder.has_next_line(): next_line = feeder.get_next_line() if not next_line.startswith("$"): raise GmshFileFormatError("expected start of section, '%s' found instead" % next_line) section_name = next_line[1:] if section_name == "MeshFormat": line_count = 0 while True: next_line = feeder.get_next_line() if next_line == "$End"+section_name: break if line_count == 0: version_number, file_type, data_size = next_line.split() if line_count > 0: raise GmshFileFormatError("more than one line found in MeshFormat section") if version_number not in ["2.1", "2.2"]: from warnings import warn warn("unexpected mesh version number '%s' found" % version_number) if file_type != "0": raise GmshFileFormatError("only ASCII gmsh file type is supported") line_count += 1 elif section_name == "Nodes": node_count = int(feeder.get_next_line()) node_idx = 1 while True: next_line = feeder.get_next_line() if next_line == "$End"+section_name: break parts = next_line.split() if len(parts) != 4: raise GmshFileFormatError("expected four-component line in $Nodes section") read_node_idx = int(parts[0]) if read_node_idx != node_idx: raise GmshFileFormatError("out-of-order node index found") if force_dimension is not None: point = [float(x) for x in parts[1:force_dimension+1]] else: point = [float(x) for x in parts[1:]] nodes.append(numpy.array(point, dtype=numpy.float64)) node_idx += 1 if node_count+1 != node_idx: raise GmshFileFormatError("unexpected number of nodes found") elif section_name == "Elements": element_count = int(feeder.get_next_line()) element_idx = 1 while True: next_line = feeder.get_next_line() if next_line == "$End"+section_name: break parts = [int(x) for x in next_line.split()] if len(parts) < 4: raise GmshFileFormatError("too few entries in element line") read_element_idx = parts[0] if read_element_idx != element_idx: raise GmshFileFormatError("out-of-order node index found") el_type_num = parts[1] try: element_type = element_type_map[el_type_num] except KeyError: raise GmshFileFormatError("unexpected element type %d" % el_type_num) tag_count = parts[2] tags = parts[3:3+tag_count] # convert to zero-based node_indices = [x-1 for x in parts[3+tag_count:]] if element_type.node_count()!= len(node_indices): raise GmshFileFormatError("unexpected number of nodes in element") gmsh_vertex_nrs = node_indices[:element_type.vertex_count] zero_based_idx = element_idx - 1 el_info = ElementInfo( index=zero_based_idx, el_type=element_type, node_indices=node_indices, gmsh_vertex_indices=gmsh_vertex_nrs, tag_numbers=[tag for tag in tags[:1] if tag != 0]) gmsh_vertex_nrs_to_element[frozenset(gmsh_vertex_nrs)] = el_info element_idx +=1 if element_count+1 != element_idx: raise GmshFileFormatError("unexpected number of elements found") elif section_name == "PhysicalNames": name_count = int(feeder.get_next_line()) name_idx = 1 while True: next_line = feeder.get_next_line() if next_line == "$End"+section_name: break dimension, number, name = next_line.split(" ", 2) dimension = int(dimension) number = int(number) if not name[0] == '"' or not name[-1] == '"': raise GmshFileFormatError("expected quotes around physical name") tag_name_map[number, dimension] = tag_mapper(name[1:-1]) name_idx +=1 if name_count+1 != name_idx: raise GmshFileFormatError("unexpected number of physical names found") else: # unrecognized section, skip while True: next_line = feeder.get_next_line() if next_line == "$End"+section_name: break # figure out dimensionalities node_dim = single_valued(len(node) for node in nodes) vol_dim = max(el.el_type.dimensions for key, el in gmsh_vertex_nrs_to_element.iteritems() ) bdry_dim = vol_dim - 1 vol_elements = [el for key, el in gmsh_vertex_nrs_to_element.iteritems() if el.el_type.dimensions == vol_dim] bdry_elements = [el for key, el in gmsh_vertex_nrs_to_element.iteritems() if el.el_type.dimensions == bdry_dim] # build hedge-compatible elements from hedge.mesh.element import TO_CURVED_CLASS hedge_vertices = [] hedge_elements = [] gmsh_node_nr_to_hedge_vertex_nr = {} hedge_el_to_gmsh_element = {} def get_vertex_nr(gmsh_node_nr): try: return gmsh_node_nr_to_hedge_vertex_nr[gmsh_node_nr] except KeyError: hedge_vertex_nr = len(hedge_vertices) hedge_vertices.append(nodes[gmsh_node_nr]) gmsh_node_nr_to_hedge_vertex_nr[gmsh_node_nr] = hedge_vertex_nr return hedge_vertex_nr for el_nr, gmsh_el in enumerate(vol_elements): el_map = LocalToGlobalMap( [nodes[ni] for ni in gmsh_el.node_indices], gmsh_el.el_type) is_affine = el_map.is_affine() el_class = gmsh_el.el_type.geometry if not is_affine: try: el_class = TO_CURVED_CLASS[el_class] except KeyError: raise GmshFileFormatError("unsupported curved element type %s" % el_class) vertex_indices = [get_vertex_nr(gmsh_node_nr) for gmsh_node_nr in gmsh_el.gmsh_vertex_indices] if is_affine: hedge_el = el_class(el_nr, vertex_indices, hedge_vertices) else: hedge_el = el_class(el_nr, vertex_indices, el_map) hedge_elements.append(hedge_el) hedge_el_to_gmsh_element[hedge_el] = gmsh_el from pytools import reverse_dictionary hedge_vertex_nr_to_gmsh_node_nr = reverse_dictionary( gmsh_node_nr_to_hedge_vertex_nr) del vol_elements def volume_tagger(el, all_v): return [tag_name_map[tag_nr, el.dimensions] for tag_nr in hedge_el_to_gmsh_element[el].tag_numbers if (tag_nr, el.dimensions) in tag_name_map] def boundary_tagger(fvi, el, fn, all_v): gmsh_vertex_nrs = frozenset( hedge_vertex_nr_to_gmsh_node_nr[face_vertex_index] for face_vertex_index in fvi) try: gmsh_element = gmsh_vertex_nrs_to_element[gmsh_vertex_nrs] except KeyError: return [] else: x = [tag_name_map[tag_nr, el.dimensions-1] for tag_nr in gmsh_element.tag_numbers if (tag_nr, el.dimensions-1) in tag_name_map] if len(x) > 1: from pudb import set_trace; set_trace() return x vertex_array = numpy.array(hedge_vertices, dtype=numpy.float64) pt_dim = vertex_array.shape[-1] if pt_dim != vol_dim: from warnings import warn warn("Found %d-dimensional mesh embedded in %d-dimensional space. " "Hedge only supports meshes of zero codimension (for now). " "Maybe you want to set force_dimension=%d?" % (vol_dim, pt_dim, vol_dim)) from hedge.mesh import make_conformal_mesh_ext return make_conformal_mesh_ext( vertex_array, hedge_elements, boundary_tagger=boundary_tagger, volume_tagger=volume_tagger, periodicity=periodicity, allow_internal_boundaries=allow_internal_boundaries)
def make_box_mesh(a=(0, 0, 0), b=(1, 1, 1), max_volume=None, periodicity=None, boundary_tagger=(lambda fvi, el, fn, all_v: []), return_meshpy_mesh=False): """Return a mesh for a brick from the origin to `dimensions`. *max_volume* specifies the maximum volume for each tetrahedron. *periodicity* is either None, or a triple of bools, indicating whether periodic BCs are to be applied along that axis. See :func:`make_conformal_mesh` for the meaning of *boundary_tagger*. A few stock boundary tags are provided for easy application of boundary conditions, namely plus_[xyz] and minus_[xyz] tag the appropriate faces of the brick. """ def count(iterable): result = 0 for i in iterable: result += 1 return result from meshpy.tet import MeshInfo, build from meshpy.geometry import make_box points, facets, _, facet_markers = make_box(a, b) mesh_info = MeshInfo() mesh_info.set_points(points) mesh_info.set_facets(facets, facet_markers) if periodicity is None: periodicity = (False, False, False) axes = ["x", "y", "z"] per_count = count(p for p in periodicity if p) marker_to_tag = {} mesh_periodicity = [] periodic_tags = set() if per_count: mesh_info.pbc_groups.resize(per_count) pbc_group_number = 0 for axis, axis_per in enumerate(periodicity): minus_marker = 1+2*axis plus_marker = 2+2*axis minus_tag = "minus_"+axes[axis] plus_tag = "plus_"+axes[axis] marker_to_tag[minus_marker] = minus_tag marker_to_tag[plus_marker] = plus_tag if axis_per: pbcg = mesh_info.pbc_groups[pbc_group_number] pbc_group_number += 1 pbcg.facet_marker_1 = minus_marker pbcg.facet_marker_2 = plus_marker translation = [0, 0, 0] translation[axis] = b[axis]-a[axis] pbcg.set_transform(translation=translation) mesh_periodicity.append((minus_tag, plus_tag)) periodic_tags.add(minus_tag) periodic_tags.add(plus_tag) else: mesh_periodicity.append(None) generated_mesh = build(mesh_info, max_volume=max_volume) fvi2fm = generated_mesh.face_vertex_indices_to_face_marker def wrapped_boundary_tagger(fvi, el, fn, all_v): face_tag = marker_to_tag[fvi2fm[frozenset(fvi)]] if face_tag in periodic_tags: return [face_tag] else: return [face_tag] + boundary_tagger(fvi, el, fn, all_v) from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Tetrahedron vertices = numpy.asarray(generated_mesh.points, dtype=float, order="C") result = make_conformal_mesh_ext( vertices, [Tetrahedron(i, el_idx, vertices) for i, el_idx in enumerate(generated_mesh.elements)], wrapped_boundary_tagger, periodicity=mesh_periodicity) if return_meshpy_mesh: return result, generated_mesh else: return result
def make_centered_regular_rect_mesh(a=(0, 0), b=(1, 1), n=(5, 5), periodicity=None, post_refine_factor=1, boundary_tagger=(lambda fvi, el, fn, all_v: [])): """Create a semi-structured rectangular mesh. :param a: the lower left hand point of the rectangle :param b: the upper right hand point of the rectangle :param n: a tuple of integers indicating the total number of points on [a,b]. :param periodicity: either None, or a tuple of bools specifying whether the mesh is to be periodic in x and y. """ if min(n) < 2: raise ValueError("need at least two points in each direction") node_dict = {} centered_node_dict = {} points = [] points_1d = [numpy.linspace(a_i, b_i, n_i) for a_i, b_i, n_i in zip(a, b, n)] dx = (numpy.array(b, dtype=numpy.float64) - numpy.array(a, dtype=numpy.float64)) / (numpy.array(n)-1) half_dx = dx/2 for j in range(n[1]): for i in range(n[0]): node_dict[i, j] = len(points) points.append(numpy.array([points_1d[0][i], points_1d[1][j]])) for j in range(n[1]-1): for i in range(n[0]-1): centered_node_dict[i, j] = len(points) points.append(numpy.array([points_1d[0][i], points_1d[1][j]]) + half_dx) elements = [] if periodicity is None: periodicity = (False, False) axes = ["x", "y"] mesh_periodicity = [] periodic_tags = set() for i, axis in enumerate(axes): if periodicity[i]: minus_tag = "minus_"+axis plus_tag = "plus_"+axis mesh_periodicity.append((minus_tag, plus_tag)) periodic_tags.add(minus_tag) periodic_tags.add(plus_tag) else: mesh_periodicity.append(None) fvi2fm = {} for i in range(n[0]-1): for j in range(n[1]-1): # c---d # |\ /| # | m | # |/ \| # a---b a = node_dict[i, j] b = node_dict[i+1, j] c = node_dict[i, j+1] d = node_dict[i+1, j+1] m = centered_node_dict[i, j] elements.append((a, b, m)) elements.append((b, d, m)) elements.append((d, c, m)) elements.append((c, a, m)) if i == 0: fvi2fm[frozenset((a, c))] = "minus_x" if i == n[0]-2: fvi2fm[frozenset((b, d))] = "plus_x" if j == 0: fvi2fm[frozenset((a, b))] = "minus_y" if j == n[1]-2: fvi2fm[frozenset((c, d))] = "plus_y" def wrapped_boundary_tagger(fvi, el, fn, all_v): btag = fvi2fm[frozenset(fvi)] if btag in periodic_tags: return [btag] else: return [btag] + boundary_tagger(fvi, el, fn, all_v) if post_refine_factor > 1: from meshpy.tools import uniform_refine_triangles points, elements, of2nf = uniform_refine_triangles( points, elements, post_refine_factor) old_fvi2fm = fvi2fm fvi2fm = {} for fvi, fm in old_fvi2fm.iteritems(): for new_fvi in of2nf[fvi]: fvi2fm[frozenset(new_fvi)] = fm vertices = numpy.asarray(points, dtype=float, order="C") from hedge.mesh import make_conformal_mesh_ext from hedge.mesh.element import Triangle return make_conformal_mesh_ext( vertices, [Triangle(i, el_idx, vertices) for i, el_idx in enumerate(elements)], wrapped_boundary_tagger, periodicity=mesh_periodicity)
def make_squaremesh(): def round_trip_connect(seq): result = [] for i in range(len(seq)): result.append((i, (i + 1) % len(seq))) return result def needs_refinement(vertices, area): x = sum(numpy.array(v) for v in vertices) / 3 max_area_volume = 0.7e-2 + 0.03 * (0.05 * x[1]**2 + 0.3 * min(x[0] + 1, 0)**2) max_area_corners = 1e-3 + 0.001 * max( la.norm(x - corner)**4 for corner in obstacle_corners) return bool(area > 2.5 * min(max_area_volume, max_area_corners)) from meshpy.geometry import make_box points, facets, _, _ = make_box((-0.5, -0.5), (0.5, 0.5)) obstacle_corners = points[:] from meshpy.geometry import GeometryBuilder, Marker profile_marker = Marker.FIRST_USER_MARKER builder = GeometryBuilder() builder.add_geometry(points=points, facets=facets, facet_markers=profile_marker) points, facets, _, facet_markers = make_box((-16, -22), (25, 22)) builder.add_geometry(points=points, facets=facets, facet_markers=facet_markers) from meshpy.triangle import MeshInfo, build mi = MeshInfo() builder.set(mi) mi.set_holes([(0, 0)]) mesh = build(mi, refinement_func=needs_refinement, allow_boundary_steiner=True, generate_faces=True) print "%d elements" % len(mesh.elements) from meshpy.triangle import write_gnuplot_mesh write_gnuplot_mesh("mesh.dat", mesh) fvi2fm = mesh.face_vertex_indices_to_face_marker face_marker_to_tag = { profile_marker: "noslip", Marker.MINUS_X: "inflow", Marker.PLUS_X: "outflow", Marker.MINUS_Y: "inflow", Marker.PLUS_Y: "inflow" } def bdry_tagger(fvi, el, fn, all_v): face_marker = fvi2fm[fvi] return [face_marker_to_tag[face_marker]] from hedge.mesh import make_conformal_mesh_ext vertices = numpy.asarray(mesh.points, dtype=float, order="C") from hedge.mesh.element import Triangle return make_conformal_mesh_ext(vertices, [ Triangle(i, el_idx, vertices) for i, el_idx in enumerate(mesh.elements) ], bdry_tagger)