Example #1
0
    def init_from_refBlade(self, refBlade):
        # Code take from rotor_geometry.py (RotorSE). It computes layup properties, independent of which turbine it is
        # Setup paths
        strucpath       = refBlade.getStructPath()
        self.materials  = Orthotropic2DMaterial.listFromPreCompFile(os.path.join(strucpath, 'materials.inp'))
        
        npts            = refBlade.npts
        self.upperCS    = [0]*npts
        self.lowerCS    = [0]*npts
        self.websCS     = [0]*npts
        self.profile    = [0]*npts

        for i in range(npts):
            webLoc      = []
            istr        = str(i) if refBlade.name == '3_35MW' or refBlade.name == '10MW' else str(i+1)
            self.upperCS[i], self.lowerCS[i], self.websCS[i] = CompositeSection.initFromPreCompLayupFile(os.path.join(strucpath, 'layup_' + istr + '.inp'), webLoc, self.materials , readLocW=True)
            self.profile[i]  = Profile.initFromPreCompFile(os.path.join(strucpath, 'shape_' + istr + '.inp'))

        self.name        = refBlade.name
        self.bladeLength = refBlade.bladeLength
        # self.eta         = refBlade.r
        self.r           = refBlade.r * refBlade.bladeLength
        self.chord       = refBlade.chord_ref
        self.le_location = refBlade.le_location
Example #2
0
    for i in range(ncomp):

        webLoc = []
        if web1[i] != -1:
            webLoc.append(web1[i])
        if web2[i] != -1:
            webLoc.append(web2[i])
        if web3[i] != -1:
            webLoc.append(web3[i])

        upper[i], lower[i], webs[
            i] = CompositeSection.initFromPreCompLayupFile(
                os.path.join(basepath, 'layup_' + str(i + 1) + '.inp'), webLoc,
                materials)
        profile[i] = Profile.initFromPreCompFile(
            os.path.join(basepath, 'shape_' + str(i + 1) + '.inp'))

    rotor.materials = materials  # (List): list of all Orthotropic2DMaterial objects used in defining the geometry
    rotor.upperCS = upper  # (List): list of CompositeSection objections defining the properties for upper surface
    rotor.lowerCS = lower  # (List): list of CompositeSection objections defining the properties for lower surface
    rotor.websCS = webs  # (List): list of CompositeSection objections defining the properties for shear webs
    rotor.profile = profile  # (List): airfoil shape at each radial position
    # --------------------------------------

    # --- fatigue ---
    rotor.rstar_damage = np.array([
        0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500,
        0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978
    ])  # (Array): nondimensional radial locations of damage equivalent moments
    rotor.Mxb_damage = 1e3 * np.array([
        2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003,
Example #3
0
def configure_nrel5mw_turbine(turbine, wind_class='I', sea_depth=0.0):
    """
    Inputs:
        rotor = RotorSE()
        nacelle = DriveSE()
        tower = TowerSE()
        wind_class : str ('I', 'III', 'Offshore' - selected wind class for project)
        sea_depth : float (sea depth if an offshore wind plant)
    """

    # === Turbine ===
    turbine.rho = 1.225  # (Float, kg/m**3): density of air
    turbine.mu = 1.81206e-5  # (Float, kg/m/s): dynamic viscosity of air
    turbine.shear_exponent = 0.2  # (Float): shear exponent
    turbine.hub_height = 90.0  # (Float, m): hub height
    turbine.turbine_class = 'I'  # (Enum): IEC turbine class
    turbine.turbulence_class = 'B'  # (Enum): IEC turbulence class class
    turbine.cdf_reference_height_wind_speed = 90.0  # (Float): reference hub height for IEC wind speed (used in CDF calculation)
    turbine.g = 9.81  # (Float, m/s**2): acceleration of gravity
    # ======================

    # === rotor ===
    # --- blade grid ---
    turbine.rotor.initial_aero_grid = np.array([
        0.02222276, 0.06666667, 0.11111057, 0.16666667, 0.23333333, 0.3,
        0.36666667, 0.43333333, 0.5, 0.56666667, 0.63333333, 0.7, 0.76666667,
        0.83333333, 0.88888943, 0.93333333, 0.97777724
    ])  # (Array): initial aerodynamic grid on unit radius
    turbine.rotor.initial_str_grid = np.array([
        0.0, 0.00492790457512, 0.00652942887106, 0.00813095316699,
        0.00983257273154, 0.0114340970275, 0.0130356213234, 0.02222276,
        0.024446481932, 0.026048006228, 0.06666667, 0.089508406455, 0.11111057,
        0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 0.276686558545,
        0.3, 0.333640766319, 0.36666667, 0.400404310407, 0.43333333, 0.5,
        0.520818918408, 0.56666667, 0.602196371696, 0.63333333, 0.667358391486,
        0.683573824984, 0.7, 0.73242031601, 0.76666667, 0.83333333, 0.88888943,
        0.93333333, 0.97777724, 1.0
    ])  # (Array): initial structural grid on unit radius
    turbine.rotor.idx_cylinder_aero = 3  # (Int): first idx in r_aero_unit of non-cylindrical section, constant twist inboard of here
    turbine.rotor.idx_cylinder_str = 14  # (Int): first idx in r_str_unit of non-cylindrical section
    turbine.rotor.hubFraction = 0.025  # (Float): hub location as fraction of radius
    # ------------------

    # --- blade geometry ---
    turbine.rotor.r_aero = np.array([
        0.02222276, 0.06666667, 0.11111057, 0.2, 0.23333333, 0.3, 0.36666667,
        0.43333333, 0.5, 0.56666667, 0.63333333, 0.64, 0.7, 0.83333333,
        0.88888943, 0.93333333, 0.97777724
    ])  # (Array): new aerodynamic grid on unit radius
    turbine.rotor.r_max_chord = 0.23577  # (Float): location of max chord on unit radius
    turbine.rotor.chord_sub = [
        3.2612, 4.5709, 3.3178, 1.4621
    ]  # (Array, m): chord at control points. defined at hub, then at linearly spaced locations from r_max_chord to tip
    turbine.rotor.theta_sub = [
        13.2783, 7.46036, 2.89317, -0.0878099
    ]  # (Array, deg): twist at control points.  defined at linearly spaced locations from r[idx_cylinder] to tip
    turbine.rotor.precurve_sub = [
        0.0, 0.0, 0.0
    ]  # (Array, m): precurve at control points.  defined at same locations at chord, starting at 2nd control point (root must be zero precurve)
    turbine.rotor.delta_precurve_sub = [
        0.0, 0.0, 0.0
    ]  # (Array, m): adjustment to precurve to account for curvature from loading
    turbine.rotor.sparT = [0.05, 0.047754, 0.045376, 0.031085, 0.0061398
                           ]  # (Array, m): spar cap thickness parameters
    turbine.rotor.teT = [0.1, 0.09569, 0.06569, 0.02569, 0.00569
                         ]  # (Array, m): trailing-edge thickness parameters
    turbine.rotor.bladeLength = 61.5  # (Float, m): blade length (if not precurved or swept) otherwise length of blade before curvature
    turbine.rotor.delta_bladeLength = 0.0  # (Float, m): adjustment to blade length to account for curvature from loading
    turbine.rotor.precone = 2.5  # (Float, deg): precone angle
    turbine.rotor.tilt = 5.0  # (Float, deg): shaft tilt
    turbine.rotor.yaw = 0.0  # (Float, deg): yaw error
    turbine.rotor.nBlades = 3  # (Int): number of blades
    # ------------------

    # --- airfoil files ---
    import rotorse
    #basepath = os.path.join('5MW_files', '5MW_AFFiles')
    basepath = os.path.join('..', 'reference_turbines', 'nrel5mw', 'airfoils')

    # load all airfoils
    airfoil_types = [0] * 8
    airfoil_types[0] = os.path.join(basepath, 'Cylinder1.dat')
    airfoil_types[1] = os.path.join(basepath, 'Cylinder2.dat')
    airfoil_types[2] = os.path.join(basepath, 'DU40_A17.dat')
    airfoil_types[3] = os.path.join(basepath, 'DU35_A17.dat')
    airfoil_types[4] = os.path.join(basepath, 'DU30_A17.dat')
    airfoil_types[5] = os.path.join(basepath, 'DU25_A17.dat')
    airfoil_types[6] = os.path.join(basepath, 'DU21_A17.dat')
    airfoil_types[7] = os.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]

    n = len(af_idx)
    af = [0] * n
    for i in range(n):
        af[i] = airfoil_types[af_idx[i]]
    turbine.rotor.airfoil_files = af  # (List): names of airfoil file
    # ----------------------

    # --- control ---
    turbine.rotor.control.Vin = 3.0  # (Float, m/s): cut-in wind speed
    turbine.rotor.control.Vout = 25.0  # (Float, m/s): cut-out wind speed
    turbine.rotor.control.ratedPower = 5e6  # (Float, W): rated power
    turbine.rotor.control.minOmega = 0.0  # (Float, rpm): minimum allowed rotor rotation speed
    turbine.rotor.control.maxOmega = 12.0  # (Float, rpm): maximum allowed rotor rotation speed
    turbine.rotor.control.tsr = 7.55  # (Float): tip-speed ratio in Region 2 (should be optimized externally)
    turbine.rotor.control.pitch = 0.0  # (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines)
    turbine.rotor.pitch_extreme = 0.0  # (Float, deg): worst-case pitch at survival wind condition
    turbine.rotor.azimuth_extreme = 0.0  # (Float, deg): worst-case azimuth at survival wind condition
    turbine.rotor.VfactorPC = 0.7  # (Float): fraction of rated speed at which the deflection is assumed to representative throughout the power curve calculation
    # ----------------------

    # --- aero and structural analysis options ---
    turbine.rotor.nSector = 4  # (Int): number of sectors to divide rotor face into in computing thrust and power
    turbine.rotor.npts_coarse_power_curve = 20  # (Int): number of points to evaluate aero analysis at
    turbine.rotor.npts_spline_power_curve = 200  # (Int): number of points to use in fitting spline to power curve
    turbine.rotor.AEP_loss_factor = 1.0  # (Float): availability and other losses (soiling, array, etc.)
    turbine.rotor.drivetrainType = 'geared'  # (Enum)
    turbine.rotor.nF = 5  # (Int): number of natural frequencies to compute
    turbine.rotor.dynamic_amplication_tip_deflection = 1.35  # (Float): a dynamic amplification factor to adjust the static deflection calculation
    # ----------------------

    # --- materials and composite layup  ---
    #basepath = os.path.join('5MW_files', '5MW_PrecompFiles')
    basepath = os.path.join('..', 'reference_turbines', 'nrel5mw', 'blade')

    materials = Orthotropic2DMaterial.listFromPreCompFile(
        os.path.join(basepath, 'materials.inp'))

    ncomp = len(turbine.rotor.initial_str_grid)
    upper = [0] * ncomp
    lower = [0] * ncomp
    webs = [0] * ncomp
    profile = [0] * ncomp

    turbine.rotor.leLoc = np.array(
        [
            0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.498, 0.497, 0.465, 0.447,
            0.43, 0.411, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4,
            0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4
        ]
    )  # (Array): array of leading-edge positions from a reference blade axis (usually blade pitch axis). locations are normalized by the local chord length. e.g. leLoc[i] = 0.2 means leading edge is 0.2*chord[i] from reference axis.  positive in -x direction for airfoil-aligned coordinate system
    turbine.rotor.sector_idx_strain_spar = [
        2
    ] * ncomp  # (Array): index of sector for spar (PreComp definition of sector)
    turbine.rotor.sector_idx_strain_te = [
        3
    ] * ncomp  # (Array): index of sector for trailing-edge (PreComp definition of sector)
    web1 = np.array([
        -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.4114, 0.4102, 0.4094,
        0.3876, 0.3755, 0.3639, 0.345, 0.3342, 0.3313, 0.3274, 0.323, 0.3206,
        0.3172, 0.3138, 0.3104, 0.307, 0.3003, 0.2982, 0.2935, 0.2899, 0.2867,
        0.2833, 0.2817, 0.2799, 0.2767, 0.2731, 0.2664, 0.2607, 0.2562, 0.1886,
        -1.0
    ])
    web2 = np.array([
        -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.5886, 0.5868, 0.5854,
        0.5508, 0.5315, 0.5131, 0.4831, 0.4658, 0.4687, 0.4726, 0.477, 0.4794,
        0.4828, 0.4862, 0.4896, 0.493, 0.4997, 0.5018, 0.5065, 0.5101, 0.5133,
        0.5167, 0.5183, 0.5201, 0.5233, 0.5269, 0.5336, 0.5393, 0.5438, 0.6114,
        -1.0
    ])
    web3 = np.array([
        -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0,
        -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
        1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0
    ])
    turbine.rotor.chord_str_ref = np.array(
        [
            3.2612, 3.3100915356, 3.32587052924, 3.34159388653, 3.35823798667,
            3.37384375335, 3.38939112914, 3.4774055542, 3.49839685,
            3.51343645709, 3.87017220335, 4.04645623801, 4.19408216643,
            4.47641008477, 4.55844487985, 4.57383098262, 4.57285771934,
            4.51914315648, 4.47677655262, 4.40075650022, 4.31069949379,
            4.20483735936, 4.08985563932, 3.82931757126, 3.74220276467,
            3.54415796922, 3.38732428502, 3.24931446473, 3.23421422609,
            3.22701537997, 3.21972125648, 3.08979310611, 2.95152261813,
            2.330753331, 2.05553464181, 1.82577817774, 1.5860853279, 1.4621
        ]
    )  # (Array, m): chord distribution for reference section, thickness of structural layup scaled with reference thickness (fixed t/c for this case)

    for i in range(ncomp):

        webLoc = []
        if web1[i] != -1:
            webLoc.append(web1[i])
        if web2[i] != -1:
            webLoc.append(web2[i])
        if web3[i] != -1:
            webLoc.append(web3[i])

        upper[i], lower[i], webs[
            i] = CompositeSection.initFromPreCompLayupFile(
                os.path.join(basepath, 'layup_' + str(i + 1) + '.inp'), webLoc,
                materials)
        profile[i] = Profile.initFromPreCompFile(
            os.path.join(basepath, 'shape_' + str(i + 1) + '.inp'))

    turbine.rotor.materials = materials  # (List): list of all Orthotropic2DMaterial objects used in defining the geometry
    turbine.rotor.upperCS = upper  # (List): list of CompositeSection objections defining the properties for upper surface
    turbine.rotor.lowerCS = lower  # (List): list of CompositeSection objections defining the properties for lower surface
    turbine.rotor.websCS = webs  # (List): list of CompositeSection objections defining the properties for shear webs
    turbine.rotor.profile = profile  # (List): airfoil shape at each radial position
    # --------------------------------------

    strain_ult_spar = 1.0e-2
    strain_ult_te = 2500 * 1e-6

    # --- fatigue ---
    turbine.rotor.rstar_damage = np.array([
        0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500,
        0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978
    ])  # (Array): nondimensional radial locations of damage equivalent moments
    turbine.rotor.Mxb_damage = 1e3 * np.array([
        2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003,
        1.0488E+003, 8.2367E+002, 6.3407E+002, 4.7727E+002, 3.4804E+002,
        2.4458E+002, 1.6339E+002, 1.0252E+002, 5.7842E+001, 2.7349E+001,
        1.1262E+001, 3.8549E+000, 4.4738E-001
    ])  # (Array, N*m): damage equivalent moments about blade c.s. x-direction
    turbine.rotor.Myb_damage = 1e3 * np.array([
        2.7732E+003, 2.8155E+003, 2.6004E+003, 2.3933E+003, 2.1371E+003,
        1.8459E+003, 1.5582E+003, 1.2896E+003, 1.0427E+003, 8.2015E+002,
        6.2449E+002, 4.5229E+002, 3.0658E+002, 1.8746E+002, 9.6475E+001,
        4.2677E+001, 1.5409E+001, 1.8426E+000
    ])  # (Array, N*m): damage equivalent moments about blade c.s. y-direction
    turbine.rotor.strain_ult_spar = 1.0e-2  # (Float): ultimate strain in spar cap
    turbine.rotor.strain_ult_te = 2500 * 1e-6 * 2  # (Float): uptimate strain in trailing-edge panels, note that I am putting a factor of two for the damage part only.
    turbine.rotor.eta_damage = 1.35 * 1.3 * 1.0  # (Float): safety factor for fatigue
    turbine.rotor.m_damage = 10.0  # (Float): slope of S-N curve for fatigue analysis
    turbine.rotor.N_damage = 365 * 24 * 3600 * 20.0  # (Float): number of cycles used in fatigue analysis  TODO: make function of rotation speed
    # ----------------
    # =================

    # === nacelle ======
    turbine.nacelle.L_ms = 1.0  # (Float, m): main shaft length downwind of main bearing in low-speed shaft
    turbine.nacelle.L_mb = 2.5  # (Float, m): main shaft length in low-speed shaft

    turbine.nacelle.h0_front = 1.7  # (Float, m): height of Ibeam in bedplate front
    turbine.nacelle.h0_rear = 1.35  # (Float, m): height of Ibeam in bedplate rear

    turbine.nacelle.drivetrain_design = 'geared'
    turbine.nacelle.crane = True  # (Bool): flag for presence of crane
    turbine.nacelle.bevel = 0  # (Int): Flag for the presence of a bevel stage - 1 if present, 0 if not
    turbine.nacelle.gear_configuration = 'eep'  # (Str): tring that represents the configuration of the gearbox (stage number and types)

    turbine.nacelle.Np = [3, 3, 1]  # (Array): number of planets in each stage
    turbine.nacelle.ratio_type = 'optimal'  # (Str): optimal or empirical stage ratios
    turbine.nacelle.shaft_type = 'normal'  # (Str): normal or short shaft length
    #turbine.nacelle.shaft_angle = 5.0  # (Float, deg): Angle of the LSS inclindation with respect to the horizontal
    turbine.nacelle.shaft_ratio = 0.10  # (Float): Ratio of inner diameter to outer diameter.  Leave zero for solid LSS
    turbine.nacelle.carrier_mass = 8000.0  # estimated for 5 MW
    turbine.nacelle.mb1Type = 'CARB'  # (Str): Main bearing type: CARB, TRB or SRB
    turbine.nacelle.mb2Type = 'SRB'  # (Str): Second bearing type: CARB, TRB or SRB
    turbine.nacelle.yaw_motors_number = 8.0  # (Float): number of yaw motors
    turbine.nacelle.uptower_transformer = True
    turbine.nacelle.flange_length = 0.5  #m
    turbine.nacelle.gearbox_cm = 0.1
    turbine.nacelle.hss_length = 1.5
    turbine.nacelle.overhang = 5.0  #TODO - should come from turbine configuration level

    turbine.nacelle.check_fatigue = 0  #0 if no fatigue check, 1 if parameterized fatigue check, 2 if known loads inputs

    # TODO: should come from rotor (these are FAST outputs)
    turbine.nacelle.DrivetrainEfficiency = 0.95
    #turbine.nacelle.rotor_bending_moment_x = 330770.0# Nm
    #turbine.nacelle.rotor_bending_moment_y = -16665000.0 # Nm
    #turbine.nacelle.rotor_bending_moment_z = 2896300.0 # Nm
    #turbine.nacelle.rotor_force_x = 599610.0 # N
    #turbine.nacelle.rotor_force_y = 186780.0 # N
    #turbine.nacelle.rotor_force_z = -842710.0 # N'''

    #turbine.nacelle.h0_rear = 1.35 # only used in drive smooth
    #turbine.nacelle.h0_front = 1.7

    # =================

    # === tower ===

    # ---- tower ------
    turbine.tower.replace('wind1', PowerWind())
    turbine.tower.replace('wind2', PowerWind())
    # onshore (no waves)

    if turbine.sea_depth <> 0.0:
        turbine.tower.replace('wave1', LinearWaves())
        turbine.tower.replace('wave2', LinearWaves())

        turbine.tower.wave1.Uc = 0.0
        turbine.tower.wave1.hs = 8.0 * 1.86
        turbine.tower.wave1.T = 10.0
        turbine.tower.wave1.z_surface = 0.0
        turbine.tower.wave1.z_floor = -sea_depth
        turbine.tower.wave1.g = 9.81
        turbine.tower.wave1.betaWave = 0.0

        turbine.tower.wave2.Uc = 0.0
        turbine.tower.wave2.hs = 8.0 * 1.86
        turbine.tower.wave2.T = 10.0
        turbine.tower.wave2.z_surface = 0.0
        turbine.tower.wave2.z_floor = -sea_depth
        turbine.tower.wave2.g = 9.81
        turbine.tower.wave2.betaWave = 0.0

    if turbine.sea_depth == 0.0:
        # --- geometry ----
        #np.insert(turbine.tower.z_param,0,87.9)
        #np.insert(turbine.tower.z_param,0,43.8)
        #np.insert(turbine.tower.z_param,0,0.0)
        turbine.tower.z_param = [0.0, 43.8, 87.9]
        turbine.tower_d = [6.0, 4.935, 3.87]
        turbine.tower.t_param = [0.027 * 1.3, 0.023 * 1.3, 0.019 * 1.3]
        n = 15
        turbine.tower.z_full = np.linspace(0.0, 87.6, n)
        turbine.tower.L_reinforced = 30.0 * np.ones(n)  # [m] buckling length
        turbine.tower.theta_stress = 0.0 * np.ones(n)
        turbine.tower.yaw = 0.0

        # --- material props ---
        turbine.tower.E = 210e9 * np.ones(n)
        turbine.tower.G = 80.8e9 * np.ones(n)
        turbine.tower.rho = 8500.0 * np.ones(n)
        turbine.tower.sigma_y = 450.0e6 * np.ones(n)
    else:
        # --- geometry ----
        #np.insert(turbine.tower.z_param,0,87.9)
        #np.insert(turbine.tower.z_param,0,43.8)
        #np.insert(turbine.tower.z_param,0,0.0)
        #np.insert(turbine.tower.z_param,0,-20.0)
        turbine.tower.z_param = [-20.0, 0.0, 43.8, 87.9]
        turbine.tower_d = [6.0, 6.0, 4.935, 3.87]
        turbine.tower.t_param = [0.06, 0.027 * 1.3, 0.023 * 1.3, 0.019 * 1.3]
        n = 20
        turbine.tower.z_full = np.linspace(-20, 87.6, n)
        turbine.tower.L_reinforced = 30.0 * np.ones(n)  # [m] buckling length
        turbine.tower.theta_stress = 0.0 * np.ones(n)
        turbine.tower.yaw = 0.0

        # --- material props ---
        turbine.tower.E = 210e9 * np.ones(n)
        turbine.tower.G = 80.8e9 * np.ones(n)
        turbine.tower.rho = 8500.0 * np.ones(n)
        turbine.tower.sigma_y = 450.0e6 * np.ones(n)

    # --- spring reaction data.  Use float('inf') for rigid constraints. ---
    turbine.tower.kidx = [0]  # applied at base
    turbine.tower.kx = [float('inf')]
    turbine.tower.ky = [float('inf')]
    turbine.tower.kz = [float('inf')]
    turbine.tower.ktx = [float('inf')]
    turbine.tower.kty = [float('inf')]
    turbine.tower.ktz = [float('inf')]

    # --- extra mass ----
    turbine.tower.midx = [n - 1]  # RNA mass at top
    turbine.tower.m = [285598.8]
    turbine.tower.mIxx = [1.14930678e+08]
    turbine.tower.mIyy = [2.20354030e+07]
    turbine.tower.mIzz = [1.87597425e+07]
    turbine.tower.mIxy = [0.00000000e+00]
    turbine.tower.mIxz = [5.03710467e+05]
    turbine.tower.mIyz = [0.00000000e+00]
    turbine.tower.mrhox = [-1.13197635]
    turbine.tower.mrhoy = [0.]
    turbine.tower.mrhoz = [0.50875268]
    turbine.tower.addGravityLoadForExtraMass = True
    # -----------

    # --- wind ---
    #turbine.tower.wind_zref = 90.0
    turbine.tower.wind_z0 = 0.0
    turbine.tower.wind1.shearExp = 0.2
    turbine.tower.wind2.shearExp = 0.2
    # ---------------

    # if addGravityLoadForExtraMass=True be sure not to double count by adding those force here also
    # # --- loading case 1: max Thrust ---
    #turbine.tower.wind_Uref1 = 11.73732
    turbine.tower.plidx1 = [n - 1]  # at tower top
    turbine.tower.Fx1 = [1284744.19620519]
    turbine.tower.Fy1 = [0.]
    turbine.tower.Fz1 = [-2914124.84400512]
    turbine.tower.Mxx1 = [3963732.76208099]
    turbine.tower.Myy1 = [-2275104.79420872]
    turbine.tower.Mzz1 = [-346781.68192839]
    # # ---------------

    # # --- loading case 2: max wind speed ---
    #turbine.tower.wind_Uref2 = 70.0
    turbine.tower.plidx2 = [n - 1]  # at tower top
    turbine.tower.Fx2 = [930198.60063279]
    turbine.tower.Fy2 = [0.]
    turbine.tower.Fz2 = [-2883106.12368949]
    turbine.tower.Mxx2 = [-1683669.22411597]
    turbine.tower.Myy2 = [-2522475.34625363]
    turbine.tower.Mzz2 = [147301.97023764]
    # # ---------------

    # --- safety factors ---
    turbine.tower.gamma_f = 1.35
    turbine.tower.gamma_m = 1.3
    turbine.tower.gamma_n = 1.0
    turbine.tower.gamma_b = 1.1
    # ---------------

    # --- fatigue ---
    turbine.tower.z_DEL = np.array([
        0.000, 1.327, 3.982, 6.636, 9.291, 11.945, 14.600, 17.255, 19.909,
        22.564, 25.218, 27.873, 30.527, 33.182, 35.836, 38.491, 41.145, 43.800,
        46.455, 49.109, 51.764, 54.418, 57.073, 59.727, 62.382, 65.036, 67.691,
        70.345, 73.000, 75.655, 78.309, 80.964, 83.618, 86.273, 87.600
    ])
    turbine.tower.M_DEL = 1e3 * np.array([
        8.2940E+003, 8.1518E+003, 7.8831E+003, 7.6099E+003, 7.3359E+003,
        7.0577E+003, 6.7821E+003, 6.5119E+003, 6.2391E+003, 5.9707E+003,
        5.7070E+003, 5.4500E+003, 5.2015E+003, 4.9588E+003, 4.7202E+003,
        4.4884E+003, 4.2577E+003, 4.0246E+003, 3.7942E+003, 3.5664E+003,
        3.3406E+003, 3.1184E+003, 2.8977E+003, 2.6811E+003, 2.4719E+003,
        2.2663E+003, 2.0673E+003, 1.8769E+003, 1.7017E+003, 1.5479E+003,
        1.4207E+003, 1.3304E+003, 1.2780E+003, 1.2673E+003, 1.2761E+003
    ])
    turbine.tower.gamma_fatigue = 1.35 * 1.3 * 1.0
    turbine.tower.life = 20.0
    turbine.tower.m_SN = 4
    # ---------------

    # --- constraints ---
    turbine.tower.min_d_to_t = 120.0
    turbine.tower.min_taper = 0.4
    # ---------------

    # ==== Other options

    if wind_class == 'I':
        turbine.rotor.turbine_class = 'I'

    elif wind_class == 'III':
        turbine.rotor.turbine_class = 'III'

        # for fatigue based analysis of class III wind turbine
        turbine.tower.M_DEL = 1.028713178 * 1e3 * np.array([
            7.8792E+003, 7.7507E+003, 7.4918E+003, 7.2389E+003, 6.9815E+003,
            6.7262E+003, 6.4730E+003, 6.2174E+003, 5.9615E+003, 5.7073E+003,
            5.4591E+003, 5.2141E+003, 4.9741E+003, 4.7399E+003, 4.5117E+003,
            4.2840E+003, 4.0606E+003, 3.8360E+003, 3.6118E+003, 3.3911E+003,
            3.1723E+003, 2.9568E+003, 2.7391E+003, 2.5294E+003, 2.3229E+003,
            2.1246E+003, 1.9321E+003, 1.7475E+003, 1.5790E+003, 1.4286E+003,
            1.3101E+003, 1.2257E+003, 1.1787E+003, 1.1727E+003, 1.1821E+003
        ])

        turbine.rotor.Mxb_damage = 1e3 * np.array([
            2.3617E+003, 2.0751E+003, 1.8051E+003, 1.5631E+003, 1.2994E+003,
            1.0388E+003, 8.1384E+002, 6.2492E+002, 4.6916E+002, 3.4078E+002,
            2.3916E+002, 1.5916E+002, 9.9752E+001, 5.6139E+001, 2.6492E+001,
            1.0886E+001, 3.7210E+000, 4.3206E-001
        ])
        turbine.rotor.Myb_damage = 1e3 * np.array([
            2.5492E+003, 2.6261E+003, 2.4265E+003, 2.2308E+003, 1.9882E+003,
            1.7184E+003, 1.4438E+003, 1.1925E+003, 9.6251E+002, 7.5564E+002,
            5.7332E+002, 4.1435E+002, 2.8036E+002, 1.7106E+002, 8.7732E+001,
            3.8678E+001, 1.3942E+001, 1.6600E+000
        ])

    elif wind_class == 'Offshore':
        turbine.rotor.turbine_class = 'I'

    # TODO: these should be specified at the turbine level and connected to other system inputs
    if turbine.sea_depth == 0.0:
        turbine.tower_d = [6.0, 4.935,
                           3.87]  # (Array, m): diameters along tower
    else:
        turbine.tower_d = [6.0, 6.0, 4.935, 3.87]
    turbine.generator_speed = 1173.7  # (Float, rpm)  # generator speed
     4.31069949379, 4.20483735936, 4.08985563932, 3.82931757126, 3.74220276467, 3.54415796922, 3.38732428502,
     3.24931446473, 3.23421422609, 3.22701537997, 3.21972125648, 3.08979310611, 2.95152261813, 2.330753331,
     2.05553464181, 1.82577817774, 1.5860853279, 1.4621])  # (Array, m): chord distribution for reference section, thickness of structural layup scaled with reference thickness (fixed t/c for this case)

