add features: add simulation model & result into db
digital-twin/RBD-multibranch/pipeline/head This commit looks good Details

ferdi_feature
akumadoferudi 2 months ago
parent 14ad828e3e
commit 599a0963d5

3
.gitignore vendored

@ -1,4 +1,5 @@
env/
__pycache__/
venv/
.env
.env
.venv

@ -1,12 +1,534 @@
from sqlalchemy import JSON, UUID, Column, DateTime, Float, ForeignKey, Integer, String
from sqlalchemy import (
JSON,
UUID,
TIMESTAMP,
Column,
DateTime,
Float,
ForeignKey,
Numeric,
Integer,
String,
Text
)
from sqlalchemy.orm import relationship
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.sql import func
from src.database.core import Base
from src.models import DefaultMixin
import uuid
class AerosProject(Base, DefaultMixin):
__tablename__ = "rbd_ms_aeros_project"
project_name = Column(String, nullable=False)
aro_file_path = Column(String, nullable=False)
# AF
class SimulationModel(Base):
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
# server_default=text("uuid_generate_v4()")
)
name = Column(
String,
# unique=True,
index=True,
nullable=True
)
payload = Column(JSON, nullable=True)
gui_payload = Column(JSON, nullable=True)
# realtionship
schemas = relationship("SimulationModelSchema", back_populates="model") # 1-to-many
assets = relationship("SimulationModelAsset", back_populates="model") # 1-to-many
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
class SimulationTask(Base):
id = Column(String, primary_key=True, index=True)
model_id = Column(Integer, nullable=False)
status = Column(String, default="pending") # pending, running, completed, failed
progress = Column(Integer, default=0)
params = Column(JSON, nullable=True)
result = Column(JSON, nullable=True)
error = Column(String, nullable=True)
created_at = Column(String, nullable=False)
updated_at = Column(String, nullable=False)
# AF
class SimulationMasterType(Base):
__tablename__ = "simulation_master_types"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
# server_default=text("uuid_generate_v4()")
)
name = Column(Text, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
model_asset_distributions = relationship("SimulationModelAssetDistribution", back_populates="type") # 1-to-many
model_schemas = relationship("SimulationModelSchema", back_populates="type") # 1-to-many
model_asset_repair_durations = relationship("SimulationModelAssetRepairDuration", back_populates="type") # many-to-1
result_events = relationship("SimulationResultEvent", back_populates="type") # 1-to-many
class SimulationModelSchema(Base):
__tablename__ = "simulation_model_schemas"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
# server_default=text("uuid_generate_v4()")
)
simulation_model_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model.id"),
nullable=True
)
# self reference
simulation_model_schemas_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model_schemas.id"),
nullable=True
)
type_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_master_types.id"),
nullable=True
)
schemaId = Column(Text, nullable=True) # not a foreign key
name = Column(Text, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
model = relationship("SimulationModel", back_populates="schemas") # many-to-1
type = relationship("SimulationMasterType", back_populates="model_schemas") # many-to-1
assets = relationship("SimulationModelAsset", back_populates="model_schema") # 1-to-many
schema_results = relationship("SimulationResultSchema", back_populates="schema_model") # 1-to-many
# SELF RELATION
parent = relationship(
"SimulationModelSchema",
remote_side=[id],
back_populates="children"
)
children = relationship(
"SimulationModelSchema",
back_populates="parent",
# cascade="all, delete"
)
class SimulationModelAsset(Base):
__tablename__ = "simulation_model_assets"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
# server_default=text("uuid_generate_v4()")
)
assetId = Column(Text, nullable=True) # not a foreign key
name = Column(Text, nullable=True)
simulation_model_schemas_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model_schemas.id"),
nullable=True
)
simulation_model_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model.id"),
nullable=True
)
max_capacity = Column(Numeric, nullable=True)
design_capacity = Column(Numeric, nullable=True)
buffer_duration = Column(Numeric, nullable=True)
transition_delay = Column(Numeric, nullable=True)
initial_age = Column(Numeric, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
model = relationship("SimulationModel", back_populates="assets") # many-to-1
asset_distribution = relationship(
"SimulationModelAssetDistribution",
back_populates="asset",
uselist=False # 1-to-1
)
asset_repair_duration = relationship(
"SimulationModelAssetRepairDuration",
back_populates="asset",
uselist=False # 1-to-1
)
asset_overhaul = relationship(
"SimulationModelAssetOverhaul",
back_populates="asset",
uselist=False # 1-to-1
)
asset_pm = relationship(
"SimulationModelAssetPm",
back_populates="asset",
uselist=False # 1-to-1
)
model_schema = relationship(
"SimulationModelSchema",
back_populates="assets" # many-to-1
)
asset_results = relationship(
"SimulationResultAsset",
back_populates="asset_model" # 1-to-many
)
class SimulationModelAssetDistribution(Base):
__tablename__ = "simulation_model_assets_distributions"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
# server_default=text("uuid_generate_v4()")
)
simulation_model_assets_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model_assets.id"),
nullable=True
)
type_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_master_types.id"),
nullable=True
)
shape = Column(Numeric, nullable=True)
scale = Column(Numeric, nullable=True)
mean = Column(Numeric, nullable=True)
std_dev = Column(Numeric, nullable=True)
eta = Column(Numeric, nullable=True)
beta = Column(Numeric, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
asset = relationship("SimulationModelAsset", back_populates="asset_distribution") # 1-to-1
type = relationship("SimulationMasterType", back_populates="model_asset_distributions") # many-to-1
class SimulationModelAssetRepairDuration(Base):
__tablename__ = "simulation_model_assets_repair_durations"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
# server_default=text("uuid_generate_v4()")
)
simulation_model_assets_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model_assets.id"),
nullable=True
)
type_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_master_types.id"),
nullable=True
)
mean = Column(Numeric, nullable=True)
std_dev = Column(Numeric, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
asset = relationship("SimulationModelAsset", back_populates="asset_repair_duration") # 1-to-1
type = relationship("SimulationMasterType", back_populates="model_asset_repair_durations") # many-to-1
class SimulationModelAssetOverhaul(Base):
__tablename__ = "simulation_model_assets_overhauls"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
# server_default=text("uuid_generate_v4()")
)
simulation_model_assets_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model_assets.id"),
nullable=True
)
interval = Column(Numeric, nullable=True)
duration = Column(Numeric, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
asset = relationship("SimulationModelAsset", back_populates="asset_overhaul") # 1-to-1
class SimulationModelAssetPm(Base):
__tablename__ = "simulation_model_assets_pms"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
# server_default=text("uuid_generate_v4()")
)
simulation_model_assets_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model_assets.id"),
nullable=True
)
interval = Column(Numeric, nullable=True)
duration = Column(Numeric, nullable=True)
restoration_factor = Column(Numeric, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
asset = relationship("SimulationModelAsset", back_populates="asset_pm") # 1-to-1
class SimulationResult(Base):
__tablename__ = "simulation_results"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
)
production_availability = Column(Numeric, nullable=True)
simulation_duration = Column(Numeric, nullable=True)
simulation_replications = Column(Numeric, nullable=True)
system_availability = Column(Numeric, nullable=True)
system_downtime = Column(Numeric, nullable=True)
system_failures = Column(Numeric, nullable=True)
system_uptime = Column(Numeric, nullable=True)
total_demand = Column(Numeric, nullable=True)
total_productions = Column(Numeric, nullable=True)
system_down_causes = Column(JSONB, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
schemas = relationship("SimulationResultSchema", back_populates="result") # 1-to-many
assets = relationship("SimulationResultAsset", back_populates="result") # 1-to-many
events = relationship("SimulationResultEvent", back_populates="result") # 1-to-many
# down_causes = relationship("SimulationResultDownCauses", back_populates="result") # 1-to-many
class SimulationResultAsset(Base):
__tablename__ = "simulation_result_assets"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
)
simulation_results_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_results.id"),
nullable=True
)
simulation_model_assets_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model_assets.id"),
nullable=True
)
assetId = Column(Text, nullable=True) # "node_blablabla"
name = Column(Text, nullable=True)
availability = Column(Numeric, nullable=True)
contribution_factor = Column(Numeric, nullable=True)
downtime = Column(Numeric, nullable=True)
uptime = Column(Numeric, nullable=True)
failures = Column(Numeric, nullable=True)
total_downtime_concurrent_with_system = Column(Numeric, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
result = relationship("SimulationResult", back_populates="assets") # many-to-1
events = relationship("SimulationResultEvent", back_populates="asset") # 1-to-many
asset_model = relationship("SimulationModelAsset", back_populates="asset_results") # many-to-1
class SimulationResultSchema(Base):
__tablename__ = "simulation_result_schemas"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
)
simulation_results_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_results.id"),
nullable=True
)
simulation_model_schemas_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_model_schemas.id"),
nullable=True
)
schemaId = Column(Text, nullable=True)
name = Column(Text, nullable=True)
availability = Column(Numeric, nullable=True)
downtime = Column(Numeric, nullable=True)
uptime = Column(Numeric, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
result = relationship("SimulationResult", back_populates="schemas") # many-to-1
events = relationship("SimulationResultEvent", back_populates="schema") # 1-to-many
schema_model = relationship("SimulationModelSchema", back_populates="schema_results") # many-to-1
class SimulationResultEvent(Base):
__tablename__ = "simulation_result_events"
id = Column(
UUID(as_uuid=True),
primary_key=True,
index=True,
default=uuid.uuid4,
)
simulation_result_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_results.id"),
nullable=True
)
simulation_result_assets_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_result_assets.id"),
nullable=True
)
simulation_result_schemas_id = Column(
UUID(as_uuid=True),
ForeignKey("simulation_result_schemas.id"),
nullable=True
)
type_id = Column(
UUID(as_uuid=True),
# asumsi ada tabel ini
ForeignKey("simulation_master_types.id"),
nullable=True
)
cause = Column(Text, nullable=True)
state = Column(Text, nullable=True)
load_factor = Column(Numeric, nullable=True)
start_time = Column(Numeric, nullable=True)
end_time = Column(Numeric, nullable=True)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)
# relationships
result = relationship("SimulationResult", back_populates="events")
asset = relationship("SimulationResultAsset", back_populates="events")
schema = relationship("SimulationResultSchema", back_populates="events")
type = relationship("SimulationMasterType", back_populates="result_events")
# class SimulationResultDownCause(Base):
# __tablename__ = "simulation_result_down_causes"
# id = Column(
# UUID(as_uuid=True),
# primary_key=True,
# index=True,
# default=uuid.uuid4,
# )
# simulation_results_id = Column(
# UUID(as_uuid=True),
# ForeignKey("simulation_results.id"),
# nullable=True
# )
# availability = Column(Numeric, nullable=True)
# downtime = Column(Numeric, nullable=True)
# uptime = Column(Numeric, nullable=True)
# failures = Column(Numeric, nullable=True)
# created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
# updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now())
# deleted_at = Column(TIMESTAMP(timezone=True), nullable=True)

