Flow gradient

Ramping of a power plant

General description

The gradient constraint can restrict a component to change the output within one time step. In this example a storage will buffer this restriction, so the more flexible the power plant can be run the less the storage will be used.

Change the GRADIENT variable in the example to see the effect on the usage of the storage.

Code

Download source code: gradient_example.py

Click to display code
import matplotlib.pyplot as plt
import pandas as pd

from oemof.solph import EnergySystem
from oemof.solph import Model
from oemof.solph import buses
from oemof.solph import components as cmp
from oemof.solph import flows
from oemof.solph import processing


def main():
    # The gradient for the output of the natural gas power plant.
    # Change the gradient between 0.1 and 0.0001 and check the results. The
    # more flexible the power plant can be run the less the storage will be
    # used.
    gradient = 0.01

    date_time_index = pd.date_range("1/1/2012", periods=48, freq="H")
    print(date_time_index)
    energysystem = EnergySystem(
        timeindex=date_time_index, infer_last_interval=True
    )

    demand = [
        209643,
        207497,
        200108,
        191892,
        185717,
        180672,
        172683,
        170048,
        171132,
        179532,
        189155,
        201026,
        208466,
        207718,
        205443,
        206255,
        217240,
        232798,
        237321,
        232387,
        224306,
        219280,
        223701,
        213926,
        201834,
        192215,
        187152,
        184355,
        184438,
        182786,
        180105,
        191509,
        207104,
        222501,
        231127,
        238410,
        241184,
        237413,
        234469,
        235193,
        242730,
        264196,
        265950,
        260283,
        245578,
        238849,
        241553,
        231372,
    ]

    # create natural gas bus
    bgas = buses.Bus(label="natural_gas")

    # create electricity bus
    bel = buses.Bus(label="electricity")

    # adding the buses to the energy system
    energysystem.add(bgas, bel)

    # create excess component for the electricity bus to allow overproduction
    energysystem.add(cmp.Sink(label="excess_bel", inputs={bel: flows.Flow()}))

    # create source object representing the gas commodity (annual limit)
    energysystem.add(
        cmp.Source(
            label="rgas",
            outputs={bgas: flows.Flow(variable_costs=5)},
        )
    )

    # create simple sink object representing the electrical demand
    energysystem.add(
        cmp.Sink(
            label="demand",
            inputs={bel: flows.Flow(fix=demand, nominal_value=1)},
        )
    )

    # create simple Converter object representing a gas power plant
    energysystem.add(
        cmp.Converter(
            label="pp_gas",
            inputs={bgas: flows.Flow()},
            outputs={
                bel: flows.Flow(
                    nominal_value=10e5,
                    negative_gradient_limit=gradient,
                    positive_gradient_limit=gradient,
                )
            },
            conversion_factors={bel: 0.58},
        )
    )

    # create storage object representing a battery
    storage = cmp.GenericStorage(
        nominal_storage_capacity=999999999,
        label="storage",
        inputs={bel: flows.Flow()},
        outputs={bel: flows.Flow()},
        loss_rate=0.0,
        initial_storage_level=None,
        inflow_conversion_factor=1,
        outflow_conversion_factor=0.8,
    )

    energysystem.add(storage)

    # initialise the operational model
    model = Model(energysystem)

    # solve
    model.solve(solver="cbc")

    # processing the results
    results = processing.results(model)

    # *** Create a table with all sequences and store it into a file (csv/xlsx)
    flows_to_bus = pd.DataFrame(
        {
            str(k[0].label): v["sequences"]["flow"]
            for k, v in results.items()
            if k[1] is not None and k[1] == bel
        }
    )
    flows_from_bus = pd.DataFrame(
        {
            str(k[1].label): v["sequences"]["flow"]
            for k, v in results.items()
            if k[1] is not None and k[0] == bel
        }
    )

    storage = pd.DataFrame(
        {
            str(k[0].label): v["sequences"]["storage_content"]
            for k, v in results.items()
            if k[1] is None and k[0] == storage
        }
    )

    my_flows = pd.concat(
        [flows_to_bus, flows_from_bus, storage],
        keys=["to_bus", "from_bus", "content", "duals"],
        axis=1,
    )

    print(my_flows)
    my_flows.plot()
    plt.show()


Installation requirements

This example requires oemof.solph (v0.5.x), install by:

pip install oemof.solph[examples]

License

MIT license