========================== Meshes and floating bodies ========================== .. contents:: Content Importing a mesh with Meshmagick -------------------------------- To load an existing mesh file, use the following syntax:: import capytaine as cpt mesh = cpt.load_mesh('path/to/mesh.dat', file_format='nemoh') body = cpt.FloatingBody(mesh=mesh) The above example uses `Nemoh's mesh format`_. .. _`Nemoh's mesh format`: https://lheea.ec-nantes.fr/logiciels-et-brevets/nemoh-mesh-192932.kjsp Thanks to Meshmagick, numerous other mesh format can be imported. The file format can be given with the :code:`file_format` optional argument. If no format is given, the code will try to infer it from the file extension:: mesh = cpt.load_mesh('path/to/mesh.msh') # gmsh file The formats currently supported in reading are listed in the following table (adapted from the documentation of Meshmagick). +-----------+-----------------+----------------------+-----------------+ | File | Software | Keywords | Extra features | | extension | | | | +===========+=================+======================+=================+ | .mar | NEMOH [#f1]_ | nemoh, mar | Symmetries | +-----------+-----------------+----------------------+-----------------+ | .nem | NEMOH [#f1]_ | nemoh_mesh, nem | | +-----------+-----------------+----------------------+-----------------+ | .gdf | WAMIT [#f2]_ | wamit, gdf | | +-----------+-----------------+----------------------+-----------------+ | .inp | DIODORE [#f3]_ | diodore-inp, inp | | +-----------+-----------------+----------------------+-----------------+ | .DAT | DIODORE [#f3]_ | diodore-dat | | +-----------+-----------------+----------------------+-----------------+ | .pnl | HAMS | pnl, hams | Symmetries | +-----------+-----------------+----------------------+-----------------+ | .hst | HYDROSTAR [#f4]_| hydrostar, hst | Symmetries | +-----------+-----------------+----------------------+-----------------+ | .nat | - | natural, nat | | +-----------+-----------------+----------------------+-----------------+ | .msh | GMSH 2 [#f5]_ | gmsh, msh | | +-----------+-----------------+----------------------+-----------------+ | .rad | RADIOSS | rad, radioss | | +-----------+-----------------+----------------------+-----------------+ | .stl | - | stl | | +-----------+-----------------+----------------------+-----------------+ | .vtu | PARAVIEW [#f6]_ | vtu | | +-----------+-----------------+----------------------+-----------------+ | .vtp | PARAVIEW [#f6]_ | vtp | | +-----------+-----------------+----------------------+-----------------+ | .vtk | PARAVIEW [#f6]_ | paraview-legacy, vtk | | +-----------+-----------------+----------------------+-----------------+ | .tec | TECPLOT [#f7]_ | tecplot, tec | | +-----------+-----------------+----------------------+-----------------+ | .med | SALOME [#f8]_ | med, salome | | +-----------+-----------------+----------------------+-----------------+ .. [#f1] NEMOH is an open source BEM Software for seakeeping developed at Ecole Centrale de Nantes (LHEEA) .. [#f2] WAMIT is a BEM Software for seakeeping developed by WAMIT, Inc. .. [#f3] DIODORE is a BEM Software for seakeeping developed by PRINCIPIA .. [#f4] HYDROSTAR is a BEM Software for seakeeping developed by BUREAU VERITAS .. [#f5] GMSH is an open source meshing software developed by C. Geuzaine and J.-F. Remacle. Version 4 of the file format is not supported at the moment. .. [#f6] PARAVIEW is an open source visualization software developed by Kitware .. [#f7] TECPLOT is a visualization software developed by Tecplot .. [#f8] SALOME-MECA is an open source software for computational mechanics developed by EDF-R&D Not all metadata is taken into account when reading the mesh file. For instance, the body symmetry is taken into account only for the `.mar` and `.hst` file formats. Feel free to open an issue on Github to suggest improvements. Importing a mesh with Meshio ---------------------------- Mesh can also be imported using the `meshio `_ library. Unlike the Meshmagick mesh readers mentioned above, this library is not packaged with Capytaine and need to be installed independently:: pip install meshio A `meshio` mesh object can be used directly to initialize a :code:`FloatingBody`:: import meshio mesh = meshio.read("myfile.stl") body = cpt.FloatingBody(mesh=mesh, dofs=...) Alternatively, the `meshio` mesh object can converted to Capytaine's mesh format with the :func:`~capytaine.io.meshio.load_from_meshio` function:: from capytaine.io.meshio import load_from_meshio cpt_mesh = cpt.load_from_meshio(mesh, name="My floating body") This features allows to use `pygmsh `_ to generate the mesh, since this library returns mesh in the same format as meshio. Below is an example of a mesh generation with `pygmsh` (which also needs to be installed independently):: import pygmsh offset = 1e-2 T1 = 0.16 T2 = 0.37 r1 = 0.88 r2 = 0.35 with pygmsh.occ.Geometry() as geom: cyl = geom.add_cylinder([0, 0, 0], [0, 0, -T1], r1) cone = geom.add_cone([0, 0, -T1], [0, 0, -T2], r1, r2) geom.translate(cyl, [0, 0, offset]) geom.translate(cone, [0, 0, offset]) geom.boolean_union([cyl, cone]) gmsh_mesh = geom.generate_mesh(dim=2) body = cpt.FloatingBody(gmsh_mesh) Display and animation --------------------- Use the :code:`show` method to display the mesh in 3D using VTK (if installed):: mesh.show() Once a :code:`FloatingBody` with dofs has been defineds, the :code:`animate` method can be used to visualize a given motion of the body:: anim = body.animate(motion={"Heave": 0.1, "Surge": 0.1j}, loop_duration=1.0) anim.run() The above example will present an interactive animation of the linear combination of heave and surge. Jupyter notebooks can also include a (non-interactive) video of the animation:: anim.embed_in_notebook(camera_position=(-1.0, -1.0, 1.0), resolution=(400, 300)) Geometric transformations ------------------------- Several functions are available to transform existing bodies and meshes. Most transformation methods exist in two versions: * one, named as a infinitive verb (`translate`, `rotate`, ...), is an in-place transformation; * the other, named as a past participle (`translated`, `rotated`, ...), is the same transformation but returning a new object. In most cases, performance is not significant and the latter method should be preferred since it makes code slightly easier to debug. Below is a list of most of the available methods. All of them can be applied to both meshes or to floating bodies, in which case the degrees of freedom will also be transformed:: # TRANSLATIONS mesh.translated_x(10.0) mesh.translated_y(10.0) mesh.translated_z(10.0) mesh.translated([10.0, 5.0, 2.0]) # Translation such that point_a would become equal to point_b mesh.translated_point_to_point(point_a=[5, 6, 7], point_b=[4, 3, 2]) # ROTATIONS mesh.rotated_x(3.14/5) # Rotation of pi/5 around the Ox axis mesh.rotated_y(3.14/5) # Rotation of pi/5 around the Oy axis mesh.rotated_z(3.14/5) # Rotation of pi/5 around the Oz axis # Rotation of pi/5 around an arbitrary axis. from capytaine import Axis my_axis = Axis(vector=[1, 1, 1], point=[3, 4, 5]) mesh.rotated(axis=my_axis, angle=3.14/5) # Rotation around a point such that vec1 would become equal to vec2 mesh.rotated_around_center_to_align_vector( center=(0, 0, 0), vec1=(1, 4, 7), vec2=(9, 2, 1) ) # REFLECTIONS from capytaine import Plane mesh.mirrored(Plane(normal=[1, 2, 1], point=[0, 4, 5])) All the above method can also be applied to :class:`~capytaine.meshes.geometry.Plane` and :class:`~capytaine.meshes.geometry.Axis` objects. Joining ------- Meshes and bodies can be merged together with the :code:`+` operator:: both_bodies = body_1 + body_2 The :code:`+` operation is associative, that is :code:`(body_1 + body_2) + body_3` is equivalent to :code:`body_1 + (body_2 + body_3)`. It is also commutative, up to some internal details which are usually not relevant. However for more than two bodies, it is recommended to use instead the :code:`join_bodies` method:: all_bodies = body_1.join_bodies(body_2, body_3, body_4) When two floating bodies with dofs are merged, the resulting body inherits from the dofs of the individual bodies with the new name :code:`body_name__dof_name`. For instance:: body_1.add_translation_dof(name="Heave") body_2.add_translation_dof(name="Heave") both_bodies = body_1 + body_2 assert 'body_1__Heave' in both_bodies.dofs assert 'body_2__Heave' in both_bodies.dofs Clipping -------- Meshes and bodies can be clipped with the :code:`clip` and :code:`clipped` methods. As for the geometric transformations, the former is in-place whereas the second returns a new object. These methods take a :class:`~capytaine.meshes.geometry.Plane` object as argument. The plane is defined by a point belonging to it and a normal vector:: xOy_Plane = Plane(point=(0, 0, 0), normal=(0, 0, 1)) clipped_body = body.clipped(xOy_Plane) Beware that the orientation of the normal vector of the :code:`Plane` will determine which part of the mesh will be returned:: higher_part = body.clipped(Plane(point=(0, 0, 0), normal=(0, 0, -1))) lower_part = body.clipped(Plane(point=(0, 0, 0), normal=(0, 0, 1))) # body = lower_part + higher_part The method :code:`immersed_part` will clip the body with respect to two horizontal planes at :math:`z=0` and :math:`z=-h`:: clipped_body = body.immersed_part(water_depth=10) Center of mass and rotation dofs -------------------------------- The center of gravity of the body can be defined by assigning a vector of 3 elements to the :code:`center_of_mass` attribute:: body.center_of_mass = np.array([0.0, -1.0, -1.0]) The center of mass is used in some hydrostatics computation. It is not required for hydrodynamical coefficients, except for the definition of the rotation degrees of freedom. When defining a rotation dof, the code looks for attributes called :code:`rotation_center`, :code:`center_of_mass` or * :code:`geometric_center` (in that order), and use them to define the rotation axis. If none of them are define, the rotation is defined around the origin of the domain :math:`(0, 0, 0)`. Defining an integration quadrature ---------------------------------- During the resolution of the BEM problem, the Green function has to be integrated on each panel of the mesh. Parts of the Green function (such as the :math:`1/r` Rankine terms) are integrated using an exact analytical expression for the integral. Other parts of the Green function rely on numerical integration. By default, this numerical integration is done by taking the value at the center of the panel and multiplying by its area. For a more accurate intagration, an higher order quadrature can be defined. To define a quadrature scheme for a mesh, run the following command:: body.mesh.compute_quadrature(method="Gauss-Legendre 2") The quadrature data can then be accessed at:: body.mesh.quadrature_points and will be used automatically when needed. .. warning:: Transformations of the mesh (merging, clipping, ...) may reset the quadrature. Compute it only on your final mesh. .. warning:: Quadratures schemes have been designed with quadrilateral panels. They work on triangular panels, but might not be as optimal then. Alternatively, the :meth:`~capytaine.meshes.quadratures.compute_quadrature` method also accepts methods from the `Quadpy` package:: import quadpy body.mesh.compute_quadrature(method=quadpy.c2.get_good_scheme(8))