[BUG]: class_ems nd_array not JSON serializable

Big Bugfix - not sure if everything works
This commit is contained in:
Andreas 2024-10-09 16:52:51 +02:00 committed by Andreas
parent e72008471f
commit 004e1f3dc7
6 changed files with 79 additions and 160 deletions

View File

@ -1,9 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from pprint import pprint import json
# Import necessary modules from the project # Import necessary modules from the project
from modules.class_optimize import optimization_problem from akkudoktoreos.class_optimize import optimization_problem
start_hour = 10 start_hour = 10
@ -216,107 +216,7 @@ gesamtlast = [
] ]
# Start Solution (binary) # Start Solution (binary)
start_solution = [ start_solution = None
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,
]
# Define parameters for the optimization problem # Define parameters for the optimization problem
parameter = { parameter = {
@ -341,7 +241,7 @@ parameter = {
# Electricity price forecast (48 hours) # Electricity price forecast (48 hours)
"strompreis_euro_pro_wh": strompreis_euro_pro_wh, "strompreis_euro_pro_wh": strompreis_euro_pro_wh,
# Minimum SOC for electric car # Minimum SOC for electric car
"eauto_min_soc": 1000, "eauto_min_soc": 80,
# Electric car battery capacity (Wh) # Electric car battery capacity (Wh)
"eauto_cap": 60000, "eauto_cap": 60000,
# Charging efficiency of the electric car # Charging efficiency of the electric car
@ -371,4 +271,7 @@ opt_class = optimization_problem(
ergebnis = opt_class.optimierung_ems(parameter=parameter, start_hour=start_hour) ergebnis = opt_class.optimierung_ems(parameter=parameter, start_hour=start_hour)
# Print or visualize the result # Print or visualize the result
pprint(ergebnis) # pprint(ergebnis)
json_data = json.dumps(ergebnis)
print(json_data)

View File

@ -58,15 +58,15 @@ class EnergieManagementSystem:
total_hours = ende - start_stunde total_hours = ende - start_stunde
# Pre-allocate arrays for the results, optimized for speed # Pre-allocate arrays for the results, optimized for speed
last_wh_pro_stunde = np.zeros(total_hours) last_wh_pro_stunde = np.full((total_hours), np.nan)
netzeinspeisung_wh_pro_stunde = np.zeros(total_hours) netzeinspeisung_wh_pro_stunde = np.full((total_hours), np.nan)
netzbezug_wh_pro_stunde = np.zeros(total_hours) netzbezug_wh_pro_stunde = np.full((total_hours), np.nan)
kosten_euro_pro_stunde = np.zeros(total_hours) kosten_euro_pro_stunde = np.full((total_hours), np.nan)
einnahmen_euro_pro_stunde = np.zeros(total_hours) einnahmen_euro_pro_stunde = np.full((total_hours), np.nan)
akku_soc_pro_stunde = np.zeros(total_hours) akku_soc_pro_stunde = np.full((total_hours), np.nan)
eauto_soc_pro_stunde = np.zeros(total_hours) eauto_soc_pro_stunde = np.full((total_hours), np.nan)
verluste_wh_pro_stunde = np.zeros(total_hours) verluste_wh_pro_stunde = np.full((total_hours), np.nan)
haushaltsgeraet_wh_pro_stunde = np.zeros(total_hours) haushaltsgeraet_wh_pro_stunde = np.full((total_hours), np.nan)
# Set initial state # Set initial state
akku_soc_pro_stunde[0] = self.akku.ladezustand_in_prozent() akku_soc_pro_stunde[0] = self.akku.ladezustand_in_prozent()
@ -78,7 +78,7 @@ class EnergieManagementSystem:
# Accumulate loads and PV generation # Accumulate loads and PV generation
verbrauch = self.gesamtlast[stunde] verbrauch = self.gesamtlast[stunde]
verluste_wh_pro_stunde[stunde_since_now] = 0.0
if self.haushaltsgeraet: if self.haushaltsgeraet:
ha_load = self.haushaltsgeraet.get_last_fuer_stunde(stunde) ha_load = self.haushaltsgeraet.get_last_fuer_stunde(stunde)
verbrauch += ha_load verbrauch += ha_load
@ -117,7 +117,7 @@ class EnergieManagementSystem:
akku_soc_pro_stunde[stunde_since_now] = self.akku.ladezustand_in_prozent() akku_soc_pro_stunde[stunde_since_now] = self.akku.ladezustand_in_prozent()
# Total cost and return # 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 einnahmen_euro_pro_stunde
) )
@ -131,35 +131,10 @@ class EnergieManagementSystem:
"Einnahmen_Euro_pro_Stunde": einnahmen_euro_pro_stunde, "Einnahmen_Euro_pro_Stunde": einnahmen_euro_pro_stunde,
"Gesamtbilanz_Euro": gesamtkosten_euro, "Gesamtbilanz_Euro": gesamtkosten_euro,
"E-Auto_SoC_pro_Stunde": eauto_soc_pro_stunde, "E-Auto_SoC_pro_Stunde": eauto_soc_pro_stunde,
"Gesamteinnahmen_Euro": np.sum(einnahmen_euro_pro_stunde), "Gesamteinnahmen_Euro": np.nansum(einnahmen_euro_pro_stunde),
"Gesamtkosten_Euro": np.sum(kosten_euro_pro_stunde), "Gesamtkosten_Euro": np.nansum(kosten_euro_pro_stunde),
"Verluste_Pro_Stunde": verluste_wh_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, "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 return out

View File

@ -16,7 +16,6 @@ class Haushaltsgeraet:
:param start_hour: The hour at which the device should start. :param start_hour: The hour at which the device should start.
""" """
self.reset() self.reset()
# Check if the duration of use is within the available time frame # Check if the duration of use is within the available time frame
if start_hour + self.dauer_h > self.hours: if start_hour + self.dauer_h > self.hours:
raise ValueError("The duration of use exceeds the available time frame.") raise ValueError("The duration of use exceeds the available time frame.")

View File

@ -15,7 +15,7 @@ from akkudoktoreos.visualize import visualisiere_ergebnisse
class optimization_problem: class optimization_problem:
def __init__( def __init__(
self, self,
prediction_hours: int = 24, prediction_hours: int = 48,
strafe: float = 10, strafe: float = 10,
optimization_hours: int = 24, optimization_hours: int = 24,
verbose: bool = False, verbose: bool = False,
@ -138,7 +138,7 @@ class optimization_problem:
""" """
try: try:
o = self.evaluate_inner(individual, ems, start_hour) 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 return (100000.0,) # Return a high penalty in case of an exception
gesamtbilanz = o["Gesamtbilanz_Euro"] * (-1.0 if worst_case else 1.0) gesamtbilanz = o["Gesamtbilanz_Euro"] * (-1.0 if worst_case else 1.0)
@ -326,6 +326,35 @@ class optimization_problem:
extra_data=extra_data, 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 final results as a dictionary
return { return {
"discharge_hours_bin": discharge_hours_bin, "discharge_hours_bin": discharge_hours_bin,

View File

@ -3,14 +3,14 @@
import os import os
from datetime import datetime from datetime import datetime
from typing import Any, TypeGuard from typing import Any, TypeGuard
import json
import matplotlib import matplotlib
# Sets the Matplotlib backend to 'Agg' for rendering plots in environments without a display # Sets the Matplotlib backend to 'Agg' for rendering plots in environments without a display
matplotlib.use("Agg") matplotlib.use("Agg")
import pandas as pd 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 import LoadForecast
from akkudoktoreos.class_load_container import Gesamtlast from akkudoktoreos.class_load_container import Gesamtlast
@ -211,6 +211,12 @@ def flask_pvprognose():
@app.route("/optimize", methods=["POST"]) @app.route("/optimize", methods=["POST"])
def flask_optimize(): 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": if request.method == "POST":
from datetime import datetime from datetime import datetime
@ -243,18 +249,17 @@ def flask_optimize():
{"error": f"Missing parameter: {', '.join(missing_params)}"} {"error": f"Missing parameter: {', '.join(missing_params)}"}
), 400 # Return error for missing parameters ), 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 # Optional min SoC PV Battery
if "min_soc_prozent" not in parameter: if "min_soc_prozent" not in parameter:
parameter["min_soc_prozent"] = None 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) # convert to JSON (None accepted by dumps)
json_data = json.dumps(result) return jsonify(result)
return Response(json_data, mimetype='application/json')
@app.route("/visualisierungsergebnisse.pdf") @app.route("/visualisierungsergebnisse.pdf")

View File

@ -1,3 +1,4 @@
import numpy as np
import pytest import pytest
from akkudoktoreos.class_akku import PVAkku from akkudoktoreos.class_akku import PVAkku
@ -279,15 +280,15 @@ def test_simulation(create_ems_instance):
# Verify that the value at index 0 is 'None' # Verify that the value at index 0 is 'None'
assert ( 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." ), "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 # Check that 'Netzeinspeisung_Wh_pro_Stunde' and 'Netzbezug_Wh_pro_Stunde' are consistent
assert ( 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." ), "The value at index 0 of 'Netzeinspeisung_Wh_pro_Stunde' should be None."
assert ( 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." ), "The value at index 0 of 'Netzbezug_Wh_pro_Stunde' should be None."
assert ( assert (
result["Netzbezug_Wh_pro_Stunde"][1] == 21679.13 result["Netzbezug_Wh_pro_Stunde"][1] == 21679.13
@ -325,7 +326,14 @@ def test_simulation(create_ems_instance):
), "The sum of 'ems.haushaltsgeraet.get_lastkurve()' should be 2000." ), "The sum of 'ems.haushaltsgeraet.get_lastkurve()' should be 2000."
assert ( 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." ), "The sum of 'Haushaltsgeraet_wh_pro_stunde' should be 2000."
print("All tests passed successfully.") print("All tests passed successfully.")