Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]: class_ems nd_array not JSON serializable #145

Merged
merged 3 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
47 changes: 14 additions & 33 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,29 +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",
"Netzbezug_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
19 changes: 13 additions & 6 deletions src/akkudoktoreosserver/flask_server.py
Original file line number Diff line number Diff line change
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,16 +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

return jsonify(result) # Return optimization results as JSON
# Perform optimization simulation
result = opt_class.optimierung_ems(
parameter=parameter, start_hour=datetime.now().hour
)
print(result)
# convert to JSON (None accepted by dumps)
return jsonify(result)


@app.route("/visualisierungsergebnisse.pdf")
Expand Down
22 changes: 15 additions & 7 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 @@ -278,16 +279,16 @@ def test_simulation(create_ems_instance):
), "The value at index 12 of 'Last_Wh_pro_Stunde' should be 1132.03."

# Verify that the value at index 0 is 'None'
assert (
result["Last_Wh_pro_Stunde"][0] is None
assert 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
assert 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
assert 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.")
Loading