cloudpss 4.0.4__py3-none-any.whl → 4.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,146 +0,0 @@
1
- import logging
2
- import sys
3
- from .jobReceiver import JobReceiver
4
- import os
5
- from urllib.parse import urlparse
6
- import websocket
7
- import pytz
8
- import threading
9
- import time
10
-
11
- utc_tz = pytz.timezone("UTC")
12
-
13
- from ..utils.IO import IO
14
-
15
-
16
- class Message(object):
17
- def __init__(self, id, token):
18
- self.id = id
19
- self.token = token
20
-
21
-
22
- class MessageStreamReceiver(JobReceiver):
23
- def __init__(self, job):
24
- super().__init__()
25
- self.job = job
26
- self.id =self.job.output
27
- self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
28
- self.__hasOpen = False
29
-
30
- def __path(self, from_=None):
31
- if self.id is None:
32
- raise Exception("id is None")
33
- u = list(urlparse(self.origin))
34
- head = "wss" if u[0] == "https" else "ws"
35
- path = head + "://" + str(u[1]) + "/api/streams/id/" + self.id
36
- if from_ is not None:
37
- path = path + "?from=" + str(from_)
38
- return path
39
-
40
- ###下面是兼容Receiver部分功能实现
41
- def __on_message_legacy(self, *args, **kwargs):
42
-
43
- if type(args[0]) != websocket.WebSocketApp:
44
- message = args[0]
45
- else:
46
- message = args[1]
47
- return self.__on_message(message)
48
-
49
- def __on_message(self, message):
50
-
51
- data = IO.deserialize(message, "ubjson")
52
- self.ws.url = self.__path(data["id"])
53
- msg = IO.deserialize(data["data"], "ubjson")
54
- self.messages.append(msg)
55
- if(msg['type']=='terminate'):
56
- self.close(self.ws)
57
- return msg
58
-
59
-
60
- def __on_error(self, *args, **kwargs):
61
- logging.debug("MessageStreamReceiver error")
62
- msg = {
63
- "type": "log",
64
- "verb": "create",
65
- "version": 1,
66
- "data": {
67
- "level": "error",
68
- "content": "websocket error",
69
- },
70
- }
71
- self.messages.append(msg)
72
-
73
- def __on_close(self, *args, **kwargs):
74
- if len(args)>1:
75
- msg =args[2]
76
-
77
- if msg is not None and msg.startswith("CMS_NO_STREAM_ID:"):
78
- self._status = 1
79
- msg = {
80
- "type": "log",
81
- "version": 1,
82
- "data": {
83
- "level": "critical",
84
- "content": "未找到任务的输出流,运行结果可能已被清理。",
85
- },
86
- }
87
- self.messages.append(msg)
88
- return
89
- logging.debug("MessageStreamReceiver close")
90
- msg = {
91
- "type": "log",
92
- "verb": "create",
93
- "version": 1,
94
- "data": {
95
- "level": "info",
96
- "content": "websocket closed",
97
- },
98
- }
99
- self.messages.append(msg)
100
- self._status = 1
101
-
102
- def __on_open(self,ws, *args, **kwargs):
103
- self.ws = ws
104
- logging.debug(f"MessageStreamReceiver on_open")
105
- self._status = 0
106
- self.__hasOpen = True
107
- pass
108
-
109
- def close(self, ws):
110
- self._status = 1
111
- ws.close()
112
-
113
- @property
114
- def status(self):
115
- return self._status
116
-
117
- def waitFor(self,timeOut=sys.maxsize):
118
- """
119
- 阻塞方法,直到任务完成
120
-
121
- :params timeOut: 超时时间
122
- """
123
- start = time.time()
124
- while self.status == 0:
125
- time.sleep(0)
126
- if time.time()-start>timeOut:
127
- raise Exception("time out")
128
-
129
-
130
- def connect(self):
131
- self._status = 1
132
- path = self.__path()
133
- logging.info(f"receive data from websocket: {path}")
134
- self.ws = websocket.WebSocketApp(
135
- path,
136
- on_open=self.__on_open,
137
- on_message=self.__on_message_legacy,
138
- on_error=self.__on_error,
139
- on_close=self.__on_close,
140
- )
141
- thread = threading.Thread(target=self.ws.run_forever, kwargs={'ping_interval':60,'ping_timeout':5,'reconnect':True})
142
- thread.setDaemon(True)
143
- thread.start()
144
- while not self.__hasOpen:
145
- time.sleep(0)
146
-
@@ -1,93 +0,0 @@
1
- import asyncio
2
- import sys, os
3
- import threading
4
- from urllib.parse import urlparse
5
-
6
- import aiohttp
7
-
8
-
9
- sys.path.append(os.path.join(os.path.dirname(__file__), "../"))
10
-
11
- import websocket
12
-
13
- from cloudpss.utils.IO import IO
14
- import time
15
- import logging
16
-
17
-
18
- class MessageStreamSender:
19
- def __init__(self, job):
20
- super().__init__()
21
- self.job = job
22
- self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
23
- self.__hasOpen = False
24
-
25
- def __on_message(self, ws, message):
26
- logging.debug("on_message", message)
27
-
28
- def __on_error(self, ws, error):
29
- logging.debug("on_error")
30
-
31
- def __on_close(self, *args, **kwargs):
32
- # print("on_close")
33
- time.sleep(0.5)
34
- self._status = 0
35
- self.__hasOpen=False
36
-
37
- logging.debug("on_close")
38
-
39
- def __on_open(self,ws):
40
- self._status = 1
41
- self.__hasOpen=True
42
- logging.debug("on_open")
43
- pass
44
-
45
- def close(self):
46
- # print("close")
47
- self._status = 0
48
- self.ws.close()
49
- if self.websocket is not None:
50
- asyncio.run(self.websocket.close())
51
- if self.session is not None:
52
- asyncio.run(self.session.close())
53
-
54
- @property
55
- def status(self):
56
- return self._status
57
-
58
- def write(self, message):
59
- data = IO.serialize(message, "ubjson", None)
60
- self.ws.send(data,websocket.ABNF.OPCODE_BINARY)
61
-
62
- def connect_legacy(self):
63
- """
64
- 同步方法连接ws
65
- """
66
- self._status = 0
67
- if self.job.input is None:
68
- raise Exception("id is None")
69
- if self.job.input == "00000000-0000-0000-0000-000000000000":
70
- return
71
- u = list(urlparse(self.origin))
72
- head = "wss" if u[0] == "https" else "ws"
73
-
74
- path = head + "://" + str(u[1]) + "/api/streams/token/" + self.job.input
75
- logging.debug(f"MessageStreamSender data from websocket: {path}")
76
-
77
- self.ws = websocket.WebSocketApp(
78
- path,
79
- on_open=self.__on_open,
80
- on_message=self.__on_message,
81
- on_error=self.__on_error,
82
- on_close=self.__on_close,
83
- )
84
- thread = threading.Thread(target=self.ws.run_forever, args=(None, None, 6, 3))
85
- thread.setDaemon(True)
86
- thread.start()
87
- while not self.__hasOpen:
88
- time.sleep(0.2)
89
- return self.ws
90
-
91
-
92
-
93
-
@@ -1,214 +0,0 @@
1
- import copy
2
- import uuid
3
- from deprecated import deprecated
4
- from .view import View
5
- class EMTView(View):
6
- """
7
- 电磁暂态结果视图,
8
-
9
- 提供快捷 plot 数据的接口函数,获取到的 plot 数据为合并后的数据格式,不在是接收时分段的数据
10
-
11
- 该类只提供 EMT 仿真使用
12
-
13
- """
14
-
15
- def getPlots(self):
16
- '''
17
- 获取所有的 plots 数据
18
-
19
- >>> result.getPlots()
20
- {...}
21
- '''
22
- for val in self._receiver:
23
- if val['type'] == 'plot':
24
- key = val['key']
25
- if self.result.get(key, None) is None:
26
- self.result[key] = copy.deepcopy(val)
27
- else:
28
- traces = val['data']['traces']
29
- for i in range(len(traces)):
30
- v = traces[i]
31
- self.result[key]['data']['traces'][i]['x'].extend(
32
- v['x'])
33
- self.result[key]['data']['traces'][i]['y'].extend(
34
- v['y'])
35
- return self.result.values()
36
-
37
- def getPlot(self, index: int):
38
- '''
39
- 获取指定序号的曲线分组
40
-
41
- :params: index 图表位置
42
-
43
- >>> result.getPlot(0)
44
- {...}
45
- '''
46
- self.getPlots()
47
- if self.result is not None:
48
- return self.result.get('plot-{0}'.format(int(index)), None)
49
-
50
- def getPlotChannelNames(self, index):
51
- '''
52
- 获取一组输出分组下的所有通道名称
53
-
54
- :params: index 输出通道位置
55
-
56
- :return: 通道名称数组
57
-
58
- >>>names= result.getPlotChannelNames(0)
59
- []
60
- '''
61
- plot = self.getPlot(int(index))
62
- if plot is None:
63
- return None
64
-
65
- return [val['name'] for val in plot['data']['traces']]
66
-
67
- def getPlotChannelData(self, index, channelName):
68
- '''
69
- 获取一组输出分组下指定通道名称的数据
70
-
71
- :params: index 输出通道位置
72
- :params: channelName 输出通道名称
73
-
74
- :return: 通道数据, 一个 trace 数据
75
-
76
- >>>channel= result.getPlotChannelData(0,'')
77
- {...}
78
- '''
79
- plot = self.getPlot(int(index))
80
- if plot is None:
81
- return None
82
- for val in plot['data']['traces']:
83
- if val['name'] == channelName:
84
- return val
85
- return val
86
-
87
- def next(self):
88
- """
89
- 前进一个时步
90
- """
91
-
92
- self.goto(-1)
93
-
94
- def goto(self,step):
95
- """
96
- 前进到指定时步
97
- """
98
- if self._sender is not None:
99
- self._sender.write({'type': 'debug', 'step': step})
100
- else:
101
- raise Exception('sender is None')
102
-
103
-
104
- def writeShm(self,path,buffer,offset):
105
- """
106
- 写内存接口 (未最终确定,后续版本进行修改,使用时注意版本)
107
- """
108
- if self._sender is not None:
109
- self._sender.write({'type': 'memory', 'path': path,'buffer':buffer,'offset':offset})
110
- else:
111
- raise Exception('transmitter is None')
112
-
113
- def _writeEvent(self,eventType,eventTime,eventTimeType,defaultApp):
114
- if self._sender is None:
115
- raise Exception('transmitter is None')
116
- event = {
117
- 'eventType': eventType,
118
- 'eventTime': eventTime,
119
- 'eventTimeType':eventTimeType,
120
- "defaultApp": defaultApp
121
- }
122
- self._sender.write({'type': 'eventchain', 'event': [event]})
123
-
124
- def stopSimulation(self):
125
- """
126
- 停止仿真
127
- """
128
- param = {
129
- "ctrl_type": "0",
130
- "uuid": str(uuid.uuid1()),
131
- 'message': {
132
- 'log': '停止任务 ',
133
- }
134
- }
135
- eventData = {}
136
- eventData = {'SimuCtrl': param}
137
-
138
- self._writeEvent('time','-1','1',{'SimuCtrl': eventData})
139
-
140
- def _snapshotControl(self,ctrlType,snapshotNumber,log):
141
- """
142
- 断面控制
143
- """
144
- param = {
145
- "ctrl_type": ctrlType,
146
- "snapshot_number": snapshotNumber,
147
- "uuid": str(uuid.uuid1()),
148
- 'message': {
149
- 'log': log
150
- },
151
- }
152
- eventData = {}
153
- eventData = {'SnapshotCtrl': param}
154
- self._writeEvent('time','-1','1',{'SnapshotCtrl': eventData})
155
- def saveSnapshot(self,snapshotNumber,log='保存断面成功'):
156
- """
157
- 通过事件链保存断面
158
- """
159
- self._snapshotControl('0',snapshotNumber,log)
160
- def loadSnapshot(self,snapshotNumber,log='加载断面成功'):
161
- """
162
- 通过事件链加载断面
163
- """
164
- self._snapshotControl('1',snapshotNumber,log)
165
-
166
- def control(self,controlParam,eventTime='-1',eventTimeType='1'):
167
- """
168
- 控制仿真
169
- """
170
-
171
- if type(controlParam) is not list:
172
- controlParam=[controlParam]
173
- para={}
174
-
175
- for param in controlParam:
176
- para[param['key']]={
177
- 'Value': {
178
- 'value': param['value'],
179
- 'uuid': param['uuid'] if param.get('uuid',None) is not None else str(uuid.uuid1()),
180
- 'cmd': 'add',
181
- 'message': param.get('message') if param.get('message',None) is not None else{
182
- 'log': param.get('log') if param.get('log',None) is not None else '值变化到 '+str(param['value']),
183
- },
184
- }
185
- }
186
- self._writeEvent('time',eventTime,eventTimeType,{'para': para})
187
- pass
188
-
189
- def monitor(self,monitorParam,eventTime='-1',eventTimeType='1'):
190
-
191
- if type(monitorParam) is not list:
192
- monitorParam=[monitorParam]
193
- para={}
194
- for param in monitorParam:
195
- para[param['key']]={
196
- 'a': {
197
- 'uuid':param['uuid'] if param.get('uuid',None) is not None else str(uuid.uuid1()),
198
- 'function':param['function'],
199
- 'cmd':'add',
200
- 'period':param['period'],
201
- 'value':param['value'],
202
- 'key':param['key'],
203
- 'freq':param['freq'],
204
- 'condition':param['condition'],
205
- 'cycle':param['cycle'],
206
- 'nCount':param['nCount'],
207
- 'message': param.get('message') if param.get('message',None) is not None else{
208
- 'log': param.get('log') if param.get('log',None) is not None else '消息达到阈值 '+str(param['value']),
209
- },
210
- }
211
- }
212
- self._writeEvent('time',eventTime,eventTimeType,{'para': para})
213
-
214
- pass
@@ -1,5 +0,0 @@
1
- from .IESView import IESView
2
-
3
-
4
- class IESLabSimulationView(IESView):
5
- pass
@@ -1,136 +0,0 @@
1
- from .IESView import IESView
2
- import re
3
- import copy
4
- class IESLabTypicalDayView(IESView):
5
-
6
- def __init__(self, *args, **kwargs):
7
- """
8
- 初始化
9
- """
10
- IESView.__init__(self, *args, **kwargs)
11
- self.__plotIndex = 0
12
- self.__typicalIndex = 0
13
- self.__type_list =['电负荷', '热负荷','冷负荷','总辐射','散射辐射', '直射辐射', '天顶角', '环境温度', '土壤温度', '10m风速', '50m风速', '建筑物高度风速', '风机高度风速']
14
- self.result = {'TypicalMonth': [],'TypicalDay': []}
15
- for i in range(12):
16
- self.result['TypicalMonth'].append({'月份': int, '持续天数': [],'电负荷': [], '热负荷': [],'冷负荷':[],'总辐射': [],'直射辐射': [],'散射辐射': [],'天顶角': [],
17
- '环境温度': [], '土壤温度': [], '建筑物高度风速': [], '风机高度风速': [],'10m风速': [], '50m风速': [] })
18
- def __readPlotResult(self):
19
- length = self.getMessageLength()
20
- if (length > self.__plotIndex):
21
- for num in range(self.__plotIndex, length):# update TypicalMonth
22
- val = self.getMessage(num)
23
- if val['type'] == 'plot':
24
- key_list = re.split('-month',val['key'])#分别为类型和月份
25
- # print(key_list)
26
- self.result['TypicalMonth'][int(key_list[1])-1]['月份'] = int(key_list[1])
27
- if key_list[0] in ['总辐射','散射辐射']:#从第一类数据中分析每个月各个典型日的天数
28
- typicalNum = len(val['data']['traces'])
29
- for i in range(typicalNum):
30
- self.result['TypicalMonth'][int(key_list[1])-1]['持续天数'].append(int(re.findall('\d+',val['data']['traces'][i]['name'])[1]))
31
- # 每个月各类型数据的各个典型日的数据,由于部分月份可能没有电冷热负荷,某月的某个典型日可能缺少冷热负荷
32
- for i in range(typicalNum):
33
- self.result['TypicalMonth'][int(key_list[1])-1][key_list[0]].append([])
34
- for i in range(len(val['data']['traces'])):
35
- self.result['TypicalMonth'][int(key_list[1])-1][key_list[0]][int(re.findall('\d+',val['data']['traces'][i]['name'])[0])-1] = copy.deepcopy(val['data']['traces'][i]['y'])
36
- self.__plotIndex = length
37
- # update TypicalDay based on TypicalMonth
38
- for m in range(12):
39
- for i in range(len(self.result['TypicalMonth'][m]['持续天数'])):
40
- self.result['TypicalDay'].append({'info':{'typicalDayID': int, 'name': str, 'duration': int, 'maxElectricalLoad': 0.0, 'maxHeatLoad': 0.0, 'maxCoolLoad': 0.0},
41
- 'data': {'电负荷': [], '热负荷': [],'冷负荷':[],'总辐射': [],'直射辐射': [],'散射辐射': [],'天顶角': [],
42
- '环境温度': [], '土壤温度': [], '建筑物高度风速': [], '风机高度风速': [],'10m风速': [], '50m风速': []}})
43
- self.result['TypicalDay'][-1]['info']['typicalDayID'] = self.__typicalIndex
44
- self.result['TypicalDay'][-1]['info']['name'] = str(m+1) + '月典型日' + str(i+1)
45
- self.result['TypicalDay'][-1]['info']['duration'] = self.result['TypicalMonth'][m]['持续天数'][i]
46
- if self.result['TypicalMonth'][m]['电负荷']:
47
- if self.result['TypicalMonth'][m]['电负荷'][i]:
48
- self.result['TypicalDay'][-1]['info']['maxElectricalLoad'] = max(self.result['TypicalMonth'][m]['电负荷'][i])
49
- if self.result['TypicalMonth'][m]['热负荷']:
50
- if self.result['TypicalMonth'][m]['热负荷'][i]:
51
- self.result['TypicalDay'][-1]['info']['maxHeatLoad'] = max(self.result['TypicalMonth'][m]['热负荷'][i])
52
- if self.result['TypicalMonth'][m]['冷负荷']:
53
- if self.result['TypicalMonth'][m]['冷负荷'][i]:
54
- self.result['TypicalDay'][-1]['info']['maxCoolLoad'] = max(self.result['TypicalMonth'][m]['冷负荷'][i])
55
- for type_i in self.__type_list:
56
- if self.result['TypicalMonth'][m][type_i]:
57
- self.result['TypicalDay'][-1]['data'][type_i] = self.result['TypicalMonth'][m][type_i][i]
58
- self.__typicalIndex += 1
59
- def GetTypical(self):
60
- '''
61
- 获取所有的 GetTypical 典型日数据
62
-
63
- >>> result.GetTypical()
64
- {...}
65
- '''
66
- self.__readPlotResult()
67
- return self.result['TypicalDay']
68
- def GetTypicalDayNum(self):
69
- '''
70
- 获取当前result的典型日数量
71
-
72
- :return: int类型,代表典型日数量
73
- '''
74
-
75
- self.__readPlotResult()
76
- return self.__typicalIndex
77
- def GetTypicalDayInfo(self,dayID):
78
- '''
79
- 获取dayID对应典型日的基础信息
80
-
81
- :params: dayID int类型,表示典型日的ID,数值位于 0~典型日数量 之间
82
-
83
- :return: dict类型,代表典型日的基础信息,包括典型日所代表的日期范围、典型日的名称等
84
- '''
85
- self.__readPlotResult()
86
- return self.result['TypicalDay'][dayID].get('info','没有该数据')
87
-
88
- def GetTypicalDayCurve(self,dayID, dataType):
89
- '''
90
- 获取dayID对应典型日下dataType参数的时序曲线
91
-
92
- :params: dayID int类型,表示典型日的ID,数值位于 0~典型日数量 之间
93
- :params: dataType enum类型,标识辐照强度、环境温度、土壤温度、建筑物高度风速、风机高度风速、电负荷、热负荷、冷负荷的参数类型
94
-
95
- :return: list<float>类型,代表以1h为时间间隔的该参数的日内时序曲线
96
- '''
97
- self.__readPlotResult()
98
- return self.result['TypicalDay'][dayID]['data'].get(dataType,'没有该类型数据')
99
-
100
- def GetTypicalMonth(self):
101
- '''
102
- 获取所有的 GetTypicalMonth 数据
103
-
104
- >>> result.GetTypicalMonth()
105
-
106
- :return: list<dict>类型,代表各月各类型的典型日数据
107
- '''
108
- self.__readPlotResult()
109
- return self.result['TypicalMonth']
110
-
111
- def GetTypicalMonthNum(self,monthID):
112
- '''
113
- 获取第monthID月各类型的典型日数据
114
-
115
- >>> result.GetTypicalMonthNum()
116
-
117
- :params: monthID int类型,表示典型月的ID,数值位于 1-12 之间
118
-
119
- :return: dict类型,代表第monthID月各类型的典型日数据
120
- {...}
121
- '''
122
- self.__readPlotResult()
123
- return self.result['TypicalMonth'][monthID-1]
124
-
125
-
126
- def GetTypicalMonthCurve(self,monthID, dataType):
127
- '''
128
- 获取dayID对应典型日下dataType参数的时序曲线
129
-
130
- :params: monthID int类型,表示典型月的ID,数值位于 1-12 之间
131
- :params: dataType enum类型,标识总辐射、环境温度、土壤温度、建筑物高度风速、风机高度风速、电负荷、热负荷、冷负荷的参数类型
132
-
133
- :return: list<list>类型,代表以1h为时间间隔的该参数的典型日内时序曲线
134
- '''
135
- self.__readPlotResult()
136
- return self.result['TypicalMonth'][monthID-1].get(dataType,'没有该类型数据')