Source code for shyft.dashboard.apps.water_route_app.simplified_water_route

import itertools

from shyft.energy_market import stm
from shyft.util.layoutgraph import WaterRouteGraph, ghost_object_factory


[docs] class SimplifiedWaterRouteGraph(WaterRouteGraph):
[docs] @staticmethod def get_next_node_downstream(obj: stm.Waterway): while obj.downstream: if isinstance(obj.downstream, stm.Waterway): obj = obj.downstream else: return obj.downstream return None
[docs] def generate_graph(self, water_course: stm.HydroPowerSystem): """ Parameters ---------- water_course Returns ------- """ self.dh_tag_obj['reservoirs'] = {res.tag: res for res in water_course.reservoirs} self.dh_tag_obj['power_stations'] = {ps.tag: ps for ps in water_course.power_stations} self.dh_tag_obj['main_water_routes'] = {ww.tag: ww for ww in water_course.waterways if ww.upstream_role.name == 'main'} self.dh_tag_obj['spill_routes'] = {ww.tag: ww for ww in water_course.waterways if ww.upstream_role.name =='flood'} self.dh_tag_obj['bypass_routes'] = {ww.tag: ww for ww in water_course.waterways if ww.upstream_role.name =='bypass'} # 1. prepare all objects to be added and evaluate graph structure # 1.1 reservoirs and power stations node_objects = list(itertools.chain(self.dh_tag_obj['reservoirs'].values(), self.dh_tag_obj['power_stations'].values())) # 1.2 all water_routes all_edge_objects = list(itertools.chain(self.dh_tag_obj['main_water_routes'].values(), self.dh_tag_obj['spill_routes'].values(), self.dh_tag_obj['bypass_routes'].values())) object_layout_keys = ['Reservoir']*len(self.dh_tag_obj['reservoirs']) object_layout_keys.extend(['PowerStation'] * len(self.dh_tag_obj['power_stations'])) # check if extra nodes are needed to add, and define start and end node lists start_objects = [] edge_objects = [] end_objects = [] oceans = [] ocean_counter = 0 spill_oceans = [] spill_ocean_cluster = [] spill_ocean_config = [] connections_dict = {} for i, obj in enumerate(all_edge_objects): # check for ocean and number of connections # connection to ocean if not isinstance(obj.upstream, stm.Waterway): node_upstream = obj.upstream if isinstance(node_upstream, stm.Unit): node_upstream = node_upstream.power_plant node_downstream = self.get_next_node_downstream(obj) if not node_downstream: # Reached the ocean ocean_counter += 1 ocean = ghost_object_factory('Ocean', f"Ocean_{obj.tag}_{ocean_counter}") node_downstream = ocean if obj.upstream_role.name == 'main': oceans.append(ocean) self.dh_tag_obj['oceans'][ocean.tag] = ocean else: spill_ocean_cluster.append(ghost_object_factory('GraphSpillOcean', f'Spill_Ocean_Cluster_{ocean_counter}')) spill_oceans.append([obj.upstreams[0].target, ocean]) self.dh_tag_obj[f'oceans_{obj.upstream_role.name}'][ocean.tag] = ocean config_key = obj.upstreams[0].target.__class__.__name__ spill_ocean_config.append([config_key, 'OceanSpill']) if isinstance(node_downstream, stm.Unit): node_downstream = node_downstream.power_plant start_objects.append(node_upstream) edge_objects.append(obj) end_objects.append(node_downstream) # 2. Add all objects to the graph # 2.1 Add all containers/nodes self.add_container(node_objects, object_layout_keys) # 2.2 Define all subgraphs (forced horizontal alignment) # create ocean subgraph ocean_subgraph_obj = ghost_object_factory('GraphOcean', 'Ocean_Subgraph') ocean_subgraph = self.add_subgraph(ocean_subgraph_obj, 'GraphOcean') # add containers to the ocean subgraph ocean_subgraph.add_container(oceans, ['Ocean']*len(oceans)) # 2.3 Define all subgraphs (forced vertical alignment) for cluster_obj, node_objects, config in zip(spill_ocean_cluster, spill_oceans, spill_ocean_config): cluster_container = self.add_subgraph(cluster_obj, None) cluster_container.add_container(node_objects, config) # 2.4 Add all edges/connections self.add_connections(edge_objects, start_objects, end_objects, [obj.upstream_role.name for obj in edge_objects]) # 3.0 Generate graph coordinates self.generate_graph_coordinates()