Exemplo n.º 1
0
    def generate_disk_mesh(radius=1.0,
                           theta_max=np.pi,
                           nr=2,
                           ntheta=4,
                           center=(0, 0, 0),
                           normal=(1, 0, 0),
                           name=None) -> Mesh:
        theta_range = np.linspace(0, 2 * theta_max, ntheta + 1)
        r_range = np.linspace(0.0, radius, nr + 1)

        nodes = np.zeros(((ntheta + 1) * (nr + 1), 3), dtype=float)
        for i, (r, t) in enumerate(product(r_range, theta_range)):
            y = +r * np.sin(t)
            z = -r * np.cos(t)
            nodes[i, :] = (0, y, z)

        panels = np.zeros((ntheta * nr, 4), dtype=int)

        for k, (i, j) in enumerate(product(range(0, nr), range(0, ntheta))):
            panels[k, :] = (j + i * (ntheta + 1), j + 1 + i * (ntheta + 1),
                            j + 1 + (i + 1) * (ntheta + 1),
                            j + (i + 1) * (ntheta + 1))

        mesh = Mesh(nodes, panels, name=name)
        mesh.merge_duplicates()
        mesh.heal_triangles()
        mesh.rotate_around_center_to_align_vectors(
            (0, 0, 0), mesh.faces_normals[0], normal)
        mesh.translate(center)
        return mesh
