示例#1
0
def vsp_read_wing(wing_id, units_type='SI'):
    """This reads an OpenVSP wing vehicle geometry and writes it into a SUAVE wing format.

	Assumptions:
	1. OpenVSP wing is divided into segments ("XSecs" in VSP).
	2. Written for OpenVSP 3.21.1

	Source:
	N/A

	Inputs:
	0. Pre-loaded VSP vehicle in memory, via vsp_read.
	1. VSP 10-digit geom ID for wing.
	2. units_type set to 'SI' (default) or 'Imperial'.

	Outputs:
	Writes SUAVE wing object, with these geometries, from VSP:
		Wings.Wing.    (* is all keys)
			origin                                  [m] in all three dimensions
			spans.projected                         [m]
			chords.root                             [m]
			chords.tip                              [m]
			aspect_ratio                            [-]
			sweeps.quarter_chord                    [radians]
			twists.root                             [radians]
			twists.tip                              [radians]
			thickness_to_chord                      [-]
			dihedral                                [radians]
			symmetric                               <boolean>
			tag                                     <string>
			areas.exposed                           [m^2]
			areas.reference                         [m^2]
			areas.wetted                            [m^2]
			Segments.
			  tag                                   <string>
			  twist                                 [radians]
			  percent_span_location                 [-]  .1 is 10%
			  root_chord_percent                    [-]  .1 is 10%
			  dihedral_outboard                     [radians]
			  sweeps.quarter_chord                  [radians]
			  thickness_to_chord                    [-]
			  airfoil                               <NACA 4-series, 6 series, or airfoil file>

	Properties Used:
	N/A
	"""

    # Check if this is vertical tail, this seems like a weird first step but it's necessary
    # Get the initial rotation to get the dihedral angles
    x_rot = vsp.GetParmVal(wing_id, 'X_Rotation', 'XForm')
    if x_rot >= 70:
        wing = SUAVE.Components.Wings.Vertical_Tail()
        wing.vertical = True
        x_rot = (90 - x_rot) * Units.deg
    else:
        # Instantiate a wing
        wing = SUAVE.Components.Wings.Wing()

    # Set the units
    if units_type == 'SI':
        units_factor = Units.meter * 1.
    else:
        units_factor = Units.foot * 1.

    # Apply a tag to the wing
    if vsp.GetGeomName(wing_id):
        tag = vsp.GetGeomName(wing_id)
        tag = tag.translate(t_table)
        wing.tag = tag
    else:
        wing.tag = 'winggeom'

    # Top level wing parameters
    # Wing origin
    wing.origin[0][0] = vsp.GetParmVal(wing_id, 'X_Location',
                                       'XForm') * units_factor
    wing.origin[0][1] = vsp.GetParmVal(wing_id, 'Y_Location',
                                       'XForm') * units_factor
    wing.origin[0][2] = vsp.GetParmVal(wing_id, 'Z_Location',
                                       'XForm') * units_factor

    # Wing Symmetry
    sym_planar = vsp.GetParmVal(wing_id, 'Sym_Planar_Flag', 'Sym')
    sym_origin = vsp.GetParmVal(wing_id, 'Sym_Ancestor', 'Sym')

    # Check for symmetry
    if sym_planar == 2. and sym_origin == 1.:  #origin at wing, not vehicle
        wing.symmetric = True
    else:
        wing.symmetric = False

    #More top level parameters
    total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan',
                                     'WingGeom') * units_factor
    wing.aspect_ratio = vsp.GetParmVal(wing_id, 'TotalAR', 'WingGeom')
    wing.areas.reference = vsp.GetParmVal(wing_id, 'TotalArea',
                                          'WingGeom') * units_factor**2
    wing.spans.projected = total_proj_span

    # Check if this is a single segment wing
    xsec_surf_id = vsp.GetXSecSurf(wing_id,
                                   0)  # This is how VSP stores surfaces.
    x_sec_1 = vsp.GetXSec(xsec_surf_id, 1)
    x_sec_1_span_parm = vsp.GetXSecParm(x_sec_1, 'Span')
    x_sec_1_span = vsp.GetParmVal(x_sec_1_span_parm) * (
        1 + wing.symmetric) * units_factor

    if x_sec_1_span == wing.spans.projected:
        single_seg = True
    else:
        single_seg = False

    segment_num = vsp.GetNumXSec(
        xsec_surf_id
    )  # Get number of wing segments (is one more than the VSP GUI shows).
    x_sec = vsp.GetXSec(xsec_surf_id, 0)
    chord_parm = vsp.GetXSecParm(x_sec, 'Root_Chord')

    total_chord = vsp.GetParmVal(chord_parm)

    span_sum = 0.  # Non-projected.
    proj_span_sum = 0.  # Projected.
    segment_spans = [None] * (segment_num)  # Non-projected.
    segment_dihedral = [None] * (segment_num)
    segment_sweeps_quarter_chord = [None] * (segment_num)

    # Check for wing segment *inside* fuselage, then skip XSec_0 to start at first exposed segment.
    if total_chord == 1.:
        start = 1
        xsec_surf_id = vsp.GetXSecSurf(wing_id, 1)
        x_sec = vsp.GetXSec(xsec_surf_id, 0)
        chord_parm = vsp.GetXSecParm(x_sec, 'Tip_Chord')
        root_chord = vsp.GetParmVal(chord_parm) * units_factor
    else:
        start = 0
        root_chord = total_chord * units_factor

    # -------------
    # Wing segments
    # -------------

    if single_seg == False:

        # Convert VSP XSecs to SUAVE segments. (Wing segments are defined by outboard sections in VSP, but inboard sections in SUAVE.)
        for i in range(start, segment_num + 1):
            segment = SUAVE.Components.Wings.Segment()
            segment.tag = 'Section_' + str(i)
            thick_cord = vsp.GetParmVal(wing_id, 'ThickChord',
                                        'XSecCurve_' + str(i - 1))
            segment.thickness_to_chord = thick_cord  # Thick_cord stored for use in airfoil, below.
            segment_root_chord = vsp.GetParmVal(
                wing_id, 'Root_Chord', 'XSec_' + str(i)) * units_factor
            segment.root_chord_percent = segment_root_chord / root_chord
            segment.percent_span_location = proj_span_sum / (total_proj_span /
                                                             2)
            segment.twist = vsp.GetParmVal(wing_id, 'Twist',
                                           'XSec_' + str(i - 1)) * Units.deg

            if i == start:
                wing.thickness_to_chord = thick_cord

            if i < segment_num:  # This excludes the tip xsec, but we need a segment in SUAVE to store airfoil.
                sweep = vsp.GetParmVal(wing_id, 'Sweep',
                                       'XSec_' + str(i)) * Units.deg
                sweep_loc = vsp.GetParmVal(wing_id, 'Sweep_Location',
                                           'XSec_' + str(i))
                AR = vsp.GetParmVal(wing_id, 'Aspect', 'XSec_' + str(i))
                taper = vsp.GetParmVal(wing_id, 'Taper', 'XSec_' + str(i))

                segment_sweeps_quarter_chord[i] = convert_sweep(
                    sweep, sweep_loc, 0.25, AR, taper)
                segment.sweeps.quarter_chord = segment_sweeps_quarter_chord[
                    i]  # Used again, below

                # Used for dihedral computation, below.
                segment_dihedral[i] = vsp.GetParmVal(
                    wing_id, 'Dihedral', 'XSec_' + str(i)) * Units.deg + x_rot
                segment.dihedral_outboard = segment_dihedral[i]

                segment_spans[i] = vsp.GetParmVal(
                    wing_id, 'Span', 'XSec_' + str(i)) * units_factor
                proj_span_sum += segment_spans[i] * np.cos(segment_dihedral[i])
                span_sum += segment_spans[i]
            else:
                segment.root_chord_percent = (vsp.GetParmVal(
                    wing_id, 'Tip_Chord',
                    'XSec_' + str(i - 1))) * units_factor / total_chord

            # XSec airfoil
            jj = i - 1  # Airfoil index i-1 because VSP airfoils and sections are one index off relative to SUAVE.
            xsec_id = str(vsp.GetXSec(xsec_surf_id, jj))
            airfoil = Airfoil()
            if vsp.GetXSecShape(
                    xsec_id
            ) == vsp.XS_FOUR_SERIES:  # XSec shape: NACA 4-series
                camber = vsp.GetParmVal(wing_id, 'Camber',
                                        'XSecCurve_' + str(jj))

                if camber == 0.:
                    camber_loc = 0.
                else:
                    camber_loc = vsp.GetParmVal(wing_id, 'CamberLoc',
                                                'XSecCurve_' + str(jj))

                airfoil.thickness_to_chord = thick_cord
                camber_round = int(np.around(camber * 100))
                camber_loc_round = int(np.around(camber_loc * 10))
                thick_cord_round = int(np.around(thick_cord * 100))
                airfoil.tag = 'NACA ' + str(camber_round) + str(
                    camber_loc_round) + str(thick_cord_round)

            elif vsp.GetXSecShape(
                    xsec_id) == vsp.XS_SIX_SERIES:  # XSec shape: NACA 6-series
                thick_cord_round = int(np.around(thick_cord * 100))
                a_value = vsp.GetParmVal(wing_id, 'A', 'XSecCurve_' + str(jj))
                ideal_CL = int(
                    np.around(
                        vsp.GetParmVal(wing_id, 'IdealCl',
                                       'XSecCurve_' + str(jj)) * 10))
                series_vsp = int(
                    vsp.GetParmVal(wing_id, 'Series', 'XSecCurve_' + str(jj)))
                series_dict = {
                    0: '63',
                    1: '64',
                    2: '65',
                    3: '66',
                    4: '67',
                    5: '63A',
                    6: '64A',
                    7: '65A'
                }  # VSP series values.
                series = series_dict[series_vsp]
                airfoil.tag = 'NACA ' + series + str(ideal_CL) + str(
                    thick_cord_round) + ' a=' + str(np.around(a_value, 1))

            elif vsp.GetXSecShape(
                    xsec_id
            ) == vsp.XS_FILE_AIRFOIL:  # XSec shape: 12 is type AF_FILE
                airfoil.thickness_to_chord = thick_cord
                airfoil.points = vsp.GetAirfoilCoordinates(
                    wing_id, float(jj / segment_num))
                # VSP airfoil API calls get coordinates and write files with the final argument being the fraction of segment position, regardless of relative spans.
                # (Write the root airfoil with final arg = 0. Write 4th airfoil of 5 segments with final arg = .8)
                vsp.WriteSeligAirfoil(
                    str(wing.tag) + '_airfoil_XSec_' + str(jj) + '.dat',
                    wing_id, float(jj / segment_num))
                airfoil.coordinate_file = 'str(wing.tag)' + '_airfoil_XSec_' + str(
                    jj) + '.dat'
                airfoil.tag = 'AF_file'

                segment.append_airfoil(airfoil)

            wing.Segments.append(segment)

        # Wing dihedral
        proj_span_sum_alt = 0.
        span_sum_alt = 0.
        sweeps_sum = 0.

        for ii in range(start, segment_num):
            span_sum_alt += segment_spans[ii]
            proj_span_sum_alt += segment_spans[ii] * np.cos(
                segment_dihedral[ii]
            )  # Use projected span to find total wing dihedral.
            sweeps_sum += segment_spans[ii] * np.tan(
                segment_sweeps_quarter_chord[ii])

        wing.dihedral = np.arccos(proj_span_sum_alt / span_sum_alt)
        wing.sweeps.quarter_chord = -np.arctan(
            sweeps_sum / span_sum_alt)  # Minus sign makes it positive sweep.

        # Add a tip segment, all values are zero except the tip chord
        tc = vsp.GetParmVal(wing_id, 'Tip_Chord',
                            'XSec_' + str(segment_num - 1)) * units_factor
        segment = SUAVE.Components.Wings.Segment()
        segment.percent_span_location = 1.0
        segment.root_chord_percent = tc / root_chord

        # Chords
        wing.chords.root = vsp.GetParmVal(wing_id, 'Tip_Chord',
                                          'XSec_0') * units_factor
        wing.chords.tip = tc
        wing.chords.mean_geometric = wing.areas.reference / wing.spans.projected

        # Just double calculate and fix things:
        wing = wing_segmented_planform(wing)

    else:
        # Single segment

        # Get ID's
        x_sec_1_dih_parm = vsp.GetXSecParm(x_sec_1, 'Dihedral')
        x_sec_1_sweep_parm = vsp.GetXSecParm(x_sec_1, 'Sweep')
        x_sec_1_sweep_loc_parm = vsp.GetXSecParm(x_sec_1, 'Sweep_Location')
        x_sec_1_taper_parm = vsp.GetXSecParm(x_sec_1, 'Taper')
        x_sec_1_rc_parm = vsp.GetXSecParm(x_sec_1, 'Root_Chord')
        x_sec_1_tc_parm = vsp.GetXSecParm(x_sec_1, 'Tip_Chord')

        # Calcs
        sweep = vsp.GetParmVal(x_sec_1_sweep_parm) * Units.deg
        sweep_loc = vsp.GetParmVal(x_sec_1_sweep_loc_parm)
        taper = vsp.GetParmVal(x_sec_1_taper_parm)
        c_4_sweep = convert_sweep(sweep, sweep_loc, 0.25, wing.aspect_ratio,
                                  taper)

        # Pull and pack
        wing.sweeps.quarter_chord = c_4_sweep
        wing.taper = taper
        wing.dihedral = vsp.GetParmVal(x_sec_1_dih_parm) * Units.deg + x_rot
        wing.chords.root = vsp.GetParmVal(x_sec_1_rc_parm) * units_factor
        wing.chords.tip = vsp.GetParmVal(x_sec_1_tc_parm) * units_factor
        wing.chords.mean_geometric = wing.areas.reference / wing.spans.projected

        # Just double calculate and fix things:
        wing = wing_planform(wing)

    # Twists
    wing.twists.root = vsp.GetParmVal(wing_id, 'Twist', 'XSec_0') * Units.deg
    wing.twists.tip = vsp.GetParmVal(
        wing_id, 'Twist', 'XSec_' + str(segment_num - 1)) * Units.deg

    return wing
