naohiro701 commited on
Commit
2b5e2ba
·
verified ·
1 Parent(s): 38191ba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -2
app.py CHANGED
@@ -11,18 +11,23 @@ import numpy as np
11
 
12
  # Function to fetch renewable energy data
13
  def get_renewable_energy_data(city_code):
 
14
  url = f"https://energy-sustainability.jp/_ajax/renewable_energy/get/?code={city_code}"
15
  response = requests.get(url)
 
16
  if response.status_code != 200:
17
  return None, "データの取得に失敗しました。"
18
 
19
  data = response.json()
 
20
  if not data:
21
  return None, "データが見つかりませんでした。"
22
 
 
23
  base_times = data[next(iter(data))]['x']
24
  result_df = pd.DataFrame({"Time": base_times})
25
 
 
26
  for energy_type, energy_data in data.items():
27
  if 'x' in energy_data and 'y' in energy_data:
28
  values = energy_data['y']
@@ -32,21 +37,24 @@ def get_renewable_energy_data(city_code):
32
 
33
  # Function to filter numeric columns
34
  def filter_numeric_columns(df):
 
35
  numeric_df = df.select_dtypes(include=['number'])
36
  return numeric_df
37
 
38
  # Function to optimize the energy system
39
  def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand):
 
40
  data, error = get_renewable_energy_data(city_code)
41
  if error:
42
  st.error(error)
43
  return None, None, None
44
 
 
45
  for col in data.columns[1:]:
46
  data[col] = pd.to_numeric(data[col], errors='coerce')
47
-
48
  data = data.fillna(0)
49
 
 
50
  time_steps = range(len(data['Time']))
51
  solar_cf = data['solar hourly capacity factor']
52
  onshore_wind_cf = data['onshore_wind hourly capacity factor']
@@ -54,6 +62,7 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
54
  river_cf = data['river hourly capacity factor']
55
  demand_cf = data['demand hourly capacity factor']
56
 
 
57
  regions = ['region1']
58
  technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']
59
  capacity_factor = {
@@ -63,12 +72,15 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
63
  'river': river_cf
64
  }
65
 
 
66
  renewable_capacity_cost = {'solar': solar_cost, 'onshore_wind': onshore_wind_cost, 'offshore_wind': offshore_wind_cost, 'river': river_cost}
67
  battery_cost_per_mwh = battery_cost
68
  battery_efficiency = 0.9
69
 
 
70
  demand = demand_cf * yearly_demand / 100 * 1000 * 1000
71
 
 
72
  renewable_capacity = pulp.LpVariable.dicts("renewable_capacity",
73
  [(r, g) for r in regions for g in technologies],
74
  lowBound=0, cat='Continuous')
@@ -80,26 +92,34 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
80
  battery_discharge = pulp.LpVariable.dicts("battery_discharge", time_steps, lowBound=0, cat='Continuous')
81
  SOC = pulp.LpVariable.dicts("SOC", time_steps, lowBound=0, cat='Continuous')
82
 
 
83
  model = pulp.LpProblem("EnergySystemOptimizationWithBattery", pulp.LpMinimize)
84
 
 
85
  model += pulp.lpSum([renewable_capacity[(r, g)] * renewable_capacity_cost[g]
86
  for r in regions for g in technologies]) + \
87
  battery_capacity * battery_cost_per_mwh, "TotalCost"
88
 
 
89
  for r in regions:
90
  for t in time_steps:
 
91
  model += pulp.lpSum([renewable_capacity[(r, g)] * capacity_factor[g][t]
92
  for g in technologies]) + battery_discharge[t] == demand[t] + battery_charge[t] + curtailment[(r,t)], f"DemandConstraint_{r}_{t}"
93
 
 
94
  if t == 0:
95
  model += SOC[t] == battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
96
  else:
97
  model += SOC[t] == SOC[t-1] + battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
98
 
 
99
  model += SOC[t] <= battery_capacity, f"SOCUpperBound_{t}"
100
 
 
101
  model.solve()
102
 
 
103
  supply_solar = solar_cf * renewable_capacity[('region1', 'solar')].varValue
104
  supply_onshore_wind = onshore_wind_cf * renewable_capacity[('region1', 'onshore_wind')].varValue
105
  supply_offshore_wind = offshore_wind_cf * renewable_capacity[('region1', 'offshore_wind')].varValue
@@ -110,11 +130,14 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
110
  SOC_values = [SOC[t].varValue for t in time_steps]
111
  curtailment_values = [curtailment[(r, t)].varValue for r in regions for t in time_steps]
112
 
 
113
  price_per_hour = [100 + 0.05 * demand[t] for t in time_steps]
114
 
 
115
  max_SOC = max(SOC_values)
