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
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
|
|
}
|