Modelling a simple grid storage

Hi,
I am trying to model an extremely simple case, but cannot find out how to do so.

I want to model a electrical storage (battery), that is simply connected to the grid. Using a variable price timeseries (day ahead prices), I simply want to create an optimized schedule of when to charge and discharge the battery. So - it would incur positiv grid prices for taking the energy and negativ prices (of the same series) for feeding into the grid. I set the storage to 90% “efficiency” like in some of the simple oemof examples. The battery should charge with “low” prices and discharge with “higher” prices and thereby generate income, quite a common approach I would think :wink:

I have tried

  • 1 electrical bus with source and sink and storage
  • 1 bus with source plus one bus with sink and storage connected to both
    All I can ever get is “unbounded”/infeasible from the solver. Adding an additional “excess” sink to either or both of the busses does not make a difference.

What is the correct way to model this? Maybe someone can provide those few lines of code that should be necessary to make this work.

Sorry to ask, quite embarrasing that I cannot get this to work but I also could not find any examples for “grid storage” or similar online or in this forum

Code tried:

def make_energy_system(demanddf):
    energysystem = solph.EnergySystem(timeindex=demanddf.index, infer_last_interval=False)
    b_el = solph.buses.Bus(label='Strom')
    b_el_out = solph.buses.Bus(label='Stromeinsp')
    energysystem.add(b_el, b_el_out)
    
    energysystem.add(cmp.Sink(label="excess_bel", inputs={b_el: solph.flows.Flow()})) # tested with both/none/either
    energysystem.add(cmp.Sink(label="excess_belout", inputs={b_el_out: solph.flows.Flow()})) # tested with both/none/either
    
    el_Netzeinsp = solph.components.Sink(label='Strom Netzeinsp.', inputs={b_el_out: solph.flows.Flow(
                variable_costs=demanddf["DA FC"]*-1)}
    )
    el_Netzbezug = solph.components.Source(label='Strom Netzbezug', outputs={b_el: solph.flows.Flow(
                variable_costs=demanddf["DA FC"])})
    energysystem.add(el_Netzeinsp, el_Netzbezug)
    storage = cmp.GenericStorage(
        nominal_storage_capacity=10077997,
        label="storage",
        inputs={b_el: Flow(nominal_value=10077997 / 6)},
        outputs={
            b_el_out: Flow(nominal_value=10077997 / 6, variable_costs=0.001)
        },
        loss_rate=0.00,
        initial_storage_level=None,
        inflow_conversion_factor=1,
        outflow_conversion_factor=0.9,
    )

    energysystem.add(storage)   
    return energysystem

@marc I just added some more tags to your original post. You can try clicking through and maybe something useful will pop up? R

1 Like

Perhaps also of use:

1 Like

Hi @marc,

I just tried your code in the following way, and it works like charm.

if __name__ == "__main__":
    time_index = pd.date_range("2025-01-01", periods=24, freq="h")

    df = pd.DataFrame(
        index=time_index, data={"DA FC": np.random.rand(24)}
    )

    es = make_energy_system(demanddf=df)

    model = solph.Model(es)

    model.solve()

    results = solph.processing.results(model)

    df["battery_out"] = results[(es.node["Strom"], es.node["storage"])][
        "sequences"
    ]

    print(df)

Note that I assume prices to be always positive. If you have negative prices, your model can earn by using the access Sinks. In that case, it’s a good idea to delete them. Maybe, there is an issue with your input data?

1 Like

Thank you both for your useful replies! The Problem actually was the negative prices, that occur sometimes during the year. Dealing with those makes the model solvable with the code remaining the same (no need for the excess sinks though, removed those). Thanks for your help!

I take it you saw this recent thread on negative prices:

Actually, without the excess sinks, negative prices are no problem in you model.