Nested Nodes

Adding sub-structure to nodes

This example gives a simplified idea how subnodes might be used to work with discretised temperatures.

Code

Download source code: result_object.py

Click to display code
import numpy as np

from oemof.network import Node
from oemof.network.network.nodes import QualifiedLabel

from oemof import solph


class HeatPump(Node):
    """A simple heat pump model (including its source) with a COP depending
    on source a temperature (parameter) and and one of multiple possible target
    temperatures (optimiser decision).
    """

    def __init__(
        self,
        label: str,
        el_supply: solph.Bus,
        heat_demand: dict[solph.Bus, float],
        source_temperature: float | list[float],
        cpf: float = 0.5,
        el_power_limit: float = None,
        parent_node=None,
    ):
        """
        Parameters
        ----------
        label: str
            Name of the heat pump
        el_supply
            Bus where electricity is taken from
        heat_demand:
            dictionary containing heat demand Buses (keys),
            and temperatures (in °C, values)
        source_temperature:
            temperature (in °C), potentially a time series
        cpf:
            Carnot Performacne Factor
            (efficiency relative to thermodynamic optimum)
        el_power_limit:
            Limit for electric power consumption.
        """
        self.el_supply_bus = el_supply
        self.heat_demand_buses = heat_demand
        self.temperature = np.array(source_temperature)

        self.cpf = cpf
        self.el_power_limit = el_power_limit

        super().__init__(label=label, parent_node=parent_node)

        el_bus = self.subnode(
            solph.Bus,
            local_name="el",
            inputs={
                self.el_supply_bus: solph.Flow(
                    nominal_capacity=self.el_power_limit,
                ),
            },
        )

        for target, temperature in self.heat_demand_buses.items():
            cop = (
                self.cpf
                * (temperature + 273.15)
                / (temperature - self.temperature)
            )

            self.subnode(
                solph.components.Converter,
                local_name=f"hp_{temperature}",
                inputs={el_bus: solph.Flow()},
                outputs={target: solph.Flow()},
                conversion_factors={target: cop},
            )


def main(optimize=True):

    date_time_index = solph.create_time_index(2025, number=2)

    # create the energysystem and assign the time index
    es = solph.EnergySystem(
        timeindex=date_time_index, infer_last_interval=False
    )

    house = Node("house")

    el_bus = house.subnode(
        solph.Bus,
        local_name="el",
    )
    el_source = solph.components.Source(
        label=QualifiedLabel(("el_grid",)),
        outputs={el_bus: solph.Flow(variable_costs=0.3)},
    )
    es.add(house, el_source)

    heat_demands = house.subnode(
        Node,
        local_name="heat demand",
    )
    demand_bus_dhw = heat_demands.subnode(solph.Bus, "b_dhw")
    demand_bus_sh = heat_demands.subnode(solph.Bus, "b_sh")

    heat_demands.subnode(
        solph.components.Sink,
        local_name="d_dhw",
        inputs={demand_bus_dhw: solph.Flow(nominal_capacity=1, fix=[0, 0.2])},
    )
    heat_demands.subnode(
        solph.components.Sink,
        local_name="d_sh",
        inputs={demand_bus_sh: solph.Flow(nominal_capacity=1, fix=[0.4, 2.1])},
    )

    house.subnode(
        HeatPump,
        local_name="hp",
        el_supply=el_bus,
        heat_demand={demand_bus_dhw: 60.0, demand_bus_sh: 30},
        source_temperature=[3, 0],
        cpf=0.45,
        el_power_limit=3,
    )

    if optimize is False:
        return es

    model = solph.Model(es)
    model.solve()

    results = solph.Results(model)

    print(results["flow"].columns)


if __name__ == "__main__":
    main()

Installation requirements

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

pip install oemof.solph>=0.6.1

License

MIT license