fix eaf calculation

main
Cizz22 4 months ago
parent 33808a0ac1
commit 3ab3338e6d

@ -14,6 +14,7 @@ from .schema import (
SimulationCalcResult,
SimulationInput,
SimulationPagination,
SimulationPlot,
SimulationPlotResult,
SimulationCalc,
SimulationData,
@ -144,7 +145,7 @@ async def get_simulation_result_plant(db_session: DbSession, simulation_id):
@router.get(
"/result/plot/{simulation_id}",
response_model=StandardResponse[SimulationPlotResult],
response_model=StandardResponse[List[SimulationPlot]],
)
async def get_simulation_result_plot(db_session: DbSession, simulation_id):
"""Get simulation result."""
@ -157,6 +158,24 @@ async def get_simulation_result_plot(db_session: DbSession, simulation_id):
"status": "success",
"message": "Simulation result retrieved successfully",
}
@router.get(
"/result/plot/{simulation_id}/{node_id}",
response_model=StandardResponse[SimulationPlot],
)
async def get_simulation_result_plot_per_node(db_session: DbSession, simulation_id, node_id):
"""Get simulation result."""
simulation_result = await get_simulation_with_plot_result(
db_session=db_session, simulation_id=simulation_id, node_id=node_id
)
return {
"data": simulation_result,
"status": "success",
"message": "Simulation result retrieved successfully",
}
@router.get("/result/ranking/{simulation_id}", response_model=StandardResponse[List[SimulationRankingParameters]])
async def get_simulation_result_ranking(db_session: DbSession, simulation_id):

