mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-09 07:56:40 +00:00
fix(optimization): clear disabled AC charge in the reported plan
With grid charging switched off (inverter.max_ac_charge_power_w = 0) the simulation zeroes the AC charge array before using it, but it did so by rebinding a local name. The solution is read back from the original array, so it still carried the optimizer's AC charge genes - genes the fitness never evaluated, because the simulation ignored them, and which are therefore arbitrary. The effect was visible as a slot with ac_charge = 0.8 where the battery SoC does not move. Harmless inside EOS, but a controller that follows the plan would grid-charge the battery at a time nobody planned or paid for. Zero the array in place so the reported plan matches what was simulated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -560,3 +560,62 @@ def test_battery_lcos_is_charged_once_on_delivered_energy(config_eos):
|
||||
assert result["Gesamtkosten_Euro"] == pytest.approx(0.06)
|
||||
assert result["Einnahmen_Euro_pro_Stunde"][0] == pytest.approx(0.08)
|
||||
assert result["Gesamtbilanz_Euro"] == pytest.approx(-0.02)
|
||||
|
||||
|
||||
def test_disabled_ac_charging_clears_the_reported_plan(config_eos):
|
||||
"""With AC charging off the reported plan must not keep charge commands.
|
||||
|
||||
The simulation ignores the AC charge genes when the inverter forbids grid
|
||||
charging. The solution is read back from the same array, so a controller
|
||||
acting on it would grid-charge the battery although no such charge was ever
|
||||
simulated or paid for.
|
||||
"""
|
||||
config_eos.merge_settings_from_dict(
|
||||
{"prediction": {"hours": 2}, "optimization": {"horizon_hours": 2}}
|
||||
)
|
||||
|
||||
battery = Battery(
|
||||
SolarPanelBatteryParameters(
|
||||
device_id="battery1",
|
||||
capacity_wh=10000,
|
||||
initial_soc_percentage=50,
|
||||
min_soc_percentage=0,
|
||||
charging_efficiency=1.0,
|
||||
discharging_efficiency=1.0,
|
||||
max_charge_power_w=5000,
|
||||
),
|
||||
prediction_hours=config_eos.prediction.hours,
|
||||
)
|
||||
inverter = Inverter(
|
||||
InverterParameters(
|
||||
device_id="inverter1",
|
||||
max_power_wh=5000.0,
|
||||
battery_id=battery.parameters.device_id,
|
||||
max_ac_charge_power_w=0, # Netzladen deaktiviert
|
||||
),
|
||||
battery=battery,
|
||||
)
|
||||
|
||||
simulation = GeneticSimulation()
|
||||
simulation.prepare(
|
||||
GeneticEnergyManagementParameters(
|
||||
pv_prognose_wh=[0.0, 0.0],
|
||||
strompreis_euro_pro_wh=[0.0003, 0.0003],
|
||||
einspeiseverguetung_euro_pro_wh=[0.0001, 0.0001],
|
||||
preis_euro_pro_wh_akku=0.0,
|
||||
gesamtlast=[0.0, 0.0],
|
||||
),
|
||||
optimization_hours=config_eos.optimization.horizon_hours,
|
||||
prediction_hours=config_eos.prediction.hours,
|
||||
inverter=inverter,
|
||||
)
|
||||
simulation.ac_charge_hours = np.array([0.8, 0.0])
|
||||
|
||||
soc_before = battery.current_soc_percentage()
|
||||
simulation.simulate(start_hour=0)
|
||||
|
||||
# Nothing was charged ...
|
||||
assert battery.current_soc_percentage() == pytest.approx(soc_before)
|
||||
# ... and the plan says so.
|
||||
assert simulation.ac_charge_hours is not None
|
||||
assert list(simulation.ac_charge_hours) == [0.0, 0.0]
|
||||
|
||||
Reference in New Issue
Block a user