Exemple #1
0
def rotor_from_excel_type03(in_op_params, in_geom_params, in_excel_description,
                            in_options):
    """
    generate_from_excel_type03_db

    Function needed to generate a wind turbine from an excel database type03

    Args:
        op_param (dict): Dictionary with operating parameters
        geom_param (dict): Dictionray with geometical parameters
        excel_description (dict): Dictionary describing the sheets of the excel file
        option (dict): Dictionary with the different options for the wind turbine generation

    Returns:
        rotor (sharpy.utils.generate_cases.AeroelasticInfromation): Aeroelastic information of the rotor
    """
    # Default values
    op_params = {}
    op_params['rotation_velocity'] = None  # Rotation velocity of the rotor
    op_params['pitch_deg'] = None  # pitch angle in degrees
    op_params[
        'wsp'] = 0.  # wind speed (It may be needed for discretisation purposes)
    op_params[
        'dt'] = 0.  # time step (It may be needed for discretisation purposes)

    geom_params = {}
    geom_params[
        'chord_panels'] = None  # Number of panels on the blade surface in the chord direction
    geom_params[
        'tol_remove_points'] = 1e-3  # maximum distance to remove adjacent points
    geom_params[
        'n_points_camber'] = 100  # number of points to define the camber of the airfoil
    geom_params[
        'h5_cross_sec_prop'] = None  # h5 containing mass and stiffness matrices along the blade
    geom_params['m_distribution'] = 'uniform'  #

    options = {}
    options[
        'camber_effect_on_twist'] = False  # When true plain airfoils are used and the blade is twisted and preloaded based on thin airfoil theory
    options[
        'user_defined_m_distribution_type'] = None  # type of distribution of the chordwise panels when 'm_distribution' == 'user_defined'
    options['include_polars'] = False  #

    excel_description = {}
    excel_description['excel_file_name'] = 'database_excel_type02.xlsx'
    excel_description['excel_sheet_parameters'] = 'parameters'
    excel_description['excel_sheet_structural_blade'] = 'structural_blade'
    excel_description[
        'excel_sheet_discretization_blade'] = 'discretization_blade'
    excel_description['excel_sheet_aero_blade'] = 'aero_blade'
    excel_description['excel_sheet_airfoil_info'] = 'airfoil_info'
    excel_description['excel_sheet_airfoil_chord'] = 'airfoil_coord'

    # Overwrite the default values with the values of the input arguments
    for key in in_op_params:
        op_params[key] = in_op_params[key]
    for key in in_geom_params:
        geom_params[key] = in_geom_params[key]
    for key in in_options:
        options[key] = in_options[key]
    for key in in_excel_description:
        excel_description[key] = in_excel_description[key]

    # Put the dictionaries information into variables (to avoid changing the function)
    rotation_velocity = op_params['rotation_velocity']
    pitch_deg = op_params['pitch_deg']
    wsp = op_params['wsp']
    dt = op_params['dt']

    chord_panels = geom_params['chord_panels']
    tol_remove_points = geom_params['tol_remove_points']
    n_points_camber = geom_params['n_points_camber']
    h5_cross_sec_prop = geom_params['h5_cross_sec_prop']
    m_distribution = geom_params['m_distribution']

    camber_effect_on_twist = options['camber_effect_on_twist']
    user_defined_m_distribution_type = options[
        'user_defined_m_distribution_type']
    include_polars = options['include_polars']

    excel_file_name = excel_description['excel_file_name']
    excel_sheet_parameters = excel_description['excel_sheet_parameters']
    excel_sheet_structural_blade = excel_description[
        'excel_sheet_structural_blade']
    excel_sheet_discretization_blade = excel_description[
        'excel_sheet_discretization_blade']
    excel_sheet_aero_blade = excel_description['excel_sheet_aero_blade']
    excel_sheet_airfoil_info = excel_description['excel_sheet_airfoil_info']
    excel_sheet_airfoil_coord = excel_description['excel_sheet_airfoil_chord']

    ######################################################################
    ## BLADE
    ######################################################################
    blade = gc.AeroelasticInformation()

    ######################################################################
    ### STRUCTURE
    ######################################################################
    # Read blade structural information from excel file
    rR_structural = gc.read_column_sheet_type01(excel_file_name,
                                                excel_sheet_structural_blade,
                                                'rR')
    OutPElAxis = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_structural_blade,
                                             'OutPElAxis')
    InPElAxis = gc.read_column_sheet_type01(excel_file_name,
                                            excel_sheet_structural_blade,
                                            'InPElAxis')
    ElAxisAftLEc = gc.read_column_sheet_type01(excel_file_name,
                                               excel_sheet_structural_blade,
                                               'ElAxisAftLEc')
    StrcTwst = gc.read_column_sheet_type01(
        excel_file_name, excel_sheet_structural_blade, 'StrcTwst') * deg2rad
    BMassDen = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_blade,
                                           'BMassDen')
    FlpStff = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_blade,
                                          'FlpStff')
    EdgStff = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_blade,
                                          'EdgStff')
    FlapEdgeStiff = gc.read_column_sheet_type01(excel_file_name,
                                                excel_sheet_structural_blade,
                                                'FlapEdgeStiff')
    GJStff = gc.read_column_sheet_type01(excel_file_name,
                                         excel_sheet_structural_blade,
                                         'GJStff')
    EAStff = gc.read_column_sheet_type01(excel_file_name,
                                         excel_sheet_structural_blade,
                                         'EAStff')
    FlpIner = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_blade,
                                          'FlpIner')
    EdgIner = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_blade,
                                          'EdgIner')
    FlapEdgeIner = gc.read_column_sheet_type01(excel_file_name,
                                               excel_sheet_structural_blade,
                                               'FlapEdgeIner')
    PrebendRef = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_structural_blade,
                                             'PrebendRef')
    PreswpRef = gc.read_column_sheet_type01(excel_file_name,
                                            excel_sheet_structural_blade,
                                            'PreswpRef')
    OutPcg = gc.read_column_sheet_type01(excel_file_name,
                                         excel_sheet_structural_blade,
                                         'OutPcg')
    InPcg = gc.read_column_sheet_type01(excel_file_name,
                                        excel_sheet_structural_blade, 'InPcg')

    # Blade parameters
    TipRad = gc.read_column_sheet_type01(excel_file_name,
                                         excel_sheet_parameters, 'TipRad')
    # HubRad = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters, 'HubRad')

    # Discretization points
    rR = gc.read_column_sheet_type01(excel_file_name,
                                     excel_sheet_discretization_blade, 'rR')

    # Interpolate excel variables into the correct locations
    # Geometry
    if rR[0] < rR_structural[0]:
        rR_structural = np.concatenate((np.array([0.]), rR_structural), )
        OutPElAxis = np.concatenate((np.array([OutPElAxis[0]]), OutPElAxis), )
        InPElAxis = np.concatenate((np.array([InPElAxis[0]]), InPElAxis), )
        ElAxisAftLEc = np.concatenate(
            (np.array([ElAxisAftLEc[0]]), ElAxisAftLEc), )
        StrcTwst = np.concatenate((np.array([StrcTwst[0]]), StrcTwst), )
        BMassDen = np.concatenate((np.array([BMassDen[0]]), BMassDen), )
        FlpStff = np.concatenate((np.array([FlpStff[0]]), FlpStff), )
        EdgStff = np.concatenate((np.array([EdgStff[0]]), EdgStff), )
        FlapEdgeStiff = np.concatenate(
            (np.array([FlapEdgeStiff[0]]), FlapEdgeStiff), )
        GJStff = np.concatenate((np.array([GJStff[0]]), GJStff), )
        EAStff = np.concatenate((np.array([EAStff[0]]), EAStff), )
        FlpIner = np.concatenate((np.array([FlpIner[0]]), FlpIner), )
        EdgIner = np.concatenate((np.array([EdgIner[0]]), EdgIner), )
        FlapEdgeIner = np.concatenate(
            (np.array([FlapEdgeIner[0]]), FlapEdgeIner), )
        PrebendRef = np.concatenate((np.array([PrebendRef[0]]), PrebendRef), )
        PreswpRef = np.concatenate((np.array([PreswpRef[0]]), PreswpRef), )
        OutPcg = np.concatenate((np.array([OutPcg[0]]), OutPcg), )
        InPcg = np.concatenate((np.array([InPcg[0]]), InPcg), )

    # Base parameters
    use_excel_struct_as_elem = False
    if use_excel_struct_as_elem:
        blade.StructuralInformation.num_node_elem = 3
        blade.StructuralInformation.num_elem = len(rR) - 2
        blade.StructuralInformation.compute_basic_num_node()

        node_r, elem_r = create_node_radial_pos_from_elem_centres(
            rR * TipRad, blade.StructuralInformation.num_node,
            blade.StructuralInformation.num_elem,
            blade.StructuralInformation.num_node_elem)
    else:
        # Use excel struct as nodes
        # Check the number of nodes
        blade.StructuralInformation.num_node_elem = 3
        blade.StructuralInformation.num_node = len(rR)
        if ((len(rR) - 1) %
            (blade.StructuralInformation.num_node_elem - 1)) == 0:
            blade.StructuralInformation.num_elem = int(
                (len(rR) - 1) /
                (blade.StructuralInformation.num_node_elem - 1))
            node_r = rR * TipRad
            elem_rR = rR[1::2] + 0.
            elem_r = rR[1::2] * TipRad + 0.
        else:
            raise RuntimeError(
                ("ERROR: Cannot build %d-noded elements from %d nodes" %
                 (blade.StructuralInformation.num_node_elem,
                  blade.StructuralInformation.num_node)))

    node_y = np.interp(rR, rR_structural, InPElAxis) + np.interp(
        rR, rR_structural, PreswpRef)
    node_z = -np.interp(rR, rR_structural, OutPElAxis) - np.interp(
        rR, rR_structural, PrebendRef)
    node_twist = -1.0 * np.interp(rR, rR_structural, StrcTwst)

    coordinates = create_blade_coordinates(
        blade.StructuralInformation.num_node, node_r, node_y, node_z)

    if h5_cross_sec_prop is None:
        # Stiffness
        elem_EA = np.interp(elem_rR, rR_structural, EAStff)
        elem_EIy = np.interp(elem_rR, rR_structural, FlpStff)
        elem_EIz = np.interp(elem_rR, rR_structural, EdgStff)
        elem_EIyz = np.interp(elem_rR, rR_structural, FlapEdgeStiff)
        elem_GJ = np.interp(elem_rR, rR_structural, GJStff)

        # Stiffness: estimate unknown properties
        cout.cout_wrap.print_file = False
        cout.cout_wrap(
            'WARNING: The poisson cofficient is assumed equal to 0.3', 3)
        cout.cout_wrap('WARNING: Cross-section area is used as shear area', 3)
        poisson_coef = 0.3
        elem_GAy = elem_EA / 2.0 / (1.0 + poisson_coef)
        elem_GAz = elem_EA / 2.0 / (1.0 + poisson_coef)
        # Inertia
        elem_pos_cg_B = np.zeros((blade.StructuralInformation.num_elem, 3), )
        elem_pos_cg_B[:, 1] = np.interp(elem_rR, rR_structural, InPcg)
        elem_pos_cg_B[:, 2] = -np.interp(elem_rR, rR_structural, OutPcg)

        elem_mass_per_unit_length = np.interp(elem_rR, rR_structural, BMassDen)
        elem_mass_iner_y = np.interp(elem_rR, rR_structural, FlpIner)
        elem_mass_iner_z = np.interp(elem_rR, rR_structural, EdgIner)
        elem_mass_iner_yz = np.interp(elem_rR, rR_structural, FlapEdgeIner)

        # Inertia: estimate unknown properties
        cout.cout_wrap(
            'WARNING: Using perpendicular axis theorem to compute the inertia around xB',
            3)
        elem_mass_iner_x = elem_mass_iner_y + elem_mass_iner_z

        # Generate blade structural properties
        blade.StructuralInformation.create_mass_db_from_vector(
            elem_mass_per_unit_length, elem_mass_iner_x, elem_mass_iner_y,
            elem_mass_iner_z, elem_pos_cg_B, elem_mass_iner_yz)
        blade.StructuralInformation.create_stiff_db_from_vector(
            elem_EA, elem_GAy, elem_GAz, elem_GJ, elem_EIy, elem_EIz,
            elem_EIyz)

    else:
        # read Mass/Stiffness from database
        cross_prop = h5.readh5(h5_cross_sec_prop).str_prop

        # create mass_db/stiffness_db (interpolate at mid-node of each element)
        blade.StructuralInformation.mass_db = scint.interp1d(
            cross_prop.radius,
            cross_prop.M,
            kind='cubic',
            copy=False,
            assume_sorted=True,
            axis=0,
            bounds_error=False,
            fill_value='extrapolate')(node_r[1::2])
        blade.StructuralInformation.stiffness_db = scint.interp1d(
            cross_prop.radius,
            cross_prop.K,
            kind='cubic',
            copy=False,
            assume_sorted=True,
            axis=0,
            bounds_error=False,
            fill_value='extrapolate')(node_r[1::2])

    blade.StructuralInformation.generate_1to1_from_vectors(
        num_node_elem=blade.StructuralInformation.num_node_elem,
        num_node=blade.StructuralInformation.num_node,
        num_elem=blade.StructuralInformation.num_elem,
        coordinates=coordinates,
        stiffness_db=blade.StructuralInformation.stiffness_db,
        mass_db=blade.StructuralInformation.mass_db,
        frame_of_reference_delta='y_AFoR',
        vec_node_structural_twist=node_twist,
        num_lumped_mass=0)

    # Boundary conditions
    blade.StructuralInformation.boundary_conditions = np.zeros(
        (blade.StructuralInformation.num_node), dtype=int)
    blade.StructuralInformation.boundary_conditions[0] = 1
    blade.StructuralInformation.boundary_conditions[-1] = -1

    ######################################################################
    ### AERODYNAMICS
    ######################################################################
    # Read blade aerodynamic information from excel file
    rR_aero = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_aero_blade, 'rR')
    chord_aero = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_aero_blade, 'BlChord')
    thickness_aero = gc.read_column_sheet_type01(excel_file_name,
                                                 excel_sheet_aero_blade,
                                                 'BlThickness')

    pure_airfoils_names = gc.read_column_sheet_type01(
        excel_file_name, excel_sheet_airfoil_info, 'Name')
    pure_airfoils_thickness = gc.read_column_sheet_type01(
        excel_file_name, excel_sheet_airfoil_info, 'Thickness')

    node_ElAxisAftLEc = np.interp(node_r, rR_structural * TipRad, ElAxisAftLEc)

    # Read coordinates of the pure airfoils
    n_pure_airfoils = len(pure_airfoils_names)

    pure_airfoils_camber = np.zeros((n_pure_airfoils, n_points_camber, 2), )
    xls = pd.ExcelFile(excel_file_name)
    excel_db = pd.read_excel(xls, sheet_name=excel_sheet_airfoil_coord)
    for iairfoil in range(n_pure_airfoils):
        # Look for the NaN
        icoord = 2
        while (not (math.isnan(
                excel_db["%s_x" % pure_airfoils_names[iairfoil]][icoord]))):
            icoord += 1
            if (icoord == len(excel_db["%s_x" %
                                       pure_airfoils_names[iairfoil]])):
                break

        # Compute the camber of the airfoils at the defined chord points
        pure_airfoils_camber[iairfoil, :, 0], pure_airfoils_camber[
            iairfoil, :, 1] = gc.get_airfoil_camber(
                excel_db["%s_x" % pure_airfoils_names[iairfoil]][2:icoord],
                excel_db["%s_y" % pure_airfoils_names[iairfoil]][2:icoord],
                n_points_camber)

    # Basic variables
    surface_distribution = np.zeros((blade.StructuralInformation.num_elem),
                                    dtype=int)

    # Interpolate in the correct positions
    node_chord = np.interp(node_r, rR_aero * TipRad, chord_aero)

    # Define the nodes with aerodynamic properties
    # Look for the first element that is goint to be aerodynamic
    first_aero_elem = 0
    while (elem_r[first_aero_elem] <= rR_aero[0] * TipRad):
        first_aero_elem += 1
    first_aero_node = first_aero_elem * (
        blade.StructuralInformation.num_node_elem - 1)
    aero_node = np.zeros((blade.StructuralInformation.num_node, ), dtype=bool)
    aero_node[first_aero_node:] = np.ones(
        (blade.StructuralInformation.num_node - first_aero_node, ), dtype=bool)

    # Define the airfoil at each stage
    # airfoils = blade.AerodynamicInformation.interpolate_airfoils_camber(pure_airfoils_camber,excel_aero_r, node_r, n_points_camber)

    node_thickness = np.interp(node_r, rR_aero * TipRad, thickness_aero)

    airfoils = blade.AerodynamicInformation.interpolate_airfoils_camber_thickness(
        pure_airfoils_camber, pure_airfoils_thickness, node_thickness,
        n_points_camber)
    airfoil_distribution = np.linspace(0,
                                       blade.StructuralInformation.num_node -
                                       1,
                                       blade.StructuralInformation.num_node,
                                       dtype=int)

    # User defined m distribution
    if (m_distribution == 'user_defined') and (user_defined_m_distribution_type
                                               == 'last_geometric'):
        blade_nodes = blade.StructuralInformation.num_node
        udmd_by_nodes = np.zeros((blade_nodes, chord_panels[0] + 1))
        for inode in range(blade_nodes):
            r = np.linalg.norm(
                blade.StructuralInformation.coordinates[inode, :])
            vrel = np.sqrt(rotation_velocity**2 * r**2 + wsp**2)
            last_length = vrel * dt / node_chord[inode]
            last_length = np.minimum(last_length, 0.5)
            if last_length <= 0.5:
                ratio = gc.get_factor_geometric_progression(
                    last_length, 1., chord_panels)
                udmd_by_nodes[inode, -1] = 1.
                udmd_by_nodes[inode, 0] = 0.
                for im in range(chord_panels[0] - 1, 0, -1):
                    udmd_by_nodes[inode,
                                  im] = udmd_by_nodes[inode,
                                                      im + 1] - last_length
                    last_length *= ratio
                # Check
                if (np.diff(udmd_by_nodes[inode, :]) < 0.).any():
                    sys.error(
                        "ERROR in the panel discretization of the blade in node %d"
                        % (inode))
            else:
                raise RuntimeError(
                    ("ERROR: cannot match the last panel size for node: %d" %
                     inode))
                udmd_by_nodes[inode, :] = np.linspace(0, 1, chord_panels + 1)
    else:
        udmd_by_nodes = None

    node_twist = np.zeros_like(node_chord)
    if camber_effect_on_twist:
        cout.cout_wrap(
            "WARNING: The steady applied Mx should be manually multiplied by the density",
            3)
        for inode in range(blade.StructuralInformation.num_node):
            node_twist[inode] = gc.get_aoacl0_from_camber(
                airfoils[inode, :, 0], airfoils[inode, :, 1])
            mu0 = gc.get_mu0_from_camber(airfoils[inode, :, 0],
                                         airfoils[inode, :, 1])
            r = np.linalg.norm(
                blade.StructuralInformation.coordinates[inode, :])
            vrel = np.sqrt(rotation_velocity**2 * r**2 + wsp**2)
            if inode == 0:
                dr = 0.5 * np.linalg.norm(
                    blade.StructuralInformation.coordinates[1, :] -
                    blade.StructuralInformation.coordinates[0, :])
            elif inode == len(blade.StructuralInformation.coordinates[:,
                                                                      0]) - 1:
                dr = 0.5 * np.linalg.norm(
                    blade.StructuralInformation.coordinates[-1, :] -
                    blade.StructuralInformation.coordinates[-2, :])
            else:
                dr = 0.5 * np.linalg.norm(
                    blade.StructuralInformation.coordinates[inode + 1, :] -
                    blade.StructuralInformation.coordinates[inode - 1, :])
            moment_factor = 0.5 * vrel**2 * node_chord[inode]**2 * dr
            # print("node", inode, "mu0", mu0, "CMc/4", 2.*mu0 + np.pi/2*node_twist[inode])
            blade.StructuralInformation.app_forces[
                inode,
                3] = (2. * mu0 + np.pi / 2 * node_twist[inode]) * moment_factor
            airfoils[inode, :, 1] *= 0.

    # Write SHARPy format
    blade.AerodynamicInformation.create_aerodynamics_from_vec(
        blade.StructuralInformation, aero_node, node_chord, node_twist,
        np.pi * np.ones_like(node_chord), chord_panels, surface_distribution,
        m_distribution, node_ElAxisAftLEc, airfoil_distribution, airfoils,
        udmd_by_nodes)

    # Read the polars of the pure airfoils
    if include_polars:
        pure_polars = [None] * n_pure_airfoils
        for iairfoil in range(n_pure_airfoils):
            excel_sheet_polar = pure_airfoils_names[iairfoil]
            aoa = gc.read_column_sheet_type01(excel_file_name,
                                              excel_sheet_polar, 'AoA')
            cl = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_polar, 'CL')
            cd = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_polar, 'CD')
            cm = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_polar, 'CM')
            polar = ap.polar()
            polar.initialise(np.column_stack((aoa, cl, cd, cm)))
            pure_polars[iairfoil] = polar

        # Generate the polars for each airfoil
        blade.AerodynamicInformation.polars = [
            None
        ] * blade.StructuralInformation.num_node
        for inode in range(blade.StructuralInformation.num_node):
            # Find the airfoils between which the node is;
            ipure = 0
            while pure_airfoils_thickness[ipure] > node_thickness[inode]:
                ipure += 1
                if (ipure == n_pure_airfoils):
                    ipure -= 1
                    break

            coef = (node_thickness[inode] - pure_airfoils_thickness[ipure - 1]
                    ) / (pure_airfoils_thickness[ipure] -
                         pure_airfoils_thickness[ipure - 1])
            polar = ap.interpolate(pure_polars[ipure - 1], pure_polars[ipure],
                                   coef)
            blade.AerodynamicInformation.polars[inode] = polar.table

    ######################################################################
    ## ROTOR
    ######################################################################

    # Read from excel file
    numberOfBlades = gc.read_column_sheet_type01(excel_file_name,
                                                 excel_sheet_parameters,
                                                 'NumBl')
    tilt = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters,
                                       'ShftTilt') * deg2rad
    cone = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters,
                                       'Cone') * deg2rad
    # pitch = gc.read_column_sheet_type01(excel_file_name, excel_sheet_rotor, 'Pitch')*deg2rad

    # Apply pitch
    blade.StructuralInformation.rotate_around_origin(np.array([1., 0., 0.]),
                                                     -pitch_deg * deg2rad)

    # Apply coning
    blade.StructuralInformation.rotate_around_origin(np.array([0., 1., 0.]),
                                                     -cone)

    # Build the whole rotor
    rotor = blade.copy()
    for iblade in range(numberOfBlades - 1):
        blade2 = blade.copy()
        blade2.StructuralInformation.rotate_around_origin(
            np.array([0., 0., 1.]),
            (iblade + 1) * (360.0 / numberOfBlades) * deg2rad)
        rotor.assembly(blade2)
        blade2 = None

    rotor.remove_duplicated_points(tol_remove_points)

    # Apply tilt
    rotor.StructuralInformation.rotate_around_origin(np.array([0., 1., 0.]),
                                                     tilt)

    return rotor
