cloudpss 3.1.3__py3-none-any.whl → 3.1.3b1__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.
@@ -14,6 +14,7 @@ class IESLabPlanModel(object):
14
14
  '''
15
15
  self.simulationId = simulationId
16
16
  self.optimizationInfo = self.GetOptimizationInfo()
17
+ self.OptimizationMode = OptimizationMode
17
18
 
18
19
  def _fetchItemData(self, url):
19
20
  '''
@@ -46,9 +47,9 @@ class IESLabPlanModel(object):
46
47
  设置当前算例的优化目标
47
48
 
48
49
  :param optType: enum 类型,代表经济性优化和环保性优化的类型
49
- :return: bool 类型,代表参数设置是否成功
50
50
  '''
51
51
  self.optimizationInfo = optType
52
+ return True
52
53
 
53
54
  def run(self) -> Runner[IESLabPlanResult]:
54
55
  '''
@@ -87,8 +88,8 @@ class IESLabPlanModel(object):
87
88
 
88
89
 
89
90
  # def GetTaskResult(self):
90
- # return IESLabPlanResult(self.simulationId)
91
- @unique
91
+ # # return IESLabPlanResult(self.simulationId)
92
+ # @unique
92
93
  class OptimizationMode(IntEnum):
93
94
  经济性 = 0
94
95
  环保性 = 1
@@ -1,3 +1,4 @@
1
1
  from .IESLabSimulation import IESLabSimulation
2
2
  from .IESLabPlan import IESLabPlan
3
- __all__ = ['IESLabSimulation','IESLabPlan']
3
+ from .PlanModel import OptimizationMode
4
+ __all__ = ['IESLabSimulation','IESLabPlan', 'OptimizationMode']
@@ -112,5 +112,39 @@ JOB_DEFINITIONS = {
112
112
  "SkipPF": "0",
113
113
  "MaxIteration": "30"
114
114
  }
115
+ },
116
+ "iesLoadPrediction": {
117
+ "name": "负荷预测方案 1",
118
+ "rid": "job-definition/ies/ies-load-prediction",
119
+ "arcs": {
120
+ "startTime": "2022 -01-01 00:00:00",
121
+ "endTime": "2022 -12-31 23:00:00",
122
+ "layer_forcast": "0",
123
+ "forcast_algorithm": "0",
124
+ "ratio_sub": [],
125
+ "ratio_feeder": [],
126
+ "ratio_trans": []
127
+ }
128
+ },
129
+ "iesPowerFlow": {
130
+ "name": "时序潮流方案 1",
131
+ "rid": "job-definition/ies/ies-power-flow",
132
+ "arcs": {
133
+ "startTime": "2022 -01-01 00:00:00",
134
+ "endTime": "2022 -12-31 23:00:00",
135
+ "solveMethod": "0",
136
+ "maxIteration": "30"
137
+ }
138
+ },
139
+ "iesEnergyStoragePlan": {
140
+ "name": "储能规划方案 1",
141
+ "rid": "job-definition/ies/ies-energy-storage-plan",
142
+ "arcs": {
143
+ "Planyear": "15",
144
+ "NetConfig": [],
145
+ "SourceConfig": [],
146
+ "LoadConfig": []
147
+ }
115
148
  }
149
+
116
150
  }
cloudpss/model/model.py CHANGED
@@ -638,4 +638,79 @@ class Model(object):
638
638
  currentConfig = self.context['currentConfig']
639
639
  config = self.configs[currentConfig]
640
640
  return self.run(job=job, config=config)
