cpAnalyst.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import os
  2. import pandas as pd
  3. import numpy as np
  4. import plotly.graph_objects as go
  5. from plotly.subplots import make_subplots
  6. import seaborn as sns
  7. import matplotlib.pyplot as plt
  8. from matplotlib.ticker import MultipleLocator
  9. from behavior.analystExcludeRatedPower import AnalystExcludeRatedPower
  10. from utils.directoryUtil import DirectoryUtil as dir
  11. from algorithmContract.confBusiness import *
  12. class CpAnalyst(AnalystExcludeRatedPower):
  13. """
  14. 风电机组风能利用系数分析
  15. """
  16. def typeAnalyst(self):
  17. return "cp"
  18. def turbinesAnalysis(self, dataFrameMerge:pd.DataFrame, outputAnalysisDir, confData: ConfBusiness):
  19. # 检查所需列是否存在
  20. required_columns = {confData.field_wind_speed,
  21. Field_Cp, Field_PowerFloor}
  22. if not required_columns.issubset(dataFrameMerge.columns):
  23. raise ValueError(f"DataFrame缺少必要的列。需要的列有: {required_columns}")
  24. self.drawLineGraphForTurbine(dataFrameMerge,outputAnalysisDir,confData)
  25. def drawLineGraphForTurbine(self,dataFrameMerge:pd.DataFrame, outputAnalysisDir, confData: ConfBusiness):
  26. sns.set_palette('deep')
  27. upLimitOfPower = confData.rated_power*0.9
  28. value_step = 0.5
  29. grouped = dataFrameMerge.groupby([Field_NameOfTurbine,Field_PowerFloor]).agg(
  30. cp=('cp', 'median'),
  31. cp_max=('cp', 'max'),
  32. cp_min=('cp', 'min'),
  33. ).reset_index()
  34. # Rename columns post aggregation for clarity
  35. grouped.columns = [Field_NameOfTurbine,Field_PowerFloor, Field_CpMedian, 'cp_max', 'cp_min']
  36. # Sort by power_floor
  37. grouped = grouped.sort_values(by=[Field_NameOfTurbine,Field_PowerFloor])
  38. fig, ax = plt.subplots()
  39. ax = sns.lineplot(x=Field_PowerFloor, y=Field_CpMedian, data=grouped,
  40. hue=Field_NameOfTurbine)
  41. # 绘制合同功率曲线
  42. ax.plot(self.dataFrameContractOfTurbine[Field_PowerFloor], self.dataFrameContractOfTurbine[Field_Cp], marker='o',
  43. c='red', label='Contract Guarantee Cp')
  44. ax.xaxis.set_major_locator(MultipleLocator(confData.graphSets["activePower"]["step"] if not self.common.isNone(
  45. confData.graphSets["activePower"]) and not self.common.isNone(
  46. confData.graphSets["activePower"]["step"]) else 250)) # 创建一个刻度 ,将定位器应用到y轴上
  47. ax.set_xlim(0, upLimitOfPower)
  48. ax.yaxis.set_major_locator(MultipleLocator(
  49. confData.graphSets["cp"]["step"] if not self.common.isNone(confData.graphSets["cp"]["step"]) else value_step)) # 创建一个刻度 ,将定位器应用到y轴上
  50. ax.set_ylim(confData.graphSets["cp"]["min"] if not self.common.isNone(confData.graphSets["cp"]["min"])
  51. else 0, confData.graphSets["cp"]["max"] if not self.common.isNone(confData.graphSets["cp"]["max"]) else 2)
  52. ax.set_title('Cp-Distribution')
  53. # plt.legend(ncol=4)
  54. plt.xticks(rotation=45) # 旋转45度
  55. plt.legend(title='Turbine', bbox_to_anchor=(1.02, 0.5),
  56. ncol=2, loc='center left', borderaxespad=0.)
  57. plt.savefig(os.path.join(
  58. outputAnalysisDir, "{}-Cp-Distribution.png".format(confData.farm_name)), bbox_inches='tight', dpi=300)
  59. plt.close()
  60. groupedX=grouped.groupby(Field_NameOfTurbine)
  61. for name,group in groupedX:
  62. color = ["lightgrey"] * len(dataFrameMerge[Field_NameOfTurbine].unique())
  63. fig, ax = plt.subplots(figsize=(8, 8))
  64. ax = sns.lineplot(x=Field_PowerFloor, y=Field_CpMedian, data=grouped, hue=Field_NameOfTurbine,
  65. palette=sns.color_palette(color), legend=False)
  66. ax = sns.lineplot(x=Field_PowerFloor, y=Field_CpMedian, data=group,
  67. color='darkblue', legend=False)
  68. # 绘制合同功率曲线
  69. ax.plot(self.dataFrameContractOfTurbine[Field_PowerFloor], self.dataFrameContractOfTurbine[Field_Cp], marker='o',
  70. c='red', label='Contract Guarantee Cp')
  71. ax.xaxis.set_major_locator(
  72. MultipleLocator(confData.graphSets["activePower"]["step"] if not self.common.isNone(
  73. confData.graphSets["activePower"]) and not self.common.isNone(
  74. confData.graphSets["activePower"]["step"]) else 250)) # 创建一个刻度 ,将定位器应用到y轴上
  75. ax.set_xlim(0, upLimitOfPower)
  76. ax.yaxis.set_major_locator(MultipleLocator(
  77. confData.graphSets["cp"]["step"] if not self.common.isNone(confData.graphSets["cp"]["step"]) else value_step)) # 创建一个刻度 ,将定位器应用到y轴上
  78. ax.set_ylim(confData.graphSets["cp"]["min"] if not self.common.isNone(confData.graphSets["cp"]["min"])
  79. else 0, confData.graphSets["cp"]["max"] if not self.common.isNone(confData.graphSets["cp"]["max"]) else 1)
  80. ax.set_title('turbine name={}'.format(name))
  81. plt.xticks(rotation=45) # 旋转45度
  82. plt.legend(title='Turbine', bbox_to_anchor=(1.02, 0.5),
  83. ncol=2, loc='center left', borderaxespad=0.)
  84. plt.savefig(os.path.join(outputAnalysisDir, "{}.png".format(
  85. name)), bbox_inches='tight', dpi=120)
  86. plt.close()
  87. def generate_cp_distribution(self, csvFileDirOfCp, confData: ConfBusiness, encoding='utf-8'):
  88. """
  89. Generates Cp distribution plots for turbines in a wind farm.
  90. Parameters:
  91. - csvFileDirOfCp: str, path to the directory containing input CSV files.
  92. - farm_name: str, name of the wind farm.
  93. - encoding: str, encoding of the input CSV files. Defaults to 'utf-8'.
  94. """
  95. output_path = csvFileDirOfCp
  96. field_Name_Turbine = "turbine_name"
  97. x_name = 'power_floor'
  98. y_name = 'cp'
  99. upLimitOfPower = confData.rated_power*0.9
  100. value_step = 0.5
  101. sns.set_palette('deep')
  102. res = pd.DataFrame()
  103. for root, dir_names, file_names in dir.list_directory(csvFileDirOfCp):
  104. for file_name in file_names:
  105. if not file_name.endswith(CSVSuffix):
  106. continue
  107. file_path = os.path.join(root, file_name)
  108. print(file_path)
  109. frame = pd.read_csv(file_path, encoding=encoding)
  110. frame = frame[(frame[x_name] > 0)]
  111. turbine_name = file_name.split(CSVSuffix)[0]
  112. frame[field_Name_Turbine] = turbine_name
  113. res = pd.concat(
  114. [res, frame.loc[:, [field_Name_Turbine, x_name, y_name]]], axis=0)
  115. ress = res.reset_index()
  116. fig, ax = plt.subplots()
  117. ax = sns.lineplot(x=x_name, y=y_name, data=ress,
  118. hue=field_Name_Turbine)
  119. ax.xaxis.set_major_locator(MultipleLocator(200)) # 创建一个刻度 ,将定位器应用到y轴上
  120. ax.set_xlim(0, upLimitOfPower)
  121. ax.yaxis.set_major_locator(MultipleLocator(
  122. confData.graphSets["cp"]["step"] if not self.common.isNone(confData.graphSets["cp"]["step"]) else value_step)) # 创建一个刻度 ,将定位器应用到y轴上
  123. ax.set_ylim(confData.graphSets["cp"]["min"] if not self.common.isNone(confData.graphSets["cp"]["min"])
  124. else 0, confData.graphSets["cp"]["max"] if not self.common.isNone(confData.graphSets["cp"]["max"]) else 2)
  125. ax.set_title('Cp-Distribution')
  126. # plt.legend(ncol=4)
  127. plt.xticks(rotation=45) # 旋转45度
  128. plt.legend(title='turbine', bbox_to_anchor=(1.02, 0.5),
  129. ncol=2, loc='center left', borderaxespad=0.)
  130. plt.savefig(os.path.join(
  131. output_path, "{}-Cp-Distribution.png".format(confData.farm_name)), bbox_inches='tight', dpi=300)
  132. plt.close()
  133. grouped = ress.groupby(field_Name_Turbine)
  134. for name, group in grouped:
  135. color = ["lightgrey"] * len(ress[field_Name_Turbine].unique())
  136. fig, ax = plt.subplots(figsize=(8, 8))
  137. ax = sns.lineplot(x=x_name, y=y_name, data=ress, hue=field_Name_Turbine,
  138. palette=sns.color_palette(color), legend=False)
  139. ax = sns.lineplot(x=x_name, y=y_name, data=group,
  140. color='darkblue', legend=False)
  141. ax.xaxis.set_major_locator(
  142. MultipleLocator(200)) # 创建一个刻度 ,将定位器应用到y轴上
  143. ax.set_xlim(0, upLimitOfPower)
  144. ax.yaxis.set_major_locator(MultipleLocator(
  145. confData.graphSets["cp"]["step"] if not self.common.isNone(confData.graphSets["cp"]["step"]) else value_step)) # 创建一个刻度 ,将定位器应用到y轴上
  146. ax.set_ylim(confData.graphSets["cp"]["min"] if not self.common.isNone(confData.graphSets["cp"]["min"])
  147. else 0, confData.graphSets["cp"]["max"] if not self.common.isNone(confData.graphSets["cp"]["max"]) else 1)
  148. ax.set_title('turbine name={}'.format(name))
  149. plt.xticks(rotation=45) # 旋转45度
  150. plt.savefig(os.path.join(output_path, "{}.png".format(
  151. name)), bbox_inches='tight', dpi=120)
  152. plt.close()
  153. def plot_cp_distribution(self, csvFileDir, farm_name):
  154. field_Name_Turbine = "设备名"
  155. x_name = 'power_floor'
  156. y_name = 'cp'
  157. # Create the output path based on the farm name
  158. output_path = csvFileDir # output_path_template.format(farm_name)
  159. # Ensure the output directory exists
  160. os.makedirs(output_path, exist_ok=True)
  161. print(csvFileDir)
  162. # Initialize a DataFrame to store results
  163. res = pd.DataFrame()
  164. # Walk through the input directory to process each file
  165. for root, _, file_names in dir.list_directory(csvFileDir):
  166. for file_name in file_names:
  167. full_path = os.path.join(root, file_name)
  168. frame = pd.read_csv(full_path, encoding='gbk')
  169. turbine_name = file_name.split(CSVSuffix)[0]
  170. print("turbine_name={}".format(turbine_name))
  171. frame[field_Name_Turbine] = turbine_name
  172. res = pd.concat(
  173. [res, frame.loc[:, [field_Name_Turbine, x_name, y_name]]], axis=0)
  174. # Reset index for plotting
  175. ress = res.reset_index(drop=True)
  176. # Plot combined Cp distribution for all turbines
  177. fig = make_subplots(rows=1, cols=1)
  178. for name, group in ress.groupby(field_Name_Turbine):
  179. fig.add_trace(go.Scatter(
  180. x=group[x_name], y=group[y_name], mode='lines', name=name))
  181. fig.update_layout(title_text='{} Cp分布'.format(
  182. farm_name), xaxis_title=x_name, yaxis_title=y_name)
  183. fig.write_image(os.path.join(
  184. output_path, "{}Cp分布.png".format(farm_name)), scale=3)
  185. # Plot individual Cp distributions
  186. unique_turbines = ress[field_Name_Turbine].unique()
  187. for name in unique_turbines:
  188. individual_fig = make_subplots(rows=1, cols=1)
  189. # Add all turbines in grey
  190. for turbine in unique_turbines:
  191. group = ress[ress[field_Name_Turbine] == turbine]
  192. individual_fig.add_trace(go.Scatter(
  193. x=group[x_name], y=group[y_name], mode='lines', name=turbine, line=dict(color='lightgrey')))
  194. # Highlight the current turbine in dark blue
  195. group = ress[ress[field_Name_Turbine] == name]
  196. individual_fig.add_trace(go.Scatter(
  197. x=group[x_name], y=group[y_name], mode='lines', name=name, line=dict(color='darkblue')))
  198. individual_fig.update_layout(title_text='设备名={}'.format(name))
  199. individual_fig.write_image(os.path.join(
  200. output_path, "all-{}.png".format(name)), scale=2)