def main(): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import \ generate_surface_of_revolution, EXT_OPEN, \ GeometryBuilder r = 1 l = 1 rz = [(0, 0), (r, 0), (r, l), (0, l)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution( rz, radial_subdiv=20, ring_markers=[1, 2, 3])) mesh_info = MeshInfo() geob.set(mesh_info) mesh = build(mesh_info, max_volume=0.01) mesh.write_vtk("cylinder.vtk") mesh.write_neu(file("cylinder.neu", "w"), { 1: ("minus_z", 1), 2: ("outer", 2), 3: ("plus_z", 3), })
def create_ball_mesh(num_longi_points=10): radius = 5.0 radial_subdiv = 2 * num_longi_points dphi = np.pi / num_longi_points # Make sure the nodes meet at the poles of the ball. def truncate(r): if abs(r) < 1e-10: return 0 else: return r # Compute the volume of a canonical tetrahedron # with edgelength radius*dphi. a = radius * dphi canonical_tet_volume = np.sqrt(2.0) / 12 * a**3 # Build outline for surface of revolution. rz = [(truncate(radius * np.sin(i * dphi)), radius * np.cos(i * dphi)) for i in range(num_longi_points + 1)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution( rz, closure=EXT_OPEN, radial_subdiv=radial_subdiv)) mesh_info = MeshInfo() geob.set(mesh_info) meshpy_mesh = build(mesh_info, max_volume=canonical_tet_volume) return np.array(meshpy_mesh.points), np.array(meshpy_mesh.elements)
def main(): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import ( generate_surface_of_revolution, EXT_OPEN, GeometryBuilder, ) r = 3 points = 10 dphi = pi / points def truncate(r): if abs(r) < 1e-10: return 0 else: return r rz = [(truncate(r * sin(i * dphi)), r * cos(i * dphi)) for i in range(points + 1)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution( rz, closure=EXT_OPEN, radial_subdiv=10)) mesh_info = MeshInfo() geob.set(mesh_info) mesh = build(mesh_info) mesh.write_vtk("ball.vtk")
def ball(h): from meshpy.geometry import ( EXT_OPEN, GeometryBuilder, generate_surface_of_revolution, ) from meshpy.tet import MeshInfo, build r = 3 polar_subdivision = int(math.pi / h) dphi = math.pi / polar_subdivision def truncate(val): return 0 if abs(val) < 1e-10 else val rz = [ [truncate(r * math.sin(i * dphi)), r * math.cos(i * dphi)] for i in range(polar_subdivision + 1) ] geob = GeometryBuilder() radial_subdivision = int(2 * math.pi / h) geob.add_geometry( *generate_surface_of_revolution( rz, closure=EXT_OPEN, radial_subdiv=radial_subdivision ) ) mesh_info = MeshInfo() geob.set(mesh_info) mesh = build(mesh_info) return numpy.array(mesh.points), numpy.array(mesh.elements)
def main(): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import generate_surface_of_revolution,\ EXT_CLOSED_IN_RZ, GeometryBuilder big_r = 3 little_r = 2.9 points = 50 dphi = 2*pi/points rz = [(big_r+little_r*cos(i*dphi), little_r*sin(i*dphi)) for i in range(points)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution(rz, closure=EXT_CLOSED_IN_RZ, radial_subdiv=20)) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.save_nodes("torus") mesh_info.save_poly("torus") mesh = build(mesh_info) mesh.write_vtk("torus.vtk") mesh.save_elements("torus_mesh") mesh.save_nodes("torus_mesh") mesh.write_neu(file("torus.neu", "w"), {1: ("pec", 0)})
def main(): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import \ generate_surface_of_revolution, EXT_OPEN, \ GeometryBuilder r = 3 points = 10 dphi = pi/points def truncate(r): if abs(r) < 1e-10: return 0 else: return r rz = [(truncate(r*sin(i*dphi)), r*cos(i*dphi)) for i in range(points+1)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution(rz, closure=EXT_OPEN, radial_subdiv=10)) mesh_info = MeshInfo() geob.set(mesh_info) mesh = build(mesh_info) mesh.write_vtk("ball.vtk")
def create_mesh(big_r=1.0, small_r=0.5, num_points=10): dphi = 2 * np.pi / num_points # Compute the volume of a canonical tetrahedron # with edgelength radius2*dphi. a = small_r * dphi canonical_tet_volume = np.sqrt(2.0) / 12 * a ** 3 radial_subdiv = int(2 * np.pi * big_r / a) rz = [ (big_r + small_r * np.cos(i * dphi), 0.5 * small_r * np.sin(i * dphi)) for i in range(num_points) ] geob = GeometryBuilder() geob.add_geometry( *generate_surface_of_revolution( rz, closure=EXT_CLOSED_IN_RZ, radial_subdiv=radial_subdiv ) ) mesh_info = MeshInfo() geob.set(mesh_info) meshpy_mesh = build(mesh_info, max_volume=canonical_tet_volume) return np.array(meshpy_mesh.points), np.array(meshpy_mesh.elements)
def main(): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import \ generate_surface_of_revolution, EXT_OPEN, \ GeometryBuilder r = 1 l = 1 rz = [(0,0), (r,0), (r,l), (0,l)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution(rz, radial_subdiv=20, ring_markers=[1,2,3])) mesh_info = MeshInfo() geob.set(mesh_info) mesh = build(mesh_info, max_volume=0.01) mesh.write_vtk("cylinder.vtk") mesh.write_neu(open("cylinder.neu", "w"), { 1: ("minus_z", 1), 2: ("outer", 2), 3: ("plus_z", 3), })
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 add_reinforcement(self, shape, mat_id, **kwargs): """Add reinforcement in a circle (for now), confine concrete inside if needed""" if shape == 'circle': if 'conf_id' in kwargs: reinforcement_builder = GeometryBuilder() reinforcement_builder.add_geometry( *make_circle(kwargs['D'] / 2, kwargs['c'], kwargs['count'])) r = ReinforcementProperties(reinforcement_builder.points, kwargs['bar'], mat_id) self.reinforcement.append(r) # Add points for confinement into mesh self.builder.add_geometry(*make_circle(kwargs['D'] / 2, kwargs['c'])) self.ele_mat_primitive.append( (kwargs['D'] / 2, kwargs['c'], kwargs['conf_id'])) else: reinforcement_builder = GeometryBuilder() reinforcement_builder.add_geometry( *make_circle(kwargs['D'] / 2, kwargs['c'], kwargs['count'])) r = ReinforcementProperties(reinforcement_builder.points, kwargs['bar'], mat_id) self.reinforcement.append(r) else: # Rectangular reinforcement # not implemented for now print("I can only currently add type='circle' reinforcement") exit()
def main(): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import ( generate_surface_of_revolution, EXT_CLOSED_IN_RZ, GeometryBuilder, ) big_r = 3 little_r = 2.9 points = 50 dphi = 2 * pi / points rz = [(big_r + little_r * cos(i * dphi), little_r * sin(i * dphi)) for i in range(points)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution( rz, closure=EXT_CLOSED_IN_RZ, radial_subdiv=20)) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.save_nodes("torus") mesh_info.save_poly("torus") mesh = build(mesh_info) mesh.write_vtk("torus.vtk") mesh.save_elements("torus_mesh") mesh.save_nodes("torus_mesh") mesh.write_neu(open("torus.neu", "w"), {1: ("pec", 0)})
def test_tet_mesh(visualize=False): pytest.importorskip("meshpy") from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import \ GeometryBuilder, generate_surface_of_revolution, EXT_CLOSED_IN_RZ pytest.importorskip("meshpy") big_r = 3 little_r = 1.5 points = 50 dphi = 2 * pi / points rz = np.array( [[big_r + little_r * cos(i * dphi), little_r * sin(i * dphi)] for i in range(points)]) geo = GeometryBuilder() geo.add_geometry(*generate_surface_of_revolution( rz, closure=EXT_CLOSED_IN_RZ, radial_subdiv=20)) mesh_info = MeshInfo() geo.set(mesh_info) mesh = build(mesh_info) def tet_face_vertices(vertices): return [ (vertices[0], vertices[1], vertices[2]), (vertices[0], vertices[1], vertices[3]), (vertices[0], vertices[2], vertices[3]), (vertices[1], vertices[2], vertices[3]), ] face_map = {} for el_id, el in enumerate(mesh.elements): for fid, face_vertices in enumerate(tet_face_vertices(el)): face_map.setdefault(frozenset(face_vertices), []).append( (el_id, fid)) adjacency = {} for face_vertices, els_faces in face_map.items(): if len(els_faces) == 2: (e1, f1), (e2, f2) = els_faces adjacency.setdefault(e1, []).append(e2) adjacency.setdefault(e2, []).append(e1) cuts, part_vert = pymetis.part_graph(17, adjacency) if visualize: import pyvtk vtkelements = pyvtk.VtkData( pyvtk.UnstructuredGrid(mesh.points, tetra=mesh.elements), "Mesh", pyvtk.CellData(pyvtk.Scalars(part_vert, name="partition"))) vtkelements.tofile('split.vtk')
def main(): import numpy as np from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import \ GeometryBuilder, generate_surface_of_revolution, EXT_CLOSED_IN_RZ big_r = 3 little_r = 1.5 points = 50 dphi = 2*pi/points rz = np.array([[big_r+little_r*cos(i*dphi), little_r*sin(i*dphi)] for i in range(points)]) geo = GeometryBuilder() geo.add_geometry( *generate_surface_of_revolution(rz, closure=EXT_CLOSED_IN_RZ, radial_subdiv=20)) mesh_info = MeshInfo() geo.set(mesh_info) mesh = build(mesh_info) def tet_face_vertices(vertices): return [(vertices[0], vertices[1], vertices[2]), (vertices[0], vertices[1], vertices[3]), (vertices[0], vertices[2], vertices[3]), (vertices[1], vertices[2], vertices[3]), ] face_map = {} for el_id, el in enumerate(mesh.elements): for fid, face_vertices in enumerate(tet_face_vertices(el)): face_map.setdefault(frozenset(face_vertices), []).append((el_id, fid)) adjacency = {} for face_vertices, els_faces in face_map.items(): if len(els_faces) == 2: (e1, f1), (e2, f2) = els_faces adjacency.setdefault(e1, []).append(e2) adjacency.setdefault(e2, []).append(e1) from pymetis import part_graph cuts, part_vert = part_graph(17, adjacency) try: import pyvtk except ImportError: print("Test succeeded, but could not import pyvtk to visualize result") else: vtkelements = pyvtk.VtkData( pyvtk.UnstructuredGrid(mesh.points, tetra=mesh.elements), "Mesh", pyvtk.CellData(pyvtk.Scalars(part_vert, name="partition"))) vtkelements.tofile('split.vtk')
def main(): import numpy from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, Marker, \ generate_extrusion, make_box from meshpy.naca import generate_naca geob = GeometryBuilder() box_marker = Marker.FIRST_USER_MARKER wing_length = 2 wing_subdiv = 5 rz_points = [ (0, -wing_length * 1.05), (0.7, -wing_length * 1.05), ] + [(r, x) for x, r in zip( numpy.linspace(-wing_length, 0, wing_subdiv, endpoint=False), numpy.linspace(0.8, 1, wing_subdiv, endpoint=False))] + [(1, 0)] + [ (r, x) for x, r in zip( numpy.linspace(wing_length, 0, wing_subdiv, endpoint=False), numpy.linspace(0.8, 1, wing_subdiv, endpoint=False)) ][::-1] + [(0.7, wing_length * 1.05), (0, wing_length * 1.05)] geob.add_geometry(*generate_extrusion( rz_points=rz_points, base_shape=generate_naca("0012", verbose=False, number_of_points=20), ring_markers=(wing_subdiv * 2 + 4) * [box_marker])) from meshpy.tools import make_swizzle_matrix swizzle_matrix = make_swizzle_matrix("z:x,y:y,x:z") geob.apply_transform(lambda p: numpy.dot(swizzle_matrix, p)) def deform_wing(p): x, y, z = p return numpy.array([ x, y + 0.1 * abs(x / wing_length)**2, z + 0.8 * abs(x / wing_length)**1.2 ]) geob.apply_transform(deform_wing) points, facets, _, facet_markers = make_box( numpy.array([-wing_length - 1, -1, -1.5]), numpy.array([wing_length + 1, 1, 3])) geob.add_geometry(points, facets, facet_markers=facet_markers) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.set_holes([(0, 0, 0.5)]) mesh = build(mesh_info) print "%d elements" % len(mesh.elements) mesh.write_vtk("airfoil3d.vtk")
def test_tet_mesh(visualize=False): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, generate_surface_of_revolution, EXT_CLOSED_IN_RZ pytest.importorskip("meshpy") big_r = 3 little_r = 1.5 points = 50 dphi = 2*pi/points rz = np.array([[big_r+little_r*cos(i*dphi), little_r*sin(i*dphi)] for i in range(points)]) geo = GeometryBuilder() geo.add_geometry( *generate_surface_of_revolution(rz, closure=EXT_CLOSED_IN_RZ, radial_subdiv=20)) mesh_info = MeshInfo() geo.set(mesh_info) mesh = build(mesh_info) def tet_face_vertices(vertices): return [(vertices[0], vertices[1], vertices[2]), (vertices[0], vertices[1], vertices[3]), (vertices[0], vertices[2], vertices[3]), (vertices[1], vertices[2], vertices[3]), ] face_map = {} for el_id, el in enumerate(mesh.elements): for fid, face_vertices in enumerate(tet_face_vertices(el)): face_map.setdefault(frozenset(face_vertices), []).append((el_id, fid)) adjacency = {} for face_vertices, els_faces in face_map.items(): if len(els_faces) == 2: (e1, f1), (e2, f2) = els_faces adjacency.setdefault(e1, []).append(e2) adjacency.setdefault(e2, []).append(e1) import ipdb; ipdb.set_trace() cuts, part_vert = pymetis.part_graph(17, adjacency) if visualize: import pyvtk vtkelements = pyvtk.VtkData( pyvtk.UnstructuredGrid(mesh.points, tetra=mesh.elements), "Mesh", pyvtk.CellData(pyvtk.Scalars(part_vert, name="partition"))) vtkelements.tofile('split.vtk')
def make_mesh(max_volume): def round_trip_connect(seq): result = [] for i in range(len(seq)): result.append((i, (i+1)%len(seq))) return result shapes = read_shape() #from matplotlib.pyplot import plot,show #plot(shapes[0][:,0], shapes[0][:,1]) #show() from meshpy.geometry import GeometryBuilder, Marker builder = GeometryBuilder() for shape in shapes: from meshpy.geometry import make_box points = shape facets = round_trip_connect(range(len(points))) builder.add_geometry(points=points, facets=facets, facet_markers=Marker.FIRST_USER_MARKER) points, facets, facet_markers = make_box((-200, -600), (400, -300)) builder.add_geometry(points=points, facets=facets, facet_markers=facet_markers) def transform(pt): x, y = pt return -0.01*x, -0.01*y builder.apply_transform(transform) from meshpy.triangle import MeshInfo, build mi = MeshInfo() builder.set(mi) holes = [] for shape, sign, frac in zip(shapes, [1, 1, -1, 1, 1, 1], [0.5, 0, 0, 0, 0, 0]): avg = np.average(shape, axis=0) start_idx = int(frac*shape.shape[0]) start = shape[start_idx] holes.append(transform(start + sign*0.01*(avg-start))) mi.set_holes(holes) mesh = build(mi, allow_boundary_steiner=True, generate_faces=True, max_volume=max_volume) return mesh
def main(): from meshpy.tet import MeshInfo, build from meshpy.geometry import generate_surface_of_revolution, GeometryBuilder simple_rz = [(0, 0), (1, 1), (1, 2), (0, 3)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution(simple_rz)) mesh_info = MeshInfo() geob.set(mesh_info) # mesh_info.save_nodes("test") # mesh_info.save_poly("test") # mesh_info.load_poly("test") mesh = build(mesh_info) mesh.write_vtk("my_mesh.vtk")
def main(): from ply import parse_ply import sys data = parse_ply(sys.argv[1]) from meshpy.geometry import GeometryBuilder builder = GeometryBuilder() builder.add_geometry(points=[pt[:3] for pt in data["vertex"].data], facets=[fd[0] for fd in data["face"].data]) builder.wrap_in_box(1) from meshpy.tet import MeshInfo, build mi = MeshInfo() builder.set(mi) mi.set_holes([builder.center()]) mesh = build(mi) print("%d elements" % len(mesh.elements)) mesh.write_vtk("out.vtk")
def main(): from ply import parse_ply import sys data = parse_ply(sys.argv[1]) from meshpy.geometry import GeometryBuilder builder = GeometryBuilder() builder.add_geometry( points=[pt[:3] for pt in data["vertex"].data], facets=[fd[0] for fd in data["face"].data]) builder.wrap_in_box(1) from meshpy.tet import MeshInfo, build mi = MeshInfo() builder.set(mi) mi.set_holes([builder.center()]) mesh = build(mi) print("%d elements" % len(mesh.elements)) mesh.write_vtk("out.vtk")
def main(): import numpy from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, Marker, make_box geob = GeometryBuilder() box_marker = Marker.FIRST_USER_MARKER extent_small = 0.1*numpy.ones(3, dtype=numpy.float64) points, facets, _, _ = \ make_box(-extent_small, extent_small) geob.add_geometry(points, facets, facet_markers=box_marker) # make small "separator box" for region attribute geob.wrap_in_box(0.3) points, facets, _, facet_markers = \ make_box(numpy.array([-1,-1,-1]), numpy.array([1,1,5])) geob.add_geometry(points, facets, facet_markers=facet_markers) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.set_holes([(0,0,0)]) # region attributes mesh_info.regions.resize(1) mesh_info.regions[0] = ( # point in region list(extent_small*2) + [ # region number 1, # max volume in region 0.0001]) mesh = build(mesh_info, max_volume=0.02, volume_constraints=True, attributes=True) print ("%d elements" % len(mesh.elements)) mesh.write_vtk("box-in-box.vtk")
def main(): from meshpy.tet import MeshInfo, build from meshpy.geometry import generate_surface_of_revolution, GeometryBuilder simple_rz = [ (0, 0), (1, 1), (1, 2), (0, 3), ] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution(simple_rz)) mesh_info = MeshInfo() geob.set(mesh_info) # mesh_info.save_nodes("test") # mesh_info.save_poly("test") # mesh_info.load_poly("test") mesh = build(mesh_info) mesh.write_vtk("my_mesh.vtk")
def test_2d_gauss_theorem(actx_factory): """Verify Gauss's theorem explicitly on a mesh""" pytest.importorskip("meshpy") from meshpy.geometry import make_circle, GeometryBuilder from meshpy.triangle import MeshInfo, build geob = GeometryBuilder() geob.add_geometry(*make_circle(1)) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info = build(mesh_info) from meshmode.mesh.io import from_meshpy from meshmode.mesh import BTAG_ALL mesh = from_meshpy(mesh_info, order=1) actx = actx_factory() dcoll = DiscretizationCollection(actx, mesh, order=2) volm_disc = dcoll.discr_from_dd(dof_desc.DD_VOLUME) x_volm = thaw(volm_disc.nodes(), actx) def f(x): return flat_obj_array( actx.np.sin(3 * x[0]) + actx.np.cos(3 * x[1]), actx.np.sin(2 * x[0]) + actx.np.cos(x[1])) f_volm = f(x_volm) int_1 = op.integral(dcoll, "vol", op.local_div(dcoll, f_volm)) prj_f = op.project(dcoll, "vol", BTAG_ALL, f_volm) normal = thaw(dcoll.normal(BTAG_ALL), actx) int_2 = op.integral(dcoll, BTAG_ALL, prj_f.dot(normal)) assert abs(int_1 - int_2) < 1e-13
def test_2d_gauss_theorem(actx_factory): """Verify Gauss's theorem explicitly on a mesh""" pytest.importorskip("meshpy") from meshpy.geometry import make_circle, GeometryBuilder from meshpy.triangle import MeshInfo, build geob = GeometryBuilder() geob.add_geometry(*make_circle(1)) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info = build(mesh_info) from meshmode.mesh.io import from_meshpy mesh = from_meshpy(mesh_info, order=1) actx = actx_factory() discr = DGDiscretizationWithBoundaries(actx, mesh, order=2) def f(x): return flat_obj_array( sym.sin(3*x[0])+sym.cos(3*x[1]), sym.sin(2*x[0])+sym.cos(x[1])) gauss_err = bind(discr, sym.integral(( sym.nabla(2) * f(sym.nodes(2)) ).sum()) - # noqa: W504 sym.integral( sym.project("vol", sym.BTAG_ALL)(f(sym.nodes(2))) .dot(sym.normal(sym.BTAG_ALL, 2)), dd=sym.BTAG_ALL) )(actx) assert abs(gauss_err) < 1e-13
def make_mesh(a, b, pml_width=0.25, **kwargs): from meshpy.geometry import GeometryBuilder, make_box geob = GeometryBuilder() box_points, box_facets, _, box_markers = make_box(a, b) geob.add_geometry(box_points, box_facets) geob.wrap_in_box(pml_width) mesh_mod = geob.mesher_module() mi = mesh_mod.MeshInfo() geob.set(mi) built_mi = mesh_mod.build(mi, **kwargs) def boundary_tagger(fvi, el, fn, points): return [] from hedge.mesh import make_conformal_mesh return make_conformal_mesh( built_mi.points, built_mi.elements, boundary_tagger)
def createSphere(center, R, m, n, mv=1): """ The function computes the panelisation of a sphere using the predefined tools available in the Python module meshpy. INPUTS: - R: radius of the sphere (m) - m: number of radial subdivisions of the mesh (integer) - n: number of circumferential subdivisions of the mesh (integer) - mv: maxium valume of an element in the thetrahedral mesh (the mesh is actually 3D but we only extract the surface panels) OUTPUTS: - verts: coordinates of each vertices of the panelisation - faces: triplets of indices representing the vertices of each triangular panel - tris: triplets explicitly representing the coordinates of the vertices of each triangular face. """ rz = [] rz.append((0, R)) for i in xrange(1, n): rz.append((R * np.sin(i * np.pi / n), R * np.cos(i * np.pi / n))) rz.append((0, -R)) geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution(rz, radial_subdiv=m)) mesh_info = MeshInfo() geob.set(mesh_info) mesh = build(mesh_info, max_volume=mv) verts = np.array(mesh.points) faces = np.array(mesh.faces) tris = verts[faces] bars = [] return verts, bars, faces # , tris
def test_torus(): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import generate_surface_of_revolution, \ EXT_CLOSED_IN_RZ, GeometryBuilder big_r = 3 little_r = 2.9 points = 50 dphi = 2 * pi / points rz = [(big_r + little_r * cos(i * dphi), little_r * sin(i * dphi)) for i in range(points)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution( rz, closure=EXT_CLOSED_IN_RZ, radial_subdiv=20)) mesh_info = MeshInfo() geob.set(mesh_info) build(mesh_info)
def test_torus(): from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import generate_surface_of_revolution, \ EXT_CLOSED_IN_RZ, GeometryBuilder big_r = 3 little_r = 2.9 points = 50 dphi = 2*pi/points rz = [(big_r+little_r*cos(i*dphi), little_r*sin(i*dphi)) for i in range(points)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution(rz, closure=EXT_CLOSED_IN_RZ, radial_subdiv=20)) mesh_info = MeshInfo() geob.set(mesh_info) build(mesh_info)
def main(): import numpy from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, Marker, make_box geob = GeometryBuilder() box_marker = Marker.FIRST_USER_MARKER extent_small = 0.3*numpy.ones(3, dtype=numpy.float64) points, facets, _, _ = \ make_box(-extent_small, extent_small) geob.add_geometry(points, facets, facet_markers=box_marker) points, facets, _, facet_markers = \ make_box(numpy.array([-1, -1, -1]), numpy.array([1, 1, 5])) geob.add_geometry(points, facets, facet_markers=facet_markers) mesh_info = MeshInfo() geob.set(mesh_info) #mesh_info.set_holes([(0, 0, 0)]) # region attributes mesh_info.regions.resize(1) mesh_info.regions[0] = ( # point in region [0, 0, 0] + [ # region number 1, # max volume in region 0.001]) mesh = build(mesh_info, max_volume=0.06, volume_constraints=True, attributes=True) print(("%d elements" % len(mesh.elements))) mesh.write_vtk("box-in-box.vtk")
def create_ball_mesh(num_longi_points=10): radius = 5.0 radial_subdiv = 2 * num_longi_points dphi = np.pi / num_longi_points # Make sure the nodes meet at the poles of the ball. def truncate(r): if abs(r) < 1e-10: return 0 else: return r # Compute the volume of a canonical tetrahedron # with edgelength radius*dphi. a = radius * dphi canonical_tet_volume = np.sqrt(2.0) / 12 * a ** 3 # Build outline for surface of revolution. rz = [ (truncate(radius * np.sin(i * dphi)), radius * np.cos(i * dphi)) for i in range(num_longi_points + 1) ] geob = GeometryBuilder() geob.add_geometry( *generate_surface_of_revolution( rz, closure=EXT_OPEN, radial_subdiv=radial_subdiv ) ) mesh_info = MeshInfo() geob.set(mesh_info) meshpy_mesh = build(mesh_info, max_volume=canonical_tet_volume) return np.array(meshpy_mesh.points), np.array(meshpy_mesh.elements)
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 grudge.mesh import make_conformal_mesh_ext vertices = numpy.asarray(mesh.points, order="C") from grudge.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")] )
class GeometryMeshPyTetgen(GeometryMeshPy): """Define and mesh 3-dimensional domains with MeshPy/Tetgen.""" def __init__(self): self.geob = GeometryBuilder() def mesh(self, h, holes=None): info = meshpy.tet.MeshInfo() self.geob.set(info) if holes is not None: info.set_holes(holes) self.m = meshpy.tet.build(info, max_volume=h**3) return self._mesh_output() def extrude(self, points, z): """A wrapper to self.advanced_extrude to create a simple extrusion of a cross section. Parameters ========== points : array of tuples An array of tuples with (x,y)-coordinates of the boundary points. The boundary points are connected by straight line segments. The last point is connected to the first point. z : float The extrusion length. """ self.advanced_extrude(points, [(0., 0.), (1., 0.), (1., z), (0., z)]) def advanced_extrude(self, points, rz): """Add a geometry defined by an extrusion. Parameters ========== points : array of tuples An array of tuples with (x,y)-coordinates of the boundary points. The boundary points are connected by straight line segments. The last point is connected to the first point. rz : array of tuples An array of tuples with (r,z)-coordinates. The first number of each tuple acts as a multiplier to increase or decrease the size of the cross section. The second number defines the z-location of the cross section. """ self.geob.add_geometry(*meshpy.geometry.generate_extrusion( rz_points=rz, base_shape=points)) def revolution(self, points, N, transform=None): """Generate a surface of revolution. Parameters ========== points : array of tuples An array of tuples with (x,y)-coordinates of the boundary points of the to-be-revolved surface. The boundary points are connected by straight line segments. The revolution is performed around y-axis. The first and the last points should be located at x=0. N : integer The number of subdivisions in the revolution. transform : (OPTIONAL) A function that takes list of 3-tuples and modifies the list somehow. Can be used to e.g. translate the points after revolving. """ if transform is None: self.geob.add_geometry( *meshpy.geometry.generate_surface_of_revolution( points, closure=meshpy.geometry.EXT_OPEN, radial_subdiv=N)) else: a, b, c, d = meshpy.geometry.generate_surface_of_revolution( points, closure=meshpy.geometry.EXT_OPEN, radial_subdiv=N) A = [transform(*x) for x in a] self.geob.add_geometry(A, b, c, d)
def test_convergence_advec(ctx_factory, mesh_name, mesh_pars, op_type, flux_type, order, visualize=False): """Test whether 2D advection actually converges""" cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() for mesh_par in mesh_pars: if mesh_name == "segment": from meshmode.mesh.generation import generate_box_mesh mesh = generate_box_mesh([np.linspace(-1.0, 1.0, mesh_par)], order=order) dim = 1 dt_factor = 1.0 elif mesh_name == "disk": pytest.importorskip("meshpy") from meshpy.geometry import make_circle, GeometryBuilder from meshpy.triangle import MeshInfo, build geob = GeometryBuilder() geob.add_geometry(*make_circle(1)) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info = build(mesh_info, max_volume=mesh_par) from meshmode.mesh.io import from_meshpy mesh = from_meshpy(mesh_info, order=1) dim = 2 dt_factor = 4 elif mesh_name.startswith("rect"): dim = int(mesh_name[4:]) from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(mesh_par, ) * dim, order=4) if dim == 2: dt_factor = 4 elif dim == 3: dt_factor = 2 else: raise ValueError("dt_factor not known for %dd" % dim) else: raise ValueError("invalid mesh name: " + mesh_name) v = np.array([0.27, 0.31, 0.1])[:dim] norm_v = la.norm(v) def f(x): return sym.sin(10 * x) def u_analytic(x): return f(-v.dot(x) / norm_v + sym.var("t", sym.DD_SCALAR) * norm_v) from grudge.models.advection import (StrongAdvectionOperator, WeakAdvectionOperator) discr = DGDiscretizationWithBoundaries(actx, mesh, order=order) op_class = { "strong": StrongAdvectionOperator, "weak": WeakAdvectionOperator, }[op_type] op = op_class(v, inflow_u=u_analytic(sym.nodes(dim, sym.BTAG_ALL)), flux_type=flux_type) bound_op = bind(discr, op.sym_operator()) u = bind(discr, u_analytic(sym.nodes(dim)))(actx, t=0) def rhs(t, u): return bound_op(t=t, u=u) if dim == 3: final_time = 0.1 else: final_time = 0.2 h_max = bind(discr, sym.h_max_from_volume(discr.ambient_dim))(actx) dt = dt_factor * h_max / order**2 nsteps = (final_time // dt) + 1 dt = final_time / nsteps + 1e-15 from grudge.shortcuts import set_up_rk4 dt_stepper = set_up_rk4("u", dt, u, rhs) last_u = None from grudge.shortcuts import make_visualizer vis = make_visualizer(discr, vis_order=order) step = 0 for event in dt_stepper.run(t_end=final_time): if isinstance(event, dt_stepper.StateComputed): step += 1 logger.debug("[%04d] t = %.5f", step, event.t) last_t = event.t last_u = event.state_component if visualize: vis.write_vtk_file("fld-%s-%04d.vtu" % (mesh_par, step), [("u", event.state_component)]) error_l2 = bind(discr, sym.norm(2, sym.var("u") - u_analytic(sym.nodes(dim))))( t=last_t, u=last_u) logger.info("h_max %.5e error %.5e", h_max, error_l2) eoc_rec.add_data_point(h_max, error_l2) logger.info( "\n%s", eoc_rec.pretty_print(abscissa_label="h", error_label="L2 Error")) assert eoc_rec.order_estimate() > order
class FyberModel: """ Full Fiber Model Can store all material and geometric properties Can run pushover of model Can display results in a variety of ways """ def __init__(self, figsize=6): # Material Properties self.materials = {} # Mesh Properties self.builder = GeometryBuilder() self.reinforcement = [] self.outer_facets = [] self.mesh_areas = {} self.mesh_centroids = {} self.mesh = None # Data structure to assign material ids after mesh generation self.ele_mat_primitive = [] self.ele_mat = {} # Load step Data self.load_angle = 0 self.phi_list = [] self.M_list = [] # States of all elements at each load step from analysis self.state_id = 0 self.states = {} self.state_y_loc = {} self.analysis_model = FiberModel() # Failure check for end of analysis (conf crush/ bar fracture) self.fail = False # Plot settings self.figsize = figsize @staticmethod def conf_pressure(shape, **kwargs): """Technically static method, but I just want one import""" if shape == 'circle': return conf_pressure_circle(kwargs['fyh'], kwargs['bar'], kwargs['s'], kwargs['D']) elif shape == 'rect': return conf_pressure_rect(kwargs['fyh'], kwargs['bar'], kwargs['s'], kwargs['b'], kwargs['w'], kwargs['nx'], kwargs['ny']) else: exit( "I can only find the confining pressure of 'circle' or 'rect'") @staticmethod def color_from_state(state): """Not sure how I want to store the states for now, so i'll just hold the options in this function""" colors = [ "Gray", "Purple", "Pink", "Blue", "Black", "Green", "Yellow", "Red", "White" ] if type(state) == int: return colors[state] else: return state def add_material(self, mat_num, mat, **kwargs): """Add materials for unconfined concrete, confined concrete, or steel""" if mat == 'concrete': if 'fple' in kwargs: self.materials[mat_num] = ConfConcMat(kwargs) else: self.materials[mat_num] = UnconfConcMat(kwargs) elif mat == 'steel': self.materials[mat_num] = SteelMat(kwargs['E'], kwargs['fy'], kwargs['fsu'], kwargs['e_sh'], kwargs['e_su'], kwargs['P']) elif mat == 'user': if 'mirror' in kwargs: self.materials[mat_num] = UserMat(kwargs['points'], kwargs['mirror']) else: self.materials[mat_num] = UserMat(kwargs['points']) else: exit("'{}' is not a material type I recognize".format(mat)) def add_geometry(self, shape, mat_id, **kwargs): if shape == 'circle': self.builder.add_geometry(*make_circle(kwargs['D'] / 2, kwargs['c'])) self.ele_mat_primitive.append( (kwargs['D'] / 2, kwargs['c'], mat_id)) if not self.outer_facets: # list empty - first points self.outer_facets = self.builder.facets # self.mesh_points.extend(builder.points) elif shape == 'rectangle': # TODO CHANGE TO builder.add_geometry(*make_rectangle) # TODO add rect primitive # self.mesh_points.extend(gen_rect_points(c, W, H)) print("I can only currently add type='circle' reinforcement") exit() else: print("'{}' is not a geometry type I recognize".format(shape)) exit() def add_reinforcement(self, shape, mat_id, **kwargs): """Add reinforcement in a circle (for now), confine concrete inside if needed""" if shape == 'circle': if 'conf_id' in kwargs: reinforcement_builder = GeometryBuilder() reinforcement_builder.add_geometry( *make_circle(kwargs['D'] / 2, kwargs['c'], kwargs['count'])) r = ReinforcementProperties(reinforcement_builder.points, kwargs['bar'], mat_id) self.reinforcement.append(r) # Add points for confinement into mesh self.builder.add_geometry(*make_circle(kwargs['D'] / 2, kwargs['c'])) self.ele_mat_primitive.append( (kwargs['D'] / 2, kwargs['c'], kwargs['conf_id'])) else: reinforcement_builder = GeometryBuilder() reinforcement_builder.add_geometry( *make_circle(kwargs['D'] / 2, kwargs['c'], kwargs['count'])) r = ReinforcementProperties(reinforcement_builder.points, kwargs['bar'], mat_id) self.reinforcement.append(r) else: # Rectangular reinforcement # not implemented for now print("I can only currently add type='circle' reinforcement") exit() def set_load(self, load_type, **kwargs): """Add axial load and moment increment/angle""" if load_type == 'Axial': self.analysis_model.P = kwargs['P'] elif load_type == 'Moment': self.analysis_model.M = kwargs['M'] else: print("This is not a load type I recognize") exit() def generate_mesh(self, mesh_size=5): """Setup Mesh Object and Properties Go through generation Builder -> MeshInfo -> Mesh""" # TODO Look into section-properties on github? # TODO Are the values from meshpy.triangle accurate? mesh_info = MeshInfo() self.builder.set(mesh_info) self.mesh = build(mesh_info, max_volume=mesh_size) # Calculate Element Centroids # C = [(x1+x2+x3)/3 , (y1+y2+y3)/3] for i, e in enumerate(self.mesh.elements): p1 = self.mesh.points[e[0]] p2 = self.mesh.points[e[1]] p3 = self.mesh.points[e[2]] self.mesh_centroids[i] = ((p1[0] + p2[0] + p3[0]) / 3, (p1[1] + p2[1] + p3[1]) / 3) # Calculate Element Areas # A = abs(x1*y2 + x2*y3 + x3*y1 - y1*x2 - y2*x3 - y3*x1)/2 for i, e in enumerate(self.mesh.elements): p1 = self.mesh.points[e[0]] p2 = self.mesh.points[e[1]] p3 = self.mesh.points[e[2]] self.mesh_areas[i] = abs(p1[0] * p2[1] + p2[0] * p3[1] + p3[0] * p1[1] - p1[1] * p2[0] - p2[1] * p3[0] - p3[1] * p1[0]) / 2 # Assign material ids to elements # A bit verbose just to show calculations - might change later # this only accounts for circle assignments for primitive in self.ele_mat_primitive: r = primitive[0] prim_c = primitive[1] mat_id = primitive[2] for n, c in self.mesh_centroids.items(): if hypot(c[0] - prim_c[0], c[1] - prim_c[1]) < r: self.ele_mat[n] = mat_id def gen_fiber_model(self): # We can re-mesh our geometry, but our reinforcement is just points # So when we add the reinforcement we should also make holes in mesh (TODO) max_y = 0 min_y = 0 for n in self.mesh_centroids.keys(): centroid = self.mesh_centroids[n] area = self.mesh_areas[n] self.analysis_model.fibers[n] = Fiber(area, centroid, self.ele_mat[n]) max_y = max(max_y, centroid[1]) min_y = min(min_y, centroid[1]) self.analysis_model.maxy = max_y self.analysis_model.miny = min_y meh = max(self.mesh_centroids.keys()) n = 1 for reinforce_group in self.reinforcement: for centroid in reinforce_group.points: # TODO - SHOULD I HAVE PATCHES REGARDLESS OF MAT/reinforcement? # MIGHT BE PROBLEM IF NEED VALUES FROM A SINGLE BAR # MAYBE SET MAX VOLUME SEPARATELY? self.analysis_model.fibers[n + meh] = Fiber( reinforce_group.area, centroid, reinforce_group.mat_id) n += 1 self.analysis_model.materials = self.materials # Generate Initial States self.states[0] = State([0] * len(self.mesh.elements) + [8] * (n - 1), 0, 0, 0) self.phi_list = [0] self.M_list = [0] def analyze(self): """Analyze a fiber model with given load step""" # setup the model with the current mesh discretization self.gen_fiber_model() # TODO allow step change? # delta_phi = 5e-6 delta_phi = 1e-5 for step in range(1, 1000): # Setup this step to run equilibrium analysis phi = step * delta_phi self.analysis_model.phi = phi # I'm not sure if scipy.optimize.newton can fail here, might need to catch exception with bisection zero_strain = newton(self.analysis_model.force_balance, self.analysis_model.zero_strain_location) self.analysis_model.zero_strain_location = zero_strain # Get Moment at current state moment = self.analysis_model.calc_moment() # Generate state data and save this load step results self.phi_list.append(round(phi, 8)) self.M_list.append(moment) self.states[step] = self.analysis_model.state # self.state_y_loc[step] = self.analysis_model.states if self.analysis_model.fail: print( f"Analysis ended at phi={round(phi, 8)}\nFailure: {self.analysis_model.fail}" ) break # Don't necessarily want to break for tension failure - Say, if entire section is steel # if M < 1: # print("Capacity of entire section failed") # break def display_material(self, mat_id, loc=None): # Plot a specific material with tag mat_id material = self.materials[mat_id] tmp_strains = material.useful_points useful_strains = [] for point in tmp_strains: useful_strains.append(point - 1e-6) useful_strains.append(point) useful_strains.append(point + 1e-6) lin_strains = np.linspace(material.useful_points[0], material.useful_points[-1], 30) strains = np.sort(np.r_[lin_strains, useful_strains[1:-1]]) stresses = [] colors = [] for strain in strains: stresses.append(material.stress(strain)) colors.append(self.color_from_state(material.state)) stresses = np.array(stresses) stresses[stresses == 0] = np.nan fig, ax = plt.subplots() # Setup Plot - Discrete between colors i = 0 x = [] y = [] color = colors[0] while True: new_color = colors[i] x.append(strains[i]) y.append(stresses[i]) if new_color != color or i == len(strains) - 1: ax.plot(x, y, c=color) color = new_color x = [strains[i]] y = [stresses[i]] if i == len(strains) - 1: break i -= 1 i += 1 # Axis Options if loc is not None: # Plot some location ax.plot(loc[0], loc[1], 'ro') ax.set_title("Material Stress Strain id={}".format(mat_id)) ax.set_xlabel('Strain (in/in)') ax.set_ylabel('Stress (ksi)') ax.grid() def display_materials(self, mat_id=None, loc=None): """Plot all loaded materials to verify stress strain curves""" if mat_id is None: # Plot standard -> all material plots for mat_id, material in self.materials.items(): self.display_material(mat_id, loc) else: self.display_material(mat_id, loc) plt.show() def display_mesh(self): """Show the current geometry and mesh (equivalent to step zero of display_mc)""" fig, ax = plt.subplots(figsize=(self.figsize, self.figsize)) patches = [] for i, pt_ids in enumerate(self.mesh.elements): p = [self.mesh.points[pt_id] for pt_id in pt_ids] new_patch = plt.Polygon(p, fc="Gray", ec='black', zorder=0) patches.append(new_patch) ax.add_patch(new_patch) for reinforce_group in self.reinforcement: for centroids in reinforce_group.points: new_patch = CirclePolygon(centroids, reinforce_group.radius, 8, fc='White', ec='black', zorder=15) patches.append(new_patch) ax.add_patch(new_patch) # Plot nodal points of mesh (useful to auto set axes limits) ax.scatter(*zip(*self.mesh.points), c='black', s=4, zorder=5) plt.show() def mc_gif(self): """Testing saving as gif""" fig, (ax, ax_mc) = plt.subplots(1, 2, figsize=(self.figsize * 2, self.figsize)) polygons = [] for element in self.mesh.elements: poly_pts = [self.mesh.points[i] for i in element] polygons.append(poly_pts) patches = [] # Draw Polygons for mesh and reinforcement i = 0 for p in polygons: new_patch = plt.Polygon(p, fc='Grey', ec='Black', zorder=0, picker=.01, gid=str(i)) patches.append(new_patch) ax.add_patch(new_patch) i += 1 if self.reinforcement: for reinforcement_group in self.reinforcement: for centroid in reinforcement_group.points: new_patch = CirclePolygon(centroid, reinforcement_group.radius, 8, fc='White', ec='Black', zorder=15, picker=.01, gid=str(i)) patches.append(new_patch) ax.add_patch(new_patch) i += 1 # Plot nodal points of mesh (useful to auto set axes limits) ax.scatter(*zip(*self.mesh.points), c='black', s=4, zorder=5) num_steps = len(self.states) - 1 # LEFT MC Plot ax_mc.plot(self.phi_list, self.M_list, 'k') ax.axis('equal') # Location indicator as patch so we can update it easily # Ellipse b/c we don't have equal axis ranges for phi/M point = Ellipse((0, 0), max(self.phi_list) / 50, max(self.M_list) / 50, fc='red', zorder=10) ax_mc.add_patch(point) # Scientific notation for phi values ax_mc.ticklabel_format(axis='x', style='sci', scilimits=(-2, 2), useMathText=True) # Setup Sliders for intractability to look through results def update(state): state = int(state) self.state_id = int(state) # Update Patch colors state_colors = [ self.color_from_state(state) for state in self.states[state].mat_state ] for patch, color in zip(patches, state_colors): patch.set_facecolor(color) point.center = (self.phi_list[state], self.M_list[state]) # fig.canvas.draw_idle() ax_slider = plt.axes([0.117, 0.01, 0.79, 0.02], facecolor='White') slider_fct = Slider(ax_slider, 'STEP', 0, num_steps, valinit=0, valstep=1, valfmt='%i') slider_fct.on_changed(update) def frame(state): # Set State - Updates everything slider_fct.set_val(state) print( "Saving animated gif. This will take a while and take several dozen megs of space.\n" "It's saving full frames and not optimizing.") test = anim.FuncAnimation(fig, frame, frames=len(self.states)) test.save("Moment_Curvature.gif", fps=16) def display_mc(self): """Plot the moment curvature, and interactive section viewer""" # TODO SEPARATE PLOT FOR FORCE/STRESS DISTRIBUTION? # TODO PATCH COLLECTION FOR INSTANTANEOUS? COLOR UPDATE? fig, (ax, ax_mc) = plt.subplots(1, 2, figsize=(self.figsize * 2, self.figsize)) polygons = [] for element in self.mesh.elements: poly_pts = [self.mesh.points[i] for i in element] polygons.append(poly_pts) patches = [] # Draw Polygons for mesh and reinforcement i = 0 for p in polygons: new_patch = plt.Polygon(p, fc="Gray", ec='black', zorder=0, picker=.01, gid=str(i)) patches.append(new_patch) ax.add_patch(new_patch) i += 1 if self.reinforcement: for reinforce_group in self.reinforcement: for centroid in reinforce_group.points: new_patch = CirclePolygon(centroid, reinforce_group.radius, 8, fc='White', ec='black', zorder=15, picker=.01, gid=str(i)) patches.append(new_patch) ax.add_patch(new_patch) i += 1 # Plot nodal points of mesh (useful to auto set axes limits) ax.scatter(*zip(*self.mesh.points), c='black', s=4, zorder=5) num_steps = len(self.states) - 1 # LEFT MC Plot ax_mc.plot(self.phi_list, self.M_list, 'k') ax.axis('equal') # Location indicator as patch so we can update it easily # Ellipse b/c we don't have equal axis ranges for phi/M point = Ellipse((0, 0), max(self.phi_list) / 50, max(self.M_list) / 50, fc='red', zorder=10) ax_mc.add_patch(point) # Scientific notation for phi values ax_mc.ticklabel_format(axis='x', style='sci', scilimits=(-2, 2), useMathText=True) # Setup Sliders for intractability to look through results def update(phi_step): phi_step = int(phi_step) self.state_id = int(phi_step) # Update Patch colors state_colors = [ self.color_from_state(state) for state in self.states[phi_step].mat_state ] for patch, color in zip(patches, state_colors): patch.set_facecolor(color) point.center = (self.phi_list[phi_step], self.M_list[phi_step]) fig.canvas.draw_idle() ax_slider = plt.axes([0.117, 0.01, 0.79, 0.02], facecolor='White') slider_fct = Slider(ax_slider, 'STEP', 0, num_steps, valinit=0, valstep=1, valfmt='%i') slider_fct.on_changed(update) # Setup mesh onclick event to view stress/strain location of each fiber def onclick(event): # print(event.mouseevent.__dict__) # print(event.artist.__dict__) # print(event.canvas.__dict__) patch_id = int(event.artist._gid) strain = self.states[self.state_id].strains[patch_id] stress = self.states[self.state_id].stresses[patch_id] self.display_materials(self.ele_mat[patch_id], (strain, stress)) return True fig.canvas.mpl_connect('pick_event', onclick) plt.show() def display_mc_2x2(self): """Plot the moment curvature, and interactive section viewer""" # TODO SEPARATE PLOT FOR FORCE/STRESS DISTRIBUTION? # TODO PATCH COLLECTION FOR INSTANTANEOUS? COLOR UPDATE? fig, axes = plt.subplots(2, 2, figsize=(self.figsize * 1.5, self.figsize * 1.5)) ax = axes[0, 0] ax_mc = axes[0, 1] ax_strain = axes[1, 0] ax_stress = axes[1, 1] polygons = [] for element in self.mesh.elements: poly_pts = [self.mesh.points[i] for i in element] polygons.append(poly_pts) patches = [] # Draw Polygons for mesh and reinforcement i = 0 for p in polygons: new_patch = plt.Polygon(p, fc="Gray", ec='black', zorder=0, picker=.01, gid=str(i)) patches.append(new_patch) ax.add_patch(new_patch) i += 1 if self.reinforcement: for reinforce_group in self.reinforcement: for centroid in reinforce_group.points: new_patch = CirclePolygon(centroid, reinforce_group.radius, 8, fc='White', ec='black', zorder=15, picker=.01, gid=str(i)) patches.append(new_patch) ax.add_patch(new_patch) i += 1 # Plot nodal points of mesh (useful to auto set axes limits) ax.scatter(*zip(*self.mesh.points), c='black', s=4, zorder=5) num_steps = len(self.states) - 1 # LEFT MC Plot ax_mc.plot(self.phi_list, self.M_list, 'k') ax.axis('equal') # Location indicator as patch so we can update it easily # Ellipse b/c we don't have equal axis ranges for phi/M point = Ellipse((0, 0), max(self.phi_list) / 50, max(self.M_list) / 50, fc='red', zorder=10) ax_mc.add_patch(point) # Scientific notation for phi values ax_mc.ticklabel_format(axis='x', style='sci', scilimits=(-2, 2), useMathText=True) line = line2 = line3 = None # Setup Sliders for intractability to look through results def update(phi_step): phi_step = int(phi_step) self.state_id = int(phi_step) # Update Patch colors state_colors = [ self.color_from_state(state) for state in self.states[phi_step].mat_state ] for patch, color in zip(patches, state_colors): patch.set_facecolor(color) point.center = (self.phi_list[phi_step], self.M_list[phi_step]) x = [ self.states[phi_step].min_strain, self.states[phi_step].max_strain ] y = [self.analysis_model.miny, self.analysis_model.maxy] line.set_data(x, y) line2.set_data( [-1, 1], [self.states[phi_step].y_loc, self.states[phi_step].y_loc]) line3.set_data([ self.analysis_model.miny * 1.1, self.analysis_model.maxy * 1.1 ], [self.states[phi_step].y_loc, self.states[phi_step].y_loc]) fig.canvas.draw_idle() # Setup mesh onclick event to view stress/strain location of each fiber def onclick(event): # print(event.mouseevent.__dict__) # print(event.artist.__dict__) # print(event.canvas.__dict__) patch_id = int(event.artist._gid) strain = self.states[self.state_id].strains[patch_id] stress = self.states[self.state_id].stresses[patch_id] self.display_materials(self.ele_mat[patch_id], (strain, stress)) return True fig.canvas.mpl_connect('pick_event', onclick) ax_slider = plt.axes([0.117, 0.01, 0.79, 0.02], facecolor='white') slider_fct = Slider(ax_slider, 'STEP', 0, num_steps, valinit=0, valstep=1, valfmt='%i') slider_fct.on_changed(update) # Strain plot ax_strain.plot([0, 0], [self.analysis_model.miny, self.analysis_model.maxy], 'k') ax_strain.set_xlim([ self.states[len(self.states) - 1].min_strain * 1.05, self.states[len(self.states) - 1].max_strain * 1.05 ]) line, = ax_strain.plot( [0, 0], [self.analysis_model.miny, self.analysis_model.maxy], color='Red') phi_step_init = 0 line2, = ax_strain.plot([-1, 1], [ self.states[phi_step_init].y_loc, self.states[phi_step_init].y_loc ], color='Blue') line3, = ax.plot( [self.analysis_model.miny * 1.1, self.analysis_model.maxy * 1.1], [ self.states[phi_step_init].y_loc, self.states[phi_step_init].y_loc ], color='Red') # Stress Plot ax_stress.plot([0, 0], [self.analysis_model.miny, self.analysis_model.maxy], 'k') ax_stress.text(0, 0, "This Plot Was\nIntentionally Left Blank\n(For Now)") plt.tight_layout() # plt.tight_layout(rect=[0, .05, 1, 1]) plt.show() def export_results(self, filename=''): out = ["phi,M"] for phi, M in zip(self.phi_list, self.M_list): out.append(f"{phi},{M}") if filename == '': print("\n".join(out)) else: with open(filename, 'w') as f: f.write("\n".join(out))
class GeometryMeshPyTetgen(GeometryMeshPy): """Define and mesh 3-dimensional domains with MeshPy/Tetgen.""" def __init__(self): self.geob=GeometryBuilder() def mesh(self,h,holes=None): info=meshpy.tet.MeshInfo() self.geob.set(info) if holes is not None: info.set_holes(holes) self.m=meshpy.tet.build(info,max_volume=h**3) return self._mesh_output() def extrude(self,points,z): """A wrapper to self.advanced_extrude to create a simple extrusion of a cross section. Parameters ========== points : array of tuples An array of tuples with (x,y)-coordinates of the boundary points. The boundary points are connected by straight line segments. The last point is connected to the first point. z : float The extrusion length. """ self.advanced_extrude(points,[(0.,0.),(1.,0.),(1.,z),(0.,z)]) def advanced_extrude(self,points,rz): """Add a geometry defined by an extrusion. Parameters ========== points : array of tuples An array of tuples with (x,y)-coordinates of the boundary points. The boundary points are connected by straight line segments. The last point is connected to the first point. rz : array of tuples An array of tuples with (r,z)-coordinates. The first number of each tuple acts as a multiplier to increase or decrease the size of the cross section. The second number defines the z-location of the cross section. """ self.geob.add_geometry(*meshpy.geometry.generate_extrusion(rz_points=rz, base_shape=points)) def revolution(self,points,N,transform=None): """Generate a surface of revolution. Parameters ========== points : array of tuples An array of tuples with (x,y)-coordinates of the boundary points of the to-be-revolved surface. The boundary points are connected by straight line segments. The revolution is performed around y-axis. The first and the last points should be located at x=0. N : integer The number of subdivisions in the revolution. transform : (OPTIONAL) A function that takes list of 3-tuples and modifies the list somehow. Can be used to e.g. translate the points after revolving. """ if transform is None: self.geob.add_geometry(*meshpy.geometry.generate_surface_of_revolution(points, closure=meshpy.geometry.EXT_OPEN,radial_subdiv=N)) else: a,b,c,d=meshpy.geometry.generate_surface_of_revolution(points, closure=meshpy.geometry.EXT_OPEN,radial_subdiv=N) A=[transform(*x) for x in a] self.geob.add_geometry(A,b,c,d)
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 main(): import numpy #from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, Marker, \ generate_extrusion, make_box from meshpy.naca import get_naca_points geob = GeometryBuilder() box_marker = Marker.FIRST_USER_MARKER wing_length = 2 wing_subdiv = 5 rz_points = [ (0, -wing_length*1.05), (0.7, -wing_length*1.05), ] + [ (r, x) for x, r in zip( numpy.linspace(-wing_length, 0, wing_subdiv, endpoint=False), numpy.linspace(0.8, 1, wing_subdiv, endpoint=False)) ] + [(1, 0)] + [ (r, x) for x, r in zip( numpy.linspace(wing_length, 0, wing_subdiv, endpoint=False), numpy.linspace(0.8, 1, wing_subdiv, endpoint=False)) ][::-1] + [ (0.7, wing_length*1.05), (0, wing_length*1.05) ] geob.add_geometry(*generate_extrusion( rz_points=rz_points, base_shape=get_naca_points("0012", verbose=False, number_of_points=20), ring_markers=(wing_subdiv*2+4)*[box_marker])) from meshpy.tools import make_swizzle_matrix swizzle_matrix = make_swizzle_matrix("z:x,y:y,x:z") geob.apply_transform(lambda p: numpy.dot(swizzle_matrix, p)) def deform_wing(p): x, y, z = p return numpy.array([ x, y + 0.1*abs(x/wing_length)**2, z + 0.8*abs(x/wing_length) ** 1.2]) geob.apply_transform(deform_wing) points, facets, _, facet_markers = make_box( numpy.array([-wing_length-1, -1, -1.5]), numpy.array([wing_length+1, 1, 3])) geob.add_geometry(points, facets, facet_markers=facet_markers) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.set_holes([(0, 0, 0.5)]) mesh = build(mesh_info) print("%d elements" % len(mesh.elements)) mesh.write_vtk("airfoil3d.vtk")
def area_of_tri(nodes): v1 = np.array(nodes[0].coord[:2]) - np.array(nodes[1].coord[:2]) v2 = np.array(nodes[0].coord[:2]) - np.array(nodes[2].coord[:2]) area = np.cross(v1, v2) / 2. return area if __name__ == "__main__": #mesh r = 1 l = 2 rz = [(0, 0), (r, 0), (r, l), (0, l)] geob = GeometryBuilder() geob.add_geometry(*generate_surface_of_revolution( rz, radial_subdiv=20, ring_markers=[1, 2, 3])) mesh_info = MeshInfo() geob.set(mesh_info) mesh = build(mesh_info, max_volume=0.01) E = 210e6 nu = 0.3 P = 2000 points = np.array(mesh.points) cells = np.array(mesh.elements) face_cells = np.array(mesh.faces) z_face0_cells = [ c for c in face_cells if np.isclose(points[c][:, 2], 0).all() ] z_face2_cells = [ c for c in face_cells if np.isclose(points[c][:, 2], 2).all()
def make_wingmesh(): import numpy from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, Marker, \ generate_extrusion, make_box geob = GeometryBuilder() profile_marker = Marker.FIRST_USER_MARKER wing_length = 2 wing_subdiv = 5 rz_points = [ (0, -wing_length * 1.05), (0.7, -wing_length * 1.05), ] + [(r, x) for x, r in zip( numpy.linspace(-wing_length, 0, wing_subdiv, endpoint=False), numpy.linspace(0.8, 1, wing_subdiv, endpoint=False))] + [(1, 0)] + [ (r, x) for x, r in zip( numpy.linspace(wing_length, 0, wing_subdiv, endpoint=False), numpy.linspace(0.8, 1, wing_subdiv, endpoint=False)) ][::-1] + [(0.7, wing_length * 1.05), (0, wing_length * 1.05)] from meshpy.naca import get_naca_points geob.add_geometry(*generate_extrusion( rz_points=rz_points, base_shape=get_naca_points("0012", number_of_points=20), ring_markers=(wing_subdiv * 2 + 4) * [profile_marker])) def deform_wing(p): x, y, z = p return numpy.array([ x + 0.8 * abs(z / wing_length)**1.2, y + 0.1 * abs(z / wing_length)**2, z ]) geob.apply_transform(deform_wing) points, facets, facet_markers = make_box( numpy.array([-1.5, -1, -wing_length - 1], dtype=numpy.float64), numpy.array([3, 1, wing_length + 1], dtype=numpy.float64)) geob.add_geometry(points, facets, facet_markers=facet_markers) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.set_holes([(0.5, 0, 0)]) mesh = build(mesh_info) 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.PLUS_Z: "inflow", Marker.MINUS_Z: "inflow" } def bdry_tagger(fvi, el, fn, all_v): face_marker = fvi2fm[fvi] return [face_marker_to_tag[face_marker]] from grudge.mesh import make_conformal_mesh return make_conformal_mesh(mesh.points, mesh.elements, bdry_tagger)
def make_wingmesh(): import numpy from math import pi, cos, sin from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, Marker, \ generate_extrusion, make_box geob = GeometryBuilder() profile_marker = Marker.FIRST_USER_MARKER wing_length = 2 wing_subdiv = 5 rz_points = [ (0, -wing_length*1.05), (0.7, -wing_length*1.05), ] + [ (r, x) for x, r in zip( numpy.linspace(-wing_length, 0, wing_subdiv, endpoint=False), numpy.linspace(0.8, 1, wing_subdiv, endpoint=False)) ] + [(1,0)] + [ (r, x) for x, r in zip( numpy.linspace(wing_length, 0, wing_subdiv, endpoint=False), numpy.linspace(0.8, 1, wing_subdiv, endpoint=False)) ][::-1] + [ (0.7, wing_length*1.05), (0, wing_length*1.05) ] from meshpy.naca import get_naca_points geob.add_geometry(*generate_extrusion( rz_points=rz_points, base_shape=get_naca_points("0012", number_of_points=20), ring_markers=(wing_subdiv*2+4)*[profile_marker])) def deform_wing(p): x, y, z = p return numpy.array([ x + 0.8*abs(z/wing_length)** 1.2, y + 0.1*abs(z/wing_length)**2, z]) geob.apply_transform(deform_wing) points, facets, facet_markers = make_box( numpy.array([-1.5,-1,-wing_length-1], dtype=numpy.float64), numpy.array([3,1,wing_length+1], dtype=numpy.float64)) geob.add_geometry(points, facets, facet_markers=facet_markers) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.set_holes([(0.5,0,0)]) mesh = build(mesh_info) 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.PLUS_Z: "inflow", Marker.MINUS_Z: "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 return make_conformal_mesh(mesh.points, mesh.elements, bdry_tagger)
def make_boxmesh(): from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, Marker, make_box geob = GeometryBuilder() box_marker = Marker.FIRST_USER_MARKER extent_small = 0.1 * numpy.ones(3, dtype=numpy.float64) geob.add_geometry(*make_box(-extent_small, extent_small)) # make small "separator box" for region attribute geob.add_geometry( *make_box(-extent_small * 4, numpy.array([4, 0.4, 0.4], dtype=numpy.float64))) geob.add_geometry(*make_box(numpy.array([-1, -1, -1], dtype=numpy.float64), numpy.array([5, 1, 1], dtype=numpy.float64))) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.set_holes([(0, 0, 0)]) # region attributes mesh_info.regions.resize(1) mesh_info.regions[0] = ( # point in region list(extent_small * 2) + [ # region number 1, # max volume in region #0.0001 0.005 ]) mesh = build(mesh_info, max_volume=0.02, volume_constraints=True, attributes=True) print("%d elements" % len(mesh.elements)) #mesh.write_vtk("box-in-box.vtk") #print "done writing" fvi2fm = mesh.face_vertex_indices_to_face_marker face_marker_to_tag = { box_marker: "noslip", Marker.MINUS_X: "inflow", Marker.PLUS_X: "outflow", Marker.MINUS_Y: "inflow", Marker.PLUS_Y: "inflow", Marker.PLUS_Z: "inflow", Marker.MINUS_Z: "inflow" } def bdry_tagger(fvi, el, fn, all_v): face_marker = fvi2fm[fvi] return [face_marker_to_tag[face_marker]] from grudge.mesh import make_conformal_mesh return make_conformal_mesh(mesh.points, mesh.elements, bdry_tagger)
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_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 grudge.mesh import make_conformal_mesh_ext vertices = numpy.asarray(mesh.points, dtype=float, order="C") from grudge.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_boxmesh(): from meshpy.tet import MeshInfo, build from meshpy.geometry import GeometryBuilder, Marker, make_box geob = GeometryBuilder() box_marker = Marker.FIRST_USER_MARKER extent_small = 0.1*numpy.ones(3, dtype=numpy.float64) geob.add_geometry(*make_box(-extent_small, extent_small)) # make small "separator box" for region attribute geob.add_geometry( *make_box( -extent_small*4, numpy.array([4, 0.4, 0.4], dtype=numpy.float64))) geob.add_geometry( *make_box( numpy.array([-1, -1, -1], dtype=numpy.float64), numpy.array([5, 1, 1], dtype=numpy.float64))) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info.set_holes([(0, 0, 0)]) # region attributes mesh_info.regions.resize(1) mesh_info.regions[0] = ( # point in region list(extent_small*2) + [ # region number 1, # max volume in region #0.0001 0.005 ]) mesh = build(mesh_info, max_volume=0.02, volume_constraints=True, attributes=True) print "%d elements" % len(mesh.elements) #mesh.write_vtk("box-in-box.vtk") #print "done writing" fvi2fm = mesh.face_vertex_indices_to_face_marker face_marker_to_tag = { box_marker: "noslip", Marker.MINUS_X: "inflow", Marker.PLUS_X: "outflow", Marker.MINUS_Y: "inflow", Marker.PLUS_Y: "inflow", Marker.PLUS_Z: "inflow", Marker.MINUS_Z: "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 return make_conformal_mesh( mesh.points, mesh.elements, bdry_tagger)
def test_convergence_advec(actx_factory, mesh_name, mesh_pars, op_type, flux_type, order, visualize=False): """Test whether 2D advection actually converges""" actx = actx_factory() from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() for mesh_par in mesh_pars: if mesh_name == "segment": mesh = mgen.generate_box_mesh([np.linspace(-1.0, 1.0, mesh_par)], order=order) dim = 1 dt_factor = 1.0 elif mesh_name == "disk": pytest.importorskip("meshpy") from meshpy.geometry import make_circle, GeometryBuilder from meshpy.triangle import MeshInfo, build geob = GeometryBuilder() geob.add_geometry(*make_circle(1)) mesh_info = MeshInfo() geob.set(mesh_info) mesh_info = build(mesh_info, max_volume=mesh_par) from meshmode.mesh.io import from_meshpy mesh = from_meshpy(mesh_info, order=1) dim = 2 dt_factor = 4 elif mesh_name.startswith("rect"): dim = int(mesh_name[-1:]) mesh = mgen.generate_regular_rect_mesh( a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(mesh_par, ) * dim, order=4) if dim == 2: dt_factor = 4 elif dim == 3: dt_factor = 2 else: raise ValueError("dt_factor not known for %dd" % dim) elif mesh_name.startswith("warped"): dim = int(mesh_name[-1:]) mesh = mgen.generate_warped_rect_mesh(dim, order=order, nelements_side=mesh_par) if dim == 2: dt_factor = 4 elif dim == 3: dt_factor = 2 else: raise ValueError("dt_factor not known for %dd" % dim) else: raise ValueError("invalid mesh name: " + mesh_name) v = np.array([0.27, 0.31, 0.1])[:dim] norm_v = la.norm(v) def f(x): return actx.np.sin(10 * x) def u_analytic(x, t=0): return f(-v.dot(x) / norm_v + t * norm_v) from grudge.models.advection import (StrongAdvectionOperator, WeakAdvectionOperator) from meshmode.mesh import BTAG_ALL dcoll = DiscretizationCollection(actx, mesh, order=order) op_class = { "strong": StrongAdvectionOperator, "weak": WeakAdvectionOperator }[op_type] adv_operator = op_class(dcoll, v, inflow_u=lambda t: u_analytic( thaw(dcoll.nodes(dd=BTAG_ALL), actx), t=t), flux_type=flux_type) nodes = thaw(dcoll.nodes(), actx) u = u_analytic(nodes, t=0) def rhs(t, u): return adv_operator.operator(t, u) if dim == 3: final_time = 0.1 else: final_time = 0.2 from grudge.dt_utils import h_max_from_volume h_max = h_max_from_volume(dcoll, dim=dcoll.ambient_dim) dt = dt_factor * h_max / order**2 nsteps = (final_time // dt) + 1 dt = final_time / nsteps + 1e-15 from grudge.shortcuts import set_up_rk4 dt_stepper = set_up_rk4("u", dt, u, rhs) last_u = None from grudge.shortcuts import make_visualizer vis = make_visualizer(dcoll) step = 0 for event in dt_stepper.run(t_end=final_time): if isinstance(event, dt_stepper.StateComputed): step += 1 logger.debug("[%04d] t = %.5f", step, event.t) last_t = event.t last_u = event.state_component if visualize: vis.write_vtk_file("fld-%s-%04d.vtu" % (mesh_par, step), [("u", event.state_component)]) error_l2 = op.norm(dcoll, last_u - u_analytic(nodes, t=last_t), 2) logger.info("h_max %.5e error %.5e", h_max, error_l2) eoc_rec.add_data_point(h_max, actx.to_numpy(error_l2)) logger.info( "\n%s", eoc_rec.pretty_print(abscissa_label="h", error_label="L2 Error")) if mesh_name.startswith("warped"): # NOTE: curvilinear meshes are hard assert eoc_rec.order_estimate() > order - 0.5 else: assert eoc_rec.order_estimate() > order