def test_repeated_topology_buildup(settings): """Test to catch a strange bug when trying to cycle through a number of countries when building up did destroy the code. Disabled for full PSSE model for time reasons""" # noinspection PyUnusedLocal logger = logging.getLogger('') if settings.settings_name != SettingsEnum.PSSETest: return True for country in settings.countries: logging.debug(f'test for country {country}:') try: file_contents = open_file(settings) except FileNotFoundError: print(f'\n{settings.input_file_name} not found, skipping test for that file.') return branches, gens, nodes = read_grid(file_contents, settings) nodes = create_nodes_and_update_branches_with_node_info(branches) set_node_country(nodes, settings) validate_topology(nodes, branches) merge_tie_lines(branches, nodes) validate_topology(nodes, branches)
def create_and_preprocess_topology(branches, generators, nodes, country, settings): t0 = time.clock() if settings.do_merge_couplers: apply_couplers_on_branches_and_generators(branches, generators, nodes) else: convert_couplers_to_lines(branches) merge_tie_lines(branches, nodes) remove_branches_with_loop_elements(branches, nodes) validate_topology(nodes, branches) n_branch_with_neg_imp = len([branch for branch in branches if branch.impedance < 0]) logging.info(f"{n_branch_with_neg_imp} branches have negative impedance.") assign_nodes_to_ring_0(nodes, branches, country) assign_nodes_to_other_rings(nodes) nodes, branches = remove_non_connected_nodes_and_branches(nodes) connect_generators_to_nodes(nodes, generators) validate_topology(nodes, branches, generators) logging.info(f"Topology determined in {round(time.clock() - t0, 3)} seconds.") return branches, nodes
def test_merge_tie_lines(branches_generators_nodes): if branches_generators_nodes.branches is None: print('Branches None, most likely because file not found') return branches = branches_generators_nodes.branches nodes = branches_generators_nodes.nodes validate_topology(nodes, branches) n_x_nodes = len([node for node in nodes if node.is_x_node()]) # to account for x_nodes with more than 2 branches: n_redundant_branches = sum( [max(len(node.branches) - 2, 0) for node in nodes if node.is_x_node()]) if n_x_nodes > 0: x_node = [node for node in nodes if node.is_x_node()][0] branch_names = (x_node.branches[0].name_branch, x_node.branches[1].name_branch) branch_node_0 = [ n for n in [x_node.branches[0].node_from, x_node.branches[0].node_to] if n != x_node ] branch_node_1 = [ n for n in [x_node.branches[1].node_from, x_node.branches[1].node_to] if n != x_node ] branch_imps = (x_node.branches[0].impedance, x_node.branches[1].impedance) branch_PATLs = (x_node.branches[0].PATL, x_node.branches[1].PATL) n_nodes = len(nodes) n_branches = len(branches) merge_tie_lines(branches, nodes) assert len([node for node in nodes if node.is_x_node()]) == 0 assert len(nodes) == n_nodes - n_x_nodes # for each x-node, two branches replaced by 1, and correct for redundant branches: assert len(branches) == n_branches - n_x_nodes - n_redundant_branches if n_x_nodes > 0: print( f"Pre merge: {x_node.name} with branches {branch_names}, impedances {branch_imps}, " f"and PATLs {branch_PATLs} - between nodes {branch_node_0[0].name} and " f"{branch_node_1[0].name}.") # noinspection PyUnboundLocalVariable new_branch = [ b for b in branches if (branch_node_0[0] in (b.node_from, b.node_to)) and ( branch_node_1[0] in (b.node_from, b.node_to)) ][0] print( f"Post merge: branch {new_branch.name_branch} with impedance " f"{new_branch.impedance:.5} and PATL {new_branch.PATL:.5} between " f"{new_branch.name_from} and {new_branch.name_to}.")
def test_remove_branches_with_loop_elements(branches_generators_nodes): if branches_generators_nodes.branches is None: print('Branches None, most likely because file not found') return branches = branches_generators_nodes.branches nodes = branches_generators_nodes.nodes nbranches_org = len(branches) remove_branches_with_loop_elements(branches, nodes) for branch in branches: assert branch.name_from != branch.name_to validate_topology(nodes, branches) print( f'Removed {nbranches_org - len(branches)} branches, {len(branches)} branches left.' )
def test_assign_nodes_to_ring_0( branches_generators_nodes_preprocessed_merged, branches_generators_nodes_preprocessed_nonmerged): for switch in range(2): if switch == 0: branches_generators_nodes = branches_generators_nodes_preprocessed_merged else: branches_generators_nodes = branches_generators_nodes_preprocessed_nonmerged if branches_generators_nodes.branches is None: print('Branches None, most likely because file not found') return branches = branches_generators_nodes.branches nodes = branches_generators_nodes.nodes countries = branches_generators_nodes.settings.countries validate_topology(nodes, branches) for country in countries: if country == 'XX': continue n_nodes_in_country = len( [n for n in nodes if n.country == country]) n_branches_in_country = len( [b for b in branches if b.country == country]) print( f'Connecting for country {country} with {n_nodes_in_country} nodes and ' f'{n_branches_in_country} branches:') assign_nodes_to_ring_0(nodes, branches, country) n_nodes_in_ring_0 = len([node for node in nodes if node.ring == 0]) print(f"Ring 0 initialised with {n_nodes_in_ring_0} nodes.") cntry_nodes_non_conn = [ n for n in nodes if n.country == country and n.ring != 0 ] for n in cntry_nodes_non_conn: print(f"Warning : {n.name} is not connected to {country}") conn_nodes_non_cntry = [ n for n in nodes if n.ring == 0 and n.country != country ] for n in conn_nodes_non_cntry: print( f"Warning : {n.name} is connected to {country} but belongs to {n.country}" ) assert len(conn_nodes_non_cntry) == 0 reset_connectivity(branches, nodes) # only for testing
def branches_generators_nodes(name_file_settings): BGN = collections.namedtuple('BranchesGeneratorsNodes', 'name branches generators nodes settings') name = name_file_settings.name file_contents = name_file_settings.file settings = name_file_settings.settings if file_contents is None: return BGN(name, None, None, None, settings) branches, generators, nodes = read_grid(file_contents, settings) validate_topology(nodes, branches) return BGN(name, branches, generators, nodes, settings)
def branches_generators_nodes_preprocessed_nonmerged(name_file_settings): BGN = collections.namedtuple('BranchesGeneratorsNodes', 'name branches generators nodes settings') name = f'{name_file_settings.name}_nonmergedcouplers' file_contents = name_file_settings.file settings = name_file_settings.settings if file_contents is None: return BGN(name, None, None, None, settings) branches, generators, nodes = read_grid(file_contents, settings) convert_couplers_to_lines(branches) merge_tie_lines(branches, nodes) remove_branches_with_loop_elements(branches, nodes) validate_topology(nodes, branches) return BGN(name, branches, generators, nodes, settings)
def test_apply_couplers_on_branches(branches_generators_nodes): if branches_generators_nodes.branches is None: print('Branches None, most likely because file not found') return branches_generators_nodes.settings.do_merge_couplers = True branches = branches_generators_nodes.branches generators = branches_generators_nodes.generators nodes = branches_generators_nodes.nodes validate_topology(nodes, branches) couplers = [b for b in branches if b.type == BranchTypeEnum.Coupler] n_nodes = len(nodes) n_couplers = len(couplers) n_branches = len(branches) dict_couplers = create_coupler_mapping(couplers) apply_couplers_on_branches_and_generators(branches, generators, nodes) validate_topology(nodes, branches) n_nodes_after = len(nodes) n_branches_after = len(branches) set_replaced_branches = set(dict_couplers.keys()) - set( dict_couplers.values()) for branch in branches: assert branch.name_from not in set_replaced_branches assert branch.name_to not in set_replaced_branches print( f'{n_couplers} couplers applied on a total of {n_nodes} nodes and {n_branches} branches' ) print( f'After application, left with {n_nodes_after} nodes and {n_branches_after} branches' ) print_examples(branches_generators_nodes.name, couplers, 'Bus bar coupler') print_stats([tr.impedance for tr in couplers], "Impedance") print_stats([tr.PATL for tr in couplers], "PATL")