StorageUnit 'spill' not working when trying to run optimization

45 views
Skip to first unread message

Franco Ferrucci

unread,
May 16, 2024, 10:16:30 PMMay 16
to pypsa
Hi there,

I'm writing regarding problem I've found when I tried to run an optimization problem in the presence of a storageUnit that should have spillage.

The code is very simple: a single electrical bus with a load, a diesel generator and a storageUnit.
The storage unit emulates a hydro generator, so it has an 'inflow' time series assigned and p_min_pu is set to 0 (to force unidirectional power flow).

The issue is simple to detect: when I set an 'inflow' time series that I know that will produce spillage, pypsa cannot find a solution. 

The only way to make the system converge is to reduce the inflow power injection so pypsa will give a solution where no spillage has occurred.

Could you please help me with this?

Below you will find the code to reproduce the issue (I used pypsa '0.25.1'). Note that there is a flag called 'i_want_to_produce_the_error' that allows us to force the error (by setting an 'appropriate' storage unit inflow time series). There is another flag, 'i_want_to_plot' that allows us to plot the results (it uses plotly library).


#%% Imports
import pandas as pd
import plotly.io as pio
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import pypsa
pio.renderers.default = 'browser'
# Panda plotly backend:
pd.options.plotting.backend = 'plotly'

#%% Network definition
# Create network:
n = pypsa.Network()

# Add bus:
n.add(
      class_name='Bus',
      name='Electrical',
      carrier='AC',)

# Add load:
n.add(
      class_name='Load',
      name='Load 1',
      bus='Electrical',)

# Add Diesel generator:
n.add(
      class_name='Generator',
      name='G_thermal',
      bus='Electrical',
      control='Slack',
      p_nom=1,
      carrier='Diesel',
      marginal_cost=1,)

# Add hydro storage unit:
n.add(
      class_name='StorageUnit',
      name='Hydro_store',
      bus='Electrical',
      p_nom=5, # MWh
      max_hours=1,
      state_of_charge_initial=0.5,
      p_min_pu=0, # to force unidirectional hydro plant
      marginal_cost=0.25)

#%% Add time series:
# Snapshots:
n.set_snapshots(range(10))

# Load time series:    
n.loads_t.p_set['Load 1'] = [0.1, 0.25, 0.3, 0.4, 0.5, 0.3, 0.3, 0.2, 0.1, 0.1]

# Flag to indicate if we want to reproduce the error:
i_want_to_produce_the_error = True

# Hydro inflow time series:
if i_want_to_produce_the_error == True:
    # Pypsa won't find a solution for this time-series:
    n.storage_units_t.inflow['Hydro_store'] = [0, 2, 2, 1, 0, 0, 4, 0, 0, 0]
else:
    # Pypsa will successfully solve the OPF with this time-series:
    n.storage_units_t.inflow['Hydro_store'] = [0, 2, 2, 1.5, 0, 0, 0, 0, 0, 0]

#%% Optimize
result_status = n.optimize()
print(result_status)
   
#%% Plot
# Flag to indicate if we want to plot or not:  
plot_this_plot = True

if plot_this_plot == True and result_status[0] == 'ok':
    # Subplot creation:
    line_mode = {"shape": 'linear'}
    fig1 = make_subplots(rows=4,
                         cols=1,
                         shared_xaxes=True,
                         x_title='Time',
                         vertical_spacing=0.05,
                         y_title='Selected variables',
                         subplot_titles=('LOADS',
                                         'GENERATORS',
                                         'STORES SoC'))
    # Load:
    for col in n.loads_t.p:
        fig1.add_trace(go.Scatter(x=n.snapshots,
                                  y=n.loads_t.p.loc[:,col],
                                  fill='tonexty',
                                  mode='lines',
                                  line=line_mode,
                                  name=col + ' MW'),
                                  row=1,col=1)
    # Generators:
    for col in n.generators_t.p:
        fig1.add_trace(go.Scatter(x=n.snapshots,
                                  y=n.generators_t.p.loc[:,col],
                                  fill='tonexty',
                                  mode='lines',
                                  line=line_mode,
                                  name=col + ' MW'),
                                  row=2,col=1)
    # Hydro power:
    for col in n.storage_units_t.p:
        fig1.add_trace(go.Scatter(x=n.snapshots,
                                  y=n.storage_units_t.p.loc[:,col],
                                  fill='tonexty',
                                  mode='lines',
                                  line=line_mode,
                                  name=col + ' dispatched MW'),
                                  row=2,col=1)
    # Hydro inflow:
    for col in n.storage_units_t.inflow:
        fig1.add_trace(go.Scatter(x=n.snapshots,
                                  y=n.storage_units_t.inflow.loc[:,col],
                                  fill='tonexty',
                                  mode='lines',
                                  line=line_mode,
                                  name=col + ' inflow MW'),
                                  row=2,col=1)
    # Hydro SoC:
    for col in n.storage_units_t.state_of_charge:
        fig1.add_trace(go.Scatter(x=n.snapshots,
                                  y=n.storage_units_t.state_of_charge.loc[:,col],
                                  fill='tonexty',
                                  mode='lines',
                                  line=line_mode,
                                  name=col + ' MWh'),
                                  row=3,col=1)
    # Hydro spillage:
    for col in n.storage_units_t.spill:
        fig1.add_trace(go.Scatter(x=n.snapshots,
                                  y=n.storage_units_t.spill.loc[:,col],
                                  fill='tonexty',
                                  mode='lines',
                                  line=line_mode,
                                  name=col + ' spill MW'),
                                  row=4,col=1)
    # Show plot on browser:
    fig1.show()


 

Franco Ferrucci

unread,
May 27, 2024, 4:53:22 PMMay 27
to pypsa
Hi there,
The problem solved itself by updating to pypsa 0.28.0 (the problem still occurs with pypsa '0.25.1').

Cheers,

Franco

Fabian Hofmann

unread,
May 28, 2024, 2:17:22 AMMay 28
to pypsa
Great to hear! 
Reply all
Reply to author
Forward
0 new messages