diff --git a/src/calculation_budget_constrains/router.py b/src/calculation_budget_constrains/router.py index 3e9ab7c..563d8de 100644 --- a/src/calculation_budget_constrains/router.py +++ b/src/calculation_budget_constrains/router.py @@ -24,7 +24,7 @@ async def get_target_reliability( """Get all scope pagination.""" results = await get_simulation_results( - simulation_id = "f31103ef-1ac8-4c29-8f66-ea9ccf06bd87", + simulation_id = "efa8ef4c-0417-4d2d-95f3-41e4283737ab", token=token ) diff --git a/src/calculation_budget_constrains/service.py b/src/calculation_budget_constrains/service.py index 3f3ee19..9aab57f 100644 --- a/src/calculation_budget_constrains/service.py +++ b/src/calculation_budget_constrains/service.py @@ -6,6 +6,7 @@ from uuid import UUID from sqlalchemy import Delete, Select from src.auth.service import CurrentUser +from src.contribution_util import calculate_contribution_accurate from src.database.core import CollectorDbSession, DbSession # from src.scope_equipment.model import ScopeEquipment # from src.scope_equipment.service import get_by_scope_name @@ -56,44 +57,48 @@ async def get_all_budget_constrains( "location_tag": equipment.location_tag, "name": equipment.equipment_name, "total_cost": equipment.overhaul_cost + equipment.service_cost, - "eaf_contribution": equipments_eaf_contribution.get(equipment.location_tag, 0) + "eaf_contribution": equipments_eaf_contribution.get(equipment.location_tag, 0), + #'cost_benefit_ratio': (equipment.overhaul_cost + equipment.service_cost) / equipments_eaf_contribution.get(equipment.location_tag, 0) if equipments_eaf_contribution.get(equipment.location_tag, 0) > 0 else 0 } for equipment in equipments ] - - # Calculate composite priority score for fair sorting - max_cost = max(eq["total_cost"] for eq in result) if result else 1 + + result.sort(key=lambda x: x['eaf_contribution'], reverse=True) + + priority_list = [] + total_cost = 0 + remaining_budget = cost_threshold for equipment in result: - # Normalize cost (0-1) - higher cost = higher priority - normalized_cost = equipment["total_cost"] / max_cost if max_cost > 0 else 0 + # # Normalize cost (0-1) - higher cost = higher priority + # normalized_cost = equipment["total_cost"] / max_cost if max_cost > 0 else 0 - # Composite score: 70% EAF contribution + 30% cost impact - # EAF contribution is already relative, so use directly - equipment["priority_score"] = (0.7 * equipment["eaf_contribution"]) + (0.3 * normalized_cost) + # # Composite score: 70% EAF contribution + 30% cost impact + # # EAF contribution is already relative, so use directly + # equipment["priority_score"] = (0.7 * equipment["eaf_contribution"]) + (0.3 * normalized_cost) + + if equipment['total_cost'] <= remaining_budget: + # We can afford this improvement, so add it to the plan + priority_list.append(equipment) + total_cost += equipment['total_cost'] + remaining_budget -= equipment['total_cost'] + else: + # This candidate is too expensive for the remaining budget + # We break out of the loop. Since the list is sorted by ratio, + # anything after this is worse value and also won't fit. + # In a more complex solution, you might skip and keep looking for smaller items. + break # Sort by composite priority score (highest to lowest) - result.sort(key=lambda x: x["priority_score"], reverse=True) + # result.sort(key=lambda x: x["priority_score"], reverse=True) + selected_components = {item['location_tag'] for item in priority_list} + consequence_list = [candidate for candidate in result if candidate['location_tag'] not in selected_components] + consequence_list.sort(key=lambda x: x['eaf_contribution'], reverse=True) + priority_list.sort(key=lambda x: x['eaf_contribution'], reverse=True) - # Filter equipment up to threshold - cumulative_cost = 0 - included_results = [] - - for equipment in result: - cumulative_cost += equipment["total_cost"] - if cumulative_cost >= cost_threshold: - break - included_results.append(equipment) - # Rest equipment is consequence list - consequence_results = result[len(included_results):] - - #Sort - consequence_results.sort(key=lambda x: x["eaf_contribution"], reverse=True) - included_results.sort(key=lambda x: x["eaf_contribution"], reverse=True) - - return included_results, consequence_results + return priority_list, consequence_list # @@ -103,7 +108,13 @@ def calculate_asset_eaf_contributions(plant_result, eq_results): Higher contribution = more impact on reducing plant EAF """ results = defaultdict(float) + + # availabilities = {asset.get('aeros_node').get('node_name'): asset.get('availability') + # for asset in eq_results} + # importance_results = calculate_contribution_accurate(availabilities, "src/calculation_target_reliability/result.json") + + for asset in eq_results: results[asset['aeros_node']['node_name']] = asset['contribution'] diff --git a/src/calculation_target_reliability/result.json b/src/calculation_target_reliability/result.json new file mode 100644 index 0000000..ee9b065 --- /dev/null +++ b/src/calculation_target_reliability/result.json @@ -0,0 +1,2668 @@ +{ + "series": [ + { + "series": [ + { + "series": [ + { + "parallel_no_redundancy": [ + "3DCS-CAB001A", + "3DCS-CAB001B" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CAB002A", + "3DCS-CAB002B" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CAB003A", + "3DCS-CAB003B" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CAB004A", + "3DCS-CAB004B" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CAB005A", + "3DCS-CAB005B", + "3DCS-CAB005C" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CAB006A", + "3DCS-CAB006B" + ] + }, + "3DCS-CAB007", + "3DCS-CAB008", + { + "parallel_no_redundancy": [ + "3DCS-CAB009A", + "3DCS-CAB009B" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CAB010A", + "3DCS-CAB010B" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CAB011A", + "3DCS-CAB011B" + ] + }, + "3DCS-CAB012", + { + "parallel_no_redundancy": [ + "3DCS-CAB013A", + "3DCS-CAB013B" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CAB014A", + "3DCS-CAB014B" + ] + }, + "3DCS-CAB015", + "3DCS-CO001", + { + "parallel_no_redundancy": [ + "3DCS-CO002A", + "3DCS-CO002B" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CO003A", + "3DCS-CO003B", + "3DCS-CO003C", + "3DCS-CO003D" + ] + }, + "3DCS-CO004", + { + "parallel_no_redundancy": [ + "3DCS-CO005A", + "3DCS-CO005B", + "3DCS-CO005C" + ] + }, + { + "parallel_no_redundancy": [ + "3DCS-CO006A", + "3DCS-CO006B", + "3DCS-CO006C" + ] + }, + "3DCS-CO007", + "3DCS-CO008" + ] + }, + { + "series": [ + { + "parallel": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "00ACR-M001A", + "00ACR-C001A" + ] + }, + { + "series": [ + "00ACR-M001B", + "00ACR-C001B" + ] + } + ] + }, + { + "series": [ + "00ACR-M001C", + "00ACR-C001C" + ] + }, + { + "series": [ + "00ACR-M001D", + "00ACR-C001D" + ] + } + ] + }, + { + "parallel": [ + "00IA-A001A", + "00IA-A001B" + ] + }, + "3IA-T005" + ] + }, + { + "series": [ + "00SCR-Z001", + "00SCR-Z015" + ] + }, + { + "series": [ + "3FW-H040", + { + "parallel": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3LOT-T010A", + { + "series": [ + "3LOT-H010A", + { + "parallel": [ + "3LOT-T090A", + "3LOT-T100A" + ] + }, + { + "parallel": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3LOT-M010A", + "3LOT-P010A" + ] + }, + { + "series": [ + "3LOT-M020A", + "3LOT-P020A" + ] + } + ] + }, + { + "series": [ + "3LOT-M050A", + "3LOT-P050A" + ] + } + ] + }, + "3LOT-M080A", + "3LOT-P080A", + { + "parallel": [ + "3LOT-S010A", + "3LOT-S020A" + ] + }, + "3LOT-PF080A", + "3LOT-M120A", + "3LOT-F120A", + "3FW-P020A", + "3FW-H011A", + "3FW-H012A", + "3FW-AU030A", + "3FW-P010A", + "3BFT-ST010A", + "3BFT-AU040A" + ] + } + ] + }, + { + "series": [ + "3LOT-T010B", + { + "series": [ + "3LOT-H010B", + { + "parallel": [ + "3LOT-T090B", + "3LOT-T100B" + ] + }, + { + "parallel": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3LOT-M010B", + "3LOT-P010B" + ] + }, + { + "series": [ + "3LOT-M020B", + "3LOT-P020B" + ] + } + ] + }, + { + "series": [ + "3LOT-M050B", + "3LOT-P050B" + ] + } + ] + }, + "3LOT-M080B", + "3LOT-P080B", + { + "parallel": [ + "3LOT-S010B", + "3LOT-S020B" + ] + }, + "3LOT-PF080B", + "3LOT-M120B", + "3LOT-F120B", + "3FW-P020B", + "3FW-H011B", + "3FW-H012B", + "3FW-AU030B", + "3FW-P010B", + "3BFT-ST010B", + "3BFT-AU040B" + ] + } + ] + } + ] + }, + { + "series": [ + "3LOM-M330", + "3LOM-P330", + "3LOM-H310", + "3LOM-P310", + "3LOM-H370", + "3LOM-P370", + "3FW-P310", + "3FW-M321", + "3FW-M320", + "3FW-AU330", + "3FW-H301", + "3FW-H302", + "3FW-P300" + ] + } + ] + }, + "3FW-H070", + "3FW-H060", + "3FW-H050" + ] + }, + { + "series": [ + { + "series": [ + "3BOL-FD501", + { + "parallel_no_redundancy": [ + { + "series": [ + { + "series": [ + "3DP-FDR711A", + "3DP-M712A", + "3DP-M711A" + ] + }, + { + "series": [ + "3DP-M741A", + "3DP-BM741A", + "3DP-CVT701A", + "3DP-CVT711A", + "3DP-M761A", + "3DP-P761A", + "3DP-M781A", + "3DP-P781A", + "3DP-M731A", + "3DP-BM731A" + ] + }, + { + "series": [ + "3DP-B701A", + "3DP-B702A", + "3DP-B703A", + "3DP-B704A" + ] + } + ] + }, + { + "series": [ + { + "series": [ + "3DP-FDR711B", + "3DP-M712B", + "3DP-M711B" + ] + }, + { + "series": [ + "3DP-M741B", + "3DP-BM741B", + "3DP-CVT701B", + "3DP-CVT711B", + "3DP-M761B", + "3DP-P761B", + "3DP-M781B", + "3DP-P781B", + "3DP-M731B", + "3DP-BM731B" + ] + }, + { + "series": [ + "3DP-B701B", + "3DP-B702B", + "3DP-B703B", + "3DP-B704B" + ] + } + ] + }, + { + "series": [ + { + "series": [ + "3DP-FDR711C", + "3DP-M712C", + "3DP-M711C" + ] + }, + { + "series": [ + "3DP-M741C", + "3DP-BM741C", + "3DP-CVT701C", + "3DP-CVT711C", + "3DP-M761C", + "3DP-P761C", + "3DP-M781C", + "3DP-P781C", + "3DP-M731C", + "3DP-BM731C" + ] + }, + { + "series": [ + "3DP-B701C", + "3DP-B702C", + "3DP-B703C", + "3DP-B704C" + ] + } + ] + }, + { + "series": [ + { + "series": [ + "3DP-FDR711D", + "3DP-M712D", + "3DP-M711D" + ] + }, + { + "series": [ + "3DP-M741D", + "3DP-BM741D", + "3DP-CVT701D", + "3DP-CVT711D", + "3DP-M761D", + "3DP-P761D", + "3DP-M781D", + "3DP-P781D", + "3DP-M731D", + "3DP-BM731D" + ] + }, + { + "series": [ + "3DP-B701D", + "3DP-B702D", + "3DP-B703D", + "3DP-B704D" + ] + } + ] + }, + { + "series": [ + { + "series": [ + "3DP-FDR711E", + "3DP-M712E", + "3DP-M711E" + ] + }, + { + "series": [ + "3DP-M741E", + "3DP-BM741E", + "3DP-CVT701E", + "3DP-CVT711E", + "3DP-M761E", + "3DP-P761E", + "3DP-M781E", + "3DP-P781E", + "3DP-M731E", + "3DP-BM731E" + ] + }, + { + "series": [ + "3DP-B701E", + "3DP-B702E", + "3DP-B703E", + "3DP-B704E" + ] + } + ] + }, + { + "series": [ + { + "series": [ + "3DP-FDR711F", + "3DP-M712F", + "3DP-M711F" + ] + }, + { + "series": [ + "3DP-M741F", + "3DP-BM741F", + "3DP-CVT701F", + "3DP-CVT711F", + "3DP-M761F", + "3DP-P761F", + "3DP-M781F", + "3DP-P781F", + "3DP-M731F", + "3DP-BM731F" + ] + }, + { + "series": [ + "3DP-B701F", + "3DP-B702F", + "3DP-B703F", + "3DP-B704F" + ] + } + ] + } + ] + } + ] + }, + { + "series": [ + "3FO-FCV501", + { + "parallel_no_redundancy": [ + { + "series": [ + "3DM-B701A", + "3DM-B702A", + "3DM-B703A", + "3DM-B704A" + ] + }, + { + "series": [ + "3DM-B701C", + "3DM-B702C", + "3DM-B703C", + "3DM-B704C" + ] + }, + { + "series": [ + "3DM-B701E", + "3DM-B702E", + "3DM-B703E", + "3DM-B704E" + ] + } + ] + } + ] + }, + { + "series": [ + "3BDW-H601", + "3BDW-T601", + "3BDW-H611", + "3BDW-H621", + "3BDW-H631", + "3BDW-H641", + { + "parallel_no_redundancy": [ + { + "series": [ + "3BDW-M521A", + "3BDW-P521A", + "3BDW-H521A" + ] + }, + { + "series": [ + "3BDW-M521B", + "3BDW-P521B", + "3BDW-H521B" + ] + } + ] + } + ] + }, + "3BOL-H501", + { + "series": [ + "3MS-HV011", + "3MS-HV012", + "3MS-HV013", + "3MS-HV014", + { + "parallel_no_redundancy": [ + "3MS-HV010A", + "3MS-HV010B" + ] + }, + { + "parallel_no_redundancy": [ + "3MS-W001A", + "3MS-W001B" + ] + }, + "3MS-W004" + ] + }, + { + "series": [ + "3BSS-H611", + { + "parallel_no_redundancy": [ + "3ATT-N501A", + "3ATT-N501B" + ] + }, + "3BSS-H621", + { + "parallel_no_redundancy": [ + "3ATT-N502A", + "3ATT-N502B" + ] + }, + "3BSS-H631" + ] + }, + "3CRH-W002", + { + "series": [ + { + "parallel_no_redundancy": ["3ATT-N503A", "3ATT-N503B"] + }, + "3BRS-H611", + "3BRS-H621", + "3BRS-H631" + ] +}, + { + "series": [ + { + "parallel_no_redundancy": [ + "3HRH-HV020A", + "3HRH-HV020B" + ] + }, + "3ATT-N561", + "3ATT-N571", + "3ATT-N581" + ] + }, + { + "series": [ + "3AI-SFV501", + { + "parallel_no_redundancy": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3AI-M501H", + "3AI-Y501H", + "3AI-M502H", + "3AI-Y502H", + "3AI-M503H", + "3AI-Y503H", + "3AI-M504H", + "3AI-Y504H", + "3AI-M505H", + "3AI-Y505H", + "3AI-M506H", + "3AI-Y506H" + ] + }, + { + "series": [ + "3AI-M501I", + "3AI-Y501I", + "3AI-M502I", + "3AI-Y502I", + "3AI-M503I", + "3AI-Y503I", + "3AI-M504I", + "3AI-Y504I", + "3AI-M505I", + "3AI-Y505I", + "3AI-M506I", + "3AI-Y506I" + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3AI-M501L", + "3AI-Y501L", + "3AI-M503L", + "3AI-Y503L", + "3AI-M504L", + "3AI-Y504L", + "3AI-M505L", + "3AI-Y505L" + ] + }, + { + "series": [ + "3AI-M502L", + "3AI-Y502L", + "3AI-M506L", + "3AI-Y506L", + "3AI-M507L", + "3AI-Y507L", + "3AI-M508L", + "3AI-Y508L", + "3AI-M509L", + "3AI-Y509L", + "3AI-M510L", + "3AI-Y510L" + ] + }, + { + "series": [ + "3AI-M511L", + "3AI-Y511L", + "3AI-M512L", + "3AI-Y512L", + "3AI-M513L", + "3AI-Y513L", + "3AI-M514L", + "3AI-Y514L", + "3AI-M515L", + "3AI-Y515L", + "3AI-M516L", + "3AI-Y516L" + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "3AI-M501R", + "3AI-Y501R", + "3AI-M503R", + "3AI-Y503R", + "3AI-M504R", + "3AI-Y504R", + "3AI-M505R", + "3AI-Y505R" + ] + }, + { + "series": [ + "3AI-M502R", + "3AI-Y502R", + "3AI-M506R", + "3AI-Y506R", + "3AI-M507R", + "3AI-Y507R", + "3AI-M508R", + "3AI-Y508R", + "3AI-M509R", + "3AI-Y509R", + "3AI-M510R", + "3AI-Y510R" + ] + }, + { + "series": [ + "3AI-M511R", + "3AI-Y511R", + "3AI-M512R", + "3AI-Y512R", + "3AI-M513R", + "3AI-Y513R", + "3AI-M514R", + "3AI-Y514R", + "3AI-M515R", + "3AI-Y515R", + "3AI-M516R", + "3AI-Y516R" + ] + } + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3AI-M501A", + "3AI-Y501A", + "3AI-M502A", + "3AI-Y502A", + "3AI-M503A", + "3AI-Y503A", + "3AI-M504A", + "3AI-Y504A", + "3AI-M505A", + "3AI-Y505A" + ] + }, + { + "series": [ + "3AI-M501B", + "3AI-Y501B", + "3AI-M502B", + "3AI-Y502B", + "3AI-M503B", + "3AI-Y503B", + "3AI-M504B", + "3AI-Y504B" + ] + }, + { + "series": [ + "3AI-M501C", + "3AI-Y501C", + "3AI-M502C", + "3AI-Y502C", + "3AI-M503C", + "3AI-Y503C", + "3AI-M504C", + "3AI-Y504C", + "3AI-M505C", + "3AI-Y505C" + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "3AI-M506A", + "3AI-Y506A", + "3AI-M507A", + "3AI-Y507A", + "3AI-M508A", + "3AI-Y508A", + "3AI-M509A", + "3AI-Y509A" + ] + }, + { + "series": [ + "3AI-M505B", + "3AI-Y505B", + "3AI-M506B", + "3AI-Y506B", + "3AI-M507B", + "3AI-Y507B" + ] + }, + { + "series": [ + "3AI-M506C", + "3AI-Y506C", + "3AI-M507C", + "3AI-Y507C", + "3AI-M508C", + "3AI-Y508C", + "3AI-M509C", + "3AI-Y509C" + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "3AI-M515A", + "3AI-Y515A", + "3AI-M516A", + "3AI-Y516A", + "3AI-M517A", + "3AI-Y517A", + "3AI-M518A", + "3AI-Y518A" + ] + }, + { + "series": [ + "3AI-M512B", + "3AI-Y512B", + "3AI-M513B", + "3AI-Y513B", + "3AI-M514B", + "3AI-Y514B" + ] + }, + { + "series": [ + "3AI-M515C", + "3AI-Y515C", + "3AI-M516C", + "3AI-Y516C", + "3AI-M517C", + "3AI-Y517C", + "3AI-M518C", + "3AI-Y518C" + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "3AI-M510A", + "3AI-Y510A", + "3AI-M511A", + "3AI-Y511A", + "3AI-M512A", + "3AI-Y512A", + "3AI-M513A", + "3AI-Y513A", + "3AI-M514A", + "3AI-Y514A" + ] + }, + { + "series": [ + "3AI-M508B", + "3AI-Y508B", + "3AI-M509B", + "3AI-Y509B", + "3AI-M510B", + "3AI-Y510B", + "3AI-M511B", + "3AI-Y511B" + ] + }, + { + "series": [ + "3AI-M510C", + "3AI-Y510C", + "3AI-M511C", + "3AI-Y511C", + "3AI-M512C", + "3AI-Y512C", + "3AI-M513C", + "3AI-Y513C", + "3AI-M514C", + "3AI-Y514C" + ] + } + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "3AI-M551A", + "3AI-Y551A" + ] + }, + { + "series": [ + "3AI-M551B", + "3AI-Y551B" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "series": [ + { + "series": [ + { + "parallel": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3LOS-M010A", + "3LOS-P010A" + ] + }, + { + "series": [ + "3LOS-M010B", + "3LOS-P010B" + ] + } + ] + }, + { + "series": [ + "3LOS-M050", + "3LOS-P050" + ] + } + ] + }, + { + "parallel": [ + "3LOS-H010A", + "3LOS-H010B" + ] + }, + "3LOS-M080", + "3LOS-P080", + { + "parallel": [ + "3LOS-S010A", + "3LOS-S010B" + ] + }, + "3LOS-PF080", + { + "parallel": [ + { + "series": [ + "3LOS-M020A", + "3LOS-F020A" + ] + }, + { + "series": [ + "3LOS-M020B", + "3LOS-F020B" + ] + } + ] + }, + "3LOS-ME020", + "3LOS-M060", + "3LOS-P060" + ] + }, + { + "series": [ + "3EHS-Z010", + { + "parallel": [ + { + "series": [ + "3EHS-M010A", + "3EHS-P010A" + ] + }, + { + "series": [ + "3EHS-M010B", + "3EHS-P010B" + ] + } + ] + }, + { + "parallel": [ + "3EHS-T090A", + "3EHS-T090B" + ] + }, + { + "parallel": [ + { + "series": [ + "3EHS-M015A", + "3EHS-F015A", + "3EHS-H010A" + ] + }, + { + "series": [ + "3EHS-M015B", + "3EHS-F015B", + "3EHS-H010B" + ] + } + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "3MT-ST010", + "3MT-ST020" + ] + }, + { + "series": [ + "3HPB-PCV010", + { + "series": [ + "3EHB-Z010", + "3EHB-P020", + "3EHB-T110", + { + "parallel": ["3EHB-P010A", "3EHB-P010B"] + } + ] +} + ] + } + ] + }, + "3MT-ST030A", + "3MT-ST030B", + "3MT-AU040", + "3AS-T010", + "3AS-BS010", + { + "series": [ + "3SCW-PF001", + { + "parallel": [ + { + "series": [ + "3SCW-H023A", + "3SCW-M001A", + "3SCW-P001A" + ] + }, + { + "series": [ + "3SCW-H023B", + "3SCW-M001B", + "3SCW-P001B" + ] + } + ] + } + ] + }, + { + "series": [ + { + "parallel": [ + { + "series": [ + "3CW-M020A", + "3CW-P020A" + ] + }, + { + "series": [ + "3CW-M020B", + "3CW-P020B" + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "3CW-M010A", + "3CW-P010A" + ] + }, + { + "series": [ + "3CW-M010B", + "3CW-P010B" + ] + } + ] + }, + { + "parallel": [ + "3CW-P011A", + "3CW-P011B" + ] + } + ] + } + ] + }, + { + "series": [ + { + "series": [ + "3GSS-H010", + { + "parallel": [ + {"series": ["3GSS-M011A", "3GSS-F011A"]}, + {"series": ["3GSS-M011B", "3GSS-F011B"]} + ] + } + ] +}, + "3GEN-GM001", + { + "series": [ + "3SO-T116", + "3SO-T114", + "3SO-T113", + { + "parallel": [ + { + "series": [ + "3SO-M001", + "3SO-P001" + ] + }, + { + "series": [ + "3SO-M002", + "3SO-P002" + ] + } + ] + } + ] + }, + { + "series": [ + "3GEN-EXC008", + "3GEN-EXC009", + "3GEN-EXC004", + "3GEN-EXC005", + "3GEN-GM001", + "3GEN-Z012", + { + "parallel_no_redundancy": [ + { + "series": [ + "3GEN-M101A", + "3GEN-M102A", + "3GEN-M103A" + ] + }, + { + "series": [ + "3GEN-M101B", + "3GEN-M102B", + "3GEN-M103B" + ] + } + ] + }, + { + "parallel": [ + { + "parallel_no_redundancy": [ + "3GEN-M201A", + "3GEN-M202A", + "3GEN-M203A", + "3GEN-M204A", + "3GEN-M205A" + ] + }, + "3GEN-M206A" + ] + } + ] + }, + { + "series": [ + "3GMC-Z002", + "3GMC-Z001", + "3GMC-Z003", + { + "parallel_no_redundancy": [ + { + "series": [ + "3GEN-M211A", + "3GEN-M211B", + "3GEN-M211C" + ] + }, + { + "series": [ + "3GEN-M212A", + "3GEN-M212B", + "3GEN-M212C" + ] + }, + { + "series": [ + "3GEN-M213A", + "3GEN-M213B", + "3GEN-M213C" + ] + }, + { + "series": [ + "3GEN-M214A", + "3GEN-M214B", + "3GEN-M214C" + ] + } + ] + } + ] + }, + { + "series": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3TR-TF002A", + "3TR-Z003A" + ] + }, + { + "series": [ + "3TR-TF002B", + "3TR-Z003B" + ] + } + ] + }, + "3TR-TF001", + "3TR-TF005", + { + "parallel_no_redundancy": [ + "3TR-F301", + "3TR-F302", + "3TR-F303", + "3TR-F304", + "3TR-F305", + "3TR-F306", + "3TR-F307", + "3TR-F308", + "3TR-F309", + "3TR-F310", + "3TR-F311", + "3TR-F312", + "3TR-F313", + "3TR-F314" + ] + } + ] + } + ] + }, + { + "series": [ + "3CO-H001", + { + "parallel": [ + { + "series": [ + "3CO-M001A", + "3CO-P001A" + ] + }, + { + "series": [ + "3CO-M001B", + "3CO-P001B" + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "3CAE-M010A", + "3CAE-P010A", + "3CAE-H010A" + ] + }, + { + "series": [ + "3CAE-M010B", + "3CAE-P010B", + "3CAE-H010B" + ] + } + ] + }, + "3CO-FCV001", + "3CO-H010", + "3CO-H020", + "3CO-H030" + ] + }, + { + "series": [ + "3CCCW-T010", + "3CCCW-M090", + "3CCCW-P090", + { + "parallel": [ + { + "series": [ + "3CCCW-M010A", + "3CCCW-P010A", + "3CCCW-H010A" + ] + }, + { + "series": [ + "3CCCW-M010B", + "3CCCW-P010B", + "3CCCW-H010B" + ] + } + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + { + "series": [ + "3AF-FCV501A", + "3AF-M501A", + "3AF-F501A" + ] + }, + { + "series": [ + "3AL-PCV501A", + "3AL-M501A", + "3AL-F501A" + ] + }, + { + "series": [ + "3AH-AU501A", + "3AH-M531A", + "3AH-P531A", + "3AH-H531A", + "3AH-M502A", + "3AH-M501A", + "3AH-H501A" + ] +}, + { + "series": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3ESP-CAB801", + "3ESP-CAB821", + "A1-FIELD 1", + "A1-FIELD 2", + "A1-FIELD 3", + "A1-FIELD 4" + ] + }, + { + "series": [ + "3ESP-CAB802", + "3ESP-CAB822", + "A2-FIELD 1", + "A2-FIELD 2", + "A2-FIELD 3", + "A2-FIELD 4" + ] + } + ] + }, + "3GG-AX801A" + ] + }, + { + "series": [ + "3GG-M810A", + "3GG-F801A", + { + "parallel": [ + "3GG-F802A", + "3GG-F802B" + ] + }, + "3GG-M801A", + { + "parallel": [ + "3GG-F803A", + "3GG-F803B" + ] + }, + { + "parallel": [ + "3GG-P801A", + "3GG-P801B" + ] + } + ] + }, + { + "series": [ + { + "parallel_no_redundancy": [ + "3GG-F853A", + "3GG-F853B", + "3GG-F853C", + "3GG-F853D" + ] + }, + "3GG-M851", + "3GG-M851A", + "3GG-F851", + "3GG-H877", + "3GG-F865A", + "3GG-M870A", + "3GG-F870A", + { + "parallel": [ + { + "series": [ + "3GG-M875A", + "3GG-F875A" + ] + }, + { + "series": [ + "3GG-M875B", + "3GG-F875B" + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "3GG-M877A", + "3GG-P877A" + ] + }, + { + "series": [ + "3GG-M877B", + "3GG-P877B" + ] + } + ] + } + ] + } + ] + }, + { + "series": [ + { + "series": [ + "3AF-FCV501B", + "3AF-M501B", + "3AF-F501B" + ] + }, + { + "series": [ + "3AL-PCV501B", + "3AL-M501B", + "3AL-F501B" + ] + }, + { + "series": [ + "3AH-AU501B", + "3AH-M531B", + "3AH-P531B", + "3AH-H531B", + "3AH-M502B", + "3AH-M501B", + "3AH-H501B" + ] + }, + { + "series": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3ESP-CAB803", + "3ESP-CAB823", + "B1-FIELD 1", + "B1-FIELD 2", + "B1-FIELD 3", + "B1-FIELD 4" + ] + }, + { + "series": [ + "3ESP-CAB804", + "3ESP-CAB824", + "B2-FIELD 1", + "B2-FIELD 2", + "B2-FIELD 3", + "B2-FIELD 4" + ] + } + ] + }, + "3GG-AX801B" + ] + }, + { + "series": [ + "3GG-M810B", + "3GG-F801B", + { + "parallel": [ + "3GG-F804A", + "3GG-F804B" + ] + }, + { + "parallel": [ + "3GG-F805A", + "3GG-F805B" + ] + }, + "3GG-M801B", + "3GG-T801B", + { + "parallel": [ + "3GG-P802A", + "3GG-P802B" + ] + } + ] + }, + { + "series": [ + { + "parallel_no_redundancy": [ + "3GG-F854A", + "3GG-F854B", + "3GG-F854C", + "3GG-F854D" + ] + }, + "3GG-M852", + "3GG-M851B", + "3GG-F852", + "3GG-H878", + "3GG-F865B", + "3GG-M870B", + "3GG-F870B", + { + "parallel": [ + { + "series": [ + "3GG-M880A", + "3GG-F880A" + ] + }, + { + "series": [ + "3GG-M880B", + "3GG-F880B" + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "3GG-M878A", + "3GG-P878A" + ] + }, + { + "series": [ + "3GG-M878B", + "3GG-P878B" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "series": [ + "3BAD-PAN501", + "3BAD-M531", + "3BAD-AG531", + "3BAD-PN501", + { + "parallel": [ + { + "series": [ + "3BAD-H511A", + "3BAD-M511A", + "3BAD-P511A" + ] + }, + { + "series": [ + "3BAD-H511B", + "3BAD-M511B", + "3BAD-P511B" + ] + } + ] + }, + "3BAD-M501", + "3BAD-CV501", + "3BAD-T531", + "3BAD-T532", + { + "parallel": [ + { + "series": [ + "3BAD-M521A", + "3BAD-P521A" + ] + }, + { + "series": [ + "3BAD-M521B", + "3BAD-P521B" + ] + } + ] + } + ] + }, + { + "series": [ + { + "series": [ + { + "parallel_no_redundancy": [ + "3APC-CB811", + "3APC-CB812", + "3APC-CB813", + "3APC-CB814" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-LV001A", + "3APC-LV001B" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-LV501A", + "3APC-LV501B" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-LV810A", + "3APC-LV810B" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-LV811P1", + "3APC-LV811P2", + "3APC-LV811P3", + "3APC-LV811P4", + "3APC-LV811P5", + "3APC-LV811P21" + ] + }, + "3APC-LV851", + "3APC-MCC002", + { + "parallel_no_redundancy": [ + "3APC-MCC501A", + "3APC-MCC501B" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-MCC502A", + "3APC-MCC502B", + "3APC-MCC502C", + "3APC-MCC502D", + "3APC-MCC502E", + "3APC-MCC502F" + ] + }, + "3APC-MCC510", + "3APC-MCC851", + { + "parallel_no_redundancy": [ + "3APC-PD501A", + "3APC-PD501B" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-PD901", + "3APC-PD902" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-PD921", + "3APC-PD922" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-TF001A", + "3APC-TF001B" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-TF501A", + "3APC-TF501B" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-TF502A", + "3APC-TF502B" + ] + }, + { + "parallel_no_redundancy": [ + "3APC-TF810A", + "3APC-TF810B" + ] + }, + "3APC-TF811", + "3APC-TF851" + ] + }, + { + "series": [ + "3APE-CAB852", + { + "parallel_no_redundancy": [ + "3APE-MV001A", + "3APE-MV001B" + ] + }, + { + "parallel_no_redundancy": [ + "3APE-MV002A", + "3APE-MV002B" + ] + }, + { + "parallel_no_redundancy": [ + "3APE-MV003A", + "3APE-MV003B", + "3APE-MV003C", + "3APE-MV003D" + ] + }, + { + "parallel_no_redundancy": [ + "3APE-MV004A", + "3APE-MV004B" + ] + }, + "3APE-MV851", + "3APE-MV852", + { + "parallel_no_redundancy": [ + "3APE-TF002A", + "3APE-TF002B" + ] + }, + "3APE-TF852", + { + "parallel_no_redundancy": [ + "3APE-Z005A", + "3APE-Z005B" + ] + } + ] + }, + { + "series": [ + "3EG-E001", + "3EG-T003" + ] + } + ] + }, + { + "series": [ + { + "series": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "3ABS-M879A", + "3ABS-AG879A" + ] + }, + { + "series": [ + "3ABS-M879B", + "3ABS-AG879B" + ] + }, + { + "series": [ + "3ABS-M879C", + "3ABS-AG879C" + ] + }, + { + "series": [ + "3ABS-M879D", + "3ABS-AG879D" + ] + }, + { + "series": [ + "3ABS-M879E", + "3ABS-AG879E" + ] + } + ] + }, + "3ABS-T931", + "3ABS-M931", + "3ABS-AG931", + { + "parallel": [ + { + "series": [ + "3ABS-M932A", + "3ABS-P932A" + ] + }, + { + "series": [ + "3ABS-M932B", + "3ABS-P932B" + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "3ABS-M888A", + "3ABS-P888A" + ] + }, + { + "series": [ + "3ABS-M888B", + "3ABS-P888B" + ] + }, + { + "series": [ + "3ABS-M888C", + "3ABS-P888C" + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "3ABS-M910A", + "3ABS-P910A" + ] + }, + { + "series": [ + "3ABS-M910B", + "3ABS-P910B" + ] + } + ] + }, + "3ABS-ABT858" + ] + } + ] + } + ] + }, + { + "series": [ + { + "series": [ + { + "parallel": [ + { + "series": [ + "00CHA-SU801A", + "00CHA-CV801A", + "00CHA-MS801A", + "00CHA-BW802A", + "00CHA-CV802A", + "00CHA-CV803A", + "00CHA-SWT801" + ] + }, + { + "series": [ + "00CHA-SU801B", + "00CHA-CV801B", + "00CHA-MS801B", + "00CHA-BW802B", + "00CHA-CV802B", + "00CHA-CV803B", + "00CHA-SWT802" + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "00CHA-CV805A", + "00CHB-SKR805A" + ] + }, + { + "series": [ + "00CHA-CV804", + "00CHA-CV805B", + "00CHB-SKR805B" + ] + } + ] + }, + "COAL YARD" + ] + }, + { + "series": [ + "BOOSTER", + "FILTER", + "TRAFO", + "CELL", + "SUMP PUMP" + ] + }, + { + "series": [ + { + "parallel_no_redundancy": [ + { + "series": [ + "00RO-M110A", + "00RO-P110A" + ] + }, + { + "series": [ + "00RO-M110B", + "00RO-P110B" + ] + }, + { + "series": [ + "00RO-M110C", + "00RO-P110C" + ] + }, + { + "series": [ + "00RO-M110D", + "00RO-P110D" + ] + } + ] + }, + "00RO-T120", + "FeCl3 DOSING", + "ANIONIC POLYMER DOSING", + "CLEAR WATER", + "CLARIFIER", + "00RO-T170", + { + "parallel": [ + { + "series": [ + "00RO-M195A", + "00RO-P195A" + ] + }, + { + "series": [ + "00RO-M195B", + "00RO-P195B" + ] + } + ] + }, + "00RO-T320", + "00RO-T130", + { + "parallel_no_redundancy": [ + { + "series": [ + "00RO-M126A", + "00RO-P126A" + ] + }, + { + "series": [ + "00RO-M126B", + "00RO-P126B" + ] + }, + { + "series": [ + "00RO-M126C", + "00RO-P126C" + ] + }, + { + "series": [ + "00RO-M126D", + "00RO-P126D" + ] + } + ] + }, + "NaOCL DOSING", + { + "parallel": [ + { + "series": [ + "00RO-F161A", + "00RO-M152A", + "00RO-F152A" + ] + }, + { + "series": [ + "00RO-F161B", + "00RO-M152B", + "00RO-F152B" + ] + } + ] + }, + "00RO-T150", + { + "parallel": [ + { + "series": [ + "00RO-M150A", + "00RO-P150A" + ] + }, + { + "series": [ + "00RO-M150B", + "00RO-P150B" + ] + } + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "00RO-M160A", + "00RO-P160A" + ] + }, + { + "series": [ + "00RO-M160B", + "00RO-P160B" + ] + }, + { + "series": [ + "00RO-M160C", + "00RO-P160C" + ] + }, + { + "series": [ + "00RO-M160D", + "00RO-P160D" + ] + } + ] + }, + "H2SO4 DOSING", + "SBS DOSING", + "ANTI SCALANT DOSING", + { + "parallel_no_redundancy": [ + { + "series": [ + "00RO-M170A", + "00RO-P170A", + "00RO-T160A", + "00RO-Z110A" + ] + }, + { + "series": [ + "00RO-M170B", + "00RO-P170B", + "00RO-T160B", + "00RO-Z110B" + ] + }, + { + "series": [ + "00RO-M170C", + "00RO-P170C", + "00RO-T160C", + "00RO-Z110C" + ] + }, + { + "series": [ + "00RO-M170D", + "00RO-P170D", + "00RO-T160D", + "00RO-Z110D" + ] + } + ] + }, + "NaOH DOSING", + "00RO-H181", + "00RO-AG181", + "00RO-M181", + { + "parallel": [ + { + "series": [ + "00RO-M180A", + "00RO-P180A" + ] + }, + { + "series": [ + "00RO-M180B", + "00RO-P180B" + ] + } + ] + }, + "header 3", + { + "parallel": [ + { + "series": [ + "00RO-M340A", + "00RO-P340A" + ] + }, + { + "series": [ + "00RO-M340B", + "00RO-P340B" + ] + } + ] + }, + "00RO-T162", + { + "parallel_no_redundancy": [ + { + "series": [ + "00RO-M190A", + "00RO-P190A" + ] + }, + { + "series": [ + "00RO-M190B", + "00RO-P190B" + ] + } + ] + } + ] + }, + "WTP", + { + "series": [ + { + "series": [ + { + "series": [ + "00DS-T888", + "00DS-M888", + "00DS-AG888", + { + "parallel": [ + { + "series": [ + "00DS-M883A", + "00DS-P883A" + ] + }, + { + "series": [ + "00DS-M883B", + "00DS-P883B" + ] + } + ] + } + ] + }, + { + "series": [ + { + "parallel": [ + "00DS-CY851A", + "00DS-CY851B" + ] + }, + "00DS-T851", + "00DS-M851", + "00DS-AG851", + { + "parallel": [ + { + "series": [ + "00DS-M860A", + "00DS-P860A" + ] + }, + { + "series": [ + "00DS-M860B", + "00DS-P860B" + ] + } + ] + }, + "00DS-T852", + "00DS-CY865" + ] + }, + { + "parallel": [ + { + "series": [ + "00DS-T901", + "00DS-M900", + "00DS-M901", + "00DS-P901", + "00DS-T900", + { + "parallel": [ + { + "series": [ + "00DS-M902A", + "00DS-P902A" + ] + }, + { + "series": [ + "00DS-M902B", + "00DS-P902B" + ] + } + ] + } + ] + }, + { + "series": [ + "00DS-T936", + "00DS-M935", + "00DS-M936", + "00DS-P936", + "00DS-T935", + { + "parallel": [ + { + "series": [ + "00DS-M937A", + "00DS-P937A" + ] + }, + { + "series": [ + "00DS-M937B", + "00DS-P937B" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "00OA-M851A", + "00OA-F851A" + ] + }, + { + "series": [ + "00OA-M851B", + "00OA-F851B" + ] + }, + { + "series": [ + "00OA-M851C", + "00OA-F851C" + ] + } + ] + }, + { + "series": [ + "00LSH-SU801", + "00LSH-HO801", + "00LSH-BW801", + "00LSH-COG801", + "00LSH-M851", + "00LSH-VFD801", + "00LSH-VI851", + "00LSH-M853A", + "00LSH-CR853", + "00LSH-CV801", + "00LSH-M901", + "00LSH-F901", + "00LSH-DC901", + "00LSH-MS801", + "00LSH-M852", + "00LSH-CV852", + "00LSH-HO851" + ] + }, + { + "series": [ + "00RP-T985", + "00RP-M985", + "00RP-AG985", + { + "parallel": [ + { + "series": [ + "00RP-M986A", + "00RP-P986A" + ] + }, + { + "series": [ + "00RP-M986B", + "00RP-P986B" + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "00RP-BM871", + { + "parallel_no_redundancy": [ + "00RP-M871A", + "00RP-M871B" + ] + } + ] + }, + { + "series": [ + "00RP-BM911", + { + "parallel": [ + "00RP-M911A", + "00RP-M911B" + ] + } + ] + } + ] + }, + { + "parallel": [ + { + "series": [ + "00RP-CY871", + "00RP-DX897", + { + "parallel": [ + "00RP-F991A", + "00RP-F991B" + ] + }, + "00RP-T885", + "00RP-M885", + "00RP-AG885", + "00RP-P992", + { + "parallel": [ + { + "series": [ + "00RP-P991A", + "00RP-M891A", + "00RP-P891A" + ] + }, + { + "series": [ + "00RP-P991B", + "00RP-M891B", + "00RP-P891B" + ] + } + ] + } + ] + }, + { + "series": [ + "00RP-CY911", + "00RP-DX837", + { + "parallel": [ + "00RP-F995A", + "00RP-F995B" + ] + }, + "00RP-F995A", + "00RP-T925", + "00RP-M925", + "00RP-AG925", + "00RP-P995", + { + "parallel": [ + { + "series": [ + "00RP-P995A", + "00RP-M931A", + "00RP-P931A" + ] + }, + { + "series": [ + "00RP-P995B", + "00RP-M931B", + "00RP-P931B" + ] + } + ] + } + ] + } + ] + }, + "00RP-T970", + "00RP-M970", + "00RP-AG970", + { + "parallel": [ + { + "series": [ + "00RP-M972A", + "00RP-P972A" + ] + }, + { + "series": [ + "00RP-M972B", + "00RP-P972B" + ] + } + ] + }, + "00RP-T950", + "00RP-M950", + "00RP-AG950", + { + "parallel": [ + { + "series": [ + "00RP-M952A", + "00RP-P952A" + ] + }, + { + "series": [ + "00RP-M952B", + "00RP-P952B" + ] + } + ] + }, + { + "parallel": [ + { + "parallel_no_redundancy": [ + "00RP-Z851A", + "00RP-Z851B", + "00RP-Z851C" + ] + }, + "00RP-Z851D" + ] + }, + { + "parallel_no_redundancy": [ + { + "series": [ + "00RP-M856A", + "00RP-Z856A" + ] + }, + { + "series": [ + "00RP-M856B", + "00RP-Z856B" + ] + } + ] + }, + "00RP-DX979" + ] + } + ] + }, + { + "series": [ + "00SSB-EV001", + "00SSB-EV002", + "00SSB-EV003", + { + "parallel_no_redundancy": [ + "00SSB-EV004", + "00SSB-EV005" + ] + }, + "00SSB-EV006", + "00SSB-EV007", + "00SSB-EV012", + "00SSB-LA008", + "00SSB-LA009", + "00SSB-TF010" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/calculation_target_reliability/router.py b/src/calculation_target_reliability/router.py index efbafd1..7f89457 100644 --- a/src/calculation_target_reliability/router.py +++ b/src/calculation_target_reliability/router.py @@ -59,7 +59,7 @@ async def get_target_reliability( # ) if not simulation_id: - simulation_id = "f31103ef-1ac8-4c29-8f66-ea9ccf06bd87" + simulation_id = "efa8ef4c-0417-4d2d-95f3-41e4283737ab" results = await get_simulation_results( simulation_id=simulation_id, diff --git a/src/calculation_target_reliability/schema.py b/src/calculation_target_reliability/schema.py index 3b6b956..f58fd1e 100644 --- a/src/calculation_target_reliability/schema.py +++ b/src/calculation_target_reliability/schema.py @@ -33,8 +33,9 @@ class OverhaulRead(OverhaulBase): class AssetWeight(OverhaulBase): node: dict + availability:float contribution: float - eaf_impact: float + required_improvement: float num_of_failures: int down_time: float diff --git a/src/calculation_target_reliability/service.py b/src/calculation_target_reliability/service.py index 91e7cfc..ae29172 100644 --- a/src/calculation_target_reliability/service.py +++ b/src/calculation_target_reliability/service.py @@ -3,6 +3,7 @@ from dataclasses import dataclass from sqlalchemy import Delete, Select import httpx from src.auth.service import CurrentUser +from src.contribution_util import calculate_contribution, calculate_contribution_accurate from src.database.core import DbSession, CollectorDbSession from datetime import datetime, timedelta import random @@ -47,9 +48,9 @@ async def get_simulation_results(*, simulation_id: str, token: str): "Content-Type": "application/json" } - calc_result_url = f"{RBD_SERVICE_API}/aeros/simulation/result/calc/{simulation_id}?nodetype=RegularNode" + calc_result_url = f"{RBD_SERVICE_API}/aeros/simulation/result/calc/default?nodetype=RegularNode" # plot_result_url = f"{RBD_SERVICE_API}/aeros/simulation/result/plot/{simulation_id}?nodetype=RegularNode" - calc_plant_result = f"{RBD_SERVICE_API}/aeros/simulation/result/calc/{simulation_id}/plant" + calc_plant_result = f"{RBD_SERVICE_API}/aeros/simulation/result/calc/default/plant" async with httpx.AsyncClient(timeout=300.0) as client: calc_task = client.get(calc_result_url, headers=headers) @@ -104,43 +105,85 @@ async def get_simulation_results(*, simulation_id: str, token: str): # return results -def calculate_asset_eaf_contributions(plant_result, eq_results, standard_scope): +def calculate_asset_eaf_contributions(plant_result, eq_results, standard_scope, eaf_gap): """ - Calculate each asset's negative contribution to plant EAF - Higher contribution = more impact on reducing plant EAF + Calculate each asset's contribution to plant EAF with realistic improvement potential. + Higher contribution = more impact on improving plant EAF """ - plant_production = plant_result.get('total_downtime', 0) - plant_eaf = plant_result.get('eaf') + # Convert EAF gap from percentage to fraction if needed + # Assuming eaf_gap is a percentage (e.g., 1.0 for 1%), convert to fraction + eaf_gap_fraction = eaf_gap / 100.0 if eaf_gap > 1.0 else eaf_gap + results = [] - + filtered_assets = [] # To track assets that were filtered out + + # # Get availabilities and calculate importance + # availabilities = {asset.get('aeros_node').get('node_name'): asset.get('availability') + # for asset in eq_results} + # importance_results = calculate_contribution_accurate(availabilities, "src/calculation_target_reliability/result.json") + + # Define realistic thresholds + MIN_BIRNBAUM_IMPORTANCE = 0.0005 # Filter out components with very low impact + REALISTIC_MAX_AVAILABILITY = 0.995 # 99.5% practical maximum + MIN_IMPROVEMENT_PERCENT = 0.05 # Minimum improvement to consider (0.5%) + min_improvement_fraction = MIN_IMPROVEMENT_PERCENT / 100.0 for asset in eq_results: - # # Weight based on production capacity (just for seri) - # capacity_weight = asset.get('total_downtime', 0) / plant_production if plant_production > 0 else 0 - if asset.get('aeros_node').get('node_name') not in standard_scope: + asset_name = asset.get('aeros_node').get('node_name') + + # Skip if not in standard scope + if asset_name not in standard_scope: continue - # # Get asset EAF and downtime - plant_eaf_minus = 100 - plant_eaf - - # # Calculate this asset's contribution to plant EAF reduction - # # This is how much this asset alone reduces the overall plant EAF - eaf_contribution = plant_eaf_minus * asset.get("contribution") - - # # Calculate actual downtime hours (if simulation hours available) - # sim_duration = plant_result.get('sim_duration', 8760) # Default to 1 year - + birnbaum = asset.get('contribution') + current_availability = asset.get('availability') + + # Calculate required improvement + required_impr = eaf_gap_fraction / birnbaum if birnbaum > 0 else 0 + + # # CHECK FILTERS - Is this asset worth considering? + # filter_reason = None + + # # Filter 1: Is the component important enough? + # if birnbaum < MIN_BIRNBAUM_IMPORTANCE: + # filter_reason = f"Low importance (Birnbaum: {birnbaum:.4f} < {MIN_BIRNBAUM_IMPORTANCE})" + + # # Filter 2: Would improvement exceed realistic maximum? + # elif (current_availability + required_impr) > REALISTIC_MAX_AVAILABILITY: + # filter_reason = f"Exceeds realistic maximum ({current_availability + required_impr:.3f} > {REALISTIC_MAX_AVAILABILITY})" + + # # Filter 3: Is the improvement too small to be worthwhile? + # elif required_impr < min_improvement_fraction: + # filter_reason = f"Improvement too small ({required_impr*100:.2f}% < {MIN_IMPROVEMENT_PERCENT}%)" + + # # If filtered, add to filtered list and skip + # if filter_reason: + # filtered_assets.append({ + # 'asset': asset_name, + # 'reason': filter_reason, + # 'birnbaum': birnbaum, + # 'current_availability': current_availability, + # 'required_improvement': required_impr + # }) + # continue + + # If it passed all filters, include it in results contribution = AssetWeight( node=asset.get('aeros_node'), - contribution=asset.get("contribution"), - eaf_impact=eaf_contribution, + availability=current_availability, + contribution=birnbaum, + required_improvement=required_impr, num_of_failures=asset.get('num_events', 0), down_time=asset.get('total_downtime') ) results.append(contribution) + # raise Exception(filtered_assets) + + # Sort by contribution (Birnbaum Importance) - most critical first results.sort(key=lambda x: x.contribution, reverse=True) + return results def project_eaf_improvement(asset: AssetWeight, improvement_factor: float = 0.3) -> float: @@ -173,9 +216,7 @@ async def identify_worst_eaf_contributors(*, simulation_result, target_eaf: floa # Get equipment results from calc_result eq_results = calc_result if isinstance(calc_result, list) else [calc_result] current_plant_eaf = plant_result.get("eaf", 0) - eaf_gap = target_eaf - current_plant_eaf - - + eaf_gap = (target_eaf - current_plant_eaf)/100.0 # # Verify our calculation by summing contributions # total_calculated_downtime = sum(contrib.eaf_impact for contrib in asset_contributions) @@ -189,26 +230,26 @@ async def identify_worst_eaf_contributors(*, simulation_result, target_eaf: floa standard_scope_location_tags = [tag.location_tag for tag in standard_scope] - asset_contributions = calculate_asset_eaf_contributions(plant_result, eq_results, standard_scope_location_tags) + asset_contributions = calculate_asset_eaf_contributions(plant_result, eq_results, standard_scope_location_tags, eaf_gap=eaf_gap) - project_eaf_improvement = 0.0 - selected_eq = [] + # project_eaf_improvement = 0.0 + # selected_eq = [] - for asset in asset_contributions: - if (project_eaf_improvement + asset.eaf_impact) <= eaf_gap: - selected_eq.append(asset) - project_eaf_improvement += asset.eaf_impact - else: - break + # for asset in asset_contributions: + # if (project_eaf_improvement + asset.eaf_impact) <= eaf_gap: + # selected_eq.append(asset) + # project_eaf_improvement += asset.eaf_impact + # else: + # break - optimization_success = current_plant_eaf + project_eaf_improvement >= target_eaf + # optimization_success = current_plant_eaf + project_eaf_improvement >= target_eaf return OptimizationResult( - current_plant_eaf=current_plant_eaf + project_eaf_improvement, + current_plant_eaf=current_plant_eaf, target_plant_eaf=target_eaf, eaf_gap=eaf_gap, - asset_contributions=selected_eq, - optimization_success=optimization_success, + asset_contributions=asset_contributions, + optimization_success=True, simulation_id=simulation_id ) diff --git a/src/calculation_time_constrains/service.py b/src/calculation_time_constrains/service.py index 7c33939..65caca6 100644 --- a/src/calculation_time_constrains/service.py +++ b/src/calculation_time_constrains/service.py @@ -1112,7 +1112,7 @@ class OptimumCostModel: async def get_failures_prediction(self, simulation_id: str, location_tag): # calc_result_url = f"{RBD_SERVICE_API}/aeros/simulation/result/calc/{simulation_id}?nodetype=RegularNode" - plot_result_url = f"{RBD_SERVICE_API}/aeros/simulation/result/plot/{simulation_id}/{location_tag}?use_location_tag=1" + plot_result_url = f"{RBD_SERVICE_API}/aeros/simulation/result/plot/default/{location_tag}?use_location_tag=1" # calc_plant_result = f"{RBD_SERVICE_API}/aeros/simulation/result/calc/{simulation_id}/plant" diff --git a/src/contribution_util.py b/src/contribution_util.py new file mode 100644 index 0000000..84644d7 --- /dev/null +++ b/src/contribution_util.py @@ -0,0 +1,286 @@ +import json +import logging +from typing import Dict, Union, Tuple +from decimal import Decimal, getcontext +import math + +# Set high precision for decimal calculations +getcontext().prec = 50 + +Structure = Union[str, Dict[str, list]] + +log = logging.getLogger(__name__) + +def prod(iterable): + """Compute product of all elements in iterable with high precision.""" + result = Decimal('1.0') + for x in iterable: + if isinstance(x, (int, float)): + x = Decimal(str(x)) + result *= x + return float(result) + + +def system_availability(structure: Structure, availabilities: Dict[str, float]) -> float: + """Recursively compute system availability with precise calculations.""" + if isinstance(structure, str): # base case - component + if structure not in availabilities: + raise ValueError(f"Component '{structure}' not found in availabilities") + return float(Decimal(str(availabilities[structure]))) + + if isinstance(structure, dict): + if "series" in structure: + components = structure["series"] + if not components: # Handle empty series + return 1.0 + + # Series: A_system = A1 * A2 * ... * An + product = Decimal('1.0') + for s in components: + availability = system_availability(s, availabilities) + product *= Decimal(str(availability)) + return float(product) + + elif "parallel" in structure: + components = structure["parallel"] + if not components: # Handle empty parallel + return 0.0 + + # Parallel: A_system = 1 - (1-A1) * (1-A2) * ... * (1-An) + product = Decimal('1.0') + for s in components: + availability = system_availability(s, availabilities) + unavailability = Decimal('1.0') - Decimal(str(availability)) + product *= unavailability + + 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"] + if not components: + return 0.0 + + availabilities_list = [system_availability(s, availabilities) for s in components] + return min(availabilities_list) + + raise ValueError(f"Invalid structure definition: {structure}") + + +def get_all_components(structure: Structure) -> set: + """Extract all component names from a structure.""" + components = set() + + def extract_components(substructure): + if isinstance(substructure, str): + components.add(substructure) + elif isinstance(substructure, dict): + for component_list in substructure.values(): + for component in component_list: + extract_components(component) + + extract_components(structure) + return components + + +def birnbaum_importance(structure: Structure, availabilities: Dict[str, float], component: str) -> float: + """ + Calculate Birnbaum importance for a component. + + Birnbaum importance = ∂A_system/∂A_component + + This is approximated as: + I_B = A_system(A_i=1) - A_system(A_i=0) + + Where A_i is the availability of component i. + """ + # Create copies for calculations + avail_up = availabilities.copy() + avail_down = availabilities.copy() + + # Set component availability to 1 (perfect) + avail_up[component] = 1.0 + + # Set component availability to 0 (failed) + avail_down[component] = 0.0 + + # Calculate system availability in both cases + system_up = system_availability(structure, avail_up) + system_down = system_availability(structure, avail_down) + + # Birnbaum importance is the difference + return system_up - system_down + + +def criticality_importance(structure: Structure, availabilities: Dict[str, float], component: str) -> float: + """ + Calculate Criticality importance for a component. + + Criticality importance = Birnbaum importance * (1 - A_component) / (1 - A_system) + + This represents the probability that component i is critical to system failure. + """ + birnbaum = birnbaum_importance(structure, availabilities, component) + system_avail = system_availability(structure, availabilities) + component_avail = availabilities[component] + + if system_avail >= 1.0: # Perfect system + return 0.0 + + criticality = birnbaum * (1.0 - component_avail) / (1.0 - system_avail) + return criticality + + +def fussell_vesely_importance(structure: Structure, availabilities: Dict[str, float], component: str) -> float: + """ + Calculate Fussell-Vesely importance for a component. + + FV importance = (A_system - A_system(A_i=0)) / A_system + + This represents the fractional decrease in system availability when component i fails. + """ + system_avail = system_availability(structure, availabilities) + + if system_avail <= 0.0: + return 0.0 + + # Calculate system availability with component failed + avail_down = availabilities.copy() + avail_down[component] = 0.0 + system_down = system_availability(structure, avail_down) + + fv = (system_avail - system_down) / system_avail + return fv + + +def compute_all_importance_measures(structure: Structure, availabilities: Dict[str, float]) -> Dict[str, Dict[str, float]]: + """ + Compute all importance measures for each component. + + Returns: + Dictionary with component names as keys and importance measures as values + """ + # Normalize availabilities to 0-1 range if needed + normalized_availabilities = {} + for k, v in availabilities.items(): + if v > 1.0: + normalized_availabilities[k] = v / 100.0 + else: + normalized_availabilities[k] = v + # Clamp to valid range [0, 1] + normalized_availabilities[k] = max(0.0, min(1.0, normalized_availabilities[k])) + + # Get all components in the system + all_components = get_all_components(structure) + + # Check for missing components + missing_components = all_components - set(normalized_availabilities.keys()) + if missing_components: + log.warning(f"Missing components (assuming 100% availability): {missing_components}") + for comp in missing_components: + normalized_availabilities[comp] = 1.0 + + # Calculate system baseline availability + system_avail = system_availability(structure, normalized_availabilities) + + # Calculate importance measures for each component + results = {} + total_birnbaum = 0.0 + + for component in all_components: + if component in normalized_availabilities: + birnbaum = birnbaum_importance(structure, normalized_availabilities, component) + criticality = criticality_importance(structure, normalized_availabilities, component) + fv = fussell_vesely_importance(structure, normalized_availabilities, component) + + results[component] = { + 'birnbaum_importance': birnbaum, + 'criticality_importance': criticality, + 'fussell_vesely_importance': fv, + 'component_availability': normalized_availabilities[component] + } + + total_birnbaum += birnbaum + + # Calculate contribution percentages based on Birnbaum importance + if total_birnbaum > 0: + for component in results: + contribution_pct = results[component]['birnbaum_importance'] / total_birnbaum + results[component]['contribution_percentage'] = contribution_pct + else: + for component in results: + results[component]['contribution_percentage'] = 0.0 + + # Add system-level information + results['_system_info'] = { + 'system_availability': system_avail, + 'system_unavailability': 1.0 - system_avail, + 'total_birnbaum_importance': total_birnbaum + } + + return results + + +def calculate_contribution_accurate(availabilities: Dict[str, float], structure_file: str = 'src/overhaul/rbd_structure.json') -> Dict[str, Dict[str, float]]: + """ + Calculate component contributions using proper importance measures. + + Args: + availabilities: Dictionary of component availabilities + structure_file: Path to RBD structure JSON file + + Returns: + Dictionary containing all importance measures and contributions + """ + try: + with open(structure_file, 'r') as model_file: + structure = json.load(model_file) + except FileNotFoundError: + raise FileNotFoundError(f"Structure file not found: {structure_file}") + except json.JSONDecodeError: + raise ValueError(f"Invalid JSON in structure file: {structure_file}") + + # Compute all importance measures + results = compute_all_importance_measures(structure, availabilities) + + # Extract system information + system_info = results.pop('_system_info') + + # Log results + log.info(f"System Availability: {system_info['system_availability']:.6f}") + log.info(f"System Unavailability: {system_info['system_unavailability']:.6f}") + + # Sort components by Birnbaum importance (most critical first) + sorted_components = sorted(results.items(), + key=lambda x: x[1]['birnbaum_importance'], + reverse=True) + + print("\n=== COMPONENT IMPORTANCE ANALYSIS ===") + print(f"System Availability: {system_info['system_availability']:.6f} ({system_info['system_availability']*100:.4f}%)") + print(f"System Unavailability: {system_info['system_unavailability']:.6f}") + print("\nComponent Rankings (by Birnbaum Importance):") + print(f"{'Component':<20} {'Availability':<12} {'Birnbaum':<12} {'Criticality':<12} {'F-V':<12} {'Contribution%':<12}") + print("-" * 92) + + for component, measures in sorted_components: + print(f"{component:<20} {measures['component_availability']:<12.6f} " + f"{measures['birnbaum_importance']:<12.6f} {measures['criticality_importance']:<12.6f} " + f"{measures['fussell_vesely_importance']:<12.6f} {measures['contribution_percentage']*100:<12.4f}") + + # Return results with system info included + # results['_system_info'] = system_info + + return results + + +# Legacy function for backwards compatibility +def calculate_contribution(availabilities): + """Legacy function - redirects to improved version.""" + try: + return calculate_contribution_accurate(availabilities) + except Exception as e: + log.error(f"Error in contribution calculation: {e}") + raise + + diff --git a/src/overhaul/rbd_structure.json b/src/overhaul/rbd_structure.json new file mode 100644 index 0000000..6af4259 --- /dev/null +++ b/src/overhaul/rbd_structure.json @@ -0,0 +1,23 @@ +{ + "series": [ + "Plant Control", + "SAC-IAC", + "SCR", + "Feedwater System", + "Boiler", + "Turbine", + "Generator", + "Condensate Water", + "Cooling Water", + "Air Flue Gas", + "Ash Handling", + "SPS", + "KLH", + "CHS", + "CL", + "Desalination", + "WTP", + "FGD", + "SSB" + ] +} \ No newline at end of file diff --git a/src/overhaul/router.py b/src/overhaul/router.py index b99046c..42158cf 100644 --- a/src/overhaul/router.py +++ b/src/overhaul/router.py @@ -2,6 +2,7 @@ from typing import List from fastapi import APIRouter, HTTPException, status +from src.auth.service import Token from src.database.core import DbSession from src.models import StandardResponse from src.overhaul.service import (get_overhaul_critical_parts, @@ -17,11 +18,11 @@ router = APIRouter() @router.get("", response_model=StandardResponse[OverhaulRead]) -async def get_overhaul(db_session: DbSession): +async def get_overhaul(db_session: DbSession, token:Token): """Get all scope pagination.""" overview = await get_overhaul_overview(db_session=db_session) schedules = await get_overhaul_schedules(db_session=db_session) - criticalParts = get_overhaul_critical_parts() + criticalParts = await get_overhaul_critical_parts(db_session=db_session, session_id=overview["overhaul"]["id"], token=token) systemComponents = get_overhaul_system_components() return StandardResponse( diff --git a/src/overhaul/schema.py b/src/overhaul/schema.py index 89966e2..8116f15 100644 --- a/src/overhaul/schema.py +++ b/src/overhaul/schema.py @@ -28,7 +28,7 @@ class OverhaulSystemComponents(OverhaulBase): class OverhaulRead(OverhaulBase): overview: Dict[str, Any] - criticalParts: List[str] + criticalParts: dict schedules: List[ScopeRead] systemComponents: Dict[str, Any] diff --git a/src/overhaul/service.py b/src/overhaul/service.py index 901a84f..da267b9 100644 --- a/src/overhaul/service.py +++ b/src/overhaul/service.py @@ -1,12 +1,18 @@ +import asyncio from typing import Optional +import httpx from sqlalchemy import Delete, Select from src.auth.service import CurrentUser +from src.calculation_target_reliability.service import RBD_SERVICE_API from src.database.core import DbSession +from src.contribution_util import calculate_contribution +from src.overhaul_activity.service import get_standard_scope_by_session_id from src.overhaul_scope.model import OverhaulScope from src.overhaul_scope.service import get_all as get_all_session from src.overhaul_scope.service import get_overview_overhaul +from src.standard_scope.service import get_by_oh_session_id async def get_overhaul_overview(db_session: DbSession): @@ -16,17 +22,92 @@ async def get_overhaul_overview(db_session: DbSession): return results -def get_overhaul_critical_parts(): +async def get_simulation_results(*, simulation_id: str, token: str): + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json" + } + + calc_result_url = f"{RBD_SERVICE_API}/aeros/simulation/result/calc/default?nodetype=RegularNode" + # plot_result_url = f"{RBD_SERVICE_API}/aeros/simulation/result/plot/{simulation_id}?nodetype=RegularNode" + calc_plant_result = f"{RBD_SERVICE_API}/aeros/simulation/result/calc/default/plant" + + async with httpx.AsyncClient(timeout=300.0) as client: + calc_task = client.get(calc_result_url, headers=headers) + # plot_task = client.get(plot_result_url, headers=headers) + plant_task = client.get(calc_plant_result, headers=headers) + + # Run all three requests concurrently + calc_response, plant_response = await asyncio.gather(calc_task, plant_task) + + calc_response.raise_for_status() + # plot_response.raise_for_status() + plant_response.raise_for_status() + + calc_data = calc_response.json()["data"] + # plot_data = plot_response.json()["data"] + plant_data = plant_response.json()["data"] + + return { + "calc_result": calc_data, + # "plot_result": plot_data, + "plant_result": plant_data + } + +async def get_overhaul_critical_parts(db_session, session_id, token): """Get all overhaul critical parts.""" - return [ - "Boiler feed pump", - "Boiler reheater system", - "Drum Level (Right) Root Valve A", - "BCP A Discharge Valve", - "BFPT A EXH Press HI Root VLV", + equipments, _ = await get_by_oh_session_id( + db_session=db_session, + oh_session_id=session_id, + ) + + + criticality_simulation = await get_simulation_results( + simulation_id="efa8ef4c-0417-4d2d-95f3-41e4283737ab", + token=token + ) + + + + rbd_simulation = {asset['aeros_node']["node_name"]: { + "availability": asset["availability"], + "criticality": asset["criticality"] + } for asset in criticality_simulation["calc_result"]} + + # Create the base result list + base_result = [ + { + "id": equipment.id, + "location_tag": equipment.location_tag, + "name": equipment.master_equipment.name, + "matrix": rbd_simulation.get(equipment.location_tag) + + } for equipment in equipments ] + # Filter out items without matrix data (where rbd_simulation.get() returned None) + filtered_result = [item for item in base_result if item["matrix"] is not None] + + # Sort by availability (lowest to highest) and limit to 10 + availability_result = sorted( + filtered_result, + key=lambda x: x["matrix"]["availability"] + )[:10] + + # Sort by criticality (highest to lowest) and limit to 10 + criticality_result = sorted( + filtered_result, + key=lambda x: x["matrix"]["criticality"], + reverse=True + )[:10] + + return { + "availability" : availability_result, + "criticality": criticality_result + } + + async def get_overhaul_schedules(*, db_session: DbSession): """Get all overhaul schedules.""" query = Select(OverhaulScope) @@ -76,7 +157,7 @@ def get_overhaul_system_components(): "total_uptime": 17419.000000000062, }, "SCR": { - "availability": 0.9996577686516085, + "availability": 0.9196577686516085, "efficiency": 0.9996690612127086, "total_uptime": 17526.0, }, @@ -139,8 +220,22 @@ def get_overhaul_system_components(): "total_uptime": 17402.000000000062, }, } + availabilities = {schematic: item['availability'] for schematic, item in powerplant_reliability.items() } + + + percentages = calculate_contribution(availabilities) + + for schema, contribution in percentages.items(): + powerplant_reliability[schema]["critical_contribution"] = contribution['criticality_importance'] + + # Sort the powerplant_reliability dictionary by critical_contribution in descending order + sorted_powerplant_reliability = dict(sorted( + powerplant_reliability.items(), + key=lambda x: x[1]["critical_contribution"], + reverse=True # Set to True for high to low sorting + )) - return powerplant_reliability + return sorted_powerplant_reliability return { "HPT": { diff --git a/src/overhaul_scope/service.py b/src/overhaul_scope/service.py index b39a846..dd1291e 100644 --- a/src/overhaul_scope/service.py +++ b/src/overhaul_scope/service.py @@ -8,7 +8,7 @@ from src.database.core import DbSession from src.database.service import search_filter_sort_paginate from src.overhaul_activity.model import OverhaulActivity from src.utils import time_now -from src.standard_scope.model import StandardScope, EquipmentOHHistory +from src.standard_scope.model import MasterEquipment, StandardScope, EquipmentOHHistory from src.workscope_group.model import MasterActivity from src.workscope_group_maintenance_type.model import WorkscopeOHType from src.equipment_workscope_group.model import EquipmentWorkscopeGroup @@ -192,6 +192,7 @@ async def get_overview_overhaul(*, db_session: DbSession): .join(StandardScope.workscope_groups) .join(EquipmentWorkscopeGroup.workscope_group) .join(MasterActivity.oh_types) + .join(MasterEquipment, StandardScope.location_tag == MasterEquipment.location_tag) .filter(WorkscopeOHType.maintenance_type_id == selected_overhaul.maintenance_type_id) .filter( (StandardScope.is_alternating_oh == False) | diff --git a/src/standard_scope/service.py b/src/standard_scope/service.py index f2889ae..5456c1c 100644 --- a/src/standard_scope/service.py +++ b/src/standard_scope/service.py @@ -74,6 +74,7 @@ async def get_by_oh_session_id(*, db_session: DbSession, oh_session_id: UUID): .join(EquipmentWorkscopeGroup.workscope_group) .join(MasterActivity.oh_types) .join(WorkscopeOHType.oh_type) + .join(MasterEquipment, StandardScope.location_tag == MasterEquipment.location_tag) .filter(MaintenanceType.name == overhaul.maintenance_type.name).filter( (StandardScope.is_alternating_oh == False) | (StandardScope.oh_history == None) |