116
  SOC_normalized = [(soc / max_SOC) * 100 for soc in SOC_values] if max_SOC > 0 else [0] * len(SOC_values)
117
 
 
118
  fig_energy = go.Figure()
119
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_solar, mode='lines', stackgroup='one', name='Solar', line=dict(color='#FFD700', width=0)))
120
  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)))
@@ -125,6 +148,7 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
125
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=-demand, mode='lines', stackgroup='two', name='Demand', line=dict(color='black', width=0)))
126
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=curtailment_values, mode='lines', stackgroup='two', name='Curtailment', line=dict(color='#aaaaaa', width=0)))
127
 
 
128
  fig_energy.update_layout(
129
  title_text='Power Supply and Demand',
130
  title_x=0.5,
@@ -140,9 +164,11 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
140
 
141
  return fig_energy, curtailment_values, price_per_hour
142
 
 
143
  st.set_page_config(page_title='Renewable Energy System Optimization', layout='wide')
144
  st.title('Renewable Energy System Optimization')
145
 
 
146
  st.markdown("""
147
  ### Overview
148
  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.
@@ -150,6 +176,7 @@ The optimization problem is solved using linear programming, ensuring a balance
150
  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.
151
  """)
152
 
 
153
  with st.sidebar:
154
  st.header('Input Parameters')
155
  city_code = st.text_input("Enter City Code", value="")
@@ -160,14 +187,17 @@ with st.sidebar:
160
  battery_cost = st.number_input("Battery Cost (¥/MWh)", value=80.0, help="Estimated average cost of battery storage per MWh")
161
  yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0, help="Total yearly power demand in TWh")
162
 
 
163
  if st.button('Calculate Optimal Energy Mix'):
164
  fig, curtailment_values, price_per_hour = optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand)
165
  if fig:
166
  st.plotly_chart(fig, use_container_width=True, height=800)
167
 
 
168
  st.markdown("### Additional Analysis")
169
  st.markdown("The following plots provide additional insights into the renewable energy mix, curtailment, and electricity price variations.")
170
 
 
171
  renewable_data = {
172
  'Solar': solar_cost,
173
  'Onshore Wind': onshore_wind_cost,
@@ -179,14 +209,17 @@ if st.button('Calculate Optimal Energy Mix'):
179
  fig_cost = px.bar(cost_df, x='Technology', y='Cost (¥/MW)', color='Technology', title='Cost Comparison of Different Renewable Technologies', template='plotly_white')
180
  st.plotly_chart(fig_cost, use_container_width=True, height=800)
181
 
 
182
  curtailment_df = pd.DataFrame({"Time": fig.data[0].x, "Curtailment (MW)": curtailment_values})
183
  fig_curtailment = px.line(curtailment_df, x='Time', y='Curtailment (MW)', title='Curtailment Over Time', template='plotly_white')
184
  st.plotly_chart(fig_curtailment, use_container_width=True, height=800)
185
 
 
186
  price_df = pd.DataFrame({"Time": fig.data[0].x, "Electricity Price (¥/MWh)": price_per_hour})
187
  fig_price = px.line(price_df, x='Time', y='Electricity Price (¥/MWh)', title='Electricity Price Variation Over Time', template='plotly_white')
188
  st.plotly_chart(fig_price, use_container_width=True, height=800)
189
 
 
190
  if city_code:
191
  st.markdown("### Correlation Between Renewable Energy Sources")
192
  energy_data_df, error = get_renewable_energy_data(city_code)
@@ -203,9 +236,10 @@ if st.button('Calculate Optimal Energy Mix'):
203
  fig_corr = px.imshow(correlation_matrix, title='Correlation Matrix of Renewable Capacity Factors', labels={'color': 'Correlation'}, template='plotly_white')
204
  st.plotly_chart(fig_corr, use_container_width=True, height=800)
205
 
 
206
  st.markdown("### Heatmap of Renewable Energy and Demand Characteristics")
207
  hourly_data = numeric_energy_data_df.copy()
208
- hourly_data['Time'] = pd.to_datetime(data['Time'], errors='coerce')
209
  hourly_data['Date'] = hourly_data['Time'].dt.date
210
  hourly_data['Hour'] = hourly_data['Time'].dt.hour
211
 
 
11
 
12
  # Function to fetch renewable energy data
13
  def get_renewable_energy_data(city_code):
14
+ # Construct the URL for fetching renewable energy data for a given city code
15
  url = f"https://energy-sustainability.jp/_ajax/renewable_energy/get/?code={city_code}"
16
  response = requests.get(url)
17
+ # If the request is unsuccessful, return an error message
18
  if response.status_code != 200:
19
  return None, "データの取得に失敗しました。"
20
 
21
  data = response.json()
22
+ # If no data is found, return an error message
23
  if not data:
24
  return None, "データが見つかりませんでした。"
25
 
26
+ # Extract base times from the first energy type and create a DataFrame
27
  base_times = data[next(iter(data))]['x']
28
  result_df = pd.DataFrame({"Time": base_times})
29
 
30
+ # Loop through each energy type and append hourly capacity factor data to the DataFrame
31
  for energy_type, energy_data in data.items():
32
  if 'x' in energy_data and 'y' in energy_data:
33
  values = energy_data['y']
 
37
 
38
  # Function to filter numeric columns
39
  def filter_numeric_columns(df):
40
+ # Select only numeric columns from the DataFrame
41
  numeric_df = df.select_dtypes(include=['number'])
42
  return numeric_df
43
 
44
  # Function to optimize the energy system
45
  def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand):