for i in range(ncomp):

    webLoc = []
    if web1[i] != -1:
        webLoc.append(web1[i])
    if web2[i] != -1:
        webLoc.append(web2[i])
    if web3[i] != -1:
        webLoc.append(web3[i])

    upper[i], lower[i], webs[i] = CompositeSection.initFromPreCompLayupFile(os.path.join(basepath, 'layup_' + str(i+1) + '.inp'), webLoc, materials)
    profile[i] = Profile.initFromPreCompFile(os.path.join(basepath, 'shape_' + str(i+1) + '.inp'))

rotor.materials = materials  # (List): list of all Orthotropic2DMaterial objects used in defining the geometry
rotor.upperCS = upper  # (List): list of CompositeSection objections defining the properties for upper surface
rotor.lowerCS = lower  # (List): list of CompositeSection objections defining the properties for lower surface
rotor.websCS = webs  # (List): list of CompositeSection objections defining the properties for shear webs
rotor.profile = profile  # (List): airfoil shape at each radial position
# --------------------------------------


# --- fatigue ---
rotor.rstar_damage = np.array([0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500,
    0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978])  # (Array): nondimensional radial locations of damage equivalent moments
rotor.Mxb_damage = 1e3*np.array([2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003,
    1.0488E+003, 8.2367E+002, 6.3407E+002, 4.7727E+002, 3.4804E+002, 2.4458E+002, 1.6339E+002,
    1.0252E+002, 5.7842E+001, 2.7349E+001, 1.1262E+001, 3.8549E+000, 4.4738E-001])  # (Array, N*m): damage equivalent moments about blade c.s. x-direction
