Cizz22 3 months ago
parent 366e4d9753
commit bd437651a2

@ -0,0 +1,163 @@
import json
from collections import defaultdict
from sqlalchemy import create_engine, text
# 🔧 Adjust this to your environment
DB_URL = "postgresql+psycopg2://postgres:postgres@192.168.1.86:5432/digital_aeros_fixed"
def export_rbd_json(project_id, output_file="rbd.json"):
engine = create_engine(DB_URL)
with engine.connect() as conn:
# --- Project info ---
project = conn.execute(
text('SELECT "ProjectId","ProjectName" FROM public."Projects" WHERE "ProjectId" = :pid'),
{"pid": project_id}
).mappings().first()
if not project:
raise ValueError(f"❌ Project {project_id} not found")
print(f"🔍 Loaded project: {project['ProjectName']} (ID={project_id})")
# --- Schematics ---
schematics = conn.execute(
text('SELECT "SchematicId","SchematicName" FROM public."Schematics" WHERE "ProjectId" = :pid'),
{"pid": project_id}
).mappings().all()
all_schematics_json = {}
for s in schematics:
sid = s["SchematicId"]
sname = s["SchematicName"]
print(f"\n=== Processing schematic {sid} ({sname}) ===")
# --- Nodes ---
nodes_data = conn.execute(
text('SELECT "NodeId","NodeUIId","NodeName","NodeTypeCode" '
'FROM public."RegularNodes" WHERE "SchematicId" = :sid'),
{"sid": sid}
).mappings().all()
# dict keyed by NodeId
nodes = {str(n["NodeId"]): dict(n) for n in nodes_data}
# map UIId -> NodeId
uiid_to_id = {str(n["NodeUIId"]): str(n["NodeId"]) for n in nodes_data}
print(f"🟦 Nodes: {len(nodes)}")
# --- Connectors (edges) ---
edges = conn.execute(
text('SELECT "SourceUIId","SinkUIId" FROM public."Connectors" WHERE "SchematicId" = :sid'),
{"sid": sid}
).mappings().all()
children_map = defaultdict(list)
for e in edges:
src_ui = str(e["SourceUIId"])
sink_ui = str(e["SinkUIId"])
if src_ui in uiid_to_id and sink_ui in uiid_to_id:
src_id = uiid_to_id[src_ui]
sink_id = uiid_to_id[sink_ui]
children_map[src_id].append(sink_id)
print(f"🔗 Connectors: {len(edges)}")
# --- Redundancies ---
redundancies = conn.execute(
text('SELECT * FROM public."Redundancies" WHERE "SchematicId" = :sid'),
{"sid": sid}
).mappings().all()
states = conn.execute(
text('SELECT * FROM public."RedundancyStates" WHERE "RedundancyId" IN '
'(SELECT "RedundancyId" FROM public."Redundancies" WHERE "SchematicId" = :sid)'),
{"sid": sid}
).mappings().all()
state_cells = conn.execute(
text('SELECT * FROM public."RedundancyStateCells" WHERE "RedundancyStateId" IN '
'(SELECT "StateId" FROM public."RedundancyStates" WHERE "RedundancyId" IN '
'(SELECT "RedundancyId" FROM public."Redundancies" WHERE "SchematicId" = :sid))'),
{"sid": sid}
).mappings().all()
# Build redundancy structure
redundancy_map = {}
for r in redundancies:
rid = str(r["RedundancyId"])
redundancy_map[rid] = {
"name": r["RedundancyName"],
"type": "standby" if r["IsKNStandby"] else "kofn",
"min_required": r["MinRequiredNodes"],
"switch_delay": r["SwitchDelay"],
"states": {}
}
for st in states:
sid2 = str(st["StateId"])
rid = str(st["RedundancyId"])
redundancy_map[rid]["states"][sid2] = {
"priority": st["StatePriority"],
"duration": st["StateDuration"],
"cells": []
}
for c in state_cells:
sid2 = str(c["RedundancyStateId"])
for r_id, r in redundancy_map.items():
if sid2 in r["states"]:
node_id = str(c["InvolvedNodeId"])
if node_id in nodes: # only link if valid
r["states"][sid2]["cells"].append({
"node_id": node_id,
"status": c["NodeStatusCode"]
})
break
# --- Build JSON nodes ---
json_nodes = {}
for node_id, n in nodes.items():
node_type = str(n["NodeTypeCode"]).lower()
node_json = {
"type": node_type,
"name": n["NodeName"],
"children": children_map.get(node_id, []), # now NodeId-based
"availability": 1.0 # ✅ default availability
}
json_nodes[node_id] = node_json
# --- Root detection ---
all_children = {c for lst in children_map.values() for c in lst}
root_candidates = [nid for nid in nodes.keys() if nid not in all_children]
root = root_candidates[0] if root_candidates else None
print(f"🌳 Root node detected: {root}")
# --- Assemble schematic JSON ---
schematic_json = {
"schematic_id": sid,
"schematic_name": sname,
"root": str(root) if root else None,
"nodes": json_nodes,
"redundancies": redundancy_map
}
all_schematics_json[str(sid)] = schematic_json
print(f"✅ Finished schematic {sid}")
# --- Final JSON ---
final_json = {
"project_id": project["ProjectId"],
"project_name": project["ProjectName"],
"schematics": all_schematics_json
}
with open(output_file, "w") as f:
json.dump(final_json, f, indent=2)
print(f"\n🎉 Exported simplified RBD JSON (NodeId-based, availability=1.0) "
f"for Project {project_id}{output_file}")
if __name__ == "__main__":
export_rbd_json(project_id=70, output_file="project_70_rbd.json")