46
+ # Fetch renewable energy data
47
  data, error = get_renewable_energy_data(city_code)
48
  if error:
49
  st.error(error)
50
  return None, None, None
51
 
52
+ # Convert all capacity factor columns to numeric, handling errors and filling missing values with zero
53
  for col in data.columns[1:]:
54
  data[col] = pd.to_numeric(data[col], errors='coerce')
 
55
  data = data.fillna(0)
56
 
57
+ # Define the time steps based on the length of the data
58
  time_steps = range(len(data['Time']))
59
  solar_cf = data['solar hourly capacity factor']
60
  onshore_wind_cf = data['onshore_wind hourly capacity factor']
 
62
  river_cf = data['river hourly capacity factor']
63
  demand_cf = data['demand hourly capacity factor']
64
 
65
+ # Define regions and technologies
66
  regions = ['region1']
67
  technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']
68
  capacity_factor = {
 
72
  'river': river_cf
73
  }
74
 
75
+ # Define the costs for each renewable capacity and battery storage
76
  renewable_capacity_cost = {'solar': solar_cost, 'onshore_wind': onshore_wind_cost, 'offshore_wind': offshore_wind_cost, 'river': river_cost}
77
  battery_cost_per_mwh = battery_cost
78
  battery_efficiency = 0.9
79
 
80
+ # Scale demand from yearly demand in TWh/year to hourly demand in MW
81
  demand = demand_cf * yearly_demand / 100 * 1000 * 1000
82
 
83
+ # Define LP variables for renewable capacities, curtailment, battery capacity, charge, discharge, and state of charge (SOC)
84
  renewable_capacity = pulp.LpVariable.dicts("renewable_capacity",
85
  [(r, g) for r in regions for g in technologies],
86
  lowBound=0, cat='Continuous')
 
92
  battery_discharge = pulp.LpVariable.dicts("battery_discharge", time_steps, lowBound=0, cat='Continuous')
93
  SOC = pulp.LpVariable.dicts("SOC", time_steps, lowBound=0, cat='Continuous')
94
 
95
+ # Define the optimization problem to minimize the total system cost
96
  model = pulp.LpProblem("EnergySystemOptimizationWithBattery", pulp.LpMinimize)
97
 
98
+ # Objective function: minimize the cost of renewable capacities and battery storage
99
  model += pulp.lpSum([renewable_capacity[(r, g)] * renewable_capacity_cost[g]
100
  for r in regions for g in technologies]) + \
101
  battery_capacity * battery_cost_per_mwh, "TotalCost"
102
 
103
+ # Constraints to meet demand, manage curtailment, and update state of charge for the battery
104
  for r in regions:
105
  for t in time_steps:
106
+ # Ensure that generation plus battery discharge meets demand, accounting for curtailment and battery charge
107
  model += pulp.lpSum([renewable_capacity[(r, g)] * capacity_factor[g][t]
108
  for g in technologies]) + battery_discharge[t] == demand[t] + battery_charge[t] + curtailment[(r,t)], f"DemandConstraint_{r}_{t}"
109
 
110
+ # Update state of charge for the battery
111
  if t == 0:
112
  model += SOC[t] == battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
113
  else:
114
  model += SOC[t] == SOC[t-1] + battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
115
 
116
+ # Ensure SOC does not exceed battery capacity
117
  model += SOC[t] <= battery_capacity, f"SOCUpperBound_{t}"
118
 
119
+ # Solve the optimization model
120
  model.solve()
121
 
122
+ # Extract optimized supply and battery values
123
  supply_solar = solar_cf * renewable_capacity[('region1', 'solar')].varValue
124
  supply_onshore_wind = onshore_wind_cf * renewable_capacity[('region1', 'onshore_wind')].varValue
125
  supply_offshore_wind = offshore_wind_cf * renewable_capacity[('region1', 'offshore_wind')].varValue
 
130
  SOC_values = [SOC[t].varValue for t in time_steps]
