py_windblade_opa 0.6.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. py_windblade_opa/__init__.py +19 -0
  2. py_windblade_opa/airfoils/__init__.py +1 -0
  3. py_windblade_opa/airfoils/af_naca4415.py +75 -0
  4. py_windblade_opa/airfoils/af_naca4415_test.py +78 -0
  5. py_windblade_opa/airfoils/airfoil_abstract.py +48 -0
  6. py_windblade_opa/airfoils/obsolete_cl.py +24 -0
  7. py_windblade_opa/bem_hansen/__init__.py +5 -0
  8. py_windblade_opa/bem_hansen/aero_coefficient_interpolator.py +219 -0
  9. py_windblade_opa/bem_hansen/blade_aux_functions.py +257 -0
  10. py_windblade_opa/bem_hansen/blade_performance_calculator.py +253 -0
  11. py_windblade_opa/bem_hansen/data_models.py +25 -0
  12. py_windblade_opa/bem_hansen/support_functions.py +16 -0
  13. py_windblade_opa/blade_geometry.py +122 -0
  14. py_windblade_opa/blade_geometry_v2.py +268 -0
  15. py_windblade_opa/blade_plotter.py +146 -0
  16. py_windblade_opa/deol_orch/__init__.py +0 -0
  17. py_windblade_opa/deol_orch/_common.py +72 -0
  18. py_windblade_opa/deol_orch/_components_array.py +63 -0
  19. py_windblade_opa/deol_orch/_components_loop.py +127 -0
  20. py_windblade_opa/deol_orch/blade_calc_orchestrator.py +249 -0
  21. py_windblade_opa/deol_orch/data_models.py +35 -0
  22. py_windblade_opa/deol_orch/refactoring.md +158 -0
  23. py_windblade_opa/performance/__init__.py +12 -0
  24. py_windblade_opa/performance/curve_data.py +30 -0
  25. py_windblade_opa/performance/formulas.py +82 -0
  26. py_windblade_opa/performance/post_processor.py +127 -0
  27. py_windblade_opa/performance/report.py +94 -0
  28. py_windblade_opa/support.py +79 -0
  29. py_windblade_opa/utils.py +66 -0
  30. py_windblade_opa/wel_blade_designer.py +177 -0
  31. py_windblade_opa-0.6.6.dist-info/METADATA +135 -0
  32. py_windblade_opa-0.6.6.dist-info/RECORD +34 -0
  33. py_windblade_opa-0.6.6.dist-info/WHEEL +4 -0
  34. py_windblade_opa-0.6.6.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,19 @@
