Functional Weave
Code in Rust

energy.gas-kwh@1.0.0

impl/python.py

1,802 bytes · the Python implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

from .energy_gas_kwh_types import GasEnergy, GasVolumeUnit
from .math_round_div import round_div  ← from math.round-div ^1.0.0 · built alongside by fune

# 1.02264 / 3.6 in lowest terms, with the scales of the arguments folded in:
# watt-hours = hundredths of m3 x 4261 x CV (thousandths of MJ/m3) / 1,500,000.
FACTOR = 4261
DIVISOR = 1_500_000
MAX_VOLUME = 1_000_000_000_000
MAX_SAFE = 9007199254740991


def _is_int(value: object) -> bool:
    return isinstance(value, int) and not isinstance(value, bool)


def gas_kwh(volume: int, volume_unit: GasVolumeUnit, calorific_value: int) -> GasEnergy:
    """Gas meter units to kWh, the way a GB bill does it: volume (x 2.83 for an
    imperial meter) x 1.02264 x calorific value / 3.6, rounded once, half-up,
    to the watt-hour.
    """
    if not _is_int(volume) or volume < 0 or volume > MAX_VOLUME:
        raise ValueError("volume must be a whole number of units from 0 to %d, received %s" % (MAX_VOLUME, volume))
    if not _is_int(calorific_value) or calorific_value < 1 or calorific_value > 100000:
        raise ValueError(
            "calorific value must be a whole number of thousandths of a MJ/m³ from 1 to 100000, received %s"
            % (calorific_value,)
        )
    if volume_unit == "cubic-metres":
        hundredths = volume * 100
    elif volume_unit == "hundreds-cubic-feet":
        hundredths = volume * 283
    else:
        raise ValueError('unknown volume unit "%s": expected cubic-metres or hundreds-cubic-feet' % (volume_unit,))

    scaled = FACTOR * calorific_value
    whole, rest = divmod(hundredths, DIVISOR)
    watt_hours = whole * scaled + round_div(rest * scaled, DIVISOR, "half-up")
    if watt_hours > MAX_SAFE:
        raise ValueError("gas energy too large to calculate exactly")
    return GasEnergy(cubic_metres_hundredths=hundredths, watt_hours=watt_hours)