@ -1,7 +1,19 @@
import json
import os
from typing import List, Optional
from fastapi import APIRouter, HTTPException, Response, status, File, UploadFile, Form
from uuid import UUID
from fastapi import (
APIRouter,
HTTPException,
Response,
status,
File,
UploadFile,
Form,
Request,
Body
)
from fastapi.responses import StreamingResponse
import httpx
from sqlalchemy import select
@ -14,7 +26,7 @@ from src.database.service import CommonParameters
from src.models import StandardResponse
from src.aeros_utils import aeros_post
from .schema import AerosProjectInput, AerosMetadata, OverhaulScheduleCreate, OverhaulScheduleUpdate
from .service import import_aro_project, fetch_aro_record, reset_project, create, update, delete
from .service import get_simulation_model_by_id_service, get_simulation_result_service, import_aro_project, fetch_aro_record, import_simulation_model_service, import_simulation_result_service, reset_project, create, update, delete
router = APIRouter()
@ -157,3 +169,357 @@ async def delete_overhaul_equipment_job(db_session: DbSession, overhaul_job_id:
data=None,
message="Data deleted successfully",
)
# import & store simulation ramp model into db (use this: input .ramp/.json file)
@router.post("/import-simulation-model/file")
async def import_simulation_model_file(
db: DbSession,
file: UploadFile = File(...)
):
try:
allowed_extensions = (
".ramp",
".json"
)
if not file.filename.endswith(
allowed_extensions
):
raise HTTPException(
400,
"Only .ramp and .json files are supported"
)
contents = await file.read()
try:
data = json.loads(
contents.decode("utf-8")
)
except Exception:
raise HTTPException(
400,
"Invalid JSON inside uploaded file"
)
# =====================================
# VALIDATION
# =====================================
validate_simulation_payload(data)
# =====================================
# IMPORT
# =====================================
result = await import_simulation_model_service(
db=db,
name=None,
data=data
)
return StandardResponse(
data=result,
message="File imported successfully"
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
500,
f"Import failed: {str(e)}"
)
# helper: validate simulation model payload from raw json
def validate_simulation_model_payload(data: dict):
if "rbd_root" not in data:
raise HTTPException(
400,
"Invalid structure: 'rbd_root' missing"
)
if "assets" not in data:
raise HTTPException(
400,
"Invalid structure: 'assets' missing"
)
if "schemas" not in data:
raise HTTPException(
400,
"Invalid structure: 'schemas' missing"
)
# import & store simulation ramp model into db (use this: input raw json)
@router.post("/import-simulation-model/json")
async def import_simulation_model_json(
db: DbSession,
payload: dict = Body(...)
):
try:
# =====================================
# VALIDATION
# =====================================
validate_simulation_model_payload(payload)
# =====================================
# IMPORT
# =====================================
result = await import_simulation_model_service(
db=db,
name=None,
data=payload
)
return StandardResponse(
data=result,
message="JSON imported successfully"
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
500,
f"Import failed: {str(e)}"
)
# get simulation model by id (USE THIS)
@router.get("/simulation-model-by-id/{simulation_model_id}")
async def get_simulation_model_by_id(db: DbSession, simulation_model_id: str):
result = await (
get_simulation_model_by_id_service(db, simulation_model_id)
)
if not result:
raise HTTPException(
status_code=404,
detail="Simulation model not found"
)
return StandardResponse(
data=result,
message="Data showed successfully",
)
# helper: validate simulation result payload from raw json
def validate_simulation_result_payload(data: dict):
required_fields = [
"asset_results",
"schema_results",
"system_events",
]
for field in required_fields:
if field not in data:
raise HTTPException(
status_code=400,
detail=f"Invalid structure: '{field}' missing"
)
# import & store simulation result into db (use this: input .json file)
@router.post("/import-simulation-result/file")
async def import_simulation_result_file(
db: DbSession,
file: UploadFile = File(...)
):
try:
# =====================================
# FILE VALIDATION
# =====================================
if not file.filename.endswith(".json"):
raise HTTPException(
status_code=400,
detail="Only .json files are supported"
)
contents = await file.read()
# =====================================
# PARSE JSON
# =====================================
try:
data = json.loads(
contents.decode("utf-8")
)
except Exception:
raise HTTPException(
status_code=400,
detail="Invalid JSON inside uploaded file"
)
# =====================================
# VALIDATION
# =====================================
validate_simulation_result_payload(
data
)
# =====================================
# IMPORT
# =====================================
# result =
await import_simulation_result_service(
db,
data
)
# =====================================
# RESPONSE
# =====================================
# final_result = {
# "status": "success",
# "simulation_result_id": result[
# "result_id"
# ],
# "asset_imported": result[
# "asset_count"
# ],
# "schema_imported": result[
# "schema_count"
# ],
# "system_event_imported": result[
# "system_event_count"
# ],
# }
return StandardResponse(
data=None,
message="Data stored successfully",
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=500,
detail={
"message": str(e),
"type": type(e).__name__,
}
)
# import & store simulation result into db (use this: input raw json)
@router.post("/import-simulation-result/json")
async def import_simulation_result_json(
db: DbSession,
data: dict
):
try:
# =====================================
# VALIDATION
# =====================================
validate_simulation_result_payload(
data
)
# =====================================
# IMPORT
# =====================================
# result =
await import_simulation_result_service(
db,
data
)
# =====================================
# RESPONSE
# =====================================
# final_result = {
# "status": "success",
# "simulation_result_id": result[
# "result_id"
# ],
# "asset_imported": result[
# "asset_count"
# ],
# "schema_imported": result[
# "schema_count"
# ],
# "system_event_imported": result[
# "system_event_count"
# ],
# }
return StandardResponse(
data=None,
message="Data stored successfully",
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=500,
detail={
"message": str(e),
"type": type(e).__name__,
}
)
# get simulation result by id
@router.get("/simulation-result-by-id/{simulation_result_id}")
async def get_simulation_result_by_id(db: DbSession, simulation_result_id: str):
result = await (
get_simulation_result_service(
db,
simulation_result_id
)
)
if not result:
raise HTTPException(
status_code=404,
detail="Simulation result not found"
)
# return result
return StandardResponse(
data=result,
message="Data showed successfully",
)

File diff suppressed because it is too large Load Diff

@ -15,7 +15,7 @@ from src.aeros_simulation.service import (
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 tkinter.constants import E
from src.dashboard_model.model import RBDMasterData
from src.dashboard_model.schema_masterdata import RBDMasterDataUpdate

Loading…
Cancel
Save