Skip to content

Commit 4e78c8d

Browse files
authored
Version 2026.02.2.rc1 (#552)
* Catch Nan values solar-prediction * Correct totals battery summary * Fix error in reports (reported by @steynovich) * Fix error when period with minimum power is less than 1 minuut (reported by @dogooder) * Fix negative or small values >0 in ml-predictions when irradiance==0 (reported by @dogooder) * Version 2026.02.2.rc1
1 parent 0305a2b commit 4e78c8d

File tree

7 files changed

+57
-12
lines changed

7 files changed

+57
-12
lines changed

dao/prog/da_base.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ def calc_solar_predictions(
603603
:param vanaf: datetime start
604604
:param tot: datetime tot
605605
:param interval: 15"min of 1 hour of None, als None wordt self.interval genomen
606-
:param ml_prediction: boolean default None(= from config)
606+
:param _ml_prediction: boolean default None(= from config)
607607
:return:
608608
"""
609609
from dao.prog.solar_predictor import SolarPredictor
@@ -627,12 +627,19 @@ def calc_solar_predictions(
627627
solar_prog = solar_predictor.predict_solar_device(
628628
solar_option, vanaf, tot
629629
)
630+
if solar_prog.isnull().any().any():
631+
logging.warning(
632+
f"NaN-waarden aangetroffen in voorspelling van {solar_name}"
633+
f"Deze zijn op '0' gezet"
634+
)
635+
solar_prog.fillna(0, inplace=True)
630636
except FileNotFoundError as ex:
631637
logging.warning(ex)
632638
logging.info(
633639
f"Voor {solar_option['name']} is geen model "
634640
f"en dus wordt DAO-predictor gebruikt"
635641
)
642+
636643
result = self.calc_solar_predictions(
637644
solar_option, vanaf, tot, interval=interval, _ml_prediction=False
638645
)

dao/prog/da_graph.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ def build(self, df, options, show=True):
300300
ax.set_xlabel(haxis["title"])
301301
num_xas = len(df.index)
302302
if num_xas > 12:
303-
ax.xaxis.set_major_locator(ticker.MultipleLocator(round(num_xas / 12)))
304-
ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))
303+
ax.xaxis.set_major_locator(ticker.MultipleLocator(12))
304+
ax.xaxis.set_minor_locator(ticker.MultipleLocator(2))
305305
if len(str(xlabels[0])) > 2:
306306
ax.set_xticks(
307307
ax.get_xticks(), ax.get_xticklabels(), rotation=45, ha="right"

dao/prog/da_report.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,8 @@ def copy_col_df(
11181118
:return: de ingevuld copy_to
11191119
"""
11201120
dt = copy_from[col_name].dtype
1121-
if dt == float:
1121+
# Use is_numeric_dtype to catch all numeric types (float64, int64, etc.)
1122+
if pd.api.types.is_numeric_dtype(dt):
11221123
copy_to[col_name] = 0.0
11231124
else:
11241125
copy_to[col_name] = ""

dao/prog/day_ahead.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ def calc_optimum(
286286

287287
# nieuwe universele methode
288288
end = prog_data["tijd"].iloc[-1]
289+
if self.interval == "1hour":
290+
end += datetime.timedelta(hours=1)
291+
else:
292+
end += datetime.timedelta(minutes=15)
289293
for s in range(solar_num):
290294
solar_prog = self.calc_solar_predictions(
291295
self.solar[s], start_interval_dt, end, self.interval
@@ -1089,7 +1093,10 @@ def calc_optimum(
10891093
heat_rate = (
10901094
power_boiler * cop_boiler * self.interval_s / (spec_heat_boiler * 1000)
10911095
)
1092-
max_steps = int((boiler_setpoint - boiler_ondergrens) / heat_rate) + 1
1096+
boiler_end_temp = max(
1097+
boiler_ondergrens, boiler_act_temp - U * boiler_cooling
1098+
)
1099+
max_steps = math.ceil((boiler_setpoint - boiler_end_temp) / heat_rate)
10931100
# interval-index waarop boiler kan worden verwarmd
10941101
if boiler_instant_start or (boiler_act_temp <= boiler_ondergrens):
10951102
boiler_start_index = 0
@@ -3234,10 +3241,15 @@ def calc_optimum(
32343241
totals = False
32353242

32363243
if totals:
3237-
df_accu[b].at[df_accu[b].index[-1], "uur"] = "Totaal"
3238-
df_accu[b].at[df_accu[b].index[-1], "eff"] = "--"
3239-
df_accu[b].at[df_accu[b].index[-1], "o_eff"] = "--"
3240-
df_accu[b].at[df_accu[b].index[-1], "SoC"] = pd.NA
3244+
# Kolom "uur" kan string "Totaal" krijgen door eerst naar object te casten
3245+
df_accu[b].iloc[:, 0] = df_accu[b].iloc[:, 0].astype(object)
3246+
df_accu[b].iloc[:, 0] = df_accu[b].iloc[:, 0].astype(object)
3247+
df_accu[b].iloc[-1, 0] = "Totaal"
3248+
df_accu[b].iloc[-1, 2] = np.nan # eff (ac->dc)
3249+
df_accu[b].iloc[-1, 6] = np.nan # eff (dc->bat)
3250+
df_accu[b].iloc[-1, 8] = np.nan # o_eff
3251+
df_accu[b].iloc[-1, 9] = np.nan # SoC
3252+
32413253
logging.info(
32423254
f"In- en uitgaande energie per {self.interval_name} batterij "
32433255
f"{self.battery_options[b]['name']}"
@@ -3750,7 +3762,7 @@ def calc_optimum(
37503762
if wf > 0:
37513763
sum_weight_factor += wf
37523764
sum_power += wf * discharge_stages[b][ds]["power"]
3753-
if sum_weight_factor < 0.95:
3765+
if 0.10 <= sum_weight_factor < 0.95:
37543766
new_state = battery_state_on_value
37553767
balance = False
37563768
netto_vermogen_bat = -round(sum_power / sum_weight_factor)

dao/prog/solar_predictor.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,16 @@ def predict_solar_device(
10231023
:param end: eind-tijdstip voorspelling
10241024
:return: dataframe met berekende voorspellingen per uur
10251025
"""
1026+
1027+
def check_prediction(prediction, irradiance):
1028+
if irradiance <= 0.0:
1029+
result = 0
1030+
else:
1031+
result = prediction
1032+
if result < 0.0:
1033+
result = 0
1034+
return result
1035+
10261036
name = self.config.get(["name"], solar_dict, "default")
10271037
self.solar_name = name.replace(" ", "_")
10281038
self.tilt = self.get_property_from_dict("tilt", solar_dict, 45)
@@ -1039,7 +1049,13 @@ def predict_solar_device(
10391049
prognose = latest_dt < end
10401050
weather_data = self.get_weatherdata(start, end, prognose=prognose)
10411051
prediction = self.predict(weather_data)
1042-
prediction["prediction"] = prediction["prediction"].round(3)
1052+
weather_data.reset_index(inplace=True)
1053+
prediction["irradiance"] = weather_data["irradiance"]
1054+
prediction["prediction"] = prediction.apply(
1055+
lambda x: check_prediction(x["prediction"], x["irradiance"]), axis=1
1056+
)
1057+
prediction["prediction"].round(3)
1058+
prediction.drop("irradiance", axis=1, inplace=True)
10431059
logging.info(f"ML prediction {self.solar_name}\n{prediction}")
10441060
return prediction
10451061

release-testing/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Changelog 刀 DAO
22
# Day Ahead Optimizer
3+
# 2026.02.2.rc1
4+
- Update several python modules
5+
- Adjusted the footer of the webpages (reported by steynovitch)
6+
- Removed NaN-values from ml-preditions
7+
- Fix error in reports (reported by @steynovich)
8+
- Correct totals battery summary
9+
- Fix error when period with minimum power is less than 1 minuut (reported by @Dogooder)
10+
- Fix negative or small values >0 in ml-predictions when irradiance==0 (reported by @Dogooder)
11+
312
# 2026.02.1.rc1
413
Add missing module tzdata
514

release-testing/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: 刀 Day Ahead Optimizer (TESTING)
3-
version: 2026.02.1.rc1
3+
version: 2026.02.2.rc1
44
stage: experimental
55
slug: day_ahead_opt-testing
66
description: Beta version of DAO. Use only for testing!

0 commit comments

Comments
 (0)