def EvaluateLCOE(BladeLength, HubHeight, MaximumRotSpeed,Verbose=False):

	############################################################################
	# Define baseline paremeters used for scaling
	ReferenceBladeLength = 35;
	ReferenceTowerHeight = 95
	WindReferenceHeight = 50
	WindReferenceMeanVelocity = 3
	WeibullShapeFactor = 2.0
	ShearFactor = 0.25

	RatedPower = 1.5e6

	# Years used for analysis
	Years = 25
	DiscountRate = 0.08
	############################################################################


	############################################################################
	### 1. Aerodynamic and structural performance using RotorSE
	rotor = RotorSE()
	# -------------------

	# === blade grid ===
	# (Array): initial aerodynamic grid on unit radius
	rotor.initial_aero_grid = np.array([0.02222276, 0.06666667, 0.11111057, \
		0.16666667, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, \
		0.63333333, 0.7, 0.76666667, 0.83333333, 0.88888943, 0.93333333, \
	    0.97777724]) 

	 # (Array): initial structural grid on unit radius
	rotor.initial_str_grid = np.array([0.0, 0.00492790457512, 0.00652942887106, 
		0.00813095316699, 0.00983257273154, 0.0114340970275, 0.0130356213234, 
		0.02222276, 0.024446481932, 0.026048006228, 0.06666667, 0.089508406455,
	    0.11111057, 0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 
	    0.276686558545, 0.3, 0.333640766319,0.36666667, 0.400404310407, 0.43333333, 
	    0.5, 0.520818918408, 0.56666667, 0.602196371696, 0.63333333,
	    0.667358391486, 0.683573824984, 0.7, 0.73242031601, 0.76666667, 0.83333333, 
	    0.88888943, 0.93333333, 0.97777724, 1.0]) 

	# (Int): first idx in r_aero_unit of non-cylindrical section, 
	# constant twist inboard of here
	rotor.idx_cylinder_aero = 3  

	# (Int): first idx in r_str_unit of non-cylindrical section
	rotor.idx_cylinder_str = 14  

	# (Float): hub location as fraction of radius
	rotor.hubFraction = 0.025  
	# ------------------

	# === blade geometry ===
	# (Array): new aerodynamic grid on unit radius
	rotor.r_aero = np.array([0.02222276, 0.06666667, 0.11111057, 0.2, 0.23333333, 
		0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, 0.63333333, 0.64, 0.7, 
		0.83333333, 0.88888943, 0.93333333, 0.97777724])  

	# (Float): location of max chord on unit radius
	rotor.r_max_chord = 0.23577

	# (Array, m): chord at control points. defined at hub, then at linearly spaced
	# locations from r_max_chord to tip
	ReferenceChord = [3.2612, 4.5709, 3.3178, 1.4621]
	rotor.chord_sub = [x * np.true_divide(BladeLength,ReferenceBladeLength) \
		for x in ReferenceChord]

	# (Array, deg): twist at control points.  defined at linearly spaced locations 
	# from r[idx_cylinder] to tip
	rotor.theta_sub = [13.2783, 7.46036, 2.89317, -0.0878099]  

	# (Array, m): precurve at control points.  defined at same locations at chord, 
	# starting at 2nd control point (root must be zero precurve)
	rotor.precurve_sub = [0.0, 0.0, 0.0] 

	# (Array, m): adjustment to precurve to account for curvature from loading
	rotor.delta_precurve_sub = [0.0, 0.0, 0.0]  

	# (Array, m): spar cap thickness parameters
	rotor.sparT = [0.05, 0.047754, 0.045376, 0.031085, 0.0061398] 

	# (Array, m): trailing-edge thickness parameters
	rotor.teT = [0.1, 0.09569, 0.06569, 0.02569, 0.00569]  

	# (Float, m): blade length (if not precurved or swept) 
	# otherwise length of blade before curvature
	rotor.bladeLength = BladeLength  

	# (Float, m): adjustment to blade length to account for curvature from 
	# loading
	rotor.delta_bladeLength = 0.0  
	rotor.precone = 2.5  # (Float, deg): precone angle
	rotor.tilt = 5.0  # (Float, deg): shaft tilt
	rotor.yaw = 0.0  # (Float, deg): yaw error
	rotor.nBlades = 3  # (Int): number of blades
	# ------------------

	# === airfoil files ===
	basepath = os.path.join(os.path.dirname(\
		os.path.realpath(__file__)), '5MW_AFFiles')

	# load all airfoils
	airfoil_types = [0]*8
	airfoil_types[0] = os.path.join(basepath, 'Cylinder1.dat')
	airfoil_types[1] = os.path.join(basepath, 'Cylinder2.dat')
	airfoil_types[2] = os.path.join(basepath, 'DU40_A17.dat')
	airfoil_types[3] = os.path.join(basepath, 'DU35_A17.dat')
	airfoil_types[4] = os.path.join(basepath, 'DU30_A17.dat')
	airfoil_types[5] = os.path.join(basepath, 'DU25_A17.dat')
	airfoil_types[6] = os.path.join(basepath, 'DU21_A17.dat')
	airfoil_types[7] = os.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]

	n = len(af_idx)
	af = [0]*n
	for i in range(n):
	    af[i] = airfoil_types[af_idx[i]]
	rotor.airfoil_files = af  # (List): names of airfoil file
	# ----------------------

	# === atmosphere ===
	rotor.rho = 1.225  # (Float, kg/m**3): density of air
	rotor.mu = 1.81206e-5  # (Float, kg/m/s): dynamic viscosity of air
	rotor.shearExp = 0.25  # (Float): shear exponent
	rotor.hubHt = HubHeight  # (Float, m): hub height
	rotor.turbine_class = 'I'  # (Enum): IEC turbine class
	rotor.turbulence_class = 'B'  # (Enum): IEC turbulence class class
	rotor.cdf_reference_height_wind_speed = 30.0 
	rotor.g = 9.81  # (Float, m/s**2): acceleration of gravity
	# ----------------------

	# === control ===
	rotor.control.Vin = 3.0  # (Float, m/s): cut-in wind speed
	rotor.control.Vout = 26.0  # (Float, m/s): cut-out wind speed
	rotor.control.ratedPower = RatedPower  # (Float, W): rated power
	
	# (Float, rpm): minimum allowed rotor rotation speed

	# (Float, rpm): maximum allowed rotor rotation speed
	rotor.control.minOmega = 0.0  
	rotor.control.maxOmega = MaximumRotSpeed

	# (Float): tip-speed ratio in Region 2 (should be optimized externally)
	rotor.control.tsr = 7
	# (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines)
	rotor.control.pitch = 0.0  
	# (Float, deg): worst-case pitch at survival wind condition
	rotor.pitch_extreme = 0.0  

	# (Float, deg): worst-case azimuth at survival wind condition
	rotor.azimuth_extreme = 0.0  

	# (Float): fraction of rated speed at which the deflection is assumed to 
	# representative throughout the power curve calculation
	rotor.VfactorPC = 0.7  
	# ----------------------

	# === aero and structural analysis options ===

	# (Int): number of sectors to divide rotor face into in computing thrust and power
	rotor.nSector = 4 

	# (Int): number of points to evaluate aero analysis at
	rotor.npts_coarse_power_curve = 20  

	# (Int): number of points to use in fitting spline to power curve
	rotor.npts_spline_power_curve = 200  

	# (Float): availability and other losses (soiling, array, etc.)
	rotor.AEP_loss_factor = 1.0 
	rotor.drivetrainType = 'geared'  # (Enum)

	# (Int): number of natural frequencies to compute
	rotor.nF = 5 

	# (Float): a dynamic amplification factor to adjust the static deflection 
	# calculation
	rotor.dynamic_amplication_tip_deflection = 1.35 
	# ----------------------

	# === materials and composite layup  ===
	basepath = os.path.join(os.path.dirname(os.path.realpath(__file__)), \
		'5MW_PrecompFiles')

	materials = Orthotropic2DMaterial.listFromPreCompFile(os.path.join(basepath,\
	 'materials.inp'))

	ncomp = len(rotor.initial_str_grid)
	upper = [0]*ncomp
	lower = [0]*ncomp
	webs = [0]*ncomp
	profile = [0]*ncomp

	# (Array): array of leading-edge positions from a reference blade axis 
	# (usually blade pitch axis). locations are normalized by the local chord 
	# length. e.g. leLoc[i] = 0.2 means leading edge is 0.2*chord[i] from reference 
	# axis.  positive in -x direction for airfoil-aligned coordinate system
	rotor.leLoc = np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.498, 0.497, 
		0.465, 0.447, 0.43, 0.411, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 
		0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4])  

	# (Array): index of sector for spar (PreComp definition of sector)
	rotor.sector_idx_strain_spar = [2]*ncomp  

	# (Array): index of sector for trailing-edge (PreComp definition of sector)
	rotor.sector_idx_strain_te = [3]*ncomp  

	web1 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.4114, 0.4102, 
		0.4094, 0.3876, 0.3755, 0.3639, 0.345, 0.3342, 0.3313, 0.3274, 0.323, 
		0.3206, 0.3172, 0.3138, 0.3104, 0.307, 0.3003, 0.2982, 0.2935, 0.2899, 
		0.2867, 0.2833, 0.2817, 0.2799, 0.2767, 0.2731, 0.2664, 0.2607, 0.2562, 
		0.1886, -1.0])

	web2 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.5886, 0.5868, 
		0.5854, 0.5508, 0.5315, 0.5131, 0.4831, 0.4658, 0.4687, 0.4726, 0.477, 
		0.4794, 0.4828, 0.4862, 0.4896, 0.493, 0.4997, 0.5018, 0.5065, 0.5101, 
		0.5133, 0.5167, 0.5183, 0.5201, 0.5233, 0.5269, 0.5336, 0.5393, 0.5438, 
		0.6114, -1.0])
	web3 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 
		-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 
		1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 
		-1.0, -1.0])

	# (Array, m): chord distribution for reference section, thickness of structural 
	# layup scaled with reference thickness (fixed t/c for this case)
	rotor.chord_str_ref = np.array([3.2612, 3.3100915356, 3.32587052924, 
		3.34159388653, 3.35823798667, 3.37384375335, 3.38939112914, 3.4774055542, 
		3.49839685, 3.51343645709, 3.87017220335, 4.04645623801, 4.19408216643,
	    4.47641008477, 4.55844487985, 4.57383098262, 4.57285771934, 4.51914315648, 
	    4.47677655262, 4.40075650022, 4.31069949379, 4.20483735936, 4.08985563932, 
	    3.82931757126, 3.74220276467, 3.54415796922, 3.38732428502, 3.24931446473, 
	    3.23421422609, 3.22701537997, 3.21972125648, 3.08979310611, 2.95152261813, 
	    2.330753331, 2.05553464181, 1.82577817774, 1.5860853279, 1.4621])* \
		np.true_divide(BladeLength,ReferenceBladeLength)


	for i in range(ncomp):
	    webLoc = []
	    if web1[i] != -1:
	        webLoc.append(web1[i])
	    if web2[i] != -1:
	        webLoc.append(web2[i])
	    if web3[i] != -1:
	        webLoc.append(web3[i])

	    upper[i], lower[i], webs[i] = CompositeSection.initFromPreCompLayupFile\
	    (os.path.join(basepath, 'layup_' + str(i+1) + '.inp'), webLoc, materials)
	    profile[i] = Profile.initFromPreCompFile(os.path.join(basepath, 'shape_' \
	    	+ str(i+1) + '.inp'))

	# (List): list of all Orthotropic2DMaterial objects used in 
	# defining the geometry
	rotor.materials = materials 

	# (List): list of CompositeSection objections defining the properties for 
	# upper surface
	rotor.upperCS = upper  

	# (List): list of CompositeSection objections defining the properties for 
	# lower surface
	rotor.lowerCS = lower  

	# (List): list of CompositeSection objections defining the properties for 
	# shear webs
	rotor.websCS = webs  

	# (List): airfoil shape at each radial position
	rotor.profile = profile  
	# --------------------------------------


	# === fatigue ===

	# (Array): nondimensional radial locations of damage equivalent moments
	rotor.rstar_damage = np.array([0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300,
	 0.367, 0.433, 0.500, 0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978]) 


	# (Array, N*m): damage equivalent moments about blade c.s. x-direction
	rotor.Mxb_damage = 1e3*np.array([2.3743E+003, 2.0834E+003, 1.8108E+003, 
		1.5705E+003, 1.3104E+003, 1.0488E+003, 8.2367E+002, 6.3407E+002, 
		4.7727E+002, 3.4804E+002, 2.4458E+002, 1.6339E+002, 1.0252E+002,
		 5.7842E+001, 2.7349E+001, 1.1262E+001, 3.8549E+000, 4.4738E-001])  

	# (Array, N*m): damage equivalent moments about blade c.s. y-direction
	rotor.Myb_damage = 1e3*np.array([2.7732E+003, 2.8155E+003, 2.6004E+003, 
		2.3933E+003, 2.1371E+003, 1.8459E+003, 1.5582E+003, 1.2896E+003, 
		1.0427E+003, 8.2015E+002, 6.2449E+002, 4.5229E+002, 3.0658E+002, 
		1.8746E+002, 9.6475E+001, 4.2677E+001, 1.5409E+001, 1.8426E+000])  

	rotor.strain_ult_spar = 1.0e-2  # (Float): ultimate strain in spar cap

	# (Float): uptimate strain in trailing-edge panels, note that I am putting a 
	# factor of two for the damage part only.
	rotor.strain_ult_te = 2500*1e-6 * 2  
	rotor.eta_damage = 1.35*1.3*1.0  # (Float): safety factor for fatigue
	rotor.m_damage = 10.0  # (Float): slope of S-N curve for fatigue analysis

	# (Float): number of cycles used in fatigue analysis  
	rotor.N_damage = 365*24*3600*20.0  
	# ----------------

	# from myutilities import plt

	# === run and outputs ===
	rotor.run()

	# Evaluate AEP Using Lewis' Functions
	# Weibull Wind Parameters
	WindReferenceHeight = 50
	WindReferenceMeanVelocity = 7.5
	WeibullShapeFactor = 2.0
	ShearFactor = 0.25

	PowerCurve = rotor.P/1e6
	PowerCurveVelocity = rotor.V

	HubHeight = rotor.hubHt

	AEP,WeibullScale = CalculateAEPWeibull(PowerCurve,PowerCurveVelocity, HubHeight, \
	  	BladeLength,WeibullShapeFactor, WindReferenceHeight, \
	  	WindReferenceMeanVelocity, ShearFactor)

	NamePlateCapacity = EstimateCapacity(PowerCurve,PowerCurveVelocity, \
		rotor.ratedConditions.V)

	# AEP At Constant 7.5m/s Wind used for benchmarking...
	#AEP = CalculateAEPConstantWind(PowerCurve, PowerCurveVelocity, 7.5)

	if (Verbose ==True):
		print '###################     ROTORSE   ######################'
		print 'AEP = %d MWH' %(AEP)
		print 'NamePlateCapacity = %fMW' %(NamePlateCapacity)
		print 'diameter =', rotor.diameter
		print 'ratedConditions.V =', rotor.ratedConditions.V
		print 'ratedConditions.Omega =', rotor.ratedConditions.Omega
		print 'ratedConditions.pitch =', rotor.ratedConditions.pitch
		print 'mass_one_blade =', rotor.mass_one_blade
		print 'mass_all_blades =', rotor.mass_all_blades
		print 'I_all_blades =', rotor.I_all_blades
		print 'freq =', rotor.freq
		print 'tip_deflection =', rotor.tip_deflection
		print 'root_bending_moment =', rotor.root_bending_moment
		print '#########################################################'

	#############################################################################
	### 2. Hub Sizing 
	# Specify hub parameters based off rotor

	# Load default hub model
	hubS = HubSE()
	hubS.rotor_diameter = rotor.Rtip*2 # m
	hubS.blade_number  = rotor.nBlades
	hubS.blade_root_diameter = rotor.chord_sub[0]*1.25
	hubS.L_rb = rotor.hubFraction*rotor.diameter
	hubS.MB1_location = np.array([-0.5, 0.0, 0.0])
	hubS.machine_rating = rotor.control.ratedPower
	hubS.blade_mass = rotor.mass_one_blade
	hubS.rotor_bending_moment = rotor.root_bending_moment

	hubS.run()

	RotorTotalWeight = rotor.mass_all_blades + hubS.spinner.mass + \
	hubS.hub.mass + hubS.pitchSystem.mass

	if (Verbose==True):
		print '##################### Hub SE ############################'
		print "Estimate of Hub Component Sizes:"
		print "Hub Components"
		print '  Hub: {0:8.1f} kg'.format(hubS.hub.mass)
		print '  Pitch system: {0:8.1f} kg'.format(hubS.pitchSystem.mass) 
		print '  Nose cone: {0:8.1f} kg'.format(hubS.spinner.mass)
		print 'Rotor Total Weight = %d kg' %RotorTotalWeight
		print '#########################################################'


	############################################################################
	### 3. Drive train + Nacelle Mass estimation
	nace = Drive4pt()
	nace.rotor_diameter = rotor.Rtip *2 # m
	nace.rotor_speed = rotor.ratedConditions.Omega # #rpm m/s
	nace.machine_rating = hubS.machine_rating/1000
	nace.DrivetrainEfficiency = 0.95

	 # 6.35e6 #4365248.74 # Nm
	nace.rotor_torque =  rotor.ratedConditions.Q
	nace.rotor_thrust = rotor.ratedConditions.T # N
	nace.rotor_mass = 0.0 #accounted for in F_z # kg

	nace.rotor_bending_moment_x = rotor.Mxyz_0[0]
	nace.rotor_bending_moment_y = rotor.Mxyz_0[1]
	nace.rotor_bending_moment_z = rotor.Mxyz_0[2]

	nace.rotor_force_x = rotor.Fxyz_0[0] # N
	nace.rotor_force_y = rotor.Fxyz_0[1]
	nace.rotor_force_z = rotor.Fxyz_0[2] # N

	# geared 3-stage Gearbox with induction generator machine
	nace.drivetrain_design = 'geared' 
	nace.gear_ratio = 96.76 # 97:1 as listed in the 5 MW reference document
	nace.gear_configuration = 'eep' # epicyclic-epicyclic-parallel

	nace.crane = True # onboard crane present
	nace.shaft_angle = 5.0 #deg
	nace.shaft_ratio = 0.10
	nace.Np = [3,3,1]
	nace.ratio_type = 'optimal'
	nace.shaft_type = 'normal'
	nace.uptower_transformer=False
	nace.shrink_disc_mass = 333.3*nace.machine_rating/1000.0 # estimated
	nace.mb1Type = 'CARB'
	nace.mb2Type = 'SRB'
	nace.flange_length = 0.5 #m
	nace.overhang = 5.0
	nace.gearbox_cm = 0.1
	nace.hss_length = 1.5

	#0 if no fatigue check, 1 if parameterized fatigue check, 
	#2 if known loads inputs
	nace.check_fatigue = 0 
	nace.blade_number=rotor.nBlades
	nace.cut_in=rotor.control.Vin #cut-in m/s
	nace.cut_out=rotor.control.Vout #cut-out m/s
	nace.Vrated=rotor.ratedConditions.V #rated windspeed m/s
	nace.weibull_k = WeibullShapeFactor # windepeed distribution shape parameter

	# windspeed distribution scale parameter
	nace.weibull_A = WeibullScale  

	nace.T_life=20. #design life in years
	nace.IEC_Class_Letter = 'B'

	# length from hub center to main bearing, leave zero if unknown
	nace.L_rb = hubS.L_rb 

	# NREL 5 MW Tower Variables
	nace.tower_top_diameter = 3.78 # m

	nace.run()

	if (Verbose==True):
		print '##################### Drive SE ############################'
		print "Estimate of Nacelle Component Sizes"
		print 'Low speed shaft: {0:8.1f} kg'.format(nace.lowSpeedShaft.mass)
		print 'Main bearings: {0:8.1f} kg'.format(\
			nace.mainBearing.mass + nace.secondBearing.mass)
		print 'Gearbox: {0:8.1f} kg'.format(nace.gearbox.mass)
		print 'High speed shaft & brakes: {0:8.1f} kg'.format\
			(nace.highSpeedSide.mass)
		print 'Generator: {0:8.1f} kg'.format(nace.generator.mass)
		print 'Variable speed electronics: {0:8.1f} kg'.format(\
			nace.above_yaw_massAdder.vs_electronics_mass)
		print 'Overall mainframe:{0:8.1f} kg'.format(\
			nace.above_yaw_massAdder.mainframe_mass)
		print '     Bedplate: {0:8.1f} kg'.format(nace.bedplate.mass)
		print 'Electrical connections: {0:8.1f} kg'.format(\
			nace.above_yaw_massAdder.electrical_mass)
		print 'HVAC system: {0:8.1f} kg'.format(\
			nace.above_yaw_massAdder.hvac_mass )
		print 'Nacelle cover: {0:8.1f} kg'.format(\
			nace.above_yaw_massAdder.cover_mass)
		print 'Yaw system: {0:8.1f} kg'.format(nace.yawSystem.mass)
		print 'Overall nacelle: {0:8.1f} kg'.format(nace.nacelle_mass, \
			nace.nacelle_cm[0], nace.nacelle_cm[1], nace.nacelle_cm[2], \
			nace.nacelle_I[0], nace.nacelle_I[1], nace.nacelle_I[2])  
		print '#########################################################'


	############################################################################
	### 4. Tower Mass

	# --- tower setup ------
	from commonse.environment import PowerWind

	tower = set_as_top(TowerSE())

	# ---- tower ------
	tower.replace('wind1', PowerWind())
	tower.replace('wind2', PowerWind())
	# onshore (no waves)

	# --- geometry ----
	tower.z_param = [0.0, HubHeight*0.5, HubHeight]
	TowerRatio = np.true_divide(HubHeight,ReferenceTowerHeight)

	tower.d_param = [6.0*TowerRatio, 4.935*TowerRatio, 3.87*TowerRatio]
	tower.t_param = [0.027*1.3*TowerRatio, 0.023*1.3*TowerRatio, \
	0.019*1.3*TowerRatio]
	n = 10

	tower.z_full = np.linspace(0.0, HubHeight, n)
	tower.L_reinforced = 15.0*np.ones(n)  # [m] buckling length
	tower.theta_stress = 0.0*np.ones(n)
	tower.yaw = 0.0

	# --- material props ---
	tower.E = 210e9*np.ones(n)
	tower.G = 80.8e9*np.ones(n)
	tower.rho = 8500.0*np.ones(n)
	tower.sigma_y = 450.0e6*np.ones(n)

	# --- spring reaction data.  Use float('inf') for rigid constraints. ---
	tower.kidx = [0]  # applied at base
	tower.kx = [float('inf')]
	tower.ky = [float('inf')]
	tower.kz = [float('inf')]
	tower.ktx = [float('inf')]
	tower.kty = [float('inf')]
	tower.ktz = [float('inf')]

	# --- extra mass ----
	tower.midx = [n-1]  # RNA mass at top
	tower.m = [0.8]
	tower.mIxx = [1.14930678e+08]
	tower.mIyy = [2.20354030e+07]
	tower.mIzz = [1.87597425e+07]
	tower.mIxy = [0.00000000e+00]
	tower.mIxz = [5.03710467e+05]
	tower.mIyz = [0.00000000e+00]
	tower.mrhox = [-1.13197635]
	tower.mrhoy = [0.]
	tower.mrhoz = [0.50875268]
	tower.addGravityLoadForExtraMass = False
	# -----------

	# --- wind ---
	tower.wind_zref = 90.0
	tower.wind_z0 = 0.0
	tower.wind1.shearExp = 0.14
	tower.wind2.shearExp = 0.14
	# ---------------

	# # --- loading case 1: max Thrust ---
	tower.wind_Uref1 = 11.73732
	tower.plidx1 = [n-1]  # at tower top
	tower.Fx1 = [0.19620519]
	tower.Fy1 = [0.]
	tower.Fz1 = [-2914124.84400512]
	tower.Mxx1 = [3963732.76208099]
	tower.Myy1 = [-2275104.79420872]
	tower.Mzz1 = [-346781.68192839]
	# # ---------------

	# # --- loading case 2: max wind speed ---
	tower.wind_Uref2 = 70.0
	tower.plidx1 = [n-1]  # at tower top
	tower.Fx1 = [930198.60063279]
	tower.Fy1 = [0.]
	tower.Fz1 = [-2883106.12368949]
	tower.Mxx1 = [-1683669.22411597]
	tower.Myy1 = [-2522475.34625363]
	tower.Mzz1 = [147301.97023764]
	# # ---------------

	# # --- run ---
	tower.run()

	if (Verbose==True):
		print '##################### Tower SE ##########################'
		print 'mass (kg) =', tower.mass
		print 'f1 (Hz) =', tower.f1
		print 'f2 (Hz) =', tower.f2
		print 'top_deflection1 (m) =', tower.top_deflection1
		print 'top_deflection2 (m) =', tower.top_deflection2
		print '#########################################################'


	############################################################################
	## 5. Turbine captial costs analysis
	turbine = Turbine_CostsSE()

	# NREL 5 MW turbine component masses based on Sunderland model approach
	# Rotor
	# inline with the windpact estimates
	turbine.blade_mass = rotor.mass_one_blade  
	turbine.hub_mass = hubS.hub.mass
	turbine.pitch_system_mass = hubS.pitchSystem.mass
	turbine.spinner_mass = hubS.spinner.mass

	# Drivetrain and Nacelle
	turbine.low_speed_shaft_mass = nace.lowSpeedShaft.mass
	turbine.main_bearing_mass=nace.mainBearing.mass 
	turbine.second_bearing_mass = nace.secondBearing.mass
	turbine.gearbox_mass = nace.gearbox.mass
	turbine.high_speed_side_mass = nace.highSpeedSide.mass
	turbine.generator_mass = nace.generator.mass
	turbine.bedplate_mass = nace.bedplate.mass
	turbine.yaw_system_mass = nace.yawSystem.mass

	# Tower
	turbine.tower_mass = tower.mass*0.5

	# Additional non-mass cost model input variables
	turbine.machine_rating = hubS.machine_rating/1000
	turbine.advanced = False
	turbine.blade_number = rotor.nBlades
	turbine.drivetrain_design = 'geared'
	turbine.crane = False
	turbine.offshore = False

	# Target year for analysis results
	turbine.year = 2010
	turbine.month =  12

	turbine.run()

	if (Verbose==True):
		print '##################### TurbinePrice SE ####################'
		print "Overall rotor cost with 3 advanced blades is ${0:.2f} USD"\
			.format(turbine.rotorCC.cost)
		print "Blade cost is ${0:.2f} USD".format(turbine.rotorCC.bladeCC.cost)
		print "Hub cost is ${0:.2f} USD".format(turbine.rotorCC.hubCC.cost)
		print "Pitch system cost is ${0:.2f} USD".format(turbine.rotorCC.pitchSysCC.cost)
		print "Spinner cost is ${0:.2f} USD".format(turbine.rotorCC.spinnerCC.cost)
		print
		print "Overall nacelle cost is ${0:.2f} USD".format(turbine.nacelleCC.cost)
		print "LSS cost is ${0:.2f} USD".format(turbine.nacelleCC.lssCC.cost)
		print "Main bearings cost is ${0:.2f} USD".format(turbine.nacelleCC.bearingsCC.cost)
		print "Gearbox cost is ${0:.2f} USD".format(turbine.nacelleCC.gearboxCC.cost)
		print "Hight speed side cost is ${0:.2f} USD".format(turbine.nacelleCC.hssCC.cost)
		print "Generator cost is ${0:.2f} USD".format(turbine.nacelleCC.generatorCC.cost)
		print "Bedplate cost is ${0:.2f} USD".format(turbine.nacelleCC.bedplateCC.cost)
		print "Yaw system cost is ${0:.2f} USD".format(turbine.nacelleCC.yawSysCC.cost)
		print
		print "Tower cost is ${0:.2f} USD".format(turbine.towerCC.cost)
		print
		print "The overall turbine cost is ${0:.2f} USD".format(turbine.turbine_cost)
		print '#########################################################'

	############################################################################
	## 6. Operating Expenses

	# A simple test of nrel_csm_bos model
	bos = bos_csm_assembly()

	# Set input parameters
	bos = bos_csm_assembly()
	bos.machine_rating = hubS.machine_rating/1000
	bos.rotor_diameter = rotor.diameter
	bos.turbine_cost = turbine.turbine_cost
	bos.hub_height = HubHeight
	bos.turbine_number = 1
	bos.sea_depth = 0
	bos.year = 2009
	bos.month = 12
	bos.multiplier = 1.0
	bos.run()

	om = opex_csm_assembly()

	om.machine_rating = rotor.control.ratedPower/1000  
	# Need to manipulate input or underlying component will not execute
	om.net_aep = AEP*10e4
	om.sea_depth = 0
	om.year = 2009
	om.month = 12
	om.turbine_number = 100

	om.run()

	if (Verbose==True):
		print '##################### Operating Costs ####################'
		print "BOS cost per turbine: ${0:.2f} USD".format(bos.bos_costs / \
			bos.turbine_number)
		print "Average annual operational expenditures"
		print "OPEX on shore with 100 turbines ${:.2f}: USD".format(\
			om.avg_annual_opex)
		print "Preventative OPEX by turbine: ${:.2f} USD".format(\
			om.opex_breakdown.preventative_opex / om.turbine_number)
		print "Corrective OPEX by turbine: ${:.2f} USD".format(\
			om.opex_breakdown.corrective_opex / om.turbine_number)
		print "Land Lease OPEX by turbine: ${:.2f} USD".format(\
			om.opex_breakdown.lease_opex / om.turbine_number)
		print '#########################################################'

	CapitalCost = turbine.turbine_cost + bos.bos_costs / bos.turbine_number
	OperatingCost = om.opex_breakdown.preventative_opex / om.turbine_number + \
	om.opex_breakdown.lease_opex / om.turbine_number + \
	om.opex_breakdown.corrective_opex / om.turbine_number

	LCOE = ComputeLCOE(AEP, CapitalCost, OperatingCost, DiscountRate, Years)

	print '######################***********************###################'
	print "Levelized Cost of Energy over %d years \
	is $%f/kWH" %(Years,LCOE/1000)
	print '######################***********************###################'

	return LCOE/1000
