File size: 7,497 Bytes
724eb6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3613412
724eb6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ca4a1a
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# Import gradio
import gradio as gr

# Data import from open-meteo.com
import openmeteo_requests               
import requests_cache
from retry_requests import retry
    
# Data management and visualization
import pandas as pd
import numpy as np
import datetime
import pickle
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

# Machine Learning
import sklearn

# Print version info
print("Version info:")
print('pandas: %s' % pd.__version__)
print('numpy: %s' % np.__version__)
print('sklearn: %s' % sklearn.__version__)
print(" ")


def makeprediction():
#%% 1. User Inputs
    # These inputs may be changed by the user
    model_file_name = "Solar RF Model_2024-01-03T08-53-53_.pkl"    # This is the name of the file generated by the script "Build_solar_RF_model.py" (must be located in same folder)
    horizon = 2                                                    # Forecast horizon in days, limit is 16 days.
                                                                   # Note that the further we look into the future, the less accurate the weather forecast is likely to be
    PV_capacity = 15                                               # The maximum capacity of your PV installation in kW, only used for plotting.
    
    #%% 2. Read Model
    # Read in the model
    f_model = open(model_file_name, 'rb')               # Opens the file
    model_dict = pickle.load(f_model)                   # Reads the dictionary from the file
    f_model.close()                                     # closes the file again
    
    #%% 3. Fetch weather forecast
    
    # Setup the Open-Meteo API client with cache and retry on error
    cache_session = requests_cache.CachedSession('.cache', expire_after = -1)
    retry_session = retry(cache_session, retries = 5, backoff_factor = 0.2)
    openmeteo = openmeteo_requests.Client(session = retry_session)
    
    # Make sure all required weather variables are listed here
    url = "https://api.open-meteo.com/v1/forecast"
    
    # Calcualte start and end date
    start_date = datetime.datetime.now()
    end_date = start_date + datetime.timedelta(days=horizon)
    sdate_str = str(start_date)[0:10]                       # First date in file as string (yyyy-mm-dd)
    edate_str = str(end_date)[0:10]                         # Last date in file as string (yyyy-mm-dd)
    
    # Use the same parameters as was used for training the model.
    params = {
    	"latitude": model_dict['API Request Params']['latitude'],
    	"longitude": model_dict['API Request Params']['longitude'],
    	"hourly": model_dict['API Request Params']['hourly'],
        "start_date": sdate_str,
        "end_date": edate_str,
    }
    responses = openmeteo.weather_api(url, params=params)
    
    # Process & print request info.
    response = responses[0]
    print("Request info:")
    print(f"Coordinates {response.Latitude()}°E {response.Longitude()}°N")
    print(f"Elevation {response.Elevation()} m asl")
    print(f"Timezone {response.Timezone()} {response.TimezoneAbbreviation()}")
    print(f"Timezone difference to GMT+0 {response.UtcOffsetSeconds()} s")
    #print(f"From: " + sdate_str + " To: " + edate_str)
    print(" ")
    
    # Process hourly data. The order of variables needs to be the same as requested.
    hourly = response.Hourly()                                  # API Response
    hourly_data = {"date": pd.date_range(                       # Dictionary that we add the API respnse to
    	start = pd.to_datetime(hourly.Time(), unit = "s"),
    	end = pd.to_datetime(hourly.TimeEnd(), unit = "s"),
    	freq = pd.Timedelta(seconds = hourly.Interval()),
    	inclusive = "left"
    )}
    
    # We iterate through the variables and add the API response data to our dictionary
    print("Adding variables to dataframe...")
    index_variable = 0
    for variable in params['hourly']:
        hourly_data[variable] = hourly.Variables(index_variable).ValuesAsNumpy()    # Add the variable to dataframe
        print("Added " + variable)
        index_variable += 1                                                         # Increment counter
        
    print(" ")
    # Create dataframe
    weather_data = pd.DataFrame(data = hourly_data)    
    weather_data = weather_data.set_index('date')    # Set index to be dates
    
    #%% 4. Data manipulation & encoding
    # Create a new dataframe to hold all data, also encode new features.
    
    # Create a main dataframe that holds all data
    main_df = weather_data.copy()
    
    for index, row in main_df.iterrows():
        main_df.loc[index,'month'] = index.month
        main_df.loc[index,'day'] = index.day
        main_df.loc[index,'hour'] = index.hour
        main_df.loc[index,'sine month'] = np.sin((index.month - 1)*np.pi/11)
        main_df.loc[index,'cos month'] = np.cos((index.month - 1)*np.pi/11)
        main_df.loc[index,'sine hour'] = np.sin((index.month - 1)*np.pi/23)
        main_df.loc[index,'cos hour'] = np.cos((index.month - 1)*np.pi/23)
    
    # Index to keep track of which hours the sun is up for.        
    Sun_index = main_df[main_df['is_day'] == 1].index        
    
    # Create a new dataframe with only relevant data, this will be used for statistical 
    sun_is_up_data = main_df.copy()                                 # Create copy
    sun_is_up_data = sun_is_up_data.loc[Sun_index]                  # Only include rows when the sun is up
    sun_is_up_data = sun_is_up_data[model_dict['Input features']]   # Only include columns needed for model
    
    
    #%% 5. Make Predictions
    print("Making predictions...")
    # Create dataframe to hold predictions and initialize with 0.
    predictions = pd.DataFrame(0, index = weather_data.index, columns = ['Main Forecast', 'Lower Bound', 'Upper Bound'])
    predictions['Date'] = predictions.index.tolist()             # Make dates also to a column for easier plotting
    
    # Make predictions
    predictions.loc[Sun_index,'Main Forecast'] = model_dict['Random Forest Model'].predict(sun_is_up_data)
    predictions.loc[Sun_index,['Lower Bound', 'Upper Bound']] = model_dict['Random Forest Quantile Model'].predict(sun_is_up_data, quantiles=[0.1, 0.9], interpolation='linear')
    print(" ")
    #%% 6. Make Plot
    
    # Plotting
    plt.style.use('_mpl-gallery')                   # Set plot style
    matplotlib.rc('font', **{'size'   : 20})        # Change font size
    fig, ax = plt.subplots()                        # Create plot
    fig.set_size_inches(18.5, 10.5, forward=True)   # Set figure size
    fig.set_dpi(100)                                # Set resolution
    ax.fill_between(predictions['Date'], predictions['Lower Bound'], predictions['Upper Bound'], alpha=.5, linewidth=0) # Plot prediction interval
    ax.plot(predictions['Date'], predictions['Main Forecast'], linewidth=4, color='black')                              # Plot main forecast
    
    # Calculate x-ticks
    step_length = int(predictions.shape[0]/32)
    ax.set(ylim = [0,PV_capacity*1.05], xticks = predictions['Date'].iloc[::step_length])
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d %H:%M'))
    plt.ylabel('Solar power [kW]')
    plt.xticks(rotation=90)
    plt.legend(['Prediction Interval (10 - 90%)', 'Main Forecast'])
    plt.title('Solar Power Forecast from ' + sdate_str + ' to ' + edate_str)
    # plt.show()
    
    return fig


iface = gr.Interface(fn=makeprediction, inputs=None, outputs=gr.Plot())
iface.launch()