def get_fuel_tank_properties(vehicle, tag, fuel_tank_set_index=3, slices_for_calculation=100): """This function computes the center of gravity, total possible fuel mass, the available volume of each fuel tank in the vehicle through a mass properties computation in OpenVSP. Assumptions: Fuel tanks exists in the fuselage and wings only All fuel tanks have unique names Source: N/A Inputs: vehicle.fuselages.*.Fuel_Tanks.*.tag [-] vehicle.wings.*.Fuel_Tanks.*.tag [-] Outputs: vehicle.fuselages.*.Fuel_Tanks.*.mass_properties. center_of_gravity [m] fuel_mass_when_full [kg] fuel_volume_when_full [m^3] vehicle.wings.*.Fuel_Tanks.*.mass_properties. center_of_gravity [m] fuel_mass_when_full [kg] fuel_volume_when_full [m^3] Properties Used: N/A """ # Reset OpenVSP to avoid including a previous vehicle vsp.ClearVSPModel() vsp.ReadVSPFile(tag + '.vsp3') # Extract fuel tanks from vehicle fuel_tanks = get_fuel_tanks(vehicle) num_slices = slices_for_calculation # Slices used to estimate mass distribution from areas in OpenVSP mass_props_output_file = tag + '_mass_props.txt' vsp.SetComputationFileName(vsp.MASS_PROP_TXT_TYPE, mass_props_output_file) print('Computing Fuel Tank Mass Properties... ') vsp.ComputeMassProps(fuel_tank_set_index, num_slices) print('Done') # Extract full tank mass properties from OpenVSP output file fo = open(mass_props_output_file) for line in fo: prop_list = line.split() try: if prop_list[0] in fuel_tanks: # Indices based on position in OpenVSP output (may change in the future) cg_x = float(prop_list[2]) cg_y = float(prop_list[3]) cg_z = float(prop_list[4]) mass = float(prop_list[1]) vol = float(prop_list[-1]) if 'center_of_gravity' not in fuel_tanks[prop_list[ 0]]: # assumes at most two identical tank names fuel_tanks[prop_list[0]].center_of_gravity = np.array( [cg_x, cg_y, cg_z]) fuel_tanks[prop_list[0]].fuel_mass_when_full = mass fuel_tanks[prop_list[0]].volume = vol else: fuel_tanks[prop_list[0]].center_of_gravity = \ (fuel_tanks[prop_list[0]].center_of_gravity+np.array([cg_x,cg_y,cg_z]))/2. fuel_tanks[prop_list[0]].fuel_mass_when_full += mass fuel_tanks[prop_list[0]].volume += vol except IndexError: # in case line is empty pass # Apply fuel tank properties to the vehicle vehicle = apply_properties(vehicle, fuel_tanks) return vehicle
def vsp_read(tag, units_type='SI'): """This reads an OpenVSP vehicle geometry and writes it into a SUAVE vehicle format. Includes wings, fuselages, and propellers. Assumptions: 1. OpenVSP vehicle is composed of conventionally shaped fuselages, wings, and propellers. 1a. OpenVSP fuselage: generally narrow at nose and tail, wider in center). 1b. 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. 1c. 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. 2. 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). 3. Written for OpenVSP 3.16.1 Source: N/A Inputs: 1. A tag for an XML file in format .vsp3. 2. Units_type set to 'SI' (default) or 'Imperial' Outputs: Writes SUAVE vehicle with these geometries from VSP: (All values default to SI. Any other 2nd argument outputs Imperial.) 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> 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> Propellers.Propeller. location[X,Y,Z] [radians] rotation[X,Y,Z] [radians] prop_attributes.tip_radius [m] prop_attributes.hub_radius [m] thrust_angle [radians] Properties Used: N/A """ vsp.ClearVSPModel() vsp.ReadVSPFile(tag) vsp_fuselages = [] vsp_wings = [] vsp_props = [] vsp_geoms = vsp.FindGeoms() geom_names = [] vehicle = SUAVE.Vehicle() vehicle.tag = tag if units_type == 'SI': units_type = 'SI' else: units_type = 'Imperial' # The two for-loops below are in anticipation of an OpenVSP API update with a call for GETGEOMTYPE. # This print function allows user to enter VSP GeomID manually as first argument in vsp_read functions. print("VSP geometry IDs: ") # Label each geom type by storing its VSP geom ID. (The API call for GETGEOMTYPE was not released as of 8/9/18, v 3.16.1) for geom in vsp_geoms: geom_name = vsp.GetGeomName(geom) geom_names.append(geom_name) print(str(geom_name) + ': ' + geom) # ----------------------------- # MANUAL VSP ENTRY & PROCESSING # ----------------------------- #fuselage = read_vsp_fuselage(fuselage_id, units_type=units_type) # Replace fuselage_id manually. #vehicle.append_component(fuselage) #wing = read_vsp_wing(wing_id, units_type=units_type) # Replace wing_id manually. #vehicle.append_component(wing) #prop = read_vsp_prop(prop_id, units_type=units_type) # Replace prop_id manually. #vehicle.append_component(prop) # -------------------------------- # AUTOMATIC VSP ENTRY & PROCESSING # -------------------------------- #for geom in vsp_geoms: #if vsp.GETGEOMTYPE(str(geom)) == 'FUSELAGE': #vsp_fuselages.append(geom) #if vsp.GETGEOMTYPE(str(geom)) == 'WING': #vsp_wings.append(geom) #if vsp.GETGEOMTYPE(str(geom)) == 'PROP': #vsp_props.append(geom) # Read VSP geoms and store in SUAVE components. #for vsp_fuselage in vsp_fuselages: #fuselage_id = vsp_fuselages[vsp_fuselage] #fuselage = read_vsp_fuselage(fuselage_id, units_type) #vehicle.append_component(fuselage) #for vsp_wing in vsp_wings: #wing_id = vsp_wings[vsp_wing] #wing = read_vsp_wing(wing_id, units_type) #vehicle.append_component(wing) #for vsp_prop in vsp_props: #prop_id = vsp_props[vsp_prop] #prop = read_vsp_prop(prop_id, units_type) #vehicle.append_component(prop) return vehicle
def write_vsp_mesh(geometry, tag, half_mesh_flag, growth_ratio, growth_limiting_flag): """This create an .stl surface mesh based on a vehicle stored in a .vsp3 file. Assumptions: None Source: N/A Inputs: geometry. - Also passed to set_sources wings.main_wing.chords.mean_aerodynamic [m] half_mesh_flag <boolean> determines if a symmetry plane is created growth_ratio [-] growth ratio for the mesh growth_limiting_flag <boolean> determines if 3D growth limiting is used Outputs: <tag>.stl Properties Used: N/A """ # Reset OpenVSP to avoid including a previous vehicle vsp.ClearVSPModel() # Turn on symmetry plane splitting to improve robustness of meshing process if half_mesh_flag == True: f = fileinput.input(tag + '.vsp3', inplace=1) for line in f: if 'SymmetrySplitting' in line: print line[0:34] + '1' + line[35:-1] else: print line vsp.ReadVSPFile(tag + '.vsp3') # Set output file types and what will be meshed file_type = vsp.CFD_STL_TYPE + vsp.CFD_KEY_TYPE set_int = vsp.SET_ALL vsp.SetComputationFileName(vsp.CFD_STL_TYPE, tag + '.stl') vsp.SetComputationFileName(vsp.CFD_KEY_TYPE, tag + '.key') # Set to create a tagged STL mesh file vehicle_cont = vsp.FindContainer('Vehicle', 0) STL_multi = vsp.FindParm(vehicle_cont, 'MultiSolid', 'STLSettings') vsp.SetParmVal(STL_multi, 1.0) vsp.SetCFDMeshVal(vsp.CFD_FAR_FIELD_FLAG, 1) if half_mesh_flag == True: vsp.SetCFDMeshVal(vsp.CFD_HALF_MESH_FLAG, 1) # Figure out the size of the bounding box vehicle_id = vsp.FindContainersWithName('Vehicle')[0] xlen = vsp.GetParmVal(vsp.FindParm(vehicle_id, "X_Len", "BBox")) ylen = vsp.GetParmVal(vsp.FindParm(vehicle_id, "Y_Len", "BBox")) zlen = vsp.GetParmVal(vsp.FindParm(vehicle_id, "Z_Len", "BBox")) # Max length max_len = np.max([xlen, ylen, zlen]) far_length = 10. * max_len vsp.SetCFDMeshVal(vsp.CFD_FAR_SIZE_ABS_FLAG, 1) vsp.SetCFDMeshVal(vsp.CFD_FAR_LENGTH, far_length) vsp.SetCFDMeshVal(vsp.CFD_FAR_WIDTH, far_length) vsp.SetCFDMeshVal(vsp.CFD_FAR_HEIGHT, far_length) vsp.SetCFDMeshVal(vsp.CFD_FAR_MAX_EDGE_LEN, max_len) vsp.SetCFDMeshVal(vsp.CFD_GROWTH_RATIO, growth_ratio) if growth_limiting_flag == True: vsp.SetCFDMeshVal(vsp.CFD_LIMIT_GROWTH_FLAG, 1.0) # Set the max edge length so we have on average 50 elements per chord length MAC = geometry.wings.main_wing.chords.mean_aerodynamic min_len = MAC / 50. vsp.SetCFDMeshVal(vsp.CFD_MAX_EDGE_LEN, min_len) # vsp.AddDefaultSources() set_sources(geometry) vsp.Update() vsp.WriteVSPFile(tag + '_premesh.vsp3') print 'Starting mesh for ' + tag + ' (This may take several minutes)' ti = time.time() vsp.ComputeCFDMesh(set_int, file_type) tf = time.time() dt = tf - ti print 'VSP meshing for ' + tag + ' completed in ' + str(dt) + ' s'
def write(vehicle, tag): # Reset OpenVSP to avoid including a previous vehicle try: vsp.ClearVSPModel() except NameError: print 'VSP import failed' return -1 area_tags = dict() # for wetted area assignment # ------------- # Wings # ------------- for wing in vehicle.wings: wing_x = wing.origin[0] wing_y = wing.origin[1] wing_z = wing.origin[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 xrange(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) 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 vsp.SetParmVal(wing_id, 'Twist', x_secs[0], tip_twist) # tip vsp.SetParmVal(wing_id, 'Twist', x_secs[0], root_twist) # root # 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 if n_segments == 0: if len(wing.Airfoil) != 0: xsecsurf = vsp.GetXSecSurf(wing_id, 0) vsp.ChangeXSecShape(xsecsurf, 0, vsp.XS_FILE_AIRFOIL) vsp.ChangeXSecShape(xsecsurf, 1, vsp.XS_FILE_AIRFOIL) 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: # The wing airfoil is still used for the root segment if the first added segment does not begin there # This could be combined with above, but is left here for clarity if (len(wing.Airfoil) != 0) and (wing.Segments[0].percent_span_location != 0.): xsecsurf = vsp.GetXSecSurf(wing_id, 0) vsp.ChangeXSecShape(xsecsurf, 0, vsp.XS_FILE_AIRFOIL) vsp.ChangeXSecShape(xsecsurf, 1, vsp.XS_FILE_AIRFOIL) 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() elif len(wing.Segments[0].Airfoil) != 0: xsecsurf = vsp.GetXSecSurf(wing_id, 0) vsp.ChangeXSecShape(xsecsurf, 0, vsp.XS_FILE_AIRFOIL) vsp.ChangeXSecShape(xsecsurf, 1, vsp.XS_FILE_AIRFOIL) 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) 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 xrange(1, n_segments + 1): # Unpack dihedral_i = wing.Segments[i_segs - 1].dihedral_outboard / Units.deg chord_i = root_chord * wing.Segments[i_segs - 1].root_chord_percent twist_i = wing.Segments[i_segs - 1].twist / Units.deg sweep_i = wing.Segments[i_segs - 1].sweeps.quarter_chord / Units.deg # 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: vsp.InsertXSec(wing_id, i_segs - 1 + adjust, vsp.XS_FILE_AIRFOIL) 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) vsp.SetParmVal(wing_id, 'Twist', x_secs[i_segs + adjust], twist_i) vsp.SetParmVal(wing_id, 'ThickChord', x_sec_curves[i_segs + adjust], tip_tc) vsp.Update() vsp.SetParmVal(wing_id, 'Tip_Chord', x_secs[-1 - (1 - adjust)], tip_chord) 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 wing.tag == 'main_wing': main_wing_id = wing_id ## Skeleton code for props and pylons can be found in previous commits (~Dec 2016) if desired ## This was a place to start and may not still be functional # ------------- # Engines # ------------- if vehicle.propulsors.has_key('turbofan'): print 'Warning: no meshing sources are currently implemented for the nacelle' # Unpack turbofan = vehicle.propulsors.turbofan n_engines = turbofan.number_of_engines length = turbofan.engine_length width = turbofan.nacelle_diameter origins = turbofan.origin bpr = turbofan.bypass_ratio for ii in xrange(0, int(n_engines)): origin = origins[ii] x = origin[0] y = origin[1] z = origin[2] nac_id = vsp.AddGeom("FUSELAGE") vsp.SetGeomName(nac_id, 'turbofan') # Length and overall diameter vsp.SetParmVal(nac_id, "Length", "Design", length) vsp.SetParmVal(nac_id, 'Abs_Or_Relitive_flag', 'XForm', vsp.ABS) vsp.SetParmVal(nac_id, 'OrderPolicy', 'Design', 1.) 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, 'Origin', 'XForm', 0.5) vsp.SetParmVal(nac_id, 'Z_Rotation', 'XForm', 180.) xsecsurf = vsp.GetXSecSurf(nac_id, 0) vsp.ChangeXSecShape(xsecsurf, 0, vsp.XS_ELLIPSE) vsp.Update() vsp.SetParmVal(nac_id, "Ellipse_Width", "XSecCurve_0", width - .2) vsp.SetParmVal(nac_id, "Ellipse_Width", "XSecCurve_1", width) vsp.SetParmVal(nac_id, "Ellipse_Width", "XSecCurve_2", width) vsp.SetParmVal(nac_id, "Ellipse_Width", "XSecCurve_3", width) vsp.SetParmVal(nac_id, "Ellipse_Height", "XSecCurve_0", width - .2) vsp.SetParmVal(nac_id, "Ellipse_Height", "XSecCurve_1", width) vsp.SetParmVal(nac_id, "Ellipse_Height", "XSecCurve_2", width) vsp.SetParmVal(nac_id, "Ellipse_Height", "XSecCurve_3", width) vsp.Update() # ------------- # Fuselage # ------------- if vehicle.fuselages.has_key('fuselage'): # Unpack fuselage = vehicle.fuselages.fuselage width = fuselage.width length = fuselage.lengths.total 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 w_ac = wing.aerodynamic_center w_origin = vehicle.wings.main_wing.origin w_c_4 = vehicle.wings.main_wing.chords.root / 4. # 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] + w_c_4) / length x3 = 1 - t_fine * width / length fuse_id = vsp.AddGeom("FUSELAGE") vsp.SetGeomName(fuse_id, fuselage.tag) area_tags[fuselage.tag] = ['fuselages', fuselage.tag] if fuselage.has_key('OpenVSP_values'): vals = fuselage.OpenVSP_values # 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) # Tail vsp.SetParmVal(fuse_id, "TopLAngle", "XSec_4", vals.tail.top.angle) vsp.SetParmVal(fuse_id, "TopLStrength", "XSec_4", vals.tail.top.strength) # 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 vals.tail.has_key('z_pos'): tail_z_pos = vals.tail.z_pos else: tail_z_pos = 0.02 vsp.SetParmVal(fuse_id, "AllSym", "XSec_4", 1) 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) # Write the vehicle to the file vsp.WriteVSPFile(tag + ".vsp3") return area_tags