Exemple #2
0
def generate_from_excel_type02(
        chord_panels,
        rotation_velocity,
        pitch_deg,
        excel_file_name='database_excel_type02.xlsx',
        excel_sheet_parameters='parameters',
        excel_sheet_structural_blade='structural_blade',
        excel_sheet_discretization_blade='discretization_blade',
        excel_sheet_aero_blade='aero_blade',
        excel_sheet_airfoil_info='airfoil_info',
        excel_sheet_airfoil_coord='airfoil_coord',
        excel_sheet_structural_tower='structural_tower',
        m_distribution='uniform',
        h5_cross_sec_prop=None,
        n_points_camber=100,
        tol_remove_points=1e-3,
        user_defined_m_distribution_type=None,
        wsp=0.,
        dt=0.):
    """
    generate_from_excel_type02

    Function needed to generate a wind turbine from an excel database according to OpenFAST inputs

    Args:
        chord_panels (int): Number of panels on the blade surface in the chord direction
        rotation_velocity (float): Rotation velocity of the rotor
        pitch_deg (float): pitch angle in degrees
        excel_file_name (str):
        excel_sheet_structural_blade (str):
        excel_sheet_aero_blade (str):
        excel_sheet_airfoil_coord (str):
        excel_sheet_parameters (str):
        excel_sheet_structural_tower (str):
        m_distribution (str):
        n_points_camber (int): number of points to define the camber of the airfoil,
        tol_remove_points (float): maximum distance to remove adjacent points
        user_defined_m_distribution_type (string): type of distribution of the chordwise panels when 'm_distribution' == 'user_defined'
        camber_effects_on_twist (bool): When true plain airfoils are used and the blade is twisted and preloaded based on thin airfoil theory
        wsp (float): wind speed (It may be needed for discretisation purposes)
        dt (float): time step (It may be needed for discretisation purposes)

    Returns:
        wt (sharpy.utils.generate_cases.AeroelasticInfromation): Aeroelastic infrmation of the wind turbine
        LC (list): list of all the Lagrange constraints needed in the cases (sharpy.utils.generate_cases.LagrangeConstraint)
        MB (list): list of the multibody information of each body (sharpy.utils.generate_cases.BodyInfrmation)
    """

    rotor = rotor_from_excel_type02(
        chord_panels,
        rotation_velocity,
        pitch_deg,
        excel_file_name=excel_file_name,
        excel_sheet_parameters=excel_sheet_parameters,
        excel_sheet_structural_blade=excel_sheet_structural_blade,
        excel_sheet_discretization_blade=excel_sheet_discretization_blade,
        excel_sheet_aero_blade=excel_sheet_aero_blade,
        excel_sheet_airfoil_info=excel_sheet_airfoil_info,
        excel_sheet_airfoil_coord=excel_sheet_airfoil_coord,
        m_distribution=m_distribution,
        h5_cross_sec_prop=h5_cross_sec_prop,
        n_points_camber=n_points_camber,
        tol_remove_points=tol_remove_points,
        user_defined_m_distribution_type=user_defined_m_distribution_type,
        wsp=0.,
        dt=0.)

    ######################################################################
    ## TOWER
    ######################################################################

    # Read from excel file
    HtFract = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_tower,
                                          'HtFract')
    TMassDen = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TMassDen')
    TwFAStif = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TwFAStif')
    TwSSStif = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TwSSStif')
    # TODO> variables to be defined
    TwGJStif = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TwGJStif')
    TwEAStif = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TwEAStif')
    TwFAIner = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TwFAIner')
    TwSSIner = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TwSSIner')
    TwFAcgOf = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TwFAcgOf')
    TwSScgOf = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_tower,
                                           'TwSScgOf')

    # Define the TOWER
    TowerHt = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_parameters, 'TowerHt')
    Elevation = TowerHt * HtFract

    tower = gc.AeroelasticInformation()
    tower.StructuralInformation.num_elem = len(Elevation) - 2
    tower.StructuralInformation.num_node_elem = 3
    tower.StructuralInformation.compute_basic_num_node()

    # Interpolate excel variables into the correct locations
    node_r, elem_r = create_node_radial_pos_from_elem_centres(
        Elevation, tower.StructuralInformation.num_node,
        tower.StructuralInformation.num_elem,
        tower.StructuralInformation.num_node_elem)

    # Stiffness
    elem_EA = np.interp(elem_r, Elevation, TwEAStif)
    elem_EIz = np.interp(elem_r, Elevation, TwSSStif)
    elem_EIy = np.interp(elem_r, Elevation, TwFAStif)
    elem_GJ = np.interp(elem_r, Elevation, TwGJStif)
    # Stiffness: estimate unknown properties
    cout.cout_wrap.print_file = False
    cout.cout_wrap('WARNING: The poisson cofficient is assumed equal to 0.3',
                   3)
    cout.cout_wrap('WARNING: Cross-section area is used as shear area', 3)
    poisson_coef = 0.3
    elem_GAy = elem_EA / 2.0 / (1.0 + poisson_coef)
    elem_GAz = elem_EA / 2.0 / (1.0 + poisson_coef)

    # Inertia
    elem_mass_per_unit_length = np.interp(elem_r, Elevation, TMassDen)
    elem_mass_iner_y = np.interp(elem_r, Elevation, TwFAIner)
    elem_mass_iner_z = np.interp(elem_r, Elevation, TwSSIner)
    # TODO: check yz axis and Flap-edge
    elem_pos_cg_B = np.zeros((tower.StructuralInformation.num_elem, 3), )
    elem_pos_cg_B[:, 1] = np.interp(elem_r, Elevation, TwSScgOf)
    elem_pos_cg_B[:, 2] = np.interp(elem_r, Elevation, TwFAcgOf)

    # Stiffness: estimate unknown properties
    cout.cout_wrap(
        'WARNING: Using perpendicular axis theorem to compute the inertia around xB',
        3)
    elem_mass_iner_x = elem_mass_iner_y + elem_mass_iner_z

    # Create the tower
    tower.StructuralInformation.create_mass_db_from_vector(
        elem_mass_per_unit_length, elem_mass_iner_x, elem_mass_iner_y,
        elem_mass_iner_z, elem_pos_cg_B)
    tower.StructuralInformation.create_stiff_db_from_vector(
        elem_EA, elem_GAy, elem_GAz, elem_GJ, elem_EIy, elem_EIz)

    coordinates = np.zeros((tower.StructuralInformation.num_node, 3), )
    coordinates[:, 0] = node_r

    tower.StructuralInformation.generate_1to1_from_vectors(
        num_node_elem=tower.StructuralInformation.num_node_elem,
        num_node=tower.StructuralInformation.num_node,
        num_elem=tower.StructuralInformation.num_elem,
        coordinates=coordinates,
        stiffness_db=tower.StructuralInformation.stiffness_db,
        mass_db=tower.StructuralInformation.mass_db,
        frame_of_reference_delta='y_AFoR',
        vec_node_structural_twist=np.zeros(
            (tower.StructuralInformation.num_node, ), ),
        num_lumped_mass=1)

    tower.StructuralInformation.boundary_conditions = np.zeros(
        (tower.StructuralInformation.num_node), dtype=int)
    tower.StructuralInformation.boundary_conditions[0] = 1

    # Read overhang and nacelle properties from excel file
    overhang_len = gc.read_column_sheet_type01(excel_file_name,
                                               excel_sheet_parameters,
                                               'overhang')
    # HubMass = gc.read_column_sheet_type01(excel_file_name, excel_sheet_nacelle, 'HubMass')
    NacelleMass = gc.read_column_sheet_type01(excel_file_name,
                                              excel_sheet_parameters,
                                              'NacMass')
    # NacelleYawIner = gc.read_column_sheet_type01(excel_file_name, excel_sheet_nacelle, 'NacelleYawIner')

    # Include nacelle mass
    tower.StructuralInformation.lumped_mass_nodes = np.array(
        [tower.StructuralInformation.num_node - 1], dtype=int)
    tower.StructuralInformation.lumped_mass = np.array([NacelleMass],
                                                       dtype=float)

    tower.AerodynamicInformation.set_to_zero(
        tower.StructuralInformation.num_node_elem,
        tower.StructuralInformation.num_node,
        tower.StructuralInformation.num_elem)

    # Assembly overhang with the tower
    # numberOfBlades = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters, 'NumBl')
    tilt = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters,
                                       'ShftTilt') * deg2rad
    # cone = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters, 'Cone')*deg2rad

    overhang = gc.AeroelasticInformation()
    overhang.StructuralInformation.num_node = 3
    overhang.StructuralInformation.num_node_elem = 3
    overhang.StructuralInformation.compute_basic_num_elem()
    node_pos = np.zeros((overhang.StructuralInformation.num_node, 3), )
    node_pos[:, 0] += tower.StructuralInformation.coordinates[-1, 0]
    node_pos[:, 0] += np.linspace(0., overhang_len * np.sin(tilt * deg2rad),
                                  overhang.StructuralInformation.num_node)
    node_pos[:, 2] = np.linspace(0., -overhang_len * np.cos(tilt * deg2rad),
                                 overhang.StructuralInformation.num_node)
    # TODO: change the following by real values
    # Same properties as the last element of the tower
    cout.cout_wrap(
        "WARNING: Using the structural properties of the last tower section for the overhang",
        3)
    oh_mass_per_unit_length = tower.StructuralInformation.mass_db[-1, 0, 0]
    oh_mass_iner = tower.StructuralInformation.mass_db[-1, 3, 3]
    oh_EA = tower.StructuralInformation.stiffness_db[-1, 0, 0]
    oh_GA = tower.StructuralInformation.stiffness_db[-1, 1, 1]
    oh_GJ = tower.StructuralInformation.stiffness_db[-1, 3, 3]
    oh_EI = tower.StructuralInformation.stiffness_db[-1, 4, 4]
    overhang.StructuralInformation.generate_uniform_sym_beam(
        node_pos,
        oh_mass_per_unit_length,
        oh_mass_iner,
        oh_EA,
        oh_GA,
        oh_GJ,
        oh_EI,
        num_node_elem=3,
        y_BFoR='y_AFoR',
        num_lumped_mass=0)

    overhang.StructuralInformation.boundary_conditions = np.zeros(
        (overhang.StructuralInformation.num_node), dtype=int)
    overhang.StructuralInformation.boundary_conditions[-1] = -1

    overhang.AerodynamicInformation.set_to_zero(
        overhang.StructuralInformation.num_node_elem,
        overhang.StructuralInformation.num_node,
        overhang.StructuralInformation.num_elem)

    tower.assembly(overhang)
    tower.remove_duplicated_points(tol_remove_points)

    ######################################################################
    ##  WIND TURBINE
    ######################################################################
    # Assembly the whole case
    wt = tower.copy()
    hub_position = tower.StructuralInformation.coordinates[-1, :]
    rotor.StructuralInformation.coordinates += hub_position
    wt.assembly(rotor)

    # Redefine the body numbers
    wt.StructuralInformation.body_number *= 0
    wt.StructuralInformation.body_number[tower.StructuralInformation.
                                         num_elem:wt.StructuralInformation.
                                         num_elem] += 1

    ######################################################################
    ## MULTIBODY
    ######################################################################
    # Define the boundary condition between the rotor and the tower tip
    LC1 = gc.LagrangeConstraint()
    LC1.behaviour = 'hinge_node_FoR_constant_vel'
    LC1.node_in_body = tower.StructuralInformation.num_node - 1
    LC1.body = 0
    LC1.body_FoR = 1
    LC1.rot_axisB = np.array([1., 0., 0.0])
    LC1.rot_vel = -rotation_velocity

    LC = []
    LC.append(LC1)

    # Define the multibody infromation for the tower and the rotor
    MB1 = gc.BodyInformation()
    MB1.body_number = 0
    MB1.FoR_position = np.zeros((6, ), )
    MB1.FoR_velocity = np.zeros((6, ), )
    MB1.FoR_acceleration = np.zeros((6, ), )
    MB1.FoR_movement = 'prescribed'
    MB1.quat = np.array([1.0, 0.0, 0.0, 0.0])

    MB2 = gc.BodyInformation()
    MB2.body_number = 1
    MB2.FoR_position = np.array([
        rotor.StructuralInformation.coordinates[0, 0],
        rotor.StructuralInformation.coordinates[0, 1],
        rotor.StructuralInformation.coordinates[0, 2], 0.0, 0.0, 0.0
    ])
    MB2.FoR_velocity = np.array([0., 0., 0., 0., 0., rotation_velocity])
    MB2.FoR_acceleration = np.zeros((6, ), )
    MB2.FoR_movement = 'free'
    MB2.quat = algebra.euler2quat(np.array([0.0, tilt, 0.0]))

    MB = []
    MB.append(MB1)
    MB.append(MB2)

    ######################################################################
    ## RETURN
    ######################################################################
    return wt, LC, MB
