Resources Numerical accuracy Calculation policy

Fault trees and reliability block diagrams

The probability of a top event, minimal cut sets, importance measures, system reliability and mean time to failure.

How the precision is kept

Probabilities are 64-bit, and the top event is computed by factoring on repeated events, not by a bound. Several formulas subtract from 1 (1 − e^(−λt), 1 − Π(1 − p)), which loses digits when probabilities are small. One of them, the unavailability of a periodically tested standby item, returns wrong values for λτ between 1e-9 and about 1e-6. Mean time to failure is a Simpson integral over 4000 steps.

Open item. Use expm1 and log1p for 1 − e^(−x) and 1 − Π(1 − p), and a series for the standby unavailability when λτ is small.

Calculations under this policy

10 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

logic.js Shared shell, every app 64-bit 10 calculations Reviewed

Tests bin/test-engines.mjs, tools/risk-test/test.mjs

Probability of a basic event

64-bit

The probability of an event from a fixed value, a failure rate and time, a test interval, or repair data.

failed by t: 1 − e^(−λt); tested every τ: 1 − (1 − e^(−λτ)) ÷ (λτ), or λτ ÷ 2 below 1e-9; repairable: MTTR ÷ (MTTF + MTTR)

1 − e^(−x) is formed by subtraction, so its relative error is about 1e-16 ÷ x. The standby form subtracts twice: its error is about 1e-16 ÷ x against a result of x ÷ 2. At λτ = 1e-6 it is right to about 4 digits, at 1e-8 it is off by about 20 %, and at 2e-9 it returns a negative number. Below 1e-9 the series value λτ ÷ 2 is used.

  • logic.js
  • lines 4 to 18
/**
 * Fault trees and reliability block diagrams on one coherent-logic core.
 *   fault tree node:  { event: 'id' }  |  { and: [nodes] }  |  { or: [nodes] }  |  { koon: [nodes], k }   (k or more of the children occur)
 *   events: { id: { p } | { lambda, t } | { lambda, tau } | { mttf, mttr } }
 * The same event id used twice is the SAME event (a repeated event); probability is then computed exactly by factoring (Shannon expansion),
 * so repeated events never get multiplied as if independent. Cut sets: MOCUS (Fussell & Vesely 1972) with absorption.
 */
export function eventProbability(e) {
  if (e == null) return NaN;
  if (e.p != null) return e.p;
  if (e.lambda != null && e.t != null) return 1 - Math.exp(-e.lambda * e.t);                       // non-repairable, failed by time t
  if (e.lambda != null && e.tau != null) { const x = e.lambda * e.tau; return x < 1e-9 ? x / 2 : 1 - (1 - Math.exp(-x)) / x; } // standby tested every tau: mean unavailability
  if (e.mttf != null && e.mttr != null) return e.mttr / (e.mttf + e.mttr);                         // repairable, steady state
  return NaN;
}

At least k of n events

64-bit

The probability that k or more of a set of independent events occur.

the distribution of the count, built one event at a time, summed from k up

A dynamic program of products and sums of probabilities. All terms are non-negative, so nothing cancels.

  • logic.js
  • lines 24 to 28
/** P(k or more of independent events with probabilities ps occur): the Poisson-binomial tail by dynamic programming. */
export function atLeast(k, ps) {
  let d = [1]; for (const p of ps) { const nd = new Array(d.length + 1).fill(0); for (let i = 0; i < d.length; i++) { nd[i] += d[i] * (1 - p); nd[i + 1] += d[i] * p; } d = nd; }
  let s = 0; for (let i = Math.max(0, k); i < d.length; i++) s += d[i]; return s;
}

AND, OR and voting gates

64-bit

The probability of a gate from its inputs when no event is repeated.

AND: Π pᵢ; OR: 1 − Π (1 − pᵢ)

The OR gate takes 1 minus a product close to 1. For inputs of 1e-9 and 2e-9 it returns 3.000000026e-9 where the true value is 2.999999998e-9: about 8 digits. The smaller the probabilities, the fewer digits remain.

  • logic.js
  • lines 30 to 37
function prob(n, p) {
  switch (kind(n)) {
    case 'event': return p.get(n.event);
    case 'and': return kids(n).reduce((a, c) => a * prob(c, p), 1);
    case 'or': return 1 - kids(n).reduce((a, c) => a * (1 - prob(c, p)), 1);
    default: return atLeast(n.k, kids(n).map((c) => prob(c, p)));
  }
}

Top event with repeated events

64-bit

The probability of the top event when the same event appears in several places.

P = p_x × P(tree | x occurs) + (1 − p_x) × P(tree | x does not)

A repeated event is conditioned on, so it is never multiplied with itself as if independent. The recursion doubles for each repeated event; the caller stops at 22.

  • logic.js
  • lines 76 to 83
function exact(n, p) {
  if (n === true) return 1; if (n === false) return 0;
  const ls = leaves(n), count = new Map(); for (const l of ls) count.set(l, (count.get(l) || 0) + 1);
  const rep = [...count].filter(([, c]) => c > 1).map(([id]) => id);
  if (!rep.length) return prob(n, p);
  const x = rep[0], px = p.get(x);
  return px * exact(condition(n, x, true), p) + (1 - px) * exact(condition(n, x, false), p);
}

Cut set probabilities and bounds

64-bit

The probability of each minimal cut set and two bounds on the top event.

rare event: min(1, Σ P(cut set)); upper bound: 1 − Π (1 − P(cut set))

Each cut set probability is a product. The rare-event value is a plain sum; the upper bound has the same 1 − product cancellation as the OR gate.

  • logic.js
  • lines 117 to 118
