naohiro701 commited on
Commit
7d659c6
·
verified ·
1 Parent(s): d7318ea

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -61
app.py CHANGED
@@ -13,23 +13,18 @@ import seaborn as sns
13
 
14
  # Function to fetch renewable energy data
15
  def get_renewable_energy_data(city_code):
16
- # Construct the URL for fetching renewable energy data for a given city code
17
  url = f"https://energy-sustainability.jp/_ajax/renewable_energy/get/?code={city_code}"
18
  response = requests.get(url)
19
- # If the request is unsuccessful, return an error message
20
  if response.status_code != 200:
21
  return None, "データの取得に失敗しました。"
22
 
23
  data = response.json()
24
- # If no data is found, return an error message
25
  if not data:
26
  return None, "データが見つかりませんでした。"
27
 
28
- # Extract base times from the first energy type and create a DataFrame
29
  base_times = data[next(iter(data))]['x']
30
  result_df = pd.DataFrame({"Time": base_times})
31
 
32
- # Loop through each energy type and append hourly capacity factor data to the DataFrame
33
  for energy_type, energy_data in data.items():
34
  if 'x' in energy_data and 'y' in energy_data:
35
  values = energy_data['y']
@@ -37,26 +32,17 @@ def get_renewable_energy_data(city_code):
37
 
38
  return result_df, None
39
 
40
- # Function to filter numeric columns
41
- def filter_numeric_columns(df):
42
- # Select only numeric columns from the DataFrame
43
- numeric_df = df.select_dtypes(include=['number'])
44
- return numeric_df
45
-
46
  # Function to optimize the energy system and create heatmaps
47
- def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand):
48
- # Fetch renewable energy data
49
  data, error = get_renewable_energy_data(city_code)
50
  if error:
51
  st.error(error)
52
  return None, None, None, None
53
 
54
- # Convert all capacity factor columns to numeric, handling errors and filling missing values with zero
55
  for col in data.columns[1:]:
56
  data[col] = pd.to_numeric(data[col], errors='coerce')
57
  data = data.fillna(0)
58
 
59
- # Define the time steps based on the length of the data
60
  time_steps = range(len(data['Time']))
61
  solar_cf = data['solar hourly capacity factor']
62
  onshore_wind_cf = data['onshore_wind hourly capacity factor']
@@ -64,7 +50,6 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
64
  river_cf = data['river hourly capacity factor']
65
  demand_cf = data['demand hourly capacity factor']
66
 
67
- # Define regions and technologies
68
  regions = ['region1']
69
  technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']
70
  capacity_factor = {
@@ -74,15 +59,12 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
74
  'river': river_cf
75
  }
76
 
77
- # Define the costs for each renewable capacity and battery storage
78
  renewable_capacity_cost = {'solar': solar_cost, 'onshore_wind': onshore_wind_cost, 'offshore_wind': offshore_wind_cost, 'river': river_cost}
79
  battery_cost_per_mwh = battery_cost
80
  battery_efficiency = 0.9
81
-
82
- # Scale demand from yearly demand in TWh/year to hourly demand in MW
83
  demand = demand_cf * yearly_demand / 100 * 1000 * 1000
84
 
85
- # Define LP variables for renewable capacities, curtailment, battery capacity, charge, discharge, and state of charge (SOC)
86
  renewable_capacity = pulp.LpVariable.dicts("renewable_capacity",
87
  [(r, g) for r in regions for g in technologies],
88
  lowBound=0, cat='Continuous')
@@ -94,34 +76,31 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
94
  battery_discharge = pulp.LpVariable.dicts("battery_discharge", time_steps, lowBound=0, cat='Continuous')
95
  SOC = pulp.LpVariable.dicts("SOC", time_steps, lowBound=0, cat='Continuous')
96
 
97
- # Define the optimization problem to minimize the total system cost
98
  model = pulp.LpProblem("EnergySystemOptimizationWithBattery", pulp.LpMinimize)
99
 
100
- # Objective function: minimize the cost of renewable capacities and battery storage
101
  model += pulp.lpSum([renewable_capacity[(r, g)] * renewable_capacity_cost[g]
102
  for r in regions for g in technologies]) + \
103
  battery_capacity * battery_cost_per_mwh, "TotalCost"
