Spaces:
Runtime error
Runtime error
Update app.py
Browse files
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
#
|
| 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')
|
| 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 (
|
| 222 |
-
onshore_wind_cost = st.number_input("Onshore Wind Capacity Cost (
|
| 223 |
-
offshore_wind_cost = st.number_input("Offshore Wind Capacity Cost (
|
| 224 |
-
river_cost = st.number_input("River Capacity Cost (
|
| 225 |
-
battery_cost = st.number_input("Battery Cost (
|
| 226 |
-
yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0
|
| 227 |
-
|
| 228 |
-
|
|
|
|
|
|
|
|
|
|
| 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 (
|
| 251 |
|
| 252 |
-
fig_cost = px.bar(cost_df, x='Technology', y='Cost (
|
| 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 (
|
| 262 |
-
fig_price = px.line(price_df, x='Time', y='Electricity Price (
|
| 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)
|