Cellular energy system

Building your system from smaller cells

General description

Cellular energy systems are proposed by the VDE-ETG. They are, as the name implies, energy systems that consist of cells. Each cell can contain multiple other cells. So there is a hierarchy between them.

However, the hierarchical levels are abstracted here and the structure is flat.

The connections between the cells are modelled as Links. Each connector Link has two inputs (buses of the parent and child cell) and two outputs (buses of the parent and child cell). Losses can be modelled by using the conversion_factors of the Link class.

Code

Download source code: cellular.py

Click to display code
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 create_time_index
from oemof.solph import flows
from oemof.solph import processing
from oemof.solph import views


def main():
    ###########################################################################
    # define the cells of the cellular energy system
    ###########################################################################
    # define necessary parameters

    n_periods = 3

    daterange = create_time_index(year=2020, interval=1, number=n_periods)

    mysolver = "cbc"

    # create the energy cells
    es = EnergySystem(timeindex=daterange, infer_last_interval=False)
    ec_1 = EnergySystem(timeindex=daterange, infer_last_interval=False)
    ec_2 = EnergySystem(timeindex=daterange, infer_last_interval=False)
    ec_1_1 = EnergySystem(timeindex=daterange, infer_last_interval=False)
    ec_1_2 = EnergySystem(timeindex=daterange, infer_last_interval=False)
    ec_2_1 = EnergySystem(timeindex=daterange, infer_last_interval=False)
    ec_2_2 = EnergySystem(timeindex=daterange, infer_last_interval=False)

    demand_1 = [10] * n_periods
    demand_2 = [10] * n_periods
    demand_1_1 = [10] * n_periods
    demand_1_2 = [10] * n_periods
    demand_2_1 = [10] * n_periods
    demand_2_2 = [80] * n_periods

    pv_1 = [10] * n_periods
    pv_2 = [10] * n_periods
    pv_1_1 = [80] * n_periods
    pv_1_2 = [40] * n_periods
    pv_2_1 = [10] * n_periods
    pv_2_2 = [10] * n_periods

    bus_el_es = buses.Bus(label="bus_el_es")
    bus_el_ec_1 = buses.Bus(label="bus_el_ec_1")
    bus_el_ec_2 = buses.Bus(label="bus_el_ec_2")
    bus_el_ec_1_1 = buses.Bus(label="bus_el_ec_1_1")
    bus_el_ec_1_2 = buses.Bus(label="bus_el_ec_1_2")
    bus_el_ec_2_1 = buses.Bus(label="bus_el_ec_2_1")
    bus_el_ec_2_2 = buses.Bus(label="bus_el_ec_2_2")

    es.add(bus_el_es)
    ec_1.add(bus_el_ec_1)
    ec_2.add(bus_el_ec_2)
    ec_1_1.add(bus_el_ec_1_1)
    ec_1_2.add(bus_el_ec_1_2)
    ec_2_1.add(bus_el_ec_2_1)
    ec_2_2.add(bus_el_ec_2_2)

    sink_el_ec_1 = cmp.Sink(
        label="sink_el_ec_1",
        inputs={bus_el_ec_1: flows.Flow(fix=demand_1, nominal_value=1)},
    )
    sink_el_ec_2 = cmp.Sink(
        label="sink_el_ec_2",
        inputs={bus_el_ec_2: flows.Flow(fix=demand_2, nominal_value=1)},
    )
    sink_el_ec_1_1 = cmp.Sink(
        label="sink_el_ec_1_1",
        inputs={bus_el_ec_1_1: flows.Flow(fix=demand_1_1, nominal_value=1)},
    )
    sink_el_ec_1_2 = cmp.Sink(
        label="sink_el_ec_1_2",
        inputs={bus_el_ec_1_2: flows.Flow(fix=demand_1_2, nominal_value=1)},
    )
    sink_el_ec_2_1 = cmp.Sink(
        label="sink_el_ec_2_1",
        inputs={bus_el_ec_2_1: flows.Flow(fix=demand_2_1, nominal_value=1)},
    )
    sink_el_ec_2_2 = cmp.Sink(
        label="sink_el_ec_2_2",
        inputs={bus_el_ec_2_2: flows.Flow(fix=demand_2_2, nominal_value=1)},
    )

    ec_1.add(sink_el_ec_1)
    ec_2.add(sink_el_ec_2)
    ec_1_1.add(sink_el_ec_1_1)
    ec_1_2.add(sink_el_ec_1_2)
    ec_2_1.add(sink_el_ec_2_1)
    ec_2_2.add(sink_el_ec_2_2)

    source_el_ec_1 = cmp.Source(
        label="source_el_ec_1",
        outputs={
            bus_el_ec_1: flows.Flow(
                max=pv_1, nominal_value=1, variable_costs=5
            )
        },
    )
    source_el_ec_2 = cmp.Source(
        label="source_el_ec_2",
        outputs={
            bus_el_ec_2: flows.Flow(
                max=pv_2, nominal_value=1, variable_costs=5
            )
        },
    )
    source_el_ec_1_1 = cmp.Source(
        label="source_el_ec_1_1",
        outputs={
            bus_el_ec_1_1: flows.Flow(
                max=pv_1_1, nominal_value=1, variable_costs=10
            )
        },
    )
    source_el_ec_1_2 = cmp.Source(
        label="source_el_ec_1_2",
        outputs={
            bus_el_ec_1_2: flows.Flow(
                max=pv_1_2, nominal_value=1, variable_costs=1
            )
        },
    )
    source_el_ec_2_1 = cmp.Source(
        label="source_el_ec_2_1",
        outputs={
            bus_el_ec_2_1: flows.Flow(
                max=pv_2_1, nominal_value=1, variable_costs=5
            )
        },
    )
    source_el_ec_2_2 = cmp.Source(
        label="source_el_ec_2_2",
        outputs={
            bus_el_ec_2_2: flows.Flow(
                max=pv_2_2, nominal_value=1, variable_costs=5
            )
        },
    )

    ec_1.add(source_el_ec_1)
    ec_2.add(source_el_ec_2)
    ec_1_1.add(source_el_ec_1_1)
    ec_1_2.add(source_el_ec_1_2)
    ec_2_1.add(source_el_ec_2_1)
    ec_2_2.add(source_el_ec_2_2)

    connector_el_ec_1 = cmp.Link(
        label="connector_el_ec_1",
        inputs={
            bus_el_es: flows.Flow(),
            bus_el_ec_1: flows.Flow(),
        },
        outputs={
            bus_el_es: flows.Flow(),
            bus_el_ec_1: flows.Flow(),
        },
        conversion_factors={
            (bus_el_es, bus_el_ec_1): 1,
            (bus_el_ec_1, bus_el_es): 1,
        },
    )

    connector_el_ec_2 = cmp.Link(
        label="connector_el_ec_2",
        inputs={
            bus_el_es: flows.Flow(),
            bus_el_ec_2: flows.Flow(),
        },
        outputs={
            bus_el_es: flows.Flow(),
            bus_el_ec_2: flows.Flow(),
        },
        conversion_factors={
            (bus_el_es, bus_el_ec_2): 1,
            (bus_el_ec_2, bus_el_es): 1,
        },
    )

    connector_el_ec_1_1 = cmp.Link(
        label="connector_el_ec_1_1",
        inputs={
            bus_el_ec_1: flows.Flow(),
            bus_el_ec_1_1: flows.Flow(),
        },
        outputs={
            bus_el_ec_1: flows.Flow(),
            bus_el_ec_1_1: flows.Flow(),
        },
        conversion_factors={
            (bus_el_ec_1, bus_el_ec_1_1): 0.85,
            (bus_el_ec_1_1, bus_el_ec_1): 0.85,
        },
    )

    connector_el_ec_1_2 = cmp.Link(
        label="connector_el_ec_1_2",
        inputs={
            bus_el_ec_1: flows.Flow(),
            bus_el_ec_1_2: flows.Flow(),
        },
        outputs={
            bus_el_ec_1: flows.Flow(),
            bus_el_ec_1_2: flows.Flow(),
        },
        conversion_factors={
            (bus_el_ec_1, bus_el_ec_1_2): 1,
            (bus_el_ec_1_2, bus_el_ec_1): 1,
        },
    )

    connector_el_ec_2_1 = cmp.Link(
        label="connector_el_ec_2_1",
        inputs={
            bus_el_ec_2: flows.Flow(),
            bus_el_ec_2_1: flows.Flow(),
        },
        outputs={
            bus_el_ec_2: flows.Flow(),
            bus_el_ec_2_1: flows.Flow(),
        },
        conversion_factors={
            (bus_el_ec_2, bus_el_ec_2_1): 1,
            (bus_el_ec_2_1, bus_el_ec_2): 1,
        },
    )

    connector_el_ec_2_2 = cmp.Link(
        label="connector_el_ec_2_2",
        inputs={
            bus_el_ec_2: flows.Flow(),
            bus_el_ec_2_2: flows.Flow(),
        },
        outputs={
            bus_el_ec_2: flows.Flow(),
            bus_el_ec_2_2: flows.Flow(),
        },
        conversion_factors={
            (bus_el_ec_2, bus_el_ec_2_2): 1,
            (bus_el_ec_2_2, bus_el_ec_2): 1,
        },
    )

    # the connectors are all part of the overarching, the upmost es
    es.add(
        connector_el_ec_1,
        connector_el_ec_2,
        connector_el_ec_1_1,
        connector_el_ec_1_2,
        connector_el_ec_2_1,
        connector_el_ec_2_2,
    )

    cmodel = Model(
        energysystem=[es, ec_1, ec_2, ec_1_1, ec_1_2, ec_2_1, ec_2_2]
    )

    cmodel.solve(solver=mysolver)

    # evaluate and plot the results
    results = processing.results(cmodel)

    print(views.node(results, "bus_el_ec_1")["sequences"].iloc[0, :])
    msg = (
        "\nAs we can see, a flow of 70 kW is going from the bus_el_ec_1 "
        "to the connector_el_ec_1. It is composed of 30 kW from "
        "connector_el_ec_1_2 (and therefore ec_1_2) and 40 kW from "
        "connector_el_ec_1_1 (and therefore ec_1_1). Where does it go?\n"
    )
    print(msg)
    print(views.node(results, "bus_el_ec_2_2")["sequences"].iloc[0, :])
    msg = (
        "\nIt is going into bus_el_ec_2_2 (and therefore ec_2_2), to "
        "supply the demand.\n"
    )
    print(msg)

    msg = (
        "Here we can see that the conversion factors are in fact considered:\n"
    )
    print(msg)
    print(views.node(results, "connector_el_ec_1_1")["sequences"].iloc[0, :])


if __name__ == "__main__":
    main()

Installation requirements

This example requires at least oemof.solph (v0.5.1), install by:

pip install oemof.solph[examples]

Licence

Lennart Schürmann <lennart.schuermann@umsicht.fraunhofer.de>

MIT license