调整epanet工具目录结构;联通前端水质分析模块功能;新建 readme.md

This commit is contained in:
2026-01-30 15:24:56 +08:00
parent 9d7a9fb2fd
commit 9037bf317b
12 changed files with 128 additions and 69 deletions

View File

@@ -5,7 +5,10 @@ from math import pi, sqrt
import pytz
import app.services.simulation as simulation
from app.algorithms.api_ex.run_simulation import run_simulation_ex, from_clock_to_seconds_2
from app.algorithms.api_ex.run_simulation import (
run_simulation_ex,
from_clock_to_seconds_2,
)
from app.native.api.project import copy_project
from app.services.epanet.epanet import Output
from app.services.scheme_management import store_scheme_info
@@ -43,7 +46,7 @@ def burst_analysis(
modify_fixed_pump_pattern: dict[str, list] = None,
modify_variable_pump_pattern: dict[str, list] = None,
modify_valve_opening: dict[str, float] = None,
scheme_Name: str = None,
scheme_name: str = None,
) -> None:
"""
爆管模拟
@@ -55,7 +58,7 @@ def burst_analysis(
:param modify_fixed_pump_pattern: dict中包含多个水泵模式str为工频水泵的idlist为修改后的pattern
:param modify_variable_pump_pattern: dict中包含多个水泵模式str为变频水泵的idlist为修改后的pattern
:param modify_valve_opening: dict中包含多个阀门开启度str为阀门的idfloat为修改后的阀门开启度
:param scheme_Name: 方案名称
:param scheme_name: 方案名称
:return:
"""
scheme_detail: dict = {
@@ -169,19 +172,19 @@ def burst_analysis(
modify_fixed_pump_pattern=modify_fixed_pump_pattern,
modify_variable_pump_pattern=modify_variable_pump_pattern,
modify_valve_opening=modify_valve_opening,
scheme_Type="burst_Analysis",
scheme_Name=scheme_Name,
scheme_type="burst_analysis",
scheme_name=scheme_name,
)
# step 3. restore the base model status
# execute_undo(name) #有疑惑
if is_project_open(new_name):
close_project(new_name)
delete_project(new_name)
# return result
# 存储方案信息到 PG 数据库
store_scheme_info(
name=name,
scheme_name=scheme_Name,
scheme_type="burst_Analysis",
scheme_name=scheme_name,
scheme_type="burst_analysis",
username="admin",
scheme_start_time=modify_pattern_start_time,
scheme_detail=scheme_detail,
@@ -400,11 +403,11 @@ def flushing_analysis(
def contaminant_simulation(
name: str,
modify_pattern_start_time: str, # 模拟开始时间,格式为'2024-11-25T09:00:00+08:00'
modify_total_duration: int = 900, # 模拟总历时,秒
source: str = None, # 污染源节点ID
concentration: float = None, # 污染源浓度单位mg/L
modify_total_duration: int, # 模拟总历时,秒
source: str, # 污染源节点ID
concentration: float, # 污染源浓度单位mg/L
scheme_name: str = None,
source_pattern: str = None, # 污染源时间变化模式名称
scheme_Name: str = None,
) -> None:
"""
污染模拟
@@ -418,6 +421,12 @@ def contaminant_simulation(
:param scheme_Name: 方案名称
:return:
"""
scheme_detail: dict = {
"source": source,
"concentration": concentration,
"duration": modify_total_duration,
"pattern": source_pattern,
}
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Analysis."
@@ -520,8 +529,8 @@ def contaminant_simulation(
simulation_type="extended",
modify_pattern_start_time=modify_pattern_start_time,
modify_total_duration=modify_total_duration,
scheme_Type="contaminant_Analysis",
scheme_Name=scheme_Name,
scheme_type="contaminant_analysis",
scheme_name=scheme_name,
)
# for i in range(1,operation_step):
@@ -529,7 +538,15 @@ def contaminant_simulation(
if is_project_open(new_name):
close_project(new_name)
delete_project(new_name)
# return result
# 存储方案信息到 PG 数据库
store_scheme_info(
name=name,
scheme_name=scheme_name,
scheme_type="contaminant_analysis",
username="admin",
scheme_start_time=modify_pattern_start_time,
scheme_detail=scheme_detail,
)
############################################################

View File

@@ -192,19 +192,24 @@ async def burst_analysis_endpoint(
return burst_analysis(network, pipe_id, start_time, end_time, burst_flow)
@router.post("/burst_analysis/")
async def fastapi_burst_analysis(data: BurstAnalysis) -> str:
item = data.dict()
@router.get("/burst_analysis/")
async def fastapi_burst_analysis(
network: str = Query(...),
modify_pattern_start_time: str = Query(...),
burst_ID: list | str = Query(..., alias="burst_ID[]"), # 添加别名以匹配 URL
burst_size: list | float | int = Query(
..., alias="burst_size[]"
), # 添加别名以匹配 URL
modify_total_duration: int = Query(...),
scheme_name: str = Query(...),
) -> str:
burst_analysis(
name=item["name"],
modify_pattern_start_time=item["modify_pattern_start_time"],
burst_ID=item["burst_ID"],
burst_size=item["burst_size"],
modify_total_duration=item["modify_total_duration"],
modify_fixed_pump_pattern=item["modify_fixed_pump_pattern"],
modify_variable_pump_pattern=item["modify_variable_pump_pattern"],
modify_valve_opening=item["modify_valve_opening"],
scheme_Name=item["scheme_Name"],
name=network,
modify_pattern_start_time=modify_pattern_start_time,
burst_ID=burst_ID,
burst_size=burst_size,
modify_total_duration=modify_total_duration,
scheme_name=scheme_name,
)
return "success"
@@ -254,7 +259,9 @@ async def fastapi_flushing_analysis(
flush_flow: float = 0,
duration: int | None = None,
) -> str:
valve_opening = {valve_id: float(valves_k[idx]) for idx, valve_id in enumerate(valves)}
valve_opening = {
valve_id: float(valves_k[idx]) for idx, valve_id in enumerate(valves)
}
result = flushing_analysis(
name=network,
modify_pattern_start_time=start_time,
@@ -266,25 +273,20 @@ async def fastapi_flushing_analysis(
return result or "success"
@router.get("/contaminantsimulation/")
async def contaminant_simulation_endpoint(
network: str, node_id: str, start_time: str, duration: float, concentration: float
):
return contaminant_simulation(network, node_id, start_time, duration, concentration)
@router.get("/contaminant_simulation/", response_class=PlainTextResponse)
async def fastapi_contaminant_simulation(
network: str,
start_time: str,
source: str,
concentration: float,
duration: int = 900,
duration: int,
scheme_name: str | None = None,
pattern: str | None = None,
) -> str:
result = contaminant_simulation(
name=network,
modify_pattern_start_time=start_time,
scheme_name=scheme_name,
modify_total_duration=duration,
source=source,
concentration=concentration,
@@ -431,9 +433,7 @@ async def fastapi_network_update(file: UploadFile = File()) -> str:
async def fastapi_pump_failure(data: PumpFailureState) -> str:
item = data.dict()
with open("./pump_failure_message.txt", "a", encoding="utf-8-sig") as f1:
f1.write(
"[{}] {}\n".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), item)
)
f1.write("[{}] {}\n".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), item))
with open("./pump_failure_status.txt", "r", encoding="utf-8-sig") as f2:
lines = f2.readlines()
first_stage_pump_status_dict = json.loads(json.dumps(eval(lines[0])))

View File

@@ -56,4 +56,4 @@ app.add_middleware(GZipMiddleware, minimum_size=1000)
# Include Routers
app.include_router(api_router, prefix="/api/v1")
# Legcy Routers without version prefix
# app.include_router(api_router)
app.include_router(api_router)

View File

@@ -30,11 +30,11 @@ class Output:
if platform.system() == "Windows":
self._lib = ctypes.CDLL(
os.path.join(os.getcwd(), "epanet", "epanet-output.dll")
os.path.join(os.path.dirname(__file__), "windows", "epanet-output.dll")
)
else:
self._lib = ctypes.CDLL(
os.path.join(os.getcwd(), "epanet", "linux", "libepanet-output.so")
os.path.join(os.path.dirname(__file__), "linux", "libepanet-output.so")
)
self._handle = ctypes.c_void_p()
@@ -314,9 +314,9 @@ def run_project_return_dict(name: str, readable_output: bool = False) -> dict[st
input = name + ".db"
if platform.system() == "Windows":
exe = os.path.join(os.path.join(dir, "epanet"), "runepanet.exe")
exe = os.path.join(os.path.dirname(__file__), "windows", "runepanet.exe")
else:
exe = os.path.join(os.path.join(dir, "epanet"), "linux", "runepanet")
exe = os.path.join(os.path.dirname(__file__), "linux", "runepanet")
inp = os.path.join(os.path.join(dir, "db_inp"), input + ".inp")
rpt = os.path.join(os.path.join(dir, "temp"), input + ".rpt")
opt = os.path.join(os.path.join(dir, "temp"), input + ".opt")
@@ -364,9 +364,9 @@ def run_project(name: str, readable_output: bool = False) -> str:
input = name + ".db"
if platform.system() == "Windows":
exe = os.path.join(os.path.join(dir, "epanet"), "runepanet.exe")
exe = os.path.join(os.path.dirname(__file__), "windows", "runepanet.exe")
else:
exe = os.path.join(os.path.join(dir, "epanet"), "linux", "runepanet")
exe = os.path.join(os.path.dirname(__file__), "linux", "runepanet")
inp = os.path.join(os.path.join(dir, "db_inp"), input + ".inp")
rpt = os.path.join(os.path.join(dir, "temp"), input + ".rpt")
opt = os.path.join(os.path.join(dir, "temp"), input + ".opt")
@@ -416,9 +416,9 @@ def run_inp(name: str) -> str:
dir = os.path.abspath(os.getcwd())
if platform.system() == "Windows":
exe = os.path.join(os.path.join(dir, "epanet"), "runepanet.exe")
exe = os.path.join(os.path.dirname(__file__), "windows", "runepanet.exe")
else:
exe = os.path.join(os.path.join(dir, "epanet"), "linux", "runepanet")
exe = os.path.join(os.path.dirname(__file__), "linux", "runepanet")
inp = os.path.join(os.path.join(dir, "inp"), name + ".inp")
rpt = os.path.join(os.path.join(dir, "temp"), name + ".rpt")
opt = os.path.join(os.path.join(dir, "temp"), name + ".opt")

View File

@@ -21,8 +21,12 @@ import app.services.globals as globals
import uuid
import app.services.project_info as project_info
from app.native.api.postgresql_info import get_pgconn_string
from app.infra.db.timescaledb.internal_queries import InternalQueries as TimescaleInternalQueries
from app.infra.db.timescaledb.internal_queries import InternalStorage as TimescaleInternalStorage
from app.infra.db.timescaledb.internal_queries import (
InternalQueries as TimescaleInternalQueries,
)
from app.infra.db.timescaledb.internal_queries import (
InternalStorage as TimescaleInternalStorage,
)
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
@@ -679,8 +683,8 @@ def run_simulation(
modify_fixed_pump_pattern: dict[str, list] = None,
modify_variable_pump_pattern: dict[str, list] = None,
modify_valve_opening: dict[str, float] = None,
scheme_Type: str = None,
scheme_Name: str = None,
scheme_type: str = None,
scheme_name: str = None,
) -> None:
"""
传入需要修改的参数,改变数据库中对应位置的值,然后计算,返回结果
@@ -695,8 +699,8 @@ def run_simulation(
:param modify_fixed_pump_pattern: dict中包含多个水泵模式str为工频水泵的idlist为修改后的pattern
:param modify_variable_pump_pattern: dict中包含多个水泵模式str为变频水泵的idlist为修改后的pattern
:param modify_valve_opening: dict中包含多个阀门开启度str为阀门的idfloat为修改后的阀门开启度
:param scheme_Type: 模拟方案类型
:param scheme_Name模拟方案名称
:param scheme_type: 模拟方案类型
:param scheme_name模拟方案名称
:return:
"""
# 记录开始时间
@@ -1235,8 +1239,8 @@ def run_simulation(
)
elif simulation_type.upper() == "EXTENDED":
TimescaleInternalStorage.store_scheme_simulation(
scheme_Type,
scheme_Name,
scheme_type,
scheme_name,
node_result,
link_result,
modify_pattern_start_time,