From d85155feb39ff945d13faadc2a2cb600e8e23b52 Mon Sep 17 00:00:00 2001 From: Cizz22 Date: Sat, 18 Apr 2026 13:18:42 +0700 Subject: [PATCH] feat: add manual deratings support to EAF calculation and simulation schema --- src/aeros_simulation/schema.py | 1 + src/aeros_simulation/simulation_save_service.py | 5 +++-- src/aeros_simulation/utils.py | 16 ++++++++++++++-- temporal/activity.py | 3 ++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/aeros_simulation/schema.py b/src/aeros_simulation/schema.py index d0c37d2..7b3ecec 100644 --- a/src/aeros_simulation/schema.py +++ b/src/aeros_simulation/schema.py @@ -26,6 +26,7 @@ class SimulationInput(DefultBase): OverhaulInterval: Optional[int] = Field(0) OverhaulDuration: Optional[int] = Field(1200) AhmJobId: Optional[str] = Field(None, max_length=50) + deratings: Optional[List[dict]] = [] class SimulationNode(DefultBase): id: UUID diff --git a/src/aeros_simulation/simulation_save_service.py b/src/aeros_simulation/simulation_save_service.py index cf15c79..18b9c66 100644 --- a/src/aeros_simulation/simulation_save_service.py +++ b/src/aeros_simulation/simulation_save_service.py @@ -252,7 +252,7 @@ async def create_calc_result_object( async def calculate_plant_eaf( - db_session: DbSession, simulation_id: UUID, mo_downtime: int, po_downtime:int, oh_interval:int, offset:int + db_session: DbSession, simulation_id: UUID, mo_downtime: int, po_downtime:int, oh_interval:int, offset:int, manual_deratings: list = None ): """Calculate overall plant EAF from individual node results.""" plant_calc_data = await get_plant_calc_result( @@ -289,7 +289,8 @@ async def calculate_plant_eaf( period_hours=total_period_time, forced_outage_hours=forced_outage, seasonal_outage_hours=seasonal_outage, - plot_data=plant_plot_data.timestamp_outs + plot_data=plant_plot_data.timestamp_outs, + manual_deratings=manual_deratings ) diff --git a/src/aeros_simulation/utils.py b/src/aeros_simulation/utils.py index cc4ec55..79ab6ed 100644 --- a/src/aeros_simulation/utils.py +++ b/src/aeros_simulation/utils.py @@ -26,7 +26,8 @@ def calculate_eaf( period_hours: float, forced_outage_hours:float, seasonal_outage_hours: float, - plot_data = None + plot_data = None, + manual_deratings: list = None ): """ Calculate EAF using the time-based method from PLN document @@ -45,9 +46,20 @@ def calculate_eaf( try: # Calculate lost production - max_capacity = 550 + max_capacity = 630 # Calculate total equivalent derate and outage hours edh = calculate_equivalent_derate_hours(plot_data, max_flow_rate=max_capacity) + + # Add manual deratings + if manual_deratings: + for d in manual_deratings: + # expected structure: { hours: float, capacity: float } + hours = float(d.get('hours', 0)) + capacity = float(d.get('capacity', 0)) + derating = max_capacity - capacity + if derating > 0: + edh += (hours * derating / max_capacity) + # Calculate EAF eaf = ((available_hours - edh) / period_hours) * 100 efor = ((forced_outage_hours + edh)/period_hours) * 100 diff --git a/temporal/activity.py b/temporal/activity.py index 0aa97fc..c11c6f4 100644 --- a/temporal/activity.py +++ b/temporal/activity.py @@ -65,7 +65,8 @@ async def calculate_plant_eaf_activity(params: dict): mo_downtime=params["MaintenanceOutages"], po_downtime=params["OverhaulDuration"], oh_interval=params["OverhaulInterval"], - offset=params["OffSet"] + offset=params["OffSet"], + manual_deratings=params.get("deratings", []) )