@@ -0,0 +1,856 @@
import numpy as np
from app . services . tjnetwork import *
from api . s36_wda_cal import *
# from get_real_status import *
from datetime import datetime , timedelta
from math import modf
import json
import pytz
import requests
import time
import app . services . project_info as project_info
url_path = ' http://10.101.15.16:9000/loong ' # 内网
# url_path = 'http://183.64.62.100:9057/loong' # 外网
url_real = url_path + ' /api/mpoints/realValue '
url_hist = url_path + ' /api/curves/data '
PATTERN_TIME_STEP = 15.0
DN_900_ID = ' 2498 '
DN_500_ID = ' 3854 '
DN_1000_ID = ' 3853 '
H_RESSURE = ' 2510 '
L_PRESURE = ' 2514 '
H_TANK = ' 4780 '
L_TANK = ' 4854 '
H_REGION_1 = ' SA_ZBBDJSCP000002 '
H_REGION_2 = ' ' #to do
L_REGION_1 = ' SA_ZBBDTJSC000001 '
L_REGION_2 = ' SA_R00003 '
# reservoir basic height
RESERVOIR_BASIC_HEIGHT = float ( 250.35 )
# regions
regions = [ ' hp ' , ' lp ' ]
regions_demand_patterns = { ' hp ' : [ ' DN900 ' , ' DN500 ' ] , ' lp ' : [ ' DN1000 ' ] } # 出厂水量近似表示用水量
regions_patterns = { ' hp ' : [ ' ChuanYiJiXiao ' , ' BeiQuanHuaYuan ' , ' ZhuangYuanFuDi ' , ' JingNingJiaYuan ' ,
' 308 ' , ' JiaYinYuan ' , ' XinChengGuoJi ' , ' YiJingBeiChen ' , ' ZhongYangXinDu ' ,
' XinHaiJiaYuan ' , ' DongFengJie ' , ' DingYaXinYu ' , ' ZiYunTai ' , ' XieMaGuangChang ' ,
' YongJinFu ' , ' BianDianZhan ' , ' BeiNanDaDao ' , ' TianShengLiJie ' , ' XueYuanXiaoQu ' ,
' YunHuaLu ' , ' GaoJiaQiao ' , ' LuZuoFuLuXiaDuan ' , ' TianRunCheng ' , ' CaoJiaBa ' ,
' PuLingChang ' , ' QiLongXiaoQu ' , ' TuanXiao ' ,
' TuanShanBaoZhongShiHua ' , ' XieMa ' , ' BeiWenQuanJiuHaoErQi ' , ' LaiYinHuSiQi ' ,
' DN500 ' , ' DN900 ' ] ,
' lp ' : [ ' PanXiMingDu ' , ' WanKeJinYuHuaFuGaoCeng ' , ' KeJiXiao ' ,
' LuGouQiao ' , ' LongJiangHuaYuan ' , ' LaoQiZhongDui ' , ' ShiYanCun ' , ' TianQiDaSha ' ,
' TianShengPaiChuSuo ' , ' TianShengShangPin ' , ' JiaoTang ' , ' RenMinHuaYuan ' ,
' TaiJiBinJiangYiQi ' , ' TianQiHuaYuan ' , ' TaiJiBinJiangErQi ' , ' 122Zhong ' ,
' WanKeJinYuHuaFuYangFang ' , ' ChengBeiCaiShiKou ' , ' WenXingShe ' , ' YueLiangTianBBGJCZ ' ,
' YueLiangTian ' , ' YueLiangTian200 ' , ' ChengTaoChang ' , ' HuoCheZhan ' , ' LiangKu ' , ' QunXingLu ' ,
' JiuYuanErTongYiYuan ' , ' TangDouHua ' , ' TaiJiBinJiangErQi(SanJi) ' ,
' ZhangDouHua ' , ' JinYunXiaoQuDN400 ' ,
' DN1000 ' ] }
# nodes
monitor_single_patterns = [ ' ChuanYiJiXiao ' , ' BeiQuanHuaYuan ' , ' ZhuangYuanFuDi ' , ' JingNingJiaYuan ' ,
' 308 ' , ' JiaYinYuan ' , ' XinChengGuoJi ' , ' YiJingBeiChen ' , ' ZhongYangXinDu ' ,
' XinHaiJiaYuan ' , ' DongFengJie ' , ' DingYaXinYu ' , ' ZiYunTai ' , ' XieMaGuangChang ' ,
' YongJinFu ' , ' PanXiMingDu ' , ' WanKeJinYuHuaFuGaoCeng ' , ' KeJiXiao ' ,
' LuGouQiao ' , ' LongJiangHuaYuan ' , ' LaoQiZhongDui ' , ' ShiYanCun ' , ' TianQiDaSha ' ,
' TianShengPaiChuSuo ' , ' TianShengShangPin ' , ' JiaoTang ' , ' RenMinHuaYuan ' ,
' TaiJiBinJiangYiQi ' , ' TianQiHuaYuan ' , ' TaiJiBinJiangErQi ' , ' 122Zhong ' ,
' WanKeJinYuHuaFuYangFang ' ]
monitor_single_patterns_id = { ' ChuanYiJiXiao ' : ' 7338 ' , ' BeiQuanHuaYuan ' : ' 7315 ' , ' ZhuangYuanFuDi ' : ' 7316 ' ,
' JingNingJiaYuan ' : ' 7528 ' , ' 308 ' : ' 8272 ' , ' JiaYinYuan ' : ' 7304 ' ,
' XinChengGuoJi ' : ' 7325 ' , ' YiJingBeiChen ' : ' 7328 ' , ' ZhongYangXinDu ' : ' 7329 ' ,
' XinHaiJiaYuan ' : ' 9138 ' , ' DongFengJie ' : ' 7302 ' , ' DingYaXinYu ' : ' 7331 ' ,
' ZiYunTai ' : ' 7420,9059 ' , ' XieMaGuangChang ' : ' 7326 ' , ' YongJinFu ' : ' 9059 ' ,
' PanXiMingDu ' : ' 7320 ' , ' WanKeJinYuHuaFuGaoCeng ' : ' 7419 ' ,
' KeJiXiao ' : ' 7305 ' , ' LuGouQiao ' : ' 7306 ' , ' LongJiangHuaYuan ' : ' 7318 ' ,
' LaoQiZhongDui ' : ' 9075 ' , ' ShiYanCun ' : ' 7309 ' , ' TianQiDaSha ' : ' 7323 ' ,
' TianShengPaiChuSuo ' : ' 7335 ' , ' TianShengShangPin ' : ' 7324 ' , ' JiaoTang ' : ' 7332 ' ,
' RenMinHuaYuan ' : ' 7322 ' , ' TaiJiBinJiangYiQi ' : ' 7333 ' , ' TianQiHuaYuan ' : ' 8235 ' ,
' TaiJiBinJiangErQi ' : ' 7334 ' , ' 122Zhong ' : ' 7314 ' , ' WanKeJinYuHuaFuYangFang ' : ' 7418 ' }
monitor_unity_patterns = [ ' BianDianZhan ' , ' BeiNanDaDao ' , ' TianShengLiJie ' , ' XueYuanXiaoQu ' ,
' YunHuaLu ' , ' GaoJiaQiao ' , ' LuZuoFuLuXiaDuan ' , ' TianRunCheng ' ,
' CaoJiaBa ' , ' PuLingChang ' , ' QiLongXiaoQu ' , ' TuanXiao ' ,
' ChengBeiCaiShiKou ' , ' WenXingShe ' , ' YueLiangTianBBGJCZ ' ,
' YueLiangTian ' , ' YueLiangTian200 ' ,
' ChengTaoChang ' , ' HuoCheZhan ' , ' LiangKu ' , ' QunXingLu ' ,
' TuanShanBaoZhongShiHua ' , ' XieMa ' , ' BeiWenQuanJiuHaoErQi ' , ' LaiYinHuSiQi ' ,
' JiuYuanErTongYiYuan ' , ' TangDouHua ' , ' TaiJiBinJiangErQi(SanJi) ' ,
' ZhangDouHua ' , ' JinYunXiaoQuDN400 ' ,
' DN500 ' , ' DN900 ' , ' DN1000 ' ]
monitor_unity_patterns_id = { ' BianDianZhan ' : ' 7339 ' , ' BeiNanDaDao ' : ' 7319 ' , ' TianShengLiJie ' : ' 8242 ' ,
' XueYuanXiaoQu ' : ' 7327 ' , ' YunHuaLu ' : ' 7312 ' , ' GaoJiaQiao ' : ' 7340 ' ,
' LuZuoFuLuXiaDuan ' : ' 7343 ' , ' TianRunCheng ' : ' 7310 ' , ' CaoJiaBa ' : ' 7300 ' ,
' PuLingChang ' : ' 7307 ' , ' QiLongXiaoQu ' : ' 7321 ' , ' TuanXiao ' : ' 8963 ' ,
' ChengBeiCaiShiKou ' : ' 7330 ' , ' WenXingShe ' : ' 7311 ' ,
' YueLiangTianBBGJCZ ' : ' 7313 ' , ' YueLiangTian ' : ' 7313 ' , ' YueLiangTian200 ' : ' 7313 ' ,
' ChengTaoChang ' : ' 7301 ' , ' HuoCheZhan ' : ' 7303 ' ,
' LiangKu ' : ' 7296 ' , ' QunXingLu ' : ' 7308 ' ,
' DN500 ' : ' 3854 ' , ' DN900 ' : ' 2498 ' , ' DN1000 ' : ' 3853 ' }
monitor_patterns = monitor_single_patterns + monitor_unity_patterns
monitor_patterns_id = { * * monitor_single_patterns_id , * * monitor_unity_patterns_id }
# pumps
pumps_name = [ ' 1# ' , ' 2# ' , ' 3# ' , ' 4# ' , ' 5# ' , ' 6# ' , ' 7# ' ]
pumps = [ ' PU00000 ' , ' PU00001 ' , ' PU00002 ' , ' PU00003 ' , ' PU00004 ' , ' PU00005 ' , ' PU00006 ' ]
variable_frequency_pumps = [ ' PU00004 ' , ' PU00005 ' , ' PU00006 ' ]
pumps_id = { ' PU00000 ' : ' 2747 ' , ' PU00001 ' : ' 2776 ' , ' PU00002 ' : ' 2730 ' , ' PU00003 ' : ' 2787 ' ,
' PU00004 ' : ' 2500 ' , ' PU00005 ' : ' 2502 ' , ' PU00006 ' : ' 2504 ' }
# reservoirs
reservoirs = [ ' ZBBDJSCP000002 ' , ' R00003 ' ]
reservoirs_id = { ' ZBBDJSCP000002 ' : ' 2497 ' , ' R00003 ' : ' 2571 ' }
# tanks
tanks = [ ' ZBBDTJSC000002 ' , ' ZBBDTJSC000001 ' ]
tanks_id = { ' ZBBDTJSC000002 ' : ' 4780 ' , ' ZBBDTJSC000001 ' : ' 9774 ' }
class DataLoader :
""" 数据加载器 """
def __init__ ( self , project_name , start_time : datetime , end_time : datetime ,
pumps_control : dict = None , tank_initial_level_control : dict = None ,
region_demand_control : dict = None , downloading_prohibition : bool = False ) :
self . project_name = project_name # 数据库名
self . current_time = self . round_time ( datetime . now ( pytz . timezone ( ' Asia/Shanghai ' ) ) , 1 ) # 圆整至整分钟
self . current_round_time = self . round_time ( self . current_time , int ( PATTERN_TIME_STEP ) )
self . updating_data_flag = True \
if self . current_round_time == self . round_time ( start_time , int ( PATTERN_TIME_STEP ) ) \
else False # 判断是否从当前时刻开始模拟(是否更新最新监测数据)
self . downloading_prohibition = downloading_prohibition # 是否禁止下载数据(默认False: 允许下载)
self . updating_data_flag = False if self . downloading_prohibition else self . updating_data_flag
self . pattern_start_index = get_pattern_index (
self . round_time ( start_time , int ( PATTERN_TIME_STEP ) ) . strftime ( " % Y- % m- %d % H: % M: % S " ) ) # pattern起始索引
self . pattern_end_index = get_pattern_index (
self . round_time ( end_time , int ( PATTERN_TIME_STEP ) ) . strftime ( " % Y- % m- %d % H: % M: % S " ) ) # pattern结束索引
self . pattern_index_list = list ( range ( self . pattern_start_index , self . pattern_end_index + 1 ) ) # pattern索引列表
self . download_id = self . get_download_id ( ) # 数据下载接口id '7338,7315,7316,...'
self . current_time_download_data = dict (
zip ( self . download_id . split ( ' , ' ) ,
[ np . nan ] * len ( list ( self . download_id . split ( ' , ' ) ) ) )
) # {id(str): value(float)}
self . current_time_download_data_flag = dict (
zip ( self . download_id . split ( ' , ' ) ,
[ False ] * len ( list ( self . download_id . split ( ' , ' ) ) ) )
) # 下载数据是否具备实时性, {id(str): flag(bool)}
self . old_flow_data = self . init_dict_of_list ( dict (
zip ( monitor_patterns ,
[ [ np . nan ] ] * ( len ( monitor_patterns ) ) )
) ) # {pattern_name(str): flow(float)}
self . old_pattern_factor = self . init_dict_of_list ( dict (
zip ( monitor_patterns ,
[ [ np . nan ] ] * ( len ( monitor_patterns ) ) )
) ) # {pattern_name(str): [pattern_factor(float)]}
self . new_flow_data = self . init_dict_of_list ( dict (
zip ( monitor_patterns ,
[ [ np . nan ] ] * ( len ( monitor_patterns ) ) )
) ) # {pattern_name(str): flow(float)}
self . new_pattern_factor = self . init_dict_of_list ( dict (
zip ( monitor_patterns ,
[ [ np . nan ] ] * ( len ( monitor_patterns ) ) )
) ) # {pattern_name(str): [pattern_factor(float)]}
self . reservoir_data = dict ( zip ( reservoirs , [ np . nan ] * len ( reservoirs ) ) ) # {reservoir_name(str): level(float)}
self . tank_data = dict ( zip ( tanks , [ np . nan ] * len ( tanks ) ) ) # {tank_name(str): level(float)}
self . pump_data = self . init_dict_of_list (
dict ( zip ( pumps , [ [ np . nan ] ] * len ( pumps ) ) ) ) # {pump_name(str): [frequency(float)]}
self . pump_control = pumps_control # {pump_name(str): [frequency(float)]}
self . tank_initial_level_control = tank_initial_level_control # {tank_name(str): level(float)}
self . region_demand_current = dict ( zip ( regions , [ 0 ] * len ( regions ) ) ) # {region_name(str): total_demand(float)}
self . region_demand_control = region_demand_control # {region_name(str): total_demand(float)}
self . region_demand_control_factor = dict (
zip ( regions , [ 1 ] * len ( regions ) ) ) # 区域流量控制系数(用于调整用水量), {region_name(str): factor(float)}
def load_data ( self ) :
""" 生成数据集 """
self . download_data ( ) # 下载实时数据
self . get_old_pattern_and_flow ( ) # 读取历史记录pattern信息
self . cal_demand_convert_factor ( ) # 计算用水量转换系数(设定用水量时)
self . set_new_flow ( ) # 设置'更新'流量
self . set_new_pattern_factor ( ) # 设置'更新'pattern factors
self . set_reservoirs ( ) # 设置清水池
self . set_tanks ( ) # 设置调节池
self . set_pumps ( ) # 设置水泵
return self . pattern_start_index
def download_data ( self ) :
""" 下载数据 """
if self . updating_data_flag is True :
print ( ' {} -- Start downloading data. ' . format (
datetime . now ( ) . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ) )
data_wait_flag = True
while data_wait_flag :
try :
newest_data_time = self . download_real_data ( self . download_id ) # 获取实时数据
except Exception as e :
print ( ' {} \n Waiting for real data. ' . format ( e ) )
time . sleep ( 1 )
else :
print ( ' {} -- Downloading data ok. Newest timestamp: {} . ' . format (
datetime . now ( ) . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
newest_data_time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ) )
data_wait_flag = False
def cal_current_region_demand ( self ) :
""" 计算区域当前用水量 """
if self . updating_data_flag is True :
for region in self . region_demand_current . keys ( ) :
total_demand = 0
for pipe in regions_demand_patterns [ region ] :
total_demand + = self . current_time_download_data [ monitor_patterns_id [ pipe ] ] # 出厂流量
self . region_demand_current [ region ] = total_demand
def cal_history_region_demand ( self , pattern_index_list ) :
""" 计算区域历史用水量(对应记录的pattern) """
old_demand = { }
for region in regions :
total_demand = 0
for pipe_pattern_name in regions_demand_patterns [ region ] :
old_flows , old_patterns = self . get_history_pattern_info ( self . project_name , pipe_pattern_name )
for idx in pattern_index_list :
total_demand + = old_flows [ idx ] / 4 # 15分钟水量
old_demand [ region ] = total_demand
return old_demand
def cal_demand_convert_factor ( self ) :
""" 计算用水量转换系数(设定用水量时) """
self . cal_current_region_demand ( ) # 计算区域当前时刻用水量
old_demand_moment = self . cal_history_region_demand ( [ self . pattern_start_index ] ) # 计算区域目标时刻总用水量
old_demand_period = self . cal_history_region_demand ( self . pattern_index_list ) # 计算区域目标时段总用水量
for region in regions :
self . region_demand_control_factor [ region ] \
= ( self . region_demand_current [ region ] / 4 ) / old_demand_moment [ region ] \
if self . updating_data_flag is True else 1
self . region_demand_control_factor [ region ] = self . region_demand_control [ region ] / old_demand_period [ region ] \
if ( self . region_demand_control is not None ) and ( region in self . region_demand_control . keys ( ) ) \
else self . region_demand_control_factor [ region ]
def get_old_pattern_and_flow ( self ) :
""" 获取所有pattern的选定时段的历史记录的pattern和flow """
for idx in monitor_patterns : # 遍历patterns
old_flows , old_patterns = self . get_history_pattern_info ( self . project_name , idx )
for pattern_idx in self . pattern_index_list :
old_flow_data = old_flows [ pattern_idx ]
old_pattern_factor = old_patterns [ pattern_idx ]
if pattern_idx == self . pattern_start_index : # 起始时刻
self . old_flow_data [ idx ] [ 0 ] = old_flow_data
self . old_pattern_factor [ idx ] [ 0 ] = old_pattern_factor
else :
self . old_flow_data [ idx ] . append ( old_flow_data )
self . old_pattern_factor [ idx ] . append ( old_pattern_factor )
def set_new_flow ( self ) :
""" 计算模拟时段新流量(相较于历史记录) """
for idx in self . new_flow_data . keys ( ) : # 遍历patterns
region_name = None
for region in regions_patterns . keys ( ) :
if idx in regions_patterns [ region ] :
region_name = region # pattern所属分区
break
# 实时流量
if self . updating_data_flag is True :
if idx in monitor_unity_patterns [ - 3 : ] : # 出水管流量
self . new_flow_data [ idx ] [ 0 ] = self . current_time_download_data [ monitor_patterns_id [ idx ] ]
else : # 其余流量
self . new_flow_data [ idx ] [ 0 ] \
= self . region_demand_control_factor [ region_name ] * self . old_flow_data [ idx ] [ 0 ]
# if idx == 'ZiYunTai':
# idx_a, idx_b = monitor_patterns_id[idx].split(',')
# self.new_flow_data[idx][0] \
# = self.current_time_download_data[idx_a] - self.current_time_download_data[idx_b]
# else:
# self.new_flow_data[idx][0] = self.current_time_download_data[monitor_patterns_id[idx]]
# for data_id in monitor_patterns_id[idx].split(','):
# if (self.current_time_download_data_flag[data_id] is False) \
# and (idx not in [pipe for pipe_list in regions_demand_patterns.values()
# for pipe in pipe_list]): # 无法获取实时数据
# self.new_flow_data[idx][0] \
# = self.region_demand_control_factor[region_name] * self.old_flow_data[idx][0]
# break
# 根据设定用水量修改新流量
if ( self . region_demand_control is not None ) \
and ( region_name in self . region_demand_control . keys ( ) ) :
for pattern_idx in self . pattern_index_list :
if pattern_idx == self . pattern_start_index : # 起始时刻
self . new_flow_data [ idx ] [ 0 ] \
= self . region_demand_control_factor [ region_name ] * self . old_flow_data [ idx ] [ 0 ]
else :
self . new_flow_data [ idx ] . append (
self . region_demand_control_factor [ region_name ]
* self . old_flow_data [ idx ] [ self . pattern_index_list . index ( pattern_idx ) ]
)
def set_new_pattern_factor ( self ) :
""" 更新计算选定时段(设定用水量)/时刻的pattern factor """
pattern_index_list = self . pattern_index_list \
if self . region_demand_control is not None \
else [ self . pattern_start_index ]
for idx in monitor_patterns : # 遍历patterns
for pattern_idx in pattern_index_list : # 遍历需要修改的pattern(index)
pattern_idx_cls = pattern_index_list . index ( pattern_idx ) # 转换index(类表存储结构)
old_flow_data = self . old_flow_data [ idx ] [ pattern_idx_cls ]
old_pattern_factor = self . old_pattern_factor [ idx ] [ pattern_idx_cls ]
if pattern_idx_cls == 0 : # 起始时刻
if idx in monitor_single_patterns :
if not np . isnan ( self . new_flow_data [ idx ] [ 0 ] ) :
self . new_pattern_factor [ idx ] [ 0 ] = ( self . new_flow_data [ idx ] [ 0 ] * 1000 / 3600 ) # m3/h to L/s
if idx in monitor_unity_patterns :
if not np . isnan ( self . new_flow_data [ idx ] [ 0 ] ) :
self . new_pattern_factor [ idx ] [ 0 ] \
= old_pattern_factor * self . new_flow_data [ idx ] [ 0 ] / old_flow_data
else :
if idx in monitor_single_patterns :
if len ( self . new_flow_data [ idx ] ) > pattern_idx_cls :
self . new_pattern_factor [ idx ] . append (
( self . new_flow_data [ idx ] [ pattern_idx_cls ] * 1000 / 3600 ) ) # m3/h to L/s
if idx in monitor_unity_patterns :
if len ( self . new_flow_data [ idx ] ) > pattern_idx_cls :
self . new_pattern_factor [ idx ] . append (
old_pattern_factor
* self . new_flow_data [ idx ] [ pattern_idx_cls ]
/ old_flow_data )
def set_reservoirs ( self ) :
""" 设置清水池 """
if self . updating_data_flag is True :
for idx in self . reservoir_data . keys ( ) :
if self . current_time_download_data_flag [ reservoirs_id [ idx ] ] is False : # 无法获取实时数据
print ( ' There is no current data of reservoir: {} . ' . format ( idx ) )
else :
self . reservoir_data [ idx ] \
= self . current_time_download_data [ reservoirs_id [ idx ] ] + RESERVOIR_BASIC_HEIGHT
def set_tanks ( self ) :
""" 设置调节池 """
for idx in self . tank_data . keys ( ) :
if self . updating_data_flag is True :
if self . current_time_download_data_flag [ tanks_id [ idx ] ] is False : # 无法获取实时数据
print ( ' There is no current data of tank: {} . ' . format ( idx ) )
else :
self . tank_data [ idx ] = self . current_time_download_data [ tanks_id [ idx ] ]
self . tank_data [ idx ] = self . tank_initial_level_control [ idx ] \
if ( self . tank_initial_level_control is not None ) and ( idx in self . tank_initial_level_control ) \
else self . tank_data [ idx ]
def set_pumps ( self ) :
""" 设置水泵 """
for idx in self . pump_data . keys ( ) :
if self . updating_data_flag is True :
if self . current_time_download_data_flag [ pumps_id [ idx ] ] is False : # 无法获取实时数据
print ( ' There is no current data of pump: {} . ' . format ( idx ) )
if ( self . pump_control is not None ) and ( idx in self . pump_control . keys ( ) ) :
self . pump_data [ idx ] = self . pump_control [ idx ]
else :
self . pump_data [ idx ] = [ self . current_time_download_data [ pumps_id [ idx ] ] ]
if ( self . pump_control is not None ) and ( idx in self . pump_control . keys ( ) ) :
self . pump_data [ idx ] = self . pump_data [ idx ] + self . pump_control [ idx ] \
if len ( self . pump_control [ idx ] ) < len ( self . pattern_index_list ) \
else self . pump_control [ idx ] # 水泵设定
else :
if ( self . pump_control is not None ) and ( idx in self . pump_control . keys ( ) ) :
self . pump_data [ idx ] = self . pump_control [ idx ]
self . pump_data [ idx ] \
= list ( np . array ( self . pump_data [ idx ] ) / 50 ) \
if idx in variable_frequency_pumps else self . pump_data [ idx ]
def set_valves ( self ) :
""" 设置阀门 """
pass
def download_real_data ( self , ids : str ) :
""" 加载实时数据 """
# 数据接口的地址
global url_real
# 设置GET请求的参数
params = { ' ids ' : ids }
# 发送GET请求获取数据
response = requests . get ( url_real , params = params )
# 检查响应状态码, 200表示请求成功
if response . status_code == 200 :
newest_data_time = None # 下载记录数据的最新时间
# 解析响应的JSON数据
data = response . json ( )
for realValue in data : # 取出逐个id的数据
data_time = convert_utc_to_bj ( realValue [ ' datadt ' ] ) # datetime
self . current_time_download_data [ str ( realValue [ ' id ' ] ) ] \
= float ( realValue [ ' realValue ' ] ) # {id(str): value(float)}
if data_time > self . current_round_time . replace ( tzinfo = None ) - timedelta ( minutes = 5 ) : # 下载数据为实时数据
self . current_time_download_data_flag [ str ( realValue [ ' id ' ] ) ] = True
if newest_data_time is None :
newest_data_time = data_time
else :
newest_data_time = data_time if data_time > newest_data_time else newest_data_time # 更新最新时间
if newest_data_time < = self . current_round_time . replace ( tzinfo = None ) - timedelta ( minutes = 5 ) : # 最新记录时间早于当前时间
warning_text = ' There is no current data with newest timestamp: {} . ' . format (
newest_data_time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) )
delta_time = self . current_round_time . replace ( tzinfo = None ) - newest_data_time
if delta_time < timedelta ( minutes = PATTERN_TIME_STEP ) : # 时间接近(可等待再次下载)
raise Exception ( warning_text )
else :
print ( warning_text )
self . updating_data_flag = False
else :
for idx in monitor_unity_patterns [ - 3 : ] : # 出水管流量
if self . current_time_download_data_flag [ monitor_patterns_id [ idx ] ] is False : # 无法获取出水管流量的实时数据
print ( ' There is no current data of outflow: {} . ' . format ( idx ) )
self . updating_data_flag = False
if self . updating_data_flag is False :
print ( ' Abandon updating data with downloaded data. ' )
return newest_data_time
else :
# 如果请求不成功,打印错误信息
print ( " 请求失败,状态码: " , response . status_code )
raise ConnectionError ( ' Cannot download data. ' )
@ staticmethod
def init_dict_of_list ( dict_of_list ) :
""" 初始化值为列表的字典(重新生成列表地址, 防止指向同一列表) """
for idx in dict_of_list . keys ( ) :
dict_of_list [ idx ] = dict_of_list [ idx ] . copy ( )
return dict_of_list
@ staticmethod
def get_download_id ( ) :
""" 生成下载数据项的id """
# id_list = (list(monitor_single_patterns_id.values())
# + list(monitor_unity_patterns_id.values())
# + list(tanks_id.values())
# + list(reservoirs_id.values())
# + list(pumps_id.values()))
id_list = ( list ( monitor_unity_patterns_id . values ( ) ) [ - 3 : ]
+ list ( tanks_id . values ( ) )
+ list ( reservoirs_id . values ( ) )
+ list ( pumps_id . values ( ) ) )
id_list = sorted ( set ( id_list ) , key = id_list . index )
if None in id_list :
id_list . remove ( None )
return ' , ' . join ( id_list )
@ staticmethod
def get_history_pattern_info ( project_name , pattern_name ) :
""" 读取选定pattern的保存的历史pattern信息(flow, factor) """
factors_list = [ ]
flow_list = [ ]
patterns_info = read_all ( project_name ,
f " select * from history_patterns_flows where id = ' { pattern_name } ' order by _order " )
for item in patterns_info :
flow_list . append ( float ( item [ ' flow ' ] ) )
factors_list . append ( float ( item [ ' factor ' ] ) )
return flow_list , factors_list
@ staticmethod
def judge_time ( current_time , time_index_list ) :
""" 时间判断 """
current_index \
= time_index_list . index ( current_time ) if ( current_time in time_index_list ) else None
return current_index
@staticmethod
def get_time_index_list ( start_time : datetime , end_time : datetime , step : int ) :
""" 生成时间索引 """
time_index_list = [ ] # 时间索引[str]
time_index = start_time
while time_index < = end_time :
time_index_list . append ( time_index )
time_index + = timedelta ( minutes = step )
return time_index_list
@ staticmethod
def round_time ( time_ : datetime , interval = 5 ) :
""" 时间向下取整到整n分钟(北京时间): 四舍六入五留双/向下取整 """
# return datetime.fromtimestamp(round(time_.timestamp() / (60 * interval)) * (60 * interval))
return datetime . fromtimestamp ( int ( ( time_ . timestamp ( ) ) / / ( 60 * interval ) ) * ( 60 * interval ) )
def convert_utc_to_bj ( utc_time_str ) :
""" 将utc时间(str)转换成北京时间(datetime) """
# 解析UTC时间字符串为datetime对象
utc_time = datetime . strptime ( utc_time_str , ' % Y- % m- %d T % H: % M: % SZ ' )
# 设定UTC时区
utc_timezone = pytz . timezone ( ' UTC ' )
# 转换为北京时间
beijing_timezone = pytz . timezone ( ' Asia/Shanghai ' )
beijing_time = utc_time . replace ( tzinfo = utc_timezone ) . astimezone ( beijing_timezone ) . replace ( tzinfo = None )
return beijing_time
def get_datetime ( cur_datetime : str ) :
str_format = " % Y- % m- %d % H: % M: % S "
return datetime . strptime ( cur_datetime , str_format )
def get_strftime ( cur_datetime : datetime ) :
str_format = " % Y- % m- %d % H: % M: % S "
return cur_datetime . strftime ( str_format )
def step_time ( cur_datetime : str , step = 5 ) :
str_format = " % Y- % m- %d % H: % M: % S "
dt = datetime . strptime ( cur_datetime , str_format )
dt = dt + timedelta ( minutes = step )
return datetime . strftime ( dt , str_format )
def get_pattern_index ( cur_datetime : str ) - > int :
str_format = " % Y- % m- %d % H: % M: % S "
dt = datetime . strptime ( cur_datetime , str_format )
hr = dt . hour
mnt = dt . minute
i = int ( ( hr * 60 + mnt ) / PATTERN_TIME_STEP )
return i
def get_pattern_index_str ( cur_datetime : str ) - > str :
i = get_pattern_index ( cur_datetime )
[ minN , hrN ] = modf ( i * PATTERN_TIME_STEP / 60 )
minN_str = str ( int ( minN * 60 ) )
minN_str = minN_str . zfill ( 2 )
hrN_str = str ( int ( hrN ) )
hrN_str = hrN_str . zfill ( 2 )
str_i = ' {} : {} :00 ' . format ( hrN_str , minN_str )
return str_i
def from_seconds_to_clock ( secs : int ) - > str :
hrs = int ( secs / 3600 )
minutes = int ( ( secs - hrs * 3600 ) / 60 )
seconds = ( secs - hrs * 3600 - minutes * 60 )
hrs_str = str ( hrs ) . zfill ( 2 )
minutes_str = str ( minutes ) . zfill ( 2 )
seconds_str = str ( seconds ) . zfill ( 2 )
str_clock = ' {} : {} : {} ' . format ( hrs_str , minutes_str , seconds_str )
return str_clock
def from_clock_to_seconds ( clock : str ) - > int :
str_format = " % Y- % m- %d % H: % M: % S "
dt = datetime . strptime ( clock , str_format )
hr = dt . hour
mnt = dt . minute
seconds = dt . second
return hr * 3600 + mnt * 60 + seconds
def from_clock_to_seconds_2 ( clock : str ) - > int :
str_format = " % H: % M: % S "
dt = datetime . strptime ( clock , str_format )
hr = dt . hour
mnt = dt . minute
seconds = dt . second
return hr * 3600 + mnt * 60 + seconds
def from_clock_to_seconds_3 ( clock : str ) - > int :
str_format = " % H: % M " # 更新时间格式以适应 "小时:分钟" 格式
dt = datetime . strptime ( clock , str_format )
hr = dt . hour
mnt = dt . minute
seconds = dt . second
return hr * 3600 + mnt * 60
###convert datetimestring
##"XXXX-XX-XXT00:00:00Z" ->"XXXX-XX-XX 00:00:00"
def trim_time_flag ( url_date_time : str ) - > str :
str_datetime = str . replace ( url_date_time , ' T ' , ' ' )
str_datetime = str . replace ( str_datetime , ' Z ' , ' ' )
return str_datetime
# 单时间步长模拟
def run_simulation ( name : str , start_datetime : str , end_datetime : str = None , duration : int = 900 ) - > str :
if ( is_project_open ( name ) ) :
close_project ( name )
open_project ( name )
#get_current_data(cur_datetime)
#extract the patternindex from datetime
#e.g. 0: the first time step for 00:00-00:14; 1: the second step for 00:15-00:30
start_datetime = trim_time_flag ( start_datetime )
if ( end_datetime != None ) :
end_datetime = trim_time_flag ( end_datetime )
## redistribute the basedemand according to the currentTotalQ and the base_totalQ
# step 1. get_real _data
if end_datetime == None or start_datetime == end_datetime :
end_datetime = step_time ( start_datetime )
# # ids=['2498','3854','3853','2510','2514','4780','4854']
# # real_data=get_real_data(ids,start_datetime,end_datetime)
# print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S")+"--获取实时数据完毕\n")
# #step 2. re-distribute the real q to base demand of the node region_sa by region_sa
# regions=get_all_service_area_ids(name)
# total_demands={}
# for region in regions:
# total_demands[region]=get_total_base_demand(name,region)
# region_demand_factor={}
# #Region_ID:SA_ZBBDJSCP000002 高区;SA_R00003+SA_ZBBDTJSC000001 低区
# H_region_real_demands=real_data[DN_900_ID][start_datetime]+real_data[DN_500_ID][start_datetime]
# L_region_real_demands=real_data[DN_1000_ID][start_datetime]
# factor_H_zone=H_region_real_demands/total_demands[H_REGION_1]/3.6 #3.6: m3/h->L/s
# factor_L_zone=L_region_real_demands/(total_demands[L_REGION_1]+total_demands[L_REGION_2])/3.6
# print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S")+"--流量因子计算完毕完毕\n")
# for region in regions:
# region_nodes=get_nodes_in_region(name,region)
# factor=1
# if region==H_REGION_1 or H_REGION_2:
# factor=factor_H_zone
# else:
# factor=factor_L_zone
#
# for node in region_nodes:
# d=get_demand(name,node)
# for r in d['demands']:
# r['demand']=factor*r['demand']
# cs=ChangeSet()
# cs.append(d)
# set_demand(name,cs)
#
# #
# #
# print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S")+"--节点流量重分配完毕\n")
#step 3. set pattern index to the current time,and set duration to 300 secs
#
str_pattern_start = get_pattern_index_str ( start_datetime )
dic_time = get_time ( name )
dic_time [ ' PATTERN START ' ] = str_pattern_start
if duration != None :
dic_time [ ' DURATION ' ] = from_seconds_to_clock ( duration )
else :
dic_time [ ' DURATION ' ] = dic_time [ ' HYDRAULIC TIMESTEP ' ]
cs = ChangeSet ( )
cs . operations . append ( dic_time )
set_time ( name , cs )
# step4. run simulation and save the result to name-time.out for download
#inp_file = 'inp\\'+name+'.inp'
#db_name=name
#dump_inp(db_name,inp_file,'2')
# result=run_inp(db_name)
result = run_project ( name )
#json string format
# simulation_result, output, report
result_data = json . loads ( result )
#print(result_data['simulation_result'])
print ( datetime . now ( pytz . timezone ( ' Asia/Shanghai ' ) ) . strftime ( " % Y- % m- %d % H: % M: % S " ) + ' run finished successfully \n ' )
#print(result_data['report'])
return result
# 在线模拟
def run_simulation_ex ( name : str , simulation_type : str , start_datetime : str ,
end_datetime : str = None , duration : int = 0 ,
pump_control : dict [ str , list ] = None , tank_initial_level_control : dict [ str , float ] = None ,
region_demand_control : dict [ str , float ] = None , valve_control : dict [ str , dict ] = None ,
downloading_prohibition : bool = False ) - > str :
time_cost_start = time . perf_counter ( )
print ( ' {} -- Hydraulic simulation started. ' . format (
datetime . now ( pytz . timezone ( ' Asia/Shanghai ' ) ) . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ) )
if is_project_open ( name ) :
close_project ( name )
if simulation_type . upper ( ) == ' REALTIME ' : # 实时模拟(修改原数据库)
name_c = name
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) ' )
open_project ( name_c )
# 时间处理
# extract the pattern index from datetime
# e.g. 0: the first time step for 00:00-00:14; 1: the second step for 00:15-00:30
# start_datetime = get_strftime(convert_utc_to_bj(start_datetime))
start_datetime = trim_time_flag ( start_datetime )
if end_datetime is not None :
# end_datetime = get_strftime(convert_utc_to_bj(end_datetime))
end_datetime = trim_time_flag ( end_datetime )
# pump name转化/输入值规范化
if pump_control is not None :
for key in list ( pump_control . keys ( ) ) :
pump_control [ key ] = [ pump_control [ key ] ] if type ( pump_control [ key ] ) is not list else pump_control [ key ]
pump_control [ pumps [ pumps_name . index ( key ) ] ] = pump_control . pop ( key )
# 重新分配节点(nodes)水量
# 1) (single)base_demand_new=1, pattern_new=real_data
# 2) (unity)base_demand_new=base_demand_old, pattern_new=factor*pattern_old(factor=flow_new/flow_old)
# 获取需水量数据
# a) 历史pattern对应水量(读取保存数据库)
# b) 实时水量(数据接口下载)
# 修改node demand = 1, pattern factor *= demand(monitor single patterns对应node)
# nodes = get_nodes(name_c) # nodes
# for node_name in nodes: # 遍历nodes
# demands_dict = get_demand(name_c, node_name) # {'demands':[{'demand':, 'pattern':}]}
# for demands in demands_dict['demands']:
# if (demands['pattern'] in monitor_single_patterns) and (demands['demand'] != 1): # 1)
# pattern = get_pattern(name_c, demands['pattern'])
# pattern['factors'] = list(demands['demand'] * np.array(pattern['factors'])) # 修改pattern
# cs = ChangeSet()
# cs.append(pattern)
# set_pattern(name_c, cs)
# demands_dict['demands'][
# demands_dict['demands'].index(demands)
# ]['demand'] = 1 # 修改demand
# cs = ChangeSet()
# cs.append(demands_dict)
# set_demand(name_c, cs)
start_time = get_datetime ( start_datetime ) # datetime
end_time = get_datetime ( end_datetime ) \
if end_datetime is not None \
else get_datetime ( start_datetime ) + timedelta ( seconds = duration ) # datetime
# modify_pattern_start_index = get_pattern_index(start_datetime) # 待修改pattern的起始索引(int)
dataset_loader = DataLoader ( project_name = name_c ,
start_time = start_time , end_time = end_time ,
pumps_control = pump_control , tank_initial_level_control = tank_initial_level_control ,
region_demand_control = region_demand_control ,
downloading_prohibition = downloading_prohibition ) # 实例化数据加载器
modify_index \
= dataset_loader . load_data ( ) # 加载数据(index: 需要修改pattern的factor index, None: 无需修改除水泵和调节池外pattern)
new_patterns \
= dataset_loader . new_pattern_factor # {name: float,} pattern factor(实时: 更新, 其他: 保持/更新(设定用水量时))
tank_init_level = dataset_loader . tank_data # {name: float,} 调节池初始液位(实时: 更新, 其他: 保持/更新(设定液位时))
reservoir_level = dataset_loader . reservoir_data # {name: float,} 水库液位(实时: 更新, 其他: 保持)
pump_freq = dataset_loader . pump_data # {name: [float,]} 水泵频率(实时: 更新, 其他: 保持/更新(设定状态时))
print ( datetime . now ( pytz . timezone ( ' Asia/Shanghai ' ) ) . strftime ( " % Y- % m- %d % H: % M: % S " ) + " -- Loading data ok. \n " )
pattern_name_list = get_patterns ( name_c ) # 所有pattern
# 修改node pattern/demand
# nodes = get_nodes(name_c) # nodes
# for node_name in nodes: # 遍历nodes
# demands_dict = get_demand(name_c, node_name) # {'demands':[{'demand':, 'pattern':}]}
# for demands in demands_dict['demands']:
# if demands['pattern'] in monitor_single_patterns: # 1)
# demands_dict['demands'][
# demands_dict['demands'].index(demands)
# ]['demand'] = 1 # 修改demand
# pattern = get_pattern(name_c, demands['pattern'])
# pattern['factors'][modify_index] = flow_new[demands['pattern']] # 修改pattern
# cs = ChangeSet()
# cs.append(pattern)
# set_pattern(name_c, cs)
# if demands['pattern'] in pattern_name_list:
# pattern_name_list.remove(demands['pattern']) # 移出待修改pattern列表
# else: # 2)
# continue
# cs = ChangeSet()
# cs.append(demands_dict)
# set_demand(name_c, cs)
for pattern_name in monitor_patterns : # 遍历patterns
if not np . isnan ( new_patterns [ pattern_name ] [ 0 ] ) :
pattern = get_pattern ( name_c , pattern_name )
pattern [ ' factors ' ] [ modify_index :
modify_index + len ( new_patterns [ pattern_name ] ) ] \
= new_patterns [ pattern_name ]
cs = ChangeSet ( )
cs . append ( pattern )
set_pattern ( name_c , cs )
if pattern_name in pattern_name_list :
pattern_name_list . remove ( pattern_name ) # 移出待修改pattern列表
# 修改清水池(reservoir)液位pattern
for reservoir_name in reservoirs : # 遍历reservoirs
if ( not np . isnan ( reservoir_level [ reservoir_name ] ) ) and ( reservoir_level [ reservoir_name ] != 0 ) :
reservoir_pattern = get_pattern ( name_c , get_reservoir ( name_c , reservoir_name ) [ ' pattern ' ] )
reservoir_pattern [ ' factors ' ] [ modify_index ] = reservoir_level [ reservoir_name ]
cs = ChangeSet ( )
cs . append ( reservoir_pattern )
set_pattern ( name_c , cs )
if reservoir_pattern [ ' id ' ] in pattern_name_list :
pattern_name_list . remove ( reservoir_pattern [ ' id ' ] ) # 移出待修改pattern列表
# 修改调节池(tank)初始液位
for tank_name in tanks : # 遍历tanks
if ( not np . isnan ( tank_init_level [ tank_name ] ) ) and ( tank_init_level [ tank_name ] != 0 ) :
tank = get_tank ( name_c , tank_name )
tank [ ' init_level ' ] = tank_init_level [ tank_name ]
cs = ChangeSet ( )
cs . append ( tank )
set_tank ( name_c , cs )
# 修改水泵(pump)pattern
for pump_name in pumps : # 遍历pumps
if not np . isnan ( pump_freq [ pump_name ] [ 0 ] ) :
pump_pattern = get_pattern ( name_c , get_pump ( name_c , pump_name ) [ ' pattern ' ] )
pump_pattern [ ' factors ' ] [ modify_index
: modify_index + len ( pump_freq [ pump_name ] ) ] \
= pump_freq [ pump_name ]
cs = ChangeSet ( )
cs . append ( pump_pattern )
set_pattern ( name_c , cs )
if pump_pattern [ ' id ' ] in pattern_name_list :
pattern_name_list . remove ( pump_pattern [ ' id ' ] ) # 移出待修改pattern列表
# 修改阀门(valve)status和setting
if valve_control is not None :
for valve in valve_control . keys ( ) :
status = get_status ( name_c , valve )
if ' status ' in valve_control [ valve ] . keys ( ) :
status [ ' status ' ] = valve_control [ valve ] [ ' status ' ]
if ' setting ' in valve_control [ valve ] . keys ( ) :
status [ ' setting ' ] = valve_control [ valve ] [ ' setting ' ]
if ' k ' in valve_control [ valve ] . keys ( ) :
valve_k = valve_control [ valve ] [ ' k ' ]
if valve_k == 0 :
status [ ' status ' ] = ' CLOSED '
else :
status [ ' setting ' ] = 0.1036 * pow ( valve_k , - 3.105 )
cs = ChangeSet ( )
cs . append ( status )
set_status ( name_c , cs )
print ( ' Finish demands amending, unmodified patterns: {} . ' . format ( pattern_name_list ) )
# 修改时间信息
str_pattern_start = get_pattern_index_str (
DataLoader . round_time ( start_time , int ( PATTERN_TIME_STEP ) ) . strftime ( " % Y- % m- %d % H: % M: % S " ) )
dic_time = get_time ( name_c )
dic_time [ ' PATTERN START ' ] = str_pattern_start
if duration is not None :
dic_time [ ' DURATION ' ] = from_seconds_to_clock ( duration )
else :
dic_time [ ' DURATION ' ] = dic_time [ ' HYDRAULIC TIMESTEP ' ]
cs = ChangeSet ( )
cs . operations . append ( dic_time )
set_time ( name_c , cs )
# 运行并返回结果
result = run_project ( name_c )
time_cost_end = time . perf_counter ( )
print ( ' {} -- Hydraulic simulation finished, cost time: {:.2f} s. ' . format (
datetime . now ( pytz . timezone ( ' Asia/Shanghai ' ) ) . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
time_cost_end - time_cost_start ) )
close_project ( name_c )
return result
if __name__ == ' __main__ ' :
# if get_current_data()==True:
# tQ=get_current_total_Q()
# print(f"the current tQ is {tQ}\n")
# data=get_hist_data(ids,conver_beingtime_to_ucttime('2024-04-10 15:05:00'),conver_beingtime_to_ucttime('2024-04-10 15:10:00'))
# open_project("beibeizone")
# read_inp("beibeizone","beibeizone-export_nochinese.inp")
# run_simulation("beibeizone","2024-04-01T08:00:00Z")
# read_inp('bb_server', 'model20_en.inp')
run_simulation_ex (
name = project_info . name , simulation_type = ' extended ' , start_datetime = ' 2024-11-09T02:30:00Z ' ,
# end_datetime='2024-05-30T16:00:00Z',
# duration=0,
# pump_control={'PU00006': [45, 40]}
# region_demand_control={'hp': 6000, 'lp': 2000}
)