Time Index

Basic time index

General description

A minimal example to show how time steps work.

  • Flows are defined in time intervals, storage content at points in time. Thus, there is one more value for storage contents then for the flow values.

  • Time intervals are named by the time at the beginning of that interval. The quantity changes to the given value at the given point in time.

  • The initial_storage_level of a GenericStorage is given at the first time step. If the storage is balanced, this is the same storage level as in the last time step.

  • The nominal_value in Flows has to be interpreted in means of power: We have nominal_value=0.5, but the maximum change of the storage content of an ideal storage is 0.125.

Code

Download source code: non_equidistant_time_step_example.py

Click to display code
import matplotlib.pyplot as plt

from oemof import solph


def main():
    solver = "cbc"  # 'glpk', 'gurobi',...
    solver_verbose = False  # show/hide solver output

    date_time_index = solph.create_time_index(2000, interval=0.25, number=8)

    energy_system = solph.EnergySystem(
        timeindex=date_time_index, infer_last_interval=False
    )

    bus = solph.buses.Bus(label="bus")
    source = solph.components.Source(
        label="source",
        outputs={
            bus: solph.flows.Flow(
                nominal_value=2,
                variable_costs=0.2,
                max=[0, 0, 0, 0, 1, 0.25, 0.75, 1],
            )
        },
    )
    storage = solph.components.GenericStorage(
        label="storage",
        inputs={bus: solph.flows.Flow()},
        outputs={bus: solph.flows.Flow()},
        nominal_storage_capacity=4,
        initial_storage_level=0.5,
    )
    sink = solph.components.Sink(
        label="sink",
        inputs={
            bus: solph.flows.Flow(
                nominal_value=2,
                variable_costs=0.1,
                fix=[1, 1, 0.5, 0.5, 0, 0, 0, 0],
            )
        },
    )

    energy_system.add(bus, source, sink, storage)
    model = solph.Model(energy_system)
    model.solve(solver=solver, solve_kwargs={"tee": solver_verbose})

    results = solph.processing.results(model)

    results_df = results[(storage, None)]["sequences"].copy()
    results_df["storage_inflow"] = results[(bus, storage)]["sequences"]["flow"]
    results_df["storage_outflow"] = results[(storage, bus)]["sequences"][
        "flow"
    ]

    print(results_df)

    if plt is not None:
        plt.plot(
            results[(bus, storage)]["sequences"],
            drawstyle="steps-post",
            label="Storage inflow",
        )
        plt.plot(
            results[(storage, None)]["sequences"], label="Storage content"
        )
        plt.plot(
            results[(storage, bus)]["sequences"],
            drawstyle="steps-post",
            label="Storage outflow",
        )

        plt.legend(loc="lower left")
        plt.show()


if __name__ == "__main__":
    main()

Installation requirements

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

pip install oemof.solph[examples]

License

MIT license

Non-equidistant time steps

General description

An example to show how non-equidistant time steps work. In addition to the comments in the simple example, note that:

  • Time steps in the beginning are 15 minutes.

  • Time steps in the end are hourly.

  • In the middle, there is a very short demand peak of one minute. This, however, does barely influence the storage contents.

  • Storage losses are defined per hour. - storage_fixed looses 1 energy unit per hour - storage_relative looses 50 % of its contents per hour

  • If possible, energy is transferred from storage with relative losses to the one with fixed losses to minimise total losses.

Code

Download source code: non_equidistant_time_step_example.py

Click to display code
import pandas as pd

from oemof import solph

try:
    import matplotlib.pyplot as plt
except ModuleNotFoundError:
    plt = None


