Reorganize algorithm packages by business responsibility, move orchestration into services, and keep database access behind pooled repositories. Harden analysis API validation, remove unsafe legacy simulation endpoints, and add regression and architecture boundary coverage. BREAKING CHANGE: legacy algorithm module paths and obsolete simulation endpoints are removed.
772 lines
28 KiB
Python
772 lines
28 KiB
Python
"""爆管定位主模块。"""
|
||
|
||
import copy
|
||
import math
|
||
import os
|
||
import sys
|
||
from datetime import datetime
|
||
from time import perf_counter
|
||
|
||
import networkx as nx
|
||
import numpy as np
|
||
import pandas as pd
|
||
|
||
from .leak_signature import cal_signature_pipe_multi_pf
|
||
from .topology_partitioning import (
|
||
cal_group_num,
|
||
metis_grouping_pipe_weight,
|
||
visualize_metis_partition,
|
||
)
|
||
from .similarity_metrics import (
|
||
adjust_ratio,
|
||
cal_similarity_all_multi_new_sq_improve_double_lzr,
|
||
decode_mode,
|
||
extra_judge,
|
||
update_similarity,
|
||
)
|
||
|
||
|
||
def _ensure_signatures_for_centers(
|
||
wn,
|
||
wn_inp_path,
|
||
center_list, # 本轮要用到的中心(list[str])
|
||
pressure_leak_all,
|
||
flow_leak_all, # 全量缓存(可为空 DF)
|
||
timestep_list, # 你现有的时序列表
|
||
pressure_monitor,
|
||
flow_monitor, # 用来推断传感器列名
|
||
leak_mag,
|
||
n_workers=1,
|
||
):
|
||
"""
|
||
只为缺失的中心补算 SLF(调用你现有的 cal_signature_pipe_multi_pf),
|
||
并把补算结果并回缓存。返回:
|
||
pressure_leak_subset, flow_leak_subset, pressure_leak_all_new, flow_leak_all_new
|
||
其中 subset 只包含 center_list 的行(顺序与 center_list 保持一致)。
|
||
"""
|
||
|
||
center_list = _dedupe_preserve_order(center_list)
|
||
|
||
# 1) 推断传感器列名(与现有数据保持一致)
|
||
sensor_name_all = list(pressure_monitor.columns)
|
||
sensor_f_name_all = (
|
||
list(flow_monitor.columns)
|
||
if (flow_monitor is not None and hasattr(flow_monitor, "columns"))
|
||
else []
|
||
)
|
||
|
||
# 2) 取出缓存里已经有的中心(考虑 MultiIndex 的第 0 层为 pipe)
|
||
def _existing_pipes(df):
|
||
if df is None or len(df) == 0:
|
||
return set()
|
||
idx = df.index
|
||
if isinstance(idx, pd.MultiIndex):
|
||
return set(idx.get_level_values(0))
|
||
else:
|
||
return set(idx)
|
||
|
||
exist_p = _existing_pipes(pressure_leak_all)
|
||
need = [p for p in center_list if p not in exist_p]
|
||
|
||
# 3) 若有缺失中心,仅为这些中心补算一次
|
||
if len(need) > 0:
|
||
p_new, _ = cal_signature_pipe_multi_pf(
|
||
wn,
|
||
leak_mag,
|
||
need,
|
||
timestep_list,
|
||
sensor_name_all,
|
||
n_workers=n_workers,
|
||
wn_inp_path=wn_inp_path,
|
||
)
|
||
# 初始化空缓存时,做一次“同构化”
|
||
if pressure_leak_all is None or len(pressure_leak_all) == 0:
|
||
pressure_leak_all = p_new
|
||
else:
|
||
pressure_leak_all = pd.concat([pressure_leak_all, p_new], axis=0)
|
||
# if (flow_leak_all is None or len(flow_leak_all) == 0) and f_new is not None:
|
||
# flow_leak_all = f_new
|
||
# elif f_new is not None:
|
||
# flow_leak_all = pd.concat([flow_leak_all, f_new], axis=0)
|
||
|
||
# 去重(如果既有缓存里不小心有重复中心)
|
||
if isinstance(pressure_leak_all.index, pd.MultiIndex):
|
||
pressure_leak_all = pressure_leak_all[
|
||
~pressure_leak_all.index.duplicated(keep="last")
|
||
]
|
||
if flow_leak_all is not None and len(flow_leak_all) > 0:
|
||
flow_leak_all = flow_leak_all[
|
||
~flow_leak_all.index.duplicated(keep="last")
|
||
]
|
||
else:
|
||
pressure_leak_all = pressure_leak_all[
|
||
~pressure_leak_all.index.duplicated(keep="last")
|
||
]
|
||
if flow_leak_all is not None and len(flow_leak_all) > 0:
|
||
flow_leak_all = flow_leak_all[
|
||
~flow_leak_all.index.duplicated(keep="last")
|
||
]
|
||
|
||
# 4) 从更新后的缓存里,取出这轮需要的中心子集(顺序与 center_list 一致)
|
||
if isinstance(pressure_leak_all.index, pd.MultiIndex):
|
||
pressure_subset = pressure_leak_all.loc[center_list]
|
||
flow_subset = (
|
||
flow_leak_all.loc[center_list]
|
||
if (flow_leak_all is not None and len(flow_leak_all) > 0)
|
||
else None
|
||
)
|
||
else:
|
||
pressure_subset = pressure_leak_all.loc[center_list, :]
|
||
flow_subset = (
|
||
flow_leak_all.loc[center_list, :]
|
||
if (flow_leak_all is not None and len(flow_leak_all) > 0)
|
||
else None
|
||
)
|
||
|
||
return pressure_subset, flow_subset, pressure_leak_all, flow_leak_all
|
||
|
||
|
||
def area_output_num_ki_improve(
|
||
candidate_center,
|
||
candidate_group,
|
||
similarity,
|
||
new_all_node,
|
||
top_group_ratio,
|
||
top_pipe_num_max,
|
||
top_pipe_num_min,
|
||
cut_ratio,
|
||
):
|
||
final_area = []
|
||
final_center = []
|
||
all_node_iter = []
|
||
if similarity.index.is_unique == False:
|
||
total_center_num = len(set(similarity.index))
|
||
else:
|
||
total_center_num = len(similarity.index)
|
||
|
||
next_group_num = min(
|
||
total_center_num, math.ceil(total_center_num / cut_ratio * top_group_ratio)
|
||
)
|
||
|
||
for i in range(next_group_num):
|
||
top_center = similarity.index[i]
|
||
top_center_index = find_list_repeat(candidate_center, top_center)
|
||
for j in range(len(top_center_index)):
|
||
final_area = final_area + candidate_group[top_center_index[j]]
|
||
all_node_iter = all_node_iter + list(new_all_node[top_center_index[j]])
|
||
final_center.append(top_center)
|
||
final_area = sorted(set(final_area))
|
||
|
||
if len(final_area) > top_pipe_num_max:
|
||
if_end = 0
|
||
elif len(final_area) > top_pipe_num_min:
|
||
if_end = 1
|
||
elif total_center_num == next_group_num:
|
||
if_end = 1
|
||
else:
|
||
if_end = 1
|
||
for i in np.arange(next_group_num, total_center_num, 1):
|
||
|
||
before_list = copy.deepcopy(final_area)
|
||
top_center = similarity.index[i]
|
||
top_center_index = candidate_center.index(top_center)
|
||
temp_group = final_area + candidate_group[top_center_index]
|
||
temp_area = sorted(set(temp_group))
|
||
|
||
if len(temp_area) < top_pipe_num_min:
|
||
|
||
final_center.append(top_center)
|
||
all_node_iter = all_node_iter + list(new_all_node[top_center_index])
|
||
final_area = temp_area
|
||
|
||
elif len(temp_area) < top_pipe_num_max:
|
||
final_center.append(top_center)
|
||
all_node_iter = all_node_iter + list(new_all_node[top_center_index])
|
||
final_area = temp_area
|
||
break
|
||
else:
|
||
a = len(temp_area) - top_pipe_num_max
|
||
b = top_pipe_num_min - len(before_list)
|
||
|
||
if a >= b:
|
||
final_area = before_list
|
||
else:
|
||
final_center.append(top_center)
|
||
all_node_iter = all_node_iter + list(new_all_node[top_center_index])
|
||
final_area = temp_area
|
||
break
|
||
|
||
final_center = sorted(set(final_center))
|
||
all_node_iter = sorted(set(all_node_iter))
|
||
return final_area, final_center, all_node_iter, if_end
|
||
|
||
|
||
def find_list_repeat(candidate_center, target):
|
||
repeated_list = []
|
||
for index, nums in enumerate(candidate_center):
|
||
if nums == target:
|
||
repeated_list.append(index)
|
||
return repeated_list
|
||
|
||
|
||
def _dedupe_preserve_order(items):
|
||
seen = set()
|
||
output = []
|
||
for item in items:
|
||
if item in seen:
|
||
continue
|
||
seen.add(item)
|
||
output.append(item)
|
||
return output
|
||
|
||
|
||
def _accumulate_stage(stage_timing, stage_name, started_at):
|
||
stage_timing[stage_name] = stage_timing.get(stage_name, 0.0) + (
|
||
perf_counter() - started_at
|
||
)
|
||
|
||
|
||
def _write_last_round_candidates_csv(
|
||
csv_path,
|
||
exit_condition,
|
||
iteration_count,
|
||
similarity_mode,
|
||
candidate_details,
|
||
fallback_similarity,
|
||
):
|
||
if not csv_path:
|
||
return None
|
||
timestamp_suffix = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
base_path, ext = os.path.splitext(csv_path)
|
||
ext = ext or ".csv"
|
||
output_path = f"{base_path}_{timestamp_suffix}{ext}"
|
||
if candidate_details is not None and len(candidate_details) > 0:
|
||
export_df = candidate_details.copy()
|
||
if export_df.index.name == "pipe_id":
|
||
export_df = export_df.reset_index()
|
||
else:
|
||
export_df = pd.DataFrame(
|
||
{
|
||
"pipe_id": [str(pipe_id) for pipe_id in fallback_similarity.index],
|
||
"final_similarity": [float(value) for value in fallback_similarity.values],
|
||
}
|
||
)
|
||
export_df["exit_condition"] = exit_condition
|
||
export_df["iterations"] = int(iteration_count)
|
||
export_df["similarity_mode"] = similarity_mode
|
||
parent_dir = os.path.dirname(output_path)
|
||
if parent_dir:
|
||
os.makedirs(parent_dir, exist_ok=True)
|
||
export_df.to_csv(output_path, index=False, encoding="utf-8-sig")
|
||
return output_path
|
||
|
||
|
||
def cal_DtoTop1(
|
||
G0, pipe_leak, located_pipe, pipe_start_node_all, pipe_end_node_all, pipe_length
|
||
):
|
||
if pipe_leak == located_pipe:
|
||
result_DtoTop1 = 0
|
||
result_DtoTop1_num = 0
|
||
else:
|
||
pipe_leak_start_node = pipe_start_node_all[pipe_leak]
|
||
pipe_leak_end_node = pipe_end_node_all[pipe_leak]
|
||
located_pipe_start_node = pipe_start_node_all[located_pipe]
|
||
located_pipe_end_node = pipe_end_node_all[located_pipe]
|
||
DtoTop1_series = pd.Series(dtype=object)
|
||
DtoTop1_num_series = pd.Series(dtype=object)
|
||
DtoTop1_series["ss"] = nx.shortest_path_length(
|
||
G0, pipe_leak_start_node, located_pipe_start_node, weight="weight"
|
||
)
|
||
DtoTop1_series["se"] = nx.shortest_path_length(
|
||
G0, pipe_leak_start_node, located_pipe_end_node, weight="weight"
|
||
)
|
||
DtoTop1_series["es"] = nx.shortest_path_length(
|
||
G0, pipe_leak_end_node, located_pipe_start_node, weight="weight"
|
||
)
|
||
DtoTop1_series["ee"] = nx.shortest_path_length(
|
||
G0, pipe_leak_end_node, located_pipe_end_node, weight="weight"
|
||
)
|
||
DtoTop1_num_series["ss"] = nx.shortest_path_length(
|
||
G0, pipe_leak_start_node, located_pipe_start_node
|
||
)
|
||
DtoTop1_num_series["se"] = nx.shortest_path_length(
|
||
G0, pipe_leak_start_node, located_pipe_end_node
|
||
)
|
||
DtoTop1_num_series["es"] = nx.shortest_path_length(
|
||
G0, pipe_leak_end_node, located_pipe_start_node
|
||
)
|
||
DtoTop1_num_series["ee"] = nx.shortest_path_length(
|
||
G0, pipe_leak_end_node, located_pipe_end_node
|
||
)
|
||
|
||
if DtoTop1_num_series.min() == 0:
|
||
result_DtoTop1_num = 1
|
||
result_DtoTop1 = DtoTop1_series.max() / 2
|
||
else:
|
||
result_DtoTop1_num = DtoTop1_num_series.min() + 1
|
||
DtoTop1_type = DtoTop1_series.argmin()
|
||
result_DtoTop1 = (
|
||
DtoTop1_series[DtoTop1_type]
|
||
+ (pipe_length[pipe_leak] + pipe_length[located_pipe]) / 2
|
||
)
|
||
return result_DtoTop1, result_DtoTop1_num
|
||
|
||
|
||
def cal_RR(located_pipe, similarity_sp):
|
||
if located_pipe in similarity_sp.index:
|
||
rank = similarity_sp.index.get_loc(located_pipe)
|
||
RR = rank / len(similarity_sp.index)
|
||
else:
|
||
RR = 1.1
|
||
return RR
|
||
|
||
|
||
def cal_cover(similarity, leak_pipe):
|
||
if leak_pipe in list(similarity.index):
|
||
cover = 1
|
||
else:
|
||
cover = 0
|
||
return cover
|
||
|
||
|
||
def cal_SD(located_pipe, real_pipe, pipe_x, pipe_y):
|
||
dx = pipe_x[located_pipe] - pipe_x[real_pipe]
|
||
dy = pipe_y[located_pipe] - pipe_y[real_pipe]
|
||
SD = math.sqrt(dx * dx + dy * dy)
|
||
return SD
|
||
|
||
|
||
def DN_search_multi_simple_add_flow_count_new(
|
||
wn,
|
||
wn_inp_path,
|
||
G0,
|
||
all_node,
|
||
node_x,
|
||
node_y,
|
||
pipe_start_node_all,
|
||
pipe_end_node_all,
|
||
pipe_diameter,
|
||
couple_node_length,
|
||
node_pipe_dic,
|
||
all_node_series,
|
||
top_group_ratio,
|
||
top_pipe_num_max,
|
||
top_pipe_num_min,
|
||
candidate_pipe_input_initial,
|
||
similarity_mode,
|
||
pressure_monitor,
|
||
pressure_predict,
|
||
pressure_normal,
|
||
pressure_leak_all,
|
||
flow_monitor,
|
||
flow_predict,
|
||
flow_normal,
|
||
flow_leak_all,
|
||
timestep_list,
|
||
max_flow,
|
||
group_basic_num,
|
||
Top_sensor_num,
|
||
if_gy,
|
||
pressure_threshold,
|
||
leak_mag,
|
||
n_workers=1,
|
||
stage_timing=None,
|
||
partition_on_full_graph=True,
|
||
visualize_partition=False,
|
||
visualize_pause_seconds=0.3,
|
||
final_candidates_csv_path=None,
|
||
):
|
||
if stage_timing is None:
|
||
stage_timing = {}
|
||
exit_condition = "unknown"
|
||
final_candidates_csv = None
|
||
iter_count = 0
|
||
all_node_iter = copy.deepcopy(all_node)
|
||
candidate_pipe_input = copy.deepcopy(candidate_pipe_input_initial) # 可能漏损管段
|
||
t1 = datetime.now()
|
||
if_flow, if_only_cos, if_only_flow = decode_mode(similarity_mode) # 定位方法
|
||
# threshold
|
||
if if_only_flow == 1:
|
||
dpressure = (flow_predict - flow_monitor).mean()
|
||
dpressure = dpressure.abs()
|
||
effective_sensor = list(dpressure.index)
|
||
|
||
else:
|
||
dpressure = (pressure_predict - pressure_monitor).mean()
|
||
dpressure = dpressure.abs()
|
||
dpressure = dpressure[dpressure > pressure_threshold]
|
||
effective_sensor = list(dpressure.index)
|
||
simulation_times = 0 # 模拟次数
|
||
if len(dpressure) > 0:
|
||
break_flag = 0
|
||
last_round_candidate_details = None
|
||
|
||
cos_h = 0
|
||
dis_h = 0
|
||
dis_f_h = 0
|
||
if_compalsive = 0
|
||
record_center_dataset = []
|
||
record_center_set = set()
|
||
# iter
|
||
while 1:
|
||
final_area = []
|
||
final_center = []
|
||
group_num = cal_group_num(candidate_pipe_input, group_basic_num)
|
||
partition_nodes = all_node if partition_on_full_graph else all_node_iter
|
||
|
||
# group 分组,得出候选漏损中心
|
||
stage_start = perf_counter()
|
||
(
|
||
candidate_center_list,
|
||
candidate_group_list,
|
||
new_all_node,
|
||
candidate_center_candidates,
|
||
) = (
|
||
metis_grouping_pipe_weight(
|
||
G0,
|
||
wn,
|
||
partition_nodes,
|
||
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,
|
||
pipe_diameter,
|
||
)
|
||
)
|
||
_accumulate_stage(stage_timing, "group_partitioning", stage_start)
|
||
if visualize_partition:
|
||
visualize_metis_partition(
|
||
G0,
|
||
candidate_center_list,
|
||
candidate_group_list,
|
||
node_x,
|
||
node_y,
|
||
pipe_start_node_all,
|
||
pipe_end_node_all,
|
||
title=(
|
||
f"METIS Partition Iteration {iter_count + 1} | "
|
||
f"candidate pipes={len(candidate_pipe_input)} "
|
||
f"groups={len(candidate_group_list)}"
|
||
),
|
||
block=False,
|
||
pause_seconds=visualize_pause_seconds,
|
||
)
|
||
simulation_times = simulation_times + len(candidate_center_list)
|
||
# pick_pressure_leak
|
||
# pressure_leak = pressure_leak_all.loc[candidate_center_list].loc[:, :]
|
||
# flow_leak = flow_leak_all.loc[candidate_center_list].loc[:, :]
|
||
# —— 新增泄漏量(保持你现在的一致,或从外部传入)——
|
||
# —— 只为缺失中心补算,然后取本轮需要的中心子集 ——
|
||
stage_start = perf_counter()
|
||
pressure_leak, flow_leak, pressure_leak_all, flow_leak_all = (
|
||
_ensure_signatures_for_centers(
|
||
wn=wn,
|
||
wn_inp_path=wn_inp_path,
|
||
center_list=candidate_center_list,
|
||
pressure_leak_all=pressure_leak_all,
|
||
flow_leak_all=flow_leak_all,
|
||
timestep_list=timestep_list,
|
||
pressure_monitor=pressure_monitor,
|
||
flow_monitor=flow_monitor,
|
||
leak_mag=leak_mag,
|
||
n_workers=n_workers,
|
||
)
|
||
)
|
||
_accumulate_stage(stage_timing, "signature_for_candidates", stage_start)
|
||
|
||
# pressure_leak_f= pressure_leak.swaplevel()
|
||
|
||
# --------------------------------------------------------
|
||
|
||
add_center = []
|
||
leak_center_dict = dict()
|
||
for i in range(len(candidate_center_list)):
|
||
primary_center = candidate_center_list[i]
|
||
houxuan_center = [
|
||
center
|
||
for center in candidate_center_candidates[i]
|
||
if center != primary_center
|
||
]
|
||
candidate_group_set = set(candidate_group_list[i])
|
||
for each_center in record_center_dataset:
|
||
if (
|
||
each_center in candidate_group_set
|
||
and each_center != primary_center
|
||
):
|
||
houxuan_center.append(each_center)
|
||
add_center = add_center + houxuan_center
|
||
leak_center_dict[primary_center] = _dedupe_preserve_order(
|
||
houxuan_center + [primary_center]
|
||
)
|
||
add_center = _dedupe_preserve_order(add_center)
|
||
for each_group_centers in candidate_center_candidates:
|
||
for each_center in each_group_centers:
|
||
if each_center not in record_center_set:
|
||
record_center_dataset.append(each_center)
|
||
record_center_set.add(each_center)
|
||
for each_center in add_center:
|
||
if each_center not in record_center_set:
|
||
record_center_dataset.append(each_center)
|
||
record_center_set.add(each_center)
|
||
|
||
# --------------------------------------------------------
|
||
# --------------------------------------------------------
|
||
# if len(add_center) > 0:
|
||
# s3 = pressure_leak_all.loc[add_center]
|
||
# pressure_leak = pd.concat([pressure_leak, s3])
|
||
# s4 = flow_leak_all.loc[add_center]
|
||
# flow_leak = pd.concat([flow_leak, s4])
|
||
# --------------------------------------------------------
|
||
# 只为 add_center 里还没算过的中心补算,并与本轮中心合并
|
||
if len(add_center) > 0:
|
||
stage_start = perf_counter()
|
||
pressure_add, flow_add, pressure_leak_all, flow_leak_all = (
|
||
_ensure_signatures_for_centers(
|
||
wn=wn,
|
||
wn_inp_path=wn_inp_path,
|
||
center_list=add_center,
|
||
pressure_leak_all=pressure_leak_all,
|
||
flow_leak_all=flow_leak_all,
|
||
timestep_list=timestep_list,
|
||
pressure_monitor=pressure_monitor,
|
||
flow_monitor=flow_monitor,
|
||
leak_mag=leak_mag, # 与上面一致
|
||
n_workers=n_workers,
|
||
)
|
||
)
|
||
_accumulate_stage(
|
||
stage_timing, "signature_for_extra_centers", stage_start
|
||
)
|
||
pressure_leak = pd.concat([pressure_leak, pressure_add], axis=0)
|
||
if (flow_leak is not None) and (flow_add is not None):
|
||
flow_leak = pd.concat([flow_leak, flow_add], axis=0)
|
||
# --------------------------------------------------------
|
||
#
|
||
if len(candidate_pipe_input) < 1.2 * top_pipe_num_max / top_group_ratio:
|
||
if_compalsive = 1
|
||
cos_h, dis_h, dis_f_h = adjust_ratio(similarity_mode, cos_h, dis_h, dis_f_h)
|
||
candidate_center_list_sup = _dedupe_preserve_order(
|
||
candidate_center_list + add_center
|
||
)
|
||
stage_start = perf_counter()
|
||
similarity, cos_h, dis_h, dis_f_h, break_flag, similarity_details = (
|
||
cal_similarity_all_multi_new_sq_improve_double_lzr(
|
||
candidate_center_list_sup,
|
||
similarity_mode,
|
||
pressure_leak,
|
||
pressure_monitor,
|
||
pressure_predict,
|
||
pressure_normal,
|
||
if_flow,
|
||
if_only_cos,
|
||
if_only_flow,
|
||
flow_leak,
|
||
flow_monitor,
|
||
flow_predict,
|
||
flow_normal,
|
||
timestep_list,
|
||
Top_sensor_num,
|
||
if_gy,
|
||
effective_sensor,
|
||
cos_h,
|
||
dis_h,
|
||
dis_f_h,
|
||
if_compalsive,
|
||
max_flow,
|
||
)
|
||
)
|
||
last_round_candidate_details = similarity_details
|
||
_accumulate_stage(stage_timing, "similarity_ranking", stage_start)
|
||
if break_flag == 1:
|
||
exit_condition = "similarity_break_flag"
|
||
break
|
||
|
||
new_similarity = update_similarity(
|
||
candidate_center_list, similarity, leak_center_dict
|
||
)
|
||
if len(candidate_pipe_input) > top_pipe_num_max / top_group_ratio:
|
||
cut_ratio, new_similarity = extra_judge(new_similarity)
|
||
else:
|
||
cut_ratio = 1
|
||
stage_start = perf_counter()
|
||
final_area_t, final_center_t, all_node_new_1, if_end = (
|
||
area_output_num_ki_improve(
|
||
candidate_center_list,
|
||
candidate_group_list,
|
||
new_similarity,
|
||
new_all_node,
|
||
top_group_ratio,
|
||
top_pipe_num_max,
|
||
top_pipe_num_min,
|
||
cut_ratio,
|
||
)
|
||
)
|
||
_accumulate_stage(stage_timing, "candidate_area_selection", stage_start)
|
||
final_area = final_area + final_area_t
|
||
final_center = final_center + final_center_t
|
||
|
||
final_area = sorted(set(final_area))
|
||
final_center = sorted(set(final_center))
|
||
if if_end == 1:
|
||
exit_condition = "candidate_area_if_end"
|
||
break
|
||
elif len(candidate_pipe_input) == len(final_area):
|
||
exit_condition = "candidate_size_no_change"
|
||
break
|
||
else:
|
||
candidate_pipe_input = final_area
|
||
if not partition_on_full_graph:
|
||
all_node_iter = all_node_new_1
|
||
iter_count += 1
|
||
sys.stdout.write(
|
||
"\r"
|
||
+ "已经完成"
|
||
+ str(iter_count)
|
||
+ "次迭代计算"
|
||
+ "候选节点"
|
||
+ str(len(final_area))
|
||
+ "个"
|
||
)
|
||
# if break_flag == 0:
|
||
# final_area_pipe = copy.deepcopy(final_area)
|
||
# simulation_times = simulation_times + len(final_area)
|
||
# pressure_leak_sp = pressure_leak_all.loc[final_area_pipe].loc[:, :]
|
||
# flow_leak_sp = flow_leak_all.loc[final_area_pipe].loc[:, :]
|
||
# similarity_sp, cos_h, dis_h, dis_f_h, break_flag = cal_similarity_all_multi_new_sq_improve_double_lzr(
|
||
# final_area_pipe, similarity_mode, pressure_leak_sp,
|
||
# pressure_monitor, pressure_predict, pressure_normal, if_flow,
|
||
# if_only_cos, if_only_flow,
|
||
# flow_leak_sp, flow_monitor, flow_predict, flow_normal,
|
||
# timestep_list, Top_sensor_num, if_gy, effective_sensor, cos_h, dis_h, dis_f_h, if_compalsive, max_flow)
|
||
if break_flag == 0:
|
||
final_area_pipe = list(final_area) # 确保是 list
|
||
|
||
# 只为还没算过的管段补齐 SLF(按需计算)
|
||
stage_start = perf_counter()
|
||
pressure_leak_sp, flow_leak_sp, pressure_leak_all, flow_leak_all = (
|
||
_ensure_signatures_for_centers(
|
||
wn=wn,
|
||
wn_inp_path=wn_inp_path,
|
||
center_list=final_area_pipe, # 这次要用的“最终区域里的所有管段”
|
||
pressure_leak_all=pressure_leak_all, # 累积缓存(会被更新)
|
||
flow_leak_all=flow_leak_all,
|
||
timestep_list=timestep_list,
|
||
pressure_monitor=pressure_monitor,
|
||
flow_monitor=flow_monitor,
|
||
leak_mag=leak_mag,
|
||
n_workers=n_workers,
|
||
)
|
||
)
|
||
_accumulate_stage(stage_timing, "signature_for_final_area", stage_start)
|
||
|
||
# 如果你要精确统计模拟次数,这里可以加上“本次新补的数量”,
|
||
# 做法:让 _ensure_signatures_for_centers 额外返回 need_cnt,再 simulation_times += need_cnt
|
||
|
||
stage_start = perf_counter()
|
||
(
|
||
similarity_sp,
|
||
cos_h,
|
||
dis_h,
|
||
dis_f_h,
|
||
break_flag,
|
||
similarity_details,
|
||
) = (
|
||
cal_similarity_all_multi_new_sq_improve_double_lzr(
|
||
final_area_pipe,
|
||
similarity_mode,
|
||
pressure_leak_sp,
|
||
pressure_monitor,
|
||
pressure_predict,
|
||
pressure_normal,
|
||
if_flow,
|
||
if_only_cos,
|
||
if_only_flow,
|
||
flow_leak_sp,
|
||
flow_monitor,
|
||
flow_predict,
|
||
flow_normal,
|
||
timestep_list,
|
||
Top_sensor_num,
|
||
if_gy,
|
||
effective_sensor,
|
||
cos_h,
|
||
dis_h,
|
||
dis_f_h,
|
||
if_compalsive,
|
||
max_flow,
|
||
)
|
||
)
|
||
last_round_candidate_details = similarity_details
|
||
_accumulate_stage(stage_timing, "similarity_final", stage_start)
|
||
|
||
else:
|
||
dpressure = (pressure_predict - pressure_monitor).mean()
|
||
dpressure = dpressure.abs()
|
||
simulation_times = simulation_times + len(dpressure.index)
|
||
similarity_sp = pd.Series(dtype=float)
|
||
for each_node in dpressure.index:
|
||
pipe = node_pipe_dic[each_node][0]
|
||
similarity_sp.loc[pipe] = dpressure.loc[each_node]
|
||
similarity_sp = similarity_sp.sort_values(ascending=False, kind="mergesort")
|
||
t2 = datetime.now()
|
||
final_area_pipe = []
|
||
|
||
sys.stdout.write(
|
||
"\r"
|
||
+ "已经完成"
|
||
+ str(iter_count + 1)
|
||
+ "次迭代计算"
|
||
+ "候选节点"
|
||
+ str(len(final_area_pipe))
|
||
+ "个"
|
||
)
|
||
t2 = datetime.now()
|
||
dt = (t2 - t1).seconds
|
||
final_candidates_csv = _write_last_round_candidates_csv(
|
||
csv_path=final_candidates_csv_path,
|
||
exit_condition=exit_condition,
|
||
iteration_count=iter_count + 1,
|
||
similarity_mode=similarity_mode,
|
||
candidate_details=last_round_candidate_details,
|
||
fallback_similarity=similarity_sp,
|
||
)
|
||
else:
|
||
exit_condition = "no_effective_sensor_after_threshold"
|
||
dpressure = (pressure_predict - pressure_monitor).mean()
|
||
dpressure = dpressure.abs()
|
||
|
||
similarity_sp = pd.Series(dtype=float)
|
||
for each_node in dpressure.index:
|
||
pipe = node_pipe_dic[each_node][0]
|
||
similarity_sp.loc[pipe] = dpressure.loc[each_node]
|
||
similarity_sp = similarity_sp.sort_values(ascending=False, kind="mergesort")
|
||
t2 = datetime.now()
|
||
dt = (t2 - t1).seconds
|
||
final_candidates_csv = _write_last_round_candidates_csv(
|
||
csv_path=final_candidates_csv_path,
|
||
exit_condition=exit_condition,
|
||
iteration_count=0,
|
||
similarity_mode=similarity_mode,
|
||
candidate_details=None,
|
||
fallback_similarity=similarity_sp,
|
||
)
|
||
stage_timing["iterations"] = iter_count + 1 if len(dpressure) > 0 else 0
|
||
stage_timing["total_elapsed_seconds"] = float(dt)
|
||
stage_timing["exit_condition"] = exit_condition
|
||
stage_timing["final_candidates_csv"] = final_candidates_csv
|
||
return (
|
||
similarity_sp.index[0],
|
||
dt,
|
||
simulation_times,
|
||
wn,
|
||
similarity_sp,
|
||
exit_condition,
|
||
final_candidates_csv,
|
||
)
|
||
|