Concepts¶
The reference behind the numbers: how RePyability computes each quantity, what each model assumes, and which method to choose. The tutorial shows these in action and the user guide shows how to call them; this page explains how they are worked out.
New to the theory?
This page is the reference for how RePyability computes each analysis. The Learn course teaches the ideas themselves, step by step: each one worked out by hand with small numbers, then with RePyability, with exercises.
Reliability block diagrams¶
A diagram's system works at t when working components connect its input
to its output, and its minimal path and cut sets describe that structure
(see Systems and
Paths and cuts). A k-out-of-n node
is up when at least k of its incoming branches are. A component in no
minimal path set is irrelevant: its state never decides whether the
system works.
The theory assumes a coherent system (repairing a component never makes it worse) with independent components, unless a dependency is modelled explicitly (a shared component, load sharing, standby, or a common-cause group).
How the system quantity is computed¶
Given each node's reliability, the system reliability is computed exactly, not by simulation, in two stages.
- Reduction. The diagram is reduced to modules: a series chain (a
node whose only successor has it as its only predecessor), a parallel
group (nodes with the same predecessors and successors, feeding nodes
that need one working input) and a k-out-of-n group (all the inputs
of a node with
k > 1, when they share their own inputs) each become one block, with the closed formsR = ∏ R_i,R = 1 − ∏ (1 − R_i)and a sum over how many members work. A node that its own input bypasses by a direct edge is dropped, as it is irrelevant. This repeats until nothing more reduces; a series-parallel diagram becomes a single module. - Pivotal decomposition. Whatever is left, the core (a bridge, a shared node), is evaluated by a pivotal (Shannon) decomposition over its modules and nodes: from its minimal path sets when it has few, and otherwise from a binary decision diagram built from its graph, whose size grows with how wide the mesh is rather than with how many paths it has. Only the core pays the combinatorial price.
Both stages depend only on the structure, so they are worked out once per
RBD and replayed for every evaluation: repeated evaluations (arrays of times,
importance measures, allocation searches) cost little more than arithmetic.
A series-parallel diagram is never expanded into its path sets, however many
it has: thirty duplicated stages in series have 2^30 of them, and are
evaluated in milliseconds. With method="c" the probability that the system
fails is computed instead, and its complement returned; the two methods give
the same value. Every step is a sum of products of node probabilities and
their complements, so both keep their full relative precision.
A core so meshed that even its decision diagram would take more than
repyability.rbd.bdd.STEP_LIMIT steps to build (25 million, a few seconds)
is not worked out. The RBD is still built, with
structure_check["is_too_meshed"] set: its simulations follow the graph
itself (a node works when it has not failed and enough of its inputs work),
and the exact analyses refuse, saying why, as analysis_routes() reports.
Raise the limit to try harder.
Both stages rest on pivotal decomposition, which also gives the importance measures.
The engine is exact given the node reliabilities. A node with no exact or
numerical reliability (a standby or load-sharing arrangement only a
simulation works out) has none to give it: the analyses that need it
refuse, the system's simulations draw its lifetimes, and
is_analytically_solvable() flags it.
analysis_routes() says how each analysis is computed, and why.
The other time functions follow from the reliability: F = 1 − R, the
cumulative hazard H = −ln R (exact), the density f = −dR/dt (a numerical
derivative of the exact reliability) and the hazard h = f / R.
Lifetimes by simulation¶
A coherent system fails when its last intact path set breaks, so its lifetime is
T_sys = max over minimal path sets P of ( min over i in P of T_i )
random() draws each component's lifetime and applies this rule, through the
modules (a series module fails at its first failure, a parallel one at its
last, a k-out-of-n one when fewer than k are left) so that the path sets
are only needed for the core. mean_time_to_failure() integrates the exact
reliability by default. With method="simulate" it averages such
lifetimes, with standard error s / √n
(why), which
mean_time_to_failure_interval() reports.
Simulation error, and making it smaller¶
The error of a simulated mean shrinks like 1/√N
(Lesson 6). Given a
tolerance, a run adds N results at a time until the confidence
interval's half-width, z · s / √N, is at most the tolerance. (The
stopping point depends on the estimated s, which makes a sequential
rule's coverage slightly below the nominal level when N is small;
checking only after each batch of N keeps the effect small.)
Two classical variance-reduction techniques make the error smaller for the
same N, without biasing the estimate (the
lesson gives the intuition;
here is why they work):
- Antithetic variates. A result is a function
f(U)of uniform random numbers.f(U)andf(1 − U)have the same distribution, and whenfis monotone in each number (in either direction) their covariance is at most zero, so the mean of the pair varies at most half as much as one result. A coherent system's lifetime increases with every component's lifetime, and each lifetime with its uniform (by inverse transform), so pairing always helps a lifetime. The availability and cost of a window are not monotone in the draws (a longer up time moves a component's later repairs, which may then overlap another component's), so they gain less, though usually still a useful amount. - Common random numbers. The difference of two designs' results has
variance
Var(A) + Var(B) − 2 Cov(A, B). Simulated independently, the covariance is zero; driven by the same random numbers wherever the designs share a component, the results move together, and the covariance removes most of the variance.
In a RepairableRBD both work component by component: each component draws
each quantity (its times to failure, its repairs, ...) from a stream of its
own, keyed by the seed, its place in the diagram and the quantity, and
counter-based, so that the stream's k-th draw in simulation r (or pair
r) is fixed by those alone. Its k-th draw is then matched, or paired, however
the components' events interleave, and every simulation is the same however
the run is split up: over processes or threads, or in a run to a tolerance.
A parallel run of a NonRepairableRBD splits the lifetimes into blocks
seeded in turn from one numpy.random.SeedSequence, whose spawned seeds
give independent streams. The block, not the process that runs it, fixes
the random numbers, so the results do not depend on the number of
processes.
Fault trees¶
A fault tree is the diagram's dual, with OR, AND and VOTE gates for series, parallel and k-of-n blocks (Lesson 3). A tree is evaluated by the same engine: each gate below which no event or gate is shared with the rest of the tree is a module with a closed form, and what the repeated events tie together is a core, solved exactly by the pivotal decomposition, on a binary decision diagram built from its gates (its cut sets are listed only when asked for). The measures of importance are the diagram's, with the top event as the system failing.
Parameter uncertainty¶
The node models are estimates, so the system's values carry epistemic
uncertainty (Lesson 2).
sf_uncertainty propagates it by
Monte Carlo over the parameters: each draw gives every uncertain node a
plausible model and the system reliability is computed exactly, all draws
at once (the node probabilities are arrays over draws and times), and the
percentiles of the draws form an uncertainty interval. A maximum-likelihood
fit's own estimate of its parameters' uncertainty (the inverse Hessian of
the log-likelihood, from surpyval) gives the draws on a transformed scale
(log for a positive parameter, logit for one in (0, 1)), which is the delta
method's normal approximation. Nodes of one population share one draw (a
tuple of nodes), as they share their parameters. The same draws give the
MTTF's, a BX life's and the time to a reliability's uncertainty
(mean_uncertainty, bx_life_uncertainty,
time_to_reliability_uncertainty): each draw's value is the exact one for
its models, the area under its reliability or the root of its reliability
less the target. A repairable system's availability and
cost rate are uncertain in the same way, through its components' lives,
repairs and maintenance times: each draw rebuilds the diagram with its
models and works its value out as the diagram's own
(mean_availability_uncertainty and the rest). The draws can be
quasi-random (sampling="sobol"), the points of a scrambled Sobol
sequence, which cover the parameters more evenly than random draws and so
settle the summaries with fewer of them.
Reliability vs availability¶
- Reliability
R(t): the probability the system has never failed byt(Lesson 1). The right question for a mission or a non-repairable item. Lives onNonRepairableRBD. - Availability
A(t): the probability the system is up att, allowing for repair (Lesson 6). The right question for a serviced, long-running system. Lives onRepairableRBD, which needs a repairability distribution per component.
Importance measures — which one, and why¶
An importance measure ranks components by how much they matter, but
"matter" has several meanings, and they disagree on purpose. All are
available at time(s) t and accept working_nodes/broken_nodes
conditioning. Below, R is the system reliability, Q = 1 − R, R_i node
i's reliability, and R(1_i)/R(0_i) the system reliability with node i
forced working/failed.
| Measure | Answers | Reach for it when |
|---|---|---|
Birnbaum birnbaum_importance |
How much does system reliability move per unit change in this node's reliability? ∂R/∂R_i = R(1_i) − R(0_i) |
Ranking where a reliability improvement pays off most right now. |
Improvement potential improvement_potential |
How much could I gain by making this node perfect? R(1_i) − R |
Bounding the upside of fixing one component. |
Risk achievement worth risk_achievement_worth |
How much more likely is system failure if this node fails? Q(0_i) / Q |
Finding components you must keep working: surveillance and protection targets. |
Risk reduction worth risk_reduction_worth |
By what factor would perfecting this node reduce system unreliability? Q / Q(1_i) |
Prioritising which single fix removes the most risk. |
Criticality criticality_importance |
Given that the system has failed, how likely is it that this node has failed and is critical? I_B · (1 − R_i) / Q, its share of the system failures (kind="success" gives I_B · R_i / R, which is 1 for every node in series) |
Ranking the culprits, series nodes included, by how much each contributes to system failure; on a repairable system, its share of the downtime. |
Fussell–Vesely fussell_vesely |
What fraction of system-failure probability involves this node? P(some cut set C ∋ i has failed) / Q, exactly (method="rare_event" gives the usual approximation Σ_{cut sets C ∋ i} Π_{j ∈ C} (1 − R_j) / Q) |
A cut-set-based culprit ranking; standard in PRA/PSA. |
Two more answer design-time and data-targeting questions rather than ranking at an operating point:
- Structural importance
structural_importance: Birnbaum with every node at ½, which depends only on the diagram (Lesson 4). - Parameter sensitivity
parameter_sensitivity: the derivative of system reliability with respect to each node's distribution parameters,∂R/∂θ = I_B · ∂R_i/∂θ, computed numerically. Where Birnbaum says which component matters, this says which fitted parameter matters, so you know where more data would most change the answer. - Differential importance
differential_importance(DIM): each node's or parameter's share of the change in the system when they all change together,I_i dθ_i / Σ_j I_j dθ_j. The other measures do not add up; the shares do, so a group's share is the sum of its members': what share of a possible gain lies in the pumps, or in the repair times against the maintenance intervals. A uniform change (everydθequal) shares out the Birnbaum importance, a proportional one (everydθ / θequal) the criticality. - Uncertainty importance
uncertainty_importance: each uncertain input's share of the variance of a system quantity (the reliability, the MTTF, a B-life, the availability, the cost rate) over the fitted models' parameter uncertainty, by the delta method or as Sobol indices: where more data would narrow the answer most. - Joint importance
joint_importance: the second-order Birnbaum measure,∂²R/∂R_i ∂R_j, for each pair. Positive for complements (series: improving one makes improving the other worth more), negative for substitutes (parallel): whether to bundle two improvements. - Rates and Barlow–Proschan
availability_rate,reliability_rate,barlow_proschan_importance: with independent components the system's rate of change is the sum of each one's Birnbaum importance times its own rate, so it splits into what each component is doing to the system now. Integrated over time, a component's part gives the probability that it caused the system's failure (Barlow–Proschan), the exact counterpart of the simulated failure criticality index.
A rule of thumb: Birnbaum for "where does an improvement help most", risk achievement worth for "what must not be allowed to fail", structural importance at the whiteboard, and parameter sensitivity when deciding where to spend a testing budget.
On a repairable system they take long-run availabilities (Lesson 4), or point availabilities over time, from new or from the components' current states.
Read together, the sensitivity measures are the system's Greeks, named after an option's: delta (Birnbaum), the levers' deltas (parameter sensitivity), their shares (differential importance), gamma (joint importance), theta (the rate of change and Barlow–Proschan) and vega (uncertainty importance). Sensitivities: the Greeks runs one pumping station through all of them.
Condition-based evaluation¶
The measures above assume every component is new. The condition-based methods
instead take each component's current life Xᵢ (a repairable system's
analyses over time take its components' states too: see
From the present). Each component's reliability is
conditioned on its age, Rᵢ(Xᵢ + x) / Rᵢ(Xᵢ)
(Lesson 1).
Feeding the conditioned per-node reliabilities through the same exact
system computation gives sf_given_state; inverting it gives
remaining_life (remaining useful life); and evaluating the importance
measures at the conditioned reliabilities gives importances_given_state.
Because the structure is static and only the state changes, each sensor update
is a cheap, exact re-evaluation: the heterogeneous generalisation of the cs
(conditional survival) method, which conditions the whole system on one
age, to per-component ages. Only lifetime (time-varying) distributions age;
a fixed-probability component's reliability does not depend on Xᵢ.
Covariate-dependent and time-varying reliability¶
A component's reliability often depends on the conditions it runs under,
not only on elapsed time. If you have fitted a regression survival model
in surpyval (accelerated failure time (AFT), proportional hazards (Cox, PH),
proportional odds (PO), …), a RegressionNode
uses it as an ordinary RBD node.
Fixed covariates. Pin the component's operating point Z (temperature,
load, duty cycle) and its reliability is the model's survival there:
R(x) = model.sf(x, Z)
That is a single univariate curve, so the node takes part in system
reliability, importance, MTTF and the condition-based (age) layer with no
special handling: a hotter-running unit is just a node with different
covariates. This is family-agnostic: AFT, PH and PO all expose sf(x, Z).
A time-varying covariate path. When the load itself changes over the
component's life, the reliability is no longer the survival at one covariate
value but the survival along the whole path Z(t). For a piecewise-constant
path (a surpyval StepSchedule) this is
R(x) = model.sf_tvc(x, schedule)
the probability of surviving each segment in turn under its own covariate.
Conditioning on an age needs no special case, because
R(x | age) = sf_tvc(age + x) / sf_tvc(age) = sf_tvc(x, schedule, given=age)
is exactly the go-forward survival from the component's current life under the schedule: the load-dependent-ageing ("digital twin") node. Whether a family composes along a path is a property of the model: AFT (the path rescales the clock) and proportional-/additive-hazards (the path accumulates hazard) do; proportional odds has no single natural extension: surpyval switches to the new covariate's hazard at each step (the survival does not jump to the new covariate's curve). The fixed-covariate node is the special case of a constant path.
Standby and repeated nodes¶
Repeated nodes. n independent, identical copies of a component with
reliability p have reliability pⁿ in series and 1 − (1 − p)ⁿ in
parallel. A RepeatedNode is exactly that, as one node. It is not the same as
one component drawn in several places (a shared power supply feeding two
branches): that is a single component, which fails once for every place it
appears, and treating its appearances as independent copies over-states
reliability.
Cold standby. With one unit operating, cold spares add their lifetimes
(Lesson 5), so the arrangement's
survival function is the convolution of theirs. RePyability computes it by
numerical convolution (deterministic, no sampling). For identical Exponential
units the sum is Erlang, in closed form, for any k operating units.
Imperfect switching. If each switch-over succeeds with probability s,
the lifetime is the sum of the first j units' lifetimes with probability
that exactly j − 1 switches succeeded before one failed (or all succeeded):
a mixture of partial sums, again computed by convolution.
Warm and hot standby. A warm spare ages at κ (the dormancy_factor)
of the operating rate
(Lesson 5). It fails when its
virtual age reaches its baseline failure age, so it can fail before it is
switched in. Identical Exponential units give a hypoexponential lifetime,
exactly, each stage (from j to j − 1 surviving units) exponential with
rate λ (k + (j − k) κ). Hot standby (κ = 1) is k-out-of-n active
parallel, and is worked out so for any units. With one unit operating and
any units, a spare switched in at τ has aged κτ and runs until its
failure age, so the lifetime follows a recursion over the switch-ins, which is computed on a time grid; with two
units, R(t) = S₁(t) + ∫₀ᵗ f₁(u) S₂(t − (1 − κ)u) du.
With k ≥ 2 operating units, cold, each operating position runs a renewal
process of the lives of the units put into it; for identical units these are
independent, so the number of failures by t is a sum of k renewal counts,
whose distributions come from the convolution, and the arrangement fails at
the n − k + 1-th. With different units, which unit goes where depends on
the order of failures. With two operating, after each failure the state is
its time and when the other operating unit started (the newcomer starts
new), a recursion on a grid of the two; with three or more, and warm with
k ≥ 2 (the spares' ages too), they are simulated.
Dependent failures: load sharing¶
Units that share a load fail sooner as their siblings fail, so independent parallel nodes over-count the redundancy (Lesson 5).
A LoadSharingModel captures the coupling as
a single node. Each unit is a fitted AFT model with load as its covariate,
so a unit running under load ℓ ages on its baseline clock at an acceleration
factor φ(ℓ) (the AFT time scaling). With s survivors sharing a total load
L, each carries L / s and ages at φ(L / s); as siblings fail, s falls,
L / s rises, and the survivors' clocks speed up. The group works while at
least k of the n units survive. This is the cumulative-exposure model:
a unit's virtual age is the integral of φ(load(t)) over real time, and it
fails when that virtual age reaches its baseline failure age.
Three regimes:
- Closed form. Identical units with an Exponential baseline give a
group lifetime that is a sum of exponential stages (each stage the time for
the next unit to fail at the current shared load), i.e. a
hypoexponential distribution, evaluated exactly with no simulation
(
is_simulated == False). - Numerical. Other identical units all age alike, so they fail in the
order of their exposures to failure, and a recursion over the failures
gives the lifetime's distribution (
is_simulated == False). - Simulation only. Different units have no survival curve: the group
draws lifetimes from the cumulative-exposure event loop for the system's
simulations, and the analyses that need its reliability refuse
(
is_simulated == True).
As a check, with no load effect (φ ≡ 1) the survivors do not accelerate and
the group reduces exactly to the ordinary k-out-of-n parallel result.
Load sharing is the "self-loading" sibling of the condition-based layer: there
the load is streamed in from sensors, here it is computed from the group's own
survivors. Warm standby uses the same virtual-age machinery with a fixed
dormant rate instead of a load-dependent one.
Common-cause failures¶
A shared cause can fail redundant units together, which the independent engine over-rates (Lesson 5); a common-cause model adds that coupling. (This is the mirror image of load sharing: there the coupling is load transfer, here it is a shared shock.)
A CCFGroup declares the coupled (symmetric) members
and the model, passed via ccf_groups. Three models:
BetaFactor(beta): a shareβof each member'sQfails the whole group at once, and the remaining(1 − β) Qis independent (Lesson 5).MGL(beta, gamma, ...): the Multiple Greek Letter model, which also resolves partial common causes (a cause failing some but not all of the group) through a cascade of conditional probabilities:β = P(shared by ≥ 2 | failed),γ = P(≥ 3 | ≥ 2), and so on. The probability that a cause fails a specific set ofkof themmembers is the standard basic-event probability
Q_k = [ 1 / C(m−1, k−1) ] · (ρ₁ ρ₂ ⋯ ρ_k) · (1 − ρ_{k+1}) · Q
with ρ₁ = 1, ρ₂ = β, ρ₃ = γ, …, ρ_{m+1} = 0; the Q_k of the sets
holding a unit sum to its Q, so, its own failure and the shared causes
being separate events, it fails with probability Q to first order (as
in PRA's basic events). A group of m members takes m − 1 letters, and MGL(β) on
two members is exactly BetaFactor(β).
- AlphaFactor(alphas): the alpha-factor
model, the same multiplicities by the shares α_1, …, α_m of a group's
failure events that failed exactly 1, …, m members, which event
counts estimate directly (NUREG/CR-5485): Q_k = α_k / C(m−1, k−1) · Q
for staggered testing, and Q_k = k α_k / (α_t C(m−1, k−1)) · Q with
α_t = Σ k α_k for non-staggered. It is the MGL model with the letters
those Q_k give.
The evaluation is exact, not a correction factor. Each model's
decompose splits the group's failure into an independent part plus a set of
mutually exclusive shocks (each a subset of members failing together).
The system reliability is then computed by conditioning on the shock outcome
of every group (in each branch the shocked members are down and the rest fail
only independently, so it is an ordinary independent system-reliability
evaluation) and blending the branches by their probabilities. Hence β = 0
reproduces the independent result exactly, and β = 1 makes a redundant
group no better than a single unit.
By default the model assumes each member's Q is small. "Exact" means
the evaluation of the model is exact; the default model is the PRA
basic-event one, which splits each member's failure probability (βQ
shared, (1 − β)Q independent) and is a rare-event model. Use it over
periods in which each member's failure probability stays small, such as a
mission or a proof-test interval. For a parallel pair with β = 0.3, the
system unreliability is within 0.3% of a rate-based beta-factor treatment at
Q = 0.01, 3.5% at Q = 0.1 and about 10% at Q = 0.3. From about
Q = 0.5 the pair comes out more reliable than an independent pair. Over
a whole life (Q → 1) the model stops describing a lifetime at all: under
the beta factor, each member would only ever fail with probability
1 − β(1 − β) (0.79 at β = 0.3). So a diagram warns, once for each group,
when a member's Q passes 0.1.
Over a lifetime, split the rate. With basis="rate" the model splits
each member's failure rate: in the members' cumulative hazard
H(t) = −log R(t), the shared cause is a shock of hazard β H(t), which has
not struck by t with probability R(t)^β, and each member's own causes
have hazard (1 − β) H(t). A member fails at the first of its causes, so
its reliability is R(t)^β · R(t)^(1 − β) = R(t): every member keeps its own
life distribution, whatever its shape, and the model holds over the whole
life. To first order in Q the shock strikes with βQ and each member fails
on its own with (1 − β)Q, as the probability split has it. Under MGL each
specific set of k members has a cause of its own, of hazard
(Q_k / Q) H(t), striking independently of the others; several may strike,
so the outcomes are the sets the struck causes fail between them.
Common cause is reflected in sf() / ff() (and quantities derived from
them) and persists through serialisation, basis included. Groups must be
symmetric (identical member models) and disjoint. An MTTF integrates over the
whole life: the exact mean() integrates a group that splits the rate, and
refuses one that splits a probability, where Q is no longer small. The
Monte-Carlo random(), mean(method="simulate") and MTTF interval draw a
rate-split group's shocks (each cause strikes at an exponential time in
H), and sample the members of a probability-split group independently,
leaving the common cause out. The importance measures condition a member
on its state through the shock outcomes (a node outside the groups is held
working and failed, as without them); parameter sensitivity and parameter
uncertainty take a group's members together, with its model's parameters;
and a copy of a beta-factor group's member joins the group in a redundancy
allocation. The condition-based methods would need members of different
ages, and raise a clear error on a CCF RBD; structural_importance, being
probability-free, is unaffected.
A RepairableRBD takes ccf_groups too. There a member's failures are a
rate, so the model splits the rate: each cause, a member's own or a shared
one, strikes at its share of it and fails the members it names that are up.
Each member alone fails as before; which are down together is a Markov chain
of the group (its members repaired at exponential rates, or found by their
tests), and the long-run values average the structure function over its
states, exactly (see Common-cause failures).
Availability¶
Each component alternates up and down, as good as new after each repair, independently of the others and of the system's state (Lesson 6).
Long-run availability and frequencies. The long-run availability is the
exact system probability at A_i = MTTF_i / (MTTF_i + MTTR_i), and the
failure frequency is ω = Σ_i I_B^i ω_i, with ω_i = 1 / (MTTF_i + MTTR_i)
and MTBF = 1 / ω, MUT = A / ω and MDT = (1 − A) / ω from it, all exact
(derivations). No
simulation is needed. An instantly repaired component (MTTR = 0) has
A_i = 1; a nested repairable RBD contributes its own system frequency.
Availability over time. From new, point_availability solves each
component's renewal equation
(Lesson 6) numerically,
on a grid of 1,000 steps over the component's typical up time (an error of
about 4e-7). Components that fail and are repaired
independently are up or down independently at every time, so the system's
A(t) is its system probability at the A_i(t), and
mission_availability is its mean over [0, T]. For a long mission that
mean is the long-run value plus about b/T: for one component
b = A (E[C²]/(2E[C]) − E[U²]/(2E[U])), C = U + D, positive for a life
that wears out, and for a system Σ_i I_B^i b_i to first order.
Expected events over a window. The frequency formula holds at every
time, not only in the long run: a component failing at t fails the system
if it is critical then, with probability I_B^i(t) at the availabilities
A_j(t). So the system's expected failures in [0, T) from new are
E[N(T)] = ∫₀ᵀ Σ_i I_B^i(t) dM_i(t)
with M_i(t) component i's expected failures by t, its renewal
function, which the renewal equation gives alongside A_i(t).
expected_failures and expected_events compute it, with the system's
planned outages counted the same way and the expected downtimes as
integrals of the unavailabilities; their long-run rates are ω and the
like. Events at exact times (replacements due at the same age or block
time) are taken together: they take the system down at most once.
From the present. Given each component's current state, only its first
period changes. A unit up at age a has a first life with survival
R(a + s) / R(a) (its replacement due at T − a under age replacement);
one down for r has a first down time with survival G(r + s) / G(r), and
starts new after it. The later units are new: their renewals are the
first period's end convolved with the renewal measure from new, so
A_i(t), M_i(t), and everything built on them above, follow as before.
Under block replacement the unit's own curve runs to the first block time,
which hands the block intervals' recursion the probability that it is up
there (and replaced) and the repairs going on; a calendar is shifted by the
state's since_scheduled, the time since its last scheduled replacement or
test. A component long in service whose state is not known starts in its
long-run (stationary) state: off a calendar it stays at A_i throughout,
with its events at their long-run rates; on one, it follows its settled
cycle from its since_scheduled. In the simulation, the first draw is the inverse
transform of the conditional distribution, qf(F(a) + u (1 − F(a))) − a,
worked through the cumulative hazard so that it keeps its precision at
great ages: still one uniform per draw.
availability() simulates mc_samples independent histories instead (each
component's alternating failures and repairs, merged in time order, with the
system's state re-evaluated at every event) and reports the fraction of
histories up at each time. The histories also give what the exact methods
do not: how much the counts, downtimes and costs over the window vary, and
the criticality measures below. Each point's confidence band is the Wilson
score interval (why).
For exponential components the simulation is held to the exact Markov
solution in the test suite, and on the benchmark diagrams to
point_availability.
A nested repairable RBD runs its own history on the same clock, and the outer system sees a state change when the nested system's state changes.
Criticality measures. From the simulated histories:
- The operational criticality index relates time: of the time the system was down, the fraction a node was also down (and likewise for up time).
- Intersection over union compares a node's up (or down) intervals with the system's: the time both were up over the time either was up.
- The failure criticality index counts events: the fraction of system failures a node's failure caused (the failure that took the system from up to down), and the fraction of the node's own failures that did so.
- The restoration criticality index does the same for repairs that restored the system.
Capacity¶
A reliability block diagram answers a yes-or-no question: does the system
work? A plant also asks how much it delivers. Give each node a capacity
c_i, the throughput it passes while it works (0 once it has failed), and
the system's capacity is the most that can flow from the input to the output
through the working nodes, each passing at most its capacity: the diagram's
maximum flow. The edges carry any amount, so
series: C = min(c_1, c_2, ...)
parallel: C = c_1 + c_2 + ...
and in general, by the max-flow min-cut theorem, the capacity is the least total capacity of a cut, a set of nodes whose failure disconnects the output:
C = min over cuts K of Σ_{i in K} c_i · [node i works]
A k-out-of-n node passes flow only while at least k of its inputs are
reached, as in the reliability analysis, so the capacity is positive exactly
when the system works: P(C > 0) is the reliability (or availability).
The distribution. Over the components' states, C takes finitely many
values. The probability of each follows as the system probability does. A
module's distribution comes from its members' in closed form: the
distribution of the least of independent capacities for a series chain, of
their sum for a parallel group, and of their sum while at least k work for
a k-out-of-n group. Combining distributions this way is the universal
generating function of multi-state systems (Ushakov; Lisnianski and
Levitin). What is left, such as a bridge, is conditioned on its parts'
capacities one at a time, carrying only each cut's running total and the
least complete total, and merging the states that agree on them.
What it gives. From the distribution:
P(C ≥ d), the probability of meeting a demandd: the system's reliability for that demand (its availability, in the long run);E[C], the expected capacity;E[min(C, d)] / d, the expected fraction of the demand delivered. In the long run this is the fraction of the demand met over time: the production availability, the figure plant owners contract on.
In the long run the probability of each level is the fraction of time spent
at it: the components' long-run availabilities stand in for their
reliabilities, as for the long-run availability. Over time from new, their
point availabilities A_i(t) do (point_capacity), and the fraction of the
demand delivered over a window is the time average of E[min(C, d)] / d
(mission_capacity). The availability simulation follows the capacity too:
after every component event it works out the capacity the components that
are up give, and the spread of the delivered fraction from window to window
comes from it.
Multi-state components. A component can itself have several levels: a
pump at full, half or no output. The distribution of each node's capacity
enters the calculation the same way, whether it has two levels or many, so
binary components are the special case. A component's levels can be fixed
(each with a probability while it works), come from a nested system, or come
from a model of its states over time: a component that degrades through
stages is in stage j at time t with probability
P(S_{j-1} ≤ t < S_j), where S_j is the sum of its first j stages'
times. In the long run, renewed after each failure, it spends its up time in
each stage in proportion to the stage's mean time (the renewal-reward
theorem); from new, it is in stage j at t if its first unit is, or a
unit put into service at s is at age t − s, summed over its renewals.
Costs¶
expected_cost_rate is the renewal-reward rate, each price times its rate
(ω_i, 1 − A_i, 1 − A_sys), with a cost distribution entering through
its mean (Lesson 7). By
linearity of expectation the expected cost of a finite window from new is
exact: expected_cost sums each category's expected events over the window (see
availability above) times its mean cost. The cost of a window is random,
though, and its distribution has no closed form, so cost() simulates it:
each history accumulates the charges at its failures and the downtime it
incurs. Its spread belongs to the system, while its mean's error shrinks
like 1/√N (Lesson 7).
The total cost of ownership is Σ a_i + H × the cost rate
(Lesson 7); with a continuous
discount_rate r, the present value, H counts as (1 − e^{−rH}) / r.
Redundancy that minimises it trades copies against downtime:
n_i independently repaired active copies of component i each cost
a_i + H · r_i (r_i its own running cost rate) and are all down
(1 − A_i)^{n_i} of the time, so a design costs
Σ n_i (a_i + H r_i) + H · downtime_cost_rate · (1 − A_sys). The bound
H · downtime_cost_rate · U^k (1 − U) on the saving of the k+1-th copy of
a component of unavailability U limits the copies tried; the search then
works as for redundancy allocation below.
Allocation¶
Redundancy allocation chooses integers n_i ≥ 1 (copies of each costed
node) to maximise system reliability subject to Σ c_i n_i ≤ budget, or to
minimise Σ c_i n_i subject to reliability ≥ target. With several
resources (cost, weight, volume, …) each has its own limit,
Σ c_ij n_i ≤ B_j, and a target may be combined with limits. With n_i
active independent copies, node i's reliability is 1 − (1 − p_i)^{n_i},
and each candidate is scored by the exact engine, so the structure is
arbitrary. A node may instead choose among component types: k_j copies of
each type j give 1 − ∏_j (1 − p_j)^{k_j}, all of one type or, with
mixing, any combination. A node may need k of its copies working
(k-out-of-n: the probability that at least k work, a binomial tail for
identical copies), and its spares may be cold standby, unpowered until
switched in, so that they do not age: the node is then a standby arrangement
of its copies. With perfect switching cold spares always beat active ones;
with imperfect switching they need not, and choosing the strategy node by node
is part of the optimisation (Coit, 2003). Both exact methods work on each
node's list of designs, less those another design of the node beats (using no
more of any resource while being at least as reliable), which can never be
part of a better system. Instead of one optimum, the whole trade-off can be
had: the designs no other beats on every resource and on reliability (the
Pareto front), which the dynamic program yields directly and which is found
by enumeration on other structures.
When every costed node is in series with the rest of the system (it lies on
every minimal path), the reliability factorises,
R = R_rest · ∏ (1 − (1 − p_i)^{n_i}), and a dynamic program over the nodes
finds the optimum exactly. It keeps only the partial designs that no other
beats on every resource and on log-reliability (dominance, as in Kettelle's
1962 method): a dominated partial design can never be completed into a
better one than the design dominating it. On other structures, because adding
a copy never lowers a coherent system's reliability, the best design within a
budget can always be found among the designs that cannot afford another copy,
which is what makes the exhaustive search practical. The greedy alternative
adds the copy with the best gain in log-reliability per unit cost (per unit
of its total share of the limits, with several) until the budget runs out;
it is fast but can stop short of the optimum.
Reliability-redundancy allocation chooses both at once: each node's
component reliability r_i, within bounds, and its copies n_i, to maximise
system reliability when what the copies use depends on both (a more reliable
component costs more). It is a mixed-integer nonlinear problem. For fixed
copies it is a continuous problem in the r_i, solved with the exact gradient
of the system reliability; over the copies, a vector can be skipped when even
the reliability with every node at the best component it could afford alone
does not beat the best design found, which keeps the exact search short.
Reliability allocation apportions a system target among components. There are many allocations that meet a target; each rule picks one.
- Equal apportionment gives every component the same reliability (Lesson 9).
- Proportional improvement (ARINC-style) scales every adjustable
component's failure probability by a common factor (
q_i → q_i · e^{−x w_i}with optional weightsw_i) and solves forx. The ARINC method scales failure rates instead, which is the same for small failure probabilities (Lesson 9). - Minimization of effort (Albert, 1958) is for a series system. If raising a
component's reliability from
xtoytakes effortG(x, y), the same function for every component, growing withyand adding up over successive steps (with Albert's regularity condition), the least total effort raises thekleast reliable components to one common levelR_0 = (R* / ∏_{i>k} R_i)^{1/k}and leaves the others, withkthe largest number for which thek-th reliability is below that level. - Cost-based allocation (Mettas, 2000) minimises
Σ c_i(R_i)subject to the system reliability reaching the target andR_min,i ≤ R_i < R_max,i, withc_i(R) = exp((1 − f_i)(R − R_min,i)/(R_max,i − R)). At the optimum, every improved component buys system reliability at the same marginal cost,c_i'(R_i) / I_B(i) = λwithI_B(i)its Birnbaum importance, and a component left unchanged would cost more thanλper unit: the improvement goes where it is cheapest per unit of system reliability. - The smallest log-odds change (not a named method) starts every
component at 0.5 and minimises
Σ s_i² / w_i, withs_icomponent i's log-oddslog(p_i / (1 − p_i))andw_iits weight, subject to the target. At the optimums_i ∝ w_i · p_i (1 − p_i) · I_B(i), so components that matter more, and more heavily weighted ones, move further. It is a structural allocation: it uses no component data, and with every component at 0.5 the Birnbaum importance is the structural importance, so small changes followw_itimes the structural importance exactly; larger ones drift as the importances are re-evaluated along the way.
Availability allocation applies the same rules to the components'
long-run availabilities A_i = MTTF_i / (MTTF_i + MTTR_i), with the system's
availability computed exactly as in Availability. An
allocated A_i fixes only the ratio MTTF_i / MTTR_i = A_i / (1 − A_i): it
is met by an MTTF of MTTR_i · A_i / (1 − A_i) at the current MTTR, or by an
MTTR of MTTF_i · (1 − A_i) / A_i at the current MTTF. Choosing between the
two is a cost-based allocation with two variables per component, the failure
rate λ_i = 1 / MTTF_i and the repair time, each with Mettas's cost
exp((1 − f)(x₀ − x)/(x − x_min)) as it falls from x₀ towards its floor
x_min. The odds that component i is down are λ_i · MTTR_i, so both
levers act on its log-odds of being up, −log λ_i − log MTTR_i, in the same
way: at the optimum every lever in use buys system availability at the same
marginal cost, the cheaper lever is used first, and at equal costs both move
by the same factor. Holding the failure rates gives maintainability
allocation. In a series system, cutting component i's MTTR by a factor
e^v raises the system's log-odds of being up at U_i / (1 − A_sys) per unit
of v, U_i its unavailability, so, at equal costs, the components down
most often get the largest cuts.
Maintenance models¶
Age replacement (NonRepairable) uses the renewal-reward rate
C(t) = (c_p R(t) + c_u F(t)) / ∫₀ᵗ R(u) du, which has a finite optimum
only for a unit that wears out; otherwise the rate is c_u / MTTF
(Lesson 8).
Minimal repair and overhaul. A minimal repair returns the unit to the
state just before it failed ("as bad as old"), so failures follow a
non-homogeneous Poisson process with cumulative intensity Λ(t). Overhauling
every t to as good as new, at cost c_o, with minimal repairs at c_r,
gives the Barlow–Hunter cost rate
C(t) = (c_r Λ(t) + c_o) / t
For a power-law (Crow–AMSAA) process, Λ(t) = (t/α)^β, and a finite optimum
needs β > 1. The expected time to the n-th failure has the closed form
E[T_n] = α Γ(n + 1/β) / Γ(n).
Imperfect repair. The Kijima virtual-age models sit between the two.
The unit fails as a new unit of its virtual age would, and each repair
resets the virtual age v after an operating interval x: in Kijima I to
v + q·x (the repair keeps a fraction q of the age added since the last
repair), in Kijima II to q·(v + x) (it keeps a fraction q of the whole
age). q = 0 is perfect repair (a renewal) and q = 1 minimal repair.
E[N(t)] then has no closed form and is estimated by simulating the process,
and the same overhaul policy applies. Replacing at the N-th failure instead
gives C(N) = (c_r (N − 1) + c_o) / E[T_N].
Scope¶
- Fitting failure data to distributions lives in
surpyval, not here. RePyability
consumes fitted models (anything exposing
sf/ff) as node inputs. - Plotting and dashboards live in the Reliafy app, not here. RePyability is the computational engine; it returns numbers and typed result objects.