Authors: Kavin Charles · Jeevika R Event: Wavez 2026 · IIT Madras
A complete ship-hydrostatics engine built from the ground up: reads a ship offset table in JSON/CSV/Excel, returns every quantity required by the hackathon brief (plus the bonus KN cross-curves), verifies the hull against the IMO 2008 IS Code intact-stability criteria, and produces a publication-ready PDF report.
The solver goes beyond the classical wall-sided approximation by performing true heeled hydrostatics via polygon clipping — the same approach used by commercial naval-architecture software (NAPA, GHS, Maxsurf).
| Deliverable | Status | Module |
|---|---|---|
| Displacement ∇, Δ (m³ / t) | ✅ Required | hydro.hydrostatics |
| Waterplane area Aₓ | ✅ Required | hydro.hydrostatics |
| Longitudinal Centre of Buoyancy (LCB) | ✅ Required | hydro.hydrostatics |
| Longitudinal Centre of Flotation (LCF) | ✅ Required | hydro.hydrostatics |
| Vertical centre of buoyancy KB | ✅ Required | hydro.hydrostatics |
| Transverse metacentric radius BM | ✅ Required | hydro.hydrostatics |
| GM (user KG input) | ✅ Required | hydro.hydrostatics |
| GZ curve (true + wall-sided) | ✅ Required | hydro.heeled / hydro.stability |
| KN cross-curves of stability | ⭐ Bonus | hydro.heeled.cross_curves_true |
| Form coefficients Cb, Cw, Cm, Cp, Cvp | ✨ Extra | hydro.hydrostatics |
| TPC, MCTC | ✨ Extra | hydro.hydrostatics |
| Bonjean curves | ✨ Extra | hydro.bonjean |
| Equilibrium trim solver | ✨ Extra | hydro.trim |
| Free-surface correction | ✨ Extra | hydro.free_surface |
| IMO 2008 IS Code compliance checker | ✨ Extra | hydro.imo |
| IMO severe-wind (weather) criterion | ✨ Extra | hydro.weather |
| Interactive 3-D hull (Plotly) | ✨ Extra | hydro.plots3d |
| Multi-page PDF report | ✨ Extra | hydro.report |
| Streamlit web UI | ✨ Extra | app.py |
| ⚡ Capsize Simulator (time-domain roll ODE) | 🔥 Showstopper | hydro.seakeeping |
Convenience launchers live in scripts/ — .bat for Windows cmd / PowerShell, .sh for Linux / macOS / Git Bash. Each one activates .venv automatically.
| Script | Purpose |
|---|---|
scripts/setup |
Create .venv, install deps, regenerate all sample hulls |
scripts/run_tests |
pytest + verbose benchmark script |
scripts/run_demo |
CLI analysis of box barge + Wigley + KCS → artefacts in output/ |
scripts/run_capsize |
Headless KCS capsize-simulator demo (3 scenarios) |
scripts/run_streamlit |
Launch the web UI on http://localhost:8501 |
scripts/run_all |
Full pipeline: setup → tests → demo → capsize |
First-time Windows user:
scripts\setup.bat
scripts\run_tests.bat
scripts\run_streamlit.batFirst-time Linux / macOS user:
bash scripts/setup.sh
bash scripts/run_tests.sh
bash scripts/run_streamlit.sh- Python 3.11 or 3.12 (tested on both in CI; 3.10 also works but is not covered by the test matrix).
pip≥ 23, plus a working C build chain forshapelywheels on Windows — every officially supported platform already ships a prebuilt wheel, so a plainpip installis normally all that is needed.- ~200 MB of free disk for the virtual environment and the optional PDF / HTML artefacts.
Check versions:
python --version # → 3.11.x or 3.12.x
python -m pip --version# Clone
git clone https://github.com/Kavin-Charles/Hydronix.git
cd Hydronix
# Create an isolated virtual environment (recommended)
python -m venv .venv
# Activate it
# Windows PowerShell:
.venv\Scripts\Activate.ps1
# Windows cmd:
.venv\Scripts\activate.bat
# Linux / macOS:
source .venv/bin/activate
# Install all runtime + test dependencies
python -m pip install --upgrade pip
python -m pip install -r requirements.txtCore runtime packages pulled in: numpy, scipy, shapely, pandas, matplotlib, plotly, reportlab, streamlit, openpyxl.
The repository ships with scripts that regenerate every offset file on demand (no large binaries tracked in git):
# Box barge (60 × 12 × 6) + Wigley parabolic hull
python samples/generate_samples.py
# KCS containership parametric synthesis (Lpp = 230 m)
python samples/build_kcs.pyResulting files land in samples/:
samples/box_barge.jsonsamples/wigley.jsonsamples/kcs_real.json
Confirm the solver matches analytical references to < 0.5 %:
python -m pytest tests/ -v
# or run the benchmark script directly
python tests/test_benchmarks.pyExpected output: 8/8 PASS, box barge exact to machine epsilon, Wigley within 0.2 %, KCS within 3 % on Cm and 5 % on LCB.
Full analysis of the box barge with IMO check and GZ sweep:
python main.py samples/box_barge.json --imo --angles "0:60:5" --tableReal containership, save JSON results and generate a PDF report:
python main.py samples/kcs_real.json \
--draft 10.8 --KG 13.5 --rho 1.025 \
--angles "0:60:5" --imo --weather \
--save output/kcs_results.json \
--report output/kcs_report.pdfHeadless run (no matplotlib windows — suitable for CI):
python main.py samples/wigley.json --imo --no-plot \
--save output/wigley.jsonstreamlit run app.pyStreamlit prints a local URL (default http://localhost:8501). Open it in a browser. Workflow:
- Sidebar → Load offset file: pick one of
samples/box_barge.json,samples/wigley.json,samples/kcs_real.json, or upload your own JSON / CSV / XLSX. - Set loading condition: draft
T, vertical centre of gravityKG, water densityρ. - Heel sweep: choose angle range (e.g.
0:60:5). - Tabs:
- Overview — hull particulars, form coefficients, roll period.
- Hydrostatics — full draft-vs-particulars table with CSV download.
- GZ / KN — true-heeled + wall-sided curves, KN cross-curves, CSV download.
- IMO — per-criterion PASS / FAIL with margins.
- Curves — Bonjean, hydrostatic curves.
- 3D Hull — interactive Plotly mesh with waterplane.
- ⚡ Capsize Sim — time-domain nonlinear roll with animated rollover.
- Trim / FS / Weather — equilibrium trim solver, free-surface correction, IMO severe-wind criterion.
- Export — PDF report + JSON dump download.
from hydro.io_formats import load
from hydro.hydrostatics import Hydrostatics
from hydro.heeled import gz_curve_true
from hydro.seakeeping import simulate_roll
hull = load("samples/kcs_real.json")
hydro = Hydrostatics(hull, draft=10.8, KG=13.5, rho=1.025)
ang, gz, _ = gz_curve_true(hull, draft=10.8, KG=13.5,
angles_deg=list(range(0, 61, 5)))
r = simulate_roll(
gz_angles_deg = ang,
gz_values_m = gz,
displacement_t= hydro.displacement_t,
B_m = hull.B_max,
GM_m = hydro.GM,
phi0_deg = 25,
duration_s = 90,
mode = "rogue",
wave_amp_Nm = 2.0e8,
)
print(f"capsized = {r.capsized}, max heel = {r.max_heel_deg:.1f}°, "
f"t_cap = {r.capsize_time_s:.1f} s, Tφ = {r.period_s:.1f} s")| Symptom | Fix |
|---|---|
ModuleNotFoundError: shapely |
pip install shapely>=2.0 (Windows prebuilt wheels need Python 3.11+) |
UnicodeEncodeError in Windows cmd |
Run chcp 65001 once, or use PowerShell / Windows Terminal |
| Streamlit port already in use | streamlit run app.py --server.port 8502 |
| Plotly 3-D animation stutters | Lower n_frames to 30 in the Capsize Sim tab |
brentq: f(a) and f(b) must have different signs in build_kcs.py |
Target Cp outside the [0.55, 0.85] practical range — edit CB_PUB |
| PDF report empty / missing fonts | pip install --upgrade reportlab; rerun with --report output/foo.pdf |
python -c "from hydro import Hull, Hydrostatics, simulate_roll; \
from hydro.io_formats import load; h=load('samples/box_barge.json'); \
print(Hydrostatics(h, draft=3.0, KG=3.0).summary())"If this prints a populated dict including displacement_volume_m3 ≈ 2160.0, the install is healthy.
python main.py <offset-file> [options]
--draft T design draft in metres (default 3.0)
--KG z vertical centre of gravity (m)
--rho ρ water density in t/m³ (1.025 salt, 1.000 fresh)
--angles lo:hi:step heel-angle sweep (degrees)
--no-heeled skip the true-heeled solver (wall-sided only)
--table print a draft-vs-hydrostatic-particulars table
--imo evaluate IMO 2008 IS Code criteria
--trim W,LCG solve equilibrium trim for weight W (t) and LCG (m)
--fsm L,B,ρ add a rectangular free-surface tank and report FSC
--weather run the severe-wind (weather) criterion
--save file.json save all results to JSON
--report file.pdf generate a multi-page PDF report
--no-plot suppress matplotlib windows (headless)
--validate run the built-in benchmark tests
{
"ship_name": "My Ship",
"rho": 1.025,
"stations": [0, 10, 20, ..., 120],
"waterlines": [0, 1, 2, 3, 4, 5, 6],
"half_breadths": [[...], [...]]
}station,waterline,half_breadth
0,0,0.00
0,1,1.20
...
| station | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 1.2 | 2.4 | 3.1 | 3.6 | 4.0 | 4.2 |
| 10 | 0 | 2.6 | 4.5 | 5.3 | 5.8 | 6.0 | 6.0 |
| … |
Load with hydro.io_formats.load(path) — extension is auto-detected.
hydro/
├── hull.py Hull dataclass (offset table → Shapely section polygons)
├── integration.py Simpson 1/3 + 3/8 hybrid, 5-8-(-1) rule, Richardson extrapolation
├── hydrostatics.py Upright properties (∇, Aₓ, LCB, LCF, KB, BM, KM, GM, IT, IL, TPC, MCTC)
├── heeled.py TRUE heeled solver (polygon clipping, bisection on draft)
├── stability.py Wall-sided GZ (Scribanti) + GZ-curve derived metrics
├── imo.py IMO 2008 IS Code Part-A intact-stability checker
├── weather.py IMO A.749 severe-wind-and-rolling criterion
├── trim.py Newton–Raphson equilibrium-trim solver
├── bonjean.py Bonjean curves (sectional area vs draft)
├── free_surface.py Free-surface moment / GM correction (rectangular tanks)
├── io_formats.py JSON / CSV (long + wide) / XLSX input-output
├── benchmarks.py Box-barge & Wigley-hull generators + analytical reference
├── plots.py Publication-quality matplotlib figures
├── plots3d.py Interactive 3-D Plotly hull viewer
└── report.py Multi-page reportlab PDF generator
tests/test_benchmarks.py ← analytical validation suite
samples/ ← sample offset files (generated)
main.py ← CLI entry point
app.py ← Streamlit web UI
Simpson's 1/3 rule requires an odd number of ordinates. The solver
detects when the station (or waterline) count is even and silently switches
to Simpson's 3/8 rule for the tail segment, so the user never has to worry
about grid parity. A Richardson-extrapolated error estimate is returned in
the hydrostatic summary under integration_error_estimate.
For half-breadths y(x, z) and a waterline at height T:
∇ = 2 · ∫₀ᴸ ∫₀ᵀ y(x, z) dz dx (displaced volume)
Aw = 2 · ∫₀ᴸ y(x, T) dx (waterplane area)
LCB = (2/∇) · ∫₀ᴸ x · ∫₀ᵀ y(x,z) dz dx
LCF = (2/Aw) · ∫₀ᴸ x · y(x, T) dx
KB = (1/∇) · ∫₀ᵀ z · Aw(z) dz
IT = (2/3) · ∫₀ᴸ y(x, T)³ dx
BM = IT / ∇
KM = KB + BM, GM = KM − KG
The wall-sided formula
GZ(φ) = sin(φ)·[GM + ½·BM·tan²(φ)]
is only valid while the bilge stays submerged and the deck edge stays dry —
a handful of degrees for a real ship. For the full range 0°–80° we:
-
Represent each station as a Shapely polygon in body-fixed
(y, z). -
Clip it with the heeled waterline half-plane
z ≤ T + (y − y_LCF)·tan(φ)(CW rotation convention: +φ heels starboard down). -
Integrate the clipped section areas along the length to get the displaced volume; bisect
Tto preserve the upright displacement. -
Area-weight the section centroids to obtain the body-frame centre of buoyancy
(y_B, z_B). -
Project into the earth-fixed frame:
GZ = y_B · cos(φ) + (z_B − KG) · sin(φ) KN = GZ + KG · sin(φ)
This recovers the wall-sided answer exactly at small heels and handles deck-edge immersion, bilge emergence, and loss of stability at large angles.
(1) Area under GZ 0° → 30° ≥ 0.055 m·rad
(2) Area under GZ 0° → 40° ≥ 0.090 m·rad (or to AVS if < 40°)
(3) Area under GZ 30° → 40° ≥ 0.030 m·rad
(4) GZ at 30° heel ≥ 0.20 m
(5) Heel at maximum GZ ≥ 25°
(6) Initial metacentric height ≥ 0.15 m
The hydro.imo.imo_intact_stability_check function returns a structured
dictionary with per-criterion pass/fail, margins and an overall verdict.
Both the closed-form box barge and the Wigley parabolic hull are checked in
tests/test_benchmarks.py. The acceptance tolerance is < 0.5 %; actual
errors are far below:
Box Barge (L=60, B=12, T=3)
Displacement ∇ 2160.000 vs 2160.000 err 0.000 %
Waterplane Aw 720.000 vs 720.000 err 0.000 %
LCB 30.0000 vs 30.0000 err 0.000 %
LCF 30.0000 vs 30.0000 err 0.000 %
KB 1.5000 vs 1.5000 err 0.000 %
BM 4.0000 vs 4.0000 err 0.000 %
KM 5.5000 vs 5.5000 err 0.000 %
IT 8640.0000 vs 8640.0000 err 0.000 %
Wigley Hull (L=100, B=10, D=6.25, T=4)
Displacement ∇ 2301.458 vs 2302.578 err 0.049 %
Waterplane Aw 393.333 vs 393.600 err 0.068 %
KB 1.840 vs 1.842 err 0.105 %
BM 0.340 vs 0.340 err 0.155 %
IT 782.393 vs 783.989 err 0.203 %
Heeled-at-zero sanity check: Δ% = 0.0002
GZ(φ = 0) = 0.000000
The box barge is exact to machine rounding because the hull is rectangular and Simpson's rule is exact for piecewise-constant integrands. The Wigley hull has Richardson-extrapolated error ≈ 10⁻¹⁴ m³ on ∇ with a 41 × 21 grid.
HYDROSTATIC SUMMARY – Box Barge 60×12×6
────────────────────────────────────────────────────────
Displacement ∇ 2160.000 m³ Δ = 2214.000 t
Waterplane Aw 720.000 m² TPC = 7.380 t/cm
LCB / LCF 30.000 / 30.000 m
KB BM KM GM 1.500 / 4.000 / 5.500 / 2.500 m
Cb Cw Cm Cp 1.000 1.000 1.000 1.000
STABILITY – GZ CURVE
φ (°) GZ true (m) GZ wall-sided KN true (m)
0.0 +0.0000 +0.0000 +0.0000
10.0 +0.4449 +0.4449 +0.9659
20.0 +0.9457 +0.9457 +1.9717
30.0 +1.5155 n/a +3.0155
40.0 +1.6431 n/a +3.5715
IMO 2008 IS Code – Intact Stability (Part A)
────────────────────────────────────────────────────────
Area 0–30° ≥ 0.055 → 0.3750 PASS
Area 0–40° ≥ 0.090 → 0.6506 PASS
Area 30°–40° ≥ 0.030 → 0.2756 PASS
GZ at 30° ≥ 0.20 → 1.5155 PASS
Heel at GZmax ≥ 25° → 40.0° PASS
Initial GM ≥ 0.15 → 2.5000 PASS
Overall: PASS (6/6)
At small heels the true (polygon) and wall-sided (Scribanti) curves agree
exactly. Above the deck-edge immersion angle (≈ 26.6° for this barge),
the wall-sided formula is silently capped with NaN while the true
polygon solver continues to deliver physically correct GZ values.
The KCS is the international CFD-benchmark containership used by SIMMAN 2008, T2015 NMRI and every major hydrodynamics workshop since. Its full-scale particulars are published — Lpp = 230 m, B = 32.2 m, T = 10.8 m, ∇ = 52 030 m³, Cb = 0.6505, Cm = 0.9849, LCB = −1.48 % Lpp forward of midship.
Since the official IGES file is not publicly redistributable, the script
samples/build_kcs.py synthesises a KCS-consistent offset table from
the published particulars using:
- a Lackenby-biased sectional-area curve (linear LCB bias
k · (2ξ−1)on top ofbase^(1/exp), decouples Cp and LCB for a clean 2-point fit), - Lewis 2-parameter cross-sections at every station (Tupper §2.8 / Biran §2.6 closed-form),
- a global half-breadth scaling that pins ∇ to 52 030 m³ to 10⁻⁴.
The solver is then run on the generated hull (samples/kcs_real.json) and
compared against the published values:
KCS full-scale parametric hull – solver vs published particulars
==========================================================================
Quantity Published Computed Err %
--------------------------------------------------------------------------
Length L (m) 230.0000 230.0000 0.000 %
Beam B (m) 32.2000 32.2000 0.000 %
Design draft T (m) 10.8000 10.8000 0.000 %
Displacement volume ∇ (m³) 52030.0000 52030.0086 0.000 %
Displacement Δ (t) 53330.7500 53330.7588 0.000 %
Block coefficient Cb 0.6505 0.6505 0.000 %
Midship coefficient Cm 0.9849 0.9545 -3.083 %
LCB (% Lpp, fwd+) -1.4800 -1.4188 4.132 %
Prismatic coefficient Cp 0.6605 0.6815 3.181 %
Full IMO 2008 IS Code intact-stability check on the KCS at the design condition (KG = 13.50 m, typical containership value):
Initial GM 0.4847 m
GZ at 30° heel 0.5701 m
Maximum GZ 0.6199 m at φ = 35°
Area 0 – 30° 0.1093 m·rad
Area 0 – 40° 0.2110 m·rad
Angle of vanishing stability 50.0°
IMO 2008 IS Code verdict PASS (6 / 6)
Residual errors (< 4 %) come from the Lewis 2-parameter sections being unable to reproduce the very blocky bow/stern sections of a real modern container ship exactly. All global coefficients (∇, Cb, LCB) match the published KCS to within a fraction of a percent, validating the solver on a realistic modern commercial hull form.
Regenerate any time with:
python samples/build_kcs.py
python main.py samples/kcs_real.json --imo --angles "0:60:5"The solver's GZ curve is a static stability measure. The Capsize
Simulator (hydro.seakeeping) plugs that curve straight into a
rigid-body roll-equation of motion and solves for heel angle vs time:
I_xx · φ̈ + b · φ̇ + Δ·g · GZ(φ) = M_wave(t)
I_xx = Δ · k_xx²,k_xx = C_roll · B(Tupper §5.3; C_roll ≈ 0.35)b = 2·ζ·ωₙ·I_xx,ωₙ = √(g·GM)/k_xxGZ(φ)is the exact polygon-clip curve, odd-extended for negative heel; past AVS it ramps to a capsizing torque over 30°- three excitation modes: calm (free decay) · beam (sinusoidal) · rogue (Gaussian pulse)
- scipy
solve_ivpRK45 with adaptive step and event detection - capsize event:
|φ|crosses AVS (non-terminal); termination at ±180°
The Streamlit ⚡ Capsize Sim tab runs the ODE and renders
φ(t), phase portrait, wave-moment trace, and an animated 3-D view
of the hull rolling in the earth frame with Play / Pause / slider
controls. It is a miniature seakeeping code — the time-domain
counterpart of a linear roll RAO at large amplitude.
from hydro.seakeeping import simulate_roll
r = simulate_roll(
gz_angles_deg=ang, gz_values_m=gz,
displacement_t=Δ, B_m=B, GM_m=GM,
phi0_deg=25, duration_s=90, mode="beam",
wave_amp_Nm=80e6, wave_period_s=10,
)
print(r.capsized, r.max_heel_deg, r.capsize_time_s)Authors: Kavin Charles · Jeevika R Event: Wavez 2026 · IIT Madras
All formulae cross-checked against:
- Tupper, Introduction to Naval Architecture (5 th ed.)
- Biran & López-Pulido, Ship Hydrostatics and Stability (2 nd ed.)
- Barrass, Ship Design and Performance for Masters and Mates
- IMO Resolution MSC.267(85) – 2008 Intact Stability Code
- IMO Resolution A.749(18) – Severe-Wind-and-Rolling Criterion
- Lloyd, Seakeeping: Ship Behaviour in Rough Weather (rev. 1998)