1
+ from importlib.metadata import version as _version, PackageNotFoundError as _PackageNotFoundError
2
+
3
+ try:
4
+ __version__ = _version("py_windblade_opa")
5
+ except _PackageNotFoundError:
6
+ __version__ = "0.0.0+unknown"
7
+
8
+ __np_package_name__ = 'py_windblade_opa'
9
+
10
+ from .support import WECSSpecs, MiscConstants, WECSConfig
11
+ from .airfoils.airfoil_abstract import AirfoilAC
12
+ from .blade_geometry import BladeGeometry
13
+ from .blade_geometry_v2 import BladeGeometryContainer
14
+ from .wel_blade_designer import WELBladeDesigner
15
+ from .blade_plotter import BladePlot
16
+ from .deol_orch.blade_calc_orchestrator import BladeCalcOrchestrator
17
+ from .utils import x_irregular_to_xnew, x_irregular_to_linspace
18
+
19
+
@@ -0,0 +1 @@
1
+ from .af_naca4415 import NACA4415
@@ -0,0 +1,75 @@
1
+ import numpy as np
2
+ from .airfoil_abstract import AirfoilAC
3
+
4
+ class NACA4415(AirfoilAC):
5
+ """ Class representing the NACA 4415 airfoil. """
6
+
7
+ def __init__(self, thickness):
8
+ super().__init__()
9
+ self.designation = "NACA4415"
10
+ self._t = thickness
11
+ self._airfoil_elastic_centre = 0.296
12
+ self.CLdataRe250000 = np.array([[-10, -0.43], [-9, -0.41], [-4, -0.16], [-2, 0.04],
13
+ [0, 0.23], [2, 0.43], [5, 0.66], [7, 0.85], [9, 1.03],
14
+ [11, 1.19], [13, 1.32], [17, 1.42], [19, 1.44], [21, 1.39],
15
+ [25, 1.23], [30, 0.92], [35, 1.08], [40, 1.22], [45, 1.21],
16
+ [50, 1.17], [60, 1.02], [69, 0.75], [78, 0.43], [87, 0.11],
17
+ [97, -0.26], [106, -0.63]]) # Fill in the rest of the data
18
+ self.CDdataRe250000 = np.array([[-10.67, 0.16], [-8.75, 0.11], [-6.67, 0.03], [-4.42, 0.02],
19
+ [-2.33, 0.02], [0.0, 0.02], [2.5, 0.02], [4.58, 0.03], [6.83, 0.03],
20
+ [9.0, 0.04], [11.25, 0.06], [13.33, 0.08], [15.42, 0.09], [17.5, 0.13],
21
+ [19.33, 0.15], [21.25, 0.19], [26.67, 0.3], [31.08, 0.53], [36.25, 0.77],
22
+ [41.67, 1.04], [46.67, 1.22], [51.67, 1.4], [61.67, 1.7], [71.25, 1.87],
23
+ [81.0, 2.05], [90.67, 2.07], [100.17, 2.05], [109.58, 2.02]]) # Fill in the rest of the data
24
+
25
+ def cl(self, angle_deg):
26
+ """ Returns the lift coefficient of the airfoil. """
27
+ return self._interpolate(angle_deg, self.CLdataRe250000)
28
+
29
+ def cd(self, angle_deg):
30
+ """ Calculates the drag coefficient. """
31
+ return self._interpolate(angle_deg, self.CDdataRe250000)
32
+
33
+ def _interpolate(self, angle_deg, xy_array):
34
+ """ Function that interpolates between a given array. """
35
+ no_rows = len(xy_array)
36
+ if angle_deg <= xy_array[0, 0]:
37
+ return xy_array[0, 1]
38
+ elif angle_deg >= xy_array[-1, 0]:
39
+ return xy_array[-1, 1]
40
+ else:
41
+ for i in range(no_rows):
42
+ if xy_array[i, 0] >= angle_deg:
43
+ break
44
+ return xy_array[i, 1] - (xy_array[i, 0] - angle_deg) * (xy_array[i, 1] - xy_array[i - 1, 1]) / (xy_array[i, 0] - xy_array[i - 1, 0])
45
+
46
+ @staticmethod
47
+ def cl_approx(iattack_deg):
48
+ """
49
+ Calculates the CL (lift coefficient) for a single Iattack (angle of attack) value.
50
+
51
+ Args:
52
+ iattack_deg (float): Single Iattack (angle of attack) value in degrees.
53
+
54
+ Returns:
55
+ float: CL (lift coefficient) value for the given Iattack.
56
+ """
57
+ if iattack_deg < -65:
58
+ CL = iattack_deg * (-0.0373) - 3.5224
59
+ elif iattack_deg > 30:
60
+ CL = (7e-6 * iattack_deg**3 - 0.0018 * iattack_deg**2 + 0.119 * iattack_deg - 1.196)
61
+ elif iattack_deg > -10:
62
+ CL = (-7e-5 * iattack_deg**3 - 0.0004 * iattack_deg**2 + 0.0962 * iattack_deg + 0.242)
63
+ else:
64
+ CL = -0.95
65
+ return CL
66
+
67
+
68
+
69
+ if __name__== "__main__":
70
+ # Example usage
71
+ naca4415 = NACA4415(thickness=0.15)
72
+ lift_coefficient = naca4415.cl(5) # Example angle
73
+ drag_coefficient = naca4415.cd(5) # Example angle
74
+
75
+ # %%
@@ -0,0 +1,78 @@
1
+ #%%
2
+ import numpy as np
3
+ try:
4
+ from .airfoil_abstract import AirfoilAC
5
+ except:
6
+ from airfoil_abstract import AirfoilAC
7
+
8
+ class NACAtest(AirfoilAC):
9
+ """ Class representing the test cases
10
+
11
+ It uses a version of the NACAtest airfoil .
12
+ """
13
+
14
+ def __init__(self, thickness):
15
+ super().__init__()
16
+ self.designation = "NACAtest"
17
+ self._t = thickness
18
+ self._airfoil_elastic_centre = 0.296
19
+ self.CLdataRe250000 = np.array([[-10, -0.43], [-9, -0.41], [-4, -0.16], [-2, 0.04],
20
+ [0, 0.23], [2, 0.43], [5, 0.66], [7, 0.85], [9, 1.03],
21
+ [11, 1.19], [13, 1.32], [17, 1.42], [19, 1.44], [21, 1.39],
22
+ [25, 1.23], [30, 0.92], [35, 1.08], [40, 1.22], [45, 1.21],
23
+ [50, 1.17], [60, 1.02], [69, 0.75], [78, 0.43], [87, 0.11],
24
+ [97, -0.26], [106, -0.63]]) # Fill in the rest of the data
25
+ self.CDdataRe250000 = np.array([[-10.67, 0.16], [-8.75, 0.11], [-6.67, 0.03], [-4.42, 0.02],
26
+ [-2.33, 0.02], [0.0, 0.02], [2.5, 0.02], [4.58, 0.03], [6.83, 0.03],
27
+ [9.0, 0.04], [11.25, 0.06], [13.33, 0.08], [15.42, 0.09], [17.5, 0.13],
28
+ [19.33, 0.15], [21.25, 0.19], [26.67, 0.3], [31.08, 0.53], [36.25, 0.77],
29
+ [41.67, 1.04], [46.67, 1.22], [51.67, 1.4], [61.67, 1.7], [71.25, 1.87],
30
+ [81.0, 2.05], [90.67, 2.07], [100.17, 2.05], [109.58, 2.02]]) # Fill in the rest of the data
31
+
32
+ def cl(self, angle_deg):
33
+ """ Returns the lift coefficient of the airfoil.
34
+
35
+ Args:
36
+ - angle_deg (float): Angle of attack in degrees.
37
+ """
38
+ return NACAtest.cl_approx(angle_deg)
39
+
40
+ def cd(self, angle_deg):
41
+ """ Calculates the drag coefficient. """
42
+ # return self._interpolate(angle_deg, self.CDdataRe250000)
43
+ raise NotImplementedError("Method not implemented yet")
44
+
45
+
46
+
47
+ @staticmethod
48
+ def cl_approx(iattack_deg):
49
+ """
50
+ Calculates the CL (lift coefficient) for a single Iattack (angle of attack) value.
51
+
52
+ Args:
53
+ iattack_deg (float): Single Iattack (angle of attack) value in degrees.
54
+
55
+ Returns:
56
+ float: CL (lift coefficient) value for the given Iattack.
57
+ """
58
+ if iattack_deg < -65:
59
+ CL = iattack_deg * (-0.0373) - 3.5224
60
+ elif iattack_deg > 30:
61
+ CL = (7e-6 * iattack_deg**3 - 0.0018 * iattack_deg**2 + 0.119 * iattack_deg - 1.196)
62
+ elif iattack_deg > -10:
63
+ CL = (-7e-5 * iattack_deg**3 - 0.0004 * iattack_deg**2 + 0.0962 * iattack_deg + 0.242)
64
+ else:
65
+ CL = -0.95
66
+ return CL
67
+
68
+
69
+
70
+ if __name__== "__main__":
71
+ # Example usage
72
+
73
+ naca4415 = NACAtest(thickness=0.15)
74
+ lift_coefficient = naca4415.cl(5) # Example angle
75
+ print(lift_coefficient)
76
+ # drag_coefficient = naca4415.cd(5) # Example angle
77
+
78
+ # %%
@@ -0,0 +1,48 @@
1
+ #%%
2
+ from abc import ABC, abstractmethod
3
+ import numpy as np
4
+
5
+ class AirfoilAC(ABC):
6
+ """ Abstract class that defines airfoil types. Only provides by default Cl, Cd. """
7
+
8
+ def __init__(self):
9
+ self.af_designation = ""
10
+ self._airfoil_elastic_centre = 0.0
11
+
12
+ @abstractmethod
13
+ def cl(self, pip):
14
+ """ Calculate the lift coefficient. """
15
+ pass
16
+
17
+ @abstractmethod
18
+ def cd(self, pip):
19
+ """ Calculate the drag coefficient. """
20
+ pass
21
+
22
+ @property
23
+ def designation(self)-> str:
24
+ """the designation of the airfoil
25
+
26
+ Returns:
27
+ _type_: _description_
28
+ """
29
+ return self.af_designation
30
+
31
+ @designation.setter
32
+ def designation(self, value):
33
+ self.af_designation = value
34
+
35
+ @property
36
+ def airfoil_centre(self)->float:
37
+ """the position of the elastic center as percentage of the chord
38
+
39
+ Returns:
40
+ float: _description_
41
+ """
42
+ return self._airfoil_elastic_centre
43
+
44
+ @airfoil_centre.setter
45
+ def airfoil_centre(self, value):
46
+ self._airfoil_elastic_centre = value
47
+
48
+
@@ -0,0 +1,24 @@
1
+ # this file contains some obsolete functions that were used in the past for the calculation of the lift coefficient (CL) for the wind turbine blade airfoil.
2
+ # they should be removed at some point.
3
+
4
+
5
+ def cl_approx(iattack_deg:float) -> float:
6
+ """ Calculates the CL (lift coefficient) for a single Iattack (angle of attack) value.
7
+
8
+ This is probably an approximation for NACA4415 airfoil.
9
+
10
+ Args:
11
+ iattack_deg (float): Single Iattack (angle of attack) value in degrees.
12
+
13
+ Returns:
14
+ float: CL (lift coefficient) value for the given Iattack.
15
+ """
16
+ if iattack_deg < -65:
17
+ CL = iattack_deg * (-0.0373) - 3.5224
18
+ elif iattack_deg > 30:
19
+ CL = (7e-6 * iattack_deg**3 - 0.0018 * iattack_deg**2 + 0.119 * iattack_deg - 1.196)
20
+ elif iattack_deg > -10:
21
+ CL = (-7e-5 * iattack_deg**3 - 0.0004 * iattack_deg**2 + 0.0962 * iattack_deg + 0.242)
22
+ else:
23
+ CL = -0.95
24
+ return CL
@@ -0,0 +1,5 @@
1
+ from .blade_aux_functions import BladeAuxFunctions
2
+ from .aero_coefficient_interpolator import AeroCoefficientInterpolator
3
+ from .support_functions import discretize_blade
4
+ from .blade_performance_calculator import BladePerformanceCalculator
5
+ from .data_models import BladeOperatingPoint
@@ -0,0 +1,219 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ from scipy.interpolate import griddata
4
+ from scipy.interpolate import interp1d
5
+
6
+ class AeroCoefficientInterpolator:
7
+ def __init__(self, df:pd.DataFrame):
8
+ """
9
+ Initialize the interpolator with a DataFrame containing aoa_deg, tcratio, C_L, C_D, and C_M.
10
+
11
+ Parameters:
12
+ df (pd.DataFrame): DataFrame with columns 'aoa_deg', 'tcratio', 'C_L', 'C_D', 'C_M'.
13
+ """
14
+ self._df = df
15
+ # Store the points (aoa_deg and tcratio) and values (C_L, C_D, C_M) for interpolation
16
+ self.points = df[['aoa_deg', 'tcratio']].values # Independent variables for interpolation
17
+
18
+ # Store the corresponding values for interpolation
19
+ self.values_cl = df['C_L'].values # Coefficient of lift
20
+ self.values_cd = df['C_D'].values # Coefficient of drag
21
+ self.values_cm = df['C_M'].values # Coefficient of moment
22
+
23
+ def interpolate_cl(self, aoa, tcratio, method:str="interp1d"):
24
+ assert method in ["interp1d", "griddata"], f"Invalid interpolation method: {method}"
25
+
26
+ if method == "interp1d":
27
+ return self.interpolate_cl_interp1d(aoa, tcratio)
28
+ elif method == "griddata":
29
+ return self.interpolate_cl_gd(aoa, tcratio)
30
+
31
+ def interpolate_cd(self, aoa, tcratio, method:str="interp1d"):
32
+ assert method in ["interp1d", "griddata"], f"Invalid interpolation method: {method}"
33
+
34
+ if method == "interp1d":
35
+ return self.interpolate_cd_interp1d(aoa, tcratio)
36
+ elif method == "griddata":
37
+ return self.interpolate_cd_gd(aoa, tcratio)
38
+
39
+ def interpolate_cm(self, aoa, tcratio, method:str="interp1d"):
40
+ assert method in ["interp1d", "griddata"], f"Invalid interpolation method: {method}"
41
+
42
+ if method == "interp1d":
43
+ return self.interpolate_cm_interp1d(aoa, tcratio)
44
+ elif method == "griddata":
45
+ return self.interpolate_cm_gd(aoa, tcratio)
46
+
47
+ #region Backwards compatible interpolation methods
48
+ def interpolate_cl_interp1d(self, aoa, tcratio):
49
+ """
50
+ Alternative interpolation method for coefficient of lift (C_L).
51
+ Interpolates for each available thickness and then for the given thickness.
52
+
53
+ Parameters:
54
+ aoa (float): The angle of attack for which to interpolate.
55
+ tcratio (float): The thickness to chord ratio for which to interpolate.
56
+
57
+ Returns:
58
+ float: Interpolated coefficient of lift (C_L).
59
+ """
60
+ # Code for alternative interpolation method
61
+ self.cl_wide = self._df.pivot(index='aoa_deg', columns='tcratio', values='C_L')
62
+ self.aoa_values = self.cl_wide.index.values # aoa_deg values (from rows)
63
+ self.tcratio_values = self.cl_wide.columns.values # tcratio values (from columns)
64
+
65
+ # Step 1: Interpolate C_L values for each thickness at the given aoa (interpolating across aoa_deg)
66
+ clthick = np.zeros_like(self.tcratio_values)
67
+ for i, tcr in enumerate(self.tcratio_values):
68
+ # Extract C_L values for this particular tcratio
69
+ cl_column = self.cl_wide[tcr].values
70
+
71
+ # Create an interpolator for aoa_deg vs C_L for the current tcratio
72
+ aoa_interpolator = interp1d(self.aoa_values, cl_column, kind='linear', fill_value="extrapolate")
73
+
74
+ # Interpolate the C_L value for the given aoa
75
+ clthick[i] = aoa_interpolator(aoa)
76
+
77
+ # Step 2: Interpolate the resulting clthick values for the actual tcratio (interpolating across tcratio)
78
+ cl_interpolator = interp1d(self.tcratio_values, clthick, kind='linear', fill_value="extrapolate")
79
+ return cl_interpolator(tcratio)
80
+
81
+ def interpolate_cd_interp1d(self, aoa, tcratio):
82
+ """Backwards compatible interpolation method for coefficient of drag (C_D).
83
+
84
+ It uses interp1d for interpolation. This method is currently used for validation purposes (units tests and matlab).
85
+
86
+ Args:
87
+ aoa (_type_): _description_
88
+ tcratio (_type_): _description_
89
+
90
+ Returns:
91
+ _type_: _description_
92
+ """
93
+ self.cd_wide = self._df.pivot(index='aoa_deg', columns='tcratio', values='C_D')
94
+ self.aoa_values = self.cd_wide.index.values # aoa_deg values (from rows)
95
+ self.tcratio_values = self.cd_wide.columns.values # tcratio values (from columns)
96
+
97
+ # Step1: Interpolate C_D values for each thickness at the given aoa (interpolating across aoa_deg)
98
+ cdthick = np.zeros_like(self.tcratio_values)
99
+ for i, tcr in enumerate(self.tcratio_values):
100
+ # Extract C_D values for this particular tcratio
101
+ cd_column = self.cd_wide[tcr].values
102
+
103
+ # Create an interpolator for aoa_deg vs C_D for the current tcratio
104
+ aoa_interpolator = interp1d(self.aoa_values, cd_column, kind='linear', fill_value="extrapolate")
105
+
106
+ # Interpolate the C_D value for the given aoa
107
+ cdthick[i] = aoa_interpolator(aoa)
108
+
109
+ # Step 2: Interpolate the resulting cdthick values for the actual tcratio (interpolating across tcratio)
110
+ cd_interpolator = interp1d(self.tcratio_values, cdthick, kind='linear', fill_value="extrapolate")
111
+ return cd_interpolator(tcratio)
112
+
113
+ def interpolate_cm_interp1d(self, aoa, tcratio):
114
+ """
115
+ Backwards compatible interpolation method for coefficient of moment (C_M).
116
+
117
+ It uses interp1d for interpolation. This method is currently used for validation purposes (units tests and matlab).
118
+
119
+ Args:
120
+ aoa (_type_): _description_
121
+ tcratio (_type_): _description_
122
+
123
+ Returns:
124
+ float: Coefficient of moment (C_M) for the given aoa and tcratio.
125
+ """
126
+ self.cm_wide = self._df.pivot(index='aoa_deg', columns='tcratio', values='C_M')
127
+ self.aoa_values = self.cm_wide.index.values
128
+ self.tcratio_values = self.cm_wide.columns.values
129
+
130
+ # Step1: Interpolate C_M values for each thickness at the given aoa (interpolating across aoa_deg)
131
+ cmthick = np.zeros_like(self.tcratio_values)
132
+ for i, tcr in enumerate(self.tcratio_values):
133
+ # Extract C_M values for this particular tcratio
134
+ cm_column = self.cm_wide[tcr].values
135
+
136
+ # Create an interpolator for aoa_deg vs C_M for the current tcratio
137
+ aoa_interpolator = interp1d(self.aoa_values, cm_column, kind='linear', fill_value="extrapolate")
138
+
139
+ # Interpolate the C_M value for the given aoa
140
+ cmthick[i] = aoa_interpolator(aoa)
141
+
142
+ # Step 2: Interpolate the resulting cmthick values for the actual tcratio (interpolating across tcratio)
143
+ cm_interpolator = interp1d(self.tcratio_values, cmthick, kind='linear', fill_value="extrapolate")
144
+ return cm_interpolator(tcratio)
145
+
146
+ #endregion
147
+
148
+ #region Griddata interpolation methods
149
+ def __interpolate(self, aoa, tcratio, values):
150
+ """
151
+ Interpolate the values for given aoa and tcratio.
152
+
153
+ Parameters:
154
+ aoa (float): The angle of attack for which to interpolate.
155
+ tcratio (float): The thickness to chord ratio for which to interpolate.
156
+ values (np.array): The values to interpolate.
157
+
158
+ Returns:
159
+ float: Interpolated value.
160
+ """
161
+ point_to_interpolate = np.array([[aoa, tcratio]])
162
+ interpolated_value = griddata(self.points, values, point_to_interpolate, method='linear')
163
+ return interpolated_value[0]
164
+
165
+ def interpolate_cl_gd(self, aoa, tcratio):
166
+ """
167
+ Interpolate the coefficient of lift (C_L) for given aoa and tcratio.
168
+
169
+ This is an advanced method, however, it is not compatible with the current unit tests.
170
+ TODO: Develop suitable unit tests
171
+
172
+ Parameters:
173
+ aoa (float): The angle of attack for which to interpolate.
174
+ tcratio (float): The thickness to chord ratio for which to interpolate.
175
+
176
+ Returns:
177
+ float: Interpolated coefficient of lift (C_L).
178
+ """
179
+ return self.__interpolate(aoa, tcratio, self.values_cl)
180
+ # point_to_interpolate = np.array([[aoa, tcratio]])
181
+ # cl_interpolated = griddata(self.points, self.values_cl, point_to_interpolate, method='linear')
182
+ # return cl_interpolated[0] # Return the interpolated value
183
+
184
+
185
+
186
+ def interpolate_cd_gd(self, aoa, tcratio):
187
+ """
188
+ Interpolate the coefficient of drag (C_D) for given aoa and tcratio.
189
+
190
+ Parameters:
191
+ aoa (float): The angle of attack for which to interpolate.
192
+ tcratio (float): The thickness to chord ratio for which to interpolate.
193
+
194
+ Returns:
195
+ float: Interpolated coefficient of drag (C_D).
196
+ """
197
+ # point_to_interpolate = np.array([[aoa, tcratio]])
198
+ # cd_interpolated = griddata(self.points, self.values_cd, point_to_interpolate, method='linear')
199
+ # return cd_interpolated[0] # Return the interpolated value
200
+ return self.__interpolate(aoa, tcratio, self.values_cd)
201
+
202
+ def interpolate_cm_gd(self, aoa, tcratio):
203
+ """
204
+ Interpolate the coefficient of moment (C_M) for given aoa and tcratio.
205
+
206
+ Parameters:
207
+ aoa (float): The angle of attack for which to interpolate.
208
+ tcratio (float): The thickness to chord ratio for which to interpolate.
209
+
210
+ Returns:
211
+ float: Interpolated coefficient of moment (C_M).
212
+ """
213
+ # point_to_interpolate = np.array([[aoa, tcratio]])
214
+ # cm_interpolated = griddata(self.points, self.values_cm, point_to_interpolate, method='linear')
215
+ # return cm_interpolated[0] # Return the interpolated value
216
+ return self.__interpolate(aoa, tcratio, self.values_cm)
217
+
218
+ #endregion
219
+