示例#2
0
文件: test.py 项目: Nic42/OpenVSP
# ==== Use Case 2 ====#

vsp.VSPRenew()
errorMgr.PopErrorAndPrint(stdout)

geoms = vsp.FindGeoms()

print("All geoms in Vehicle.")
print(geoms)

# Add Fuse
fuse_id = vsp.AddGeom("FUSELAGE")

# Get XSec Surf ID
xsurf_id = vsp.GetXSecSurf(fuse_id, 0)

# Change Type of First XSec
vsp.ChangeXSecShape(xsurf_id, 0, vsp.XS_SUPER_ELLIPSE)
errorMgr.PopErrorAndPrint(stdout)

# Change Type First XSec Properties
xsec_id = vsp.GetXSec(xsurf_id, 0)
width_id = vsp.GetXSecParm(xsec_id, "Super_Width")
height_id = vsp.GetXSecParm(xsec_id, "Super_Height")
vsp.SetParmVal(width_id, 4.0)
vsp.SetParmVal(height_id, 2.0)

# Copy Cross-Section to Clipboard
vsp.CopyXSec(fuse_id, 0)
示例#3
0
def write_vsp_turbofan(turbofan, OML_set_ind):
    """This converts turbofans into OpenVSP format.
    
    Assumptions:
    None

    Source:
    N/A

    Inputs:
    turbofan.
      number_of_engines                       [-]
      engine_length                           [m]
      nacelle_diameter                        [m]
      origin                                  [m] in all three dimension, should have as many origins as engines
      OpenVSP_flow_through                    <boolean> if True create a flow through nacelle, if False create a cylinder

    Outputs:
    Operates on the active OpenVSP model, no direct output

    Properties Used:
    N/A
    """    
    n_engines   = turbofan.number_of_engines
    length      = turbofan.engine_length
    width       = turbofan.nacelle_diameter
    origins     = turbofan.origin
    inlet_width = turbofan.inlet_diameter
    tf_tag      = turbofan.tag
    
    # True will create a flow-through subsonic nacelle (which may have dimensional errors)
    # False will create a cylindrical stack (essentially a cylinder)
    ft_flag = turbofan.OpenVSP_flow_through
    
    import operator # import here since engines are not always needed
    # sort engines per left to right convention
    origins_sorted = sorted(origins, key=operator.itemgetter(1))
    
    for ii in range(0,int(n_engines)):

        origin = origins_sorted[ii]
        
        x = origin[0]
        y = origin[1]
        z = origin[2]
        
        if ft_flag == True:
            nac_id = vsp.AddGeom( "BODYOFREVOLUTION")
            vsp.SetGeomName(nac_id, tf_tag+'_'+str(ii+1))
            
            # Origin
            vsp.SetParmVal(nac_id,'X_Location','XForm',x)
            vsp.SetParmVal(nac_id,'Y_Location','XForm',y)
            vsp.SetParmVal(nac_id,'Z_Location','XForm',z)
            vsp.SetParmVal(nac_id,'Abs_Or_Relitive_flag','XForm',vsp.ABS) # misspelling from OpenVSP  
            
            # Length and overall diameter
            vsp.SetParmVal(nac_id,"Diameter","Design",inlet_width)
            
            vsp.ChangeBORXSecShape(nac_id ,vsp.XS_SUPER_ELLIPSE)
            vsp.Update()
            vsp.SetParmVal(nac_id, "Super_Height", "XSecCurve", (width-inlet_width)/2)
            vsp.SetParmVal(nac_id, "Super_Width", "XSecCurve", length)
            vsp.SetParmVal(nac_id, "Super_MaxWidthLoc", "XSecCurve", -1.)
            vsp.SetParmVal(nac_id, "Super_M", "XSecCurve", 2.)
            vsp.SetParmVal(nac_id, "Super_N", "XSecCurve", 1.)             
            
        else:
            nac_id = vsp.AddGeom("STACK")
            vsp.SetGeomName(nac_id, tf_tag+'_'+str(ii+1))
            
            # Origin
            vsp.SetParmVal(nac_id,'X_Location','XForm',x)
            vsp.SetParmVal(nac_id,'Y_Location','XForm',y)
            vsp.SetParmVal(nac_id,'Z_Location','XForm',z)
            vsp.SetParmVal(nac_id,'Abs_Or_Relitive_flag','XForm',vsp.ABS) # misspelling from OpenVSP
            vsp.SetParmVal(nac_id,'Origin','XForm',0.5)            
            
            vsp.CutXSec(nac_id,2) # remove extra default subsurface
            xsecsurf = vsp.GetXSecSurf(nac_id,0)
            vsp.ChangeXSecShape(xsecsurf,1,vsp.XS_CIRCLE)
            vsp.ChangeXSecShape(xsecsurf,2,vsp.XS_CIRCLE)
            vsp.Update()
            vsp.SetParmVal(nac_id, "Circle_Diameter", "XSecCurve_1", width)
            vsp.SetParmVal(nac_id, "Circle_Diameter", "XSecCurve_2", width)
            vsp.SetParmVal(nac_id, "XDelta", "XSec_1", 0)
            vsp.SetParmVal(nac_id, "XDelta", "XSec_2", length)
            vsp.SetParmVal(nac_id, "XDelta", "XSec_3", 0)
            
        vsp.SetSetFlag(nac_id, OML_set_ind, True)
        
        vsp.Update()
