Ejemplo n.º 1
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)
Ejemplo n.º 2
0
    def _generate_mesh_with_reflection_symmetry(self, resolution, top, bottom,
                                                name):
        width, thickness, height = self.size
        nw, nth, nh = resolution

        half_front = Rectangle.generate_rectangle_mesh(
            width=width / 2,
            height=height,
            nw=nw // 2,
            nh=nh,
            center=(-width / 4, thickness / 2, 0),
            normal=(0, 1, 0),
            name=f"half_front_of_{name}_mesh")

        quarter_of_top = Rectangle.generate_rectangle_mesh(
            width=thickness / 2,
            height=width / 2,
            nw=nth // 2,
            nh=nw // 2,
            center=(-width / 4, thickness / 4, height / 2),
            normal=(0, 0, 1),
            name=f"top_panel_of_{name}_mesh")

        quarter_of_bottom = quarter_of_top.mirror(
            plane=xOy_Plane,
            inplace=False,
            name=f"bottom_panel_of_{name}_mesh")

        half_side = Rectangle.generate_rectangle_mesh(
            width=thickness / 2,
            height=height,
            nw=nth // 2,
            nh=nh,
            center=(-width / 2, thickness / 4, 0),
            normal=(1, 0, 0),
            name=f"half_side_of_{name}_mesh")

        panels = [half_front, half_side]
        if top:
            panels.append(quarter_of_top)
        if bottom:
            panels.append(quarter_of_bottom)
        quarter_of_mesh = CollectionOfMeshes(
            panels, name=f"quarter_of_{name}_mesh").merged()

        half_mesh = ReflectionSymmetricMesh(quarter_of_mesh,
                                            plane=yOz_Plane,
                                            name=f"half_of_{name}_mesh")
        return ReflectionSymmetricMesh(half_mesh,
                                       plane=xOz_Plane,
                                       name=f"{name}_mesh")
