Example #1
0
def plot_propeller_geometry(axes,prop,network,network_name,prop_face_color='red',prop_edge_color='darkred',prop_alpha=1):
    """ This plots a 3D surface of the  propeller

    Assumptions:
    None

    Source:
    None

    Inputs:
    network            - network data structure

    Properties Used:
    N/A
    """

    # unpack
    num_B  = prop.number_of_blades
    a_sec  = prop.airfoil_geometry
    a_secl = prop.airfoil_polar_stations
    beta   = prop.twist_distribution
    a_o    = prop.azimuthal_offset_angle
    b      = prop.chord_distribution
    r      = prop.radius_distribution
    MCA    = prop.mid_chord_alignment
    t      = prop.max_thickness_distribution
    origin = prop.origin
 
    n_points  = 20
    af_pts    = n_points-1
    dim       = len(b)
    theta     = np.linspace(0,2*np.pi,num_B+1)[:-1]

    # create empty data structure for storing geometry
    G = Data()


    rot    = prop.rotation 
    flip_1 =  (np.pi/2)
    flip_2 =  (np.pi/2)

    MCA_2d = np.repeat(np.atleast_2d(MCA).T,n_points,axis=1)
    b_2d   = np.repeat(np.atleast_2d(b).T  ,n_points,axis=1)
    t_2d   = np.repeat(np.atleast_2d(t).T  ,n_points,axis=1)
    r_2d   = np.repeat(np.atleast_2d(r).T  ,n_points,axis=1)
    shift  = np.repeat(np.atleast_2d(np.ones_like(b)*b[0]).T  ,n_points,axis=1)

    for i in range(num_B):
        # get airfoil coordinate geometry
        if a_sec != None:
            airfoil_data = import_airfoil_geometry(a_sec,npoints=n_points)
            xpts         = np.take(airfoil_data.x_coordinates,a_secl,axis=0)
            zpts         = np.take(airfoil_data.y_coordinates,a_secl,axis=0)
            max_t        = np.take(airfoil_data.thickness_to_chord,a_secl,axis=0)

        else:
            camber       = 0.02
            camber_loc   = 0.4
            thickness    = 0.10
            airfoil_data = compute_naca_4series(camber, camber_loc, thickness,(n_points - 2))
            xpts         = np.repeat(np.atleast_2d(airfoil_data.x_coordinates) ,dim,axis=0)
            zpts         = np.repeat(np.atleast_2d(airfoil_data.y_coordinates) ,dim,axis=0)
            max_t        = np.repeat(airfoil_data.thickness_to_chord,dim,axis=0)

        # store points of airfoil in similar format as Vortex Points (i.e. in vertices)
        max_t2d = np.repeat(np.atleast_2d(max_t).T ,n_points,axis=1)

        xp      = (- MCA_2d + xpts*b_2d - shift/2 )     # x-coord of airfoil
        yp      = r_2d*np.ones_like(xp)       # radial location
        zp      = zpts*(t_2d/max_t2d)         # former airfoil y coord

        matrix = np.zeros((len(zp),n_points,3)) # radial location, airfoil pts (same y)
        matrix[:,:,0] = xp*rot
        matrix[:,:,1] = yp
        matrix[:,:,2] = zp

        # ROTATION MATRICES FOR INNER SECTION
        # rotation about y axis to create twist and position blade upright
        trans_1 = np.zeros((dim,3,3))
        trans_1[:,0,0] = np.cos(flip_1 - rot*beta)
        trans_1[:,0,2] = -np.sin(flip_1 - rot*beta)
        trans_1[:,1,1] = 1
        trans_1[:,2,0] = np.sin(flip_1 - rot*beta)
        trans_1[:,2,2] = np.cos(flip_1 - rot*beta)

        # rotation about x axis to create azimuth locations
        trans_2 = np.array([[1 , 0 , 0],
                       [0 , np.cos(theta[i] + a_o + flip_2 ), -np.sin(theta[i] +a_o +  flip_2)],
                       [0,np.sin(theta[i] + a_o + flip_2), np.cos(theta[i] + a_o + flip_2)]])
        trans_2 =  np.repeat(trans_2[ np.newaxis,:,: ],dim,axis=0)

        # rotation about y to orient propeller/rotor to thrust angle
        trans_3 =  prop.prop_vel_to_body()
        trans_3 =  np.repeat(trans_3[ np.newaxis,:,: ],dim,axis=0) 
        
        # rotation 180 degrees 
        trans_4 = np.zeros((dim,3,3))
        trans_4[:,0,0] = np.cos(np.pi)
        trans_4[:,0,2] = -np.sin(np.pi)
        trans_4[:,1,1] = 1
        trans_4[:,2,0] = np.sin(np.pi)
        trans_4[:,2,2] = np.cos(np.pi)
        
        trans     = np.matmul(trans_4,np.matmul(trans_3,np.matmul(trans_2,trans_1)))
        rot_mat   = np.repeat(trans[:, np.newaxis,:,:],n_points,axis=1)

        # ---------------------------------------------------------------------------------------------
        # ROTATE POINTS
        mat  =  np.matmul(rot_mat,matrix[...,None]).squeeze()

        # ---------------------------------------------------------------------------------------------
        # store points
        G.XA1  = mat[:-1,:-1,0] + origin[0][0]
        G.YA1  = mat[:-1,:-1,1] + origin[0][1]
        G.ZA1  = mat[:-1,:-1,2] + origin[0][2]
        G.XA2  = mat[:-1,1:,0]  + origin[0][0]
        G.YA2  = mat[:-1,1:,1]  + origin[0][1]
        G.ZA2  = mat[:-1,1:,2]  + origin[0][2]

        G.XB1  = mat[1:,:-1,0] + origin[0][0]
        G.YB1  = mat[1:,:-1,1] + origin[0][1]
        G.ZB1  = mat[1:,:-1,2] + origin[0][2]
        G.XB2  = mat[1:,1:,0]  + origin[0][0]
        G.YB2  = mat[1:,1:,1]  + origin[0][1]
        G.ZB2  = mat[1:,1:,2]  + origin[0][2]

        # ------------------------------------------------------------------------
        # Plot Propeller Blade
        # ------------------------------------------------------------------------
        for sec in range(dim-1):
            for loc in range(af_pts):
                X = [G.XA1[sec,loc],
                     G.XB1[sec,loc],
                     G.XB2[sec,loc],
                     G.XA2[sec,loc]]
                Y = [G.YA1[sec,loc],
                     G.YB1[sec,loc],
                     G.YB2[sec,loc],
                     G.YA2[sec,loc]]
                Z = [G.ZA1[sec,loc],
                     G.ZB1[sec,loc],
                     G.ZB2[sec,loc],
                     G.ZA2[sec,loc]]
                prop_verts = [list(zip(X, Y, Z))]
                prop_collection = Poly3DCollection(prop_verts)
                prop_collection.set_facecolor(prop_face_color)
                prop_collection.set_edgecolor(prop_edge_color)
                prop_collection.set_alpha(prop_alpha)
                axes.add_collection3d(prop_collection)
    return
