fix calculation

main
Cizz22 12 months ago
parent a8610b3a2d
commit 5995a42b5f

@ -10,11 +10,11 @@ from src.overhaul_scope.service import get_all
from .schema import CalculationTimeConstrainsParametersRead, CalculationTimeConstrainsParametersRetrive, CalculationTimeConstrainsParametersCreate, CalculationTimeConstrainsRead 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 .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 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): async def get_create_calculation_parameters(*, db_session: DbSession, calculation_id: str):
if calculation_id is not None: 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: if not calculation:
raise HTTPException( 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): async def create_calculation(*, db_session: DbSession, calculation_time_constrains_in: CalculationTimeConstrainsParametersCreate, created_by: str):
calculation_data = await create_param_and_data( calculation_data = await create_param_and_data(
db_session=db_session, calculation_param_in=calculation_time_constrains_in, created_by=created_by) 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 return results

@ -2,7 +2,7 @@
from enum import Enum from enum import Enum
from typing import List, Optional, Union 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 sqlalchemy.orm import relationship
from src.database.core import Base, DbSession from src.database.core import Base, DbSession
from src.models import DefaultMixin, IdentityMixin, TimeStampMixin, UUIDMixin from src.models import DefaultMixin, IdentityMixin, TimeStampMixin, UUIDMixin
@ -145,5 +145,6 @@ class CalculationEquipmentResult(Base, DefaultMixin):
service_cost = Column(Float, nullable=False) service_cost = Column(Float, nullable=False)
calculation_data_id = Column(UUID(as_uuid=True), ForeignKey('oh_tr_calculation_data.id'), nullable=True) calculation_data_id = Column(UUID(as_uuid=True), ForeignKey('oh_tr_calculation_data.id'), nullable=True)
optimum_day = Column(Integer, default=1) optimum_day = Column(Integer, default=1)
is_included = Column(Boolean, default=True)

@ -74,6 +74,7 @@ class EquipmentResult(CalculationTimeConstrainsBase):
class CalculationTimeConstrainsRead(CalculationTimeConstrainsBase): class CalculationTimeConstrainsRead(CalculationTimeConstrainsBase):
id: Union[UUID, str] id: Union[UUID, str]
reference: UUID reference: UUID
scope: str
results: List[CalculationResultsRead] results: List[CalculationResultsRead]
equipment_results: List[EquipmentResult] equipment_results: List[EquipmentResult]
optimum_oh: Any optimum_oh: Any

@ -2,6 +2,7 @@ from typing import List, Optional, Tuple
from uuid import UUID from uuid import UUID
import numpy as np import numpy as np
from sqlalchemy import and_, func, select from sqlalchemy import and_, func, select
from sqlalchemy.engine import result
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from src.database.core import DbSession from src.database.core import DbSession
from src.overhaul_activity.service import get_all_by_session_id 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 fastapi import HTTPException, status
from src.overhaul_scope.service import get_by_scope_name, get from src.overhaul_scope.service import get_by_scope_name, get
from src.scope_equipment.service import get_by_assetnum 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) exponents = np.arange(0, days)
results = overhaul_cost / (2 ** exponents) results = overhaul_cost / (2 ** exponents)
results = np.where(np.isfinite(results), results, 0) results = np.where(np.isfinite(results), results, 0)
return results return results
def get_corrective_cost_time_chart(material_cost: float, service_cost: float, days: int) -> Tuple[np.ndarray, np.ndarray]: 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) 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): 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) scope_calculation = await get_calculation_data_by_id(db_session=db_session, calculation_id=calculation_id)
if not scope_calculation: if not scope_calculation:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.", 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 # Check if calculation already exist
return CalculationTimeConstrainsRead( return CalculationTimeConstrainsRead(
id=scope_calculation.id, id=scope_calculation.id,
reference=scope_calculation.overhaul_session_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, optimum_oh=scope_calculation.optimum_oh_day,
equipment_results=scope_calculation.equipment_results equipment_results=scope_calculation.equipment_results
) )
async def get_calculation_data_by_id(db_session: DbSession, calculation_id) -> CalculationData: async def get_calculation_data_by_id(db_session: DbSession, calculation_id) -> CalculationData:
stmt = select(CalculationData).filter(CalculationData.id == stmt = select(CalculationData).filter(
calculation_id).options(joinedload(CalculationData.results), joinedload(CalculationData.equipment_results)) CalculationData.id == calculation_id
).options(
joinedload(CalculationData.equipment_results), joinedload(CalculationData.parameter)
)
result = await db_session.execute(stmt) result = await db_session.execute(stmt)
return result.unique().scalar() 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( async def create_calculation_result_service(
db_session: DbSession, db_session: DbSession,
calculation_id: UUID, calculation: CalculationData,
) -> CalculationTimeConstrainsRead: ) -> CalculationTimeConstrainsRead:
days = 365 # Changed to 365 days as per requirement 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 # 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) 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( overhaul_cost_points = get_overhaul_cost_by_time_chart(
calculation.parameter.overhaul_cost, calculation_data.parameter.overhaul_cost,
days=days days=days
) )
# Store results for each equipment # Store results for each equipment
equipment_results: List[CalculationEquipmentResult] = [] equipment_results: List[CalculationEquipmentResult] = []
@ -181,13 +237,6 @@ async def create_calculation_result_service(
equipment_optimum_index = np.argmin(equipment_total_cost) equipment_optimum_index = np.argmin(equipment_total_cost)
equipment_failure_sum = sum(daily_failures[:equipment_optimum_index]) 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( equipment_results.append(CalculationEquipmentResult(
corrective_costs=corrective_costs.tolist(), corrective_costs=corrective_costs.tolist(),
overhaul_costs=overhaul_cost_points.tolist(), overhaul_costs=overhaul_cost_points.tolist(),
@ -204,6 +253,7 @@ async def create_calculation_result_service(
total_daily_failures += daily_failures total_daily_failures += daily_failures
db_session.add_all(equipment_results) db_session.add_all(equipment_results)
# Calculate optimum points using total costs # Calculate optimum points using total costs
total_cost = total_corrective_costs + overhaul_cost_points total_cost = total_corrective_costs + overhaul_cost_points
@ -217,31 +267,30 @@ async def create_calculation_result_service(
days=int(optimum_oh_index + 1) days=int(optimum_oh_index + 1)
) )
# Create calculation results for database # # Create calculation results for database
calculation_results = [] # calculation_results = []
for i in range(days): # for i in range(days):
result = CalculationResult( # result = CalculationResult(
parameter_id=calculation.parameter_id, # parameter_id=calculation.parameter_id,
calculation_data_id=calculation.id, # calculation_data_id=calculation.id,
day=(i + 1), # day=(i + 1),
corrective_cost=float(total_corrective_costs[i]), # corrective_cost=float(total_corrective_costs[i]),
overhaul_cost=float(overhaul_cost_points[i]), # overhaul_cost=float(overhaul_cost_points[i]),
num_failures=int(total_daily_failures[i]), # num_failures=int(total_daily_failures[i]),
) # )
calculation_results.append(result) # calculation_results.append(result)
# Update calculation with optimum day # Update calculation with optimum day
calculation.optimum_oh_day = optimum.days calculation.optimum_oh_day = optimum.days
# Save to database
db_session.add_all(calculation_results)
await db_session.commit() await db_session.commit()
# Return results including individual equipment data # Return results including individual equipment data
return CalculationTimeConstrainsRead( return CalculationTimeConstrainsRead(
id=calculation.id, id=calculation.id,
reference=calculation.overhaul_session_id, reference=calculation.overhaul_session_id,
results=calculation_results, scope=scope.type,
results=[],
optimum_oh=optimum, optimum_oh=optimum,
equipment_results=equipment_results equipment_results=equipment_results
) )

Loading…
Cancel
Save