Functional Weave
Code in TypeScript

manufacturing.oee@1.0.0

impl/python.py

2,658 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 .manufacturing_oee_types import Oee
from .math_round_div import RoundingMode, round_div  ← from math.round-div ^1.0.0 · built alongside by fune

MAX_SAFE = 2**53 - 1
MAX_PLANNED = 10**11


def _whole(name: str, value: int) -> None:
    if isinstance(value, bool) or not isinstance(value, int) or value > MAX_SAFE or value < -MAX_SAFE:
        raise ValueError("%s must be a whole number, received %r" % (name, value))


def overall_equipment_effectiveness(
    planned_seconds: int,
    downtime_seconds: int,
    ideal_cycle_millis: int,
    total_count: int,
    good_count: int,
    mode: RoundingMode,
) -> Oee:
    """OEE and its three factors in basis points. OEE is rounded once from the
    exact product (good count x ideal cycle / planned time), never from the
    three already-rounded factors, which is off by one surprisingly often.
    """
    _whole("plannedSeconds", planned_seconds)
    _whole("downtimeSeconds", downtime_seconds)
    _whole("idealCycleMillis", ideal_cycle_millis)
    _whole("totalCount", total_count)
    _whole("goodCount", good_count)
    if planned_seconds <= 0 or planned_seconds > MAX_PLANNED:
        raise ValueError("plannedSeconds must be from 1 to 10^11, received %d" % planned_seconds)
    if downtime_seconds < 0 or downtime_seconds > planned_seconds:
        raise ValueError("downtimeSeconds must be from 0 to plannedSeconds, received %d" % downtime_seconds)
    if ideal_cycle_millis <= 0:
        raise ValueError("idealCycleMillis must be greater than zero, received %d" % ideal_cycle_millis)
    if total_count < 0:
        raise ValueError("totalCount must not be negative, received %d" % total_count)
    if good_count < 0 or good_count > total_count:
        raise ValueError("goodCount must be from 0 to totalCount, received %d" % good_count)
    if total_count * ideal_cycle_millis * 10000 > MAX_SAFE:
        raise ValueError(
            "totalCount and idealCycleMillis are too large: total x ideal cycle x 10000 must stay within 2^53 - 1"
        )
    run_seconds = planned_seconds - downtime_seconds
    if run_seconds == 0 and total_count > 0:
        raise ValueError("no units can be made with no run time, received totalCount %d" % total_count)
    availability = round_div(run_seconds * 10000, planned_seconds, mode)
    performance = 0 if run_seconds == 0 else round_div(ideal_cycle_millis * total_count * 10000, run_seconds * 1000, mode)
    quality = 0 if total_count == 0 else round_div(good_count * 10000, total_count, mode)
    oee = round_div(good_count * ideal_cycle_millis * 10000, planned_seconds * 1000, mode)
    return Oee(availability=availability, performance=performance, quality=quality, oee=oee, run_seconds=run_seconds)