Example #2
0
def generate_nacelle_points(nac,tessellation = 24):
    """ This generates the coordinate points on the surface of the nacelle

    Assumptions:
    None

    Source:
    None

    Inputs: 
    Properties Used:
    N/A 
    """
     
    
    num_nac_segs = len(nac.Segments.keys())   
    theta        = np.linspace(0,2*np.pi,tessellation)
    n_points     = 20
    
    if num_nac_segs == 0:
        num_nac_segs = int(n_points/2)
        nac_pts      = np.zeros((num_nac_segs,tessellation,3))
        naf          = nac.Airfoil
        
        if naf.naca_4_series_airfoil != None: 
            # use mean camber surface of airfoil
            camber       = float(naf.naca_4_series_airfoil[0])/100
            camber_loc   = float(naf.naca_4_series_airfoil[1])/10
            thickness    = float(naf.naca_4_series_airfoil[2:])/100 
            airfoil_data = compute_naca_4series(camber, camber_loc, thickness,(n_points - 2))
            xpts         = np.repeat(np.atleast_2d(airfoil_data.x_lower_surface).T,tessellation,axis = 1)*nac.length 
            zpts         = np.repeat(np.atleast_2d(airfoil_data.camber_coordinates[0]).T,tessellation,axis = 1)*nac.length  
        
        elif naf.coordinate_file != None: 
            a_sec        = naf.coordinate_file
            a_secl       = [0]
            airfoil_data = import_airfoil_geometry(a_sec,npoints=num_nac_segs)
            xpts         = np.repeat(np.atleast_2d(np.take(airfoil_data.x_coordinates,a_secl,axis=0)).T,tessellation,axis = 1)*nac.length  
            zpts         = np.repeat(np.atleast_2d(np.take(airfoil_data.y_coordinates,a_secl,axis=0)).T,tessellation,axis = 1)*nac.length  
        
        else:
            # if no airfoil defined, use super ellipse as default
            a =  nac.length/2 
            b =  (nac.diameter - nac.inlet_diameter)/2 
            b = np.maximum(b,1E-3) # ensure 
            xpts =  np.repeat(np.atleast_2d(np.linspace(-a,a,num_nac_segs)).T,tessellation,axis = 1) 
            zpts = (np.sqrt((b**2)*(1 - (xpts**2)/(a**2) )))*nac.length 
            xpts = (xpts+a)*nac.length  

        if nac.flow_through: 
            zpts = zpts + nac.inlet_diameter/2  
                
        # create geometry 
        theta_2d = np.repeat(np.atleast_2d(theta),num_nac_segs,axis =0) 
        nac_pts[:,:,0] =  xpts
        nac_pts[:,:,1] =  zpts*np.cos(theta_2d)
        nac_pts[:,:,2] =  zpts*np.sin(theta_2d)  
                
    else:
        nac_pts = np.zeros((num_nac_segs,tessellation,3)) 
        for i_seg in range(num_nac_segs):
            a        = nac.Segments[i_seg].width/2
            b        = nac.Segments[i_seg].height/2
            r        = np.sqrt((b*np.sin(theta))**2  + (a*np.cos(theta))**2)
            nac_ypts = r*np.cos(theta)
            nac_zpts = r*np.sin(theta)
            nac_pts[i_seg,:,0] = nac.Segments[i_seg].percent_x_location*nac.length
            nac_pts[i_seg,:,1] = nac_ypts + nac.Segments[i_seg].percent_y_location*nac.length 
            nac_pts[i_seg,:,2] = nac_zpts + nac.Segments[i_seg].percent_z_location*nac.length  
            
    # rotation about y to orient propeller/rotor to thrust angle
    rot_trans =  nac.nac_vel_to_body()
    rot_trans =  np.repeat( np.repeat(rot_trans[ np.newaxis,:,: ],tessellation,axis=0)[ np.newaxis,:,:,: ],num_nac_segs,axis=0)    
    
    NAC_PTS  =  np.matmul(rot_trans,nac_pts[...,None]).squeeze()  
     
    # translate to body 
    NAC_PTS[:,:,0] = NAC_PTS[:,:,0] + nac.origin[0][0]
    NAC_PTS[:,:,1] = NAC_PTS[:,:,1] + nac.origin[0][1]
    NAC_PTS[:,:,2] = NAC_PTS[:,:,2] + nac.origin[0][2]
    return NAC_PTS
