Tank Modeling Tutorial
This tutorial demonstrates how to model fluid tanks in pynavaltoolbox, including creating different tank types, managing fill levels, and incorporating free surface effects into stability calculations.
Introduction
Tanks are essential for modeling ballast, fuel, and cargo liquids in vessels. pynavaltoolbox provides tools to:
Define tank geometries from files or dimensions
Calculate tank volumes, mass, and center of gravity
Compute free surface moments for stability corrections
Integrate tanks with hydrostatic and stability calculations
Creating Tanks
From Box Dimensions
The simplest way to create a tank is from rectangular dimensions:
from pynavaltoolbox.tanks import Tank
# Create a fuel tank
fuel_tank = Tank.from_box(
x_min=30.0, x_max=45.0, # 15m length
y_min=-4.0, y_max=4.0, # 8m width
z_min=2.0, z_max=8.0, # 6m height
fluid_density=850.0, # Heavy fuel oil (kg/m³)
name="FuelTank_P"
)
print(f"Tank volume: {fuel_tank.total_volume:.1f} m³")
# Output: Tank volume: 720.0 m³
From Hull Intersection
For tanks that follow the ship’s hull shape (like double bottoms):
from pynavaltoolbox import Hull
from pynavaltoolbox.tanks import Tank
# Load hull geometry
hull = Hull("ship_hull.stl")
# Create double-bottom tank
db_tank = Tank.from_box_hull_intersection(
hull,
x_min=40.0, x_max=80.0, # Midship section
y_min=-12.0, y_max=12.0, # Full beam
z_min=0.0, z_max=1.8, # Double bottom height
fluid_density=1025.0, # Seawater ballast
name="DoubleBottom_Center"
)
print(f"Tank volume: {db_tank.total_volume:.1f} m³")
# Volume follows hull's curved bottom
Managing Fill Levels
Fill levels can be set using different units:
tank = Tank.from_box(
x_min=0.0, x_max=10.0,
y_min=-5.0, y_max=5.0,
z_min=0.0, z_max=10.0,
fluid_density=1000.0,
name="TestTank"
)
# Total volume: 1000 m³
# Set by percentage
tank.set_fill_level(75, unit='percent')
print(f"Fill: {tank.fill_percent}% = {tank.fill_volume:.0f} m³")
# Output: Fill: 75.0% = 750 m³
# Set by fraction
tank.set_fill_level(0.5, unit='fraction')
print(f"Fill: {tank.fill_percent}% = {tank.fill_volume:.0f} m³")
# Output: Fill: 50.0% = 500 m³
# Set by volume in cubic meters
tank.set_fill_level(300.0, unit='m³')
print(f"Fill: {tank.fill_percent}% = {tank.fill_volume:.0f} m³")
# Output: Fill: 30.0% = 300 m³
Tank Properties
Each tank provides various properties:
tank.set_fill_level(60, unit='percent')
# Basic properties
print(f"Total capacity: {tank.total_volume:.1f} m³")
print(f"Current fill: {tank.fill_volume:.1f} m³")
print(f"Fluid mass: {tank.fluid_mass:.0f} kg")
# Center of gravity (of the fluid)
cog = tank.center_of_gravity
print(f"CoG: X={cog[0]:.2f}, Y={cog[1]:.2f}, Z={cog[2]:.2f} m")
# Free surface moments (for stability)
print(f"I_transverse: {tank.free_surface_moment_t:.1f} m⁴")
print(f"I_longitudinal: {tank.free_surface_moment_l:.1f} m⁴")
Free Surface Effects
When a tank has a free surface (not completely full or empty), the liquid can shift when the vessel heels, causing a virtual rise in the center of gravity. This is known as the free surface effect.
Understanding the Correction
The free surface correction is calculated as:
GG' = (I × ρ_fluid) / (∇ × ρ_water)
Where: - GG’ = virtual rise of center of gravity (m) - I = second moment of area of the free surface (m⁴) - ρ_fluid = density of the tank fluid (kg/m³) - ∇ = displacement volume of the vessel (m³) - ρ_water = density of seawater (kg/m³)
The corrected GM is:
GM_corrected = GM_dry - GG'
Integration with Vessel
Adding Tanks to a Vessel
from pynavaltoolbox import Vessel, Hull
from pynavaltoolbox.tanks import Tank
# Create vessel with tanks
hull = Hull("ship.stl")
tanks = [
Tank.from_box(
x_min=20.0, x_max=40.0,
y_min=-4.0, y_max=4.0,
z_min=1.0, z_max=5.0,
fluid_density=850.0,
name="Fuel_P"
),
Tank.from_box(
x_min=50.0, x_max=80.0,
y_min=-6.0, y_max=6.0,
z_min=0.0, z_max=2.0,
fluid_density=1025.0,
name="Ballast_Aft"
)
]
# Set fill levels
tanks[0].set_fill_level(60, unit='percent')
tanks[1].set_fill_level(80, unit='percent')
vessel = Vessel(hull, tanks=tanks)
# Get combined tank properties
print(f"Total tanks mass: {vessel.get_total_tanks_mass():.0f} kg")
print(f"Combined CoG: {vessel.get_tanks_center_of_gravity()}")
Hydrostatics with Free Surface Correction
When calculating hydrostatics with tanks, the calculator automatically includes free surface corrections:
from pynavaltoolbox.hydrostatics import HydrostaticsCalculator
calc = HydrostaticsCalculator(vessel)
state = calc.calculate_at_draft(draft=6.0, vcg=7.0)
print(f"GM dry: {state.gmt_dry:.3f} m")
print(f"Free surface correction: {state.free_surface_correction_t:.3f} m")
print(f"GM wet: {state.gmt_wet:.3f} m")
Stability with Free Surface Correction
The GZ curve also includes free surface corrections:
from pynavaltoolbox.stability import StabilityCalculator
stab = StabilityCalculator(vessel)
curve = stab.calculate_gz_curve(
displacement_mass=5000000, # kg
cog=(45.0, 0.0, 7.0), # LCG, TCG, VCG
heels=list(range(0, 61, 5))
)
print(f"GG' (free surface effect): {curve.gg_prime:.3f} m")
print(f"\nHeel GZ_dry GZ_wet")
for pt in curve.points:
print(f"{pt.heel:5.0f}° {pt.gz:7.3f} {pt.gz_corrected:7.3f}")
# Compare stability parameters
print(f"\nMax GZ (dry): {curve.get_max_gz(corrected=False):.3f} m")
print(f"Max GZ (wet): {curve.get_max_gz(corrected=True):.3f} m")
Complete Example
Here’s a complete example showing a loading condition analysis:
from pynavaltoolbox import Hull, Vessel
from pynavaltoolbox.tanks import Tank
from pynavaltoolbox.hydrostatics import HydrostaticsCalculator
from pynavaltoolbox.stability import StabilityCalculator
# Load hull
hull = Hull("cargo_ship.stl")
# Create tanks
fuel_ps = Tank.from_box(
x_min=30.0, x_max=50.0,
y_min=-8.0, y_max=-2.0,
z_min=1.0, z_max=6.0,
fluid_density=850.0,
name="Fuel_PS"
)
fuel_ps.set_fill_level(70, unit='percent')
fuel_sb = Tank.from_box(
x_min=30.0, x_max=50.0,
y_min=2.0, y_max=8.0,
z_min=1.0, z_max=6.0,
fluid_density=850.0,
name="Fuel_SB"
)
fuel_sb.set_fill_level(70, unit='percent')
ballast = Tank.from_box_hull_intersection(
hull,
x_min=10.0, x_max=90.0,
y_min=-12.0, y_max=12.0,
z_min=0.0, z_max=1.5,
fluid_density=1025.0,
name="DoubleBottom"
)
ballast.set_fill_level(50, unit='percent')
# Create vessel
vessel = Vessel(hull, tanks=[fuel_ps, fuel_sb, ballast])
# Find equilibrium
hydro = HydrostaticsCalculator(vessel)
state = hydro.find_equilibrium(
displacement_mass=8000000, # Target displacement
center_of_gravity=(50.0, 0.0, 8.0),
initial_draft=6.0
)
print("=== Hydrostatic Analysis ===")
print(f"Draft: {state.draft:.2f} m")
print(f"Displacement: {state.displacement_mass:.0f} kg")
print(f"GM dry: {state.gmt_dry:.3f} m")
print(f"Free surface corr: {state.free_surface_correction_t:.3f} m")
print(f"GM wet: {state.gmt_wet:.3f} m")
# Calculate GZ curve
stab = StabilityCalculator(vessel)
gz_curve = stab.calculate_gz_curve(
displacement_mass=state.displacement_mass,
cog=(50.0, 0.0, 8.0),
heels=list(range(0, 71, 5))
)
print("\n=== Stability Analysis ===")
print(f"GG' = {gz_curve.gg_prime:.3f} m")
print(f"Max GZ: {gz_curve.get_max_gz():.3f} m at {gz_curve.get_angle_of_max_gz():.0f}°")
print(f"Range of stability: {gz_curve.get_range_of_stability():.1f}°")
Visualizing Vessels with Tanks
The VesselVisualizer class provides methods to visualize vessels
with their tanks, using transparent hulls to see tank contents.
Interactive 3D Viewer
from pynavaltoolbox.hydrostatics import VesselVisualizer
viz = VesselVisualizer(vessel)
# Open interactive 3D window
viz.show_with_tanks(
hull_opacity=0.3, # Transparent hull (0-1)
show_fluid=True, # Show current fluid levels
show_tank_bounds=True # Show tank outlines
)
Controls in the 3D viewer:
Left mouse: Rotate
Right mouse: Zoom
Middle mouse: Pan
‘q’: Close window
Saving Screenshots
# Save a view with tanks
viz.save_view_with_tanks(
"vessel_tanks.png",
view_type='iso', # 'iso', 'side', 'front', 'rear', 'top'
hull_opacity=0.25,
show_fluid=True,
show_tank_bounds=True,
draft=6.0 # Optional: show waterline
)
Visualization Features
Hull transparency: Adjust
hull_opacityto see inside the vesselTank colors: Each tank is rendered in a different color
Fluid level: Solid rendering of current fill level
Tank bounds: Wireframe showing tank geometry
Waterline: Optional visualization at specified draft