From 5995a42b5ffe9abe27ca449bb72046df9fe46805 Mon Sep 17 00:00:00 2001 From: Cizz22 Date: Mon, 20 Jan 2025 13:46:27 +0700 Subject: [PATCH] fix calculation --- src/calculation_time_constrains/flows.py | 9 +- src/calculation_time_constrains/model.py | 3 +- src/calculation_time_constrains/schema.py | 1 + src/calculation_time_constrains/service.py | 115 +++++++++++++++------ 4 files changed, 89 insertions(+), 39 deletions(-) diff --git a/src/calculation_time_constrains/flows.py b/src/calculation_time_constrains/flows.py index dfb01ca..debcffb 100644 --- a/src/calculation_time_constrains/flows.py +++ b/src/calculation_time_constrains/flows.py @@ -10,11 +10,11 @@ from src.overhaul_scope.service import get_all from .schema import CalculationTimeConstrainsParametersRead, CalculationTimeConstrainsParametersRetrive, CalculationTimeConstrainsParametersCreate, CalculationTimeConstrainsRead from .service import get_calculation_by_reference_and_parameter, get_calculation_result, get_overhaul_cost_by_time_chart, get_corrective_cost_time_chart, create_param_and_data, get_calculation_data_by_id, create_calculation_result_service, get_avg_cost_by_asset from src.scope_equipment.service import get_by_assetnum - +from fastapi import HTTPException, status async def get_create_calculation_parameters(*, db_session: DbSession, calculation_id: str): if calculation_id is not None: - calculation = get_calculation_data_by_id(calculation_id) + calculation = await get_calculation_data_by_id(calculation_id=calculation_id, db_session=db_session) if not calculation: raise HTTPException( @@ -63,10 +63,9 @@ async def get_create_calculation_parameters(*, db_session: DbSession, calculatio async def create_calculation(*, db_session: DbSession, calculation_time_constrains_in: CalculationTimeConstrainsParametersCreate, created_by: str): calculation_data = await create_param_and_data( db_session=db_session, calculation_param_in=calculation_time_constrains_in, created_by=created_by) + - results = await create_calculation_result_service(db_session=db_session, calculation_id=calculation_data.id) - - + results = await create_calculation_result_service(db_session=db_session, calculation=calculation_data) return results diff --git a/src/calculation_time_constrains/model.py b/src/calculation_time_constrains/model.py index fc4549f..7d12834 100644 --- a/src/calculation_time_constrains/model.py +++ b/src/calculation_time_constrains/model.py @@ -2,7 +2,7 @@ from enum import Enum from typing import List, Optional, Union -from sqlalchemy import UUID, Column, Float, ForeignKey, Integer, String, JSON, Numeric +from sqlalchemy import UUID, Column, Float, ForeignKey, Integer, String, JSON, Numeric, Boolean from sqlalchemy.orm import relationship from src.database.core import Base, DbSession from src.models import DefaultMixin, IdentityMixin, TimeStampMixin, UUIDMixin @@ -145,5 +145,6 @@ class CalculationEquipmentResult(Base, DefaultMixin): service_cost = Column(Float, nullable=False) calculation_data_id = Column(UUID(as_uuid=True), ForeignKey('oh_tr_calculation_data.id'), nullable=True) optimum_day = Column(Integer, default=1) + is_included = Column(Boolean, default=True) diff --git a/src/calculation_time_constrains/schema.py b/src/calculation_time_constrains/schema.py index 00c2e0b..b39f22f 100644 --- a/src/calculation_time_constrains/schema.py +++ b/src/calculation_time_constrains/schema.py @@ -74,6 +74,7 @@ class EquipmentResult(CalculationTimeConstrainsBase): class CalculationTimeConstrainsRead(CalculationTimeConstrainsBase): id: Union[UUID, str] reference: UUID + scope: str results: List[CalculationResultsRead] equipment_results: List[EquipmentResult] optimum_oh: Any diff --git a/src/calculation_time_constrains/service.py b/src/calculation_time_constrains/service.py index 58ad5bd..82456e9 100644 --- a/src/calculation_time_constrains/service.py +++ b/src/calculation_time_constrains/service.py @@ -2,6 +2,7 @@ from typing import List, Optional, Tuple from uuid import UUID import numpy as np from sqlalchemy import and_, func, select +from sqlalchemy.engine import result from sqlalchemy.orm import joinedload from src.database.core import DbSession from src.overhaul_activity.service import get_all_by_session_id @@ -12,15 +13,34 @@ from .model import CalculationParam, OverhaulReferenceType, CalculationData, Cal from fastapi import HTTPException, status from src.overhaul_scope.service import get_by_scope_name, get from src.scope_equipment.service import get_by_assetnum +from src.overhaul_scope.service import get as get_scope +from .schema import CalculationResultsRead -def get_overhaul_cost_by_time_chart(overhaul_cost: float, days: int) -> list: +def get_overhaul_cost_by_time_chart(overhaul_cost: float, days: int) -> np.ndarray: + """ + Calculate decreasing overhaul costs over time using exponential decay. + + Args: + overhaul_cost (float): Initial overhaul cost + days (int): Number of days to calculate cost for + + Returns: + np.ndarray: Array of daily costs with exponential decay + + Raises: + ValueError: If overhaul_cost is negative or days is not positive + """ + if overhaul_cost < 0: + raise ValueError("Overhaul cost cannot be negative") + if days <= 0: + raise ValueError("Days must be positive") + exponents = np.arange(0, days) results = overhaul_cost / (2 ** exponents) results = np.where(np.isfinite(results), results, 0) return results - def get_corrective_cost_time_chart(material_cost: float, service_cost: float, days: int) -> Tuple[np.ndarray, np.ndarray]: day_points = np.arange(0, days) @@ -63,28 +83,62 @@ async def create_param_and_data(*, db_session: DbSession, calculation_param_in: async def get_calculation_result(db_session: DbSession, calculation_id: str): + days=365 scope_calculation = await get_calculation_data_by_id(db_session=db_session, calculation_id=calculation_id) if not scope_calculation: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="A data with this id does not exist.", ) + + scope_overhaul = await get_scope(db_session=db_session, overhaul_session_id=scope_calculation.overhaul_session_id) + if not scope_overhaul: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="A data with this id does not exist.", + ) + + + calculation_results = [] + for i in range(days): + result = { + "overhaul_cost": 0, + "corrective_cost": 0, + "num_failures": 0, + "day": i + 1 + } + + for eq in scope_calculation.equipment_results: + if not eq.is_included: + continue + result["corrective_cost"] += float(eq.corrective_costs[i]) + result["overhaul_cost"] += float(eq.overhaul_costs[i]) + result["num_failures"] += int(eq.daily_failures[i]) + + + calculation_results.append(CalculationResultsRead(**result)) + # Check if calculation already exist return CalculationTimeConstrainsRead( id=scope_calculation.id, reference=scope_calculation.overhaul_session_id, - results=scope_calculation.results, + scope=scope_overhaul.type, + results=calculation_results, optimum_oh=scope_calculation.optimum_oh_day, equipment_results=scope_calculation.equipment_results ) async def get_calculation_data_by_id(db_session: DbSession, calculation_id) -> CalculationData: - stmt = select(CalculationData).filter(CalculationData.id == - calculation_id).options(joinedload(CalculationData.results), joinedload(CalculationData.equipment_results)) + stmt = select(CalculationData).filter( + CalculationData.id == calculation_id + ).options( + joinedload(CalculationData.equipment_results), joinedload(CalculationData.parameter) + ) + + result = await db_session.execute(stmt) - return result.unique().scalar() @@ -149,19 +203,21 @@ async def get_calculation_data_by_id(db_session: DbSession, calculation_id) -> C async def create_calculation_result_service( db_session: DbSession, - calculation_id: UUID, + calculation: CalculationData, ) -> CalculationTimeConstrainsRead: days = 365 # Changed to 365 days as per requirement - calculation = await get_calculation_data_by_id(db_session=db_session, calculation_id=calculation_id) # Get all equipment for this calculation session equipments = await get_all_by_session_id(db_session=db_session, overhaul_session_id=calculation.overhaul_session_id) + scope = await get_scope(db_session=db_session, overhaul_session_id=calculation.overhaul_session_id) - # Calculate overhaul costs once since it's shared + calculation_data = await get_calculation_data_by_id(db_session=db_session, calculation_id=calculation.id) + overhaul_cost_points = get_overhaul_cost_by_time_chart( - calculation.parameter.overhaul_cost, + calculation_data.parameter.overhaul_cost, days=days ) + # Store results for each equipment equipment_results: List[CalculationEquipmentResult] = [] @@ -181,13 +237,6 @@ async def create_calculation_result_service( equipment_optimum_index = np.argmin(equipment_total_cost) equipment_failure_sum = sum(daily_failures[:equipment_optimum_index]) - equipment_optimum = OptimumResult( - overhaul_cost=float(overhaul_cost_points[equipment_optimum_index]), - corrective_cost=float(corrective_costs[equipment_optimum_index]), - num_failures=int(equipment_failure_sum), - days=int(equipment_optimum_index + 1) - ) - equipment_results.append(CalculationEquipmentResult( corrective_costs=corrective_costs.tolist(), overhaul_costs=overhaul_cost_points.tolist(), @@ -204,6 +253,7 @@ async def create_calculation_result_service( total_daily_failures += daily_failures db_session.add_all(equipment_results) + # Calculate optimum points using total costs total_cost = total_corrective_costs + overhaul_cost_points @@ -217,31 +267,30 @@ async def create_calculation_result_service( days=int(optimum_oh_index + 1) ) - # Create calculation results for database - calculation_results = [] - for i in range(days): - result = CalculationResult( - parameter_id=calculation.parameter_id, - calculation_data_id=calculation.id, - day=(i + 1), - corrective_cost=float(total_corrective_costs[i]), - overhaul_cost=float(overhaul_cost_points[i]), - num_failures=int(total_daily_failures[i]), - ) - calculation_results.append(result) + # # Create calculation results for database + # calculation_results = [] + # for i in range(days): + # result = CalculationResult( + # parameter_id=calculation.parameter_id, + # calculation_data_id=calculation.id, + # day=(i + 1), + # corrective_cost=float(total_corrective_costs[i]), + # overhaul_cost=float(overhaul_cost_points[i]), + # num_failures=int(total_daily_failures[i]), + # ) + # calculation_results.append(result) # Update calculation with optimum day calculation.optimum_oh_day = optimum.days - - # Save to database - db_session.add_all(calculation_results) + await db_session.commit() # Return results including individual equipment data return CalculationTimeConstrainsRead( id=calculation.id, reference=calculation.overhaul_session_id, - results=calculation_results, + scope=scope.type, + results=[], optimum_oh=optimum, equipment_results=equipment_results )