cloudpss 4.0.0a7__py3-none-any.whl → 4.0.2__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.
- cloudpss/dslab/dataManageModel.py +13 -2
- cloudpss/dslab/dslab.py +65 -0
- cloudpss/job/__init__.py +5 -0
- cloudpss/job/job.py +277 -0
- cloudpss/job/jobMachine.py +11 -0
- cloudpss/job/jobPolicy.py +129 -0
- cloudpss/job/jobQueue.py +14 -0
- cloudpss/job/jobReceiver.py +33 -0
- cloudpss/job/jobTres.py +6 -0
- cloudpss/job/messageStreamReceiver.py +120 -0
- cloudpss/job/messageStreamSender.py +74 -0
- cloudpss/job/view/EMTView.py +216 -0
- cloudpss/job/view/IESLabSimulationView.py +5 -0
- cloudpss/job/view/IESLabTypicalDayView.py +27 -0
- cloudpss/job/view/IESView.py +103 -0
- cloudpss/job/view/PowerFlowView.py +80 -0
- cloudpss/job/view/__init__.py +42 -0
- cloudpss/job/view/view.py +122 -0
- cloudpss/utils/IO.py +18 -7
- cloudpss/utils/httprequests.py +1 -1
- cloudpss/version.py +1 -1
- {cloudpss-4.0.0a7.dist-info → cloudpss-4.0.2.dist-info}/METADATA +1 -1
- {cloudpss-4.0.0a7.dist-info → cloudpss-4.0.2.dist-info}/RECORD +25 -9
- {cloudpss-4.0.0a7.dist-info → cloudpss-4.0.2.dist-info}/WHEEL +0 -0
- {cloudpss-4.0.0a7.dist-info → cloudpss-4.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,120 @@
|
|
1
|
+
import logging
|
2
|
+
from .jobReceiver import JobReceiver
|
3
|
+
import os
|
4
|
+
from urllib.parse import urlparse
|
5
|
+
import websocket
|
6
|
+
import pytz
|
7
|
+
import threading
|
8
|
+
import time
|
9
|
+
utc_tz = pytz.timezone('UTC')
|
10
|
+
|
11
|
+
from ..utils.IO import IO
|
12
|
+
|
13
|
+
|
14
|
+
class Message(object):
|
15
|
+
|
16
|
+
def __init__(self, id, token):
|
17
|
+
self.id = id
|
18
|
+
self.token = token
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
class MessageStreamReceiver(JobReceiver):
|
23
|
+
|
24
|
+
def __init__(self, job, dev=False):
|
25
|
+
super().__init__()
|
26
|
+
self.job = job
|
27
|
+
self.dev = dev
|
28
|
+
self.origin = os.environ.get('CLOUDPSS_API_URL',
|
29
|
+
'https://cloudpss.net/')
|
30
|
+
self.__hasOpen=False
|
31
|
+
|
32
|
+
def receive(self, id, fr0m, on_open, on_message, on_error, on_close):
|
33
|
+
"""
|
34
|
+
读取消息流中的数据
|
35
|
+
id: 消息流id
|
36
|
+
fr0m: 从哪个位置开始读取,如果为0则从头开始读取
|
37
|
+
on_open: 连接建立时的回调函数
|
38
|
+
on_message: 收到消息时的回调函数
|
39
|
+
on_error: 发生错误时的回调函数
|
40
|
+
on_close: 连接关闭时的回调函数
|
41
|
+
"""
|
42
|
+
if id is None:
|
43
|
+
raise Exception('id is None')
|
44
|
+
u = list(urlparse(self.origin))
|
45
|
+
head = 'wss' if u[0] == 'https' else 'ws'
|
46
|
+
|
47
|
+
path = head + '://' + str(u[1]) + '/api/streams/id/' + id
|
48
|
+
if fr0m is not None:
|
49
|
+
path = path + '&from=' + str(fr0m)
|
50
|
+
logging.info(f"receive data from websocket: {path}")
|
51
|
+
ws = websocket.WebSocketApp(path,
|
52
|
+
on_open=on_open,
|
53
|
+
on_message=on_message,
|
54
|
+
on_error=on_error,
|
55
|
+
on_close=on_close)
|
56
|
+
|
57
|
+
return ws
|
58
|
+
|
59
|
+
###下面是兼容Receiver部分功能实现
|
60
|
+
|
61
|
+
def on_message(self, ws, message):
|
62
|
+
data = IO.deserialize(message, 'ubjson')
|
63
|
+
msg = IO.deserialize(data['data'], 'ubjson')
|
64
|
+
if msg.get('type', None) == 'log' and self.dev:
|
65
|
+
print(msg)
|
66
|
+
self.messages.append(msg)
|
67
|
+
# if msg and type(msg) is dict and msg.get('type', None) == 'terminate':
|
68
|
+
# self.close(ws)
|
69
|
+
|
70
|
+
def on_error(self, ws, error):
|
71
|
+
logging.info("MessageStreamReceiver error")
|
72
|
+
msg = {
|
73
|
+
'type': 'log',
|
74
|
+
'verb': 'create',
|
75
|
+
'version': 1,
|
76
|
+
'data': {
|
77
|
+
'level': 'error',
|
78
|
+
'content': "websocket error",
|
79
|
+
},
|
80
|
+
}
|
81
|
+
self.messages.append(msg)
|
82
|
+
|
83
|
+
def on_close(self, *args, **kwargs):
|
84
|
+
logging.info("MessageStreamReceiver close")
|
85
|
+
self._status = 0
|
86
|
+
msg = {
|
87
|
+
'type': 'log',
|
88
|
+
'verb': 'create',
|
89
|
+
'version': 1,
|
90
|
+
'data': {
|
91
|
+
'level': 'error',
|
92
|
+
'content': "websocket closed",
|
93
|
+
},
|
94
|
+
}
|
95
|
+
self.messages.append(msg)
|
96
|
+
|
97
|
+
def on_open(self, ws):
|
98
|
+
self._status = 1
|
99
|
+
self.__hasOpen=True
|
100
|
+
pass
|
101
|
+
|
102
|
+
def close(self, ws):
|
103
|
+
self._status = 0
|
104
|
+
ws.close()
|
105
|
+
|
106
|
+
@property
|
107
|
+
def end(self):
|
108
|
+
return not self._status
|
109
|
+
|
110
|
+
def connect(self):
|
111
|
+
self._status = 0
|
112
|
+
self.ws = self.receive(self.job.output, None, self.on_open,
|
113
|
+
self.on_message, self.on_error, self.on_close)
|
114
|
+
|
115
|
+
|
116
|
+
thread = threading.Thread(target=self.ws.run_forever, args=(None , None , 6, 3))
|
117
|
+
thread.setDaemon(True)
|
118
|
+
thread.start()
|
119
|
+
while not self.__hasOpen:
|
120
|
+
time.sleep(0.2)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import sys,os
|
2
|
+
import threading
|
3
|
+
from urllib.parse import urlparse
|
4
|
+
sys.path.append(os.path.join(os.path.dirname(__file__), '../'))
|
5
|
+
|
6
|
+
import websocket
|
7
|
+
|
8
|
+
from cloudpss.utils.IO import IO
|
9
|
+
import time
|
10
|
+
import logging
|
11
|
+
|
12
|
+
class MessageStreamSender():
|
13
|
+
|
14
|
+
def __init__(self, job, dev=False):
|
15
|
+
super().__init__()
|
16
|
+
self.job = job
|
17
|
+
self.dev = dev
|
18
|
+
self.origin = os.environ.get('CLOUDPSS_API_URL',
|
19
|
+
'https://cloudpss.net/')
|
20
|
+
|
21
|
+
###下面是兼容Receiver部分功能实现
|
22
|
+
|
23
|
+
def on_message(self, ws, message):
|
24
|
+
logging.info('on_message',message)
|
25
|
+
|
26
|
+
def on_error(self, ws, error):
|
27
|
+
logging.info('on_error')
|
28
|
+
|
29
|
+
def on_close(self, *args, **kwargs):
|
30
|
+
time.sleep(0.5)
|
31
|
+
self._status = 0
|
32
|
+
|
33
|
+
logging.info('on_close')
|
34
|
+
|
35
|
+
def on_open(self, ws):
|
36
|
+
self._status = 1
|
37
|
+
logging.info('on_open')
|
38
|
+
pass
|
39
|
+
|
40
|
+
def close(self):
|
41
|
+
|
42
|
+
self._status = 0
|
43
|
+
self.ws.close()
|
44
|
+
|
45
|
+
@property
|
46
|
+
def status(self):
|
47
|
+
return self._status
|
48
|
+
|
49
|
+
def write(self, message):
|
50
|
+
data = IO.serialize(message, 'ubjson',None)
|
51
|
+
self.ws.send(data, websocket.ABNF.OPCODE_BINARY)
|
52
|
+
|
53
|
+
def connect(self):
|
54
|
+
logging.info('connect')
|
55
|
+
self._status = 0
|
56
|
+
if self.job.input is None:
|
57
|
+
raise Exception('id is None')
|
58
|
+
u = list(urlparse(self.origin))
|
59
|
+
head = 'wss' if u[0] == 'https' else 'ws'
|
60
|
+
|
61
|
+
path = head + '://' + str(u[1]) + '/api/streams/token/' + self.job.input
|
62
|
+
logging.info(f"receive data from websocket: {path}")
|
63
|
+
|
64
|
+
self.ws = websocket.WebSocketApp(path,
|
65
|
+
on_open=self.on_open,
|
66
|
+
on_message=self.on_message,
|
67
|
+
on_error=self.on_error,
|
68
|
+
on_close=self.on_close)
|
69
|
+
|
70
|
+
thread = threading.Thread(target=self.ws.run_forever, args=(None , None , 6, 3))
|
71
|
+
thread.setDaemon(True)
|
72
|
+
thread.start()
|
73
|
+
while self.status != 1:
|
74
|
+
time.sleep(0.2)
|
@@ -0,0 +1,216 @@
|
|
1
|
+
import copy
|
2
|
+
import uuid
|
3
|
+
|
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
|
+
def writeShm(self,path,buffer,offset):
|
104
|
+
"""
|
105
|
+
写内存接口
|
106
|
+
"""
|
107
|
+
if self._sender is not None:
|
108
|
+
self._sender.write({'type': 'memory', 'path': path,'value':buffer,'offset':offset})
|
109
|
+
else:
|
110
|
+
raise Exception('transmitter is None')
|
111
|
+
|
112
|
+
def _writeEvent(self,eventType,eventTime,eventTimeType,defaultApp):
|
113
|
+
if self._sender is None:
|
114
|
+
raise Exception('transmitter is None')
|
115
|
+
event = {
|
116
|
+
'eventType': eventType,
|
117
|
+
'eventTime': eventTime,
|
118
|
+
'eventTimeType':eventTimeType,
|
119
|
+
"defaultApp": defaultApp
|
120
|
+
}
|
121
|
+
self._sender.write({'type': 'eventchain', 'event': [event]})
|
122
|
+
|
123
|
+
def stopSimulation(self):
|
124
|
+
"""
|
125
|
+
停止仿真
|
126
|
+
"""
|
127
|
+
param = {
|
128
|
+
"ctrl_type": "0",
|
129
|
+
"uuid": str(uuid.uuid1()),
|
130
|
+
'message': {
|
131
|
+
'log': '停止任务 ',
|
132
|
+
}
|
133
|
+
}
|
134
|
+
eventData = {}
|
135
|
+
eventData = {'SimuCtrl': param}
|
136
|
+
|
137
|
+
self._writeEvent('time','-1','1',{'SimuCtrl': eventData})
|
138
|
+
|
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
|
+
|
156
|
+
def saveSnapshot(self,snapshotNumber,log='保存断面成功'):
|
157
|
+
"""
|
158
|
+
通过事件链保存断面
|
159
|
+
"""
|
160
|
+
self._snapshotControl('0',snapshotNumber,log)
|
161
|
+
def loadSnapshot(self,snapshotNumber,log='加载断面成功'):
|
162
|
+
"""
|
163
|
+
通过事件链加载断面
|
164
|
+
"""
|
165
|
+
self._snapshotControl('1',snapshotNumber,log)
|
166
|
+
|
167
|
+
|
168
|
+
def control(self,controlParam,eventTime='-1',eventTimeType='1'):
|
169
|
+
"""
|
170
|
+
控制仿真
|
171
|
+
"""
|
172
|
+
|
173
|
+
if type(controlParam) is not list:
|
174
|
+
controlParam=[controlParam]
|
175
|
+
para={}
|
176
|
+
|
177
|
+
for param in controlParam:
|
178
|
+
para[param['key']]={
|
179
|
+
'Value': {
|
180
|
+
'value': param['value'],
|
181
|
+
'uuid': param['uuid'] if param.get('uuid',None) is not None else str(uuid.uuid1()),
|
182
|
+
'cmd': 'add',
|
183
|
+
'message': param.get('message') if param.get('message',None) is not None else{
|
184
|
+
'log': param.get('log') if param.get('log',None) is not None else '值变化到 '+str(param['value']),
|
185
|
+
},
|
186
|
+
}
|
187
|
+
}
|
188
|
+
self._writeEvent('time',eventTime,eventTimeType,{'para': para})
|
189
|
+
pass
|
190
|
+
|
191
|
+
def monitor(self,monitorParam,eventTime='-1',eventTimeType='1'):
|
192
|
+
|
193
|
+
if type(controlParam) is not list:
|
194
|
+
controlParam=[controlParam]
|
195
|
+
para={}
|
196
|
+
for param in controlParam:
|
197
|
+
para[param['key']]={
|
198
|
+
'a': {
|
199
|
+
'uuid':param['uuid'] if param.get('uuid',None) is not None else str(uuid.uuid1()),
|
200
|
+
'function':param['function'],
|
201
|
+
'cmd':'add',
|
202
|
+
'period':param['period'],
|
203
|
+
'value':param['value'],
|
204
|
+
'key':param['key'],
|
205
|
+
'freq':param['freq'],
|
206
|
+
'condition':param['condition'],
|
207
|
+
'cycle':param['cycle'],
|
208
|
+
'nCount':param['nCount'],
|
209
|
+
'message': param.get('message') if param.get('message',None) is not None else{
|
210
|
+
'log': param.get('log') if param.get('log',None) is not None else '消息达到阈值 '+str(param['value']),
|
211
|
+
},
|
212
|
+
}
|
213
|
+
}
|
214
|
+
self._writeEvent('time',eventTime,eventTimeType,{'para': para})
|
215
|
+
|
216
|
+
pass
|
@@ -0,0 +1,27 @@
|
|
1
|
+
from .IESView import IESView
|
2
|
+
|
3
|
+
class IESLabTypicalDayView(IESView):
|
4
|
+
def GetTypicalDayNum():
|
5
|
+
'''
|
6
|
+
获取当前result的典型日数量
|
7
|
+
|
8
|
+
:return: int类型,代表典型日数量
|
9
|
+
'''
|
10
|
+
def GetTypicalDayInfo(dayID):
|
11
|
+
'''
|
12
|
+
获取dayID对应典型日的基础信息
|
13
|
+
|
14
|
+
:params: dayID int类型,表示典型日的ID,数值位于 0~典型日数量 之间
|
15
|
+
|
16
|
+
:return: dict类型,代表典型日的基础信息,包括典型日所代表的日期范围、典型日的名称等
|
17
|
+
'''
|
18
|
+
def GetTypicalDayCurve(dayID, dataType):
|
19
|
+
'''
|
20
|
+
获取dayID对应典型日下dataType参数的时序曲线
|
21
|
+
|
22
|
+
:params: dayID int类型,表示典型日的ID,数值位于 0~典型日数量 之间
|
23
|
+
:params: dataType enum类型,标识辐照强度、环境温度、土壤温度、建筑物高度风速、风机高度风速、电负荷、热负荷、冷负荷的参数类型
|
24
|
+
|
25
|
+
:return: list<float>类型,代表以1h为时间间隔的该参数的日内时序曲线
|
26
|
+
'''
|
27
|
+
pass
|
@@ -0,0 +1,103 @@
|
|
1
|
+
import copy
|
2
|
+
import collections
|
3
|
+
|
4
|
+
class IESView(object):
|
5
|
+
"""
|
6
|
+
综合能源结果视图,
|
7
|
+
|
8
|
+
提供快捷 plot 数据的接口函数,获取到的 plot 数据为合并后的数据格式,不在是接收时分段的数据
|
9
|
+
|
10
|
+
该类只提供 IES 仿真使用
|
11
|
+
|
12
|
+
"""
|
13
|
+
|
14
|
+
|
15
|
+
def __init__(self,receiver) -> None:
|
16
|
+
|
17
|
+
self.result = {'Sankey': []}
|
18
|
+
self.__receiver = receiver
|
19
|
+
|
20
|
+
|
21
|
+
def __readPlotResult(self):
|
22
|
+
for val in self.__receiver:
|
23
|
+
if val['type'] == 'plot':
|
24
|
+
key = val['key']
|
25
|
+
if key == 'Sankey':
|
26
|
+
self.result['Sankey'].append(copy.deepcopy(val))
|
27
|
+
else:
|
28
|
+
if self.result.get(key, None) is None:
|
29
|
+
self.result[key] = copy.deepcopy(val)
|
30
|
+
else:
|
31
|
+
traces = val['data']['traces']
|
32
|
+
for i in range(len(traces)):
|
33
|
+
v = traces[i]
|
34
|
+
self.result[key]['data']['traces'][i][
|
35
|
+
'x'].extend(v['x'])
|
36
|
+
self.result[key]['data']['traces'][i][
|
37
|
+
'y'].extend(v['y'])
|
38
|
+
|
39
|
+
def getPlotData(self, compID, labelName, traceName='all', index=-1):
|
40
|
+
'''
|
41
|
+
获取元件ID为compID的元件,对应标签为labelName、图例名称为traceName的plot 数据的第index项
|
42
|
+
|
43
|
+
:params: compID string类型,代表元件的标识符
|
44
|
+
:params: labelName string类型,代表plot曲线的分组标签
|
45
|
+
:params: traceName string类型,代表Plot曲线对应分组下的图例名称,当为'all'时,返回所有图例的数据
|
46
|
+
:params: index int类型,代表对应图例时序数据中的第index项,当小于0时,返回该图例所有的时序数据
|
47
|
+
|
48
|
+
:return: dict类型
|
49
|
+
'''
|
50
|
+
self.__readPlotResult()
|
51
|
+
key = compID + '_' + labelName
|
52
|
+
if key not in self.result.keys():
|
53
|
+
raise Exception('未找到元件标志为{0},对应label为{1}的plot数据'.format(
|
54
|
+
compID, labelName))
|
55
|
+
|
56
|
+
traceData = self.result[key]['data']['traces']
|
57
|
+
if traceName != 'all':
|
58
|
+
traceNameList = [traceName]
|
59
|
+
else:
|
60
|
+
traceNameList = [
|
61
|
+
traceData[i]['name'] for i in range(len(traceData))
|
62
|
+
]
|
63
|
+
|
64
|
+
startIndex = 0
|
65
|
+
endIndex = len(traceData[0]['x'])
|
66
|
+
if index >= 0:
|
67
|
+
startIndex = index
|
68
|
+
endIndex = index + 1
|
69
|
+
|
70
|
+
plotData = collections.defaultdict(lambda: {})
|
71
|
+
for tName in traceNameList:
|
72
|
+
for i in range(len(traceData)):
|
73
|
+
dataLen = len(traceData[i]['x'])
|
74
|
+
if traceData[i]['name'] == tName:
|
75
|
+
if endIndex > dataLen:
|
76
|
+
raise Exception('请求的index超过了plot数据序列的长度')
|
77
|
+
plotData[tName]['x'] = traceData[i]['x'][
|
78
|
+
startIndex:endIndex]
|
79
|
+
plotData[tName]['y'] = traceData[i]['y'][
|
80
|
+
startIndex:endIndex]
|
81
|
+
|
82
|
+
return plotData
|
83
|
+
|
84
|
+
|
85
|
+
def getSankey(self, index):
|
86
|
+
'''
|
87
|
+
获取第index个桑基图数据
|
88
|
+
|
89
|
+
>>> result.getSankey(index)
|
90
|
+
{...}
|
91
|
+
'''
|
92
|
+
self.__readPlotResult()
|
93
|
+
if index >= len(self.result['Sankey']):
|
94
|
+
raise Exception('index超过了桑基图数据序列的长度')
|
95
|
+
return self.result['Sankey'][index]
|
96
|
+
def getSankeyNum(self):
|
97
|
+
'''
|
98
|
+
获取桑基图数据序列的长度
|
99
|
+
|
100
|
+
>>> result.getSankeyNum()
|
101
|
+
'''
|
102
|
+
self.__readPlotResult()
|
103
|
+
return len(self.result['Sankey'])
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import copy
|
2
|
+
import re
|
3
|
+
|
4
|
+
from .view import View
|
5
|
+
|
6
|
+
|
7
|
+
class PowerFlowView(View):
|
8
|
+
"""
|
9
|
+
潮流结果视图,
|
10
|
+
|
11
|
+
提供快速获取 buses 和 branches 的接口,并提供潮流写入项目的接口
|
12
|
+
|
13
|
+
该类只提供潮流仿真时使用
|
14
|
+
|
15
|
+
"""
|
16
|
+
|
17
|
+
def getBuses(self):
|
18
|
+
"""
|
19
|
+
获取所有的 buses 数据
|
20
|
+
|
21
|
+
>>> view.getBuses()
|
22
|
+
[...]
|
23
|
+
"""
|
24
|
+
result = []
|
25
|
+
pattern = re.compile("value=\"(.*)\"")
|
26
|
+
data = self.getMessagesByKey('buses-table')
|
27
|
+
if len(data) == 0:
|
28
|
+
return []
|
29
|
+
table = copy.deepcopy(data[0])
|
30
|
+
columns = table['data']['columns']
|
31
|
+
for column in columns:
|
32
|
+
if column['type'] == 'html':
|
33
|
+
data = column['data']
|
34
|
+
for i in range(len(data)):
|
35
|
+
if data[i] != '':
|
36
|
+
s = pattern.findall(data[i])
|
37
|
+
data[i] = s[0].replace('/', '')
|
38
|
+
|
39
|
+
result.append(table)
|
40
|
+
return result
|
41
|
+
|
42
|
+
|
43
|
+
def getBranches(self):
|
44
|
+
"""
|
45
|
+
获取潮流结果 branches 数据
|
46
|
+
|
47
|
+
>>> view.getBranches()
|
48
|
+
[...]
|
49
|
+
"""
|
50
|
+
|
51
|
+
result = []
|
52
|
+
pattern = re.compile("value=\"(.*)\"")
|
53
|
+
data = self.getMessagesByKey('branches-table')
|
54
|
+
if len(data) == 0:
|
55
|
+
return []
|
56
|
+
table = copy.deepcopy(data[0])
|
57
|
+
|
58
|
+
columns = table['data']['columns']
|
59
|
+
for column in columns:
|
60
|
+
if column['type'] == 'html':
|
61
|
+
data = column['data']
|
62
|
+
for i in range(len(data)):
|
63
|
+
if data[i] != '':
|
64
|
+
s = pattern.findall(data[i])
|
65
|
+
data[i] = s[0].replace('/', '')
|
66
|
+
|
67
|
+
result.append(table)
|
68
|
+
return result
|
69
|
+
|
70
|
+
def powerFlowModify(self, model):
|
71
|
+
"""
|
72
|
+
潮流数据写入 model
|
73
|
+
|
74
|
+
>>> view.powerFlowModify(model)
|
75
|
+
"""
|
76
|
+
|
77
|
+
data = self.getMessagesByKey('power-flow-modify')
|
78
|
+
if len(data) == 0:
|
79
|
+
raise Exception('未找到到数据')
|
80
|
+
self.modify(data[0], model)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
from .IESView import IESView
|
2
|
+
from .view import View
|
3
|
+
from .EMTView import EMTView
|
4
|
+
from .PowerFlowView import PowerFlowView
|
5
|
+
from .IESLabSimulationView import IESLabSimulationView
|
6
|
+
from .IESLabTypicalDayView import IESLabTypicalDayView
|
7
|
+
from ..messageStreamReceiver import MessageStreamReceiver
|
8
|
+
from ..messageStreamSender import MessageStreamSender
|
9
|
+
__all__ = [
|
10
|
+
'View','EMTView','PowerFlowView','IESLabSimulationView','IESView','IESLabTypicalDayView'
|
11
|
+
]
|
12
|
+
|
13
|
+
VIEW = {
|
14
|
+
'function/CloudPSS/emtp': EMTView,
|
15
|
+
'function/CloudPSS/emtps': EMTView,
|
16
|
+
'function/CloudPSS/sfemt': EMTView,
|
17
|
+
'function/CloudPSS/power-flow': PowerFlowView,
|
18
|
+
'function/CloudPSS/ies-simulation': IESView,
|
19
|
+
'function/CloudPSS/ies-optimization': IESView,
|
20
|
+
'function/ies/ies-optimization': IESView,
|
21
|
+
'function/CloudPSS/three-phase-powerFlow': PowerFlowView,
|
22
|
+
'function/ies/ies-simulation': IESLabSimulationView,
|
23
|
+
'function/ies/ies-gmm':IESLabTypicalDayView,
|
24
|
+
'function/CloudPSS/ieslab-simulation': IESLabSimulationView,
|
25
|
+
'function/CloudPSS/ieslab-gmm':IESLabTypicalDayView,
|
26
|
+
'function/CloudPSS/ieslab-optimization': IESView,
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
def getViewClass(rid: str) -> View:
|
31
|
+
"""
|
32
|
+
获取仿真结果视图
|
33
|
+
|
34
|
+
:param rid: 仿真任务的 rid
|
35
|
+
:param db: 仿真任务的数据库
|
36
|
+
|
37
|
+
:return: 仿真结果视图
|
38
|
+
|
39
|
+
>>> view = get_view('function/CloudPSS/emtp', db)
|
40
|
+
>>> view.getPlots()
|
41
|
+
"""
|
42
|
+
return VIEW.get(rid, View)
|