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 }