857 lines
43 KiB
Python
857 lines
43 KiB
Python
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
|
||
|
||
|
||
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='bb', 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}
|
||
)
|