File diff suppressed because it is too large Load Diff

@ -0,0 +1,111 @@
import json
def series_availability(avails):
result = 1.0
for a in avails:
result *= a
return result
def parallel_availability(avails):
result = 1.0
for a in avails:
result *= (1 - a)
return 1 - result
def kofn_availability(avails, k):
if k <= 1:
return parallel_availability(avails)
return sum(avails) / len(avails) # simple approx
def compute_node_availability(node_id, schematic, schematics, overrides, visited):
if node_id in visited:
return 1.0
visited.add(node_id)
node = schematic["nodes"].get(node_id)
if not node:
return 1.0
node_name = node.get("name", "").strip().lower()
if node_name in overrides:
return overrides[node_name]
ntype = node["type"].lower()
if ntype == "regularnode":
return node.get("availability", 1.0)
elif ntype == "series":
return series_availability([
compute_node_availability(child, schematic, schematics, overrides, visited.copy())
for child in node.get("children", [])
])
elif ntype == "parallel":
return parallel_availability([
compute_node_availability(child, schematic, schematics, overrides, visited.copy())
for child in node.get("children", [])
])
elif ntype == "kofn":
k = node.get("min_required", 1)
return kofn_availability([
compute_node_availability(child, schematic, schematics, overrides, visited.copy())
for child in node.get("children", [])
], k)
elif ntype == "subschematic":
tschematic_id = node.get("tschematic_id")
if tschematic_id and str(tschematic_id) in schematics:
sub_schematic = schematics[str(tschematic_id)]
root = sub_schematic.get("root")
if root:
return compute_node_availability(root, sub_schematic, schematics, overrides, set())
return node.get("availability", 1.0)
return node.get("availability", 1.0)
def compute_schematic_availability(schematic, schematics, overrides):
root = schematic.get("root")
if not root:
return 1.0
return compute_node_availability(root, schematic, schematics, overrides, set())
def evaluate_project(json_file, overrides=None):
with open(json_file, "r") as f:
data = json.load(f)
schematics = data["schematics"]
overrides = overrides or {}
results = {}
top_availability = None
for sid, schematic in schematics.items():
name = schematic["schematic_name"].strip()
avail = compute_schematic_availability(schematic, schematics, overrides)
results[name] = avail
if name == "- TJB - Unit 3 -":
top_availability = avail
return results, top_availability
if __name__ == "__main__":
overrides = {
"WTP": 0.0, # Example override
}
results, top_avail = evaluate_project("project_70_rbd.json", overrides=overrides)
print("\n--- Schematic Availabilities ---")
for sch_name, avail in results.items():
print(f"{sch_name:25s}: {avail:.6f}")
print("\n=== TOTAL SYSTEM AVAILABILITY ===")
if top_avail is not None:
print(f"Top schematic (- TJB - Unit 3 -): {top_avail:.6f}")
else:
print("Top schematic not found in JSON!")