def main():
    solver = "cbc"  # 'glpk', 'gurobi',...
    solver_verbose = False  # show/hide solver output

    date_time_index = pd.DatetimeIndex(
        data=[
            "2000-1-1T00:00:00",
            "2000-1-1T00:15:00",
            "2000-1-1T00:30:00",
            "2000-1-1T00:45:00",
            "2000-1-1T01:00:00",
            "2000-1-1T01:00:01",
            "2000-1-1T02:00:00",
            "2000-1-1T03:00:00",
            "2000-1-1T04:00:00",
            "2000-1-1T05:00:00",
        ]
    )

    energy_system = solph.EnergySystem(
        timeindex=date_time_index, infer_last_interval=False
    )

    bus = solph.buses.Bus(label="bus")
    source = solph.components.Source(
        label="source",
        outputs={
            bus: solph.flows.Flow(
                nominal_value=16,
                variable_costs=0.2,
                max=[0, 0, 0, 0, 0, 0, 0, 1, 1],
            )
        },
    )

    # storage with constant losses
    storage_fixed = solph.components.GenericStorage(
        label="storage_fixed",
        inputs={bus: solph.flows.Flow()},
        outputs={bus: solph.flows.Flow()},
        nominal_storage_capacity=8,
        initial_storage_level=1,
        fixed_losses_absolute=1,  # 1 energy unit loss per hour
    )

    # storage with relative losses, we disallow outflows in the first time
    # steps, so that the content is not transferred to storage_fixed
    storage_relative = solph.components.GenericStorage(
        label="storage_relative",
        inputs={bus: solph.flows.Flow()},
        outputs={
            bus: solph.flows.Flow(
                nominal_value=4, max=[0, 0, 0, 0, 0, 0, 0, 1, 1]
            )
        },
        nominal_storage_capacity=8,
        initial_storage_level=1,
        loss_rate=0.5,  # 50 % losses per hour
    )
    sink = solph.components.Sink(
        label="sink",
        inputs={
            bus: solph.flows.Flow(
                nominal_value=8,
                variable_costs=0.1,
                fix=[0.75, 0.5, 0, 0, 1, 0, 0, 0, 0],
            )
        },
    )

    energy_system.add(bus, source, sink, storage_relative, storage_fixed)
    model = solph.Model(energy_system)
    model.solve(solver=solver, solve_kwargs={"tee": solver_verbose})

    results = solph.processing.results(model)

    results_df = results[(storage_fixed, None)]["sequences"].copy()
    results_df.rename(
        columns={"storage_content": "storage_fixed"}, inplace=True
    )
    results_df["storage_fixed_inflow"] = results[(bus, storage_fixed)][
        "sequences"
    ]["flow"]
    results_df["storage_fixed_outflow"] = results[(storage_fixed, bus)][
        "sequences"
    ]["flow"]
    results_df["storage_relative"] = results[(storage_relative, None)][
        "sequences"
    ]
    results_df["storage_relative_inflow"] = results[(bus, storage_relative)][
        "sequences"
    ]["flow"]
    results_df["storage_relative_outflow"] = results[(storage_relative, bus)][
        "sequences"
    ]["flow"]

    print(results_df)

    if plt is not None:
        plt.plot(
            results[(bus, storage_fixed)]["sequences"],
            "r-",
            drawstyle="steps-post",
            label="storage_fixed inflow",
        )
        plt.plot(
            results[(storage_fixed, None)]["sequences"],
            "r--",
            label="storage_fixed content",
        )
        plt.plot(results[(storage_fixed, None)]["sequences"], "r+")
        plt.plot(
            results[(storage_fixed, bus)]["sequences"],
            "r:",
            drawstyle="steps-post",
            label="storage_fixed outflow",
        )

        plt.plot(
            results[(bus, storage_relative)]["sequences"],
            "m-",
            drawstyle="steps-post",
            label="storage_relative inflow",
        )
        plt.plot(
            results[(storage_relative, None)]["sequences"],
            "m--",
            label="storage_relative content",
        )
        plt.plot(results[(storage_relative, None)]["sequences"], "m+")
        plt.plot(
            results[(storage_relative, bus)]["sequences"],
            "m:",
            drawstyle="steps-post",
            label="storage_relative outflow",
        )

        plt.legend()
        plt.show()


if __name__ == "__main__":
    main()

Installation requirements

This example requires oemof.solph, install by:

pip install oemof.solph