def example(wind_class='I',sea_depth=0.0,with_new_nacelle=False,with_landbos=False,flexible_blade=False,with_3pt_drive=False, with_ecn_opex=False, ecn_file=None,with_openwind=False,ow_file=None,ow_wkbook=None):
    """
    Inputs:
        wind_class : str ('I', 'III', 'Offshore' - selected wind class for project)
        sea_depth : float (sea depth if an offshore wind plant)
    """

    # === Create LCOE SE assembly ========
    lcoe_se = lcoe_se_assembly(with_new_nacelle,with_landbos,flexible_blade,with_3pt_drive,with_ecn_opex,ecn_file)

    # === Set assembly variables and objects ===
    lcoe_se.sea_depth = sea_depth # 0.0 for land-based turbine
    lcoe_se.turbine_number = 100
    lcoe_se.year = 2009
    lcoe_se.month = 12

    rotor = lcoe_se.rotor
    nacelle = lcoe_se.nacelle
    jacket = lcoe_se.jacket
    tcc_a = lcoe_se.tcc_a
    # bos_a = lcoe_se.bos_a
    # opex_a = lcoe_se.opex_a
    aep_a = lcoe_se.aep_a
    fin_a = lcoe_se.fin_a

    # Turbine ===========
    from wisdem.reference_turbines.nrel5mw.nrel5mw_jacket import configure_nrel5mw_turbine_with_jacket
    configure_nrel5mw_turbine_with_jacket(lcoe_se,wind_class,lcoe_se.sea_depth)

    # TODO: these should be specified at the turbine level and connected to other system inputs
    lcoe_se.tower_dt = 3.87  # (Array, m): diameters along tower # float for jacket
    lcoe_se.generator_speed = 1173.7  # (Float, rpm)  # generator speed
    # extra variable constant for now
    #lcoe_se.nacelle.bedplate.rotor_bending_moment_y = -2.3250E+06 # shouldnt be needed anymore

    # tcc ====
    lcoe_se.advanced_blade = True
    lcoe_se.offshore = False
    lcoe_se.assemblyCostMultiplier = 0.30
    lcoe_se.profitMultiplier = 0.20
    lcoe_se.overheadCostMultiplier = 0.0
    lcoe_se.transportMultiplier = 0.0

    # for new landBOS
    ''' # === new landBOS ===
    lcoe_se.voltage = 137
    lcoe_se.distInter = 5
    lcoe_se.terrain = 'FLAT_TO_ROLLING'
    lcoe_se.layout = 'SIMPLE'
    lcoe_se.soil = 'STANDARD' '''

    # aep ====
    if not with_openwind:
        lcoe_se.array_losses = 0.059
    lcoe_se.other_losses = 0.0
    if not with_ecn_opex:
        lcoe_se.availability = 0.94

    # fin ===
    lcoe_se.fixed_charge_rate = 0.095
    lcoe_se.construction_finance_rate = 0.0
    lcoe_se.tax_rate = 0.4
    lcoe_se.discount_rate = 0.07
    lcoe_se.construction_time = 1.0
    lcoe_se.project_lifetime = 20.0

    # Set plant level inputs ===
    shearExp = 0.2 #TODO : should be an input to lcoe
    rotor.cdf_reference_height_wind_speed = 90.0
    if not with_openwind:
        lcoe_se.array_losses = 0.1
    lcoe_se.other_losses = 0.0
    if not with_ecn_opex:
        lcoe_se.availability = 0.98
    rotor.turbulence_class = 'B'
    lcoe_se.multiplier = 2.23

    if wind_class == 'Offshore':
        # rotor.cdf_reference_mean_wind_speed = 8.4 # TODO - aep from its own module
        # rotor.cdf_reference_height_wind_speed = 50.0
        # rotor.weibull_shape = 2.1
        shearExp = 0.14 # TODO : should be an input to lcoe
        lcoe_se.array_losses = 0.15
        if not with_ecn_opex:
            lcoe_se.availability = 0.96
        lcoe_se.offshore = True
        lcoe_se.multiplier = 2.33
        lcoe_se.fixed_charge_rate = 0.118

    rotor.shearExp = shearExp
    #tower.wind1.shearExp = shearExp # not needed for jacket
    #tower.wind2.shearExp = shearExp

    # ====




    from rotorse.precomp import Profile, Orthotropic2DMaterial, CompositeSection  # TODO: can just pass file names and do this initialization inside of rotor
    #from commonse.environment import PowerWind, TowerSoil
    #from wisdem.reference_turbines.nrel5mw.nrel5mw_jacket import configure_nrel5mw_turbine_with_jacket
    from commonse.utilities import print_vars

    #configure_nrel5mw_turbine_with_jacket(turbine)
    # print_vars(turbine, list_type='inputs', prefix='turbine')

    rotor = lcoe_se.rotor
    nacelle = lcoe_se.nacelle
    jacket = lcoe_se.jacket

    # =================

    # === Turbine Configuration ===

    # --- atmosphere ---
    lcoe_se.rho = 1.225  # (Float, kg/m**3): density of air
    lcoe_se.mu = 1.81206e-5  # (Float, kg/m/s): dynamic viscosity of air
    lcoe_se.shear_exponent = 0.2  # (Float): shear exponent
    lcoe_se.hub_height = 90.0  # (Float, m): hub height
    lcoe_se.turbine_class = 'I'  # (Enum): IEC turbine class
    lcoe_se.turbulence_class = 'B'  # (Enum): IEC turbulence class class
    lcoe_se.cdf_reference_height_wind_speed = 90.0  # (Float): reference hub height for IEC wind speed (used in CDF calculation)
    lcoe_se.g = 9.81  # (Float, m/s**2): acceleration of gravity
    lcoe_se.downwind = False  # (Bool): flag if rotor is downwind
    lcoe_se.generator_speed = 1173.7  # (Float, rpm)  # generator speed
    lcoe_se.tower_dt = 3.87
    # ----------------------

    # ============================


    # === rotor ===
    # --- blade grid ---
    rotor.initial_aero_grid = np.array([0.02222276, 0.06666667, 0.11111057, 0.16666667, 0.23333333, 0.3, 0.36666667,
        0.43333333, 0.5, 0.56666667, 0.63333333, 0.7, 0.76666667, 0.83333333, 0.88888943, 0.93333333,
        0.97777724])  # (Array): initial aerodynamic grid on unit radius
    rotor.initial_str_grid = np.array([0.0, 0.00492790457512, 0.00652942887106, 0.00813095316699, 0.00983257273154,
        0.0114340970275, 0.0130356213234, 0.02222276, 0.024446481932, 0.026048006228, 0.06666667, 0.089508406455,
        0.11111057, 0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 0.276686558545, 0.3, 0.333640766319,
        0.36666667, 0.400404310407, 0.43333333, 0.5, 0.520818918408, 0.56666667, 0.602196371696, 0.63333333,
        0.667358391486, 0.683573824984, 0.7, 0.73242031601, 0.76666667, 0.83333333, 0.88888943, 0.93333333, 0.97777724,
        1.0])  # (Array): initial structural grid on unit radius
    rotor.idx_cylinder_aero = 3  # (Int): first idx in r_aero_unit of non-cylindrical section, constant twist inboard of here
    rotor.idx_cylinder_str = 14  # (Int): first idx in r_str_unit of non-cylindrical section
    rotor.hubFraction = 0.025  # (Float): hub location as fraction of radius
    # ------------------

    # --- blade geometry ---
    rotor.r_aero = np.array([0.02222276, 0.06666667, 0.11111057, 0.2, 0.23333333, 0.3, 0.36666667, 0.43333333,
        0.5, 0.56666667, 0.63333333, 0.64, 0.7, 0.83333333, 0.88888943, 0.93333333,
        0.97777724])  # (Array): new aerodynamic grid on unit radius
    rotor.r_max_chord = 0.23577  # (Float): location of max chord on unit radius
    rotor.chord_sub = [3.2612, 4.5709, 3.3178, 1.4621]  # (Array, m): chord at control points. defined at hub, then at linearly spaced locations from r_max_chord to tip
    rotor.theta_sub = [13.2783, 7.46036, 2.89317, -0.0878099]  # (Array, deg): twist at control points.  defined at linearly spaced locations from r[idx_cylinder] to tip
    rotor.precurve_sub = [0.0, 0.0, 0.0]  # (Array, m): precurve at control points.  defined at same locations at chord, starting at 2nd control point (root must be zero precurve)
    rotor.delta_precurve_sub = [0.0, 0.0, 0.0]  # (Array, m): adjustment to precurve to account for curvature from loading
    rotor.sparT = [0.05, 0.047754, 0.045376, 0.031085, 0.0061398]  # (Array, m): spar cap thickness parameters
    rotor.teT = [0.1, 0.09569, 0.06569, 0.02569, 0.00569]  # (Array, m): trailing-edge thickness parameters
    rotor.bladeLength = 61.5  # (Float, m): blade length (if not precurved or swept) otherwise length of blade before curvature
    rotor.delta_bladeLength = 0.0  # (Float, m): adjustment to blade length to account for curvature from loading
    rotor.precone = 2.5  # (Float, deg): precone angle
    rotor.tilt = 5.0  # (Float, deg): shaft tilt
    rotor.yaw = 0.0  # (Float, deg): yaw error
    rotor.nBlades = 3  # (Int): number of blades
    # ------------------

    # --- airfoil files ---
    import rotorse
    basepath = os.path.join(os.path.dirname(rotorse.__file__), '5MW_AFFiles')
    # basepath = os.path.join(os.path.dirname(os.path.realpath(__file__)), '5MW_AFFiles')

    # load all airfoils
    airfoil_types = [0]*8
    airfoil_types[0] = os.path.join(basepath, 'Cylinder1.dat')
    airfoil_types[1] = os.path.join(basepath, 'Cylinder2.dat')
    airfoil_types[2] = os.path.join(basepath, 'DU40_A17.dat')
    airfoil_types[3] = os.path.join(basepath, 'DU35_A17.dat')
    airfoil_types[4] = os.path.join(basepath, 'DU30_A17.dat')
    airfoil_types[5] = os.path.join(basepath, 'DU25_A17.dat')
    airfoil_types[6] = os.path.join(basepath, 'DU21_A17.dat')
    airfoil_types[7] = os.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]

    n = len(af_idx)
    af = [0]*n
    for i in range(n):
        af[i] = airfoil_types[af_idx[i]]
    rotor.airfoil_files = af  # (List): names of airfoil file
    # ----------------------

    # --- control ---
    rotor.control.Vin = 3.0  # (Float, m/s): cut-in wind speed
    rotor.control.Vout = 25.0  # (Float, m/s): cut-out wind speed
    #rotor.control.ratedPower = 5e6  # (Float, W): rated power
    lcoe_se.machine_rating = 5e3 # (Float, kW): rated power
    rotor.control.minOmega = 0.0  # (Float, rpm): minimum allowed rotor rotation speed
    rotor.control.maxOmega = 12.0  # (Float, rpm): maximum allowed rotor rotation speed
    rotor.control.tsr = 7.55  # (Float): tip-speed ratio in Region 2 (should be optimized externally)
    rotor.control.pitch = 0.0  # (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines)
    rotor.pitch_extreme = 0.0  # (Float, deg): worst-case pitch at survival wind condition
    rotor.azimuth_extreme = 0.0  # (Float, deg): worst-case azimuth at survival wind condition
    rotor.VfactorPC = 0.7  # (Float): fraction of rated speed at which the deflection is assumed to representative throughout the power curve calculation
    # ----------------------

    # --- aero and structural analysis options ---
    rotor.nSector = 4  # (Int): number of sectors to divide rotor face into in computing thrust and power
    rotor.npts_coarse_power_curve = 20  # (Int): number of points to evaluate aero analysis at
    rotor.npts_spline_power_curve = 200  # (Int): number of points to use in fitting spline to power curve
    rotor.AEP_loss_factor = 1.0  # (Float): availability and other losses (soiling, array, etc.)
    rotor.drivetrainType = 'geared'  # (Enum)
    rotor.nF = 5  # (Int): number of natural frequencies to compute
    rotor.dynamic_amplication_tip_deflection = 1.35  # (Float): a dynamic amplification factor to adjust the static deflection calculation
    # ----------------------

    # --- materials and composite layup  ---
    basepath = os.path.join(os.path.dirname(rotorse.__file__), '5MW_PreCompFiles')
    # basepath = os.path.join(os.path.dirname(os.path.realpath(__file__)), '5MW_PrecompFiles')

    materials = Orthotropic2DMaterial.listFromPreCompFile(os.path.join(basepath, 'materials.inp'))

    ncomp = len(rotor.initial_str_grid)
    upper = [0]*ncomp
    lower = [0]*ncomp
    webs = [0]*ncomp
    profile = [0]*ncomp

    rotor.leLoc = np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.498, 0.497, 0.465, 0.447, 0.43, 0.411,
        0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4,
        0.4, 0.4, 0.4, 0.4])    # (Array): array of leading-edge positions from a reference blade axis (usually blade pitch axis). locations are normalized by the local chord length. e.g. leLoc[i] = 0.2 means leading edge is 0.2*chord[i] from reference axis.  positive in -x direction for airfoil-aligned coordinate system
    rotor.sector_idx_strain_spar = [2]*ncomp  # (Array): index of sector for spar (PreComp definition of sector)
    rotor.sector_idx_strain_te = [3]*ncomp  # (Array): index of sector for trailing-edge (PreComp definition of sector)
    web1 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.4114, 0.4102, 0.4094, 0.3876, 0.3755, 0.3639, 0.345, 0.3342, 0.3313, 0.3274, 0.323, 0.3206, 0.3172, 0.3138, 0.3104, 0.307, 0.3003, 0.2982, 0.2935, 0.2899, 0.2867, 0.2833, 0.2817, 0.2799, 0.2767, 0.2731, 0.2664, 0.2607, 0.2562, 0.1886, -1.0])
    web2 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.5886, 0.5868, 0.5854, 0.5508, 0.5315, 0.5131, 0.4831, 0.4658, 0.4687, 0.4726, 0.477, 0.4794, 0.4828, 0.4862, 0.4896, 0.493, 0.4997, 0.5018, 0.5065, 0.5101, 0.5133, 0.5167, 0.5183, 0.5201, 0.5233, 0.5269, 0.5336, 0.5393, 0.5438, 0.6114, -1.0])
    web3 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0])
    rotor.chord_str_ref = np.array([3.2612, 3.3100915356, 3.32587052924, 3.34159388653, 3.35823798667, 3.37384375335,
        3.38939112914, 3.4774055542, 3.49839685, 3.51343645709, 3.87017220335, 4.04645623801, 4.19408216643,
         4.47641008477, 4.55844487985, 4.57383098262, 4.57285771934, 4.51914315648, 4.47677655262, 4.40075650022,
         4.31069949379, 4.20483735936, 4.08985563932, 3.82931757126, 3.74220276467, 3.54415796922, 3.38732428502,
         3.24931446473, 3.23421422609, 3.22701537997, 3.21972125648, 3.08979310611, 2.95152261813, 2.330753331,
         2.05553464181, 1.82577817774, 1.5860853279, 1.4621])  # (Array, m): chord distribution for reference section, thickness of structural layup scaled with reference thickness (fixed t/c for this case)

    for i in range(ncomp):

        webLoc = []
        if web1[i] != -1:
            webLoc.append(web1[i])
        if web2[i] != -1:
            webLoc.append(web2[i])
        if web3[i] != -1:
            webLoc.append(web3[i])

        upper[i], lower[i], webs[i] = CompositeSection.initFromPreCompLayupFile(os.path.join(basepath, 'layup_' + str(i+1) + '.inp'), webLoc, materials)
        profile[i] = Profile.initFromPreCompFile(os.path.join(basepath, 'shape_' + str(i+1) + '.inp'))

    rotor.materials = materials  # (List): list of all Orthotropic2DMaterial objects used in defining the geometry
    rotor.upperCS = upper  # (List): list of CompositeSection objections defining the properties for upper surface
    rotor.lowerCS = lower  # (List): list of CompositeSection objections defining the properties for lower surface
    rotor.websCS = webs  # (List): list of CompositeSection objections defining the properties for shear webs
    rotor.profile = profile  # (List): airfoil shape at each radial position
    # --------------------------------------


    # --- fatigue ---
    rotor.rstar_damage = np.array([0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500,
        0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978])  # (Array): nondimensional radial locations of damage equivalent moments
    rotor.Mxb_damage = 1e3*np.array([2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003,
        1.0488E+003, 8.2367E+002, 6.3407E+002, 4.7727E+002, 3.4804E+002, 2.4458E+002, 1.6339E+002,
        1.0252E+002, 5.7842E+001, 2.7349E+001, 1.1262E+001, 3.8549E+000, 4.4738E-001])  # (Array, N*m): damage equivalent moments about blade c.s. x-direction
    rotor.Myb_damage = 1e3*np.array([2.7732E+003, 2.8155E+003, 2.6004E+003, 2.3933E+003, 2.1371E+003,
        1.8459E+003, 1.5582E+003, 1.2896E+003, 1.0427E+003, 8.2015E+002, 6.2449E+002, 4.5229E+002,
        3.0658E+002, 1.8746E+002, 9.6475E+001, 4.2677E+001, 1.5409E+001, 1.8426E+000])  # (Array, N*m): damage equivalent moments about blade c.s. y-direction
    rotor.strain_ult_spar = 1.0e-2  # (Float): ultimate strain in spar cap
    rotor.strain_ult_te = 2500*1e-6 * 2   # (Float): uptimate strain in trailing-edge panels, note that I am putting a factor of two for the damage part only.
    rotor.eta_damage = 1.35*1.3*1.0  # (Float): safety factor for fatigue
    rotor.m_damage = 10.0  # (Float): slope of S-N curve for fatigue analysis
    rotor.N_damage = 365*24*3600*20.0  # (Float): number of cycles used in fatigue analysis  TODO: make function of rotation speed
    # ----------------
    # =================

    # === nacelle ======
    nacelle.L_ms = 1.0  # (Float, m): main shaft length downwind of main bearing in low-speed shaft
    nacelle.L_mb = 2.5  # (Float, m): main shaft length in low-speed shaft

    nacelle.h0_front = 1.7  # (Float, m): height of Ibeam in bedplate front
    nacelle.h0_rear = 1.35  # (Float, m): height of Ibeam in bedplate rear

    # TODO: sync with rotor drivetrainType variable
    nacelle.drivetrain_design = 'geared'
    nacelle.crane = True  # (Bool): flag for presence of crane
    nacelle.bevel = 0  # (Int): Flag for the presence of a bevel stage - 1 if present, 0 if not
    nacelle.gear_configuration = 'eep'  # (Str): tring that represents the configuration of the gearbox (stage number and types)

    nacelle.Np = [3, 3, 1]  # (Array): number of planets in each stage
    nacelle.ratio_type = 'optimal'  # (Str): optimal or empirical stage ratios
    nacelle.shaft_type = 'normal'  # (Str): normal or short shaft length
    #nacelle.shaft_angle = 5.0  # (Float, deg): Angle of the LSS inclindation with respect to the horizontal
    nacelle.shaft_ratio = 0.10  # (Float): Ratio of inner diameter to outer diameter.  Leave zero for solid LSS
    #nacelle.shrink_disc_mass = 1000.0  # (Float, kg): Mass of the shrink disc
    nacelle.mb1Type = 'CARB'  # (Str): Main bearing type: CARB, TRB or SRB
    nacelle.mb2Type = 'SRB'  # (Str): Second bearing type: CARB, TRB or SRB
    nacelle.yaw_motors_number = 8.0  # (Float): number of yaw motors
    nacelle.uptower_transformer = True
    nacelle.flange_length = 0.5 #m
    nacelle.gearbox_cm = 0.1
    nacelle.hss_length = 1.5
    nacelle.overhang = 5.0 #TODO - should come from turbine configuration level

    nacelle.check_fatigue = 0 #0 if no fatigue check, 1 if parameterized fatigue check, 2 if known loads inputs

    # TODO: should come from rotor (these are FAST outputs)
    nacelle.DrivetrainEfficiency = 0.95
    nacelle.rotor_bending_moment_x = 330770.0# Nm
    nacelle.rotor_bending_moment_y = -16665000.0 # Nm
    nacelle.rotor_bending_moment_z = 2896300.0 # Nm
    nacelle.rotor_force_x = 599610.0 # N
    nacelle.rotor_force_y = 186780.0 # N
    nacelle.rotor_force_z = -842710.0 # N

    #nacelle.h0_rear = 1.35 # only used in drive smooth
    #nacelle.h0_front = 1.7

    # =================

    # === jacket ===
    #--- Set Jacket Input Parameters ---#
    Jcktins=JcktGeoInputs()
    Jcktins.nlegs =4
    Jcktins.nbays =5
    Jcktins.batter=12.
    Jcktins.dck_botz =16.
    Jcktins.dck_width=2*6.
    Jcktins.weld2D   =0.5
    Jcktins.VPFlag = True    #vertical pile T/F;  to enable piles in frame3DD set pileinputs.ndiv>0
    Jcktins.clamped= False    #whether or not the bottom of the structure is rigidly connected. Use False when equivalent spring constants are being used.
    Jcktins.AFflag = False  #whether or not to use apparent fixity piles
    Jcktins.PreBuildTPLvl = 5  #if >0, the TP is prebuilt according to rules per PreBuildTP

    #Soil inputs
    Soilinputs=SoilGeoInputs()
    Soilinputs.zbots   =-np.array([3.,5.,7.,15.,30.,50.])
    Soilinputs.gammas  =np.array([10000.,10000.,10000.,10000.,10000.,10000.])
    Soilinputs.cus     =np.array([60000.,60000.,60000.,60000.,60000.,60000.])
    Soilinputs.phis    =np.array([26.,26.,26.,26.,26.,26])#np.array([36.,33.,26.,37.,35.,37.5])#np.array([36.,33.,26.,37.,35.,37.5])
    Soilinputs.delta   =25.
    Soilinputs.sndflg   =True
    Soilinputs.PenderSwtch   =False #True
    Soilinputs.SoilSF   =1.

    Soilinputs2=copy.copy(Soilinputs) #Parked case. We assume same stiffness although this may not be the case under a different load

    #Water and wind inputs
    Waterinputs=WaterInputs()
    Waterinputs.wdepth   =30.
    Waterinputs.wlevel   =30. #Distance from bottom of structure to surface  THIS, I believe is no longer needed as piles may be negative in z, to check and remove in case
    Waterinputs.T=12.  #Wave Period
    Waterinputs.HW=10. #Wave Height
    Waterinputs.Cd=3.  #Drag Coefficient, enhanced to account for marine growth and other members not calculated
    Waterinputs.Cm=8.#2.  #ADded mass Coefficient

    Waterinputs2=copy.copy(Waterinputs)  #PARKED CONDITIONS - still max wave here
    Waterinputs.T=8.  #Wave Period
    Waterinputs.HW=4. #Wave Height

    Windinputs=WindInputs()
    Windinputs.Cdj=4.  #Drag Coefficient for jacket members, enhanced to account for TP drag not calculated otherwise
    Windinputs.Cdt=2  #Drag Coefficient for tower, enhanced to account for TP drag not calculated otherwise
    Windinputs.HH=100. #CHECK HOW THIS COMPLIES....
    Windinputs.U50HH=30. #assumed gust speed

    ## if turbine_jacket
    ##Windinputs.HH=90. #CHECK HOW THIS COMPLIES....
    ##Windinputs.U50HH=11.7373200354 # using rated loads
    ##Windinputs.rho = 1.225
    ##Windinputs.mu = 1.81206e-05

    Windinputs2=copy.copy(Windinputs)
    Windinputs2.U50HH=70. #assumed gust speed

    #Pile data
    Pilematin=MatInputs()
    Pilematin.matname=np.array(['steel'])
    Pilematin.E=np.array([ 25.e9])
    Dpile=2.5#0.75 # 2.0
    tpile=0.01
    Lp=20. #45

    Pileinputs=PileGeoInputs()
    Pileinputs.Pilematins=Pilematin
    Pileinputs.ndiv=0 #3
    Pileinputs.Dpile=Dpile
    Pileinputs.tpile=tpile
    Pileinputs.Lp=Lp #[m] Embedment length

    #Legs data
    legmatin=MatInputs()
    legmatin.matname=(['heavysteel','heavysteel','heavysteel','heavysteel'])
    #legmatin.E=np.array([2.0e11])
    Dleg=np.array([1.5,1.5,1.5,1.5,1.5,1.5])
    tleg=1.5*np.array([0.0254]).repeat(Dleg.size)
    leginputs=LegGeoInputs()
    leginputs.legZbot   = 1.0
    leginputs.ndiv=1
    leginputs.legmatins=legmatin
    leginputs.Dleg0=Dleg[0]
    leginputs.tleg0=tleg[0]

    legbot_stmphin =1.5  #Distance from bottom of leg to second joint along z; must be>0

    #Xbrc data
    Xbrcmatin=MatInputs()
    Xbrcmatin.matname=np.array(['heavysteel']).repeat(Jcktins.nbays)
    #Xbrcmatin.E=np.array([ 2.2e11, 2.0e11,2.0e11,2.0e11,2.0e11])
    Dbrc=np.array([1.,1.,1.0,1.0,1.0])
    tbrc=np.array([1.,1.,1.0,1.0,1.0])*0.0254

    Xbrcinputs=XBrcGeoInputs()
    Xbrcinputs.Dbrc0=Dbrc[0]
    Xbrcinputs.tbrc0=tbrc[0]
    Xbrcinputs.ndiv=2#2
    Xbrcinputs.Xbrcmatins=Xbrcmatin
    Xbrcinputs.precalc=False #True   #This can be set to true if we want Xbraces to be precalculated in D and t, in which case the above set Dbrc and tbrc would be overwritten

    #Mbrc data
    Mbrcmatin=MatInputs()
    Mbrcmatin.matname=np.array(['heavysteel'])
    #Mbrcmatin.E=np.array([ 2.5e11])
    Dbrc_mud=1.5

    Mbrcinputs=MudBrcGeoInputs()
    Mbrcinputs.Dbrc_mud=Dbrc_mud
    Mbrcinputs.ndiv=2
    Mbrcinputs.Mbrcmatins=Mbrcmatin
    Mbrcinputs.precalc=False #True   #This can be set to true if we want Mudbrace to be precalculated in D and t, in which case the above set Dbrc_mud and tbrc_mud would be overwritten

    #Hbrc data
    Hbrcmatin=MatInputs()
    Hbrcmatin.matname=np.array(['heavysteel'])
    Hbrcmatin.E=np.array([ 2.5e11])
    Dbrc_hbrc=1.1

    Hbrcinputs=HBrcGeoInputs()
    Hbrcinputs.Dbrch=Dbrc_hbrc
    Hbrcinputs.ndiv=0#2
    Hbrcinputs.Hbrcmatins=Hbrcmatin
    Hbrcinputs.precalc=True   #This can be set to true if we want Hbrace to be set=Xbrace top D and t, in which case the above set Dbrch and tbrch would be overwritten

    #TP data
    TPlumpinputs=TPlumpMass()
    TPlumpinputs.mass=200.e3 #[kg]

    TPstmpsmatin=MatInputs()
    TPbrcmatin=MatInputs()
    TPstemmatin=MatInputs()
    TPbrcmatin.matname=np.array(['heavysteel'])
    #TPbrcmatin.E=np.array([ 2.5e11])
    TPstemmatin.matname=np.array(['heavysteel']).repeat(2)
    #TPstemmatin.E=np.array([ 2.1e11]).repeat(2)

    TPinputs=TPGeoInputs()
    TPinputs.TPbrcmatins=TPbrcmatin
    TPinputs.TPstemmatins=TPstemmatin
    TPinputs.TPstmpmatins=TPstmpsmatin
    TPinputs.Dstrut=leginputs.Dleg[-1]
    TPinputs.tstrut=leginputs.tleg[-1]
    TPinputs.Dgir=Dbrc_hbrc
    TPinputs.tgir=0.0254
    TPinputs.Dbrc=1.1
    TPinputs.Dbrc=TPinputs.Dgir
    TPinputs.tbrc=TPinputs.tgir

    TPinputs.hstump=1.0#1.0
    TPinputs.Dstump=1.25#1.0
    TPinputs.stumpndiv=1#2
    TPinputs.brcndiv=1#2
    TPinputs.girndiv=1#2
    TPinputs.strutndiv=1#2
    TPinputs.stemndiv=1#2
    TPinputs.nstems=3
    TPinputs.Dstem=np.array([6.]).repeat(TPinputs.nstems)
    TPinputs.tstem=np.array([0.1,0.11,0.11])
    TPinputs.hstem=np.array([6./TPinputs.nstems]).repeat(TPinputs.nstems)

    #Tower data
    Twrmatin=MatInputs()
    Twrmatin.matname=np.array(['heavysteel'])
    #Twrmatin.E=np.array([ 2.77e11])
    Twrinputs=TwrGeoInputs()
    Twrinputs.Twrmatins=Twrmatin
    #Twrinputs.Htwr=70.  #Trumped by HH
    Twrinputs.Htwr2frac=0.2   #fraction of tower height with constant x-section
    Twrinputs.ndiv=np.array([6,12])  #ndiv for uniform and tapered section
    Twrinputs.DeltaZmax= 6. #[m], maximum FE element length allowed in the tower members (i.e. the uniform and the tapered members)
    Twrinputs.Db=5.6
    Twrinputs.DTRb=130.
    Twrinputs.DTRt=150.
    Twrinputs.Dt=0.55*Twrinputs.Db
    ## if turbine_jacket
    ##Twrinputs.Dt = 3.87

    TwrRigidTop=True #False       #False=Account for RNA via math rather than a physical rigidmember

    #RNA data
    RNAins=RNAprops()
    RNAins.mass=3*350.e3
    RNAins.I[0]=86.579E+6
    RNAins.I[1]=53.530E+6
    RNAins.I[2]=58.112E+6
    RNAins.CMoff[2]=2.34
    RNAins.yawangle=45.  #angle with respect to global X, CCW looking from above, wind from left
    RNAins.rna_weightM=True
    ## if turbine_jacket
    ##RNAins.mass=285598.806453
    ##RNAins.I = np.array([1.14930678e8, 2.20354030e7, 1.87597425e7, 0.0, 5.03710467e5, 0.0])
    ##RNAins.CMoff = np.array([-1.13197635, 0.0, 0.50875268])
    ##RNAins.yawangle=0.0  #angle with respect to global X, CCW looking from above, wind from left
    #RNAins.rna_weightM=True

    RNAins2=copy.copy(RNAins)  #PARKED CASE, for now assume the same

    #RNA loads              Fx-z,         Mxx-zz
    RNA_F=np.array([1000.e3,0.,0.,0.,0.,0.])    #operational
    RNA_F2=np.array([500.e3,0.,0.,0.,0.,0.])    #Parked
    ## if turbine_jacket
    ##RNA_F=np.array([1284744.19620519,0.,-2914124.84400512,3963732.76208099,-2275104.79420872,-346781.68192839])

    #Frame3DD parameters
    FrameAuxIns=Frame3DDaux()
    FrameAuxIns.sh_fg=1               #shear flag-->Timoshenko
    FrameAuxIns.deltaz=5.
    FrameAuxIns.geo_fg=0
    FrameAuxIns.nModes = 6             # number of desired dynamic modes of vibration
    FrameAuxIns.Mmethod = 1            # 1: subspace Jacobi     2: Stodola
    FrameAuxIns.lump = 0               # 0: consistent mass ... 1: lumped mass matrix
    FrameAuxIns.tol = 1e-9             # mode shape tolerance
    FrameAuxIns.shift = 0.0            # shift value ... for unrestrained structures
    FrameAuxIns.gvector=np.array([0.,0.,-9.8065])    #GRAVITY
    ## if turbine_jacket
    ##FrameAuxIns.gvector=np.array([0.,0.,-9.81])    #GRAVITY

    #Decide whether or not to consider DLC 6.1 as well
    twodlcs=False

    #-----Launch the assembly-----#

    #turbine.jacket=JacketSE(Jcktins.clamped,Jcktins.AFflag,twodlcs=twodlcs)
    #turbine.jacket=set_as_top(JacketSE(Jcktins.clamped,Jcktins.AFflag,twodlcs=twodlcs)) ##(Jcktins.PreBuildTPLvl>0),

    #Pass all inputs to assembly
    lcoe_se.jacket.JcktGeoIn=Jcktins

    lcoe_se.jacket.Soilinputs=Soilinputs
    lcoe_se.jacket.Soilinputs2=Soilinputs2   #Parked conditions

    lcoe_se.jacket.Waterinputs=Waterinputs
    lcoe_se.jacket.Windinputs=Windinputs
    lcoe_se.jacket.RNA_F=RNA_F
    lcoe_se.jacket.Waterinputs2=Waterinputs2 #Parked conditions
    lcoe_se.jacket.Windinputs2=Windinputs2   #Parked conditions
    lcoe_se.jacket.RNA_F2=RNA_F2            #Parked conditions

    lcoe_se.jacket.Pileinputs=Pileinputs
    lcoe_se.jacket.leginputs=leginputs
    #lcoe_se.jacket.legbot_stmphin =legbot_stmphin
    lcoe_se.jacket.Xbrcinputs=Xbrcinputs
    lcoe_se.jacket.Mbrcinputs=Mbrcinputs
    lcoe_se.jacket.Hbrcinputs=Hbrcinputs
    lcoe_se.jacket.TPlumpinputs=TPlumpinputs
    lcoe_se.jacket.TPinputs=TPinputs
    lcoe_se.jacket.RNAinputs=RNAins
    lcoe_se.jacket.RNAinputs2=RNAins2
    lcoe_se.jacket.Twrinputs=Twrinputs
    lcoe_se.jacket.TwrRigidTop=TwrRigidTop
    lcoe_se.jacket.FrameAuxIns=FrameAuxIns





    # === Run default assembly and print results
    lcoe_se.run()
    # ====

    # === Print ===

    print "Key Turbine Outputs for NREL 5 MW Reference Turbine"
    print 'mass rotor blades:{0:.2f} (kg) '.format(lcoe_se.rotor.mass_all_blades)
    print 'mass hub system: {0:.2f} (kg) '.format(lcoe_se.hub.hub_system_mass)
    print 'mass nacelle: {0:.2f} (kg) '.format(lcoe_se.nacelle.nacelle_mass)
    print 'mass tower: {0:.2f} (kg) '.format(lcoe_se.jacket.Tower.Twrouts.mass)
    print 'maximum tip deflection: {0:.2f} (m) '.format(lcoe_se.maxdeflection.max_tip_deflection)
    print 'ground clearance: {0:.2f} (m) '.format(lcoe_se.maxdeflection.ground_clearance)
    print
    print "Key Plant Outputs for wind plant with NREL 5 MW Turbine"
    #print "LCOE: ${0:.4f} USD/kWh".format(lcoe_se.lcoe) # not in base output set (add to assembly output if desired)
    print "COE: ${0:.4f} USD/kWh".format(lcoe_se.coe)
    print
    print "AEP per turbine: {0:.1f} kWh/turbine".format(lcoe_se.net_aep / lcoe_se.turbine_number)
    print "Turbine Cost: ${0:.2f} USD".format(lcoe_se.turbine_cost)
    print "BOS costs per turbine: ${0:.2f} USD/turbine".format(lcoe_se.bos_costs / lcoe_se.turbine_number)
    print "OPEX per turbine: ${0:.2f} USD/turbine".format(lcoe_se.avg_annual_opex / lcoe_se.turbine_number)    