File diff suppressed because it is too large Load Diff

@ -58,17 +58,40 @@ def system_availability(structure: Structure, availabilities: Dict[str, float])
result = Decimal('1.0') - product
return float(result)
elif "parallel_no_redundancy" in structure:
# Load sharing - system availability is minimum of components
components = structure["parallel_no_redundancy"]
elif "k_of_n" in structure:
k = structure["k_of_n"]["k"]
components = structure["k_of_n"]["components"]
if not components:
return 0.0
availabilities_list = [system_availability(s, availabilities) for s in components]
return min(availabilities_list)
component_availabilities = [system_availability(s, availabilities) for s in components]
return k_of_n_availability(component_availabilities, k)
raise ValueError(f"Invalid structure definition: {structure}")
from itertools import combinations
from decimal import Decimal
from math import comb
def k_of_n_availability(availabilities: list[float], k: int) -> float:
n = len(availabilities)
total = Decimal('0.0')
# Iterate over all combinations of components that can be working
for j in range(k, n+1):
for subset in combinations(range(n), j):
prob = Decimal('1.0')
for i in range(n):
if i in subset:
prob *= Decimal(str(availabilities[i]))
else:
prob *= (Decimal('1.0') - Decimal(str(availabilities[i])))
total += prob
return float(total)
def get_all_components(structure: Structure) -> set:
"""Extract all component names from a structure."""

@ -132,6 +132,8 @@ class AerosSimulationCalcResult(Base, DefaultMixin):
contribution = Column(Float, nullable=True)
criticality = Column(Float, nullable=True)
contribution_factor = Column(Float, nullable=True)
total_mo_downtime = Column(Float, nullable=True)
total_po_downtime = Column(Float, nullable=True)
aeros_simulation_id = Column(
UUID(as_uuid=True), ForeignKey("rbd_tr_aeros_simulation.id"), nullable=False

@ -231,14 +231,14 @@ async def get_simulation_result_plot_per_node(db_session: DbSession, simulation_
}
@router.get("/result/ranking/{simulation_id}", response_model=StandardResponse[List[SimulationRankingParameters]])
async def get_simulation_result_ranking(db_session: DbSession, simulation_id):
async def get_simulation_result_ranking(db_session: DbSession, simulation_id, limit:int = Query(None)):
"""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)
simulation_result = await get_result_ranking(db_session=db_session, simulation_id=simulation_id, limit=limit)
return {
"data": simulation_result,

@ -213,7 +213,7 @@ async def get_plant_calc_result(
return calc.scalar_one_or_none()
async def get_result_ranking(*, db_session: DbSession, simulation_id: UUID):
async def get_result_ranking(*, db_session: DbSession, simulation_id: UUID, limit: Optional[int]):
query = select(AerosEquipment, AerosSimulationCalcResult.availability).join(AerosNode, AerosNode.node_name == AerosEquipment.node_name).join(AerosSimulationCalcResult, AerosSimulationCalcResult.aeros_node_id == AerosNode.id)
@ -225,7 +225,10 @@ async def get_result_ranking(*, db_session: DbSession, simulation_id: UUID):
)
)
query = query.order_by(AerosSimulationCalcResult.availability.desc()).limit(10)
query = query.order_by(AerosSimulationCalcResult.availability.desc())
if limit:
query = query.limit(limit)
query = query.options(

Loading…
Cancel
Save