def solve_nonlinear(self, params, unknowns, resids): self.r = params['r'] self.chord = params['chord'] self.theta = params['theta'] self.Rhub = params['Rhub'] self.Rtip = params['Rtip'] self.hubHt = params['hubHt'] self.precone = params['precone'] self.tilt = params['tilt'] self.yaw = params['yaw'] self.precurve = params['precurve'] self.precurveTip = params['precurveTip'] self.airfoils = params['airfoils'] self.B = params['B'] self.rho = params['rho'] self.mu = params['mu'] self.shearExp = params['shearExp'] self.nSector = params['nSector'] self.tiploss = params['tiploss'] self.hubloss = params['hubloss'] self.wakerotation = params['wakerotation'] self.usecd = params['usecd'] self.Uhub = params['Uhub'] self.Omega = params['Omega'] self.pitch = params['pitch'] self.ccblade = CCBlade(self.r, self.chord, self.theta, self.airfoils, self.Rhub, self.Rtip, self.B, self.rho, self.mu, self.precone, self.tilt, self.yaw, self.shearExp, self.hubHt, self.nSector, self.precurve, self.precurveTip, tiploss=self.tiploss, hubloss=self.hubloss, wakerotation=self.wakerotation, usecd=self.usecd, derivatives=True) # power, thrust, torque self.P, self.T, self.Q, self.M, self.dP, self.dT, self.dQ \ = self.ccblade.evaluate(self.Uhub, self.Omega, self.pitch, coefficients=False) unknowns['T'] = self.T unknowns['Q'] = self.Q unknowns['P'] = self.P
def setUp(self): # geometry Rhub = 1.5 Rtip = 63.0 r = np.array([2.8667, 5.6000, 8.3333, 11.7500, 15.8500, 19.9500, 24.0500, 28.1500, 32.2500, 36.3500, 40.4500, 44.5500, 48.6500, 52.7500, 56.1667, 58.9000, 61.6333]) chord = np.array([3.542, 3.854, 4.167, 4.557, 4.652, 4.458, 4.249, 4.007, 3.748, 3.502, 3.256, 3.010, 2.764, 2.518, 2.313, 2.086, 1.419]) theta = np.array([13.308, 13.308, 13.308, 13.308, 11.480, 10.162, 9.011, 7.795, 6.544, 5.361, 4.188, 3.125, 2.319, 1.526, 0.863, 0.370, 0.106]) B = 3 # number of blades # atmosphere rho = 1.225 mu = 1.81206e-5 afinit = CCAirfoil.initFromAerodynFile # just for shorthand basepath = path.join(path.dirname(path.realpath(__file__)), '5MW_AFFiles') # load all airfoils airfoil_types = [0]*8 airfoil_types[0] = afinit(path.join(basepath, 'Cylinder1.dat')) airfoil_types[1] = afinit(path.join(basepath, 'Cylinder2.dat')) airfoil_types[2] = afinit(path.join(basepath, 'DU40_A17.dat')) airfoil_types[3] = afinit(path.join(basepath, 'DU35_A17.dat')) airfoil_types[4] = afinit(path.join(basepath, 'DU30_A17.dat')) airfoil_types[5] = afinit(path.join(basepath, 'DU25_A17.dat')) airfoil_types[6] = afinit(path.join(basepath, 'DU21_A17.dat')) airfoil_types[7] = afinit(path.join(basepath, 'NACA64_A17.dat')) # place at appropriate radial stations af_idx = [0, 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7] af = [0]*len(r) for i in range(len(r)): af[i] = airfoil_types[af_idx[i]] tilt = -5.0 precone = 2.5 yaw = 0.0 # create CCBlade object self.rotor = CCBlade(r, chord, theta, af, Rhub, Rtip, B, rho, mu, precone, tilt, yaw, shearExp=0.2, hubHt=90.0)
# The parameters tiploss and hubloss toggle Prandtl tip and hub losses repsectively. # The parameter wakerotation toggles wake swirl (i.e., a′=0). # The parameter usecd can be used to disable the inclusion of drag in the # calculation of the induction factors (it is always used in calculations of the # distributed loads). However, doing so may cause potential failure in the # solution methodology (see [4]). In practice, it should work fine, but special care # for that particular case has not yet been examined, and the default implementation # allows for the possibility of convergence failure. # All four of these parameters are True by default. # The parameter iterRe is for advanced usage. # Referring to [4], this parameter controls the number of internal iterations on the Reynolds number. # One iteration is almost always sufficient, but for high accuracy in the Reynolds number # iterRe could be set at 2. Anything larger than that is unnecessary. m1_rotor = CCBlade(m1_r, m1_chord, m1_theta, m1_af, m1_Rhub, m1_Rtip, B, m1_rho, m1_mu, precone, tilt, yaw, shearExp, m1_hubHt, nSector) m4_rotor = CCBlade(m4_r, m4_chord, m4_theta, m4_af, m4_Rhub, m4_Rtip, B, m4_rho, m4_mu, precone, tilt, yaw, shearExp, m4_hubHt, nSector) m6_rotor = CCBlade(m6_r, m6_chord, m6_theta, m6_af, m6_Rhub, m6_Rtip, B, m6_rho, m6_mu, precone, tilt, yaw, shearExp, m6_hubHt, nSector) m66_rotor = CCBlade(m66_r, m66_chord, m66_theta, m66_af, m66_Rhub, m66_Rtip, B, m66_rho, m66_mu, precone, tilt, yaw, shearExp, m66_hubHt, nSector) m66yaw20_rotor = CCBlade(m66_r, m66_chord, m66_theta, m66_af, m66_Rhub, m66_Rtip, B, m66_rho, m66_mu, precone, tilt, 20.0, shearExp, m66_hubHt, nSector) m67_rotor = CCBlade(m67_r, m67_chord, m67_theta, m67_af, m67_Rhub, m67_Rtip, B, m67_rho, m67_mu, precone, tilt, yaw, shearExp, m67_hubHt, nSector) # convert to RPM m1_Omega = m1_Uinf*tsr/m1_Rtip * 30.0/pi m4_Omega = m4_Uinf*tsr/m4_Rtip * 30.0/pi m6_Omega = m6_Uinf*tsr/m6_Rtip * 30.0/pi
def solve_nonlinear(self, params, unknowns, resids): self.r = params['r'] self.chord = params['chord'] self.theta = params['theta'] self.Rhub = params['Rhub'] self.Rtip = params['Rtip'] self.hubHt = params['hubHt'] self.precone = params['precone'] self.tilt = params['tilt'] self.yaw = params['yaw'] self.precurve = params['precurve'] self.precurveTip = params['precurveTip'] self.airfoils = params['airfoils'] self.B = params['B'] self.rho = params['rho'] self.mu = params['mu'] self.shearExp = params['shearExp'] self.nSector = params['nSector'] self.tiploss = params['tiploss'] self.hubloss = params['hubloss'] self.wakerotation = params['wakerotation'] self.usecd = params['usecd'] self.V_load = params['V_load'] self.Omega_load = params['Omega_load'] self.pitch_load = params['pitch_load'] self.azimuth_load = params['azimuth_load'] if len(self.precurve) == 0: self.precurve = np.zeros_like(self.r) # airfoil files n = len(self.airfoils) af = self.airfoils # af = [0]*n # for i in range(n): # af[i] = CCAirfoil.initFromAerodynFile(self.airfoil_files[i]) self.ccblade = CCBlade(self.r, self.chord, self.theta, af, self.Rhub, self.Rtip, self.B, self.rho, self.mu, self.precone, self.tilt, self.yaw, self.shearExp, self.hubHt, self.nSector, self.precurve, self.precurveTip, tiploss=self.tiploss, hubloss=self.hubloss, wakerotation=self.wakerotation, usecd=self.usecd, derivatives=True) # distributed loads Np, Tp, self.dNp, self.dTp \ = self.ccblade.distributedAeroLoads(self.V_load, self.Omega_load, self.pitch_load, self.azimuth_load) # concatenate loads at root/tip unknowns['loads_r'] = self.r # conform to blade-aligned coordinate system unknowns['loads_Px'] = Np unknowns['loads_Py'] = -Tp unknowns['loads_Pz'] = 0*Np # return other outputs needed unknowns['loads_V'] = self.V_load unknowns['loads_Omega'] = self.Omega_load unknowns['loads_pitch'] = self.pitch_load unknowns['loads_azimuth'] = self.azimuth_load
# 1 ---------- precone = 0.0 precurve = np.linspace(0, 4.9, len(r))**2 precurveTip = 25.0 # create CCBlade object rotor = CCBlade(r, chord, theta, af, Rhub, Rtip, B, rho, mu, precone, tilt, yaw, shearExp, hubHt, nSector, precurve=precurve, precurveTip=precurveTip) # 1 ---------- plt.plot(precurve, r, 'k') plt.plot(precurve, -r, 'k') plt.axis('equal') plt.grid()
def get_loads(Uinf, yaw, azimuth, yawcorrection=False, coupled=False, return_bounds=False, return_az_variation=False, station_idx=0): fname = 'H%02d%04d0' % (Uinf, yaw) fid = open(fname + '.HD1', 'r') fid.readline() parts = fid.readline().split(',') nchan = int(parts[0]) nsamp = int(parts[1]) fid.close() th_idx = np.zeros(5) tq_idx = np.zeros(5) q_idx = np.zeros(5) with open(fname + '.HD1', 'r') as inF: for num, line in enumerate(inF): if 'Thrust coefficient at 30% span' in line: th_idx[0] = int(num) - 2 elif 'Thrust coefficient at 47% span' in line: th_idx[1] = int(num) - 2 elif 'Thrust coefficient at 63% span' in line: th_idx[2] = int(num) - 2 elif 'Thrust coefficient at 80% span' in line: th_idx[3] = int(num) - 2 elif 'Thrust coefficient at 95% span' in line: th_idx[4] = int(num) - 2 if 'Torque coefficient at 30% span' in line: tq_idx[0] = int(num) - 2 elif 'Torque coefficient at 47% span' in line: tq_idx[1] = int(num) - 2 elif 'Torque coefficient at 63% span' in line: tq_idx[2] = int(num) - 2 elif 'Torque coefficient at 80% span' in line: tq_idx[3] = int(num) - 2 elif 'Torque coefficient at 95% span' in line: tq_idx[4] = int(num) - 2 elif 'QNORM30' in line: q_idx[0] = int(num) - 2 elif 'QNORM47' in line: q_idx[1] = int(num) - 2 elif 'QNORM63' in line: q_idx[2] = int(num) - 2 elif 'QNORM80' in line: q_idx[3] = int(num) - 2 elif 'QNORM95' in line: q_idx[4] = int(num) - 2 elif 'Blade azimuth angle' in line: az_idx = int(num) - 2 elif 'CONE' in line: cone_idx = int(num) - 2 elif 'RHOTUN' in line: rho_idx = int(num) - 2 elif 'RPM' in line: rpm_idx = int(num) - 2 data = get_eng_data(fname + '.ENG', nsamp, nchan) az_vec = data[:, az_idx] idx = np.nonzero(np.abs(az_vec - azimuth) < 1) cone_vec = data[:, cone_idx] cone = np.mean(cone_vec[idx]) rho_vec = data[:, rho_idx] rho = np.mean(rho_vec[idx]) rpm_vec = data[:, rpm_idx] rpm = np.mean(rpm_vec[idx]) r_exp = [0.3, 0.47, 0.63, 0.8, 0.95] c_exp = [0.711, 0.62492758, 0.54337911, 0.457, 0.381] q_exp = np.zeros(5) cn_exp = np.zeros(5) ct_exp = np.zeros(5) th_mean = np.zeros(5) th_max = np.zeros(5) th_min = np.zeros(5) tq_mean = np.zeros(5) tq_max = np.zeros(5) tq_min = np.zeros(5) th_vec_all = np.zeros((5, nsamp)) tq_vec_all = np.zeros((5, nsamp)) for i in range(5): cth_vec = data[:, th_idx[i]] ctq_vec = data[:, tq_idx[i]] q_vec = data[:, q_idx[i]] th_vec = cth_vec * q_vec * c_exp[i] / np.cos(np.radians(cone_vec)) tq_vec = ctq_vec * q_vec * c_exp[i] / np.cos(np.radians(cone_vec)) th_mean[i] = np.mean(th_vec[idx]) th_max[i] = np.max(th_vec[idx]) th_min[i] = np.min(th_vec[idx]) tq_mean[i] = np.mean(tq_vec[idx]) tq_max[i] = np.max(tq_vec[idx]) tq_min[i] = np.min(tq_vec[idx]) th_vec_all[i, :] = th_vec tq_vec_all[i, :] = tq_vec Np_exp = th_mean Tp_exp = tq_mean Np_min = th_min Tp_min = tq_min Np_max = th_max Tp_max = tq_max # geometry Rhub = 0.508 Rtip = 5.029 # 0.508, # r = np.array([0.660, 0.883, 1.008, 1.067, 1.133, 1.257, 1.343, 1.510, 1.648, # 1.952, 2.257, 2.343, 2.562, 2.867, 3.172, 3.185, 3.476, 3.781, 4.023, 4.086, 4.391, # 4.696, 4.780, 5.000]) # , 5.305, 5.532] # # 0.218, # chord = np.array([0.218, 0.183, 0.349, 0.441, 0.544, 0.737, 0.728, 0.711, 0.697, # 0.666, 0.636, 0.627, 0.605, 0.574, 0.543, 0.542, 0.512, 0.482, 0.457, 0.451, 0.420, # 0.389, 0.381, 0.358]) # , 0.328, 0.305]) # # 0.0, # theta = np.array([0.0, 0.0, 6.7, 9.9, 13.4, 20.04, 18.074, 14.292, 11.909, 7.979, # 5.308, 4.715, 3.425, 2.083, 1.15, 1.115, 0.494, -0.015, -0.381, -0.475, -0.920, # -1.352, -1.469, -1.775]) # , -2.191, -2.5]) # af_idx = [0, 0, 0, 0, 0, 3, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7] r = np.array([ 0.6060, 0.8801, 1.2321, 1.5087, 1.7099, 1.9278, 2.1457, 2.3469, 2.5480, 2.7660, 2.9840, 3.1850, 3.3862, 3.6041, 3.8220, 4.0232, 4.2244, 4.4004, 4.5764, 4.7776, 4.9536 ]) chord = np.array([ 0.219, 0.181, 0.714, 0.711, 0.691, 0.668, 0.647, 0.627, 0.606, 0.584, 0.561, 0.542, 0.522, 0.499, 0.478, 0.457, 0.437, 0.419, 0.401, 0.381, 0.363 ]) theta = np.array([ 0.000, -0.098, 19.423, 14.318, 10.971, 8.244, 6.164, 4.689, 3.499, 2.478, 1.686, 1.115, 0.666, 0.267, -0.079, -0.381, -0.679, -0.933, -1.184, -1.466, -1.711 ]) af_idx = [0, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7] B = 2 # number of blades # # atmosphere # rho = 1.225 # rho = 1.224385 mu = 1.81206e-5 # import os afinit = CCAirfoil.initFromAerodynFile # just for shorthand basepath = 'af_files2' + os.path.sep airfoil_types = [0] * 8 airfoil_types[0] = afinit(basepath + 'cylinder.dat') airfoil_types[1] = afinit(basepath + 'S809_CLN_129.dat') # .648741 airfoil_types[2] = afinit(basepath + 'S809_CLN_185.dat') # .930365 airfoil_types[3] = afinit(basepath + 'S809_CLN_242.dat') # 1.217018 airfoil_types[4] = afinit(basepath + 'S809_CLN_298.dat') # 1.498642 airfoil_types[5] = afinit(basepath + 'S809_CLN_354.dat') # 1.780266 airfoil_types[6] = afinit(basepath + 'S809_CLN_410.dat') # 2.06189 airfoil_types[7] = afinit(basepath + 'S809_CLN_Outboard.dat') # ere is a cylindrical section at the root that extends from 0.508 to 0.883 m. The airfoil transition begins at approximately the 0.883- m radial station. af = [0] * len(r) for i in range(len(r)): af[i] = airfoil_types[af_idx[i]] tilt = 0.0 precone_ccblade = -cone yaw_ccblade = yaw shearExp = 0.05 hubHt = 12.192 nSector = 8 # create CCBlade object aeroanalysis = CCBlade(r, chord, theta, af, Rhub, Rtip, B, rho, mu, precone_ccblade, tilt, yaw_ccblade, shearExp, hubHt, nSector, yawcorrection=yawcorrection, coupled=coupled) # # set conditions # Uinf = 10.0 # tsr = 7.55 pitch = 3.0 Omega = rpm # Uinf*tsr/Rtip * 30.0/pi # convert to RPM # azimuth_ccblade = (360.0 - azimuth) % 360 # opposite definition azimuth_ccblade = azimuth # evaluate distributed loadsp Np, Tp = aeroanalysis.distributedAeroLoads(Uinf, Omega, pitch, azimuth_ccblade) q = 0.5 * rho * (Uinf + Omega * r * 3.14 / 30)**2 q_exp = np.interp(r_exp, r / Rtip, q) # cn = Np / (q * chord) # ct = Tp / (q * chord) # cn_exp = th_mean / (q_exp * c_exp) # ct_exp = tq_mean / (q_exp * c_exp) rstar = r / Rtip if return_bounds: return rstar, Np, Tp, r_exp, Np_exp, Tp_exp, Np_min, Tp_min, Np_max, Tp_max elif return_az_variation: Np_vec_exp = th_vec_all[station_idx, :] Tp_vec_exp = tq_vec_all[station_idx, :] n = 200 az_vec_sim = np.linspace(0, 360, n) Np_vec = np.zeros(n) Tp_vec = np.zeros(n) for iii in range(n): Np, Tp = aeroanalysis.distributedAeroLoads(Uinf, Omega, pitch, az_vec_sim[iii]) Np_vec[iii] = np.interp(r_exp[station_idx], r / Rtip, Np) Tp_vec[iii] = np.interp(r_exp[station_idx], r / Rtip, Tp) return az_vec, Np_vec_exp, Tp_vec_exp, az_vec_sim, Np_vec, Tp_vec else: return rstar, Np, Tp, r_exp, Np_exp, Tp_exp
for i in range(len(r)): af[i] = airfoil_types[af_idx[i]] # 2 ---------- # 3 ---------- # create CCBlade object rotor = CCBlade(r, chord, theta, af, Rhub, Rtip, B, rho, mu, precone, tilt, yaw, shearExp, hubHt, nSector, derivatives=True) # 3 ---------- # 4 ---------- # set conditions Uinf = 10.0 tsr = 7.55 pitch = 0.0
def CCrotor( Rtip=base_R, Rhub=1.5, hubHt=90.0, shearExp=0.2, rho=1.225, mu=1.81206e-5, path_to_af="5MW_AFFiles", ): r = (Rtip / base_R) * np.array([ 2.8667, 5.6000, 8.3333, 11.7500, 15.8500, 19.9500, 24.0500, 28.1500, 32.2500, 36.3500, 40.4500, 44.5500, 48.6500, 52.7500, 56.1667, 58.9000, 61.6333, ]) chord = (Rtip / base_R) * np.array([ 3.542, 3.854, 4.167, 4.557, 4.652, 4.458, 4.249, 4.007, 3.748, 3.502, 3.256, 3.010, 2.764, 2.518, 2.313, 2.086, 1.419, ]) theta = np.array([ 13.308, 13.308, 13.308, 13.308, 11.480, 10.162, 9.011, 7.795, 6.544, 5.361, 4.188, 3.125, 2.319, 1.526, 0.863, 0.370, 0.106, ]) B = 3 # number of blades # In this initial version, hard-code to be NREL 5MW afinit = CCAirfoil.initFromAerodynFile # just for shorthand basepath = path_to_af # load all airfoils airfoil_types = [0] * 8 airfoil_types[0] = afinit(path.join(basepath, "Cylinder1.dat")) airfoil_types[1] = afinit(path.join(basepath, "Cylinder2.dat")) airfoil_types[2] = afinit(path.join(basepath, "DU40_A17.dat")) airfoil_types[3] = afinit(path.join(basepath, "DU35_A17.dat")) airfoil_types[4] = afinit(path.join(basepath, "DU30_A17.dat")) airfoil_types[5] = afinit(path.join(basepath, "DU25_A17.dat")) airfoil_types[6] = afinit(path.join(basepath, "DU21_A17.dat")) airfoil_types[7] = afinit(path.join(basepath, "NACA64_A17.dat")) # place at appropriate radial stations af_idx = [0, 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7] af = [0] * len(r) for i in range(len(r)): af[i] = airfoil_types[af_idx[i]] tilt = -5.0 precone = 2.5 yaw = 0.0 nSector = 8 # azimuthal discretization rotor = CCBlade( r, chord, theta, af, Rhub, Rtip, B, rho, mu, precone, tilt, yaw, shearExp, hubHt, nSector, ) return rotor
def solve_nonlinear(self, params, unknowns, resids): self.ccblade = CCBlade(params['r'], params['chord'], params['theta'], params['airfoils'], params['Rhub'], params['Rtip'], params['B'], params['rho'], params['mu'], params['precone'], params['tilt'], params['yaw'], params['shearExp'], params['hubHt'], params['nSector']) Uhub = np.linspace(params['control_Vin'],params['control_Vout'], self.n_pc) P_aero = np.zeros_like(Uhub) Cp_aero = np.zeros_like(Uhub) P = np.zeros_like(Uhub) Cp = np.zeros_like(Uhub) T = np.zeros_like(Uhub) Q = np.zeros_like(Uhub) M = np.zeros_like(Uhub) Omega = np.zeros_like(Uhub) pitch = np.zeros_like(Uhub) + params['control_pitch'] Omega_max = min([params['control_maxTS'] / params['Rtip'], params['control_maxOmega']*np.pi/30.]) # Region II for i in range(len(Uhub)): Omega[i] = Uhub[i] * params['control_tsr'] / params['Rtip'] P_aero, T, Q, M, Cp_aero, _, _, _ = self.ccblade.evaluate(Uhub, Omega * 30. / np.pi, pitch, coefficients=True) P, eff = CSMDrivetrain(P_aero, params['control_ratedPower'], params['drivetrainType']) Cp = Cp_aero*eff # search for Region 2.5 bounds for i in range(len(Uhub)): if Omega[i] > Omega_max and P[i] < params['control_ratedPower']: Omega[i] = Omega_max Uhub[i] = Omega[i] * params['Rtip'] / params['control_tsr'] P_aero[i], T[i], Q[i], M[i], Cp_aero[i], _, _, _ = self.ccblade.evaluate([Uhub[i]], [Omega[i] * 30. / np.pi], [pitch[i]], coefficients=True) P[i], eff = CSMDrivetrain(P_aero[i], params['control_ratedPower'], params['drivetrainType']) Cp[i] = Cp_aero[i]*eff regionIIhalf = True i_IIhalf_start = i unknowns['V_R25'] = Uhub[i] break if P[i] > params['control_ratedPower']: regionIIhalf = False break def maxPregionIIhalf(pitch, Uhub, Omega): Uhub_i = Uhub Omega_i = Omega pitch = pitch P, _, _, _ = self.ccblade.evaluate([Uhub_i], [Omega_i * 30. / np.pi], [pitch], coefficients=False) return -P # Solve for regoin 2.5 pitch options = {} options['disp'] = False options['xatol'] = 1.e-2 if regionIIhalf == True: for i in range(i_IIhalf_start + 1, len(Uhub)): Omega[i] = Omega_max pitch0 = pitch[i-1] bnds = [pitch0 - 10., pitch0 + 10.] pitch_regionIIhalf = minimize_scalar(lambda x: maxPregionIIhalf(x, Uhub[i], Omega[i]), bounds=bnds, method='bounded', options=options)['x'] pitch[i] = pitch_regionIIhalf P_aero[i], T[i], Q[i], M[i], Cp_aero[i], _, _, _ = self.ccblade.evaluate([Uhub[i]], [Omega[i] * 30. / np.pi], [pitch[i]], coefficients=True) P[i], eff = CSMDrivetrain(P_aero[i], params['control_ratedPower'], params['drivetrainType']) Cp[i] = Cp_aero[i]*eff if P[i] > params['control_ratedPower']: break def constantPregionIII(pitch, Uhub, Omega): Uhub_i = Uhub Omega_i = Omega pitch = pitch P_aero, _, _, _ = self.ccblade.evaluate([Uhub_i], [Omega_i * 30. / np.pi], [pitch], coefficients=False) P, eff = CSMDrivetrain(P_aero, params['control_ratedPower'], params['drivetrainType']) return abs(P - params['control_ratedPower']) if regionIIhalf == True: # Rated conditions def min_Uhub_rated_II12(min_params): return min_params[1] def get_Uhub_rated_II12(min_params): Uhub_i = min_params[1] Omega_i = Omega_max pitch = min_params[0] P_aero_i, _, _, _ = self.ccblade.evaluate([Uhub_i], [Omega_i * 30. / np.pi], [pitch], coefficients=False) P_i,eff = CSMDrivetrain(P_aero_i, params['control_ratedPower'], params['drivetrainType']) return abs(P_i - params['control_ratedPower']) x0 = [pitch[i] + 2. , Uhub[i]] bnds = [(pitch0, pitch0 + 10.),(Uhub[i-1],Uhub[i+1])] const = {} const['type'] = 'eq' const['fun'] = get_Uhub_rated_II12 params_rated = minimize(min_Uhub_rated_II12, x0, method='SLSQP', tol = 1.e-2, bounds=bnds, constraints=const) U_rated = params_rated.x[1] if not np.isnan(U_rated): Uhub[i] = U_rated pitch[i] = params_rated.x[0] else: print('Regulation trajectory is struggling to find a solution for rated wind speed. Check rotor_aeropower.py') Omega[i] = Omega_max P_aero[i], T[i], Q[i], M[i], Cp_aero[i], _, _, _ = self.ccblade.evaluate([Uhub[i]], [Omega[i] * 30. / np.pi], [pitch0], coefficients=True) P_i, eff = CSMDrivetrain(P_aero[i], params['control_ratedPower'], params['drivetrainType']) Cp[i] = Cp_aero[i]*eff P[i] = params['control_ratedPower'] else: # Rated conditions def get_Uhub_rated_noII12(pitch, Uhub): Uhub_i = Uhub Omega_i = min([Uhub_i * params['control_tsr'] / params['Rtip'], Omega_max]) pitch_i = pitch P_aero_i, _, _, _ = self.ccblade.evaluate([Uhub_i], [Omega_i * 30. / np.pi], [pitch_i], coefficients=False) P_i, eff = CSMDrivetrain(P_aero_i, params['control_ratedPower'], params['drivetrainType']) return abs(P_i - params['control_ratedPower']) bnds = [Uhub[i-1], Uhub[i+1]] U_rated = minimize_scalar(lambda x: get_Uhub_rated_noII12(pitch[i], x), bounds=bnds, method='bounded', options=options)['x'] if not np.isnan(U_rated): Uhub[i] = U_rated else: print('Regulation trajectory is struggling to find a solution for rated wind speed. Check rotor_aeropower.py') Omega[i] = min([Uhub[i] * params['control_tsr'] / params['Rtip'], Omega_max]) pitch0 = pitch[i] P_aero[i], T[i], Q[i], M[i], Cp_aero[i], _, _, _ = self.ccblade.evaluate([Uhub[i]], [Omega[i] * 30. / np.pi], [pitch0], coefficients=True) P[i], eff = CSMDrivetrain(P_aero[i], params['control_ratedPower'], params['drivetrainType']) Cp[i] = Cp_aero[i]*eff for j in range(i + 1,len(Uhub)): Omega[j] = Omega[i] if self.regulation_reg_III == True: pitch0 = pitch[j-1] bnds = [pitch0, pitch0 + 15.] pitch_regionIII = minimize_scalar(lambda x: constantPregionIII(x, Uhub[j], Omega[j]), bounds=bnds, method='bounded', options=options)['x'] pitch[j] = pitch_regionIII P_aero[j], T[j], Q[j], M[j], Cp_aero[j], _, _, _ = self.ccblade.evaluate([Uhub[j]], [Omega[j] * 30. / np.pi], [pitch[j]], coefficients=True) P[j], eff = CSMDrivetrain(P_aero[j], params['control_ratedPower'], params['drivetrainType']) Cp[j] = Cp_aero[j]*eff if abs(P[j] - params['control_ratedPower']) > 1e+4: print('The pitch in region III is not being determined correctly at wind speed ' + str(Uhub[j]) + ' m/s') P[j] = params['control_ratedPower'] T[j] = T[j-1] Q[j] = P[j] / Omega[j] M[j] = M[j-1] pitch[j] = pitch[j-1] Cp[j] = P[j] / (0.5 * params['rho'] * np.pi * params['Rtip']**2 * Uhub[i]**3) P[j] = params['control_ratedPower'] else: P[j] = params['control_ratedPower'] T[j] = 0 Q[j] = Q[i] M[j] = 0 pitch[j] = 0 Cp[j] = P[j] / (0.5 * params['rho'] * np.pi * params['Rtip']**2 * Uhub[i]**3) unknowns['T'] = T unknowns['Q'] = Q unknowns['Omega'] = Omega * 30. / np.pi unknowns['P'] = P unknowns['Cp'] = Cp unknowns['V'] = Uhub unknowns['M'] = M unknowns['pitch'] = pitch self.ccblade.induction_inflow = True a_regII, ap_regII, alpha_regII,_, _ = self.ccblade.distributedAeroLoads(Uhub[0], Omega[0] * 30. / np.pi, pitch[0], 0.0) # Fit spline to powercurve for higher grid density spline = PchipInterpolator(Uhub, P) V_spline = np.linspace(params['control_Vin'],params['control_Vout'], num=self.n_pc_spline) P_spline = spline(V_spline) # outputs idx_rated = list(Uhub).index(U_rated) unknowns['rated_V'] = U_rated unknowns['rated_Omega'] = Omega[idx_rated] * 30. / np.pi unknowns['rated_pitch'] = pitch[idx_rated] unknowns['rated_T'] = T[idx_rated] unknowns['rated_Q'] = Q[idx_rated] unknowns['V_spline'] = V_spline unknowns['P_spline'] = P_spline unknowns['ax_induct_cutin'] = a_regII unknowns['tang_induct_cutin'] = ap_regII unknowns['aoa_cutin'] = alpha_regII