liveBook · Manning

Torricelli's law

As explained in Digital Twins in Action

Torricelli's law relates the outflow speed of fluid through an opening to the fluid height above that opening under gravity.

Torricelli’s law describes the speed of fluid leaving an opening. For a tank draining through a hole at its base, it provides a rate-of-change equation for the water height. Solving that ordinary differential equation (ODE) turns an initial water level into a predicted drainage curve and an estimated emptying time. section 9.2 section 9.2.2

A simple model combines tank area, hole area, and gravity into k = (hole area / tank area) × √(2g). While water remains, the height changes at dh/dt = −k√h; at or below zero, the model stops the outflow. The negative sign means the level falls, and the square-root term makes the modeled rate depend on the current height. section 9.2.2

Estimate when a tank will empty

With a 1.5 m tank diameter, a 1 cm opening, and an initial water height of 3 m, a Python model passes the height-rate function to SciPy’s solve_ivp. Its simulated curve puts emptying at approximately four hours. An ultrasonic level-sensor reading can replace the assumed initial height when making a prediction for the tank’s current state. section 9.2.2

Listing 9.1 Using a SciPy integrator to simulate tank drainage
import numpy as np
from scipy.integrate import solve_ivp

D_tank = 1.5  # Tank diameter (m)
R_tank = D_tank / 2  # Tank radius (m)
A_tank = np.pi * R_tank**2  # Tank cross-sectional area (m²)

D_hole = 0.01  # Leak diameter (m) - 1 cm
R_hole = D_hole / 2  # Leak radius (m)
A_hole = np.pi * R_hole**2  # Leak area (m²)
g = 9.81  # Gravity (m/s²)

k = (A_hole / A_tank) * np.sqrt(2 * g)  #1

def leaking_tank(t, h):  #2
    if h <= 0:
        return 0  # No more water to leak
    return -k * np.sqrt(h)

h0 = 3.0  # Start with 3 meters of water

hours = 5
t_span = (0, hours * 3600)  # 0 to 1.5 hours in seconds
t_eval = np.linspace(0, hours * 3600, 1000)

solution = solve_ivp(  #3
    leaking_tank, t_span, [h0], t_eval=t_eval, method="RK45",
    dense_output=True
)

The listing calculates k from the tank and opening dimensions, defines the ODE, and integrates it from a specified starting height. section 9.2.2

The same drainage question can be modeled in OpenModelica by defining a tank, its outlet, the initial level, and the connected components. This component-based approach avoids importing an integration solver or specifying time steps in the model. Check initial conditions before comparing runs: the Python example starts at 3 m, while the shown Modelica tank starts at 2 m. section 9.2.2 section 9.3.2

Listing 9.2 Modelica tank model with 1 cm outlet hole
model WaterTankDrainage
  import Modelica.Constants.pi;

  inner Modelica.Fluid.System system  #1
    annotation (Placement(transformation(extent={{60,60},{80,80}})));

  Modelica.Fluid.Vessels.OpenTank tank(  #2
    redeclare package Medium = Modelica.Media.Water.
    ConstantPropertyLiquidWater,
    crossArea = pi * (1.5/2)^2,  // 1.767 m²
    height = 3.0,                // Max tank height
    level_start = 2.0,           // Initial water level
    nPorts = 1,                  // Number of ports
    portsData = {Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
                   diameter = 0.01, // Hole diameter
                   height = 0.0)})  // Port at bottom of tank
    annotation (Placement(transformation(extent={{-20,20},{20,60}})));

  Modelica.Fluid.Sources.Boundary_pT atmosphere(  #3
    redeclare package Medium = Modelica.Media.Water.
    ConstantPropertyLiquidWater,
    nPorts = 1,
    p = 101325,  // Atmospheric pressure (Pa)
    T = 293.15)  // Temperature (K)
    annotation (Placement(transformation(extent={{60,-20},{40,0}})));

equation
  connect(tank.ports[1], atmosphere.ports[1])  #4
    annotation (Line(points={{0,20},{0,-10},{50,-10}}, color={0,127,255}));

end WaterTankDrainage;

The Modelica listing shows how tank geometry, a bottom outlet, and a starting level are specified as model parameters. section 9.3.2

How Digital Twins in Action covers it

How deep it goes
Works through a height-rate ODE and numerical simulation, then shows a component model without deriving the physical law.
Examples
Uses a rainwater tank, a SciPy drainage script, an ultrasonic level reading, and an OpenModelica tank simulation.
What it assumes
Introduces differential equations as rates of change, then uses Python code and a graphical Modelica workflow to implement the model.
What you can do after
Apply it via SciPy’s solve_ivp or OpenModelica to predict how a tank’s water level changes over time.
How it connects
Connects ordinary differential equations, initial value problems, numerical integration, digital twins, and Modelica fluid components.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Digital Twins in Action. The section links point to the parts of the book it draws on.