GA = 1e9
EI = 0.15
tip_force = 0.0 * np.array([0.0, 0.0, 1.0, 0.0, 0.0, 0.0])
tip_mass = 10.
theta_ini = 0. * deg2rad
euler = np.array([0, theta_ini, 0])

# Useless aero information
m = 1
mstar = 1
m_distribution = 'uniform'
airfoil = np.zeros((1, 20, 2), )
airfoil[0, :, 0] = np.linspace(0., 1., 20)

# Create the structure
beam1 = gc.AeroelasticInformation()
node_pos = np.zeros((nnodes, 3), )
# node_pos[:, 0] = np.linspace(0.0, length, nnodes)
r = np.linspace(0.0, length, nnodes)
node_pos[:, 0] = -r * np.sin(theta_ini)
node_pos[:, 2] = -r * np.cos(theta_ini)
beam1.StructuralInformation.generate_uniform_sym_beam(node_pos,
                                                      mass_per_unit_length,
                                                      mass_iner,
                                                      EA,
                                                      GA,
                                                      GJ,
                                                      EI,
                                                      num_node_elem=3,
                                                      y_BFoR='y_AFoR',
                                                      num_lumped_mass=1)
Exemple #4
0
    def setUp(self):

        nodes_per_elem = 3

        # beam1: uniform and symmetric with aerodynamic properties equal to zero
        nnodes1 = 11
        length1  = 10.
        mass_per_unit_length = 0.1
        mass_iner = 1e-4
        EA = 1e9
        GA = 1e9
        GJ = 1e3
        EI = 1e4

        # Create beam1
        beam1 = gc.AeroelasticInformation()
        # Structural information
        beam1.StructuralInformation.num_node = nnodes1
        beam1.StructuralInformation.num_node_elem = nodes_per_elem
        beam1.StructuralInformation.compute_basic_num_elem()
        beam1.StructuralInformation.set_to_zero(beam1.StructuralInformation.num_node_elem, beam1.StructuralInformation.num_node, beam1.StructuralInformation.num_elem)
        node_pos = np.zeros((nnodes1, 3), )
        node_pos[:, 0] = np.linspace(0.0, length1, nnodes1)
        beam1.StructuralInformation.generate_uniform_sym_beam(node_pos, mass_per_unit_length, mass_iner, EA, GA, GJ, EI, num_node_elem = 3, y_BFoR = 'y_AFoR', num_lumped_mass=2)
        beam1.StructuralInformation.boundary_conditions[0] = 1
        beam1.StructuralInformation.boundary_conditions[-1] = -1
        beam1.StructuralInformation.lumped_mass_nodes = np.array([0, nnodes1-1], dtype=int)
        beam1.StructuralInformation.lumped_mass = np.array([2., 1.])
        beam1.StructuralInformation.lumped_mass_inertia = np.zeros((2, 3, 3),)
        beam1.StructuralInformation.lumped_mass_position = np.zeros((2, 3),)

        # Aerodynamic information
        airfoil = np.zeros((1, 20, 2),)
        airfoil[0, :, 0] = np.linspace(0., 1., 20)
        beam1.AerodynamicInformation.create_one_uniform_aerodynamics(
            beam1.StructuralInformation,
            chord=1.,
            twist=0.,
            sweep=0.,
            num_chord_panels=4,
            m_distribution='uniform',
            elastic_axis=0.5,
            num_points_camber=20,
            airfoil=airfoil)

        # SOLVER CONFIGURATION
        SimInfo = gc.SimulationInformation()
        SimInfo.set_default_values()

        SimInfo.define_uinf(np.array([0.0,1.0,0.0]), 10.)

        SimInfo.solvers['SHARPy']['flow'] = ['BeamLoader',
                                             'AerogridLoader',
                                             'StaticCoupled',
                                             'DynamicCoupled']
        self.name = 'fix_node_velocity_wrtG'
        SimInfo.solvers['SHARPy']['case'] = self.name
        SimInfo.solvers['SHARPy']['write_screen'] = 'off'
        SimInfo.solvers['SHARPy']['route'] = folder + '/'
        SimInfo.set_variable_all_dicts('dt', 0.1)
        SimInfo.set_variable_all_dicts('rho', 0.0)
        SimInfo.set_variable_all_dicts('velocity_field_input', SimInfo.solvers['SteadyVelocityField'])
        SimInfo.set_variable_all_dicts('folder', folder + '/output/')

        SimInfo.solvers['BeamLoader']['unsteady'] = 'on'

        SimInfo.solvers['AerogridLoader']['unsteady'] = 'on'
        SimInfo.solvers['AerogridLoader']['mstar'] = 2
        SimInfo.solvers['AerogridLoader']['wake_shape_generator'] = 'StraightWake'
        SimInfo.solvers['AerogridLoader']['wake_shape_generator_input'] = {'u_inf':10.,
                                                                           'u_inf_direction': np.array([0., 1., 0.]),
                                                                           'dt': 0.1}


        SimInfo.solvers['NonLinearStatic']['print_info'] = False

        SimInfo.solvers['StaticCoupled']['structural_solver'] = 'NonLinearStatic'
        SimInfo.solvers['StaticCoupled']['structural_solver_settings'] = SimInfo.solvers['NonLinearStatic']
        SimInfo.solvers['StaticCoupled']['aero_solver'] = 'StaticUvlm'
        SimInfo.solvers['StaticCoupled']['aero_solver_settings'] = SimInfo.solvers['StaticUvlm']

        SimInfo.solvers['WriteVariablesTime']['structure_nodes'] = np.array([0,  int((nnodes1-1)/2), -1], dtype = int)
        SimInfo.solvers['WriteVariablesTime']['structure_variables'] = ['pos']

        SimInfo.solvers['BeamPlot']['include_FoR'] = True

        SimInfo.solvers['NonLinearDynamicMultibody']['relaxation_factor'] = 0.0
        SimInfo.solvers['NonLinearDynamicMultibody']['min_delta'] = 1e-5
        SimInfo.solvers['NonLinearDynamicMultibody']['max_iterations'] = 200
        SimInfo.solvers['NonLinearDynamicMultibody']['newmark_damp'] = 1e-3
        # SimInfo.solvers['NonLinearDynamicMultibody']['gravity_on'] = 'off'

        SimInfo.solvers['NonLinearDynamicMultibody']['relaxation_factor'] = 0.0

        SimInfo.solvers['DynamicCoupled']['structural_solver'] = 'NonLinearDynamicMultibody'
        SimInfo.solvers['DynamicCoupled']['structural_solver_settings'] = SimInfo.solvers['NonLinearDynamicMultibody']
        SimInfo.solvers['DynamicCoupled']['aero_solver'] = 'StepUvlm'
        SimInfo.solvers['DynamicCoupled']['aero_solver_settings'] = SimInfo.solvers['StepUvlm']
        SimInfo.solvers['DynamicCoupled']['postprocessors'] = ['WriteVariablesTime', 'BeamPlot', 'AerogridPlot']
        SimInfo.solvers['DynamicCoupled']['postprocessors_settings'] = {'WriteVariablesTime': SimInfo.solvers['WriteVariablesTime'],
                                                                        'BeamPlot': SimInfo.solvers['BeamPlot'],
                                                                        'AerogridPlot': SimInfo.solvers['AerogridPlot']}

        ntimesteps = 10

        SimInfo.define_num_steps(ntimesteps)

        # Define dynamic simulation
        SimInfo.with_forced_vel = False
        SimInfo.with_dynamic_forces = False

        LC2 = gc.LagrangeConstraint()
        LC2.behaviour = 'lin_vel_node_wrtG'
        LC2.velocity = np.zeros((ntimesteps, 3))
        LC2.velocity[:int(ntimesteps/2),1] = 0.5
        LC2.velocity[int(ntimesteps/2):,1] = -0.5
        LC2.body_number = 0
        LC2.node_number = int((nnodes1-1)/2)

        LC = []
        # LC.append(LC1)
        LC.append(LC2)

        # Define the multibody infromation for the tower and the rotor
        MB1 = gc.BodyInformation()
        MB1.body_number = 0
        MB1.FoR_position = np.zeros((6,),)
        MB1.FoR_velocity = np.zeros((6,),)
        MB1.FoR_acceleration = np.zeros((6,),)
        MB1.FoR_movement = 'free'
        MB1.quat = np.array([1.0,0.0,0.0,0.0])

        MB = []
        MB.append(MB1)


        gc.clean_test_files(
            SimInfo.solvers['SHARPy']['route'],
            SimInfo.solvers['SHARPy']['case'])
        SimInfo.generate_solver_file()
        SimInfo.generate_dyn_file(ntimesteps)
        beam1.generate_h5_files(
            SimInfo.solvers['SHARPy']['route'],
            SimInfo.solvers['SHARPy']['case'])
        gc.generate_multibody_file(LC,
                                   MB,SimInfo.solvers['SHARPy']['route'],
                                   SimInfo.solvers['SHARPy']['case'])
