import numpy as np from 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 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('{}\nWaiting 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-%dT%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} )