cpWindSpeedAnalyst.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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. for turbineCode in dataFrameOfTurbines[Field_CodeOfTurbine].unique():
  54. group = dataFrameOfTurbines[dataFrameOfTurbines[Field_CodeOfTurbine] == turbineCode]
  55. currTurbineInfo = self.common.getTurbineInfo(
  56. conf.dataContract.dataFilter.powerFarmID, turbineCode, self.turbineInfo)
  57. fig.add_trace(go.Scatter(x=group[Field_WindSpeedFloor], y=group[Field_Cp],
  58. mode='lines',
  59. # line=dict(color=colors[idx % len(colors)]),
  60. name=currTurbineInfo[Field_NameOfTurbine]))
  61. fig.update_layout(title={'text': f'风能利用系数分布-{turbineModelInfo[Field_MachineTypeCode]}', 'x': 0.5},
  62. xaxis_title='风速', yaxis_title='风能利用系数',
  63. legend=dict(
  64. orientation="h", # Horizontal orientation
  65. xanchor="center", # Anchor the legend to the center
  66. x=0.5, # Position legend at the center of the x-axis
  67. y=-0.2, # Position legend below the x-axis
  68. # itemsizing='constant', # Keep the size of the legend entries constant
  69. # itemwidth=50
  70. ),
  71. xaxis=dict(range=[0, 26], tickmode='linear',
  72. dtick=1, tickangle=-45),
  73. yaxis=dict(
  74. dtick=self.axisStepCp,
  75. range=[self.axisLowerLimitCp,
  76. self.axisUpperLimitCp]
  77. )
  78. )
  79. # 保存HTML
  80. htmlFileName = f"{self.powerFarmInfo[Field_PowerFarmName].iloc[0]}-{turbineModelInfo[Field_MillTypeCode]}-Cp-Distribution.html"
  81. htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
  82. fig.write_html(htmlFilePath)
  83. result_rows = []
  84. result_rows.append({
  85. Field_Return_TypeAnalyst: self.typeAnalyst(),
  86. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  87. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  88. Field_CodeOfTurbine: Const_Output_Total,
  89. Field_Return_FilePath: htmlFilePath,
  90. Field_Return_IsSaveDatabase: True
  91. })
  92. # Generate individual turbine plots
  93. for turbineCode, group in dataFrameOfTurbines.groupby(Field_CodeOfTurbine):
  94. currTurbineInfo = self.common.getTurbineInfo(
  95. conf.dataContract.dataFilter.powerFarmID, turbineCode, self.turbineInfo)
  96. fig = go.Figure()
  97. for turbineCode in dataFrameOfTurbines[Field_CodeOfTurbine].unique():
  98. tempDataFrame = dataFrameOfTurbines[dataFrameOfTurbines[Field_CodeOfTurbine] == turbineCode]
  99. fig.add_trace(go.Scatter(x=tempDataFrame[Field_WindSpeedFloor],
  100. y=tempDataFrame[Field_Cp],
  101. mode='lines',
  102. line=dict(color='lightgray', width=1),
  103. showlegend=False))
  104. fig.add_trace(go.Scatter(x=group[Field_WindSpeedFloor], y=group[Field_Cp], mode='lines', line=dict(
  105. color='darkblue'), showlegend=False))
  106. fig.update_layout(title=f'风机: {currTurbineInfo[Field_NameOfTurbine]}',
  107. xaxis_title='风速', yaxis_title='风能利用系数',
  108. xaxis=dict(
  109. range=[0, 26], tickmode='linear', dtick=1, tickangle=-45),
  110. yaxis=dict(
  111. dtick=self.axisStepCp,
  112. range=[self.axisLowerLimitCp,
  113. self.axisUpperLimitCp]
  114. )
  115. )
  116. # 保存图像
  117. pngFileName = f"{currTurbineInfo[Field_NameOfTurbine]}.png"
  118. pngFilePath = os.path.join(outputAnalysisDir, pngFileName)
  119. fig.write_image(pngFilePath, scale=3)
  120. # 保存HTML
  121. htmlFileName = f"{currTurbineInfo[Field_NameOfTurbine]}.html"
  122. htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
  123. fig.write_html(htmlFilePath)
  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: currTurbineInfo[Field_CodeOfTurbine],
  129. Field_Return_FilePath: pngFilePath,
  130. Field_Return_IsSaveDatabase: False
  131. })
  132. result_rows.append({
  133. Field_Return_TypeAnalyst: self.typeAnalyst(),
  134. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  135. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  136. Field_CodeOfTurbine: currTurbineInfo[Field_CodeOfTurbine],
  137. Field_Return_FilePath: htmlFilePath,
  138. Field_Return_IsSaveDatabase: True
  139. })
  140. result_df = pd.DataFrame(result_rows)
  141. return result_df