Skip to content

Commit

Permalink
[BUG]: class_ems nd_array not JSON serializable
Browse files Browse the repository at this point in the history
Big Bugfix - not sure if everything works
  • Loading branch information
drbacke committed Oct 9, 2024
1 parent ce99db7 commit 25f7c5a
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 160 deletions.
113 changes: 8 additions & 105 deletions single_test_optimization.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env python3

from pprint import pprint
import json

# Import necessary modules from the project
from modules.class_optimize import optimization_problem
from akkudoktoreos.class_optimize import optimization_problem

start_hour = 10

Expand Down Expand Up @@ -216,107 +216,7 @@
]

# Start Solution (binary)
start_solution = [
1,
1,
1,
1,
0,
1,
0,
0,
1,
1,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
]
start_solution = None

# Define parameters for the optimization problem
parameter = {
Expand All @@ -341,7 +241,7 @@
# Electricity price forecast (48 hours)
"strompreis_euro_pro_wh": strompreis_euro_pro_wh,
# Minimum SOC for electric car
"eauto_min_soc": 1000,
"eauto_min_soc": 80,
# Electric car battery capacity (Wh)
"eauto_cap": 60000,
# Charging efficiency of the electric car
Expand Down Expand Up @@ -371,4 +271,7 @@
ergebnis = opt_class.optimierung_ems(parameter=parameter, start_hour=start_hour)

# Print or visualize the result
pprint(ergebnis)
# pprint(ergebnis)

json_data = json.dumps(ergebnis)
print(json_data)
53 changes: 14 additions & 39 deletions src/akkudoktoreos/class_ems.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ def simuliere(self, start_stunde: int) -> dict:
total_hours = ende - start_stunde

# Pre-allocate arrays for the results, optimized for speed
last_wh_pro_stunde = np.zeros(total_hours)
netzeinspeisung_wh_pro_stunde = np.zeros(total_hours)
netzbezug_wh_pro_stunde = np.zeros(total_hours)
kosten_euro_pro_stunde = np.zeros(total_hours)
einnahmen_euro_pro_stunde = np.zeros(total_hours)
akku_soc_pro_stunde = np.zeros(total_hours)
eauto_soc_pro_stunde = np.zeros(total_hours)
verluste_wh_pro_stunde = np.zeros(total_hours)
haushaltsgeraet_wh_pro_stunde = np.zeros(total_hours)
last_wh_pro_stunde = np.full((total_hours), np.nan)
netzeinspeisung_wh_pro_stunde = np.full((total_hours), np.nan)
netzbezug_wh_pro_stunde = np.full((total_hours), np.nan)
kosten_euro_pro_stunde = np.full((total_hours), np.nan)
einnahmen_euro_pro_stunde = np.full((total_hours), np.nan)
akku_soc_pro_stunde = np.full((total_hours), np.nan)
eauto_soc_pro_stunde = np.full((total_hours), np.nan)
verluste_wh_pro_stunde = np.full((total_hours), np.nan)
haushaltsgeraet_wh_pro_stunde = np.full((total_hours), np.nan)

# Set initial state
akku_soc_pro_stunde[0] = self.akku.ladezustand_in_prozent()
Expand All @@ -78,7 +78,7 @@ def simuliere(self, start_stunde: int) -> dict:

# Accumulate loads and PV generation
verbrauch = self.gesamtlast[stunde]

verluste_wh_pro_stunde[stunde_since_now] = 0.0
if self.haushaltsgeraet:
ha_load = self.haushaltsgeraet.get_last_fuer_stunde(stunde)
verbrauch += ha_load
Expand Down Expand Up @@ -117,7 +117,7 @@ def simuliere(self, start_stunde: int) -> dict:
akku_soc_pro_stunde[stunde_since_now] = self.akku.ladezustand_in_prozent()

# Total cost and return
gesamtkosten_euro = np.sum(kosten_euro_pro_stunde) - np.sum(
gesamtkosten_euro = np.nansum(kosten_euro_pro_stunde) - np.nansum(
einnahmen_euro_pro_stunde
)

Expand All @@ -131,35 +131,10 @@ def simuliere(self, start_stunde: int) -> dict:
"Einnahmen_Euro_pro_Stunde": einnahmen_euro_pro_stunde,
"Gesamtbilanz_Euro": gesamtkosten_euro,
"E-Auto_SoC_pro_Stunde": eauto_soc_pro_stunde,
"Gesamteinnahmen_Euro": np.sum(einnahmen_euro_pro_stunde),
"Gesamtkosten_Euro": np.sum(kosten_euro_pro_stunde),
"Gesamteinnahmen_Euro": np.nansum(einnahmen_euro_pro_stunde),
"Gesamtkosten_Euro": np.nansum(kosten_euro_pro_stunde),
"Verluste_Pro_Stunde": verluste_wh_pro_stunde,
"Gesamt_Verluste": np.sum(verluste_wh_pro_stunde),
"Gesamt_Verluste": np.nansum(verluste_wh_pro_stunde),
"Haushaltsgeraet_wh_pro_stunde": haushaltsgeraet_wh_pro_stunde,
}

# List output keys where the first element needs to be changed to None
keys_to_modify = [
"Last_Wh_pro_Stunde",
"Netzeinspeisung_Wh_pro_Stunde",
"akku_soc_pro_stunde",
"Netzbezug_Wh_pro_Stunde",
"Kosten_Euro_pro_Stunde",
"Einnahmen_Euro_pro_Stunde",
"E-Auto_SoC_pro_Stunde",
"Verluste_Pro_Stunde",
"Haushaltsgeraet_wh_pro_stunde"
]

# Loop through each key in the list
for key in keys_to_modify:
# Convert the NumPy array to a list
element_list = out[key].tolist()

# Change the first value to None
element_list[0] = None

# Assign the modified list back to the dictionary
out[key] = element_list

return out
1 change: 0 additions & 1 deletion src/akkudoktoreos/class_haushaltsgeraet.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ def set_startzeitpunkt(self, start_hour, global_start_hour=0):
:param start_hour: The hour at which the device should start.
"""
self.reset()

# Check if the duration of use is within the available time frame
if start_hour + self.dauer_h > self.hours:
raise ValueError("The duration of use exceeds the available time frame.")
Expand Down
33 changes: 31 additions & 2 deletions src/akkudoktoreos/class_optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class optimization_problem:
def __init__(
self,
prediction_hours: int = 24,
prediction_hours: int = 48,
strafe: float = 10,
optimization_hours: int = 24,
verbose: bool = False,
Expand Down Expand Up @@ -138,7 +138,7 @@ def evaluate(
"""
try:
o = self.evaluate_inner(individual, ems, start_hour)
except Exception:
except Exception as e:
return (100000.0,) # Return a high penalty in case of an exception

gesamtbilanz = o["Gesamtbilanz_Euro"] * (-1.0 if worst_case else 1.0)
Expand Down Expand Up @@ -326,6 +326,35 @@ def optimierung_ems(
extra_data=extra_data,
)

# List output keys where the first element needs to be changed to None
keys_to_modify = [
"Last_Wh_pro_Stunde",
"Netzeinspeisung_Wh_pro_Stunde",
"akku_soc_pro_stunde",
"Netzbezug_Wh_pro_Stunde",
"Kosten_Euro_pro_Stunde",
"Einnahmen_Euro_pro_Stunde",
"E-Auto_SoC_pro_Stunde",
"Verluste_Pro_Stunde",
"Haushaltsgeraet_wh_pro_stunde",
]

# Loop through each key in the list
for key in keys_to_modify:
# Convert the NumPy array to a list
element_list = o[key].tolist()

# Change the first value to None
element_list[0] = None
# Change the NaN to None (JSON)
element_list = [
None if isinstance(x, (int, float)) and np.isnan(x) else x
for x in element_list
]

# Assign the modified list back to the dictionary
o[key] = element_list

# Return final results as a dictionary
return {
"discharge_hours_bin": discharge_hours_bin,
Expand Down
23 changes: 14 additions & 9 deletions src/akkudoktoreosserver/flask_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import os
from datetime import datetime
from typing import Any, TypeGuard
import json

import matplotlib

# Sets the Matplotlib backend to 'Agg' for rendering plots in environments without a display
matplotlib.use("Agg")

import pandas as pd
from flask import Flask, jsonify, redirect, request, send_from_directory, url_for, Response
from flask import Flask, jsonify, redirect, request, send_from_directory, url_for

from akkudoktoreos.class_load import LoadForecast
from akkudoktoreos.class_load_container import Gesamtlast
Expand Down Expand Up @@ -211,6 +211,12 @@ def flask_pvprognose():

@app.route("/optimize", methods=["POST"])
def flask_optimize():
with open(
"C:\\Users\\drbac\\OneDrive\\Dokumente\\PythonPojects\\EOS\\debug_output.txt",
"a",
) as f:
f.write("Test\n")

if request.method == "POST":
from datetime import datetime

Expand Down Expand Up @@ -243,18 +249,17 @@ def flask_optimize():
{"error": f"Missing parameter: {', '.join(missing_params)}"}
), 400 # Return error for missing parameters

# Perform optimization simulation
result = opt_class.optimierung_ems(
parameter=parameter, start_hour=datetime.now().hour
)

# Optional min SoC PV Battery
if "min_soc_prozent" not in parameter:
parameter["min_soc_prozent"] = None

# Perform optimization simulation
result = opt_class.optimierung_ems(
parameter=parameter, start_hour=datetime.now().hour
)
print(result)
# convert to JSON (None accepted by dumps)
json_data = json.dumps(result)
return Response(json_data, mimetype='application/json')
return jsonify(result)


@app.route("/visualisierungsergebnisse.pdf")
Expand Down
16 changes: 12 additions & 4 deletions tests/test_class_ems.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import numpy as np
import pytest

from akkudoktoreos.class_akku import PVAkku
Expand Down Expand Up @@ -279,15 +280,15 @@ def test_simulation(create_ems_instance):

# Verify that the value at index 0 is 'None'
assert (
result["Last_Wh_pro_Stunde"][0] is None
np.isnan(result["Last_Wh_pro_Stunde"][0])
), "The value at index 0 of 'Last_Wh_pro_Stunde' should be None."

# Check that 'Netzeinspeisung_Wh_pro_Stunde' and 'Netzbezug_Wh_pro_Stunde' are consistent
assert (
result["Netzeinspeisung_Wh_pro_Stunde"][0] is None
np.isnan(result["Netzeinspeisung_Wh_pro_Stunde"][0])
), "The value at index 0 of 'Netzeinspeisung_Wh_pro_Stunde' should be None."
assert (
result["Netzbezug_Wh_pro_Stunde"][0] is None
np.isnan(result["Netzbezug_Wh_pro_Stunde"][0])
), "The value at index 0 of 'Netzbezug_Wh_pro_Stunde' should be None."
assert (
result["Netzbezug_Wh_pro_Stunde"][1] == 21679.13
Expand Down Expand Up @@ -325,7 +326,14 @@ def test_simulation(create_ems_instance):
), "The sum of 'ems.haushaltsgeraet.get_lastkurve()' should be 2000."

assert (
sum(result["Haushaltsgeraet_wh_pro_stunde"]) == 2000
np.nansum(
np.where(
np.equal(result["Haushaltsgeraet_wh_pro_stunde"], None),
np.nan,
np.array(result["Haushaltsgeraet_wh_pro_stunde"]),
)
)
== 2000
), "The sum of 'Haushaltsgeraet_wh_pro_stunde' should be 2000."

print("All tests passed successfully.")

0 comments on commit 25f7c5a

Please sign in to comment.