diff --git a/modules/class_ems.py b/modules/class_ems.py index aac0020..3d5fd34 100644 --- a/modules/class_ems.py +++ b/modules/class_ems.py @@ -1,5 +1,17 @@ from datetime import datetime from pprint import pprint +import numpy as np + +def replace_nan_with_none(data): + if isinstance(data, dict): + return {key: replace_nan_with_none(value) for key, value in data.items()} + elif isinstance(data, list): + return [replace_nan_with_none(element) for element in data] + elif isinstance(data, float) and np.isnan(data): + return None + else: + return data + class EnergieManagementSystem: @@ -58,10 +70,29 @@ class EnergieManagementSystem: ende = min( len(lastkurve_wh),len(self.pv_prognose_wh), len(self.strompreis_euro_pro_wh)) + # Endzustände auf NaN setzen, damit diese übersprungen werden für die Stunde + last_wh_pro_stunde.append(np.nan) + netzeinspeisung_wh_pro_stunde.append(np.nan) + netzbezug_wh_pro_stunde.append(np.nan) + kosten_euro_pro_stunde.append(np.nan) + akku_soc_pro_stunde.append(self.akku.ladezustand_in_prozent()) + einnahmen_euro_pro_stunde.append(np.nan) + eauto_soc_pro_stunde.append(self.eauto.ladezustand_in_prozent()) + verluste_wh_pro_stunde.append(np.nan) + haushaltsgeraet_wh_pro_stunde.append(np.nan) + # Berechnet das Ende basierend auf der Länge der Lastkurve - for stunde in range(start_stunde, ende): + for stunde in range(start_stunde+1, ende): + + # Zustand zu Beginn der Stunde (Anfangszustand) + akku_soc_start = self.akku.ladezustand_in_prozent() # Anfangszustand Akku-SoC + if self.eauto: + eauto_soc_start = self.eauto.ladezustand_in_prozent() # Anfangszustand E-Auto-SoC + + + # Anpassung, um sicherzustellen, dass Indizes korrekt sind - verbrauch = lastkurve_wh[stunde] + verbrauch = lastkurve_wh[stunde] # Verbrauch für die Stunde if self.haushaltsgeraet != None: verbrauch = verbrauch + self.haushaltsgeraet.get_last_fuer_stunde(stunde) haushaltsgeraet_wh_pro_stunde.append(self.haushaltsgeraet.get_last_fuer_stunde(stunde)) @@ -69,8 +100,8 @@ class EnergieManagementSystem: haushaltsgeraet_wh_pro_stunde.append(0) erzeugung = self.pv_prognose_wh[stunde] strompreis = self.strompreis_euro_pro_wh[stunde] if stunde < len(self.strompreis_euro_pro_wh) else self.strompreis_euro_pro_wh[-1] - verluste_wh_pro_stunde.append(0.0) + verluste_wh_pro_stunde.append(0.0) # Logik für die E-Auto-Ladung bzw. Entladung if self.eauto: # Falls ein E-Auto vorhanden ist @@ -108,7 +139,7 @@ class EnergieManagementSystem: einnahmen_euro_pro_stunde.append(stündliche_einnahmen_euro) - gesamtkosten_euro = sum(kosten_euro_pro_stunde) - sum(einnahmen_euro_pro_stunde) + gesamtkosten_euro = np.nansum(kosten_euro_pro_stunde) - np.nansum(einnahmen_euro_pro_stunde) expected_length = ende - start_stunde array_names = ['Eigenverbrauch_Wh_pro_Stunde', 'Netzeinspeisung_Wh_pro_Stunde', 'Netzbezug_Wh_pro_Stunde', 'Kosten_Euro_pro_Stunde', 'akku_soc_pro_stunde', 'Einnahmen_Euro_pro_Stunde','E-Auto_SoC_pro_Stunde', "Verluste_Pro_Stunde"] all_arrays = [last_wh_pro_stunde, netzeinspeisung_wh_pro_stunde, netzbezug_wh_pro_stunde, kosten_euro_pro_stunde, akku_soc_pro_stunde, einnahmen_euro_pro_stunde,eauto_soc_pro_stunde,verluste_wh_pro_stunde] @@ -128,11 +159,13 @@ class EnergieManagementSystem: 'Einnahmen_Euro_pro_Stunde': einnahmen_euro_pro_stunde, 'Gesamtbilanz_Euro': gesamtkosten_euro, 'E-Auto_SoC_pro_Stunde':eauto_soc_pro_stunde, - 'Gesamteinnahmen_Euro': sum(einnahmen_euro_pro_stunde), - 'Gesamtkosten_Euro': 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":sum(verluste_wh_pro_stunde), + "Gesamt_Verluste":np.nansum(verluste_wh_pro_stunde), "Haushaltsgeraet_wh_pro_stunde":haushaltsgeraet_wh_pro_stunde } + out = replace_nan_with_none(out) + return out diff --git a/modules/class_optimize.py b/modules/class_optimize.py index 893fb54..7a51448 100644 --- a/modules/class_optimize.py +++ b/modules/class_optimize.py @@ -154,8 +154,16 @@ class optimization_problem: final_soc = ems.eauto.ladezustand_in_prozent() # Nimmt den SoC am Ende des Optimierungszeitraums - eauto_roi = max(0,(parameter['eauto_min_soc']-ems.eauto.ladezustand_in_prozent()) ) + + if (parameter['eauto_min_soc']-ems.eauto.ladezustand_in_prozent()) <= 0.0: + #print (parameter['eauto_min_soc']," " ,ems.eauto.ladezustand_in_prozent()," ",(parameter['eauto_min_soc']-ems.eauto.ladezustand_in_prozent())) + for i in range(0, self.prediction_hours): + if eautocharge_hours_float[i] != 0.0: # Wenn die letzten x Stunden von einem festen Wert abweichen + gesamtbilanz += self.strafe # Bestrafe den Optimierer + + + eauto_roi = (parameter['eauto_min_soc']-ems.eauto.ladezustand_in_prozent()) individual.extra_data = (o["Gesamtbilanz_Euro"],o["Gesamt_Verluste"], eauto_roi ) @@ -191,7 +199,7 @@ class optimization_problem: if start_solution is not None and start_solution != -1: population.insert(0, creator.Individual(start_solution)) - algorithms.eaMuPlusLambda(population, self.toolbox, 100, 200, cxpb=0.2, mutpb=0.2, ngen=1000, stats=stats, halloffame=hof, verbose=True) + algorithms.eaMuPlusLambda(population, self.toolbox, mu=200, lambda_=300, cxpb=0.3, mutpb=0.4, ngen=500, stats=stats, halloffame=hof, verbose=True) #algorithms.eaSimple(population, self.toolbox, cxpb=0.2, mutpb=0.2, ngen=1000, stats=stats, halloffame=hof, verbose=True) member = {"bilanz":[],"verluste":[],"nebenbedingung":[]} diff --git a/modules/visualize.py b/modules/visualize.py index 0dbebfd..d4ab670 100644 --- a/modules/visualize.py +++ b/modules/visualize.py @@ -113,7 +113,8 @@ def visualisiere_ergebnisse(gesamtlast, pv_forecast, strompreise, ergebnisse, d plt.subplot(3, 2, 2) plt.plot(stunden, ergebnisse['akku_soc_pro_stunde'], label='PV Akku (%)', marker='x') plt.plot(stunden, ergebnisse['E-Auto_SoC_pro_Stunde'], label='E-Auto Akku (%)', marker='x') - plt.legend(loc='upper left') + plt.legend(loc='upper left', bbox_to_anchor=(1, 1)) # Legende außerhalb des Plots platzieren + plt.grid(True, which='both', axis='x') # Grid für jede Stunde ax1 = plt.subplot(3, 2, 3) for hour, value in enumerate(discharge_hours): diff --git a/test.py b/test.py index 753a8f8..b6cb077 100644 --- a/test.py +++ b/test.py @@ -23,7 +23,7 @@ import os -start_hour = 11 +start_hour = 13 pv_forecast= [ 0, @@ -325,262 +325,11 @@ start_solution= [ 1, 1 ] -parameter= {"preis_euro_pro_wh_akku": 30e-05,'pv_soc': 60.4052, 'pv_akku_cap': 30000, 'year_energy': 4100000, 'einspeiseverguetung_euro_pro_wh': 7e-05, 'max_heizleistung': 1000,"gesamtlast":gesamtlast, 'pv_forecast': pv_forecast, "temperature_forecast":temperature_forecast, "strompreis_euro_pro_wh":strompreis_euro_pro_wh, 'eauto_min_soc': 80, 'eauto_cap': 60000, 'eauto_charge_efficiency': 0.95, 'eauto_charge_power': 7590, 'eauto_soc': 53, 'pvpowernow': 211.137503624, 'start_solution': start_solution, 'haushaltsgeraet_wh': 937, 'haushaltsgeraet_dauer': 0} +parameter= {"preis_euro_pro_wh_akku": 30e-05,'pv_soc': 95.00, 'pv_akku_cap': 30000, 'year_energy': 4100000, 'einspeiseverguetung_euro_pro_wh': 7e-05, 'max_heizleistung': 1000,"gesamtlast":gesamtlast, 'pv_forecast': pv_forecast, "temperature_forecast":temperature_forecast, "strompreis_euro_pro_wh":strompreis_euro_pro_wh, 'eauto_min_soc': 0, 'eauto_cap': 60000, 'eauto_charge_efficiency': 0.95, 'eauto_charge_power': 7590, 'eauto_soc': 53, 'pvpowernow': 211.137503624, 'start_solution': start_solution, 'haushaltsgeraet_wh': 937, 'haushaltsgeraet_dauer': 0} opt_class = optimization_problem(prediction_hours=48, strafe=10,optimization_hours=24) ergebnis = opt_class.optimierung_ems(parameter=parameter, start_hour=start_hour) - - -# #Gesamtlast -# ############# -# gesamtlast = Gesamtlast() - - -# # Load Forecast -# ############### -# lf = LoadForecast(filepath=r'load_profiles.npz', year_energy=year_energy) -# #leistung_haushalt = lf.get_daily_stats(date)[0,...] # Datum anpassen -# leistung_haushalt = lf.get_stats_for_date_range(date_now,date)[0,...].flatten() -# # print(date_now," ",date) -# # print(leistung_haushalt.shape) -# gesamtlast.hinzufuegen("Haushalt", leistung_haushalt) - -# # PV Forecast -# ############### -# #PVforecast = PVForecast(filepath=os.path.join(r'test_data', r'pvprognose.json')) -# PVforecast = PVForecast(prediction_hours = prediction_hours, url="https://api.akkudoktor.net/forecast?lat=50.8588&lon=7.3747&power=5000&azimuth=-10&tilt=7&powerInvertor=10000&horizont=20,27,22,20&power=4800&azimuth=-90&tilt=7&powerInvertor=10000&horizont=30,30,30,50&power=1400&azimuth=-40&tilt=60&powerInvertor=2000&horizont=60,30,0,30&power=1600&azimuth=5&tilt=45&powerInvertor=1400&horizont=45,25,30,60&past_days=5&cellCoEff=-0.36&inverterEfficiency=0.8&albedo=0.25&timezone=Europe%2FBerlin&hourly=relativehumidity_2m%2Cwindspeed_10m") -# pv_forecast = PVforecast.get_pv_forecast_for_date_range(date_now,date) #get_forecast_for_date(date) - -# temperature_forecast = PVforecast.get_temperature_for_date_range(date_now,date) - - - -# # Strompreise -# ############### -# filepath = os.path.join (r'test_data', r'strompreise_akkudokAPI.json') # Pfad zur JSON-Datei anpassen -# #price_forecast = HourlyElectricityPriceForecast(source=filepath) -# price_forecast = HourlyElectricityPriceForecast(source="https://api.akkudoktor.net/prices?start="+date_now+"&end="+date+"") -# specific_date_prices = price_forecast.get_price_for_daterange(date_now,date) -# # print("13:",specific_date_prices[13]) -# # print("14:",specific_date_prices[14]) -# # print("15:",specific_date_prices[15]) -# # sys.exit() -# # WP -# ############## -# leistung_wp = wp.simulate_24h(temperature_forecast) -# gesamtlast.hinzufuegen("Heatpump", leistung_wp) - - -# # EAuto -# ###################### -# # leistung_eauto = eauto.get_stuendliche_last() -# # soc_eauto = eauto.get_stuendlicher_soc() -# # gesamtlast.hinzufuegen("eauto", leistung_eauto) - -# # print(gesamtlast.gesamtlast_berechnen()) - -# # EMS / Stromzähler Bilanz -# #akku=None, pv_prognose_wh=None, strompreis_cent_pro_wh=None, einspeiseverguetung_cent_pro_wh=None, eauto=None, gesamtlast=None - -# ems = EnergieManagementSystem(akku=akku, gesamtlast = gesamtlast, pv_prognose_wh=pv_forecast, strompreis_cent_pro_wh=specific_date_prices, einspeiseverguetung_cent_pro_wh=einspeiseverguetung_cent_pro_wh, eauto=eauto) - - -# o = ems.simuliere(start_hour)#ems.simuliere_ab_jetzt() -# #pprint(o) -# #pprint(o["Gesamtbilanz_Euro"]) - -# #visualisiere_ergebnisse(gesamtlast, pv_forecast, specific_date_prices, o,discharge_array,laden_moeglich, temperature_forecast, start_hour, prediction_hours) - - - -# # Optimierung - -# def evaluate_inner(individual): - # #print(individual) - # discharge_hours_bin = individual[0::2] - # eautocharge_hours_float = individual[1::2] - - # #print(discharge_hours_bin) - # #print(len(eautocharge_hours_float)) - # ems.reset() - # #eauto.reset() - # ems.set_akku_discharge_hours(discharge_hours_bin) - # ems.set_eauto_charge_hours(eautocharge_hours_float) - - # #eauto.set_laden_moeglich(eautocharge_hours_float) - # #eauto.berechne_ladevorgang() - # #leistung_eauto = eauto.get_stuendliche_last() - # #gesamtlast.hinzufuegen("eauto", leistung_eauto) - - # #ems.set_gesamtlast(gesamtlast.gesamtlast_berechnen()) - - # o = ems.simuliere(start_hour) - # return o, eauto - -# # Fitness-Funktion (muss Ihre EnergieManagementSystem-Logik integrieren) -# def evaluate(individual): - # o,eauto = evaluate_inner(individual) - # gesamtbilanz = o["Gesamtbilanz_Euro"] - - # # Überprüfung, ob der Mindest-SoC erreicht wird - # final_soc = eauto.ladezustand_in_prozent() # Nimmt den SoC am Ende des Optimierungszeitraums - # strafe = 0.0 - # #if final_soc < min_soc_eauto: - # # Fügt eine Strafe hinzu, wenn der Mindest-SoC nicht erreicht wird - # strafe = max(0,(min_soc_eauto - final_soc) * hohe_strafe ) # `hohe_strafe` ist ein vorher festgelegter Strafwert - # gesamtbilanz += strafe - # gesamtbilanz += o["Gesamt_Verluste"]/1000.0 - # return (gesamtbilanz,) - - - - - -# # Werkzeug-Setup -# creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) -# creator.create("Individual", list, fitness=creator.FitnessMin) - -# toolbox = base.Toolbox() - -# toolbox.register("attr_bool", random.randint, 0, 1) -# toolbox.register("attr_bool", random.randint, 0, 1) -# toolbox.register("individual", tools.initCycle, creator.Individual, (toolbox.attr_bool,toolbox.attr_bool), n=prediction_hours) - - - -# toolbox.register("population", tools.initRepeat, list, toolbox.individual) - -# toolbox.register("evaluate", evaluate) -# toolbox.register("mate", tools.cxTwoPoint) -# toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) -# toolbox.register("select", tools.selTournament, tournsize=3) - -# # Genetischer Algorithmus -# def optimize(): - # population = toolbox.population(n=500) - # hof = tools.HallOfFame(1) - - # stats = tools.Statistics(lambda ind: ind.fitness.values) - # stats.register("avg", np.mean) - # stats.register("min", np.min) - # stats.register("max", np.max) - - # algorithms.eaMuPlusLambda(population, toolbox, 50, 100, cxpb=0.5, mutpb=0.5, ngen=500, stats=stats, halloffame=hof, verbose=True) - # #algorithms.eaSimple(population, toolbox, cxpb=0.2, mutpb=0.2, ngen=1000, stats=stats, halloffame=hof, verbose=True) - # return hof[0] - - -# start_solution = optimize() - - -# print("Start Lösung:", start_solution) - - - - -# # # Werkzeug-Setup -# # creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) -# # creator.create("Individual", list, fitness=creator.FitnessMin) - -# # toolbox = base.Toolbox() - - - - -# # toolbox.register("attr_bool", random.randint, 0, 1) -# # toolbox.register("attr_float", random.uniform, 0.0, 1.0) -# # toolbox.register("individual", tools.initCycle, creator.Individual, (toolbox.attr_bool,toolbox.attr_float), n=prediction_hours) - -# # start_individual = toolbox.individual() -# # start_individual[:] = start_solution - -# # toolbox.register("population", tools.initRepeat, list, toolbox.individual) - -# # toolbox.register("evaluate", evaluate) -# # toolbox.register("mate", tools.cxTwoPoint) -# # toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) -# # toolbox.register("select", tools.selTournament, tournsize=3) - -# # # Genetischer Algorithmus -# # def optimize(): - # # population = toolbox.population(n=1000) - # # population[0] = start_individual - # # hof = tools.HallOfFame(1) - - # # stats = tools.Statistics(lambda ind: ind.fitness.values) - # # stats.register("avg", np.mean) - # # stats.register("min", np.min) - # # stats.register("max", np.max) - - # # algorithms.eaMuPlusLambda(population, toolbox, 100, 200, cxpb=0.5, mutpb=0.2, ngen=1000, stats=stats, halloffame=hof, verbose=True) - # # #algorithms.eaSimple(population, toolbox, cxpb=0.2, mutpb=0.2, ngen=1000, stats=stats, halloffame=hof, verbose=True) - # # return hof[0] - -# # best_solution = optimize() -# best_solution = start_solution -# print("Beste Lösung:", best_solution) - -# #ems.set_akku_discharge_hours(best_solution) -# o,eauto = evaluate_inner(best_solution) - -# # soc_eauto = eauto.get_stuendlicher_soc() -# # print(soc_eauto) -# # pprint(o) -# # pprint(eauto.get_stuendlicher_soc()) - - -# #visualisiere_ergebnisse(gesamtlast,leistung_haushalt,leistung_wp, pv_forecast, specific_date_prices, o,soc_eauto,best_solution[0::2],best_solution[1::2] , temperature_forecast) -# visualisiere_ergebnisse(gesamtlast, pv_forecast, specific_date_prices, o,best_solution[0::2],best_solution[1::2] , temperature_forecast, start_hour, prediction_hours) - - -# # for data in forecast.get_forecast_data(): - # # print(data.get_date_time(), data.get_dc_power(), data.get_ac_power(), data.get_windspeed_10m(), data.get_temperature())for data in forecast.get_forecast_data(): - - - - -# # app = Flask(__name__) - - - -# # @app.route('/getdata', methods=['GET']) -# # def get_data(): - # # # Hole das Datum aus den Query-Parametern - # # date_str = request.args.get('date') - # # year_energy = request.args.get('year_energy') - - # # try: - # # # Konvertiere das Datum in ein datetime-Objekt - # # date_obj = datetime.strptime(date_str, '%Y-%m-%d') - # # filepath = r'.\load_profiles.npz' # Pfad zur JSON-Datei anpassen - # # lf = cl.LoadForecast(filepath=filepath, year_energy=float(year_energy)) - # # specific_date_prices = lf.get_daily_stats('2024-02-16') - - - # # # Berechne den Tag des Jahres - # # #day_of_year = date_obj.timetuple().tm_yday - - # # # Konvertiere den Tag des Jahres in einen String, falls die Schlüssel als Strings gespeichert sind - # # #day_key = int(day_of_year) - # # #print(day_key) - # # # Überprüfe, ob der Tag im Jahr in den Daten vorhanden ist - # # array_list = lf.get_daily_stats(date_str) - # # pprint(array_list) - # # pprint(array_list.shape) - # # if array_list.shape == (2,24): - # # #if day_key < len(load_profiles_exp): - # # # Konvertiere das Array in eine Liste für die JSON-Antwort - # # #((load_profiles_exp_l[day_key]).tolist(),(load_profiles_std_l)[day_key].tolist()) - - # # return jsonify({date_str: array_list.tolist()}) - # # else: - # # return jsonify({"error": "Datum nicht gefunden"}), 404 - # # except ValueError: - # # # Wenn das Datum nicht im richtigen Format ist oder ungültig ist - # # return jsonify({"error": "Ungültiges Datum"}), 400 - -# # if __name__ == '__main__': - # # app.run(debug=True) - +print(ergebnis) +print(jsonify(ergebnis)) \ No newline at end of file