diff --git a/src/calculation_budget_constrains/service.py b/src/calculation_budget_constrains/service.py index 6f9a14c..85f0c97 100644 --- a/src/calculation_budget_constrains/service.py +++ b/src/calculation_budget_constrains/service.py @@ -1,13 +1,15 @@ +from collections import defaultdict import random from typing import Optional +from uuid import UUID from sqlalchemy import Delete, Select from src.auth.service import CurrentUser -from src.database.core import DbSession +from src.database.core import CollectorDbSession, DbSession # from src.scope_equipment.model import ScopeEquipment # from src.scope_equipment.service import get_by_scope_name -from src.overhaul_activity.service import get_all_by_session_id +from src.overhaul_activity.service import get_all_by_session_id, get_standard_scope_by_session_id # async def get_all_budget_constrains( # *, db_session: DbSession, session_id: str, cost_threshold: float = 100000000 @@ -19,11 +21,14 @@ _equipment_eaf_cache = {} import random async def get_all_budget_constrains( - *, db_session: DbSession, session_id: str, cost_threshold: float = 100000000 + *, db_session: DbSession, collector_db: CollectorDbSession, session_id: UUID, cost_threshold: float = 100000000, plant_result=None, eq_results=None, plot_result=None ): """Get all overhaul overview with EAF values that sum to 100%.""" - equipments = await get_all_by_session_id(db_session=db_session, overhaul_session_id=session_id) - + equipments = await get_standard_scope_by_session_id( + db_session=db_session, + overhaul_session_id=session_id, + collector_db=collector_db + ) # If no equipments found, return empty list if not equipments: return [], [] @@ -34,29 +39,11 @@ async def get_all_budget_constrains( # Generate EAF values for new equipment IDs equipment_ids = [equipment.id for equipment in equipments] - # Generate new random EAF values if they don't exist - if not _equipment_eaf_cache or set(equipment_ids) != set(_equipment_eaf_cache.keys()): - total_eaf = 100.0 - remaining_items = len(equipment_ids) - - _equipment_eaf_cache.clear() - - # Ensure minimum EAF value for each equipment - min_eaf = 0.1 # Minimum 1% for each equipment - reserved_eaf = min_eaf * remaining_items - distributable_eaf = total_eaf - reserved_eaf - - for eq_id in equipment_ids[:-1]: # All except last item - if remaining_items > 1: - # Generate a random value between min_eaf and the remaining distributable EAF - max_allowed = distributable_eaf / (remaining_items - 1) - eaf = round(min_eaf + random.uniform(0, max_allowed), 2) - _equipment_eaf_cache[eq_id] = eaf - distributable_eaf -= (eaf - min_eaf) - remaining_items -= 1 - - # Assign remaining EAF to last item, ensuring it's at least min_eaf - _equipment_eaf_cache[equipment_ids[-1]] = round(distributable_eaf + min_eaf, 2) + equipments_eaf_contribution = calculate_asset_eaf_contributions( + plant_result=plant_result, + eq_results=eq_results, + plot_result=plot_result + ) # Create result array of dictionaries result = [ @@ -65,8 +52,8 @@ async def get_all_budget_constrains( "assetnum": equipment.assetnum, "location_tag": equipment.equipment.location_tag, "name": equipment.equipment.name, - "total_cost": equipment.material_cost + equipment.service_cost, - "eaf_contribution": _equipment_eaf_cache[equipment.id] + "total_cost": equipment.overhaul_cost + equipment.service_cost, + "eaf_contribution": equipments_eaf_contribution.get(equipment.location_tag, 0) } for equipment in equipments ] @@ -93,3 +80,36 @@ async def get_all_budget_constrains( return included_results, consequence_results # + + +def calculate_asset_eaf_contributions(plant_result, eq_results, plot_result): + """ + Calculate each asset's negative contribution to plant EAF + Higher contribution = more impact on reducing plant EAF + """ + plant_production = plant_result.get('production', 0) + results = defaultdict(list) + + + for asset in eq_results: + # Weight based on production capacity + capacity_weight = asset.get('production', 0) / plant_production if plant_productions > 0 else 0 + plot_data = next((item for item in plot_result if item['aeros_node']['node_name'] == asset['aeros_node']['node_name']), None) + + # Get asset EAF and downtime + asset_eaf = asset.get('eaf', 0) + asset_derating_pct = 100 - asset_eaf + + # Calculate this asset's contribution to plant EAF reduction + # This is how much this asset alone reduces the overall plant EAF + eaf_contribution = asset_derating_pct * capacity_weight + + # Calculate actual downtime hours (if simulation hours available) + sim_duration = plant_result.get('sim_duration', 8760) # Default to 1 year + downtime_hours = (asset_derating_pct / 100) * sim_duration + + results[asset['aeros_node']['node_name']] = eaf_contribution + + # Sort by contribution (worst contributors first) + results = sorted(results.items(), key=lambda x: x[1], reverse=True) + return results \ No newline at end of file diff --git a/src/calculation_target_reliability/router.py b/src/calculation_target_reliability/router.py index ba5822a..7643232 100644 --- a/src/calculation_target_reliability/router.py +++ b/src/calculation_target_reliability/router.py @@ -52,13 +52,13 @@ async def get_target_reliability( # oh_duration=duration # ) - simulation_id = await run_rbd_simulation( - sim_hours=duration, - token=token - ) + # simulation_id = await run_rbd_simulation( + # sim_hours=duration, + # token=token + # ) results = await get_simulation_results( - simulation_id=simulation_id["data"], + simulation_id="993c7b01-b2ab-4cc4-8b95-fc8e489e02aa", token=token ) diff --git a/src/overhaul_activity/service.py b/src/overhaul_activity/service.py index cf1c214..5e47d71 100644 --- a/src/overhaul_activity/service.py +++ b/src/overhaul_activity/service.py @@ -144,18 +144,30 @@ async def get_standard_scope_by_session_id(*, db_session: DbSession, overhaul_se prev_oh_scope = await get_prev_oh(db_session=db_session, overhaul_session=overhaul) query = ( - Select(StandardScope) - .outerjoin(StandardScope.oh_history) # Use outerjoin to handle None values - .join(StandardScope.workscope_groups) - .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) | - (StandardScope.oh_history.has(EquipmentOHHistory.last_oh_type != overhaul.maintenance_type.name)) - ).distinct() + Select(StandardScope) + .outerjoin( + StandardScope.oh_history + ) # Use outerjoin to handle None values + .join(StandardScope.workscope_groups) + .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 is None) + | ( + StandardScope.oh_history.has( + EquipmentOHHistory.last_oh_type + != overhaul.maintenance_type.name + ) + ) + ) + .distinct() ) data = await db_session.execute(query)