新增爆管位置检测模块及相关API接口

This commit is contained in:
2026-03-06 15:27:59 +08:00
parent 63d3458fb4
commit b83b895e2b
11 changed files with 3084 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
from __future__ import annotations
from pathlib import Path
from typing import Any
from uuid import uuid4
import pandas as pd
from app.algorithms.burst_location import run_burst_location
from app.services.tjnetwork import dump_inp
SeriesInput = pd.Series | dict[str, Any] | list[dict[str, Any]]
def _normalize_series(data: SeriesInput, field_name: str) -> pd.Series:
if isinstance(data, pd.Series):
series = data.copy()
elif isinstance(data, dict):
series = pd.Series(data, dtype=float)
elif isinstance(data, list):
if len(data) == 0:
return pd.Series(dtype=float)
frame = pd.DataFrame(data)
if not {"id", "value"}.issubset(frame.columns):
raise ValueError(f"{field_name} list item must include 'id' and 'value'.")
series = pd.Series(
frame["value"].values, index=frame["id"].astype(str).values, dtype=float
)
else:
raise ValueError(f"Unsupported data format for {field_name}.")
series.index = series.index.map(str)
return pd.to_numeric(series, errors="raise")
def run_burst_location_by_network(
*,
network: str,
pressure_scada_ids: list[str],
burst_pressure: SeriesInput,
normal_pressure: SeriesInput,
burst_leakage: float,
flow_scada_ids: list[str] | None = None,
burst_flow: SeriesInput | None = None,
normal_flow: SeriesInput | None = None,
min_dpressure: float = 2.0,
basic_pressure: float = 10.0,
) -> dict[str, Any]:
if not network:
raise ValueError("network is required.")
tmp_filename = f"burst_location_{network}_{uuid4().hex}.inp"
inp_path = Path.cwd() / tmp_filename
try:
dump_inp(network, tmp_filename)
burst_pressure_series = _normalize_series(burst_pressure, "burst_pressure")
normal_pressure_series = _normalize_series(normal_pressure, "normal_pressure")
burst_flow_series = (
_normalize_series(burst_flow, "burst_flow") if burst_flow is not None else None
)
normal_flow_series = (
_normalize_series(normal_flow, "normal_flow")
if normal_flow is not None
else None
)
return run_burst_location(
wn_inp_path=str(inp_path),
pressure_scada_ids=pressure_scada_ids,
burst_pressure=burst_pressure_series,
normal_pressure=normal_pressure_series,
burst_leakage=burst_leakage,
flow_scada_ids=flow_scada_ids,
burst_flow=burst_flow_series,
normal_flow=normal_flow_series,
min_dpressure=min_dpressure,
basic_pressure=basic_pressure,
)
finally:
if inp_path.exists():
inp_path.unlink()