Example #3
0
def generate_lofted_propeller_points(prop):
    """
    Generates nodes on the lofted propeller.

    Inputs:
       prop          Data structure of SUAVE propeller                  [Unitless]

    Outputs:
       N/A

    Properties Used:
       N/A

    Assumptions:
       Quad cell structures for mesh

    Source:
       None

    """
    num_B  = prop.number_of_blades
    a_sec  = prop.airfoil_geometry
    a_secl = prop.airfoil_polar_stations
    beta   = prop.twist_distribution
    b      = prop.chord_distribution
    r      = prop.radius_distribution
    MCA    = prop.mid_chord_alignment
    t      = prop.max_thickness_distribution
    ta     = prop.orientation_euler_angles[1]
    origin = prop.origin

    try:
        a_o = -prop.start_angle[0]
    except:
        # default is no azimuthal offset (blade 1 starts vertical)
        a_o = 0.0

    n_r       = len(b)                               # number radial points
    n_a_loft  = prop.number_points_around_airfoil    # number points around airfoil
    n_a_cw    = n_a_loft//2                          # number of airfoil chordwise points
    theta     = np.linspace(0,2*np.pi,num_B+1)[:-1]  # azimuthal stations

    # create empty data structure for storing propeller geometries
    G           = Data()
    Gprops      = Data()
    Gprops.n_af = n_a_loft

    rot         = prop.rotation
    flip_1      = (np.pi/2)
    flip_2      = (np.pi/2)

    MCA_2d = np.repeat(np.atleast_2d(MCA).T,n_a_loft,axis=1)
    b_2d   = np.repeat(np.atleast_2d(b).T  ,n_a_loft,axis=1)
    t_2d   = np.repeat(np.atleast_2d(t).T  ,n_a_loft,axis=1)
    r_2d   = np.repeat(np.atleast_2d(r).T  ,n_a_loft,axis=1)

    for i in range(num_B):
        Gprops[i] = Data()
        # get airfoil coordinate geometry
        if a_sec != None:
            airfoil_data   = import_airfoil_geometry(a_sec,npoints=n_a_loft)

            xpts         = np.take(airfoil_data.x_coordinates,a_secl,axis=0)
            zpts         = np.take(airfoil_data.y_coordinates,a_secl,axis=0)
            max_t        = np.take(airfoil_data.thickness_to_chord,a_secl,axis=0)

        else:
            camber       = 0.02
            camber_loc   = 0.4
            thickness    = 0.10
            airfoil_data = compute_naca_4series(camber, camber_loc, thickness,(n_a_loft - 2))
            xpts         = np.repeat(np.atleast_2d(airfoil_data.x_coordinates) ,n_r,axis=0)
            zpts         = np.repeat(np.atleast_2d(airfoil_data.y_coordinates) ,n_r,axis=0)
            max_t        = np.repeat(airfoil_data.thickness_to_chord,n_r,axis=0)

        # store points of airfoil in similar format as Vortex Points (i.e. in vertices)
        max_t2d = np.repeat(np.atleast_2d(max_t).T ,n_a_loft,axis=1)

        airfoil_le_offset = (b[0]/2 - np.repeat(b[:,None], n_a_loft, axis=1)/2 ) # no sweep
        xp      = rot*(- MCA_2d + xpts*b_2d + airfoil_le_offset)  # x coord of airfoil
        yp      = r_2d*np.ones_like(xp)                           # radial location
        zp      = zpts*(t_2d/max_t2d)                             # former airfoil y coord

        matrix = np.zeros((n_r,n_a_loft,3)) # radial location, airfoil pts (same y)
        matrix[:,:,0] = xp
        matrix[:,:,1] = yp
        matrix[:,:,2] = zp


        # ROTATION MATRICES FOR INNER SECTION
        # rotation about y axis to create twist and position blade upright
        trans_1 = np.zeros((n_r,3,3))
        trans_1[:,0,0] = np.cos(rot*flip_1 - rot*beta)
        trans_1[:,0,2] = -np.sin(rot*flip_1 - rot*beta)
        trans_1[:,1,1] = 1
        trans_1[:,2,0] = np.sin(rot*flip_1 - rot*beta)
        trans_1[:,2,2] = np.cos(rot*flip_1 - rot*beta)

        # rotation about x axis to create azimuth locations
        trans_2 = np.array([[1 , 0 , 0],
                            [0 , np.cos(theta[i] + rot*a_o + flip_2 ), -np.sin(theta[i] + rot*a_o + flip_2)],
                            [0,np.sin(theta[i] + rot*a_o + flip_2), np.cos(theta[i] + rot*a_o + flip_2)]   ])
        trans_2 =  np.repeat(trans_2[ np.newaxis,:,: ],n_r,axis=0)

        # rotation about y to orient propeller/rotor to thrust angle
        trans_3 = prop.body_to_prop_vel() #prop.prop_vel_to_body()
        trans_3 =  np.repeat(trans_3[ np.newaxis,:,: ],n_r,axis=0)

        trans   = np.matmul(trans_3,np.matmul(trans_2,trans_1))
        rot_mat = np.repeat(trans[:, np.newaxis,:,:],n_a_loft,axis=1)

        # ---------------------------------------------------------------------------------------------
        # ROTATE POINTS
        mat  =  np.matmul(rot_mat,matrix[...,None]).squeeze()

        # ---------------------------------------------------------------------------------------------
        # store node points
        G.X  = mat[:,:,0] + origin[0][0]
        G.Y  = mat[:,:,1] + origin[0][1]
        G.Z  = mat[:,:,2] + origin[0][2]

        # store cell points
        G.XA1  = mat[:-1,:-1,0] + origin[0][0]
        G.YA1  = mat[:-1,:-1,1] + origin[0][1]
        G.ZA1  = mat[:-1,:-1,2] + origin[0][2]
        G.XA2  = mat[:-1,1:,0]  + origin[0][0]
        G.YA2  = mat[:-1,1:,1]  + origin[0][1]
        G.ZA2  = mat[:-1,1:,2]  + origin[0][2]

        G.XB1  = mat[1:,:-1,0] + origin[0][0]
        G.YB1  = mat[1:,:-1,1] + origin[0][1]
        G.ZB1  = mat[1:,:-1,2] + origin[0][2]
        G.XB2  = mat[1:,1:,0]  + origin[0][0]
        G.YB2  = mat[1:,1:,1]  + origin[0][1]
        G.ZB2  = mat[1:,1:,2]  + origin[0][2]

        # Store G for this blade:
        Gprops[i] = copy.deepcopy(G)

    return Gprops
