pitchTSRCpAnalyst.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import os
  2. import math
  3. import pandas as pd
  4. import plotly.graph_objects as go
  5. from algorithmContract.confBusiness import *
  6. from algorithmContract.contract import Contract
  7. from behavior.analystWithGoodPoint import AnalystWithGoodPoint
  8. from plotly.subplots import make_subplots
  9. class PitchTSRCpAnalyst(AnalystWithGoodPoint):
  10. def typeAnalyst(self):
  11. return "pitch_tsr_cp"
  12. def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
  13. dictionary=self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_PitchAngel1,Field_WindSpeed,Field_ActiverPower,Field_RotorSpeed,Field_GeneratorSpeed])
  14. dataFrameMerge=self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
  15. turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes, self.turbineInfo)
  16. return self.windRoseAnalysis(dataFrameMerge,turbineInfos, outputAnalysisDir, conf)
  17. def windRoseAnalysis(self, dataFrameMerge: pd.DataFrame, turbineModelInfo: pd.Series,outputAnalysisDir, conf: Contract):
  18. """
  19. 绘制3D曲面图。
  20. 参数:
  21. df: pandas.DataFrame, 必须包含Field_PitchAngel1, Field_TSR, 和 Field_Cp这三个字段。
  22. 返回:
  23. 一个Plotly图形对象。
  24. """
  25. # 检查所需列是否存在
  26. required_columns = {Field_PitchAngel1, Field_TSR, Field_Cp}
  27. if not required_columns.issubset(dataFrameMerge.columns):
  28. raise ValueError(f"DataFrame缺少必要的列。需要的列有: {required_columns},Available: {dataFrameMerge.columns}")
  29. # # 按设备名分组数据
  30. # grouped = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
  31. result_rows = []
  32. ## 分图
  33. dataFrameMerge['PitchAngleBin'] = pd.cut(dataFrameMerge[Field_PitchAngel1], bins=[-1, 1, 3, 5, 7, 9], right=True, labels=['[-1,1]', '(1,3]', '(3,5]', '(5,7]', '(7,9]'])
  34. # turbines = dataFrameMerge[Field_NameOfTurbine].unique()
  35. turbines = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine]).groups.keys()
  36. for turbine_name, turbine_code in turbines:
  37. fig = make_subplots(rows=1, cols=1)
  38. # 选择当前风力发电机的数据
  39. turbine_data = dataFrameMerge[dataFrameMerge[Field_NameOfTurbine] == turbine_name]
  40. # 按角区间分组
  41. grouped = turbine_data.groupby('PitchAngleBin')
  42. # 为每个区间添加一个数据迹
  43. for pitch_bin, group in grouped:
  44. fig.add_trace(go.Scatter(
  45. x=group[Field_TSR],
  46. y=group[Field_Cp],
  47. mode='markers',
  48. name=pitch_bin,
  49. marker=dict(
  50. size=3, # Smaller size, default is usually around 10
  51. opacity=0.8 # Reduced opacity, default is 1
  52. )
  53. # name=f'Pitch: {name}'
  54. ))
  55. # 更新布局
  56. fig.update_layout(
  57. title=f'风能利用系数 vs. 叶尖速比 : {turbine_name}',
  58. xaxis_title='叶尖速比',
  59. yaxis_title='风能利用系数',
  60. legend_title='桨距角',
  61. legend=dict(
  62. # orientation="h",
  63. itemsizing="constant", # Use constant size for legend items
  64. itemwidth=80 # Set the width of legend items to 50 pixels
  65. ),
  66. xaxis=dict(
  67. # dtick=2,
  68. range=[5,20]),
  69. yaxis=dict(
  70. dtick=self.axisStepCp,
  71. range=[self.axisLowerLimitCp,self.axisUpperLimitCp]
  72. )
  73. # legend=dict(
  74. # orientation="h",
  75. # xanchor="center",
  76. # x=0.5,
  77. # y=-0.2
  78. # )
  79. )
  80. # 确保从 Series 中提取的是具体的值
  81. engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
  82. if isinstance(engineTypeCode, pd.Series):
  83. engineTypeCode = engineTypeCode.iloc[0]
  84. engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
  85. if isinstance(engineTypeName, pd.Series):
  86. engineTypeName = engineTypeName.iloc[0]
  87. # 构建最终的JSON对象
  88. json_output = {
  89. "analysisTypeCode": "变桨和叶尖速比及风能利用系数分析",
  90. "engineCode": engineTypeCode,
  91. "engineTypeName": engineTypeName,
  92. "xaixs": "叶尖速比",
  93. "yaixs": "风能利用系数",
  94. "data": [{
  95. "engineName": turbine_name,
  96. "engineCode": turbine_code,
  97. "title":f' 风能利用系数 vs. 叶尖速比-{turbine_name}',
  98. # "xData": group[Field_TSR].tolist(),
  99. "xData":[None if math.isinf(val) else val for val in group[Field_TSR].tolist()],
  100. # "yData":group[Field_Cp].tolist(),
  101. "yData":[None if math.isinf(val) else val for val in group[Field_Cp].tolist()],
  102. "colorbar": pitch_bin,
  103. "colorbartitle": "桨距角"
  104. }]
  105. }
  106. # 保存html
  107. # filePathOfPng = os.path.join(outputAnalysisDir, f"{turbine_name}.png")
  108. # fig.write_image(filePathOfPng)
  109. # filePathOfHtml = os.path.join(outputAnalysisDir, f"{turbine_name}.html")
  110. # fig.write_html(filePathOfHtml)
  111. # 将JSON对象保存到文件
  112. output_json_path = os.path.join(outputAnalysisDir, f"pitch_TSR_cp{turbine_name}.json")
  113. with open(output_json_path, 'w', encoding='utf-8') as f:
  114. import json
  115. json.dump(json_output, f, ensure_ascii=False, indent=4)
  116. # 如果需要返回DataFrame,可以包含文件路径
  117. result_rows.append({
  118. Field_Return_TypeAnalyst: self.typeAnalyst(),
  119. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  120. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  121. Field_CodeOfTurbine: turbine_code,
  122. Field_Return_FilePath: output_json_path,
  123. Field_Return_IsSaveDatabase: True
  124. })
  125. # result_rows.append({
  126. # Field_Return_TypeAnalyst: self.typeAnalyst(),
  127. # Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  128. # Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  129. # Field_CodeOfTurbine: turbine_code,
  130. # Field_Return_FilePath: filePathOfPng,
  131. # Field_Return_IsSaveDatabase: False
  132. # })
  133. # result_rows.append({
  134. # Field_Return_TypeAnalyst: self.typeAnalyst(),
  135. # Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  136. # Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  137. # Field_CodeOfTurbine: turbine_code,
  138. # Field_Return_FilePath: filePathOfHtml,
  139. # Field_Return_IsSaveDatabase: True
  140. # })
  141. result_df = pd.DataFrame(result_rows)
  142. return result_df