///|
pub struct FailureMode {
id : String
process : String
cause : String
effect : String
severity : Int
occurrence : Int
detection : Int
owner : String
mitigation : String
closed : Bool
} derive(Debug, ToJson)
///|
pub fn failure_mode(
id~ : String,
process~ : String,
cause~ : String,
effect~ : String,
severity~ : Int,
occurrence~ : Int,
detection~ : Int,
owner~ : String,
mitigation~ : String,
) -> FailureMode {
{
id,
process,
cause,
effect,
severity: severity.max(1).min(10),
occurrence: occurrence.max(1).min(10),
detection: detection.max(1).min(10),
owner,
mitigation,
closed: false,
}
}
///|
pub fn FailureMode::rpn(self : FailureMode) -> Int {
self.severity * self.occurrence * self.detection
}
///|
pub fn FailureMode::risk_level(self : FailureMode) -> String {
let score = self.rpn()
if score >= 200 {
"critical"
} else if score >= 100 {
"high"
} else if score >= 50 {
"medium"
} else {
"low"
}
}
///|
pub fn close_failure_mode(mode : FailureMode) -> FailureMode {
{ ..mode, closed: true }
}
///|
pub fn sort_failure_modes(modes : Array[FailureMode]) -> Array[FailureMode] {
let result = modes.copy()
result.sort_by(fn(a, b) { b.rpn() - a.rpn() })
result
}
///|
pub fn critical_failure_modes(modes : Array[FailureMode]) -> Array[FailureMode] {
let result : Array[FailureMode] = []
for mode in modes {
if mode.rpn() >= 200 {
result.push(mode)
}
}
result
}
///|
pub fn open_failure_modes(modes : Array[FailureMode]) -> Int {
let mut count = 0
for mode in modes {
if !mode.closed {
count += 1
}
}
count
}
///|
pub fn average_rpn(modes : Array[FailureMode]) -> Double {
if modes.length() == 0 {
0.0
} else {
let mut total = 0
for mode in modes {
total += mode.rpn()
}
total.to_double() / modes.length().to_double()
}
}
///|
pub fn mitigation_coverage(modes : Array[FailureMode]) -> Double {
if modes.length() == 0 {
0.0
} else {
let mut count = 0
for mode in modes {
if mode.mitigation.length() > 0 {
count += 1
}
}
count.to_double() / modes.length().to_double()
}
}
///|
pub fn risk_reduction(before : FailureMode, after : FailureMode) -> Double {
let old = before.rpn().to_double()
if old <= 0.0 {
0.0
} else {
(old - after.rpn().to_double()) / old
}
}
///|
pub fn failure_modes_by_process(
modes : Array[FailureMode],
process : String,
) -> Array[FailureMode] {
let result : Array[FailureMode] = []
for mode in modes {
if mode.process == process {
result.push(mode)
}
}
result
}