新增爆管位置检测模块及相关API接口
This commit is contained in:
@@ -0,0 +1,375 @@
|
||||
"""管网分区模块。"""
|
||||
|
||||
import math
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
import networkx as networkx
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pymetis
|
||||
from scipy.sparse import coo_matrix, csr_matrix
|
||||
from scipy.sparse.csgraph import connected_components
|
||||
|
||||
|
||||
def pick_center_pipe(node_x, node_y, candidate_pipe, pipe_start_node, pipe_end_node):
|
||||
data_set_t = pd.DataFrame(dtype=object)
|
||||
data_set_t["x"] = (
|
||||
node_x[pipe_start_node[candidate_pipe]].values
|
||||
+ node_x[pipe_start_node[candidate_pipe]].values
|
||||
) / 2
|
||||
data_set_t["y"] = (
|
||||
node_y[pipe_end_node[candidate_pipe]].values
|
||||
+ node_y[pipe_end_node[candidate_pipe]].values
|
||||
) / 2
|
||||
data_set_t.index = list(candidate_pipe)
|
||||
mean_x = data_set_t["x"].mean()
|
||||
mean_y = data_set_t["y"].mean()
|
||||
data_set_t["d"] = abs(data_set_t["x"] - mean_x) + abs(data_set_t["y"] - mean_y)
|
||||
distance_t = data_set_t["d"].sort_values(ascending=True, inplace=False)
|
||||
"""if distance_t.index==[]:
|
||||
print(candidate_pipe)
|
||||
else:"""
|
||||
center_t = distance_t.index[0]
|
||||
return center_t
|
||||
|
||||
|
||||
def find_new_center_pipe(
|
||||
node_x, node_y, candidate_pipe, pipe_start_node, pipe_end_node, record_center
|
||||
):
|
||||
new_candidate_pipe = list(set(candidate_pipe) - set(record_center))
|
||||
if new_candidate_pipe == []:
|
||||
new_candidate_pipe = candidate_pipe
|
||||
center_t = pick_center_pipe(
|
||||
node_x, node_y, new_candidate_pipe, pipe_start_node, pipe_end_node
|
||||
)
|
||||
return center_t
|
||||
|
||||
|
||||
def cal_area_node_linked_pipe(nodeset, node_pipe_dic):
|
||||
pipeset = []
|
||||
nodeset = list(nodeset)
|
||||
for i in range(len(nodeset)):
|
||||
temp_node = nodeset[i]
|
||||
pipe = node_pipe_dic[temp_node]
|
||||
pipeset = pipeset + pipe
|
||||
return pipeset
|
||||
|
||||
|
||||
def metis_grouping_pipe_weight(
|
||||
G0,
|
||||
wn,
|
||||
all_node_iter,
|
||||
candidate_pipe_input,
|
||||
group_num,
|
||||
node_x,
|
||||
node_y,
|
||||
pipe_start_node_all,
|
||||
pipe_end_node_all,
|
||||
node_pipe_dic,
|
||||
all_node_series,
|
||||
couple_node_length,
|
||||
):
|
||||
all_node_iter_series_new = all_node_series[all_node_iter]
|
||||
all_node_iter_series_new = all_node_iter_series_new.sort_values(ascending=True)
|
||||
all_node_iter_new = list(all_node_iter_series_new.index)
|
||||
|
||||
G1 = G0.subgraph(all_node_iter_new)
|
||||
delimiter = " "
|
||||
adjacency_list = []
|
||||
node_dict = {}
|
||||
c_new = 0
|
||||
for each_node in all_node_iter_new:
|
||||
node_dict[each_node] = c_new
|
||||
c_new = c_new + 1
|
||||
correspond_dic = {}
|
||||
count_node = 0
|
||||
w = []
|
||||
for line in generate_adjlist_with_all_edges(G1, delimiter):
|
||||
temp_node_name = line.split(sep=delimiter)
|
||||
w_temp = []
|
||||
for i in range(len(temp_node_name) - 1):
|
||||
temp_name_1 = temp_node_name[0] + "," + temp_node_name[i + 1]
|
||||
w_temp.append(couple_node_length[temp_name_1])
|
||||
w.append(w_temp)
|
||||
n_t = []
|
||||
for each_node in temp_node_name:
|
||||
n_t.append(node_dict[each_node])
|
||||
correspond_dic[n_t[0]] = count_node
|
||||
count_node = count_node + 1
|
||||
# del n_t[0]
|
||||
adjacency_list.append(n_t)
|
||||
adjacency_list_new = [[] * 1 for i in range(len(adjacency_list))]
|
||||
w_new = [[] * 1 for i in range(len(adjacency_list))]
|
||||
for i in range(len(adjacency_list)):
|
||||
adjacency_list_new[int(adjacency_list[i][0])] = adjacency_list[i]
|
||||
w_new[int(adjacency_list[i][0])] = w[i]
|
||||
|
||||
for i in range(len(adjacency_list)):
|
||||
del adjacency_list_new[i][0]
|
||||
xadj = [0]
|
||||
w_f = []
|
||||
final_adjacency_list = []
|
||||
for i in range(len(adjacency_list_new)):
|
||||
final_adjacency_list = final_adjacency_list + adjacency_list_new[i]
|
||||
xadj.append(len(final_adjacency_list))
|
||||
w_f = w_f + w_new[i]
|
||||
|
||||
# (edgecuts, parts) = pymetis.part_graph(nparts=group_num, adjacency=adjacency_list_new)
|
||||
(edgecuts, parts) = pymetis.part_graph(
|
||||
nparts=group_num, adjncy=final_adjacency_list, xadj=xadj, eweights=w_f
|
||||
)
|
||||
# (edgecuts, parts) = pymetis.part_graph(nparts=group_num, adjacency=adjacency_list_new)
|
||||
candidate_group_list = [[] * 1 for i in range(group_num)]
|
||||
for i in range(len(all_node_iter_new)):
|
||||
candidate_group_list[parts[i]].append(all_node_iter_new[i])
|
||||
|
||||
"""parts_new = np.zeros(len(candidate_node_input), dtype=int)
|
||||
for i in range(len(candidate_group_list)):
|
||||
temp_group = candidate_group_list[i]
|
||||
for each_node in temp_group:
|
||||
parts_new[node_dict[each_node]] = i
|
||||
parts_new = list(parts_new)"""
|
||||
|
||||
new_center = []
|
||||
new_group = []
|
||||
new_all_node = []
|
||||
candidate_pipe_set = set(candidate_pipe_input)
|
||||
all_grouped_pipe = []
|
||||
for i in range(group_num):
|
||||
# 构建子图
|
||||
G_sub = G0.subgraph(candidate_group_list[i])
|
||||
|
||||
# 计算联通子图
|
||||
sub_graphs = networkx.connected_components(G_sub)
|
||||
if networkx.number_connected_components(G_sub) == 1:
|
||||
# 求交集
|
||||
nodeset = G_sub.nodes()
|
||||
pipeset_set = set(cal_area_node_linked_pipe(nodeset, node_pipe_dic))
|
||||
candidate_pipe = list(pipeset_set.intersection(candidate_pipe_set))
|
||||
|
||||
# 判断集合是否保留
|
||||
if len(candidate_pipe) > 0:
|
||||
# 保留 计算中心
|
||||
center_t = pick_center_pipe(
|
||||
node_x,
|
||||
node_y,
|
||||
candidate_pipe,
|
||||
pipe_start_node_all,
|
||||
pipe_end_node_all,
|
||||
)
|
||||
|
||||
# 更新
|
||||
new_center.append(center_t)
|
||||
new_group.append(candidate_pipe)
|
||||
new_all_node.append(nodeset)
|
||||
all_grouped_pipe = all_grouped_pipe + candidate_pipe
|
||||
else:
|
||||
for c in sub_graphs:
|
||||
G_temp = G0.subgraph(c)
|
||||
nodeset = G_temp.nodes()
|
||||
pipeset = cal_area_node_linked_pipe(nodeset, node_pipe_dic)
|
||||
pipeset_set = set(pipeset)
|
||||
|
||||
# 求交集
|
||||
candidate_pipe = list(pipeset_set.intersection(candidate_pipe_set))
|
||||
# print(len(candidate_node))
|
||||
# 判断集合是否保留
|
||||
if len(candidate_pipe) > 0:
|
||||
# 保留 计算中心
|
||||
center_t = pick_center_pipe(
|
||||
node_x,
|
||||
node_y,
|
||||
candidate_pipe,
|
||||
pipe_start_node_all,
|
||||
pipe_end_node_all,
|
||||
)
|
||||
# 更新
|
||||
new_center.append(center_t)
|
||||
new_group.append(candidate_pipe)
|
||||
new_all_node.append(nodeset)
|
||||
all_grouped_pipe = all_grouped_pipe + candidate_pipe
|
||||
record_center = []
|
||||
c_g = 0
|
||||
for each_group in new_group:
|
||||
if len(each_group) < 3:
|
||||
record_center.append(new_center[c_g])
|
||||
c_g += 1
|
||||
c_g = 0
|
||||
for each_group in new_group:
|
||||
if len(each_group) >= 3:
|
||||
if new_center[c_g] in record_center:
|
||||
new_center[c_g] = find_new_center_pipe(
|
||||
node_x,
|
||||
node_y,
|
||||
each_group,
|
||||
pipe_start_node_all,
|
||||
pipe_end_node_all,
|
||||
record_center,
|
||||
)
|
||||
record_center.append(new_center[c_g])
|
||||
c_g += 1
|
||||
|
||||
# visualize_metis_partition(
|
||||
# G0, new_center, new_group,
|
||||
# node_x, node_y,
|
||||
# pipe_start_node_all, pipe_end_node_all
|
||||
# )
|
||||
return new_center, new_group, new_all_node
|
||||
|
||||
|
||||
def visualize_metis_partition(
|
||||
G, center_pipes, pipe_groups, node_x, node_y, pipe_start_node_all, pipe_end_node_all
|
||||
):
|
||||
"""
|
||||
可视化METIS分区结果(单图模式)
|
||||
参数:
|
||||
G: 原始管网图(nx.Graph)
|
||||
center_pipes: 中心管道列表(list)
|
||||
pipe_groups: 分组管道列表(list of lists)
|
||||
node_x: 节点X坐标字典(dict)
|
||||
node_y: 节点Y坐标字典(dict)
|
||||
pipe_start_node_all: 管道起点字典(dict)
|
||||
pipe_end_node_all: 管道终点字典(dict)
|
||||
"""
|
||||
plt.figure(figsize=(9, 10))
|
||||
|
||||
# 生成颜色映射(自动扩展颜色数量)
|
||||
colors = plt.cm.tab20(np.linspace(0, 1, len(pipe_groups)))
|
||||
|
||||
# --- 绘制背景管网(灰色半透明) ---
|
||||
for edge in G.edges():
|
||||
start_node, end_node = edge
|
||||
plt.plot(
|
||||
[node_x[start_node], node_x[end_node]],
|
||||
[node_y[start_node], node_y[end_node]],
|
||||
color="lightgray",
|
||||
linewidth=0.5,
|
||||
alpha=0.3,
|
||||
zorder=1, # 确保背景在底层
|
||||
)
|
||||
|
||||
# --- 绘制各分区管道(彩色)---
|
||||
legend_handles = [] # 用于图例的句柄
|
||||
for i, (group, center) in enumerate(zip(pipe_groups, center_pipes)):
|
||||
color = colors[i % len(colors)] # 循环使用颜色
|
||||
|
||||
# 绘制分组管道
|
||||
for pipe in group:
|
||||
start = pipe_start_node_all[pipe]
|
||||
end = pipe_end_node_all[pipe]
|
||||
line = plt.plot(
|
||||
[node_x[start], node_x[end]],
|
||||
[node_y[start], node_y[end]],
|
||||
color=color,
|
||||
linewidth=2.5,
|
||||
alpha=0.8,
|
||||
zorder=2,
|
||||
)
|
||||
# 只为每个分组的第一个管道添加图例句柄
|
||||
if pipe == group[0]:
|
||||
legend_handles.append(line[0])
|
||||
|
||||
# 高亮中心管道(红色虚线)
|
||||
if center in pipe_start_node_all and center in pipe_end_node_all:
|
||||
start = pipe_start_node_all[center]
|
||||
end = pipe_end_node_all[center]
|
||||
plt.plot(
|
||||
[node_x[start], node_x[end]],
|
||||
[node_y[start], node_y[end]],
|
||||
color="red",
|
||||
linewidth=4,
|
||||
linestyle="--",
|
||||
dash_capstyle="round",
|
||||
zorder=3, # 确保中心管道在最顶层
|
||||
)
|
||||
|
||||
# --- 添加图例和标注 ---
|
||||
# 分组图例
|
||||
group_labels = [f"Group {i + 1}" for i in range(len(pipe_groups))]
|
||||
plt.legend(
|
||||
legend_handles,
|
||||
group_labels,
|
||||
loc="upper right",
|
||||
title="Partitions",
|
||||
fontsize=8,
|
||||
title_fontsize=10,
|
||||
)
|
||||
|
||||
# 中心管道标注(可选)
|
||||
for i, center in enumerate(center_pipes):
|
||||
if center in pipe_start_node_all:
|
||||
x = (
|
||||
node_x[pipe_start_node_all[center]] + node_x[pipe_end_node_all[center]]
|
||||
) / 2
|
||||
y = (
|
||||
node_y[pipe_start_node_all[center]] + node_y[pipe_end_node_all[center]]
|
||||
) / 2
|
||||
plt.text(
|
||||
x,
|
||||
y,
|
||||
f"C{i + 1}",
|
||||
color="red",
|
||||
fontsize=10,
|
||||
ha="center",
|
||||
va="center",
|
||||
bbox=dict(facecolor="white", alpha=0.8, edgecolor="none"),
|
||||
)
|
||||
|
||||
# --- 图形美化 ---
|
||||
plt.title("Water Network Partitioning Overview", fontsize=14, pad=20)
|
||||
plt.xlabel("X Coordinate", fontsize=10)
|
||||
plt.ylabel("Y Coordinate", fontsize=10)
|
||||
plt.grid(True, alpha=0.2, linestyle=":")
|
||||
plt.tight_layout()
|
||||
|
||||
# 显示图形
|
||||
plt.show()
|
||||
|
||||
|
||||
def generate_adjlist_with_all_edges(G, delimiter):
|
||||
for s, nbrs in G.adjacency():
|
||||
line = str(s) + delimiter
|
||||
for t, data in nbrs.items():
|
||||
line += str(t) + delimiter
|
||||
yield line[: -len(delimiter)]
|
||||
|
||||
|
||||
def cal_group_num(candidate_node_input, cal_group_num):
|
||||
candidate_node_num = len(candidate_node_input)
|
||||
if candidate_node_num > 100:
|
||||
group_num_input = cal_group_num # 30
|
||||
else:
|
||||
group_num_input = 10
|
||||
|
||||
return group_num_input
|
||||
|
||||
|
||||
class NetworkPartitioner:
|
||||
@staticmethod
|
||||
def metis_grouping_pipe_weight(*args, **kwargs):
|
||||
return metis_grouping_pipe_weight(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def visualize_metis_partition(*args, **kwargs):
|
||||
return visualize_metis_partition(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def generate_adjlist_with_all_edges(*args, **kwargs):
|
||||
return generate_adjlist_with_all_edges(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def pick_center_pipe(*args, **kwargs):
|
||||
return pick_center_pipe(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def find_new_center_pipe(*args, **kwargs):
|
||||
return find_new_center_pipe(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def cal_area_node_linked_pipe(*args, **kwargs):
|
||||
return cal_area_node_linked_pipe(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def cal_group_num(*args, **kwargs):
|
||||
return cal_group_num(*args, **kwargs)
|
||||
Reference in New Issue
Block a user