|
|
|
|
@ -1,9 +1,11 @@
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
import json
|
|
|
|
|
from typing import Optional
|
|
|
|
|
from uuid import uuid4, uuid4, UUID
|
|
|
|
|
import logging
|
|
|
|
|
import httpx
|
|
|
|
|
from fastapi import HTTPException, status
|
|
|
|
|
import ijson
|
|
|
|
|
from sqlalchemy import delete, select, update, and_
|
|
|
|
|
from sqlalchemy.orm import selectinload
|
|
|
|
|
|
|
|
|
|
@ -31,6 +33,7 @@ client = httpx.AsyncClient(timeout=300.0)
|
|
|
|
|
active_simulations = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Get Data Service
|
|
|
|
|
async def get_all(common: CommonParameters):
|
|
|
|
|
query = select(AerosSimulation).where(AerosSimulation.status == "completed")
|
|
|
|
|
|
|
|
|
|
@ -38,6 +41,19 @@ async def get_all(common: CommonParameters):
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
async def get_all_aeros_node(*, db_session: DbSession, schematic_name: Optional[str] = None):
|
|
|
|
|
query = select(AerosNode)
|
|
|
|
|
|
|
|
|
|
if schematic_name:
|
|
|
|
|
aeros_schematic = await get_aeros_schematic_by_name(db_session=db_session, schematic_name=schematic_name)
|
|
|
|
|
|
|
|
|
|
if not aeros_schematic:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Schematic not found")
|
|
|
|
|
|
|
|
|
|
query = query.where(AerosNode.aeros_schematic_id == aeros_schematic.id)
|
|
|
|
|
|
|
|
|
|
results = await db_session.execute(query)
|
|
|
|
|
return results.scalars().all()
|
|
|
|
|
|
|
|
|
|
async def get_simulation_by_id(
|
|
|
|
|
*,
|
|
|
|
|
@ -59,7 +75,6 @@ async def get_simulation_by_id(
|
|
|
|
|
results = await db_session.execute(query)
|
|
|
|
|
return results.scalar()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_simulation_node_by(*, db_session: DbSession, **kwargs):
|
|
|
|
|
"""Get a simulation node by column."""
|
|
|
|
|
# Build WHERE conditions from kwargs
|
|
|
|
|
@ -75,15 +90,12 @@ async def get_simulation_node_by(*, db_session: DbSession, **kwargs):
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
return result.scalar()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_or_save_node(*, db_session: DbSession, node_data: dict, type: str = "calc"):
|
|
|
|
|
"""Get a simulation node by column."""
|
|
|
|
|
node = await get_simulation_node_by(
|
|
|
|
|
db_session=db_session, node_name=node_data["nodeName"]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
raise Exception(node_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not node:
|
|
|
|
|
print("Creating new node")
|
|
|
|
|
@ -131,6 +143,195 @@ async def get_or_save_node(*, db_session: DbSession, node_data: dict, type: str
|
|
|
|
|
|
|
|
|
|
return node
|
|
|
|
|
|
|
|
|
|
async def get_aeros_schematic_by_name(*, db_session: DbSession, schematic_name: str):
|
|
|
|
|
query = select(AerosSchematic).where(AerosSchematic.schematic_name == schematic_name)
|
|
|
|
|
results = await db_session.execute(query)
|
|
|
|
|
return results.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
async def get_simulation_with_calc_result(
|
|
|
|
|
*, db_session: DbSession, simulation_id: UUID, aeros_node_id: Optional[UUID] = None, schematic_name: Optional[str] = None, node_type: Optional[str] = None
|
|
|
|
|
):
|
|
|
|
|
"""Get a simulation by id."""
|
|
|
|
|
query = (select(AerosSimulationCalcResult).filter(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id))
|
|
|
|
|
|
|
|
|
|
if schematic_name:
|
|
|
|
|
if schematic_name == "WTP":
|
|
|
|
|
query = query.join(
|
|
|
|
|
AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id
|
|
|
|
|
).filter(AerosNode.structure_name.contains(schematic_name))
|
|
|
|
|
else:
|
|
|
|
|
query = query.join(
|
|
|
|
|
AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id
|
|
|
|
|
).filter(AerosNode.structure_name.contains(schematic_name))
|
|
|
|
|
|
|
|
|
|
if node_type:
|
|
|
|
|
query = query.join(
|
|
|
|
|
AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id
|
|
|
|
|
).filter(AerosNode.node_type == node_type)
|
|
|
|
|
|
|
|
|
|
query = query.options(
|
|
|
|
|
selectinload(AerosSimulationCalcResult.aeros_node).options(
|
|
|
|
|
selectinload(AerosNode.equipment)
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
simulation = await db_session.execute(query)
|
|
|
|
|
|
|
|
|
|
return simulation.scalars().all()
|
|
|
|
|
|
|
|
|
|
async def get_plant_calc_result(
|
|
|
|
|
*, db_session, simulation_id: UUID
|
|
|
|
|
):
|
|
|
|
|
query = (select(AerosSimulationCalcResult).filter(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id,
|
|
|
|
|
).join(AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id)
|
|
|
|
|
.filter(AerosNode.node_name == "- TJB - Unit 3 -"))
|
|
|
|
|
|
|
|
|
|
query = query.options(
|
|
|
|
|
selectinload(AerosSimulationCalcResult.aeros_node).options(
|
|
|
|
|
selectinload(AerosNode.equipment)
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
calc = await db_session.execute(query)
|
|
|
|
|
|
|
|
|
|
return calc.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
async def get_result_ranking(*, db_session: DbSession, simulation_id: UUID):
|
|
|
|
|
|
|
|
|
|
query = select(AerosEquipment, AerosSimulationCalcResult.eaf).join(AerosNode, AerosNode.node_name == AerosEquipment.node_name).join(AerosSimulationCalcResult, AerosSimulationCalcResult.aeros_node_id == AerosNode.id)
|
|
|
|
|
|
|
|
|
|
query = query.filter(
|
|
|
|
|
and_(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id,
|
|
|
|
|
AerosNode.node_type == "RegularNode",
|
|
|
|
|
AerosEquipment.custom_parameters.any()
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
query = query.order_by(AerosSimulationCalcResult.eaf.desc())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
query = query.options(
|
|
|
|
|
selectinload(AerosEquipment.custom_parameters)).options(
|
|
|
|
|
selectinload(AerosEquipment.master_equipment)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
|
|
|
|
|
data = [
|
|
|
|
|
SimulationRankingParameters(
|
|
|
|
|
location_tag=equipment.location_tag,
|
|
|
|
|
master_equipment=equipment.master_equipment,
|
|
|
|
|
custom_parameters=equipment.custom_parameters,
|
|
|
|
|
eaf=eaf
|
|
|
|
|
)
|
|
|
|
|
for equipment, eaf in result
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_simulation_with_plot_result(
|
|
|
|
|
*, db_session: DbSession, simulation_id: UUID, node_type: 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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_calc_result_by(
|
|
|
|
|
*, db_session: DbSession, simulation_id: UUID, node_name: Optional[str] = None
|
|
|
|
|
):
|
|
|
|
|
"""Get a simulation node by column."""
|
|
|
|
|
# Build WHERE conditions from kwargs
|
|
|
|
|
query = select(AerosSimulationCalcResult).where(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if node_name:
|
|
|
|
|
query = query.join(AerosSimulationCalcResult.aeros_node).filter(AerosNode.node_name == node_name)
|
|
|
|
|
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
return result.scalar()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_custom_parameters(*, db_session: DbSession, simulation_id: UUID):
|
|
|
|
|
"""Get a simulation node by column."""
|
|
|
|
|
# Build WHERE conditions from kwargs
|
|
|
|
|
query = select(AerosSimulationCalcResult).where(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id
|
|
|
|
|
)
|
|
|
|
|
query = query.join(
|
|
|
|
|
AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id
|
|
|
|
|
)
|
|
|
|
|
query = query.where(AerosNode.node_type == "RegularNode")
|
|
|
|
|
query = (
|
|
|
|
|
query.order_by(AerosSimulationCalcResult.eaf.desc())
|
|
|
|
|
.limit(20)
|
|
|
|
|
.options(selectinload(AerosSimulationCalcResult.aeros_node))
|
|
|
|
|
)
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
return result.scalars().all()
|
|
|
|
|
|
|
|
|
|
async def get_regular_nodes_by_schematic(*, db_session: DbSession, schematic_name: str) -> set[UUID]:
|
|
|
|
|
"""
|
|
|
|
|
Get all regular node IDs that are descendants of a given schematic (system or subsystem).
|
|
|
|
|
Uses recursive CTE to traverse the hierarchy.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# Using recursive CTE to find all descendants
|
|
|
|
|
# First, find the root node(s) with the given schematic name
|
|
|
|
|
root_cte = (
|
|
|
|
|
select(AerosNode.id, AerosNode.schematic_id, AerosNode.ref_schematic_id,AerosNode.node_type, AerosNode.node_name)
|
|
|
|
|
.where(AerosNode.node_name == schematic_name)
|
|
|
|
|
.cte(name="hierarchy", recursive=True)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Recursive part: find all children
|
|
|
|
|
children_cte = (
|
|
|
|
|
select(AerosNode.id, AerosNode.schematic_id,AerosNode.ref_schematic_id ,AerosNode.node_type, AerosNode.node_name)
|
|
|
|
|
.select_from(
|
|
|
|
|
AerosNode.join(root_cte, AerosNode.schematic_id == root_cte.c.ref_schematic_id)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Union the base case and recursive case
|
|
|
|
|
hierarchy_cte = root_cte.union_all(children_cte)
|
|
|
|
|
|
|
|
|
|
# Final query to get only regular nodes from the hierarchy
|
|
|
|
|
query = (
|
|
|
|
|
select(hierarchy_cte.c.id)
|
|
|
|
|
.where(hierarchy_cte.c.node_type == "RegularNode") # Adjust this condition based on your node_type values
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
return set(result.scalars().all())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_all_schematic_aeros(*, db_session: DbSession):
|
|
|
|
|
query = select(AerosSchematic)
|
|
|
|
|
results = await db_session.execute(query)
|
|
|
|
|
return results.scalars().all()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Aeros Simulation Execution Service
|
|
|
|
|
|
|
|
|
|
async def execute_simulation(*, db_session: DbSession, simulation_id: Optional[UUID] = None, sim_data: dict, is_saved: bool = False, eq_update: dict = None):
|
|
|
|
|
"""Execute the actual simulation call"""
|
|
|
|
|
@ -139,6 +340,27 @@ async def execute_simulation(*, db_session: DbSession, simulation_id: Optional[U
|
|
|
|
|
print("Executing simulation with id: %s", simulation_id, sim_data["SchematicName"])
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if not is_saved:
|
|
|
|
|
response = await client.post(
|
|
|
|
|
f"{AEROS_BASE_URL}/api/Simulation/RunSimulation",
|
|
|
|
|
json=sim_data,
|
|
|
|
|
headers={"Content-Type": "application/json"},
|
|
|
|
|
)
|
|
|
|
|
response.raise_for_status()
|
|
|
|
|
result = response.json()
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
simulation = await get_simulation_by_id(
|
|
|
|
|
db_session=db_session, simulation_id=simulation_id
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
simulation.status = "processing"
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
|
|
|
|
|
print("Simulation started with id: %s", simulation.id)
|
|
|
|
|
|
|
|
|
|
response = await client.post(
|
|
|
|
|
f"{AEROS_BASE_URL}/api/Simulation/RunSimulation",
|
|
|
|
|
json=sim_data,
|
|
|
|
|
@ -147,19 +369,14 @@ async def execute_simulation(*, db_session: DbSession, simulation_id: Optional[U
|
|
|
|
|
response.raise_for_status()
|
|
|
|
|
result = response.json()
|
|
|
|
|
|
|
|
|
|
if is_saved:
|
|
|
|
|
simulation = await get_simulation_by_id(
|
|
|
|
|
db_session=db_session, simulation_id=simulation_id
|
|
|
|
|
)
|
|
|
|
|
simulation.status = "proccessing"
|
|
|
|
|
simulation.result = result
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
await save_simulation_result(
|
|
|
|
|
db_session=db_session, simulation_id=simulation_id, result=result, schematic_name=sim_data["SchematicName"],eq_update=eq_update
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
print("Simulation completed with id: %s", simulation_id)
|
|
|
|
|
return result
|
|
|
|
|
await save_simulation_result(
|
|
|
|
|
db_session=db_session, simulation_id=simulation.id, result=result, schematic_name=sim_data["SchematicName"], eq_update=eq_update
|
|
|
|
|
)
|
|
|
|
|
print("Simulation completed with id: %s", simulation.id)
|
|
|
|
|
simulation.status = "completed"
|
|
|
|
|
simulation.completed_at = datetime.now()
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
simulation = await get_simulation_by_id(
|
|
|
|
|
@ -176,20 +393,144 @@ async def execute_simulation(*, db_session: DbSession, simulation_id: Optional[U
|
|
|
|
|
) from e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_all_aeros_node(*, db_session: DbSession, schematic_name: Optional[str] = None):
|
|
|
|
|
query = select(AerosNode)
|
|
|
|
|
async def save_simulation_result_streaming(
|
|
|
|
|
*, db_session: DbSession, simulation, response_stream, schematic_name: str, eq_update: dict
|
|
|
|
|
):
|
|
|
|
|
"""Save simulation result by streaming and processing in batches."""
|
|
|
|
|
print("Saving simulation result (streaming)")
|
|
|
|
|
|
|
|
|
|
if schematic_name:
|
|
|
|
|
aeros_schematic = await get_aeros_schematic_by_name(db_session=db_session, schematic_name=schematic_name)
|
|
|
|
|
# Pre-load available nodes once
|
|
|
|
|
available_nodes = {
|
|
|
|
|
f"{node.node_type}:{node.node_name}": node
|
|
|
|
|
for node in await get_all_aeros_node(db_session=db_session, schematic_name=schematic_name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if not aeros_schematic:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Schematic not found")
|
|
|
|
|
batch_size = 100 # Adjust based on your needs
|
|
|
|
|
|
|
|
|
|
query = query.where(AerosNode.aeros_schematic_id == aeros_schematic.id)
|
|
|
|
|
try:
|
|
|
|
|
# Process calc results in batches
|
|
|
|
|
await process_calc_results_streaming(
|
|
|
|
|
db_session, simulation.id, response_stream, available_nodes, eq_update, batch_size
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
results = await db_session.execute(query)
|
|
|
|
|
return results.scalars().all()
|
|
|
|
|
# # Process plot results in batches
|
|
|
|
|
# await process_plot_results_streaming(
|
|
|
|
|
# db_session, simulation_id, response_stream, available_nodes, batch_size
|
|
|
|
|
# )
|
|
|
|
|
|
|
|
|
|
# Update simulation status
|
|
|
|
|
simulation.status = "completed"
|
|
|
|
|
simulation.completed_at = datetime.now()
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
simulation.status = "failed"
|
|
|
|
|
simulation.error = str(e)
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
|
|
|
|
|
log.error("Simulation failed with error: %s", str(e))
|
|
|
|
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e)
|
|
|
|
|
) from e
|
|
|
|
|
|
|
|
|
|
async def process_calc_results_streaming(
|
|
|
|
|
db_session, simulation_id, response_stream, available_nodes, eq_update, batch_size
|
|
|
|
|
):
|
|
|
|
|
"""Process calc results in streaming batches."""
|
|
|
|
|
calc_batch = []
|
|
|
|
|
|
|
|
|
|
# Parse nodeResultOuts array incrementally
|
|
|
|
|
calc_results = ijson.items(response_stream, 'nodeResultOuts.item')
|
|
|
|
|
|
|
|
|
|
raise Exception(calc_results)
|
|
|
|
|
|
|
|
|
|
async for result in calc_results:
|
|
|
|
|
calc_obj = await create_calc_result_object(
|
|
|
|
|
simulation_id, result, available_nodes, eq_update, db_session
|
|
|
|
|
)
|
|
|
|
|
if calc_obj:
|
|
|
|
|
calc_batch.append(calc_obj)
|
|
|
|
|
|
|
|
|
|
# Save batch when it reaches batch_size
|
|
|
|
|
if len(calc_batch) >= batch_size:
|
|
|
|
|
db_session.add_all(calc_batch)
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
calc_batch.clear()
|
|
|
|
|
|
|
|
|
|
# Save remaining items
|
|
|
|
|
if calc_batch:
|
|
|
|
|
db_session.add_all(calc_batch)
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
|
|
|
|
|
async def create_calc_result_object(
|
|
|
|
|
simulation_id, result, available_nodes, eq_update, db_session
|
|
|
|
|
) :
|
|
|
|
|
"""Create a single calc result object."""
|
|
|
|
|
node_type = "RegularNode" if result["nodeType"] == "RegularNode" else "SchematicNode"
|
|
|
|
|
node = available_nodes.get(f"{node_type}:{result['nodeName']}")
|
|
|
|
|
|
|
|
|
|
if not node:
|
|
|
|
|
if result["nodeType"] not in ["RegularNode", "Schematic"]:
|
|
|
|
|
return None
|
|
|
|
|
node = await get_or_save_node(db_session=db_session, node_data=result, type="calc")
|
|
|
|
|
# Add to available_nodes for future use
|
|
|
|
|
available_nodes[f"{node_type}:{result['nodeName']}"] = node
|
|
|
|
|
|
|
|
|
|
eq_reliability = eq_update.get(result["nodeName"], {
|
|
|
|
|
"eta": 0, "beta": 0, "mttr": 0, "parameters": {}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
eaf, derating_hours = calculate_eaf(
|
|
|
|
|
available_hours=result["totalUpTime"],
|
|
|
|
|
period_hours=result["totalUpTime"] + result["totalDowntime"],
|
|
|
|
|
actual_production=result["production"],
|
|
|
|
|
ideal_production=result["idealProduction"]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
efor = (result["totalDowntime"] / (result["totalDowntime"] + result["totalUpTime"])) * 100 if (result["totalDowntime"] + result["totalUpTime"]) > 0 else 0
|
|
|
|
|
|
|
|
|
|
return AerosSimulationCalcResult(
|
|
|
|
|
aeros_simulation_id=simulation_id,
|
|
|
|
|
aeros_node_id=node.id,
|
|
|
|
|
total_downtime=result["totalDowntime"],
|
|
|
|
|
total_uptime=result["totalUpTime"],
|
|
|
|
|
num_events=result["numEvents"],
|
|
|
|
|
production=result["production"],
|
|
|
|
|
production_std=result["productionStd"],
|
|
|
|
|
ideal_production=result["idealProduction"],
|
|
|
|
|
availability=result["availability"],
|
|
|
|
|
efficiency=result["efficiency"],
|
|
|
|
|
effective_loss=result["effectiveLoss"],
|
|
|
|
|
num_cm=result["numCM"],
|
|
|
|
|
cm_waiting_time=result["cmWaitingTime"],
|
|
|
|
|
total_cm_downtime=result["totalCMDowntime"],
|
|
|
|
|
num_pm=result["numPM"],
|
|
|
|
|
total_pm_downtime=result["totalPMDowntime"],
|
|
|
|
|
num_ip=result["numIP"],
|
|
|
|
|
total_ip_downtime=result["totalIPDowntime"],
|
|
|
|
|
num_oh=result["numOH"],
|
|
|
|
|
total_oh_downtime=result["totalOHDowntime"],
|
|
|
|
|
t_wait_for_crew=result["tWaitForCrew"],
|
|
|
|
|
t_wait_for_spare=result["tWaitForSpare"],
|
|
|
|
|
duration_at_full=result["durationAtFull"],
|
|
|
|
|
duration_above_hh=result["durationAboveHH"],
|
|
|
|
|
duration_above_h=result["durationAboveH"],
|
|
|
|
|
duration_below_l=result["durationBelowL"],
|
|
|
|
|
duration_below_ll=result["durationBelowLL"],
|
|
|
|
|
duration_at_empty=result["durationAtEmpty"],
|
|
|
|
|
stg_input=result["stgInput"],
|
|
|
|
|
stg_output=result["stgOutput"],
|
|
|
|
|
average_level=result["averageLevel"],
|
|
|
|
|
potential_production=result["potentialProduction"],
|
|
|
|
|
eaf=eaf,
|
|
|
|
|
efor=efor,
|
|
|
|
|
derating_hours=derating_hours,
|
|
|
|
|
beta=eq_reliability["beta"] if node_type == "RegularNode" else None,
|
|
|
|
|
eta=eq_reliability["eta"] if node_type == "RegularNode" else None,
|
|
|
|
|
mttr=eq_reliability["mttr"] if node_type == "RegularNode" else None,
|
|
|
|
|
parameters=eq_reliability["parameters"] if node_type == "RegularNode" else None
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def save_simulation_result(
|
|
|
|
|
@ -418,10 +759,6 @@ async def save_recusive_simulation_result_node(*, db_session: DbSession, data, s
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_aeros_schematic_by_name(*, db_session: DbSession, schematic_name: str):
|
|
|
|
|
query = select(AerosSchematic).where(AerosSchematic.schematic_name == schematic_name)
|
|
|
|
|
results = await db_session.execute(query)
|
|
|
|
|
return results.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
async def save_default_simulation_node(
|
|
|
|
|
*, db_session: DbSession, project_name: str = "trialapi"
|
|
|
|
|
@ -489,186 +826,7 @@ async def create_simulation(*, db_session: DbSession, simulation_in: SimulationI
|
|
|
|
|
return simulation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_simulation_with_calc_result(
|
|
|
|
|
*, db_session: DbSession, simulation_id: UUID, aeros_node_id: Optional[UUID] = None, schematic_name: Optional[str] = None, node_type: Optional[str] = None
|
|
|
|
|
):
|
|
|
|
|
"""Get a simulation by id."""
|
|
|
|
|
query = (select(AerosSimulationCalcResult).filter(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id))
|
|
|
|
|
|
|
|
|
|
if schematic_name:
|
|
|
|
|
if schematic_name == "WTP":
|
|
|
|
|
query = query.join(
|
|
|
|
|
AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id
|
|
|
|
|
).filter(AerosNode.structure_name.contains(schematic_name))
|
|
|
|
|
else:
|
|
|
|
|
query = query.join(
|
|
|
|
|
AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id
|
|
|
|
|
).filter(AerosNode.structure_name.contains(schematic_name))
|
|
|
|
|
|
|
|
|
|
if node_type:
|
|
|
|
|
query = query.join(
|
|
|
|
|
AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id
|
|
|
|
|
).filter(AerosNode.node_type == node_type)
|
|
|
|
|
|
|
|
|
|
query = query.options(
|
|
|
|
|
selectinload(AerosSimulationCalcResult.aeros_node).options(
|
|
|
|
|
selectinload(AerosNode.equipment)
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
simulation = await db_session.execute(query)
|
|
|
|
|
|
|
|
|
|
return simulation.scalars().all()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_plant_calc_result(
|
|
|
|
|
*, db_session, simulation_id: UUID
|
|
|
|
|
):
|
|
|
|
|
query = (select(AerosSimulationCalcResult).filter(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id,
|
|
|
|
|
).join(AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id)
|
|
|
|
|
.filter(AerosNode.node_name == "- TJB - Unit 3 -"))
|
|
|
|
|
|
|
|
|
|
query = query.options(
|
|
|
|
|
selectinload(AerosSimulationCalcResult.aeros_node).options(
|
|
|
|
|
selectinload(AerosNode.equipment)
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
calc = await db_session.execute(query)
|
|
|
|
|
|
|
|
|
|
return calc.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
async def get_result_ranking(*, db_session: DbSession, simulation_id: UUID):
|
|
|
|
|
|
|
|
|
|
query = select(AerosEquipment, AerosSimulationCalcResult.eaf).join(AerosNode, AerosNode.node_name == AerosEquipment.node_name).join(AerosSimulationCalcResult, AerosSimulationCalcResult.aeros_node_id == AerosNode.id)
|
|
|
|
|
|
|
|
|
|
query = query.filter(
|
|
|
|
|
and_(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id,
|
|
|
|
|
AerosNode.node_type == "RegularNode",
|
|
|
|
|
AerosEquipment.custom_parameters.any()
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
query = query.order_by(AerosSimulationCalcResult.eaf.desc())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
query = query.options(
|
|
|
|
|
selectinload(AerosEquipment.custom_parameters)).options(
|
|
|
|
|
selectinload(AerosEquipment.master_equipment)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
|
|
|
|
|
data = [
|
|
|
|
|
SimulationRankingParameters(
|
|
|
|
|
location_tag=equipment.location_tag,
|
|
|
|
|
master_equipment=equipment.master_equipment,
|
|
|
|
|
custom_parameters=equipment.custom_parameters,
|
|
|
|
|
eaf=eaf
|
|
|
|
|
)
|
|
|
|
|
for equipment, eaf in result
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_simulation_with_plot_result(
|
|
|
|
|
*, db_session: DbSession, simulation_id: UUID, node_type: 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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_calc_result_by(
|
|
|
|
|
*, db_session: DbSession, simulation_id: UUID, node_name: Optional[str] = None
|
|
|
|
|
):
|
|
|
|
|
"""Get a simulation node by column."""
|
|
|
|
|
# Build WHERE conditions from kwargs
|
|
|
|
|
query = select(AerosSimulationCalcResult).where(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if node_name:
|
|
|
|
|
query = query.join(AerosSimulationCalcResult.aeros_node).filter(AerosNode.node_name == node_name)
|
|
|
|
|
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
return result.scalar()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_custom_parameters(*, db_session: DbSession, simulation_id: UUID):
|
|
|
|
|
"""Get a simulation node by column."""
|
|
|
|
|
# Build WHERE conditions from kwargs
|
|
|
|
|
query = select(AerosSimulationCalcResult).where(
|
|
|
|
|
AerosSimulationCalcResult.aeros_simulation_id == simulation_id
|
|
|
|
|
)
|
|
|
|
|
query = query.join(
|
|
|
|
|
AerosNode, AerosNode.id == AerosSimulationCalcResult.aeros_node_id
|
|
|
|
|
)
|
|
|
|
|
query = query.where(AerosNode.node_type == "RegularNode")
|
|
|
|
|
query = (
|
|
|
|
|
query.order_by(AerosSimulationCalcResult.eaf.desc())
|
|
|
|
|
.limit(20)
|
|
|
|
|
.options(selectinload(AerosSimulationCalcResult.aeros_node))
|
|
|
|
|
)
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
return result.scalars().all()
|
|
|
|
|
|
|
|
|
|
async def get_regular_nodes_by_schematic(*, db_session: DbSession, schematic_name: str) -> set[UUID]:
|
|
|
|
|
"""
|
|
|
|
|
Get all regular node IDs that are descendants of a given schematic (system or subsystem).
|
|
|
|
|
Uses recursive CTE to traverse the hierarchy.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# Using recursive CTE to find all descendants
|
|
|
|
|
# First, find the root node(s) with the given schematic name
|
|
|
|
|
root_cte = (
|
|
|
|
|
select(AerosNode.id, AerosNode.schematic_id, AerosNode.ref_schematic_id,AerosNode.node_type, AerosNode.node_name)
|
|
|
|
|
.where(AerosNode.node_name == schematic_name)
|
|
|
|
|
.cte(name="hierarchy", recursive=True)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Recursive part: find all children
|
|
|
|
|
children_cte = (
|
|
|
|
|
select(AerosNode.id, AerosNode.schematic_id,AerosNode.ref_schematic_id ,AerosNode.node_type, AerosNode.node_name)
|
|
|
|
|
.select_from(
|
|
|
|
|
AerosNode.join(root_cte, AerosNode.schematic_id == root_cte.c.ref_schematic_id)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Union the base case and recursive case
|
|
|
|
|
hierarchy_cte = root_cte.union_all(children_cte)
|
|
|
|
|
|
|
|
|
|
# Final query to get only regular nodes from the hierarchy
|
|
|
|
|
query = (
|
|
|
|
|
select(hierarchy_cte.c.id)
|
|
|
|
|
.where(hierarchy_cte.c.node_type == "RegularNode") # Adjust this condition based on your node_type values
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
return set(result.scalars().all())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def get_all_schematic_aeros(*, db_session: DbSession):
|
|
|
|
|
query = select(AerosSchematic)
|
|
|
|
|
results = await db_session.execute(query)
|
|
|
|
|
return results.scalars().all()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def update_simulation(*, db_session: DbSession, simulation_id: UUID, data: dict):
|
|
|
|
|
|