Example #7
0
def configure_nrel5mw_turbine(turbine, wind_class="I", sea_depth=0.0):
    """
    Inputs:
        rotor = RotorSE()
        nacelle = DriveSE()
        tower = TowerSE()
        wind_class : str ('I', 'III', 'Offshore' - selected wind class for project)
        sea_depth : float (sea depth if an offshore wind plant)
    """

    # === Turbine ===
    turbine.rho = 1.225  # (Float, kg/m**3): density of air
    turbine.mu = 1.81206e-5  # (Float, kg/m/s): dynamic viscosity of air
    turbine.shear_exponent = 0.2  # (Float): shear exponent
    turbine.hub_height = 90.0  # (Float, m): hub height
    turbine.turbine_class = "I"  # (Enum): IEC turbine class
    turbine.turbulence_class = "B"  # (Enum): IEC turbulence class class
    turbine.cdf_reference_height_wind_speed = (
        90.0
    )  # (Float): reference hub height for IEC wind speed (used in CDF calculation)
    turbine.g = 9.81  # (Float, m/s**2): acceleration of gravity
    # ======================

    # === rotor ===
    # --- blade grid ---
    turbine.rotor.initial_aero_grid = np.array(
        [
            0.02222276,
            0.06666667,
            0.11111057,
            0.16666667,
            0.23333333,
            0.3,
            0.36666667,
            0.43333333,
            0.5,
            0.56666667,
            0.63333333,
            0.7,
            0.76666667,
            0.83333333,
            0.88888943,
            0.93333333,
            0.97777724,
        ]
    )  # (Array): initial aerodynamic grid on unit radius
    turbine.rotor.initial_str_grid = np.array(
        [
            0.0,
            0.00492790457512,
            0.00652942887106,
            0.00813095316699,
            0.00983257273154,
            0.0114340970275,
            0.0130356213234,
            0.02222276,
            0.024446481932,
            0.026048006228,
            0.06666667,
            0.089508406455,
            0.11111057,
            0.146462614229,
            0.16666667,
            0.195309105255,
            0.23333333,
            0.276686558545,
            0.3,
            0.333640766319,
            0.36666667,
            0.400404310407,
            0.43333333,
            0.5,
            0.520818918408,
            0.56666667,
            0.602196371696,
            0.63333333,
            0.667358391486,
            0.683573824984,
            0.7,
            0.73242031601,
            0.76666667,
            0.83333333,
            0.88888943,
            0.93333333,
            0.97777724,
            1.0,
        ]
    )  # (Array): initial structural grid on unit radius
    turbine.rotor.idx_cylinder_aero = (
        3
    )  # (Int): first idx in r_aero_unit of non-cylindrical section, constant twist inboard of here
    turbine.rotor.idx_cylinder_str = 14  # (Int): first idx in r_str_unit of non-cylindrical section
    turbine.rotor.hubFraction = 0.025  # (Float): hub location as fraction of radius
    # ------------------

    # --- blade geometry ---
    turbine.rotor.r_aero = np.array(
        [
            0.02222276,
            0.06666667,
            0.11111057,
            0.2,
            0.23333333,
            0.3,
            0.36666667,
            0.43333333,
            0.5,
            0.56666667,
            0.63333333,
            0.64,
            0.7,
            0.83333333,
            0.88888943,
            0.93333333,
            0.97777724,
        ]
    )  # (Array): new aerodynamic grid on unit radius
    turbine.rotor.r_max_chord = 0.23577  # (Float): location of max chord on unit radius
    turbine.rotor.chord_sub = [
        3.2612,
        4.5709,
        3.3178,
        1.4621,
    ]  # (Array, m): chord at control points. defined at hub, then at linearly spaced locations from r_max_chord to tip
    turbine.rotor.theta_sub = [
        13.2783,
        7.46036,
        2.89317,
        -0.0878099,
    ]  # (Array, deg): twist at control points.  defined at linearly spaced locations from r[idx_cylinder] to tip
    turbine.rotor.precurve_sub = [
        0.0,
        0.0,
        0.0,
    ]  # (Array, m): precurve at control points.  defined at same locations at chord, starting at 2nd control point (root must be zero precurve)
    turbine.rotor.delta_precurve_sub = [
        0.0,
        0.0,
        0.0,
    ]  # (Array, m): adjustment to precurve to account for curvature from loading
    turbine.rotor.sparT = [0.05, 0.047754, 0.045376, 0.031085, 0.0061398]  # (Array, m): spar cap thickness parameters
    turbine.rotor.teT = [0.1, 0.09569, 0.06569, 0.02569, 0.00569]  # (Array, m): trailing-edge thickness parameters
    turbine.rotor.bladeLength = (
        61.5
    )  # (Float, m): blade length (if not precurved or swept) otherwise length of blade before curvature
    turbine.rotor.delta_bladeLength = (
        0.0
    )  # (Float, m): adjustment to blade length to account for curvature from loading
    turbine.rotor.precone = 2.5  # (Float, deg): precone angle
    turbine.rotor.tilt = 5.0  # (Float, deg): shaft tilt
    turbine.rotor.yaw = 0.0  # (Float, deg): yaw error
    turbine.rotor.nBlades = 3  # (Int): number of blades
    # ------------------

    # --- airfoil files ---
    import rotorse

    # basepath = os.path.join('5MW_files', '5MW_AFFiles')
    basepath = os.path.join("..", "reference_turbines", "nrel5mw", "airfoils")

    # load all airfoils
    airfoil_types = [0] * 8
    airfoil_types[0] = os.path.join(basepath, "Cylinder1.dat")
    airfoil_types[1] = os.path.join(basepath, "Cylinder2.dat")
    airfoil_types[2] = os.path.join(basepath, "DU40_A17.dat")
    airfoil_types[3] = os.path.join(basepath, "DU35_A17.dat")
    airfoil_types[4] = os.path.join(basepath, "DU30_A17.dat")
    airfoil_types[5] = os.path.join(basepath, "DU25_A17.dat")
    airfoil_types[6] = os.path.join(basepath, "DU21_A17.dat")
    airfoil_types[7] = os.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]

    n = len(af_idx)
    af = [0] * n
    for i in range(n):
        af[i] = airfoil_types[af_idx[i]]
    turbine.rotor.airfoil_files = af  # (List): names of airfoil file
    # ----------------------

    # --- control ---
    turbine.rotor.control.Vin = 3.0  # (Float, m/s): cut-in wind speed
    turbine.rotor.control.Vout = 25.0  # (Float, m/s): cut-out wind speed
    turbine.rotor.control.ratedPower = 5e6  # (Float, W): rated power
    turbine.rotor.control.minOmega = 0.0  # (Float, rpm): minimum allowed rotor rotation speed
    turbine.rotor.control.maxOmega = 12.0  # (Float, rpm): maximum allowed rotor rotation speed
    turbine.rotor.control.tsr = 7.55  # (Float): tip-speed ratio in Region 2 (should be optimized externally)
    turbine.rotor.control.pitch = 0.0  # (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines)
    turbine.rotor.pitch_extreme = 0.0  # (Float, deg): worst-case pitch at survival wind condition
    turbine.rotor.azimuth_extreme = 0.0  # (Float, deg): worst-case azimuth at survival wind condition
    turbine.rotor.VfactorPC = (
        0.7
    )  # (Float): fraction of rated speed at which the deflection is assumed to representative throughout the power curve calculation
    # ----------------------

    # --- aero and structural analysis options ---
    turbine.rotor.nSector = 4  # (Int): number of sectors to divide rotor face into in computing thrust and power
    turbine.rotor.npts_coarse_power_curve = 20  # (Int): number of points to evaluate aero analysis at
    turbine.rotor.npts_spline_power_curve = 200  # (Int): number of points to use in fitting spline to power curve
    turbine.rotor.AEP_loss_factor = 1.0  # (Float): availability and other losses (soiling, array, etc.)
    turbine.rotor.drivetrainType = "geared"  # (Enum)
    turbine.rotor.nF = 5  # (Int): number of natural frequencies to compute
    turbine.rotor.dynamic_amplication_tip_deflection = (
        1.35
    )  # (Float): a dynamic amplification factor to adjust the static deflection calculation
    # ----------------------

    # --- materials and composite layup  ---
    # basepath = os.path.join('5MW_files', '5MW_PrecompFiles')
    basepath = os.path.join("..", "reference_turbines", "nrel5mw", "blade")

    materials = Orthotropic2DMaterial.listFromPreCompFile(os.path.join(basepath, "materials.inp"))

    ncomp = len(turbine.rotor.initial_str_grid)
    upper = [0] * ncomp
    lower = [0] * ncomp
    webs = [0] * ncomp
    profile = [0] * ncomp

    turbine.rotor.leLoc = np.array(
        [
            0.5,
            0.5,
            0.5,
            0.5,
            0.5,
            0.5,
            0.5,
            0.5,
            0.498,
            0.497,
            0.465,
            0.447,
            0.43,
            0.411,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
            0.4,
        ]
    )  # (Array): array of leading-edge positions from a reference blade axis (usually blade pitch axis). locations are normalized by the local chord length. e.g. leLoc[i] = 0.2 means leading edge is 0.2*chord[i] from reference axis.  positive in -x direction for airfoil-aligned coordinate system
    turbine.rotor.sector_idx_strain_spar = [
        2
    ] * ncomp  # (Array): index of sector for spar (PreComp definition of sector)
    turbine.rotor.sector_idx_strain_te = [
        3
    ] * ncomp  # (Array): index of sector for trailing-edge (PreComp definition of sector)
    web1 = np.array(
        [
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            0.4114,
            0.4102,
            0.4094,
            0.3876,
            0.3755,
            0.3639,
            0.345,
            0.3342,
            0.3313,
            0.3274,
            0.323,
            0.3206,
            0.3172,
            0.3138,
            0.3104,
            0.307,
            0.3003,
            0.2982,
            0.2935,
            0.2899,
            0.2867,
            0.2833,
            0.2817,
            0.2799,
            0.2767,
            0.2731,
            0.2664,
            0.2607,
            0.2562,
            0.1886,
            -1.0,
        ]
    )
    web2 = np.array(
        [
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            0.5886,
            0.5868,
            0.5854,
            0.5508,
            0.5315,
            0.5131,
            0.4831,
            0.4658,
            0.4687,
            0.4726,
            0.477,
            0.4794,
            0.4828,
            0.4862,
            0.4896,
            0.493,
            0.4997,
            0.5018,
            0.5065,
            0.5101,
            0.5133,
            0.5167,
            0.5183,
            0.5201,
            0.5233,
            0.5269,
            0.5336,
            0.5393,
            0.5438,
            0.6114,
            -1.0,
        ]
    )
    web3 = np.array(
        [
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
            -1.0,
        ]
    )
    turbine.rotor.chord_str_ref = np.array(
        [
            3.2612,
            3.3100915356,
            3.32587052924,
            3.34159388653,
            3.35823798667,
            3.37384375335,
            3.38939112914,
            3.4774055542,
            3.49839685,
            3.51343645709,
            3.87017220335,
            4.04645623801,
            4.19408216643,
            4.47641008477,
            4.55844487985,
            4.57383098262,
            4.57285771934,
            4.51914315648,
            4.47677655262,
            4.40075650022,
            4.31069949379,
            4.20483735936,
            4.08985563932,
            3.82931757126,
            3.74220276467,
            3.54415796922,
            3.38732428502,
            3.24931446473,
            3.23421422609,
            3.22701537997,
            3.21972125648,
            3.08979310611,
            2.95152261813,
            2.330753331,
            2.05553464181,
            1.82577817774,
            1.5860853279,
            1.4621,
        ]
    )  # (Array, m): chord distribution for reference section, thickness of structural layup scaled with reference thickness (fixed t/c for this case)

    for i in range(ncomp):

        webLoc = []
        if web1[i] != -1:
            webLoc.append(web1[i])
        if web2[i] != -1:
            webLoc.append(web2[i])
        if web3[i] != -1:
            webLoc.append(web3[i])

        upper[i], lower[i], webs[i] = CompositeSection.initFromPreCompLayupFile(
            os.path.join(basepath, "layup_" + str(i + 1) + ".inp"), webLoc, materials
        )
        profile[i] = Profile.initFromPreCompFile(os.path.join(basepath, "shape_" + str(i + 1) + ".inp"))

    turbine.rotor.materials = (
        materials
    )  # (List): list of all Orthotropic2DMaterial objects used in defining the geometry
    turbine.rotor.upperCS = (
        upper
    )  # (List): list of CompositeSection objections defining the properties for upper surface
    turbine.rotor.lowerCS = (
        lower
    )  # (List): list of CompositeSection objections defining the properties for lower surface
    turbine.rotor.websCS = webs  # (List): list of CompositeSection objections defining the properties for shear webs
    turbine.rotor.profile = profile  # (List): airfoil shape at each radial position
    # --------------------------------------

    strain_ult_spar = 1.0e-2
    strain_ult_te = 2500 * 1e-6

    # --- fatigue ---
    turbine.rotor.rstar_damage = np.array(
        [
            0.000,
            0.022,
            0.067,
            0.111,
            0.167,
            0.233,
            0.300,
            0.367,
            0.433,
            0.500,
            0.567,
            0.633,
            0.700,
            0.767,
            0.833,
            0.889,
            0.933,
            0.978,
        ]
    )  # (Array): nondimensional radial locations of damage equivalent moments
    turbine.rotor.Mxb_damage = 1e3 * np.array(
        [
            2.3743e003,
            2.0834e003,
            1.8108e003,
            1.5705e003,
            1.3104e003,
            1.0488e003,
            8.2367e002,
            6.3407e002,
            4.7727e002,
            3.4804e002,
            2.4458e002,
            1.6339e002,
            1.0252e002,
            5.7842e001,
            2.7349e001,
            1.1262e001,
            3.8549e000,
            4.4738e-001,
        ]
    )  # (Array, N*m): damage equivalent moments about blade c.s. x-direction
    turbine.rotor.Myb_damage = 1e3 * np.array(
        [
            2.7732e003,
            2.8155e003,
            2.6004e003,
            2.3933e003,
            2.1371e003,
            1.8459e003,
            1.5582e003,
            1.2896e003,
            1.0427e003,
            8.2015e002,
            6.2449e002,
            4.5229e002,
            3.0658e002,
            1.8746e002,
            9.6475e001,
            4.2677e001,
            1.5409e001,
            1.8426e000,
        ]
    )  # (Array, N*m): damage equivalent moments about blade c.s. y-direction
    turbine.rotor.strain_ult_spar = 1.0e-2  # (Float): ultimate strain in spar cap
    turbine.rotor.strain_ult_te = (
        2500 * 1e-6 * 2
    )  # (Float): uptimate strain in trailing-edge panels, note that I am putting a factor of two for the damage part only.
    turbine.rotor.eta_damage = 1.35 * 1.3 * 1.0  # (Float): safety factor for fatigue
    turbine.rotor.m_damage = 10.0  # (Float): slope of S-N curve for fatigue analysis
    turbine.rotor.N_damage = (
        365 * 24 * 3600 * 20.0
    )  # (Float): number of cycles used in fatigue analysis  TODO: make function of rotation speed
    # ----------------
    # =================

    # === nacelle ======
    turbine.nacelle.L_ms = 1.0  # (Float, m): main shaft length downwind of main bearing in low-speed shaft
    turbine.nacelle.L_mb = 2.5  # (Float, m): main shaft length in low-speed shaft

    turbine.nacelle.h0_front = 1.7  # (Float, m): height of Ibeam in bedplate front
    turbine.nacelle.h0_rear = 1.35  # (Float, m): height of Ibeam in bedplate rear

    turbine.nacelle.drivetrain_design = "geared"
    turbine.nacelle.crane = True  # (Bool): flag for presence of crane
    turbine.nacelle.bevel = 0  # (Int): Flag for the presence of a bevel stage - 1 if present, 0 if not
    turbine.nacelle.gear_configuration = (
        "eep"
    )  # (Str): tring that represents the configuration of the gearbox (stage number and types)

    turbine.nacelle.Np = [3, 3, 1]  # (Array): number of planets in each stage
    turbine.nacelle.ratio_type = "optimal"  # (Str): optimal or empirical stage ratios
    turbine.nacelle.shaft_type = "normal"  # (Str): normal or short shaft length
    # turbine.nacelle.shaft_angle = 5.0  # (Float, deg): Angle of the LSS inclindation with respect to the horizontal
    turbine.nacelle.shaft_ratio = 0.10  # (Float): Ratio of inner diameter to outer diameter.  Leave zero for solid LSS
    turbine.nacelle.carrier_mass = 8000.0  # estimated for 5 MW
    turbine.nacelle.mb1Type = "CARB"  # (Str): Main bearing type: CARB, TRB or SRB
    turbine.nacelle.mb2Type = "SRB"  # (Str): Second bearing type: CARB, TRB or SRB
    turbine.nacelle.yaw_motors_number = 8.0  # (Float): number of yaw motors
    turbine.nacelle.uptower_transformer = True
    turbine.nacelle.flange_length = 0.5  # m
    turbine.nacelle.gearbox_cm = 0.1
    turbine.nacelle.hss_length = 1.5
    turbine.nacelle.overhang = 5.0  # TODO - should come from turbine configuration level

    turbine.nacelle.check_fatigue = (
        0
    )  # 0 if no fatigue check, 1 if parameterized fatigue check, 2 if known loads inputs

    # TODO: should come from rotor (these are FAST outputs)
    turbine.nacelle.DrivetrainEfficiency = 0.95
    # turbine.nacelle.rotor_bending_moment_x = 330770.0# Nm
    # turbine.nacelle.rotor_bending_moment_y = -16665000.0 # Nm
    # turbine.nacelle.rotor_bending_moment_z = 2896300.0 # Nm
    # turbine.nacelle.rotor_force_x = 599610.0 # N
    # turbine.nacelle.rotor_force_y = 186780.0 # N
    # turbine.nacelle.rotor_force_z = -842710.0 # N'''

    # turbine.nacelle.h0_rear = 1.35 # only used in drive smooth
    # turbine.nacelle.h0_front = 1.7

    # =================

    # === tower ===

    # ---- tower ------
    turbine.tower.replace("wind1", PowerWind())
    turbine.tower.replace("wind2", PowerWind())
    # onshore (no waves)

    if turbine.sea_depth <> 0.0:
        turbine.tower.replace("wave1", LinearWaves())
        turbine.tower.replace("wave2", LinearWaves())

        turbine.tower.wave1.Uc = 0.0
        turbine.tower.wave1.hs = 8.0 * 1.86
        turbine.tower.wave1.T = 10.0
        turbine.tower.wave1.z_surface = 0.0
        turbine.tower.wave1.z_floor = -sea_depth
        turbine.tower.wave1.g = 9.81
        turbine.tower.wave1.betaWave = 0.0

        turbine.tower.wave2.Uc = 0.0
        turbine.tower.wave2.hs = 8.0 * 1.86
        turbine.tower.wave2.T = 10.0
        turbine.tower.wave2.z_surface = 0.0
        turbine.tower.wave2.z_floor = -sea_depth
        turbine.tower.wave2.g = 9.81
        turbine.tower.wave2.betaWave = 0.0

    if turbine.sea_depth == 0.0:
        # --- geometry ----
        # np.insert(turbine.tower.z_param,0,87.9)
        # np.insert(turbine.tower.z_param,0,43.8)
        # np.insert(turbine.tower.z_param,0,0.0)
        turbine.tower.z_param = [0.0, 43.8, 87.9]
        turbine.tower_d = [6.0, 4.935, 3.87]
        turbine.tower.t_param = [0.027 * 1.3, 0.023 * 1.3, 0.019 * 1.3]
        n = 15
        turbine.tower.z_full = np.linspace(0.0, 87.6, n)
        turbine.tower.L_reinforced = 30.0 * np.ones(n)  # [m] buckling length
        turbine.tower.theta_stress = 0.0 * np.ones(n)
        turbine.tower.yaw = 0.0

        # --- material props ---
        turbine.tower.E = 210e9 * np.ones(n)
        turbine.tower.G = 80.8e9 * np.ones(n)
        turbine.tower.rho = 8500.0 * np.ones(n)
        turbine.tower.sigma_y = 450.0e6 * np.ones(n)
    else:
        # --- geometry ----
        # np.insert(turbine.tower.z_param,0,87.9)
        # np.insert(turbine.tower.z_param,0,43.8)
        # np.insert(turbine.tower.z_param,0,0.0)
        # np.insert(turbine.tower.z_param,0,-20.0)
        turbine.tower.z_param = [-20.0, 0.0, 43.8, 87.9]
        turbine.tower_d = [6.0, 6.0, 4.935, 3.87]
        turbine.tower.t_param = [0.06, 0.027 * 1.3, 0.023 * 1.3, 0.019 * 1.3]
        n = 20
        turbine.tower.z_full = np.linspace(-20, 87.6, n)
        turbine.tower.L_reinforced = 30.0 * np.ones(n)  # [m] buckling length
        turbine.tower.theta_stress = 0.0 * np.ones(n)
        turbine.tower.yaw = 0.0

        # --- material props ---
        turbine.tower.E = 210e9 * np.ones(n)
        turbine.tower.G = 80.8e9 * np.ones(n)
        turbine.tower.rho = 8500.0 * np.ones(n)
        turbine.tower.sigma_y = 450.0e6 * np.ones(n)

    # --- spring reaction data.  Use float('inf') for rigid constraints. ---
    turbine.tower.kidx = [0]  # applied at base
    turbine.tower.kx = [float("inf")]
    turbine.tower.ky = [float("inf")]
    turbine.tower.kz = [float("inf")]
    turbine.tower.ktx = [float("inf")]
    turbine.tower.kty = [float("inf")]
    turbine.tower.ktz = [float("inf")]

    # --- extra mass ----
    turbine.tower.midx = [n - 1]  # RNA mass at top
    turbine.tower.m = [285598.8]
    turbine.tower.mIxx = [1.14930678e08]
    turbine.tower.mIyy = [2.20354030e07]
    turbine.tower.mIzz = [1.87597425e07]
    turbine.tower.mIxy = [0.00000000e00]
    turbine.tower.mIxz = [5.03710467e05]
    turbine.tower.mIyz = [0.00000000e00]
    turbine.tower.mrhox = [-1.13197635]
    turbine.tower.mrhoy = [0.0]
    turbine.tower.mrhoz = [0.50875268]
    turbine.tower.addGravityLoadForExtraMass = True
    # -----------

    # --- wind ---
    # turbine.tower.wind_zref = 90.0
    turbine.tower.wind_z0 = 0.0
    turbine.tower.wind1.shearExp = 0.2
    turbine.tower.wind2.shearExp = 0.2
    # ---------------

    # if addGravityLoadForExtraMass=True be sure not to double count by adding those force here also
    # # --- loading case 1: max Thrust ---
    # turbine.tower.wind_Uref1 = 11.73732
    turbine.tower.plidx1 = [n - 1]  # at tower top
    turbine.tower.Fx1 = [1284744.19620519]
    turbine.tower.Fy1 = [0.0]
    turbine.tower.Fz1 = [-2914124.84400512]
    turbine.tower.Mxx1 = [3963732.76208099]
    turbine.tower.Myy1 = [-2275104.79420872]
    turbine.tower.Mzz1 = [-346781.68192839]
    # # ---------------

    # # --- loading case 2: max wind speed ---
    # turbine.tower.wind_Uref2 = 70.0
    turbine.tower.plidx2 = [n - 1]  # at tower top
    turbine.tower.Fx2 = [930198.60063279]
    turbine.tower.Fy2 = [0.0]
    turbine.tower.Fz2 = [-2883106.12368949]
    turbine.tower.Mxx2 = [-1683669.22411597]
    turbine.tower.Myy2 = [-2522475.34625363]
    turbine.tower.Mzz2 = [147301.97023764]
    # # ---------------

    # --- safety factors ---
    turbine.tower.gamma_f = 1.35
    turbine.tower.gamma_m = 1.3
    turbine.tower.gamma_n = 1.0
    turbine.tower.gamma_b = 1.1
    # ---------------

    # --- fatigue ---
    turbine.tower.z_DEL = np.array(
        [
            0.000,
            1.327,
            3.982,
            6.636,
            9.291,
            11.945,
            14.600,
            17.255,
            19.909,
            22.564,
            25.218,
            27.873,
            30.527,
            33.182,
            35.836,
            38.491,
            41.145,
            43.800,
            46.455,
            49.109,
            51.764,
            54.418,
            57.073,
            59.727,
            62.382,
            65.036,
            67.691,
            70.345,
            73.000,
            75.655,
            78.309,
            80.964,
            83.618,
            86.273,
            87.600,
        ]
    )
    turbine.tower.M_DEL = 1e3 * np.array(
        [
            8.2940e003,
            8.1518e003,
            7.8831e003,
            7.6099e003,
            7.3359e003,
            7.0577e003,
            6.7821e003,
            6.5119e003,
            6.2391e003,
            5.9707e003,
            5.7070e003,
            5.4500e003,
            5.2015e003,
            4.9588e003,
            4.7202e003,
            4.4884e003,
            4.2577e003,
            4.0246e003,
            3.7942e003,
            3.5664e003,
            3.3406e003,
            3.1184e003,
            2.8977e003,
            2.6811e003,
            2.4719e003,
            2.2663e003,
            2.0673e003,
            1.8769e003,
            1.7017e003,
            1.5479e003,
            1.4207e003,
            1.3304e003,
            1.2780e003,
            1.2673e003,
            1.2761e003,
        ]
    )
    turbine.tower.gamma_fatigue = 1.35 * 1.3 * 1.0
    turbine.tower.life = 20.0
    turbine.tower.m_SN = 4
    # ---------------

    # --- constraints ---
    turbine.tower.min_d_to_t = 120.0
    turbine.tower.min_taper = 0.4
    # ---------------

    # ==== Other options

    if wind_class == "I":
        turbine.rotor.turbine_class = "I"

    elif wind_class == "III":
        turbine.rotor.turbine_class = "III"

        # for fatigue based analysis of class III wind turbine
        turbine.tower.M_DEL = (
            1.028713178
            * 1e3
            * np.array(
                [
                    7.8792e003,
                    7.7507e003,
                    7.4918e003,
                    7.2389e003,
                    6.9815e003,
                    6.7262e003,
                    6.4730e003,
                    6.2174e003,
                    5.9615e003,
                    5.7073e003,
                    5.4591e003,
                    5.2141e003,
                    4.9741e003,
                    4.7399e003,
                    4.5117e003,
                    4.2840e003,
                    4.0606e003,
                    3.8360e003,
                    3.6118e003,
                    3.3911e003,
                    3.1723e003,
                    2.9568e003,
                    2.7391e003,
                    2.5294e003,
                    2.3229e003,
                    2.1246e003,
                    1.9321e003,
                    1.7475e003,
                    1.5790e003,
                    1.4286e003,
                    1.3101e003,
                    1.2257e003,
                    1.1787e003,
                    1.1727e003,
                    1.1821e003,
                ]
            )
        )

        turbine.rotor.Mxb_damage = 1e3 * np.array(
            [
                2.3617e003,
                2.0751e003,
                1.8051e003,
                1.5631e003,
                1.2994e003,
                1.0388e003,
                8.1384e002,
                6.2492e002,
                4.6916e002,
                3.4078e002,
                2.3916e002,
                1.5916e002,
                9.9752e001,
                5.6139e001,
                2.6492e001,
                1.0886e001,
                3.7210e000,
                4.3206e-001,
            ]
        )
        turbine.rotor.Myb_damage = 1e3 * np.array(
            [
                2.5492e003,
                2.6261e003,
                2.4265e003,
                2.2308e003,
                1.9882e003,
                1.7184e003,
                1.4438e003,
                1.1925e003,
                9.6251e002,
                7.5564e002,
                5.7332e002,
                4.1435e002,
                2.8036e002,
                1.7106e002,
                8.7732e001,
                3.8678e001,
                1.3942e001,
                1.6600e000,
            ]
        )

    elif wind_class == "Offshore":
        turbine.rotor.turbine_class = "I"

    # TODO: these should be specified at the turbine level and connected to other system inputs
    if turbine.sea_depth == 0.0:
        turbine.tower_d = [6.0, 4.935, 3.87]  # (Array, m): diameters along tower
    else:
        turbine.tower_d = [6.0, 6.0, 4.935, 3.87]
    turbine.generator_speed = 1173.7  # (Float, rpm)  # generator speed
