CFD Verification · OpenFOAM · free-surface (VOF) + forced motion

2D tank sloshing — forced roll, and the ballast tank as a passive roll damper

Partially-filled rectangular tank under prescribed roll, verified against analytical sloshing theory and a recognised forced-roll benchmark, then swept over fill and frequency and reduced to the added roll damping a ballast tank contributes as a passive tuned-liquid-damper.

VERIFIED · real OpenFOAM v2312

SolverinterFoam (VOF)
MotionESI solidBody forced roll
Nat-freq error0.29% / 0.002%
Best anti-roll fill70% raw damping · 50% coupled

The problem

A partially-filled tank contains a gravity-driven free-surface (sloshing) mode. Tune its first-mode period near a vessel's roll natural period and the sloshing moment acts out of phase with roll — a passive tuned-liquid-damper, the naval "anti-roll tank." This page verifies the 2D CFD machinery for that problem: prescribed tank roll on a rigid moving mesh, partial fill via VOF, extraction of the tank reaction moment, and reduction to frequency-dependent added roll inertia and damping.

Method

Rigid whole-mesh roll motion θ(t) = θ₀·sin(ωt) via the ESI solidBody motion solver (dynamicMotionSolverFvMesh + motionSolver solidBody) — a pure rigid transform, robust on 2D slabs. Partial fill is initialised with setFields snapped so the still-water surface lands on a cell face. The first-mode sloshing natural frequency of a rectangular tank of breadth L and fill depth h is the analytical target:

ωn² = (nπg / L) · tanh(nπh / L)   (n = 1)

which saturates in deep fill (set by L) and collapses toward the shallow-water speed √(gh) in shallow fill — so fill depth is the dominant tuning knob.

Free-surface visualization — the effect of roll

Real 2D VOF free-surface fields from OpenFOAM v2312. Left: with forced roll, the tank sloshes wall-to-wall; right: without roll, the surface stays flat and calm — the mechanism this study quantifies. Shown at h/L = 0.70 (water navy, air pale, interface at α = 0.5).

With vs without forced roll — 2D VOF free-surface fields
With roll (sloshing) vs without roll (calm), same tank — a live OpenFOAM VOF animation. One roll cycle in phases and the full study: the 2D CFD study →

Verification 1 — natural frequency, across the fill range

Free-decay: the tank is given a small free-surface perturbation and rings down; the fundamental frequency is extracted by FFT and compared to the analytical tanh dispersion. Bracketed at intermediate and deep fill:

RegimeTank (L, h)MeasuredAnalyticalError
Intermediate (h/L = 0.3)1.0 m, 0.3 m0.75587 Hz0.75805 Hz0.29%
Deep / standing-wave (h/L = 0.7)1.0 m, 0.7 m0.87258 Hz0.87260 Hz0.002%
Result. The forced-motion + partial-fill + VOF pipeline reproduces the analytical first-mode frequency to 0.29% at intermediate fill and 0.002% at deep fill. The deep case being essentially exact is physical — deep-water free-decay stays linear, with none of the shallow-water nonlinearity that mildly perturbs the intermediate case.

Verification 2 — forced roll vs the SPHERIC benchmark

The recognised 2D forced-roll rectangular-tank benchmark (Delorme et al. / SPHERIC): L = 0.9 m, h = 0.093 m (~18% fill), 4° roll at the benchmark drive period (T ≈ 1.63 s). The case runs stably to t = 8.1 s on the 2D moving mesh and reproduces the characteristic violent shallow-water sloshing:

QuantityValueNote
Wall run-up above still level0.064 m~69% of still depth
Stabilityt = 8.1 sstable, no mesh blow-up
Dominant surface response≈ 1.21 Hz≈ 2× drive (impact-per-cycle harmonic)

Quantitative pressure matching has since been completed against the published SPHERIC experimental statistics: the CFD first-impact peak at Sensor 1 is 4,688 Pa vs the experimental 3,710 ± 732 Pa (100-run mean ± σ, CoV ≈ 20%) — inside the 2σ scatter band (2,246–5,174 Pa), consistent with the known VOF tendency to over-predict impact peaks. Full traces and discussion: the 2D CFD study →

Application — ballast tank as a passive roll damper

For each {fill × drive frequency} the tank roll-reaction moment M(t) is extracted from a forces function object about the roll axis and reduced against the imposed roll into an in-phase (stiffness/inertia-like) and a quadrature (damping) coefficient. A 3×3 sweep — fill {25, 50, 70}% × three drive frequencies — run through a reduced-order coupling model answers the design question directly: which fill best damps roll near a target period?

Drive freqPeriodBest anti-roll fillPeak quad. coeff.
0.682 Hz1.47 s25%—
0.784 Hz1.27 s70%2.02 N·m/(rad/s)
0.923 Hz1.08 s70%—
Reading. Every fill produces a dissipative (anti-roll) tank moment — the mechanism the concept predicts. Higher fill (50–70%) gives the strongest damping in the energetic mid-band; the lowest drive frequency favours the shallow 25% case. This matches the literature's finding that ~50–70% fill is the most energetic sloshing regime. (Drive periods here are representative; a specific vessel study substitutes its measured roll RAO.)
Raw damping is not the design optimum. This table ranks the raw quadrature (damping) coefficient, where 70% fill is strongest in the mid-band. The subsequent coupled tuned-liquid-damper analysis in the 2D CFD study shows that, once the tank is coupled to a vessel roll mode (Den Hartog model), the 50% fill gives the best vessel-level response (ζ ≈ 0.18 — the lowest coupled peak response of the fills tested; note the Den Hartog optimum is ζ = 0.127, so this is not the nearest in raw ζ) and the 70% fill is over-damped — maximum raw damping and best coupled anti-roll performance are different questions.

What this gates & how to run

This verifies the path from prescribed tank motion → partial-fill VOF → tank moment → reduced-order roll coupling. It gates coupled tank-sloshing / roll studies (anti-roll ballast tanks, sloshing loads at partial fill). The engine lives in digitalmodel:

from digitalmodel.solvers.openfoam.validation.sloshing_2d import build_forced_roll_case from digitalmodel.solvers.openfoam.validation.sloshing_sweep import SloshingSweep from digitalmodel.solvers.openfoam.sloshing_coupling import SloshingCouplingModel m = SloshingCouplingModel.from_sweep_manifest("sweep_manifest.json") m.best_antiroll_fill(natural_period_s=<roll period>)

References