104
 
105
- # Constraints to meet demand, manage curtailment, and update state of charge for the battery
106
  for r in regions:
107
  for t in time_steps:
108
- # Ensure that generation plus battery discharge meets demand, accounting for curtailment and battery charge
109
  model += pulp.lpSum([renewable_capacity[(r, g)] * capacity_factor[g][t]
110
  for g in technologies]) + battery_discharge[t] == demand[t] + battery_charge[t] + curtailment[(r,t)], f"DemandConstraint_{r}_{t}"
111
 
112
- # Update state of charge for the battery
113
  if t == 0:
114
  model += SOC[t] == battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
115
  else:
116
  model += SOC[t] == SOC[t-1] + battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
117
 
118
- # Ensure SOC does not exceed battery capacity
119
  model += SOC[t] <= battery_capacity, f"SOCUpperBound_{t}"
120
 
121
- # Solve the optimization model
 
 
 
 
122
  model.solve()
123
 
124
- # Extract optimized supply and battery values
125
  supply_solar = solar_cf * renewable_capacity[('region1', 'solar')].varValue
126
  supply_onshore_wind = onshore_wind_cf * renewable_capacity[('region1', 'onshore_wind')].varValue
127
  supply_offshore_wind = offshore_wind_cf * renewable_capacity[('region1', 'offshore_wind')].varValue
@@ -132,14 +111,11 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
132
  SOC_values = [SOC[t].varValue for t in time_steps]
133
  curtailment_values = [-curtailment[(r, t)].varValue for r in regions for t in time_steps]
134
 
135
- # Calculate price per hour based on demand and generation (simplified example)
136
  price_per_hour = [100 + 0.05 * demand[t] for t in time_steps]
137
 
138
- # Normalize state of charge (SOC) to a percentage
139
  max_SOC = max(SOC_values)
140
  SOC_normalized = [(soc / max_SOC) * 100 for soc in SOC_values] if max_SOC > 0 else [0] * len(SOC_values)
141
 
142
- # Create plot for energy dispatch
143
  fig_energy = go.Figure()
144
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_solar, mode='lines', stackgroup='one', name='Solar', line=dict(color='#FFD700', width=0)))
145
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_onshore_wind, mode='lines', stackgroup='one', name='Onshore Wind', line=dict(color='#1F78B4', width=0)))
@@ -150,7 +126,6 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
150
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=-demand, mode='lines', stackgroup='two', name='Demand', line=dict(color='black', width=0)))
151
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=curtailment_values, mode='lines', stackgroup='two', name='Curtailment', line=dict(color='#aaaaaa', width=0)))
152
 
153
- # Layout settings for energy dispatch plot
154
  fig_energy.update_layout(
155
  title_text='Power Supply and Demand',
156
  title_x=0.5,
@@ -163,16 +138,15 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
163
  xaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray'),
164
  yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')
165
  )
166
-
167
- # Create a heatmap for each energy source (solar, onshore wind, offshore wind, river)
168
  heatmaps = []
169
  for energy_source in ['solar', 'onshore_wind', 'offshore_wind', 'river']:
170
  df_heatmap = data[['Time', f'{energy_source} hourly capacity factor']].copy()
171
- df_heatmap['Time'] = pd.to_datetime(df_heatmap['Time'], errors='coerce') # Ensure Time is in datetime format
172
  df_heatmap['day_of_year'] = df_heatmap['Time'].dt.dayofyear
173
  df_heatmap['hour_of_day'] = df_heatmap['Time'].dt.hour
174
-
175
- # Use pivot_table instead of pivot to handle duplicates
176
  pivot_df = df_heatmap.pivot_table(
177
  index='hour_of_day',
178
  columns='day_of_year',
@@ -180,7 +154,6 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
180
  aggfunc='mean'
181
  )
182
 