Exemple #5
0
    def setUp(self):
        import sharpy.utils.generate_cases as gc

        deg2rad = np.pi/180.

        # Structural properties
        mass_per_unit_length = 1.
        mass_iner = 1e-4
        EA = 1e9
        GA = 1e9
        GJ = 1e9
        EI = 1e9

        # Beam1
        global nnodes1
        nnodes1 = 11
        l1 = 1.0
        m1 = 1.0
        theta_ini1 = 90.*deg2rad

        # Beam2
        nnodes2 = nnodes1
        l2 = l1
        m2 = m1
        theta_ini2 = 00.*deg2rad

        # airfoils
        airfoil = np.zeros((1,20,2),)
        airfoil[0,:,0] = np.linspace(0.,1.,20)

        # Simulation
        numtimesteps = 10
        dt = 0.01

        # Create the structure
        beam1 = gc.AeroelasticInformation()
        r1 = np.linspace(0.0, l1, nnodes1)
        node_pos1 = np.zeros((nnodes1,3),)
        node_pos1[:, 0] = r1*np.sin(theta_ini1)
        node_pos1[:, 2] = -r1*np.cos(theta_ini1)
        beam1.StructuralInformation.generate_uniform_sym_beam(node_pos1, mass_per_unit_length, mass_iner, EA, GA, GJ, EI, num_node_elem = 3, y_BFoR = 'y_AFoR', num_lumped_mass=1)
        beam1.StructuralInformation.body_number = np.zeros((beam1.StructuralInformation.num_elem,), dtype = int)
        beam1.StructuralInformation.boundary_conditions[0] = 1
        beam1.StructuralInformation.boundary_conditions[-1] = -1
        beam1.StructuralInformation.lumped_mass_nodes = np.array([nnodes1-1], dtype = int)
        beam1.StructuralInformation.lumped_mass = np.ones((1,))*m1
        beam1.StructuralInformation.lumped_mass_inertia = np.zeros((1,3,3))
        beam1.StructuralInformation.lumped_mass_position = np.zeros((1,3))
        beam1.AerodynamicInformation.create_one_uniform_aerodynamics(
                                            beam1.StructuralInformation,
                                            chord = 1.,
                                            twist = 0.,
                                            sweep = 0.,
                                            num_chord_panels = 4,
                                            m_distribution = 'uniform',
                                            elastic_axis = 0.25,
                                            num_points_camber = 20,
                                            airfoil = airfoil)

        beam2 = gc.AeroelasticInformation()
        r2 = np.linspace(0.0, l2, nnodes2)
        node_pos2 = np.zeros((nnodes2,3),)
        node_pos2[:, 0] = r2*np.sin(theta_ini2) + node_pos1[-1, 0]
        node_pos2[:, 2] = -r2*np.cos(theta_ini2) + node_pos1[-1, 2]
        beam2.StructuralInformation.generate_uniform_sym_beam(node_pos2, mass_per_unit_length, mass_iner, EA, GA, GJ, EI, num_node_elem = 3, y_BFoR = 'y_AFoR', num_lumped_mass=1)
        beam2.StructuralInformation.body_number = np.zeros((beam1.StructuralInformation.num_elem,), dtype = int)
        beam2.StructuralInformation.boundary_conditions[0] = 1
        beam2.StructuralInformation.boundary_conditions[-1] = -1
        beam2.StructuralInformation.lumped_mass_nodes = np.array([nnodes2-1], dtype = int)
        beam2.StructuralInformation.lumped_mass = np.ones((1,))*m2
        beam2.StructuralInformation.lumped_mass_inertia = np.zeros((1,3,3))
        beam2.StructuralInformation.lumped_mass_position = np.zeros((1,3))
        beam2.AerodynamicInformation.create_one_uniform_aerodynamics(
                                            beam2.StructuralInformation,
                                            chord = 1.,
                                            twist = 0.,
                                            sweep = 0.,
                                            num_chord_panels = 4,
                                            m_distribution = 'uniform',
                                            elastic_axis = 0.25,
                                            num_points_camber = 20,
                                            airfoil = airfoil)

        beam1.assembly(beam2)

        # Simulation details
        SimInfo = gc.SimulationInformation()
        SimInfo.set_default_values()

        SimInfo.define_uinf(np.array([0.0,1.0,0.0]), 1.)

        SimInfo.solvers['SHARPy']['flow'] = ['BeamLoader',
                                'AerogridLoader',
                                # 'InitializeMultibody',
                                'DynamicCoupled']
        global name
        name = 'double_pendulum_geradin'
        SimInfo.solvers['SHARPy']['case'] = 'double_pendulum_geradin'
        SimInfo.solvers['SHARPy']['write_screen'] = 'off'
        SimInfo.solvers['SHARPy']['route'] = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + '/'
        SimInfo.solvers['SHARPy']['log_folder'] = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + '/'
        SimInfo.set_variable_all_dicts('dt', dt)
        SimInfo.define_num_steps(numtimesteps)
        SimInfo.set_variable_all_dicts('rho', 0.0)
        SimInfo.set_variable_all_dicts('velocity_field_input', SimInfo.solvers['SteadyVelocityField'])
        SimInfo.set_variable_all_dicts('output', os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + '/output/')

        SimInfo.solvers['BeamLoader']['unsteady'] = 'on'

        SimInfo.solvers['AerogridLoader']['unsteady'] = 'on'
        SimInfo.solvers['AerogridLoader']['mstar'] = 2

        SimInfo.solvers['WriteVariablesTime']['FoR_number'] = np.array([0, 1], dtype = int)
        SimInfo.solvers['WriteVariablesTime']['FoR_variables'] = ['mb_quat']
        SimInfo.solvers['WriteVariablesTime']['structure_nodes'] = np.array([nnodes1-1, nnodes1+nnodes2-1], dtype = int)
        SimInfo.solvers['WriteVariablesTime']['structure_variables'] = ['pos']

        SimInfo.solvers['NonLinearDynamicMultibody']['gravity_on'] = True
        SimInfo.solvers['NonLinearDynamicMultibody']['newmark_damp'] = 0.15

        SimInfo.solvers['BeamPlot']['include_FoR'] = True

        SimInfo.solvers['DynamicCoupled']['structural_solver'] = 'NonLinearDynamicMultibody'
        SimInfo.solvers['DynamicCoupled']['structural_solver_settings'] = SimInfo.solvers['NonLinearDynamicMultibody']
        SimInfo.solvers['DynamicCoupled']['aero_solver'] = 'StepUvlm'
        SimInfo.solvers['DynamicCoupled']['aero_solver_settings'] = SimInfo.solvers['StepUvlm']
        SimInfo.solvers['DynamicCoupled']['postprocessors'] = ['WriteVariablesTime', 'BeamPlot', 'AerogridPlot']
        SimInfo.solvers['DynamicCoupled']['postprocessors_settings'] = {'WriteVariablesTime': SimInfo.solvers['WriteVariablesTime'],
                                                                        'BeamPlot': SimInfo.solvers['BeamPlot'],
                                                                        'AerogridPlot': SimInfo.solvers['AerogridPlot']}

        SimInfo.solvers['DynamicCoupled']['postprocessors_settings']['WriteVariablesTime']['folder'] = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + '/output/'
        SimInfo.solvers['DynamicCoupled']['postprocessors_settings']['BeamPlot']['folder'] = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + '/output/'
        SimInfo.solvers['DynamicCoupled']['postprocessors_settings']['AerogridPlot']['folder'] = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + '/output/'
        SimInfo.with_forced_vel = False
        SimInfo.with_dynamic_forces = False

        # Create the MB and BC files
        LC1 = gc.LagrangeConstraint()
        LC1.behaviour = 'hinge_FoR'
        LC1.body_FoR = 0
        LC1.rot_axis_AFoR = np.array([0.0,1.0,0.0])

        LC2 = gc.LagrangeConstraint()
        LC2.behaviour = 'hinge_node_FoR'
        LC2.node_in_body = nnodes1-1
        LC2.body = 0
        LC2.body_FoR = 1
        LC2.rot_axisB = np.array([0.0,1.0,0.0])

        LC = []
        LC.append(LC1)
        LC.append(LC2)

        MB1 = gc.BodyInformation()
        MB1.body_number = 0
        MB1.FoR_position = np.zeros((6,),)
        MB1.FoR_velocity = np.zeros((6,),)
        MB1.FoR_acceleration = np.zeros((6,),)
        MB1.FoR_movement = 'free'
        MB1.quat = np.array([1.0,0.0,0.0,0.0])

        MB2 = gc.BodyInformation()
        MB2.body_number = 1
        MB2.FoR_position = np.array([node_pos2[0, 0], node_pos2[0, 1], node_pos2[0, 2], 0.0, 0.0, 0.0])
        MB2.FoR_velocity = np.zeros((6,),)
        MB2.FoR_acceleration = np.zeros((6,),)
        MB2.FoR_movement = 'free'
        MB2.quat = np.array([1.0,0.0,0.0,0.0])

        MB = []
        MB.append(MB1)
        MB.append(MB2)

        # Write files
        gc.clean_test_files(SimInfo.solvers['SHARPy']['route'], SimInfo.solvers['SHARPy']['case'])
        SimInfo.generate_solver_file()
        SimInfo.generate_dyn_file(numtimesteps)
        beam1.generate_h5_files(SimInfo.solvers['SHARPy']['route'], SimInfo.solvers['SHARPy']['case'])
        gc.generate_multibody_file(LC, MB,SimInfo.solvers['SHARPy']['route'], SimInfo.solvers['SHARPy']['case'])
