|
|
|
|
@ -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
|