183
- # Create Plotly heatmap
184
  fig_heatmap = px.imshow(
185
  pivot_df.values,
186
  labels=dict(x="Day of Year", y="Hour of Day", color=f"{energy_source.replace('_', ' ').title()} Capacity Factor"),
@@ -206,28 +179,22 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
206
  st.set_page_config(page_title='Renewable Energy System Optimization', layout='wide')
207
  st.title('Renewable Energy System Optimization')
208
 
209
- # Overview section explaining the project
210
- st.markdown("""
211
- ### Overview
212
- This application is designed to help researchers and policymakers explore and optimize renewable energy systems for a specified region. By inputting cost parameters for different renewable energy sources and energy storage systems, the application determines the optimal mix of resources to meet energy demand while minimizing cost.
213
- The optimization problem is solved using linear programming, ensuring a balance between supply and demand, and incorporating battery energy storage to manage intermittency issues inherent in renewable energy.
214
- The visualizations provided help to better understand how different energy sources contribute to the overall power supply, how energy storage systems are utilized, and the impact of cost variations on energy prices.
215
- """)
216
-
217
- # Sidebar input fields for user to provide parameters
218
  with st.sidebar:
219
  st.header('Input Parameters')
220
  city_code = st.text_input("Enter City Code", value=999999)
221
- solar_cost = st.number_input("Solar Capacity Cost (¥/MW)", value=80.0, help="Estimated average cost of solar capacity per MW")
222
- onshore_wind_cost = st.number_input("Onshore Wind Capacity Cost (¥/MW)", value=120.0, help="Estimated average cost of onshore wind capacity per MW")
223
- offshore_wind_cost = st.number_input("Offshore Wind Capacity Cost (¥/MW)", value=180.0, help="Estimated average cost of offshore wind capacity per MW")
224
- river_cost = st.number_input("River Capacity Cost (¥/MW)", value=1000.0, help="Estimated average cost of river (hydro) capacity per MW")
225
- battery_cost = st.number_input("Battery Cost (¥/MWh)", value=80.0, help="Estimated average cost of battery storage per MWh")
226
- yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0, help="Total yearly power demand in TWh")
227
-
228
- # Button to trigger optimization
 
 
 
229
  if st.button('Calculate Optimal Energy Mix'):
230
- fig_energy, heatmaps, curtailment_values, price_per_hour = optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand)
231
 
232
  if fig_energy:
233
  st.plotly_chart(fig_energy, use_container_width=True, height=800)
@@ -247,9 +214,9 @@ if st.button('Calculate Optimal Energy Mix'):
247
  'Offshore Wind': offshore_wind_cost,
248
  'Run of River': river_cost
249
  }
250
- cost_df = pd.DataFrame(list(renewable_data.items()), columns=['Technology', 'Cost (¥/MW)'])
251
 
252
- fig_cost = px.bar(cost_df, x='Technology', y='Cost (¥/MW)', color='Technology', title='Cost Comparison of Different Renewable Technologies', template='plotly_white')
253
  st.plotly_chart(fig_cost, use_container_width=True, height=800)
254
 
255
  # Plot curtailment over time
@@ -258,6 +225,6 @@ if st.button('Calculate Optimal Energy Mix'):
258
  st.plotly_chart(fig_curtailment, use_container_width=True, height=800)
259
 
260
  # Plot electricity price variation over time
261
- price_df = pd.DataFrame({"Time": fig_energy.data[0].x, "Electricity Price (¥/MWh)": price_per_hour})
262
- fig_price = px.line(price_df, x='Time', y='Electricity Price (¥/MWh)', title='Electricity Price Variation Over Time', template='plotly_white')
263
- st.plotly_chart(fig_price, use_container_width=True, height=800)
 
13
 
14
  # Function to fetch renewable energy data
15
  def get_renewable_energy_data(city_code):
 
16
  url = f"https://energy-sustainability.jp/_ajax/renewable_energy/get/?code={city_code}"
17
  response = requests.get(url)
 
18
  if response.status_code != 200:
19
  return None, "データの取得に失敗しました。"
20
 
21
  data = response.json()
 
22
  if not data:
23
  return None, "データが見つかりませんでした。"
24
 
 
25
  base_times = data[next(iter(data))]['x']
26
  result_df = pd.DataFrame({"Time": base_times})
27
 
 
28
  for energy_type, energy_data in data.items():
29
  if 'x' in energy_data and 'y' in energy_data:
30
  values = energy_data['y']
 
32
 
33
  return result_df, None
34
 
 
 
 
 
 
 
35
  # Function to optimize the energy system and create heatmaps
36
+ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand, solar_min, solar_max, wind_min, wind_max):
 
