feat: add support for equipment reliability levels and enable manual maintenance outage derating calculations

main
Cizz22 3 months ago
parent 9c8c3ae7a6
commit e021c62d37

@ -476,31 +476,57 @@ async def update_equipment_for_simulation(
# ---- CUSTOM INPUT HAS PRIORITY ----
if eq_name in custom_map:
custom_param = custom_map[eq_name]
level = custom_param.get("level")
mttr = custom_param.get("mttr")
failure_rate = custom_param.get("failure_rate")
if mttr is None or failure_rate is None:
log.warning(
"Custom input incomplete for %s, skipping",
eq_name_raw
)
continue
if failure_rate == 0:
MTBF = 1000000
else:
MTBF = 1e6 / float(failure_rate)
eq["cmDisP1"] = mttr
eq["relDisType"] = custom_param.get("distribution", "Fixed")
if eq["relDisType"] == "Fixed":
eq["relDisP1"] = MTBF
# Hard-coded states for specific levels
if level == "NoFailure":
log.info("Applying NoFailure state for %s", eq_name_raw)
mttr = 0
eq["relDisType"] = "Fixed"
eq["relDisP1"] = 1000000000.0 # Effectively never fails
eq["relDisP2"] = 0
eq["cmDisP1"] = 0
eq["cmDisType"] = "Fixed"
elif level == "Out of Service":
log.info("Applying Out of Service (Always Fail) state for %s", eq_name_raw)
mttr = 1000000000.0
eq["relDisType"] = "Fixed"
eq["relDisP1"] = 0.0001 # Fails immediately
eq["relDisP2"] = 0
eq["cmDisP1"] = mttr
eq["cmDisType"] = "Fixed"
else:
eq["relDisP1"] = 1
eq["relDisP2"] = MTBF
if mttr is None or failure_rate is None:
log.warning(
"Custom input incomplete for %s, skipping",
eq_name_raw
)
continue
# Handle failure_rate being an array (Numeric array in DB)
if isinstance(failure_rate, list):
rate_val = float(failure_rate[0]) if failure_rate else 1.0
else:
rate_val = float(failure_rate)
if rate_val <= 0:
MTBF = 1000000000.0
else:
MTBF = 1e6 / rate_val
eq["cmDisP1"] = mttr
eq["relDisType"] = custom_param.get("distribution", "Fixed")
if eq["relDisType"] == "Fixed":
eq["relDisP1"] = MTBF
eq["relDisP2"] = 0
else:
# For Weibull, use P1 as beta (1.0 default) and P2 as eta (MTBF)
eq["relDisP1"] = 1.0
eq["relDisP2"] = MTBF
eq["ohDisP1"] = overhaul_duration
eq["ohDisUnitCode"] = "UHour"

@ -309,13 +309,13 @@ async def calculate_plant_eaf(
manual_deratings=manual_deratings
)
# # Adjust EAF and edh for manual MO deratings
# if manual_mo_equiv_hours > 0:
# # eaf remains reduced by both edh and manual_mo_equiv_hours
# eaf = ((total_uptime - (edh + manual_mo_equiv_hours)) / total_period_time) * 100
# # maintenance deratings should contribute to scheduled metrics (SOF/ESOF)
# sof = ((seasonal_outage + manual_mo_equiv_hours) / total_period_time) * 100
# edh += manual_mo_equiv_hours
# Adjust EAF and edh for manual MO deratings
if manual_mo_equiv_hours > 0:
# eaf remains reduced by both edh and manual_mo_equiv_hours
eaf = ((total_uptime - (edh + manual_mo_equiv_hours)) / total_period_time) * 100
# maintenance deratings should contribute to scheduled metrics (SOF/ESOF)
sof = ((seasonal_outage + manual_mo_equiv_hours) / total_period_time) * 100
edh += manual_mo_equiv_hours
plant_calc_data.total_mo_downtime = manual_mo_outage_hours
plant_calc_data.total_po_downtime = po_downtime

Loading…
Cancel
Save