Bathtub
A bathtub, one stock of water with an inflow from the faucet and an outflow through the drain.
- Name:
bathtub - Field:
engineering/processes - Formalism: ordinary differential equations
- References: Meadows 2008
Factory
@register_model(
field='engineering/processes',
tags=('stocks and flows', 'system dynamics', 'ode'),
references=('Meadows 2008',),
defaults={'until': 10.0, 'dt': 0.5},
)
def bathtub(water: float = 50.0, *, inflow: float = 5.0, outflow: float = 5.0) -> System:
"""Return a bathtub, one stock of water with an inflow from the faucet and an outflow through the drain.
The drain empties the tub at `outflow` gallons per minute while there is water, and the faucet opens to `inflow`
gallons per minute after five minutes. With equal flows the level falls for five minutes and then stays constant.
Args:
water:
The initial water in the tub, in gallons.
inflow:
The inflow after five minutes, in gallons per minute.
outflow:
The outflow, in gallons per minute.
Returns:
system:
The model, with the water `tub.water` in gallons and the flows `tub.faucet` and `tub.drain` in gallons
per minute, over minutes.
Examples:
>>> from skcomplex.models.engineering.processes import bathtub
>>> bathtub(water=20.0).elements[0].water
20.0
"""
return System(elements=[TubElement('tub', water=water, inflow=inflow, outflow=outflow)])
Components
class TubElement(Element):
"""Tub of water, a stock filled by a faucet that opens after five minutes and emptied by a drain."""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
water: Annotated[object, StateSpec(domain=RealSet.closed_open(0, oo), quantity='water')] = 50.0,
inflow: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 5.0,
outflow: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 5.0,
) -> None:
super().__init__(label, visual=visual)
self.water = water
self.inflow = inflow
self.outflow = outflow
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the faucet and drain flows of the tub."""
return [
TransferLaw(Source(), s.water, s.inflow * step(s.t, INFLOW_START), label='faucet'),
TransferLaw(s.water, Sink(), where(s.water > 0, s.outflow, 0), label='drain'),
]
Equations
tub.water: diff(water_tub(t), t) == inflow_tub*where(t >= 5.0, 1.0, 0) - where(water_tub(t) > 0, outflow_tub, 0)