|
|
|
@ -334,7 +334,7 @@ class OptimumCostModelWithSpareparts:
|
|
|
|
|
|
|
|
|
|
|
|
async def calculate_cost_all_equipment_with_spareparts(self, db_session,collector_db_session ,equipments: List,
|
|
|
|
async def calculate_cost_all_equipment_with_spareparts(self, db_session,collector_db_session ,equipments: List,
|
|
|
|
calculation, preventive_cost: float,
|
|
|
|
calculation, preventive_cost: float,
|
|
|
|
simulation_id: str = "default") -> Dict:
|
|
|
|
simulation_id: str = "default"):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Calculate optimal overhaul timing for entire fleet considering sparepart constraints
|
|
|
|
Calculate optimal overhaul timing for entire fleet considering sparepart constraints
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
@ -373,7 +373,13 @@ class OptimumCostModelWithSpareparts:
|
|
|
|
|
|
|
|
|
|
|
|
plant_capacity_loss_money = [metrics['derated_mwh'] * COST_PER_MWH for metrics in plant_monthly_metrics.values()]
|
|
|
|
plant_capacity_loss_money = [metrics['derated_mwh'] * COST_PER_MWH for metrics in plant_monthly_metrics.values()]
|
|
|
|
cumulative_loss_money = np.cumsum(plant_capacity_loss_money)
|
|
|
|
cumulative_loss_money = np.cumsum(plant_capacity_loss_money)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
total_simulation_period = int((importance_results["plant_result"]['total_downtime'] + importance_results["plant_result"]['total_uptime'])/720)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loss_production_per_month = np.arange(0, total_simulation_period)
|
|
|
|
|
|
|
|
k = 5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loss_exp = (importance_results["plant_result"]['total_downtime'] * 660 * 500_000) * (np.exp(k * (loss_production_per_month / total_simulation_period)) - 1) / (np.exp(k) - 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for equipment in equipments:
|
|
|
|
for equipment in equipments:
|
|
|
|
@ -434,7 +440,7 @@ class OptimumCostModelWithSpareparts:
|
|
|
|
|
|
|
|
|
|
|
|
# Phase 3: Generate final results and database objects
|
|
|
|
# Phase 3: Generate final results and database objects
|
|
|
|
fleet_results = []
|
|
|
|
fleet_results = []
|
|
|
|
total_corrective_costs = np.zeros(max_interval) + cumulative_loss_money[0:max_interval]
|
|
|
|
total_corrective_costs = np.zeros(max_interval) + loss_exp[0:max_interval]
|
|
|
|
total_preventive_costs = np.zeros(max_interval)
|
|
|
|
total_preventive_costs = np.zeros(max_interval)
|
|
|
|
total_procurement_costs = np.zeros(max_interval)
|
|
|
|
total_procurement_costs = np.zeros(max_interval)
|
|
|
|
total_costs = np.zeros(max_interval)
|
|
|
|
total_costs = np.zeros(max_interval)
|
|
|
|
@ -507,7 +513,7 @@ class OptimumCostModelWithSpareparts:
|
|
|
|
f"(Procurement cost: ${cost_data['procurement_cost']:,.2f})")
|
|
|
|
f"(Procurement cost: ${cost_data['procurement_cost']:,.2f})")
|
|
|
|
|
|
|
|
|
|
|
|
# Calculate fleet optimal interval
|
|
|
|
# Calculate fleet optimal interval
|
|
|
|
fleet_optimal_index = np.argmin(total_costs)
|
|
|
|
fleet_optimal_index = np.argmin(total_corrective_costs + total_preventive_costs)
|
|
|
|
fleet_optimal_cost = total_costs[fleet_optimal_index]
|
|
|
|
fleet_optimal_cost = total_costs[fleet_optimal_index]
|
|
|
|
|
|
|
|
|
|
|
|
# Generate procurement optimization report
|
|
|
|
# Generate procurement optimization report
|
|
|
|
@ -528,26 +534,7 @@ class OptimumCostModelWithSpareparts:
|
|
|
|
self.logger.info(f" - Total procurement cost: ${total_fleet_procurement_cost:,.2f}")
|
|
|
|
self.logger.info(f" - Total procurement cost: ${total_fleet_procurement_cost:,.2f}")
|
|
|
|
self.logger.info(f" - Equipment with sparepart constraints: {len([r for r in individual_results.values() if not r['sparepart_available']])}")
|
|
|
|
self.logger.info(f" - Equipment with sparepart constraints: {len([r for r in individual_results.values() if not r['sparepart_available']])}")
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return fleet_optimal_index
|
|
|
|
'id': calculation.id,
|
|
|
|
|
|
|
|
'fleet_results': fleet_results,
|
|
|
|
|
|
|
|
'fleet_optimal_interval': fleet_optimal_index + 1,
|
|
|
|
|
|
|
|
'fleet_optimal_cost': fleet_optimal_cost,
|
|
|
|
|
|
|
|
'total_corrective_costs': total_corrective_costs.tolist(),
|
|
|
|
|
|
|
|
'total_preventive_costs': total_preventive_costs.tolist(),
|
|
|
|
|
|
|
|
'total_procurement_costs': total_procurement_costs.tolist(),
|
|
|
|
|
|
|
|
'individual_results': individual_results,
|
|
|
|
|
|
|
|
'optimized_plan': improved_plan,
|
|
|
|
|
|
|
|
'procurement_plan': procurement_plan,
|
|
|
|
|
|
|
|
'total_fleet_procurement_cost': total_fleet_procurement_cost,
|
|
|
|
|
|
|
|
'analysis_parameters': {
|
|
|
|
|
|
|
|
'planned_oh_months': self.planned_oh_months,
|
|
|
|
|
|
|
|
'analysis_window_months': self.time_window_months,
|
|
|
|
|
|
|
|
'last_oh_date': self.last_oh_date.isoformat(),
|
|
|
|
|
|
|
|
'next_oh_date': self.next_oh_date.isoformat(),
|
|
|
|
|
|
|
|
'sparepart_optimization_enabled': True
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _optimize_fleet_with_sparepart_constraints(self, individual_results: Dict, equipments: List,
|
|
|
|
def _optimize_fleet_with_sparepart_constraints(self, individual_results: Dict, equipments: List,
|
|
|
|
equipment_birnbaum: Dict, simulation_id: str) -> List[Tuple[str, int]]:
|
|
|
|
equipment_birnbaum: Dict, simulation_id: str) -> List[Tuple[str, int]]:
|
|
|
|
@ -713,27 +700,58 @@ async def run_simulation_with_spareparts(*, db_session, calculation, token: str,
|
|
|
|
base_url=RBD_SERVICE_API,
|
|
|
|
base_url=RBD_SERVICE_API,
|
|
|
|
sparepart_manager=sparepart_manager
|
|
|
|
sparepart_manager=sparepart_manager
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
simulation_ids = ["41a9b376-fe55-4cec-9234-db4951019b8a",
|
|
|
|
|
|
|
|
"ea3c8d32-fb1e-417c-914a-296ba08516a1",
|
|
|
|
|
|
|
|
"ed586b3d-c215-4b58-a6a8-7577f91e0b6b",
|
|
|
|
|
|
|
|
"97357934-8703-4ef5-90c8-858d3a5c5a35",
|
|
|
|
|
|
|
|
"f674918f-af74-4601-99a3-96f44bfdb4e4",
|
|
|
|
|
|
|
|
"a2a7fc3e-f638-4c88-830c-88232b45d2f5",
|
|
|
|
|
|
|
|
"18012150-9458-419a-9537-de8f096f2e36",
|
|
|
|
|
|
|
|
"835d5027-6abf-47d8-af04-f3428634d118",
|
|
|
|
|
|
|
|
"37c68489-23e2-4def-ae31-81dc79df7851",
|
|
|
|
|
|
|
|
"ce7a1d4f-c9c4-41c1-97ee-20911d354bba"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
# Run fleet optimization with sparepart management
|
|
|
|
optimum_collection = []
|
|
|
|
results = await optimum_oh_model.calculate_cost_all_equipment_with_spareparts(
|
|
|
|
|
|
|
|
db_session=db_session,
|
|
|
|
for sim_id in simulation_ids:
|
|
|
|
collector_db_session=collector_db_session,
|
|
|
|
# Run fleet optimization with sparepart management
|
|
|
|
equipments=equipments,
|
|
|
|
results = await optimum_oh_model.calculate_cost_all_equipment_with_spareparts(
|
|
|
|
calculation=calculation_data,
|
|
|
|
db_session=db_session,
|
|
|
|
preventive_cost=calculation_data.parameter.overhaul_cost,
|
|
|
|
collector_db_session=collector_db_session,
|
|
|
|
simulation_id=simulation_id
|
|
|
|
equipments=equipments,
|
|
|
|
)
|
|
|
|
calculation=calculation_data,
|
|
|
|
|
|
|
|
preventive_cost=calculation_data.parameter.overhaul_cost,
|
|
|
|
# Generate sparepart report
|
|
|
|
simulation_id=sim_id
|
|
|
|
# sparepart_report = optimum_oh_model.generate_sparepart_report(results)
|
|
|
|
)
|
|
|
|
# print(sparepart_report)
|
|
|
|
|
|
|
|
|
|
|
|
optimum_collection.append(results)
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
finally:
|
|
|
|
finally:
|
|
|
|
await optimum_oh_model._close_session()
|
|
|
|
await optimum_oh_model._close_session()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
np_optimum = np.array(optimum_collection)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stats = {
|
|
|
|
|
|
|
|
'min': float(np.min(np_optimum)),
|
|
|
|
|
|
|
|
'max': float(np.max(np_optimum)),
|
|
|
|
|
|
|
|
'mean': float(np.mean(np_optimum)),
|
|
|
|
|
|
|
|
'median': float(np.median(np_optimum)),
|
|
|
|
|
|
|
|
'std': float(np.std(np_optimum)),
|
|
|
|
|
|
|
|
'variance': float(np.var(np_optimum)),
|
|
|
|
|
|
|
|
'range': float(np.ptp(np_optimum)), # max - min
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
calculation_data.optimum_analysis = stats
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
"id": calculation_data.id,
|
|
|
|
|
|
|
|
"optimum": stats
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def create_param_and_data(
|
|
|
|
async def create_param_and_data(
|
|
|
|
@ -992,7 +1010,8 @@ async def get_calculation_result(db_session: DbSession, calculation_id: str, tok
|
|
|
|
"next_planned_overhaul": scope_overhaul.start_date.isoformat(),
|
|
|
|
"next_planned_overhaul": scope_overhaul.start_date.isoformat(),
|
|
|
|
"calculation_type": "sparepart_optimized" if fleet_statistics['equipment_with_sparepart_constraints'] > 0 else "standard",
|
|
|
|
"calculation_type": "sparepart_optimized" if fleet_statistics['equipment_with_sparepart_constraints'] > 0 else "standard",
|
|
|
|
"total_equipment_analyzed": len(all_equipment),
|
|
|
|
"total_equipment_analyzed": len(all_equipment),
|
|
|
|
"included_in_optimization": len(included_equipment)
|
|
|
|
"included_in_optimization": len(included_equipment),
|
|
|
|
|
|
|
|
"optimal_stat": scope_calculation.optimum_analysis
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|