You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
6.0 KiB
Python
220 lines
6.0 KiB
Python
from uuid import uuid4
|
|
|
|
from src.aeros_simulation.ramp_engine import (
|
|
_calc_result,
|
|
_duration_to_hours,
|
|
_filter_overrides_to_model,
|
|
build_ramp_distribution_overrides_from_rbd_reliability,
|
|
build_ramp_distribution_overrides,
|
|
selected_simulation_engine,
|
|
)
|
|
from src.aeros_simulation.schema import SimulationCalc
|
|
|
|
|
|
def test_selected_simulation_engine_defaults_to_aeros():
|
|
assert selected_simulation_engine({}) == "aeros"
|
|
|
|
|
|
def test_duration_to_hours_supports_aeros_units():
|
|
assert _duration_to_hours(2, "UYear") == 17520
|
|
assert _duration_to_hours(3, "UDay") == 72
|
|
assert _duration_to_hours(5, "UHour") == 5
|
|
|
|
|
|
def test_build_ramp_distribution_overrides_from_ahm_custom_input():
|
|
overrides = build_ramp_distribution_overrides(
|
|
{
|
|
"CustomInput": {
|
|
"EQ001": {
|
|
"mttr": 10,
|
|
"failure_rate": 0.5,
|
|
"distribution": "Weibull",
|
|
}
|
|
}
|
|
}
|
|
)
|
|
|
|
assert overrides["EQ001"]["repair_duration"] == 10
|
|
assert overrides["EQ001"]["model"] == {
|
|
"type": "NonRepairable",
|
|
"distribution": {"type": "Weibull", "shape": 1.0, "scale": 2000000.0},
|
|
}
|
|
|
|
|
|
def test_build_ramp_distribution_overrides_from_aeros_distribution_fields():
|
|
overrides = build_ramp_distribution_overrides(
|
|
{
|
|
"DistributionOverrides": {
|
|
"PUMP-A": {
|
|
"relDisType": "Weibull2",
|
|
"relDisP1": 1.7,
|
|
"relDisP2": 9000,
|
|
"cmDisType": "Normal",
|
|
"cmDisP1": 8,
|
|
"cmDisP2": 1.5,
|
|
}
|
|
}
|
|
}
|
|
)
|
|
|
|
assert overrides["PUMP-A"]["model"]["distribution"] == {
|
|
"type": "Weibull",
|
|
"shape": 1.7,
|
|
"scale": 9000.0,
|
|
}
|
|
assert overrides["PUMP-A"]["repair_duration"] == {
|
|
"type": "Normal",
|
|
"mean": 8.0,
|
|
"std_dev": 1.5,
|
|
}
|
|
|
|
|
|
def test_ramp_calc_result_uses_numeric_defaults_for_aeros_only_fields():
|
|
calc = _calc_result(
|
|
simulation_id=uuid4(),
|
|
node_id=uuid4(),
|
|
metrics={
|
|
"system_availability": 0.95,
|
|
"system_uptime": 95,
|
|
"system_downtime": 5,
|
|
"system_failures": 2,
|
|
},
|
|
)
|
|
|
|
assert calc.stg_input == 0
|
|
assert calc.stg_output == 0
|
|
assert calc.average_level == 0
|
|
assert calc.availability == 0.95
|
|
assert calc.eaf == 95.0
|
|
assert calc.sof == 0
|
|
assert calc.total_mo_downtime == 0
|
|
assert calc.total_po_downtime == 0
|
|
|
|
|
|
def test_simulation_calc_response_defaults_nullable_numbers_for_fe():
|
|
payload = {
|
|
"id": uuid4(),
|
|
"total_downtime": 5,
|
|
"total_uptime": 95,
|
|
"num_events": 2,
|
|
"production": 10,
|
|
"production_std": 0,
|
|
"ideal_production": 12,
|
|
"availability": 0.95,
|
|
"efficiency": 83.3,
|
|
"effective_loss": 2,
|
|
"num_cm": 2,
|
|
"cm_waiting_time": 0,
|
|
"total_cm_downtime": 5,
|
|
"num_pm": 0,
|
|
"total_pm_downtime": 0,
|
|
"num_ip": 0,
|
|
"total_ip_downtime": 0,
|
|
"num_oh": 0,
|
|
"total_oh_downtime": 0,
|
|
"t_wait_for_crew": 0,
|
|
"t_wait_for_spare": 0,
|
|
"duration_at_full": 95,
|
|
"duration_above_hh": 0,
|
|
"duration_above_h": 0,
|
|
"duration_below_l": 0,
|
|
"duration_below_ll": 0,
|
|
"duration_at_empty": 5,
|
|
"stg_input": 0,
|
|
"eaf": 95,
|
|
"eaf_konkin": None,
|
|
"efor": None,
|
|
"derating_hours": None,
|
|
"aeros_node": {
|
|
"id": uuid4(),
|
|
"node_type": "SchematicNode",
|
|
"node_id": 1,
|
|
"node_name": "- TJB - Unit 3 -",
|
|
"structure_name": "- TJB - Unit 3 -",
|
|
"schematic_name": "- TJB - Unit 3 -",
|
|
"schematic_id": uuid4(),
|
|
"model_image": [],
|
|
"equipment": None,
|
|
},
|
|
"contribution": None,
|
|
"criticality": None,
|
|
"contribution_factor": None,
|
|
"sof": None,
|
|
}
|
|
|
|
calc = SimulationCalc.model_validate(payload)
|
|
|
|
assert calc.eaf_konkin == 0
|
|
assert calc.efor == 0
|
|
assert calc.derating_hours == 0
|
|
assert calc.sof == 0
|
|
|
|
|
|
def test_build_ramp_distribution_overrides_from_rbd_reliability():
|
|
overrides = build_ramp_distribution_overrides_from_rbd_reliability(
|
|
{
|
|
"PUMP-A": {
|
|
"distribution": "NHPPTTFF",
|
|
"beta": 1.4,
|
|
"eta": 8000,
|
|
"mttr": 12,
|
|
},
|
|
"PUMP-B": {
|
|
"distribution": "Weibull2",
|
|
"beta": 2,
|
|
"eta": 9000,
|
|
"mttr": 8,
|
|
},
|
|
}
|
|
)
|
|
|
|
assert overrides["PUMP-A"]["model"] == {
|
|
"type": "RepairableNHPP",
|
|
"beta": 1.4,
|
|
"eta": 8000.0,
|
|
}
|
|
assert overrides["PUMP-A"]["repair_duration"] == 12.0
|
|
assert overrides["PUMP-B"]["model"]["distribution"] == {
|
|
"type": "Weibull",
|
|
"shape": 2.0,
|
|
"scale": 9000.0,
|
|
}
|
|
|
|
|
|
def test_build_ramp_distribution_overrides_uses_rbd_eta_for_exponential():
|
|
overrides = build_ramp_distribution_overrides_from_rbd_reliability(
|
|
{
|
|
"HEATER-A": {
|
|
"distribution": "Exponential2",
|
|
"beta": 13034.0,
|
|
"eta": 8760.0,
|
|
"mttr": 6,
|
|
}
|
|
}
|
|
)
|
|
|
|
assert overrides["HEATER-A"]["model"]["distribution"] == {
|
|
"type": "Exponential",
|
|
"eta": 8760.0,
|
|
}
|
|
|
|
|
|
def test_filter_overrides_keeps_only_assets_present_in_model():
|
|
overrides = {
|
|
"3AH-AU501A": {"repair_duration": 4},
|
|
"3bad-m531": {"repair_duration": 6},
|
|
"00CHA-CV804": {"repair_duration": 8},
|
|
}
|
|
kept, dropped = _filter_overrides_to_model(overrides, {"3AH-AU501A", "3BAD-M531"})
|
|
|
|
assert set(kept) == {"3AH-AU501A", "3bad-m531"}
|
|
assert dropped == ["00CHA-CV804"]
|
|
|
|
|
|
def test_filter_overrides_passes_through_when_model_assets_unknown():
|
|
overrides = {"3AH-AU501A": {"repair_duration": 4}}
|
|
kept, dropped = _filter_overrides_to_model(overrides, set())
|
|
|
|
assert kept == overrides
|
|
assert dropped == []
|