diff --git a/wetb/hawc2/bladeinfo.py b/wetb/hawc2/bladeinfo.py index 12c1d4aa556aa99c6facaabe0a2609d1711a98ce..e89bd9ab10c5d3619f38b442870bf0e115250cd8 100644 --- a/wetb/hawc2/bladeinfo.py +++ b/wetb/hawc2/bladeinfo.py @@ -14,53 +14,54 @@ from wetb.hawc2.st_file import StFile -class BladeInfo(object): - def twist(self, radius=None): - """Aerodynamic twist [deg]. Negative when leading edge is twisted towards wind(opposite to normal definition)\n +# class BladeInfo(object): +# def twist(self, radius=None): +# """Aerodynamic twist [deg]. Negative when leading edge is twisted towards wind(opposite to normal definition)\n +# +# Parameters +# --------- +# radius : float or array_like, optional +# radius [m] of interest +# If None (default) the twist of all points are returned +# +# Returns +# ------- +# twist [deg] : float +# """ +# raise NotImplementedError() +# +# def chord(self, radius=None): +# """Aerodynamic chord +# +# Parameters +# --------- +# radius : float or array_like, optional +# radius [m] of interest +# If None (default) the twist of all points are returned +# +# Returns +# ------- +# chord [m] : float +# """ +# raise NotImplementedError() +# +# +# +# def c2nd(self, radius_nd): +# """Return center line position +# +# Parameters +# --------- +# radius_nd : float or array_like, optional +# non dimensional radius +# +# Returns +# ------- +# x,y,z : float +# """ - Parameters - --------- - radius : float or array_like, optional - radius [m] of interest - If None (default) the twist of all points are returned - - Returns - ------- - twist [deg] : float - """ - raise NotImplementedError() - - def chord(self, radius=None): - """Aerodynamic chord - - Parameters - --------- - radius : float or array_like, optional - radius [m] of interest - If None (default) the twist of all points are returned - - Returns - ------- - chord [m] : float - """ - raise NotImplementedError() - - - def c2nd(self, radius_nd): - """Return center line position - - Parameters - --------- - radius_nd : float or array_like, optional - non dimensional radius - - Returns - ------- - x,y,z : float - """ - -class H2BladeInfo(BladeInfo, PCFile, AtTimeFile): +class H2aeroBladeInfo(PCFile, AtTimeFile): """Provide HAWC2 info about a blade From AE file: @@ -85,45 +86,64 @@ class H2BladeInfo(BladeInfo, PCFile, AtTimeFile): """ - def __init__(self, htcfile, ae_filename=None, pc_filename=None, at_time_filename=None, st_filename=None, blade_name=None): + def __init__(self, htcfile, ae_filename=None, pc_filename=None, at_time_filename=None, blade_name=None): if isinstance(htcfile, str): assert htcfile.lower().endswith('.htc') htcfile = HTCFile(htcfile) - + self.htcfile = htcfile blade_name = blade_name or htcfile.aero.link[2] - s = htcfile.new_htc_structure + #s = htcfile.new_htc_structure at_time_filename = at_time_filename or ("output_at_time" in htcfile and os.path.join(htcfile.modelpath, htcfile.output_at_time.filename[0] + ".dat")) pc_filename = pc_filename or os.path.join(htcfile.modelpath, htcfile.aero.pc_filename[0]) ae_filename = ae_filename or os.path.join(htcfile.modelpath, htcfile.aero.ae_filename[0]) - mainbodies = [s[k] for k in s.keys() if s[k].name_ == "main_body"] - mainbody_blade = [mb for mb in mainbodies if mb.name[0] == blade_name][0] - st_filename = st_filename or os.path.join(htcfile.modelpath, mainbody_blade.timoschenko_input.filename[0]) + #mainbodies = [s[k] for k in s.keys() if s[k].name_ == "main_body"] + #self.mainbody_blade = [mb for mb in mainbodies if mb.name[0] == blade_name][0] if os.path.isfile(pc_filename) and os.path.isfile(ae_filename): PCFile.__init__(self, pc_filename, ae_filename) blade_radius = self.ae_sets[1][-1,0] - if os.path.isfile(st_filename): - StFile.__init__(self, st_filename) if os.path.isfile(at_time_filename): AtTimeFile.__init__(self, at_time_filename, blade_radius) - - - self.c2def = np.array([v.values[1:5] for v in mainbody_blade.c2_def if v.name_ == "sec"]) + self.curved_length = self.radius_curved_ac()[-1] + else: + raise NotImplementedError + #z_nd = (np.cos(np.linspace(np.pi, np.pi*2,len(curved_length)-1))+1)/2 + #self.curved_length = np.cumsum(np.sqrt(np.sum(np.diff(self.c2def[:, :3], 1, 0) ** 2, 1)))[-1] - #self.c2nd = lambda x : interp1d(self.c2def[:, 2] / self.c2def[-1, 2], self.c2def[:, :3], axis=0, kind='cubic')(np.max([np.min([x, np.ones_like(x)], 0), np.zeros_like(x) + self.c2def[0, 2] / self.c2def[-1, 2]], 0)) - x, y, z, twist = self.hawc2_splines() - def interpolate(r): - r = (np.max([np.min([r, np.ones_like(r)], 0), np.zeros_like(r) + self.c2def[0, 2] / self.c2def[-1, 2]], 0)) - return np.array([np.interp(r, np.array(z) / z[-1], xyz) for xyz in [x,y,z, twist]]).T - - self.c2nd = interpolate #lambda r : interp1d(np.array(z) / z[-1], np.array([x, y, z]).T, axis=0, kind=1)(np.max([np.min([r, np.ones_like(r)], 0), np.zeros_like(r) + self.c2def[0, 2] / self.c2def[-1, 2]], 0)) + + self.hawc2_splines_data = self.hawc2_splines() + + + @property + def c2def(self): + if not hasattr(self, "_c2def"): + self._c2def = np.array([v.values[1:5] for v in self.htcfile.blade_c2_def if v.name_ == "sec"]) + return self._c2def + + + def c2nd(self, l_nd, curved_length=True): + curve_l_nd, x, y, z, twist = self.hawc2_splines_data + if curved_length: + l_nd = (np.max([np.min([l_nd, np.ones_like(l_nd)], 0), np.zeros_like(l_nd) + self.c2def[0, 2] / self.c2def[-1, 2]], 0)) + return np.array([np.interp(l_nd, curve_l_nd, xyz) for xyz in [x,y,z, twist]]).T + else: + l_nd = (np.max([np.min([l_nd, np.ones_like(l_nd)], 0), np.zeros_like(l_nd)], 0)) + return np.array([np.interp(l_nd, z/z[-1], xyz) for xyz in [x,y,z, twist]]).T + + def c2(self, l, curved_length=True): + if curved_length: + L = self.curved_length + else: + L = self.c2def[-1,2] + return self.c2nd(l/L, curved_length) + def hawc2_splines(self): - curve_z = np.r_[0, np.cumsum(np.sqrt(np.sum(np.diff(self.c2def[:, :3], 1, 0) ** 2, 1)))] - curve_z_nd = curve_z / curve_z[-1] + curve_l = np.r_[0, np.cumsum(np.sqrt(np.sum(np.diff(self.c2def[:, :3], 1, 0) ** 2, 1)))] + curve_l_nd = curve_l / curve_l[-1] def akima(x, y): n = len(x) @@ -166,10 +186,11 @@ class H2BladeInfo(BladeInfo, PCFile, AtTimeFile): z = np.linspace(0, s[i + 1] - s[i ], 10, endpoint=i >= co.shape[0] - 2) x.extend(s[i] + z) y.extend(p(z)) - return y + return x,y - x, y, z, twist = [coef2spline(curve_z_nd, akima(curve_z_nd, self.c2def[:, i])) for i in range(4)] - return x, y, z, twist + x, y, z, twist = [coef2spline(curve_l_nd, akima(curve_l_nd, self.c2def[:, i]))[1] for i in range(4)] + curve_l_nd = coef2spline(curve_l_nd, akima(curve_l_nd, self.c2def[:, 0]))[0] + return curve_l_nd, x, y, z, twist def xyztwist(self, l=None, curved_length=False): """Return splined x,y,z and twist @@ -188,44 +209,120 @@ class H2BladeInfo(BladeInfo, PCFile, AtTimeFile): x,y,z,twist """ if l is None: - return self.c2def[:, 3] + return self.c2def[:, :3] else: - r_nd = np.linspace(0,1,100) + r_nd = np.linspace(0,1,1000) if curved_length: - curved_length = np.cumsum(np.sqrt((np.diff(self.c2nd(np.linspace(0,1,100)),1,0)[:,:3]**2).sum(1))) - assert np.all(l>=curved_length[0]) and np.all(l<=curved_length[-1]) - return self.c2nd(r_nd[np.argmin(np.abs(curved_length-l))+1]) + #curved_length = np.cumsum(np.sqrt((np.diff(self.c2nd(np.linspace(0,1,100)),1,0)[:,:3]**2).sum(1))) + return self.c2nd(l/self.radius_curved_ac()[-1]) +# z_nd = (np.cos(np.linspace(np.pi, np.pi*2,len(curved_length)-1))+1)/2 +# assert np.all(l>=curved_length[0]) and np.all(l<=curved_length[-1]) +# return self.c2nd(r_nd[np.argmin(np.abs(curved_length-l))+1]) else: assert np.all(l>=self.c2def[0,2]) and np.all(l<=self.c2def[-1,2]) return self.c2nd(l/self.c2def[-1, 2]) - - -class H2aeroBladeInfo(H2BladeInfo): - - def __init__(self, at_time_filename, ae_filename, pc_filename, htc_filename): - """ - at_time_filename: file name of at time file containing twist and chord data - """ - PCFile.__init__(self, pc_filename, ae_filename) - blade_radius = self.ae_sets[1][-1,0] - AtTimeFile.__init__(self, at_time_filename, blade_radius) - - assert('twist' in self.attribute_names) - htcfile = HTCFile(htc_filename) - - - self.c2def = np.array([v.values[1:5] for v in htcfile.blade_c2_def if v.name_ == "sec"]) - #self._c2nd = interp1d(self.c2def[:, 2] / self.c2def[-1, 2], self.c2def[:, :3], axis=0, kind='cubic') - - ac_radii = self.ac_radius() - c2_axis_length = np.r_[0, np.cumsum(np.sqrt((np.diff(self.c2def[:, :3], 1, 0) ** 2).sum(1)))] - self._c2nd = interp1d(c2_axis_length / c2_axis_length[-1], self.c2def[:, :3], axis=0, kind='cubic') - #self._c2nd = interp1d(self.c2def[:,2]/self.c2def[-1,2], self.c2def[:, :3], axis=0, kind='cubic') - - def c2nd(self, r_nd): - r_nd_min = np.zeros_like(r_nd) + self.c2def[0, 2] / self.c2def[-1, 2] - r_nd_max = np.ones_like(r_nd) - r_nd = np.max([np.min([r_nd, r_nd_max], 0), r_nd_min], 0) - return self._c2nd(r_nd) + + +class H2BladeInfo(H2aeroBladeInfo): + """Provide HAWC2 info about a blade + + From AE file: + - chord(radius=None, set_nr=1): + - thickness(radius=None, set_nr=1) + - radius_ae(radius=None, set_nr=1) + + From PC file + - CL(radius, alpha, ae_set_nr=1) + - CD(radius, alpha, ae_set_nr=1) + - CM(radius, alpha, ae_set_nr=1) + From at_time_filename + - attribute_names + - xxx(radius=None, curved_length=None) # xxx for each attribute name + - radius_curved_ac(radius=None) # Curved length of nearest/all aerodynamic calculation points + + From ST file + - radius_st(radius=None, mset=1, set=1) + - xxx(radius=None, mset=1, set=1) # xxx for each of r, m, x_cg,y_cg, ri_x, ri_y, xs, ys, E, G, Ix, Iy, K, kx, ky, A, pitch, xe, ye + with template + + """ + def __init__(self, htcfile, ae_filename=None, pc_filename=None, at_time_filename=None, st_filename=None, blade_name=None): + if isinstance(htcfile, str): + htcfile = HTCFile(htcfile) + s = htcfile.new_htc_structure +# at_time_filename = at_time_filename or ("output_at_time" in htcfile and os.path.join(htcfile.modelpath, htcfile.output_at_time.filename[0] + ".dat")) +# pc_filename = pc_filename or os.path.join(htcfile.modelpath, htcfile.aero.pc_filename[0]) +# ae_filename = ae_filename or os.path.join(htcfile.modelpath, htcfile.aero.ae_filename[0]) +# + mainbodies = [s[k] for k in s.keys() if s[k].name_ == "main_body"] + if blade_name is None: + blade_name = htcfile.aero.link[2] + self.mainbody_blade = [mb for mb in mainbodies if mb.name[0] == blade_name][0] + H2aeroBladeInfo.__init__(self, htcfile, ae_filename=ae_filename, pc_filename=pc_filename, at_time_filename=at_time_filename, blade_name=blade_name) + +# def __init__(self, htcfile, ae_filename=None, pc_filename=None, at_time_filename=None, st_filename=None, blade_name=None): +# +# if isinstance(htcfile, str): +# assert htcfile.lower().endswith('.htc') +# htcfile = HTCFile(htcfile) +# +# blade_name = blade_name or htcfile.aero.link[2] + st_filename = st_filename or os.path.join(htcfile.modelpath, self.mainbody_blade.timoschenko_input.filename[0]) +# +# if os.path.isfile(pc_filename) and os.path.isfile(ae_filename): +# PCFile.__init__(self, pc_filename, ae_filename) +# blade_radius = self.ae_sets[1][-1,0] +# + if os.path.isfile(st_filename): + StFile.__init__(self, st_filename) +# if os.path.isfile(at_time_filename): +# AtTimeFile.__init__(self, at_time_filename, blade_radius) +# self.curved_length = self.radius_curved_ac()[-1] +# else: +# raise NotImplementedError +# #z_nd = (np.cos(np.linspace(np.pi, np.pi*2,len(curved_length)-1))+1)/2 +# #self.curved_length = np.cumsum(np.sqrt(np.sum(np.diff(self.c2def[:, :3], 1, 0) ** 2, 1)))[-1] +# +# self.c2def = np.array([v.values[1:5] for v in mainbody_blade.c2_def if v.name_ == "sec"]) +# +# self.hawc2_splines_data = self.hawc2_splines() + @property + def c2def(self): + if not hasattr(self, "_c2def"): + self._c2def = np.array([v.values[1:5] for v in self.mainbody_blade.c2_def if v.name_ == "sec"]) + return self._c2def + +# +# class H2aeroBladeInfo(H2BladeInfo): +# +# def __init__(self, at_time_filename, ae_filename, pc_filename, htc_filename): +# """ +# at_time_filename: file name of at time file containing twist and chord data +# """ +# PCFile.__init__(self, pc_filename, ae_filename) +# blade_radius = self.ae_sets[1][-1,0] +# AtTimeFile.__init__(self, at_time_filename, blade_radius) +# +# assert('twist' in self.attribute_names) +# htcfile = HTCFile(htc_filename) +# +# +# self.c2def = np.array([v.values[1:5] for v in htcfile.blade_c2_def if v.name_ == "sec"]) +# #self._c2nd = interp1d(self.c2def[:, 2] / self.c2def[-1, 2], self.c2def[:, :3], axis=0, kind='cubic') +# +# ac_radii = self.radius_curved_ac() +# self.hawc2_splines_data = self.hawc2_splines() +# self.curved_length = np.cumsum(np.sqrt(np.sum(np.diff(self.c2def[:, :3], 1, 0) ** 2, 1)))[-1] +# +# # c2_axis_length = np.r_[0, np.cumsum(np.sqrt((np.diff(self.c2def[:, :3], 1, 0) ** 2).sum(1)))] +# # self._c2nd = interp1d(c2_axis_length / c2_axis_length[-1], self.c2def[:, :3], axis=0, kind='cubic') +# #self._c2nd = interp1d(self.c2def[:,2]/self.c2def[-1,2], self.c2def[:, :3], axis=0, kind='cubic') +# # +# # def c2nd(self, r_nd): +# # r_nd_min = np.zeros_like(r_nd) + self.c2def[0, 2] / self.c2def[-1, 2] +# # r_nd_max = np.ones_like(r_nd) +# # r_nd = np.max([np.min([r_nd, r_nd_max], 0), r_nd_min], 0) +# # return self._c2nd(r_nd) +#