37
  data, error = get_renewable_energy_data(city_code)
38
  if error:
39
  st.error(error)
40
  return None, None, None, None
41
 
 
42
  for col in data.columns[1:]:
43
  data[col] = pd.to_numeric(data[col], errors='coerce')
44
  data = data.fillna(0)
45
 
 
46
  time_steps = range(len(data['Time']))
47
  solar_cf = data['solar hourly capacity factor']
48
  onshore_wind_cf = data['onshore_wind hourly capacity factor']
 
50
  river_cf = data['river hourly capacity factor']
51
  demand_cf = data['demand hourly capacity factor']
52
 
 
53
  regions = ['region1']
54
  technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']
55
  capacity_factor = {
 
59
  'river': river_cf
60
  }
61
 
 
62
  renewable_capacity_cost = {'solar': solar_cost, 'onshore_wind': onshore_wind_cost, 'offshore_wind': offshore_wind_cost, 'river': river_cost}
63
  battery_cost_per_mwh = battery_cost
64
  battery_efficiency = 0.9
65
+
 
66
  demand = demand_cf * yearly_demand / 100 * 1000 * 1000
67
 
 
68
  renewable_capacity = pulp.LpVariable.dicts("renewable_capacity",
69
  [(r, g) for r in regions for g in technologies],
70
  lowBound=0, cat='Continuous')
 
76
  battery_discharge = pulp.LpVariable.dicts("battery_discharge", time_steps, lowBound=0, cat='Continuous')
77
  SOC = pulp.LpVariable.dicts("SOC", time_steps, lowBound=0, cat='Continuous')
78
 
 
79
  model = pulp.LpProblem("EnergySystemOptimizationWithBattery", pulp.LpMinimize)
80
 
 
81
  model += pulp.lpSum([renewable_capacity[(r, g)] * renewable_capacity_cost[g]
82
  for r in regions for g in technologies]) + \
83
  battery_capacity * battery_cost_per_mwh, "TotalCost"
84
 
 
85
  for r in regions:
86
  for t in time_steps:
 
87
  model += pulp.lpSum([renewable_capacity[(r, g)] * capacity_factor[g][t]
88
  for g in technologies]) + battery_discharge[t] == demand[t] + battery_charge[t] + curtailment[(r,t)], f"DemandConstraint_{r}_{t}"
89
 
 
90
  if t == 0:
91
  model += SOC[t] == battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
92
  else:
93
  model += SOC[t] == SOC[t-1] + battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
94
 
 
95
  model += SOC[t] <= battery_capacity, f"SOCUpperBound_{t}"
96
 
97
+ model += renewable_capacity[('region1', 'solar')] >= solar_min, "SolarMinConstraint"
98
+ model += renewable_capacity[('region1', 'solar')] <= solar_max, "SolarMaxConstraint"
99
+ model += renewable_capacity[('region1', 'onshore_wind')] >= wind_min, "WindMinConstraint"
100
+ model += renewable_capacity[('region1', 'onshore_wind')] <= wind_max, "WindMaxConstraint"
101
+
102
  model.solve()
103
 
 
104
  supply_solar = solar_cf * renewable_capacity[('region1', 'solar')].varValue
105
  supply_onshore_wind = onshore_wind_cf * renewable_capacity[('region1', 'onshore_wind')].varValue
106
  supply_offshore_wind = offshore_wind_cf * renewable_capacity[('region1', 'offshore_wind')].varValue
 
111
  SOC_values = [SOC[t].varValue for t in time_steps]
112
  curtailment_values = [-curtailment[(r, t)].varValue for r in regions for t in time_steps]
113
 
 
114
  price_per_hour = [100 + 0.05 * demand[t] for t in time_steps]
115
 
 
116
  max_SOC = max(SOC_values)
117
  SOC_normalized = [(soc / max_SOC) * 100 for soc in SOC_values] if max_SOC > 0 else [0] * len(SOC_values)
118
 
 
119
  fig_energy = go.Figure()
120
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_solar, mode='lines', stackgroup='one', name='Solar', line=dict(color='#FFD700', width=0)))
121
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_onshore_wind, mode='lines', stackgroup='one', name='Onshore Wind', line=dict(color='#1F78B4', width=0)))
 
