optimize.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. import os
  2. from datetime import datetime,timedelta
  3. from pathlib import Path
  4. from pprint import pprint
  5. from typing import Union
  6. import pandas as pd
  7. from ...model.DHU.DHU_AB import DHU_AB
  8. from ...model.DHU.SDHU_AB import SDHU_AB
  9. from .config_reader import ConfigReader
  10. from ...tools.data_loader import DataLoader
  11. from ..._utils.data_summary import print_dataframe,summary_dataframe
  12. def optimize(*inputs,config=None):
  13. config = {} if config is None else config
  14. if '__LOCAL' in config.keys():
  15. config_reader_path = config['__LOCAL']
  16. data_URL = config['__URL']
  17. else:
  18. config_reader_path = '/mnt/workflow_data'
  19. data_URL = 'http://basedataportal-svc:8080/data/getpointsdata'
  20. config_reader = ConfigReader(path=f'{config_reader_path}/DHU配置.xlsx')
  21. ALL_RESULT = {
  22. 'EXCEPTION':{
  23. 'State' : {},
  24. 'Mod' : {},
  25. 'Data_ATD' : {},
  26. 'Opt' : {},
  27. 'Push' : {}
  28. },
  29. 'STATUS':{
  30. 'Mode_Steady': [],
  31. 'Mode_Low' : [],
  32. 'Mode_Off' : []
  33. }
  34. }
  35. ALL_OPT_RES = []
  36. for each_eaup_name,each_eaup_name_short in zip(
  37. config_reader.all_equp_names,
  38. config_reader.all_equp_names_short
  39. ):
  40. # 加载模型
  41. # 加载数据
  42. # 运行判断
  43. # 稳态判断:房间露点设定值与反馈值是否接近
  44. # 模型调整
  45. # 模型判断:模型精度是否满足要求
  46. # 模式判断:
  47. # 1. 基于当前露点优化模式:基于房间露点设定值减偏差
  48. # 2. 快速提升送风露点模式:约束送风露点保持不变
  49. if not config_reader.get_app_info(each_eaup_name,'实时优化','开始实时优化','bool'):
  50. continue
  51. each_equp_type = config_reader.get_equp_info(each_eaup_name,key='设备类型',info_type='str')
  52. global NOW
  53. NOW = config_reader.get_app_info(each_eaup_name,'实时优化','运行时间','datetime').replace(second=0,microsecond=0)
  54. print(f'{each_eaup_name}开始实时优化,设备类型为{each_equp_type},运行时间为{NOW}')
  55. try:
  56. dhu_State = load_dhu_State(
  57. each_eaup_name = each_eaup_name,
  58. config_reader = config_reader,
  59. config_reader_path = config_reader_path,
  60. data_URL = data_URL,
  61. NOW = NOW
  62. )
  63. print(f'{each_eaup_name}设备状态为{dhu_State}')
  64. if dhu_State < 1:
  65. print('设备处于非运行状态,跳过')
  66. ALL_RESULT['STATUS']['Mode_Off'].append(each_eaup_name)
  67. continue
  68. except Exception as e:
  69. ALL_RESULT['EXCEPTION']['State'][each_eaup_name] = e
  70. raise e
  71. continue
  72. # 加载模型
  73. try:
  74. MODEL = load_model(
  75. each_eaup_name = each_eaup_name,
  76. each_equp_type = each_equp_type,
  77. config_reader = config_reader,
  78. config_reader_path = config_reader_path
  79. )
  80. except Exception as e:
  81. ALL_RESULT['EXCEPTION']['Mod'][each_eaup_name] = e
  82. continue
  83. try:
  84. data_dhu = load_data_dhu(
  85. each_eaup_name = each_eaup_name,
  86. each_equp_type = each_equp_type,
  87. config_reader = config_reader,
  88. config_reader_path = config_reader_path,
  89. data_URL = data_URL
  90. )
  91. except Exception as e:
  92. ALL_RESULT['EXCEPTION']['Data_ATD'][each_eaup_name] = e
  93. continue
  94. try:
  95. ALL_RESULT['STATUS']['Mode_Steady'].append(each_eaup_name)
  96. opt_result = optimize_dhu(
  97. MODEL = MODEL,
  98. data_cur = data_dhu,
  99. config_reader = config_reader,
  100. each_eaup_name = each_eaup_name,
  101. each_equp_type = each_equp_type
  102. )
  103. ALL_OPT_RES.append(opt_result['opt_summary'][1].assign(equp_name=each_eaup_name))
  104. except Exception as e:
  105. ALL_RESULT['EXCEPTION']['Opt'][each_eaup_name] = e
  106. raise e
  107. continue
  108. try:
  109. push_result(
  110. each_eaup_name = each_eaup_name,
  111. each_eaup_name_short = each_eaup_name_short,
  112. each_equp_type = each_equp_type,
  113. config_reader = config_reader,
  114. opt_result = opt_result,
  115. data_cur = data_dhu
  116. )
  117. except Exception as e:
  118. ALL_RESULT['EXCEPTION']['Push'][each_eaup_name] = e
  119. continue
  120. pprint(ALL_RESULT)
  121. print_dataframe(pd.concat(ALL_OPT_RES,axis=0),'优化结果')
  122. def load_model(
  123. each_eaup_name,
  124. each_equp_type,
  125. config_reader:ConfigReader,
  126. config_reader_path,
  127. use_adj_name = True
  128. ):
  129. adjust_equp_name = config_reader.get_equp_info(each_eaup_name,'替代模型','str')
  130. if (adjust_equp_name in config_reader.all_equp_names_total) and use_adj_name:
  131. print(f'{each_eaup_name}使用替代模型{adjust_equp_name}')
  132. each_eaup_name = adjust_equp_name
  133. else:
  134. pass
  135. if each_equp_type in ['DHU_A','DHU_B']:
  136. MODEL = DHU_AB
  137. elif each_equp_type in ['SDHU_A','SDHU_B']:
  138. MODEL = SDHU_AB
  139. else:
  140. raise NotImplementedError
  141. if config_reader.get_app_info(
  142. each_eaup_name,
  143. app_type = '实时优化',
  144. key = '使用临时模型',
  145. info_type = 'bool'
  146. ):
  147. # 从文件夹中获取临时模型
  148. MODEL = MODEL.load(path=f'{config_reader_path}/model/{each_eaup_name}.pkl')
  149. else:
  150. MODEL = MODEL.load_from_platform(
  151. source = 'id',
  152. model_id = config_reader.get_equp_info(
  153. equp_name = each_eaup_name,
  154. key = '模型编号',
  155. info_type = 'str'
  156. )
  157. )
  158. return MODEL
  159. def load_dhu_State(
  160. each_eaup_name,
  161. config_reader,
  162. config_reader_path,
  163. data_URL,
  164. NOW,
  165. ):
  166. data_last = (
  167. DataLoader(
  168. path = f'{config_reader_path}/data/optimize/data_cur/',
  169. start_time = NOW - timedelta(minutes=1),
  170. end_time = NOW,
  171. print_process = False
  172. )
  173. .download_equp_data(
  174. equp_name = each_eaup_name,
  175. point = {'State':config_reader.get_equp_point(each_eaup_name,equp_class=['A'])['State']},
  176. url = data_URL,
  177. clean_cache = True
  178. )
  179. .get_equp_data(
  180. equp_name = each_eaup_name,
  181. )
  182. )
  183. return data_last.iat[-1,0]
  184. def load_data_room(
  185. each_eaup_name,
  186. each_equp_type,
  187. config_reader,
  188. config_reader_path,
  189. data_URL
  190. ):
  191. room_steady_len = config_reader.get_app_info(each_eaup_name,'实时优化','房间稳态判断时长','float')
  192. room_data_loader = DataLoader(
  193. path = f'{config_reader_path}/data/optimize/data_cur/',
  194. start_time = NOW - timedelta(minutes=room_steady_len),
  195. end_time = NOW,
  196. print_process = False
  197. )
  198. room_data_loader.download_equp_data(
  199. equp_name = each_eaup_name,
  200. point = config_reader.get_equp_point(each_eaup_name,equp_class=['C']),
  201. url = data_URL,
  202. clean_cache = True
  203. )
  204. room_data = room_data_loader.get_equp_data(each_eaup_name)
  205. summary_dataframe(room_data,f'{each_eaup_name}房间数据')
  206. room_Dew_SP_adj = config_reader.get_app_info(each_eaup_name,'实时优化','房间露点设定值偏差','float')
  207. room_Dew_SP = room_data.room_DSP.mean() + room_Dew_SP_adj
  208. room_Dew_PV = room_data.room_DPV.mean()
  209. room_Dew_diff_dwlim = config_reader.get_app_info(each_eaup_name,'实时优化','房间露点过低阈值','float')
  210. # 模式判断
  211. is_room_Dew_steady = (room_Dew_PV < (room_Dew_SP + 0.5)) and (room_Dew_PV > (room_Dew_SP - 0.5))
  212. is_room_Dew_low = room_Dew_PV < (room_Dew_SP - room_Dew_diff_dwlim)
  213. data_room = {
  214. 'is_room_Dew_steady': is_room_Dew_steady,
  215. 'is_room_Dew_low' : is_room_Dew_low,
  216. 'room_Dew_SP' : room_Dew_SP,
  217. 'room_Dew_PV' : room_Dew_PV
  218. }
  219. return data_room
  220. def load_data_dhu(
  221. each_eaup_name,
  222. each_equp_type,
  223. config_reader,
  224. config_reader_path,
  225. data_URL,
  226. ):
  227. dhu_steady_len = config_reader.get_app_info(each_eaup_name,'实时优化','除湿机工况均值时长','float')
  228. data_input_point = config_reader.get_equp_point(each_eaup_name,equp_class=['A','B'])
  229. data_last = (
  230. DataLoader(
  231. path = f'{config_reader_path}/data/optimize/data_cur/',
  232. start_time = NOW - timedelta(minutes=dhu_steady_len),
  233. end_time = NOW,
  234. print_process = False
  235. )
  236. .download_equp_data(
  237. equp_name = each_eaup_name,
  238. point = data_input_point,
  239. url = data_URL,
  240. clean_cache = True
  241. )
  242. .get_equp_data(
  243. equp_name = each_eaup_name,
  244. )
  245. )
  246. data_cur = data_last.mean(axis=0).to_frame().T
  247. summary_dataframe(data_last,f'{each_eaup_name}除湿机数据')
  248. return data_cur
  249. def optimize_dhu(
  250. MODEL : Union[DHU_AB,SDHU_AB],
  251. data_cur : pd.DataFrame,
  252. config_reader : ConfigReader,
  253. each_eaup_name : str,
  254. each_equp_type : str
  255. ):
  256. # 模型精度判断
  257. predict = MODEL.predict_system(input_data=data_cur)
  258. TVP_data = (
  259. predict.T.set_axis(['pred'],axis=1)
  260. .join(
  261. data_cur.T.set_axis(['real'],axis=1),
  262. how = 'left'
  263. )
  264. .dropna(axis=0)
  265. .assign(diff=lambda x: x['pred'] - x['real'])
  266. )
  267. print(TVP_data)
  268. # 实时优化
  269. if each_equp_type in ['DHU_A','DHU_B']:
  270. opt_res = MODEL.optimize(
  271. cur_input_data=data_cur,
  272. wheel_1_TinR=(
  273. config_reader.get_equp_info(each_eaup_name,key='前再生温度上限',info_type='float'),
  274. config_reader.get_equp_info(each_eaup_name,key='前再生温度下限',info_type='float')
  275. ),
  276. wheel_2_TinR=(
  277. config_reader.get_equp_info(each_eaup_name,key='后再生温度上限',info_type='float'),
  278. config_reader.get_equp_info(each_eaup_name,key='后再生温度下限',info_type='float')
  279. ),
  280. fan_2_Hz = None,
  281. constrains = ['coil_3_DoutA-[coil_3_DoutA]<0'],
  282. logging = False,
  283. target = 'summary_waste',
  284. target_min = True
  285. )
  286. elif each_equp_type in ['SDHU_A','SDHU_B']:
  287. opt_res = MODEL.optimize(
  288. cur_input_data = data_cur,
  289. wheel_1_TinR = (
  290. config_reader.get_equp_info(each_eaup_name,key='前再生温度上限',info_type='float'),
  291. config_reader.get_equp_info(each_eaup_name,key='前再生温度下限',info_type='float')
  292. ),
  293. fan_2_Hz = (30,45),
  294. constrains = ['wheel_1_DoutP-[wheel_1_DoutP]<0'],
  295. logging = False,
  296. target = 'summary_waste',
  297. target_min = True
  298. )
  299. opt_summary = opt_res['opt_summary']
  300. opt_var = opt_res['opt_var']
  301. print_dataframe(opt_summary,'优化结果')
  302. print_dataframe(opt_var,'优化变量')
  303. return {
  304. 'opt_summary': opt_summary,
  305. 'opt_var' : opt_var,
  306. }
  307. def push_result(
  308. each_eaup_name,
  309. each_eaup_name_short,
  310. each_equp_type,
  311. config_reader:ConfigReader,
  312. opt_result:dict,
  313. data_cur:pd.DataFrame
  314. ):
  315. equp_point = config_reader.get_equp_point(each_eaup_name,equp_class=['D'])
  316. if each_equp_type in ['DHU_A','DHU_B']:
  317. rcmd = [
  318. {
  319. 'name' : '前再生加热温度',
  320. 'rcmd_value': opt_result['opt_var'][0].iat[0,0],
  321. 'children' : [
  322. {
  323. 'name' : '前再生加热温度',
  324. 'rcmd_value': opt_result['opt_var'][0].round(1).iat[0,0],
  325. 'curr_value': data_cur.loc[:,['wheel_1_TinR']].round(1).iat[0,0],
  326. 'point_id' : f'{each_eaup_name}_{equp_point["wheel_1_TinR_AISP"]}'
  327. }
  328. ]
  329. },
  330. {
  331. 'name' : '后再生加热温度',
  332. 'rcmd_value': opt_result['opt_var'][1].iat[0,0],
  333. 'children' : [
  334. {
  335. 'name' : '后再生加热温度',
  336. 'rcmd_value': opt_result['opt_var'][1].round(1).iat[0,0],
  337. 'curr_value': data_cur.loc[:,['wheel_2_TinR']].round(1).iat[0,0],
  338. 'point_id' : f'{each_eaup_name}_{equp_point["wheel_2_TinR_AISP"]}'
  339. }
  340. ]
  341. },
  342. ]
  343. elif each_equp_type in ['SDHU_A','SDHU_B']:
  344. rcmd = [
  345. {
  346. 'name' : '再生加热温度',
  347. 'rcmd_value': opt_result['opt_var'][0].iat[0,0],
  348. 'children' : [
  349. {
  350. 'name' : '再生加热温度',
  351. 'rcmd_value': opt_result['opt_var'][0].round(1).iat[0,0],
  352. 'curr_value': data_cur.loc[:,['wheel_1_TinR']].round(1).iat[0,0],
  353. 'point_id' : f'{each_eaup_name}_{equp_point["wheel_1_TinR_AISP"]}'
  354. }
  355. ]
  356. },
  357. {
  358. 'name' : '排风机频率',
  359. 'rcmd_value': opt_result['opt_var'][1].iat[0,0],
  360. 'children' : [
  361. {
  362. 'name' : '排风机频率',
  363. 'rcmd_value': opt_result['opt_var'][1].round(1).iat[0,0],
  364. 'curr_value': data_cur.loc[:,['fan_2_Hz']].round(1).iat[0,0],
  365. 'point_id' : f'{each_eaup_name}_{equp_point["fan_2_Hz_AISP"]}'
  366. }
  367. ]
  368. },
  369. ]
  370. else:
  371. raise Exception('MODEL_TYPE_ERROR')
  372. if config_reader.get_app_info(each_eaup_name,'实时优化','推送策略','bool'):
  373. add_ai_rcmd_operation(
  374. code = each_eaup_name_short,
  375. job_id = os.environ.get('JOB_ID', None),
  376. rcmd = rcmd,
  377. custom_details = []
  378. )
  379. else:
  380. pprint(rcmd)
  381. def add_ai_rcmd_operation(code,job_id,rcmd,custom_details):
  382. from workflowlib import requests
  383. json_info = {
  384. "job_id": job_id,
  385. "code" : code,
  386. "data" : {
  387. "rcmd" : rcmd,
  388. "custom_details": custom_details
  389. },
  390. }
  391. print('ai_rcmd',json_info)
  392. try:
  393. # 下发分步指令
  394. url = 'http://m2-backend-svc:8000/api/ai/ai_rcmd_operation/add_ai_rcmd_operation_v3'
  395. r = requests.post(url,json=json_info,headers={'Content-Type': "application/json", "Connection": "close"})
  396. jsonResp = r.json()
  397. print(f'下发指令 jsonResp',jsonResp)
  398. except Exception as e:
  399. print(e)
  400. return