Exemple #6
0
def rotor_from_excel_type02(
        chord_panels,
        rotation_velocity,
        pitch_deg,
        excel_file_name='database_excel_type02.xlsx',
        excel_sheet_parameters='parameters',
        excel_sheet_structural_blade='structural_blade',
        excel_sheet_discretization_blade='discretization_blade',
        excel_sheet_aero_blade='aero_blade',
        excel_sheet_airfoil_info='airfoil_info',
        excel_sheet_airfoil_coord='airfoil_coord',
        m_distribution='uniform',
        h5_cross_sec_prop=None,
        n_points_camber=100,
        tol_remove_points=1e-3,
        user_defined_m_distribution_type=None,
        camber_effect_on_twist=False,
        wsp=0.,
        dt=0.):
    """
    generate_from_excel_type02_db

    Function needed to generate a wind turbine from an excel database type02

    Args:
        chord_panels (int): Number of panels on the blade surface in the chord direction
        rotation_velocity (float): Rotation velocity of the rotor
        pitch_deg (float): pitch angle in degrees
        excel_file_name (str):
        excel_sheet_structural_blade (str):
        excel_sheet_discretization_blade (str):
        excel_sheet_aero_blade (str):
        excel_sheet_airfoil_info (str):
        excel_sheet_airfoil_coord (str):
        excel_sheet_parameters (str):
        h5_cross_sec_prop (str): h5 containing mass and stiffness matrices along the blade.
        m_distribution (str):
        n_points_camber (int): number of points to define the camber of the airfoil,
        tol_remove_points (float): maximum distance to remove adjacent points
        user_defined_m_distribution_type (string): type of distribution of the chordwise panels when 'm_distribution' == 'user_defined'
        camber_effects_on_twist (bool): When true plain airfoils are used and the blade is twisted and preloaded based on thin airfoil theory
        wsp (float): wind speed (It may be needed for discretisation purposes)
        dt (float): time step (It may be needed for discretisation purposes)

    Returns:
        rotor (sharpy.utils.generate_cases.AeroelasticInfromation): Aeroelastic information of the rotor

    Note:
        - h5_cross_sec_prop is a path to a h5 containing the following groups:
            - str_prop: with:
                - K: list of 6x6 stiffness matrices
                - M: list of 6x6 mass matrices
                - radius: radial location (including hub) of K and M matrices
        - when h5_cross_sec_prop is not None, mass and stiffness properties are
        interpolated at BlFract location specified in "excel_sheet_structural_blade"
    """

    ######################################################################
    ## BLADE
    ######################################################################
    blade = gc.AeroelasticInformation()

    ######################################################################
    ### STRUCTURE
    ######################################################################
    # Read blade structural information from excel file
    rR_structural = gc.read_column_sheet_type01(excel_file_name,
                                                excel_sheet_structural_blade,
                                                'rR')
    OutPElAxis = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_structural_blade,
                                             'OutPElAxis')
    InPElAxis = gc.read_column_sheet_type01(excel_file_name,
                                            excel_sheet_structural_blade,
                                            'InPElAxis')
    ElAxisAftLEc = gc.read_column_sheet_type01(excel_file_name,
                                               excel_sheet_structural_blade,
                                               'ElAxisAftLEc')
    StrcTwst = gc.read_column_sheet_type01(
        excel_file_name, excel_sheet_structural_blade, 'StrcTwst') * deg2rad
    BMassDen = gc.read_column_sheet_type01(excel_file_name,
                                           excel_sheet_structural_blade,
                                           'BMassDen')
    FlpStff = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_blade,
                                          'FlpStff')
    EdgStff = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_blade,
                                          'EdgStff')
    FlapEdgeStiff = gc.read_column_sheet_type01(excel_file_name,
                                                excel_sheet_structural_blade,
                                                'FlapEdgeStiff')
    GJStff = gc.read_column_sheet_type01(excel_file_name,
                                         excel_sheet_structural_blade,
                                         'GJStff')
    EAStff = gc.read_column_sheet_type01(excel_file_name,
                                         excel_sheet_structural_blade,
                                         'EAStff')
    FlpIner = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_blade,
                                          'FlpIner')
    EdgIner = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_structural_blade,
                                          'EdgIner')
    FlapEdgeIner = gc.read_column_sheet_type01(excel_file_name,
                                               excel_sheet_structural_blade,
                                               'FlapEdgeIner')
    PrebendRef = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_structural_blade,
                                             'PrebendRef')
    PreswpRef = gc.read_column_sheet_type01(excel_file_name,
                                            excel_sheet_structural_blade,
                                            'PreswpRef')
    OutPcg = gc.read_column_sheet_type01(excel_file_name,
                                         excel_sheet_structural_blade,
                                         'OutPcg')
    InPcg = gc.read_column_sheet_type01(excel_file_name,
                                        excel_sheet_structural_blade, 'InPcg')

    # Blade parameters
    TipRad = gc.read_column_sheet_type01(excel_file_name,
                                         excel_sheet_parameters, 'TipRad')
    # HubRad = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters, 'HubRad')

    # Discretization points
    rR = gc.read_column_sheet_type01(excel_file_name,
                                     excel_sheet_discretization_blade, 'rR')

    # Interpolate excel variables into the correct locations
    # Geometry
    if rR[0] < rR_structural[0]:
        rR_structural = np.concatenate((np.array([0.]), rR_structural), )
        OutPElAxis = np.concatenate((np.array([OutPElAxis[0]]), OutPElAxis), )
        InPElAxis = np.concatenate((np.array([InPElAxis[0]]), InPElAxis), )
        ElAxisAftLEc = np.concatenate(
            (np.array([ElAxisAftLEc[0]]), ElAxisAftLEc), )
        StrcTwst = np.concatenate((np.array([StrcTwst[0]]), StrcTwst), )
        BMassDen = np.concatenate((np.array([BMassDen[0]]), BMassDen), )
        FlpStff = np.concatenate((np.array([FlpStff[0]]), FlpStff), )
        EdgStff = np.concatenate((np.array([EdgStff[0]]), EdgStff), )
        FlapEdgeStiff = np.concatenate(
            (np.array([FlapEdgeStiff[0]]), FlapEdgeStiff), )
        GJStff = np.concatenate((np.array([GJStff[0]]), GJStff), )
        EAStff = np.concatenate((np.array([EAStff[0]]), EAStff), )
        FlpIner = np.concatenate((np.array([FlpIner[0]]), FlpIner), )
        EdgIner = np.concatenate((np.array([EdgIner[0]]), EdgIner), )
        FlapEdgeIner = np.concatenate(
            (np.array([FlapEdgeIner[0]]), FlapEdgeIner), )
        PrebendRef = np.concatenate((np.array([PrebendRef[0]]), PrebendRef), )
        PreswpRef = np.concatenate((np.array([PreswpRef[0]]), PreswpRef), )
        OutPcg = np.concatenate((np.array([OutPcg[0]]), OutPcg), )
        InPcg = np.concatenate((np.array([InPcg[0]]), InPcg), )

    # Base parameters
    use_excel_struct_as_elem = False
    if use_excel_struct_as_elem:
        blade.StructuralInformation.num_node_elem = 3
        blade.StructuralInformation.num_elem = len(rR) - 2
        blade.StructuralInformation.compute_basic_num_node()

        node_r, elem_r = create_node_radial_pos_from_elem_centres(
            rR * TipRad, blade.StructuralInformation.num_node,
            blade.StructuralInformation.num_elem,
            blade.StructuralInformation.num_node_elem)
    else:
        # Use excel struct as nodes
        # Check the number of nodes
        blade.StructuralInformation.num_node_elem = 3
        blade.StructuralInformation.num_node = len(rR)
        if ((len(rR) - 1) %
            (blade.StructuralInformation.num_node_elem - 1)) == 0:
            blade.StructuralInformation.num_elem = int(
                (len(rR) - 1) /
                (blade.StructuralInformation.num_node_elem - 1))
            node_r = rR * TipRad
            elem_rR = rR[1::2] + 0.
            elem_r = rR[1::2] * TipRad + 0.
        else:
            print("ERROR: Cannot build ",
                  blade.StructuralInformation.num_node_elem,
                  "-noded elements from ",
                  blade.StructuralInformation.num_node, "nodes")

    node_y = np.interp(rR, rR_structural, InPElAxis) + np.interp(
        rR, rR_structural, PreswpRef)
    node_z = -np.interp(rR, rR_structural, OutPElAxis) - np.interp(
        rR, rR_structural, PrebendRef)
    node_twist = -1.0 * np.interp(rR, rR_structural, StrcTwst)

    coordinates = create_blade_coordinates(
        blade.StructuralInformation.num_node, node_r, node_y, node_z)

    if h5_cross_sec_prop is None:
        # Stiffness
        elem_EA = np.interp(elem_rR, rR_structural, EAStff)
        elem_EIy = np.interp(elem_rR, rR_structural, FlpStff)
        elem_EIz = np.interp(elem_rR, rR_structural, EdgStff)
        elem_EIyz = np.interp(elem_rR, rR_structural, FlapEdgeStiff)
        elem_GJ = np.interp(elem_rR, rR_structural, GJStff)

        # Stiffness: estimate unknown properties
        print('WARNING: The poisson cofficient is assumed equal to 0.3')
        print('WARNING: Cross-section area is used as shear area')
        poisson_coef = 0.3
        elem_GAy = elem_EA / 2.0 / (1.0 + poisson_coef)
        elem_GAz = elem_EA / 2.0 / (1.0 + poisson_coef)
        # Inertia
        elem_pos_cg_B = np.zeros((blade.StructuralInformation.num_elem, 3), )
        elem_pos_cg_B[:, 1] = np.interp(elem_rR, rR_structural, InPcg)
        elem_pos_cg_B[:, 2] = -np.interp(elem_rR, rR_structural, OutPcg)

        elem_mass_per_unit_length = np.interp(elem_rR, rR_structural, BMassDen)
        elem_mass_iner_y = np.interp(elem_rR, rR_structural, FlpIner)
        elem_mass_iner_z = np.interp(elem_rR, rR_structural, EdgIner)
        elem_mass_iner_yz = np.interp(elem_rR, rR_structural, FlapEdgeIner)

        # Inertia: estimate unknown properties
        print(
            'WARNING: Using perpendicular axis theorem to compute the inertia around xB'
        )
        elem_mass_iner_x = elem_mass_iner_y + elem_mass_iner_z

        # Generate blade structural properties
        blade.StructuralInformation.create_mass_db_from_vector(
            elem_mass_per_unit_length, elem_mass_iner_x, elem_mass_iner_y,
            elem_mass_iner_z, elem_pos_cg_B, elem_mass_iner_yz)
        blade.StructuralInformation.create_stiff_db_from_vector(
            elem_EA, elem_GAy, elem_GAz, elem_GJ, elem_EIy, elem_EIz,
            elem_EIyz)

    else:
        # read Mass/Stiffness from database
        cross_prop = h5.readh5(h5_cross_sec_prop).str_prop

        # create mass_db/stiffness_db (interpolate at mid-node of each element)
        blade.StructuralInformation.mass_db = scint.interp1d(
            cross_prop.radius,
            cross_prop.M,
            kind='cubic',
            copy=False,
            assume_sorted=True,
            axis=0,
            bounds_error=False,
            fill_value='extrapolate')(node_r[1::2])
        blade.StructuralInformation.stiffness_db = scint.interp1d(
            cross_prop.radius,
            cross_prop.K,
            kind='cubic',
            copy=False,
            assume_sorted=True,
            axis=0,
            bounds_error=False,
            fill_value='extrapolate')(node_r[1::2])

    blade.StructuralInformation.generate_1to1_from_vectors(
        num_node_elem=blade.StructuralInformation.num_node_elem,
        num_node=blade.StructuralInformation.num_node,
        num_elem=blade.StructuralInformation.num_elem,
        coordinates=coordinates,
        stiffness_db=blade.StructuralInformation.stiffness_db,
        mass_db=blade.StructuralInformation.mass_db,
        frame_of_reference_delta='y_AFoR',
        vec_node_structural_twist=node_twist,
        num_lumped_mass=0)

    # Boundary conditions
    blade.StructuralInformation.boundary_conditions = np.zeros(
        (blade.StructuralInformation.num_node), dtype=int)
    blade.StructuralInformation.boundary_conditions[0] = 1
    blade.StructuralInformation.boundary_conditions[-1] = -1

    ######################################################################
    ### AERODYNAMICS
    ######################################################################
    # Read blade aerodynamic information from excel file
    rR_aero = gc.read_column_sheet_type01(excel_file_name,
                                          excel_sheet_aero_blade, 'rR')
    chord_aero = gc.read_column_sheet_type01(excel_file_name,
                                             excel_sheet_aero_blade, 'BlChord')
    thickness_aero = gc.read_column_sheet_type01(excel_file_name,
                                                 excel_sheet_aero_blade,
                                                 'BlThickness')

    pure_airfoils_names = gc.read_column_sheet_type01(
        excel_file_name, excel_sheet_airfoil_info, 'Name')
    pure_airfoils_thickness = gc.read_column_sheet_type01(
        excel_file_name, excel_sheet_airfoil_info, 'Thickness')

    node_ElAxisAftLEc = np.interp(node_r, rR_structural * TipRad, ElAxisAftLEc)

    # Read coordinates of the pure airfoils
    n_pure_airfoils = len(pure_airfoils_names)

    pure_airfoils_camber = np.zeros((n_pure_airfoils, n_points_camber, 2), )
    xls = pd.ExcelFile(excel_file_name)
    excel_db = pd.read_excel(xls, sheet_name=excel_sheet_airfoil_coord)
    for iairfoil in range(n_pure_airfoils):
        # Look for the NaN
        icoord = 2
        while (not (math.isnan(
                excel_db["%s_x" % pure_airfoils_names[iairfoil]][icoord]))):
            icoord += 1
            if (icoord == len(excel_db["%s_x" %
                                       pure_airfoils_names[iairfoil]])):
                break

        # Compute the camber of the airfoils at the defined chord points
        pure_airfoils_camber[iairfoil, :, 0], pure_airfoils_camber[
            iairfoil, :, 1] = gc.get_airfoil_camber(
                excel_db["%s_x" % pure_airfoils_names[iairfoil]][2:icoord],
                excel_db["%s_y" % pure_airfoils_names[iairfoil]][2:icoord],
                n_points_camber)

    # Basic variables
    surface_distribution = np.zeros((blade.StructuralInformation.num_elem),
                                    dtype=int)

    # Interpolate in the correct positions
    node_chord = np.interp(node_r, rR_aero * TipRad, chord_aero)

    # Define the nodes with aerodynamic properties
    # Look for the first element that is goint to be aerodynamic
    first_aero_elem = 0
    while (elem_r[first_aero_elem] <= rR_aero[0] * TipRad):
        first_aero_elem += 1
    first_aero_node = first_aero_elem * (
        blade.StructuralInformation.num_node_elem - 1)
    aero_node = np.zeros((blade.StructuralInformation.num_node, ), dtype=bool)
    aero_node[first_aero_node:] = np.ones(
        (blade.StructuralInformation.num_node - first_aero_node, ), dtype=bool)

    # Define the airfoil at each stage
    # airfoils = blade.AerodynamicInformation.interpolate_airfoils_camber(pure_airfoils_camber,excel_aero_r, node_r, n_points_camber)

    node_thickness = np.interp(node_r, rR_aero * TipRad, thickness_aero)

    airfoils = blade.AerodynamicInformation.interpolate_airfoils_camber_thickness(
        pure_airfoils_camber, pure_airfoils_thickness, node_thickness,
        n_points_camber)
    airfoil_distribution = np.linspace(0,
                                       blade.StructuralInformation.num_node -
                                       1,
                                       blade.StructuralInformation.num_node,
                                       dtype=int)

    # User defined m distribution
    if (m_distribution == 'user_defined') and (user_defined_m_distribution_type
                                               == 'last_geometric'):
        blade_nodes = blade.StructuralInformation.num_node
        udmd_by_nodes = np.zeros((blade_nodes, chord_panels[0] + 1))
        for inode in range(blade_nodes):
            r = np.linalg.norm(
                blade.StructuralInformation.coordinates[inode, :])
            vrel = np.sqrt(rotation_velocity**2 * r**2 + wsp**2)
            last_length = vrel * dt / node_chord[inode]
            last_length = np.minimum(last_length, 0.5)
            if last_length <= 0.5:
                ratio = gc.get_factor_geometric_progression(
                    last_length, 1., chord_panels)
                udmd_by_nodes[inode, -1] = 1.
                udmd_by_nodes[inode, 0] = 0.
                for im in range(chord_panels[0] - 1, 0, -1):
                    udmd_by_nodes[inode,
                                  im] = udmd_by_nodes[inode,
                                                      im + 1] - last_length
                    last_length *= ratio
                # Check
                if (np.diff(udmd_by_nodes[inode, :]) < 0.).any():
                    sys.error(
                        "ERROR in the panel discretization of the blade in node %d"
                        % (inode))
            else:
                print("ERROR: cannot match the last panel size for node:",
                      inode)
                udmd_by_nodes[inode, :] = np.linspace(0, 1, chord_panels + 1)
    else:
        udmd_by_nodes = None

    node_twist = np.zeros_like(node_chord)
    if camber_effect_on_twist:
        print(
            "WARNING: The steady applied Mx should be manually multiplied by the density"
        )
        for inode in range(blade.StructuralInformation.num_node):
            node_twist[inode] = gc.get_aoacl0_from_camber(
                airfoils[inode, :, 0], airfoils[inode, :, 1])
            mu0 = gc.get_mu0_from_camber(airfoils[inode, :, 0],
                                         airfoils[inode, :, 1])
            r = np.linalg.norm(
                blade.StructuralInformation.coordinates[inode, :])
            vrel = np.sqrt(rotation_velocity**2 * r**2 + wsp**2)
            if inode == 0:
                dr = 0.5 * np.linalg.norm(
                    blade.StructuralInformation.coordinates[1, :] -
                    blade.StructuralInformation.coordinates[0, :])
            elif inode == len(blade.StructuralInformation.coordinates[:,
                                                                      0]) - 1:
                dr = 0.5 * np.linalg.norm(
                    blade.StructuralInformation.coordinates[-1, :] -
                    blade.StructuralInformation.coordinates[-2, :])
            else:
                dr = 0.5 * np.linalg.norm(
                    blade.StructuralInformation.coordinates[inode + 1, :] -
                    blade.StructuralInformation.coordinates[inode - 1, :])
            moment_factor = 0.5 * vrel**2 * node_chord[inode]**2 * dr
            # print("node", inode, "mu0", mu0, "CMc/4", 2.*mu0 + np.pi/2*node_twist[inode])
            blade.StructuralInformation.app_forces[
                inode,
                3] = (2. * mu0 + np.pi / 2 * node_twist[inode]) * moment_factor
            airfoils[inode, :, 1] *= 0.

    # Write SHARPy format
    blade.AerodynamicInformation.create_aerodynamics_from_vec(
        blade.StructuralInformation, aero_node, node_chord, node_twist,
        np.pi * np.ones_like(node_chord), chord_panels, surface_distribution,
        m_distribution, node_ElAxisAftLEc, airfoil_distribution, airfoils,
        udmd_by_nodes)

    ######################################################################
    ## ROTOR
    ######################################################################

    # Read from excel file
    numberOfBlades = gc.read_column_sheet_type01(excel_file_name,
                                                 excel_sheet_parameters,
                                                 'NumBl')
    tilt = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters,
                                       'ShftTilt') * deg2rad
    cone = gc.read_column_sheet_type01(excel_file_name, excel_sheet_parameters,
                                       'Cone') * deg2rad
    # pitch = gc.read_column_sheet_type01(excel_file_name, excel_sheet_rotor, 'Pitch')*deg2rad

    # Apply pitch
    blade.StructuralInformation.rotate_around_origin(np.array([1., 0., 0.]),
                                                     -pitch_deg * deg2rad)

    # Apply coning
    blade.StructuralInformation.rotate_around_origin(np.array([0., 1., 0.]),
                                                     -cone)

    # Build the whole rotor
    rotor = blade.copy()
    for iblade in range(numberOfBlades - 1):
        blade2 = blade.copy()
        blade2.StructuralInformation.rotate_around_origin(
            np.array([0., 0., 1.]),
            (iblade + 1) * (360.0 / numberOfBlades) * deg2rad)
        rotor.assembly(blade2)
        blade2 = None

    rotor.remove_duplicated_points(tol_remove_points)

    # Apply tilt
    rotor.StructuralInformation.rotate_around_origin(np.array([0., 1., 0.]),
                                                     tilt)

    return rotor