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.
396 lines
13 KiB
Python
396 lines
13 KiB
Python
from collections import defaultdict
|
|
from datetime import datetime
|
|
from typing import List, Optional
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter, BackgroundTasks, HTTPException, background, status, Query
|
|
from sqlalchemy import select
|
|
from temporalio.client import Client
|
|
from src.aeros_contribution.service import update_contribution_bulk_mappings
|
|
from src.aeros_equipment.model import AerosEquipment
|
|
from src.aeros_simulation.model import EafContribution
|
|
from src.auth.service import CurrentUser
|
|
from src.database.core import DbSession
|
|
from src.database.service import CommonParameters
|
|
from src.models import StandardResponse
|
|
from src.aeros_equipment.service import update_equipment_for_simulation
|
|
from src.aeros_project.service import get_project
|
|
from temporal.workflow import SimulationWorkflow
|
|
from .schema import (
|
|
SimulationCalcResult,
|
|
SimulationInput,
|
|
SimulationPagination,
|
|
SimulationPlot,
|
|
SimulationPlotResult,
|
|
SimulationCalc,
|
|
SimulationData,
|
|
SimulationRankingParameters
|
|
)
|
|
from .service import (
|
|
create_simulation,
|
|
# execute_simulation,
|
|
get_all,
|
|
get_custom_parameters,
|
|
get_default_simulation,
|
|
get_simulation_by_id,
|
|
get_simulation_with_calc_result,
|
|
get_simulation_with_plot_result,
|
|
update_simulation,
|
|
get_result_ranking,
|
|
get_plant_calc_result
|
|
)
|
|
|
|
from .simulation_save_service import calculate_plant_eaf, execute_simulation
|
|
|
|
from src.aeros_equipment.schema import EquipmentWithCustomParameters
|
|
|
|
router = APIRouter()
|
|
active_simulations = {}
|
|
|
|
|
|
@router.get("", response_model=StandardResponse[SimulationPagination])
|
|
async def get_all_simulation(db_session: DbSession, common: CommonParameters, status: Optional[str] = Query(None)):
|
|
"""Get all simulation."""
|
|
|
|
results = await get_all(common, status)
|
|
|
|
return {
|
|
"data": results,
|
|
"status": "success",
|
|
"message": "Simulations result retrieved successfully",
|
|
}
|
|
|
|
@router.get("/{simulation_id}", response_model=StandardResponse[SimulationData])
|
|
async def get_simulation(db_session: DbSession, simulation_id):
|
|
"""Get simulation."""
|
|
result = await get_simulation_by_id(db_session=db_session, simulation_id=simulation_id)
|
|
|
|
return {
|
|
"data": result,
|
|
"status": "success",
|
|
"message": "Simulation result retrieved successfully",
|
|
}
|
|
|
|
@router.post("/run", response_model=StandardResponse[str])
|
|
async def run_simulations(
|
|
db_session: DbSession,
|
|
simulation_in: SimulationInput,
|
|
background_tasks: BackgroundTasks
|
|
):
|
|
"""RUN Simulation"""
|
|
|
|
temporal_client = await Client.connect("http://192.168.1.86:7233")
|
|
|
|
simulation = await create_simulation(
|
|
db_session=db_session, simulation_in=simulation_in
|
|
)
|
|
simulation_id = simulation.id
|
|
|
|
project = await get_project(db_session=db_session)
|
|
|
|
sim_data = simulation_in.model_dump()
|
|
sim_data["HubCnnId"] = str(simulation_id)
|
|
sim_data["projectName"] = project.project_name
|
|
|
|
# # Prepare async background task
|
|
# async def run_full_simulation():
|
|
# try:
|
|
# results = await update_equipment_for_simulation(
|
|
# db_session=db_session,
|
|
# project_name=project.project_name,
|
|
# schematic_name=simulation_in.SchematicName,
|
|
# overhaul_duration=simulation_in.OverhaulDuration,
|
|
# overhaul_interval=simulation_in.OverhaulInterval,
|
|
# offset=simulation_in.OffSet,
|
|
# custom_input=simulation_in.CustomInput,
|
|
# )
|
|
|
|
# await execute_simulation(
|
|
# db_session=db_session,
|
|
# simulation_id=simulation_id,
|
|
# sim_data=sim_data,
|
|
# is_saved=True,
|
|
# eq_update=results,
|
|
# )
|
|
|
|
# await calculate_plant_eaf(
|
|
# db_session=db_session,
|
|
# simulation_id=simulation_id,
|
|
# is_default=simulation_in.IsDefault,
|
|
# konkin_offset=simulation_in.Konkin_offset,
|
|
# )
|
|
|
|
# await update_contribution_bulk_mappings(
|
|
# db_session=db_session, simulation_id=simulation_id
|
|
# )
|
|
|
|
# except Exception as e:
|
|
# # TODO: log error into DB or logger
|
|
# print(f"Simulation {simulation_id} failed: {e}")
|
|
|
|
# # Add to background
|
|
# background_tasks.add_task(run_full_simulation)
|
|
|
|
handle = await temporal_client.start_workflow(
|
|
SimulationWorkflow.run,
|
|
sim_data,
|
|
id=f"simulation-{simulation_id}",
|
|
task_queue="simulation-task-queue",
|
|
)
|
|
|
|
return {
|
|
"data": str(simulation_id),
|
|
"status": "success",
|
|
"message": "Simulation started successfully",
|
|
}
|
|
|
|
@router.get(
|
|
"/result/calc/{simulation_id}",
|
|
response_model=StandardResponse[List[SimulationCalc]],
|
|
)
|
|
async def get_simulation_result(db_session: DbSession, simulation_id, schematic_name: Optional[str] = Query(None), node_type = Query(None, alias="nodetype")):
|
|
"""Get simulation result."""
|
|
if simulation_id == 'default':
|
|
simulation = await get_default_simulation(db_session=db_session)
|
|
simulation_id = simulation.id
|
|
|
|
simulation_result = await get_simulation_with_calc_result(
|
|
db_session=db_session, simulation_id=simulation_id, schematic_name=schematic_name, node_type=node_type
|
|
)
|
|
|
|
return {
|
|
"data": simulation_result,
|
|
"status": "success",
|
|
"message": "Simulation result retrieved successfully",
|
|
}
|
|
|
|
@router.get(
|
|
"/result/calc/{simulation_id}/plant",
|
|
response_model=StandardResponse[SimulationCalc],
|
|
)
|
|
async def get_simulation_result_plant(db_session: DbSession, simulation_id):
|
|
"""Get simulation result."""
|
|
if simulation_id == 'default':
|
|
simulation = await get_default_simulation(db_session=db_session)
|
|
simulation_id = simulation.id
|
|
|
|
|
|
simulation_result = await get_plant_calc_result(
|
|
db_session=db_session, simulation_id=simulation_id
|
|
)
|
|
|
|
return {
|
|
"data": simulation_result,
|
|
"status": "success",
|
|
"message": "Simulation result retrieved successfully",
|
|
}
|
|
|
|
|
|
|
|
@router.get(
|
|
"/result/plot/{simulation_id}",
|
|
response_model=StandardResponse[List[SimulationPlot]],
|
|
)
|
|
async def get_simulation_result_plot(db_session: DbSession, simulation_id):
|
|
"""Get simulation result."""
|
|
if simulation_id == 'default':
|
|
simulation = await get_default_simulation(db_session=db_session)
|
|
simulation_id = simulation.id
|
|
|
|
simulation_result = await get_simulation_with_plot_result(
|
|
db_session=db_session, simulation_id=simulation_id
|
|
)
|
|
|
|
return {
|
|
"data": simulation_result,
|
|
"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, use_location_tag: Optional[int] = Query(0)):
|
|
"""Get simulation result."""
|
|
if simulation_id == 'default':
|
|
simulation = await get_default_simulation(db_session=db_session)
|
|
simulation_id = simulation.id
|
|
|
|
|
|
simulation_result = await get_simulation_with_plot_result(
|
|
db_session=db_session, simulation_id=simulation_id, node_id=node_id, use_location_tag=use_location_tag
|
|
)
|
|
|
|
|
|
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):
|
|
"""Get simulation result."""
|
|
if simulation_id == 'default':
|
|
simulation = await get_default_simulation(db_session=db_session)
|
|
simulation_id = simulation.id
|
|
|
|
|
|
simulation_result = await get_result_ranking(db_session=db_session, simulation_id=simulation_id)
|
|
|
|
return {
|
|
"data": simulation_result,
|
|
"status": "success",
|
|
"message": "Simulation result retrieved successfully",
|
|
}
|
|
|
|
|
|
@router.get("/custom_parameters", response_model=StandardResponse[list])
|
|
async def get_custom_parameters_controller(db_session: DbSession):
|
|
"""Get simulation result."""
|
|
latest_simulation = await get_simulation_by_id(
|
|
db_session=db_session, simulation_id=None, is_completed=True
|
|
)
|
|
custom_parameters = await get_custom_parameters(
|
|
db_session=db_session, simulation_id=latest_simulation.id
|
|
)
|
|
|
|
results = [{node.aeros_node.node_name: node.eaf} for node in custom_parameters]
|
|
|
|
return {
|
|
"data": results,
|
|
"status": "success",
|
|
"message": "Simulation result retrieved successfully",
|
|
}
|
|
|
|
|
|
|
|
airflow_router = APIRouter()
|
|
|
|
@airflow_router.post("/calculate_eaf_contribution", response_model=StandardResponse[dict])
|
|
async def calculate_contribution(
|
|
db_session: DbSession,
|
|
simulation_in: SimulationInput,
|
|
batch_num: int = Query(0, ge=0)
|
|
):
|
|
"""RUN Simulation"""
|
|
|
|
#simulation_id = "2e0755bf-8cce-4743-9659-8d9920d556e7"
|
|
project = await get_project(db_session=db_session)
|
|
main_edh = 1.5000000000000966
|
|
main_efficiency_uptime = 697.5303030303029 - 1.5000000000000966
|
|
|
|
try:
|
|
contribution_results = defaultdict()
|
|
simulations_eq = select(AerosEquipment)
|
|
eaf_contributions_data = []
|
|
|
|
eqs = (await db_session.execute(simulations_eq)).scalars().all()
|
|
|
|
batch_size = 20
|
|
start_index = batch_num * batch_size
|
|
end_index = start_index + batch_size
|
|
|
|
|
|
if start_index >= len(eqs):
|
|
return {
|
|
"data": contribution_results,
|
|
"status": "success",
|
|
"message": "No more equipment to process",
|
|
}
|
|
|
|
if end_index > len(eqs):
|
|
end_index = len(eqs)
|
|
|
|
|
|
|
|
eqs = eqs[start_index:end_index]
|
|
for eq in eqs:
|
|
simulation = await create_simulation(
|
|
db_session=db_session, simulation_in=simulation_in
|
|
)
|
|
|
|
sim_data = simulation_in.model_dump(exclude={"SimulationName"})
|
|
sim_data["HubCnnId"] = str(simulation.id)
|
|
sim_data["projectName"] = project.project_name
|
|
|
|
custom_input = {
|
|
eq.node_name: {
|
|
"mttr": 721,
|
|
"failure_rate": 0.01,
|
|
}
|
|
}
|
|
|
|
results = await update_equipment_for_simulation(
|
|
db_session=db_session, project_name=project.project_name, schematic_name=simulation_in.SchematicName, custom_input=custom_input
|
|
)
|
|
|
|
# await update_simulation(
|
|
# db_session=db_session, simulation_id=simulation_id, data={"reliability": results}
|
|
# )
|
|
|
|
await execute_simulation(
|
|
db_session=db_session, simulation_id=simulation.id, sim_data=sim_data, is_saved=True, eq_update=results
|
|
)
|
|
|
|
eaf, edh, efficiency_uptime = await calculate_plant_eaf(db_session=db_session, simulation_id=simulation.id)
|
|
|
|
eaf_contribution = (main_efficiency_uptime - efficiency_uptime)/main_efficiency_uptime if main_efficiency_uptime else 0
|
|
|
|
contribution_results[eq.node_name] = {
|
|
"eaf": eaf,
|
|
"edh": edh,
|
|
"efficiency_uptime": efficiency_uptime,
|
|
"eaf_contribution": eaf_contribution
|
|
}
|
|
|
|
eaf_conf = EafContribution(
|
|
location_tag=eq.node_name,
|
|
eaf_contribution=eaf_contribution,
|
|
efficiency_uptime=efficiency_uptime,
|
|
edh=edh,
|
|
)
|
|
|
|
eaf_contributions_data.append(eaf_conf)
|
|
|
|
await db_session.delete(simulation)
|
|
await db_session.commit()
|
|
|
|
db_session.add_all(eaf_contributions_data)
|
|
await db_session.commit()
|
|
return {
|
|
"data": contribution_results,
|
|
"status": "success",
|
|
"message": "Simulation created successfully",
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e)
|
|
)
|
|
|
|
|
|
# @router.get("/status/{simulation_id}", response_model=StandardResponse[None])
|
|
# async def get_simulation_status(simulation_id: str):
|
|
# """Get simulation status."""
|
|
# if simulation_id not in active_simulations:
|
|
# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Simulation not found")
|
|
|
|
# return active_simulations[simulation_id]
|
|
|
|
|
|
# @router.post("/cancel/{simulation_id}", response_model=StandardResponse[None])
|
|
# async def cancel_simulation(simulation_id: str):
|
|
# """Cancel simulation."""
|
|
# if simulation_id not in active_simulations:
|
|
# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Simulation not found")
|
|
|
|
# active_simulations[simulation_id].update({
|
|
# "status": "cancelled",
|
|
# "cancelled_at": datetime.now()
|
|
# })
|
|
|
|
# return active_simulations[simulation_id]
|