Exemplo n.º 2
0
    def _generate_open_cylinder_mesh(self,
                                     nx,
                                     ntheta,
                                     reflection_symmetry,
                                     translation_symmetry,
                                     name=None):
        """Open horizontal cylinder using the symmetries (translation and reflection) to speed up the computations"""
        theta_max = np.pi
        theta = np.linspace(0, theta_max, ntheta // 2 + 1)
        X = np.array([0, self.length / nx])

        # Nodes
        nodes = np.zeros(((ntheta // 2 + 1) * 2, 3), dtype=float)

        for i, (t, x) in enumerate(product(theta, X)):
            y = +self.radius * np.sin(t)
            z = -self.radius * np.cos(t)
            nodes[i, :] = (x, y, z)
        nodes += -np.array([self.length / 2, 0, 0])

        # Connectivities
        panels = np.zeros((ntheta // 2, 4), dtype=int)

        for k, i in enumerate(range(0, ntheta // 2)):
            panels[k, :] = (2 * i, 2 * i + 2, 2 * i + 3, 2 * i + 1)
        half_ring = Mesh(nodes, panels, name=f"half_ring_of_{name}_mesh")

        if reflection_symmetry:
            if nx == 1:
                half_cylinder = half_ring
            else:
                half_cylinder = TranslationalSymmetricMesh(
                    half_ring,
                    translation=np.asarray([self.length / nx, 0.0, 0.0]),
                    nb_repetitions=nx - 1,
                    name=f"half_{name}_mesh")
                if not translation_symmetry:
                    half_cylinder = half_cylinder.merged()

            return ReflectionSymmetricMesh(half_cylinder,
                                           plane=xOz_Plane,
                                           name=f"{name}_mesh")

        else:
            strip = half_ring + half_ring.mirrored(plane=xOz_Plane)
            if nx == 1:
                return strip

            else:
                cylinder = TranslationalSymmetricMesh(
                    strip,
                    translation=np.asarray([self.length / nx, 0.0, 0.0]),
                    nb_repetitions=nx - 1,
                    name=f"half_{name}_mesh")
                if not translation_symmetry:
                    cylinder = cylinder.merged()

            return cylinder
Exemplo n.º 3
0
def load_MAR(filename, name=None):
    """Loads Nemoh (Ecole Centrale de Nantes) mesh files.

    Parameters
    ----------
    filename: str
        name of the meh file on disk

    Returns
    -------
    Mesh or ReflectionSymmetry
        the loaded mesh

    Note
    ----
    MAR files have a 1-indexing
    """

    _check_file(filename)

    ifile = open(filename, 'r')

    header = ifile.readline()
    _, symmetric_mesh = header.split()

    vertices = []
    while 1:
        line = ifile.readline()
        line = line.split()
        if line[0] == '0':
            break
        vertices.append(list(map(float, line[1:])))

    vertices = np.array(vertices, dtype=np.float)
    faces = []
    while 1:
        line = ifile.readline()
        line = line.split()
        if line[0] == '0':
            break
        faces.append(list(map(int, line)))

    faces = np.array(faces, dtype=np.int)

    ifile.close()

    if int(symmetric_mesh) == 1:
        if name is None:
            half_mesh = Mesh(vertices, faces - 1)
            return ReflectionSymmetricMesh(half_mesh, plane=xOz_Plane)
        else:
            half_mesh = Mesh(vertices, faces - 1, name=f"half_of_{name}")
            return ReflectionSymmetricMesh(half_mesh,
                                           plane=xOz_Plane,
                                           name=name)
    else:
        return Mesh(vertices, faces - 1, name)
Exemplo n.º 4
0
def test_mesh_initialization():
    """Test how the code checks the validity of the parameters."""
    with pytest.raises(AssertionError):
        Mesh(vertices=np.random.rand(6, 3), faces=[(0, 1, 2), (3, 4, 5)])

    with pytest.raises(AssertionError):
        Mesh(vertices=np.random.rand(4, 3), faces=[(0, 1, 2, -1)])

    with pytest.raises(AssertionError):
        Mesh(vertices=np.random.rand(3, 3), faces=[(0, 1, 2, 3)])
Exemplo n.º 5
0
def clip(source_mesh: Mesh, plane: Plane, vicinity_tol=1e-3, name=None):
    """Return a new mesh containing the source mesh clipped by the plane.

    Parameters
    ----------
    source_mesh : Mesh
        The mesh to be clipped.
    plane : Plane, optional
        The clipping plane.
    vicinity_tol : float, optional
        The absolute tolerance to consider en vertex is on the plane. Default is 1e-3.
    name: string, optional
        A name for the new clipped mesh.
    """
    vertices_data = _vertices_positions_wrt_plane(source_mesh, plane,
                                                  vicinity_tol)

    nb_vertices_above_or_on_plane = np.count_nonzero(
        vertices_data['vertices_above_mask']
        | vertices_data['vertices_on_mask'])
    nb_vertices_below_or_on_plane = np.count_nonzero(
        vertices_data['vertices_below_mask']
        | vertices_data['vertices_on_mask'])

    if nb_vertices_above_or_on_plane == source_mesh.nb_vertices:
        LOG.warning(
            f"Clipping {source_mesh.name} by {plane}: all vertices are removed."
        )
        clipped_mesh = Mesh(None, None)
        clipped_mesh._clipping_data = dict(faces_ids=[])

    elif nb_vertices_below_or_on_plane == source_mesh.nb_vertices:
        LOG.info(f"Clipping {source_mesh.name} by {plane}: no action.")
        clipped_mesh = source_mesh.copy()
        clipped_mesh._clipping_data = dict(
            faces_ids=list(range(source_mesh.nb_faces)))

    else:
        upper_mesh, crown_mesh, lower_mesh = _partition_mesh(
            vertices_data, source_mesh)

        if crown_mesh.nb_faces > 0:
            clipped_crown_mesh = _clip_crown(crown_mesh, plane)
            clipped_mesh = lower_mesh + clipped_crown_mesh
            clipped_mesh._clipping_data = {
                'faces_ids':
                np.concatenate(
                    (lower_mesh._clipping_data['faces_ids'],
                     clipped_crown_mesh._clipping_data['faces_ids']))
            }
        else:
            clipped_mesh = lower_mesh

    if name is None:
        clipped_mesh.name = f'{source_mesh.name}_clipped'
    clipped_mesh.remove_unused_vertices()

    return clipped_mesh
Exemplo n.º 6
0
def test_mesh_naming():
    """Test how the mesh handle names and string representation."""
    # Test string representation
    assert str(test_mesh) == 'test_mesh'  # Just the name
    assert repr(
        test_mesh
    ) == "Mesh(nb_vertices=4, nb_faces=1, name=test_mesh)"  # A longer representation.

    # Test automatic naming
    dummy_mesh = Mesh()  # Automatically named something like mesh_1
    other_dummy_mesh = Mesh()  # Automatically named something like mesh_2
    assert dummy_mesh.name[:5] == "mesh_"
    assert other_dummy_mesh.name[:5] == "mesh_"
    assert int(dummy_mesh.name[5:]) + 1 == int(other_dummy_mesh.name[5:])
Exemplo n.º 7
0
    def from_meshio(mesh, name=None) -> 'FloatingBody':
        """Create a FloatingBody from a meshio mesh object."""

        import meshio
        if not isinstance(mesh, meshio._mesh.Mesh):
            raise TypeError(
                'mesh must be of type meshio._mesh.Mesh, recevied {:}'.format(
                    type(mesh)))

        if name is None:
            date_str = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
            name = 'fb_{:}'.format(date_str)

        def all_faces_as_quads(cells):
            all_faces = []
            if 'quad' in cells:
                all_faces.append(cells['quad'])
            if 'triangle' in cells:
                num_triangles = len(mesh.cells_dict['triangle'])
                LOG.info("Stored {:} triangle faces as quadrilaterals".format(
                    num_triangles))
                triangles_as_quads = np.empty((cells['triangle'].shape[0], 4),
                                              dtype=int)
                triangles_as_quads[:, :3] = cells['triangle'][:, :]
                triangles_as_quads[:, 3] = cells[
                    'triangle'][:, 2]  # Repeat one node to make a quad
                all_faces.append(triangles_as_quads)
            return np.concatenate(all_faces)

        cpt_mesh = Mesh(vertices=mesh.points,
                        faces=all_faces_as_quads(mesh.cells_dict),
                        name=name + "_mesh")

        fb = FloatingBody(mesh=cpt_mesh, name=name)
        return fb
Exemplo n.º 8
0
def test_vertices_and_faces_get_and_set():
    """Test get and set functions for vertices and faces."""
    # Get faces
    faces = cylinder.faces
    vertices = cylinder.vertices

    new_cylinder = Mesh(name="new_cylinder")

    # Set faces
    with pytest.raises(AssertionError):
        new_cylinder.faces = faces
        # You should set the vertices first.
    new_cylinder.vertices = vertices
    new_cylinder.faces = faces

    assert new_cylinder == cylinder
Exemplo n.º 9
0
def load_VTP(filename, name=None):
    """Loads VTK file format in the new XML format (vtp file extension for polydata meshes).

    It relies on the reader from the VTK library.

    Parameters
    ----------
    filename: str
        name of the meh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Note
    ----
    VTP files have a 0-indexing
    """
    _check_file(filename)

    vtk = import_optional_dependency("vtk")

    reader = vtk.vtkXMLPolyDataReader()
    reader.SetFileName(filename)
    reader.Update()
    vtk_mesh = reader.GetOutput()

    vertices, faces = _dump_vtk(vtk_mesh)
    return Mesh(vertices, faces, name)
Exemplo n.º 10
0
    def __init__(self,
                 mesh=None,
                 dofs=None,
                 mass=None,
                 center_of_mass=None,
                 name=None):
        if mesh is None:
            mesh = Mesh(name="dummy_mesh")

        if dofs is None:
            dofs = {}

        if name is None:
            name = mesh.name

        assert isinstance(mesh, Mesh) or isinstance(mesh, CollectionOfMeshes)
        self.mesh = mesh
        self.full_body = None
        self.dofs = dofs
        self.mass = mass
        self.center_of_mass = center_of_mass
        self.name = name

        if self.mesh.nb_vertices == 0 or self.mesh.nb_faces == 0:
            LOG.warning(f"New floating body (with empty mesh!): {self.name}.")
        else:
            self.mesh.heal_mesh()
            LOG.info(f"New floating body: {self.name}.")
Exemplo n.º 11
0
def load_MED(filename, name=None):
    """Loads MED mesh files generated by SALOME MECA.

    Parameters
    ----------
    filename: str
        name of the mesh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Note
    ----
    MED files have a 1-indexing
    """

    try:
        import h5py
    except ImportError:
        raise ImportError('MED file format reader needs h5py module to be installed')

    _check_file(filename)

    file = h5py.File(filename)

    list_of_names = []
    file.visit(list_of_names.append)

    # TODO: gerer les cas ou on a que des tris ou que des quads...
    nb_quadrangles = nb_triangles = 0

    for item in list_of_names:
        if '/NOE/COO' in item:
            vertices = file.get(item).value.reshape((3, -1)).T
            nv = vertices.shape[0]
        if '/MAI/TR3/NOD' in item:
            triangles = file.get(item).value.reshape((3, -1)).T - 1
            nb_triangles = triangles.shape[0]
        if '/MAI/QU4/NOD' in item:
            quadrangles = file.get(item).value.reshape((4, -1)).T - 1
            nb_quadrangles = quadrangles.shape[0]

    file.close()

    if nb_triangles == 0:
        triangles = np.zeros((0, 4), dtype=int)
    else:
        triangles = np.column_stack((triangles, triangles[:, 0]))
    if nb_quadrangles == 0:
        quadrangles = np.zeros((0, 4), dtype=int)

    faces = np.zeros((nb_triangles+nb_quadrangles, 4), dtype=int)
    faces[:nb_triangles] = triangles
    # faces[:nb_triangles, -1] = triangles[:, 0]
    faces[nb_triangles:] = quadrangles

    vertices = np.ascontiguousarray(vertices)
    return Mesh(vertices, faces)
Exemplo n.º 12
0
def load_VTK(filename, name=None):
    """Loads VTK file format in the legacy format (vtk file extension).

    It relies on the reader from the VTK library.

    Parameters
    ----------
    filename: str
        name of the meh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Note
    ----
    VTU files have a 0-indexing
    """
    _check_file(filename)

    from vtk import vtkPolyDataReader
    reader = vtkPolyDataReader()
    reader.SetFileName(filename)
    reader.Update()
    vtk_mesh = reader.GetOutput()

    vertices, faces = _dump_vtk(vtk_mesh)
    return Mesh(vertices, faces, name)
Exemplo n.º 13
0
def load_NAT(filename, name=None):
    """This function loads natural file format for meshes.

    Parameters
    ----------
    filename: str
        name of the meh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Notes
    -----
    The file format is as follow::

        xsym    ysym
        n    m
        x1    y1    z1
        .
        .
        .
        xn    yn    zn
        i1    j1    k1    l1
        .
        .
        .
        im    jm    km    lm

    where :
    n : number of nodes
    m : number of cells
    x1 y1 z1 : cartesian coordinates of node 1
    i1 j1 k1 l1 : counterclock wise Ids of nodes for cell 1
    if cell 1 is a triangle, i1==l1

    Note
    ----
    NAT files have a 1-indexing
    """

    _check_file(filename)

    ifile = open(filename, 'r')
    ifile.readline()
    nv, nf = list(map(int, ifile.readline().split()))

    vertices = []
    for i in range(nv):
        vertices.append(list(map(float, ifile.readline().split())))
    vertices = np.array(vertices, dtype=np.float)

    faces = []
    for i in range(nf):
        faces.append(list(map(int, ifile.readline().split())))
    faces = np.array(faces, dtype=np.int)

    ifile.close()
    return Mesh(vertices, faces - 1, name)
Exemplo n.º 14
0
def test_clipper_corner_cases():
    mesh = sphere.translated_z(10.0)

    plane = Plane(point=(0, 0, 0), normal=(0, 0, 1))
    clipped_mesh = mesh.clip(plane, inplace=False)
    assert clipped_mesh == Mesh(None, None)  # Empty mesh

    plane = Plane(point=(0, 0, 0), normal=(0, 0, -1))
    clipped_mesh = mesh.clip(plane, inplace=False)
    assert clipped_mesh == mesh  # Unchanged mesh

    # Two distinct bodies
    two_spheres = Mesh.join_meshes(sphere.translated_z(10.0),
                                   sphere.translated_z(-10.0))
    plane = Plane(point=(0, 0, 0), normal=(0, 0, -1))
    one_sphere_remaining = two_spheres.clip(plane, inplace=False)
    assert one_sphere_remaining == sphere.translated_z(10.0)
Exemplo n.º 15
0
def load_GDF(filename, name=None):
    """Loads WAMIT (Wamit INC. (c)) GDF mesh files.

    As GDF file format maintains a redundant set of vertices for each faces of the mesh, it returns a merged list of
    nodes and connectivity array by using the merge_duplicates function.

    Parameters
    ----------
    filename: str
        name of the mesh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Note
    ----
    GDF files have a 1-indexing
    """

    _check_file(filename)

    ifile = open(filename, 'r')

    ifile.readline()  # skip one header line
    line = ifile.readline().split()
    ulen = line[0]
    grav = line[1]

    line = ifile.readline().split()
    isx = line[0]
    isy = line[1]

    line = ifile.readline().split()
    nf = int(line[0])

    vertices = np.zeros((4 * nf, 3), dtype=float)
    faces = np.zeros((nf, 4), dtype=int)

    iv = 0
    for icell in range(nf):
        
        n_coords = 0
        face_coords = np.zeros((12,), dtype=float)
        
        while n_coords < 12:
            line = np.array(ifile.readline().split())
            face_coords[n_coords:n_coords+len(line)] = line
            n_coords += len(line)

        vertices[iv:iv+4, :] = np.split(face_coords, 4)
        faces[icell, :] = np.arange(iv, iv+4)
        iv += 4

    ifile.close()

    return Mesh(vertices, faces, name)
Exemplo n.º 16
0
def mesh_from_set_of_faces():
    A, B, C, D = (0, 0, 0), (1, 0, 0), (0, 1, 0), (1, 1, 0)

    # Two triangular faces
    faces = {frozenset({A, B, C}), frozenset({B, C, D})}
    mesh = Mesh.from_set_of_faces(faces)
    assert mesh.nb_vertices == 4
    assert mesh.nb_faces == 2
    assert mesh.is_triangle(0) and mesh.is_triangle(1)
Exemplo n.º 17
0
def test_LinearPotentialFlowProblem():
    # Without a body
    pb = LinearPotentialFlowProblem(omega=1.0)
    assert pb.omega == 1.0
    assert pb.period == 2 * np.pi
    assert pb.wavenumber == 1.0 / 9.81
    assert pb.wavelength == 9.81 * 2 * np.pi

    assert LinearPotentialFlowProblem(free_surface=np.infty,
                                      sea_bottom=-np.infty).depth == np.infty
    assert LinearPotentialFlowProblem(free_surface=0.0,
                                      sea_bottom=-np.infty).depth == np.infty

    pb = LinearPotentialFlowProblem(free_surface=0.0,
                                    sea_bottom=-1.0,
                                    omega=1.0)
    assert pb.depth == 1.0
    assert np.isclose(pb.omega**2,
                      pb.g * pb.wavenumber * np.tanh(pb.wavenumber * pb.depth))
    assert pb.dimensionless_wavenumber == pb.wavenumber * 1.0

    with pytest.raises(NotImplementedError):
        LinearPotentialFlowProblem(free_surface=2.0)

    with pytest.raises(NotImplementedError):
        LinearPotentialFlowProblem(free_surface=np.infty, sea_bottom=0.0)

    with pytest.raises(ValueError):
        LinearPotentialFlowProblem(free_surface=0.0, sea_bottom=1.0)

    with pytest.raises(TypeError):
        LinearPotentialFlowProblem(wave_direction=1.0)

    with pytest.raises(TypeError):
        LinearPotentialFlowProblem(radiating_dof="Heave")

    with pytest.raises(ValueError):
        LinearPotentialFlowProblem(body=FloatingBody(mesh=Mesh([], [])))

    # With a body
    sphere = Sphere(center=(0, 0, -2.0))
    sphere.add_translation_dof(direction=(0, 0, 1), name="Heave")
    pb = LinearPotentialFlowProblem(body=sphere, omega=1.0)
    pb.boundary_condition = sphere.mesh.faces_normals @ (1, 1, 1)
    assert list(pb.influenced_dofs.keys()) == ['Heave']

    pb2 = LinearPotentialFlowProblem(body=sphere, omega=2.0)
    pb2.boundary_condition = sphere.mesh.faces_normals @ (1, 1, 1)
    assert pb < pb2

    # Test transformation to result class
    res = pb.make_results_container()
    assert isinstance(res, LinearPotentialFlowResult)
    assert res.problem is pb
    assert res.omega == pb.omega
    assert res.period == pb.period
    assert res.body is pb.body
Exemplo n.º 18
0
    def generate_rectangle_mesh(width=1.0,
                                height=1.0,
                                nw=1,
                                nh=1,
                                center=(0, 0, 0),
                                normal=(1, 0, 0),
                                name=None):
        Y = np.linspace(-width / 2, width / 2, nw + 1)
        Z = np.linspace(-height / 2, height / 2, nh + 1)

        nodes = np.zeros(((nw + 1) * (nh + 1), 3), dtype=np.float)
        panels = np.zeros((nw * nh, 4), dtype=np.int)

        for i, (x, y, z) in enumerate(product([0.0], Y, Z)):
            nodes[i, :] = x, y, z

        for k, (i, j) in enumerate(product(range(0, nw), range(0, nh))):
            panels[k, :] = (j + i * (nh + 1), j + 1 + i * (nh + 1),
                            j + 1 + (i + 1) * (nh + 1), j + (i + 1) * (nh + 1))

        if name is None:
            name = f"rectangle_{next(Mesh._ids)}"

        mesh = Mesh(nodes, panels, name=f"{name}_mesh")
        mesh.rotate_around_center_to_align_vectors(
            (0, 0, 0), mesh.faces_normals[0], normal)
        mesh.translate(center)

        return mesh
Exemplo n.º 19
0
def load_MSH(filename, name=None):
    """Loads .MSH mesh files generated by GMSH by C. Geuzaine and J.F. Remacle.

    Parameters
    ----------
    filename: str
        name of the meh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Note
    ----
    MSH files have a 1-indexing
    """

    import re

    _check_file(filename)

    with open(filename, 'r') as file:
        data = file.read()

    nb_nodes, nodes_data = re.search(r'\$Nodes\n(\d+)\n(.+)\$EndNodes', data,
                                     re.DOTALL).groups()
    nb_elts, elts_data = re.search(r'\$Elements\n(\d+)\n(.+)\$EndElements',
                                   data, re.DOTALL).groups()

    vertices = np.asarray(list(map(float, nodes_data.split())),
                          dtype=np.float).reshape((-1, 4))[:, 1:]
    vertices = np.ascontiguousarray(vertices)
    faces = []

    # Triangles
    for tri_elt in re.findall(r'(^\d+\s2(?:\s\d+)+?$)', elts_data,
                              re.MULTILINE):
        tri_elt = list(map(int, tri_elt.split()))
        triangle = tri_elt[-3:]
        triangle.append(triangle[0])
        faces.append(triangle)

    for quad_elt in re.findall(r'(^\d+\s3(?:\s\d+)+?$)', elts_data,
                               re.MULTILINE):
        quad_elt = list(map(int, quad_elt.split()))
        quadrangle = quad_elt[-4:]
        faces.append(quadrangle)

    faces = np.asarray(faces, dtype=np.int) - 1

    return Mesh(vertices, faces, name)
Exemplo n.º 20
0
    def extract_faces(self, id_faces_to_extract, return_index=False):
        """Create a new FloatingBody by extracting some faces from the mesh.
        The dofs evolve accordingly.
        """
        if isinstance(self.mesh, CollectionOfMeshes):
            raise NotImplementedError  # TODO

        if return_index:
            new_mesh, id_v = Mesh.extract_faces(self.mesh, id_faces_to_extract, return_index)
        else:
            new_mesh = Mesh.extract_faces(self.mesh, id_faces_to_extract, return_index)
        new_body = FloatingBody(new_mesh)
        LOG.info(f"Extract floating body from {self.name}.")

        new_body.dofs = {}
        for name, dof in self.dofs.items():
            new_body.dofs[name] = dof[id_faces_to_extract, :]

        if return_index:
            return new_body, id_v
        else:
            return new_body
Exemplo n.º 21
0
def load_STL(filename, name=None):
    """Loads STL file format.

    It relies on the reader from the VTK library. As STL file format maintains a redundant set of vertices for each
    faces of the mesh, it returns a merged list of nodes and connectivity array by using the merge_duplicates function.

    Parameters
    ----------
    filename: str
        name of the meh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Note
    ----
    STL files have a 0-indexing
    """
    vtk = import_optional_dependency("vtk")

    from capytaine.meshes.quality import merge_duplicate_rows

    _check_file(filename)

    reader = vtk.vtkSTLReader()
    reader.SetFileName(filename)
    reader.Update()

    data = reader.GetOutputDataObject(0)

    nv = data.GetNumberOfPoints()
    vertices = np.zeros((nv, 3), dtype=float)
    for k in range(nv):
        vertices[k] = np.array(data.GetPoint(k))
    nf = data.GetNumberOfCells()
    faces = np.zeros((nf, 4), dtype=int)
    for k in range(nf):
        cell = data.GetCell(k)
        if cell is not None:
            for l in range(3):
                faces[k][l] = cell.GetPointId(l)
                faces[k][3] = faces[k][
                    0]  # always repeating the first node as stl is triangle only

    # Merging duplicates nodes
    vertices, new_id = merge_duplicate_rows(vertices)
    faces = new_id[faces]

    return Mesh(vertices, faces, name)
Exemplo n.º 22
0
def load_RAD(filename, name=None):
    """Loads RADIOSS mesh files. This export file format may be chosen in ICEM meshing program.

    Parameters
    ----------
    filename: str
        name of the meh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Note
    ----
    RAD files have a 1-indexing
    """

    import re
    _check_file(filename)
    ifile = open(filename, 'r')
    data = ifile.read()
    ifile.close()

    # node_line = r'\s*\d+(?:\s*' + real_str + '){3}'
    node_line = r'\s*\d+\s*(' + real_str + r')\s*(' + real_str + r')\s*(' + real_str + ')'
    node_section = r'((?:' + node_line + ')+)'

    elem_line = r'^\s*(?:\d+\s+){6}\d+\s*[\r\n]+'
    elem_section = r'((?:' + elem_line + '){3,})'

    pattern_node_line = re.compile(node_line, re.MULTILINE)
    # pattern_node_line_group = re.compile(node_line, re.MULTILINE)
    pattern_elem_line = re.compile(elem_line, re.MULTILINE)
    pattern_node_section = re.compile(node_section, re.MULTILINE)
    pattern_elem_section = re.compile(elem_section, re.MULTILINE)

    vertices = []
    node_section = pattern_node_section.search(data).group(1)
    for node in pattern_node_line.finditer(node_section):
        vertices.append(list(map(float, list(node.groups()))))
    vertices = np.asarray(vertices, dtype=float)

    faces = []
    elem_section = pattern_elem_section.search(data).group(1)
    for elem in pattern_elem_line.findall(elem_section):
        faces.append(list(map(int, elem.strip().split()[3:])))
    faces = np.asarray(faces, dtype=np.int) - 1

    return Mesh(vertices, faces, name)
Exemplo n.º 23
0
def test_dof():
    nodes = np.array([[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]])
    faces = np.array([[0, 1, 2, 3]])
    body = FloatingBody(Mesh(nodes, faces), name="one_face")
    assert body.dofs == {}

    body.add_translation_dof(direction=(1.0, 0.0, 0.0), name="1")
    assert np.allclose(body.dofs["1"], np.array([1.0, 0.0, 0.0]))

    body.add_translation_dof(direction=(0.0, 1.0, 0.0), name="2")
    assert np.allclose(body.dofs["2"], np.array([0.0, 1.0, 0.0]))

    body.add_rotation_dof(Axis(vector=(0.0, 0.0, 1.0)), name="3")
    body.add_rotation_dof(Axis(point=(0.5, 0, 0), vector=(0.0, 0.0, 1.0)), name="4")
Exemplo n.º 24
0
 def merged(self, name=None) -> Mesh:
     """Merge the sub-meshes and return a full mesh.
     If the collection contains other collections, they are merged recursively.
     Optionally, a new name can be given to the resulting mesh."""
     if name is None:
         name = self.name
     merged = Mesh(self.vertices, self.faces, name=name)
     merged.merge_duplicates()
     merged.heal_triangles()
     return merged
Exemplo n.º 25
0
def test_as_set_of_faces():
    """Test the representation of the mesh as a set of faces.
    Also allows to define the equality of two meshes."""
    faces = cylinder.as_set_of_faces()
    assert isinstance(faces, frozenset)
    assert len(faces) == cylinder.nb_faces
    assert all(len(face) == 4 or len(face) == 3
               for face in faces)  # Each face is represented by 3 or 4 points
    assert all(
        len(vertex) == 3 for face in faces
        for vertex in face)  # Each point is represented by 3 coordinates.

    assert cylinder == cylinder  # The equality is defined as the equality of the set of faces.
    assert Mesh.from_set_of_faces(
        faces
    ) == cylinder  # The mesh can be reconstructed from a set of faces.
Exemplo n.º 26
0
    def _generate_mesh(self):
        """Generate a 2D cartesian mesh."""
        nodes = np.zeros(((self.nx+1)*(self.ny+1), 3), dtype=np.float)
        panels = np.zeros((self.nx*self.ny, 4), dtype=np.int)

        X = np.linspace(*self.x_range, self.nx+1)
        Y = np.linspace(*self.y_range, self.ny+1)
        for i, (x, y, z) in enumerate(product(X, Y, [0.0])):
            nodes[i, :] = x, y, z

        for k, (i, j) in enumerate(product(range(0, self.nx), range(0, self.ny))):
            panels[k, :] = (j+i*(self.ny+1),
                            (j+1)+i*(self.ny+1),
                            (j+1)+(i+1)*(self.ny+1),
                            j+(i+1)*(self.ny+1))

        return Mesh(nodes, panels, name=f"{self.name}_mesh")
Exemplo n.º 27
0
    def __init__(self, mesh=None, dofs=None, name=None):
        if mesh is None:
            mesh = Mesh(name="dummy_mesh")

        if dofs is None:
            dofs = {}

        if name is None:
            name = mesh.name

        assert isinstance(mesh, Mesh) or isinstance(mesh, CollectionOfMeshes)
        self.mesh = mesh
        self.full_body = None
        self.dofs = dofs
        self.name = name

        LOG.info(f"New floating body: {self.name}.")
Exemplo n.º 28
0
    def from_profile(profile: Union[Callable, Iterable[float]],
                     z_range: Iterable[float]=np.linspace(-5, 0, 20),
                     axis: Axis=Oz_axis,
                     nphi: int=20,
                     name=None):
        """Return a floating body using the axial symmetry.
        The shape of the body can be defined either with a function defining the profile as [f(z), 0, z] for z in z_range.
        Alternatively, the profile can be defined as a list of points.
        The number of vertices along the vertical direction is len(z_range) in the first case and profile.shape[0] in the second case.

        Parameters
        ----------
        profile : function(float → float)  or  array(N, 3)
            define the shape of the body either as a function or a list of points.
        z_range: array(N), optional
            used only if the profile is defined as a function.
        axis : Axis
            symmetry axis
        nphi : int, optional
            number of vertical slices forming the body
        name : str, optional
            name of the generated body (optional)

        Returns
        -------
        AxialSymmetricMesh
            the generated mesh
        """

        if name is None:
            name = "axisymmetric_mesh"

        if callable(profile):
            z_range = np.asarray(z_range)
            x_values = [profile(z) for z in z_range]
            profile_array = np.stack([x_values, np.zeros(len(z_range)), z_range]).T
        else:
            profile_array = np.asarray(profile)

        assert len(profile_array.shape) == 2
        assert profile_array.shape[1] == 3

        n = profile_array.shape[0]
        angle = 2 * np.pi / nphi

        nodes_slice = np.concatenate([profile_array, axis.rotate_points(profile_array, angle)])
        faces_slice = np.array([[i, i+n, i+n+1, i+1] for i in range(n-1)])
        body_slice = Mesh(nodes_slice, faces_slice, name=f"slice_of_{name}")
        body_slice.merge_duplicates()
        body_slice.heal_triangles()

        return AxialSymmetricMesh(body_slice, axis=axis, nb_repetitions=nphi - 1, name=name)
Exemplo n.º 29
0
def load_TEC(filename, name=None):
    """Loads TECPLOT (Tecplot (c)) mesh files.

    It relies on the tecplot file reader from the VTK library.

    Parameters
    ----------
    filename: str
        name of the meh file on disk

    Returns
    -------
    Mesh
        the loaded mesh

    Note
    ----
    TEC files have a 1-indexing
    """

    import re

    _check_file(filename)

    data_pattern = re.compile(
        r'ZONE.*\s*N\s*=\s*(\d+)\s*,\s*E=\s*(\d+)\s*,\s*F\s*=\s*FEPOINT\s*,\s*ET\s*=\s*QUADRILATERAL\s+'
        + r'(^(?:\s*' + real_str + r'){3,})\s+' + r'(^(?:\s*\d+)*)',
        re.MULTILINE)

    with open(filename, 'r') as f:
        data = f.read()

    nv, nf, vertices, faces = data_pattern.search(data).groups()
    nv = int(nv)
    nf = int(nf)

    vertices = np.asarray(list(map(float, vertices.split())),
                          dtype=np.float).reshape((nv, -1))[:, :3]
    faces = np.asarray(list(map(int, faces.split())), dtype=np.int).reshape(
        (nf, 4)) - 1

    return Mesh(vertices, faces, name)
def test_collection_of_meshes():
    # Create some dummy meshes
    vertices = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]],
                        dtype=float)
    dummy_meshes = [Mesh(vertices, [[0, 1, 2, 3]])]
    for i in range(3):
        dummy_meshes.append(dummy_meshes[0].copy())
        dummy_meshes[i + 1].translate_z(i + 1)

    # A first collection from a list
    coll = CollectionOfMeshes(dummy_meshes[:2])
    assert coll.nb_submeshes == 2
    assert coll.nb_vertices == 8
    assert coll.nb_faces == 2
    assert coll[1].nb_faces == 1
    assert np.all(coll.faces_areas == np.asarray([1.0, 1.0]))
    assert np.all(coll.faces == np.asarray([[0, 1, 2, 3], [4, 5, 6, 7]]))
    assert np.all(coll.indices_of_mesh(1) == slice(1, 2))

    # A copy of the collection
    copy_coll = coll.copy()
    copy_coll.translate_x(1.0)  # Move
    assert copy_coll.nb_faces == 2
    assert np.all(copy_coll.vertices[:, 0] >= 1.0)  # Has moved

    # Another collection from an iterable
    other_coll = CollectionOfMeshes(iter(dummy_meshes))
    assert other_coll.nb_faces == 4
    assert np.all(other_coll.vertices[:, 0] <= 1.0)  # Did not move

    # A collection of collections
    big_coll = CollectionOfMeshes((copy_coll, other_coll))
    assert big_coll.nb_faces == 6
    assert big_coll.nb_submeshes == 2

    # Move one object in one of the sub-meshes
    copy_coll[1].translate_x(1.0)
    assert big_coll.vertices[:, 0].max() == 3.0

    # Merging the big collection
    merged = big_coll.merged()
    assert isinstance(merged, Mesh)