const csP = cs.sets.map((s) => s.reduce((a, e) => a * p.get(e), 1)), rare = Math.min(1, csP.reduce((a, b) => a + b, 0)), mcub = 1 - csP.reduce((a, b) => a * (1 - b), 1);
if (cs.truncated) probs.push(problem('cutsets-truncated', 'warning', 'There are more cut sets than the limit; the list and its bounds are incomplete.', []));

Importance measures

64-bit

How much each event matters to the top event.

Birnbaum = P(top | p = 1) − P(top | p = 0); Fussell–Vesely = (P − P₀) ÷ P; RAW = P₁ ÷ P; RRW = P ÷ P₀

Two full recomputations per event. Fussell–Vesely subtracts two top probabilities, which are nearly equal for an event that matters little, so small importances have few digits.

  • logic.js
  • lines 123 to 126
if (top != null) for (const id of count.keys()) {
  const hi = exact(tree, new Map(p).set(id, 1)), lo = exact(tree, new Map(p).set(id, 0)), pi = p.get(id);
  imp[id] = { p: pi, birnbaum: hi - lo, criticality: P > 0 ? (hi - lo) * pi / P : 0, fussellVesely: P > 0 ? (P - lo) / P : 0, raw: P > 0 ? hi / P : null, rrw: lo > 0 ? P / lo : null };
}

Reliability of a component

64-bit

The chance a block still works at the mission time.

R = e^(−λt); Weibull: R = e^(−(t ÷ η)^β)

Direct 64-bit evaluation. The block diagram then uses 1 − R as the failure probability, which loses digits when R is close to 1.

  • logic.js
  • lines 139 to 144
export function compReliability(c, t) {
  if (c.r != null) return c.r;
  if (c.lambda != null) return Math.exp(-c.lambda * t);
  if (c.weibull) return Math.exp(-Math.pow(t / c.weibull.eta, c.weibull.beta));
  return NaN;
}

Block diagram reliability

64-bit

The reliability of series, parallel and k-of-n arrangements.

series = OR of failures; parallel = AND; reliability = 1 − P(failure)

The diagram is turned into failure logic and solved as a fault tree. Reliability is 1 minus the top probability, so for a very reliable system the unreliability is the number that keeps its digits.

  • logic.js
  • lines 152 to 161
export function rbd(node, comps, t) {
  const events = {}, probs = [];
  for (const [id, c] of Object.entries(comps)) { const r = compReliability(c, t); events[id] = { p: 1 - r }; if (!(r >= 0 && r <= 1)) probs.push(problem('rbd-r', 'error', `Block "${id}" gives a reliability of ${r}.`, [{ id }])); }
  const koonBad = (n) => (n.koon && !(Number.isInteger(n.k) && n.k >= 1 && n.k <= n.koon.length)) || [n.series, n.parallel, n.koon].some((c) => c && c.some(koonBad));
  if (koonBad(node)) probs.push(problem('rbd-koon', 'error', 'A k-of-n block needs k between 1 and n.', []));
  if (probs.length) return { ok: false, problems: probs, method: M_RBD };
  const ft = faultTree(toFailure(node), events);
  if (!ft.ok) return { ok: false, problems: ft.problems, method: M_RBD };
  return { ok: true, reliability: 1 - ft.top, unreliability: ft.top, cutSets: ft.cutSets, importance: ft.importance, problems: ft.problems, method: M_RBD };
}

Mean time to failure

64-bit

The mean life of a system that is not repaired.

MTTF = ∫ R(t) dt by Simpson's rule, 4000 steps, to the time R ≤ 1e-9

The horizon is found by doubling from 1 time unit, so it can be up to twice the time needed, and the step is the horizon ÷ 4000. The result has the error of Simpson's rule at that step, and the tail beyond the horizon is left out.

  • logic.js
  • lines 163 to 170
/** Mean time to failure of a non-repairable diagram: ∫ R(t) dt by Simpson's rule to the time R falls below 1e-9 (or `horizon`). */
export function rbdMttf(node, comps, { horizon = null, steps = 4000 } = {}) {
  let H = horizon;
  if (H == null) { H = 1; while (H < 1e12 && rbd(node, comps, H).reliability > 1e-9) H *= 2; }
  const n = steps - (steps % 2), h = H / n; let s = 0;
  for (let i = 0; i <= n; i++) { const r = rbd(node, comps, i * h).reliability; s += r * (i === 0 || i === n ? 1 : i % 2 ? 4 : 2); }
  return { mttf: s * h / 3, horizon: H, method: M_RBD };
}

Common-cause split

64-bit

The independent and the shared part of a failure rate.

independent = λ (1 − β); common = λ β

Two multiplications in 64-bit, with 1 − β formed by one subtraction.

  • logic.js
  • lines 172 to 173
/** Beta-factor common cause (IEC 61508-6 Annex D, simple form): the part of a unit's failure rate shared by the whole redundant group. */
export function betaFactor(lambda, beta) { return { independent: lambda * (1 - beta), common: lambda * beta }; }

In detail

Method
Shannon expansion on repeated events; MOCUS cut sets with absorption (the file cites Fussell and Vesely 1972); Poisson-binomial tail for k-of-n gates; rare-event and min-cut upper bounds; Birnbaum, criticality, Fussell–Vesely, risk achievement and risk reduction importance; Simpson's rule.
Number types
64-bit numbers.
Tolerances
The standby unavailability switches to λτ ÷ 2 below λτ = 1e-9. The integration horizon is doubled from 1 until the reliability is at most 1e-9, or until 1e12.
Checked by
The engines test compares a top event with 1 − 0.99 × 0.98 and a block diagram reliability with its closed form, both within 1e-4.
Limits
Factoring is limited to 22 repeated events; above that only the bounds are given. Cut sets are cut off at 20,000 inside an AND gate.

Approach: 64-bit, stated limit

The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.

Every policy that takes this approach