Ejemplo n.º 3
0
    def _generate_open_cylinder_mesh(self, nx, ntheta, name=None):
        """Open horizontal cylinder using the symmetry 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")

        ring = ReflectionSymmetricMesh(half_ring,
                                       plane=xOz_Plane,
                                       name=f"ring_of_{name}_mesh")

        if nx == 1:
            return ring
        else:
            return TranslationalSymmetricMesh(
                ring,
                translation=np.asarray([self.length / nx, 0.0, 0.0]),
                nb_repetitions=nx - 1,
                name=f"{name}_mesh")
Ejemplo n.º 4
0
    def __init__(self, size=(5.0, 5.0), resolution=(5, 5),
                 center=(0, 0, 0), normal=(1, 0, 0),
                 translational_symmetry=False, reflection_symmetry=False, name=None):
        assert len(size) == 2, "Size of a rectangle should be given as a couple of values."
        assert all([h > 0 for h in size]), "Size of the rectangle mesh should be given as positive values."

        assert len(resolution) == 2, "Resolution of a rectangle should be given as a couple a values."
        assert all([h > 0 for h in resolution]), "Resolution of the rectangle mesh should be given as positive values."
        assert all([i == int(i) for i in resolution]), "Resolution of a rectangle should be given as integer values."

        assert len(center) == 3, "Position of the center of a rectangle should be given a 3-ple of values."

        self.size = np.asarray(size, dtype=np.float)
        width, height = self.size
        self.geometric_center = np.asarray(center, dtype=np.float)
        nw, nh = resolution

        if translational_symmetry and reflection_symmetry:
            raise NotImplementedError("Rectangle generation with both reflection and translational symmetries "
                                      "has not been implemented yet.")

        if translational_symmetry and nw == 1:
            LOG.warning("To use the translation symmetry of the mesh, "
                        "it should have more than one panel in this direction. "
                        "Will return a standard mesh instead.")

        if reflection_symmetry and nw % 2 == 1:
            raise ValueError("To use the reflection symmetry of the mesh, "
                             "it should have an even number of panels in this direction.")

        if (reflection_symmetry or translational_symmetry) and normal[2] != 0:
            raise ValueError("To use the symmetry of the mesh, it should be vertical.")

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

        LOG.debug(f"New rectangle body of size ({width}, {height}) and resolution ({nw}, {nh}), named {name}.")

        if reflection_symmetry:
            half_mesh = Rectangle.generate_rectangle_mesh(
                width=width/2, height=height, nw=nw//2, nh=nh,
                center=(0, -width/4, 0), name=f"half_of_{name}_mesh"
            )
            mesh = ReflectionSymmetricMesh(half_mesh, plane=xOz_Plane, name=f"{name}_mesh")

        elif translational_symmetry and nw > 1:
            strip = Rectangle.generate_rectangle_mesh(
                width=width/nw, height=height, nw=1, nh=nh,
                center=(0, -width/2 + width/(2*nw), 0), name=f"strip_of_{name}_mesh"
            )
            mesh = TranslationalSymmetricMesh(strip,
                                              translation=np.asarray([0, width/nw, 0]), nb_repetitions=int(nw)-1,
                                              name=name)

        else:
            mesh = Rectangle.generate_rectangle_mesh(width=width, height=height, nw=nw, nh=nh, name=name)

        mesh.rotate_around_center_to_align_vectors((0, 0, 0), mesh.faces_normals[0], normal)
        mesh.translate(center)
        FloatingBody.__init__(self, mesh=mesh, name=name)
def test_floating_sphere(depth, omega):
    """Comparison of the added mass and radiation damping
    for a heaving sphere described using several symmetries
    in finite and infinite depth.
    """
    reso = 2

    full_sphere = Sphere(radius=1.0, ntheta=reso, nphi=4*reso, axial_symmetry=False, clip_free_surface=True)
    full_sphere.add_translation_dof(direction=(0, 0, 1), name="Heave")
    problem = RadiationProblem(body=full_sphere, omega=omega, sea_bottom=-depth)
    result1 = solver_with_sym.solve(problem)

    half_sphere_mesh = full_sphere.mesh.extract_faces(
        np.where(full_sphere.mesh.faces_centers[:, 1] > 0)[0],
        name="half_sphere_mesh")
    two_halves_sphere = FloatingBody(ReflectionSymmetricMesh(half_sphere_mesh, xOz_Plane))
    two_halves_sphere.add_translation_dof(direction=(0, 0, 1), name="Heave")
    problem = RadiationProblem(body=two_halves_sphere, omega=omega, sea_bottom=-depth)
    result2 = solver_with_sym.solve(problem)

    quarter_sphere_mesh = half_sphere_mesh.extract_faces(
        np.where(half_sphere_mesh.faces_centers[:, 0] > 0)[0],
        name="quarter_sphere_mesh")
    four_quarter_sphere = FloatingBody(ReflectionSymmetricMesh(ReflectionSymmetricMesh(quarter_sphere_mesh, yOz_Plane), xOz_Plane))
    assert 'None' not in four_quarter_sphere.mesh.tree_view()
    four_quarter_sphere.add_translation_dof(direction=(0, 0, 1), name="Heave")
    problem = RadiationProblem(body=four_quarter_sphere, omega=omega, sea_bottom=-depth)
    result3 = solver_with_sym.solve(problem)

    clever_sphere = Sphere(radius=1.0, ntheta=reso, nphi=4*reso, axial_symmetry=True, clip_free_surface=True)
    clever_sphere.add_translation_dof(direction=(0, 0, 1), name="Heave")
    problem = RadiationProblem(body=clever_sphere, omega=omega, sea_bottom=-depth)
    result4 = solver_with_sym.solve(problem)

    # (quarter_sphere + half_sphere + full_sphere + clever_sphere).show()

    volume = 4/3*np.pi
    assert np.isclose(result1.added_masses["Heave"], result2.added_masses["Heave"], atol=1e-4*volume*problem.rho)
    assert np.isclose(result1.added_masses["Heave"], result3.added_masses["Heave"], atol=1e-4*volume*problem.rho)
    assert np.isclose(result1.added_masses["Heave"], result4.added_masses["Heave"], atol=1e-4*volume*problem.rho)
    assert np.isclose(result1.radiation_dampings["Heave"], result2.radiation_dampings["Heave"], atol=1e-4*volume*problem.rho)
    assert np.isclose(result1.radiation_dampings["Heave"], result3.radiation_dampings["Heave"], atol=1e-4*volume*problem.rho)
    assert np.isclose(result1.radiation_dampings["Heave"], result4.radiation_dampings["Heave"], atol=1e-4*volume*problem.rho)
Ejemplo n.º 6
0
    def __init__(self,
                 radius=1.0,
                 resolution=(3, 5),
                 center=(0, 0, 0),
                 normal=(1, 0, 0),
                 reflection_symmetry=False,
                 axial_symmetry=False,
                 name=None):
        assert radius > 0, "Radius of the disk mesh should be given as a positive value."

        assert len(
            resolution
        ) == 2, "Resolution of a disk should be given as a couple a values."
        assert all([
            h > 0 for h in resolution
        ]), "Resolution of the disk mesh should be given as positive values."
        assert all([
            i == int(i) for i in resolution
        ]), "Resolution of a disk should be given as integer values."

        assert len(
            center
        ) == 3, "Position of the center of a disk should be given a 3-ple of values."

        self.radius = float(radius)
        self.geometric_center = np.asarray(center, dtype=float)
        nr, ntheta = resolution

        if reflection_symmetry and ntheta % 2 == 1:
            raise ValueError(
                "To use the reflection symmetry of the mesh, "
                "it should have an even number of panels in this direction.")

        if reflection_symmetry and axial_symmetry:
            raise NotImplementedError(
                "Disk generators with both symmetries have not been implemented."
            )

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

        LOG.debug(
            f"New disk body of radius {radius} and resolution ({nr}, {ntheta}), named {name}."
        )

        if reflection_symmetry:
            half_mesh = Disk.generate_disk_mesh(radius=self.radius,
                                                theta_max=np.pi / 2,
                                                nr=nr,
                                                ntheta=ntheta // 2,
                                                name=f"half_of_{name}_mesh")
            mesh = ReflectionSymmetricMesh(half_mesh,
                                           plane=xOz_Plane,
                                           name=f"{name}_mesh")

        elif axial_symmetry:
            mesh_slice = Disk.generate_disk_mesh(radius=self.radius,
                                                 theta_max=np.pi / ntheta,
                                                 nr=nr,
                                                 ntheta=1,
                                                 name=f"slice_of_{name}_mesh")
            mesh_slice.rotate_around_center_to_align_vectors(
                (0, 0, 0), e_x, e_z
            )  # Convoluted way to avoid a warning message in AxialSymmetry...
            mesh = AxialSymmetricMesh(mesh_slice,
                                      axis=Oz_axis,
                                      nb_repetitions=ntheta - 1,
                                      name=f"{name}_mesh")
            mesh.rotate_around_center_to_align_vectors((0, 0, 0), e_z, e_x)

        else:
            mesh = Disk.generate_disk_mesh(radius=self.radius,
                                           nr=nr,
                                           ntheta=ntheta,
                                           name=f"{name}_mesh")

        mesh.rotate_around_center_to_align_vectors(
            (0, 0, 0), mesh.faces_normals[0], normal)
        mesh.translate(center)
        FloatingBody.__init__(self, mesh=mesh, name=name)
Ejemplo n.º 7
0
    def __init__(self,
                 length=10.0,
                 radius=1.0,
                 center=(0, 0, 0),
                 nx=10,
                 ntheta=10,
                 nr=2,
                 reflection_symmetry=True,
                 translation_symmetry=False,
                 clever=None,
                 name=None):
        self.length = length
        self.radius = radius
        self.geometric_center = np.asarray(center, dtype=float)

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

        ntheta = 2 * (ntheta // 2)  # Temporary fix to avoid mismatch in mesh
        # When symmetries are used, one needs an even number of panels.
        # TODO: When symmetries are not used, implement the odd case.

        if clever is not None:
            LOG.warning(
                "Deprecation warning: `clever` argument for HorizontalCylinder is deprecated."
                "Use `reflection_symmetry` and/or `translation_symmetry` instead."
            )

        open_cylinder = self._generate_open_cylinder_mesh(
            nx,
            ntheta,
            reflection_symmetry=reflection_symmetry,
            translation_symmetry=translation_symmetry,
            name=f"body_of_{name}")

        if nr == 0:  # No sides
            mesh = open_cylinder

        else:  # Sides
            side = Disk(radius=radius,
                        center=(-np.array([length / 2, 0, 0])),
                        normal=(-1, 0, 0),
                        reflection_symmetry=reflection_symmetry,
                        resolution=(nr, ntheta),
                        name=f"side_of_{name}").mesh

            other_side = side.copy(name=f"other_side_of_{name}_mesh")
            other_side.mirror(yOz_Plane)

            if reflection_symmetry:  # Knit the sides into the symmetric representation of the open cylinder
                half_sides = CollectionOfMeshes(
                    (side.half, other_side.half),
                    name="half_sides_of_{name}_mesh")
                half_mesh = CollectionOfMeshes(
                    (open_cylinder.half, half_sides), name="half_{name}_mesh")
                mesh = ReflectionSymmetricMesh(half_mesh,
                                               plane=xOz_Plane,
                                               name=f"{name}_mesh")
            else:
                sides = CollectionOfMeshes(
                    (side, other_side), name="sides_of_cylinder_{name}_mesh")
                mesh = CollectionOfMeshes((open_cylinder, sides),
                                          name=f"{name}_mesh")

        if not reflection_symmetry and not translation_symmetry:
            mesh = mesh.merged()

        mesh.heal_mesh()

        mesh.translate(self.geometric_center)
        mesh.name = f"{name}_mesh"

        FloatingBody.__init__(self, mesh=mesh, name=name)
Ejemplo n.º 8
0
 def symmetrized(self, plane):
     from capytaine.meshes.symmetric import ReflectionSymmetricMesh
     half = self.clipped(plane, name=f"{self.name}_half")
     return ReflectionSymmetricMesh(half,
                                    plane=plane,
                                    name=f"symmetrized_of_{self.name}")
Ejemplo n.º 9
0
def load_HST(filename, name=None):
    """Loads HYDROSTAR (Bureau Veritas (c)) mesh files.

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

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

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

    _check_file(filename)

    with open(filename, 'r') as f:
        lines = f.readlines()

    optional_keywords = ['PROJECT', 'SYMMETRY']
    not_implemented_optional_keywords = ['USER', 'REFLENGTH', 'GRAVITY', 'RHO', 'NBBODY']

    vertices = []
    faces = []
    optional_data = {kw: None for kw in optional_keywords}
    current_context = None
    ignored_lines = []

    for i_line, line in enumerate(lines):
        line = line.lstrip()

        if line == '':
            continue

        elif line.startswith("COORDINATES"):
            current_context = 'vertices'

        elif current_context == 'vertices' and line.startswith("ENDCOORDINATES"):
            current_context = None

        elif line.startswith("PANEL"):
            panels_type = int(line[10:])
            current_context = ('panels', panels_type)

        elif (current_context == ('panels', 0) or current_context == ('panels', 1)) and line.startswith("ENDPANEL"):
            current_context = None

        elif current_context == 'vertices':  # parse vertex coordinates
            numbers = line.split()
            if len(numbers) == 4:
                i_vertex, x, y, z = numbers
                if int(i_vertex) != len(vertices) + 1:
                    raise ValueError(
                        f"HST mesh reader expected the next vertex to be indexed as {len(vertices)+1}, "
                        f"but it was actually indexed as {i_vertex} (line {i_line+1} of {filename}).")
            elif len(numbers) == 3:
                x, y, z = numbers
            vertices.append([x, y, z])

        elif current_context == ('panels', 0):  # parse face definition (no index given)
            numbers = line.split()
            if len(numbers) == 3:
                v1, v2, v3 = numbers
                v4 = v3
            elif len(numbers) == 4:
                v1, v2, v3, v4 = numbers
            faces.append([v1, v2, v3, v4])

        elif current_context == ('panels', 1):  # parse face definition
            numbers = line.split()
            if len(numbers) == 4:
                i_face, v1, v2, v3 = numbers
                v4 = v3
            elif len(numbers) == 5:
                i_face, v1, v2, v3, v4 = numbers

            if int(i_face) != len(faces) + 1:
                ii = len(faces) + 1
                raise ValueError(f"HST mesh reader expected the next face to be indexed {ii},\n"
                                 f"but it was actually indexed with {i_face} (line {i_line+1} of file {filename}).")
            faces.append([v1, v2, v3, v4])

        elif line.startswith("ENDFILE"):
            break

        else:
            for keyword in optional_data:
                if line.startswith(keyword):
                    optional_data[keyword] = line[len(keyword)+1:].lstrip(':').strip()
                    break
            else:
                ignored_lines.append((i_line+1, line))

    if len(ignored_lines) > 0:
        formatted_ignored_lines = ["{: 4} | {}".format(i, line.strip('\n')) for (i, line) in ignored_lines]
        LOG.warning(f"HST mesh reader ignored the following lines from file {filename}:\n" + "\n".join(formatted_ignored_lines))

    vertices = np.array(vertices, dtype=float)
    faces = np.array(faces, dtype=int) - 1

    if name is None: name = optional_data['PROJECT']

    if optional_data['SYMMETRY'] == '1':
        return ReflectionSymmetricMesh(Mesh(vertices, faces, f"half_of_{name}"), xOz_Plane, name)
    elif optional_data['SYMMETRY'] == '2':
        return ReflectionSymmetricMesh(ReflectionSymmetricMesh(Mesh(vertices, faces, f"quarter_of_{name}"), yOz_Plane, f"half_of_{name}"), xOz_Plane, name)
    else:
        return Mesh(vertices, faces, name)