Source code for suboptimumg.sweep.pack_optimizer_models

from pyexpat import model
from typing import List, Optional, Tuple

import numpy.typing as npt
import pandas as pd
from attr import field
from pydantic import (
    BaseModel,
    ConfigDict,
    Field,
    field_validator,
    model_validator,
)

from ..compsim.models import CompetitionResults
from .models import SweepParamConfig


[docs] class PackOptimizerConfig(BaseModel): """Configuration for the pack optimizer.""" model_config = ConfigDict(frozen=True, extra="forbid") # Parameters to optimize (if None, defaults are chosen based on mode) parameters: List[SweepParamConfig] = Field( description="Explicit list of parameters to optimize", ) max_iterations: int = Field( default=100, description="Maximum number of DE generations", gt=0 ) population_size: int = Field( default=15, description="DE population size multiplier", gt=0 ) seed: Optional[int] = Field( default=42, description="Random seed for reproducibility" ) capacity_margin: float = Field( default=0.1, description="Safety margin subtracted from battery capacity (kWh)", ge=0, )
[docs] class FixedPackConfig(PackOptimizerConfig): """Configuration for fixed-mass optimization mode.""" model_config = ConfigDict(frozen=True, extra="forbid") capacity: float = Field( description="Fixed battery capacity (kWh) when fixed_pack_mode=True", ) @field_validator("parameters") @classmethod def _validate_parameters( cls, parameters: List[SweepParamConfig] ) -> List[SweepParamConfig]: for param in parameters: if "accum" in param.name: raise ValueError( f"Invalid parameter '{param.name}' in fixed pack mode. " "Only driving parameters can be optimized when capacity is fixed." ) return parameters
[docs] class EvaluationRecord(BaseModel): """Record of a single objective function evaluation.""" model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True) param_names: List[str] = Field(description="Names of the modified parameters") params: npt.NDArray = Field(description="List of modified parameters") mass: float = Field(description="Vehicle mass at this evaluation (kg)") capacity: float = Field(description="Battery capacity at this evaluation (kWh)") score: float = Field( description="Penalized score used by optimizer (points - penalty)" ) feasible: bool = Field( description="Whether the solution is feasible (i.e., consumed energy < capacity)" ) competition_results: Optional[CompetitionResults] = Field( default=None, description="Competition Results", )
[docs] @model_validator(mode="after") def check_consistency(self): if len(self.params) != len(self.param_names): raise ValueError( "Length of params and param_names must be the same. " f"Got {len(self.params)} params and {len(self.param_names)} names." ) return self
[docs] class PackOptimizationData(BaseModel): """Output of a single pack optimization run.""" model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True) optimal_evaluation: Optional[EvaluationRecord] = Field( default=None, description="Best evaluation record by penalized score", ) evaluation_history: List[EvaluationRecord] = Field( description="History of all evaluations during the optimization" )