示例#4
0
def write_vsp_fuselage(fuselage,area_tags, main_wing, fuel_tank_set_ind, OML_set_ind):
    """This writes a fuselage into OpenVSP format.
    
    Assumptions:
    None

    Source:
    N/A

    Inputs:
    fuselage
      width                                   [m]
      lengths.total                           [m]
      heights.
        maximum                               [m]
        at_quarter_length                     [m]
        at_wing_root_quarter_chord            [m]
        at_three_quarters_length              [m]
      effective_diameter                      [m]
      fineness.nose                           [-] ratio of nose section length to fuselage width
      fineness.tail                           [-] ratio of tail section length to fuselage width
      tag                                     <string>
      OpenVSP_values.  (optional)
        nose.top.angle                        [degrees]
        nose.top.strength                     [-] this determines how much the specified angle influences that shape
        nose.side.angle                       [degrees]
        nose.side.strength                    [-]
        nose.TB_Sym                           <boolean> determines if top angle is mirrored on bottom
        nose.z_pos                            [-] z position of the nose as a percentage of fuselage length (.1 is 10%)
        tail.top.angle                        [degrees]
        tail.top.strength                     [-]
        tail.z_pos (optional, 0.02 default)   [-] z position of the tail as a percentage of fuselage length (.1 is 10%)
      Segments. (optional)
        width                                 [m]
        height                                [m]
        percent_x_location                    [-] .1 is 10% length
        percent_z_location                    [-] .1 is 10% length
    area_tags                                 <dict> used to keep track of all tags needed in wetted area computation           
    main_wing.origin                          [m]
    main_wing.chords.root                     [m]
    fuel_tank_set_index                       <int> OpenVSP object set containing the fuel tanks    

    Outputs:
    Operates on the active OpenVSP model, no direct output

    Properties Used:
    N/A
    """     
    
    num_segs           = len(fuselage.Segments)
    length             = fuselage.lengths.total
    fuse_x             = fuselage.origin[0][0]    
    fuse_y             = fuselage.origin[0][1]
    fuse_z             = fuselage.origin[0][2]
    fuse_x_rotation    = fuselage.x_rotation   
    fuse_y_rotation    = fuselage.y_rotation
    fuse_z_rotation    = fuselage.z_rotation    
    if num_segs==0: # SUAVE default fuselage shaping
    
        width    = fuselage.width
        hmax     = fuselage.heights.maximum
        height1  = fuselage.heights.at_quarter_length
        height2  = fuselage.heights.at_wing_root_quarter_chord 
        height3  = fuselage.heights.at_three_quarters_length
        effdia   = fuselage.effective_diameter
        n_fine   = fuselage.fineness.nose 
        t_fine   = fuselage.fineness.tail  
        
        try:
            if main_wing != None:                
                w_origin = main_wing.origin
                w_c_4    = main_wing.chords.root/4.
            else:
                w_origin = 0.5*length
                w_c_4    = 0.5*length
        except AttributeError:
            raise AttributeError('Main wing not detected. Fuselage must have specified sections in this configuration.')
        
        # Figure out the location x location of each section, 3 sections, end of nose, wing origin, and start of tail
        
        x1 = n_fine*width/length
        x2 = (w_origin[0][0]+w_c_4)/length
        x3 = 1-t_fine*width/length
        
        end_ind = 4
        
    else: # Fuselage shaping based on sections
        widths  = []
        heights = []
        x_poses = []
        z_poses = []
        segs = fuselage.Segments
        for seg in segs:
            widths.append(seg.width)
            heights.append(seg.height)
            x_poses.append(seg.percent_x_location)
            z_poses.append(seg.percent_z_location)
            
        end_ind = num_segs-1
    
    fuse_id = vsp.AddGeom("FUSELAGE") 
    vsp.SetGeomName(fuse_id, fuselage.tag)
    area_tags[fuselage.tag] = ['fuselages',fuselage.tag]

    tail_z_pos = 0.02 # default value

    # set fuselage relative location and rotation
    vsp.SetParmVal( fuse_id,'X_Rel_Rotation','XForm',fuse_x_rotation)
    vsp.SetParmVal( fuse_id,'Y_Rel_Rotation','XForm',fuse_y_rotation)
    vsp.SetParmVal( fuse_id,'Z_Rel_Rotation','XForm',fuse_z_rotation)
    
    vsp.SetParmVal( fuse_id,'X_Rel_Location','XForm',fuse_x)
    vsp.SetParmVal( fuse_id,'Y_Rel_Location','XForm',fuse_y)
    vsp.SetParmVal( fuse_id,'Z_Rel_Location','XForm',fuse_z)


    if 'OpenVSP_values' in fuselage:        
        vals = fuselage.OpenVSP_values

        # for wave drag testing
        fuselage.OpenVSP_ID = fuse_id
        
        # Nose
        vsp.SetParmVal(fuse_id,"TopLAngle","XSec_0",vals.nose.top.angle)
        vsp.SetParmVal(fuse_id,"TopLStrength","XSec_0",vals.nose.top.strength)
        vsp.SetParmVal(fuse_id,"RightLAngle","XSec_0",vals.nose.side.angle)
        vsp.SetParmVal(fuse_id,"RightLStrength","XSec_0",vals.nose.side.strength)
        vsp.SetParmVal(fuse_id,"TBSym","XSec_0",vals.nose.TB_Sym)
        vsp.SetParmVal(fuse_id,"ZLocPercent","XSec_0",vals.nose.z_pos)
        if not vals.nose.TB_Sym:
            vsp.SetParmVal(fuse_id,"BottomLAngle","XSec_0",vals.nose.bottom.angle)
            vsp.SetParmVal(fuse_id,"BottomLStrength","XSec_0",vals.nose.bottom.strength)           

        # Tail
        # Below can be enabled if AllSym (below) is removed
        #vsp.SetParmVal(fuse_id,"RightLAngle","XSec_4",vals.tail.side.angle)
        #vsp.SetParmVal(fuse_id,"RightLStrength","XSec_4",vals.tail.side.strength)
        #vsp.SetParmVal(fuse_id,"TBSym","XSec_4",vals.tail.TB_Sym)
        #vsp.SetParmVal(fuse_id,"BottomLAngle","XSec_4",vals.tail.bottom.angle)
        #vsp.SetParmVal(fuse_id,"BottomLStrength","XSec_4",vals.tail.bottom.strength)
        if 'z_pos' in vals.tail:
            tail_z_pos = vals.tail.z_pos
        else:
            pass # use above default


    if num_segs == 0:
        vsp.SetParmVal(fuse_id,"Length","Design",length)
        vsp.SetParmVal(fuse_id,"Diameter","Design",width)
        vsp.SetParmVal(fuse_id,"XLocPercent","XSec_1",x1)
        vsp.SetParmVal(fuse_id,"XLocPercent","XSec_2",x2)
        vsp.SetParmVal(fuse_id,"XLocPercent","XSec_3",x3)
        vsp.SetParmVal(fuse_id,"ZLocPercent","XSec_4",tail_z_pos)
        vsp.SetParmVal(fuse_id, "Ellipse_Width", "XSecCurve_1", width)
        vsp.SetParmVal(fuse_id, "Ellipse_Width", "XSecCurve_2", width)
        vsp.SetParmVal(fuse_id, "Ellipse_Width", "XSecCurve_3", width)
        vsp.SetParmVal(fuse_id, "Ellipse_Height", "XSecCurve_1", height1);
        vsp.SetParmVal(fuse_id, "Ellipse_Height", "XSecCurve_2", height2);
        vsp.SetParmVal(fuse_id, "Ellipse_Height", "XSecCurve_3", height3);  
    else:
        # OpenVSP vals do not exist:
        vals                   = Data()
        vals.nose              = Data()
        vals.tail              = Data()
        vals.tail.top          = Data()
        
        vals.nose.z_pos        = 0.0
        vals.tail.top.angle    = 0.0
        vals.tail.top.strength = 0.0
        
        if len(np.unique(x_poses)) != len(x_poses):
            raise ValueError('Duplicate fuselage section positions detected.')
        vsp.SetParmVal(fuse_id,"Length","Design",length)
        if num_segs != 5: # reduce to only nose and tail
            vsp.CutXSec(fuse_id,1) # remove extra default section
            vsp.CutXSec(fuse_id,1) # remove extra default section
            vsp.CutXSec(fuse_id,1) # remove extra default section
            for i in range(num_segs-2): # add back the required number of sections
                vsp.InsertXSec(fuse_id, 0, vsp.XS_ELLIPSE)           
                vsp.Update()
        for i in range(num_segs-2):
            # Bunch sections to allow proper length settings in the next step
            # This is necessary because OpenVSP will not move a section past an adjacent section
            vsp.SetParmVal(fuse_id, "XLocPercent", "XSec_"+str(i+1),1e-6*(i+1))
            vsp.Update()
        if x_poses[1] < (num_segs-2)*1e-6:
            print('Warning: Second fuselage section is too close to the nose. OpenVSP model may not be accurate.')
        for i in reversed(range(num_segs-2)):
            # order is reversed because sections are initially bunched in the front and cannot be extended passed the next
            vsp.SetParmVal(fuse_id, "XLocPercent", "XSec_"+str(i+1),x_poses[i+1])
            vsp.SetParmVal(fuse_id, "ZLocPercent", "XSec_"+str(i+1),z_poses[i+1])
            vsp.SetParmVal(fuse_id, "Ellipse_Width", "XSecCurve_"+str(i+1), widths[i+1])
            vsp.SetParmVal(fuse_id, "Ellipse_Height", "XSecCurve_"+str(i+1), heights[i+1])   
            vsp.Update()             
            set_section_angles(i, vals.nose.z_pos, tail_z_pos, x_poses, z_poses, heights, widths,length,end_ind,fuse_id)            
            
        vsp.SetParmVal(fuse_id, "XLocPercent", "XSec_"+str(0),x_poses[0])
        vsp.SetParmVal(fuse_id, "ZLocPercent", "XSec_"+str(0),z_poses[0])
        vsp.SetParmVal(fuse_id, "XLocPercent", "XSec_"+str(end_ind),x_poses[-1])
        vsp.SetParmVal(fuse_id, "ZLocPercent", "XSec_"+str(end_ind),z_poses[-1])    
        
        # Tail
        if heights[-1] > 0.:
            stdout = vsp.cvar.cstdout
            errorMgr = vsp.ErrorMgrSingleton_getInstance()
            errorMgr.PopErrorAndPrint(stdout)
            
            pos = len(heights)-1
            vsp.InsertXSec(fuse_id, pos-1, vsp.XS_ELLIPSE)
            vsp.Update()
            vsp.SetParmVal(fuse_id, "Ellipse_Width", "XSecCurve_"+str(pos), widths[-1])
            vsp.SetParmVal(fuse_id, "Ellipse_Height", "XSecCurve_"+str(pos), heights[-1])
            vsp.SetParmVal(fuse_id, "XLocPercent", "XSec_"+str(pos),x_poses[-1])
            vsp.SetParmVal(fuse_id, "ZLocPercent", "XSec_"+str(pos),z_poses[-1])              
            
            xsecsurf = vsp.GetXSecSurf(fuse_id,0)
            vsp.ChangeXSecShape(xsecsurf,pos+1,vsp.XS_POINT)
            vsp.Update()           
            vsp.SetParmVal(fuse_id, "XLocPercent", "XSec_"+str(pos+1),x_poses[-1])
            vsp.SetParmVal(fuse_id, "ZLocPercent", "XSec_"+str(pos+1),z_poses[-1])     
            
            # update strengths to make end flat
            vsp.SetParmVal(fuse_id,"TopRStrength","XSec_"+str(pos), 0.)
            vsp.SetParmVal(fuse_id,"RightRStrength","XSec_"+str(pos), 0.)
            vsp.SetParmVal(fuse_id,"BottomRStrength","XSec_"+str(pos), 0.)
            vsp.SetParmVal(fuse_id,"TopLStrength","XSec_"+str(pos+1), 0.)
            vsp.SetParmVal(fuse_id,"RightLStrength","XSec_"+str(pos+1), 0.)            
        
        else:
            vsp.SetParmVal(fuse_id,"TopLAngle","XSec_"+str(end_ind),vals.tail.top.angle)
            vsp.SetParmVal(fuse_id,"TopLStrength","XSec_"+str(end_ind),vals.tail.top.strength)
            vsp.SetParmVal(fuse_id,"AllSym","XSec_"+str(end_ind),1)
            vsp.Update()
            
            
        if 'z_pos' in vals.tail:
            tail_z_pos = vals.tail.z_pos
        else:
            pass # use above default         
    
    if 'Fuel_Tanks' in fuselage:
        for tank in fuselage.Fuel_Tanks:
            write_fuselage_conformal_fuel_tank(fuse_id, tank, fuel_tank_set_ind)    
            
    vsp.SetSetFlag(fuse_id, OML_set_ind, True)
                
    return area_tags
