Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { type RoundingMode, roundDiv } from "./math_round_div.ts"; ← from math.round-div ^1.0.0 · built alongside by fune
import { type Oee } from "./manufacturing_oee_types.ts";
const MAX_PLANNED = 100_000_000_000;
function whole(name: string, value: number): void {
if (!Number.isSafeInteger(value)) {
throw new RangeError(`${name} must be a whole number, received ${value}`);
}
}
/**
* 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.
*/
export function overallEquipmentEffectiveness(
plannedSeconds: number,
downtimeSeconds: number,
idealCycleMillis: number,
totalCount: number,
goodCount: number,
mode: RoundingMode,
): Oee {
whole("plannedSeconds", plannedSeconds);
whole("downtimeSeconds", downtimeSeconds);
whole("idealCycleMillis", idealCycleMillis);
whole("totalCount", totalCount);
whole("goodCount", goodCount);
if (plannedSeconds <= 0 || plannedSeconds > MAX_PLANNED) {
throw new RangeError(`plannedSeconds must be from 1 to 10^11, received ${plannedSeconds}`);
}
if (downtimeSeconds < 0 || downtimeSeconds > plannedSeconds) {
throw new RangeError(`downtimeSeconds must be from 0 to plannedSeconds, received ${downtimeSeconds}`);
}
if (idealCycleMillis <= 0) {
throw new RangeError(`idealCycleMillis must be greater than zero, received ${idealCycleMillis}`);
}
if (totalCount < 0) {
throw new RangeError(`totalCount must not be negative, received ${totalCount}`);
}
if (goodCount < 0 || goodCount > totalCount) {
throw new RangeError(`goodCount must be from 0 to totalCount, received ${goodCount}`);
}
if (BigInt(totalCount) * BigInt(idealCycleMillis) * 10000n > BigInt(Number.MAX_SAFE_INTEGER)) {
throw new RangeError("totalCount and idealCycleMillis are too large: total x ideal cycle x 10000 must stay within 2^53 - 1");
}
const runSeconds = plannedSeconds - downtimeSeconds;
if (runSeconds === 0 && totalCount > 0) {
throw new RangeError(`no units can be made with no run time, received totalCount ${totalCount}`);
}
const availability = roundDiv(runSeconds * 10000, plannedSeconds, mode);
const performance = runSeconds === 0 ? 0 : roundDiv(idealCycleMillis * totalCount * 10000, runSeconds * 1000, mode);
const quality = totalCount === 0 ? 0 : roundDiv(goodCount * 10000, totalCount, mode);
const oee = roundDiv(goodCount * idealCycleMillis * 10000, plannedSeconds * 1000, mode);
return { availability, performance, quality, oee, runSeconds };
}