def generate_propeller_geometry(prop, angle_offset=0):
    """This plots the geoemtry of a propeller or rotor

    Assumptions:
    None

    Source:
    None

    Inputs:
    SUAVE.Components.Energy.Converters.Propeller()

    Outputs: 
    Plots

    Properties Used:
    N/A	
    """

    # unpack
    # ------------------------------------------------------------------------
    # Generate Propeller Geoemtry
    # ------------------------------------------------------------------------

    # unpack
    Rt = prop.tip_radius
    Rh = prop.hub_radius
    num_B = prop.number_blades
    a_sec = prop.airfoil_geometry
    a_secl = prop.airfoil_polar_stations
    beta = prop.twist_distribution
    b = prop.chord_distribution
    r = prop.radius_distribution
    MCA = prop.mid_chord_aligment
    t = prop.max_thickness_distribution

    airfoil_pts = 20
    dim = len(b)
    num_props = len(prop.origin)
    theta = np.linspace(0, 2 * np.pi, num_B + 1)[:-1]
    if any(r) == None:
        r = np.linspace(Rh, Rt, len(b))

    # create empty arrays for storing geometry
    G = Data()
    G.XA1 = np.zeros((num_props, num_B, dim - 1, (2 * airfoil_pts) - 1))
    G.YA1 = np.zeros_like(G.XA1)
    G.ZA1 = np.zeros_like(G.XA1)
    G.XA2 = np.zeros_like(G.XA1)
    G.YA2 = np.zeros_like(G.XA1)
    G.ZA2 = np.zeros_like(G.XA1)
    G.XB1 = np.zeros_like(G.XA1)
    G.YB1 = np.zeros_like(G.XA1)
    G.ZB1 = np.zeros_like(G.XA1)
    G.XB2 = np.zeros_like(G.XA1)
    G.YB2 = np.zeros_like(G.XA1)
    G.ZB2 = np.zeros_like(G.XA1)

    for n_p in range(num_props):

        a_o = prop.rotation[n_p] * angle_offset
        flip_1 = (np.pi / 2) * prop.rotation[n_p]
        flip_2 = (np.pi / 2) * prop.rotation[n_p]
        if prop.rotation[n_p] == -1:
            flip_3 = -np.pi
        else:
            flip_3 = 0

        for i in range(num_B):
            # check if airfoils are defined
            if a_sec != None and a_secl != None:
                # check dimension of section
                dim_sec = len(a_secl)
                if dim_sec != dim:
                    raise AssertionError(
                        "Number of sections not equal to number of stations")

                # get airfoil coordinate geometry
                airfoil_data = import_airfoil_geometry(a_sec,
                                                       npoints=airfoil_pts)

            # if no airfoil defined, use NACA 0012
            else:
                airfoil_data = compute_naca_4series(0,
                                                    0,
                                                    12,
                                                    npoints=(airfoil_pts * 2) -
                                                    2)
                a_secl = np.zeros(dim).astype(int)

            # store points of airfoil in similar format as Vortex Points (i.e. in vertices)
            for j in range(dim - 1):  # loop through each radial station
                # iba - imboard airfoil section
                iba_max_t = airfoil_data.thickness_to_chord[a_secl[j]]
                iba_xp = b[j] - MCA[j] - airfoil_data.x_coordinates[
                    a_secl[j]] * b[j]  # x coord of airfoil
                iba_yp = r[j] * np.ones_like(iba_xp)  # radial location
                iba_zp = airfoil_data.y_coordinates[a_secl[j]] * b[j] * (
                    t[j] / iba_max_t)  # former airfoil y coord

                iba_trans_1 = [
                    [np.cos(beta[j] + flip_3), 0, -np.sin(beta[j] + flip_3)],
                    [0, 1, 0],
                    [np.sin(beta[j] + flip_3), 0,
                     np.cos(beta[j] + flip_3)]
                ]

                iba_trans_2 = [[
                    np.cos(theta[i] + a_o), -np.sin(theta[i] + a_o), 0
                ], [np.sin(theta[i] + a_o),
                    np.cos(theta[i] + a_o), 0], [0, 0, 1]]

                iba_trans_3 = [[1, 0, 0], [0,
                                           np.cos(flip_1),
                                           np.sin(flip_1)],
                               [0, np.sin(flip_1),
                                np.cos(flip_1)]]

                iba_trans_4 = [[np.cos(flip_2), -np.sin(flip_2), 0],
                               [np.sin(flip_2),
                                np.cos(flip_2), 0], [0, 0, 1]]

                iba_trans = np.matmul(
                    iba_trans_4,
                    np.matmul(iba_trans_3, np.matmul(iba_trans_2,
                                                     iba_trans_1)))

                # oba - outboard airfoil section
                oba_max_t = airfoil_data.thickness_to_chord[a_secl[j + 1]]
                oba_xp = b[j + 1] - MCA[j + 1] - airfoil_data.x_coordinates[
                    a_secl[j + 1]] * b[j + 1]  # x coord of airfoil
                oba_yp = r[j + 1] * np.ones_like(oba_xp)  # radial location
                oba_zp = airfoil_data.y_coordinates[a_secl[j + 1]] * b[
                    j + 1] * (t[j + 1] / oba_max_t)  # former airfoil y coord

                oba_trans_1 = [[
                    np.cos(beta[j + 1] + flip_3), 0,
                    -np.sin(beta[j + 1] + flip_3)
                ], [0, 1, 0],
                               [
                                   np.sin(beta[j + 1] + flip_3), 0,
                                   np.cos(beta[j + 1] + flip_3)
                               ]]

                oba_trans_2 = [[
                    np.cos(theta[i] + a_o), -np.sin(theta[i] + a_o), 0
                ], [np.sin(theta[i] + a_o),
                    np.cos(theta[i] + a_o), 0], [0, 0, 1]]

                oba_trans_3 = [[1, 0, 0], [0,
                                           np.cos(flip_1),
                                           np.sin(flip_1)],
                               [0, np.sin(flip_1),
                                np.cos(flip_1)]]

                oba_trans_4 = [[np.cos(flip_2), -np.sin(flip_2), 0],
                               [np.sin(flip_2),
                                np.cos(flip_2), 0], [0, 0, 1]]

                oba_trans = np.matmul(
                    oba_trans_4,
                    np.matmul(oba_trans_3, np.matmul(oba_trans_2,
                                                     oba_trans_1)))

                iba_x = np.zeros(len(iba_xp))
                iba_y = np.zeros(len(iba_yp))
                iba_z = np.zeros(len(iba_zp))
                oba_x = np.zeros(len(oba_xp))
                oba_y = np.zeros(len(oba_yp))
                oba_z = np.zeros(len(oba_zp))

                for k in range(len(iba_yp)):
                    iba_vec_1 = [[iba_xp[k]], [iba_yp[k]], [iba_zp[k]]]
                    iba_vec_2 = np.matmul(iba_trans, iba_vec_1)

                    iba_x[k] = iba_vec_2[0]
                    iba_y[k] = iba_vec_2[1]
                    iba_z[k] = iba_vec_2[2]

                    oba_vec_1 = [[oba_xp[k]], [oba_yp[k]], [oba_zp[k]]]
                    oba_vec_2 = np.matmul(oba_trans, oba_vec_1)
                    oba_x[k] = oba_vec_2[0]
                    oba_y[k] = oba_vec_2[1]
                    oba_z[k] = oba_vec_2[2]

                # store points
                G.XA1[n_p, i, j, :] = iba_x[:-1] + prop.origin[n_p][0]
                G.YA1[n_p, i, j, :] = iba_y[:-1] + prop.origin[n_p][1]
                G.ZA1[n_p, i, j, :] = iba_z[:-1] + prop.origin[n_p][2]
                G.XA2[n_p, i, j, :] = iba_x[1:] + prop.origin[n_p][0]
                G.YA2[n_p, i, j, :] = iba_y[1:] + prop.origin[n_p][1]
                G.ZA2[n_p, i, j, :] = iba_z[1:] + prop.origin[n_p][2]

                G.XB1[n_p, i, j, :] = oba_x[:-1] + prop.origin[n_p][0]
                G.YB1[n_p, i, j, :] = oba_y[:-1] + prop.origin[n_p][1]
                G.ZB1[n_p, i, j, :] = oba_z[:-1] + prop.origin[n_p][2]
                G.XB2[n_p, i, j, :] = oba_x[1:] + prop.origin[n_p][0]
                G.YB2[n_p, i, j, :] = oba_y[1:] + prop.origin[n_p][1]
                G.ZB2[n_p, i, j, :] = oba_z[1:] + prop.origin[n_p][2]

    return G