示例#5
0
def write_vsp_wing(wing, area_tags, fuel_tank_set_ind, OML_set_ind):
    """This write a given wing into OpenVSP format
    
    Assumptions:
    If wing segments are defined, they must cover the full span.
    (may work in some other cases, but functionality will not be maintained)

    Source:
    N/A

    Inputs:
    wing.
      origin                                  [m] in all three dimensions
      spans.projected                         [m]
      chords.root                             [m]
      chords.tip                              [m]
      sweeps.quarter_chord                    [radians]
      twists.root                             [radians]
      twists.tip                              [radians]
      thickness_to_chord                      [-]
      dihedral                                [radians]
      tag                                     <string>
      Segments.*. (optional)
        twist                                 [radians]
        percent_span_location                 [-]  .1 is 10%
        root_chord_percent                    [-]  .1 is 10%
        dihedral_outboard                     [radians]
        sweeps.quarter_chord                  [radians]
        thickness_to_chord                    [-]
    area_tags                                 <dict> used to keep track of all tags needed in wetted area computation           
    fuel_tank_set_index                       <int> OpenVSP object set containing the fuel tanks    

    Outputs:
    area_tags                                 <dict> used to keep track of all tags needed in wetted area computation           
    wing_id                                   <str>  OpenVSP ID for given wing

    Properties Used:
    N/A
    """       
    wing_x = wing.origin[0][0]    
    wing_y = wing.origin[0][1]
    wing_z = wing.origin[0][2]
    if wing.symmetric == True:
        span   = wing.spans.projected/2. # span of one side
    else:
        span   = wing.spans.projected
    root_chord = wing.chords.root
    tip_chord  = wing.chords.tip
    sweep      = wing.sweeps.quarter_chord / Units.deg
    sweep_loc  = 0.25
    root_twist = wing.twists.root / Units.deg
    tip_twist  = wing.twists.tip  / Units.deg
    root_tc    = wing.thickness_to_chord 
    tip_tc     = wing.thickness_to_chord 
    dihedral   = wing.dihedral / Units.deg

    # Check to see if segments are defined. Get count
    if len(wing.Segments.keys())>0:
        n_segments = len(wing.Segments.keys())
    else:
        n_segments = 0

    # Create the wing
    wing_id = vsp.AddGeom( "WING" )
    vsp.SetGeomName(wing_id, wing.tag)
    area_tags[wing.tag] = ['wings',wing.tag]

    # Make names for each section and insert them into the wing if necessary
    x_secs       = []
    x_sec_curves = []
    # n_segments + 2 will create an extra segment if the root segment is 
    # included in the list of segments. This is not used and the tag is
    # removed when the segments are checked for this case.
    for i_segs in range(0,n_segments+2):
        x_secs.append('XSec_' + str(i_segs))
        x_sec_curves.append('XSecCurve_' + str(i_segs))

    # Apply the basic characteristics of the wing to root and tip
    if wing.symmetric == False:
        vsp.SetParmVal( wing_id,'Sym_Planar_Flag','Sym',0)
    if wing.vertical == True:
        vsp.SetParmVal( wing_id,'X_Rel_Rotation','XForm',90)
        dihedral = -dihedral # check for vertical tail, direction reverses from SUAVE/AVL

    vsp.SetParmVal( wing_id,'X_Rel_Location','XForm',wing_x)
    vsp.SetParmVal( wing_id,'Y_Rel_Location','XForm',wing_y)
    vsp.SetParmVal( wing_id,'Z_Rel_Location','XForm',wing_z)

    # This ensures that the other VSP parameters are driven properly
    vsp.SetDriverGroup( wing_id, 1, vsp.SPAN_WSECT_DRIVER, vsp.ROOTC_WSECT_DRIVER, vsp.TIPC_WSECT_DRIVER )

    # Root chord
    vsp.SetParmVal( wing_id,'Root_Chord',x_secs[1],root_chord)

    # Sweep of the first section
    vsp.SetParmVal( wing_id,'Sweep',x_secs[1],sweep)
    vsp.SetParmVal( wing_id,'Sweep_Location',x_secs[1],sweep_loc)

    # Twists
    if n_segments != 0:
        if np.isclose(wing.Segments[0].percent_span_location,0.):
            vsp.SetParmVal( wing_id,'Twist',x_secs[0],wing.Segments[0].twist / Units.deg) # root
        else:
            vsp.SetParmVal( wing_id,'Twist',x_secs[0],root_twist) # root
        # The tips should write themselves
    else:
        vsp.SetParmVal( wing_id,'Twist',x_secs[0],root_twist) # root
        vsp.SetParmVal( wing_id,'Twist',x_secs[1],tip_twist) # tip


    # Figure out if there is an airfoil provided

    # Airfoils should be in Lednicer format
    # i.e. :
    #
    #EXAMPLE AIRFOIL
    # 3. 3. 
    #
    # 0.0 0.0
    # 0.5 0.1
    # 1.0 0.0
    #
    # 0.0 0.0
    # 0.5 -0.1
    # 1.0 0.0

    # Note this will fail silently if airfoil is not in correct format
    # check geometry output
    
    airfoil_vsp_types = []
    if n_segments > 0:
        for i in range(n_segments): 
            if 'airfoil_type' in wing.Segments[i].keys():
                if wing.Segments[i].airfoil_type == 'biconvex': 
                    airfoil_vsp_types.append(vsp.XS_BICONVEX)
                else:
                    airfoil_vsp_types.append(vsp.XS_FILE_AIRFOIL)
            else:
                airfoil_vsp_types.append(vsp.XS_FILE_AIRFOIL)
    elif 'airfoil_type' in wing.keys():
        if wing.airfoil_type == 'biconvex': 
            airfoil_vsp_types.append(vsp.XS_BICONVEX)
        else:
            airfoil_vsp_types.append(vsp.XS_FILE_AIRFOIL)        
    else:
        airfoil_vsp_types = [vsp.XS_FILE_AIRFOIL]    

    if n_segments==0:
        if len(wing.Airfoil) != 0 or 'airfoil_type' in wing.keys():
            xsecsurf = vsp.GetXSecSurf(wing_id,0)
            vsp.ChangeXSecShape(xsecsurf,0,airfoil_vsp_types[0])
            vsp.ChangeXSecShape(xsecsurf,1,airfoil_vsp_types[0])
            if len(wing.Airfoil) != 0:
                xsec1 = vsp.GetXSec(xsecsurf,0)
                xsec2 = vsp.GetXSec(xsecsurf,1)
                vsp.ReadFileAirfoil(xsec1,wing.Airfoil['airfoil'].coordinate_file)
                vsp.ReadFileAirfoil(xsec2,wing.Airfoil['airfoil'].coordinate_file)
            vsp.Update()
    else:
        if len(wing.Segments[0].Airfoil) != 0 or 'airfoil_type' in wing.Segments[0].keys():
            xsecsurf = vsp.GetXSecSurf(wing_id,0)
            vsp.ChangeXSecShape(xsecsurf,0,airfoil_vsp_types[0])
            vsp.ChangeXSecShape(xsecsurf,1,airfoil_vsp_types[0])
            if len(wing.Segments[0].Airfoil) != 0:
                xsec1 = vsp.GetXSec(xsecsurf,0)
                xsec2 = vsp.GetXSec(xsecsurf,1)
                vsp.ReadFileAirfoil(xsec1,wing.Segments[0].Airfoil['airfoil'].coordinate_file)
                vsp.ReadFileAirfoil(xsec2,wing.Segments[0].Airfoil['airfoil'].coordinate_file)
            vsp.Update()              

    # Thickness to chords
    vsp.SetParmVal( wing_id,'ThickChord','XSecCurve_0',root_tc)
    vsp.SetParmVal( wing_id,'ThickChord','XSecCurve_1',tip_tc)

    # Dihedral
    vsp.SetParmVal( wing_id,'Dihedral',x_secs[1],dihedral)

    # Span and tip of the section
    if n_segments>1:
        local_span    = span*wing.Segments[0].percent_span_location  
        sec_tip_chord = root_chord*wing.Segments[0].root_chord_percent
        vsp.SetParmVal( wing_id,'Span',x_secs[1],local_span) 
        vsp.SetParmVal( wing_id,'Tip_Chord',x_secs[1],sec_tip_chord)
    else:
        vsp.SetParmVal( wing_id,'Span',x_secs[1],span/np.cos(dihedral*Units.degrees)) 

    vsp.Update()

    if n_segments>0:
        if wing.Segments[0].percent_span_location==0.:
            x_secs[-1] = [] # remove extra section tag (for clarity)
            segment_0_is_root_flag = True
            adjust = 0 # used for indexing
        else:
            segment_0_is_root_flag = False
            adjust = 1
    else:
        adjust = 1


    # Loop for the number of segments left over
    for i_segs in range(1,n_segments+1):  

        if (wing.Segments[i_segs-1] == wing.Segments[-1]) and (wing.Segments[-1].percent_span_location == 1.):
            break

        # Unpack
        dihedral_i = wing.Segments[i_segs-1].dihedral_outboard / Units.deg
        chord_i    = root_chord*wing.Segments[i_segs-1].root_chord_percent
        try:
            twist_i    = wing.Segments[i_segs].twist / Units.deg
            no_twist_flag = False
        except:
            no_twist_flag = True
        sweep_i    = wing.Segments[i_segs-1].sweeps.quarter_chord / Units.deg
        tc_i       = wing.Segments[i_segs-1].thickness_to_chord

        # Calculate the local span
        if i_segs == n_segments:
            span_i = span*(1 - wing.Segments[i_segs-1].percent_span_location)/np.cos(dihedral_i*Units.deg)
        else:
            span_i = span*(wing.Segments[i_segs].percent_span_location-wing.Segments[i_segs-1].percent_span_location)/np.cos(dihedral_i*Units.deg)                      

        # Insert the new wing section with specified airfoil if available
        if len(wing.Segments[i_segs-1].Airfoil) != 0 or 'airfoil_type' in wing.Segments[i_segs-1].keys():
            vsp.InsertXSec(wing_id,i_segs-1+adjust,airfoil_vsp_types[i_segs-1])
            if len(wing.Segments[i_segs-1].Airfoil) != 0:
                xsecsurf = vsp.GetXSecSurf(wing_id,0)
                xsec = vsp.GetXSec(xsecsurf,i_segs+adjust)
                vsp.ReadFileAirfoil(xsec, wing.Segments[i_segs-1].Airfoil['airfoil'].coordinate_file)                
        else:
            vsp.InsertXSec(wing_id,i_segs-1+adjust,vsp.XS_FOUR_SERIES)

        # Set the parms
        vsp.SetParmVal( wing_id,'Span',x_secs[i_segs+adjust],span_i)
        vsp.SetParmVal( wing_id,'Dihedral',x_secs[i_segs+adjust],dihedral_i)
        vsp.SetParmVal( wing_id,'Sweep',x_secs[i_segs+adjust],sweep_i)
        vsp.SetParmVal( wing_id,'Sweep_Location',x_secs[i_segs+adjust],sweep_loc)      
        vsp.SetParmVal( wing_id,'Root_Chord',x_secs[i_segs+adjust],chord_i)
        if not no_twist_flag:
            vsp.SetParmVal( wing_id,'Twist',x_secs[i_segs+adjust],twist_i)
        vsp.SetParmVal( wing_id,'ThickChord',x_sec_curves[i_segs+adjust],tc_i)

        if adjust and (i_segs == 1):
            vsp.Update()
            vsp.SetParmVal( wing_id,'Twist',x_secs[1],wing.Segments[i_segs-1].twist / Units.deg)

        vsp.Update()

    if (n_segments != 0) and (wing.Segments[-1].percent_span_location == 1.):
        tip_chord = root_chord*wing.Segments[-1].root_chord_percent
        vsp.SetParmVal( wing_id,'Tip_Chord',x_secs[n_segments-1+adjust],tip_chord)
        vsp.SetParmVal( wing_id,'ThickChord',x_sec_curves[n_segments-1+adjust],wing.Segments[-1].thickness_to_chord)
        # twist is set in the normal loop
    else:
        vsp.SetParmVal( wing_id,'Tip_Chord',x_secs[-1-(1-adjust)],tip_chord)
        vsp.SetParmVal( wing_id,'Twist',x_secs[-1-(1-adjust)],tip_twist)
        # a single trapezoidal wing is assumed to have constant thickness to chord
    vsp.Update()
    vsp.SetParmVal(wing_id,'CapUMaxOption','EndCap',2.)
    vsp.SetParmVal(wing_id,'CapUMaxStrength','EndCap',1.)

    vsp.Update() # to fix problems with chords not matching up
    
    if 'Fuel_Tanks' in wing:
        for tank in wing.Fuel_Tanks:
            write_wing_conformal_fuel_tank(wing, wing_id, tank, fuel_tank_set_ind)
            
    vsp.SetSetFlag(wing_id, OML_set_ind, True)
    
    return area_tags, wing_id
