Skip to content

odys.domain.entities.battery

Battery value object: capacity, power limits, charging/discharging efficiency, state-of-charge bounds, self-discharge, and degradation cost. Owned by BatteryStorage and ElectricVehicle.

See Battery in the User Guide.

Battery value object.

This module provides the Battery class: the physics of storing electrical energy, shared by assets that have a battery (battery storage, electric vehicles).

Battery

Bases: BaseModel

Physics of a battery: capacity, power limits, efficiencies, and state of charge limits.

A battery has no name and no identity of its own. It is a value object that an asset (BatteryStorage, ElectricVehicle) owns. Its state of charge at the start and end of an optimization belongs to that run, not to the battery, and is given as an initial or final condition of the EnergySystem.

Source code in src/odys/domain/entities/battery.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class Battery(BaseModel):
    """Physics of a battery: capacity, power limits, efficiencies, and state of charge limits.

    A battery has no name and no identity of its own. It is a value object that
    an asset (`BatteryStorage`, `ElectricVehicle`) owns. Its state of charge at
    the start and end of an optimization belongs to that run, not to the battery,
    and is given as an initial or final condition of the `EnergySystem`.
    """

    model_config = ConfigDict(frozen=True, extra="forbid")

    capacity: float = Field(
        strict=True,
        gt=0,
        description="Storage capacity in MWh.",
    )
    max_charge_power: float = Field(
        strict=True,
        gt=0,
        description="Maximum charging power in MW.",
    )
    max_discharge_power: float = Field(
        strict=True,
        ge=0,
        description="Maximum discharging power in MW. 0 = charge-only.",
    )
    efficiency_charging: float = Field(
        default=1,
        strict=True,
        gt=0,
        le=1,
        description="Charging efficiency (0-1).",
    )
    efficiency_discharging: float = Field(
        default=1,
        strict=True,
        gt=0,
        le=1,
        description="Discharging efficiency (0-1).",
    )
    soc_min: float = Field(
        default=0,
        strict=True,
        ge=0,
        le=1,
        description="Minimum state of charge as a fraction of capacity (0-1).",
    )
    soc_max: float = Field(
        default=1,
        strict=True,
        ge=0,
        le=1,
        description="Maximum state of charge as a fraction of capacity (0-1).",
    )
    degradation_cost: float = Field(
        default=0.0,
        strict=True,
        ge=0,
        description="Degradation cost, in currency per MWh cycled.",
    )
    self_discharge_rate: float = Field(
        default=0.0,
        strict=True,
        ge=0,
        le=1,
        description="Self-discharge rate (0-1) per hour.",
    )

    @model_validator(mode="after")
    def _validate_soc_min_less_than_max(self) -> Self:
        if self.soc_min >= self.soc_max:
            msg = f"soc_min ({self.soc_min}) must be < soc_max ({self.soc_max})."
            raise OdysValidationError(msg)
        return self