diff --git a/libs/ManagerRegler.php b/libs/ManagerRegler.php index b7f3876..2e0f65a 100644 --- a/libs/ManagerRegler.php +++ b/libs/ManagerRegler.php @@ -155,22 +155,29 @@ final class ManagerRegler $verteilbudget = (int) round($aktuelleLeistung + $zielnetzleistung - $netzleistung); $sollwerte = []; - $minimumSumme = 0; + $ausgangssumme = 0; foreach ($steuerbar as $eintrag) { - $minimum = self::kleinsterLeistungswert($eintrag['Leistungswerte_W']); - $sollwerte[$eintrag['InstanzID']] = $minimum; - $minimumSumme += $minimum; + $ausgangswert = self::neutralerLeistungswert($eintrag['Leistungswerte_W']); + $sollwerte[$eintrag['InstanzID']] = $ausgangswert; + $ausgangssumme += $ausgangswert; } - $verfuegbar = max(0, $verteilbudget - $nichtSteuerbar - $minimumSumme); + $rest = $verteilbudget - $nichtSteuerbar - $ausgangssumme; foreach ($steuerbar as $eintrag) { $instanzID = $eintrag['InstanzID']; - $minimum = $sollwerte[$instanzID]; - $neuerSollwert = self::groessterLeistungswertBis( - $eintrag['Leistungswerte_W'], - $minimum + $verfuegbar - ); - $verfuegbar -= $neuerSollwert - $minimum; + $ausgangswert = $sollwerte[$instanzID]; + if ($rest >= 0) { + $neuerSollwert = self::groessterLeistungswertBis( + $eintrag['Leistungswerte_W'], + $ausgangswert + $rest + ); + } else { + $neuerSollwert = self::kleinsterLeistungswertAb( + $eintrag['Leistungswerte_W'], + $ausgangswert + $rest + ); + } + $rest -= $neuerSollwert - $ausgangswert; $sollwerte[$instanzID] = $neuerSollwert; } @@ -231,6 +238,43 @@ final class ManagerRegler } } + /** + * @param list $leistungswerte + */ + private static function neutralerLeistungswert(array $leistungswerte): int + { + $negativ = null; + $positiv = null; + foreach ($leistungswerte as $eintrag) { + if (is_int($eintrag)) { + if ($eintrag === 0) { + return 0; + } + $negativ = $eintrag < 0 ? max($negativ ?? $eintrag, $eintrag) : $negativ; + $positiv = $eintrag > 0 ? min($positiv ?? $eintrag, $eintrag) : $positiv; + continue; + } + if ($eintrag['Von_W'] <= 0 && $eintrag['Bis_W'] >= 0) { + return 0; + } + $negativ = $eintrag['Bis_W'] < 0 + ? max($negativ ?? $eintrag['Bis_W'], $eintrag['Bis_W']) + : $negativ; + $positiv = $eintrag['Von_W'] > 0 + ? min($positiv ?? $eintrag['Von_W'], $eintrag['Von_W']) + : $positiv; + } + + if ($negativ === null) { + return $positiv; + } + if ($positiv === null) { + return $negativ; + } + + return abs($negativ) <= abs($positiv) ? $negativ : $positiv; + } + /** * @param list $leistungswerte */ @@ -264,4 +308,26 @@ final class ManagerRegler return $gewaehlt; } + + /** + * @param list $leistungswerte + */ + private static function kleinsterLeistungswertAb(array $leistungswerte, int $untergrenze): int + { + foreach ($leistungswerte as $eintrag) { + if (is_int($eintrag)) { + if ($eintrag >= $untergrenze) { + return $eintrag; + } + continue; + } + if ($eintrag['Bis_W'] < $untergrenze) { + continue; + } + + return max($eintrag['Von_W'], $untergrenze); + } + + return self::neutralerLeistungswert($leistungswerte); + } } diff --git a/tests/ManagerReglerTest.php b/tests/ManagerReglerTest.php index 4587c5a..34e229f 100644 --- a/tests/ManagerReglerTest.php +++ b/tests/ManagerReglerTest.php @@ -192,6 +192,42 @@ final class ManagerReglerTest extends TestCase self::assertSame(0, $ergebnis['Restabweichung_W']); } + public function testBatterieGleichtFesteLastenAusOhneSolarladungZuSpeisen(): void + { + $ergebnis = ManagerRegler::verteile( + -4526.0, + -50.0, + [ + $this->verbraucher(29743, 1, [0, 6500], 6500), + $this->verbraucher(38676, 1, [0, 4600], 4600), + $this->verbraucher(22078, 2, [7690], 0, false), + $this->verbraucher(31986, 2, [11000], 10942, false), + $this->verbraucher(43878, 2, [0, 4150, 10300], 9908), + $this->verbraucher( + 44234, + 6, + [['Von_W' => -39000, 'Bis_W' => 39000]], + -22769 + ), + ], + 'PrioritaetPV' + ); + + self::assertSame(13657, $ergebnis['Verteilbudget_W']); + self::assertSame( + [ + 29743 => 0, + 38676 => 0, + 22078 => 7690, + 31986 => 11000, + 43878 => 0, + 44234 => -5033, + ], + $ergebnis['Sollwerte'] + ); + self::assertSame(0, $ergebnis['Restabweichung_W']); + } + public function testBegrenztesFahrzeugLaedtVorBatterieOhneBatterieentladung(): void { $ergebnis = ManagerRegler::verteile(