641
+
642
+ def runIESLoadPrediction(self,job=None,config=None)->Runner[IESResult]:
643
+ '''
644
+ 运行 负荷预测方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
645
+
646
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
647
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
648
+
649
+ :return: runner Runner[IESResult]
650
+ '''
651
+ if job is None:
652
+ currentJob = self.context['currentJob']
653
+ job = self.jobs[currentJob]
654
+ if job['rid'] != 'job-definition/ies/ies-load-prediction':
655
+ for j in self.jobs:
656
+ if j['rid'] == 'job-definition/ies/ies-load-prediction':
657
+ job = j
658
+ if job is None:
659
+ raise Exception("找不到负荷预测方案内核运行的计算方案")
660
+ if job['rid'] != 'job-definition/ies/ies-load-prediction':
661
+ raise Exception("不是负荷预测方案内核运行生成算法的计算方案")
662
+ if config is None:
663
+ currentConfig = self.context['currentConfig']
664
+ config = self.configs[currentConfig]
665
+ return self.run(job=job, config=config)
666
+
667
+ def runIESPowerFlow(self,job=None,config=None)->Runner[IESResult]:
668
+ '''
669
+ 运行 时序潮流方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
670
+
671
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
672
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
673
+
674
+ :return: runner Runner[IESResult]
675
+ '''
676
+ if job is None:
677
+ currentJob = self.context['currentJob']
678
+ job = self.jobs[currentJob]
679
+ if job['rid'] != 'job-definition/ies/ies-power-flow':
680
+ for j in self.jobs:
681
+ if j['rid'] == 'job-definition/ies/ies-power-flow':
682
+ job = j
683
+ if job is None:
684
+ raise Exception("找不到时序潮流方案内核运行的计算方案")
685
+ if job['rid'] != 'job-definition/ies/ies-power-flow':
686
+ raise Exception("不是时序潮流方案内核运行生成算法的计算方案")
687
+ if config is None:
688
+ currentConfig = self.context['currentConfig']
689
+ config = self.configs[currentConfig]
690
+ return self.run(job=job, config=config)
691
+
692
+ def runIESEnergyStoragePlan(self,job=None,config=None)->Runner[IESResult]:
693
+ '''
694
+ 运行 储能规划方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
695
+
696
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
697
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
698
+
699
+ :return: runner Runner[IESResult]
700
+ '''
701
+ if job is None:
702
+ currentJob = self.context['currentJob']
703
+ job = self.jobs[currentJob]
704
+ if job['rid'] != 'job-definition/ies/ies-energy-storage-plan':
705
+ for j in self.jobs:
706
+ if j['rid'] == 'job-definition/ies/ies-energy-storage-plan':
707
+ job = j
708
+ if job is None:
709
+ raise Exception("找不到储能规划方案内核运行的计算方案")
710
+ if job['rid'] != 'job-definition/ies/ies-energy-storage-plan':
711
+ raise Exception("不是储能规划方案内核运行生成算法的计算方案")
712
+ if config is None:
713
+ currentConfig = self.context['currentConfig']
714
+ config = self.configs[currentConfig]
715
+ return self.run(job=job, config=config)
641
716
 
@@ -52,18 +52,20 @@ class IESLabEvaluationResult(object):
52
52
 
53
53
  :return: boolean 类型
54
54
  '''
55
- result = None
56
- if self.cmdType is None:
57
- result = self.GetOverviewResult()
58
- elif self.cmdType == 'energyEvaluation':
59
- result = self.GetEnergyEvaluationResult()
60
- elif self.cmdType == 'environmentalEvaluation':
61
- result = self.GetEnvironmentalEvaluationResult()
62
- if result is None:
55
+ # 定义一个字典,把命令类型映射到相应的方法
56
+ cmd_dict = {
57
+ None: self.GetOverviewResult,
58
+ 'energyEvaluation': self.GetEnergyEvaluationResult,
59
+ 'environmentalEvaluation': self.GetEnvironmentalEvaluationResult
60
+ }
61
+ # 从字典中获取对应的方法,如果没有找到,就抛出一个异常或返回False
62
+ result = cmd_dict.get(self.cmdType, lambda x: None)(self.planId)
63
+ if result is None or type(result) is list:
63
64
  return False
64
65
  return True
65
66
 
66
- def GetFinancialResult(self, resultType):
67
+
68
+ def GetFinancialResult(self, resultType, planID):
67
69
  '''
68
70
  获取planID对应的优化方案下resultType财务评估结果
69
71
 
@@ -76,16 +78,17 @@ class IESLabEvaluationResult(object):
76
78
  assert (resultType in self._kindNameMap), "数据类型不存在"
77
79
  kind = self._kindNameMap.get(resultType, resultType)
78
80
  url = self._baseUri + kind
79
- list = self._fetchItemData(url, self.planId)
81
+ list = self._fetchItemData(url, planID)
80
82
  dict_result = dict()
81
83
  for val in list['results']:
82
84
  for k, v in val.items():
83
85
  dict_result[k] = v
84
86
  return dict_result['data']
85
87
 
86
- def GetOverviewResult(self):
88
+ def GetOverviewResult(self, planID):
87
89
  '''
88
90
  获取当前结果类对应的优化方案下的概览结果
91
+ :param planID int 类型,表示优化方案的ID,数值位于0~优化方案数量之间
89
92
 
90
93
  :return: array类型,代表该方案对应的概览结果
91
94
  '''
@@ -93,17 +96,18 @@ class IESLabEvaluationResult(object):
93
96
  "api/ieslab-plan/taskmanager/getOverviewResult",