def vsp_read_fuselage(fuselage_id, units_type='SI', fineness=True):
    """This reads an OpenVSP fuselage geometry and writes it to a SUAVE fuselage format.

	Assumptions:
	1. OpenVSP fuselage is "conventionally shaped" (generally narrow at nose and tail, wider in center). 
	2. Fuselage is designed in VSP as it appears in real life. That is, the VSP model does not rely on
	   superficial elements such as canopies, stacks, or additional fuselages to cover up internal lofting oddities.
	3. This program will NOT account for multiple geometries comprising the fuselage. For example: a wingbox mounted beneath
	   is a separate geometry and will NOT be processed.
	4. Fuselage origin is located at nose. VSP file origin can be located anywhere, preferably at the forward tip
	   of the vehicle or in front (to make all X-coordinates of vehicle positive).
	5. Written for OpenVSP 3.16.1
	
	Source:
	N/A

	Inputs:
	0. Pre-loaded VSP vehicle in memory, via vsp_read.
	1. VSP 10-digit geom ID for fuselage.
	2. Units_type set to 'SI' (default) or 'Imperial'.
	3. Boolean for whether or not to compute fuselage finenesses (default = True).
	4. Uses exterior function get_vsp_areas, in SUAVE/trunk/SUAVE/Input_Output/OpenVSP.
	
	Outputs:
	Writes SUAVE fuselage, with these geometries:           (all defaults are SI, but user may specify Imperial)

		Fuselages.Fuselage.			
			origin                                  [m] in all three dimensions
			width                                   [m]
			lengths.
			  total                                 [m]
			  nose                                  [m]
			  tail                                  [m]
			heights.
			  maximum                               [m]
			  at_quarter_length                     [m]
			  at_three_quarters_length              [m]
			effective_diameter                      [m]
			fineness.nose                           [-] ratio of nose section length to fuselage effective diameter
			fineness.tail                           [-] ratio of tail section length to fuselage effective diameter
			areas.wetted                            [m^2]
			tag                                     <string>
			segment[].   (segments are in ordered container and callable by number)
			  vsp.shape                               [point,circle,round_rect,general_fuse,fuse_file]
			  vsp.xsec_id                             <10 digit string>
			  percent_x_location
			  percent_z_location
			  height
			  width
			  length
			  effective_diameter
			  tag
			vsp.xsec_num                              <integer of fuselage segment quantity>
			vsp.xsec_surf_id                          <10 digit string>

	Properties Used:
	N/A
	"""
    fuselage = SUAVE.Components.Fuselages.Fuselage()

    if units_type == 'SI':
        units_factor = Units.meter * 1.
    else:
        units_factor = Units.foot * 1.

    if vsp.GetGeomName(fuselage_id):
        fuselage.tag = vsp.GetGeomName(fuselage_id)
    else:
        fuselage.tag = 'FuselageGeom'

    fuselage.origin[0][0] = vsp.GetParmVal(fuselage_id, 'X_Location',
                                           'XForm') * units_factor
    fuselage.origin[0][1] = vsp.GetParmVal(fuselage_id, 'Y_Location',
                                           'XForm') * units_factor
    fuselage.origin[0][2] = vsp.GetParmVal(fuselage_id, 'Z_Location',
                                           'XForm') * units_factor

    fuselage.lengths.total = vsp.GetParmVal(fuselage_id, 'Length',
                                            'Design') * units_factor
    fuselage.vsp_data.xsec_surf_id = vsp.GetXSecSurf(
        fuselage_id, 0)  # There is only one XSecSurf in geom.
    fuselage.vsp_data.xsec_num = vsp.GetNumXSec(
        fuselage.vsp_data.xsec_surf_id)  # Number of xsecs in fuselage.

    x_locs = []
    heights = []
    widths = []
    eff_diams = []
    lengths = []

    # -----------------
    # Fuselage segments
    # -----------------

    for ii in range(0, fuselage.vsp_data.xsec_num):
        segment = SUAVE.Components.Fuselages.Segment()
        segment.vsp_data.xsec_id = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id,
                                               ii)  # VSP XSec ID.
        segment.tag = 'segment_' + str(ii)
        segment.percent_x_location = vsp.GetParmVal(
            fuselage_id, 'XLocPercent',
            'XSec_' + str(ii))  # Along fuselage length.
        segment.percent_z_location = vsp.GetParmVal(
            fuselage_id, 'ZLocPercent',
            'XSec_' + str(ii))  # Vertical deviation of fuselage center.
        segment.height = vsp.GetXSecHeight(
            segment.vsp_data.xsec_id) * units_factor
        segment.width = vsp.GetXSecWidth(
            segment.vsp_data.xsec_id) * units_factor
        segment.effective_diameter = (segment.height + segment.width) / 2.

        x_locs.append(segment.percent_x_location
                      )  # Save into arrays for later computation.
        heights.append(segment.height)
        widths.append(segment.width)
        eff_diams.append(segment.effective_diameter)

        if ii != (
                fuselage.vsp_data.xsec_num - 1
        ):  # Segment length: stored as length since previous segment. (First segment will have length 0.0.)
            segment.length = fuselage.lengths.total * (
                fuselage.Segments[ii + 1].percent_x_location -
                segment.percent_x_location) * units_factor
        else:
            segment.length = 0.0
        lengths.append(segment.length)

        shape = vsp.GetXSecShape(segment.vsp_data.xsec_id)
        shape_dict = {
            0: 'point',
            1: 'circle',
            2: 'ellipse',
            3: 'super ellipse',
            4: 'rounded rectangle',
            5: 'general fuse',
            6: 'fuse file'
        }
        segment.vsp_data.shape = shape_dict[shape]

        fuselage.Segments.append(segment)

    fuselage.heights.at_quarter_length = get_fuselage_height(
        fuselage, .25)  # Calls get_fuselage_height function (below).
    fuselage.heights.at_three_quarters_length = get_fuselage_height(
        fuselage, .75)
    fuselage.heights.at_wing_root_quarter_chord = get_fuselage_height(
        fuselage, .4)

    fuselage.heights.maximum = max(heights)  # Max segment height.
    fuselage.width = max(widths)  # Max segment width.
    fuselage.effective_diameter = max(eff_diams)  # Max segment effective diam.

    fuselage.areas.front_projected = np.pi * (
        (fuselage.effective_diameter) / 2)**2

    eff_diam_gradients_fwd = np.array(eff_diams[1:]) - np.array(
        eff_diams[:-1])  # Compute gradients of segment effective diameters.
    eff_diam_gradients_fwd = np.multiply(eff_diam_gradients_fwd, lengths[:-1])

    fuselage = compute_fuselage_fineness(fuselage, x_locs, eff_diams,
                                         eff_diam_gradients_fwd)

    return fuselage
