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.

205 lines
6.8 KiB
Python

from typing import Optional, List
from uuid import UUID
from fastapi import HTTPException, status
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from src.aeros_simulation.model import AerosSimulation
from src.aeros_simulation.service import (
get_calc_result_by,
get_default_simulation,
get_simulation_by_id,
get_simulation_node_by,
)
from src.auth.service import CurrentUser
from src.database.core import DbSession
from src.database.service import search_filter_sort_paginate
from tkinter.constants import E
from src.dashboard_model.model import RBDMasterData
from src.dashboard_model.schema_masterdata import RBDMasterDataUpdate
async def _get_or_create_master_data(db_session: DbSession, name: str, default_float: float):
query = select(RBDMasterData).where(RBDMasterData.name == name)
result = await db_session.execute(query)
record = result.scalars().first()
if not record:
record = RBDMasterData(name=name, value_float=default_float)
db_session.add(record)
await db_session.commit()
await db_session.refresh(record)
return record
async def get_master_data_list(db_session: DbSession):
# Ensure Current EAF exists
await _get_or_create_master_data(db_session, "Current EAF Realization", 85.62)
await _get_or_create_master_data(db_session, "Last Overhaul Date", 0)
query = select(RBDMasterData)
result = await db_session.execute(query)
return result.scalars().all()
async def update_master_data(db_session: DbSession, md_id: UUID, payload: RBDMasterDataUpdate):
query = select(RBDMasterData).where(RBDMasterData.id == md_id)
result = await db_session.execute(query)
record = result.scalars().first()
if not record:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Master Data not found"
)
if payload.value_float is not None:
record.value_float = payload.value_float
if payload.value_string is not None:
record.value_string = payload.value_string
if payload.month is not None:
record.month = payload.month
if payload.year is not None:
record.year = payload.year
await db_session.commit()
await db_session.refresh(record)
return record
async def get_model_data(*, db_session: DbSession, simulation_id: Optional[UUID]):
if simulation_id:
simulation = await get_simulation_by_id(db_session=db_session, simulation_id=simulation_id)
else:
simulation = await get_default_simulation(db_session=db_session)
if not simulation:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Simulation not found"
)
main_calc_data = await get_calc_result_by(
db_session=db_session, simulation_id=simulation.id, node_name="- TJB - Unit 3 -"
)
# Total time period
total_time = main_calc_data.total_uptime + main_calc_data.total_downtime
# Availability Factor (same as your first formula - this one is correct)
availability = (main_calc_data.availability) * 100
is_oh = (main_calc_data.sof >= 10)
# Equivalent Forced Outage Rate (EFOR)
EFOR = main_calc_data.efor
#Prediction
EAF = main_calc_data.eaf
Derating = main_calc_data.derating_hours
Trip = main_calc_data.num_events
EAF_KONKIN = main_calc_data.eaf_konkin
SOF = main_calc_data.sof
#Fetch Master Data EAF realization
eaf_record = await _get_or_create_master_data(db_session, "Current EAF Realization", 85.62)
eaf_real_val = eaf_record.value_float if eaf_record.value_float is not None else 85.62
#Realization
EAF_REAL = eaf_real_val
EFOR_REAL = 1.7
EAF_KONKIN_REAL = eaf_real_val
powerplant_reliability = {
"Plant Control": 98,
"SPS": 98,
"Turbine": 98,
"Generator": 98,
"Condensate Water": 98,
"Feedwater System": 98,
"Cooling Water": 98,
"SCR": 98,
"Ash Handling": 98,
"Air Flue Gas": 98,
"Boiler": 98,
"SAC-IAC": 98,
"KLH": 98,
"CL": 98,
"DESALINATION (CP)": 98,
"FGD": 98,
"CHS": 98,
"SSB": 98,
"WTP": 98,
}
# Fetch Forecasts
forecast_weekly = await get_latest_sim_results_by_pattern(db_session, "Simulation_weekly_%")
forecast_monthly = await get_latest_sim_results_by_pattern(db_session, "Simulation_monthly_%")
return {
"id": str(simulation.id),
"name": simulation.simulation_name,
"availability": availability,
"EFOR": EFOR,
"SOF": SOF,
"EAF": {
"Prediction_EAF": EAF,
"Prediction_EAF_KONKIN": EAF_KONKIN,
"Real_EAF": EAF_REAL,
"Real_EAF_KONKIN": EAF_KONKIN_REAL,
"month": eaf_record.month,
"year": eaf_record.year
},
"Trip": {
"Prediction_Trip": Trip,
"Real_Trip": Trip
},
"Derating": {
"Prediction_Derating": Derating,
"Real_Derating": Derating
},
"powerplant_reliability": powerplant_reliability,
"forecast_weekly": forecast_weekly,
"forecast_monthly": forecast_monthly
}
async def get_latest_sim_results_by_pattern(db_session: DbSession, pattern: str):
from sqlalchemy import select
from src.aeros_simulation.model import AerosSimulation, AerosSimulationCalcResult, AerosNode
from src.aeros_simulation.service import get_plant_calc_result
query = select(AerosSimulation).where(AerosSimulation.simulation_name.like(pattern)).order_by(AerosSimulation.created_at.desc()).limit(1)
result = await db_session.execute(query)
simulation = result.scalars().first()
if not simulation:
return None
# Get plant node result
plant_res = await get_plant_calc_result(db_session=db_session, simulation_id=simulation.id)
# Get top 5 equipment causing trips (num_events)
trip_query = select(AerosSimulationCalcResult).join(AerosNode).where(
AerosSimulationCalcResult.aeros_simulation_id == simulation.id,
AerosNode.node_type == 'RegularNode'
).options(selectinload(AerosSimulationCalcResult.aeros_node)).order_by(AerosSimulationCalcResult.num_events.desc()).limit(5)
trip_res_exec = await db_session.execute(trip_query)
trip_results = trip_res_exec.scalars().all()
top_trips = []
for tr in trip_results:
if tr.num_events > 0:
top_trips.append({
"name": tr.aeros_node.node_name,
"events": tr.num_events,
"tag": tr.aeros_node.node_name
})
return {
"simulation_id": str(simulation.id),
"name": simulation.simulation_name,
"eaf": plant_res.eaf if plant_res else 0,
"efor": plant_res.efor if plant_res else 0,
"trips": int(plant_res.num_events) if plant_res else 0,
"top_trip_equipment": top_trips
}