cpWindSpeedAnalyst.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import os
  2. import pandas as pd
  3. import plotly.graph_objects as go
  4. from algorithmContract.confBusiness import *
  5. from algorithmContract.contract import Contract
  6. from behavior.analystWithGoodPoint import AnalystWithGoodPoint
  7. class CpWindSpeedAnalyst(AnalystWithGoodPoint):
  8. """
  9. 风电机组风能利用系数分析
  10. """
  11. def typeAnalyst(self):
  12. return "cp_windspeed"
  13. def dataReprocess(self, dataFrameTurbines: pd.DataFrame) -> pd.DataFrame:
  14. dataFrame = dataFrameTurbines.groupby([Field_CodeOfTurbine, Field_WindSpeedFloor]).agg(
  15. cp=(Field_Cp, 'median'),
  16. cp_max=(Field_Cp, 'max'),
  17. cp_min=(Field_Cp, 'min'),
  18. ).reset_index()
  19. dataFrame.columns = [Field_CodeOfTurbine, Field_WindSpeedFloor,
  20. Field_Cp, Field_CpMax, Field_CpMin]
  21. dataFrame = dataFrame.sort_values(
  22. by=[Field_CodeOfTurbine, Field_WindSpeedFloor], ascending=[True, True])
  23. return dataFrame
  24. def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
  25. dictionary = self.processTurbineData(turbineCodes, conf, [
  26. Field_DeviceCode, Field_Time, Field_WindSpeed, Field_ActiverPower])
  27. dataFrameOfTurbines = self.userDataFrame(
  28. dictionary, conf.dataContract.configAnalysis, self)
  29. # 检查所需列是否存在
  30. required_columns = {Field_WindSpeedFloor, Field_Cp}
  31. if not required_columns.issubset(dataFrameOfTurbines.columns):
  32. raise ValueError(f"DataFrame缺少必要的列。需要的列有: {required_columns}")
  33. turbrineInfos = self.common.getTurbineInfos(
  34. conf.dataContract.dataFilter.powerFarmID, turbineCodes, self.turbineInfo)
  35. groupedOfTurbineModel = turbrineInfos.groupby(Field_MillTypeCode)
  36. returnDatas = []
  37. for turbineModelCode, group in groupedOfTurbineModel:
  38. currTurbineCodes = group[Field_CodeOfTurbine].unique().tolist()
  39. currTurbineModeInfo = self.common.getTurbineModelByCode(
  40. turbineModelCode, self.turbineModelInfo)
  41. currDataFrameOfTurbines = dataFrameOfTurbines[dataFrameOfTurbines[Field_CodeOfTurbine].isin(
  42. currTurbineCodes)]
  43. dataFrame = self.dataReprocess(currDataFrameOfTurbines)
  44. returnData = self.buildChart(
  45. dataFrame, outputAnalysisDir, conf, currTurbineModeInfo)
  46. returnDatas.append(returnData)
  47. returnResult = pd.concat(returnDatas, ignore_index=True)
  48. return returnResult
  49. def buildChart(self, dataFrameOfTurbines: pd.DataFrame, outputAnalysisDir, conf: Contract, turbineModelInfo: pd.Series):
  50. # Create the main Cp distribution plot using Plotly
  51. fig = go.Figure()
  52. # colors = px.colors.sequential.Turbo
  53. # 创建一个列表来存储各个风电机组的数据
  54. turbine_data_list = []
  55. for turbineCode in dataFrameOfTurbines[Field_CodeOfTurbine].unique():
  56. group = dataFrameOfTurbines[dataFrameOfTurbines[Field_CodeOfTurbine] == turbineCode]
  57. currTurbineInfo = self.common.getTurbineInfo(
  58. conf.dataContract.dataFilter.powerFarmID, turbineCode, self.turbineInfo)
  59. fig.add_trace(go.Scatter(x=group[Field_WindSpeedFloor], y=group[Field_Cp],
  60. mode='lines',
  61. # line=dict(color=colors[idx % len(colors)]),
  62. name=currTurbineInfo[Field_NameOfTurbine]))
  63. # 提取数据
  64. turbine_data_total = {
  65. "engineName": currTurbineInfo[Field_NameOfTurbine],
  66. "engineCode": turbineCode,
  67. "xData": group[Field_WindSpeedFloor].tolist(),
  68. "yData": group[Field_Cp].tolist(),
  69. }
  70. turbine_data_list.append(turbine_data_total)
  71. fig.update_layout(title={'text': f'风能利用系数分布-{turbineModelInfo[Field_MachineTypeCode]}', 'x': 0.5},
  72. xaxis_title='风速', yaxis_title='风能利用系数',
  73. legend=dict(
  74. orientation="h", # Horizontal orientation
  75. xanchor="center", # Anchor the legend to the center
  76. x=0.5, # Position legend at the center of the x-axis
  77. y=-0.2, # Position legend below the x-axis
  78. # itemsizing='constant', # Keep the size of the legend entries constant
  79. # itemwidth=50
  80. ),
  81. xaxis=dict(range=[0, 26], tickmode='linear',
  82. dtick=1, tickangle=-45),
  83. yaxis=dict(
  84. dtick=self.axisStepCp,
  85. range=[self.axisLowerLimitCp,
  86. self.axisUpperLimitCp]
  87. )
  88. )
  89. engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
  90. if isinstance(engineTypeCode, pd.Series):
  91. engineTypeCode = engineTypeCode.iloc[0]
  92. engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
  93. if isinstance(engineTypeName, pd.Series):
  94. engineTypeName = engineTypeName.iloc[0]
  95. # 构建最终的JSON对象
  96. json_output = {
  97. "analysisTypeCode": "风电机组风能利用系数分析",
  98. "typecode": turbineModelInfo[Field_MillTypeCode],
  99. "engineCode": engineTypeCode,
  100. "engineTypeName": engineTypeName,
  101. "title": f'风能利用系数分布-{turbineModelInfo[Field_MachineTypeCode]}',
  102. "xaixs": "风速",
  103. "yaixs": "风能利用系数",
  104. "data": turbine_data_list
  105. }
  106. output_json_path = os.path.join(outputAnalysisDir, f"{turbineModelInfo[Field_MillTypeCode]}.json")
  107. with open(output_json_path, 'w', encoding='utf-8') as f:
  108. import json
  109. json.dump(json_output, f, ensure_ascii=False, indent=4)
  110. # 保存HTML
  111. # htmlFileName = f"{self.powerFarmInfo[Field_PowerFarmName].iloc[0]}-{turbineModelInfo[Field_MillTypeCode]}-Cp-Distribution.html"
  112. # htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
  113. # fig.write_html(htmlFilePath)
  114. result_rows = []
  115. # result_rows.append({
  116. # Field_Return_TypeAnalyst: self.typeAnalyst(),
  117. # Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  118. # Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  119. # Field_CodeOfTurbine: Const_Output_Total,
  120. # Field_Return_FilePath: htmlFilePath,
  121. # Field_Return_IsSaveDatabase: True
  122. # })
  123. # 如果需要返回DataFrame,可以包含文件路径
  124. result_rows.append({
  125. Field_Return_TypeAnalyst: self.typeAnalyst(),
  126. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  127. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  128. Field_CodeOfTurbine: 'total',
  129. Field_MillTypeCode: turbineModelInfo[Field_MillTypeCode],
  130. Field_Return_FilePath: output_json_path,
  131. Field_Return_IsSaveDatabase: True
  132. })
  133. # Generate individual turbine plots
  134. for turbineCode, group in dataFrameOfTurbines.groupby(Field_CodeOfTurbine):
  135. currTurbineInfo = self.common.getTurbineInfo(
  136. conf.dataContract.dataFilter.powerFarmID, turbineCode, self.turbineInfo)
  137. # 创建一个列表来存储各个风电机组的数据
  138. turbine_data_list_each = []
  139. fig = go.Figure()
  140. for turbineCode in dataFrameOfTurbines[Field_CodeOfTurbine].unique():
  141. tempDataFrame = dataFrameOfTurbines[dataFrameOfTurbines[Field_CodeOfTurbine] == turbineCode]
  142. tempTurbineInfo = self.common.getTurbineInfo(
  143. conf.dataContract.dataFilter.powerFarmID, turbineCode, self.turbineInfo)
  144. fig.add_trace(go.Scatter(x=tempDataFrame[Field_WindSpeedFloor],
  145. y=tempDataFrame[Field_Cp],
  146. mode='lines',
  147. line=dict(color='lightgray', width=1),
  148. showlegend=False))
  149. # 提取数据
  150. turbine_data_other_each = {
  151. "engineName": tempTurbineInfo[Field_NameOfTurbine],
  152. "engineCode": turbineCode,
  153. "xData": tempDataFrame[Field_WindSpeedFloor].tolist(),
  154. "yData": tempDataFrame[Field_Cp].tolist(),
  155. }
  156. turbine_data_list_each.append(turbine_data_other_each)
  157. fig.add_trace(go.Scatter(x=group[Field_WindSpeedFloor], y=group[Field_Cp], mode='lines', line=dict(
  158. color='darkblue'), showlegend=False))
  159. fig.update_layout(title=f'风机: {currTurbineInfo[Field_NameOfTurbine]}',
  160. xaxis_title='风速', yaxis_title='风能利用系数',
  161. xaxis=dict(
  162. range=[0, 26], tickmode='linear', dtick=1, tickangle=-45),
  163. yaxis=dict(
  164. dtick=self.axisStepCp,
  165. range=[self.axisLowerLimitCp,
  166. self.axisUpperLimitCp]
  167. )
  168. )
  169. engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
  170. if isinstance(engineTypeCode, pd.Series):
  171. engineTypeCode = engineTypeCode.iloc[0]
  172. engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
  173. if isinstance(engineTypeName, pd.Series):
  174. engineTypeName = engineTypeName.iloc[0]
  175. # 构建最终的JSON对象
  176. json_output = {
  177. "analysisTypeCode": "风电机组风能利用系数分析",
  178. "typecode": turbineModelInfo[Field_MillTypeCode],
  179. "engineCode": engineTypeCode,
  180. "engineTypeName": engineTypeName,
  181. "title": f'风机: {currTurbineInfo[Field_NameOfTurbine]}',
  182. "xaixs": "风速",
  183. "yaixs": "风能利用系数",
  184. "data": turbine_data_list_each
  185. }
  186. # 将JSON对象保存到文件
  187. output_json_path_each = os.path.join(outputAnalysisDir,
  188. f"{currTurbineInfo[Field_NameOfTurbine]}.json")
  189. with open(output_json_path_each, 'w', encoding='utf-8') as f:
  190. import json
  191. json.dump(json_output, f, ensure_ascii=False, indent=4)
  192. # 保存图像
  193. pngFileName = f"{currTurbineInfo[Field_NameOfTurbine]}.png"
  194. pngFilePath = os.path.join(outputAnalysisDir, pngFileName)
  195. fig.write_image(pngFilePath, scale=3)
  196. # 保存HTML
  197. # htmlFileName = f"{currTurbineInfo[Field_NameOfTurbine]}.html"
  198. # htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
  199. # fig.write_html(htmlFilePath)
  200. result_rows.append({
  201. Field_Return_TypeAnalyst: self.typeAnalyst(),
  202. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  203. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  204. Field_CodeOfTurbine: currTurbineInfo[Field_CodeOfTurbine],
  205. Field_Return_FilePath: pngFilePath,
  206. Field_Return_IsSaveDatabase: False
  207. })
  208. # 如果需要返回DataFrame,可以包含文件路径
  209. result_rows.append({
  210. Field_Return_TypeAnalyst: self.typeAnalyst(),
  211. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  212. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  213. Field_CodeOfTurbine: turbineCode,
  214. Field_Return_FilePath: output_json_path_each,
  215. Field_Return_IsSaveDatabase: True
  216. })
  217. # result_rows.append({
  218. # Field_Return_TypeAnalyst: self.typeAnalyst(),
  219. # Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  220. # Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  221. # Field_CodeOfTurbine: currTurbineInfo[Field_CodeOfTurbine],
  222. # Field_Return_FilePath: htmlFilePath,
  223. # Field_Return_IsSaveDatabase: True
  224. # })
  225. result_df = pd.DataFrame(result_rows)
  226. return result_df