-
-
Notifications
You must be signed in to change notification settings - Fork 39
/
forecast.py
118 lines (94 loc) · 4.13 KB
/
forecast.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from datetime import datetime, timedelta
import pandas as pd
from quartz_solar_forecast.data import get_nwp, make_pv_data
from quartz_solar_forecast.forecasts import forecast_v1_tilt_orientation, TryolabsSolarPowerPredictor
from quartz_solar_forecast.pydantic_models import PVSite
def predict_ocf(
site: PVSite, model=None, ts: datetime | str = None, nwp_source: str = "icon"
):
"""
Run the forecast with the gb model, which can take tilt and orientation as inputs
:param site: the PV site
:param model: the model to use for prediction
:param ts: the timestamp of the site. If None, defaults to the current timestamp rounded down to 15 minutes.
:param nwp_source: the nwp data source. Either "gfs" or "icon". Defaults to "icon"
:return: The PV forecast of the site for time (ts) for 48 hours
"""
if ts is None:
ts = pd.Timestamp.now().round("15min")
if isinstance(ts, str):
ts = datetime.fromisoformat(ts)
# make pv and nwp data from nwp_source
nwp_xr = get_nwp(site=site, ts=ts, nwp_source=nwp_source)
pv_xr = make_pv_data(site=site, ts=ts)
# load and run models
pred_df = forecast_v1_tilt_orientation(nwp_source, nwp_xr, pv_xr, ts, model=model)
return pred_df
def predict_tryolabs(
site: PVSite, ts: datetime | str = None):
"""
Run the forecast with the xgb model
:param site: the PV site
:param ts: the timestamp of the site. If None, defaults to the current timestamp rounded down to 15 minutes.
:return: The PV forecast of the site for time (ts) for 48 hours
"""
# instantiate class to make predictions
solar_power_predictor = TryolabsSolarPowerPredictor()
# set start and end time, if no time is given use current time
if ts is None:
start_date = pd.Timestamp.now().strftime("%Y-%m-%d")
start_time = pd.Timestamp.now().round(freq='h')
else:
start_date = pd.Timestamp(ts).strftime("%Y-%m-%d")
start_time = pd.Timestamp(ts).round(freq='h')
end_time = start_time + pd.Timedelta(hours=48)
start_date_datetime = datetime.strptime(start_date, "%Y-%m-%d")
# Check if the start date is more than 3 months ago
three_months_ago = datetime.today() - timedelta(days=3 * 30)
if start_date_datetime < three_months_ago:
print(
f"Start date ({start_date}) is more than 3 months ago, no",
"forecast data available.",
)
else:
# download the model from google drive and decompress if necessary
solar_power_predictor.load_model()
# make predictions
predictions = solar_power_predictor.predict_power_output(
latitude=site.latitude,
longitude=site.longitude,
start_date=start_date,
kwp=site.capacity_kwp,
orientation=site.orientation,
tilt=site.tilt,
)
# postprocessing of the dataframe
predictions = predictions[
(predictions["date"] >= start_time) & (predictions["date"] < end_time)
]
predictions = predictions.reset_index(drop=True)
predictions.set_index("date", inplace=True)
print("Predictions finished.")
return predictions
def run_forecast(
site: PVSite,
model: str = "gb",
ts: datetime | str = None,
nwp_source: str = "icon",
) -> pd.DataFrame:
"""
Predict solar power output for a given site using a specified model.
:param site: the PV site
:param model: the model to use for prediction, choose between "ocf" and "tryolabs",
by default "ocf" is used
:param ts: the timestamp of the site. If None, defaults to the current timestamp rounded down to 15 minutes.
:param nwp_source: the nwp data source. Either "gfs" or "icon". Defaults to "icon"
(only relevant if model=="gb")
:return: The PV forecast of the site for time (ts) for 48 hours
"""
if model == "gb":
return predict_ocf(site, None, ts, nwp_source)
elif model == "xgb":
return predict_tryolabs(site, ts)
else:
raise ValueError(f"Unsupported model: {model}. Choose between 'xgb' and 'gb'")