def EvaluateLCOE(BladeLength, HubHeight, MaximumRotSpeed, Verbose=False):

    ############################################################################
    # Define baseline paremeters used for scaling
    ReferenceBladeLength = 35
    ReferenceTowerHeight = 95
    WindReferenceHeight = 50
    WindReferenceMeanVelocity = 3
    WeibullShapeFactor = 2.0
    ShearFactor = 0.25

    RatedPower = 1.5e6

    # Years used for analysis
    Years = 25
    DiscountRate = 0.08
    ############################################################################

    ############################################################################
    ### 1. Aerodynamic and structural performance using RotorSE
    rotor = RotorSE()
    # -------------------

    # === blade grid ===
    # (Array): initial aerodynamic grid on unit radius
    rotor.initial_aero_grid = np.array([0.02222276, 0.06666667, 0.11111057, \
     0.16666667, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, \
     0.63333333, 0.7, 0.76666667, 0.83333333, 0.88888943, 0.93333333, \
        0.97777724])

    # (Array): initial structural grid on unit radius
    rotor.initial_str_grid = np.array([
        0.0, 0.00492790457512, 0.00652942887106, 0.00813095316699,
        0.00983257273154, 0.0114340970275, 0.0130356213234, 0.02222276,
        0.024446481932, 0.026048006228, 0.06666667, 0.089508406455, 0.11111057,
        0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 0.276686558545,
        0.3, 0.333640766319, 0.36666667, 0.400404310407, 0.43333333, 0.5,
        0.520818918408, 0.56666667, 0.602196371696, 0.63333333, 0.667358391486,
        0.683573824984, 0.7, 0.73242031601, 0.76666667, 0.83333333, 0.88888943,
        0.93333333, 0.97777724, 1.0
    ])

    # (Int): first idx in r_aero_unit of non-cylindrical section,
    # constant twist inboard of here
    rotor.idx_cylinder_aero = 3

    # (Int): first idx in r_str_unit of non-cylindrical section
    rotor.idx_cylinder_str = 14

    # (Float): hub location as fraction of radius
    rotor.hubFraction = 0.025
    # ------------------

    # === blade geometry ===
    # (Array): new aerodynamic grid on unit radius
    rotor.r_aero = np.array([
        0.02222276, 0.06666667, 0.11111057, 0.2, 0.23333333, 0.3, 0.36666667,
        0.43333333, 0.5, 0.56666667, 0.63333333, 0.64, 0.7, 0.83333333,
        0.88888943, 0.93333333, 0.97777724
    ])

    # (Float): location of max chord on unit radius
    rotor.r_max_chord = 0.23577

    # (Array, m): chord at control points. defined at hub, then at linearly spaced
    # locations from r_max_chord to tip
    ReferenceChord = [3.2612, 4.5709, 3.3178, 1.4621]
    rotor.chord_sub = [x * np.true_divide(BladeLength,ReferenceBladeLength) \
     for x in ReferenceChord]

    # (Array, deg): twist at control points.  defined at linearly spaced locations
    # from r[idx_cylinder] to tip
    rotor.theta_sub = [13.2783, 7.46036, 2.89317, -0.0878099]

    # (Array, m): precurve at control points.  defined at same locations at chord,
    # starting at 2nd control point (root must be zero precurve)
    rotor.precurve_sub = [0.0, 0.0, 0.0]

    # (Array, m): adjustment to precurve to account for curvature from loading
    rotor.delta_precurve_sub = [0.0, 0.0, 0.0]

    # (Array, m): spar cap thickness parameters
    rotor.sparT = [0.05, 0.047754, 0.045376, 0.031085, 0.0061398]

    # (Array, m): trailing-edge thickness parameters
    rotor.teT = [0.1, 0.09569, 0.06569, 0.02569, 0.00569]

    # (Float, m): blade length (if not precurved or swept)
    # otherwise length of blade before curvature
    rotor.bladeLength = BladeLength

    # (Float, m): adjustment to blade length to account for curvature from
    # loading
    rotor.delta_bladeLength = 0.0
    rotor.precone = 2.5  # (Float, deg): precone angle
    rotor.tilt = 5.0  # (Float, deg): shaft tilt
    rotor.yaw = 0.0  # (Float, deg): yaw error
    rotor.nBlades = 3  # (Int): number of blades
    # ------------------

    # === airfoil files ===
    basepath = os.path.join(os.path.dirname(\
     os.path.realpath(__file__)), '5MW_AFFiles')

    # load all airfoils
    airfoil_types = [0] * 8
    airfoil_types[0] = os.path.join(basepath, 'Cylinder1.dat')
    airfoil_types[1] = os.path.join(basepath, 'Cylinder2.dat')
    airfoil_types[2] = os.path.join(basepath, 'DU40_A17.dat')
    airfoil_types[3] = os.path.join(basepath, 'DU35_A17.dat')
    airfoil_types[4] = os.path.join(basepath, 'DU30_A17.dat')
    airfoil_types[5] = os.path.join(basepath, 'DU25_A17.dat')
    airfoil_types[6] = os.path.join(basepath, 'DU21_A17.dat')
    airfoil_types[7] = os.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]

    n = len(af_idx)
    af = [0] * n
    for i in range(n):
        af[i] = airfoil_types[af_idx[i]]
    rotor.airfoil_files = af  # (List): names of airfoil file
    # ----------------------

    # === atmosphere ===
    rotor.rho = 1.225  # (Float, kg/m**3): density of air
    rotor.mu = 1.81206e-5  # (Float, kg/m/s): dynamic viscosity of air
    rotor.shearExp = 0.25  # (Float): shear exponent
    rotor.hubHt = HubHeight  # (Float, m): hub height
    rotor.turbine_class = 'I'  # (Enum): IEC turbine class
    rotor.turbulence_class = 'B'  # (Enum): IEC turbulence class class
    rotor.cdf_reference_height_wind_speed = 30.0
    rotor.g = 9.81  # (Float, m/s**2): acceleration of gravity
    # ----------------------

    # === control ===
    rotor.control.Vin = 3.0  # (Float, m/s): cut-in wind speed
    rotor.control.Vout = 26.0  # (Float, m/s): cut-out wind speed
    rotor.control.ratedPower = RatedPower  # (Float, W): rated power

    # (Float, rpm): minimum allowed rotor rotation speed

    # (Float, rpm): maximum allowed rotor rotation speed
    rotor.control.minOmega = 0.0
    rotor.control.maxOmega = MaximumRotSpeed

    # (Float): tip-speed ratio in Region 2 (should be optimized externally)
    rotor.control.tsr = 7
    # (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines)
    rotor.control.pitch = 0.0
    # (Float, deg): worst-case pitch at survival wind condition
    rotor.pitch_extreme = 0.0

    # (Float, deg): worst-case azimuth at survival wind condition
    rotor.azimuth_extreme = 0.0

    # (Float): fraction of rated speed at which the deflection is assumed to
    # representative throughout the power curve calculation
    rotor.VfactorPC = 0.7
    # ----------------------

    # === aero and structural analysis options ===

    # (Int): number of sectors to divide rotor face into in computing thrust and power
    rotor.nSector = 4

    # (Int): number of points to evaluate aero analysis at
    rotor.npts_coarse_power_curve = 20

    # (Int): number of points to use in fitting spline to power curve
    rotor.npts_spline_power_curve = 200

    # (Float): availability and other losses (soiling, array, etc.)
    rotor.AEP_loss_factor = 1.0
    rotor.drivetrainType = 'geared'  # (Enum)

    # (Int): number of natural frequencies to compute
    rotor.nF = 5

    # (Float): a dynamic amplification factor to adjust the static deflection
    # calculation
    rotor.dynamic_amplication_tip_deflection = 1.35
    # ----------------------

    # === materials and composite layup  ===
    basepath = os.path.join(os.path.dirname(os.path.realpath(__file__)), \
     '5MW_PrecompFiles')

    materials = Orthotropic2DMaterial.listFromPreCompFile(os.path.join(basepath,\
     'materials.inp'))

    ncomp = len(rotor.initial_str_grid)
    upper = [0] * ncomp
    lower = [0] * ncomp
    webs = [0] * ncomp
    profile = [0] * ncomp

    # (Array): array of leading-edge positions from a reference blade axis
    # (usually blade pitch axis). locations are normalized by the local chord
    # length. e.g. leLoc[i] = 0.2 means leading edge is 0.2*chord[i] from reference
    # axis.  positive in -x direction for airfoil-aligned coordinate system
    rotor.leLoc = np.array([
        0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.498, 0.497, 0.465, 0.447,
        0.43, 0.411, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4,
        0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4
    ])

    # (Array): index of sector for spar (PreComp definition of sector)
    rotor.sector_idx_strain_spar = [2] * ncomp

    # (Array): index of sector for trailing-edge (PreComp definition of sector)
    rotor.sector_idx_strain_te = [3] * ncomp

    web1 = np.array([
        -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.4114, 0.4102, 0.4094,
        0.3876, 0.3755, 0.3639, 0.345, 0.3342, 0.3313, 0.3274, 0.323, 0.3206,
        0.3172, 0.3138, 0.3104, 0.307, 0.3003, 0.2982, 0.2935, 0.2899, 0.2867,
        0.2833, 0.2817, 0.2799, 0.2767, 0.2731, 0.2664, 0.2607, 0.2562, 0.1886,
        -1.0
    ])

    web2 = np.array([
        -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.5886, 0.5868, 0.5854,
        0.5508, 0.5315, 0.5131, 0.4831, 0.4658, 0.4687, 0.4726, 0.477, 0.4794,
        0.4828, 0.4862, 0.4896, 0.493, 0.4997, 0.5018, 0.5065, 0.5101, 0.5133,
        0.5167, 0.5183, 0.5201, 0.5233, 0.5269, 0.5336, 0.5393, 0.5438, 0.6114,
        -1.0
    ])
    web3 = np.array([
        -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0,
        -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
        1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0
    ])

    # (Array, m): chord distribution for reference section, thickness of structural
    # layup scaled with reference thickness (fixed t/c for this case)
    rotor.chord_str_ref = np.array([3.2612, 3.3100915356, 3.32587052924,
     3.34159388653, 3.35823798667, 3.37384375335, 3.38939112914, 3.4774055542,
     3.49839685, 3.51343645709, 3.87017220335, 4.04645623801, 4.19408216643,
        4.47641008477, 4.55844487985, 4.57383098262, 4.57285771934, 4.51914315648,
        4.47677655262, 4.40075650022, 4.31069949379, 4.20483735936, 4.08985563932,
        3.82931757126, 3.74220276467, 3.54415796922, 3.38732428502, 3.24931446473,
        3.23421422609, 3.22701537997, 3.21972125648, 3.08979310611, 2.95152261813,
        2.330753331, 2.05553464181, 1.82577817774, 1.5860853279, 1.4621])* \
     np.true_divide(BladeLength,ReferenceBladeLength)

    for i in range(ncomp):
        webLoc = []
        if web1[i] != -1:
            webLoc.append(web1[i])
        if web2[i] != -1:
            webLoc.append(web2[i])
        if web3[i] != -1:
            webLoc.append(web3[i])

        upper[i], lower[i], webs[i] = CompositeSection.initFromPreCompLayupFile\
        (os.path.join(basepath, 'layup_' + str(i+1) + '.inp'), webLoc, materials)
        profile[i] = Profile.initFromPreCompFile(os.path.join(basepath, 'shape_' \
         + str(i+1) + '.inp'))

    # (List): list of all Orthotropic2DMaterial objects used in
    # defining the geometry
    rotor.materials = materials

    # (List): list of CompositeSection objections defining the properties for
    # upper surface
    rotor.upperCS = upper

    # (List): list of CompositeSection objections defining the properties for
    # lower surface
    rotor.lowerCS = lower

    # (List): list of CompositeSection objections defining the properties for
    # shear webs
    rotor.websCS = webs

    # (List): airfoil shape at each radial position
    rotor.profile = profile
    # --------------------------------------

    # === fatigue ===

    # (Array): nondimensional radial locations of damage equivalent moments
    rotor.rstar_damage = np.array([
        0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500,
        0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978
    ])

    # (Array, N*m): damage equivalent moments about blade c.s. x-direction
    rotor.Mxb_damage = 1e3 * np.array([
        2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003,
        1.0488E+003, 8.2367E+002, 6.3407E+002, 4.7727E+002, 3.4804E+002,
        2.4458E+002, 1.6339E+002, 1.0252E+002, 5.7842E+001, 2.7349E+001,
        1.1262E+001, 3.8549E+000, 4.4738E-001
    ])

    # (Array, N*m): damage equivalent moments about blade c.s. y-direction
    rotor.Myb_damage = 1e3 * np.array([
        2.7732E+003, 2.8155E+003, 2.6004E+003, 2.3933E+003, 2.1371E+003,
        1.8459E+003, 1.5582E+003, 1.2896E+003, 1.0427E+003, 8.2015E+002,
        6.2449E+002, 4.5229E+002, 3.0658E+002, 1.8746E+002, 9.6475E+001,
        4.2677E+001, 1.5409E+001, 1.8426E+000
    ])

    rotor.strain_ult_spar = 1.0e-2  # (Float): ultimate strain in spar cap

    # (Float): uptimate strain in trailing-edge panels, note that I am putting a
    # factor of two for the damage part only.
    rotor.strain_ult_te = 2500 * 1e-6 * 2
    rotor.eta_damage = 1.35 * 1.3 * 1.0  # (Float): safety factor for fatigue
    rotor.m_damage = 10.0  # (Float): slope of S-N curve for fatigue analysis

    # (Float): number of cycles used in fatigue analysis
    rotor.N_damage = 365 * 24 * 3600 * 20.0
    # ----------------

    # from myutilities import plt

    # === run and outputs ===
    rotor.run()

    # Evaluate AEP Using Lewis' Functions
    # Weibull Wind Parameters
    WindReferenceHeight = 50
    WindReferenceMeanVelocity = 7.5
    WeibullShapeFactor = 2.0
    ShearFactor = 0.25

    PowerCurve = rotor.P / 1e6
    PowerCurveVelocity = rotor.V

    HubHeight = rotor.hubHt

    AEP,WeibullScale = CalculateAEPWeibull(PowerCurve,PowerCurveVelocity, HubHeight, \
       BladeLength,WeibullShapeFactor, WindReferenceHeight, \
       WindReferenceMeanVelocity, ShearFactor)

    NamePlateCapacity = EstimateCapacity(PowerCurve,PowerCurveVelocity, \
     rotor.ratedConditions.V)

    # AEP At Constant 7.5m/s Wind used for benchmarking...
    #AEP = CalculateAEPConstantWind(PowerCurve, PowerCurveVelocity, 7.5)

    if (Verbose == True):
        print '###################     ROTORSE   ######################'
        print 'AEP = %d MWH' % (AEP)
        print 'NamePlateCapacity = %fMW' % (NamePlateCapacity)
        print 'diameter =', rotor.diameter
        print 'ratedConditions.V =', rotor.ratedConditions.V
        print 'ratedConditions.Omega =', rotor.ratedConditions.Omega
        print 'ratedConditions.pitch =', rotor.ratedConditions.pitch
        print 'mass_one_blade =', rotor.mass_one_blade
        print 'mass_all_blades =', rotor.mass_all_blades
        print 'I_all_blades =', rotor.I_all_blades
        print 'freq =', rotor.freq
        print 'tip_deflection =', rotor.tip_deflection
        print 'root_bending_moment =', rotor.root_bending_moment
        print '#########################################################'

    #############################################################################
    ### 2. Hub Sizing
    # Specify hub parameters based off rotor

    # Load default hub model
    hubS = HubSE()
    hubS.rotor_diameter = rotor.Rtip * 2  # m
    hubS.blade_number = rotor.nBlades
    hubS.blade_root_diameter = rotor.chord_sub[0] * 1.25
    hubS.L_rb = rotor.hubFraction * rotor.diameter
    hubS.MB1_location = np.array([-0.5, 0.0, 0.0])
    hubS.machine_rating = rotor.control.ratedPower
    hubS.blade_mass = rotor.mass_one_blade
    hubS.rotor_bending_moment = rotor.root_bending_moment

    hubS.run()

    RotorTotalWeight = rotor.mass_all_blades + hubS.spinner.mass + \
    hubS.hub.mass + hubS.pitchSystem.mass

    if (Verbose == True):
        print '##################### Hub SE ############################'
        print "Estimate of Hub Component Sizes:"
        print "Hub Components"
        print '  Hub: {0:8.1f} kg'.format(hubS.hub.mass)
        print '  Pitch system: {0:8.1f} kg'.format(hubS.pitchSystem.mass)
        print '  Nose cone: {0:8.1f} kg'.format(hubS.spinner.mass)
        print 'Rotor Total Weight = %d kg' % RotorTotalWeight
        print '#########################################################'

    ############################################################################
    ### 3. Drive train + Nacelle Mass estimation
    nace = Drive4pt()
    nace.rotor_diameter = rotor.Rtip * 2  # m
    nace.rotor_speed = rotor.ratedConditions.Omega  # #rpm m/s
    nace.machine_rating = hubS.machine_rating / 1000
    nace.DrivetrainEfficiency = 0.95

    # 6.35e6 #4365248.74 # Nm
    nace.rotor_torque = rotor.ratedConditions.Q
    nace.rotor_thrust = rotor.ratedConditions.T  # N
    nace.rotor_mass = 0.0  #accounted for in F_z # kg

    nace.rotor_bending_moment_x = rotor.Mxyz_0[0]
    nace.rotor_bending_moment_y = rotor.Mxyz_0[1]
    nace.rotor_bending_moment_z = rotor.Mxyz_0[2]

    nace.rotor_force_x = rotor.Fxyz_0[0]  # N
    nace.rotor_force_y = rotor.Fxyz_0[1]
    nace.rotor_force_z = rotor.Fxyz_0[2]  # N

    # geared 3-stage Gearbox with induction generator machine
    nace.drivetrain_design = 'geared'
    nace.gear_ratio = 96.76  # 97:1 as listed in the 5 MW reference document
    nace.gear_configuration = 'eep'  # epicyclic-epicyclic-parallel

    nace.crane = True  # onboard crane present
    nace.shaft_angle = 5.0  #deg
    nace.shaft_ratio = 0.10
    nace.Np = [3, 3, 1]
    nace.ratio_type = 'optimal'
    nace.shaft_type = 'normal'
    nace.uptower_transformer = False
    nace.shrink_disc_mass = 333.3 * nace.machine_rating / 1000.0  # estimated
    nace.mb1Type = 'CARB'
    nace.mb2Type = 'SRB'
    nace.flange_length = 0.5  #m
    nace.overhang = 5.0
    nace.gearbox_cm = 0.1
    nace.hss_length = 1.5

    #0 if no fatigue check, 1 if parameterized fatigue check,
    #2 if known loads inputs
    nace.check_fatigue = 0
    nace.blade_number = rotor.nBlades
    nace.cut_in = rotor.control.Vin  #cut-in m/s
    nace.cut_out = rotor.control.Vout  #cut-out m/s
    nace.Vrated = rotor.ratedConditions.V  #rated windspeed m/s
    nace.weibull_k = WeibullShapeFactor  # windepeed distribution shape parameter

    # windspeed distribution scale parameter
    nace.weibull_A = WeibullScale

    nace.T_life = 20.  #design life in years
    nace.IEC_Class_Letter = 'B'

    # length from hub center to main bearing, leave zero if unknown
    nace.L_rb = hubS.L_rb

    # NREL 5 MW Tower Variables
    nace.tower_top_diameter = 3.78  # m

    nace.run()

    if (Verbose == True):
        print '##################### Drive SE ############################'
        print "Estimate of Nacelle Component Sizes"
        print 'Low speed shaft: {0:8.1f} kg'.format(nace.lowSpeedShaft.mass)
        print 'Main bearings: {0:8.1f} kg'.format(\
         nace.mainBearing.mass + nace.secondBearing.mass)
        print 'Gearbox: {0:8.1f} kg'.format(nace.gearbox.mass)
        print 'High speed shaft & brakes: {0:8.1f} kg'.format\
         (nace.highSpeedSide.mass)
        print 'Generator: {0:8.1f} kg'.format(nace.generator.mass)
        print 'Variable speed electronics: {0:8.1f} kg'.format(\
         nace.above_yaw_massAdder.vs_electronics_mass)
        print 'Overall mainframe:{0:8.1f} kg'.format(\
         nace.above_yaw_massAdder.mainframe_mass)
        print '     Bedplate: {0:8.1f} kg'.format(nace.bedplate.mass)
        print 'Electrical connections: {0:8.1f} kg'.format(\
         nace.above_yaw_massAdder.electrical_mass)
        print 'HVAC system: {0:8.1f} kg'.format(\
         nace.above_yaw_massAdder.hvac_mass )
        print 'Nacelle cover: {0:8.1f} kg'.format(\
         nace.above_yaw_massAdder.cover_mass)
        print 'Yaw system: {0:8.1f} kg'.format(nace.yawSystem.mass)
        print 'Overall nacelle: {0:8.1f} kg'.format(nace.nacelle_mass, \
         nace.nacelle_cm[0], nace.nacelle_cm[1], nace.nacelle_cm[2], \
         nace.nacelle_I[0], nace.nacelle_I[1], nace.nacelle_I[2])
        print '#########################################################'

    ############################################################################
    ### 4. Tower Mass

    # --- tower setup ------
    from commonse.environment import PowerWind

    tower = set_as_top(TowerSE())

    # ---- tower ------
    tower.replace('wind1', PowerWind())
    tower.replace('wind2', PowerWind())
    # onshore (no waves)

    # --- geometry ----
    tower.z_param = [0.0, HubHeight * 0.5, HubHeight]
    TowerRatio = np.true_divide(HubHeight, ReferenceTowerHeight)

    tower.d_param = [6.0 * TowerRatio, 4.935 * TowerRatio, 3.87 * TowerRatio]
    tower.t_param = [0.027*1.3*TowerRatio, 0.023*1.3*TowerRatio, \
    0.019*1.3*TowerRatio]
    n = 10

    tower.z_full = np.linspace(0.0, HubHeight, n)
    tower.L_reinforced = 15.0 * np.ones(n)  # [m] buckling length
    tower.theta_stress = 0.0 * np.ones(n)
    tower.yaw = 0.0

    # --- material props ---
    tower.E = 210e9 * np.ones(n)
    tower.G = 80.8e9 * np.ones(n)
    tower.rho = 8500.0 * np.ones(n)
    tower.sigma_y = 450.0e6 * np.ones(n)

    # --- spring reaction data.  Use float('inf') for rigid constraints. ---
    tower.kidx = [0]  # applied at base
    tower.kx = [float('inf')]
    tower.ky = [float('inf')]
    tower.kz = [float('inf')]
    tower.ktx = [float('inf')]
    tower.kty = [float('inf')]
    tower.ktz = [float('inf')]

    # --- extra mass ----
    tower.midx = [n - 1]  # RNA mass at top
    tower.m = [0.8]
    tower.mIxx = [1.14930678e+08]
    tower.mIyy = [2.20354030e+07]
    tower.mIzz = [1.87597425e+07]
    tower.mIxy = [0.00000000e+00]
    tower.mIxz = [5.03710467e+05]
    tower.mIyz = [0.00000000e+00]
    tower.mrhox = [-1.13197635]
    tower.mrhoy = [0.]
    tower.mrhoz = [0.50875268]
    tower.addGravityLoadForExtraMass = False
    # -----------

    # --- wind ---
    tower.wind_zref = 90.0
    tower.wind_z0 = 0.0
    tower.wind1.shearExp = 0.14
    tower.wind2.shearExp = 0.14
    # ---------------

    # # --- loading case 1: max Thrust ---
    tower.wind_Uref1 = 11.73732
    tower.plidx1 = [n - 1]  # at tower top
    tower.Fx1 = [0.19620519]
    tower.Fy1 = [0.]
    tower.Fz1 = [-2914124.84400512]
    tower.Mxx1 = [3963732.76208099]
    tower.Myy1 = [-2275104.79420872]
    tower.Mzz1 = [-346781.68192839]
    # # ---------------

    # # --- loading case 2: max wind speed ---
    tower.wind_Uref2 = 70.0
    tower.plidx1 = [n - 1]  # at tower top
    tower.Fx1 = [930198.60063279]
    tower.Fy1 = [0.]
    tower.Fz1 = [-2883106.12368949]
    tower.Mxx1 = [-1683669.22411597]
    tower.Myy1 = [-2522475.34625363]
    tower.Mzz1 = [147301.97023764]
    # # ---------------

    # # --- run ---
    tower.run()

    if (Verbose == True):
        print '##################### Tower SE ##########################'
        print 'mass (kg) =', tower.mass
        print 'f1 (Hz) =', tower.f1
        print 'f2 (Hz) =', tower.f2
        print 'top_deflection1 (m) =', tower.top_deflection1
        print 'top_deflection2 (m) =', tower.top_deflection2
        print '#########################################################'

    ############################################################################
    ## 5. Turbine captial costs analysis
    turbine = Turbine_CostsSE()

    # NREL 5 MW turbine component masses based on Sunderland model approach
    # Rotor
    # inline with the windpact estimates
    turbine.blade_mass = rotor.mass_one_blade
    turbine.hub_mass = hubS.hub.mass
    turbine.pitch_system_mass = hubS.pitchSystem.mass
    turbine.spinner_mass = hubS.spinner.mass

    # Drivetrain and Nacelle
    turbine.low_speed_shaft_mass = nace.lowSpeedShaft.mass
    turbine.main_bearing_mass = nace.mainBearing.mass
    turbine.second_bearing_mass = nace.secondBearing.mass
    turbine.gearbox_mass = nace.gearbox.mass
    turbine.high_speed_side_mass = nace.highSpeedSide.mass
    turbine.generator_mass = nace.generator.mass
    turbine.bedplate_mass = nace.bedplate.mass
    turbine.yaw_system_mass = nace.yawSystem.mass

    # Tower
    turbine.tower_mass = tower.mass * 0.5

    # Additional non-mass cost model input variables
    turbine.machine_rating = hubS.machine_rating / 1000
    turbine.advanced = False
    turbine.blade_number = rotor.nBlades
    turbine.drivetrain_design = 'geared'
    turbine.crane = False
    turbine.offshore = False

    # Target year for analysis results
    turbine.year = 2010
    turbine.month = 12

    turbine.run()

    if (Verbose == True):
        print '##################### TurbinePrice SE ####################'
        print "Overall rotor cost with 3 advanced blades is ${0:.2f} USD"\
         .format(turbine.rotorCC.cost)
        print "Blade cost is ${0:.2f} USD".format(turbine.rotorCC.bladeCC.cost)
        print "Hub cost is ${0:.2f} USD".format(turbine.rotorCC.hubCC.cost)
        print "Pitch system cost is ${0:.2f} USD".format(
            turbine.rotorCC.pitchSysCC.cost)
        print "Spinner cost is ${0:.2f} USD".format(
            turbine.rotorCC.spinnerCC.cost)
        print
        print "Overall nacelle cost is ${0:.2f} USD".format(
            turbine.nacelleCC.cost)
        print "LSS cost is ${0:.2f} USD".format(turbine.nacelleCC.lssCC.cost)
        print "Main bearings cost is ${0:.2f} USD".format(
            turbine.nacelleCC.bearingsCC.cost)
        print "Gearbox cost is ${0:.2f} USD".format(
            turbine.nacelleCC.gearboxCC.cost)
        print "Hight speed side cost is ${0:.2f} USD".format(
            turbine.nacelleCC.hssCC.cost)
        print "Generator cost is ${0:.2f} USD".format(
            turbine.nacelleCC.generatorCC.cost)
        print "Bedplate cost is ${0:.2f} USD".format(
            turbine.nacelleCC.bedplateCC.cost)
        print "Yaw system cost is ${0:.2f} USD".format(
            turbine.nacelleCC.yawSysCC.cost)
        print
        print "Tower cost is ${0:.2f} USD".format(turbine.towerCC.cost)
        print
        print "The overall turbine cost is ${0:.2f} USD".format(
            turbine.turbine_cost)
        print '#########################################################'

    ############################################################################
    ## 6. Operating Expenses

    # A simple test of nrel_csm_bos model
    bos = bos_csm_assembly()

    # Set input parameters
    bos = bos_csm_assembly()
    bos.machine_rating = hubS.machine_rating / 1000
    bos.rotor_diameter = rotor.diameter
    bos.turbine_cost = turbine.turbine_cost
    bos.hub_height = HubHeight
    bos.turbine_number = 1
    bos.sea_depth = 0
    bos.year = 2009
    bos.month = 12
    bos.multiplier = 1.0
    bos.run()

    om = opex_csm_assembly()

    om.machine_rating = rotor.control.ratedPower / 1000
    # Need to manipulate input or underlying component will not execute
    om.net_aep = AEP * 10e4
    om.sea_depth = 0
    om.year = 2009
    om.month = 12
    om.turbine_number = 100

    om.run()

    if (Verbose == True):
        print '##################### Operating Costs ####################'
        print "BOS cost per turbine: ${0:.2f} USD".format(bos.bos_costs / \
         bos.turbine_number)
        print "Average annual operational expenditures"
        print "OPEX on shore with 100 turbines ${:.2f}: USD".format(\
         om.avg_annual_opex)
        print "Preventative OPEX by turbine: ${:.2f} USD".format(\
         om.opex_breakdown.preventative_opex / om.turbine_number)
        print "Corrective OPEX by turbine: ${:.2f} USD".format(\
         om.opex_breakdown.corrective_opex / om.turbine_number)
        print "Land Lease OPEX by turbine: ${:.2f} USD".format(\
         om.opex_breakdown.lease_opex / om.turbine_number)
        print '#########################################################'

    CapitalCost = turbine.turbine_cost + bos.bos_costs / bos.turbine_number
    OperatingCost = om.opex_breakdown.preventative_opex / om.turbine_number + \
    om.opex_breakdown.lease_opex / om.turbine_number + \
    om.opex_breakdown.corrective_opex / om.turbine_number

    LCOE = ComputeLCOE(AEP, CapitalCost, OperatingCost, DiscountRate, Years)

    print '######################***********************###################'
    print "Levelized Cost of Energy over %d years \
	is $%f/kWH" % (Years, LCOE / 1000)
    print '######################***********************###################'

    return LCOE / 1000