示例#7
0
def read_vsp_wing(wing_id, units_type='SI',write_airfoil_file=True): 	
    """This reads an OpenVSP wing vehicle geometry and writes it into a SUAVE wing format.

    Assumptions:
    1. OpenVSP wing is divided into segments ("XSecs" in VSP).
    2. Written for OpenVSP 3.21.1

    Source:
    N/A

    Inputs:
    1. VSP 10-digit geom ID for wing.
    2. units_type set to 'SI' (default) or 'Imperial'.

    Outputs:
    Writes SUAVE wing object, with these geometries, from VSP:
    	Wings.Wing.    (* is all keys)
    		origin                                  [m] in all three dimensions
    		spans.projected                         [m]
    		chords.root                             [m]
    		chords.tip                              [m]
    		aspect_ratio                            [-]
    		sweeps.quarter_chord                    [radians]
    		twists.root                             [radians]
    		twists.tip                              [radians]
    		thickness_to_chord                      [-]
    		dihedral                                [radians]
    		symmetric                               <boolean>
    		tag                                     <string>
    		areas.reference                         [m^2]
    		areas.wetted                            [m^2]
    		Segments.
    		  tag                                   <string>
    		  twist                                 [radians]
    		  percent_span_location                 [-]  .1 is 10%
    		  root_chord_percent                    [-]  .1 is 10%
    		  dihedral_outboard                     [radians]
    		  sweeps.quarter_chord                  [radians]
    		  thickness_to_chord                    [-]
    		  airfoil                               <NACA 4-series, 6 series, or airfoil file>

    Properties Used:
    N/A
    """  

    # Check if this is vertical tail, this seems like a weird first step but it's necessary
    # Get the initial rotation to get the dihedral angles
    x_rot = vsp.GetParmVal( wing_id,'X_Rotation','XForm')		
    if  x_rot >=70:
        wing = SUAVE.Components.Wings.Vertical_Tail()
        wing.vertical = True
        x_rot = (90-x_rot) * Units.deg
    else:
        # Instantiate a wing
        wing = SUAVE.Components.Wings.Wing()	
        x_rot =  x_rot  * Units.deg	

    # Set the units
    if units_type == 'SI':
        units_factor = Units.meter * 1.
    elif units_type == 'imperial':
        units_factor = Units.foot * 1.
    elif units_type == 'inches':
        units_factor = Units.inch * 1.		

    # Apply a tag to the wing
    if vsp.GetGeomName(wing_id):
        tag = vsp.GetGeomName(wing_id)
        tag = tag.translate(t_table)
        wing.tag = tag
    else: 
        wing.tag = 'winggeom'
    
    scaling           = vsp.GetParmVal(wing_id, 'Scale', 'XForm')  
    units_factor      = units_factor*scaling
        
    # Top level wing parameters
    # Wing origin
    wing.origin[0][0] = vsp.GetParmVal(wing_id, 'X_Location', 'XForm') * units_factor 
    wing.origin[0][1] = vsp.GetParmVal(wing_id, 'Y_Location', 'XForm') * units_factor 
    wing.origin[0][2] = vsp.GetParmVal(wing_id, 'Z_Location', 'XForm') * units_factor 

    # Wing Symmetry
    sym_planar = vsp.GetParmVal(wing_id, 'Sym_Planar_Flag', 'Sym')
    sym_origin = vsp.GetParmVal(wing_id, 'Sym_Ancestor_Origin_Flag', 'Sym')

    # Check for symmetry
    if sym_planar == 2. and sym_origin == 1.: #origin at wing, not vehicle
        wing.symmetric = True	
    else:
        wing.symmetric = False 

    #More top level parameters
    total_proj_span      = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') * units_factor
    wing.aspect_ratio    = vsp.GetParmVal(wing_id, 'TotalAR', 'WingGeom')
    wing.areas.reference = vsp.GetParmVal(wing_id, 'TotalArea', 'WingGeom') * units_factor**2 
    wing.spans.projected = total_proj_span 

    # Check if this is a single segment wing
    xsec_surf_id      = vsp.GetXSecSurf(wing_id, 0)   # This is how VSP stores surfaces.
    x_sec_1           = vsp.GetXSec(xsec_surf_id, 1) 

    if vsp.GetNumXSec(xsec_surf_id) == 2:
        single_seg = True
    else:
        single_seg = False
    
    segment_num = vsp.GetNumXSec(xsec_surf_id) # Get number of segments

    span_sum         = 0.				# Non-projected.
    proj_span_sum    = 0.				# Projected.
    segment_spans    = [None] * (segment_num) 	        # Non-projected.
    segment_dihedral = [None] * (segment_num)
    segment_sweeps_quarter_chord = [None] * (segment_num) 

    # Necessary wing segment definitions start at XSec_1 (XSec_0 exists mainly to hold the root airfoil)
    xsec_surf_id = vsp.GetXSecSurf(wing_id, 0)
    x_sec = vsp.GetXSec(xsec_surf_id, 1)
    chord_parm = vsp.GetXSecParm(x_sec,'Root_Chord')
    root_chord = vsp.GetParmVal(chord_parm) * units_factor

    # -------------
    # Wing segments
    # -------------

    if single_seg == False:

        # Convert VSP XSecs to SUAVE segments. (Wing segments are defined by outboard sections in VSP, but inboard sections in SUAVE.) 
        for i in range(1, segment_num+1):	
            # XSec airfoil
            jj = i-1  # Airfoil index i-1 because VSP airfoils and sections are one index off relative to SUAVE.
		
            segment = SUAVE.Components.Wings.Segment()
            segment.tag                   = 'Section_' + str(i)
            thick_cord                    = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(jj))
            segment.thickness_to_chord    = thick_cord	# Thick_cord stored for use in airfoil, below.		
            if i!=segment_num:
                segment_root_chord    = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(i)) * units_factor
            else:
                segment_root_chord    = 0.0
            segment.root_chord_percent    = segment_root_chord / root_chord		
            segment.percent_span_location = proj_span_sum / (total_proj_span/(1+wing.symmetric))
            segment.twist                 = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(jj)) * Units.deg

            if i==1:
                wing.thickness_to_chord = thick_cord

            if i < segment_num:      # This excludes the tip xsec, but we need a segment in SUAVE to store airfoil.
                sweep     = vsp.GetParmVal(wing_id, 'Sweep', 'XSec_' + str(i)) * Units.deg
                sweep_loc = vsp.GetParmVal(wing_id, 'Sweep_Location', 'XSec_' + str(i))
                AR        = 2*vsp.GetParmVal(wing_id, 'Aspect', 'XSec_' + str(i))
                taper     = vsp.GetParmVal(wing_id, 'Taper', 'XSec_' + str(i))

                segment_sweeps_quarter_chord[i] = convert_sweep(sweep,sweep_loc,0.25,AR,taper)
                segment.sweeps.quarter_chord    = segment_sweeps_quarter_chord[i]  # Used again, below

                # Used for dihedral computation, below.
                segment_dihedral[i]	      = vsp.GetParmVal(wing_id, 'Dihedral', 'XSec_' + str(i)) * Units.deg  + x_rot
                segment.dihedral_outboard     = segment_dihedral[i]

                segment_spans[i] 	      = vsp.GetParmVal(wing_id, 'Span', 'XSec_' + str(i)) * units_factor
                proj_span_sum += segment_spans[i] * np.cos(segment_dihedral[i])	
                span_sum      += segment_spans[i]
            else:
                segment.root_chord_percent    = (vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(i-1))) * units_factor /root_chord


            xsec_id = str(vsp.GetXSec(xsec_surf_id, jj))
            airfoil = Airfoil()
            if vsp.GetXSecShape(xsec_id) == vsp.XS_FOUR_SERIES: 	# XSec shape: NACA 4-series
                camber = vsp.GetParmVal(wing_id, 'Camber', 'XSecCurve_' + str(jj)) 

                if camber == 0.:
                    camber_loc = 0.
                else:
                    camber_loc = vsp.GetParmVal(wing_id, 'CamberLoc', 'XSecCurve_' + str(jj))

                airfoil.thickness_to_chord = thick_cord
                camber_round               = int(np.around(camber*100))
                camber_loc_round           = int(np.around(camber_loc*10)) 
                thick_cord_round           = int(np.around(thick_cord*100))
                airfoil.tag                = 'NACA ' + str(camber_round) + str(camber_loc_round) + str(thick_cord_round)	

            elif vsp.GetXSecShape(xsec_id) == vsp.XS_SIX_SERIES: 	# XSec shape: NACA 6-series
                thick_cord_round = int(np.around(thick_cord*100))
                a_value          = vsp.GetParmVal(wing_id, 'A', 'XSecCurve_' + str(jj))
                ideal_CL         = int(np.around(vsp.GetParmVal(wing_id, 'IdealCl', 'XSecCurve_' + str(jj))*10))
                series_vsp       = int(vsp.GetParmVal(wing_id, 'Series', 'XSecCurve_' + str(jj)))
                series_dict      = {0:'63',1:'64',2:'65',3:'66',4:'67',5:'63A',6:'64A',7:'65A'} # VSP series values.
                series           = series_dict[series_vsp]
                airfoil.tag      = 'NACA ' + series + str(ideal_CL) + str(thick_cord_round) + ' a=' + str(np.around(a_value,1))			


            elif vsp.GetXSecShape(xsec_id) == vsp.XS_FILE_AIRFOIL:	# XSec shape: 12 is type AF_FILE
                airfoil.thickness_to_chord = thick_cord
                # VSP airfoil API calls get coordinates and write files with the final argument being the fraction of segment position, regardless of relative spans. 
                # (Write the root airfoil with final arg = 0. Write 4th airfoil of 5 segments with final arg = .8)

            if write_airfoil_file==True:
                vsp.WriteSeligAirfoil(str(wing.tag) + '_airfoil_XSec_' + str(jj) +'.dat', wing_id, float(jj/segment_num))
                airfoil.coordinate_file    = str(wing.tag) + '_airfoil_XSec_' + str(jj) +'.dat'
                airfoil.tag                = 'airfoil'	

                segment.append_airfoil(airfoil)

            wing.Segments.append(segment)

        # Wing dihedral 
        proj_span_sum_alt = 0.
        span_sum_alt      = 0.
        sweeps_sum        = 0.			

        for ii in range(1, segment_num):
            span_sum_alt += segment_spans[ii]
            proj_span_sum_alt += segment_spans[ii] * np.cos(segment_dihedral[ii])  # Use projected span to find total wing dihedral.
            sweeps_sum += segment_spans[ii] * np.tan(segment_sweeps_quarter_chord[ii])	

        wing.dihedral              = np.arccos(proj_span_sum_alt / span_sum_alt) 
        wing.sweeps.quarter_chord  = -np.arctan(sweeps_sum / span_sum_alt)  # Minus sign makes it positive sweep.

        # Add a tip segment, all values are zero except the tip chord
        tc = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(segment_num-1)) * units_factor

        # Chords
        wing.chords.root              = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_0') * units_factor
        wing.chords.tip               = tc
        wing.chords.mean_geometric    = wing.areas.reference / wing.spans.projected

        # Just double calculate and fix things:
        wing = wing_segmented_planform(wing)


    else:
        # Single segment

        # Get ID's
        x_sec_1_dih_parm       = vsp.GetXSecParm(x_sec_1,'Dihedral')
        x_sec_1_sweep_parm     = vsp.GetXSecParm(x_sec_1,'Sweep')
        x_sec_1_sweep_loc_parm = vsp.GetXSecParm(x_sec_1,'Sweep_Location')
        x_sec_1_taper_parm     = vsp.GetXSecParm(x_sec_1,'Taper')
        x_sec_1_rc_parm        = vsp.GetXSecParm(x_sec_1,'Root_Chord')
        x_sec_1_tc_parm        = vsp.GetXSecParm(x_sec_1,'Tip_Chord')
        x_sec_1_t_parm        = vsp.GetXSecParm(x_sec_1,'ThickChord')
     
        # Calcs
        sweep     = vsp.GetParmVal(x_sec_1_sweep_parm) * Units.deg
        sweep_loc = vsp.GetParmVal(x_sec_1_sweep_loc_parm)
        taper     = vsp.GetParmVal(x_sec_1_taper_parm)
        c_4_sweep = convert_sweep(sweep,sweep_loc,0.25,wing.aspect_ratio,taper)		

        # Pull and pack
        wing.sweeps.quarter_chord  = c_4_sweep
        wing.taper                 = taper
        wing.dihedral              = vsp.GetParmVal(x_sec_1_dih_parm) * Units.deg + x_rot
        wing.chords.root           = vsp.GetParmVal(x_sec_1_rc_parm)* units_factor
        wing.chords.tip            = vsp.GetParmVal(x_sec_1_tc_parm) * units_factor	
        wing.chords.mean_geometric = wing.areas.reference / wing.spans.projected
        wing.thickness_to_chord    = vsp.GetParmVal(x_sec_1_t_parm) 

        # Just double calculate and fix things:
        wing = wing_planform(wing)		


    # Twists
    wing.twists.root      = vsp.GetParmVal(wing_id, 'Twist', 'XSec_0') * Units.deg
    wing.twists.tip       = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(segment_num-1)) * Units.deg

    # check if control surface (sub surfaces) are defined
    tags                 = []
    LE_flags             = []
    span_fraction_starts = []
    span_fraction_ends   = []
    chord_fractions      = []
    
    num_cs = vsp.GetNumSubSurf(wing_id)
    
    # loop through wing and get all control surface parameters 
    for cs_idx in range(num_cs):
        cs_id   = vsp.GetSubSurf(wing_id,cs_idx)
        param_names = vsp.GetSubSurfParmIDs(cs_id)
        tags.append(vsp.GetSubSurfName(cs_id))
        for p_idx in range(len(param_names)):
            if 'LE_Flag' == vsp.GetParmName(param_names[p_idx]):
                LE_flags.append(vsp.GetParmVal(param_names[p_idx]))
            if 'UStart' == vsp.GetParmName(param_names[p_idx]):
                span_fraction_starts.append(vsp.GetParmVal(param_names[p_idx]))
            if 'UEnd' == vsp.GetParmName(param_names[p_idx]):
                span_fraction_ends.append(vsp.GetParmVal(param_names[p_idx]))
            if 'Length_C_Start' == vsp.GetParmName(param_names[p_idx]):
                chord_fractions.append(vsp.GetParmVal(param_names[p_idx]))
                
    # assign control surface parameters to wings. Outer most control surface on main/horizontal wing is assigned a aileron
    for cs_idx in range(num_cs):   
        aileron_present = False
        if num_cs > 1:
            aileron_loc = np.argmax(np.array(span_fraction_starts))   
            if cs_idx == aileron_loc: 
                aileron_present = True
        if LE_flags[cs_idx] == 1.0:
            CS = SUAVE.Components.Wings.Control_Surfaces.Slat()
        else:
            if wing.vertical == True:
                CS = SUAVE.Components.Wings.Control_Surfaces.Rudder()
            else:
                if aileron_present:
                    CS = SUAVE.Components.Wings.Control_Surfaces.Aileron()
                else: 
                    CS = SUAVE.Components.Wings.Control_Surfaces.Flap()
        CS.tag                 = tags[cs_idx]
        CS.span_fraction_start = span_fraction_starts[cs_idx]*3 - 1
        CS.span_fraction_end   = span_fraction_ends[cs_idx]*3 - 1
        CS.chord_fraction      = chord_fractions[cs_idx]
        CS.span                = (CS.span_fraction_end - CS.span_fraction_start)*wing.spans.projected
        wing.append_control_surface(CS)
    
    return wing
