Spaces:
Runtime error
Runtime error
File size: 16,328 Bytes
784ba07 18b7c9d 784ba07 99662df 173cac5 784ba07 18b7c9d 7b3e296 173cac5 784ba07 7b3e296 784ba07 173cac5 784ba07 18b7c9d 7b3e296 6f04a37 784ba07 38191ba 784ba07 18b7c9d 784ba07 18b7c9d 784ba07 18b7c9d 784ba07 38191ba 7d659c6 784ba07 438ff43 784ba07 18b7c9d 04ffbd0 784ba07 18b7c9d 784ba07 438ff43 18b7c9d 784ba07 438ff43 18b7c9d 784ba07 18b7c9d 784ba07 438ff43 18b7c9d 438ff43 18b7c9d 438ff43 18b7c9d 438ff43 18b7c9d 7b3e296 18b7c9d |
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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
import streamlit as st
import requests
import pandas as pd
import pulp
import plotly.graph_objs as go
import plotly.express as px
import numpy as np
import json
# Function to fetch renewable energy data
def get_json():
"""
open data.json
"""
with open('data.json') as f:
data = json.load(f)
if not data:
return None, "No data found."
base_times = data[next(iter(data))]['x']
result_df = pd.DataFrame({"Time": base_times})
for energy_type, energy_data in data.items():
if 'x' in energy_data and 'y' in energy_data:
values = energy_data['y']
result_df[f"{energy_type} hourly capacity factor"] = values
return result_df
# Function to optimize the energy system and create visualizations
def optimize_energy_system(solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand, solar_range, wind_range, river_range, offshore_wind_range):
data = get_json()
for col in data.columns[1:]:
data[col] = pd.to_numeric(data[col], errors='coerce')
data = data.fillna(0)
time_steps = range(len(data['Time']))
solar_cf = data['solar hourly capacity factor']
onshore_wind_cf = data['onshore_wind hourly capacity factor']
offshore_wind_cf = data['offshore_wind hourly capacity factor']
river_cf = data['river hourly capacity factor']
demand_cf = data['demand hourly capacity factor']
regions = ['region1']
technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']
capacity_factor = {
'solar': solar_cf,
'onshore_wind': onshore_wind_cf,
'offshore_wind': offshore_wind_cf,
'river': river_cf
}
renewable_capacity_cost = {'solar': solar_cost, 'onshore_wind': onshore_wind_cost, 'offshore_wind': offshore_wind_cost, 'river': river_cost}
battery_cost_per_mwh = battery_cost
battery_efficiency = 0.9
demand = demand_cf * yearly_demand / 100 * 1000 * 1000
renewable_capacity = pulp.LpVariable.dicts("renewable_capacity",
[(r, g) for r in regions for g in technologies],
lowBound=0, cat='Continuous')
curtailment = pulp.LpVariable.dicts("curtailment",
[(r, t) for r in regions for t in time_steps],
lowBound=0, cat='Continuous')
battery_capacity = pulp.LpVariable("battery_capacity", lowBound=0, cat='Continuous')
battery_charge = pulp.LpVariable.dicts("battery_charge", time_steps, lowBound=0, cat='Continuous')
battery_discharge = pulp.LpVariable.dicts("battery_discharge", time_steps, lowBound=0, cat='Continuous')
SOC = pulp.LpVariable.dicts("SOC", time_steps, lowBound=0, cat='Continuous')
model = pulp.LpProblem("EnergySystemOptimizationWithBattery", pulp.LpMinimize)
model += pulp.lpSum([renewable_capacity[(r, g)] * renewable_capacity_cost[g]
for r in regions for g in technologies]) + \
battery_capacity * battery_cost_per_mwh, "TotalCost"
for r in regions:
for t in time_steps:
model += pulp.lpSum([renewable_capacity[(r, g)] * capacity_factor[g][t]
for g in technologies]) + battery_discharge[t] == demand[t] + battery_charge[t] + curtailment[(r, t)], f"DemandConstraint_{r}_{t}"
if t == 0:
model += SOC[t] == battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
else:
model += SOC[t] == SOC[t - 1] + battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"
model += SOC[t] <= battery_capacity, f"SOCUpperBound_{t}"
model += renewable_capacity[('region1', 'solar')] >= solar_range[0], "SolarMinConstraint"
model += renewable_capacity[('region1', 'solar')] <= solar_range[1], "SolarMaxConstraint"
model += renewable_capacity[('region1', 'onshore_wind')] >= wind_range[0], "WindMinConstraint"
model += renewable_capacity[('region1', 'onshore_wind')] <= wind_range[1], "WindMaxConstraint"
model += renewable_capacity[('region1', 'offshore_wind')] >= offshore_wind_range[0], "OffshoreWindMinConstraint"
model += renewable_capacity[('region1', 'offshore_wind')] <= offshore_wind_range[1], "OffshoreWindMaxConstraint"
model += renewable_capacity[('region1', 'river')] >= river_range[0], "RiverMinConstraint"
model += renewable_capacity[('region1', 'river')] <= river_range[1], "RiverMaxConstraint"
model.solve()
supply_solar = solar_cf * renewable_capacity[('region1', 'solar')].varValue
supply_onshore_wind = onshore_wind_cf * renewable_capacity[('region1', 'onshore_wind')].varValue
supply_offshore_wind = offshore_wind_cf * renewable_capacity[('region1', 'offshore_wind')].varValue
supply_river = river_cf * renewable_capacity[('region1', 'river')].varValue
battery_discharge_values = [battery_discharge[t].varValue for t in time_steps]
battery_charge_values = [-battery_charge[t].varValue for t in time_steps]
SOC_values = [SOC[t].varValue for t in time_steps]
curtailment_values = [-curtailment[(r, t)].varValue for r in regions for t in time_steps]
max_SOC = max(SOC_values)
SOC_normalized = [(soc / max_SOC) * 100 for soc in SOC_values] if max_SOC > 0 else [0] * len(SOC_values)
fig_energy = go.Figure()
fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_solar, mode='lines', stackgroup='one', name='Solar', line=dict(color='#FFD700', width=0)))
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)))
fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_offshore_wind, mode='lines', stackgroup='one', name='Offshore Wind', line=dict(color='#66C2A5', width=0)))
fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_river, mode='lines', stackgroup='one', name='Run of River', line=dict(color='#FF7F00', width=0)))
fig_energy.add_trace(go.Scatter(x=data['Time'], y=battery_discharge_values, mode='lines', stackgroup='one', name='Battery Discharge', fill='tonexty', line=dict(color='#6A3D9A', width=0)))
fig_energy.add_trace(go.Scatter(x=data['Time'], y=battery_charge_values, mode='lines', stackgroup='two', name='Battery Charge', fill='tonexty', line=dict(color='#6A3D9A', width=0)))
fig_energy.add_trace(go.Scatter(x=data['Time'], y=-demand, mode='lines', stackgroup='two', name='Demand', line=dict(color='black', width=0)))
fig_energy.add_trace(go.Scatter(x=data['Time'], y=curtailment_values, mode='lines', stackgroup='two', name='Curtailment', line=dict(color='#aaaaaa', width=0)))
fig_energy.update_layout(
title_text='Power Supply and Demand',
title_x=0.5,
yaxis_title='Power dispatch (MW)',
legend_title='Source',
font=dict(size=12),
margin=dict(l=40, r=40, t=40, b=40),
hovermode='x unified',
plot_bgcolor='white',
xaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray'),
yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')
)
# Heatmap generation for each renewable energy source
heatmaps = []
for energy_source in ['solar', 'onshore_wind', 'offshore_wind', 'river']:
df_heatmap = data[['Time', f'{energy_source} hourly capacity factor']].copy()
df_heatmap['Time'] = pd.to_datetime(df_heatmap['Time'], errors='coerce')
df_heatmap['day_of_year'] = df_heatmap['Time'].dt.dayofyear
df_heatmap['hour_of_day'] = df_heatmap['Time'].dt.hour
pivot_df = df_heatmap.pivot_table(
index='hour_of_day',
columns='day_of_year',
values=f'{energy_source} hourly capacity factor',
aggfunc='mean'
)
fig_heatmap = px.imshow(
pivot_df.values,
labels=dict(x="Day of Year", y="Hour of Day", color=f"{energy_source.replace('_', ' ').title()} Capacity Factor"),
x=pivot_df.columns,
y=pivot_df.index,
aspect="auto",
color_continuous_scale='Plasma'
)
fig_heatmap.update_layout(
title=f'{energy_source.replace("_", " ").title()} Hourly Capacity Factor (24 Hours x 365 Days)',
xaxis_title='Day of Year',
yaxis_title='Hour of Day',
font=dict(size=12),
plot_bgcolor='white',
margin=dict(l=40, r=40, t=40, b=40),
)
heatmaps.append(fig_heatmap)
# Create capacity range visualization for each technology
fig_capacity_ranges = go.Figure()
technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']
capacity_ranges = [solar_range, wind_range, offshore_wind_range, river_range]
optimized_capacities = [
renewable_capacity[('region1', 'solar')].varValue,
renewable_capacity[('region1', 'onshore_wind')].varValue,
renewable_capacity[('region1', 'offshore_wind')].varValue,
renewable_capacity[('region1', 'river')].varValue
]
for tech, cap_range, optimized_cap in zip(technologies, capacity_ranges, optimized_capacities):
fig_capacity_ranges.add_trace(go.Scatter(
x=[tech, tech],
y=cap_range,
mode='lines',
name=f'{tech} capacity range',
line=dict(color='blue', width=4)
))
fig_capacity_ranges.add_trace(go.Scatter(
x=[tech],
y=[optimized_cap],
mode='markers',
name=f'{tech} optimized capacity',
marker=dict(color='red', symbol='x', size=10)
))
fig_capacity_ranges.update_layout(
title_text='Optimized Capacity vs. Capacity Ranges',
title_x=0.5,
yaxis_title='Capacity (MW)',
xaxis_title='Technology',
font=dict(size=12),
margin=dict(l=40, r=40, t=40, b=40),
hovermode='x unified',
plot_bgcolor='white',
xaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray'),
yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')
)
return fig_energy, heatmaps, curtailment_values, SOC_normalized, fig_capacity_ranges, renewable_capacity
# 資源コストの感度解析を行う関数
def analyze_cost_sensitivity(renewable_capacity_cost, technologies, renewable_capacity):
# コストの変動範囲(0.5倍から1.5倍)
cost_multipliers = np.linspace(0.5, 1.5, 11)
# 結果を格納する辞書
sensitivity_results = {}
for tech in technologies:
# 各技術ごとのコスト変動に対する総コストの変化を計算
original_cost = renewable_capacity_cost[tech]
total_costs = []
for multiplier in cost_multipliers:
# コストを変更
modified_cost = original_cost * multiplier
# 総コスト = 変更後のコスト * 設備容量
total_cost = modified_cost * renewable_capacity[('region1', tech)].varValue
total_costs.append(total_cost)
# 技術ごとに結果を保存
sensitivity_results[tech] = total_costs
# 可視化
fig = go.Figure()
for tech, total_costs in sensitivity_results.items():
fig.add_trace(go.Scatter(
x=cost_multipliers,
y=total_costs,
mode='lines+markers',
name=f'{tech} Cost Sensitivity'
))
# グラフのレイアウト
fig.update_layout(
title='Cost Sensitivity Analysis: Impact of Cost Changes on Total System Cost',
xaxis_title='Cost Multiplier (0.5x to 1.5x)',
yaxis_title='Total System Cost (¥)',
hovermode='x unified',
plot_bgcolor='white',
xaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray'),
yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')
)
return fig
# Streamlit UI setup
st.set_page_config(page_title='Renewable Energy System Optimization', layout='wide')
st.title('Renewable Energy System Optimization')
st.markdown("""
### Model Overview
This application is designed to optimize renewable energy systems for a specific region. The model allows the user to set the costs for different renewable energy technologies and battery storage, as well as minimum and maximum capacity limits for each technology. The optimization uses linear programming to minimize the total cost while ensuring demand is met, incorporating energy storage to help manage intermittency.
The renewable technologies considered are:
- Solar PV
- Onshore Wind
- Offshore Wind
- Run of River (Hydro)
The optimization problem aims to balance supply and demand at minimal cost, while also providing flexibility in the form of battery energy storage. Curtailment and battery state of charge are also considered in the model.
""")
with st.sidebar:
st.header('Input Parameters')
solar_cost = st.number_input("Solar Capacity Cost (¥/MW)", value=80.0)
onshore_wind_cost = st.number_input("Onshore Wind Capacity Cost (¥/MW)", value=120.0)
offshore_wind_cost = st.number_input("Offshore Wind Capacity Cost (¥/MW)", value=180.0)
river_cost = st.number_input("River Capacity Cost (¥/MW)", value=1000.0)
battery_cost = st.number_input("Battery Cost (¥/MWh)", value=80.0)
yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0)
solar_range = st.slider("Solar Capacity Range (MW)", 0, 10000, (0, 10000))
wind_range = st.slider("Onshore Wind Capacity Range (MW)", 0, 10000, (0, 10000))
offshore_wind_range = st.slider("Offshore Wind Capacity Range (MW)", 0, 10000, (0, 10000))
river_range = st.slider("River Capacity Range (MW)", 0, 10000, (0, 10000))
calculated_optimal_energy_mix = False
if st.button('Calculate Optimal Energy Mix'):
fig_energy, heatmaps, curtailment_values, soc_per_hour, fig_capacity_ranges, renewable_capacity = optimize_energy_system(
solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand, solar_range, wind_range, river_range, offshore_wind_range
)
if fig_energy:
st.plotly_chart(fig_energy, use_container_width=True, height=800)
# Additional visualizations
st.markdown("### Hourly Capacity Factor Heatmaps")
for fig_heatmap in heatmaps:
st.plotly_chart(fig_heatmap, use_container_width=True, height=800)
st.markdown("### Additional Analysis")
st.markdown("The following plots provide additional insights into the renewable energy mix, curtailment, and electricity price variations.")
# Plot curtailment over time
curtailment_df = pd.DataFrame({"Time": fig_energy.data[0].x, "Curtailment (MW)": curtailment_values})
fig_curtailment = px.line(curtailment_df, x='Time', y='Curtailment (MW)', title='Curtailment Over Time', template='plotly_white')
st.plotly_chart(fig_curtailment, use_container_width=True, height=800)
# Plot electricity price variation over time
soc_df = pd.DataFrame({"Time": fig_energy.data[0].x, "State of charge [%]": soc_per_hour})
fig_battery_operation = px.line(soc_df, x='Time', y='State of charge [%]', title='State of charge in battery', template='plotly_white')
st.plotly_chart(fig_battery_operation, use_container_width=True, height=800)
# Plot optimized capacity vs. capacity ranges
st.plotly_chart(fig_capacity_ranges, use_container_width=True, height=800)
calculated_optimal_energy_mix = True
# Streamlit UIに感度解析ボタンを追加
if st.button('Analyze Cost Sensitivity'):
if calculated_optimal_energy_mix:
fig_sensitivity = analyze_cost_sensitivity({
'solar': solar_cost,
'onshore_wind': onshore_wind_cost,
'offshore_wind': offshore_wind_cost,
'river': river_cost
}, ['solar', 'onshore_wind', 'offshore_wind', 'river'], renewable_capacity)
st.plotly_chart(fig_sensitivity, use_container_width=True, height=800)
else:
st.error("Please calculate the optimal energy mix first before running the cost sensitivity analysis.") |