94
97
  params={
95
98
  "simu_id": self.simulationId,
96
- "planId": self.planId,
99
+ "planId": planID,
97
100
  "time": self.timeId
98
101
  })
99
102
  result = json.loads(r.text)
100
- if len(result['results']) > 0:
103
+ if len(result['results']) > 0 and len(result['results'][0]['data']) > 0:
101
104
  return result['results'][0]['data']
102
- return None
105
+ return []
103
106
 
104
- def GetEnergyEvaluationResult(self):
107
+ def GetEnergyEvaluationResult(self, planID):
105
108
  '''
106
109
  获取当前结果类对应的优化方案下的能效评价
110
+ :param planID int 类型,表示优化方案的ID,数值位于0~优化方案数量之间
107
111
 
108
112
  :return: array类型,代表该方案对应的能效评价结果
109
113
  '''
@@ -111,17 +115,18 @@ class IESLabEvaluationResult(object):
111
115
  "api/ieslab-plan/taskmanager/getEnergyEvaluation",
112
116
  params={
113
117
  "simu_id": self.simulationId,
114
- "planId": self.planId,
118
+ "planId": planID,
115
119
  "time": self.timeId
116
120
  })
117
121
  result = json.loads(r.text)
118
- if len(result['results']) > 0:
122
+ if len(result['results']) > 0 and len(result['results'][0]['data']) > 0:
119
123
  return result['results'][0]['data']
120
- return None
124
+ return []
121
125
 
122
- def GetEnvironmentalEvaluationResult(self):
126
+ def GetEnvironmentalEvaluationResult(self, planID):
123
127
  '''
124
128
  获取当前结果类对应的优化方案下的环保评价
129
+ :param planID int 类型,表示优化方案的ID,数值位于0~优化方案数量之间
125
130
 
126
131
  :return: array类型,代表该方案对应的环保评价结果
127
132
  '''
@@ -129,10 +134,10 @@ class IESLabEvaluationResult(object):
129
134
  "api/ieslab-plan/taskmanager/getEnvironmentalEvaluation",
130
135
  params={
131
136
  "simu_id": self.simulationId,
132
- "planId": self.planId,
137
+ "planId": planID,
133
138
  "time": self.timeId
134
139
  })
135
140
  result = json.loads(r.text)
136
- if len(result['results']) > 0:
141
+ if len(result['results']) > 0 and len(result['results'][0]['data']) > 0:
137
142
  return result['results'][0]['data']
138
- return None
143
+ return []
@@ -68,6 +68,30 @@ class IESLabPlanResult(object):
68
68
  result = json.loads(r.text)
69
69
  return len(result['data'])
70
70
 
71
+ def GetPlanInfo(self, planID):
72
+ '''
73
+ 获取planID对应的优化方案的基础信息
74
+
75
+ :param: planID int类型,表示优化方案的ID,数值位于 0~优化方案数量 之间
76
+
77
+ :return: dict类型,代表该方案的基础信息,包括投资、运行成本、负荷总量等信息
78
+ '''
79
+ if self.taskId is None:
80
+ raise Exception('未开始运行')
81
+ r = request('GET',
82
+ 'api/ieslab-plan/taskmanager/getOptimizationResult',
83
+ params={
84
+ 'simuid': self.simulationId,
85
+ 'taskid': self.taskId,
86
+ 'resultType': 0
87
+ })
88
+ data = json.loads(r.text).get('data', [])
89
+ result = data[planID].get('data', {}).get('data', [])[0]
90
+ header = data[planID].get('data', {}).get('headerDesc', [])
91
+ dict_result = {val.get('hearderName', ''): result.get(val.get('key', ''), '') for val in header}
92
+ return dict_result
93
+
94
+
71
95
  def GetPlanConfiguration(self, planID):