示例#8
0
def write_vsp_nacelle(nacelle, OML_set_ind):
    """This converts nacelles into OpenVSP format.
    
    Assumptions: 
    1. If nacelle segments are defined, geometry written to OpenVSP is of type "StackGeom". 
       1.a  This type of nacelle can be either set as flow through or not flow through.
       1.b  Segments are defined in a similar manner to fuselage segments. See geometric 
            documentation in SUAVE-Components-Nacelles-Nacelle
    
    2. If nacelle segments are not defined, geometry written to OpenVSP is of type "BodyofRevolution".
       2.a This type of nacelle can be either set as flow through or not flow through.
       2.b BodyofRevolution can be either be a 4 digit airfoil (type string) or super ellipse (default)
    Source:
    N/A
    Inputs: 
      nacelle.
      origin                              [m] in all three dimension, should have as many origins as engines 
      length                              [m]
      diameter                            [m]
      flow_through                        <boolean> if True create a flow through nacelle, if False create a cylinder
      segment(optional).
         width                            [m]
         height                           [m]
         lenght                           [m]
         percent_x_location               [m]     
         percent_y_location               [m]        
         percent_z_location               [m] 
       
    Outputs:
    Operates on the active OpenVSP model, no direct output
    Properties Used:
    N/A
    """
    # default tesselation
    radial_tesselation = 21
    axial_tesselation = 25

    # True will create a flow-through subsonic nacelle (which may have dimensional errors)
    # False will create a cylindrical stack (essentially a cylinder)
    ft_flag = nacelle.flow_through
    length = nacelle.length
    height = nacelle.diameter - nacelle.inlet_diameter
    diameter = nacelle.diameter - height / 2
    nac_tag = nacelle.tag
    nac_x = nacelle.origin[0][0]
    nac_y = nacelle.origin[0][1]
    nac_z = nacelle.origin[0][2]
    nac_x_rotation = nacelle.orientation_euler_angles[0] / Units.degrees
    nac_y_rotation = nacelle.orientation_euler_angles[1] / Units.degrees
    nac_z_rotation = nacelle.orientation_euler_angles[2] / Units.degrees
    num_segs = len(nacelle.Segments)

    if num_segs > 0:
        if nacelle.Airfoil.naca_4_series_airfoil != None:
            raise AssertionError(
                'Nacelle segments defined. Airfoil section will not be used.')
        nac_id = vsp.AddGeom("STACK")
        vsp.SetGeomName(nac_id, nac_tag)

        # set nacelle relative location and rotation
        vsp.SetParmVal(nac_id, 'Abs_Or_Relitive_flag', 'XForm', vsp.ABS)
        vsp.SetParmVal(nac_id, 'X_Rotation', 'XForm', nac_x_rotation)
        vsp.SetParmVal(nac_id, 'Y_Rotation', 'XForm', nac_y_rotation)
        vsp.SetParmVal(nac_id, 'Z_Rotation', 'XForm', nac_z_rotation)
        vsp.SetParmVal(nac_id, 'X_Location', 'XForm', nac_x)
        vsp.SetParmVal(nac_id, 'Y_Location', 'XForm', nac_y)
        vsp.SetParmVal(nac_id, 'Z_Location', 'XForm', nac_z)
        vsp.SetParmVal(nac_id, 'Tess_U', 'Shape', radial_tesselation)
        vsp.SetParmVal(nac_id, 'Tess_W', 'Shape', axial_tesselation)

        widths = []
        heights = []
        x_delta = []
        x_poses = []
        z_delta = []

        segs = nacelle.Segments
        for seg in range(num_segs):
            widths.append(segs[seg].width)
            heights.append(segs[seg].height)
            x_poses.append(segs[seg].percent_x_location)
            if seg == 0:
                x_delta.append(0)
                z_delta.append(0)
            else:
                x_delta.append(length * (segs[seg].percent_x_location -
                                         segs[seg - 1].percent_x_location))
                z_delta.append(length * (segs[seg].percent_z_location -
                                         segs[seg - 1].percent_z_location))

        vsp.CutXSec(nac_id, 4)  # remove point section at end
        vsp.CutXSec(nac_id, 0)  # remove point section at beginning
        vsp.CutXSec(nac_id, 1)  # remove point section at beginning
        for _ in range(num_segs -
                       2):  # add back the required number of sections
            vsp.InsertXSec(nac_id, 1, vsp.XS_ELLIPSE)
            vsp.Update()
        xsec_surf = vsp.GetXSecSurf(nac_id, 0)
        for i3 in reversed(range(num_segs)):
            xsec = vsp.GetXSec(xsec_surf, i3)
            if i3 == 0:
                pass
            else:
                vsp.SetParmVal(nac_id, "XDelta", "XSec_" + str(i3),
                               x_delta[i3])
                vsp.SetParmVal(nac_id, "ZDelta", "XSec_" + str(i3),
                               z_delta[i3])
            vsp.SetXSecWidthHeight(xsec, widths[i3], heights[i3])
            vsp.SetXSecTanAngles(xsec, vsp.XSEC_BOTH_SIDES, 0, 0, 0, 0)
            vsp.SetXSecTanSlews(xsec, vsp.XSEC_BOTH_SIDES, 0, 0, 0, 0)
            vsp.SetXSecTanStrengths(xsec, vsp.XSEC_BOTH_SIDES, 0, 0, 0, 0)
            vsp.Update()

        if ft_flag:
            pass
        else:
            # append front point
            xsecsurf = vsp.GetXSecSurf(nac_id, 0)
            vsp.ChangeXSecShape(xsecsurf, 0, vsp.XS_POINT)
            vsp.Update()
            xsecsurf = vsp.GetXSecSurf(nac_id, 0)
            vsp.ChangeXSecShape(xsecsurf, num_segs - 1, vsp.XS_POINT)
            vsp.Update()

    else:
        nac_id = vsp.AddGeom("BODYOFREVOLUTION")
        vsp.SetGeomName(nac_id, nac_tag)

        # Origin
        vsp.SetParmVal(nac_id, 'Abs_Or_Relitive_flag', 'XForm', vsp.ABS)
        vsp.SetParmVal(nac_id, 'X_Rotation', 'XForm', nac_x_rotation)
        vsp.SetParmVal(nac_id, 'Y_Rotation', 'XForm', nac_y_rotation)
        vsp.SetParmVal(nac_id, 'Z_Rotation', 'XForm', nac_z_rotation)
        vsp.SetParmVal(nac_id, 'X_Location', 'XForm', nac_x)
        vsp.SetParmVal(nac_id, 'Y_Location', 'XForm', nac_y)
        vsp.SetParmVal(nac_id, 'Z_Location', 'XForm', nac_z)
        vsp.SetParmVal(nac_id, 'Tess_U', 'Shape', radial_tesselation)
        vsp.SetParmVal(nac_id, 'Tess_W', 'Shape', axial_tesselation)

        # Length and overall diameter
        vsp.SetParmVal(nac_id, "Diameter", "Design", diameter)
        if ft_flag:
            vsp.SetParmVal(nac_id, "Mode", "Design", 0.0)
        else:
            vsp.SetParmVal(nac_id, "Mode", "Design", 1.0)

        if nacelle.Airfoil.naca_4_series_airfoil != None:
            if isinstance(
                    nacelle.Airfoil.naca_4_series_airfoil,
                    str) and len(nacelle.Airfoil.naca_4_series_airfoil) != 4:
                raise AssertionError(
                    'Nacelle cowling airfoil must be of type < string > and length < 4 >'
                )
            else:
                angle = nacelle.cowling_airfoil_angle / Units.degrees
                camber = float(nacelle.Airfoil.naca_4_series_airfoil[0]) / 100
                camber_loc = float(
                    nacelle.Airfoil.naca_4_series_airfoil[1]) / 10
                thickness = float(
                    nacelle.Airfoil.naca_4_series_airfoil[2:]) / 100

                vsp.ChangeBORXSecShape(nac_id, vsp.XS_FOUR_SERIES)
                vsp.Update()
                vsp.SetParmVal(nac_id, "Diameter", "Design", diameter)
                vsp.SetParmVal(nac_id, "Angle", "Design", angle)
                vsp.SetParmVal(nac_id, "Chord", "XSecCurve", length)
                vsp.SetParmVal(nac_id, "ThickChord", "XSecCurve", thickness)
                vsp.SetParmVal(nac_id, "Camber", "XSecCurve", camber)
                vsp.SetParmVal(nac_id, "CamberLoc", "XSecCurve", camber_loc)
                vsp.Update()
        else:
            vsp.ChangeBORXSecShape(nac_id, vsp.XS_SUPER_ELLIPSE)
            vsp.Update()
            if ft_flag:
                vsp.SetParmVal(nac_id, "Super_Height", "XSecCurve", height)
                vsp.SetParmVal(nac_id, "Diameter", "Design", diameter)
            else:
                vsp.SetParmVal(nac_id, "Super_Height", "XSecCurve", diameter)
            vsp.SetParmVal(nac_id, "Super_Width", "XSecCurve", length)
            vsp.SetParmVal(nac_id, "Super_MaxWidthLoc", "XSecCurve", 0.)
            vsp.SetParmVal(nac_id, "Super_M", "XSecCurve", 2.)
            vsp.SetParmVal(nac_id, "Super_N", "XSecCurve", 1.)

    vsp.SetSetFlag(nac_id, OML_set_ind, True)

    vsp.Update()
    return
