refactor(db)!: finalize pooled WNDB v2 migration

This commit is contained in:
2026-08-27 17:26:22 +08:00
parent fa188af0b1
commit b74799a39d
105 changed files with 4988 additions and 5565 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
"""Service package.
Keep package initialization lightweight. Import concrete service modules directly,
for example: `from app.services.tjnetwork import open_project`.
for example: `from app.services.tjnetwork import get_junction`.
"""
+291 -264
View File
@@ -9,7 +9,6 @@ from app.services.tjnetwork import (
get_status,
get_tank,
get_time,
open_project,
read_all,
run_project,
set_demand,
@@ -34,7 +33,8 @@ import logging
import app.services.globals as globals
import app.services.project_info as project_info
from app.services.time_api import parse_beijing_time, parse_clock_duration_seconds
from app.native.wndb.core.connection import project_connection
from app.native.wndb.core.connection import project_connection, project_transaction
from app.native.wndb.core.database import refresh_materialized_views_after_commit
from app.infra.db.timescaledb.internal_queries import (
InternalQueries as TimescaleInternalQueries,
)
@@ -48,6 +48,31 @@ logging.basicConfig(
)
def _primary_demand(demand_set: dict) -> dict:
"""Return sequence-zero demand, creating it when a junction has none."""
demands = demand_set.setdefault("demands", [])
if not demands:
demands.append({"demand": 0.0, "pattern": None, "category": None})
return demands[0]
def _primary_demand_pattern(demand_set: dict) -> str:
"""Return the first configured pattern in deterministic sequence order."""
pattern = next(
(
demand.get("pattern")
for demand in demand_set.get("demands", [])
if demand.get("pattern")
),
None,
)
if pattern is None:
raise ValueError(
f"Junction {demand_set.get('junction')!r} has no demand pattern"
)
return str(pattern)
def query_corresponding_element_id_and_query_id(name: str) -> None:
"""Load realtime device-to-element mappings from the new asset schema."""
target_maps = {
@@ -221,281 +246,283 @@ def run_simulation(
# elif simulation_type.upper() == 'EXTENDED': # 扩展模拟(复制数据库)
# name_c = '_'.join([name, 'c'])
# if have_project(name_c):
# if is_project_open(name_c):
# close_project(name_c)
# delete_project(name_c)
# copy_project(name, name_c) # 备份项目
# else:
# raise Exception('Incorrect simulation type, choose in (realtime, extended)')
name_c = name
# 打开数据库
open_project(name_c)
dic_time = get_time(name_c)
with project_transaction(name_c):
dic_time = get_time(name_c)
print(dic_time)
print(dic_time)
# 获取水力模拟步长,如’0:15:00‘
globals.hydraulic_timestep = dic_time["HYDRAULIC TIMESTEP"]
# 转换为分钟浮点数,兼容 EPANET 的 H:MM 和 H:MM:SS 写法
globals.PATTERN_TIME_STEP = (
parse_clock_duration_seconds(
globals.hydraulic_timestep,
field_name="HYDRAULIC TIMESTEP",
# 获取水力模拟步长,如’0:15:00‘
globals.hydraulic_timestep = dic_time["HYDRAULIC TIMESTEP"]
# 转换为分钟浮点数,兼容 EPANET 的 H:MM 和 H:MM:SS 写法
globals.PATTERN_TIME_STEP = (
parse_clock_duration_seconds(
globals.hydraulic_timestep,
field_name="HYDRAULIC TIMESTEP",
)
/ 60
)
/ 60
)
# 对输入的时间参数进行处理
pattern_start_time = convert_time_format(modify_pattern_start_time)
# 获取模拟开始时间是对应pattern的第几个数
modify_index = get_pattern_index(pattern_start_time)
# 遍历水泵的pattern_id,并根据输入的pump_pattern修改pattern的值
# for pump_pattern_id in pump_pattern_ids:
# # 检查pump_pattern中pump_pattern_id对应的第一个频率值是否为有效数字(非空、非NaN)。如果该值有效,则继续执行代码块。
# if not np.isnan(modify_pump_pattern[pump_pattern_id][0]):
# # 取出数据库中的pattern
# pump_pattern = get_pattern(name_c, get_pump(name_c, pump_pattern_id)['pattern'])
# # 替换数据库中的pattern为modify_pump_pattern
# pump_pattern['factors'][modify_index: modify_index + len(modify_pump_pattern[pump_pattern_id])] \
# = modify_pump_pattern[pump_pattern_id]
# cs = ChangeSet()
# cs.append(pump_pattern)
# set_pattern(name_c, cs)
# 修改模拟开始的时间
str_pattern_start = get_pattern_index_str(
convert_time_format(modify_pattern_start_time)
)
dic_time = get_time(name_c)
dic_time["PATTERN START"] = str_pattern_start
dic_time["DURATION"] = from_seconds_to_clock(modify_total_duration)
if simulation_type.upper() == "REALTIME":
dic_time["DURATION"] = 0
cs = ChangeSet()
cs.operations.append(dic_time)
set_time(name_c, cs)
# 根据SCADA实时数据进行修改,如果没有对应的SCADA数据,如未来的时间点,则不改变pg数据库的数据
if globals.reservoirs_id:
# reservoirs_id = {'ZBBDJSCP000002': '2497', 'R00003': '2571'}
# 1.获取reservoir的SCADA数据,形式如{'2497': '3.1231', '2571': '2.7387'}
reservoir_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.reservoirs_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
# 对输入的时间参数进行处理
pattern_start_time = convert_time_format(modify_pattern_start_time)
# 获取模拟开始时间是对应pattern的第几个数
modify_index = get_pattern_index(pattern_start_time)
# 遍历水泵的pattern_id,并根据输入的pump_pattern修改pattern的值
# for pump_pattern_id in pump_pattern_ids:
# # 检查pump_pattern中pump_pattern_id对应的第一个频率值是否为有效数字(非空、非NaN)。如果该值有效,则继续执行代码块。
# if not np.isnan(modify_pump_pattern[pump_pattern_id][0]):
# # 取出数据库中的pattern
# pump_pattern = get_pattern(name_c, get_pump(name_c, pump_pattern_id)['pattern'])
# # 替换数据库中的pattern为modify_pump_pattern
# pump_pattern['factors'][modify_index: modify_index + len(modify_pump_pattern[pump_pattern_id])] \
# = modify_pump_pattern[pump_pattern_id]
# cs = ChangeSet()
# cs.append(pump_pattern)
# set_pattern(name_c, cs)
# 修改模拟开始的时间
str_pattern_start = get_pattern_index_str(
convert_time_format(modify_pattern_start_time)
)
# 2.构建出新字典,形式如{'ZBBDJSCP000002': '3.1231', 'R00003': '2.7387'}
reservoir_dict = {
key: reservoir_SCADA_data_dict[value]
for key, value in globals.reservoirs_id.items()
}
# 3.修改reservoir液位模式
for reservoir_name, value in reservoir_dict.items():
if value and float(value) != 0:
# 根据reservoir获取对应的pattern,再对pattern进行修改
reservoir_pattern = get_pattern(
name_c, get_reservoir(name_c, reservoir_name)["pattern"]
)
reservoir_pattern["factors"][modify_index] = (
float(value) + globals.RESERVOIR_BASIC_HEIGHT
)
cs = ChangeSet()
cs.append(reservoir_pattern)
set_pattern(name_c, cs)
if globals.tanks_id:
# 修改tank初始液位
tank_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.tanks_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
)
tank_dict = {
key: tank_SCADA_data_dict[value] for key, value in globals.tanks_id.items()
}
for tank_name, value in tank_dict.items():
if value and float(value) != 0:
tank = get_tank(name_c, tank_name)
tank["init_level"] = float(value)
cs = ChangeSet()
cs.append(tank)
set_tank(name_c, cs)
if globals.fixed_pumps_id:
# 修改工频泵的pattern
fixed_pump_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.fixed_pumps_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
)
# print(fixed_pump_SCADA_data_dict)
fixed_pump_dict = {
key: fixed_pump_SCADA_data_dict[value]
for key, value in globals.fixed_pumps_id.items()
}
# print(fixed_pump_dict)
for fixed_pump_name, value in fixed_pump_dict.items():
if value:
pump_pattern = get_pattern(
name_c, get_pump(name_c, fixed_pump_name)["pattern"]
)
# print(pump_pattern)
pump_pattern["factors"][modify_index] = float(value)
# print(pump_pattern['factors'][modify_index])
cs = ChangeSet()
cs.append(pump_pattern)
set_pattern(name_c, cs)
if globals.variable_pumps_id:
# 修改变频泵的pattern
variable_pump_SCADA_data_dict = (
TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.variable_pumps_id.values()),
dic_time = get_time(name_c)
dic_time["PATTERN START"] = str_pattern_start
dic_time["DURATION"] = from_seconds_to_clock(modify_total_duration)
if simulation_type.upper() == "REALTIME":
dic_time["DURATION"] = 0
cs = ChangeSet()
cs.operations.append(dic_time)
set_time(name_c, cs)
# 根据SCADA实时数据进行修改,如果没有对应的SCADA数据,如未来的时间点,则不改变pg数据库的数据
if globals.reservoirs_id:
# reservoirs_id = {'ZBBDJSCP000002': '2497', 'R00003': '2571'}
# 1.获取reservoir的SCADA数据,形式如{'2497': '3.1231', '2571': '2.7387'}
reservoir_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.reservoirs_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
)
)
variable_pump_dict = {
key: variable_pump_SCADA_data_dict[value]
for key, value in globals.variable_pumps_id.items()
}
for variable_pump_name, value in variable_pump_dict.items():
if value:
pump_pattern = get_pattern(
name_c, get_pump(name_c, variable_pump_name)["pattern"]
)
pump_pattern["factors"][modify_index] = float(value) / 50
cs = ChangeSet()
cs.append(pump_pattern)
set_pattern(name_c, cs)
if globals.demand_id:
# 基于实时数据,修改大用户节点的pattern
demand_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.demand_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
)
demand_dict = {
key: demand_SCADA_data_dict[value]
for key, value in globals.demand_id.items()
}
for demand_name, value in demand_dict.items():
if value:
demand_pattern = get_pattern(
name_c, get_demand(name_c, demand_name)["pattern"]
)
if get_option(name_c)["UNITS"] == "LPS":
demand_pattern["factors"][modify_index] = (
float(value) / 3.6
) # 默认SCADA数据获取的是流量单位是m3/h, 转换为 L/s
elif get_option(name_c)["UNITS"] == "CMH":
demand_pattern["factors"][modify_index] = float(value)
cs = ChangeSet()
cs.append(demand_pattern)
set_pattern(name_c, cs)
# 水质、压力实时数据使用方法待补充
#############################
# 显式请求参数覆盖实时设备数据,用于扩展模拟。
# 修改清水池(reservoir)液位的pattern
if modify_reservoir_head_pattern:
for reservoir_name in modify_reservoir_head_pattern.keys():
# 这句代码的作用是判断modify_reservoir_head_pattern[reservoir_name][0]是否不是NaN。
# 如果modify_reservoir_head_pattern[reservoir_name][0]不是NaN,则条件成立,代码块会执行
if not np.isnan(modify_reservoir_head_pattern[reservoir_name][0]):
# 给 list 中的所有元素加上 RESERVOIR_BASIC_HEIGHT
modified_values = [
value + globals.RESERVOIR_BASIC_HEIGHT
for value in modify_reservoir_head_pattern[reservoir_name]
]
reservoir_pattern = get_pattern(
name_c, get_reservoir(name_c, reservoir_name)["pattern"]
)
reservoir_pattern["factors"][
modify_index : modify_index + len(modified_values)
] = modified_values
cs = ChangeSet()
cs.append(reservoir_pattern)
set_pattern(name_c, cs)
# 修改调节池(tank)初始液位
if modify_tank_initial_level:
for tank_name in modify_tank_initial_level.keys():
if (not np.isnan(modify_tank_initial_level[tank_name])) and (
modify_tank_initial_level[tank_name] != 0
):
tank = get_tank(name_c, tank_name)
tank["init_level"] = modify_tank_initial_level[tank_name]
cs = ChangeSet()
cs.append(tank)
set_tank(name_c, cs)
# 修改节点(junction)基础水量(demand
if modify_junction_base_demand:
for junction_name in modify_junction_base_demand.keys():
if not np.isnan(modify_junction_base_demand[junction_name]):
junction = get_demand(name_c, junction_name)
junction["demand"] = modify_junction_base_demand[junction_name]
cs = ChangeSet()
cs.append(junction)
set_demand(name_c, cs)
# 修改节点(junction)的水量模式(pattern
if modify_junction_damand_pattern:
for pattern_name in modify_junction_damand_pattern.keys():
if not np.isnan(modify_junction_damand_pattern[pattern_name][0]):
junction_pattern = get_pattern(name_c, pattern_name)
junction_pattern["factors"][
modify_index : modify_index
+ len(modify_junction_damand_pattern[pattern_name])
] = modify_junction_damand_pattern[pattern_name]
cs = ChangeSet()
cs.append(junction_pattern)
set_pattern(name_c, cs)
# 修改工频水泵(fixed_pump)的pattern
if modify_fixed_pump_pattern:
for pump_name in modify_fixed_pump_pattern.keys():
if not np.isnan(modify_fixed_pump_pattern[pump_name][0]):
pump_pattern = get_pattern(
name_c, get_pump(name_c, pattern_name)["pattern"]
)
pump_pattern["factors"][
modify_index : modify_index + len(modify_fixed_pump_pattern)
] = modify_fixed_pump_pattern[pump_name]
cs = ChangeSet()
cs.append(pump_pattern)
set_pattern(name_c, cs)
# 修改变频水泵(variable_pump)的pattern
if modify_variable_pump_pattern:
for pump_name in modify_variable_pump_pattern.keys():
if not np.isnan(modify_variable_pump_pattern[pump_name][0]):
# 给 list 中的所有元素除以 50Hz
modified_values = [
value / 50 for value in modify_variable_pump_pattern[pump_name]
]
pump_pattern = get_pattern(
name_c, get_pump(name_c, pattern_name)["pattern"]
)
pump_pattern["factors"][
modify_index : modify_index + len(modified_values)
] = modified_values
cs = ChangeSet()
cs.append(pump_pattern)
set_pattern(name_c, cs)
# 显式阀门控制沿用 run_simulation_ex 的处理顺序和覆盖规则。
if valve_control is not None:
_apply_valve_control(name_c, valve_control)
# 保留原开度参数逻辑,兼容现有方案调用。
elif modify_valve_opening:
for valve_name in modify_valve_opening.keys():
if not np.isnan(modify_valve_opening[valve_name]):
valve_status = get_status(name_c, valve_name)
if modify_valve_opening[valve_name] == 0:
valve_status["status"] = "CLOSED"
valve_status["setting"] = 0
elif modify_valve_opening[valve_name] < 1:
valve_status["status"] = "OPEN"
valve_status["setting"] = 0.1036 * pow(
modify_valve_opening[valve_name], -3.105
# 2.构建出新字典,形式如{'ZBBDJSCP000002': '3.1231', 'R00003': '2.7387'}
reservoir_dict = {
key: reservoir_SCADA_data_dict[value]
for key, value in globals.reservoirs_id.items()
}
# 3.修改reservoir液位模式
for reservoir_name, value in reservoir_dict.items():
if value and float(value) != 0:
# 先根据reservoir获取对应的pattern,再对pattern进行修改
reservoir_pattern = get_pattern(
name_c, get_reservoir(name_c, reservoir_name)["pattern"]
)
elif modify_valve_opening[valve_name] == 1:
valve_status["status"] = "OPEN"
valve_status["setting"] = 0
cs = ChangeSet()
cs.append(valve_status)
set_status(name_c, cs)
# 运行并返回结果
result_data = json.loads(run_project(name_c))
reservoir_pattern["factors"][modify_index] = (
float(value) + globals.RESERVOIR_BASIC_HEIGHT
)
cs = ChangeSet()
cs.append(reservoir_pattern)
set_pattern(name_c, cs)
if globals.tanks_id:
# 修改tank初始液位
tank_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.tanks_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
)
tank_dict = {
key: tank_SCADA_data_dict[value] for key, value in globals.tanks_id.items()
}
for tank_name, value in tank_dict.items():
if value and float(value) != 0:
tank = get_tank(name_c, tank_name)
tank["init_level"] = float(value)
cs = ChangeSet()
cs.append(tank)
set_tank(name_c, cs)
if globals.fixed_pumps_id:
# 修改工频泵的pattern
fixed_pump_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.fixed_pumps_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
)
# print(fixed_pump_SCADA_data_dict)
fixed_pump_dict = {
key: fixed_pump_SCADA_data_dict[value]
for key, value in globals.fixed_pumps_id.items()
}
# print(fixed_pump_dict)
for fixed_pump_name, value in fixed_pump_dict.items():
if value:
pump_pattern = get_pattern(
name_c, get_pump(name_c, fixed_pump_name)["pattern"]
)
# print(pump_pattern)
pump_pattern["factors"][modify_index] = float(value)
# print(pump_pattern['factors'][modify_index])
cs = ChangeSet()
cs.append(pump_pattern)
set_pattern(name_c, cs)
if globals.variable_pumps_id:
# 修改变频泵的pattern
variable_pump_SCADA_data_dict = (
TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.variable_pumps_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
)
)
variable_pump_dict = {
key: variable_pump_SCADA_data_dict[value]
for key, value in globals.variable_pumps_id.items()
}
for variable_pump_name, value in variable_pump_dict.items():
if value:
pump_pattern = get_pattern(
name_c, get_pump(name_c, variable_pump_name)["pattern"]
)
pump_pattern["factors"][modify_index] = float(value) / 50
cs = ChangeSet()
cs.append(pump_pattern)
set_pattern(name_c, cs)
if globals.demand_id:
# 基于实时数据,修改大用户节点的pattern
demand_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time(
device_ids=list(globals.demand_id.values()),
query_time=modify_pattern_start_time,
db_name=name,
)
demand_dict = {
key: demand_SCADA_data_dict[value]
for key, value in globals.demand_id.items()
}
for demand_name, value in demand_dict.items():
if value is not None and not np.isnan(float(value)):
demand_set = get_demand(name_c, demand_name)
demand_pattern = get_pattern(
name_c, _primary_demand_pattern(demand_set)
)
if get_option(name_c)["UNITS"] == "LPS":
demand_pattern["factors"][modify_index] = (
float(value) / 3.6
) # 默认SCADA数据获取的是流量单位是m3/h, 转换为 L/s
elif get_option(name_c)["UNITS"] == "CMH":
demand_pattern["factors"][modify_index] = float(value)
cs = ChangeSet()
cs.append(demand_pattern)
set_pattern(name_c, cs)
# 水质、压力实时数据使用方法待补充
#############################
# 显式请求参数覆盖实时设备数据,用于扩展模拟。
# 修改清水池(reservoir)液位的pattern
if modify_reservoir_head_pattern:
for reservoir_name in modify_reservoir_head_pattern.keys():
# 这句代码的作用是判断modify_reservoir_head_pattern[reservoir_name][0]是否不是NaN。
# 如果modify_reservoir_head_pattern[reservoir_name][0]不是NaN,则条件成立,代码块会执行
if not np.isnan(modify_reservoir_head_pattern[reservoir_name][0]):
# 给 list 中的所有元素加上 RESERVOIR_BASIC_HEIGHT
modified_values = [
value + globals.RESERVOIR_BASIC_HEIGHT
for value in modify_reservoir_head_pattern[reservoir_name]
]
reservoir_pattern = get_pattern(
name_c, get_reservoir(name_c, reservoir_name)["pattern"]
)
reservoir_pattern["factors"][
modify_index : modify_index + len(modified_values)
] = modified_values
cs = ChangeSet()
cs.append(reservoir_pattern)
set_pattern(name_c, cs)
# 修改调节池(tank)初始液位
if modify_tank_initial_level:
for tank_name in modify_tank_initial_level.keys():
if (not np.isnan(modify_tank_initial_level[tank_name])) and (
modify_tank_initial_level[tank_name] != 0
):
tank = get_tank(name_c, tank_name)
tank["init_level"] = modify_tank_initial_level[tank_name]
cs = ChangeSet()
cs.append(tank)
set_tank(name_c, cs)
# 修改节点(junction)基础水量(demand
if modify_junction_base_demand:
for junction_name in modify_junction_base_demand.keys():
if not np.isnan(modify_junction_base_demand[junction_name]):
junction = get_demand(name_c, junction_name)
_primary_demand(junction)["demand"] = (
modify_junction_base_demand[junction_name]
)
cs = ChangeSet()
cs.append(junction)
set_demand(name_c, cs)
# 修改节点(junction)的水量模式(pattern
if modify_junction_damand_pattern:
for pattern_name in modify_junction_damand_pattern.keys():
if not np.isnan(modify_junction_damand_pattern[pattern_name][0]):
junction_pattern = get_pattern(name_c, pattern_name)
junction_pattern["factors"][
modify_index : modify_index
+ len(modify_junction_damand_pattern[pattern_name])
] = modify_junction_damand_pattern[pattern_name]
cs = ChangeSet()
cs.append(junction_pattern)
set_pattern(name_c, cs)
# 修改工频水泵(fixed_pump)的pattern
if modify_fixed_pump_pattern:
for pump_name in modify_fixed_pump_pattern.keys():
if not np.isnan(modify_fixed_pump_pattern[pump_name][0]):
pump_pattern = get_pattern(
name_c, get_pump(name_c, pump_name)["pattern"]
)
pump_pattern["factors"][
modify_index
: modify_index + len(modify_fixed_pump_pattern[pump_name])
] = modify_fixed_pump_pattern[pump_name]
cs = ChangeSet()
cs.append(pump_pattern)
set_pattern(name_c, cs)
# 修改变频水泵(variable_pump)的pattern
if modify_variable_pump_pattern:
for pump_name in modify_variable_pump_pattern.keys():
if not np.isnan(modify_variable_pump_pattern[pump_name][0]):
# 给 list 中的所有元素除以 50Hz
modified_values = [
value / 50 for value in modify_variable_pump_pattern[pump_name]
]
pump_pattern = get_pattern(
name_c, get_pump(name_c, pump_name)["pattern"]
)
pump_pattern["factors"][
modify_index : modify_index + len(modified_values)
] = modified_values
cs = ChangeSet()
cs.append(pump_pattern)
set_pattern(name_c, cs)
# 显式阀门控制沿用 run_simulation_ex 的处理顺序和覆盖规则。
if valve_control is not None:
_apply_valve_control(name_c, valve_control)
# 保留原开度参数逻辑,兼容现有方案调用。
elif modify_valve_opening:
for valve_name in modify_valve_opening.keys():
if not np.isnan(modify_valve_opening[valve_name]):
valve_status = get_status(name_c, valve_name)
if modify_valve_opening[valve_name] == 0:
valve_status["status"] = "CLOSED"
valve_status["setting"] = 0
elif modify_valve_opening[valve_name] < 1:
valve_status["status"] = "OPEN"
valve_status["setting"] = 0.1036 * pow(
modify_valve_opening[valve_name], -3.105
)
elif modify_valve_opening[valve_name] == 1:
valve_status["status"] = "OPEN"
valve_status["setting"] = 0
cs = ChangeSet()
cs.append(valve_status)
set_status(name_c, cs)
# 运行并返回结果
result_data = json.loads(run_project(name_c))
refresh_materialized_views_after_commit(name_c)
time_cost_end = time.perf_counter()
print(
"{} -- Hydraulic simulation finished, cost time: {:.2f} s.".format(
+42 -54
View File
@@ -1,55 +1,60 @@
import json
from datetime import datetime
from functools import wraps
from math import pi
import pytz
from app.algorithms.simulation.runner import run_simulation_ex
from app.native.wndb.core.projects import temporary_project_database
from app.services.tjnetwork import (
close_project,
copy_project,
delete_project,
get_pipe,
get_tank,
have_project,
is_project_open,
open_project,
)
def _isolated_operation(purpose: str):
def decorator(func):
@wraps(func)
def wrapper(prj_name: str, *args, **kwargs):
with temporary_project_database(prj_name, purpose) as temporary:
kwargs["_temporary_project"] = temporary
return func(prj_name, *args, **kwargs)
return wrapper
return decorator
############################################################
# project management 07 ***暂时不使用,与业务需求无关***
############################################################
@_isolated_operation("project_management")
def project_management(
prj_name,
start_datetime,
pump_control,
tank_initial_level_control=None,
region_demand_control=None,
_temporary_project=None,
) -> str:
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Analysis."
)
new_name = f"project_management_{prj_name}"
if have_project(new_name):
if is_project_open(new_name):
close_project(new_name)
delete_project(new_name)
# if is_project_open(prj_name):
# close_project(prj_name)
if _temporary_project is None:
raise RuntimeError("Project-management isolation was not prepared")
new_name = _temporary_project
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Copying Database."
)
copy_project(prj_name + "_template", new_name)
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Opening Database."
)
open_project(new_name)
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Database Loading OK."
@@ -64,9 +69,6 @@ def project_management(
region_demand_control=region_demand_control,
downloading_prohibition=True,
)
if is_project_open(new_name):
close_project(new_name)
delete_project(new_name)
return result
@@ -75,31 +77,31 @@ def project_management(
############################################################
@_isolated_operation("scheduling")
def scheduling_simulation(
prj_name, start_time, pump_control, tank_id, water_plant_output_id, time_delta=300
prj_name,
start_time,
pump_control,
tank_id,
water_plant_output_id,
time_delta=300,
_temporary_project=None,
) -> str:
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Analysis."
)
new_name = f"scheduling_{prj_name}"
if have_project(new_name):
if is_project_open(new_name):
close_project(new_name)
delete_project(new_name)
# if is_project_open(prj_name):
# close_project(prj_name)
if _temporary_project is None:
raise RuntimeError("Scheduling isolation was not prepared")
new_name = _temporary_project
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Copying Database."
)
copy_project(prj_name + "_template", new_name)
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Opening Database."
)
open_project(new_name)
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Database Loading OK."
@@ -115,9 +117,6 @@ def scheduling_simulation(
if not isinstance(output_data, dict):
raise RuntimeError("run_simulation_ex did not return JSON output content")
if not is_project_open(new_name):
open_project(new_name)
tank = get_tank(new_name, tank_id) # 水塔信息
tank_floor_space = pi * pow(tank["diameter"] / 2, 2) # 水塔底面积(m^2)
tank_init_level = tank["init_level"] # 水塔初始水位(m)
@@ -158,38 +157,34 @@ def scheduling_simulation(
"tank_level": tank_level,
}
if is_project_open(new_name):
close_project(new_name)
delete_project(new_name)
return json.dumps(simulation_results)
@_isolated_operation("daily_scheduling")
def daily_scheduling_simulation(
prj_name, start_time, pump_control, reservoir_id, tank_id, water_plant_output_id
prj_name,
start_time,
pump_control,
reservoir_id,
tank_id,
water_plant_output_id,
_temporary_project=None,
) -> str:
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Analysis."
)
new_name = f"daily_scheduling_{prj_name}"
if have_project(new_name):
if is_project_open(new_name):
close_project(new_name)
delete_project(new_name)
# if is_project_open(prj_name):
# close_project(prj_name)
if _temporary_project is None:
raise RuntimeError("Daily-scheduling isolation was not prepared")
new_name = _temporary_project
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Copying Database."
)
copy_project(prj_name + "_template", new_name)
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Start Opening Database."
)
open_project(new_name)
print(
datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
+ " -- Database Loading OK."
@@ -209,9 +204,6 @@ def daily_scheduling_simulation(
if not isinstance(output_data, dict):
raise RuntimeError("run_simulation_ex did not return JSON output content")
if not is_project_open(new_name):
open_project(new_name)
node_results = output_data.get("node_results") or [] # [{'node': str, 'result': [{'pressure': float, 'head': float}]}]
water_plant_output_pressure = []
reservoir_level = []
@@ -235,8 +227,4 @@ def daily_scheduling_simulation(
"tank_level": tank_level,
}
if is_project_open(new_name):
close_project(new_name)
delete_project(new_name)
return json.dumps(simulation_results)
+6 -41
View File
@@ -32,14 +32,11 @@ from app.native.wndb.commands.api import (
)
from app.native.wndb.core.database import ChangeSet, read_all
from app.native.wndb.core.projects import (
close_project,
copy_project,
create_project,
delete_project,
have_project,
is_project_open,
list_project,
open_project,
)
from app.native.wndb.gis.backdrop import (
get_backdrop,
@@ -54,6 +51,12 @@ from app.native.wndb.gis.labels import (
get_label_schema,
set_label,
)
from app.native.wndb.gis.network_views import (
get_major_node_coords,
get_major_pipe_nodes,
get_network_link_nodes,
get_network_node_coords,
)
from app.native.wndb.gis.region_geometry import get_nodes_in_region
from app.native.wndb.gis.regions import (
add_region,
@@ -89,16 +92,11 @@ from app.native.wndb.model.elements import (
get_curves,
get_element_type,
get_element_type_value,
get_link_nodes,
get_link_type,
get_links,
get_links_id_and_type,
get_major_nodes,
get_major_pipes,
get_node_links,
get_node_type,
get_nodes,
get_nodes_id_and_type,
get_patterns,
get_regions,
is_curve,
@@ -280,39 +278,6 @@ def get_element_properties(name: str, element_id: str) -> dict[str, Any]:
return get_scada_info(name, element_id)
def get_network_node_coords(name: str) -> dict[str, dict[str, Any]]:
nodes = get_nodes_id_and_type(name)
return {
node_id: {**get_node_coord(name, node_id), "type": node_type}
for node_id, node_type in nodes.items()
}
def get_major_node_coords(name: str, diameter: int) -> dict[str, dict[str, Any]]:
node_types = get_nodes_id_and_type(name)
return {
node_id: {**get_node_coord(name, node_id), "type": node_types[node_id]}
for node_id in get_major_nodes(name, diameter)
}
def get_network_link_nodes(name: str) -> list[str]:
links = get_links_id_and_type(name)
return [
f"{link_id}:{link_type}:{nodes[0]}:{nodes[1]}"
for link_id, link_type in links.items()
if (nodes := get_link_nodes(name, link_id))
]
def get_major_pipe_nodes(name: str, diameter: int) -> list[str]:
return [
f"{link_id}:pipe:{nodes[0]}:{nodes[1]}"
for link_id in get_major_pipes(name, diameter)
if (nodes := get_link_nodes(name, link_id))
]
def get_network_in_extent(
name: str, x1: float, y1: float, x2: float, y2: float
) -> dict[str, Any]: