Source code for RCAIDE.Framework.External_Interfaces.OpenVSP.vsp_nacelle

# RCAIDE/Framework/External_Interfaces/OpenVSP/vsp_nacelle.py

# Created:  Sep 2021, M. Clarke

# ----------------------------------------------------------------------------------------------------------------------
#  IMPORT
# ----------------------------------------------------------------------------------------------------------------------  
# RCAIDE imports 

import RCAIDE
from RCAIDE.Framework.Core import Units, Data 
import numpy as np
try:
    import vsp as vsp
except ImportError:
    try:
        import openvsp as vsp
    except ImportError:
        # This allows RCAIDE to build without OpenVSP
        pass
    
# ---------------------------------------------------------------------------------------------------------------------- 
#  vsp_nacelle  
# ---------------------------------------------------------------------------------------------------------------------- 
[docs] 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 RCAIDE-Library-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 if type(nacelle) == RCAIDE.Library.Components.Nacelles.Stack_Nacelle: num_segs = len(nacelle.segments) 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 segment_list = list(nacelle.segments.keys()) for seg in range(num_segs): widths.append(segs[segment_list[seg]].width) heights.append(segs[segment_list[seg]].height) x_poses.append(segs[segment_list[seg]].percent_x_location) if seg == 0: x_delta.append(0) z_delta.append(0) else: x_delta.append(length*(segs[segment_list[seg]].percent_x_location - segs[segment_list[seg-1]].percent_x_location)) z_delta.append(length*(segs[segment_list[seg]].percent_z_location - segs[segment_list[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() vsp.SetSetFlag(nac_id, OML_set_ind, True) vsp.Update() elif type(nacelle) == RCAIDE.Library.Components.Nacelles.Body_of_Revolution_Nacelle: 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 != None: airfoil = nacelle.airfoil if type(airfoil) == RCAIDE.Library.Components.Airfoils.NACA_4_Series_Airfoil: angle = nacelle.cowling_airfoil_angle/Units.degrees camber = float(airfoil.NACA_4_Series_code[0])/100 camber_loc = float(airfoil.NACA_4_Series_code[1])/10 thickness = float(airfoil.NACA_4_Series_code[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() # TO DO: ADD MORE AIRFOIL SECTIONS 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() else: pass return
# ---------------------------------------------------------------------------------------------------------------------- # read_vsp_nacelle # ----------------------------------------------------------------------------------------------------------------------
[docs] 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 RCAIDE 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 import_vsp_vehicle. 1. VSP 10-digit geom ID for nacelle. 2. Units_type set to 'SI' (default) or 'Imperial'. Outputs: Writes RCAIDE 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 """ 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_nacelle_type == 'Stack': nacelle = RCAIDE.Library.Components.Nacelles.Stack_Nacelle() 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 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 = [] diameter = 0 for i in range(num_segs): # Create the segment xsec_id = vsp.GetXSec(xsec_surf_id, i) # VSP XSec ID. segment = RCAIDE.Library.Components.Fuselages.Segments.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, 'ZDelta') 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 diameter = np.max([np.sqrt(segment.height**2 + segment.width**2),diameter]) nacelle.segments.append(segment) nacelle.length = abs_x_location_vec[-1] * units_factor nacelle.diameter = diameter segs = nacelle.segments segment_list = list(nacelle.segments.keys()) for seg in range(num_segs): segs[segment_list[seg]].percent_x_location = np.array(abs_x_location_vec[seg])/abs_x_location_vec[-1] segs[segment_list[seg]].percent_y_location = np.array(abs_y_location_vec[seg])/abs_x_location_vec[-1] segs[segment_list[seg]].percent_z_location = np.array(abs_z_location_vec[seg])/abs_x_location_vec[-1] elif vsp_nacelle_type =='BodyOfRevolution': nacelle = RCAIDE.Library.Components.Nacelles.Body_of_Revolution_Nacelle() 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 diameter = vsp.GetParmVal(nacelle_id, "Diameter","Design") * units_factor angle = vsp.GetParmVal(nacelle_id, "Angle","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 = RCAIDE.Library.Components.Airfoils.NACA_4_Series_Airfoil() length = vsp.GetParmVal(nacelle_id, "Chord", "XSecCurve") * units_factor 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 = '{0:02d}'.format(camber) + str(camber_loc) + str(thickness) height = (thickness /10 ) *length naf.NACA_4_Series_code = 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") * units_factor diameter = vsp.GetParmVal(nacelle_id, "Diameter","Design") * units_factor length = vsp.GetParmVal(nacelle_id, "Super_Width", "XSecCurve") * units_factor else: diameter = vsp.GetParmVal(nacelle_id, "Super_Height", "XSecCurve") * units_factor length = vsp.GetParmVal(nacelle_id, "Super_Width", "XSecCurve") * units_factor height = diameter/2 elif shape_dict[shape] == 'file airfoil': naf = RCAIDE.Library.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 nacelle.inlet_diameter = diameter - height nacelle.cowling_airfoil_angle = angle return nacelle