示例#9
0
def read_vsp_nacelle(nacelle_id, vsp_nacelle_type, units_type='SI'):
    """This reads an OpenVSP stack geometry or body of revolution and writes it to a SUAVE nacelle format.
    If an airfoil is defined in body-of-revolution, its coordinates are not read in due to absence of
    API functions in VSP.

    Assumptions: 
    
    Source:
    N/A

    Inputs:
    0. Pre-loaded VSP vehicle in memory, via vsp_read.
    1. VSP 10-digit geom ID for nacelle.
    2. Units_type set to 'SI' (default) or 'Imperial'. 

    Outputs:
    Writes SUAVE nacelle, with these geometries:           (all defaults are SI, but user may specify Imperial)

        Nacelles.Nacelle.	
            origin                  [m] in all three dimensions
            width                   [m]
            lengths                 [m]
            heights                 [m]
            tag                     <string>
            segment[].   (segments are in ordered container and callable by number) 
              percent_x_location    [unitless]
              percent_z_location    [unitless]
              height                [m]
              width                 [m]

    Properties Used:
    N/A
    """
    nacelle = SUAVE.Components.Nacelles.Nacelle()

    if units_type == 'SI':
        units_factor = Units.meter * 1.
    elif units_type == 'imperial':
        units_factor = Units.foot * 1.
    elif units_type == 'inches':
        units_factor = Units.inch * 1.

    if vsp.GetGeomName(nacelle_id):
        nacelle.tag = vsp.GetGeomName(nacelle_id)
    else:
        nacelle.tag = 'NacelleGeom'

    nacelle.origin[0][0] = vsp.GetParmVal(nacelle_id, 'X_Location',
                                          'XForm') * units_factor
    nacelle.origin[0][1] = vsp.GetParmVal(nacelle_id, 'Y_Location',
                                          'XForm') * units_factor
    nacelle.origin[0][2] = vsp.GetParmVal(nacelle_id, 'Z_Location',
                                          'XForm') * units_factor
    nacelle.x_rotation = vsp.GetParmVal(nacelle_id, 'X_Rotation',
                                        'XForm') * units_factor
    nacelle.y_rotation = vsp.GetParmVal(nacelle_id, 'Y_Rotation',
                                        'XForm') * units_factor
    nacelle.z_rotation = vsp.GetParmVal(nacelle_id, 'Z_Rotation',
                                        'XForm') * units_factor

    if vsp_nacelle_type == 'Stack':

        xsec_surf_id = vsp.GetXSecSurf(
            nacelle_id, 0)  # There is only one XSecSurf in geom.
        num_segs = vsp.GetNumXSec(xsec_surf_id)  # Number of xsecs in nacelle.
        abs_x_location = 0
        abs_y_location = 0
        abs_z_location = 0
        abs_x_location_vec = []
        abs_y_location_vec = []
        abs_z_location_vec = []

        for i in range(num_segs):
            # Create the segment
            xsec_id = vsp.GetXSec(xsec_surf_id, i)  # VSP XSec ID.
            segment = SUAVE.Components.Lofted_Body_Segment.Segment()
            segment.tag = 'segment_' + str(i)

            # Pull out Parms that will be needed
            X_Loc_P = vsp.GetXSecParm(xsec_id, 'XDelta')
            Y_Loc_P = vsp.GetXSecParm(xsec_id, 'YDelta')
            Z_Loc_P = vsp.GetXSecParm(xsec_id, 'XDelta')

            del_x = vsp.GetParmVal(X_Loc_P)
            del_y = vsp.GetParmVal(Y_Loc_P)
            del_z = vsp.GetParmVal(Z_Loc_P)

            abs_x_location = abs_x_location + del_x
            abs_y_location = abs_y_location + del_y
            abs_z_location = abs_z_location + del_z

            abs_x_location_vec.append(abs_x_location)
            abs_y_location_vec.append(abs_y_location)
            abs_z_location_vec.append(abs_z_location)

            shape = vsp.GetXSecShape(xsec_id)
            shape_dict = {
                0: 'point',
                1: 'circle',
                2: 'ellipse',
                3: 'super ellipse',
                4: 'rounded rectangle',
                5: 'general fuse',
                6: 'fuse file'
            }

            if shape_dict[shape] == 'point':
                segment.height = 0.0
                segment.width = 0.0
                if i == 0:
                    nacelle.flow_through = False
            else:
                segment.height = vsp.GetXSecHeight(xsec_id) * units_factor
                segment.width = vsp.GetXSecWidth(xsec_id) * units_factor
                if i == 0:
                    nacelle.flow_through = True

            nacelle.Segments.append(segment)

        nacelle.length = abs_x_location_vec[-1]
        segs = nacelle.Segments
        for seg in range(num_segs):
            segs[seg].percent_x_location = np.array(
                abs_x_location_vec) / abs_x_location_vec[-1]
            segs[seg].percent_y_location = np.array(
                abs_y_location_vec) / abs_x_location_vec[-1]
            segs[seg].percent_z_location = np.array(
                abs_z_location_vec) / abs_x_location_vec[-1]

    elif vsp_nacelle_type == 'BodyOfRevolution':
        diameter = vsp.GetParmVal(nacelle_id, "Diameter",
                                  "Design") * units_factor
        angle = vsp.GetParmVal(nacelle_id, "Diameter",
                               "Design") * Units.degrees
        ft_flag_idx = vsp.GetParmVal(nacelle_id, "Mode", "Design")
        if ft_flag_idx == 0.0:
            ft_flag = True
        else:
            ft_flag = False
        nacelle.flow_through = ft_flag

        shape = vsp.GetBORXSecShape(nacelle_id)
        shape_dict = {0:'point',1:'circle',2:'ellipse',3:'super ellipse',4:'rounded rectangle',5:'general fuse',6:'fuse file',\
                      7:'four series',8:'six series',9:'biconvex',10:'wedge',11:'editcurve',12:'file airfoil'}
        if shape_dict[shape] == 'four series':
            naf = SUAVE.Components.Airfoils.Airfoil()
            length = vsp.GetParmVal(nacelle_id, "Chord", "XSecCurve")
            thickness = int(
                round(
                    vsp.GetParmVal(nacelle_id, "ThickChord", "XSecCurve") * 10,
                    0))
            camber = int(
                round(
                    vsp.GetParmVal(nacelle_id, "Camber", "XSecCurve") * 100,
                    0))
            camber_loc = int(
                round(
                    vsp.GetParmVal(nacelle_id, "CamberLoc", "XSecCurve") * 10,
                    0))

            airfoil = str(camber) + str(camber_loc) + str(thickness)
            height = thickness
            naf.naca_4_series_airfoil = str(airfoil)
            naf.thickness_to_chord = thickness
            nacelle.append_airfoil(naf)

        elif shape_dict[shape] == 'super ellipse':
            if ft_flag:
                height = vsp.GetParmVal(nacelle_id, "Super_Height",
                                        "XSecCurve")
                diameter = vsp.GetParmVal(nacelle_id, "Diameter", "Design")
                length = vsp.GetParmVal(nacelle_id, "Super_Width", "XSecCurve")
            else:
                diameter = vsp.GetParmVal(nacelle_id, "Super_Height",
                                          "XSecCurve")
                length = vsp.GetParmVal(nacelle_id, "Super_Width", "XSecCurve")
                height = diameter / 2

        elif shape_dict[shape] == 'file airfoil':
            naf = SUAVE.Components.Airfoils.Airfoil()
            thickness_to_chord = vsp.GetParmVal(nacelle_id, "ThickChord",
                                                "XSecCurve") * units_factor
            length = vsp.GetParmVal(nacelle_id, "Chord",
                                    "XSecCurve") * units_factor
            height = thickness_to_chord * length * units_factor
            if ft_flag:
                diameter = vsp.GetParmVal(nacelle_id, "Diameter",
                                          "Design") * units_factor
            else:
                diameter = 0
            naf.thickness_to_chord = thickness_to_chord
            nacelle.append_airfoil(naf)

        nacelle.length = length
        nacelle.diameter = diameter + height / 2
        nacelle.inlet_diameter = nacelle.diameter - height
        nacelle.cowling_airfoil_angle = angle

    return nacelle