cpAnalyst.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 .analyst import Analyst
  9. from .utils.directoryUtil import DirectoryUtil as dir
  10. from confBusiness import ConfBusiness
  11. class CpAnalyst(Analyst):
  12. """
  13. 风电机组风能利用系数分析
  14. """
  15. def typeAnalyst(self):
  16. return "cp"
  17. def turbineAnalysis(self,
  18. dataFrame,
  19. outputAnalysisDir,
  20. outputFilePath,
  21. confData: ConfBusiness,
  22. turbineName):
  23. self.cp(dataFrame, outputFilePath,
  24. confData.field_wind_speed, confData.field_rotor_speed, confData.field_power, confData.field_pitch_angle1, confData.rotor_diameter, confData.density_air)
  25. def cp(self, dataFrame, output_path, wind_speed_col, field_rotor_speed, power_col, pitch_col, rotor_diameter, air_density):
  26. print('rotor_diameter={} air_density={}'.format(
  27. rotor_diameter, air_density))
  28. dataFrame['power'] = dataFrame[power_col] # Alias the power column
  29. # Floor division by 10 and then multiply by 10
  30. dataFrame['power_floor'] = (dataFrame[power_col] / 10).astype(int) * 10
  31. dataFrame['wind_speed'] = dataFrame[wind_speed_col].astype(float)
  32. dataFrame['rotor_speed'] = dataFrame[field_rotor_speed].astype(float)
  33. # Power coefficient calculation
  34. dataFrame['power'] = pd.to_numeric(dataFrame['power'], errors='coerce')
  35. dataFrame['wind_speed'] = pd.to_numeric(
  36. dataFrame['wind_speed'], errors='coerce')
  37. rotor_diameter = pd.to_numeric(rotor_diameter, errors='coerce')
  38. air_density = pd.to_numeric(air_density, errors='coerce')
  39. print('rotor_diameter={} air_density={}'.format(
  40. rotor_diameter, air_density))
  41. # Calculate cp
  42. dataFrame['cp'] = dataFrame['power'] * 1000 / \
  43. (0.5 * np.pi * air_density *
  44. (rotor_diameter ** 2) / 4 * dataFrame['wind_speed'] ** 3)
  45. # Group by power_floor and calculate mean, max, and min of the specified columns
  46. grouped = dataFrame.groupby('power_floor').agg(
  47. wind_speed=('wind_speed', 'mean'),
  48. rotor_speed=('rotor_speed', 'mean'),
  49. cp=('cp', 'mean'),
  50. cp_max=('cp', 'max'),
  51. cp_min=('cp', 'min'),
  52. ).reset_index()
  53. # grouped = dataFrame.groupby('power_floor').agg({
  54. # 'wind_speed': 'mean',
  55. # 'rotor_speed': 'mean',
  56. # 'cp': ['mean', 'max', 'min']
  57. # }).reset_index()
  58. # Rename columns post aggregation for clarity
  59. grouped.columns = ['power_floor', 'wind_speed',
  60. 'rotor_speed', 'cp', 'cp_max', 'cp_min']
  61. # Sort by power_floor
  62. grouped = grouped.sort_values('power_floor')
  63. # Write the dataframe to a CSV file
  64. grouped.to_csv(output_path, index=False)
  65. def turbinesAnalysis(self, dataFrameMerge, outputAnalysisDir, confData: ConfBusiness):
  66. self.generate_cp_distribution(outputAnalysisDir, confData.farm_name)
  67. def generate_cp_distribution(self, csvFileDirOfCp, farm_name, encoding='utf-8'):
  68. """
  69. Generates Cp distribution plots for turbines in a wind farm.
  70. Parameters:
  71. - csvFileDirOfCp: str, path to the directory containing input CSV files.
  72. - farm_name: str, name of the wind farm.
  73. - encoding: str, encoding of the input CSV files. Defaults to 'utf-8'.
  74. """
  75. output_path = csvFileDirOfCp
  76. field_Name_Turbine = "turbine_name"
  77. x_name = 'power_floor'
  78. y_name = 'cp'
  79. split_way = '_cp.csv'
  80. sns.set_palette('deep')
  81. res = pd.DataFrame()
  82. for root, dir_names, file_names in dir.list_directory(csvFileDirOfCp):
  83. for file_name in file_names:
  84. if not file_name.endswith(".csv"):
  85. continue
  86. file_path = os.path.join(root, file_name)
  87. print(file_path)
  88. frame = pd.read_csv(file_path, encoding=encoding)
  89. turbine_name = file_name.split(split_way)[0]
  90. frame[field_Name_Turbine] = turbine_name
  91. res = pd.concat(
  92. [res, frame.loc[:, [field_Name_Turbine, x_name, y_name]]], axis=0)
  93. ress = res.reset_index()
  94. fig, ax = plt.subplots(figsize=(16, 8))
  95. ax = sns.lineplot(x=x_name, y=y_name, data=ress,
  96. hue=field_Name_Turbine)
  97. ax.set_title('Cp-Distribution')
  98. # plt.legend(ncol=4)
  99. plt.legend(title='turbine',bbox_to_anchor=(1.02, 0.5),ncol=2, loc='center left', borderaxespad=0.)
  100. plt.savefig(os.path.join(
  101. output_path, "{}-Cp-Distribution.png".format(farm_name)), bbox_inches='tight', dpi=300)
  102. plt.close()
  103. grouped = ress.groupby(field_Name_Turbine)
  104. for name, group in grouped:
  105. color = ["lightgrey"] * len(ress[field_Name_Turbine].unique())
  106. fig, ax = plt.subplots(figsize=(8, 8))
  107. ax = sns.lineplot(x=x_name, y=y_name, data=ress, hue=field_Name_Turbine,
  108. palette=sns.color_palette(color), legend=False)
  109. ax = sns.lineplot(x=x_name, y=y_name, data=group,
  110. color='darkblue', legend=False)
  111. ax.set_title('turbine name={}'.format(name))
  112. plt.savefig(os.path.join(output_path, "{}.png".format(
  113. name)), bbox_inches='tight', dpi=120)
  114. plt.close()
  115. def plot_cp_distribution(self, csvFileDir, farm_name):
  116. field_Name_Turbine = "设备名"
  117. x_name = 'power_floor'
  118. y_name = 'cp'
  119. split_way = '_cp.csv'
  120. # Create the output path based on the farm name
  121. output_path = csvFileDir # output_path_template.format(farm_name)
  122. # Ensure the output directory exists
  123. os.makedirs(output_path, exist_ok=True)
  124. print(csvFileDir)
  125. # Initialize a DataFrame to store results
  126. res = pd.DataFrame()
  127. # Walk through the input directory to process each file
  128. for root, _, file_names in dir.list_directory(csvFileDir):
  129. for file_name in file_names:
  130. full_path = os.path.join(root, file_name)
  131. frame = pd.read_csv(full_path, encoding='gbk')
  132. turbine_name = file_name.split(split_way)[0]
  133. print("turbine_name={}".format(turbine_name))
  134. frame[field_Name_Turbine] = turbine_name
  135. res = pd.concat(
  136. [res, frame.loc[:, [field_Name_Turbine, x_name, y_name]]], axis=0)
  137. # Reset index for plotting
  138. ress = res.reset_index(drop=True)
  139. # Plot combined Cp distribution for all turbines
  140. fig = make_subplots(rows=1, cols=1)
  141. for name, group in ress.groupby(field_Name_Turbine):
  142. fig.add_trace(go.Scatter(
  143. x=group[x_name], y=group[y_name], mode='lines', name=name))
  144. fig.update_layout(title_text='{} Cp分布'.format(
  145. farm_name), xaxis_title=x_name, yaxis_title=y_name)
  146. fig.write_image(os.path.join(
  147. output_path, "{}Cp分布.png".format(farm_name)), scale=3)
  148. # Plot individual Cp distributions
  149. unique_turbines = ress[field_Name_Turbine].unique()
  150. for name in unique_turbines:
  151. individual_fig = make_subplots(rows=1, cols=1)
  152. # Add all turbines in grey
  153. for turbine in unique_turbines:
  154. group = ress[ress[field_Name_Turbine] == turbine]
  155. individual_fig.add_trace(go.Scatter(
  156. x=group[x_name], y=group[y_name], mode='lines', name=turbine, line=dict(color='lightgrey')))
  157. # Highlight the current turbine in dark blue
  158. group = ress[ress[field_Name_Turbine] == name]
  159. individual_fig.add_trace(go.Scatter(
  160. x=group[x_name], y=group[y_name], mode='lines', name=name, line=dict(color='darkblue')))
  161. individual_fig.update_layout(title_text='设备名={}'.format(name))
  162. individual_fig.write_image(os.path.join(
  163. output_path, "all-{}.png".format(name)), scale=2)