131
  curtailment_values = [curtailment[(r, t)].varValue for r in regions for t in time_steps]
132
 
133
+ # Calculate price per hour based on demand and generation (simplified example)
134
  price_per_hour = [100 + 0.05 * demand[t] for t in time_steps]
135
 
136
+ # Normalize state of charge (SOC) to a percentage
137
  max_SOC = max(SOC_values)
138
  SOC_normalized = [(soc / max_SOC) * 100 for soc in SOC_values] if max_SOC > 0 else [0] * len(SOC_values)
139
 
140
+ # Create plot for energy dispatch
141
  fig_energy = go.Figure()
142
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_solar, mode='lines', stackgroup='one', name='Solar', line=dict(color='#FFD700', width=0)))
143
  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)))
 
148
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=-demand, mode='lines', stackgroup='two', name='Demand', line=dict(color='black', width=0)))
149
  fig_energy.add_trace(go.Scatter(x=data['Time'], y=curtailment_values, mode='lines', stackgroup='two', name='Curtailment', line=dict(color='#aaaaaa', width=0)))
150
 
151
+ # Layout settings for energy dispatch plot
152
  fig_energy.update_layout(
153
  title_text='Power Supply and Demand',
154
  title_x=0.5,
 
164
 
165
  return fig_energy, curtailment_values, price_per_hour
166
 
167
+ # Streamlit UI setup
168
  st.set_page_config(page_title='Renewable Energy System Optimization', layout='wide')
169
  st.title('Renewable Energy System Optimization')
170
 
171
+ # Overview section explaining the project
172
  st.markdown("""
173
  ### Overview
174
  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.
 
176
  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.
177
  """)
178
 
179
+ # Sidebar input fields for user to provide parameters
180
  with st.sidebar:
181
  st.header('Input Parameters')
182
  city_code = st.text_input("Enter City Code", value="")
 
187
  battery_cost = st.number_input("Battery Cost (¥/MWh)", value=80.0, help="Estimated average cost of battery storage per MWh")
188
  yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0, help="Total yearly power demand in TWh")
189
 
190
+ # Button to trigger optimization
191
  if st.button('Calculate Optimal Energy Mix'):
192
  fig, curtailment_values, price_per_hour = optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand)
193
  if fig:
194
  st.plotly_chart(fig, use_container_width=True, height=800)
195
 
196
+ # Additional analysis and visualizations
197
  st.markdown("### Additional Analysis")
198
  st.markdown("The following plots provide additional insights into the renewable energy mix, curtailment, and electricity price variations.")
199
 
200
+ # Plot cost comparison of different renewable technologies
201
  renewable_data = {
202
  'Solar': solar_cost,
203
  'Onshore Wind': onshore_wind_cost,
 
209
  fig_cost = px.bar(cost_df, x='Technology', y='Cost (¥/MW)', color='Technology', title='Cost Comparison of Different Renewable Technologies', template='plotly_white')
210
  st.plotly_chart(fig_cost, use_container_width=True, height=800)
211
 
212
+ # Plot curtailment over time
213
  curtailment_df = pd.DataFrame({"Time": fig.data[0].x, "Curtailment (MW)": curtailment_values})
214
  fig_curtailment = px.line(curtailment_df, x='Time', y='Curtailment (MW)', title='Curtailment Over Time', template='plotly_white')
215
  st.plotly_chart(fig_curtailment, use_container_width=True, height=800)
216
 
217
+ # Plot electricity price variation over time
218
  price_df = pd.DataFrame({"Time": fig.data[0].x, "Electricity Price (¥/MWh)": price_per_hour})
219
  fig_price = px.line(price_df, x='Time', y='Electricity Price (¥/MWh)', title='Electricity Price Variation Over Time', template='plotly_white')
220
  st.plotly_chart(fig_price, use_container_width=True, height=800)
221
 
222
+ # Correlation analysis between renewable energy sources
223
  if city_code:
224
  st.markdown("### Correlation Between Renewable Energy Sources")
225
  energy_data_df, error = get_renewable_energy_data(city_code)
 
236
  fig_corr = px.imshow(correlation_matrix, title='Correlation Matrix of Renewable Capacity Factors', labels={'color': 'Correlation'}, template='plotly_white')
237
  st.plotly_chart(fig_corr, use_container_width=True, height=800)
238
 
239
+ # Heatmap of renewable energy and demand characteristics
240
  st.markdown("### Heatmap of Renewable Energy and Demand Characteristics")
241
  hourly_data = numeric_energy_data_df.copy()
242
+ hourly_data['Time'] = pd.to_datetime(energy_data_df['Time'], errors='coerce')
243
  hourly_data['Date'] = hourly_data['Time'].dt.date
244
  hourly_data['Hour'] = hourly_data['Time'].dt.hour
245