import ctypes import os import numpy as np import pymetis from .database import * from .s0_base import get_nodes from .s32_region_util import get_nodes_in_region from .s32_region_util import Topology PARTITION_TYPE_RB = 0 PARTITION_TYPE_KWAY = 1 ''' adjacency_list = [np.array([4, 2, 1]), np.array([0, 2, 3]), np.array([4, 3, 1, 0]), np.array([1, 2, 5, 6]), np.array([0, 2, 5]), np.array([4, 3, 6]), np.array([5, 3])] n_cuts, membership = pymetis.part_graph(2, adjacency=adjacency_list) # n_cuts = 3 # membership = [1, 1, 1, 0, 1, 0, 0] nodes_part_0 = np.argwhere(np.array(membership) == 0).ravel() # [3, 5, 6] nodes_part_1 = np.argwhere(np.array(membership) == 1).ravel() # [0, 1, 2, 4] print(nodes_part_0) print(nodes_part_1) ''' def calculate_district_metering_area_for_nodes(name: str, nodes: list[str], part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]: topology = Topology(name, nodes) t_nodes = topology.nodes() t_links = topology.links() t_node_list = topology.node_list() adjacency_list = [] for node in t_node_list: links: list[str] = t_nodes[node]['links'] a_nodes: list[int] = [] for link in links: if t_links[link]['node1'] == node: i = t_node_list.index(t_links[link]['node2']) a_nodes.append(i) elif t_links[link]['node2'] == node: i = t_node_list.index(t_links[link]['node1']) a_nodes.append(i) adjacency_list.append(np.array(a_nodes)) recursive = part_type == PARTITION_TYPE_RB n_cuts, membership = pymetis.part_graph(nparts=part_count, adjacency=adjacency_list, recursive=recursive, contiguous=True) result: list[list[str]] = [] for i in range(0, part_count): indices: list[int] = list(np.argwhere(np.array(membership) == i).ravel()) index_strs: list[str] = [] for index in indices: index_strs.append(t_node_list[index]) result.append(index_strs) return result def _calculate_district_metering_area_for_nodes(name: str, nodes: list[str], part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]: if part_type != PARTITION_TYPE_RB and part_type != PARTITION_TYPE_KWAY: return [] if part_count <= 0: return [] elif part_count == 1: return [nodes] lib = ctypes.CDLL(os.path.join(os.getcwd(), 'api', 'CMetis.dll')) METIS_NOPTIONS = 40 c_options = (ctypes.c_int64 * METIS_NOPTIONS)() METIS_OK = 1 result = lib.set_default_options(c_options) if result != METIS_OK: return [] METIS_OPTION_PTYPE , METIS_OPTION_CONTIG = 0, 13 c_options[METIS_OPTION_PTYPE] = part_type c_options[METIS_OPTION_CONTIG] = 1 topology = Topology(name, nodes) t_nodes = topology.nodes() t_links = topology.links() t_node_list = topology.node_list() t_link_list = topology.link_list() nedges = len(t_link_list) * 2 c_nvtxs = ctypes.c_int64(len(t_node_list)) c_ncon = ctypes.c_int64(1) c_xadj = (ctypes.c_int64 * (c_nvtxs.value + 1))() c_adjncy = (ctypes.c_int64 * nedges)() c_vwgt = (ctypes.c_int64 * (c_ncon.value * c_nvtxs.value))() c_adjwgt = (ctypes.c_int64 * nedges)() c_vsize = (ctypes.c_int64 * c_nvtxs.value)() c_xadj[0] = 0 l, n = 0, 0 c_xadj_i = 1 for node in t_node_list: links = t_nodes[node]['links'] for link in links: node1 = t_links[link]['node1'] node2 = t_links[link]['node2'] c_adjncy[l] = t_node_list.index(node2) if node2 != node else t_node_list.index(node1) c_adjwgt[l] = 1 l += 1 if len(links) > 0: c_xadj[c_xadj_i] = l # adjncy.size() c_xadj_i += 1 c_vwgt[n] = 1 c_vsize[n] = 1 n += 1 part_func = lib.part_graph_recursive if part_type == PARTITION_TYPE_RB else lib.part_graph_kway c_nparts = ctypes.c_int64(part_count) c_tpwgts = ctypes.POINTER(ctypes.c_double)() c_ubvec = ctypes.POINTER(ctypes.c_double)() c_out_edgecut = ctypes.c_int64(0) c_out_part = (ctypes.c_int64 * c_nvtxs.value)() result = part_func(ctypes.byref(c_nvtxs), ctypes.byref(c_ncon), c_xadj, c_adjncy, c_vwgt, c_vsize, c_adjwgt, ctypes.byref(c_nparts), c_tpwgts, c_ubvec, c_options, ctypes.byref(c_out_edgecut), c_out_part) if result != METIS_OK: return [] dmas : list[list[str]]= [] for i in range(part_count): dmas.append([]) for i in range(c_nvtxs.value): dmas[c_out_part[i]].append(t_node_list[i]) return dmas def calculate_district_metering_area_for_region(name: str, region: str, part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]: nodes = get_nodes_in_region(name, region) return calculate_district_metering_area_for_nodes(name, nodes, part_count, part_type) def calculate_district_metering_area_for_network(name: str, part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]: nodes = get_nodes(name) return calculate_district_metering_area_for_nodes(name, nodes, part_count, part_type)