Example #9
0
def configure_nrel5mw_turbine_with_jacket(turbine,wind_class='I',sea_depth = 0.0):
    """
    Inputs:
        rotor = RotorSE()
        nacelle = DriveSE()
        jacket = JacketSE()
        wind_class : str ('I', 'III', 'Offshore' - selected wind class for project)
        sea_depth : float (sea depth if an offshore wind plant)
    """

    # =================


    # === Turbine ===
    turbine.rho = 1.225  # (Float, kg/m**3): density of air
    turbine.mu = 1.81206e-5  # (Float, kg/m/s): dynamic viscosity of air
    turbine.shear_exponent = 0.2  # (Float): shear exponent
    turbine.hub_height = 90.0  # (Float, m): hub height
    turbine.turbine_class = 'I'  # (Enum): IEC turbine class
    turbine.turbulence_class = 'B'  # (Enum): IEC turbulence class class
    turbine.cdf_reference_height_wind_speed = 90.0  # (Float): reference hub height for IEC wind speed (used in CDF calculation)
    turbine.g = 9.81  # (Float, m/s**2): acceleration of gravity
    # ======================

    # === rotor ===
    # --- blade grid ---
    turbine.rotor.initial_aero_grid = np.array([0.02222276, 0.06666667, 0.11111057, 0.16666667, 0.23333333, 0.3, 0.36666667,
        0.43333333, 0.5, 0.56666667, 0.63333333, 0.7, 0.76666667, 0.83333333, 0.88888943, 0.93333333,
        0.97777724])  # (Array): initial aerodynamic grid on unit radius
    turbine.rotor.initial_str_grid = np.array([0.0, 0.00492790457512, 0.00652942887106, 0.00813095316699, 0.00983257273154,
        0.0114340970275, 0.0130356213234, 0.02222276, 0.024446481932, 0.026048006228, 0.06666667, 0.089508406455,
        0.11111057, 0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 0.276686558545, 0.3, 0.333640766319,
        0.36666667, 0.400404310407, 0.43333333, 0.5, 0.520818918408, 0.56666667, 0.602196371696, 0.63333333,
        0.667358391486, 0.683573824984, 0.7, 0.73242031601, 0.76666667, 0.83333333, 0.88888943, 0.93333333, 0.97777724,
        1.0])  # (Array): initial structural grid on unit radius
    turbine.rotor.idx_cylinder_aero = 3  # (Int): first idx in r_aero_unit of non-cylindrical section, constant twist inboard of here
    turbine.rotor.idx_cylinder_str = 14  # (Int): first idx in r_str_unit of non-cylindrical section
    turbine.rotor.hubFraction = 0.025  # (Float): hub location as fraction of radius
    # ------------------

    # --- blade geometry ---
    turbine.rotor.r_aero = np.array([0.02222276, 0.06666667, 0.11111057, 0.2, 0.23333333, 0.3, 0.36666667, 0.43333333,
        0.5, 0.56666667, 0.63333333, 0.64, 0.7, 0.83333333, 0.88888943, 0.93333333,
        0.97777724])  # (Array): new aerodynamic grid on unit radius
    turbine.rotor.r_max_chord = 0.23577  # (Float): location of max chord on unit radius
    turbine.rotor.chord_sub = [3.2612, 4.5709, 3.3178, 1.4621]  # (Array, m): chord at control points. defined at hub, then at linearly spaced locations from r_max_chord to tip
    turbine.rotor.theta_sub = [13.2783, 7.46036, 2.89317, -0.0878099]  # (Array, deg): twist at control points.  defined at linearly spaced locations from r[idx_cylinder] to tip
    turbine.rotor.precurve_sub = [0.0, 0.0, 0.0]  # (Array, m): precurve at control points.  defined at same locations at chord, starting at 2nd control point (root must be zero precurve)
    turbine.rotor.delta_precurve_sub = [0.0, 0.0, 0.0]  # (Array, m): adjustment to precurve to account for curvature from loading
    turbine.rotor.sparT = [0.05, 0.047754, 0.045376, 0.031085, 0.0061398]  # (Array, m): spar cap thickness parameters
    turbine.rotor.teT = [0.1, 0.09569, 0.06569, 0.02569, 0.00569]  # (Array, m): trailing-edge thickness parameters
    turbine.rotor.bladeLength = 61.5  # (Float, m): blade length (if not precurved or swept) otherwise length of blade before curvature
    turbine.rotor.delta_bladeLength = 0.0  # (Float, m): adjustment to blade length to account for curvature from loading
    turbine.rotor.precone = 2.5  # (Float, deg): precone angle
    turbine.rotor.tilt = 5.0  # (Float, deg): shaft tilt
    turbine.rotor.yaw = 0.0  # (Float, deg): yaw error
    turbine.rotor.nBlades = 3  # (Int): number of blades
    # ------------------

    # --- airfoil files ---
    import rotorse
    #basepath = os.path.join('5MW_files', '5MW_AFFiles')
    basepath = os.path.join('..','reference_turbines','nrel5mw','airfoils')

    # load all airfoils
    airfoil_types = [0]*8
    airfoil_types[0] = os.path.join(basepath, 'Cylinder1.dat')
    airfoil_types[1] = os.path.join(basepath, 'Cylinder2.dat')
    airfoil_types[2] = os.path.join(basepath, 'DU40_A17.dat')
    airfoil_types[3] = os.path.join(basepath, 'DU35_A17.dat')
    airfoil_types[4] = os.path.join(basepath, 'DU30_A17.dat')
    airfoil_types[5] = os.path.join(basepath, 'DU25_A17.dat')
    airfoil_types[6] = os.path.join(basepath, 'DU21_A17.dat')
    airfoil_types[7] = os.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]

    n = len(af_idx)
    af = [0]*n
    for i in range(n):
        af[i] = airfoil_types[af_idx[i]]
    turbine.rotor.airfoil_files = af  # (List): names of airfoil file
    # ----------------------

    # --- control ---
    turbine.rotor.control.Vin = 3.0  # (Float, m/s): cut-in wind speed
    turbine.rotor.control.Vout = 25.0  # (Float, m/s): cut-out wind speed
    turbine.rotor.control.ratedPower = 5e6  # (Float, W): rated power
    turbine.rotor.control.minOmega = 0.0  # (Float, rpm): minimum allowed rotor rotation speed
    turbine.rotor.control.maxOmega = 12.0  # (Float, rpm): maximum allowed rotor rotation speed
    turbine.rotor.control.tsr = 7.55  # (Float): tip-speed ratio in Region 2 (should be optimized externally)
    turbine.rotor.control.pitch = 0.0  # (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines)
    turbine.rotor.pitch_extreme = 0.0  # (Float, deg): worst-case pitch at survival wind condition
    turbine.rotor.azimuth_extreme = 0.0  # (Float, deg): worst-case azimuth at survival wind condition
    turbine.rotor.VfactorPC = 0.7  # (Float): fraction of rated speed at which the deflection is assumed to representative throughout the power curve calculation
    # ----------------------

    # --- aero and structural analysis options ---
    turbine.rotor.nSector = 4  # (Int): number of sectors to divide rotor face into in computing thrust and power
    turbine.rotor.npts_coarse_power_curve = 20  # (Int): number of points to evaluate aero analysis at
    turbine.rotor.npts_spline_power_curve = 200  # (Int): number of points to use in fitting spline to power curve
    turbine.rotor.AEP_loss_factor = 1.0  # (Float): availability and other losses (soiling, array, etc.)
    turbine.rotor.drivetrainType = 'geared'  # (Enum)
    turbine.rotor.nF = 5  # (Int): number of natural frequencies to compute
    turbine.rotor.dynamic_amplication_tip_deflection = 1.35  # (Float): a dynamic amplification factor to adjust the static deflection calculation
    # ----------------------


    # --- materials and composite layup  ---
    #basepath = os.path.join('5MW_files', '5MW_PrecompFiles')
    basepath = os.path.join('..', 'reference_turbines','nrel5mw','blade')

    materials = Orthotropic2DMaterial.listFromPreCompFile(os.path.join(basepath, 'materials.inp'))

    ncomp = len(turbine.rotor.initial_str_grid)
    upper = [0]*ncomp
    lower = [0]*ncomp
    webs = [0]*ncomp
    profile = [0]*ncomp

    turbine.rotor.leLoc = np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.498, 0.497, 0.465, 0.447, 0.43, 0.411,
        0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4,
        0.4, 0.4, 0.4, 0.4])    # (Array): array of leading-edge positions from a reference blade axis (usually blade pitch axis). locations are normalized by the local chord length. e.g. leLoc[i] = 0.2 means leading edge is 0.2*chord[i] from reference axis.  positive in -x direction for airfoil-aligned coordinate system
    turbine.rotor.sector_idx_strain_spar = [2]*ncomp  # (Array): index of sector for spar (PreComp definition of sector)
    turbine.rotor.sector_idx_strain_te = [3]*ncomp  # (Array): index of sector for trailing-edge (PreComp definition of sector)
    web1 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.4114, 0.4102, 0.4094, 0.3876, 0.3755, 0.3639, 0.345, 0.3342, 0.3313, 0.3274, 0.323, 0.3206, 0.3172, 0.3138, 0.3104, 0.307, 0.3003, 0.2982, 0.2935, 0.2899, 0.2867, 0.2833, 0.2817, 0.2799, 0.2767, 0.2731, 0.2664, 0.2607, 0.2562, 0.1886, -1.0])
    web2 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.5886, 0.5868, 0.5854, 0.5508, 0.5315, 0.5131, 0.4831, 0.4658, 0.4687, 0.4726, 0.477, 0.4794, 0.4828, 0.4862, 0.4896, 0.493, 0.4997, 0.5018, 0.5065, 0.5101, 0.5133, 0.5167, 0.5183, 0.5201, 0.5233, 0.5269, 0.5336, 0.5393, 0.5438, 0.6114, -1.0])
    web3 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0])
    turbine.rotor.chord_str_ref = np.array([3.2612, 3.3100915356, 3.32587052924, 3.34159388653, 3.35823798667, 3.37384375335,
        3.38939112914, 3.4774055542, 3.49839685, 3.51343645709, 3.87017220335, 4.04645623801, 4.19408216643,
         4.47641008477, 4.55844487985, 4.57383098262, 4.57285771934, 4.51914315648, 4.47677655262, 4.40075650022,
         4.31069949379, 4.20483735936, 4.08985563932, 3.82931757126, 3.74220276467, 3.54415796922, 3.38732428502,
         3.24931446473, 3.23421422609, 3.22701537997, 3.21972125648, 3.08979310611, 2.95152261813, 2.330753331,
         2.05553464181, 1.82577817774, 1.5860853279, 1.4621])  # (Array, m): chord distribution for reference section, thickness of structural layup scaled with reference thickness (fixed t/c for this case)

    for i in range(ncomp):

        webLoc = []
        if web1[i] != -1:
            webLoc.append(web1[i])
        if web2[i] != -1:
            webLoc.append(web2[i])
        if web3[i] != -1:
            webLoc.append(web3[i])

        upper[i], lower[i], webs[i] = CompositeSection.initFromPreCompLayupFile(os.path.join(basepath, 'layup_' + str(i+1) + '.inp'), webLoc, materials)
        profile[i] = Profile.initFromPreCompFile(os.path.join(basepath, 'shape_' + str(i+1) + '.inp'))

    turbine.rotor.materials = materials  # (List): list of all Orthotropic2DMaterial objects used in defining the geometry
    turbine.rotor.upperCS = upper  # (List): list of CompositeSection objections defining the properties for upper surface
    turbine.rotor.lowerCS = lower  # (List): list of CompositeSection objections defining the properties for lower surface
    turbine.rotor.websCS = webs  # (List): list of CompositeSection objections defining the properties for shear webs
    turbine.rotor.profile = profile  # (List): airfoil shape at each radial position
    # --------------------------------------

    strain_ult_spar = 1.0e-2
    strain_ult_te = 2500*1e-6

    # --- fatigue ---
    turbine.rotor.rstar_damage = np.array([0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500,
        0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978])  # (Array): nondimensional radial locations of damage equivalent moments
    turbine.rotor.Mxb_damage = 1e3*np.array([2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003,
        1.0488E+003, 8.2367E+002, 6.3407E+002, 4.7727E+002, 3.4804E+002, 2.4458E+002, 1.6339E+002,
        1.0252E+002, 5.7842E+001, 2.7349E+001, 1.1262E+001, 3.8549E+000, 4.4738E-001])  # (Array, N*m): damage equivalent moments about blade c.s. x-direction
    turbine.rotor.Myb_damage = 1e3*np.array([2.7732E+003, 2.8155E+003, 2.6004E+003, 2.3933E+003, 2.1371E+003,
        1.8459E+003, 1.5582E+003, 1.2896E+003, 1.0427E+003, 8.2015E+002, 6.2449E+002, 4.5229E+002,
        3.0658E+002, 1.8746E+002, 9.6475E+001, 4.2677E+001, 1.5409E+001, 1.8426E+000])  # (Array, N*m): damage equivalent moments about blade c.s. y-direction
    turbine.rotor.strain_ult_spar = 1.0e-2  # (Float): ultimate strain in spar cap
    turbine.rotor.strain_ult_te = 2500*1e-6 * 2   # (Float): uptimate strain in trailing-edge panels, note that I am putting a factor of two for the damage part only.
    turbine.rotor.eta_damage = 1.35*1.3*1.0  # (Float): safety factor for fatigue
    turbine.rotor.m_damage = 10.0  # (Float): slope of S-N curve for fatigue analysis
    turbine.rotor.N_damage = 365*24*3600*20.0  # (Float): number of cycles used in fatigue analysis  TODO: make function of rotation speed
    # ----------------
    # =================


    # === nacelle ======
    turbine.nacelle.L_ms = 1.0  # (Float, m): main shaft length downwind of main bearing in low-speed shaft
    turbine.nacelle.L_mb = 2.5  # (Float, m): main shaft length in low-speed shaft

    turbine.nacelle.h0_front = 1.7  # (Float, m): height of Ibeam in bedplate front
    turbine.nacelle.h0_rear = 1.35  # (Float, m): height of Ibeam in bedplate rear

    turbine.nacelle.drivetrain_design = 'geared'
    turbine.nacelle.crane = True  # (Bool): flag for presence of crane
    turbine.nacelle.bevel = 0  # (Int): Flag for the presence of a bevel stage - 1 if present, 0 if not
    turbine.nacelle.gear_configuration = 'eep'  # (Str): tring that represents the configuration of the gearbox (stage number and types)

    turbine.nacelle.Np = [3, 3, 1]  # (Array): number of planets in each stage
    turbine.nacelle.ratio_type = 'optimal'  # (Str): optimal or empirical stage ratios
    turbine.nacelle.shaft_type = 'normal'  # (Str): normal or short shaft length
    #turbine.nacelle.shaft_angle = 5.0  # (Float, deg): Angle of the LSS inclindation with respect to the horizontal
    turbine.nacelle.shaft_ratio = 0.10  # (Float): Ratio of inner diameter to outer diameter.  Leave zero for solid LSS
    turbine.nacelle.carrier_mass = 8000.0 # estimated for 5 MW
    turbine.nacelle.mb1Type = 'CARB'  # (Str): Main bearing type: CARB, TRB or SRB
    turbine.nacelle.mb2Type = 'SRB'  # (Str): Second bearing type: CARB, TRB or SRB
    turbine.nacelle.yaw_motors_number = 8.0  # (Float): number of yaw motors
    turbine.nacelle.uptower_transformer = True
    turbine.nacelle.flange_length = 0.5 #m
    turbine.nacelle.gearbox_cm = 0.1
    turbine.nacelle.hss_length = 1.5
    turbine.nacelle.overhang = 5.0 #TODO - should come from turbine configuration level

    turbine.nacelle.check_fatigue = 0 #0 if no fatigue check, 1 if parameterized fatigue check, 2 if known loads inputs

    # TODO: should come from rotor (these are FAST outputs)
    turbine.nacelle.DrivetrainEfficiency = 0.95
    turbine.nacelle.rotor_bending_moment_x = 330770.0# Nm
    turbine.nacelle.rotor_bending_moment_y = -16665000.0 # Nm
    turbine.nacelle.rotor_bending_moment_z = 2896300.0 # Nm
    turbine.nacelle.rotor_force_x = 599610.0 # N
    turbine.nacelle.rotor_force_y = 186780.0 # N
    turbine.nacelle.rotor_force_z = -842710.0 # N

    #turbine.nacelle.h0_rear = 1.35 # only used in drive smooth
    #turbine.nacelle.h0_front = 1.7

    # =================

    if wind_class == 'I':
        turbine.rotor.turbine_class = 'I'

    elif wind_class == 'III':
        turbine.rotor.turbine_class = 'III'

        # for fatigue based analysis of class III wind turbine
        turbine.tower.M_DEL = 1.028713178 * 1e3*np.array([7.8792E+003, 7.7507E+003, 7.4918E+003, 7.2389E+003, 6.9815E+003, 6.7262E+003, 6.4730E+003, 6.2174E+003, 5.9615E+003, 5.7073E+003, 5.4591E+003, 5.2141E+003, 4.9741E+003, 4.7399E+003, 4.5117E+003, 4.2840E+003, 4.0606E+003, 3.8360E+003, 3.6118E+003, 3.3911E+003, 3.1723E+003, 2.9568E+003, 2.7391E+003, 2.5294E+003, 2.3229E+003, 2.1246E+003, 1.9321E+003, 1.7475E+003, 1.5790E+003, 1.4286E+003, 1.3101E+003, 1.2257E+003, 1.1787E+003, 1.1727E+003, 1.1821E+003])

        turbine.rotor.Mxb_damage = 1e3*np.array([2.3617E+003, 2.0751E+003, 1.8051E+003, 1.5631E+003, 1.2994E+003, 1.0388E+003, 8.1384E+002, 6.2492E+002, 4.6916E+002, 3.4078E+002, 2.3916E+002, 1.5916E+002, 9.9752E+001, 5.6139E+001, 2.6492E+001, 1.0886E+001, 3.7210E+000, 4.3206E-001])
        turbine.rotor.Myb_damage = 1e3*np.array([2.5492E+003, 2.6261E+003, 2.4265E+003, 2.2308E+003, 1.9882E+003, 1.7184E+003, 1.4438E+003, 1.1925E+003, 9.6251E+002, 7.5564E+002, 5.7332E+002, 4.1435E+002, 2.8036E+002, 1.7106E+002, 8.7732E+001, 3.8678E+001, 1.3942E+001, 1.6600E+000])

    elif wind_class == 'Offshore':
        turbine.rotor.turbine_class = 'I'

    # =================

    # === jacket ===

    #--- Set Jacket Input Parameters ---#
    Jcktins=JcktGeoInputs()
    Jcktins.nlegs =4
    Jcktins.nbays =5
    Jcktins.batter=12.
    Jcktins.dck_botz =16.
    Jcktins.weld2D   =0.5
    Jcktins.VPFlag = True    #vertical pile T/F;  to enable piles in frame3DD set pileinputs.ndiv>0
    Jcktins.clamped= False    #whether or not the bottom of the structure is rigidly connected. Use False when equivalent spring constants are being used.
    Jcktins.AFflag = False  #whether or not to use apparent fixity piles
    Jcktins.PreBuildTPLvl = 2  #if >0, the TP is prebuilt according to rules per PreBuildTP

    #Soil inputs
    Soilinputs=SoilGeoInputs()
    Soilinputs.zbots   =-np.array([3.,5.,7.,15.,30.,50.])
    Soilinputs.gammas  =np.array([10000.,10000.,10000.,10000.,10000.,10000.])
    Soilinputs.cus     =np.array([60000.,60000.,60000.,60000.,60000.,60000.])
    Soilinputs.phis    =np.array([26.,26.,26.,26.,26.,26])#np.array([36.,33.,26.,37.,35.,37.5])#np.array([36.,33.,26.,37.,35.,37.5])
    Soilinputs.delta   =25.
    Soilinputs.sndflg   =True
    Soilinputs.PenderSwtch   =False #True
    Soilinputs.SoilSF   =1.

    #Water and wind inputs
    Waterinputs=WaterInputs()
    Waterinputs.wdepth   =30.
    Waterinputs.wlevel   =30. #Distance from bottom of structure to surface  THIS, I believe is no longer needed as piles may be negative in z, to check and remove in case
    Waterinputs.T=12.  #Wave Period
    Waterinputs.HW=10. #Wave Height
    '''Windinputs=WindInputs()
    Windinputs.HH=100. #CHECK HOW THIS COMPLIES....
    Windinputs.U50HH=30. #assumed gust speed'''

    #RNA loads              Fx-z,         Mxx-zz
    #RNA_F=np.array([1000.e3,0.,0.,0.,0.,0.])

    #Pile data
    Pilematin=MatInputs()
    Pilematin.matname=np.array(['steel'])
    Pilematin.E=np.array([ 25.e9])
    Dpile=2.5#0.75 # 2.0
    tpile=0.01
    Lp=20. #45

    Pileinputs=PileGeoInputs()
    Pileinputs.Pilematins=Pilematin
    Pileinputs.ndiv=0 #3
    Pileinputs.Dpile=Dpile
    Pileinputs.tpile=tpile
    Pileinputs.Lp=Lp #[m] Embedment length

    #Legs data
    legmatin=MatInputs()
    legmatin.matname=(['steel','steel','steel','steel'])
    legmatin.E=np.array([2.0e11])
    Dleg=np.array([2.0,1.8,1.8,1.8,1.8,1.8])
    tleg=1.55*np.array([0.0254]).repeat(Dleg.size)
    leginputs=LegGeoInputs()
    leginputs.legZbot   = 1.0
    leginputs.ndiv=1
    leginputs.legmatins=legmatin
    leginputs.Dleg=Dleg
    leginputs.tleg=tleg

    legbot_stmphin =1.5  #Distance from bottom of leg to second joint along z; must be>0

    #Xbrc data
    Xbrcmatin=MatInputs()
    Xbrcmatin.matname=np.array(['steel']).repeat(Jcktins.nbays)
    Xbrcmatin.E=np.array([ 2.2e11, 2.0e11,2.0e11,2.0e11,2.0e11])
    Dbrc=np.array([1.,1.,1.0,1.0,1.0])
    tbrc=np.array([1.,1.,1.0,1.0,1.0])*0.0254

    Xbrcinputs=XBrcGeoInputs()
    Xbrcinputs.Dbrc=Dbrc
    Xbrcinputs.tbrc=tbrc
    Xbrcinputs.ndiv=2#2
    Xbrcinputs.Xbrcmatins=Xbrcmatin
    Xbrcinputs.precalc=True   #This can be set to true if we want Xbraces to be precalculated in D and t, in which case the above set Dbrc and tbrc would be overwritten

    #Mbrc data
    Mbrcmatin=MatInputs()
    Mbrcmatin.matname=np.array(['steel'])
    Mbrcmatin.E=np.array([ 2.5e11])
    Dbrc_mud=1.5

    Mbrcinputs=MudBrcGeoInputs()
    Mbrcinputs.Dbrc_mud=Dbrc_mud
    Mbrcinputs.ndiv=2
    Mbrcinputs.Mbrcmatins=Mbrcmatin
    Mbrcinputs.precalc=True   #This can be set to true if we want Mudbrace to be precalculated in D and t, in which case the above set Dbrc_mud and tbrc_mud would be overwritten
    #Hbrc data
    Hbrcmatin=MatInputs()
    Hbrcmatin.matname=np.array(['steel'])
    Hbrcmatin.E=np.array([ 2.5e11])
    Dbrc_hbrc=1.1

    Hbrcinputs=HBrcGeoInputs()
    Hbrcinputs.Dbrch=Dbrc_hbrc
    Hbrcinputs.ndiv=0#2
    Hbrcinputs.Hbrcmatins=Hbrcmatin
    Hbrcinputs.precalc=True   #This can be set to true if we want Hbrace to be set=Xbrace top D and t, in which case the above set Dbrch and tbrch would be overwritten

    #TP data
    TPlumpinputs=TPlumpMass()
    TPlumpinputs.mass=300.e3 #[kg]

    TPstmpsmatin=MatInputs()
    TPbrcmatin=MatInputs()
    TPstemmatin=MatInputs()
    TPbrcmatin.matname=np.array(['steel'])
    TPbrcmatin.E=np.array([ 2.5e11])
    TPstemmatin.matname=np.array(['steel']).repeat(2)
    TPstemmatin.E=np.array([ 2.1e11]).repeat(2)

    TPinputs=TPGeoInputs()
    TPinputs.TPbrcmatins=TPbrcmatin
    TPinputs.TPstemmatins=TPstemmatin
    TPinputs.TPstmpmatins=TPstmpsmatin
    TPinputs.Dstrut=1.6
    TPinputs.Dgir=Dbrc_hbrc
    TPinputs.Dbrc=1.1
    TPinputs.hstump=0.0#1.0
    TPinputs.stumpndiv=1#2
    TPinputs.brcndiv=1#2
    TPinputs.girndiv=1#2
    TPinputs.strutndiv=1#2
    TPinputs.stemndiv=1#2
    TPinputs.nstems=3
    TPinputs.Dstem=np.array([6.]).repeat(TPinputs.nstems)
    TPinputs.tstem=np.array([0.1,0.11,0.11])
    TPinputs.hstem=np.array([4.,3.,1.])

    #Tower data
    Twrmatin=MatInputs()
    Twrmatin.matname=np.array(['steel'])
    Twrmatin.E=np.array([ 2.77e11])
    Db=5.6
    tb=0.05
    Dt=Db*0.55

    '''Twrinputs=TwrGeoInputs()
    Twrinputs.Twrmatins=Twrmatin
    #Twrinputs.Htwr=70.  #Trumped by HH
    Twrinputs.Htwr2frac=0.2   #fraction of tower height with constant x-section
    Twrinputs.ndiv=np.array([6,6])  #ndiv for uniform and tapered section
    Twrinputs.Db=Db
    Twrinputs.DTRb=Db/tb
    #Twrinputs.Dt=Dt'''

    TwrRigidTop=True #False       #False=Account for RNA via math rather than a physical rigidmember

    #RNA data
    '''RNAins=RNAprops()
    RNAins.mass=3*350.e3
    RNAins.I[0]=86.579E+6
    RNAins.I[1]=53.530E+6
    RNAins.I[2]=58.112E+6
    RNAins.CMoff[2]=2.34
    RNAins.yawangle=45.  #angle with respect to global X, CCW looking from above, wind from left
    RNAins.rna_weightM=True'''

    #Frame3DD parameters
    FrameAuxIns=Frame3DDaux()
    FrameAuxIns.sh_fg=1               #shear flag-->Timoshenko
    FrameAuxIns.deltaz=5.
    FrameAuxIns.geo_fg=0
    FrameAuxIns.nModes = 6             # number of desired dynamic modes of vibration
    FrameAuxIns.Mmethod = 1            # 1: subspace Jacobi     2: Stodola
    FrameAuxIns.lump = 0               # 0: consistent mass ... 1: lumped mass matrix
    FrameAuxIns.tol = 1e-9             # mode shape tolerance
    FrameAuxIns.shift = 0.0            # shift value ... for unrestrained structures
    FrameAuxIns.gvector=np.array([0.,0.,-9.8065])    #GRAVITY

    #Pass all inputs to jacket assembly
    turbine.jacket.JcktGeoIn=Jcktins
    turbine.jacket.Soilinputs=Soilinputs
    turbine.jacket.Waterinputs=Waterinputs
    #turbine.jacket.Windinputs=Windinputs
    #turbine.jacket.RNA_F=RNA_F
    turbine.jacket.Pileinputs=Pileinputs
    turbine.jacket.leginputs=leginputs
    turbine.jacket.legbot_stmphin =legbot_stmphin
    turbine.jacket.Xbrcinputs=Xbrcinputs
    turbine.jacket.Mbrcinputs=Mbrcinputs
    turbine.jacket.Hbrcinputs=Hbrcinputs
    turbine.jacket.TPlumpinputs=TPlumpinputs
    turbine.jacket.TPinputs=TPinputs
    #turbine.jacket.RNAinputs=RNAins
    #turbine.jacket.Twrinputs=Twrinputs
    turbine.jacket.Twrinputs.Twrmatins=Twrmatin
    turbine.jacket.Twrinputs.Htwr2frac=0.2   #fraction of tower height with constant x-section
    turbine.jacket.Twrinputs.ndiv=np.array([6,6])  #ndiv for uniform and tapered section
    turbine.jacket.Twrinputs.Db=Db
    turbine.jacket.Twrinputs.Dt=Dt
    turbine.jacket.Twrinputs.DTRb=Db/tb
    turbine.jacket.Twrinputs.DTRt=Db/Dt # TODO double check
    turbine.jacket.TwrRigidTop=TwrRigidTop
    turbine.jacket.FrameAuxIns=FrameAuxIns