CoolFace
Apppublic

naohiro701/ToyModel-EnergySystemOptimizations

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
app.py331 linesDownload Raw Back to root
1import streamlit as st2import requests3import pandas as pd4import pulp5import plotly.graph_objs as go6import plotly.express as px7import numpy as np8import json9 10# Function to fetch renewable energy data11def get_json():12    """13    open data.json14    """15    with open('data.json') as f:16        data = json.load(f)17    if not data:18        return None, "No data found."19 20    base_times = data[next(iter(data))]['x']21    result_df = pd.DataFrame({"Time": base_times})22 23    for energy_type, energy_data in data.items():24        if 'x' in energy_data and 'y' in energy_data:25            values = energy_data['y']26            result_df[f"{energy_type} hourly capacity factor"] = values27 28    return result_df29 30# Function to optimize the energy system and create visualizations31def 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):32    data = get_json()33 34    for col in data.columns[1:]:35        data[col] = pd.to_numeric(data[col], errors='coerce')36    data = data.fillna(0)37 38    time_steps = range(len(data['Time']))39    solar_cf = data['solar hourly capacity factor']40    onshore_wind_cf = data['onshore_wind hourly capacity factor']41    offshore_wind_cf = data['offshore_wind hourly capacity factor']42    river_cf = data['river hourly capacity factor']43    demand_cf = data['demand hourly capacity factor']44 45    regions = ['region1']46    technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']47    capacity_factor = {48        'solar': solar_cf,49        'onshore_wind': onshore_wind_cf,50        'offshore_wind': offshore_wind_cf,51        'river': river_cf52    }53 54    renewable_capacity_cost = {'solar': solar_cost, 'onshore_wind': onshore_wind_cost, 'offshore_wind': offshore_wind_cost, 'river': river_cost}55    battery_cost_per_mwh = battery_cost56    battery_efficiency = 0.957 58    demand = demand_cf * yearly_demand / 100 * 1000 * 100059 60    renewable_capacity = pulp.LpVariable.dicts("renewable_capacity",61                                               [(r, g) for r in regions for g in technologies],62                                               lowBound=0, cat='Continuous')63    curtailment = pulp.LpVariable.dicts("curtailment",64                                        [(r, t) for r in regions for t in time_steps],65                                        lowBound=0, cat='Continuous')66    battery_capacity = pulp.LpVariable("battery_capacity", lowBound=0, cat='Continuous')67    battery_charge = pulp.LpVariable.dicts("battery_charge", time_steps, lowBound=0, cat='Continuous')68    battery_discharge = pulp.LpVariable.dicts("battery_discharge", time_steps, lowBound=0, cat='Continuous')69    SOC = pulp.LpVariable.dicts("SOC", time_steps, lowBound=0, cat='Continuous')70 71    model = pulp.LpProblem("EnergySystemOptimizationWithBattery", pulp.LpMinimize)72 73    model += pulp.lpSum([renewable_capacity[(r, g)] * renewable_capacity_cost[g]74                         for r in regions for g in technologies]) + \75             battery_capacity * battery_cost_per_mwh, "TotalCost"76 77    for r in regions:78        for t in time_steps:79            model += pulp.lpSum([renewable_capacity[(r, g)] * capacity_factor[g][t]80                                 for g in technologies]) + battery_discharge[t] == demand[t] + battery_charge[t] + curtailment[(r, t)], f"DemandConstraint_{r}_{t}"81 82            if t == 0:83                model += SOC[t] == battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"84            else:85                model += SOC[t] == SOC[t - 1] + battery_charge[t] * battery_efficiency - battery_discharge[t] * (1 / battery_efficiency), f"SOCUpdate_{t}"86 87            model += SOC[t] <= battery_capacity, f"SOCUpperBound_{t}"88 89    model += renewable_capacity[('region1', 'solar')] >= solar_range[0], "SolarMinConstraint"90    model += renewable_capacity[('region1', 'solar')] <= solar_range[1], "SolarMaxConstraint"91    model += renewable_capacity[('region1', 'onshore_wind')] >= wind_range[0], "WindMinConstraint"92    model += renewable_capacity[('region1', 'onshore_wind')] <= wind_range[1], "WindMaxConstraint"93    model += renewable_capacity[('region1', 'offshore_wind')] >= offshore_wind_range[0], "OffshoreWindMinConstraint"94    model += renewable_capacity[('region1', 'offshore_wind')] <= offshore_wind_range[1], "OffshoreWindMaxConstraint"95    model += renewable_capacity[('region1', 'river')] >= river_range[0], "RiverMinConstraint"96    model += renewable_capacity[('region1', 'river')] <= river_range[1], "RiverMaxConstraint"97 98    model.solve()99 100    supply_solar = solar_cf * renewable_capacity[('region1', 'solar')].varValue101    supply_onshore_wind = onshore_wind_cf * renewable_capacity[('region1', 'onshore_wind')].varValue102    supply_offshore_wind = offshore_wind_cf * renewable_capacity[('region1', 'offshore_wind')].varValue103    supply_river = river_cf * renewable_capacity[('region1', 'river')].varValue104 105    battery_discharge_values = [battery_discharge[t].varValue for t in time_steps]106    battery_charge_values = [-battery_charge[t].varValue for t in time_steps]107    SOC_values = [SOC[t].varValue for t in time_steps]108    curtailment_values = [-curtailment[(r, t)].varValue for r in regions for t in time_steps]109 110    max_SOC = max(SOC_values)111    SOC_normalized = [(soc / max_SOC) * 100 for soc in SOC_values] if max_SOC > 0 else [0] * len(SOC_values)112 113    fig_energy = go.Figure()114    fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_solar, mode='lines', stackgroup='one', name='Solar', line=dict(color='#FFD700', width=0)))115    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)))116    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)))117    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)))118    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)))119    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)))120    fig_energy.add_trace(go.Scatter(x=data['Time'], y=-demand, mode='lines', stackgroup='two', name='Demand', line=dict(color='black', width=0)))121    fig_energy.add_trace(go.Scatter(x=data['Time'], y=curtailment_values, mode='lines', stackgroup='two', name='Curtailment', line=dict(color='#aaaaaa', width=0)))122    123    fig_energy.update_layout(124        title_text='Power Supply and Demand',125        title_x=0.5,126        yaxis_title='Power dispatch (MW)',127        legend_title='Source',128        font=dict(size=12),129        margin=dict(l=40, r=40, t=40, b=40),130        hovermode='x unified',131        plot_bgcolor='white',132        xaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray'),133        yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')134    )135 136    # Heatmap generation for each renewable energy source137    heatmaps = []138    for energy_source in ['solar', 'onshore_wind', 'offshore_wind', 'river']:139        df_heatmap = data[['Time', f'{energy_source} hourly capacity factor']].copy()140        df_heatmap['Time'] = pd.to_datetime(df_heatmap['Time'], errors='coerce')141        df_heatmap['day_of_year'] = df_heatmap['Time'].dt.dayofyear142        df_heatmap['hour_of_day'] = df_heatmap['Time'].dt.hour143 144        pivot_df = df_heatmap.pivot_table(145            index='hour_of_day',146            columns='day_of_year',147            values=f'{energy_source} hourly capacity factor',148            aggfunc='mean'149        )150 151        fig_heatmap = px.imshow(152            pivot_df.values,153            labels=dict(x="Day of Year", y="Hour of Day", color=f"{energy_source.replace('_', ' ').title()} Capacity Factor"),154            x=pivot_df.columns,155            y=pivot_df.index,156            aspect="auto",157            color_continuous_scale='Plasma'158        )159 160        fig_heatmap.update_layout(161            title=f'{energy_source.replace("_", " ").title()} Hourly Capacity Factor (24 Hours x 365 Days)',162            xaxis_title='Day of Year',163            yaxis_title='Hour of Day',164            font=dict(size=12),165            plot_bgcolor='white',166            margin=dict(l=40, r=40, t=40, b=40),167        )168        heatmaps.append(fig_heatmap)169 170    # Create capacity range visualization for each technology171    fig_capacity_ranges = go.Figure()172    technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']173    capacity_ranges = [solar_range, wind_range, offshore_wind_range, river_range]174    optimized_capacities = [175        renewable_capacity[('region1', 'solar')].varValue,176        renewable_capacity[('region1', 'onshore_wind')].varValue,177        renewable_capacity[('region1', 'offshore_wind')].varValue,178        renewable_capacity[('region1', 'river')].varValue179    ]180 181    for tech, cap_range, optimized_cap in zip(technologies, capacity_ranges, optimized_capacities):182        fig_capacity_ranges.add_trace(go.Scatter(183            x=[tech, tech],184            y=cap_range,185            mode='lines',186            name=f'{tech} capacity range',187            line=dict(color='blue', width=4)188        ))189        fig_capacity_ranges.add_trace(go.Scatter(190            x=[tech],191            y=[optimized_cap],192            mode='markers',193            name=f'{tech} optimized capacity',194            marker=dict(color='red', symbol='x', size=10)195        ))196 197    fig_capacity_ranges.update_layout(198        title_text='Optimized Capacity vs. Capacity Ranges',199        title_x=0.5,200        yaxis_title='Capacity (MW)',201        xaxis_title='Technology',202        font=dict(size=12),203        margin=dict(l=40, r=40, t=40, b=40),204        hovermode='x unified',205        plot_bgcolor='white',206        xaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray'),207        yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')208    )209 210    return fig_energy, heatmaps, curtailment_values, SOC_normalized, fig_capacity_ranges, renewable_capacity211 212# 資源コストの感度解析を行う関数213def analyze_cost_sensitivity(renewable_capacity_cost, technologies, renewable_capacity):214    # コストの変動範囲(0.5倍から1.5倍)215    cost_multipliers = np.linspace(0.5, 1.5, 11)216 217    # 結果を格納する辞書218    sensitivity_results = {}219 220    for tech in technologies:221        # 各技術ごとのコスト変動に対する総コストの変化を計算222        original_cost = renewable_capacity_cost[tech]223        total_costs = []224 225        for multiplier in cost_multipliers:226            # コストを変更227            modified_cost = original_cost * multiplier228            # 総コスト = 変更後のコスト * 設備容量229            total_cost = modified_cost * renewable_capacity[('region1', tech)].varValue230            total_costs.append(total_cost)231 232        # 技術ごとに結果を保存233        sensitivity_results[tech] = total_costs234 235    # 可視化236    fig = go.Figure()237 238    for tech, total_costs in sensitivity_results.items():239        fig.add_trace(go.Scatter(240            x=cost_multipliers,241            y=total_costs,242            mode='lines+markers',243            name=f'{tech} Cost Sensitivity'244        ))245 246    # グラフのレイアウト247    fig.update_layout(248        title='Cost Sensitivity Analysis: Impact of Cost Changes on Total System Cost',249        xaxis_title='Cost Multiplier (0.5x to 1.5x)',250        yaxis_title='Total System Cost (¥)',251        hovermode='x unified',252        plot_bgcolor='white',253        xaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray'),254        yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')255    )256 257    return fig258 259# Streamlit UI setup260st.set_page_config(page_title='Renewable Energy System Optimization', layout='wide')261st.title('Renewable Energy System Optimization')262 263st.markdown("""264### Model Overview265This 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.266The renewable technologies considered are:267- Solar PV268- Onshore Wind269- Offshore Wind270- Run of River (Hydro)271The 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.272""")273 274with st.sidebar:275    st.header('Input Parameters')276    solar_cost = st.number_input("Solar Capacity Cost (¥/MW)", value=80.0)277    onshore_wind_cost = st.number_input("Onshore Wind Capacity Cost (¥/MW)", value=120.0)278    offshore_wind_cost = st.number_input("Offshore Wind Capacity Cost (¥/MW)", value=180.0)279    river_cost = st.number_input("River Capacity Cost (¥/MW)", value=1000.0)280    battery_cost = st.number_input("Battery Cost (¥/MWh)", value=80.0)281    yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0)282    solar_range = st.slider("Solar Capacity Range (MW)", 0, 10000, (0, 10000))283    wind_range = st.slider("Onshore Wind Capacity Range (MW)", 0, 10000, (0, 10000))284    offshore_wind_range = st.slider("Offshore Wind Capacity Range (MW)", 0, 10000, (0, 10000))285    river_range = st.slider("River Capacity Range (MW)", 0, 10000, (0, 10000))286 287calculated_optimal_energy_mix = False288 289if st.button('Calculate Optimal Energy Mix'):290    fig_energy, heatmaps, curtailment_values, soc_per_hour, fig_capacity_ranges, renewable_capacity = optimize_energy_system(291        solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand, solar_range, wind_range, river_range, offshore_wind_range292    )293    294    if fig_energy:295        st.plotly_chart(fig_energy, use_container_width=True, height=800)296 297        # Additional visualizations298        st.markdown("### Hourly Capacity Factor Heatmaps")299        for fig_heatmap in heatmaps:300            st.plotly_chart(fig_heatmap, use_container_width=True, height=800)301 302        st.markdown("### Additional Analysis")303        st.markdown("The following plots provide additional insights into the renewable energy mix, curtailment, and electricity price variations.")304 305        # Plot curtailment over time306        curtailment_df = pd.DataFrame({"Time": fig_energy.data[0].x, "Curtailment (MW)": curtailment_values})307        fig_curtailment = px.line(curtailment_df, x='Time', y='Curtailment (MW)', title='Curtailment Over Time', template='plotly_white')308        st.plotly_chart(fig_curtailment, use_container_width=True, height=800)309 310        # Plot electricity price variation over time311        soc_df = pd.DataFrame({"Time": fig_energy.data[0].x, "State of charge [%]": soc_per_hour})312        fig_battery_operation = px.line(soc_df, x='Time', y='State of charge [%]', title='State of charge in battery', template='plotly_white')313        st.plotly_chart(fig_battery_operation, use_container_width=True, height=800)314 315        # Plot optimized capacity vs. capacity ranges316        st.plotly_chart(fig_capacity_ranges, use_container_width=True, height=800)317 318        calculated_optimal_energy_mix = True319 320# Streamlit UIに感度解析ボタンを追加321if st.button('Analyze Cost Sensitivity'):322    if calculated_optimal_energy_mix:323        fig_sensitivity = analyze_cost_sensitivity({324            'solar': solar_cost,325            'onshore_wind': onshore_wind_cost,326            'offshore_wind': offshore_wind_cost,327            'river': river_cost328        }, ['solar', 'onshore_wind', 'offshore_wind', 'river'], renewable_capacity)329        st.plotly_chart(fig_sensitivity, use_container_width=True, height=800)330    else:331        st.error("Please calculate the optimal energy mix first before running the cost sensitivity analysis.")