Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
# 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()
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
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
Ejemplo n.º 9
0
    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