Source code for oemof.graph

# -*- coding: utf-8 -*-

"""Modules for creating and analysing energy system graphs.

This file is part of project oemof (github.com/oemof/oemof). It's copyrighted
by the contributors recorded in the version control history of the file,
available from its original location oemof/oemof/graph.py

SPDX-License-Identifier: GPL-3.0-or-later
"""

import networkx as nx
import warnings


[docs]def create_nx_graph(energy_system=None, optimization_model=None, remove_nodes=None, filename=None, remove_nodes_with_substrings=None, remove_edges=None): """ Create a `networkx.DiGraph` for the passed energy system and plot it. See http://networkx.readthedocs.io/en/latest/ for more information. Parameters ---------- energy_system : `oemof.solph.network.EnergySystem` filename : str Absolute filename (with path) to write your graph in the graphml format. If no filename is given no file will be written. remove_nodes: list of strings Nodes to be removed e.g. ['node1', node2')] remove_nodes_with_substrings: list of strings Nodes that contain substrings to be removed e.g. ['elec', 'heat')] remove_edges: list of string tuples Edges to be removed e.g. [('resource_gas', 'gas_balance')] Examples -------- >>> import os >>> import pandas as pd >>> from oemof.solph import (Bus, Sink, Transformer, Flow, EnergySystem) >>> import oemof.graph as grph >>> datetimeindex = pd.date_range('1/1/2017', periods=3, freq='H') >>> es = EnergySystem(timeindex=datetimeindex) >>> b_gas = Bus(label='b_gas', balanced=False) >>> bel1 = Bus(label='bel1') >>> bel2 = Bus(label='bel2') >>> demand_el = Sink(label='demand_el', ... inputs = {bel1: Flow(nominal_value=85, ... actual_value=[0.5, 0.25, 0.75], ... fixed=True)}) >>> pp_gas = Transformer(label='pp_gas', ... inputs={b_gas: Flow()}, ... outputs={bel1: Flow(nominal_value=41, ... variable_costs=40)}, ... conversion_factors={bel1: 0.5}) >>> line_to2 = Transformer(label='line_to2', ... inputs={bel1: Flow()}, outputs={bel2: Flow()}) >>> line_from2 = Transformer(label='line_from2', ... inputs={bel2: Flow()}, outputs={bel1: Flow()}) >>> es.add(b_gas, bel1, demand_el, pp_gas, bel2, line_to2, line_from2) >>> my_graph = grph.create_nx_graph(es) >>> # export graph as .graphml for programs like Yed where it can be >>> # sorted and customized. this is especially helpful for large graphs >>> # grph.create_nx_graph(es, filename="my_graph.graphml") >>> [my_graph.has_node(n) ... for n in ['b_gas', 'bel1', 'pp_gas', 'demand_el', 'tester']] [True, True, True, True, False] >>> list(nx.attracting_components(my_graph)) [{'demand_el'}] >>> sorted(list(nx.strongly_connected_components(my_graph))[1]) ['bel1', 'bel2', 'line_from2', 'line_to2'] >>> new_graph = grph.create_nx_graph(energy_system=es, ... remove_nodes_with_substrings=['b_'], ... remove_nodes=['pp_gas'], ... remove_edges=[('bel2', 'line_from2')], ... filename='test_graph') >>> [new_graph.has_node(n) ... for n in ['b_gas', 'bel1', 'pp_gas', 'demand_el', 'tester']] [False, True, False, True, False] >>> my_graph.has_edge('pp_gas', 'bel1') True >>> new_graph.has_edge('bel2', 'line_from2') False >>> os.remove('test_graph.graphml') Notes ----- Needs graphviz and networkx (>= v.1.11) to work properly. Tested on Ubuntu 16.04 x64 and solydxk (debian 9). """ # construct graph from nodes and flows grph = nx.DiGraph() # Get energy_system from Model if energy_system is None: msg = ("\nThe optimisation_model attribute will be removed, pass the " "energy system instead.") warnings.warn(msg, FutureWarning) energy_system = optimization_model.es # add nodes for n in energy_system.nodes: grph.add_node(n.label, label=n.label) # add labeled flows on directed edge if an optimization_model has been # passed or undirected edge otherwise for n in energy_system.nodes: for i in n.inputs.keys(): weight = getattr(energy_system.flows()[(i, n)], 'nominal_value', None) if weight is None: grph.add_edge(i.label, n.label) else: grph.add_edge(i.label, n.label, weigth=format(weight, '.2f')) # remove nodes and edges based on precise labels if remove_nodes is not None: grph.remove_nodes_from(remove_nodes) if remove_edges is not None: grph.remove_edges_from(remove_edges) # remove nodes based on substrings if remove_nodes_with_substrings is not None: for i in remove_nodes_with_substrings: remove_nodes = [v.label for v in energy_system.nodes if i in v.label] grph.remove_nodes_from(remove_nodes) if filename is not None: if filename[:-8] != '.graphml': filename = filename + '.graphml' nx.write_graphml(grph, filename) return grph