126
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=-demand, mode='lines', stackgroup='two', name='Demand', line=dict(color='black', width=0)))
127
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=curtailment_values, mode='lines', stackgroup='two', name='Curtailment', line=dict(color='#aaaaaa', width=0)))
128
 
 
129
  fig_energy.update_layout(
130
  title_text='Power Supply and Demand',
131
  title_x=0.5,
 
138
  xaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray'),
139
  yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')
140
  )
141
+
142
+ # Heatmap generation for each renewable energy source
143
  heatmaps = []
144
  for energy_source in ['solar', 'onshore_wind', 'offshore_wind', 'river']:
145
  df_heatmap = data[['Time', f'{energy_source} hourly capacity factor']].copy()
146
+ df_heatmap['Time'] = pd.to_datetime(df_heatmap['Time'], errors='coerce')
147
  df_heatmap['day_of_year'] = df_heatmap['Time'].dt.dayofyear
148
  df_heatmap['hour_of_day'] = df_heatmap['Time'].dt.hour
149
+
 
150
  pivot_df = df_heatmap.pivot_table(
151
  index='hour_of_day',
152
  columns='day_of_year',
 
154
  aggfunc='mean'
155
  )
156
 
 
157
  fig_heatmap = px.imshow(
158
  pivot_df.values,
159
  labels=dict(x="Day of Year", y="Hour of Day", color=f"{energy_source.replace('_', ' ').title()} Capacity Factor"),
 
179
  st.set_page_config(page_title='Renewable Energy System Optimization', layout='wide')
180
  st.title('Renewable Energy System Optimization')
181
 
 
 
 
 
 
 
 
 
 
182
  with st.sidebar:
183
  st.header('Input Parameters')
184
  city_code = st.text_input("Enter City Code", value=999999)
185
+ solar_cost = st.number_input("Solar Capacity Cost (\u00a5/MW)", value=80.0)
186
+ onshore_wind_cost = st.number_input("Onshore Wind Capacity Cost (\u00a5/MW)", value=120.0)
187
+ offshore_wind_cost = st.number_input("Offshore Wind Capacity Cost (\u00a5/MW)", value=180.0)
188
+ river_cost = st.number_input("River Capacity Cost (\u00a5/MW)", value=1000.0)
189
+ battery_cost = st.number_input("Battery Cost (\u00a5/MWh)", value=80.0)
190
+ yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0)
191
+ solar_min = st.slider("Minimum Solar Capacity (MW)", 0, 10000, 0)
192
+ solar_max = st.slider("Maximum Solar Capacity (MW)", 0, 10000, 10000)
193
+ wind_min = st.slider("Minimum Onshore Wind Capacity (MW)", 0, 10000, 0)
194
+ wind_max = st.slider("Maximum Onshore Wind Capacity (MW)", 0, 10000, 10000)
195
+
196
  if st.button('Calculate Optimal Energy Mix'):
197
+ fig_energy, heatmaps, curtailment_values, price_per_hour = optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand, solar_min, solar_max, wind_min, wind_max)
198
 
199
  if fig_energy:
200
  st.plotly_chart(fig_energy, use_container_width=True, height=800)
 
214
  'Offshore Wind': offshore_wind_cost,
215
  'Run of River': river_cost
216
  }
217
+ cost_df = pd.DataFrame(list(renewable_data.items()), columns=['Technology', 'Cost (\u00a5/MW)'])
218
 
219
+ fig_cost = px.bar(cost_df, x='Technology', y='Cost (\u00a5/MW)', color='Technology', title='Cost Comparison of Different Renewable Technologies', template='plotly_white')
220
  st.plotly_chart(fig_cost, use_container_width=True, height=800)
221
 
222
  # Plot curtailment over time
 
225
  st.plotly_chart(fig_curtailment, use_container_width=True, height=800)
226
 
227
  # Plot electricity price variation over time
228
+ price_df = pd.DataFrame({"Time": fig_energy.data[0].x, "Electricity Price (\u00a5/MWh)": price_per_hour})
229
+ fig_price = px.line(price_df, x='Time', y='Electricity Price (\u00a5/MWh)', title='Electricity Price Variation Over Time', template='plotly_white')
230
+ st.plotly_chart(fig_price, use_container_width=True, height=800)