Example #5
0
def main():
    # Define Panelization
    npanel = 200

    # -----------------------------------------------
    # Batch analysis of single airfoil - NACA 2410
    # -----------------------------------------------
    Re_batch = np.atleast_2d(np.array([1E5, 2E5])).T
    AoA_batch = np.atleast_2d(np.linspace(-5, 10, 4) * Units.degrees).T
    airfoil_geometry = compute_naca_4series(0.02, 0.4, 0.1, npoints=npanel)
    airfoil_properties_1 = airfoil_analysis(airfoil_geometry,
                                            AoA_batch,
                                            Re_batch,
                                            npanel,
                                            batch_analysis=True)

    # Plots
    plot_airfoil_analysis_polars(airfoil_properties_1, show_legend=True)
    plot_airfoil_analysis_surface_forces(airfoil_properties_1,
                                         show_legend=True)
    plot_airfoil_analysis_boundary_layer_properties(airfoil_properties_1,
                                                    show_legend=True)

    # XFOIL Validation - Source :
    xfoil_data_Cl = 0.7922
    xfoil_data_Cd = 0.01588
    xfoil_data_Cm = -0.0504

    diff_CL = np.abs(airfoil_properties_1.Cl[2, 0] - xfoil_data_Cl)
    expected_Cl_error = -0.01801472136594917
    print('\nCL difference')
    print(diff_CL)
    assert np.abs(
        ((airfoil_properties_1.Cl[2, 0] - expected_Cl_error) - xfoil_data_Cl) /
        xfoil_data_Cl) < 1e-6

    diff_CD = np.abs(airfoil_properties_1.Cd[2, 0] - xfoil_data_Cd)
    expected_Cd_error = -0.00012125071270768784
    print('\nCD difference')
    print(diff_CD)
    assert np.abs(
        ((airfoil_properties_1.Cd[2, 0] - expected_Cd_error) - xfoil_data_Cd) /
        xfoil_data_Cd) < 1e-6

    diff_CM = np.abs(airfoil_properties_1.Cm[2, 0] - xfoil_data_Cm)
    expected_Cm_error = -0.002782281182096287
    print('\nCM difference')
    print(diff_CM)
    assert np.abs(
        ((airfoil_properties_1.Cm[2, 0] - expected_Cm_error) - xfoil_data_Cm) /
        xfoil_data_Cm) < 1e-6

    # -----------------------------------------------
    # Single Condition Analysis of multiple airfoils
    # -----------------------------------------------
    ospath = os.path.abspath(__file__)
    separator = os.path.sep
    rel_path = ospath.split(
        'airfoil_analysis' + separator + 'airfoil_panel_method_test.py'
    )[0] + 'Vehicles' + separator + 'Airfoils' + separator
    Re_vals = np.atleast_2d(np.array([1E5, 1E5, 1E5, 1E5, 1E5, 1E5])).T
    AoA_vals = np.atleast_2d(np.array([2, 2, 2, 2, 2, 2]) * Units.degrees).T
    airfoil_stations = [0, 1, 0, 1, 0, 1]
    airfoils = [rel_path + 'NACA_4412.txt', rel_path + 'Clark_y.txt']
    airfoil_geometry = import_airfoil_geometry(airfoils, npoints=(npanel + 2))
    airfoil_properties_2 = airfoil_analysis(airfoil_geometry,
                                            AoA_vals,
                                            Re_vals,
                                            npanel,
                                            batch_analysis=False,
                                            airfoil_stations=airfoil_stations)

    True_Cls = np.array([[0.68788905], [0.60906619], [0.68788905],
                         [0.60906619], [0.68788905], [0.60906619]])
    True_Cds = np.array([[0.01015395], [0.00846174], [0.01015395],
                         [0.00846174], [0.01015395], [0.00846174]])
    True_Cms = np.array([[-0.10478782], [-0.08727453], [-0.10478782],
                         [-0.08727453], [-0.10478782], [-0.08727453]])

    print('\n\nSingle Point Validation')
    print('\nCL difference')
    print(np.sum(np.abs((airfoil_properties_2.Cl - True_Cls) / True_Cls)))
    assert np.sum(np.abs(
        (airfoil_properties_2.Cl - True_Cls) / True_Cls)) < 1e-5

    print('\nCD difference')
    print(np.sum(np.abs((airfoil_properties_2.Cd - True_Cds) / True_Cds)))
    assert np.sum(np.abs(
        (airfoil_properties_2.Cd - True_Cds) / True_Cds)) < 1e-5

    print('\nCM difference')
    print(np.sum(np.abs((airfoil_properties_2.Cm - True_Cms) / True_Cms)))
    assert np.sum(np.abs(
        (airfoil_properties_2.Cm - True_Cms) / True_Cms)) < 1e-5
    return