diff --git a/ngraph/blueprints.py b/ngraph/blueprints.py index 17aaa01..7f6e828 100644 --- a/ngraph/blueprints.py +++ b/ngraph/blueprints.py @@ -4,7 +4,7 @@ import re from dataclasses import dataclass from itertools import product, zip_longest -from typing import Any, Dict, List +from typing import Any, Dict, List, Set from ngraph.network import Link, Network, Node @@ -19,10 +19,13 @@ class Blueprint: Attributes: name (str): Unique identifier of this blueprint. - groups (Dict[str, Any]): A mapping of group_name -> group definition - (e.g., node_count, name_template, attrs, use_blueprint, etc.). - adjacency (List[Dict[str, Any]]): A list of adjacency dictionaries - describing how groups are linked. + groups (Dict[str, Any]): A mapping of group_name -> group definition. + Allowed top-level keys in each group definition here are the same + as in normal group definitions (e.g. node_count, name_template, + attrs, disabled, risk_groups, or nested use_blueprint references, etc.). + adjacency (List[Dict[str, Any]]): A list of adjacency definitions + describing how these groups are linked, using the DSL fields + (source, target, pattern, link_params, etc.). """ name: str @@ -53,13 +56,23 @@ def expand_network_dsl(data: Dict[str, Any]) -> Network: 1) Parse "blueprints" into Blueprint objects. 2) Build a new Network from "network" metadata (e.g. name, version). 3) Expand 'network["groups"]'. - - If a group references a blueprint, incorporate that blueprint's subgroups. - - Otherwise, directly create nodes. - 4) Process any direct node definitions. + - If a group references a blueprint, incorporate that blueprint's subgroups + while merging parent's attrs + disabled + risk_groups into subgroups. + - Otherwise, directly create nodes (a "direct node group"). + 4) Process any direct node definitions (network["nodes"]). 5) Expand adjacency definitions in 'network["adjacency"]'. - 6) Process any direct link definitions. - 7) Process link overrides (applied in order if multiple overrides match). - 8) Process node overrides (applied in order if multiple overrides match). + 6) Process any direct link definitions (network["links"]). + 7) Process link overrides (in order if multiple overrides match). + 8) Process node overrides (in order if multiple overrides match). + + Under the new rules: + - Only certain top-level fields are permitted in each structure. Any extra + keys raise a ValueError. "attrs" is where arbitrary user fields go. + - For link_params, recognized fields are "capacity", "cost", "disabled", + "risk_groups", "attrs". Everything else must go inside link_params["attrs"]. + - For node/group definitions, recognized fields include "node_count", + "name_template", "attrs", "disabled", "risk_groups" or "use_blueprint" + for blueprint-based groups. Args: data (Dict[str, Any]): The YAML-parsed dictionary containing @@ -70,16 +83,45 @@ def expand_network_dsl(data: Dict[str, Any]) -> Network: """ # 1) Parse blueprint definitions blueprint_map: Dict[str, Blueprint] = {} - for bp_name, bp_data in data.get("blueprints", {}).items(): - blueprint_map[bp_name] = Blueprint( - name=bp_name, - groups=bp_data.get("groups", {}), - adjacency=bp_data.get("adjacency", []), - ) + if "blueprints" in data: + if not isinstance(data["blueprints"], dict): + raise ValueError("'blueprints' must be a dictionary.") + for bp_name, bp_data in data["blueprints"].items(): + if not isinstance(bp_data, dict): + raise ValueError( + f"Blueprint definition for '{bp_name}' must be a dict." + ) + _check_no_extra_keys( + bp_data, + allowed={"groups", "adjacency"}, + context=f"blueprint '{bp_name}'", + ) + blueprint_map[bp_name] = Blueprint( + name=bp_name, + groups=bp_data.get("groups", {}), + adjacency=bp_data.get("adjacency", []), + ) # 2) Initialize the Network from "network" metadata network_data = data.get("network", {}) + if not isinstance(network_data, dict): + raise ValueError("'network' must be a dictionary if present.") + net = Network() + # Pull recognized top-level fields from network_data + for key in network_data.keys(): + if key not in ( + "name", + "version", + "groups", + "nodes", + "adjacency", + "links", + "link_overrides", + "node_overrides", + ): + raise ValueError(f"Unrecognized top-level key in 'network': {key}") + if "name" in network_data: net.attrs["name"] = network_data["name"] if "version" in network_data: @@ -90,6 +132,8 @@ def expand_network_dsl(data: Dict[str, Any]) -> Network: # 3) Expand top-level groups for group_name, group_def in network_data.get("groups", {}).items(): + if not isinstance(group_def, dict): + raise ValueError(f"Group definition for '{group_name}' must be a dict.") _expand_group(ctx, parent_path="", group_name=group_name, group_def=group_def) # 4) Process direct node definitions @@ -97,6 +141,8 @@ def expand_network_dsl(data: Dict[str, Any]) -> Network: # 5) Expand adjacency definitions for adj_def in network_data.get("adjacency", []): + if not isinstance(adj_def, dict): + raise ValueError("Each adjacency entry must be a dictionary.") _expand_adjacency(ctx, adj_def) # 6) Process direct link definitions @@ -116,6 +162,7 @@ def _expand_group( parent_path: str, group_name: str, group_def: Dict[str, Any], + inherited_risk_groups: Set[str] = frozenset(), ) -> None: """ Expands a single group definition into either: @@ -124,31 +171,48 @@ def _expand_group( - Possibly replicating itself if group_name has bracket expansions. If 'use_blueprint' is present, we expand that blueprint. Otherwise, we - create nodes. We also handle bracket expansions in 'group_name' to - replicate the definition multiple times. + create nodes directly. + + For blueprint usage: + Allowed keys: {"use_blueprint", "parameters", "attrs", "disabled", "risk_groups"}. + We merge 'attrs', 'disabled', and 'risk_groups' from this parent group + into each blueprint subgroup's definition. + + For direct node groups (no 'use_blueprint'): + Allowed keys: {"node_count", "name_template", "attrs", "disabled", "risk_groups"}. + + If group_name includes bracket expansions like "fa[1-2]", it replicates the + same group_def for each expanded name. Args: ctx (DSLExpansionContext): The context containing blueprint info and the Network. parent_path (str): The parent path in the hierarchy. group_name (str): The current group's name (may have bracket expansions). - group_def (Dict[str, Any]): The group definition (e.g. node_count, use_blueprint, etc.). + group_def (Dict[str, Any]): The group definition (node_count, name_template, etc.). + inherited_risk_groups (Set[str]): Risk groups inherited from a higher-level group. """ - # First, check if group_name has expansions like 'fa[1-16]' expanded_names = _expand_name_patterns(group_name) + # If bracket expansions exist, replicate for each expansion if len(expanded_names) > 1 or expanded_names[0] != group_name: - # We have multiple expansions: replicate group_def for each expanded name for expanded_name in expanded_names: - _expand_group(ctx, parent_path, expanded_name, group_def) + _expand_group( + ctx, parent_path, expanded_name, group_def, inherited_risk_groups + ) return - # No expansions: proceed normally + # Compute the full path for this group if parent_path: effective_path = f"{parent_path}/{group_name}" else: effective_path = group_name if "use_blueprint" in group_def: - # Expand blueprint subgroups + # Blueprint usage => recognized keys + _check_no_extra_keys( + group_def, + allowed={"use_blueprint", "parameters", "attrs", "disabled", "risk_groups"}, + context=f"group '{group_name}' using blueprint", + ) blueprint_name: str = group_def["use_blueprint"] bp = ctx.blueprints.get(blueprint_name) if not bp: @@ -156,62 +220,95 @@ def _expand_group( f"Group '{group_name}' references unknown blueprint '{blueprint_name}'." ) + parent_attrs = copy.deepcopy(group_def.get("attrs", {})) + if not isinstance(parent_attrs, dict): + raise ValueError(f"'attrs' must be a dict in group '{group_name}'.") + parent_disabled = bool(group_def.get("disabled", False)) + + # Merge parent's risk_groups + parent_risk_groups = set(inherited_risk_groups) + if "risk_groups" in group_def: + rg_val = group_def["risk_groups"] + if not isinstance(rg_val, (list, set)): + raise ValueError( + f"'risk_groups' must be list or set in group '{group_name}'." + ) + parent_risk_groups |= set(rg_val) + param_overrides: Dict[str, Any] = group_def.get("parameters", {}) - coords = group_def.get("coords") + if not isinstance(param_overrides, dict): + raise ValueError(f"'parameters' must be a dict in group '{group_name}'.") - # For each subgroup in the blueprint, apply overrides and expand + # For each subgroup in the blueprint, apply param overrides and + # merge parent's attrs/disabled/risk_groups for bp_sub_name, bp_sub_def in bp.groups.items(): merged_def = _apply_parameters(bp_sub_name, bp_sub_def, param_overrides) - if coords is not None and "coords" not in merged_def: - merged_def["coords"] = coords + merged_def = dict(merged_def) # ensure we can mutate + + # Force disabled if parent is disabled + if parent_disabled: + merged_def["disabled"] = True + + # Merge parent's attrs + child_attrs = merged_def.get("attrs", {}) + if not isinstance(child_attrs, dict): + raise ValueError( + f"Subgroup '{bp_sub_name}' has non-dict 'attrs' inside blueprint '{blueprint_name}'." + ) + merged_def["attrs"] = {**parent_attrs, **child_attrs} + # Merge parent's risk_groups with child's + child_rgs = set(merged_def.get("risk_groups", [])) + merged_def["risk_groups"] = parent_risk_groups | child_rgs + + # Recursively expand _expand_group( ctx, parent_path=effective_path, group_name=bp_sub_name, group_def=merged_def, + inherited_risk_groups=merged_def["risk_groups"], ) - # Expand blueprint adjacency + # Expand blueprint adjacency under this parent's path for adj_def in bp.adjacency: _expand_blueprint_adjacency(ctx, adj_def, effective_path) else: - # It's a direct node group + # Direct node group => recognized keys + _check_no_extra_keys( + group_def, + allowed={"node_count", "name_template", "attrs", "disabled", "risk_groups"}, + context=f"group '{group_name}'", + ) node_count = group_def.get("node_count", 1) name_template = group_def.get("name_template", f"{group_name}-{{node_num}}") + if not isinstance(node_count, int) or node_count < 1: + raise ValueError( + f"group '{group_name}' has invalid node_count: {node_count}" + ) - # Start from the user-supplied 'attrs' or create new combined_attrs = copy.deepcopy(group_def.get("attrs", {})) + if not isinstance(combined_attrs, dict): + raise ValueError(f"attrs must be a dict in group '{group_name}'.") + group_disabled = bool(group_def.get("disabled", False)) - # Copy any other top-level keys (besides recognized ones) into 'combined_attrs' - recognized_keys = { - "node_count", - "name_template", - "coords", - "attrs", - "use_blueprint", - "parameters", - } - for key, val in group_def.items(): - if key not in recognized_keys: - combined_attrs[key] = val + # Merge parent's risk groups + parent_risk_groups = set(inherited_risk_groups) + child_rgs = set(group_def.get("risk_groups", [])) + final_risk_groups = parent_risk_groups | child_rgs for i in range(1, node_count + 1): label = name_template.format(node_num=i) node_name = f"{effective_path}/{label}" if effective_path else label - node = Node(name=node_name) - - # If coords are specified, store them - if "coords" in group_def: - node.attrs["coords"] = group_def["coords"] - - # Merge combined_attrs into node.attrs - node.attrs.update(combined_attrs) - # Ensure node.attrs has a default "type" if not set + node = Node( + name=node_name, + disabled=group_disabled, + attrs=copy.deepcopy(combined_attrs), + ) node.attrs.setdefault("type", "node") - + node.risk_groups = final_risk_groups.copy() ctx.network.add_node(node) @@ -222,14 +319,18 @@ def _expand_blueprint_adjacency( ) -> None: """ Expands adjacency definitions from within a blueprint, using parent_path - as the local root. This also handles optional expand_vars. + as the local root. This also handles optional expand_vars for repeated adjacency. + + Recognized adjacency keys: + {"source", "target", "pattern", "link_count", "link_params", + "expand_vars", "expansion_mode"}. Args: ctx (DSLExpansionContext): The context object with blueprint info and the network. - adj_def (Dict[str, Any]): The adjacency definition inside the blueprint, - containing 'source', 'target', 'pattern', etc. + adj_def (Dict[str, Any]): The adjacency definition inside the blueprint. parent_path (str): The path serving as the base for the blueprint's node paths. """ + _check_adjacency_keys(adj_def, context="blueprint adjacency") expand_vars = adj_def.get("expand_vars", {}) if expand_vars: _expand_adjacency_with_variables(ctx, adj_def, parent_path) @@ -239,6 +340,7 @@ def _expand_blueprint_adjacency( target_rel = adj_def["target"] pattern = adj_def.get("pattern", "mesh") link_params = adj_def.get("link_params", {}) + _check_link_params(link_params, context="blueprint adjacency") link_count = adj_def.get("link_count", 1) src_path = _join_paths(parent_path, source_rel) @@ -252,11 +354,15 @@ def _expand_adjacency(ctx: DSLExpansionContext, adj_def: Dict[str, Any]) -> None Expands a top-level adjacency definition from 'network.adjacency'. If 'expand_vars' is provided, we expand the source/target as templates repeatedly. + Recognized adjacency keys: + {"source", "target", "pattern", "link_count", "link_params", + "expand_vars", "expansion_mode"}. + Args: ctx (DSLExpansionContext): The context containing the target network. - adj_def (Dict[str, Any]): The adjacency definition dict, containing 'source', 'target', - and optional 'pattern', 'link_params', 'link_count', 'expand_vars'. + adj_def (Dict[str, Any]): The adjacency definition dict. """ + _check_adjacency_keys(adj_def, context="top-level adjacency") expand_vars = adj_def.get("expand_vars", {}) if expand_vars: _expand_adjacency_with_variables(ctx, adj_def, parent_path="") @@ -267,6 +373,7 @@ def _expand_adjacency(ctx: DSLExpansionContext, adj_def: Dict[str, Any]) -> None pattern = adj_def.get("pattern", "mesh") link_count = adj_def.get("link_count", 1) link_params = adj_def.get("link_params", {}) + _check_link_params(link_params, context="top-level adjacency") source_path = _join_paths("", source_path_raw) target_path = _join_paths("", target_path_raw) @@ -284,18 +391,6 @@ def _expand_adjacency_with_variables( We substitute variables into the 'source' and 'target' templates to produce multiple adjacency expansions. Then each expansion is passed to _expand_adjacency_pattern. - Example adjacency entry: - source: "/ssw-{dc_id}" - target: "/fa{fa_id}/fadu" - expand_vars: - dc_id: [1, 2, 3] - fa_id: [5, 6] - pattern: one_to_one - link_params: - capacity: 200 - cost: 1 - expansion_mode: "cartesian" or "zip" - Args: ctx (DSLExpansionContext): The DSL expansion context. adj_def (Dict[str, Any]): The adjacency definition including expand_vars, source, target, etc. @@ -305,16 +400,15 @@ def _expand_adjacency_with_variables( target_template = adj_def["target"] pattern = adj_def.get("pattern", "mesh") link_params = adj_def.get("link_params", {}) + _check_link_params(link_params, context="adjacency with expand_vars") link_count = adj_def.get("link_count", 1) expand_vars = adj_def["expand_vars"] expansion_mode = adj_def.get("expansion_mode", "cartesian") - # Sort the variables so we have a consistent order for product or zip var_names = sorted(expand_vars.keys()) lists_of_values = [expand_vars[var] for var in var_names] if expansion_mode == "zip": - # If zip mode, we zip all lists in lockstep. All must be same length or we raise. lengths = [len(lst) for lst in lists_of_values] if len(set(lengths)) != 1: raise ValueError( @@ -330,15 +424,10 @@ def _expand_adjacency_with_variables( parent_path, target_template.format(**combo_dict) ) _expand_adjacency_pattern( - ctx, - expanded_src, - expanded_tgt, - pattern, - link_params, - link_count, + ctx, expanded_src, expanded_tgt, pattern, link_params, link_count ) else: - # "cartesian" by default + # "cartesian" default for combo_tuple in product(*lists_of_values): combo_dict = dict(zip(var_names, combo_tuple)) expanded_src = _join_paths( @@ -348,12 +437,7 @@ def _expand_adjacency_with_variables( parent_path, target_template.format(**combo_dict) ) _expand_adjacency_pattern( - ctx, - expanded_src, - expanded_tgt, - pattern, - link_params, - link_count, + ctx, expanded_src, expanded_tgt, pattern, link_params, link_count ) @@ -375,12 +459,15 @@ def _expand_adjacency_pattern( using wrap-around. The larger set size must be a multiple of the smaller set size. + link_params must only contain recognized keys: capacity, cost, disabled, + risk_groups, attrs. + Args: ctx (DSLExpansionContext): The context with the target network. source_path (str): Path pattern identifying source node group(s). target_path (str): Path pattern identifying target node group(s). pattern (str): "mesh" or "one_to_one". - link_params (Dict[str, Any]): Additional link parameters (capacity, cost, etc.). + link_params (Dict[str, Any]): Additional link parameters (capacity, cost, disabled, risk_groups, attrs). link_count (int): Number of parallel links to create for each adjacency. """ source_node_groups = ctx.network.select_node_groups_by_path(source_path) @@ -444,19 +531,25 @@ def _create_link( ) -> None: """ Creates and adds one or more Links to the network, applying capacity, cost, - and attributes from link_params. + disabled, risk_groups, and attrs from link_params if present. Args: net (Network): The network to which the new link(s) will be added. source (str): Source node name for the link. target (str): Target node name for the link. - link_params (Dict[str, Any]): Dict possibly containing 'capacity', 'cost', 'attrs'. + link_params (Dict[str, Any]): Dict possibly containing + 'capacity', 'cost', 'disabled', 'risk_groups', 'attrs'. link_count (int): Number of parallel links to create between source and target. """ + _check_link_params(link_params, context=f"creating link {source}->{target}") + for _ in range(link_count): capacity = link_params.get("capacity", 1.0) cost = link_params.get("cost", 1.0) attrs = copy.deepcopy(link_params.get("attrs", {})) + disabled_flag = bool(link_params.get("disabled", False)) + # If link_params has risk_groups, we set them (replace). + link_rgs = set(link_params.get("risk_groups", [])) link = Link( source=source, @@ -464,29 +557,52 @@ def _create_link( capacity=capacity, cost=cost, attrs=attrs, + disabled=disabled_flag, ) + link.risk_groups = link_rgs net.add_link(link) def _process_direct_nodes(net: Network, network_data: Dict[str, Any]) -> None: """ Processes direct node definitions (network_data["nodes"]) and adds them to the network - if they do not already exist. If the node name already exists, no new node is created. + if they do not already exist. If the node name already exists, we do nothing. - Example: - nodes: - my_node: - coords: [10, 20] - hw_type: "X100" + Allowed top-level keys for each node: {"disabled", "attrs", "risk_groups"}. + Everything else must be placed inside "attrs" or it triggers an error. Args: net (Network): The network to which nodes are added. network_data (Dict[str, Any]): DSL data possibly containing a "nodes" dict. """ - for node_name, attrs in network_data.get("nodes", {}).items(): + nodes_dict = network_data.get("nodes", {}) + if not isinstance(nodes_dict, dict): + return + + for node_name, raw_def in nodes_dict.items(): + if not isinstance(raw_def, dict): + raise ValueError(f"Node definition for '{node_name}' must be a dict.") + _check_no_extra_keys( + raw_def, + allowed={"disabled", "attrs", "risk_groups"}, + context=f"node '{node_name}'", + ) + if node_name not in net.nodes: - new_node = Node(name=node_name, attrs=attrs or {}) + disabled_flag = bool(raw_def.get("disabled", False)) + attrs_dict = raw_def.get("attrs", {}) + if not isinstance(attrs_dict, dict): + raise ValueError(f"'attrs' must be a dict in node '{node_name}'.") + # risk_groups => set them if provided + rgs = set(raw_def.get("risk_groups", [])) + + new_node = Node( + name=node_name, + disabled=disabled_flag, + attrs=copy.deepcopy(attrs_dict), + ) new_node.attrs.setdefault("type", "node") + new_node.risk_groups = rgs net.add_node(new_node) @@ -494,31 +610,43 @@ def _process_direct_links(net: Network, network_data: Dict[str, Any]) -> None: """ Processes direct link definitions (network_data["links"]) and adds them to the network. - Example: - links: - - source: A - target: B - link_params: - capacity: 100 - cost: 2 - attrs: - color: "blue" - link_count: 2 + Each link dict must contain {"source", "target"} plus optionally + {"link_params", "link_count"}. No other top-level keys allowed. + link_params must obey the recognized link_params format (including optional risk_groups). Args: net (Network): The network to which links are added. network_data (Dict[str, Any]): DSL data possibly containing a "links" list. """ - existing_node_names = set(net.nodes.keys()) - for link_info in network_data.get("links", []): + links_list = network_data.get("links", []) + if not isinstance(links_list, list): + return + + for link_info in links_list: + if not isinstance(link_info, dict): + raise ValueError("Each link definition must be a dictionary.") + _check_no_extra_keys( + link_info, + allowed={"source", "target", "link_params", "link_count"}, + context="direct link", + ) + source = link_info["source"] target = link_info["target"] - if source not in existing_node_names or target not in existing_node_names: + if source not in net.nodes or target not in net.nodes: raise ValueError(f"Link references unknown node(s): {source}, {target}.") if source == target: raise ValueError(f"Link cannot have the same source and target: {source}") + link_params = link_info.get("link_params", {}) + if not isinstance(link_params, dict): + raise ValueError(f"link_params must be a dict for link {source}->{target}.") link_count = link_info.get("link_count", 1) + if not isinstance(link_count, int) or link_count < 1: + raise ValueError( + f"Invalid link_count={link_count} for link {source}->{target}." + ) + _create_link(net, source, target, link_params, link_count) @@ -528,26 +656,35 @@ def _process_link_overrides(net: Network, network_data: Dict[str, Any]) -> None: existing links with new parameters. Overrides are applied in order if multiple items match the same link. - Example: - link_overrides: - - source: "/region1/*" - target: "/region2/*" - link_params: - capacity: 200 - attrs: - shared_risk_group: "SRG1" - any_direction: true + Each override must contain {"source", "target", "link_params"} plus + optionally {"any_direction"}. link_params must obey recognized fields + (capacity, cost, disabled, risk_groups, attrs). + + If link_params["risk_groups"] is given, it *replaces* the link's existing risk_groups. Args: net (Network): The Network whose links will be updated. network_data (Dict[str, Any]): DSL data possibly containing 'link_overrides'. """ link_overrides = network_data.get("link_overrides", []) + if not isinstance(link_overrides, list): + return + for link_override in link_overrides: + if not isinstance(link_override, dict): + raise ValueError("Each link_override must be a dict.") + _check_no_extra_keys( + link_override, + allowed={"source", "target", "link_params", "any_direction"}, + context="link override", + ) source = link_override["source"] target = link_override["target"] link_params = link_override["link_params"] + if not isinstance(link_params, dict): + raise ValueError("link_params must be dict in link override.") any_direction = link_override.get("any_direction", True) + _update_links(net, source, target, link_params, any_direction) @@ -557,22 +694,41 @@ def _process_node_overrides(net: Network, network_data: Dict[str, Any]) -> None: existing nodes with new attributes in bulk. Overrides are applied in order if multiple items match the same node. - Example: - node_overrides: - - path: "/region1/spine*" - attrs: - hw_type: "DellX" - shared_risk_group: "SRG2" + Each override must have {"path"} plus optionally {"attrs", "disabled", "risk_groups"}. + + - If "disabled" is present at top level, we set node.disabled. + - If "risk_groups" is present, we *replace* the node's risk_groups. + - Everything else merges into node.attrs. Args: net (Network): The Network whose nodes will be updated. network_data (Dict[str, Any]): DSL data possibly containing 'node_overrides'. """ node_overrides = network_data.get("node_overrides", []) + if not isinstance(node_overrides, list): + return + for override in node_overrides: + if not isinstance(override, dict): + raise ValueError("Each node_override must be a dict.") + _check_no_extra_keys( + override, + allowed={"path", "attrs", "disabled", "risk_groups"}, + context="node override", + ) + path = override["path"] - attrs_to_set = override["attrs"] - _update_nodes(net, path, attrs_to_set) + top_level_disabled = override.get("disabled", None) + override_risk_groups = override.get("risk_groups", None) + + if "attrs" in override and not isinstance(override["attrs"], dict): + raise ValueError("attrs must be a dict in node override.") + + attrs_to_set = copy.deepcopy(override.get("attrs", {})) + + # We'll process disabled as a separate boolean + # We'll process risk_groups as a direct replacement if given + _update_nodes(net, path, attrs_to_set, top_level_disabled, override_risk_groups) def _update_links( @@ -584,18 +740,23 @@ def _update_links( ) -> None: """ Updates all Link objects between nodes matching 'source' and 'target' paths - with new parameters. + with new parameters (capacity, cost, disabled, risk_groups, attrs). If any_direction=True, both (source->target) and (target->source) links are updated if present. + If link_params["risk_groups"] is given, it *replaces* the link's existing risk_groups. + Args: net (Network): The network whose links should be updated. source (str): A path pattern identifying source node group(s). target (str): A path pattern identifying target node group(s). - link_params (Dict[str, Any]): New parameter values (capacity, cost, attrs). + link_params (Dict[str, Any]): New parameter values + (capacity, cost, disabled, risk_groups, attrs). any_direction (bool): If True, also update reversed direction links. """ + _check_link_params(link_params, context="link override processing") + source_node_groups = net.select_node_groups_by_path(source) target_node_groups = net.select_node_groups_by_path(target) @@ -606,6 +767,12 @@ def _update_links( node.name for _, nodes in target_node_groups.items() for node in nodes } + new_disabled_val = link_params.get("disabled", None) + new_capacity = link_params.get("capacity", None) + new_cost = link_params.get("cost", None) + new_risk_groups = link_params.get("risk_groups", None) + new_attrs = link_params.get("attrs", {}) + for link in net.links.values(): forward_match = link.source in source_nodes and link.target in target_nodes reverse_match = ( @@ -614,23 +781,50 @@ def _update_links( and link.target in source_nodes ) if forward_match or reverse_match: - link.capacity = link_params.get("capacity", link.capacity) - link.cost = link_params.get("cost", link.cost) - link.attrs.update(link_params.get("attrs", {})) - - -def _update_nodes(net: Network, path: str, attrs: Dict[str, Any]) -> None: + if new_capacity is not None: + link.capacity = new_capacity + if new_cost is not None: + link.cost = new_cost + if new_disabled_val is not None: + link.disabled = bool(new_disabled_val) + if new_risk_groups is not None: + link.risk_groups = set(new_risk_groups) + if new_attrs: + link.attrs.update(new_attrs) + + +def _update_nodes( + net: Network, + path: str, + attrs: Dict[str, Any], + disabled_val: Any = None, + risk_groups_val: Any = None, +) -> None: """ Updates attributes on all nodes matching a given path pattern. + - If 'disabled_val' is not None, sets node.disabled to that boolean value. + - If 'risk_groups_val' is not None, *replaces* the node's risk_groups with that new set. + - Everything else in 'attrs' is merged into node.attrs. + Args: net (Network): The network containing the nodes. path (str): A path pattern identifying which node group(s) to modify. attrs (Dict[str, Any]): A dictionary of new attributes to set/merge. + disabled_val (Any): Boolean or None for disabling or enabling nodes. + risk_groups_val (Any): List or set or None for replacing node.risk_groups. """ node_groups = net.select_node_groups_by_path(path) for _, nodes in node_groups.items(): for node in nodes: + if disabled_val is not None: + node.disabled = bool(disabled_val) + if risk_groups_val is not None: + if not isinstance(risk_groups_val, (list, set)): + raise ValueError( + f"risk_groups override must be list or set, got {type(risk_groups_val)}." + ) + node.risk_groups = set(risk_groups_val) node.attrs.update(attrs) @@ -646,7 +840,7 @@ def _apply_parameters( If 'spine.attrs.hw_type' = 'Dell', it sets subgroup_def['attrs']['hw_type'] = 'Dell'. Args: - subgroup_name (str): Name of the subgroup in the blueprint (e.g. 'spine'). + subgroup_name (str): Name of the subgroup in the blueprint. subgroup_def (Dict[str, Any]): The default definition of that subgroup. params_overrides (Dict[str, Any]): Overrides in the form of {'spine.node_count': 6, 'spine.attrs.hw_type': 'Dell'}. @@ -659,7 +853,6 @@ def _apply_parameters( for key, val in params_overrides.items(): parts = key.split(".") if parts[0] == subgroup_name and len(parts) > 1: - # We have a dotted path that might refer to nested dictionaries. subpath = parts[1:] _apply_nested_path(out, subpath, val) @@ -743,7 +936,7 @@ def _parse_range_expr(expr: str) -> List[str]: expr (str): The raw expression from inside brackets, e.g. "1-3,5,7-9". Returns: - List[str]: A sorted list of all string expansions. + List[str]: A sorted list of all expansions. """ values = [] parts = [x.strip() for x in expr.split(",")] @@ -783,3 +976,61 @@ def _join_paths(parent_path: str, rel_path: str) -> str: if parent_path: return f"{parent_path}/{rel_path}" return rel_path + + +def _check_no_extra_keys( + data_dict: Dict[str, Any], allowed: set[str], context: str +) -> None: + """ + Checks that data_dict only has keys in 'allowed'. Raises ValueError if not. + + Args: + data_dict (Dict[str, Any]): The dict to check. + allowed (set[str]): The set of recognized keys. + context (str): A short description of what we are validating. + """ + extra_keys = set(data_dict.keys()) - allowed + if extra_keys: + raise ValueError( + f"Unrecognized key(s) in {context}: {', '.join(sorted(extra_keys))}. " + f"Allowed keys are: {sorted(allowed)}" + ) + + +def _check_adjacency_keys(adj_def: Dict[str, Any], context: str) -> None: + """ + Ensures adjacency definitions only contain recognized keys. + + Recognized adjacency keys are: + {"source", "target", "pattern", "link_count", "link_params", + "expand_vars", "expansion_mode"}. + """ + _check_no_extra_keys( + adj_def, + allowed={ + "source", + "target", + "pattern", + "link_count", + "link_params", + "expand_vars", + "expansion_mode", + }, + context=context, + ) + if "source" not in adj_def or "target" not in adj_def: + raise ValueError(f"Adjacency in {context} must have 'source' and 'target'.") + + +def _check_link_params(link_params: Dict[str, Any], context: str) -> None: + """ + Checks that link_params only has recognized keys: + {"capacity", "cost", "disabled", "risk_groups", "attrs"}. + """ + recognized = {"capacity", "cost", "disabled", "risk_groups", "attrs"} + extra = set(link_params.keys()) - recognized + if extra: + raise ValueError( + f"Unrecognized link_params key(s) in {context}: {', '.join(sorted(extra))}. " + f"Allowed: {sorted(recognized)}" + ) diff --git a/ngraph/failure_policy.py b/ngraph/failure_policy.py index 845b0a3..013f917 100644 --- a/ngraph/failure_policy.py +++ b/ngraph/failure_policy.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from dataclasses import dataclass, field -from typing import Any, Dict, List, Literal +from typing import Any, Dict, List, Literal, Optional, Set from random import random, sample from collections import defaultdict, deque @@ -10,7 +12,6 @@ class FailureCondition: A single condition for matching an entity's attribute with an operator and value. Example usage (YAML): - conditions: - attr: "capacity" operator: "<" @@ -18,12 +19,12 @@ class FailureCondition: Attributes: attr (str): - The name of the attribute to inspect (e.g., "type", "capacity"). + The name of the attribute to inspect (e.g., "capacity", "region"). operator (str): - The comparison operator: "==", "!=", "<", "<=", ">", ">=", "contains", - "not_contains", "any_value", or "no_value". + The comparison operator: "==", "!=", "<", "<=", ">", ">=", + "contains", "not_contains", "any_value", or "no_value". value (Any): - The value to compare against (e.g., "node", 100, True, etc.). + The value to compare against (e.g., 100, True, "foo", etc.). """ attr: str @@ -31,29 +32,36 @@ class FailureCondition: value: Any +# Supported entity scopes for a rule +EntityScope = Literal["node", "link", "risk_group"] + + @dataclass class FailureRule: """ - Defines how to match entities and then select them for failure. + Defines how to match and then select entities for failure. Attributes: + entity_scope (EntityScope): + The type of entities this rule applies to: "node", "link", or "risk_group". conditions (List[FailureCondition]): A list of conditions to filter matching entities. logic (Literal["and", "or", "any"]): - - "and": All conditions must be true for a match. - - "or": At least one condition is true for a match. - - "any": Skip condition checks and match all entities. + "and": All conditions must be true for a match. + "or": At least one condition is true for a match. + "any": Skip condition checks and match all. rule_type (Literal["random", "choice", "all"]): The selection strategy among the matched set: - - "random": Each matched entity is chosen with probability=`probability`. - - "choice": Pick exactly `count` items (random sample). - - "all": Select every matched entity. + - "random": each matched entity is chosen with probability = `probability`. + - "choice": pick exactly `count` items from the matched set (random sample). + - "all": select every matched entity in the matched set. probability (float): Probability in [0,1], used if `rule_type="random"`. count (int): Number of entities to pick if `rule_type="choice"`. """ + entity_scope: EntityScope conditions: List[FailureCondition] = field(default_factory=list) logic: Literal["and", "or", "any"] = "and" rule_type: Literal["random", "choice", "all"] = "all" @@ -61,11 +69,8 @@ class FailureRule: count: int = 1 def __post_init__(self) -> None: - """ - Validate the probability if rule_type is 'random'. - """ if self.rule_type == "random": - if not 0.0 <= self.probability <= 1.0: + if not (0.0 <= self.probability <= 1.0): raise ValueError( f"probability={self.probability} must be within [0,1] " f"for rule_type='random'." @@ -78,188 +83,315 @@ class FailurePolicy: A container for multiple FailureRules plus optional metadata in `attrs`. The main entry point is `apply_failures`, which: - 1) Merges all nodes and links into a single entity dictionary. - 2) Applies each FailureRule, collecting a set of failed entity IDs. - 3) Optionally expands failures to include entities sharing a - 'shared_risk_group' with any entity that failed. + 1) For each rule, gather the relevant entities (node, link, or risk_group). + 2) Match them based on rule conditions (or skip if 'logic=any'). + 3) Apply the selection strategy (all, random, or choice). + 4) Collect the union of all failed entities across all rules. + 5) Optionally expand failures by shared-risk groups or sub-risks. + + Large-scale performance: + - If you set `use_cache=True`, matched sets for each rule are cached, + so repeated calls to `apply_failures` can skip re-matching if the + network hasn't changed. If your network changes between calls, + you should clear the cache or re-initialize the policy. Attributes: rules (List[FailureRule]): A list of FailureRules to apply. attrs (Dict[str, Any]): Arbitrary metadata about this policy (e.g. "name", "description"). - If `fail_shared_risk_groups=True`, then shared-risk expansion is used. + fail_shared_risk_groups (bool): + If True, after initial selection, expand failures among any + node/link that shares a risk group with a failed entity. + fail_risk_group_children (bool): + If True, and if a risk_group is marked as failed, expand to + children risk_groups recursively. + use_cache (bool): + If True, match results for each rule are cached to speed up + repeated calls. If the network changes, the cached results + may be stale. + """ rules: List[FailureRule] = field(default_factory=list) attrs: Dict[str, Any] = field(default_factory=dict) + fail_shared_risk_groups: bool = False + fail_risk_group_children: bool = False + use_cache: bool = False + + # Internal cache for matched sets: (rule_index -> set_of_entities) + _match_cache: Dict[int, Set[str]] = field(default_factory=dict, init=False) def apply_failures( self, - nodes: Dict[str, Dict[str, Any]], - links: Dict[str, Dict[str, Any]], + network_nodes: Dict[str, Any], + network_links: Dict[str, Any], + network_risk_groups: Dict[str, Any] = None, ) -> List[str]: """ Identify which entities fail given the defined rules, then optionally - expand by shared-risk groups. + expand by shared-risk groups or nested risk groups. Args: - nodes: Dict[node_name, node_attributes]. Must have 'type'="node". - links: Dict[link_id, link_attributes]. Must have 'type'="link". + network_nodes: {node_id -> node_object_or_dict}, each with top-level attributes + (capacity, disabled, risk_groups, etc.). + network_links: {link_id -> link_object_or_dict}, similarly. + network_risk_groups: {rg_name -> RiskGroup} or dict. If you don't have risk + groups, pass None or {}. Returns: - A list of failed entity IDs (union of all rule matches). + A list of IDs that fail (union of all rule matches, possibly expanded). + For risk groups, the ID is the risk group's name. """ - all_entities = {**nodes, **links} - failed_entities = set() - - # 1) Collect matched failures from each rule - for rule in self.rules: - matched = self._match_entities(all_entities, rule.conditions, rule.logic) - selected = self._select_entities(matched, all_entities, rule) - failed_entities.update(selected) - - # 2) Optionally expand failures by shared-risk group - if self.attrs.get("fail_shared_risk_groups", False): - self._expand_shared_risk_groups(failed_entities, all_entities) - - return list(failed_entities) + if network_risk_groups is None: + network_risk_groups = {} + + failed_nodes: Set[str] = set() + failed_links: Set[str] = set() + failed_risk_groups: Set[str] = set() + + # 1) Collect matched from each rule + for idx, rule in enumerate(self.rules): + matched_ids = self._match_scope( + idx, + rule, + network_nodes, + network_links, + network_risk_groups, + ) + # Then select a subset from matched_ids according to rule_type + selected = self._select_entities(matched_ids, rule) + + # Add them to the respective fail sets + if rule.entity_scope == "node": + failed_nodes |= set(selected) + elif rule.entity_scope == "link": + failed_links |= set(selected) + elif rule.entity_scope == "risk_group": + failed_risk_groups |= set(selected) + + # 2) Optionally expand failures by shared-risk groups + if self.fail_shared_risk_groups: + self._expand_shared_risk_groups( + failed_nodes, failed_links, network_nodes, network_links + ) + + # 3) Optionally expand risk-group children (if a risk group is failed, recursively fail children) + if self.fail_risk_group_children and failed_risk_groups: + self._expand_failed_risk_group_children( + failed_risk_groups, network_risk_groups + ) + + # Return union: node IDs, link IDs, and risk_group names + # For the code that uses this, you can interpret them in your manager. + all_failed = set(failed_nodes) | set(failed_links) | set(failed_risk_groups) + return sorted(all_failed) + + def _match_scope( + self, + rule_idx: int, + rule: FailureRule, + network_nodes: Dict[str, Any], + network_links: Dict[str, Any], + network_risk_groups: Dict[str, Any], + ) -> Set[str]: + """ + Get the set of IDs matched by the given rule, either from cache + or by performing a fresh match over the relevant entity type. + """ + if self.use_cache and rule_idx in self._match_cache: + return self._match_cache[rule_idx] + + # Decide which mapping to iterate + if rule.entity_scope == "node": + matched = self._match_entities(network_nodes, rule.conditions, rule.logic) + elif rule.entity_scope == "link": + matched = self._match_entities(network_links, rule.conditions, rule.logic) + else: # risk_group + matched = self._match_entities( + network_risk_groups, rule.conditions, rule.logic + ) + + if self.use_cache: + self._match_cache[rule_idx] = matched + return matched def _match_entities( self, - all_entities: Dict[str, Dict[str, Any]], + entity_map: Dict[str, Any], conditions: List[FailureCondition], logic: str, - ) -> List[str]: + ) -> Set[str]: """ - Return all entity IDs matching the given conditions based on 'and'/'or'/'any' logic. + Return all entity IDs that match the given conditions based on 'and'/'or'/'any' logic. - Args: - all_entities: {entity_id: attributes}. - conditions: List of FailureCondition to evaluate. - logic: "and", "or", or "any". + entity_map is either nodes, links, or risk_groups: + {entity_id -> {top_level_attr: value, ...}} + + If logic='any', skip condition checks and return everything. + If no conditions and logic!='any', return empty set. Returns: - A list of matching entity IDs. + A set of matching entity IDs. """ if logic == "any": - # Skip condition checks; everything matches. - return list(all_entities.keys()) + return set(entity_map.keys()) if not conditions: - # If zero conditions, we match nothing unless logic='any'. - return [] + return set() + + matched = set() + for entity_id, attrs in entity_map.items(): + if self._evaluate_conditions(attrs, conditions, logic): + matched.add(entity_id) - matched = [] - for entity_id, attr_dict in all_entities.items(): - if self._evaluate_conditions(attr_dict, conditions, logic): - matched.append(entity_id) return matched @staticmethod def _evaluate_conditions( - entity_attrs: Dict[str, Any], + attrs: Dict[str, Any], conditions: List[FailureCondition], logic: str, ) -> bool: """ Evaluate multiple conditions on a single entity. All or any condition(s) must pass, depending on 'logic'. - - Args: - entity_attrs: Attribute dict for one entity. - conditions: List of FailureCondition to test. - logic: "and" or "or". - - Returns: - True if conditions pass, else False. """ - if logic not in ("and", "or"): + if logic == "and": + return all(_evaluate_condition(attrs, c) for c in conditions) + elif logic == "or": + return any(_evaluate_condition(attrs, c) for c in conditions) + else: raise ValueError(f"Unsupported logic: {logic}") - results = [_evaluate_condition(entity_attrs, c) for c in conditions] - return all(results) if logic == "and" else any(results) - @staticmethod - def _select_entities( - entity_ids: List[str], - all_entities: Dict[str, Dict[str, Any]], - rule: FailureRule, - ) -> List[str]: + def _select_entities(entity_ids: Set[str], rule: FailureRule) -> Set[str]: """ From the matched IDs, pick which entities fail under the given rule_type. - - Args: - entity_ids: Matched entity IDs from _match_entities. - all_entities: Full entity map (unused now, but available if needed). - rule: The FailureRule specifying 'random', 'choice', or 'all'. - - Returns: - A list of selected entity IDs to fail. """ if not entity_ids: - return [] + return set() if rule.rule_type == "random": - return [eid for eid in entity_ids if random() < rule.probability] + return {eid for eid in entity_ids if random() < rule.probability} elif rule.rule_type == "choice": count = min(rule.count, len(entity_ids)) - return sample(sorted(entity_ids), k=count) + # sample needs a list + return set(sample(list(entity_ids), k=count)) elif rule.rule_type == "all": return entity_ids else: raise ValueError(f"Unsupported rule_type: {rule.rule_type}") def _expand_shared_risk_groups( - self, failed_entities: set[str], all_entities: Dict[str, Dict[str, Any]] + self, + failed_nodes: Set[str], + failed_links: Set[str], + network_nodes: Dict[str, Any], + network_links: Dict[str, Any], + ) -> None: + """ + Expand failures among any node/link that shares a risk group + with a failed entity. BFS until no new failures. + """ + # We'll handle node + link expansions only. (Risk group expansions are separate.) + # Build a map risk_group -> set of node or link IDs + rg_to_entities: Dict[str, Set[str]] = defaultdict(set) + + # Gather risk_groups from nodes + for n_id, nd in network_nodes.items(): + if "risk_groups" in nd and nd["risk_groups"]: + for rg in nd["risk_groups"]: + rg_to_entities[rg].add(n_id) + + # Gather risk_groups from links + for l_id, lk in network_links.items(): + if "risk_groups" in lk and lk["risk_groups"]: + for rg in lk["risk_groups"]: + rg_to_entities[rg].add(l_id) + + # Combined set of failed node/link IDs + queue = deque(failed_nodes | failed_links) + visited = set(queue) # track which entity IDs we've processed + + while queue: + current_id = queue.popleft() + # figure out if current_id is a node or a link by seeing where it appears + current_rgs = [] + if current_id in network_nodes: + # node + nd = network_nodes[current_id] + current_rgs = nd.get("risk_groups", []) + elif current_id in network_links: + # link + lk = network_links[current_id] + current_rgs = lk.get("risk_groups", []) + + for rg in current_rgs: + # all entity IDs in rg_to_entities[rg] should be failed + for other_id in rg_to_entities[rg]: + if other_id not in visited: + visited.add(other_id) + queue.append(other_id) + if other_id in network_nodes: + failed_nodes.add(other_id) + elif other_id in network_links: + failed_links.add(other_id) + # if other_id in risk_groups => not handled here + + def _expand_failed_risk_group_children( + self, + failed_rgs: Set[str], + all_risk_groups: Dict[str, Any], ) -> None: """ - Expand the 'failed_entities' set so that if an entity has - shared_risk_group=X, all other entities with the same group also fail. + If we fail a risk_group, also fail its descendants recursively. - This is done iteratively until no new failures are found. + We assume each entry in all_risk_groups is something like: + rg_name -> RiskGroup object or { 'name': .., 'children': [...] } - Args: - failed_entities: Set of entity IDs already marked as failed. - all_entities: Map of entity_id -> attributes (which may contain 'shared_risk_group'). + BFS or DFS any children to mark them as failed as well. """ - # Pre-compute SRG -> entity IDs mapping for efficiency - srg_map = defaultdict(set) - for eid, attrs in all_entities.items(): - srg = attrs.get("shared_risk_group") - if srg: - srg_map[srg].add(eid) - - queue = deque(failed_entities) + queue = deque(failed_rgs) while queue: - current = queue.popleft() - current_srg = all_entities[current].get("shared_risk_group") - if not current_srg: + rg_name = queue.popleft() + rg_data = all_risk_groups.get(rg_name) + if not rg_data: continue - - # All entities in the same SRG should fail - for other_eid in srg_map[current_srg]: - if other_eid not in failed_entities: - failed_entities.add(other_eid) - queue.append(other_eid) + # Suppose the children are in rg_data["children"] + # or if it's an actual RiskGroup object => rg_data.children + child_list = [] + if isinstance(rg_data, dict): + child_list = rg_data.get("children", []) + else: + # assume it's a RiskGroup object with a .children + child_list = rg_data.children + + for child_obj in child_list: + # child_obj might be a dict or RiskGroup with name + child_name = ( + child_obj["name"] if isinstance(child_obj, dict) else child_obj.name + ) + if child_name not in failed_rgs: + failed_rgs.add(child_name) + queue.append(child_name) -def _evaluate_condition(entity: Dict[str, Any], cond: FailureCondition) -> bool: +def _evaluate_condition(entity_attrs: Dict[str, Any], cond: FailureCondition) -> bool: """ - Evaluate a single FailureCondition against an entity's attributes. + Evaluate a single FailureCondition against entity attributes. Operators supported: - ==, !=, <, <=, >, >=, contains, not_contains, any_value, no_value + ==, !=, <, <=, >, >= + contains, not_contains + any_value, no_value - Args: - entity: Entity attributes (e.g., node.attrs or link.attrs). - cond: FailureCondition specifying (attr, operator, value). + If entity_attrs does not have cond.attr => derived_value=None. - Returns: - True if the condition passes, else False. + Returns True if condition passes, else False. """ - has_attr = cond.attr in entity - derived_value = entity.get(cond.attr, None) + has_attr = cond.attr in entity_attrs + derived_value = entity_attrs.get(cond.attr, None) op = cond.operator if op == "==": @@ -283,8 +415,7 @@ def _evaluate_condition(entity: Dict[str, Any], cond: FailureCondition) -> bool: return True return cond.value not in derived_value elif op == "any_value": - # Pass if the attribute key exists, even if the value is None - return has_attr + return has_attr # True if attribute key exists elif op == "no_value": # Pass if the attribute key is missing or the value is None return (not has_attr) or (derived_value is None) diff --git a/ngraph/network.py b/ngraph/network.py index 16827b7..1459ea7 100644 --- a/ngraph/network.py +++ b/ngraph/network.py @@ -4,7 +4,7 @@ import re import uuid from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple, Set from ngraph.lib.algorithms.base import FlowPlacement from ngraph.lib.algorithms.max_flow import calc_max_flow @@ -31,12 +31,14 @@ class Node: Attributes: name (str): Unique identifier for the node. - attrs (Dict[str, Any]): Optional metadata (e.g., type, coordinates, region). - Set attrs["disabled"] = True to mark the node as inactive. - Defaults to an empty dict. + disabled (bool): Whether the node is disabled (excluded from calculations). + risk_groups (Set[str]): Set of risk group names this node belongs to. + attrs (Dict[str, Any]): Additional metadata (e.g., coordinates, region). """ name: str + disabled: bool = False + risk_groups: Set[str] = field(default_factory=set) attrs: Dict[str, Any] = field(default_factory=dict) @@ -50,28 +52,46 @@ class Link: target (str): Name of the target node. capacity (float): Link capacity (default 1.0). cost (float): Link cost (default 1.0). - attrs (Dict[str, Any]): Optional metadata (e.g., type, distance). - Set attrs["disabled"] = True to mark link as inactive. - Defaults to an empty dict. - id (str): Auto-generated unique identifier in the form - "{source}|{target}|". + disabled (bool): Whether the link is disabled. + risk_groups (Set[str]): Set of risk group names this link belongs to. + attrs (Dict[str, Any]): Additional metadata (e.g., distance). + id (str): Auto-generated unique identifier: "{source}|{target}|". """ source: str target: str capacity: float = 1.0 cost: float = 1.0 + disabled: bool = False + risk_groups: Set[str] = field(default_factory=set) attrs: Dict[str, Any] = field(default_factory=dict) id: str = field(init=False) def __post_init__(self) -> None: """ - Generate the link's unique ID by combining source, target, - and a random Base64-encoded UUID. + Generate the link's unique ID upon initialization. """ self.id = f"{self.source}|{self.target}|{new_base64_uuid()}" +@dataclass(slots=True) +class RiskGroup: + """ + Represents a shared-risk or failure domain, which may have nested children. + + Attributes: + name (str): Unique name of this risk group. + children (List[RiskGroup]): Subdomains in a nested structure. + disabled (bool): Whether this group was declared disabled on load. + attrs (Dict[str, Any]): Additional metadata for the risk group. + """ + + name: str + children: List[RiskGroup] = field(default_factory=list) + disabled: bool = False + attrs: Dict[str, Any] = field(default_factory=dict) + + @dataclass(slots=True) class Network: """ @@ -80,28 +100,25 @@ class Network: Attributes: nodes (Dict[str, Node]): Mapping from node name -> Node object. links (Dict[str, Link]): Mapping from link ID -> Link object. + risk_groups (Dict[str, RiskGroup]): Top-level risk groups by name. attrs (Dict[str, Any]): Optional metadata about the network. """ nodes: Dict[str, Node] = field(default_factory=dict) links: Dict[str, Link] = field(default_factory=dict) + risk_groups: Dict[str, RiskGroup] = field(default_factory=dict) attrs: Dict[str, Any] = field(default_factory=dict) def add_node(self, node: Node) -> None: """ Add a node to the network (keyed by node.name). - Auto-tags node.attrs["type"] = "node" if not already set, - and node.attrs["disabled"] = False if not specified. - Args: - node: Node to add. + node (Node): Node to add. Raises: ValueError: If a node with the same name already exists. """ - node.attrs.setdefault("type", "node") - node.attrs.setdefault("disabled", False) if node.name in self.nodes: raise ValueError(f"Node '{node.name}' already exists in the network.") self.nodes[node.name] = node @@ -110,11 +127,8 @@ def add_link(self, link: Link) -> None: """ Add a link to the network (keyed by the link's auto-generated ID). - Auto-tags link.attrs["type"] = "link" if not already set, - and link.attrs["disabled"] = False if not specified. - Args: - link: Link to add. + link (Link): Link to add. Raises: ValueError: If the link's source or target node does not exist. @@ -124,39 +138,31 @@ def add_link(self, link: Link) -> None: if link.target not in self.nodes: raise ValueError(f"Target node '{link.target}' not found in network.") - link.attrs.setdefault("type", "link") - link.attrs.setdefault("disabled", False) self.links[link.id] = link def to_strict_multidigraph(self, add_reverse: bool = True) -> StrictMultiDiGraph: """ Create a StrictMultiDiGraph representation of this Network. - Nodes and links whose attrs["disabled"] == True are omitted. + Skips disabled nodes/links. Optionally adds reverse edges. Args: - add_reverse: If True, also add a reverse edge for each link. + add_reverse (bool): If True, also add a reverse edge for each link. Returns: StrictMultiDiGraph: A directed multigraph representation of the network. """ graph = StrictMultiDiGraph() - - # Identify disabled nodes for quick checks - disabled_nodes = { - name - for name, node in self.nodes.items() - if node.attrs.get("disabled", False) - } + disabled_nodes = {name for name, nd in self.nodes.items() if nd.disabled} # Add enabled nodes for node_name, node in self.nodes.items(): - if not node.attrs.get("disabled", False): + if not node.disabled: graph.add_node(node_name, **node.attrs) # Add enabled links for link_id, link in self.links.items(): - if link.attrs.get("disabled", False): + if link.disabled: continue if link.source in disabled_nodes or link.target in disabled_nodes: continue @@ -189,14 +195,13 @@ def select_node_groups_by_path(self, path: str) -> Dict[str, List[Node]]: """ Select and group nodes whose names match a given regular expression. - This method uses re.match(), so the pattern is anchored at the start - of the node name. If the pattern includes capturing groups, - the group label is formed by joining all non-None captures with '|'. - If no capturing groups exist, the group label is the original - pattern string. + Uses re.match(), so the pattern is anchored at the start of the node name. + If the pattern includes capturing groups, the group label is formed by + joining all non-None captures with '|'. If no capturing groups exist, + the group label is the original pattern string. Args: - path: A Python regular expression pattern (e.g., "^foo", "bar(\\d+)", etc.). + path (str): A Python regular expression pattern (e.g., "^foo", "bar(\\d+)", etc.). Returns: Dict[str, List[Node]]: A mapping from group label -> list of matching nodes. @@ -205,9 +210,9 @@ def select_node_groups_by_path(self, path: str) -> Dict[str, List[Node]]: groups_map: Dict[str, List[Node]] = {} for node in self.nodes.values(): - m = pattern.match(node.name) - if m: - captures = m.groups() + match = pattern.match(node.name) + if match: + captures = match.groups() if captures: label = "|".join(c for c in captures if c is not None) else: @@ -226,24 +231,25 @@ def max_flow( ) -> Dict[Tuple[str, str], float]: """ Compute maximum flow between groups of source nodes and sink nodes. + Returns a dictionary of flow values keyed by (source_label, sink_label). Args: - source_path: Regex pattern for selecting source nodes. - sink_path: Regex pattern for selecting sink nodes. - mode: Either "combine" or "pairwise". + source_path (str): Regex pattern for selecting source nodes. + sink_path (str): Regex pattern for selecting sink nodes. + mode (str): Either "combine" or "pairwise". - "combine": Treat all matched sources as one group, - and all matched sinks as one group. Returns a single dict entry. + and all matched sinks as one group. Returns a single entry. - "pairwise": Compute flow for each (source_group, sink_group) pair. - shortest_path: If True, flows are constrained to shortest paths. - flow_placement: Determines how parallel equal-cost paths are handled. + shortest_path (bool): If True, flows are constrained to shortest paths. + flow_placement (FlowPlacement): Determines how parallel equal-cost paths + are handled. Returns: - Dict[Tuple[str, str], float]: Flow values for each (src_label, snk_label) pair. + Dict[Tuple[str, str], float]: Flow values keyed by (src_label, snk_label). Raises: - ValueError: If no matching source or sink groups are found, - or if the mode is invalid. + ValueError: If no matching source or sink groups are found, or invalid mode. """ src_groups = self.select_node_groups_by_path(source_path) snk_groups = self.select_node_groups_by_path(sink_path) @@ -293,7 +299,7 @@ def _compute_flow_single_group( sources: List[Node], sinks: List[Node], shortest_path: bool, - flow_placement: FlowPlacement, + flow_placement: Optional[FlowPlacement], ) -> float: """ Attach a pseudo-source and pseudo-sink to the provided node lists, @@ -303,16 +309,20 @@ def _compute_flow_single_group( Disabled nodes are excluded from flow computation. Args: - sources: List of source nodes. - sinks: List of sink nodes. - shortest_path: If True, use only shortest paths for flow. - flow_placement: Strategy for placing flow among parallel equal-cost paths. + sources (List[Node]): List of source nodes. + sinks (List[Node]): List of sink nodes. + shortest_path (bool): If True, restrict flows to shortest paths only. + flow_placement (FlowPlacement or None): Strategy for placing flow among + parallel equal-cost paths. If None, defaults to FlowPlacement.PROPORTIONAL. Returns: - float: The computed maximum flow value, or 0.0 if there are no active sources or sinks. + float: The computed max flow value, or 0.0 if no active sources or sinks. """ - active_sources = [s for s in sources if not s.attrs.get("disabled", False)] - active_sinks = [s for s in sinks if not s.attrs.get("disabled", False)] + if flow_placement is None: + flow_placement = FlowPlacement.PROPORTIONAL + + active_sources = [s for s in sources if not s.disabled] + active_sinks = [s for s in sinks if not s.disabled] if not active_sources or not active_sinks: return 0.0 @@ -321,8 +331,11 @@ def _compute_flow_single_group( graph.add_node("source") graph.add_node("sink") + # Connect pseudo-source to active sources for src_node in active_sources: graph.add_edge("source", src_node.name, capacity=float("inf"), cost=0) + + # Connect active sinks to pseudo-sink for sink_node in active_sinks: graph.add_edge(sink_node.name, "sink", capacity=float("inf"), cost=0) @@ -340,85 +353,86 @@ def disable_node(self, node_name: str) -> None: Mark a node as disabled. Args: - node_name: Name of the node to disable. + node_name (str): Name of the node to disable. Raises: ValueError: If the specified node does not exist. """ if node_name not in self.nodes: raise ValueError(f"Node '{node_name}' does not exist.") - self.nodes[node_name].attrs["disabled"] = True + self.nodes[node_name].disabled = True def enable_node(self, node_name: str) -> None: """ Mark a node as enabled. Args: - node_name: Name of the node to enable. + node_name (str): Name of the node to enable. Raises: ValueError: If the specified node does not exist. """ if node_name not in self.nodes: raise ValueError(f"Node '{node_name}' does not exist.") - self.nodes[node_name].attrs["disabled"] = False + self.nodes[node_name].disabled = False def disable_link(self, link_id: str) -> None: """ Mark a link as disabled. Args: - link_id: ID of the link to disable. + link_id (str): ID of the link to disable. Raises: ValueError: If the specified link does not exist. """ if link_id not in self.links: raise ValueError(f"Link '{link_id}' does not exist.") - self.links[link_id].attrs["disabled"] = True + self.links[link_id].disabled = True def enable_link(self, link_id: str) -> None: """ Mark a link as enabled. Args: - link_id: ID of the link to enable. + link_id (str): ID of the link to enable. Raises: ValueError: If the specified link does not exist. """ if link_id not in self.links: raise ValueError(f"Link '{link_id}' does not exist.") - self.links[link_id].attrs["disabled"] = False + self.links[link_id].disabled = False def enable_all(self) -> None: """ Mark all nodes and links as enabled. """ for node in self.nodes.values(): - node.attrs["disabled"] = False + node.disabled = False for link in self.links.values(): - link.attrs["disabled"] = False + link.disabled = False def disable_all(self) -> None: """ Mark all nodes and links as disabled. """ for node in self.nodes.values(): - node.attrs["disabled"] = True + node.disabled = True for link in self.links.values(): - link.attrs["disabled"] = True + link.disabled = True def get_links_between(self, source: str, target: str) -> List[str]: """ - Retrieve all link IDs that connect the specified source node to the target node. + Retrieve all link IDs that connect the specified source node + to the target node. Args: - source: Name of the source node. - target: Name of the target node. + source (str): Source node name. + target (str): Target node name. Returns: - List[str]: All link IDs where (link.source == source and link.target == target). + List[str]: A list of link IDs for all direct links from source to target. """ matches = [] for link_id, link in self.links.items(): @@ -436,37 +450,97 @@ def find_links( Search for links using optional regex patterns for source or target node names. Args: - source_regex: Regex pattern to match link.source. If None, matches all. - target_regex: Regex pattern to match link.target. If None, matches all. - any_direction: If True, also match links where source and target are reversed. + source_regex (str or None): Regex to match link.source. If None, matches all sources. + target_regex (str or None): Regex to match link.target. If None, matches all targets. + any_direction (bool): If True, also match reversed source/target. Returns: - List[Link]: A list of Link objects that match the provided criteria. - If both patterns are None, returns all links. + List[Link]: A list of unique Link objects that match the criteria. """ - if source_regex: - src_pat = re.compile(source_regex) - else: - src_pat = None - if target_regex: - tgt_pat = re.compile(target_regex) - else: - tgt_pat = None + src_pat = re.compile(source_regex) if source_regex else None + tgt_pat = re.compile(target_regex) if target_regex else None results = [] + seen_ids = set() + for link in self.links.values(): - if src_pat and not src_pat.search(link.source): - continue - if tgt_pat and not tgt_pat.search(link.target): - continue - results.append(link) + forward_match = (not src_pat or src_pat.search(link.source)) and ( + not tgt_pat or tgt_pat.search(link.target) + ) + reverse_match = False + if any_direction: + reverse_match = (not src_pat or src_pat.search(link.target)) and ( + not tgt_pat or tgt_pat.search(link.source) + ) - if any_direction: - for link in self.links.values(): - if src_pat and not src_pat.search(link.target): - continue - if tgt_pat and not tgt_pat.search(link.source): - continue - results.append(link) + if forward_match or reverse_match: + if link.id not in seen_ids: + results.append(link) + seen_ids.add(link.id) return results + + def disable_risk_group(self, name: str, recursive: bool = True) -> None: + """ + Disable all nodes/links that have 'name' in their risk_groups. + If recursive=True, also disable items belonging to child risk groups. + + Args: + name (str): The name of the risk group to disable. + recursive (bool): If True, also disable subgroups recursively. + """ + if name not in self.risk_groups: + return + + to_disable: Set[str] = set() + queue = [self.risk_groups[name]] + while queue: + grp = queue.pop() + to_disable.add(grp.name) + if recursive: + queue.extend(grp.children) + + # Disable nodes + for node_name, node_obj in self.nodes.items(): + if node_obj.risk_groups & to_disable: + self.disable_node(node_name) + + # Disable links + for link_id, link_obj in self.links.items(): + if link_obj.risk_groups & to_disable: + self.disable_link(link_id) + + def enable_risk_group(self, name: str, recursive: bool = True) -> None: + """ + Enable all nodes/links that have 'name' in their risk_groups. + If recursive=True, also enable items belonging to child risk groups. + + Note: + If a node or link is in multiple risk groups, enabling this group + will re-enable that node/link even if other groups containing it + remain disabled. + + Args: + name (str): The name of the risk group to enable. + recursive (bool): If True, also enable subgroups recursively. + """ + if name not in self.risk_groups: + return + + to_enable: Set[str] = set() + queue = [self.risk_groups[name]] + while queue: + grp = queue.pop() + to_enable.add(grp.name) + if recursive: + queue.extend(grp.children) + + # Enable nodes + for node_name, node_obj in self.nodes.items(): + if node_obj.risk_groups & to_enable: + self.enable_node(node_name) + + # Enable links + for link_id, link_obj in self.links.items(): + if link_obj.risk_groups & to_enable: + self.enable_link(link_id) diff --git a/ngraph/scenario.py b/ngraph/scenario.py index 988f716..c43ff53 100644 --- a/ngraph/scenario.py +++ b/ngraph/scenario.py @@ -4,8 +4,12 @@ from dataclasses import dataclass, field from typing import Any, Dict, List, Optional -from ngraph.network import Network -from ngraph.failure_policy import FailurePolicy, FailureRule, FailureCondition +from ngraph.network import Network, RiskGroup +from ngraph.failure_policy import ( + FailurePolicy, + FailureRule, + FailureCondition, +) from ngraph.traffic_demand import TrafficDemand from ngraph.results import Results from ngraph.workflow.base import WorkflowStep, WORKFLOW_STEP_REGISTRY @@ -19,7 +23,7 @@ class Scenario: Represents a complete scenario for building and executing network workflows. This scenario includes: - - A network (nodes and links), constructed via blueprint expansion. + - A network (nodes/links), constructed via blueprint expansion. - A failure policy (one or more rules). - A set of traffic demands. - A list of workflow steps to execute. @@ -31,18 +35,10 @@ class Scenario: scenario = Scenario.from_yaml(yaml_str, default_components=default_lib) scenario.run() # Inspect scenario.results - - Attributes: - network (Network): The network model containing nodes and links. - failure_policy (FailurePolicy): Defines how and which entities fail. - traffic_demands (List[TrafficDemand]): Describes source/target flows. - workflow (List[WorkflowStep]): Defines the execution pipeline. - results (Results): Stores outputs from the workflow steps. - components_library (ComponentsLibrary): Stores hardware/optics definitions. """ network: Network - failure_policy: FailurePolicy + failure_policy: Optional[FailurePolicy] traffic_demands: List[TrafficDemand] workflow: List[WorkflowStep] results: Results = field(default_factory=Results) @@ -50,10 +46,10 @@ class Scenario: def run(self) -> None: """ - Executes the scenario's workflow steps in the defined order. + Executes the scenario's workflow steps in order. - Each step may access and modify scenario data, or store outputs in - scenario.results. + Each step may modify scenario data or store outputs + in scenario.results. """ for step in self.workflow: step.run(self) @@ -68,35 +64,64 @@ def from_yaml( Constructs a Scenario from a YAML string, optionally merging with a default ComponentsLibrary if provided. - Expected top-level YAML keys: - - blueprints: Optional blueprint definitions. - - network: Network DSL referencing blueprints or direct node/link definitions. - - failure_policy: Multi-rule policy definition. - - traffic_demands: A list of demands (source, target, amount). - - workflow: Steps to execute in sequence. - - components: Optional dictionary defining scenario-specific components. + Top-level YAML keys can include: + - blueprints + - network + - failure_policy + - traffic_demands + - workflow + - components + - risk_groups + + If no 'workflow' key is provided, the scenario has no steps to run. + If 'failure_policy' is omitted, scenario.failure_policy is None. + If 'components' is provided, it is merged with default_components. + If any unrecognized top-level key is found, a ValueError is raised. Args: yaml_str (str): The YAML string that defines the scenario. - default_components (Optional[ComponentsLibrary]): An optional default - library to merge with scenario-specific components. + default_components (ComponentsLibrary, optional): + A default library to merge with scenario-specific components. Returns: Scenario: An initialized Scenario with expanded network. Raises: - ValueError: If the YAML is malformed or missing required sections. + ValueError: If the YAML is malformed or missing required sections, + or if there are any unrecognized top-level keys. + TypeError: If a workflow step's arguments are invalid for the step class. """ data = yaml.safe_load(yaml_str) + if data is None: + data = {} if not isinstance(data, dict): raise ValueError("The provided YAML must map to a dictionary at top-level.") + # Ensure only recognized top-level keys are present. + recognized_keys = { + "blueprints", + "network", + "failure_policy", + "traffic_demands", + "workflow", + "components", + "risk_groups", + } + extra_keys = set(data.keys()) - recognized_keys + if extra_keys: + raise ValueError( + f"Unrecognized top-level key(s) in scenario: {', '.join(sorted(extra_keys))}. " + f"Allowed keys are {sorted(recognized_keys)}" + ) + # 1) Build the network using blueprint expansion logic - network = expand_network_dsl(data) + network_obj = expand_network_dsl(data) + if network_obj is None: + network_obj = Network() - # 2) Build the multi-rule failure policy + # 2) Build the multi-rule failure policy (may be empty or None) fp_data = data.get("failure_policy", {}) - failure_policy = cls._build_failure_policy(fp_data) + failure_policy = cls._build_failure_policy(fp_data) if fp_data else None # 3) Build traffic demands traffic_demands_data = data.get("traffic_demands", []) @@ -113,67 +138,122 @@ def from_yaml( if scenario_comps_data else None ) - final_components = ( default_components.clone() if default_components else ComponentsLibrary() ) if scenario_comps_lib: final_components.merge(scenario_comps_lib) + # 6) Parse optional risk_groups, then attach them to the network + rg_data = data.get("risk_groups", []) + if rg_data: + risk_groups = cls._build_risk_groups(rg_data) + for rg in risk_groups: + network_obj.risk_groups[rg.name] = rg + if rg.disabled: + network_obj.disable_risk_group(rg.name, recursive=True) + return cls( - network=network, + network=network_obj, failure_policy=failure_policy, traffic_demands=traffic_demands, workflow=workflow_steps, components_library=final_components, ) + @staticmethod + def _build_risk_groups(rg_data: List[Dict[str, Any]]) -> List[RiskGroup]: + """ + Recursively builds a list of RiskGroup objects from YAML data. + + Each entry may have keys: "name", "children", "disabled", and "attrs" (dict). + + Args: + rg_data (List[Dict[str, Any]]): The list of risk-group definitions. + + Returns: + List[RiskGroup]: Possibly nested risk groups. + + Raises: + ValueError: If any group is missing 'name'. + """ + + def build_one(d: Dict[str, Any]) -> RiskGroup: + name = d.get("name") + if not name: + raise ValueError("RiskGroup entry missing 'name' field.") + disabled = d.get("disabled", False) + children_list = d.get("children", []) + child_objs = [build_one(cd) for cd in children_list] + attrs = d.get("attrs", {}) + return RiskGroup( + name=name, disabled=disabled, children=child_objs, attrs=attrs + ) + + return [build_one(entry) for entry in rg_data] + @staticmethod def _build_failure_policy(fp_data: Dict[str, Any]) -> FailurePolicy: """ - Constructs a FailurePolicy from data that may specify multiple rules. + Constructs a FailurePolicy from data that may specify multiple rules plus + optional top-level fields like fail_shared_risk_groups, fail_risk_group_children, + use_cache, and attrs. - Example structure: + Example: failure_policy: - name: "anySingleLink" - description: "Test single-link failures." + name: "test" # (Currently unused if present) fail_shared_risk_groups: true + fail_risk_group_children: false + use_cache: true + attrs: + custom_key: custom_val rules: - - conditions: - - attr: "type" - operator: "==" - value: "link" + - entity_scope: "node" + conditions: + - attr: "capacity" + operator: ">" + value: 100 logic: "and" rule_type: "choice" - count: 1 + count: 2 Args: - fp_data (Dict[str, Any]): Dictionary from the 'failure_policy' section. + fp_data (Dict[str, Any]): Dictionary from the 'failure_policy' section of the YAML. Returns: - FailurePolicy: A policy containing a list of FailureRule objects. + FailurePolicy: The constructed policy. If no rules exist, it's an empty policy. Raises: - ValueError: If 'rules' is not a list when provided. + ValueError: If 'rules' is present but not a list, or if conditions are not lists. """ + fail_srg = fp_data.get("fail_shared_risk_groups", False) + fail_rg_children = fp_data.get("fail_risk_group_children", False) + use_cache = fp_data.get("use_cache", False) + attrs = fp_data.get("attrs", {}) + + # Extract rules rules_data = fp_data.get("rules", []) if not isinstance(rules_data, list): raise ValueError("failure_policy 'rules' must be a list if present.") rules: List[FailureRule] = [] for rule_dict in rules_data: + entity_scope = rule_dict.get("entity_scope", "node") conditions_data = rule_dict.get("conditions", []) + if not isinstance(conditions_data, list): + raise ValueError("Each rule's 'conditions' must be a list if present.") conditions: List[FailureCondition] = [] for cond_dict in conditions_data: - # Rely on KeyError to surface missing required fields - condition = FailureCondition( - attr=cond_dict["attr"], - operator=cond_dict["operator"], - value=cond_dict["value"], + conditions.append( + FailureCondition( + attr=cond_dict["attr"], + operator=cond_dict["operator"], + value=cond_dict["value"], + ) ) - conditions.append(condition) rule = FailureRule( + entity_scope=entity_scope, conditions=conditions, logic=rule_dict.get("logic", "and"), rule_type=rule_dict.get("rule_type", "all"), @@ -182,38 +262,43 @@ def _build_failure_policy(fp_data: Dict[str, Any]) -> FailurePolicy: ) rules.append(rule) - # Put any extra keys (like "name" or "description") into policy.attrs - attrs = {k: v for k, v in fp_data.items() if k != "rules"} - - return FailurePolicy(rules=rules, attrs=attrs) + return FailurePolicy( + rules=rules, + attrs=attrs, + fail_shared_risk_groups=fail_srg, + fail_risk_group_children=fail_rg_children, + use_cache=use_cache, + ) @staticmethod def _build_workflow_steps( workflow_data: List[Dict[str, Any]], ) -> List[WorkflowStep]: """ - Converts workflow step dictionaries into instantiated WorkflowStep objects. + Converts workflow step dictionaries into WorkflowStep objects. Each step dict must have a "step_type" referencing a registered workflow - step in WORKFLOW_STEP_REGISTRY. Additional keys are passed to that step's init. - - Example: - workflow: - - step_type: BuildGraph - name: build_graph - - step_type: ComputeRoutes - name: compute_routes + step in WORKFLOW_STEP_REGISTRY. All other keys in the dict are passed + to that step's constructor as keyword arguments. Args: - workflow_data (List[Dict[str, Any]]): A list of dictionaries, each - describing a workflow step. + workflow_data (List[Dict[str, Any]]): A list of dictionaries describing + each workflow step, for example: + [ + { + "step_type": "MyStep", + "arg1": "value1", + "arg2": "value2", + }, + ... + ] Returns: - List[WorkflowStep]: A list of WorkflowStep instances. + List[WorkflowStep]: A list of instantiated WorkflowStep objects. Raises: - ValueError: If workflow_data is not a list, or if any entry - lacks "step_type" or references an unknown step type. + ValueError: If any step lacks "step_type" or references an unknown type. + TypeError: If step initialization fails due to invalid arguments. """ if not isinstance(workflow_data, list): raise ValueError("'workflow' must be a list if present.") @@ -224,12 +309,15 @@ def _build_workflow_steps( if not step_type: raise ValueError( "Each workflow entry must have a 'step_type' field " - "to indicate the WorkflowStep subclass to use." + "indicating the WorkflowStep subclass to use." ) + step_cls = WORKFLOW_STEP_REGISTRY.get(step_type) if not step_cls: raise ValueError(f"Unrecognized 'step_type': {step_type}") - step_args = {k: v for k, v in step_info.items() if k != "step_type"} - steps.append(step_cls(**step_args)) + ctor_args = {k: v for k, v in step_info.items() if k != "step_type"} + step_obj = step_cls(**ctor_args) + steps.append(step_obj) + return steps diff --git a/notebooks/scenario_dc.ipynb b/notebooks/scenario_dc.ipynb index c4364b4..7e22768 100644 --- a/notebooks/scenario_dc.ipynb +++ b/notebooks/scenario_dc.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 9, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -18,14 +18,15 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "scenario_yaml = \"\"\"\n", "blueprints:\n", " server_pod:\n", - " rsw:\n", + " groups:\n", + " rsw:\n", " node_count: 48\n", " attrs:\n", " hw_component: Minipack2_128x200GE\n", @@ -178,16 +179,16 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Node(name='dc1/plane1/ssw/ssw-1', attrs={'hw_component': 'Minipack2_128x200GE', 'type': 'node', 'disabled': False})" + "Node(name='dc1/plane1/ssw/ssw-1', disabled=False, risk_groups=set(), attrs={'hw_component': 'Minipack2_128x200GE', 'type': 'node'})" ] }, - "execution_count": 11, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -198,7 +199,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -207,7 +208,7 @@ "Component(name='Minipack2_128x200GE', component_type='router', description='', cost=0.0, power_watts=1750.0, power_watts_max=0.0, capacity=0.0, ports=0, count=1, attrs={}, children={})" ] }, - "execution_count": 12, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -219,7 +220,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -228,7 +229,7 @@ "{('.*/fsw.*', '.*/eb.*'): 819200.0}" ] }, - "execution_count": 13, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -244,288 +245,7 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 6762378 function calls (6746975 primitive calls) in 2.177 seconds\n", - "\n", - " Ordered by: internal time\n", - "\n", - " ncalls tottime percall cumtime percall filename:lineno(function)\n", - " 339840 0.399 0.000 1.184 0.000 /Users/networmix/ws/NetGraph/ngraph/lib/graph.py:143(add_edge)\n", - " 339840 0.253 0.000 0.269 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/coreviews.py:81(__getitem__)\n", - " 1 0.251 0.251 0.274 0.274 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/spf.py:94(_spf_fast_all_min_cost_with_cap_remaining_dijkstra)\n", - " 339840 0.237 0.000 0.327 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/multidigraph.py:417(add_edge)\n", - " 1 0.165 0.165 0.189 0.189 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/calc_capacity.py:10(_init_graph_data)\n", - " 1 0.155 0.155 1.281 1.281 /Users/networmix/ws/NetGraph/ngraph/network.py:131(to_strict_multidigraph)\n", - " 4/2 0.068 0.017 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/events.py:87(_run)\n", - " 1 0.061 0.061 0.111 0.111 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/flow_init.py:6(init_flow_graph)\n", - " 339840 0.056 0.000 0.073 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/coreviews.py:103(__getitem__)\n", - " 1 0.053 0.053 0.303 0.303 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/calc_capacity.py:294(calc_graph_capacity)\n", - " 725446 0.052 0.000 0.052 0.000 {method 'setdefault' of 'dict' objects}\n", - " 685700 0.044 0.000 0.044 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/graph.py:462(__contains__)\n", - " 339840 0.039 0.000 0.112 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/graph.py:498(__getitem__)\n", - " 345859 0.036 0.000 0.036 0.000 {method 'update' of 'dict' objects}\n", - " 345858 0.034 0.000 0.051 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/utils/misc.py:595(_clear_cache)\n", - " 679681 0.033 0.000 0.033 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/coreviews.py:44(__init__)\n", - " 15393/1 0.029 0.000 0.035 0.035 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/calc_capacity.py:178(_push_flow_dfs)\n", - " 1 0.023 0.023 0.339 0.339 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/place_flow.py:29(place_flow_on_graph)\n", - " 279548 0.020 0.000 0.020 0.000 {method 'get' of 'dict' objects}\n", - " 373200 0.020 0.000 0.020 0.000 {method 'items' of 'dict' objects}\n", - " 339840 0.017 0.000 0.017 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/coreviews.py:53(__getitem__)\n", - " 345866 0.016 0.000 0.016 0.000 {built-in method builtins.getattr}\n", - " 341568 0.013 0.000 0.013 0.000 {built-in method builtins.abs}\n", - " 182336 0.012 0.000 0.017 0.000 {built-in method builtins.sum}\n", - " 2 0.011 0.006 0.012 0.006 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/calc_capacity.py:148(_set_levels_bfs)\n", - " 177732 0.010 0.000 0.010 0.000 {method 'append' of 'list' objects}\n", - " 24128 0.006 0.000 0.006 0.000 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/place_flow.py:104()\n", - " 1 0.005 0.005 2.040 2.040 /Users/networmix/ws/NetGraph/ngraph/network.py:291(_compute_flow_single_group)\n", - " 2 0.005 0.002 0.030 0.015 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/sugar/socket.py:709(send_multipart)\n", - " 3872 0.004 0.000 0.004 0.000 {built-in method posix.urandom}\n", - " 6018 0.004 0.000 0.004 0.000 {built-in method _heapq.heappop}\n", - " 3872 0.004 0.000 0.005 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/uuid.py:142(__init__)\n", - " 1744 0.003 0.000 0.007 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/ipykernel/ipkernel.py:775(_clean_thread_parent_frames)\n", - " 41412 0.003 0.000 0.003 0.000 {method 'add' of 'set' objects}\n", - " 6018 0.003 0.000 0.004 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/digraph.py:439(add_node)\n", - " 2 0.002 0.001 0.075 0.037 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/ipykernel/iostream.py:278(_really_send)\n", - " 6018 0.002 0.000 0.007 0.000 /Users/networmix/ws/NetGraph/ngraph/lib/graph.py:104(add_node)\n", - " 1 0.002 0.002 0.726 0.726 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/max_flow.py:8(calc_max_flow)\n", - " 2 0.002 0.001 0.005 0.002 /Users/networmix/ws/NetGraph/ngraph/network.py:188(select_node_groups_by_path)\n", - " 2/1 0.002 0.001 0.006 0.006 {method 'control' of 'select.kqueue' objects}\n", - " 12032 0.002 0.000 0.002 0.000 {method 'match' of 're.Pattern' objects}\n", - " 3872 0.002 0.000 0.015 0.000 /Users/networmix/ws/NetGraph/ngraph/lib/graph.py:11(new_base64_uuid)\n", - " 872 0.001 0.000 0.002 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:1477(enumerate)\n", - " 3872 0.001 0.000 0.010 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/uuid.py:710(uuid4)\n", - " 14 0.001 0.000 0.007 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/sugar/socket.py:632(send)\n", - " 1 0.001 0.001 0.006 0.006 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/IPython/core/history.py:845(writeout_cache)\n", - " 2 0.001 0.000 0.063 0.032 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/eventloop/zmqstream.py:547(_run_callback)\n", - " 6976 0.001 0.000 0.001 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:1110(ident)\n", - " 3872 0.001 0.000 0.002 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/base64.py:112(urlsafe_b64encode)\n", - " 15393 0.001 0.000 0.001 0.000 {built-in method builtins.min}\n", - " 2 0.001 0.000 0.001 0.000 /Users/networmix/ws/NetGraph/ngraph/lib/graph.py:254(get_nodes)\n", - " 12076 0.001 0.000 0.001 0.000 {method 'popleft' of 'collections.deque' objects}\n", - " 12073 0.001 0.000 0.001 0.000 {method 'append' of 'collections.deque' objects}\n", - " 3872 0.001 0.000 0.001 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/uuid.py:288(bytes)\n", - " 3872 0.000 0.000 0.015 0.000 /Users/networmix/ws/NetGraph/ngraph/lib/graph.py:64(new_edge_key)\n", - " 3872 0.000 0.000 0.001 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/base64.py:51(b64encode)\n", - " 6017 0.000 0.000 0.000 0.000 {built-in method _heapq.heappush}\n", - "5756/5752 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance}\n", - " 3872 0.000 0.000 0.000 0.000 {method 'to_bytes' of 'int' objects}\n", - " 3872 0.000 0.000 0.000 0.000 {method 'count' of 'list' objects}\n", - " 3872 0.000 0.000 0.000 0.000 {method 'translate' of 'bytes' objects}\n", - " 3490 0.000 0.000 0.000 0.000 {method 'keys' of 'dict' objects}\n", - " 3872 0.000 0.000 0.000 0.000 {method 'decode' of 'bytes' objects}\n", - " 3872 0.000 0.000 0.000 0.000 {built-in method binascii.b2a_base64}\n", - " 3872 0.000 0.000 0.000 0.000 {built-in method from_bytes}\n", - " 3887 0.000 0.000 0.000 0.000 {built-in method builtins.len}\n", - " 1750 0.000 0.000 0.000 0.000 {method 'values' of 'dict' objects}\n", - " 3872 0.000 0.000 0.000 0.000 {method 'groups' of 're.Match' objects}\n", - " 873 0.000 0.000 0.000 0.000 {method '__exit__' of '_thread.RLock' objects}\n", - " 4 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/sugar/attrsettr.py:66(_get_attr_opt)\n", - " 2 0.000 0.000 0.000 0.000 {built-in method builtins.compile}\n", - " 15 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/enum.py:1592(__or__)\n", - " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", - " 63 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/enum.py:1585(_get_value)\n", - " 2/1 0.000 0.000 0.006 0.006 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py:1953(_run_once)\n", - " 27 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/enum.py:695(__call__)\n", - " 4 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/sugar/attrsettr.py:43(__getattr__)\n", - " 1 0.000 0.000 0.000 0.000 {method 'execute' of 'sqlite3.Connection' objects}\n", - " 2 0.000 0.000 0.000 0.000 {method 'recv' of '_socket.socket' objects}\n", - " 27 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/enum.py:1152(__new__)\n", - " 2/1 0.000 0.000 0.006 0.006 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/selectors.py:540(select)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:3120(_bind)\n", - " 1 0.000 0.000 0.013 0.013 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/IPython/core/history.py:55(only_when_enabled)\n", - " 2 0.000 0.000 0.000 0.000 {method '__exit__' of 'sqlite3.Connection' objects}\n", - " 3 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/eventloop/zmqstream.py:654(_rebuild_io_state)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/ipykernel/kernelbase.py:302(poll_control_queue)\n", - " 8 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:676(__get__)\n", - " 1 0.000 0.000 0.000 0.000 {method 'send' of '_socket.socket' objects}\n", - " 6 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/enum.py:1603(__and__)\n", - " 6 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/typing.py:426(inner)\n", - " 3 0.000 0.000 0.000 0.000 {method 'run' of '_contextvars.Context' objects}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/sugar/socket.py:780(recv_multipart)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py:3495(compare)\n", - " 3 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/eventloop/zmqstream.py:677(_update_handler)\n", - " 2 0.000 0.000 0.075 0.037 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/ipykernel/iostream.py:276()\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/digraph.py:334(__init__)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/typing.py:1665(__subclasscheck__)\n", - " 4 0.000 0.000 0.000 0.000 {method 'extend' of 'list' objects}\n", - " 1 0.000 0.000 0.025 0.025 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/decorator.py:229(fun)\n", - " 8 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:629(get)\n", - " 3 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py:847(_call_soon)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph/lib/graph.py:49(__init__)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/codeop.py:113(__call__)\n", - " 3 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/queue.py:115(empty)\n", - " 4 0.000 0.000 0.000 0.000 :1390(_handle_fromlist)\n", - " 3 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py:767(time)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/functools.py:1023(__get__)\n", - " 9 0.000 0.000 0.000 0.000 {built-in method builtins.hasattr}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/platform/asyncio.py:225(add_callback)\n", - " 10 0.000 0.000 0.000 0.000 {built-in method builtins.next}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/decorator.py:199(fix)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/typing.py:1374(__instancecheck__)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/selector_events.py:129(_read_from_self)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:225(get)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/concurrent/futures/_base.py:537(set_result)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/eventloop/zmqstream.py:574(_handle_events)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:3259(bind)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:209(put_nowait)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:689(set)\n", - " 1 0.000 0.000 0.274 0.274 /Users/networmix/ws/NetGraph/ngraph/lib/algorithms/spf.py:159(spf)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:3631(set)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/ipykernel/iostream.py:213(_is_master_process)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:186(put)\n", - " 4 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/typing.py:1443(__hash__)\n", - " 3 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/events.py:36(__init__)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:3474(validate)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py:108(__init__)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:1527(_notify_observers)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:718(_validate)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/multidigraph.py:302(__init__)\n", - " 2 0.000 0.000 0.062 0.031 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/ipykernel/iostream.py:157(_handle_event)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/ioloop.py:742(_run_callback)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:727(_cross_validate)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py:303(helper)\n", - " 2 0.000 0.000 0.000 0.000 {built-in method _abc._abc_subclasscheck}\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:2934(apply_defaults)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/re/__init__.py:330(_compile)\n", - " 1 0.000 0.000 0.000 0.000 /var/folders/xh/83kdwyfd0fv66b04mchbfzcc0000gn/T/ipykernel_98256/1424787899.py:1()\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:315(_acquire_restore)\n", - " 3 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/reportviews.py:207(__call__)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:3624(validate_elements)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:322(_consume_expired)\n", - " 3 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:303(__enter__)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:631(clear)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/reportviews.py:333(__iter__)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/eventloop/zmqstream.py:615(_handle_recv)\n", - " 3 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/eventloop/zmqstream.py:533(sending)\n", - " 5 0.000 0.000 0.000 0.000 {built-in method builtins.iter}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/IPython/core/history.py:833(_writeout_input_cache)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/graph.py:745(nodes)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:708(__set__)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py:818(call_soon)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/futures.py:391(_call_set_state)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/ipykernel/iostream.py:216(_check_mp_mode)\n", - " 4 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/IPython/core/compilerop.py:180(extra_flags)\n", - " 2 0.000 0.000 0.000 0.000 {built-in method builtins.issubclass}\n", - " 2 0.000 0.000 0.000 0.000 {built-in method builtins.sorted}\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py:145(__exit__)\n", - " 1/0 0.000 0.000 0.000 {built-in method builtins.exec}\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/selector_events.py:141(_write_to_self)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:2881(args)\n", - " 3 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:306(__exit__)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:2304(validate)\n", - " 2 0.000 0.000 0.000 0.000 :121(__subclasscheck__)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:317(__put_internal)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:256(get_nowait)\n", - " 2 0.000 0.000 0.000 0.000 {method 'set_result' of '_asyncio.Future' objects}\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/re/__init__.py:287(compile)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py:871(call_soon_threadsafe)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/IPython/core/history.py:839(_writeout_output_cache)\n", - " 28 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/typing.py:2367(cast)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:428(notify_all)\n", - " 4 0.000 0.000 0.000 0.000 {method 'upper' of 'str' objects}\n", - " 1/0 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py:3543(run_code)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:1523(notify_change)\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py:136(__enter__)\n", - " 1 0.000 0.000 0.000 0.000 {method 'values' of 'mappingproxy' objects}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:1512(_notify_trait)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/concurrent.py:182(future_set_result_unless_cancelled)\n", - " 4 0.000 0.000 0.000 0.000 {built-in method builtins.max}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/graph.py:63(__set__)\n", - " 3 0.000 0.000 0.000 0.000 {built-in method time.monotonic}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/multidigraph.py:365(adj)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:2904(kwargs)\n", - " 3 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/queue.py:267(_qsize)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/concurrent/futures/_base.py:337(_invoke_callbacks)\n", - " 1 0.000 0.000 0.000 0.000 :2(__init__)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:312(_release_save)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/eventloop/zmqstream.py:685()\n", - " 7 0.000 0.000 0.000 0.000 {method '__exit__' of '_thread.lock' objects}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:312(_put)\n", - " 2 0.000 0.000 0.000 0.000 {built-in method _contextvars.copy_context}\n", - " 3 0.000 0.000 0.000 0.000 {method 'items' of 'mappingproxy' objects}\n", - " 3 0.000 0.000 0.000 0.000 {method 'acquire' of '_thread.lock' objects}\n", - " 2 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/selector_events.py:740(_process_events)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:398(notify)\n", - " 4 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/zmq/eventloop/zmqstream.py:529(receiving)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/digraph.py:41(__set__)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/traitlets/traitlets.py:3486(validate_elements)\n", - " 10 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:2791(kind)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/reportviews.py:187(__iter__)\n", - " 2 0.000 0.000 0.000 0.000 {built-in method posix.getpid}\n", - " 4 0.000 0.000 0.000 0.000 {built-in method builtins.hash}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/digraph.py:78(__set__)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py:1277(user_global_ns)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/reportviews.py:180(__init__)\n", - " 3 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph/lib/graph.py:263(get_edges)\n", - " 5 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py:2051(get_debug)\n", - " 1 0.000 0.000 0.000 0.000 {built-in method _asyncio.get_running_loop}\n", - " 1 0.000 0.000 0.000 0.000 {method '__enter__' of '_thread.RLock' objects}\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/unix_events.py:83(_process_self_data)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:173(qsize)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:309(_get)\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:177(empty)\n", - " 2 0.000 0.000 0.000 0.000 {method '__enter__' of '_thread.lock' objects}\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/ipykernel/iostream.py:255(closed)\n", - " 4 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:2779(name)\n", - " 2 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/networkx/classes/reportviews.py:315(__init__)\n", - " 2 0.000 0.000 0.000 0.000 {method 'cancelled' of '_asyncio.Future' objects}\n", - " 1 0.000 0.000 0.000 0.000 {method 'done' of '_asyncio.Future' objects}\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:2873(__init__)\n", - " 2 0.000 0.000 0.000 0.000 {method 'join' of 'str' objects}\n", - " 4 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/inspect.py:3074(parameters)\n", - " 3 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py:549(_check_closed)\n", - " 1 0.000 0.000 0.000 0.000 {method '_is_owned' of '_thread.RLock' objects}\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/threading.py:318(_is_owned)\n", - " 1 0.000 0.000 0.000 0.000 {built-in method _thread.allocate_lock}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/queues.py:59(_set_timeout)\n", - " 1 0.000 0.000 0.000 0.000 {method 'release' of '_thread.lock' objects}\n", - " 1 0.000 0.000 0.000 0.000 /Users/networmix/ws/NetGraph/ngraph-venv/lib/python3.13/site-packages/tornado/locks.py:224(clear)\n", - " 1 0.000 0.000 0.000 0.000 /opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py:753(is_closed)\n", - "\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Profiling\n", - "import cProfile\n", - "import pstats\n", - "\n", - "profiler = cProfile.Profile()\n", - "profiler.enable()\n", - "\n", - "network.max_flow(\n", - " source_path=\".*/fsw.*\",\n", - " sink_path=\".*/eb.*\",\n", - " mode=\"combine\",\n", - " shortest_path=True,\n", - ")\n", - "\n", - "profiler.disable()\n", - "\n", - "stats = pstats.Stats(profiler)\n", - "stats.sort_stats(pstats.SortKey.TIME).print_stats()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -534,3402 +254,222 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "- root | Nodes=6016, Links=167984, Cost=0.0, Power=10472000.0 | IntLinkCap=35072000.0, ExtLinkCap=0.0\n", - " - dc1 | Nodes=1056, Links=32256, Cost=0.0, Power=1848000.0 | IntLinkCap=5529600.0, ExtLinkCap=921600.0\n", - " -> External to [fa/fa1/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa10/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa11/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa12/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa13/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa14/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa15/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa16/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa2/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa3/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa4/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa5/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa6/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa7/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa8/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa9/fadu]: 288 links, cap=57600.0\n", - " - plane1 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc1/plane1/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc1/plane1/ssw]: 3456 links, cap=691200.0\n", - " - plane2 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc1/plane2/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc1/plane2/ssw]: 3456 links, cap=691200.0\n", - " - plane3 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc1/plane3/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc1/plane3/ssw]: 3456 links, cap=691200.0\n", - " - plane4 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc1/plane4/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc1/plane4/ssw]: 3456 links, cap=691200.0\n", - " - plane5 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc1/plane5/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc1/plane5/ssw]: 3456 links, cap=691200.0\n", - " - plane6 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc1/plane6/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc1/plane6/ssw]: 3456 links, cap=691200.0\n", - " - plane7 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc1/plane7/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc1/plane7/ssw]: 3456 links, cap=691200.0\n", - " - plane8 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc1/plane8/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc1/plane8/ssw]: 3456 links, cap=691200.0\n", - " - dc2 | Nodes=1056, Links=32256, Cost=0.0, Power=1848000.0 | IntLinkCap=5529600.0, ExtLinkCap=921600.0\n", - " -> External to [fa/fa1/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa10/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa11/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa12/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa13/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa14/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa15/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa16/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa2/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa3/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa4/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa5/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa6/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa7/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa8/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa9/fadu]: 288 links, cap=57600.0\n", - " - plane1 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc2/plane1/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc2/plane1/ssw]: 3456 links, cap=691200.0\n", - " - plane2 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc2/plane2/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc2/plane2/ssw]: 3456 links, cap=691200.0\n", - " - plane3 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc2/plane3/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc2/plane3/ssw]: 3456 links, cap=691200.0\n", - " - plane4 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc2/plane4/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc2/plane4/ssw]: 3456 links, cap=691200.0\n", - " - plane5 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc2/plane5/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc2/plane5/ssw]: 3456 links, cap=691200.0\n", - " - plane6 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc2/plane6/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc2/plane6/ssw]: 3456 links, cap=691200.0\n", - " - plane7 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc2/plane7/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc2/plane7/ssw]: 3456 links, cap=691200.0\n", - " - plane8 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc2/plane8/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc2/plane8/ssw]: 3456 links, cap=691200.0\n", - " - dc3 | Nodes=1056, Links=32256, Cost=0.0, Power=1848000.0 | IntLinkCap=5529600.0, ExtLinkCap=921600.0\n", - " -> External to [fa/fa1/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa10/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa11/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa12/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa13/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa14/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa15/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa16/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa2/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa3/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa4/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa5/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa6/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa7/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa8/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa9/fadu]: 288 links, cap=57600.0\n", - " - plane1 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc3/plane1/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc3/plane1/ssw]: 3456 links, cap=691200.0\n", - " - plane2 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc3/plane2/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc3/plane2/ssw]: 3456 links, cap=691200.0\n", - " - plane3 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc3/plane3/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc3/plane3/ssw]: 3456 links, cap=691200.0\n", - " - plane4 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc3/plane4/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc3/plane4/ssw]: 3456 links, cap=691200.0\n", - " - plane5 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc3/plane5/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc3/plane5/ssw]: 3456 links, cap=691200.0\n", - " - plane6 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc3/plane6/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc3/plane6/ssw]: 3456 links, cap=691200.0\n", - " - plane7 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc3/plane7/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc3/plane7/ssw]: 3456 links, cap=691200.0\n", - " - plane8 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc3/plane8/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc3/plane8/ssw]: 3456 links, cap=691200.0\n", - " - dc5 | Nodes=1056, Links=32256, Cost=0.0, Power=1848000.0 | IntLinkCap=5529600.0, ExtLinkCap=921600.0\n", - " -> External to [fa/fa1/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa10/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa11/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa12/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa13/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa14/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa15/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa16/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa2/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa3/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa4/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa5/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa6/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa7/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa8/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa9/fadu]: 288 links, cap=57600.0\n", - " - plane1 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc5/plane1/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc5/plane1/ssw]: 3456 links, cap=691200.0\n", - " - plane2 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc5/plane2/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc5/plane2/ssw]: 3456 links, cap=691200.0\n", - " - plane3 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc5/plane3/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc5/plane3/ssw]: 3456 links, cap=691200.0\n", - " - plane4 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc5/plane4/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc5/plane4/ssw]: 3456 links, cap=691200.0\n", - " - plane5 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc5/plane5/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc5/plane5/ssw]: 3456 links, cap=691200.0\n", - " - plane6 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc5/plane6/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc5/plane6/ssw]: 3456 links, cap=691200.0\n", - " - plane7 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc5/plane7/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc5/plane7/ssw]: 3456 links, cap=691200.0\n", - " - plane8 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc5/plane8/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc5/plane8/ssw]: 3456 links, cap=691200.0\n", - " - dc6 | Nodes=1056, Links=32256, Cost=0.0, Power=1848000.0 | IntLinkCap=5529600.0, ExtLinkCap=921600.0\n", - " -> External to [fa/fa1/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa10/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa11/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa12/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa13/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa14/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa15/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa16/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa2/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa3/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa4/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa5/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa6/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa7/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa8/fadu]: 288 links, cap=57600.0\n", - " -> External to [fa/fa9/fadu]: 288 links, cap=57600.0\n", - " - plane1 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc6/plane1/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc6/plane1/ssw]: 3456 links, cap=691200.0\n", - " - plane2 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc6/plane2/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc6/plane2/ssw]: 3456 links, cap=691200.0\n", - " - plane3 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc6/plane3/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc6/plane3/ssw]: 3456 links, cap=691200.0\n", - " - plane4 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc6/plane4/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc6/plane4/ssw]: 3456 links, cap=691200.0\n", - " - plane5 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc6/plane5/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc6/plane5/ssw]: 3456 links, cap=691200.0\n", - " - plane6 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc6/plane6/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc6/plane6/ssw]: 3456 links, cap=691200.0\n", - " - plane7 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc6/plane7/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc6/plane7/ssw]: 3456 links, cap=691200.0\n", - " - plane8 | Nodes=132, Links=4032, Cost=0.0, Power=231000.0 | IntLinkCap=691200.0, ExtLinkCap=115200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=806400.0\n", - " -> External to [dc6/plane8/fsw]: 3456 links, cap=691200.0\n", - " -> External to [fa/fa1/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fadu]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fadu]: 36 links, cap=7200.0\n", - " - fsw | Nodes=96, Links=3456, Cost=0.0, Power=168000.0 | IntLinkCap=0.0, ExtLinkCap=691200.0\n", - " -> External to [dc6/plane8/ssw]: 3456 links, cap=691200.0\n", - " - fa | Nodes=704, Links=29696, Cost=0.0, Power=1232000.0 | IntLinkCap=1843200.0, ExtLinkCap=5427200.0\n", - " -> External to [dc1/plane1/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc1/plane2/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc1/plane3/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc1/plane4/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc1/plane5/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc1/plane6/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc1/plane7/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc1/plane8/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc2/plane1/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc2/plane2/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc2/plane3/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc2/plane4/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc2/plane5/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc2/plane6/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc2/plane7/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc2/plane8/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc3/plane1/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc3/plane2/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc3/plane3/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc3/plane4/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc3/plane5/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc3/plane6/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc3/plane7/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc3/plane8/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc5/plane1/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc5/plane2/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc5/plane3/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc5/plane4/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc5/plane5/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc5/plane6/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc5/plane7/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc5/plane8/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc6/plane1/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc6/plane2/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc6/plane3/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc6/plane4/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc6/plane5/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc6/plane6/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc6/plane7/ssw]: 576 links, cap=115200.0\n", - " -> External to [dc6/plane8/ssw]: 576 links, cap=115200.0\n", - " -> External to [ebb/eb01]: 256 links, cap=102400.0\n", - " -> External to [ebb/eb02]: 256 links, cap=102400.0\n", - " -> External to [ebb/eb03]: 256 links, cap=102400.0\n", - " -> External to [ebb/eb04]: 256 links, cap=102400.0\n", - " -> External to [ebb/eb05]: 256 links, cap=102400.0\n", - " -> External to [ebb/eb06]: 256 links, cap=102400.0\n", - " -> External to [ebb/eb07]: 256 links, cap=102400.0\n", - " -> External to [ebb/eb08]: 256 links, cap=102400.0\n", - " - fa1 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa1/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa1/fauu]: 288 links, cap=115200.0\n", - " - fa2 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa2/fauu]: 288 links, cap=115200.0\n", - " - fa3 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa3/fauu]: 288 links, cap=115200.0\n", - " - fa4 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa4/fauu]: 288 links, cap=115200.0\n", - " - fa5 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa5/fauu]: 288 links, cap=115200.0\n", - " - fa6 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa6/fauu]: 288 links, cap=115200.0\n", - " - fa7 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa7/fauu]: 288 links, cap=115200.0\n", - " - fa8 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa8/fauu]: 288 links, cap=115200.0\n", - " - fa9 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa9/fauu]: 288 links, cap=115200.0\n", - " - fa10 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa10/fauu]: 288 links, cap=115200.0\n", - " - fa11 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa11/fauu]: 288 links, cap=115200.0\n", - " - fa12 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa12/fauu]: 288 links, cap=115200.0\n", - " - fa13 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa13/fauu]: 288 links, cap=115200.0\n", - " - fa14 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa14/fauu]: 288 links, cap=115200.0\n", - " - fa15 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa15/fauu]: 288 links, cap=115200.0\n", - " - fa16 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0 | IntLinkCap=115200.0, ExtLinkCap=339200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0 | IntLinkCap=0.0, ExtLinkCap=166400.0\n", - " -> External to [ebb/eb01]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb02]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb03]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb04]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb05]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb06]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb07]: 16 links, cap=6400.0\n", - " -> External to [ebb/eb08]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fadu]: 288 links, cap=115200.0\n", - " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0 | IntLinkCap=0.0, ExtLinkCap=403200.0\n", - " -> External to [dc1/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc1/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc2/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc3/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc5/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane1/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane2/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane3/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane4/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane5/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane6/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane7/ssw]: 36 links, cap=7200.0\n", - " -> External to [dc6/plane8/ssw]: 36 links, cap=7200.0\n", - " -> External to [fa/fa16/fauu]: 288 links, cap=115200.0\n", - " - ebb | Nodes=32, Links=2096, Cost=0.0, Power=0.0 | IntLinkCap=153600.0, ExtLinkCap=819200.0\n", - " -> External to [fa/fa1/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa10/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa11/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa12/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa13/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa14/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa15/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa16/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa2/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa3/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa4/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa5/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa6/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa7/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa8/fauu]: 128 links, cap=51200.0\n", - " -> External to [fa/fa9/fauu]: 128 links, cap=51200.0\n", - " - eb01 | Nodes=4, Links=262, Cost=0.0, Power=0.0 | IntLinkCap=19200.0, ExtLinkCap=102400.0\n", - " -> External to [fa/fa1/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fauu]: 16 links, cap=6400.0\n", - " - eb02 | Nodes=4, Links=262, Cost=0.0, Power=0.0 | IntLinkCap=19200.0, ExtLinkCap=102400.0\n", - " -> External to [fa/fa1/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fauu]: 16 links, cap=6400.0\n", - " - eb03 | Nodes=4, Links=262, Cost=0.0, Power=0.0 | IntLinkCap=19200.0, ExtLinkCap=102400.0\n", - " -> External to [fa/fa1/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fauu]: 16 links, cap=6400.0\n", - " - eb04 | Nodes=4, Links=262, Cost=0.0, Power=0.0 | IntLinkCap=19200.0, ExtLinkCap=102400.0\n", - " -> External to [fa/fa1/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fauu]: 16 links, cap=6400.0\n", - " - eb05 | Nodes=4, Links=262, Cost=0.0, Power=0.0 | IntLinkCap=19200.0, ExtLinkCap=102400.0\n", - " -> External to [fa/fa1/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fauu]: 16 links, cap=6400.0\n", - " - eb06 | Nodes=4, Links=262, Cost=0.0, Power=0.0 | IntLinkCap=19200.0, ExtLinkCap=102400.0\n", - " -> External to [fa/fa1/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fauu]: 16 links, cap=6400.0\n", - " - eb07 | Nodes=4, Links=262, Cost=0.0, Power=0.0 | IntLinkCap=19200.0, ExtLinkCap=102400.0\n", - " -> External to [fa/fa1/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fauu]: 16 links, cap=6400.0\n", - " - eb08 | Nodes=4, Links=262, Cost=0.0, Power=0.0 | IntLinkCap=19200.0, ExtLinkCap=102400.0\n", - " -> External to [fa/fa1/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa10/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa11/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa12/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa13/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa14/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa15/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa16/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa2/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa3/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa4/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa5/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa6/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa7/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa8/fauu]: 16 links, cap=6400.0\n", - " -> External to [fa/fa9/fauu]: 16 links, cap=6400.0\n" + "- root | Nodes=6496, Links=191024, Cost=0.0, Power=11312000.0\n", + " - dc1 | Nodes=1152, Links=36864, Cost=0.0, Power=2016000.0\n", + " - plane1 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane2 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane3 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane4 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane5 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane6 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane7 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane8 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - pod1 | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - pod36 | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - dc2 | Nodes=1152, Links=36864, Cost=0.0, Power=2016000.0\n", + " - plane1 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane2 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane3 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane4 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane5 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane6 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane7 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane8 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - pod1 | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - pod36 | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - dc3 | Nodes=1152, Links=36864, Cost=0.0, Power=2016000.0\n", + " - plane1 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane2 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane3 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane4 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane5 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane6 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane7 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane8 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - pod1 | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - pod36 | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - dc5 | Nodes=1152, Links=36864, Cost=0.0, Power=2016000.0\n", + " - plane1 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane2 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane3 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane4 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane5 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane6 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane7 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane8 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - pod1 | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - pod36 | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - dc6 | Nodes=1152, Links=36864, Cost=0.0, Power=2016000.0\n", + " - plane1 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane2 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane3 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane4 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane5 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane6 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane7 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - plane8 | Nodes=132, Links=4608, Cost=0.0, Power=231000.0\n", + " - ssw | Nodes=36, Links=4032, Cost=0.0, Power=63000.0\n", + " - fsw | Nodes=96, Links=4032, Cost=0.0, Power=168000.0\n", + " - pod1 | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=4224, Cost=0.0, Power=84000.0\n", + " - pod36 | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - rsw | Nodes=48, Links=384, Cost=0.0, Power=84000.0\n", + " - fa | Nodes=704, Links=29696, Cost=0.0, Power=1232000.0\n", + " - fa1 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa2 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa3 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa4 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa5 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa6 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa7 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa8 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa9 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa10 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa11 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa12 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa13 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa14 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa15 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - fa16 | Nodes=44, Links=1856, Cost=0.0, Power=77000.0\n", + " - fauu | Nodes=8, Links=416, Cost=0.0, Power=14000.0\n", + " - fadu | Nodes=36, Links=1728, Cost=0.0, Power=63000.0\n", + " - ebb | Nodes=32, Links=2096, Cost=0.0, Power=0.0\n", + " - eb01 | Nodes=4, Links=262, Cost=0.0, Power=0.0\n", + " - eb02 | Nodes=4, Links=262, Cost=0.0, Power=0.0\n", + " - eb03 | Nodes=4, Links=262, Cost=0.0, Power=0.0\n", + " - eb04 | Nodes=4, Links=262, Cost=0.0, Power=0.0\n", + " - eb05 | Nodes=4, Links=262, Cost=0.0, Power=0.0\n", + " - eb06 | Nodes=4, Links=262, Cost=0.0, Power=0.0\n", + " - eb07 | Nodes=4, Links=262, Cost=0.0, Power=0.0\n", + " - eb08 | Nodes=4, Links=262, Cost=0.0, Power=0.0\n" ] } ], "source": [ - "explorer.print_tree(skip_leaves=True, detailed=True)" + "explorer.print_tree(skip_leaves=True, detailed=False)" ] }, { diff --git a/notebooks/small_demo.ipynb b/notebooks/small_demo.ipynb index ce87051..b80243b 100644 --- a/notebooks/small_demo.ipynb +++ b/notebooks/small_demo.ipynb @@ -174,18 +174,18 @@ "output_type": "stream", "text": [ "Overall Statistics:\n", - " mean: 208.79\n", - " stdev: 23.94\n", + " mean: 208.84\n", + " stdev: 24.57\n", " min: 178.94\n", - " max: 253.71\n" + " max: 251.57\n" ] } ], "source": [ "my_rules = [\n", " FailureRule(\n", - " conditions=[FailureCondition(attr=\"type\", operator=\"==\", value=\"link\")],\n", - " logic=\"and\",\n", + " entity_scope=\"link\",\n", + " logic=\"any\",\n", " rule_type=\"choice\",\n", " count=2,\n", " ),\n", @@ -210,13 +210,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "/var/folders/xh/83kdwyfd0fv66b04mchbfzcc0000gn/T/ipykernel_78882/4192461833.py:60: UserWarning: No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.\n", + "/var/folders/xh/83kdwyfd0fv66b04mchbfzcc0000gn/T/ipykernel_99569/4192461833.py:60: UserWarning: No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.\n", " plt.legend(title=\"Priority\")\n" ] }, { "data": { - "image/png": "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sjdv3owpU6ZIr318fEwS9kyBV18WABnfRoWIiEgWWrdujeXLlyMlJQU7d+7E0KFDoVKpEBYWpjdeamoqAMDV1TVfJ9OnpqbC0tISzs7O+ep3QeKeMiIiIip0arUa7u7u8Pb2xqeffoqAgABs374dffr0QceOHTF16lR4enqiRo0aAAwPX969excdOnSAnZ0d7O3t0blzZ8TExEjDJ06ciPr16+OXX35BxYoVpdtUvHr4skWLFrhz5w4+//xzac9dYmIi7O3t8fvvv+v1d+vWrbC1tcXz588LrCYMZURERGR21tbW0l6xffv24dq1awgPD8f27dsNxtVqtejQoQNiY2Nx6NAhhIeH49atW+jSpYveeDdu3MCmTZuwefNmREZGGsxn8+bNKF++PCZPnozo6GhER0fD1tYWXbt2xfLly/XGXb58OTp16oTSpUubbqVfw8OXREREZDZCCOzbtw+7d+/GZ599hsePH8PW1ha//PILLC0todVqkZCQoDfNvn37cOHCBURFRcHLywsA8Ouvv6JWrVo4efIkGjVqBEB3yPLXX3+Fq6ur0WU7OztDqVSidOnScHd3l9r79++Ppk2bIjo6Gh4eHnj06BF27tyJvXv3FlAVdLinjIiIiArdn3/+CTs7O1hZWaFNmzbo0qULJk6cCACoU6dOls+QvHLlCry8vKRABgA1a9aEo6Mjrly5IrV5e3tnGsiy0rhxY9SqVQsrV64EAKxevRre3t5o3rx5rueVGwxlREREVOjeffddREZG4vr160hOTsbKlStha2sLANJ/8ys/8+nfvz9WrFgBQHfosm/fvgX+QHSGMiIiIip0tra2qFKlCipUqIBSpXJ3NlWNGjVw79493Lt3T2q7fPky4uLiULNmzVzNy9LSEunphvcU7dmzJ+7cuYMffvgBly9fRu/evXM137xgKCMiIqIiJSAgAHXq1EGPHj1w5swZnDhxAiEhIfD390fDhg1zNS8fHx8cPnwY9+/fx5MnT6R2JycnfPjhhxg9ejQCAwNRvnx5U6+GAYayAsanLBEREZmWQqHAtm3b4OTkhObNmyMgIACVKlXChg0bcj2vyZMn4/bt26hcubLB+Wf9+vVDamoqPvnkE1N1PUu8+rKAfbw4Ajv+83aBH4cmIiIqKjLO1crNsFu3bundPLZChQrYtm1bpvOZOHGidOHAqw4ePKj3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yjh69CimTp1qko4RERERlSR52lP2eiCTZmZhga+//jpfHSIiIiIqifJ8oj8RERERmQ5DGREREZEMMJQRERERyQBDGREREZEMMJQRERERyUC+QlnHjh3x2WefSa9v3rwJT0/PfHeKiIiIqKTJcyiLj4/Hzp07sXHjRqktLS0NMTExJukYERERUUmS51C2Z88euLu7IykpCSdPnjRln4iIiIhKnDyHsp07d6Jdu3Zo2bIldu7caco+EREREZU4eQ5lu3fvRvv27dG2bVuGMiIiIqJ8ylMoO336NOLj4/Hee++hTZs2OHPmDJ48eWLqvhERERGVGHkKZTt37kSLFi1gZWUFLy8vVK9eHbt27TJ134iIiIhKjDyHsnbt2kmv27Ztix07dpisU0REREQlTa5DWXJyMpRKJdq3by+1ffjhh4iPj4e1tTUaN25s0g4SERERlQSlcjuBtbU1/v77b722Jk2aSCf7R0REmKZnRERERCUIH7NEREREJAMMZUREREQywFBGREREJAMMZUREREQywFBGREREJAO5CmVLly7Ncvjz58/Rv3//fHWIiIiIqCTKVSgLDQ1F+/bt8fDhQ4Nhu3fvRq1atXDy5EmTdY6IiIiopMhVKDt37hwSExNRq1YtrFu3DoBu71i/fv0QHByMnj174tSpUwXSUSIiIqLiLFc3j/Xx8cGBAwcwd+5cDBgwAGvWrMGFCxdgZ2eHo0ePolGjRgXVTyIiIqJiLdd39AeAQYMG4fDhw9i6dStsbW3x559/ok6dOqbuGxEREVGJkeurL48ePYp69erh6tWr2LVrF9q0aQM/Pz/MmzevIPpHREREVCLkKpSNHDkSLVu2RHBwMM6cOYPAwED89ttvWLp0Kb755hu0aNECUVFRBdVXIiIiomIrV6Fs27Zt2Lt3L2bPng0rKyupvUuXLrh48SIcHBxQt25dk3eSiIiIqLjL1Tll58+fh42NjdFhbm5u2LZtG1atWmWSjhERERGVJLnaU5ZZIHtVr1698twZIiIiopIqx6FsxowZSEpKytG4x48fx44dO/LcKSIiIqKSJseh7PLly/D29saQIUPw119/4fHjx9KwtLQ0nD9/HgsXLkTTpk3RpUsXlC5dukA6TERERFQc5ficsl9//RXnzp3Djz/+iO7duyMhIQFKpRJqtVrag9agQQP0798fffr00bsQgIiIiIiylqsT/evVq4eff/4ZP/30E86dO4e7d+8iOTkZLi4uqF+/PlxcXAqqn0RERETFWp7u6G9hYYEGDRqgQYMGpu4PERERUYmUq6sv09PTMXPmTDRr1gyNGjXC2LFjkZycXFB9IyIiIioxcrWnbNq0aZg4cSICAgJgbW2NefPm4dGjR1i2bFlB9Y/IQFJqurm7YDIaTRpS0oGk1DSohMLc3TFgrVJCoZBfv4iIiqNchbJff/0VCxcuxKBBgwAAe/fuRbt27fDLL7/AwiLXj9EkypOG3+w1dxdMrBTGnNhv7k4Y1dDbCRsH+zGYEREVglwlqbt376Jt27bS64CAACgUCjx48MDkHSN6lbVKiYbeTubuRolz6s4zJGuKz55JIiI5y9WesrS0NINbXahUKmg0GpN2iuh1CoUCGwf7FbuAoNFosHv3HgQFBUKlUpm7O5Kk1PRiuEeSiEjechXKhBDo06cP1Gq11Pby5UsMHjwYtra2UtvmzZtN10Oi/6dQKGBjmacLhmVLoxBQKwEby1JQqYrXuhERUe7k6legd+/eBm09e/Y0WWeIiIiISqpchbLly5cXVD+IiIiISjReMklEREQkAwxlRERERDLAUEZEREQkAwxlRERERDIgi1C2YMEC+Pj4wMrKCk2aNMGJEydyNN369euhUCjQsWPHgu0gERERUQEzeyjbsGEDQkNDMWHCBJw5cwb16tVDUFAQHj16lOV0t2/fxqhRo/DOO+8UUk+JiIiICo7Z71Y5Z84cDBgwAH379gUALF68GDt27MCyZcswduxYo9Okp6ejR48emDRpEo4cOYK4uLhC7DFRyVIYD4CX+4PZC4sp68CHyRMVPWYNZampqTh9+jTCwsKkNgsLCwQEBCAiIiLT6SZPnoyyZcuiX79+OHLkSJbLSElJQUpKivQ6ISEBgO7xNuZ4PFTGMkv6o6lYBx251kGjSZP+v/AetyTfB7MXLtPUwbeCI9b1b1Qkg5lcPxeFjXXQKQ51yGnfzRrKnjx5gvT0dLi5uem1u7m54erVq0an+fvvv7F06VJERkbmaBnTp0/HpEmTDNr37NkDGxubXPfZVMLDw822bDlhHXTkVgchgIqllYh6XvR+0Enn9N04bP3zL6iV5u5J3sntc2EurINOUa5DUlJSjsYz++HL3Hj+/Dl69eqFn3/+GS4uLjmaJiwsDKGhodLrhIQEeHl5ITAwEPb29gXV1UxpNBqEh4ejVatWsnoAdWFjHXTkXIe2bUWhPQBeo0nD/v370bJlyxL9DFBT1CE5NR1vzTwEAAgKCiySz4uV8+eiMLEOOsWhDhlH6bJj1k+ri4sLlEolYmJi9NpjYmLg7u5uMP7Nmzdx+/ZtBAcHS21arRYAUKpUKVy7dg2VK1fWm0atVus9QD2DSqUy65tr7uXLBeugI9c6WFoWznI0Gg3USsDB1kqWdSgspqiDSpX2yv+rinTIlevnorCxDjpFuQ457bdZr760tLSEr68v9u3bJ7VptVrs27cPfn5+BuNXr14dFy5cQGRkpPT3/vvv491330VkZCS8vLwKs/tEREREJmP2f0KFhoaid+/eaNiwIRo3boy5c+ciMTFRuhozJCQE5cqVw/Tp02FlZYXatWvrTe/o6AgABu1ERERERYnZQ1mXLl3w+PFjjB8/Hg8fPkT9+vWxa9cu6eT/u3fvwsLC7LdTIyIiIipQZg9lADBs2DAMGzbM6LCDBw9mOe2KFStM3yEiIiKiQsZdUEREREQywFBGREREJAMMZUREREQywFBGREREJAOyONGfiIhML6uHyfOB5UTyw1BGRFRMZfUw+YbeTtg42I/BjEhGePiSiKgYsVYp0dDbKdvxTt15VmjPNiWinOGeMiKiYkShUGDjYL9MA1dSanqWe9CIyHwYyoiIihmFQgEbS369ExU1PHxJREREJAMMZUREREQywFBGREREJAMMZUREREQywFBGREREJAMMZUREREQywFBGREREJAO8kQ0RUQmV1bMxzUmjSUNKOpCUmgaVyPljoPg8TyrqGMqIiEooed/ZvxTGnNifqyn4PE8q6nj4koioBMnpszGLIj7Pk4o67ikjIipBsns2phxoNBrs3r0HQUGBUKlU2Y7P53lSccFQRkRUwsj92ZgahYBaCdhYloJKJd9+EpkaD18SERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyUApc3eAiIjIVJJS082yXGuVEgqFwizLpuKDoYyIiIqNht/sNc9yvZ2wcbAfgxnlCw9fEhFRkWatUqKht5NZ+3DqzjMka8yzl46KD+4pIyKiIk2hUGDjYD+zhKKk1HSz7Z2j4oehjIiIijyFQgEbS/6kUdHGw5dEREREMsBQRkRERCQDDGVEREREMsBQRkRERCQDDGVEREREMsBQRkRERCQDDGVEREREMsBQRkRERCQDDGVEREREMsBQRkRERCQDDGVEREREMsBQRkRERCQDDGVEREREMsBQRkRERCQDDGVEREREMsBQRkRERCQDDGVEREREMsBQRkRERCQDDGVEREREMiCLULZgwQL4+PjAysoKTZo0wYkTJzId9+eff8Y777wDJycnODk5ISAgIMvxiYiIiIoCs4eyDRs2IDQ0FBMmTMCZM2dQr149BAUF4dGjR0bHP3jwILp164YDBw4gIiICXl5eCAwMxP379wu550RERESmY/ZQNmfOHAwYMAB9+/ZFzZo1sXjxYtjY2GDZsmVGx1+zZg2GDBmC+vXro3r16vjll1+g1Wqxb9++Qu45ERHR/ySlpiMpNc3onxDC3N2jIqCUOReempqK06dPIywsTGqzsLBAQEAAIiIicjSPpKQkaDQaODs7Gx2ekpKClJQU6XVCQgIAQKPRQKPR5KP3eZOxTHMsW05YBx3WQYd10GEddIpSHTSaNOn/G36zN9PxfCs4Yl3/RlAoFLmYd9GpQ0EqDnXIad8Vwozx/cGDByhXrhyOHTsGPz8/qX3MmDE4dOgQjh8/nu08hgwZgt27d+PSpUuwsrIyGD5x4kRMmjTJoH3t2rWwsbHJ3woQEVGJJgQw75ISUc+zD1vfNk6DWlkInSLZSUpKQvfu3REfHw97e/tMxzPrnrL8mjFjBtavX4+DBw8aDWQAEBYWhtDQUOl1QkKCdB5aVoUpKBqNBuHh4WjVqhVUKlWhL18uWAcd1kGHddBhHXSKWh3athVI1qQbHZacmo63Zh4CAAQFBcLGMuc/u0WtDgWlONQh4yhddswaylxcXKBUKhETE6PXHhMTA3d39yynnTVrFmbMmIG9e/eibt26mY6nVquhVqsN2lUqlVnfXHMvXy5YBx3WQYd10GEddIpSHSwtjberVGmv/L8KKlXuf3aLUh0KUlGuQ077bdYT/S0tLeHr66t3kn7GSfuvHs583bfffospU6Zg165daNiwYWF0lYiIiKhAmf3wZWhoKHr37o2GDRuicePGmDt3LhITE9G3b18AQEhICMqVK4fp06cDAGbOnInx48dj7dq18PHxwcOHDwEAdnZ2sLOzM9t6EBEREeWH2UNZly5d8PjxY4wfPx4PHz5E/fr1sWvXLri5uQEA7t69CwuL/+3QW7RoEVJTU9GpUye9+UyYMAETJ04szK4TERERmYzZQxkADBs2DMOGDTM67ODBg3qvb9++XfAdIiIiIipkZr95LBERERExlBERERHJAkMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJAEMZERERkQwwlBERERHJQClzd4CIiKgkSEpNz9X4Gk0aUtKBpNQ0qISigHolf7mpg7VKCYWi6NaKoYyIiKgQNPxmbx6mKoUxJ/abvC9FT87q0NDbCRsH+xXZYMbDl0RERAXEWqVEQ28nc3ejxDh15xmSNbnbIykn3FNGRERUQBQKBTYO9stTUNBoNNi9ew+CggKhUqkKoHdFQ07qkJSansc9kfLCUEZERFSAFAoFbCxz/3OrUQiolYCNZSmoVCX357ok1YGHL4mIiIhkgKGMiIiISAYYyoiIiIhkgKGMiIiISAYYyoiIiIhkgKGMiIiISAYYyoiIiIhkgKGMiIiISAaK913YiIiIqETJ7YPfAfk8yJyhjIiIiIqNvDxuSS4PMufhSyIiIirS8vvgd7k8yJx7yoiIiKhIy+uD3+X2IHOGMiIiIiry8vrgdznh4UsiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBWYSyBQsWwMfHB1ZWVmjSpAlOnDiR5fgbN25E9erVYWVlhTp1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", + "image/png": "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Y3U9W7z6khThrekH0NDLEesG+hX4MXsiIjKtzHO18jLs+vXrstflypXD5s2bs5zP6NGjMWXKFL32/fv3y16/9dZbOH36tMF53L59G6VKlUK7du2yXI4xcU8ZmYyVuRo+5Ryk18dvPOIzMImIyORSUlIQExODadOmYcCAAdleCWpMDGVkMiqVCqv7NsLXDdNN3RUiIiLJN998g2rVqsHNzU3vsU8FiaGMTEqlUsGCWyERESnIhAkToNVqsWfPHtja2hbacvlzSERERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERAVCCGHqLhQaY6wrQxkREREZlbm5OYAXz5AsLjLXNXPd86OEsTpDREREBABqtRoODg64d+8eAMDa2hoqlarQlq/T6ZCWlobnz5/DzKxg9z8JIZCSkoJ79+7BwcEBarU63/NiKCMiIiKjc3NzAwApmBUmIQSePXsGKyurQguDDg4O0jrnF0MZERERGZ1KpYK7uztKly4NrVZbqMvWarU4ePAgmjVr9lqHE3PL3Nz8tfaQZWIoIyIiogKjVquNEljyusz09HRYWloWSigzFp7oT0RERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQADGVERERECsBQRkRERKQAJg9lc+fOhbe3NywtLeHr64ujR49mO/6sWbNQtWpVWFlZwdPTE1988QWeP39eSL0lIiIiKhgmDWVr165FaGgoxo8fj5MnT6Ju3boICgrCvXv3DI6/atUqjB49GuPHj8fFixexaNEirF27FmPGjCnknhMREREZl0lDWUREBPr164fevXujRo0aWLBgAaytrbF48WKD4x8+fBhNmzZF165d4e3tjcDAQHTp0iXHvWtERERESlfCVAtOS0vDiRMnEBYWJrWZmZkhICAA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gUqlwrqBflkGrpS0jGz3oFHRx1BGRERUSFQqFawt+NNLhvHwJREREZECMJQRERERKQBDGREREZECMJQRERERKQBDGREREZECMJQRERERKQBDGREREZECMJQREREpjBCm7gGZAkMZERGRwnyyIAqCyazYYSgjIiJSACtzNWq42wEALsQl8fmXxRBDGRERkQJkPhuTii+GMiIiIoVQqUzdAzIlhjIiIiIiBWAoIyIiIlIAhjIiIiIiBWAoIyIiIlIAhjIiIiIiBWAoIyIiIlIAhjIiIiIiBWAoIyIiIlKAEqbuABEREelLScvbY5a02nSkZgApaekwF8X7LrR5qYWVuRoqhdy1l6GMiIhIgRp+vTsfU5XAqKN7jd6XN1PuatHQyxHrBvopIpjx8CUREZFCWJmr0dDL0dTdKFaO33ikmIe/c08ZERGRQmQ+lDw/IUGr1WLnzl0ICgqEubl5AfTuzZGbWqSkZeRzb2TBYSgjIiJSEJVKBWuLvP88a1UCGjVgbVEC5ubF++f9Ta0FD18SERERKQBDGREREZECMJQRERERKQBDGREREZECMJQRERERKQBDGREREZECMJQRERERKQBDGREREZECMJQRERFRsSaEqXvwAkMZERERFWufLIiCUEAyYygjIiKiYsfKXI0a7nYAgAtxSYp4KDlDGRERERU7mQ9/VxKGMiIiIiqWVCpT90COoYyIiIhIARjKiIiIiBSAoYyIiIhIARjKiIiIiBSAoYyIiIhIARjKiIiIiBSAoYyIiIhIARjKiIiIiBSAoYyIiIhIARjKiIiIiBSAoYyIiIhIARjKiIiIiBSAoYyIiIhIARjKiIiIiBSAoYyIiIhIARjKiIiIiBSAoYyIiIhIARjKiIiIiBSAoYyIiIhIARQRyubOnQtvb29YWlrC19cXR48ezXb8devWoVq1arC0tETt2rWxffv2QuopERERUcEweShbu3YtQkNDMX78eJw8eRJ169ZFUFAQ7t27Z3D8w4cPo0uXLujTpw9OnTqF9u3bo3379jh37lwh95yIiIjIeEweyiIiItCvXz/07t0bNWrUwIIFC2BtbY3FixcbHH/27Nlo2bIlRo4cierVq2PSpElo0KABfvjhh0LuOREREZHxlDDlwtPS0nDixAmEhYVJbWZmZggICEBUVJTBaaKiohAaGiprCwoKwqZNmwyOn5qa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Bg1k48yfPx8dOnTAoEGDUK1aNfTr1w/JyckAIO0VzMjIQGBgIGrXro1hw4bBwcFBCl7ffvst3nnnHQQHByMgIABvv/12rs95+vjjj6HRaGBtbS27+7y1tTV27tyJhIQENGrUCB06dMD777+PH374Ict5hYWFwd/fH23btkWbNm3Qvn17VKxYMY8V0xcUFIStW7di165daNSoEd566y1899130l49Q0qVKoUPP/wQK1eu1Bs2bdo0TJs2DXXr1sVff/2FLVu2SHt3clPv/BoxYgTUajVq1KgBFxcX3Lx5M9/Lq1u3LiIiIjB9+nTUqlULK1euxNSpU2XjNGnSBAMHDkSnTp3g4uKCb775Rm8+KpUKmzdvhqOjI5o1a4aAgABUqFABa9euzdO6PX/+HJs2bUK/fv3yNB1RQVGJV0+mICIikzlz5gxatGiBmJgY2Nra4vr16yhfvjxOnTqFevXqmbp7Rcr8+fOxceNG7Nq1y9RdIQLAPWVERIpSp04dTJ8+3SjntVH2zM3NMWfOHFN3g0jCPWVERArGPWVExQdDGREREZEC8PAlERERkQIwlBEREREpAEMZERERkQIwlBEREREpAEMZERERkQIwlBEREREpAEMZERERkQIwlBEREREpwP8B5CYPoBep/FMAAAAASUVORK5CYII=", "text/plain": [ "
" ] diff --git a/tests/scenarios/scenario_1.yaml b/tests/scenarios/scenario_1.yaml index 2b0229e..33b3109 100644 --- a/tests/scenarios/scenario_1.yaml +++ b/tests/scenarios/scenario_1.yaml @@ -4,17 +4,23 @@ network: nodes: SEA: - coords: [47.6062, -122.3321] + attrs: + coords: [47.6062, -122.3321] SFO: - coords: [37.7749, -122.4194] + attrs: + coords: [37.7749, -122.4194] DEN: - coords: [39.7392, -104.9903] + attrs: + coords: [39.7392, -104.9903] DFW: - coords: [32.8998, -97.0403] + attrs: + coords: [32.8998, -97.0403] JFK: - coords: [40.641766, -73.780968] + attrs: + coords: [40.641766, -73.780968] DCA: - coords: [38.907192, -77.036871] + attrs: + coords: [38.907192, -77.036871] links: # West -> Middle @@ -102,14 +108,12 @@ network: distance_km: 342.69 failure_policy: - name: "anySingleLink" - description: "Evaluate traffic routing under any single link failure." + attrs: + name: "anySingleLink" + description: "Evaluate traffic routing under any single link failure." rules: - - conditions: - - attr: "type" - operator: "==" - value: "link" - logic: "and" + - logic: "any" + entity_scope: "link" rule_type: "choice" count: 1 diff --git a/tests/scenarios/scenario_2.yaml b/tests/scenarios/scenario_2.yaml index ddaf9e5..d14e960 100644 --- a/tests/scenarios/scenario_2.yaml +++ b/tests/scenarios/scenario_2.yaml @@ -69,12 +69,14 @@ network: # "SEA/clos_instance" and "SEA/edge_nodes" in the global scope. SEA: use_blueprint: city_cloud - coords: [47.6062, -122.3321] + attrs: + coords: [47.6062, -122.3321] # 2) 'SFO' references 'single_node' (one-node blueprint). SFO: use_blueprint: single_node - coords: [37.7749, -122.4194] + attrs: + coords: [37.7749, -122.4194] adjacency: # Each adjacency definition uses "mesh" in this scenario. Self-loops are automatically skipped. @@ -117,13 +119,17 @@ network: # Standalone nodes nodes: DEN: - coords: [39.7392, -104.9903] + attrs: + coords: [39.7392, -104.9903] DFW: - coords: [32.8998, -97.0403] + attrs: + coords: [32.8998, -97.0403] JFK: - coords: [40.641766, -73.780968] + attrs: + coords: [40.641766, -73.780968] DCA: - coords: [38.907192, -77.036871] + attrs: + coords: [38.907192, -77.036871] # Additional direct links # Note that each link references existing nodes (e.g., DEN, DFW). @@ -174,14 +180,12 @@ network: distance_km: 342.69 failure_policy: - name: "anySingleLink" - description: "Evaluate traffic routing under any single link failure." + attrs: + name: "anySingleLink" + description: "Evaluate traffic routing under any single link failure." rules: - - conditions: - - attr: "type" - operator: "==" - value: "link" - logic: "and" + - entity_scope: "link" + logic: "any" rule_type: "choice" count: 1 diff --git a/tests/scenarios/scenario_3.yaml b/tests/scenarios/scenario_3.yaml index 86e7242..2eeaeb8 100644 --- a/tests/scenarios/scenario_3.yaml +++ b/tests/scenarios/scenario_3.yaml @@ -73,29 +73,29 @@ network: any_direction: True link_params: attrs: - shared_risk_group: "SpineSRG" + shared_risk_groups: ["SpineSRG"] hw_component: "400G-LR4" # Example node overrides that assign SRGs and hardware types node_overrides: - path: my_clos1/b1/t1 attrs: - shared_risk_group: "clos1-b1t1-SRG" + shared_risk_groups: ["clos1-b1t1-SRG"] hw_component: "LeafHW-A" - path: my_clos2/b2/t1 attrs: - shared_risk_group: "clos2-b2t1-SRG" + shared_risk_groups: ["clos2-b2t1-SRG"] hw_component: "LeafHW-B" - path: my_clos1/spine/t3.* attrs: - shared_risk_group: "clos1-spine-SRG" + shared_risk_groups: ["clos1-spine-SRG"] hw_component: "SpineHW" - path: my_clos2/spine/t3.* attrs: - shared_risk_group: "clos2-spine-SRG" + shared_risk_groups: ["clos2-spine-SRG"] hw_component: "SpineHW" workflow: diff --git a/tests/scenarios/test_scenario_1.py b/tests/scenarios/test_scenario_1.py index 434c59c..39d1a1a 100644 --- a/tests/scenarios/test_scenario_1.py +++ b/tests/scenarios/test_scenario_1.py @@ -61,17 +61,8 @@ def test_scenario_1_build_graph() -> None: assert len(policy.rules) == 1, "Should only have 1 rule for 'anySingleLink'." rule = policy.rules[0] - # - conditions: [ {attr: 'type', operator: '==', value: 'link'} ] - # - logic: 'and' - # - rule_type: 'choice' - # - count: 1 - assert len(rule.conditions) == 1, "Expected exactly 1 condition for matching links." - cond = rule.conditions[0] - assert cond.attr == "type" - assert cond.operator == "==" - assert cond.value == "link" - - assert rule.logic == "and" + assert rule.entity_scope == "link" + assert rule.logic == "any" assert rule.rule_type == "choice" assert rule.count == 1 diff --git a/tests/scenarios/test_scenario_2.py b/tests/scenarios/test_scenario_2.py index d101503..60e6bec 100644 --- a/tests/scenarios/test_scenario_2.py +++ b/tests/scenarios/test_scenario_2.py @@ -75,12 +75,8 @@ def test_scenario_2_build_graph() -> None: assert len(policy.rules) == 1, "Should only have 1 rule for 'anySingleLink'." rule = policy.rules[0] - assert len(rule.conditions) == 1, "Expected exactly 1 condition for matching links." - cond = rule.conditions[0] - assert cond.attr == "type" - assert cond.operator == "==" - assert cond.value == "link" - assert rule.logic == "and" + assert rule.entity_scope == "link" + assert rule.logic == "any" assert rule.rule_type == "choice" assert rule.count == 1 assert policy.attrs.get("name") == "anySingleLink" diff --git a/tests/scenarios/test_scenario_3.py b/tests/scenarios/test_scenario_3.py index 7e9fa3f..bd73856 100644 --- a/tests/scenarios/test_scenario_3.py +++ b/tests/scenarios/test_scenario_3.py @@ -58,9 +58,9 @@ def test_scenario_3_build_graph_and_capacity_probe() -> None: # 7) Verify no traffic demands in this scenario assert len(scenario.traffic_demands) == 0, "Expected zero traffic demands." - # 8) Verify the default (empty) failure policy + # 8) Verify the default failure policy is None policy: FailurePolicy = scenario.failure_policy - assert len(policy.rules) == 0, "Expected an empty failure policy." + assert policy is None, "Expected no failure policy in this scenario." # 9) Check presence of some expanded nodes assert ( @@ -78,19 +78,19 @@ def test_scenario_3_build_graph_and_capacity_probe() -> None: assert ( node_a1.attrs.get("hw_component") == "LeafHW-A" ), "Expected hw_component=LeafHW-A for 'my_clos1/b1/t1/t1-1', but not found." - assert ( - node_a1.attrs.get("shared_risk_group") == "clos1-b1t1-SRG" - ), "Expected shared_risk_group=clos1-b1t1-SRG for 'my_clos1/b1/t1/t1-1'." + assert node_a1.attrs.get("shared_risk_groups") == [ + "clos1-b1t1-SRG" + ], "Expected shared_risk_group=clos1-b1t1-SRG for 'my_clos1/b1/t1/t1-1'." # For "my_clos2/b2/t1/t1-1", check hw_component="LeafHW-B" and SRG="clos2-b2t1-SRG" node_b2 = net.nodes["my_clos2/b2/t1/t1-1"] assert node_b2.attrs.get("hw_component") == "LeafHW-B" - assert node_b2.attrs.get("shared_risk_group") == "clos2-b2t1-SRG" + assert node_b2.attrs.get("shared_risk_groups") == ["clos2-b2t1-SRG"] # For "my_clos1/spine/t3-1", check hw_component="SpineHW" and SRG="clos1-spine-SRG" node_spine1 = net.nodes["my_clos1/spine/t3-1"] assert node_spine1.attrs.get("hw_component") == "SpineHW" - assert node_spine1.attrs.get("shared_risk_group") == "clos1-spine-SRG" + assert node_spine1.attrs.get("shared_risk_groups") == ["clos1-spine-SRG"] # (B) Link attribute checks from link_overrides: # The override sets capacity=1 for "my_clos1/spine/t3-1" <-> "my_clos2/spine/t3-1" @@ -107,7 +107,7 @@ def test_scenario_3_build_graph_and_capacity_probe() -> None: "'my_clos2/spine/t3-1'" ) - # Another override sets shared_risk_group="SpineSRG" + hw_component="400G-LR4" on all spine-spine links + # Another override sets shared_risk_groups=["SpineSRG"] + hw_component="400G-LR4" on all spine-spine links # We'll check a random spine pair, e.g. "t3-2" link_id_2 = net.find_links( "my_clos1/spine/t3-2$", @@ -115,9 +115,9 @@ def test_scenario_3_build_graph_and_capacity_probe() -> None: ) assert link_id_2, "Spine link (t3-2) not found for override check." for link_obj in link_id_2: - assert ( - link_obj.attrs.get("shared_risk_group") == "SpineSRG" - ), "Expected SRG=SpineSRG on spine<->spine link." + assert link_obj.attrs.get("shared_risk_groups") == [ + "SpineSRG" + ], "Expected SRG=SpineSRG on spine<->spine link." assert ( link_obj.attrs.get("hw_component") == "400G-LR4" ), "Expected hw_component=400G-LR4 on spine<->spine link." diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py index 517722d..3dbab18 100644 --- a/tests/test_blueprints.py +++ b/tests/test_blueprints.py @@ -22,24 +22,15 @@ def test_join_paths(): - """ - Tests _join_paths for correct handling of leading slash, parent/child combinations, etc. - """ - # No parent path, no slash + """Tests _join_paths for correct handling of leading slash, parent/child combinations, etc.""" assert _join_paths("", "SFO") == "SFO" - # No parent path, child with leading slash => "SFO" assert _join_paths("", "/SFO") == "SFO" - # Parent path plus child => "SEA/leaf" assert _join_paths("SEA", "leaf") == "SEA/leaf" - # Parent path plus leading slash => "SEA/leaf" assert _join_paths("SEA", "/leaf") == "SEA/leaf" def test_apply_parameters(): - """ - Tests _apply_parameters to ensure user-provided overrides get applied - to the correct subgroup fields. - """ + """Tests _apply_parameters to ensure user-provided overrides get applied correctly.""" original_def = { "node_count": 4, "name_template": "spine-{node_num}", @@ -63,9 +54,7 @@ def test_apply_parameters(): def test_create_link(): - """ - Tests _create_link to verify creation and insertion into a Network. - """ + """Tests _create_link to verify creation and insertion into a Network.""" net = Network() net.add_node(Node("A")) net.add_node(Node("B")) @@ -79,12 +68,34 @@ def test_create_link(): assert link_obj.capacity == 50 assert link_obj.cost == 5 assert link_obj.attrs["color"] == "red" + # risk_groups defaults empty + assert link_obj.risk_groups == set() + + +def test_create_link_risk_groups(): + """Tests _create_link with 'risk_groups' in link_params => sets link.risk_groups.""" + net = Network() + net.add_node(Node("X")) + net.add_node(Node("Y")) + + _create_link( + net, + "X", + "Y", + { + "capacity": 20, + "risk_groups": ["RG1", "RG2"], + "attrs": {"line_type": "fiber"}, + }, + ) + assert len(net.links) == 1 + link_obj = next(iter(net.links.values())) + assert link_obj.risk_groups == {"RG1", "RG2"} + assert link_obj.attrs["line_type"] == "fiber" def test_create_link_multiple(): - """ - Tests _create_link with link_count=2 to ensure multiple parallel links are created. - """ + """Tests _create_link with link_count=2 => multiple parallel links are created.""" net = Network() net.add_node(Node("A")) net.add_node(Node("B")) @@ -107,10 +118,7 @@ def test_create_link_multiple(): def test_expand_adjacency_pattern_one_to_one(): - """ - Tests _expand_adjacency_pattern in 'one_to_one' mode for a simple 2:2 case. - Should produce pairs: (S1->T1), (S2->T2). - """ + """Tests _expand_adjacency_pattern in 'one_to_one' mode for a simple 2:2 case.""" ctx_net = Network() ctx_net.add_node(Node("S1")) ctx_net.add_node(Node("S2")) @@ -122,27 +130,19 @@ def test_expand_adjacency_pattern_one_to_one(): _expand_adjacency_pattern(ctx, "S", "T", "one_to_one", {"capacity": 10}) # We expect 2 links: S1->T1, S2->T2 assert len(ctx_net.links) == 2 - # Confirm the pairs pairs = {(l.source, l.target) for l in ctx_net.links.values()} assert pairs == {("S1", "T1"), ("S2", "T2")} - - # Also confirm the capacity for l in ctx_net.links.values(): assert l.capacity == 10 def test_expand_adjacency_pattern_one_to_one_wrap(): - """ - Tests 'one_to_one' with wrapping case: e.g., 4 vs 2. (both sides a multiple). - => S1->T1, S2->T2, S3->T1, S4->T2 => total 4 links. - """ + """Tests 'one_to_one' with wrapping case: 4 vs 2 => total 4 links.""" ctx_net = Network() - # 4 source nodes ctx_net.add_node(Node("S1")) ctx_net.add_node(Node("S2")) ctx_net.add_node(Node("S3")) ctx_net.add_node(Node("S4")) - # 2 target nodes ctx_net.add_node(Node("T1")) ctx_net.add_node(Node("T2")) @@ -151,7 +151,6 @@ def test_expand_adjacency_pattern_one_to_one_wrap(): _expand_adjacency_pattern(ctx, "S", "T", "one_to_one", {"cost": 99}) # Expect 4 total links assert len(ctx_net.links) == 4 - # Check the actual pairs pairs = {(l.source, l.target) for l in ctx_net.links.values()} expected = { ("S1", "T1"), @@ -165,12 +164,8 @@ def test_expand_adjacency_pattern_one_to_one_wrap(): def test_expand_adjacency_pattern_one_to_one_mismatch(): - """ - Tests 'one_to_one' with a mismatch (3 vs 2) => raises a ValueError - since 3 % 2 != 0. - """ + """Tests 'one_to_one' with mismatch => raises ValueError.""" ctx_net = Network() - # 3 sources, 2 targets ctx_net.add_node(Node("S1")) ctx_net.add_node(Node("S2")) ctx_net.add_node(Node("S3")) @@ -181,15 +176,11 @@ def test_expand_adjacency_pattern_one_to_one_mismatch(): with pytest.raises(ValueError) as exc: _expand_adjacency_pattern(ctx, "S", "T", "one_to_one", {}) - # Our error text checks assert "requires sizes with a multiple factor" in str(exc.value) def test_expand_adjacency_pattern_mesh(): - """ - Tests _expand_adjacency_pattern in 'mesh' mode: all-to-all links among matched nodes, - skipping self-loops and deduplicating reversed pairs. - """ + """Tests _expand_adjacency_pattern in 'mesh' mode: all-to-all, skipping self-loops.""" ctx_net = Network() ctx_net.add_node(Node("X1")) ctx_net.add_node(Node("X2")) @@ -197,8 +188,6 @@ def test_expand_adjacency_pattern_mesh(): ctx_net.add_node(Node("Y2")) ctx = DSLExpansionContext({}, ctx_net) - - # mesh => X1,X2 => Y1,Y2 => 4 links total _expand_adjacency_pattern(ctx, "X", "Y", "mesh", {"capacity": 99}) assert len(ctx_net.links) == 4 for link in ctx_net.links.values(): @@ -206,9 +195,7 @@ def test_expand_adjacency_pattern_mesh(): def test_expand_adjacency_pattern_mesh_link_count(): - """ - Tests 'mesh' mode with link_count=2 to ensure multiple parallel links are created per pairing. - """ + """Tests 'mesh' mode with link_count=2 => multiple parallel links per pairing.""" ctx_net = Network() ctx_net.add_node(Node("A1")) ctx_net.add_node(Node("A2")) @@ -216,18 +203,14 @@ def test_expand_adjacency_pattern_mesh_link_count(): ctx_net.add_node(Node("B2")) ctx = DSLExpansionContext({}, ctx_net) - _expand_adjacency_pattern(ctx, "A", "B", "mesh", {"attrs": {"color": "purple"}}, 2) - # A1->B1, A1->B2, A2->B1, A2->B2 => each repeated 2 times => 8 total links assert len(ctx_net.links) == 8 for link in ctx_net.links.values(): assert link.attrs.get("color") == "purple" def test_expand_adjacency_pattern_unknown(): - """ - Tests that an unknown adjacency pattern raises ValueError. - """ + """Tests that an unknown adjacency pattern raises ValueError.""" ctx_net = Network() ctx_net.add_node(Node("N1")) ctx_net.add_node(Node("N2")) @@ -240,34 +223,41 @@ def test_expand_adjacency_pattern_unknown(): def test_process_direct_nodes(): """ - Tests _process_direct_nodes to ensure direct node creation works. - Existing nodes are not overwritten. + Tests _process_direct_nodes with recognized top-level keys (disabled, attrs, risk_groups). + We must put anything else inside 'attrs' or it triggers an error. """ net = Network() net.add_node(Node("Existing")) network_data = { "nodes": { - "New1": {"foo": "bar"}, - "Existing": { - "override": "ignored" - }, # This won't be merged since node already exists + # 'New1' node + "New1": { + "disabled": True, + "attrs": { + "foo": "bar", + }, + "risk_groups": ["RGalpha"], + }, + # "Existing" won't be changed because it's already present + "Existing": {"attrs": {"would": "be_ignored"}, "risk_groups": ["RGbeta"]}, }, } _process_direct_nodes(net, network_data) - - # "New1" was created + # "New1" is added assert "New1" in net.nodes + assert net.nodes["New1"].disabled is True assert net.nodes["New1"].attrs["foo"] == "bar" - # "Existing" was not overwritten - assert "override" not in net.nodes["Existing"].attrs + assert net.nodes["New1"].risk_groups == {"RGalpha"} + + # "Existing" => not overwritten + assert net.nodes["Existing"].attrs == {} + assert net.nodes["Existing"].risk_groups == set() def test_process_direct_links(): - """ - Tests _process_direct_links to ensure direct link creation works. - """ + """Tests _process_direct_links to ensure direct link creation works under the new rules.""" net = Network() net.add_node(Node("Existing1")) net.add_node(Node("Existing2")) @@ -277,25 +267,22 @@ def test_process_direct_links(): { "source": "Existing1", "target": "Existing2", - "link_params": {"capacity": 5}, + "link_params": {"capacity": 5, "risk_groups": ["RGlink"]}, } ], } _process_direct_links(net, network_data) - - # Confirm that links were created assert len(net.links) == 1 link = next(iter(net.links.values())) assert link.source == "Existing1" assert link.target == "Existing2" assert link.capacity == 5 + assert link.risk_groups == {"RGlink"} def test_process_direct_links_link_count(): - """ - Tests _process_direct_links with link_count > 1 to ensure multiple parallel links. - """ + """Tests _process_direct_links with link_count > 1 => multiple parallel links.""" net = Network() net.add_node(Node("N1")) net.add_node(Node("N2")) @@ -305,7 +292,7 @@ def test_process_direct_links_link_count(): { "source": "N1", "target": "N2", - "link_params": {"capacity": 20}, + "link_params": {"capacity": 20, "risk_groups": ["RGmulti"]}, "link_count": 3, } ] @@ -317,13 +304,11 @@ def test_process_direct_links_link_count(): assert link_obj.capacity == 20 assert link_obj.source == "N1" assert link_obj.target == "N2" + assert link_obj.risk_groups == {"RGmulti"} def test_direct_links_same_node_raises(): - """ - Tests that creating a link that references the same node as source and target - raises a ValueError. - """ + """Tests that creating a link with same source & target raises ValueError.""" net = Network() net.add_node(Node("X")) network_data = { @@ -334,7 +319,6 @@ def test_direct_links_same_node_raises(): } ] } - with pytest.raises(ValueError) as excinfo: _process_direct_links(net, network_data) assert "Link cannot have the same source and target" in str(excinfo.value) @@ -342,8 +326,8 @@ def test_direct_links_same_node_raises(): def test_expand_blueprint_adjacency(): """ - Tests _expand_blueprint_adjacency: verifying that relative paths inside a blueprint - are joined with parent_path, then expanded as normal adjacency. + Tests _expand_blueprint_adjacency with local parent_path => verifying + that relative paths get joined with parent_path. """ ctx_net = Network() ctx_net.add_node(Node("Parent/leaf-1")) @@ -358,11 +342,9 @@ def test_expand_blueprint_adjacency(): "pattern": "mesh", "link_params": {"cost": 999}, } - # parent_path => "Parent" _expand_blueprint_adjacency(ctx, adj_def, "Parent") - # Only "Parent/leaf-1" matches the source path => single source node, - # "Parent/spine-1" => single target node => 1 link + # leaf-1 => spine-1 => single link assert len(ctx_net.links) == 1 link = next(iter(ctx_net.links.values())) assert link.source == "Parent/leaf-1" @@ -371,17 +353,13 @@ def test_expand_blueprint_adjacency(): def test_expand_adjacency(): - """ - Tests _expand_adjacency for a top-level adjacency definition (non-blueprint), - verifying that leading '/' is stripped and used to find nodes in the global context. - """ + """Tests _expand_adjacency for a top-level adjacency definition.""" ctx_net = Network() ctx_net.add_node(Node("Global/A1")) ctx_net.add_node(Node("Global/B1")) ctx = DSLExpansionContext({}, ctx_net) - # adjacency => "one_to_one" with /Global/A1 -> /Global/B1 adj_def = { "source": "/Global/A1", "target": "/Global/B1", @@ -390,7 +368,6 @@ def test_expand_adjacency(): } _expand_adjacency(ctx, adj_def) - # single pairing => A1 -> B1 assert len(ctx_net.links) == 1 link = next(iter(ctx_net.links.values())) assert link.source == "Global/A1" @@ -400,8 +377,8 @@ def test_expand_adjacency(): def test_expand_group_direct(): """ - Tests _expand_group for a direct node group (no use_blueprint), - ensuring node_count and name_template usage. + Tests _expand_group for a direct node group, ensuring node_count, + name_template usage, plus optional risk_groups. """ ctx_net = Network() ctx = DSLExpansionContext({}, ctx_net) @@ -409,29 +386,32 @@ def test_expand_group_direct(): group_def = { "node_count": 3, "name_template": "myNode-{node_num}", - "coords": [1, 2], + "attrs": {"coords": [1, 2]}, + "risk_groups": ["RGtest"], } _expand_group(ctx, parent_path="", group_name="TestGroup", group_def=group_def) - # Expect 3 nodes => "TestGroup/myNode-1" ... "TestGroup/myNode-3" + # 3 nodes => "TestGroup/myNode-1..3" assert len(ctx_net.nodes) == 3 for i in range(1, 4): name = f"TestGroup/myNode-{i}" assert name in ctx_net.nodes - node = ctx_net.nodes[name] - assert node.attrs["coords"] == [1, 2] - assert node.attrs["type"] == "node" + node_obj = ctx_net.nodes[name] + assert node_obj.attrs["coords"] == [1, 2] + assert node_obj.attrs["type"] == "node" + assert node_obj.risk_groups == {"RGtest"} def test_expand_group_blueprint(): """ - Tests _expand_group referencing a blueprint (basic subgroups + adjacency). - We'll create a blueprint 'bp1' with one subgroup and adjacency, then reference it from group 'Main'. + Tests _expand_group referencing a blueprint. The parent's 'attrs' and 'risk_groups' + are merged into the child nodes. We expect child nodes to have parent's coords + plus parent's risk group. """ bp = Blueprint( name="bp1", groups={ - "leaf": {"node_count": 2}, + "leaf": {"node_count": 2, "risk_groups": ["RGblue"]}, }, adjacency=[ { @@ -444,10 +424,10 @@ def test_expand_group_blueprint(): ctx_net = Network() ctx = DSLExpansionContext(blueprints={"bp1": bp}, network=ctx_net) - # group_def referencing the blueprint group_def = { "use_blueprint": "bp1", - "coords": [10, 20], + "attrs": {"coords": [10, 20]}, + "risk_groups": ["RGparent"], } _expand_group( ctx, @@ -456,32 +436,30 @@ def test_expand_group_blueprint(): group_def=group_def, ) - # This expands 2 leaf nodes => "Main/leaf/leaf-1", "Main/leaf/leaf-2" - # plus adjacency => single link (leaf-1 <-> leaf-2) due to mesh + dedup + # expands 2 leaf nodes => "Main/leaf/leaf-1", "Main/leaf/leaf-2" assert len(ctx_net.nodes) == 2 assert "Main/leaf/leaf-1" in ctx_net.nodes assert "Main/leaf/leaf-2" in ctx_net.nodes - # coords should be carried over + + # parent's risk group => RGparent, child's => RGblue => union => {RGparent, RGblue} + assert ctx_net.nodes["Main/leaf/leaf-1"].risk_groups == {"RGparent", "RGblue"} assert ctx_net.nodes["Main/leaf/leaf-1"].attrs["coords"] == [10, 20] - # adjacency => mesh => 1 unique link + # adjacency => single link assert len(ctx_net.links) == 1 link = next(iter(ctx_net.links.values())) - sources_targets = {link.source, link.target} - assert sources_targets == {"Main/leaf/leaf-1", "Main/leaf/leaf-2"} + assert set([link.source, link.target]) == {"Main/leaf/leaf-1", "Main/leaf/leaf-2"} def test_expand_group_blueprint_with_params(): - """ - Tests _expand_group with blueprint usage and parameter overrides. - """ + """Tests blueprint usage + parameter overrides + parent attrs + risk_groups merging.""" bp = Blueprint( name="bp1", groups={ "leaf": { "node_count": 2, "name_template": "leafy-{node_num}", - "attrs": {"role": "old"}, + "risk_groups": ["RGchild"], }, }, adjacency=[], @@ -492,10 +470,10 @@ def test_expand_group_blueprint_with_params(): group_def = { "use_blueprint": "bp1", "parameters": { - # Overriding the name_template for the subgroup 'leaf' "leaf.name_template": "newleaf-{node_num}", - "leaf.attrs.role": "updated", }, + "attrs": {"coords": [10, 20]}, + "risk_groups": ["RGparent"], } _expand_group( ctx, @@ -504,21 +482,20 @@ def test_expand_group_blueprint_with_params(): group_def=group_def, ) - # We expect 2 nodes => "ZoneA/Main/leaf/newleaf-1" and "...-2" - # plus the updated role attribute + # 2 nodes => "ZoneA/Main/leaf/newleaf-1" & "ZoneA/Main/leaf/newleaf-2" assert len(ctx_net.nodes) == 2 - n1_name = "ZoneA/Main/leaf/newleaf-1" - n2_name = "ZoneA/Main/leaf/newleaf-2" - assert n1_name in ctx_net.nodes - assert n2_name in ctx_net.nodes - assert ctx_net.nodes[n1_name].attrs["role"] == "updated" - assert ctx_net.nodes[n2_name].attrs["role"] == "updated" + n1 = "ZoneA/Main/leaf/newleaf-1" + n2 = "ZoneA/Main/leaf/newleaf-2" + assert n1 in ctx_net.nodes + assert n2 in ctx_net.nodes + + # risk_groups => {RGparent, RGchild} + assert ctx_net.nodes[n1].risk_groups == {"RGparent", "RGchild"} + assert ctx_net.nodes[n1].attrs["coords"] == [10, 20] def test_expand_group_blueprint_unknown(): - """ - Tests _expand_group with a reference to an unknown blueprint -> ValueError. - """ + """Tests referencing an unknown blueprint => ValueError.""" ctx_net = Network() ctx = DSLExpansionContext(blueprints={}, network=ctx_net) @@ -538,29 +515,42 @@ def test_expand_group_blueprint_unknown(): def test_update_nodes(): """ Tests _update_nodes to ensure it updates matching node attributes in bulk. + If 'disabled_val' is provided, sets node.disabled. If 'risk_groups_val' is provided, + it replaces the node's existing risk_groups. Everything else merges into node.attrs. """ net = Network() - net.add_node(Node("N1", attrs={"foo": "old"})) - net.add_node(Node("N2", attrs={"foo": "old"})) + net.add_node(Node("N1", attrs={"foo": "old"}, risk_groups={"RGold"})) + net.add_node(Node("N2", attrs={"foo": "old"}, risk_groups={"RGold"})) net.add_node(Node("M1", attrs={"foo": "unchanged"})) - # We only want to update nodes whose path matches "N" - _update_nodes(net, "N", {"hw_type": "X100", "foo": "new"}) - - # N1, N2 should get updated - assert net.nodes["N1"].attrs["hw_type"] == "X100" + # Force N* nodes to disabled, replace risk_groups with RGnew, plus merge new attrs + _update_nodes( + net, + "N", + {"hw_type": "X100", "foo": "new"}, + disabled_val=True, + risk_groups_val=["RGnew"], + ) + # N1, N2 => updated + assert net.nodes["N1"].disabled is True + assert net.nodes["N1"].risk_groups == {"RGnew"} assert net.nodes["N1"].attrs["foo"] == "new" - assert net.nodes["N2"].attrs["hw_type"] == "X100" + assert net.nodes["N1"].attrs["hw_type"] == "X100" + + assert net.nodes["N2"].disabled is True + assert net.nodes["N2"].risk_groups == {"RGnew"} assert net.nodes["N2"].attrs["foo"] == "new" + assert net.nodes["N2"].attrs["hw_type"] == "X100" - # M1 remains unchanged - assert "hw_type" not in net.nodes["M1"].attrs + # M1 => unchanged + assert net.nodes["M1"].disabled is False assert net.nodes["M1"].attrs["foo"] == "unchanged" def test_update_links(): """ - Tests _update_links to ensure it updates matching links in bulk. + Tests _update_links to ensure it updates matching links in bulk, + using recognized link_params fields only, replacing risk_groups if provided. """ net = Network() net.add_node(Node("S1")) @@ -568,143 +558,153 @@ def test_update_links(): net.add_node(Node("T1")) net.add_node(Node("T2")) - # Create some links - net.add_link(Link("S1", "T1")) - net.add_link(Link("S2", "T2")) - net.add_link(Link("T1", "S2")) # reversed direction + ln1 = Link("S1", "T1", risk_groups={"RGold"}) + ln2 = Link("S2", "T2") + ln3 = Link("T1", "S2") # reversed direction + net.add_link(ln1) + net.add_link(ln2) + net.add_link(ln3) - # Update all links from S->T with capacity=999 - _update_links(net, "S", "T", {"capacity": 999}) + _update_links( + net, + "S", + "T", + {"capacity": 999, "risk_groups": ["RGoverride"]}, + ) - # The link S1->T1 is updated - link_st = [l for l in net.links.values() if l.source == "S1" and l.target == "T1"] - assert link_st[0].capacity == 999 + # S1->T1 updated + link_st1 = net.links[ln1.id] + assert link_st1.capacity == 999 + assert link_st1.risk_groups == {"RGoverride"} - link_st2 = [l for l in net.links.values() if l.source == "S2" and l.target == "T2"] - assert link_st2[0].capacity == 999 + link_st2 = net.links[ln2.id] + assert link_st2.capacity == 999 + assert link_st2.risk_groups == {"RGoverride"} - # The reversed link T1->S2 also matches if any_direction is True by default - link_ts = [l for l in net.links.values() if l.source == "T1" and l.target == "S2"] - assert link_ts[0].capacity == 999 + # reversed T1->S2 also updated (any_direction=True by default) + link_ts = net.links[ln3.id] + assert link_ts.capacity == 999 + assert link_ts.risk_groups == {"RGoverride"} def test_update_links_any_direction_false(): """ - Tests _update_links with any_direction=False to ensure reversed links are NOT updated. + Tests _update_links with any_direction=False => only forward direction updated. """ net = Network() net.add_node(Node("S1")) net.add_node(Node("T1")) - # Create forward and reversed links - fwd_link = Link("S1", "T1", capacity=10) - rev_link = Link("T1", "S1", capacity=10) + fwd_link = Link("S1", "T1", capacity=10, risk_groups={"RGinit"}) + rev_link = Link("T1", "S1", capacity=10, risk_groups={"RGinit"}) net.add_link(fwd_link) net.add_link(rev_link) - # Update only S->T direction - _update_links(net, "S", "T", {"capacity": 999}, any_direction=False) - - # Only the forward link is updated + _update_links( + net, "S", "T", {"capacity": 999, "risk_groups": ["RGnew"]}, any_direction=False + ) assert net.links[fwd_link.id].capacity == 999 + assert net.links[fwd_link.id].risk_groups == {"RGnew"} + + # Reverse link is not updated assert net.links[rev_link.id].capacity == 10 + assert net.links[rev_link.id].risk_groups == {"RGinit"} def test_process_node_overrides(): """ - Tests _process_node_overrides to verify node attributes get updated - based on the DSL's node_overrides block. + Tests _process_node_overrides => merges top-level 'disabled', 'risk_groups' + and merges 'attrs' into node.attrs. """ net = Network() - net.add_node(Node("A/1")) - net.add_node(Node("A/2")) + net.add_node(Node("A/1", risk_groups={"RGold"})) + net.add_node(Node("A/2", risk_groups={"RGold"})) net.add_node(Node("B/1")) network_data = { "node_overrides": [ { - "path": "A", # matches "A/1" and "A/2" - "attrs": {"optics_type": "SR4", "shared_risk_group": "SRG1"}, + "path": "A", + "disabled": True, + "risk_groups": ["RGnew"], + "attrs": {"optics_type": "SR4"}, } ] } _process_node_overrides(net, network_data) - # "A/1" and "A/2" should be updated + # A/1, A/2 => updated + assert net.nodes["A/1"].disabled is True + assert net.nodes["A/1"].risk_groups == {"RGnew"} assert net.nodes["A/1"].attrs["optics_type"] == "SR4" - assert net.nodes["A/1"].attrs["shared_risk_group"] == "SRG1" + assert net.nodes["A/2"].disabled is True + assert net.nodes["A/2"].risk_groups == {"RGnew"} assert net.nodes["A/2"].attrs["optics_type"] == "SR4" - assert net.nodes["A/2"].attrs["shared_risk_group"] == "SRG1" - # "B/1" remains unchanged + # B/1 => unchanged + assert net.nodes["B/1"].disabled is False + assert net.nodes["B/1"].risk_groups == set() assert "optics_type" not in net.nodes["B/1"].attrs - assert "shared_risk_group" not in net.nodes["B/1"].attrs def test_process_link_overrides(): """ - Tests _process_link_overrides to verify link attributes get updated - based on the DSL's link_overrides block. + Tests _process_link_overrides => recognized top-level keys are source/target/link_params/any_direction, + plus recognized link_params keys. No unknown keys are allowed. + Also checks that 'risk_groups' in link_params replaces existing. """ net = Network() net.add_node(Node("A/1")) net.add_node(Node("A/2")) net.add_node(Node("B/1")) - net.add_link(Link("A/1", "A/2", attrs={"color": "red"})) - net.add_link(Link("A/1", "B/1")) + l1 = Link("A/1", "A/2", attrs={"color": "red"}, risk_groups={"RGold"}) + l2 = Link("A/1", "B/1", risk_groups={"RGx"}) + net.add_link(l1) + net.add_link(l2) network_data = { "link_overrides": [ { "source": "A/1", "target": "A/2", - "link_params": {"capacity": 123, "attrs": {"color": "blue"}}, + "link_params": { + "capacity": 123, + "attrs": {"color": "blue"}, + "risk_groups": ["RGnew"], + }, } ] } - _process_link_overrides(net, network_data) - # Only the link A/1->A/2 is updated - link1 = [l for l in net.links.values() if l.source == "A/1" and l.target == "A/2"][ - 0 - ] - assert link1.capacity == 123 - assert link1.attrs["color"] == "blue" + # Only A/1->A/2 updated + assert net.links[l1.id].capacity == 123 + assert net.links[l1.id].attrs["color"] == "blue" + assert net.links[l1.id].risk_groups == {"RGnew"} - # The other link remains unmodified - link2 = [l for l in net.links.values() if l.source == "A/1" and l.target == "B/1"][ - 0 - ] - assert link2.capacity == 1.0 # default - assert "color" not in link2.attrs + # A/1->B/1 => not updated + assert net.links[l2.id].capacity == 1.0 + assert net.links[l2.id].risk_groups == {"RGx"} def test_minimal_no_blueprints(): - """ - Tests a minimal DSL with no blueprints, no adjacency, and a single direct node/link. - Ensures the DSL creates expected nodes/links in the simplest scenario. - """ + """Tests a minimal DSL with no blueprints, a single direct node, and link.""" scenario_data = { "network": { "name": "simple_network", - "nodes": {"A": {"test_attr": 123}, "B": {}}, + "nodes": {"A": {"attrs": {"test_attr": 123}}, "B": {"attrs": {}}}, "links": [{"source": "A", "target": "B", "link_params": {"capacity": 10}}], } } - net = expand_network_dsl(scenario_data) assert net.attrs["name"] == "simple_network" assert len(net.nodes) == 2 assert len(net.links) == 1 - assert "A" in net.nodes assert net.nodes["A"].attrs["test_attr"] == 123 assert "B" in net.nodes - - # Grab the first (and only) Link object link = next(iter(net.links.values())) assert link.source == "A" assert link.target == "B" @@ -713,8 +713,8 @@ def test_minimal_no_blueprints(): def test_simple_blueprint(): """ - Tests a scenario with one blueprint used by one group. - Verifies that blueprint-based groups expand properly and adjacency is handled. + Tests a scenario with one blueprint used by one group, verifying adjacency. + This also tests that no unknown keys are present in the blueprint or group usage. """ scenario_data = { "blueprints": { @@ -732,19 +732,20 @@ def test_simple_blueprint(): }, "network": { "name": "test_simple_blueprint", - "groups": {"R1": {"use_blueprint": "clos_1tier"}}, + "groups": { + "R1": { + "use_blueprint": "clos_1tier", + # we could add "attrs", "disabled" or "risk_groups" here if we wanted + }, + }, }, } net = expand_network_dsl(scenario_data) - - # Expect 2 leaf nodes under path "R1/leaf" + assert net.attrs["name"] == "test_simple_blueprint" assert len(net.nodes) == 2 assert "R1/leaf/leaf-1" in net.nodes assert "R1/leaf/leaf-2" in net.nodes - - # The adjacency is "leaf <-> leaf" mesh => leaf-1 <-> leaf-2 - # mesh deduplicates reversed links => single link assert len(net.links) == 1 only_link = next(iter(net.links.values())) assert only_link.source.endswith("leaf-1") @@ -753,10 +754,7 @@ def test_simple_blueprint(): def test_blueprint_parameters(): - """ - Tests parameter overrides in a blueprint scenario. - Ensures that user-provided overrides (e.g., node_count) are applied. - """ + """Tests parameter overrides in a blueprint scenario.""" scenario_data = { "blueprints": { "multi_layer": { @@ -781,22 +779,18 @@ def test_blueprint_parameters(): } net = expand_network_dsl(scenario_data) - - # layerA gets overridden to node_count=3 - # layerB remains node_count=2 => total 5 nodes + # layerA => 3, layerB => 2 => total 5 nodes assert len(net.nodes) == 5 - - # Confirm naming override overrideA_nodes = [n for n in net.nodes if "overrideA-" in n] - assert len(overrideA_nodes) == 3, "Expected 3 overrideA- nodes" + assert len(overrideA_nodes) == 3 layerB_nodes = [n for n in net.nodes if "layerB-" in n] - assert len(layerB_nodes) == 2, "Expected 2 layerB- nodes" + assert len(layerB_nodes) == 2 def test_direct_nodes_and_links_alongside_blueprints(): """ - Tests mixing a blueprint with direct nodes and links. - Verifies direct nodes are added, links to blueprint-created nodes are valid. + Tests mixing blueprint with direct nodes/links. All extra keys + must be inside 'attrs' or recognized fields like 'risk_groups'. """ scenario_data = { "blueprints": { @@ -809,38 +803,38 @@ def test_direct_nodes_and_links_alongside_blueprints(): }, "network": { "groups": {"BP1": {"use_blueprint": "single_group"}}, - "nodes": {"ExtraNode": {"tag": "extra"}}, + "nodes": { + "ExtraNode": {"attrs": {"tag": "extra"}, "risk_groups": ["RGextra"]} + }, "links": [ { "source": "BP1/mygroup/g-1", "target": "ExtraNode", - "link_params": {"capacity": 50}, + "link_params": {"capacity": 50, "risk_groups": ["RGlink"]}, } ], }, } net = expand_network_dsl(scenario_data) - # 2 blueprint nodes + 1 direct node => 3 total assert len(net.nodes) == 3 assert "BP1/mygroup/g-1" in net.nodes assert "BP1/mygroup/g-2" in net.nodes assert "ExtraNode" in net.nodes + assert net.nodes["ExtraNode"].risk_groups == {"RGextra"} - # One link connecting blueprint node to direct node + # 1 link connecting blueprint node to direct node assert len(net.links) == 1 link = next(iter(net.links.values())) assert link.source == "BP1/mygroup/g-1" assert link.target == "ExtraNode" assert link.capacity == 50 + assert link.risk_groups == {"RGlink"} def test_adjacency_one_to_one(): - """ - Tests a one_to_one adjacency among two groups of equal size (2:2). - We expect each source node pairs with one target node => total 2 links. - """ + """Tests a one_to_one adjacency among two groups of equal size (2:2).""" scenario_data = { "network": { "groups": {"GroupA": {"node_count": 2}, "GroupB": {"node_count": 2}}, @@ -856,25 +850,21 @@ def test_adjacency_one_to_one(): } net = expand_network_dsl(scenario_data) - - # 4 total nodes + # 4 total nodes => 2 from each group assert len(net.nodes) == 4 - # one_to_one => 2 total links - link_names = {(l.source, l.target) for l in net.links.values()} - expected_links = { + # one_to_one => 2 links + pairs = {(l.source, l.target) for l in net.links.values()} + expected = { ("GroupA/GroupA-1", "GroupB/GroupB-1"), ("GroupA/GroupA-2", "GroupB/GroupB-2"), } - assert link_names == expected_links + assert pairs == expected for l in net.links.values(): assert l.capacity == 99 def test_adjacency_one_to_one_wrap(): - """ - Tests a one_to_one adjacency among groups of size 4 and 2. - Because 4%2 == 0, we can wrap around the smaller side => total 4 links. - """ + """Tests a one_to_one adjacency among groups of size 4 vs 2 => wrap => 4 links.""" scenario_data = { "network": { "groups": {"Big": {"node_count": 4}, "Small": {"node_count": 2}}, @@ -890,10 +880,9 @@ def test_adjacency_one_to_one_wrap(): } net = expand_network_dsl(scenario_data) - - # 6 total nodes => Big(4) + Small(2) + # 6 total => Big(4) + Small(2) assert len(net.nodes) == 6 - # Wrap => Big-1->Small-1, Big-2->Small-2, Big-3->Small-1, Big-4->Small-2 => 4 links + # wrap => 4 links assert len(net.links) == 4 link_pairs = {(l.source, l.target) for l in net.links.values()} expected = { @@ -908,14 +897,12 @@ def test_adjacency_one_to_one_wrap(): def test_adjacency_mesh(): - """ - Tests a mesh adjacency among two groups, ensuring all nodes from each group are interconnected. - """ + """Tests a mesh adjacency among two groups => all nodes cross-connected.""" scenario_data = { "network": { "groups": { - "Left": {"node_count": 2}, # => Left/Left-1, Left/Left-2 - "Right": {"node_count": 2}, # => Right/Right-1, Right/Right-2 + "Left": {"node_count": 2}, + "Right": {"node_count": 2}, }, "adjacency": [ { @@ -929,7 +916,6 @@ def test_adjacency_mesh(): } net = expand_network_dsl(scenario_data) - # 4 total nodes assert len(net.nodes) == 4 # mesh => 4 unique links @@ -938,19 +924,17 @@ def test_adjacency_mesh(): assert link.cost == 5 -def test_fallback_prefix_behavior(): +def test_fallback_small_single_node(): """ - Tests the fallback prefix logic. If no normal match, we do partial or 'path-' fallback. - In this scenario, we have 1 node => "FallbackGroup/FallbackGroup-1". - The adjacency tries a one_to_one pattern => if we want to skip self-loops in all patterns, - the result is 0 links. + Just a small check: 1 group => 1 node => adjacency among same group => one_to_one + => but single node => no link created if skipping self-loops. """ scenario_data = { "network": { "groups": { "FallbackGroup": { "node_count": 1, - "name_template": "FallbackGroup-{node_num}", + "name_template": "X-{node_num}", } }, "adjacency": [ @@ -964,29 +948,22 @@ def test_fallback_prefix_behavior(): } net = expand_network_dsl(scenario_data) - - # 1 node => name "FallbackGroup/FallbackGroup-1" + # 1 node => "FallbackGroup/X-1" assert len(net.nodes) == 1 - assert "FallbackGroup/FallbackGroup-1" in net.nodes - - # "one_to_one" with a single node => skipping self-loops => 0 links + # adjacency => single node => no link assert len(net.links) == 0 def test_direct_link_unknown_node_raises(): - """ - Ensures that referencing unknown nodes in a direct link raises an error. - """ + """Ensures referencing unknown nodes in a direct link => ValueError.""" scenario_data = { "network": { - "nodes": {"KnownNode": {}}, + "nodes": {"KnownNode": {"attrs": {}}}, "links": [{"source": "KnownNode", "target": "UnknownNode"}], } } - with pytest.raises(ValueError) as excinfo: expand_network_dsl(scenario_data) - assert "Link references unknown node(s): KnownNode, UnknownNode" in str( excinfo.value ) @@ -994,267 +971,75 @@ def test_direct_link_unknown_node_raises(): def test_existing_node_preserves_attrs(): """ - Tests that if a node is already present in the network, direct node definitions don't overwrite - its existing attributes except for 'type' which is ensured by default. + Tests that if a node is already present (like from a group), + direct node definition with same name does nothing (we skip). """ scenario_data = { "network": { "groups": {"Foo": {"node_count": 1, "name_template": "X-{node_num}"}}, - "nodes": {"Foo/X-1": {"myattr": 123}}, + # We'll define the same node here. The code should skip, leaving it as-is. + "nodes": {"Foo/X-1": {"attrs": {"myattr": 123}, "disabled": True}}, } } net = expand_network_dsl(scenario_data) - - # There's only 1 node => "Foo/X-1" + # There's 1 node => "Foo/X-1" from group assert len(net.nodes) == 1 node_obj = net.nodes["Foo/X-1"] - - # The code sets "type"="node" if not present but doesn't merge other attributes. - # So "myattr" won't appear, because the node was created from groups. - assert "myattr" not in node_obj.attrs + # from the group creation => the node has "type": "node" but not "myattr" + # and not disabled. We do not merge the direct node definition with it. assert node_obj.attrs["type"] == "node" + assert "myattr" not in node_obj.attrs + assert node_obj.disabled is False def test_expand_network_dsl_empty(): - """ - Tests calling expand_network_dsl with an empty dictionary => empty Network. - """ + """Tests calling expand_network_dsl with an empty dictionary => empty Network.""" net = expand_network_dsl({}) assert len(net.nodes) == 0 assert len(net.links) == 0 - assert not net.attrs, "No attributes expected in an empty scenario." + assert not net.attrs def test_network_version_attribute(): - """ - Tests that 'version' in the network data is recorded in net.attrs. - """ - scenario_data = { - "network": { - "version": "1.2.3", - } - } + """Tests that 'version' in the network data is recorded in net.attrs.""" + scenario_data = {"network": {"version": "1.2.3"}} net = expand_network_dsl(scenario_data) assert net.attrs["version"] == "1.2.3" def test_expand_group_with_bracket_expansions(): - """ - Tests bracket expansions in group names, e.g. group_name='fa[1-2]_plane[3-4]'. - We expect 4 expansions => fa1_plane3, fa1_plane4, fa2_plane3, fa2_plane4. - """ + """Tests bracket expansions in group names => multiple expansions => replicate group_def.""" ctx_net = Network() ctx = DSLExpansionContext({}, ctx_net) - group_def = {"node_count": 1} # We'll create 1 node per expanded group + group_def = {"node_count": 1} _expand_group( ctx, parent_path="", group_name="fa[1-2]_plane[3-4]", group_def=group_def ) - # We expect 4 groups => each with 1 node => total 4 nodes - expected_names = { + expected = { "fa1_plane3/fa1_plane3-1", "fa1_plane4/fa1_plane4-1", "fa2_plane3/fa2_plane3-1", "fa2_plane4/fa2_plane4-1", } - assert set(ctx_net.nodes.keys()) == expected_names + assert set(ctx_net.nodes.keys()) == expected def test_apply_parameters_nested_fields(): """ Tests parameter overrides for nested fields beyond just 'attrs'. - E.g., 'leaf.some_field.nested_key = 999'. + Here we keep 'some_field' under 'attrs' so it is recognized as user-defined. """ bp = Blueprint( name="bp1", groups={ "leaf": { "node_count": 1, - "some_field": {"nested_key": 111}, - }, - }, - adjacency=[], - ) - ctx_net = Network() - ctx = DSLExpansionContext(blueprints={"bp1": bp}, network=ctx_net) - - group_def = { - "use_blueprint": "bp1", - "parameters": { - "leaf.some_field.nested_key": 999, - }, - } - _expand_group( - ctx, - parent_path="Region", - group_name="Main", - group_def=group_def, - ) - - # Expect 1 node => "Region/Main/leaf/leaf-1" - assert len(ctx_net.nodes) == 1 - node_obj = ctx_net.nodes["Region/Main/leaf/leaf-1"] - # Check that nested field was updated - assert node_obj.attrs["some_field"]["nested_key"] == 999 - - -def test_link_overrides_repeated(): - """ - Tests applying multiple link_overrides in sequence to the same links. - Each override can set different fields, verifying that the last override - wins if there's a conflict. - """ - net = Network() - net.add_node(Node("S1")) - net.add_node(Node("T1")) - link = Link("S1", "T1", capacity=5, cost=5, attrs={}) - net.add_link(link) - - network_data = { - "link_overrides": [ - { - "source": "S1", - "target": "T1", - "link_params": { - "capacity": 100, - "attrs": {"color": "red"}, - }, - }, - { - "source": "S1", - "target": "T1", - "link_params": { - "cost": 999, - "attrs": {"color": "blue"}, # Overwrites 'color': 'red' - }, - }, - ] - } - _process_link_overrides(net, network_data) - assert link.capacity == 100 - assert link.cost == 999 - assert link.attrs["color"] == "blue" # second override wins - - -def test_node_overrides_repeated(): - """ - Tests multiple node_overrides in sequence, verifying that the last override - wins on conflicting attributes and merges others. - """ - net = Network() - net.add_node(Node("X", attrs={"existing": "keep"})) - - network_data = { - "node_overrides": [ - { - "path": "X", - "attrs": { - "role": "old_role", - "color": "red", - }, - }, - { - "path": "X", "attrs": { - "role": "updated_role", - "speed": "fast", - }, - }, - ] - } - _process_node_overrides(net, network_data) - node_attrs = net.nodes["X"].attrs - - # existing attribute is retained - assert node_attrs["existing"] == "keep" - # role was overwritten by second override - assert node_attrs["role"] == "updated_role" - # color is from the first override but not overwritten by the second => remains - assert node_attrs["color"] == "red" - # speed is added by the second override - assert node_attrs["speed"] == "fast" - - -def test_adjacency_no_matching_source_or_target(): - """ - Tests adjacency expansion where the source or target path does not match any nodes. - Should simply skip and create no links. - """ - scenario_data = { - "network": { - "nodes": {"RealNode": {}}, - "adjacency": [ - { - "source": "/MissingSource", - "target": "/RealNode", - "pattern": "mesh", - }, - { - "source": "/RealNode", - "target": "/MissingTarget", - "pattern": "mesh", + "some_field": {"nested_key": 111}, }, - ], - } - } - net = expand_network_dsl(scenario_data) - # Only 1 node => RealNode - assert len(net.nodes) == 1 - # No valid adjacency => no links - assert len(net.links) == 0 - - -def test_provide_network_version_and_name(): - """ - Tests that both 'name' and 'version' keys in the DSL are captured as net.attrs. - """ - data = { - "network": { - "name": "NetGraphTest", - "version": "2.0-beta", - } - } - net = expand_network_dsl(data) - assert net.attrs["name"] == "NetGraphTest" - assert net.attrs["version"] == "2.0-beta" - - -def test_expand_group_with_bracket_expansions(): - """ - Tests bracket expansions in group names, e.g. group_name='fa[1-2]_plane[3-4]'. - We expect 4 expansions => fa1_plane3, fa1_plane4, fa2_plane3, fa2_plane4. - """ - ctx_net = Network() - ctx = DSLExpansionContext({}, ctx_net) - - group_def = {"node_count": 1} # We'll create 1 node per expanded group - _expand_group( - ctx, parent_path="", group_name="fa[1-2]_plane[3-4]", group_def=group_def - ) - - # We expect 4 groups => each with 1 node => total 4 nodes - expected_names = { - "fa1_plane3/fa1_plane3-1", - "fa1_plane4/fa1_plane4-1", - "fa2_plane3/fa2_plane3-1", - "fa2_plane4/fa2_plane4-1", - } - assert set(ctx_net.nodes.keys()) == expected_names - - -def test_apply_parameters_nested_fields(): - """ - Tests parameter overrides for nested fields beyond just 'attrs'. - E.g., 'leaf.some_field.nested_key = 999'. - """ - bp = Blueprint( - name="bp1", - groups={ - "leaf": { - "node_count": 1, - "some_field": {"nested_key": 111}, }, }, adjacency=[], @@ -1265,7 +1050,8 @@ def test_apply_parameters_nested_fields(): group_def = { "use_blueprint": "bp1", "parameters": { - "leaf.some_field.nested_key": 999, + # Note we override the nested field by referencing 'leaf.attrs.some_field.nested_key' + "leaf.attrs.some_field.nested_key": 999, }, } _expand_group( @@ -1275,19 +1061,15 @@ def test_apply_parameters_nested_fields(): group_def=group_def, ) - # Expect 1 node => "Region/Main/leaf/leaf-1" + # 1 node => "Region/Main/leaf/leaf-1" assert len(ctx_net.nodes) == 1 node_obj = ctx_net.nodes["Region/Main/leaf/leaf-1"] - # Check that nested field was updated + # 'some_field' is stored under node_obj.attrs assert node_obj.attrs["some_field"]["nested_key"] == 999 def test_link_overrides_repeated(): - """ - Tests applying multiple link_overrides in sequence to the same links. - Each override can set different fields, verifying that the last override - wins if there's a conflict. - """ + """Tests applying multiple link_overrides in sequence => last override wins on conflict.""" net = Network() net.add_node(Node("S1")) net.add_node(Node("T1")) @@ -1309,7 +1091,8 @@ def test_link_overrides_repeated(): "target": "T1", "link_params": { "cost": 999, - "attrs": {"color": "blue"}, # Overwrites 'color': 'red' + "attrs": {"color": "blue"}, # overwrites 'red' + "risk_groups": ["RGfinal"], }, }, ] @@ -1317,16 +1100,15 @@ def test_link_overrides_repeated(): _process_link_overrides(net, network_data) assert link.capacity == 100 assert link.cost == 999 - assert link.attrs["color"] == "blue" # second override wins + assert link.attrs["color"] == "blue" + # The second override sets risk_groups => replaces any existing + assert link.risk_groups == {"RGfinal"} def test_node_overrides_repeated(): - """ - Tests multiple node_overrides in sequence, verifying that the last override - wins on conflicting attributes and merges others. - """ + """Tests multiple node_overrides => last one overwrites shared attrs, merges distinct ones, replaces risk_groups if set.""" net = Network() - net.add_node(Node("X", attrs={"existing": "keep"})) + net.add_node(Node("X", attrs={"existing": "keep"}, risk_groups={"RGold"})) network_data = { "node_overrides": [ @@ -1336,6 +1118,7 @@ def test_node_overrides_repeated(): "role": "old_role", "color": "red", }, + "risk_groups": ["RGfirst"], }, { "path": "X", @@ -1343,212 +1126,30 @@ def test_node_overrides_repeated(): "role": "updated_role", "speed": "fast", }, + "risk_groups": ["RGsecond"], }, ] } _process_node_overrides(net, network_data) node_attrs = net.nodes["X"].attrs - - # existing attribute is retained + # existing => remains assert node_attrs["existing"] == "keep" - # role was overwritten by second override + # role => updated_role assert node_attrs["role"] == "updated_role" - # color is from the first override but not overwritten by the second => remains + # color => from first override, not overwritten by second => still "red" assert node_attrs["color"] == "red" - # speed is added by the second override + # speed => from second assert node_attrs["speed"] == "fast" - -def test_adjacency_no_matching_source_or_target(): - """ - Tests adjacency expansion where the source or target path does not match any nodes. - Should simply skip and create no links. - """ - scenario_data = { - "network": { - "nodes": {"RealNode": {}}, - "adjacency": [ - { - "source": "/MissingSource", - "target": "/RealNode", - "pattern": "mesh", - }, - { - "source": "/RealNode", - "target": "/MissingTarget", - "pattern": "mesh", - }, - ], - } - } - net = expand_network_dsl(scenario_data) - # Only 1 node => RealNode - assert len(net.nodes) == 1 - # No valid adjacency => no links - assert len(net.links) == 0 - - -def test_provide_network_version_and_name(): - """ - Tests that both 'name' and 'version' keys in the DSL are captured as net.attrs. - """ - data = { - "network": { - "name": "NetGraphTest", - "version": "2.0-beta", - } - } - net = expand_network_dsl(data) - assert net.attrs["name"] == "NetGraphTest" - assert net.attrs["version"] == "2.0-beta" - - -def test_expand_group_with_bracket_expansions(): - """ - Tests bracket expansions in group names, e.g. group_name='fa[1-2]_plane[3-4]'. - We expect 4 expansions => fa1_plane3, fa1_plane4, fa2_plane3, fa2_plane4. - """ - ctx_net = Network() - ctx = DSLExpansionContext({}, ctx_net) - - group_def = {"node_count": 1} # We'll create 1 node per expanded group - _expand_group( - ctx, parent_path="", group_name="fa[1-2]_plane[3-4]", group_def=group_def - ) - - # We expect 4 groups => each with 1 node => total 4 nodes - expected_names = { - "fa1_plane3/fa1_plane3-1", - "fa1_plane4/fa1_plane4-1", - "fa2_plane3/fa2_plane3-1", - "fa2_plane4/fa2_plane4-1", - } - assert set(ctx_net.nodes.keys()) == expected_names - - -def test_apply_parameters_nested_fields(): - """ - Tests parameter overrides for nested fields beyond just 'attrs'. - E.g., 'leaf.some_field.nested_key = 999'. - """ - bp = Blueprint( - name="bp1", - groups={ - "leaf": { - "node_count": 1, - "some_field": {"nested_key": 111}, - }, - }, - adjacency=[], - ) - ctx_net = Network() - ctx = DSLExpansionContext(blueprints={"bp1": bp}, network=ctx_net) - - group_def = { - "use_blueprint": "bp1", - "parameters": { - "leaf.some_field.nested_key": 999, - }, - } - _expand_group( - ctx, - parent_path="Region", - group_name="Main", - group_def=group_def, - ) - - # Expect 1 node => "Region/Main/leaf/leaf-1" - assert len(ctx_net.nodes) == 1 - node_obj = ctx_net.nodes["Region/Main/leaf/leaf-1"] - # Check that nested field was updated - assert node_obj.attrs["some_field"]["nested_key"] == 999 - - -def test_link_overrides_repeated(): - """ - Tests applying multiple link_overrides in sequence to the same links. - Each override can set different fields, verifying that the last override - wins if there's a conflict. - """ - net = Network() - net.add_node(Node("S1")) - net.add_node(Node("T1")) - link = Link("S1", "T1", capacity=5, cost=5, attrs={}) - net.add_link(link) - - network_data = { - "link_overrides": [ - { - "source": "S1", - "target": "T1", - "link_params": { - "capacity": 100, - "attrs": {"color": "red"}, - }, - }, - { - "source": "S1", - "target": "T1", - "link_params": { - "cost": 999, - "attrs": {"color": "blue"}, # Overwrites 'color': 'red' - }, - }, - ] - } - _process_link_overrides(net, network_data) - assert link.capacity == 100 - assert link.cost == 999 - assert link.attrs["color"] == "blue" # second override wins - - -def test_node_overrides_repeated(): - """ - Tests multiple node_overrides in sequence, verifying that the last override - wins on conflicting attributes and merges others. - """ - net = Network() - net.add_node(Node("X", attrs={"existing": "keep"})) - - network_data = { - "node_overrides": [ - { - "path": "X", - "attrs": { - "role": "old_role", - "color": "red", - }, - }, - { - "path": "X", - "attrs": { - "role": "updated_role", - "speed": "fast", - }, - }, - ] - } - _process_node_overrides(net, network_data) - node_attrs = net.nodes["X"].attrs - - # existing attribute is retained - assert node_attrs["existing"] == "keep" - # role was overwritten by second override - assert node_attrs["role"] == "updated_role" - # color is from the first override but not overwritten by the second => remains - assert node_attrs["color"] == "red" - # speed is added by the second override - assert node_attrs["speed"] == "fast" + # risk_groups => replaced by second => RGsecond + assert net.nodes["X"].risk_groups == {"RGsecond"} def test_adjacency_no_matching_source_or_target(): - """ - Tests adjacency expansion where the source or target path does not match any nodes. - Should simply skip and create no links. - """ + """Tests adjacency expansion where source/target path doesn't match any nodes => skip.""" scenario_data = { "network": { - "nodes": {"RealNode": {}}, + "nodes": {"RealNode": {"attrs": {}}}, "adjacency": [ { "source": "/MissingSource", @@ -1564,16 +1165,12 @@ def test_adjacency_no_matching_source_or_target(): } } net = expand_network_dsl(scenario_data) - # Only 1 node => RealNode assert len(net.nodes) == 1 - # No valid adjacency => no links assert len(net.links) == 0 def test_provide_network_version_and_name(): - """ - Tests that both 'name' and 'version' keys in the DSL are captured as net.attrs. - """ + """Tests that both 'name' and 'version' in DSL => net.attrs.""" data = { "network": { "name": "NetGraphTest", @@ -1586,16 +1183,13 @@ def test_provide_network_version_and_name(): def test_expand_adjacency_with_variables_zip(): - """ - Tests adjacency expansion with 'expand_vars' in 'zip' mode. - Verifies that expansions occur in lockstep for equal-length lists. - """ + """Tests adjacency with expand_vars in 'zip' mode => expansions in lockstep.""" scenario_data = { "network": { "groups": { - "RackA": {"node_count": 1, "name_template": "RackA-{node_num}"}, - "RackB": {"node_count": 1, "name_template": "RackB-{node_num}"}, - "RackC": {"node_count": 1, "name_template": "RackC-{node_num}"}, + "RackA": {"node_count": 1}, + "RackB": {"node_count": 1}, + "RackC": {"node_count": 1}, }, "adjacency": [ { @@ -1613,19 +1207,10 @@ def test_expand_adjacency_with_variables_zip(): } } net = expand_network_dsl(scenario_data) - - # We have 3 racks: RackA-1, RackB-1, RackC-1 - # expand_vars with zip => (A->B), (B->C), (C->A) for the source/target - # pattern=mesh => each source node to each target node => but each "group" here has only 1 node - # => we get exactly 3 unique links + # (A->B), (B->C), (C->A) assert len(net.nodes) == 3 assert len(net.links) == 3 - link_pairs = {(l.source, l.target) for l in net.links.values()} - # RackA-1 -> RackB-1 - # RackB-1 -> RackC-1 - # RackC-1 -> RackA-1 - # (no duplication, no self-loops) expected = { ("RackA/RackA-1", "RackB/RackB-1"), ("RackB/RackB-1", "RackC/RackC-1"), @@ -1637,9 +1222,7 @@ def test_expand_adjacency_with_variables_zip(): def test_expand_adjacency_with_variables_zip_mismatch(): - """ - Tests that 'zip' mode with lists of different lengths raises ValueError. - """ + """Tests 'zip' mode with mismatched list lengths => ValueError.""" scenario_data = { "network": { "groups": { @@ -1653,7 +1236,7 @@ def test_expand_adjacency_with_variables_zip_mismatch(): "target": "/Rack{other_rack_id}", "expand_vars": { "rack_id": ["A", "B"], - "other_rack_id": ["C", "A", "B"], # mismatch length + "other_rack_id": ["C", "A", "B"], # mismatch }, "expansion_mode": "zip", } diff --git a/tests/test_failure_policy.py b/tests/test_failure_policy.py index 99f3526..2437a78 100644 --- a/tests/test_failure_policy.py +++ b/tests/test_failure_policy.py @@ -9,427 +9,279 @@ ) -def test_empty_policy_no_failures(): - """ - Verify that if no rules are present, no entities fail. - """ - policy = FailurePolicy(rules=[]) - - # Suppose we have 2 nodes, 1 link - nodes = { - "N1": {"type": "node", "capacity": 100}, - "N2": {"type": "node", "capacity": 200}, - } - links = { - "N1-N2-abc123": {"type": "link", "capacity": 50}, - } - - failed = policy.apply_failures(nodes, links) - assert failed == [], "No rules => no entities fail." - - -def test_single_rule_all_matched(): - """ - If we have a rule that matches all entities and selects 'all', - then everything fails. - """ +def test_node_scope_all(): + """Rule with entity_scope='node' and rule_type='all' => fails all matched nodes.""" rule = FailureRule( - conditions=[FailureCondition(attr="type", operator="!=", value="")], + entity_scope="node", + conditions=[FailureCondition(attr="capacity", operator=">", value=50)], logic="and", rule_type="all", ) policy = FailurePolicy(rules=[rule]) - nodes = {"N1": {"type": "node"}, "N2": {"type": "node"}} + # 3 nodes, 2 links + nodes = { + "N1": {"capacity": 100, "region": "west"}, + "N2": {"capacity": 40, "region": "east"}, + "N3": {"capacity": 60}, + } links = { - "L1": {"type": "link"}, - "L2": {"type": "link"}, + "L1": {"capacity": 999}, + "L2": {"capacity": 10}, } failed = policy.apply_failures(nodes, links) - assert set(failed) == {"N1", "N2", "L1", "L2"} + # Should fail nodes with capacity>50 => N1(100), N3(60) + # Does not consider links at all + assert set(failed) == {"N1", "N3"} -def test_single_rule_choice(): - """ - Test rule_type='choice': it picks exactly 'count' entities from the matched set. - """ +def test_link_scope_choice(): + """Rule with entity_scope='link' => only matches links, ignoring nodes.""" rule = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="node")], + entity_scope="link", + conditions=[FailureCondition(attr="capacity", operator="==", value=100)], logic="and", rule_type="choice", - count=2, + count=1, ) policy = FailurePolicy(rules=[rule]) nodes = { - "SEA": {"type": "node", "capacity": 100}, - "SFO": {"type": "node", "capacity": 200}, - "DEN": {"type": "node", "capacity": 300}, + "N1": {"capacity": 100}, + "N2": {"capacity": 100}, } links = { - "SEA-SFO-xxx": {"type": "link", "capacity": 400}, + "L1": {"capacity": 100, "risk_groups": ["RG1"]}, + "L2": {"capacity": 100}, + "L3": {"capacity": 50}, } - with patch("ngraph.failure_policy.sample", return_value=["SEA", "DEN"]): + with patch("ngraph.failure_policy.sample", return_value=["L2"]): failed = policy.apply_failures(nodes, links) - assert set(failed) == {"SEA", "DEN"} + # Matches L1, L2 (capacity=100), picks exactly 1 => "L2" + assert set(failed) == {"L2"} -@patch("ngraph.failure_policy.random") -def test_single_rule_random(mock_random): +def test_risk_group_scope_random(): """ - For rule_type='random', each matched entity is selected if random() < probability. - We'll mock out random() to test. + Rule with entity_scope='risk_group' => matches risk groups by cost>100 and selects + each match with probability=0.5. We mock random() calls so the first match is picked, + the second match is skipped, but the iteration order is not guaranteed. Therefore, we + only verify that exactly one of the matched RGs is selected. """ rule = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="link")], + entity_scope="risk_group", + conditions=[FailureCondition(attr="cost", operator=">", value=100)], logic="and", rule_type="random", probability=0.5, ) policy = FailurePolicy(rules=[rule]) - nodes = { - "SEA": {"type": "node"}, - "SFO": {"type": "node"}, - } - links = { - "L1": {"type": "link", "capacity": 100}, - "L2": {"type": "link", "capacity": 100}, - "L3": {"type": "link", "capacity": 100}, - } - - mock_random.side_effect = [0.4, 0.6, 0.3] - failed = policy.apply_failures(nodes, links) - assert set(failed) == {"L1", "L3"}, "Should fail those where random() < 0.5" - - -def test_operator_conditions(): - """ - Check that <, != conditions evaluate correctly in 'and' logic. - (We also have coverage for ==, > in other tests.) - """ - conditions = [ - FailureCondition(attr="capacity", operator="<", value=300), - FailureCondition(attr="region", operator="!=", value="east"), - ] - rule = FailureRule(conditions=conditions, logic="and", rule_type="all") - policy = FailurePolicy(rules=[rule]) - - nodes = { - "N1": {"type": "node", "capacity": 100, "region": "west"}, # matches - "N2": {"type": "node", "capacity": 100, "region": "east"}, # fails != - "N3": {"type": "node", "capacity": 300, "region": "west"}, # fails < - } - links = { - "L1": {"type": "link", "capacity": 200, "region": "east"}, # fails != - } - - failed = policy.apply_failures(nodes, links) - assert failed == ["N1"] - - -def test_logic_or(): - """ - Check 'or' logic: an entity is matched if it satisfies at least one condition (>150 or region=east). - """ - conditions = [ - FailureCondition(attr="capacity", operator=">", value=150), - FailureCondition(attr="region", operator="==", value="east"), - ] - rule = FailureRule(conditions=conditions, logic="or", rule_type="all") - policy = FailurePolicy(rules=[rule]) - - nodes = { - "N1": {"type": "node", "capacity": 100, "region": "west"}, # fails both - "N2": { - "type": "node", - "capacity": 200, - "region": "west", - }, # passes capacity>150 - "N3": {"type": "node", "capacity": 100, "region": "east"}, # passes region=east - "N4": {"type": "node", "capacity": 200, "region": "east"}, # passes both - } + nodes = {} links = {} - failed = policy.apply_failures(nodes, links) - assert set(failed) == {"N2", "N3", "N4"} - - -def test_logic_any(): - """ - 'any' logic means all entities are selected, ignoring conditions. - """ - rule = FailureRule( - conditions=[FailureCondition(attr="capacity", operator="==", value=-999)], - logic="any", - rule_type="all", - ) - policy = FailurePolicy(rules=[rule]) + risk_groups = { + "RG1": {"name": "RG1", "cost": 200}, + "RG2": {"name": "RG2", "cost": 50}, + "RG3": {"name": "RG3", "cost": 300}, + } - nodes = {"N1": {"type": "node"}, "N2": {"type": "node"}} - links = {"L1": {"type": "link"}, "L2": {"type": "link"}} + # RG1 and RG3 match; RG2 does not + # We'll mock random => [0.4, 0.6] so that one match is picked (0.4 < 0.5) + # and the other is skipped (0.6 >= 0.5). The set iteration order is not guaranteed, + # so we only check that exactly 1 RG is chosen, and it must be from RG1/RG3. + with patch("ngraph.failure_policy.random") as mock_random: + mock_random.side_effect = [0.4, 0.6] + failed = policy.apply_failures(nodes, links, risk_groups) - failed = policy.apply_failures(nodes, links) - assert set(failed) == {"N1", "N2", "L1", "L2"} + # Exactly one should fail, and it must be one of the two matched. + assert len(failed) == 1 + assert set(failed).issubset({"RG1", "RG3"}) -def test_multiple_rules_union(): +def test_multi_rule_union(): """ - If multiple rules exist, the final set of failed entities is the union - of each rule's selection. + Two rules => union of results: one rule fails certain nodes, the other fails certain links. """ - rule1 = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="node")], + r1 = FailureRule( + entity_scope="node", + conditions=[FailureCondition(attr="capacity", operator=">", value=100)], logic="and", rule_type="all", ) - rule2 = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="link")], + r2 = FailureRule( + entity_scope="link", + conditions=[FailureCondition(attr="cost", operator="==", value=9)], logic="and", rule_type="choice", count=1, ) - policy = FailurePolicy(rules=[rule1, rule2]) - - nodes = {"N1": {"type": "node"}, "N2": {"type": "node"}} - links = {"L1": {"type": "link"}, "L2": {"type": "link"}} + policy = FailurePolicy(rules=[r1, r2]) + nodes = { + "N1": {"capacity": 50}, + "N2": {"capacity": 120}, # fails rule1 + } + links = { + "L1": {"cost": 9}, # matches rule2 + "L2": {"cost": 9}, # matches rule2 + "L3": {"cost": 7}, + } with patch("ngraph.failure_policy.sample", return_value=["L1"]): failed = policy.apply_failures(nodes, links) - assert set(failed) == {"N1", "N2", "L1"} - - -def test_unsupported_logic(): - """ - Ensure that if a rule specifies an unsupported logic string, - _evaluate_conditions() raises ValueError. - """ - rule = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="node")], - logic="UNSUPPORTED", - rule_type="all", - ) - policy = FailurePolicy(rules=[rule]) + # fails N2 from rule1, fails L1 from rule2 => union + assert set(failed) == {"N2", "L1"} - nodes = {"A": {"type": "node"}} - links = {} - with pytest.raises(ValueError, match="Unsupported logic: UNSUPPORTED"): - policy.apply_failures(nodes, links) - -def test_unsupported_rule_type(): +def test_fail_shared_risk_groups(): """ - Ensure that if a rule has an unknown rule_type, - _select_entities() raises ValueError. + If fail_shared_risk_groups=True, failing any node/link also fails + all node/links that share a risk group with it. """ rule = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="node")], - logic="and", - rule_type="UNKNOWN", - ) - policy = FailurePolicy(rules=[rule]) - - nodes = {"A": {"type": "node"}} - links = {} - with pytest.raises(ValueError, match="Unsupported rule_type: UNKNOWN"): - policy.apply_failures(nodes, links) - - -def test_unsupported_operator(): - """ - If a condition has an unknown operator, _evaluate_condition() raises ValueError. - """ - cond = FailureCondition(attr="capacity", operator="??", value=100) - with pytest.raises(ValueError, match="Unsupported operator: "): - _evaluate_condition({"capacity": 100}, cond) - - -def test_no_conditions_with_non_any_logic(): - """ - If logic is not 'any' but conditions is empty, - we expect _evaluate_conditions() to return False. - """ - rule = FailureRule(conditions=[], logic="and", rule_type="all") - policy = FailurePolicy(rules=[rule]) - - nodes = {"N1": {"type": "node"}} - links = {} - failed = policy.apply_failures(nodes, links) - assert failed == [], "No conditions => no match => no failures." - - -def test_choice_larger_count_than_matched(): - """ - If rule.count > number of matched entities, we pick all matched. - """ - rule = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="node")], + entity_scope="link", + conditions=[FailureCondition(attr="capacity", operator=">", value=100)], logic="and", rule_type="choice", - count=10, + count=1, ) - policy = FailurePolicy(rules=[rule]) - - nodes = {"A": {"type": "node"}, "B": {"type": "node"}} - links = {"L1": {"type": "link"}} - failed = policy.apply_failures(nodes, links) - assert set(failed) == {"A", "B"} - - -def test_choice_zero_count(): - """ - If rule.count=0, we select none from the matched entities. - """ - rule = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="node")], - logic="and", - rule_type="choice", - count=0, + # Only "L2" has capacity>100 => it will definitely match + # We pick exactly 1 => "L2" + policy = FailurePolicy( + rules=[rule], + fail_shared_risk_groups=True, ) - policy = FailurePolicy(rules=[rule]) - - nodes = {"A": {"type": "node"}, "B": {"type": "node"}, "C": {"type": "node"}} - links = {} - failed = policy.apply_failures(nodes, links) - assert failed == [], "count=0 => no entities chosen." + nodes = { + "N1": {"capacity": 999, "risk_groups": ["RGalpha"]}, # not matched by link rule + "N2": {"capacity": 10, "risk_groups": ["RGalpha"]}, + } + links = { + "L1": {"capacity": 100, "risk_groups": ["RGbeta"]}, + "L2": {"capacity": 300, "risk_groups": ["RGalpha"]}, # matched + "L3": {"capacity": 80, "risk_groups": ["RGalpha"]}, + "L4": {"capacity": 500, "risk_groups": ["RGgamma"]}, + } -def test_operator_condition_le_ge(): - """ - Verify that the '<=' and '>=' operators in _evaluate_condition are correctly handled. - """ - cond_le = FailureCondition(attr="capacity", operator="<=", value=100) - cond_ge = FailureCondition(attr="capacity", operator=">=", value=100) - - # Entity with capacity=100 => passes both <=100 and >=100 - e1 = {"capacity": 100} - assert _evaluate_condition(e1, cond_le) is True - assert _evaluate_condition(e1, cond_ge) is True - - # capacity=90 => pass <=100, fail >=100 - e2 = {"capacity": 90} - assert _evaluate_condition(e2, cond_le) is True - assert _evaluate_condition(e2, cond_ge) is False - - # capacity=110 => fail <=100, pass >=100 - e3 = {"capacity": 110} - assert _evaluate_condition(e3, cond_le) is False - assert _evaluate_condition(e3, cond_ge) is True + with patch("ngraph.failure_policy.sample", return_value=["L2"]): + failed = policy.apply_failures(nodes, links) + # L2 fails => shares risk_groups "RGalpha" => that includes N1, N2, L3 + # so they all fail + # L4 is not in RGalpha => remains unaffected + assert set(failed) == {"L2", "N1", "N2", "L3"} -def test_operator_contains_not_contains(): +def test_fail_risk_group_children(): """ - Verify that 'contains' and 'not_contains' operators work with string or list attributes. + If fail_risk_group_children=True, failing a risk group also fails + its children recursively. """ - rule_contains = FailureRule( - conditions=[FailureCondition(attr="tags", operator="contains", value="foo")], + # We'll fail any RG with cost>=200 + rule = FailureRule( + entity_scope="risk_group", + conditions=[FailureCondition(attr="cost", operator=">=", value=200)], logic="and", rule_type="all", ) - rule_not_contains = FailureRule( - conditions=[ - FailureCondition(attr="tags", operator="not_contains", value="bar") - ], - logic="and", - rule_type="all", + policy = FailurePolicy( + rules=[rule], + fail_risk_group_children=True, ) - # Entities with a 'tags' attribute - nodes = { - "N1": {"type": "node", "tags": ["foo", "bar"]}, # contains 'foo' - "N2": {"type": "node", "tags": ["baz", "qux"]}, # doesn't contain 'foo' - "N3": {"type": "node", "tags": "foobar"}, # string containing 'foo' - "N4": {"type": "node", "tags": ""}, # string not containing anything + rgs = { + "TopRG": { + "name": "TopRG", + "cost": 250, + "children": [ + {"name": "SubRG1", "cost": 100, "children": []}, + {"name": "SubRG2", "cost": 300, "children": []}, + ], + }, + "OtherRG": { + "name": "OtherRG", + "cost": 50, + "children": [], + }, + "SubRG1": { + "name": "SubRG1", + "cost": 100, + "children": [], + }, + "SubRG2": { + "name": "SubRG2", + "cost": 300, + "children": [], + }, } + nodes = {} links = {} - # Test the 'contains' rule - failed_contains = FailurePolicy(rules=[rule_contains]).apply_failures(nodes, links) - # N1 has 'foo' in list, N3 has 'foo' in string "foobar" - assert set(failed_contains) == {"N1", "N3"} - - # Test the 'not_contains' rule - failed_not_contains = FailurePolicy(rules=[rule_not_contains]).apply_failures( - nodes, links - ) - # N2 => doesn't have 'bar', N4 => empty string, also doesn't have 'bar' - assert set(failed_not_contains) == {"N2", "N4"} + failed = policy.apply_failures(nodes, links, rgs) + # "TopRG" cost=250 => fails => also fails children SubRG1, SubRG2 + # "SubRG2" cost=300 => also matches rule => but anyway it's included + # "OtherRG" is unaffected + assert set(failed) == {"TopRG", "SubRG1", "SubRG2"} -def test_operator_any_value_no_value(): +def test_use_cache(): """ - Verify that 'any_value' matches entities that have the attribute (non-None), - and 'no_value' matches entities that do not have that attribute or None. + Demonstrate that if use_cache=True, repeated calls do not re-match + conditions. We'll just check that the second call returns the same + result and that we've only used matching logic once. """ - any_rule = FailureRule( - conditions=[ - FailureCondition(attr="capacity", operator="any_value", value=None) - ], - logic="and", - rule_type="all", - ) - none_rule = FailureRule( - conditions=[FailureCondition(attr="capacity", operator="no_value", value=None)], + rule = FailureRule( + entity_scope="node", + conditions=[FailureCondition(attr="capacity", operator=">", value=50)], logic="and", rule_type="all", ) + policy = FailurePolicy(rules=[rule], use_cache=True) nodes = { - "N1": {"type": "node", "capacity": 100}, # has capacity - "N2": {"type": "node"}, # no 'capacity' attr - "N3": {"type": "node", "capacity": None}, # capacity is explicitly None + "N1": {"capacity": 100}, + "N2": {"capacity": 40}, } links = {} - failed_any = FailurePolicy(rules=[any_rule]).apply_failures(nodes, links) - # N1 has capacity=100, N3 has capacity=None (still present, even if None) - assert set(failed_any) == {"N1", "N3"} + first_fail = policy.apply_failures(nodes, links) + assert set(first_fail) == {"N1"} + # Clear the node capacity for N1 => but we do NOT clear the cache + nodes["N1"]["capacity"] = 10 + + second_fail = policy.apply_failures(nodes, links) + # Because of caching, it returns the same "failed" set => ignoring the updated capacity + assert set(second_fail) == {"N1"}, "Cache used => no re-check of conditions" - failed_none = FailurePolicy(rules=[none_rule]).apply_failures(nodes, links) - # N2 has no 'capacity' attribute. N3 has capacity=None => attribute is present but None => also matches - # This depends on your interpretation of "no_value", but typically "no_value" means derived_value is None. - # We do see from the code that derived_value= entity.get(cond.attr, None) => if the key is missing or is None, we pass - assert set(failed_none) == {"N2", "N3"} + # If we want the new matching, we must clear the cache + policy._match_cache.clear() + third_fail = policy.apply_failures(nodes, links) + # Now N1 capacity=10 => does not match capacity>50 => no failures + assert third_fail == [] -def test_shared_risk_groups_expansion(): +def test_cache_disabled(): """ - Verify that if fail_shared_risk_groups=True is set, any failed entity - causes all entities in the same shared_risk_group to fail. + If use_cache=False, each call re-checks conditions => we see updated results. """ - # This rule matches link type=link, then chooses exactly 1 rule = FailureRule( - conditions=[FailureCondition(attr="type", operator="==", value="link")], + entity_scope="node", + conditions=[FailureCondition(attr="capacity", operator=">", value=50)], logic="and", - rule_type="choice", - count=1, - ) - policy = FailurePolicy( - rules=[rule], - attrs={"fail_shared_risk_groups": True}, + rule_type="all", ) + policy = FailurePolicy(rules=[rule], use_cache=False) nodes = { - "N1": {"type": "node"}, - "N2": {"type": "node"}, + "N1": {"capacity": 100}, + "N2": {"capacity": 40}, } - # Suppose L1 and L2 are in SRG1, L3 in SRG2 - links = { - "L1": {"type": "link", "shared_risk_group": "SRG1"}, - "L2": {"type": "link", "shared_risk_group": "SRG1"}, - "L3": {"type": "link", "shared_risk_group": "SRG2"}, - } - - # Mock picking "L1" - with patch("ngraph.failure_policy.sample", return_value=["L1"]): - failed = policy.apply_failures(nodes, links) + links = {} - # L1 was chosen, which triggers any others in SRG1 => L2 also fails. - # L3 is unaffected. - assert set(failed) == {"L1", "L2"} + first_fail = policy.apply_failures(nodes, links) + assert set(first_fail) == {"N1"} - # If we pick "L3", L1 & L2 remain healthy - with patch("ngraph.failure_policy.sample", return_value=["L3"]): - failed = policy.apply_failures(nodes, links) - assert set(failed) == {"L3"} + # Now reduce capacity => we re-check => no longer fails + nodes["N1"]["capacity"] = 10 + second_fail = policy.apply_failures(nodes, links) + assert set(second_fail) == set() diff --git a/tests/test_network.py b/tests/test_network.py index 1cd02f7..daf2e95 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -1,5 +1,11 @@ import pytest -from ngraph.network import Network, Node, Link, new_base64_uuid +from ngraph.network import ( + Network, + Node, + Link, + RiskGroup, + new_base64_uuid, +) from ngraph.lib.graph import StrictMultiDiGraph @@ -33,6 +39,8 @@ def test_node_creation_default_attrs(): node = Node("A") assert node.name == "A" assert node.attrs == {} + assert node.risk_groups == set() + assert node.disabled is False def test_node_creation_custom_attrs(): @@ -43,6 +51,8 @@ def test_node_creation_custom_attrs(): node = Node("B", attrs=custom_attrs) assert node.name == "B" assert node.attrs == custom_attrs + assert node.risk_groups == set() + assert node.disabled is False def test_link_defaults_and_id_generation(): @@ -55,6 +65,8 @@ def test_link_defaults_and_id_generation(): assert link.capacity == 1.0 assert link.cost == 1.0 assert link.attrs == {} + assert link.risk_groups == set() + assert link.disabled is False # ID should start with 'A|B|' and have a random suffix assert link.id.startswith("A|B|") @@ -74,6 +86,8 @@ def test_link_custom_values(): assert link.capacity == 2.0 assert link.cost == 4.0 assert link.attrs == custom_attrs + assert link.risk_groups == set() + assert link.disabled is False assert link.id.startswith("X|Y|") @@ -343,50 +357,27 @@ def test_max_flow_combine_empty(): Demonstrate that if the dictionary for sinks is not empty, but all matched sink nodes are disabled, the final combined_snk_nodes is empty => returns 0.0 (rather than raising ValueError). - - We add: - - Node("A") enabled => matches ^(A|Z)$ (source) - - Node("Z") disabled => also matches ^(A|Z)$ - So the final combined source label is "A|Z". - - - Node("C") disabled => matches ^(C|Y)$ - - Node("Y") disabled => matches ^(C|Y)$ - So the final combined sink label is "C|Y". - - Even though the source group is partially enabled (A), - the sink group ends up fully disabled (C, Y). - That yields 0.0 flow and the final label is ("A|Z", "C|Y"). """ net = Network() - net.add_node(Node("A")) # enabled - net.add_node( - Node("Z", attrs={"disabled": True}) - ) # disabled => but still recognized by regex - - net.add_node(Node("C", attrs={"disabled": True})) - net.add_node(Node("Y", attrs={"disabled": True})) + net.add_node(Node("A")) + net.add_node(Node("Z", disabled=True)) # disabled => but recognized by ^(A|Z)$ + net.add_node(Node("C", disabled=True)) + net.add_node(Node("Y", disabled=True)) flow_vals = net.max_flow("^(A|Z)$", "^(C|Y)$", mode="combine") - # Because "C" and "Y" are *all* disabled, the combined sink side is empty => 0.0 - # However, the label becomes "A|Z" for sources (both matched by pattern), - # and "C|Y" for sinks. That matches what the code returns. assert flow_vals == {("A|Z", "C|Y"): 0.0} def test_max_flow_pairwise_some_empty(): """ In 'pairwise' mode, we want distinct groups to appear in the result, - even if one group is fully disabled. Here: - - ^(A|B)$ => "A" => Node("A", enabled), "B" => Node("B", enabled) - - ^(C|Z)$ => "C" => Node("C", enabled), "Z" => Node("Z", disabled) - This yields pairs: (A,C), (A,Z), (B,C), (B,Z). - The 'Z' sub-group is fully disabled => flow=0.0 from either A or B to Z. + even if one group is fully disabled. """ net = Network() net.add_node(Node("A")) net.add_node(Node("B")) net.add_node(Node("C")) - net.add_node(Node("Z", attrs={"disabled": True})) # needed for the label "C|Z" + net.add_node(Node("Z", disabled=True)) # A->B->C net.add_link(Link("A", "B", capacity=5)) @@ -394,17 +385,16 @@ def test_max_flow_pairwise_some_empty(): flow_vals = net.max_flow("^(A|B)$", "^(C|Z)$", mode="pairwise") assert flow_vals == { - ("A", "C"): 3.0, # active path - ("A", "Z"): 0.0, # sink is disabled - ("B", "C"): 3.0, # active path - ("B", "Z"): 0.0, # sink is disabled + ("A", "C"): 3.0, + ("A", "Z"): 0.0, + ("B", "C"): 3.0, + ("B", "Z"): 0.0, } def test_max_flow_invalid_mode(): """ - Passing an invalid mode should raise ValueError. This covers the - else-branch in max_flow that was previously untested. + Passing an invalid mode should raise ValueError. """ net = Network() net.add_node(Node("A")) @@ -433,25 +423,31 @@ def test_compute_flow_single_group_empty_source_or_sink(): def test_disable_enable_node(): + """ + Tests disabling and enabling a single node. + """ net = Network() net.add_node(Node("A")) net.add_node(Node("B")) net.add_link(Link("A", "B")) # Initially, nothing is disabled - assert not net.nodes["A"].attrs["disabled"] - assert not net.nodes["B"].attrs["disabled"] + assert net.nodes["A"].disabled is False + assert net.nodes["B"].disabled is False net.disable_node("A") - assert net.nodes["A"].attrs["disabled"] - assert not net.nodes["B"].attrs["disabled"] + assert net.nodes["A"].disabled is True + assert net.nodes["B"].disabled is False # Re-enable net.enable_node("A") - assert not net.nodes["A"].attrs["disabled"] + assert net.nodes["A"].disabled is False def test_disable_node_does_not_exist(): + """ + Tests that disabling/enabling a non-existent node raises ValueError. + """ net = Network() with pytest.raises(ValueError, match="Node 'A' does not exist."): net.disable_node("A") @@ -461,22 +457,28 @@ def test_disable_node_does_not_exist(): def test_disable_enable_link(): + """ + Tests disabling and enabling a single link. + """ net = Network() net.add_node(Node("A")) net.add_node(Node("B")) link = Link("A", "B") net.add_link(link) - assert not net.links[link.id].attrs["disabled"] + assert net.links[link.id].disabled is False net.disable_link(link.id) - assert net.links[link.id].attrs["disabled"] + assert net.links[link.id].disabled is True net.enable_link(link.id) - assert not net.links[link.id].attrs["disabled"] + assert net.links[link.id].disabled is False def test_disable_link_does_not_exist(): + """ + Tests that disabling/enabling a non-existent link raises ValueError. + """ net = Network() with pytest.raises(ValueError, match="Link 'xyz' does not exist."): net.disable_link("xyz") @@ -485,6 +487,10 @@ def test_disable_link_does_not_exist(): def test_enable_all_disable_all(): + """ + Ensures that enable_all and disable_all correctly toggle + all nodes and links in the network. + """ net = Network() net.add_node(Node("A")) net.add_node(Node("B")) @@ -492,21 +498,21 @@ def test_enable_all_disable_all(): net.add_link(link) # Everything enabled by default - assert not net.nodes["A"].attrs["disabled"] - assert not net.nodes["B"].attrs["disabled"] - assert not net.links[link.id].attrs["disabled"] + assert net.nodes["A"].disabled is False + assert net.nodes["B"].disabled is False + assert net.links[link.id].disabled is False # Disable all net.disable_all() - assert net.nodes["A"].attrs["disabled"] - assert net.nodes["B"].attrs["disabled"] - assert net.links[link.id].attrs["disabled"] + assert net.nodes["A"].disabled is True + assert net.nodes["B"].disabled is True + assert net.links[link.id].disabled is True # Enable all net.enable_all() - assert not net.nodes["A"].attrs["disabled"] - assert not net.nodes["B"].attrs["disabled"] - assert not net.links[link.id].attrs["disabled"] + assert net.nodes["A"].disabled is False + assert net.nodes["B"].disabled is False + assert net.links[link.id].disabled is False def test_to_strict_multidigraph_excludes_disabled(): @@ -540,6 +546,9 @@ def test_to_strict_multidigraph_excludes_disabled(): def test_get_links_between(): + """ + Tests retrieving all links that connect a specific source to a target. + """ net = Network() net.add_node(Node("A")) net.add_node(Node("B")) @@ -568,6 +577,10 @@ def test_get_links_between(): def test_find_links(): + """ + Tests finding links by optional source_regex, target_regex, + and the any_direction parameter. + """ net = Network() net.add_node(Node("srcA")) net.add_node(Node("srcB")) @@ -595,3 +608,112 @@ def test_find_links(): b_links = net.find_links(source_regex="srcB", target_regex="^C$") assert len(b_links) == 1 assert b_links[0].id == link_b_c.id + + +# +# New tests to improve coverage for RiskGroup-related methods. +# +def test_disable_risk_group_nonexistent(): + """ + If we call disable_risk_group on a name that is not in net.risk_groups, + it should do nothing (not raise an error). + """ + net = Network() + # no risk groups at all + net.disable_risk_group("nonexistent_group") # Should not raise + + +def test_enable_risk_group_nonexistent(): + """ + If we call enable_risk_group on a name that is not in net.risk_groups, + it should do nothing (not raise an error). + """ + net = Network() + # no risk groups at all + net.enable_risk_group("nonexistent_group") # Should not raise + + +def test_disable_risk_group_recursive(): + """ + Tests disabling a top-level group with recursive=True + which should also disable child subgroups. + """ + net = Network() + + # Set up nodes/links + net.add_node(Node("A", risk_groups={"top"})) + net.add_node(Node("B", risk_groups={"child1"})) + net.add_node(Node("C", risk_groups={"child2"})) + link = Link("A", "C", risk_groups={"child2"}) + net.add_link(link) + + # Add risk groups: "top" with children => child1, child2 + net.risk_groups["top"] = RiskGroup( + "top", children=[RiskGroup("child1"), RiskGroup("child2")] + ) + + # By default, all are enabled + assert net.nodes["A"].disabled is False + assert net.nodes["B"].disabled is False + assert net.nodes["C"].disabled is False + assert net.links[link.id].disabled is False + + # Disable top group recursively + net.disable_risk_group("top", recursive=True) + + # A is in "top", B in "child1", C/link in "child2" => all disabled + assert net.nodes["A"].disabled is True + assert net.nodes["B"].disabled is True + assert net.nodes["C"].disabled is True + assert net.links[link.id].disabled is True + + +def test_disable_risk_group_non_recursive(): + """ + Tests disabling a top-level group with recursive=False + which should NOT disable child subgroups. + """ + net = Network() + net.add_node(Node("A", risk_groups={"top"})) + net.add_node(Node("B", risk_groups={"child1"})) + net.add_node(Node("C", risk_groups={"child2"})) + + net.risk_groups["top"] = RiskGroup( + "top", children=[RiskGroup("child1"), RiskGroup("child2")] + ) + + # Disable top group, but do NOT recurse + net.disable_risk_group("top", recursive=False) + + # A is in "top" => disabled + # B is in "child1" => still enabled + # C is in "child2" => still enabled + assert net.nodes["A"].disabled is True + assert net.nodes["B"].disabled is False + assert net.nodes["C"].disabled is False + + +def test_enable_risk_group_multi_membership(): + """ + A node belongs to multiple risk groups. Disabling one group + will disable that node, but enabling a different group that + also includes that node should re-enable it. + """ + net = Network() + + # Node X belongs to "group1" and "group2" + net.add_node(Node("X", risk_groups={"group1", "group2"})) + # Add risk groups + net.risk_groups["group1"] = RiskGroup("group1") + net.risk_groups["group2"] = RiskGroup("group2") + + # Initially enabled + assert net.nodes["X"].disabled is False + + # Disable group1 => X disabled + net.disable_risk_group("group1") + assert net.nodes["X"].disabled is True + + # Enable group2 => X re-enabled because it's in "group2" also + net.enable_risk_group("group2") + assert net.nodes["X"].disabled is False diff --git a/tests/test_scenario.py b/tests/test_scenario.py index bd60bd1..81f0935 100644 --- a/tests/test_scenario.py +++ b/tests/test_scenario.py @@ -18,9 +18,6 @@ from ngraph.scenario import Scenario -# ------------------------------------------------------------------- -# Dummy workflow steps for testing -# ------------------------------------------------------------------- @register_workflow_step("DoSmth") @dataclass class DoSmth(WorkflowStep): @@ -56,7 +53,7 @@ def valid_scenario_yaml() -> str: """ Returns a YAML string for constructing a Scenario with: - A small network of three nodes and two links - - A multi-rule failure policy + - A multi-rule failure policy referencing 'type' in conditions - Two traffic demands - Two workflow steps """ @@ -64,12 +61,18 @@ def valid_scenario_yaml() -> str: network: nodes: NodeA: - role: ingress - location: somewhere + attrs: + role: ingress + location: somewhere + type: node NodeB: - role: transit + attrs: + role: transit + type: node NodeC: - role: egress + attrs: + role: egress + type: node links: - source: NodeA target: NodeB @@ -77,29 +80,29 @@ def valid_scenario_yaml() -> str: capacity: 10 cost: 5 attrs: + type: link some_attr: some_value - source: NodeB target: NodeC link_params: capacity: 20 cost: 4 - attrs: {} + attrs: + type: link failure_policy: - name: "multi_rule_example" - description: "Testing multi-rule approach." + attrs: + name: "multi_rule_example" + description: "Testing multi-rule approach." + fail_shared_risk_groups: false + fail_risk_group_children: false + use_cache: false rules: - - conditions: - - attr: "type" - operator: "==" - value: "node" - logic: "and" + - entity_scope: node + logic: "any" rule_type: "choice" count: 1 - - conditions: - - attr: "type" - operator: "==" - value: "link" - logic: "and" + - entity_scope: link + logic: "any" rule_type: "all" traffic_demands: - source_path: NodeA @@ -202,11 +205,34 @@ def extra_param_yaml() -> str: """ +@pytest.fixture +def minimal_scenario_yaml() -> str: + """ + Returns a YAML string with only a single workflow step, no network, + no failure_policy, and no traffic_demands. Should be valid but minimal. + """ + return """ +workflow: + - step_type: DoSmth + name: JustStep + some_param: 100 +""" + + +@pytest.fixture +def empty_yaml() -> str: + """ + Returns an empty YAML string; from_yaml should still construct + a Scenario object but with none/empty fields if possible. + """ + return "" + + def test_scenario_from_yaml_valid(valid_scenario_yaml: str) -> None: """ - Tests that a Scenario can be correctly constructed from a valid YAML string. + Tests that a Scenario can be constructed from a valid YAML string. Ensures that: - - Network has correct nodes and links + - Network has correct nodes/links - FailurePolicy is set with multiple rules - TrafficDemands are parsed - Workflow steps are instantiated @@ -219,87 +245,70 @@ def test_scenario_from_yaml_valid(valid_scenario_yaml: str) -> None: assert len(scenario.network.nodes) == 3 # NodeA, NodeB, NodeC assert len(scenario.network.links) == 2 # NodeA->NodeB, NodeB->NodeC - node_names = [node.name for node in scenario.network.nodes.values()] + node_names = list(scenario.network.nodes.keys()) assert "NodeA" in node_names assert "NodeB" in node_names assert "NodeC" in node_names - links = list(scenario.network.links.values()) - assert len(links) == 2 - - link_ab = next((lk for lk in links if lk.source == "NodeA"), None) - link_bc = next((lk for lk in links if lk.source == "NodeB"), None) + link_names = list(scenario.network.links.keys()) + assert len(link_names) == 2 - assert link_ab is not None, "Link from NodeA to NodeB was not found." + # Link from NodeA -> NodeB + link_ab = next( + (lk for lk in scenario.network.links.values() if lk.source == "NodeA"), None + ) + link_bc = next( + (lk for lk in scenario.network.links.values() if lk.source == "NodeB"), None + ) + assert link_ab is not None, "Could not find link NodeA->NodeB" assert link_ab.target == "NodeB" assert link_ab.capacity == 10 assert link_ab.cost == 5 assert link_ab.attrs.get("some_attr") == "some_value" - assert link_bc is not None, "Link from NodeB to NodeC was not found." + assert link_bc is not None, "Could not find link NodeB->NodeC" assert link_bc.target == "NodeC" assert link_bc.capacity == 20 assert link_bc.cost == 4 # Check failure policy assert isinstance(scenario.failure_policy, FailurePolicy) - assert len(scenario.failure_policy.rules) == 2, "Expected 2 rules in the policy." - # leftover fields (e.g., name, description) in policy.attrs + assert not scenario.failure_policy.fail_shared_risk_groups + assert not scenario.failure_policy.fail_risk_group_children + assert not scenario.failure_policy.use_cache + + assert len(scenario.failure_policy.rules) == 2 assert scenario.failure_policy.attrs.get("name") == "multi_rule_example" assert ( scenario.failure_policy.attrs.get("description") == "Testing multi-rule approach." ) - # Rule1 => "choice", count=1, conditions => type == "node" + # Rule1 => entity_scope=node, rule_type=choice, count=1 rule1 = scenario.failure_policy.rules[0] + assert rule1.entity_scope == "node" assert rule1.rule_type == "choice" assert rule1.count == 1 - assert len(rule1.conditions) == 1 - cond1 = rule1.conditions[0] - assert cond1.attr == "type" - assert cond1.operator == "==" - assert cond1.value == "node" - # Rule2 => "all", conditions => type == "link" + # Rule2 => entity_scope=link, rule_type=all rule2 = scenario.failure_policy.rules[1] + assert rule2.entity_scope == "link" assert rule2.rule_type == "all" - assert len(rule2.conditions) == 1 - cond2 = rule2.conditions[0] - assert cond2.attr == "type" - assert cond2.operator == "==" - assert cond2.value == "link" # Check traffic demands assert len(scenario.traffic_demands) == 2 - demand_ab = next( - ( - d - for d in scenario.traffic_demands - if d.source_path == "NodeA" and d.sink_path == "NodeB" - ), - None, - ) - demand_ac = next( - ( - d - for d in scenario.traffic_demands - if d.source_path == "NodeA" and d.sink_path == "NodeC" - ), - None, - ) - assert demand_ab is not None, "Demand from NodeA to NodeB not found." - assert demand_ab.demand == 15 - - assert demand_ac is not None, "Demand from NodeA to NodeC not found." - assert demand_ac.demand == 5 + d1 = scenario.traffic_demands[0] + d2 = scenario.traffic_demands[1] + assert d1.source_path == "NodeA" + assert d1.sink_path == "NodeB" + assert d1.demand == 15 + assert d2.source_path == "NodeA" + assert d2.sink_path == "NodeC" + assert d2.demand == 5 # Check workflow assert len(scenario.workflow) == 2 - step1 = scenario.workflow[0] - step2 = scenario.workflow[1] - - # Verify the step types come from the registry + step1, step2 = scenario.workflow assert step1.__class__ == WORKFLOW_STEP_REGISTRY["DoSmth"] assert step1.name == "Step1" assert step1.some_param == 42 @@ -308,21 +317,19 @@ def test_scenario_from_yaml_valid(valid_scenario_yaml: str) -> None: assert step2.name == "Step2" assert step2.factor == 2.0 - # Check the scenario results store + # Check results assert isinstance(scenario.results, Results) def test_scenario_run(valid_scenario_yaml: str) -> None: """ - Tests that calling scenario.run() executes each workflow step in order - without errors. Steps may store data in scenario.results. + Tests scenario.run() => each workflow step is executed in order, + storing data in scenario.results. """ scenario = Scenario.from_yaml(valid_scenario_yaml) scenario.run() - # The first step's name is "Step1" in the YAML: assert scenario.results.get("Step1", "ran", default=False) is True - # The second step's name is "Step2" in the YAML: assert scenario.results.get("Step2", "ran", default=False) is True @@ -332,7 +339,7 @@ def test_scenario_from_yaml_missing_step_type(missing_step_type_yaml: str) -> No is missing the 'step_type' field. """ with pytest.raises(ValueError) as excinfo: - _ = Scenario.from_yaml(missing_step_type_yaml) + Scenario.from_yaml(missing_step_type_yaml) assert "must have a 'step_type' field" in str(excinfo.value) @@ -344,18 +351,89 @@ def test_scenario_from_yaml_unrecognized_step_type( is not found in the WORKFLOW_STEP_REGISTRY. """ with pytest.raises(ValueError) as excinfo: - _ = Scenario.from_yaml(unrecognized_step_type_yaml) + Scenario.from_yaml(unrecognized_step_type_yaml) assert "Unrecognized 'step_type'" in str(excinfo.value) def test_scenario_from_yaml_unsupported_param(extra_param_yaml: str) -> None: """ - Tests that Scenario.from_yaml raises a TypeError if a workflow step - in the YAML has an unsupported parameter. + Tests that Scenario.from_yaml raises TypeError if a workflow step + has an unsupported parameter in the YAML. """ with pytest.raises(TypeError) as excinfo: - _ = Scenario.from_yaml(extra_param_yaml) - - # Typically the error message is something like: - # "DoSmth.__init__() got an unexpected keyword argument 'extra_param'" + Scenario.from_yaml(extra_param_yaml) assert "extra_param" in str(excinfo.value) + + +def test_scenario_minimal(minimal_scenario_yaml: str) -> None: + """ + A minimal scenario with only workflow steps => no network, no demands, no policy. + Should still produce a valid Scenario object. + """ + scenario = Scenario.from_yaml(minimal_scenario_yaml) + assert scenario.network is not None + assert len(scenario.network.nodes) == 0 + assert len(scenario.network.links) == 0 + + # If no failure_policy block, scenario.failure_policy => None + assert scenario.failure_policy is None + + assert scenario.traffic_demands == [] + assert len(scenario.workflow) == 1 + step = scenario.workflow[0] + assert step.name == "JustStep" + assert step.some_param == 100 + + +def test_scenario_empty_yaml(empty_yaml: str) -> None: + """ + Constructing from an empty YAML => produce empty scenario + with no network, no policy, no demands, no steps. + """ + scenario = Scenario.from_yaml(empty_yaml) + assert scenario.network is not None + assert len(scenario.network.nodes) == 0 + assert len(scenario.network.links) == 0 + assert scenario.failure_policy is None + assert scenario.traffic_demands == [] + assert scenario.workflow == [] + + +def test_scenario_risk_groups() -> None: + """ + Tests that risk groups are parsed, and if 'disabled' is True, + the group is disabled on load. + """ + scenario_yaml = """ +network: + nodes: + NodeA: {} + NodeB: {} + links: [] +risk_groups: + - name: "RG1" + disabled: false + - name: "RG2" + disabled: true +""" + scenario = Scenario.from_yaml(scenario_yaml) + assert "RG1" in scenario.network.risk_groups + assert "RG2" in scenario.network.risk_groups + rg1 = scenario.network.risk_groups["RG1"] + rg2 = scenario.network.risk_groups["RG2"] + assert rg1.disabled is False + assert rg2.disabled is True + + +def test_scenario_risk_group_missing_name() -> None: + """ + If a risk group is missing 'name', raise ValueError. + """ + scenario_yaml = """ +network: {} +risk_groups: + - name_missing: "RG1" +""" + with pytest.raises(ValueError) as excinfo: + Scenario.from_yaml(scenario_yaml) + assert "RiskGroup entry missing 'name' field" in str(excinfo.value) diff --git a/tests/workflow/test_build_graph.py b/tests/workflow/test_build_graph.py index 50652f6..ce2458e 100644 --- a/tests/workflow/test_build_graph.py +++ b/tests/workflow/test_build_graph.py @@ -3,65 +3,37 @@ from ngraph.lib.graph import StrictMultiDiGraph from ngraph.workflow.build_graph import BuildGraph -from ngraph.network import Network - - -class MockNode: - """ - A simple mock Node to simulate scenario.network.nodes[node_name]. - """ - - def __init__(self, attrs=None): - self.attrs = attrs or {} - - -class MockLink: - """ - A simple mock Link to simulate scenario.network.links[link_id]. - """ - - def __init__(self, link_id, source, target, capacity, cost, attrs=None): - self.id = link_id - self.source = source - self.target = target - self.capacity = capacity - self.cost = cost - self.attrs = attrs or {} +from ngraph.network import Network, Node, Link @pytest.fixture def mock_scenario(): """ - Provides a mock Scenario object for testing. + Provides a mock Scenario object for testing, including: + - A Network object with two nodes (A, B). + - Two links (L1, L2), each of which is auto-created via Link + but we override their IDs to maintain the naming expected by the tests. + - A MagicMock-based results object for verifying output. """ scenario = MagicMock() scenario.network = Network() - # Sample data: - scenario.network.nodes = { - "A": MockNode(attrs={"type": "router", "location": "rack1"}), - "B": MockNode(attrs={"type": "router", "location": "rack2"}), - } - scenario.network.links = { - "L1": MockLink( - link_id="L1", - source="A", - target="B", - capacity=100, - cost=5, - attrs={"fiber": True}, - ), - "L2": MockLink( - link_id="L2", - source="B", - target="A", - capacity=50, - cost=2, - attrs={"copper": True}, - ), - } - - # Mock results object with a MagicMocked put method + # Create real Node objects and add them to the network + node_a = Node(name="A", attrs={"type": "router", "location": "rack1"}) + node_b = Node(name="B", attrs={"type": "router", "location": "rack2"}) + scenario.network.add_node(node_a) + scenario.network.add_node(node_b) + + # Create real Link objects, then override their ID to match the original test expectations. + link1 = Link(source="A", target="B", capacity=100, cost=5, attrs={"fiber": True}) + link1.id = "L1" # Force the ID so the test can look up "L1" + scenario.network.links[link1.id] = link1 # Insert directly + + link2 = Link(source="B", target="A", capacity=50, cost=2, attrs={"copper": True}) + link2.id = "L2" + scenario.network.links[link2.id] = link2 + + # Mock results object scenario.results = MagicMock() scenario.results.put = MagicMock() return scenario @@ -106,17 +78,19 @@ def test_build_graph_stores_multidigraph_in_results(mock_scenario): ), "Should have two edges (forward/reverse) for each link." # Check forward edge from link 'L1' - edge_data = created_graph.get_edge_data("A", "B", key="L1") - assert edge_data is not None, "Forward edge 'L1' should exist from A to B." - assert edge_data["capacity"] == 100 - assert edge_data["cost"] == 5 - assert "fiber" in edge_data + edge_data_l1 = created_graph.get_edge_data("A", "B", key="L1") + assert edge_data_l1 is not None, "Forward edge 'L1' should exist from A to B." + assert edge_data_l1["capacity"] == 100 + assert edge_data_l1["cost"] == 5 + assert "fiber" in edge_data_l1 # Check reverse edge from link 'L1' - rev_edge_data = created_graph.get_edge_data("B", "A", key="L1_rev") - assert rev_edge_data is not None, "Reverse edge 'L1_rev' should exist from B to A." + rev_edge_data_l1 = created_graph.get_edge_data("B", "A", key="L1_rev") + assert ( + rev_edge_data_l1 is not None + ), "Reverse edge 'L1_rev' should exist from B to A." assert ( - rev_edge_data["capacity"] == 100 + rev_edge_data_l1["capacity"] == 100 ), "Reverse edge should share the same capacity." # Check forward edge from link 'L2'