72
96
  '''
73
97
  获取planID对应的优化方案的配置信息
@@ -91,7 +115,6 @@ class IESLabPlanResult(object):
91
115
  result = {}
92
116
  for val in d['data']:
93
117
  result[val['u_name']] = val['data']['data']
94
-
95
118
  return result
96
119
 
97
120
  def GetComponentResult(self, planID, componentID, typicalDayName=''):
@@ -0,0 +1,193 @@
1
+ import os
2
+ from urllib.parse import urlparse
3
+ import requests
4
+ import websocket
5
+ import datetime
6
+ import pytz
7
+ utc_tz = pytz.timezone('UTC')
8
+
9
+ from ..utils.IO import IO
10
+
11
+
12
+ class Message(object):
13
+
14
+ def __init__(self, id, token):
15
+ self.id = id
16
+ self.token = token
17
+
18
+
19
+ class MessageStreamReceiver(object):
20
+ """消息流读取函数结果"""
21
+
22
+ def __init__(self, id, db):
23
+ self.origin = os.environ.get('CLOUDPSS_API_URL',
24
+ 'https://cloudpss.net/')
25
+ self.id = id
26
+ self.db = db
27
+ self._status = 0
28
+ self.error = None
29
+ self.isOpen = False
30
+
31
+ def create(self, type, comment=None, durability=1):
32
+ """
33
+ 创建消息流
34
+ type: 消息流类型 'object' or 'binary'
35
+ comment: 消息流描述
36
+ durability: 消息流的数据将在多少天后被删除,其取值范围从 0 ~ MAX_DURABILITY
37
+ MAX_DURABILITY 默认为20
38
+ """
39
+ param = {}
40
+ if type != 'object' and type != 'binary':
41
+ raise Exception('type must be object or binary')
42
+ param['type'] = type
43
+ param['comment'] = comment
44
+ param['durability'] = durability
45
+ r = requests.post(self.origin + 'api/streams', json=param)
46
+ r.raise_for_status()
47
+ res = r.json()
48
+ print(res)
49
+ message = Message(res['id'], res['token'])
50
+ return message
51
+
52
+ def createBulk(self, param):
53
+ """
54
+ 批量创建消息流
55
+ param: [{ "type": "{{type}}", "comment": "{{comment}}" , "durability": {{durability}}, "volume": {{volume}} }, ... ]
56
+ type: 消息流类型 'object' or 'binary'
57
+ comment: 消息流描述
58
+ durability: 消息流的数据将在多少天后被删除,其取值范围从 0 ~ MAX_DURABILITY
59
+ MAX_DURABILITY 默认为20
60
+
61
+ 状态码说明:
62
+ 201 返回流信息数组
63
+ 400 不支持的 type,或其他输入错误
64
+ """
65
+ r = requests.post(self.origin + 'api/streams/bulk', json=param)
66
+ r.raise_for_status()
67
+ res = r.json()
68
+ messages = []
69
+ for item in res:
70
+ message = Message(item['id'], item['token'])
71
+ messages.append(message)
72
+ return messages
73
+
74
+ def info(self, id):
75
+ """
76
+ 获取消息流信息
77
+ """
78
+ if id is None:
79
+ raise Exception('id is None')
80
+ r = requests.get(self.origin + 'api/streams/id/' + id + '/info')
81
+ r.raise_for_status()
82
+ return r.json()
83
+
84
+ def infoByToken(self, token):
85
+ """
86
+ 获取消息流信息
87
+ 相较于id获取消息流信息,token能够额外获取到handler的信息
88
+ """
89
+ if token is None:
90
+ raise Exception('token is None')
91
+ r = requests.get(self.origin + 'api/streams/token/' + token + '/info')
92
+ r.raise_for_status()
93
+ return r.json()
94
+
95
+ def freeze(self, token):
96
+ """
97
+ 冻结消息流
98
+
99
+ 状态码说明:
100
+ 201 冻结成功
101
+ 204 流已经被冻结
102
+ 409 流正在活动中
103
+ 404 未找到对应流
104
+ """
105
+ if token is None:
106
+ raise Exception('token is None')
107
+ r = requests.put(self.origin + 'api/streams/token/' + token +
108
+ '/freeze')
109
+ r.raise_for_status()
110
+ return r.status_code
111
+
112
+ def delete(self, token):
113
+ """
114
+ 删除消息流
115
+
116
+ 状态码说明:
117
+ 204 删除成功
118
+ 409 流正在活动中
119
+ 404 未找到对应流
120
+ """
121
+ if token is None:
122
+ raise Exception('token is None')
123
+ r = requests.delete(self.origin + 'api/streams/token/' + token)
124
+ r.raise_for_status()
125
+ return r.status_code
126
+
127
+ def receive(self, id, fr0m, on_open, on_message, on_error, on_close):
128
+ """
129
+ 读取消息流中的数据
130
+ id: 消息流id
131
+ fr0m: 从哪个位置开始读取,如果为0则从头开始读取
132
+ on_open: 连接建立时的回调函数
133
+ on_message: 收到消息时的回调函数
134
+ on_error: 发生错误时的回调函数
135
+ on_close: 连接关闭时的回调函数
136
+ """
137
+ if id is None:
138
+ raise Exception('id is None')
139
+ u = list(urlparse(self.origin))
140
+ head = 'wss' if u[0] == 'https' else 'ws'
141
+
142
+ path = head + '://' + str(u[1]) + '/api/streams/id/' + id
143
+ if fr0m is not None:
144
+ path = path + '&from=' + str(fr0m)
145
+ ws = websocket.WebSocketApp(path,
146
+ on_open=on_open,
147
+ on_message=on_message,
148
+ on_error=on_error,
149
+ on_close=on_close)
150
+ ws.run_forever()
151
+ return ws
152
+
153
+ ###下面是兼容Receiver部分功能实现
154
+ def on_message(self, ws, message):
155
+ data = IO.deserialize(message, 'ubjson')
156
+ msg = IO.deserialize(data['data'], 'ubjson')
157
+ if "when" not in msg:
158
+ msg['when']= datetime.datetime.now()
159
+ self.db.storeMessage(msg)
160
+
161
+ def on_error(self, ws, error):
162
+ msg = {
163
+ 'type': 'log',
164
+ 'verb': 'create',
165
+ 'version': 1,
166
+ 'data': {
167
+ 'level': 'error',
168
+ 'content': "websocket error",
169
+ },
170
+ }
171
+ self.db.storeMessage(msg)
172
+ self.error = error
173
+ self._status = -1
174
+
175
+
176
+ def on_close(self, ws,*args,**kwargs):
177
+ self.db.finished = datetime.datetime.now(tz=utc_tz).isoformat()
178
+ self._status = 1
179
+
180
+ def on_open(self, ws):
181
+ self.isOpen = True
182
+
183
+ def close(self, ws):
184
+ ws.close()
185
+
186
+ def status(self):
187
+ return self._status
188
+
189
+ def connect(self):
190
+ self._status = 0
191
+ self.ws = self.receive(self.id, None, self.on_open, self.on_message, self.on_error, self.on_close)
192
+
193
+
cloudpss/runner/result.py CHANGED
@@ -335,7 +335,7 @@ class IESResult(Result):
335
335
  获取元件ID为compID的元件,对应标签为labelName、图例名称为traceName的plot 数据的第index项
336
336
 
337
337
  :params: compID string类型,代表元件的标识符
338
- :params: lableName string类型,代表plot曲线的分组标签
338
+ :params: labelName string类型,代表plot曲线的分组标签
339
339
  :params: traceName string类型,代表Plot曲线对应分组下的图例名称,当为'all'时,返回所有图例的数据
340
340
  :params: index int类型,代表对应图例时序数据中的第index项,当小于0时,返回该图例所有的时序数据
341
341
 
cloudpss/runner/runner.py CHANGED
@@ -22,6 +22,7 @@ IES_LAB_RESULT = {
22
22
  'function/ieslab/plan': IESLabPlanResult,
23
23
  'function/ieslab/evaluation': IESLabEvaluationResult
24
24
  }
25
+
25
26
  RESULT_DB = {
26
27
  'job-definition/cloudpss/emtp': EMTResult,
27
28
  'job-definition/cloudpss/emtps': EMTResult,
@@ -29,6 +30,8 @@ RESULT_DB = {
29
30
  'job-definition/cloudpss/power-flow': PowerFlowResult,
30
31
  'job-definition/cloudpss/ies-simulation': IESResult,
31
32
  'job-definition/cloudpss/ies-optimization': IESResult,
33
+ # 'job-definition/ies/ies-simulation': IESResult,
34
+ 'job-definition/ies/ies-optimization': IESResult,
32
35
  'job-definition/cloudpss/three-phase-powerFlow': PowerFlowResult,
33
36
  'job-definition/ies/ies-simulation': IESLabSimulationResult,
34
37
  'job-definition/ies/ies-gmm':IESLabTypicalDayResult,
@@ -36,11 +39,9 @@ RESULT_DB = {
36
39
  'job-definition/cloudpss/ieslab-gmm':IESLabTypicalDayResult,
37
40
  }
38
41
 
39
-
40
42
  class Runner(Generic[T]):
41
43
  def __init__(self, taskId, name, job, config, revision, modelRid,
42
44
  **kwargs):
43
-
44
45
  self.taskId = taskId
45
46
  self.db = Storage(taskId, name, job, config, revision, modelRid)
46
47
  result = RESULT_DB.get(job['rid'], Result)
@@ -143,4 +144,3 @@ class HttpRunner(Runner[T]):
143
144
  if self.__taskId is None:
144
145
  return False
145
146
  return self.result.status() # type: ignore
146
- pass