examples.BuoyantBody
Floating spar-buoy platform: a rigid body with buoyancy and hydrodynamic forces from the surrounding water.
The hull is a vertical cylinder (spar) of length length_spar and radius radius_spar, aligned with the local y-axis of frame_a, which sits at the geometric center of the spar. An internal Body carries the mass and inertia properties; the center of mass is typically placed below the frame origin (ballast) so that buoyancy above and weight below produce a restoring moment in roll and pitch.
The water surface is a monochromatic traveling wave of amplitude wave_amplitude and angular frequency wave_omega, propagating along the world x-axis with the deep-water dispersion relation. The buoyancy force equals the weight of the displaced water column, computed from the submerged length of the (possibly tilted) spar below the local wave elevation, and acts at the center of the submerged section. Linear hydrodynamic drag pulls the body toward the local wave orbital velocity, which both damps the platform motion and excites surge and pitch as waves pass by. A linear rotational drag damps angular motion.
The body is a free-floating 6-DOF root with quaternion orientation state: do not connect frame_a to the world through any joint; moor it with force elements or Cables instead.
Model assumptions and validity limits:
Hydrostatics use the submerged length along the spar axis divided by the vertical component of the spar axis; the model is invalid for tilt angles approaching 90 degrees (the axis projection is guarded below 0.1).
No added mass, no wave diffraction/radiation, linear drag only.
The wave field is not affected by the body.
This component extends from MultibodyComponents.Renderable
Usage
MultibodyComponents.examples.BuoyantBody(render=true, color=[0.95, 0.6, 0.1, 1], specular_coefficient=1.5, m=2e4, r_cm=[0, -3, 0], I_11=2e5, I_22=1e4, I_33=2e5, radius_spar=1, length_spar=10, rho_water=1000, d_translation=2e4, d_rotation=2e5, wave_amplitude=0.5, wave_omega=1.05, r_0_start=[0, -1.4, 0], A_c=π * radius_spar ^ 2, wave_k=wave_omega ^ 2 / 9.80665)
Parameters:
| Name | Description | Units | Default value |
|---|---|---|---|
point_gravity | Whether to use a point-gravity field, see World | – | false |
initialize_orientation | Specify identity initial orientation; set to false to let initialization solve for the orientation | – | true |
render | – | true | |
color | – | [0.95, 0.6, 0.1, 1] | |
specular_coefficient | – | 1.5 | |
m | Mass of the platform including ballast | kg | 2e4 |
r_cm | Center of mass relative to frame_a, resolved in frame_a; place below the origin for ballast stability | m | [0, -3, 0] |
I_11 | Moment of inertia about the local x-axis | kg.m2 | 2e5 |
I_22 | Moment of inertia about the local y-axis (spar axis) | kg.m2 | 1e4 |
I_33 | Moment of inertia about the local z-axis | kg.m2 | 2e5 |
radius_spar | Radius of the spar cylinder | m | 1 |
length_spar | Length of the spar cylinder along the local y-axis | m | 10 |
rho_water | Density of the water | – | 1000 |
d_translation | Linear translational drag coefficient toward the local water velocity | – | 2e4 |
d_rotation | Linear rotational drag coefficient | – | 2e5 |
wave_amplitude | Amplitude of the traveling surface wave | m | 0.5 |
wave_omega | Angular frequency of the traveling surface wave | – | 1.05 |
r_0_start | Initial position of frame_a in the world frame | m | [0, -1.4, 0] |
Connectors
frame_a- Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or severalFrame
connectors that can be connected together (Frame3D)
Variables
| Name | Description | Units |
|---|---|---|
h_local | Local wave elevation at the platform x-position | – |
v_water | Wave orbital velocity at the platform, resolved in the world frame | – |
e_axis_0 | Spar axis direction resolved in the world frame | – |
r_bot | Position of the spar bottom end in the world frame | – |
L_sub | Submerged length of the spar, measured along the spar axis | – |
r_cb | Center of buoyancy (centroid of the submerged section) in the world frame | – |
f_hydro | Total hydrodynamic force resolved in the world frame | – |
tau_hydro | Total hydrodynamic torque about frame_a, resolved in the world frame | – |
Behavior
Source
"""
Floating spar-buoy platform: a rigid body with buoyancy and hydrodynamic
forces from the surrounding water.
The hull is a vertical cylinder (spar) of length `length_spar` and radius
`radius_spar`, aligned with the local y-axis of `frame_a`, which sits at the
geometric center of the spar. An internal `Body` carries the mass and inertia
properties; the center of mass is typically placed below the frame origin
(ballast) so that buoyancy above and weight below produce a restoring moment
in roll and pitch.
The water surface is a monochromatic traveling wave of amplitude
`wave_amplitude` and angular frequency `wave_omega`, propagating along the
world x-axis with the deep-water dispersion relation. The buoyancy force
equals the weight of the displaced water column, computed from the submerged
length of the (possibly tilted) spar below the local wave elevation, and acts
at the center of the submerged section. Linear hydrodynamic drag pulls the
body toward the local wave orbital velocity, which both damps the platform
motion and excites surge and pitch as waves pass by. A linear rotational drag
damps angular motion.
The body is a free-floating 6-DOF root with quaternion orientation state:
do not connect `frame_a` to the world through any joint; moor it with force
elements or `Cable`s instead.
Model assumptions and validity limits:
- Hydrostatics use the submerged length along the spar axis divided by the
vertical component of the spar axis; the model is invalid for tilt angles
approaching 90 degrees (the axis projection is guarded below 0.1).
- No added mass, no wave diffraction/radiation, linear drag only.
- The wave field is not affected by the body.
"""
component BuoyantBody
extends MultibodyComponents.Renderable(color = [0.95, 0.6, 0.1, 1])
frame_a = Frame3D()
body = MultibodyComponents.Body(m = m, r_cm = r_cm, I_11 = I_11, I_22 = I_22, I_33 = I_33, orientation_state = OrientationState.Quaternion(), statePriority = 100, linearStatePriority = 100, render = false, r_0(initial = r_0_start), v_0(initial = [0, 0, 0]), initialize_orientation = initialize_orientation)
buoy_force = MultibodyComponents.WorldForce(resolve_in_frame = ResolveInFrame.World(), render = false)
buoy_torque = MultibodyComponents.WorldTorque(resolve_in_frame = ResolveInFrame.World())
spar_vis = MultibodyComponents.CylinderVisualizer(color = color, render = render, length = length_spar, radius = radius_spar, length_direction = [0, 1, 0], r_shape = [0, -length_spar / 2, 0])
"Whether to use a point-gravity field, see `World`"
structural parameter point_gravity::Boolean = false
"Specify identity initial orientation; set to false to let initialization solve for the orientation"
structural parameter initialize_orientation::Boolean = true
"Mass of the platform including ballast"
parameter m::Mass = 2e4
"Center of mass relative to frame_a, resolved in frame_a; place below the origin for ballast stability"
parameter r_cm::Length[3] = [0, -3, 0]
"Moment of inertia about the local x-axis"
parameter I_11::Inertia = 2e5
"Moment of inertia about the local y-axis (spar axis)"
parameter I_22::Inertia = 1e4
"Moment of inertia about the local z-axis"
parameter I_33::Inertia = 2e5
"Radius of the spar cylinder"
parameter radius_spar::Length = 1
"Length of the spar cylinder along the local y-axis"
parameter length_spar::Length = 10
"Density of the water"
parameter rho_water::Real = 1000
"Linear translational drag coefficient toward the local water velocity"
parameter d_translation::Real = 2e4
"Linear rotational drag coefficient"
parameter d_rotation::Real = 2e5
"Amplitude of the traveling surface wave"
parameter wave_amplitude::Length = 0.5
"Angular frequency of the traveling surface wave"
parameter wave_omega::Real = 1.05
"Initial position of frame_a in the world frame"
parameter r_0_start::Length[3] = [0, -1.4, 0]
"Cross-section area of the spar"
final parameter A_c::Real = π * radius_spar ^ 2
"Wave number from the deep-water dispersion relation"
final parameter wave_k::Real = wave_omega ^ 2 / 9.80665
"Local wave elevation at the platform x-position"
variable h_local::Real
"Wave orbital velocity at the platform, resolved in the world frame"
variable v_water::Real[3]
"Spar axis direction resolved in the world frame"
variable e_axis_0::Real[3]
"Position of the spar bottom end in the world frame"
variable r_bot::Real[3]
"Submerged length of the spar, measured along the spar axis"
variable L_sub::Real
"Center of buoyancy (centroid of the submerged section) in the world frame"
variable r_cb::Real[3]
"Total hydrodynamic force resolved in the world frame"
variable f_hydro::Real[3]
"Total hydrodynamic torque about frame_a, resolved in the world frame"
variable tau_hydro::Real[3]
relations
connect(frame_a, body.frame_a, buoy_force.frame_b, buoy_torque.frame_b, spar_vis.frame_a)
if !initialize_orientation
guess body.Q_hat = [1, 0, 0, 0]
end
h_local = wave_amplitude * sin(wave_omega * time - wave_k * frame_a.r_0[1])
v_water = [wave_amplitude * wave_omega * cos(wave_omega * time - wave_k * frame_a.r_0[1]), 0, 0]
e_axis_0 = MultibodyComponents.resolve1(frame_a.R, [0, 1, 0])
r_bot = frame_a.r_0 - (length_spar / 2) * e_axis_0
# Distance from the spar bottom to the water surface along the spar axis,
# clamped to the physical range; the axis projection is guarded away from
# zero to avoid a singularity at horizontal spar orientations
L_sub = min(max((h_local - r_bot[2]) / max(e_axis_0[2], 0.1), 0), length_spar)
r_cb = r_bot + (L_sub / 2) * e_axis_0
f_hydro = -rho_water * A_c * L_sub * MultibodyComponents.gravity_acceleration(r_cb, point_gravity) + d_translation * (v_water - body.v_0)
tau_hydro = MultibodyComponents.cross(r_cb - frame_a.r_0, f_hydro) - d_rotation * MultibodyComponents.resolve1(frame_a.R, body.w_a)
buoy_force.force_x = f_hydro[1]
buoy_force.force_y = f_hydro[2]
buoy_force.force_z = f_hydro[3]
buoy_torque.torque_x = tau_hydro[1]
buoy_torque.torque_y = tau_hydro[2]
buoy_torque.torque_z = tau_hydro[3]
metadata {
"Dyad": {
"icons": {"default": "dyad://MultibodyComponents/BuoyantBody.svg"},
"labels": [
{
"label": "$(instance)",
"x": 500,
"y": 150,
"rot": 0,
"attrs": {"font-size": "160"}
}
]
}
}
endFlattened Source
"""
Floating spar-buoy platform: a rigid body with buoyancy and hydrodynamic
forces from the surrounding water.
The hull is a vertical cylinder (spar) of length `length_spar` and radius
`radius_spar`, aligned with the local y-axis of `frame_a`, which sits at the
geometric center of the spar. An internal `Body` carries the mass and inertia
properties; the center of mass is typically placed below the frame origin
(ballast) so that buoyancy above and weight below produce a restoring moment
in roll and pitch.
The water surface is a monochromatic traveling wave of amplitude
`wave_amplitude` and angular frequency `wave_omega`, propagating along the
world x-axis with the deep-water dispersion relation. The buoyancy force
equals the weight of the displaced water column, computed from the submerged
length of the (possibly tilted) spar below the local wave elevation, and acts
at the center of the submerged section. Linear hydrodynamic drag pulls the
body toward the local wave orbital velocity, which both damps the platform
motion and excites surge and pitch as waves pass by. A linear rotational drag
damps angular motion.
The body is a free-floating 6-DOF root with quaternion orientation state:
do not connect `frame_a` to the world through any joint; moor it with force
elements or `Cable`s instead.
Model assumptions and validity limits:
- Hydrostatics use the submerged length along the spar axis divided by the
vertical component of the spar axis; the model is invalid for tilt angles
approaching 90 degrees (the axis projection is guarded below 0.1).
- No added mass, no wave diffraction/radiation, linear drag only.
- The wave field is not affected by the body.
"""
component BuoyantBody
parameter render::Boolean = true
parameter color::Real[4] = [0.5, 0.5, 0.5, 1.0]
parameter specular_coefficient::Real = 1.5
frame_a = Frame3D()
body = MultibodyComponents.Body(m = m, r_cm = r_cm, I_11 = I_11, I_22 = I_22, I_33 = I_33, orientation_state = OrientationState.Quaternion(), statePriority = 100, linearStatePriority = 100, render = false, r_0(initial = r_0_start), v_0(initial = [0, 0, 0]), initialize_orientation = initialize_orientation)
buoy_force = MultibodyComponents.WorldForce(resolve_in_frame = ResolveInFrame.World(), render = false)
buoy_torque = MultibodyComponents.WorldTorque(resolve_in_frame = ResolveInFrame.World())
spar_vis = MultibodyComponents.CylinderVisualizer(color = color, render = render, length = length_spar, radius = radius_spar, length_direction = [0, 1, 0], r_shape = [0, -length_spar / 2, 0])
"Whether to use a point-gravity field, see `World`"
structural parameter point_gravity::Boolean = false
"Specify identity initial orientation; set to false to let initialization solve for the orientation"
structural parameter initialize_orientation::Boolean = true
"Mass of the platform including ballast"
parameter m::Mass = 2e4
"Center of mass relative to frame_a, resolved in frame_a; place below the origin for ballast stability"
parameter r_cm::Length[3] = [0, -3, 0]
"Moment of inertia about the local x-axis"
parameter I_11::Inertia = 2e5
"Moment of inertia about the local y-axis (spar axis)"
parameter I_22::Inertia = 1e4
"Moment of inertia about the local z-axis"
parameter I_33::Inertia = 2e5
"Radius of the spar cylinder"
parameter radius_spar::Length = 1
"Length of the spar cylinder along the local y-axis"
parameter length_spar::Length = 10
"Density of the water"
parameter rho_water::Real = 1000
"Linear translational drag coefficient toward the local water velocity"
parameter d_translation::Real = 2e4
"Linear rotational drag coefficient"
parameter d_rotation::Real = 2e5
"Amplitude of the traveling surface wave"
parameter wave_amplitude::Length = 0.5
"Angular frequency of the traveling surface wave"
parameter wave_omega::Real = 1.05
"Initial position of frame_a in the world frame"
parameter r_0_start::Length[3] = [0, -1.4, 0]
"Cross-section area of the spar"
final parameter A_c::Real = π * radius_spar ^ 2
"Wave number from the deep-water dispersion relation"
final parameter wave_k::Real = wave_omega ^ 2 / 9.80665
"Local wave elevation at the platform x-position"
variable h_local::Real
"Wave orbital velocity at the platform, resolved in the world frame"
variable v_water::Real[3]
"Spar axis direction resolved in the world frame"
variable e_axis_0::Real[3]
"Position of the spar bottom end in the world frame"
variable r_bot::Real[3]
"Submerged length of the spar, measured along the spar axis"
variable L_sub::Real
"Center of buoyancy (centroid of the submerged section) in the world frame"
variable r_cb::Real[3]
"Total hydrodynamic force resolved in the world frame"
variable f_hydro::Real[3]
"Total hydrodynamic torque about frame_a, resolved in the world frame"
variable tau_hydro::Real[3]
relations
connect(frame_a, body.frame_a, buoy_force.frame_b, buoy_torque.frame_b, spar_vis.frame_a)
if !initialize_orientation
guess body.Q_hat = [1, 0, 0, 0]
end
h_local = wave_amplitude * sin(wave_omega * time - wave_k * frame_a.r_0[1])
v_water = [wave_amplitude * wave_omega * cos(wave_omega * time - wave_k * frame_a.r_0[1]), 0, 0]
e_axis_0 = MultibodyComponents.resolve1(frame_a.R, [0, 1, 0])
r_bot = frame_a.r_0 - (length_spar / 2) * e_axis_0
# Distance from the spar bottom to the water surface along the spar axis,
# clamped to the physical range; the axis projection is guarded away from
# zero to avoid a singularity at horizontal spar orientations
L_sub = min(max((h_local - r_bot[2]) / max(e_axis_0[2], 0.1), 0), length_spar)
r_cb = r_bot + (L_sub / 2) * e_axis_0
f_hydro = -rho_water * A_c * L_sub * MultibodyComponents.gravity_acceleration(r_cb, point_gravity) + d_translation * (v_water - body.v_0)
tau_hydro = MultibodyComponents.cross(r_cb - frame_a.r_0, f_hydro) - d_rotation * MultibodyComponents.resolve1(frame_a.R, body.w_a)
buoy_force.force_x = f_hydro[1]
buoy_force.force_y = f_hydro[2]
buoy_force.force_z = f_hydro[3]
buoy_torque.torque_x = tau_hydro[1]
buoy_torque.torque_y = tau_hydro[2]
buoy_torque.torque_z = tau_hydro[3]
metadata {
"Dyad": {
"icons": {"default": "dyad://MultibodyComponents/BuoyantBody.svg"},
"labels": [
{
"label": "$(instance)",
"x": 500,
"y": 150,
"rot": 0,
"attrs": {"font-size": "160"}
}
]
}
}
endTest Cases
No test cases defined.
Related
Examples
Experiments
Analyses