Stability Tutorial#

This tutorial covers GZ curve calculations for intact stability analysis.

Introduction#

The GZ (righting arm) curve shows how a vessel’s stability changes with heel angle. Positive GZ values indicate the vessel will return to upright.

Basic GZ Calculation#

from navaltoolbox import Hull, Vessel, StabilityCalculator

# Load hull
hull = Hull("dtmb5415.stl")
vessel = Vessel(hull)

# Create stability calculator
calc = StabilityCalculator(vessel, water_density=1025.0)

# Define loading condition
# Note: This is the vessel mass EXCLUDING dynamic tank fluids.
# The calculator will add the mass of any active tanks to this value.
displacement = 8635000  # kg (8635 tonnes)
cog = (71.67, 0.0, 7.555)  # LCG, TCG, VCG in meters (Base/Lightship COG)

# Heel angles to calculate
heels = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60]

# Calculate GZ curve
curve = calc.calculate_gz_curve(displacement, cog, heels)

# Print results
print("Heel (°)   GZ (m)")
print("-" * 20)
for heel, gz in zip(curve.heels(), curve.values()):
    print(f"{heel:6.1f}    {gz:+.3f}")

Analyzing the Curve#

Extract key stability metrics:

# Get GZ values
heels = curve.heels()
gz_values = curve.values()

# Find maximum GZ
max_gz = max(gz_values)
max_gz_idx = gz_values.index(max_gz)
max_gz_heel = heels[max_gz_idx]

print(f"Maximum GZ: {max_gz:.3f}m at {max_gz_heel:.1f}°")

# Check positive range
positive_range = [h for h, gz in zip(heels, gz_values) if gz > 0]
print(f"Positive GZ range: 0° to {max(positive_range):.0f}°")

# Initial GM (from slope at 0°)
# GZ ≈ GM × sin(φ) for small angles
if len(gz_values) > 1 and heels[1] > 0:
    gm_approx = gz_values[1] / math.sin(math.radians(heels[1]))
    print(f"Approximate GM: {gm_approx:.2f}m")

Effect of VCG#

VCG (vertical center of gravity) significantly affects stability:

# Compare different VCG values
vcg_values = [6.5, 7.0, 7.5, 8.0, 8.5]

print("VCG (m)    Max GZ (m)    Max GZ Angle")
print("-" * 45)

for vcg in vcg_values:
    cog = (71.67, 0.0, vcg)
    curve = calc.calculate_gz_curve(displacement, cog, [0, 10, 20, 30, 40, 50])

    gz_vals = curve.values()
    max_gz = max(gz_vals)
    max_idx = gz_vals.index(max_gz)

    print(f"{vcg:6.1f}      {max_gz:.3f}        {curve.heels()[max_idx]:.0f}°")

DTMB 5415 Reference Values#

NavalToolbox has been validated against reference data from Ariffin (2017).

Heel

Reference

NavalToolbox

10°

0.339 m

0.333 m

20°

0.674 m

0.669 m

30°

0.993 m

0.982 m

40°

1.077 m

1.052 m

Maximum error: 2.5cm

Plotting Results#

Visualize the GZ curve using matplotlib:

import matplotlib.pyplot as plt

heels = curve.heels()
gz_values = curve.values()

plt.figure(figsize=(10, 6))
plt.plot(heels, gz_values, 'b-o', linewidth=2, markersize=6)
plt.axhline(y=0, color='k', linestyle='-', linewidth=0.5)
plt.xlabel('Heel Angle (degrees)')
plt.ylabel('GZ (m)')
plt.title('Stability Curve (GZ)')
plt.grid(True, alpha=0.3)
plt.xlim(0, max(heels))
plt.show()

Including Tanks#

Free surface effects reduce effective GM:

from navaltoolbox import Tank

# Add a fuel tank
fuel_tank = Tank.from_box(
    "Fuel Tank",
    x_min=50, x_max=70,
    y_min=-5, y_max=5,
    z_min=0, z_max=4,
    fluid_density=850.0
)
fuel_tank.fill_percent = 50  # Partial fill = free surface

vessel.add_tank(fuel_tank)

# Free surface correction
fsm = fuel_tank.free_surface_moment_t
fs_correction = (fsm * fuel_tank.fluid_mass / fuel_tank.fill_volume) / displacement

print(f"Free surface moment: {fsm:.1f} m⁴")
print(f"GM reduction (virtual VCG rise): {fs_correction:.3f}m")

print(f"GM reduction (virtual VCG rise): {fs_correction:.3f}m")

# Note: Both HydrostaticsCalculator and StabilityCalculator apply this
# correction automatically if tanks are present in the vessel.
# The GZ curve computed above ALREADY includes this reduction.
# No manual adjustment of VCG is required.