@ -26,7 +26,7 @@ from .model import (
)
from src.aeros_equipment.model import AerosEquipment, AerosEquipmentCustomParameterData
from src.aeros_equipment.schema import EquipmentWithCustomParameters
from .schema import SimulationInput, SimulationRankingParameters
from .schema import SimulationInput, SimulationPlotResult, SimulationRankingParameters
from .utils import calculate_eaf
client = httpx.AsyncClient(timeout=300.0)
@ -232,27 +232,56 @@ async def get_result_ranking(*, db_session: DbSession, simulation_id: UUID):
async def get_simulation_with_plot_result(
*, db_session: DbSession, simulation_id: UUID, node_type: Optional[str] = None
*, db_session: DbSession, simulation_id: UUID, node_type: Optional[str] = None, node_id: Optional[str] = None
):
"""Get a simulation by id."""
query = (
select(AerosSimulation)
.where(AerosSimulation.id == simulation_id)
.options(
selectinload(AerosSimulation.plot_results).options(
selectinload(AerosSimulationPlotResult.aeros_node)
)
)
)
if node_type:
query = query.join(
AerosNode, AerosNode.id == AerosSimulation.plot_results.aeros_node_id
).filter(AerosNode.node_type == node_type)
simulation = await db_session.execute(query)
return simulation.scalar()
# query = (
# select(AerosSimulation)
# .where(AerosSimulation.id == simulation_id)
# .options(
# selectinload(AerosSimulation.plot_results).options(
# selectinload(AerosSimulationPlotResult.aeros_node)
# )
# )
# )
# if node_type:
# query = query.join(
# AerosNode, AerosNode.id == AerosSimulation.plot_results.aeros_node_id
# ).filter(AerosNode.node_type == node_type)
# if node_id:
# if node_id == 'plant':
# query = query.join(
# AerosNode, AerosNode.id == AerosSimulation.plot_results.aeros_node_id
# ).filter(AerosNode.node_name == '- TJB - Unit 3 -')
# else:
# query = query.join(
# AerosNode, AerosNode.id == AerosSimulation.plot_results.aeros_node_id
# ).filter(AerosNode.id == node_id)
# simulation = await db_session.execute(query)
# return simulation.scalar()
query = select(AerosSimulationPlotResult).where(
AerosSimulationPlotResult.aeros_simulation_id == simulation_id
).options(selectinload(AerosSimulationPlotResult.aeros_node))
if node_id:
if node_id == 'plant':
query = query.join(
AerosNode, AerosNode.id == AerosSimulationPlotResult.aeros_node_id
).filter(AerosNode.node_name == '- TJB - Unit 3 -')
else:
query = query.join(
AerosNode, AerosNode.id == AerosSimulationPlotResult.aeros_node_id
).filter(AerosNode.id == node_id)
res = await db_session.execute(query)
return res.scalar_one_or_none()
simulation_plots = await db_session.execute(query)
return simulation_plots.scalars().all()
async def get_calc_result_by(
*, db_session: DbSession, simulation_id: UUID, node_name: Optional[str] = None
@ -548,9 +577,33 @@ async def save_simulation_result(
}
calc_objects = []
plot_objects = []
try:
for result in plot_result:
node_type = "RegularNode" if result["nodeType"] == "RegularNode" else "SchematicNode"
node = avaiable_nodes.get(f"{node_type}:{result['nodeName']}", None)
if not node:
if result["nodeType"] != "RegularNode" and result["nodeType"] != "Schematic":
continue
node = await get_or_save_node(
db_session=db_session, node_data=result, type="plot"
)
plot_result = AerosSimulationPlotResult(
aeros_simulation_id=simulation_id,
aeros_node_id=node.id,
max_flow_rate=result["maxFlowrate"],
storage_capacity=result["storageCapacity"],
point_availabilities=result["pointAvailabilities"],
point_flowrates=result["pointFlowrates"],
timestamp_outs=result["timeStampOuts"],
)
plot_objects.append(plot_result)
for result in calc_result:
node_type = "RegularNode" if result["nodeType"] == "RegularNode" else "SchematicNode"
node = avaiable_nodes.get(f"{node_type}:{result['nodeName']}", None)
@ -561,6 +614,9 @@ async def save_simulation_result(
"mttr": 0,
"parameters": {}
})
plot_data = next(plot for plot in plot_objects if plot.aeros_node_id == node.id) if node else {}
if not node:
@ -574,7 +630,9 @@ async def save_simulation_result(
available_hours=result["totalUpTime"],
period_hours=result["totalUpTime"] + result["totalDowntime"],
actual_production=result["production"],
ideal_production=result["idealProduction"]
ideal_production=result["idealProduction"],
downtime_hours = result["totalDowntime"],
plot_data=plot_data
)
efor = (result["totalDowntime"] / (result["totalDowntime"] + result["totalUpTime"]))*100 if (result["totalDowntime"] + result["totalUpTime"]) > 0 else 0
@ -623,27 +681,7 @@ async def save_simulation_result(
calc_objects.append(calc_result)
for result in plot_result:
node_type = "RegularNode" if result["nodeType"] == "RegularNode" else "SchematicNode"
node = avaiable_nodes.get(f"{node_type}:{result['nodeName']}", None)
if not node:
if result["nodeType"] != "RegularNode" and result["nodeType"] != "Schematic":
continue
node = await get_or_save_node(
db_session=db_session, node_data=result, type="plot"
)
plot_result = AerosSimulationPlotResult(
aeros_simulation_id=simulation_id,
aeros_node_id=node.id,
max_flow_rate=result["maxFlowrate"],
storage_capacity=result["storageCapacity"],
point_availabilities=result["pointAvailabilities"],
point_flowrates=result["pointFlowrates"],
timestamp_outs=result["timeStampOuts"],
)
plot_objects.append(plot_result)
except Exception as e:
simulation = await get_simulation_by_id(

@ -2,7 +2,9 @@ def calculate_eaf(
available_hours: float,
period_hours: float,
actual_production: float,
ideal_production: float
ideal_production: float,
downtime_hours,
plot_data
):
"""
Calculate EAF using the time-based method from PLN document
@ -20,18 +22,19 @@ def calculate_eaf(
"""
try:
# Calculate lost production
lost_production = ideal_production - actual_production
max_capacity = 660
# Calculate total equivalent derate hours
total_equivalent_derate_hours = lost_production / max_capacity
# Calculate EAF
effective_available_hours = available_hours - total_equivalent_derate_hours
return (effective_available_hours / period_hours) * 100 if period_hours > 0 else 0, total_equivalent_derate_hours
# Calculate lost production
lost_production = ideal_production - actual_production
max_capacity = plot_data.max_flow_rate
# Calculate total equivalent derate and outage hours
total_equivalent_derate_and_outage_hours = lost_production / max_capacity if max_capacity > 0 else 0
total_equivalent_derate = total_equivalent_derate_and_outage_hours - downtime_hours
# Calculate EAF
effective_available_hours = available_hours - total_equivalent_derate
return (effective_available_hours / period_hours) * 100 if period_hours > 0 else 0, total_equivalent_derate
except Exception as e:
print("Error calculating EAF:", str(e))
raise
print("Error calculating EAF:", e)
raise
# def calculate_efor(
# forced_outage_hours: float,
@ -54,3 +57,33 @@ def calculate_eaf(
# numerator_efor = forced_outage_hours + equivalent_forced_derate_hours
# denominator_efor = forced_outage_hours + service_hours + synchronous_hours + equivalent_forced_derate_hours_rs
# return (numerator_efor / denominator_efor * 100) if denominator_efor > 0 else 0
def calculate_derating(data_list, max_flow_rate: float = 660) -> float:
"""
Calculate total time when flow rate is below maximum.
Method 2: Time intervals AFTER each measurement point.
This assumes each data point represents the start of a period with that flow rate.
"""
# Sort data by cumulative time to ensure proper order
sorted_data = sorted(data_list, key=lambda x: x['cumulativeTime'])
total_time_below_max = 0.0
print("=== Method 2: Time intervals AFTER each measurement ===")
for i in range(len(sorted_data) - 1):
current_data = sorted_data[i]
next_data = sorted_data[i + 1]
# If current flow rate is below max, add this time interval
if current_data['flowRate'] < max_flow_rate and current_data['flowRate'] != 0:
# Time interval until next measurement
time_interval = next_data['cumulativeTime'] - current_data['cumulativeTime']
total_time_below_max += time_interval
print(f"Derating hours: {time_interval:.2f}")
return total_time_below_max
Loading…
Cancel
Save