=============
Floating body
=============

As described in the :doc:`tutorial`, a floating body is defined as a mesh with degrees of freedom and optionally other properties, such as a mass and a center of mass.

Initialization
--------------

The floating body is set up by initializing the
:class:`~capytaine.bodies.bodies.FloatingBody` class::

    body = cpt.FloatingBody(mesh=mesh, dofs={})

The above example creates a new body without degrees of freedom.

Mesh
~~~~

The ``mesh`` can be a :class:`~capytaine.meshes.meshes.Mesh` object, or any of
the variants defined in Capytaine, such as a
:class:`~capytaine.meshes.symmetric_meshes.ReflectionSymmetricMesh`.

.. _set-lid-mesh-in-body:

Lid mesh
~~~~~~~~

For irregular frequencies removal, a second mesh can be provided when defining
the body. It is meant to be a mesh of a lid of the part of the free surface
that is inside the body. The lid can either on the free surface or slightly
below. This mesh is ignored for many computations (such as hydrostatics) and is
only used when solving a BEM problem.

It is set as in the following example::

    body = cpt.FloatingBody(mesh=mesh, lid_mesh=lid_mesh)

where ``lid_mesh`` is a mesh object which can loaded in the same way as the
main mesh (see :ref:`loading-a-mesh` or using the specific methods of
:ref:`lid-generation`.

Once a lid mesh has been defined, it is automatically used for irregular
frequencies removal without any other action from the user.
The lid does not need neither to cover the whole interior free surface, nor
to be connected with the hull mesh. (The lid automatically generated by
:meth:`~capytaine.meshes.meshes.Mesh.generate_lid` typically does not.)
Nonetheless, the more interior free surface is covered, the more efficiently
the irregular frequencies will be removed.

For irregular frequencies removal, the lid is expected to have normals going
down (towards the fluid, through the body). If the lid appears to be horizontal
with normal going up, Capytaine will switch the direction of its normal
vectors.

When working with symmetric meshes, the ``mesh`` and the ``lid_mesh`` should
have the exact same symmetry. If so, the symmetry is used for the resolution.
Otherwise, the symmetry is discarded and a full resolution is done.

Dofs
~~~~

Degrees of freedoms are stored in a Python dictionary associating the name
of each dof to the description of the corresponding motion or deformation.

For rigid bodies, the motion is encoded in an ad-hoc Python object of class
:class:`~capytaine.bodies.dofs.TranslationDof` or :class:`~capytaine.bodies.dofs.RotationDof`.
It is recommended to initialize them in the following way::

   body = cpt.FloatingBody(
       mesh=mesh,
       dofs=cpt.rigid_body_dofs(rotation_center=(0, 0, -1)),
   )

If no ``rotation_center`` is provided, :math:`(0, 0, 0)` is used as a default.
The standard names used to refer to the rigid body dofs are::

   print(body.dofs.keys())
   # dict_keys(['Surge', 'Sway', 'Heave', 'Roll', 'Pitch', 'Yaw'])

If only some dofs are of interest, you can use the following syntax::

   body = cpt.FloatingBody(
       mesh=mesh,
       dofs=cpt.rigid_body_dofs(only=["Heave"], rotation_center=(0, 0, -1))
   )
   print(body.dofs.keys())
   # dict_keys(['Heave'])

Generalized degrees of freedom can be defined as a Numpy array of shape ``(nb_faces, 3)``.
This array stores the displacement vector at the center of each face of the
mesh::

   body = cpt.FloatingBody(
           mesh=mesh,
           dofs={
               "heave-like": np.array([(0, 0, 1) for x, y, z in mesh.faces_centers]),
               "x-shear": np.array([(np.cos(np.pi*z/2), 0, 0) for x, y, z in mesh.faces_centers])
               },
           )

Defining a rigid-body-dof as a generalized dof (as in the example above for
heave) does not make a difference for first-order hydrodynamics without forward
speed. It makes a difference for the hydrostatic stiffness, when the
generalized dofs are using a approximate formula, whereas exact values can be
returned for rigid body dofs.

For multiple bodies, the dofs of the component bodies should transparently be
defined for the compound body object. See also the section dedicated to
multiple bodies.


Other parameters
~~~~~~~~~~~~~~~~

Besides the mandatory ``mesh`` and ``dofs``, a floating body can also be
defined with a ``mass``, given a floating point number and a
``center_of_mass``, given a three coordinates.
These two arguments are required for :doc:`hydrostatics` but not for
first-order wave-structure interaction.
Their only role then is 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)`.

Finally, as the mesh objects, the floating body can be assigned a name.


Display and animation
---------------------

The methods :meth:`~capytaine.bodies.bodies.FloatingBody.show()` and
:meth:`~capytaine.bodies.bodies.FloatingBody.show_matplotlib()` of meshes can
also be used on ``FloatingBody``.

.. Once a :code:`FloatingBody` with dofs has been defined, the
.. :meth:`~capytaine.bodies.bodies.FloatingBody.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
-------------------------

All the geometric transformation defined on meshes in :doc:`mesh` can also be
applied to ``FloatingBody``. Beside updating the mesh, they also update the
definition of the degrees of freedom and the center of mass (if relevant).
