From 6033766c35c4d7afd821f5fddfda28a48aa3be74 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Mon, 2 Aug 2021 15:03:16 +0300 Subject: [PATCH 01/58] initial commit --- aerosandbox/tools/openvsp/vsp_read.py | 173 ++++++++++ .../tools/openvsp/vsp_read_fuselage.py | 196 +++++++++++ aerosandbox/tools/openvsp/vsp_read_wing.py | 321 ++++++++++++++++++ 3 files changed, 690 insertions(+) create mode 100644 aerosandbox/tools/openvsp/vsp_read.py create mode 100644 aerosandbox/tools/openvsp/vsp_read_fuselage.py create mode 100644 aerosandbox/tools/openvsp/vsp_read_wing.py diff --git a/aerosandbox/tools/openvsp/vsp_read.py b/aerosandbox/tools/openvsp/vsp_read.py new file mode 100644 index 000000000..e12520d58 --- /dev/null +++ b/aerosandbox/tools/openvsp/vsp_read.py @@ -0,0 +1,173 @@ +## @ingroup Input_Output-OpenVSP +# vsp_read.py + +# Created: Jun 2018, T. St Francis +# Modified: Aug 2018, T. St Francis +# Jan 2020, T. MacDonald +# Jul 2020, E. Botero + +# ---------------------------------------------------------------------- +# Imports +# ---------------------------------------------------------------------- + +import aerosandbox +from aerosandbox.tools.openvsp.vsp_read_fuselage import vsp_read_fuselage +from aerosandbox.tools.openvsp.vsp_read_wing import vsp_read_wing + +import openvsp as vsp + + +# ---------------------------------------------------------------------- +# vsp read +# ---------------------------------------------------------------------- + + +## @ingroup Input_Output-OpenVSP +def vsp_read(tag, units_type='SI'): + """This reads an OpenVSP vehicle geometry and writes it into a Aerosandbox 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.21.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 Aerosandbox 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 + tag + areas.exposed [m^2] + areas.reference [m^2] + areas.wetted [m^2] + Segments. + tag + 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 + + 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 + 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 + vsp.xsec_surf_id <10 digit string> + + Propellers.Propeller. + location[X,Y,Z] [radians] + rotation[X,Y,Z] [radians] + tip_radius [m] + 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 = aerosandbox.Airplane() + vehicle.tag = tag + + if units_type == 'SI': + units_type = 'SI' + elif units_type == 'inches': + units_type = 'inches' + 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. + + for geom in vsp_geoms: + geom_name = vsp.GetGeomName(geom) + geom_names.append(geom_name) + print(str(geom_name) + ': ' + geom) + + # -------------------------------- + # AUTOMATIC VSP ENTRY & PROCESSING + # -------------------------------- + + for geom in vsp_geoms: + geom_name = vsp.GetGeomTypeName(str(geom)) + + if geom_name == 'Fuselage': + vsp_fuselages.append(geom) + if geom_name == 'Wing': + vsp_wings.append(geom) + # No propeller geometry class available + #if geom_name == 'Propeller': + # vsp_props.append(geom) + + #Read VSP geoms and store in Aerosandbox components + + for fuselage_id in vsp_fuselages: + fuselage = vsp_read_fuselage(fuselage_id, units_type) + #vehicle.append_component(fuselage) + + for wing_id in vsp_wings: + wing = vsp_read_wing(wing_id, units_type) + #vehicle.append_component(wing) + + return vehicle diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py new file mode 100644 index 000000000..01b4d2523 --- /dev/null +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -0,0 +1,196 @@ +## @ingroup Input_Output-OpenVSP +# vsp_read_fuselage.py + +# Created: Jun 2018, T. St Francis +# Modified: Aug 2018, T. St Francis +# Jan 2020, T. MacDonald +# Jul 2020, E. Botero + +# ---------------------------------------------------------------------- +# Imports +# ---------------------------------------------------------------------- + +import aerosandbox +from aerosandbox.geometry import Fuselage +import openvsp as vsp +import aerosandbox.numpy as np + +# ---------------------------------------------------------------------- +# vsp read fuselage +# ---------------------------------------------------------------------- + +def vsp_read_fuselage(fuselage_id, units_type='SI', fineness=True): + """This reads an OpenVSP fuselage geometry and writes it to a aerosandbox 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.21.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). + + Outputs: + Writes aerosandbox 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 + 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 + vsp.xsec_surf_id <10 digit string> + + Properties Used: + N/A + """ + fuselage = aerosandbox.geometry.Fuselage() + + 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(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): + + # Create the segment + x_sec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii) # VSP XSec ID. + segment = aerosandbox.geometry.FuselageXSec() + segment.vsp_data.xsec_id = x_sec + segment.tag = 'segment_' + str(ii) + + # Pull out Parms that will be needed + X_Loc_P = vsp.GetXSecParm(x_sec, 'XLocPercent') + Z_Loc_P = vsp.GetXSecParm(x_sec, 'ZLocPercent') + + segment.percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. + segment.percent_z_location = vsp.GetParmVal(Z_Loc_P ) # 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. (last segment will have length 0.0.) + next_xsec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii+1) + X_Loc_P_p = vsp.GetXSecParm(next_xsec, 'XLocPercent') + percent_x_loc_p1 = vsp.GetParmVal(X_Loc_P_p) + segment.length = fuselage.lengths.total*(percent_x_loc_p1 - 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]) + + + return fuselage + + +def get_fuselage_height(fuselage, location): + """This linearly estimates fuselage height at any percentage point (0,100) along fuselage length. + + Assumptions: + Written for OpenVSP 3.16.1 + + Source: + N/A + + Inputs: + 0. Pre-loaded VSP vehicle in memory, via vsp_read. + 1. Suave fuselage [object], containing fuselage.vsp_data.xsec_num in its data structure. + 2. Fuselage percentage point [float]. + + Outputs: + height [m] + + Properties Used: + N/A + """ + for jj in range(1, fuselage.vsp_data.xsec_num): # Begin at second section, working toward tail. + if fuselage.Segments[jj].percent_x_location>=location and fuselage.Segments[jj-1].percent_x_location + tag + areas.exposed [m^2] + areas.reference [m^2] + areas.wetted [m^2] + Segments. + tag + 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 + + 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 = aerosandbox.Components.Wings.Vertical_Tail() + # wing.vertical = True + # x_rot = (90-x_rot) * Units.deg + #else: + # Instantiate a wing + wing = aerosandbox.geometry.Wing() + + # 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' + + # 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 np.isclose(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 aerosandbox segments. (Wing segments are defined by outboard sections in VSP, but inboard sections in aerosandbox.) + for i in range(start, segment_num+1): + # XSec airfoil + if start!=0: + jj = i-1 # Airfoil index i-1 because VSP airfoils and sections are one index off relative to aerosandbox. + else: + jj= i*1 + segment = aerosandbox.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==start: + wing.thickness_to_chord = thick_cord + + if i < segment_num: # This excludes the tip xsec, but we need a segment in aerosandbox 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(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 + + # 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 + + +def convert_sweep(sweep,sweep_loc,new_sweep_loc,AR,taper): + + sweep_LE = np.arctan(np.tan(sweep)+4*sweep_loc* + (1-taper)/(AR*(1+taper))) + + new_sweep = np.arctan(np.tan(sweep_LE)-4*new_sweep_loc* + (1-taper)/(AR*(1+taper))) + + return new_sweep From 22f13b21e4ac4a2bbcf9ccad9ba655c905be7f63 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Mon, 2 Aug 2021 16:01:50 +0300 Subject: [PATCH 02/58] some fuse work --- .../tools/openvsp/vsp_read_fuselage.py | 159 +++++------------- 1 file changed, 46 insertions(+), 113 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 01b4d2523..8f74c1dc5 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -19,7 +19,7 @@ # vsp read fuselage # ---------------------------------------------------------------------- -def vsp_read_fuselage(fuselage_id, units_type='SI', fineness=True): +def vsp_read_fuselage(fuselage_id, units_type='SI'): """This reads an OpenVSP fuselage geometry and writes it to a aerosandbox fuselage format. Assumptions: @@ -38,129 +38,62 @@ def vsp_read_fuselage(fuselage_id, units_type='SI', fineness=True): 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). Outputs: - Writes aerosandbox fuselage, with these geometries: (all defaults are SI, but user may specify Imperial) + aerosandbox fuselage - 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 - 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 - vsp.xsec_surf_id <10 digit string> - - Properties Used: - N/A """ - fuselage = aerosandbox.geometry.Fuselage() - - 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(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. + # read the xsec data + fuselage.vsp_data.xsec_num = vsp.GetNumXSec(fuselage.vsp_data.xsec_surf_id) # Number of xsecs in fuselage. + xsec = [] + for i in range(0, fuselage.vsp_data.xsec_num): + xsec.append(getXsec(i)) + # get the name + if vsp.GetGeomName(fuselage_id): + fuselage.tag = vsp.GetGeomName(fuselage_id) + else: + fuselage.tag = 'FuselageGeom' + # get leading edge + xyz_le = np.array([0, 0, 0]) + xyz_le[0] = vsp.GetParmVal(fuselage_id, 'X_Location', 'XForm') + xyz_le[1] = vsp.GetParmVal(fuselage_id, 'Y_Location', 'XForm') + xyz_le[2] = vsp.GetParmVal(fuselage_id, 'Z_Location', 'XForm') + # create the fuselage + fuselage = aerosandbox.geometry.Fuselage(fuselage.tag, xyz_le, xsec) - x_locs = [] - heights = [] - widths = [] - eff_diams = [] - lengths = [] +# Get Fuselage segments +def getVspXSec(i): + # Create the segment + xyz_c = np.array([0, 0, 0]) + x_sec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii) # VSP XSec ID. + X_Loc_P = vsp.GetXSecParm(x_sec, 'XLocPercent') + Z_Loc_P = vsp.GetXSecParm(x_sec, 'ZLocPercent') + radius = vsp.GetXSecParm(x_sec, 'Circle_Diameter')/2 - # ----------------- - # Fuselage segments - # ----------------- - - for ii in range(0, fuselage.vsp_data.xsec_num): - - # Create the segment - x_sec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii) # VSP XSec ID. - segment = aerosandbox.geometry.FuselageXSec() - segment.vsp_data.xsec_id = x_sec - segment.tag = 'segment_' + str(ii) + segment.percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. + segment.percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. + segment.height = vsp.GetXSecHeight(segment.vsp_data.xsec_id) + segment.width = vsp.GetXSecWidth(segment.vsp_data.xsec_id) + segment.effective_diameter = (segment.height+segment.width)/2. - # Pull out Parms that will be needed - X_Loc_P = vsp.GetXSecParm(x_sec, 'XLocPercent') - Z_Loc_P = vsp.GetXSecParm(x_sec, 'ZLocPercent') - - segment.percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. - segment.percent_z_location = vsp.GetParmVal(Z_Loc_P ) # 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. (last segment will have length 0.0.) - next_xsec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii+1) - X_Loc_P_p = vsp.GetXSecParm(next_xsec, 'XLocPercent') - percent_x_loc_p1 = vsp.GetParmVal(X_Loc_P_p) - segment.length = fuselage.lengths.total*(percent_x_loc_p1 - 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] + if ii != (fuselage.vsp_data.xsec_num-1): # Segment length: stored as length since previous segment. (last segment will have length 0.0.) + next_xsec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii+1) + X_Loc_P_p = vsp.GetXSecParm(next_xsec, 'XLocPercent') + percent_x_loc_p1 = vsp.GetParmVal(X_Loc_P_p) + segment.length = fuselage.lengths.total*(percent_x_loc_p1 - segment.percent_x_location) + else: + segment.length = 0.0 + lengths.append(segment.length) - 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. + #xsec shape not supported for aerosandbox FuselageXSec + #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'} + #vsp_data.shape = shape_dict[shape] - 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]) - + return FuselageXSec(xyz_c, radius) - return fuselage +return fuselage def get_fuselage_height(fuselage, location): From 5dae54974a106110d3650d12b0763f112f135887 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Tue, 3 Aug 2021 09:43:33 +0300 Subject: [PATCH 03/58] more work --- .../tools/openvsp/vsp_read_fuselage.py | 196 ++++---- aerosandbox/tools/openvsp/vsp_read_wing.py | 476 +++++++----------- 2 files changed, 287 insertions(+), 385 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 8f74c1dc5..3c7467215 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -20,110 +20,108 @@ # ---------------------------------------------------------------------- def vsp_read_fuselage(fuselage_id, units_type='SI'): - """This reads an OpenVSP fuselage geometry and writes it to a aerosandbox fuselage format. + """This reads an OpenVSP fuselage geometry and writes it to a aerosandbox 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.21.1 - - Source: - N/A + 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.21.1 + + Source: + N/A - Inputs: - 0. Pre-loaded VSP vehicle in memory, via vsp_read. - 1. VSP 10-digit geom ID for fuselage. - - Outputs: - aerosandbox fuselage + Inputs: + 0. Pre-loaded VSP vehicle in memory, via vsp_read. + 1. VSP 10-digit geom ID for fuselage. + + Outputs: + aerosandbox fuselage - """ + """ - # read the xsec data - fuselage.vsp_data.xsec_num = vsp.GetNumXSec(fuselage.vsp_data.xsec_surf_id) # Number of xsecs in fuselage. - xsec = [] - for i in range(0, fuselage.vsp_data.xsec_num): - xsec.append(getXsec(i)) - # get the name - if vsp.GetGeomName(fuselage_id): - fuselage.tag = vsp.GetGeomName(fuselage_id) - else: - fuselage.tag = 'FuselageGeom' - # get leading edge - xyz_le = np.array([0, 0, 0]) - xyz_le[0] = vsp.GetParmVal(fuselage_id, 'X_Location', 'XForm') - xyz_le[1] = vsp.GetParmVal(fuselage_id, 'Y_Location', 'XForm') - xyz_le[2] = vsp.GetParmVal(fuselage_id, 'Z_Location', 'XForm') - # create the fuselage - fuselage = aerosandbox.geometry.Fuselage(fuselage.tag, xyz_le, xsec) - + # read the xsec data + xsec_root_id = vsp.GetXSecSurf(fuselage_id, 0) + xsec_num = vsp.GetNumXSec(xsec_root_id) + xsec = [] + for increment in range(0, xsec_num): + xsec.append(getVspXSec(increment)) + # get the name + if vsp.GetGeomName(fuselage_id): + tag = vsp.GetGeomName(fuselage_id) + else: + tag = 'FuselageGeom' + # get leading edge + xyz_le = np.array([0, 0, 0]) + xyz_le[0] = vsp.GetParmVal(fuselage_id, 'X_Location', 'XForm') + xyz_le[1] = vsp.GetParmVal(fuselage_id, 'Y_Location', 'XForm') + xyz_le[2] = vsp.GetParmVal(fuselage_id, 'Z_Location', 'XForm') + # create the fuselage + fuselage = aerosandbox.geometry.Fuselage(tag, xyz_le, xsec) + # Get Fuselage segments -def getVspXSec(i): - # Create the segment - xyz_c = np.array([0, 0, 0]) - x_sec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii) # VSP XSec ID. - X_Loc_P = vsp.GetXSecParm(x_sec, 'XLocPercent') - Z_Loc_P = vsp.GetXSecParm(x_sec, 'ZLocPercent') - radius = vsp.GetXSecParm(x_sec, 'Circle_Diameter')/2 - - segment.percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. - segment.percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. - segment.height = vsp.GetXSecHeight(segment.vsp_data.xsec_id) - segment.width = vsp.GetXSecWidth(segment.vsp_data.xsec_id) - segment.effective_diameter = (segment.height+segment.width)/2. - - if ii != (fuselage.vsp_data.xsec_num-1): # Segment length: stored as length since previous segment. (last segment will have length 0.0.) - next_xsec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii+1) - X_Loc_P_p = vsp.GetXSecParm(next_xsec, 'XLocPercent') - percent_x_loc_p1 = vsp.GetParmVal(X_Loc_P_p) - segment.length = fuselage.lengths.total*(percent_x_loc_p1 - segment.percent_x_location) - else: - segment.length = 0.0 - lengths.append(segment.length) - - #xsec shape not supported for aerosandbox FuselageXSec - #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'} - #vsp_data.shape = shape_dict[shape] - - return FuselageXSec(xyz_c, radius) - -return fuselage - +def getVspXSec(xsec_root_id, increment): + # Create the segment + xyz_c = np.array([0, 0, 0]) + x_sec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. + X_Loc_P = vsp.GetXSecParm(x_sec, 'XLocPercent') + Z_Loc_P = vsp.GetXSecParm(x_sec, 'ZLocPercent') + radius = vsp.GetXSecParm(x_sec, 'Circle_Diameter')/2 + + percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. + percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. + height = vsp.GetXSecHeight(segment.vsp_data.xsec_id) + width = vsp.GetXSecWidth(segment.vsp_data.xsec_id) + effective_diameter = (height+width)/2. + + if ii != (fuselage.vsp_data.xsec_num-1): # Segment length: stored as length since previous segment. (last segment will have length 0.0.) + next_xsec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii+1) + X_Loc_P_p = vsp.GetXSecParm(next_xsec, 'XLocPercent') + percent_x_loc_p1 = vsp.GetParmVal(X_Loc_P_p) + segment.length = fuselage.lengths.total*(percent_x_loc_p1 - segment.percent_x_location) + else: + segment.length = 0.0 + lengths.append(length) + + #xsec shape not supported for aerosandbox FuselageXSec + #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'} + #vsp_data.shape = shape_dict[shape] + return FuselageXSec(xyz_c, radius) + def get_fuselage_height(fuselage, location): - """This linearly estimates fuselage height at any percentage point (0,100) along fuselage length. - - Assumptions: - Written for OpenVSP 3.16.1 - - Source: - N/A + """This linearly estimates fuselage height at any percentage point (0,100) along fuselage length. + + Assumptions: + Written for OpenVSP 3.16.1 + + Source: + N/A - Inputs: - 0. Pre-loaded VSP vehicle in memory, via vsp_read. - 1. Suave fuselage [object], containing fuselage.vsp_data.xsec_num in its data structure. - 2. Fuselage percentage point [float]. - - Outputs: - height [m] - - Properties Used: - N/A - """ - for jj in range(1, fuselage.vsp_data.xsec_num): # Begin at second section, working toward tail. - if fuselage.Segments[jj].percent_x_location>=location and fuselage.Segments[jj-1].percent_x_location=location and fuselage.Segments[jj-1].percent_x_location - tag - areas.exposed [m^2] - areas.reference [m^2] - areas.wetted [m^2] - Segments. - tag - 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 - - 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 = aerosandbox.Components.Wings.Vertical_Tail() - # wing.vertical = True - # x_rot = (90-x_rot) * Units.deg - #else: - # Instantiate a wing - wing = aerosandbox.geometry.Wing() - - # 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' - - # 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 +def vsp_read_wing(wing_id, units_type='SI',write_airfoil_file=True): + """This reads an OpenVSP wing vehicle geometry and writes it into a aerosandbox 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 aerosandbox wing object + + Properties Used: + N/A + """ + + # Apply a tag to the wing + if vsp.GetGeomName(wing_id): + tag = vsp.GetGeomName(wing_id) + tag = tag.translate(t_table) + tag = tag + else: + tag = 'winggeom' + + # Wing origin + xyz_le = np.array([0, 0, 0]) + xyz_le[0] = vsp.GetParmVal(wing_id, 'X_Location', 'XForm') + xyz_le[1] = vsp.GetParmVal(wing_id, 'Y_Location', 'XForm') + xyz_le[2] = vsp.GetParmVal(wing_id, 'Z_Location', 'XForm') + + # 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 + symmetric = True + else: + symmetric = False + + + + #More top level parameters + total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') + aspect_ratio = vsp.GetParmVal(wing_id, 'TotalAR', 'WingGeom') + area = vsp.GetParmVal(wing_id, 'TotalArea', 'WingGeom') + span = 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 np.isclose(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 aerosandbox segments. (Wing segments are defined by outboard sections in VSP, but inboard sections in aerosandbox.) - for i in range(start, segment_num+1): - # XSec airfoil - if start!=0: - jj = i-1 # Airfoil index i-1 because VSP airfoils and sections are one index off relative to aerosandbox. - else: - jj= i*1 - segment = aerosandbox.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==start: - wing.thickness_to_chord = thick_cord - - if i < segment_num: # This excludes the tip xsec, but we need a segment in aerosandbox 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(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 - - # 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 - + # 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 == span: + 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) + + # ------------- + # Wing segments + # ------------- + start = 0 + root_chord = total_chord + if single_seg == False: + # Convert VSP XSecs to aerosandbox segments. + for increment in range(start, segment_num+1): + xsec = getWingXsec(increment) + 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) + 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 + sweeps.quarter_chord = c_4_sweep + taper = taper + dihedral = vsp.GetParmVal(x_sec_1_dih_parm) * x_rot + chords.root = vsp.GetParmVal(x_sec_1_rc_parm)* units_factor + chords.tip = vsp.GetParmVal(x_sec_1_tc_parm) * units_factor + chords.mean_geometric = wing.areas.reference / wing.spans.projected + + # Wing dihedral + proj_span_sum_alt = 0. + span_sum_alt = 0. + sweeps_sum = 0. + + for increment in range(start, segment_num): + span_sum_alt += segment_spans[increment] + proj_span_sum_alt += segment_spans[increment] * np.cos(segment_dihedral[increment]) # Use projected span to find total wing dihedral. + sweeps_sum += segment_spans[increment] * np.tan(segment_sweeps_quarter_chord[increment]) + + 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 + chords_root = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_0') * units_factor + chords_tip = tc + chords_mean_geometric = wing.areas.reference / wing.spans.projected + + # Twists + twists_root = vsp.GetParmVal(wing_id, 'Twist', 'XSec_0') + twists_tip = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(segment_num-1)) + return wing + +def getWingXsec(increment, segment_num): + # XSec airfoil + tag = 'Section_' + str(increment) + thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(increment)) + thickness_to_chord = thick_cord # Thick_cord stored for use in airfoil, below. + root_chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) * units_factor + root_chord_percent = segment_root_chord / root_chord + percent_span_location = proj_span_sum / (total_proj_span/(1+wing.symmetric)) + twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) + + if increment < segment_num: # This excludes the tip xsec. + sweep = vsp.GetParmVal(wing_id, 'Sweep', 'XSec_' + str(increment)) + sweep_loc = vsp.GetParmVal(wing_id, 'Sweep_Location', 'XSec_' + str(increment)) + AR = 2*vsp.GetParmVal(wing_id, 'Aspect', 'XSec_' + str(increment)) + taper = vsp.GetParmVal(wing_id, 'Taper', 'XSec_' + str(increment)) + + segment_sweeps_quarter_chord[incremement] = convert_sweep(sweep,sweep_loc,0.25,AR,taper) + + # Used for dihedral computation, below. + segment_dihedral = vsp.GetParmVal(wing_id, 'Dihedral', 'XSec_' + str(increment)) * x_rot + segment_spans = vsp.GetParmVal(wing_id, 'Span', 'XSec_' + str(increment)) * units_factor + proj_span_sum += segment_spans[i] * np.cos(segment_dihedral[i]) + span_sum += segment_spans[i] + else: + root_chord_percent = (vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment-1))) * units_factor /root_chord + + + xsec_id = str(vsp.GetXSec(xsec_surf_id, increment)) + 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 + + return xsec + + def convert_sweep(sweep,sweep_loc,new_sweep_loc,AR,taper): - - sweep_LE = np.arctan(np.tan(sweep)+4*sweep_loc* + sweep_LE = np.arctan(np.tan(sweep)+4*sweep_loc* (1-taper)/(AR*(1+taper))) - - new_sweep = np.arctan(np.tan(sweep_LE)-4*new_sweep_loc* + new_sweep = np.arctan(np.tan(sweep_LE)-4*new_sweep_loc* (1-taper)/(AR*(1+taper))) - - return new_sweep + return new_sweep From 9b054c05a1f7b0e49af37e11ef8a914aae497836 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Tue, 3 Aug 2021 11:47:59 +0300 Subject: [PATCH 04/58] more work --- aerosandbox/tools/openvsp/vsp_read.py | 78 ++----------------- .../tools/openvsp/vsp_read_fuselage.py | 29 +++---- aerosandbox/tools/openvsp/vsp_read_wing.py | 36 ++++----- 3 files changed, 37 insertions(+), 106 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read.py b/aerosandbox/tools/openvsp/vsp_read.py index e12520d58..b3a3928df 100644 --- a/aerosandbox/tools/openvsp/vsp_read.py +++ b/aerosandbox/tools/openvsp/vsp_read.py @@ -23,7 +23,7 @@ ## @ingroup Input_Output-OpenVSP -def vsp_read(tag, units_type='SI'): +def vsp_read(tag): """This reads an OpenVSP vehicle geometry and writes it into a Aerosandbox vehicle format. Includes wings, fuselages, and propellers. @@ -46,69 +46,8 @@ def vsp_read(tag, units_type='SI'): 2. Units_type set to 'SI' (default) or 'Imperial' Outputs: - Writes Aerosandbox 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 - tag - areas.exposed [m^2] - areas.reference [m^2] - areas.wetted [m^2] - Segments. - tag - 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 - - 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 - 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 - vsp.xsec_surf_id <10 digit string> - - Propellers.Propeller. - location[X,Y,Z] [radians] - rotation[X,Y,Z] [radians] - tip_radius [m] - hub_radius [m] - thrust_angle [radians] - + Writes Aerosandbox vehicle + Properties Used: N/A """ @@ -126,13 +65,6 @@ def vsp_read(tag, units_type='SI'): vehicle = aerosandbox.Airplane() vehicle.tag = tag - if units_type == 'SI': - units_type = 'SI' - elif units_type == 'inches': - units_type = 'inches' - 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. @@ -163,11 +95,11 @@ def vsp_read(tag, units_type='SI'): #Read VSP geoms and store in Aerosandbox components for fuselage_id in vsp_fuselages: - fuselage = vsp_read_fuselage(fuselage_id, units_type) + fuselage = vsp_read_fuselage(fuselage_id) #vehicle.append_component(fuselage) for wing_id in vsp_wings: - wing = vsp_read_wing(wing_id, units_type) + wing = vsp_read_wing(wing_id) #vehicle.append_component(wing) return vehicle diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 3c7467215..6244ca712 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -12,6 +12,7 @@ import aerosandbox from aerosandbox.geometry import Fuselage +from aerosandbox.geometry import FuselageXSec import openvsp as vsp import aerosandbox.numpy as np @@ -43,13 +44,16 @@ def vsp_read_fuselage(fuselage_id, units_type='SI'): aerosandbox fuselage """ + + # get total length of fuselage + total_length = vsp.GetParmVal(fuselage_id, 'Length', 'Design') # read the xsec data xsec_root_id = vsp.GetXSecSurf(fuselage_id, 0) xsec_num = vsp.GetNumXSec(xsec_root_id) xsec = [] for increment in range(0, xsec_num): - xsec.append(getVspXSec(increment)) + xsec.append(getVspXSec(xsec_root_id, xsec_num, total_length, increment)) # get the name if vsp.GetGeomName(fuselage_id): tag = vsp.GetGeomName(fuselage_id) @@ -64,28 +68,27 @@ def vsp_read_fuselage(fuselage_id, units_type='SI'): fuselage = aerosandbox.geometry.Fuselage(tag, xyz_le, xsec) # Get Fuselage segments -def getVspXSec(xsec_root_id, increment): +def getVspXSec(xsec_root_id, xsec_num, total_length, increment): # Create the segment xyz_c = np.array([0, 0, 0]) - x_sec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. - X_Loc_P = vsp.GetXSecParm(x_sec, 'XLocPercent') - Z_Loc_P = vsp.GetXSecParm(x_sec, 'ZLocPercent') - radius = vsp.GetXSecParm(x_sec, 'Circle_Diameter')/2 + xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. + X_Loc_P = vsp.GetXSecParm(xsec, 'XLocPercent') + Z_Loc_P = vsp.GetXSecParm(xsec, 'ZLocPercent') percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. - height = vsp.GetXSecHeight(segment.vsp_data.xsec_id) - width = vsp.GetXSecWidth(segment.vsp_data.xsec_id) + height = vsp.GetXSecHeight(xsec) + width = vsp.GetXSecWidth(xsec) effective_diameter = (height+width)/2. + radius = effective_diameter/2. - if ii != (fuselage.vsp_data.xsec_num-1): # Segment length: stored as length since previous segment. (last segment will have length 0.0.) - next_xsec = vsp.GetXSec(fuselage.vsp_data.xsec_surf_id, ii+1) + if increment != (xsec_num-1): # Segment length: stored as length since previous segment. (last segment will have length 0.0.) + next_xsec = vsp.GetXSec(xsec_root_id, increment+1) X_Loc_P_p = vsp.GetXSecParm(next_xsec, 'XLocPercent') percent_x_loc_p1 = vsp.GetParmVal(X_Loc_P_p) - segment.length = fuselage.lengths.total*(percent_x_loc_p1 - segment.percent_x_location) + length = total_length*(percent_x_loc_p1 - percent_x_location) else: - segment.length = 0.0 - lengths.append(length) + length = 0.0 #xsec shape not supported for aerosandbox FuselageXSec #shape = vsp.GetXSecShape(segment.vsp_data.xsec_id) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 02b7189d9..d1cdfd078 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -28,7 +28,7 @@ # ---------------------------------------------------------------------- ## @ingroup Input_Output-OpenVSP -def vsp_read_wing(wing_id, units_type='SI',write_airfoil_file=True): +def vsp_read_wing(wing_id, write_airfoil_file=True): """This reads an OpenVSP wing vehicle geometry and writes it into a aerosandbox wing format. Assumptions: @@ -80,15 +80,14 @@ def vsp_read_wing(wing_id, units_type='SI',write_airfoil_file=True): total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') aspect_ratio = vsp.GetParmVal(wing_id, 'TotalAR', 'WingGeom') area = vsp.GetParmVal(wing_id, 'TotalArea', 'WingGeom') - span = 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 + x_sec_1_span = vsp.GetParmVal(x_sec_1_span_parm)*(1+symmetric) # symmetric is 1 if True - if x_sec_1_span == span: + if x_sec_1_span == total_proj_span: single_seg = True else: single_seg = False @@ -111,7 +110,7 @@ def vsp_read_wing(wing_id, units_type='SI',write_airfoil_file=True): if single_seg == False: # Convert VSP XSecs to aerosandbox segments. for increment in range(start, segment_num+1): - xsec = getWingXsec(increment) + xsec = getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, segment_num, increment) else: # Single segment @@ -127,15 +126,15 @@ def vsp_read_wing(wing_id, units_type='SI',write_airfoil_file=True): sweep = vsp.GetParmVal(x_sec_1_sweep_parm) 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) + c_4_sweep = convert_sweep(sweep,sweep_loc,0.25,aspect_ratio,taper) # Pull and pack sweeps.quarter_chord = c_4_sweep taper = taper dihedral = vsp.GetParmVal(x_sec_1_dih_parm) * x_rot - chords.root = vsp.GetParmVal(x_sec_1_rc_parm)* units_factor - chords.tip = vsp.GetParmVal(x_sec_1_tc_parm) * units_factor - chords.mean_geometric = wing.areas.reference / wing.spans.projected + chords.root = vsp.GetParmVal(x_sec_1_rc_parm) + chords.tip = vsp.GetParmVal(x_sec_1_tc_parm) + chords.mean_geometric = area / total_proj_span # Wing dihedral proj_span_sum_alt = 0. @@ -151,10 +150,10 @@ def vsp_read_wing(wing_id, units_type='SI',write_airfoil_file=True): 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 + tc = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(segment_num-1)) # Chords - chords_root = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_0') * units_factor + chords_root = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_0') chords_tip = tc chords_mean_geometric = wing.areas.reference / wing.spans.projected @@ -163,14 +162,13 @@ def vsp_read_wing(wing_id, units_type='SI',write_airfoil_file=True): twists_tip = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(segment_num-1)) return wing -def getWingXsec(increment, segment_num): +def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, segment_num, increment): # XSec airfoil tag = 'Section_' + str(increment) thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(increment)) - thickness_to_chord = thick_cord # Thick_cord stored for use in airfoil, below. - root_chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) * units_factor - root_chord_percent = segment_root_chord / root_chord - percent_span_location = proj_span_sum / (total_proj_span/(1+wing.symmetric)) + segment_root_chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) + root_chord_percent = segment_root_chord / root_chord + percent_span_location = proj_span_sum / (total_proj_span/(1+symmetric)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) if increment < segment_num: # This excludes the tip xsec. @@ -178,16 +176,14 @@ def getWingXsec(increment, segment_num): sweep_loc = vsp.GetParmVal(wing_id, 'Sweep_Location', 'XSec_' + str(increment)) AR = 2*vsp.GetParmVal(wing_id, 'Aspect', 'XSec_' + str(increment)) taper = vsp.GetParmVal(wing_id, 'Taper', 'XSec_' + str(increment)) - segment_sweeps_quarter_chord[incremement] = convert_sweep(sweep,sweep_loc,0.25,AR,taper) - # Used for dihedral computation, below. segment_dihedral = vsp.GetParmVal(wing_id, 'Dihedral', 'XSec_' + str(increment)) * x_rot - segment_spans = vsp.GetParmVal(wing_id, 'Span', 'XSec_' + str(increment)) * units_factor + segment_spans = vsp.GetParmVal(wing_id, 'Span', 'XSec_' + str(increment)) proj_span_sum += segment_spans[i] * np.cos(segment_dihedral[i]) span_sum += segment_spans[i] else: - root_chord_percent = (vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment-1))) * units_factor /root_chord + root_chord_percent = (vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment-1))) /root_chord xsec_id = str(vsp.GetXSec(xsec_surf_id, increment)) From 14c732c5ea7b7e874ba857cd14f894a5965f2ba1 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Tue, 3 Aug 2021 21:43:49 +0300 Subject: [PATCH 05/58] more conversion --- aerosandbox/tools/openvsp/vsp_read_wing.py | 114 ++++++++++++++------- 1 file changed, 77 insertions(+), 37 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index d1cdfd078..0f1fce050 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -14,6 +14,7 @@ import aerosandbox from aerosandbox.geometry.airfoil import Airfoil from aerosandbox.geometry import Wing +from aerosandbox.geometry import WingXSec import openvsp as vsp import aerosandbox.numpy as np import string @@ -41,7 +42,6 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): 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 aerosandbox wing object @@ -49,6 +49,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): Properties Used: N/A """ + x_rot = vsp.GetParmVal(wing_id,'X_Rotation','XForm') # Apply a tag to the wing if vsp.GetGeomName(wing_id): @@ -74,16 +75,14 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): else: symmetric = False - - #More top level parameters total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') aspect_ratio = vsp.GetParmVal(wing_id, 'TotalAR', 'WingGeom') area = vsp.GetParmVal(wing_id, 'TotalArea', 'WingGeom') # 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) + xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. + x_sec_1 = vsp.GetXSec(xsec_root_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+symmetric) # symmetric is 1 if True @@ -92,8 +91,8 @@ def vsp_read_wing(wing_id, write_airfoil_file=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) + segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). + x_sec = vsp.GetXSec(xsec_root_id, 0) chord_parm = vsp.GetXSecParm(x_sec,'Root_Chord') total_chord = vsp.GetParmVal(chord_parm) span_sum = 0. # Non-projected. @@ -107,10 +106,12 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): # ------------- start = 0 root_chord = total_chord + xsec = [] if single_seg == False: # Convert VSP XSecs to aerosandbox segments. for increment in range(start, segment_num+1): - xsec = getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, segment_num, increment) + xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, xsec_root_id, x_rot, segment_num, increment) + xsec.append(xsec_next) else: # Single segment @@ -140,14 +141,15 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): proj_span_sum_alt = 0. span_sum_alt = 0. sweeps_sum = 0. - + xsec_spans = getXSecSpans(xsec_root_id) + xsec_dihedral = getXSecDihedrals(xsec_root_id) + xsec_sweeps_quarter_chord = getXSecSweepsQuarterChord(xsec_root_id) for increment in range(start, segment_num): - span_sum_alt += segment_spans[increment] - proj_span_sum_alt += segment_spans[increment] * np.cos(segment_dihedral[increment]) # Use projected span to find total wing dihedral. - sweeps_sum += segment_spans[increment] * np.tan(segment_sweeps_quarter_chord[increment]) - - 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. + span_sum_alt += xsec_spans[increment] + proj_span_sum_alt += xsec_spans[increment] * np.cos(xsec_dihedral[increment]) # Use projected span to find total wing dihedral. + sweeps_sum += xsec_spans[increment] * np.tan(xsec_sweeps_quarter_chord[increment]) + dihedral = np.arccos(proj_span_sum_alt / span_sum_alt) + 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)) @@ -155,17 +157,22 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): # Chords chords_root = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_0') chords_tip = tc - chords_mean_geometric = wing.areas.reference / wing.spans.projected + chords_mean_geometric = areas_reference / spans_projected # Twists twists_root = vsp.GetParmVal(wing_id, 'Twist', 'XSec_0') twists_tip = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(segment_num-1)) + + wing = Wing(tag, xyz_le, xsecs, symmetric) return wing -def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, segment_num, increment): - # XSec airfoil +def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, xsec_root_id, x_rot, segment_num, increment): + xyz_le = np.array([0, 0, 0]) + chord = 0 + twist = 0 + twist_angle = 0 tag = 'Section_' + str(increment) - thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(increment)) + thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(increment)) segment_root_chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) root_chord_percent = segment_root_chord / root_chord percent_span_location = proj_span_sum / (total_proj_span/(1+symmetric)) @@ -176,46 +183,79 @@ def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, sweep_loc = vsp.GetParmVal(wing_id, 'Sweep_Location', 'XSec_' + str(increment)) AR = 2*vsp.GetParmVal(wing_id, 'Aspect', 'XSec_' + str(increment)) taper = vsp.GetParmVal(wing_id, 'Taper', 'XSec_' + str(increment)) - segment_sweeps_quarter_chord[incremement] = convert_sweep(sweep,sweep_loc,0.25,AR,taper) + segment_sweeps_quarter_chord = convert_sweep(sweep,sweep_loc,0.25,AR,taper) # Used for dihedral computation, below. - segment_dihedral = vsp.GetParmVal(wing_id, 'Dihedral', 'XSec_' + str(increment)) * x_rot + segment_dihedral = vsp.GetParmVal(wing_id, 'Dihedral', 'XSec_' + str(increment)) + # segment_dihedral = vsp.GetParmVal(wing_id, 'Dihedral', 'XSec_' + str(increment))*1.0 + x_rot segment_spans = vsp.GetParmVal(wing_id, 'Span', 'XSec_' + str(increment)) - proj_span_sum += segment_spans[i] * np.cos(segment_dihedral[i]) - span_sum += segment_spans[i] + #proj_span_sum += segment_spans[i] * np.cos(segment_dihedral[i]) + #span_sum += segment_spans[i] else: root_chord_percent = (vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment-1))) /root_chord - xsec_id = str(vsp.GetXSec(xsec_surf_id, increment)) + xsec_id = str(vsp.GetXSec(xsec_root_id, increment)) if vsp.GetXSecShape(xsec_id) == vsp.XS_FOUR_SERIES: # XSec shape: NACA 4-series - camber = vsp.GetParmVal(wing_id, 'Camber', 'XSecCurve_' + str(jj)) + camber = vsp.GetParmVal(wing_id, 'Camber', 'XSecCurve_' + str(increment)) if camber == 0.: camber_loc = 0. else: - camber_loc = vsp.GetParmVal(wing_id, 'CamberLoc', 'XSecCurve_' + str(jj)) - airfoil.thickness_to_chord = thick_cord + camber_loc = vsp.GetParmVal(wing_id, 'CamberLoc', 'XSecCurve_' + str(increment)) + 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) + 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))) + a_value = vsp.GetParmVal(wing_id, 'A', 'XSecCurve_' + str(increment)) + ideal_CL = int(np.around(vsp.GetParmVal(wing_id, 'IdealCl', 'XSecCurve_' + str(increment))*10)) + series_vsp = int(vsp.GetParmVal(wing_id, 'Series', 'XSecCurve_' + str(increment))) 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 + thickness_to_chord = thick_cord + xsec = WingXSec(xyz_le, chord, twist, twist_angle, airfoil=Airfoil("naca0012")) return xsec - - -def convert_sweep(sweep,sweep_loc,new_sweep_loc,AR,taper): +def getXSecSpans(wing_id): + xsec_spans = [] + xsec_root_id = vsp.GetXSecSurf(wing_id, 0) + segment_num = vsp.GetNumXSec(xsec_root_id) + for increment in range(0, segment_num): + xsec_id = str(vsp.GetXSec(xsec_root_id, increment)) + segment_span = vsp.GetParmVal(wing_id, 'Span', 'XSec_' + str(i)) + xsec_spans.append(segment_span) + return xsec_spans + +def getXSecDihedrals(wing_id): + xsec_dihedral = [] + xsec_root_id = vsp.GetXSecSurf(wing_id, 0) + segment_num = vsp.GetNumXSec(xsec_root_id) + for increment in range(0, segment_num): + xsec_id = str(vsp.GetXSec(xsec_root_id, increment)) + xsec_dihedral.append() + return xsec_dihedral + +def getXSecSweepsQuarterChord(wing_id): + xsec_sweeps_quarter_chord = [] + xsec_root_id = vsp.GetXSecSurf(wing_id, 0) + segment_num = vsp.GetNumXSec(xsec_root_id) + for increment in range(0, segment_num): + xsec_id = str(vsp.GetXSec(xsec_root_id, increment)) + sweep = vsp.GetParmVal(wing_id, 'Sweep', 'XSec_' + str(i)) * Units.deg + sweep_loc = vsp.GetParmVal(wing_id, 'Sweep_Location', 'XSec_' + str(i)) + aspect_ration = 2*vsp.GetParmVal(wing_id, 'Aspect', 'XSec_' + str(i)) + taper = vsp.GetParmVal(wing_id, 'Taper', 'XSec_' + str(i)) + c_4_sweep = convert_sweep(sweep,sweep_loc,0.25,aspect_ratio,taper) + xsec_sweeps_quarter_chord.append(c_4_sweep) + return xsec_sweeps_quarter_chord + +def convert_sweep(sweep,sweep_loc,new_sweep_loc,aspect_ratio,taper): sweep_LE = np.arctan(np.tan(sweep)+4*sweep_loc* - (1-taper)/(AR*(1+taper))) + (1-taper)/(aspect_ratio*(1+taper))) new_sweep = np.arctan(np.tan(sweep_LE)-4*new_sweep_loc* - (1-taper)/(AR*(1+taper))) + (1-taper)/(aspect_ratio*(1+taper))) return new_sweep From efdb6bc7bec9ea3ecfd66a3b3a72d14e991e4c5f Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Tue, 3 Aug 2021 22:23:56 +0300 Subject: [PATCH 06/58] more conversion --- aerosandbox/tools/openvsp/vsp_read_wing.py | 45 +++++++--------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 0f1fce050..077016190 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -77,7 +77,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): #More top level parameters total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') - aspect_ratio = vsp.GetParmVal(wing_id, 'TotalAR', 'WingGeom') + aspect_ratio = vsp.GetParmVal(wing_id, 'Totalaspect_ratio', 'WingGeom') area = vsp.GetParmVal(wing_id, 'TotalArea', 'WingGeom') # Check if this is a single segment wing @@ -110,7 +110,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): if single_seg == False: # Convert VSP XSecs to aerosandbox segments. for increment in range(start, segment_num+1): - xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, xsec_root_id, x_rot, segment_num, increment) + xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, x_rot, segment_num, increment) xsec.append(xsec_next) else: # Single segment @@ -166,35 +166,19 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): wing = Wing(tag, xyz_le, xsecs, symmetric) return wing -def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, xsec_root_id, x_rot, segment_num, increment): +def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, x_rot, segment_num, increment): + xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xyz_le = np.array([0, 0, 0]) - chord = 0 - twist = 0 - twist_angle = 0 - tag = 'Section_' + str(increment) - thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(increment)) - segment_root_chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) - root_chord_percent = segment_root_chord / root_chord - percent_span_location = proj_span_sum / (total_proj_span/(1+symmetric)) - twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) + thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(increment)) + chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) + twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) - if increment < segment_num: # This excludes the tip xsec. - sweep = vsp.GetParmVal(wing_id, 'Sweep', 'XSec_' + str(increment)) - sweep_loc = vsp.GetParmVal(wing_id, 'Sweep_Location', 'XSec_' + str(increment)) - AR = 2*vsp.GetParmVal(wing_id, 'Aspect', 'XSec_' + str(increment)) - taper = vsp.GetParmVal(wing_id, 'Taper', 'XSec_' + str(increment)) - segment_sweeps_quarter_chord = convert_sweep(sweep,sweep_loc,0.25,AR,taper) - # Used for dihedral computation, below. - segment_dihedral = vsp.GetParmVal(wing_id, 'Dihedral', 'XSec_' + str(increment)) - # segment_dihedral = vsp.GetParmVal(wing_id, 'Dihedral', 'XSec_' + str(increment))*1.0 + x_rot - segment_spans = vsp.GetParmVal(wing_id, 'Span', 'XSec_' + str(increment)) - #proj_span_sum += segment_spans[i] * np.cos(segment_dihedral[i]) - #span_sum += segment_spans[i] - else: - root_chord_percent = (vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment-1))) /root_chord - - xsec_id = str(vsp.GetXSec(xsec_root_id, increment)) + airfoil = getXsecAirfoil(wing_id, xsec_id): + xsec = WingXSec(xyz_le, chord, twist, airfoil=airfoil) + return xsec + +def getXsecAirfoil(wing_id, xsec_id, thick_cord): if vsp.GetXSecShape(xsec_id) == vsp.XS_FOUR_SERIES: # XSec shape: NACA 4-series camber = vsp.GetParmVal(wing_id, 'Camber', 'XSecCurve_' + str(increment)) if camber == 0.: @@ -216,9 +200,8 @@ def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, 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 thickness_to_chord = thick_cord - - xsec = WingXSec(xyz_le, chord, twist, twist_angle, airfoil=Airfoil("naca0012")) - return xsec + airfoil=Airfoil("naca0012") + return airfoil def getXSecSpans(wing_id): xsec_spans = [] From 12dd1b0e0cb02a68837d1bf01d9f9be780d980a5 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Tue, 3 Aug 2021 22:34:05 +0300 Subject: [PATCH 07/58] more conversion --- aerosandbox/tools/openvsp/vsp_read_wing.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 077016190..545cfa68e 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -169,22 +169,22 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, x_rot, segment_num, increment): xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xyz_le = np.array([0, 0, 0]) - thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(increment)) chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) xsec_id = str(vsp.GetXSec(xsec_root_id, increment)) - airfoil = getXsecAirfoil(wing_id, xsec_id): + airfoil = getXsecAirfoil(wing_id, xsec_id, increment): xsec = WingXSec(xyz_le, chord, twist, airfoil=airfoil) return xsec -def getXsecAirfoil(wing_id, xsec_id, thick_cord): +def getXsecAirfoil(wing_id, xsec_id, xsec_num): if vsp.GetXSecShape(xsec_id) == vsp.XS_FOUR_SERIES: # XSec shape: NACA 4-series - camber = vsp.GetParmVal(wing_id, 'Camber', 'XSecCurve_' + str(increment)) + thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(xsec_num)) + camber = vsp.GetParmVal(wing_id, 'Camber', 'XSecCurve_' + str(xsec_num)) if camber == 0.: camber_loc = 0. else: - camber_loc = vsp.GetParmVal(wing_id, 'CamberLoc', 'XSecCurve_' + str(increment)) + camber_loc = vsp.GetParmVal(wing_id, 'CamberLoc', 'XSecCurve_' + str(xsec_num)) thickness_to_chord = thick_cord camber_round = int(np.around(camber*100)) camber_loc_round = int(np.around(camber_loc*10)) @@ -192,9 +192,9 @@ def getXsecAirfoil(wing_id, xsec_id, thick_cord): 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(increment)) - ideal_CL = int(np.around(vsp.GetParmVal(wing_id, 'IdealCl', 'XSecCurve_' + str(increment))*10)) - series_vsp = int(vsp.GetParmVal(wing_id, 'Series', 'XSecCurve_' + str(increment))) + a_value = vsp.GetParmVal(wing_id, 'A', 'XSecCurve_' + str(xsec_num)) + ideal_CL = int(np.around(vsp.GetParmVal(wing_id, 'IdealCl', 'XSecCurve_' + str(xsec_num))*10)) + series_vsp = int(vsp.GetParmVal(wing_id, 'Series', 'XSecCurve_' + str(xsec_num))) 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)) From 8be8f96637f27fc7f651f3ae3ace91509ef89925 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 08:08:15 +0300 Subject: [PATCH 08/58] more conversion --- .../tools/openvsp/vsp_read_fuselage.py | 1 + aerosandbox/tools/openvsp/vsp_read_wing.py | 89 +++---------------- 2 files changed, 12 insertions(+), 78 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 6244ca712..ea65354fc 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -45,6 +45,7 @@ def vsp_read_fuselage(fuselage_id, units_type='SI'): """ + print("Converting fuselage: " + fuselage_id) # get total length of fuselage total_length = vsp.GetParmVal(fuselage_id, 'Length', 'Design') diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 545cfa68e..a9d4cbdfc 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -49,6 +49,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): Properties Used: N/A """ + print("Converting wing: " + wing_id) x_rot = vsp.GetParmVal(wing_id,'X_Rotation','XForm') # Apply a tag to the wing @@ -60,10 +61,10 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): tag = 'winggeom' # Wing origin - xyz_le = np.array([0, 0, 0]) - xyz_le[0] = vsp.GetParmVal(wing_id, 'X_Location', 'XForm') - xyz_le[1] = vsp.GetParmVal(wing_id, 'Y_Location', 'XForm') - xyz_le[2] = vsp.GetParmVal(wing_id, 'Z_Location', 'XForm') + xyz_le = np.array([0, 0, 0]) + xyz_le[0] = vsp.GetParmVal(wing_id, 'X_Location', 'XForm') + xyz_le[1] = vsp.GetParmVal(wing_id, 'Y_Location', 'XForm') + xyz_le[2] = vsp.GetParmVal(wing_id, 'Z_Location', 'XForm') # Wing Symmetry sym_planar = vsp.GetParmVal(wing_id, 'Sym_Planar_Flag', 'Sym') @@ -79,90 +80,22 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') aspect_ratio = vsp.GetParmVal(wing_id, 'Totalaspect_ratio', 'WingGeom') area = vsp.GetParmVal(wing_id, 'TotalArea', 'WingGeom') - - # Check if this is a single segment wing xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. - x_sec_1 = vsp.GetXSec(xsec_root_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+symmetric) # symmetric is 1 if True - - if x_sec_1_span == total_proj_span: - single_seg = True - else: - single_seg = False - segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). x_sec = vsp.GetXSec(xsec_root_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) # ------------- # Wing segments # ------------- start = 0 root_chord = total_chord - xsec = [] - if single_seg == False: - # Convert VSP XSecs to aerosandbox segments. - for increment in range(start, segment_num+1): - xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, x_rot, segment_num, increment) - xsec.append(xsec_next) - 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) - 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,aspect_ratio,taper) - - # Pull and pack - sweeps.quarter_chord = c_4_sweep - taper = taper - dihedral = vsp.GetParmVal(x_sec_1_dih_parm) * x_rot - chords.root = vsp.GetParmVal(x_sec_1_rc_parm) - chords.tip = vsp.GetParmVal(x_sec_1_tc_parm) - chords.mean_geometric = area / total_proj_span - - # Wing dihedral - proj_span_sum_alt = 0. - span_sum_alt = 0. - sweeps_sum = 0. - xsec_spans = getXSecSpans(xsec_root_id) - xsec_dihedral = getXSecDihedrals(xsec_root_id) - xsec_sweeps_quarter_chord = getXSecSweepsQuarterChord(xsec_root_id) - for increment in range(start, segment_num): - span_sum_alt += xsec_spans[increment] - proj_span_sum_alt += xsec_spans[increment] * np.cos(xsec_dihedral[increment]) # Use projected span to find total wing dihedral. - sweeps_sum += xsec_spans[increment] * np.tan(xsec_sweeps_quarter_chord[increment]) - dihedral = np.arccos(proj_span_sum_alt / span_sum_alt) - 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)) - - # Chords - chords_root = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_0') - chords_tip = tc - chords_mean_geometric = areas_reference / spans_projected - - # Twists - twists_root = vsp.GetParmVal(wing_id, 'Twist', 'XSec_0') - twists_tip = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(segment_num-1)) - + xsecs = [] + # Convert VSP XSecs to aerosandbox segments. + for increment in range(start, segment_num+1): + xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, x_rot, segment_num, increment) + xsecs.append(xsec_next) wing = Wing(tag, xyz_le, xsecs, symmetric) return wing @@ -173,7 +106,7 @@ def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) xsec_id = str(vsp.GetXSec(xsec_root_id, increment)) - airfoil = getXsecAirfoil(wing_id, xsec_id, increment): + airfoil = getXsecAirfoil(wing_id, xsec_id, increment) xsec = WingXSec(xyz_le, chord, twist, airfoil=airfoil) return xsec From 36b413dd72b84de326a6b2d2c1ac664f39e68682 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 09:11:22 +0300 Subject: [PATCH 09/58] fix airfoils --- .../tools/openvsp/vsp_read_fuselage.py | 1 + aerosandbox/tools/openvsp/vsp_read_wing.py | 39 ++++++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index ea65354fc..09907c8db 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -70,6 +70,7 @@ def vsp_read_fuselage(fuselage_id, units_type='SI'): # Get Fuselage segments def getVspXSec(xsec_root_id, xsec_num, total_length, increment): + print(" Processing xsec: " + str(increment)) # Create the segment xyz_c = np.array([0, 0, 0]) xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index a9d4cbdfc..8fc5411da 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -77,14 +77,12 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): symmetric = False #More top level parameters - total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') - aspect_ratio = vsp.GetParmVal(wing_id, 'Totalaspect_ratio', 'WingGeom') - area = vsp.GetParmVal(wing_id, 'TotalArea', 'WingGeom') - xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. - segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). - x_sec = vsp.GetXSec(xsec_root_id, 0) - chord_parm = vsp.GetXSecParm(x_sec,'Root_Chord') - total_chord = vsp.GetParmVal(chord_parm) + total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') + xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. + segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). + x_sec = vsp.GetXSec(xsec_root_id, 0) + chord_parm = vsp.GetXSecParm(x_sec,'Root_Chord') + total_chord = vsp.GetParmVal(chord_parm) # ------------- # Wing segments @@ -93,13 +91,14 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): root_chord = total_chord xsecs = [] # Convert VSP XSecs to aerosandbox segments. - for increment in range(start, segment_num+1): - xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, x_rot, segment_num, increment) + for increment in range(start, segment_num): + xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, symmetric, x_rot, segment_num, increment) xsecs.append(xsec_next) wing = Wing(tag, xyz_le, xsecs, symmetric) return wing -def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, x_rot, segment_num, increment): +def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, x_rot, segment_num, increment): + print(" Processing xsec: " + str(increment) + " for wing: " + wing_id) xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xyz_le = np.array([0, 0, 0]) chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) @@ -111,6 +110,9 @@ def getWingXsec(wing_id, root_chord, total_proj_span, proj_span_sum, symmetric, return xsec def getXsecAirfoil(wing_id, xsec_id, xsec_num): + xsec_root_id = vsp.GetXSecSurf(wing_id, 0) + total_xsec = vsp.GetNumXSec(xsec_root_id) + print(" Processing airfoil: " + str(xsec_num) + " for wing: " + wing_id) if vsp.GetXSecShape(xsec_id) == vsp.XS_FOUR_SERIES: # XSec shape: NACA 4-series thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(xsec_num)) camber = vsp.GetParmVal(wing_id, 'Camber', 'XSecCurve_' + str(xsec_num)) @@ -123,6 +125,8 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): camber_loc_round = int(np.around(camber_loc*10)) thick_cord_round = int(np.around(thick_cord*100)) tag = 'NACA ' + str(camber_round) + str(camber_loc_round) + str(thick_cord_round) + print(" Airfoil is XS_FOUR_SERIES: " + tag) + return Airfoil(name=tag) 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(xsec_num)) @@ -130,11 +134,16 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): series_vsp = int(vsp.GetParmVal(wing_id, 'Series', 'XSecCurve_' + str(xsec_num))) 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)) + tag = 'NACA ' + series + str(ideal_CL) + str(thick_cord_round) + ' a=' + str(np.around(a_value,1)) + print(" Airfoil is XS_SIX_SERIES: " + tag) + return Airfoil(name=tag) elif vsp.GetXSecShape(xsec_id) == vsp.XS_FILE_AIRFOIL: # XSec shape: 12 is type AF_FILE - thickness_to_chord = thick_cord - airfoil=Airfoil("naca0012") - return airfoil + print(" Airfoil is XS_FILE_AIRFOIL") + vsp.WriteSeligAirfoil(str(wing.tag) + '_airfoil_XSec_' + str(xsec_num) +'.dat', wing_id, float(xsec_num/total_xsec)) + return Airfoil(name="str(wing.tag) + '_airfoil_XSec_' + str(xsec_num)", coordinates=str(wing.tag) + '_airfoil_XSec_' + str(xsec_num) +'.dat') + else: + print(" Error: Could not determine airfoil") + return Airfoil("naca0012") def getXSecSpans(wing_id): xsec_spans = [] From f868ede888b97e8315cbec7a5477a02c23d4378b Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 09:59:22 +0300 Subject: [PATCH 10/58] fix airfoils --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 09907c8db..779c9f98d 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -52,9 +52,9 @@ def vsp_read_fuselage(fuselage_id, units_type='SI'): # read the xsec data xsec_root_id = vsp.GetXSecSurf(fuselage_id, 0) xsec_num = vsp.GetNumXSec(xsec_root_id) - xsec = [] + xsecs = [] for increment in range(0, xsec_num): - xsec.append(getVspXSec(xsec_root_id, xsec_num, total_length, increment)) + xsecs.append(getVspXSec(xsec_root_id, xsec_num, total_length, increment)) # get the name if vsp.GetGeomName(fuselage_id): tag = vsp.GetGeomName(fuselage_id) @@ -66,7 +66,7 @@ def vsp_read_fuselage(fuselage_id, units_type='SI'): xyz_le[1] = vsp.GetParmVal(fuselage_id, 'Y_Location', 'XForm') xyz_le[2] = vsp.GetParmVal(fuselage_id, 'Z_Location', 'XForm') # create the fuselage - fuselage = aerosandbox.geometry.Fuselage(tag, xyz_le, xsec) + fuselage = aerosandbox.geometry.Fuselage(tag, xyz_le, xsecs) # Get Fuselage segments def getVspXSec(xsec_root_id, xsec_num, total_length, increment): @@ -78,7 +78,12 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): Z_Loc_P = vsp.GetXSecParm(xsec, 'ZLocPercent') percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. + y_location = vsp.GetXSecParm(xsec,'X_Location') + print(y_location) + xyz_c[0] = percent_x_location*total_length + print(" percent x location: " + str(percent_x_location) + " xloc: " + str(xyz_c[0])) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. + print(" percent z location: " + str(percent_z_location)) height = vsp.GetXSecHeight(xsec) width = vsp.GetXSecWidth(xsec) effective_diameter = (height+width)/2. From f637f6077ff664a8952d0457d09b49ddd60dcab5 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 11:54:35 +0300 Subject: [PATCH 11/58] return airplane --- aerosandbox/tools/openvsp/vsp_read.py | 143 +++++++++--------- .../tools/openvsp/vsp_read_fuselage.py | 3 +- aerosandbox/tools/openvsp/vsp_read_wing.py | 9 +- 3 files changed, 74 insertions(+), 81 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read.py b/aerosandbox/tools/openvsp/vsp_read.py index b3a3928df..48c379865 100644 --- a/aerosandbox/tools/openvsp/vsp_read.py +++ b/aerosandbox/tools/openvsp/vsp_read.py @@ -11,8 +11,10 @@ # ---------------------------------------------------------------------- import aerosandbox +from aerosandbox.geometry import Airplane from aerosandbox.tools.openvsp.vsp_read_fuselage import vsp_read_fuselage from aerosandbox.tools.openvsp.vsp_read_wing import vsp_read_wing +import aerosandbox.numpy as np import openvsp as vsp @@ -23,83 +25,76 @@ ## @ingroup Input_Output-OpenVSP -def vsp_read(tag): - """This reads an OpenVSP vehicle geometry and writes it into a Aerosandbox vehicle format. - Includes wings, fuselages, and propellers. +def vsp_read(tag): + """This reads an OpenVSP vehicle geometry and writes it into a Aerosandbox 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.21.1 - - Source: - N/A + 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.21.1 + + Source: + N/A - Inputs: - 1. A tag for an XML file in format .vsp3. - 2. Units_type set to 'SI' (default) or 'Imperial' + Inputs: + 1. A tag for an XML file in format .vsp3. + 2. Units_type set to 'SI' (default) or 'Imperial' - Outputs: - Writes Aerosandbox vehicle + Outputs: + Writes Aerosandbox vehicle - Properties Used: - N/A - """ - - vsp.ClearVSPModel() - vsp.ReadVSPFile(tag) - - vsp_fuselages = [] - vsp_wings = [] - vsp_props = [] - - vsp_geoms = vsp.FindGeoms() - geom_names = [] + Properties Used: + N/A + """ + + vsp.ClearVSPModel() + vsp.ReadVSPFile(tag) + + vsp_fuselages = [] + vsp_wings = [] + vsp_props = [] + vsp_geoms = vsp.FindGeoms() + geom_names = [] - vehicle = aerosandbox.Airplane() - vehicle.tag = tag - - # 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. - - for geom in vsp_geoms: - geom_name = vsp.GetGeomName(geom) - geom_names.append(geom_name) - print(str(geom_name) + ': ' + geom) - - # -------------------------------- - # AUTOMATIC VSP ENTRY & PROCESSING - # -------------------------------- - - for geom in vsp_geoms: - geom_name = vsp.GetGeomTypeName(str(geom)) - - if geom_name == 'Fuselage': - vsp_fuselages.append(geom) - if geom_name == 'Wing': - vsp_wings.append(geom) + # 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. + for geom in vsp_geoms: + geom_name = vsp.GetGeomName(geom) + geom_names.append(geom_name) + print(str(geom_name) + ': ' + geom) + + # -------------------------------- + # AUTOMATIC VSP ENTRY & PROCESSING + # -------------------------------- + for geom in vsp_geoms: + geom_name = vsp.GetGeomTypeName(str(geom)) + + if geom_name == 'Fuselage': + vsp_fuselages.append(geom) + if geom_name == 'Wing': + vsp_wings.append(geom) # No propeller geometry class available - #if geom_name == 'Propeller': - # vsp_props.append(geom) - - #Read VSP geoms and store in Aerosandbox components - - for fuselage_id in vsp_fuselages: - fuselage = vsp_read_fuselage(fuselage_id) - #vehicle.append_component(fuselage) - - for wing_id in vsp_wings: - wing = vsp_read_wing(wing_id) - #vehicle.append_component(wing) - - return vehicle + #if geom_name == 'Propeller': + # vsp_props.append(geom) + + #Read VSP geoms and store in Aerosandbox components + xyz_ref = np.array([0, 0, 0]) + fuselages = [] + for fuselage_id in vsp_fuselages: + fuselages.append(vsp_read_fuselage(fuselage_id)) + + wings = [] + for wing_id in vsp_wings: + wings.append(vsp_read_wing(wing_id)) + + return Airplane(tag, xyz_ref, wings, fuselages) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 779c9f98d..7933c354b 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -75,11 +75,10 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): xyz_c = np.array([0, 0, 0]) xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. X_Loc_P = vsp.GetXSecParm(xsec, 'XLocPercent') + Y_Loc_P = vsp.GetXSecParm(xsec, 'YLocPercent') Z_Loc_P = vsp.GetXSecParm(xsec, 'ZLocPercent') percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. - y_location = vsp.GetXSecParm(xsec,'X_Location') - print(y_location) xyz_c[0] = percent_x_location*total_length print(" percent x location: " + str(percent_x_location) + " xloc: " + str(xyz_c[0])) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 8fc5411da..db7a4edbe 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -103,9 +103,8 @@ def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, x_rot, segment_ xyz_le = np.array([0, 0, 0]) chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) - - xsec_id = str(vsp.GetXSec(xsec_root_id, increment)) - airfoil = getXsecAirfoil(wing_id, xsec_id, increment) + xsec = vsp.GetXSec(xsec_root_id, increment) + airfoil = getXsecAirfoil(wing_id, xsec, increment) xsec = WingXSec(xyz_le, chord, twist, airfoil=airfoil) return xsec @@ -139,8 +138,8 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): return Airfoil(name=tag) elif vsp.GetXSecShape(xsec_id) == vsp.XS_FILE_AIRFOIL: # XSec shape: 12 is type AF_FILE print(" Airfoil is XS_FILE_AIRFOIL") - vsp.WriteSeligAirfoil(str(wing.tag) + '_airfoil_XSec_' + str(xsec_num) +'.dat', wing_id, float(xsec_num/total_xsec)) - return Airfoil(name="str(wing.tag) + '_airfoil_XSec_' + str(xsec_num)", coordinates=str(wing.tag) + '_airfoil_XSec_' + str(xsec_num) +'.dat') + vsp.WriteSeligAirfoil(str(wing_id) + '_airfoil_XSec_' + str(xsec_num) +'.dat', wing_id, float(xsec_num/total_xsec)) + return Airfoil(name="str(wing_id) + '_airfoil_XSec_' + str(xsec_num)", coordinates=str(wing_id) + '_airfoil_XSec_' + str(xsec_num) +'.dat') else: print(" Error: Could not determine airfoil") return Airfoil("naca0012") From 9951a31d4d42c1ab0a5ebc73269e07c2077f8a73 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 13:00:44 +0300 Subject: [PATCH 12/58] try drawing --- .../tools/openvsp/vsp_read_fuselage.py | 22 +++++-------------- aerosandbox/tools/openvsp/vsp_read_wing.py | 6 ++--- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 7933c354b..c100ffb72 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -1,6 +1,3 @@ -## @ingroup Input_Output-OpenVSP -# vsp_read_fuselage.py - # Created: Jun 2018, T. St Francis # Modified: Aug 2018, T. St Francis # Jan 2020, T. MacDonald @@ -20,7 +17,7 @@ # vsp read fuselage # ---------------------------------------------------------------------- -def vsp_read_fuselage(fuselage_id, units_type='SI'): +def vsp_read_fuselage(fuselage_id): """This reads an OpenVSP fuselage geometry and writes it to a aerosandbox fuselage format. Assumptions: @@ -42,7 +39,6 @@ def vsp_read_fuselage(fuselage_id, units_type='SI'): Outputs: aerosandbox fuselage - """ print("Converting fuselage: " + fuselage_id) @@ -66,7 +62,7 @@ def vsp_read_fuselage(fuselage_id, units_type='SI'): xyz_le[1] = vsp.GetParmVal(fuselage_id, 'Y_Location', 'XForm') xyz_le[2] = vsp.GetParmVal(fuselage_id, 'Z_Location', 'XForm') # create the fuselage - fuselage = aerosandbox.geometry.Fuselage(tag, xyz_le, xsecs) + return Fuselage(tag, xyz_le, xsecs) # Get Fuselage segments def getVspXSec(xsec_root_id, xsec_num, total_length, increment): @@ -81,21 +77,16 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. xyz_c[0] = percent_x_location*total_length print(" percent x location: " + str(percent_x_location) + " xloc: " + str(xyz_c[0])) + percent_y_location = vsp.GetParmVal(Y_Loc_P) + print(" percent y location: " + str(percent_y_location)) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. print(" percent z location: " + str(percent_z_location)) height = vsp.GetXSecHeight(xsec) width = vsp.GetXSecWidth(xsec) effective_diameter = (height+width)/2. radius = effective_diameter/2. + print(" radius: " + str(radius)) - if increment != (xsec_num-1): # Segment length: stored as length since previous segment. (last segment will have length 0.0.) - next_xsec = vsp.GetXSec(xsec_root_id, increment+1) - X_Loc_P_p = vsp.GetXSecParm(next_xsec, 'XLocPercent') - percent_x_loc_p1 = vsp.GetParmVal(X_Loc_P_p) - length = total_length*(percent_x_loc_p1 - percent_x_location) - else: - length = 0.0 - #xsec shape not supported for aerosandbox FuselageXSec #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'} @@ -119,9 +110,6 @@ def get_fuselage_height(fuselage, location): Outputs: height [m] - - Properties Used: - N/A """ for jj in range(1, fuselage.vsp_data.xsec_num): # Begin at second section, working toward tail. if fuselage.Segments[jj].percent_x_location>=location and fuselage.Segments[jj-1].percent_x_location Date: Wed, 4 Aug 2021 14:20:12 +0300 Subject: [PATCH 13/58] get wing working --- aerosandbox/tools/openvsp/vsp_read_wing.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index e529b8b5b..d7cd910d2 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -16,8 +16,10 @@ from aerosandbox.geometry import Wing from aerosandbox.geometry import WingXSec import openvsp as vsp -import aerosandbox.numpy as np +#import aerosandbox.numpy as np +import numpy as np import string +from ctypes import * # This enforces lowercase names chars = string.punctuation + string.whitespace @@ -92,17 +94,20 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): xsecs = [] # Convert VSP XSecs to aerosandbox segments. for increment in range(start, segment_num): - xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, symmetric, x_rot, segment_num, increment) + xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, increment) xsecs.append(xsec_next) + print(xsecs) return Wing(tag, xyz_le, xsecs, symmetric) -def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, x_rot, segment_num, increment): +def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, increment): print(" Processing xsec: " + str(increment) + " for wing: " + wing_id) xsec_root_id = vsp.GetXSecSurf(wing_id, 0) - xyz_le = np.array([0, 0, 0]) + xsec = vsp.GetXSec(xsec_root_id, increment) + point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge + p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + xyz_le = np.array(list(p)) chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) - xsec = vsp.GetXSec(xsec_root_id, increment) airfoil = getXsecAirfoil(wing_id, xsec, increment) return WingXSec(xyz_le, chord, twist, airfoil=airfoil) From 5d464d6c8aa1f049f043dd87cffd2e6321313aca Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 14:57:20 +0300 Subject: [PATCH 14/58] wing working --- aerosandbox/tools/openvsp/vsp_read_wing.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index d7cd910d2..99deb9716 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -126,7 +126,7 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): 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)) - tag = 'NACA ' + str(camber_round) + str(camber_loc_round) + str(thick_cord_round) + tag = 'naca' + str(camber_round) + str(camber_loc_round) + str(thick_cord_round) print(" Airfoil is XS_FOUR_SERIES: " + tag) return Airfoil(name=tag) elif vsp.GetXSecShape(xsec_id) == vsp.XS_SIX_SERIES: # XSec shape: NACA 6-series @@ -136,16 +136,16 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): series_vsp = int(vsp.GetParmVal(wing_id, 'Series', 'XSecCurve_' + str(xsec_num))) 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] - tag = 'NACA ' + series + str(ideal_CL) + str(thick_cord_round) + ' a=' + str(np.around(a_value,1)) + tag = 'naca' + series + str(ideal_CL) + str(thick_cord_round) + ' a=' + str(np.around(a_value,1)) print(" Airfoil is XS_SIX_SERIES: " + tag) return Airfoil(name=tag) elif vsp.GetXSecShape(xsec_id) == vsp.XS_FILE_AIRFOIL: # XSec shape: 12 is type AF_FILE print(" Airfoil is XS_FILE_AIRFOIL") - vsp.WriteSeligAirfoil(str(wing_id) + '_airfoil_XSec_' + str(xsec_num) +'.dat', wing_id, float(xsec_num/total_xsec)) - return Airfoil(name="str(wing_id) + '_airfoil_XSec_' + str(xsec_num)", coordinates=str(wing_id) + '_airfoil_XSec_' + str(xsec_num) +'.dat') + name=str(wing_id) + '_airfoil_XSec_' + str(xsec_num) + vsp.WriteSeligAirfoil(name +'.dat', wing_id, float(xsec_num/total_xsec)) + return Airfoil(name=name, coordinates=name +'.dat') else: print(" Error: Could not determine airfoil") - return Airfoil("naca0012") def getXSecSpans(wing_id): xsec_spans = [] From bbb7b5d15121f7dd085beea50347f1d5a2eaf4f1 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 15:03:40 +0300 Subject: [PATCH 15/58] remove print statements --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 4 ---- aerosandbox/tools/openvsp/vsp_read_wing.py | 1 - 2 files changed, 5 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index c100ffb72..63311e546 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -76,16 +76,12 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. xyz_c[0] = percent_x_location*total_length - print(" percent x location: " + str(percent_x_location) + " xloc: " + str(xyz_c[0])) percent_y_location = vsp.GetParmVal(Y_Loc_P) - print(" percent y location: " + str(percent_y_location)) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. - print(" percent z location: " + str(percent_z_location)) height = vsp.GetXSecHeight(xsec) width = vsp.GetXSecWidth(xsec) effective_diameter = (height+width)/2. radius = effective_diameter/2. - print(" radius: " + str(radius)) #xsec shape not supported for aerosandbox FuselageXSec #shape = vsp.GetXSecShape(segment.vsp_data.xsec_id) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 99deb9716..ff783ea3a 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -96,7 +96,6 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): for increment in range(start, segment_num): xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, increment) xsecs.append(xsec_next) - print(xsecs) return Wing(tag, xyz_le, xsecs, symmetric) def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, increment): From 4932ae025e638cbb9f7984742f441020eb059918 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 15:16:40 +0300 Subject: [PATCH 16/58] cleanup --- aerosandbox/tools/openvsp/vsp_read.py | 6 +++--- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 9 --------- aerosandbox/tools/openvsp/vsp_read_wing.py | 13 ------------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read.py b/aerosandbox/tools/openvsp/vsp_read.py index 48c379865..51863a922 100644 --- a/aerosandbox/tools/openvsp/vsp_read.py +++ b/aerosandbox/tools/openvsp/vsp_read.py @@ -2,7 +2,8 @@ # vsp_read.py # Created: Jun 2018, T. St Francis -# Modified: Aug 2018, T. St Francis +# Modified: Aug 2021 Michael Shamberger +# Aug 2018, T. St Francis # Jan 2020, T. MacDonald # Jul 2020, E. Botero @@ -45,7 +46,6 @@ def vsp_read(tag): Inputs: 1. A tag for an XML file in format .vsp3. - 2. Units_type set to 'SI' (default) or 'Imperial' Outputs: Writes Aerosandbox vehicle @@ -83,7 +83,7 @@ def vsp_read(tag): vsp_fuselages.append(geom) if geom_name == 'Wing': vsp_wings.append(geom) - # No propeller geometry class available + # No propeller geometry class available #if geom_name == 'Propeller': # vsp_props.append(geom) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 63311e546..24101e9c5 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -1,12 +1,3 @@ -# Created: Jun 2018, T. St Francis -# Modified: Aug 2018, T. St Francis -# Jan 2020, T. MacDonald -# Jul 2020, E. Botero - -# ---------------------------------------------------------------------- -# Imports -# ---------------------------------------------------------------------- - import aerosandbox from aerosandbox.geometry import Fuselage from aerosandbox.geometry import FuselageXSec diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index ff783ea3a..2c992aa99 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -1,16 +1,3 @@ -## @ingroup Input_Output-OpenVSP -# vsp_read_wing.py - -# Created: Jun 2018, T. St Francis -# Modified: Aug 2018, T. St Francis -# Jan 2020, T. MacDonald -# Jul 2020, E. Botero -# May 2021, E. Botero - -# ---------------------------------------------------------------------- -# Imports -# ---------------------------------------------------------------------- - import aerosandbox from aerosandbox.geometry.airfoil import Airfoil from aerosandbox.geometry import Wing From a77afe91f3131ee17e8fd912a421ae17fd1ab45f Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Wed, 4 Aug 2021 21:40:46 +0300 Subject: [PATCH 17/58] fix airfoil but for naca 6 --- aerosandbox/tools/openvsp/vsp_read_wing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 2c992aa99..55b134c5e 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -101,14 +101,13 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): xsec_root_id = vsp.GetXSecSurf(wing_id, 0) total_xsec = vsp.GetNumXSec(xsec_root_id) print(" Processing airfoil: " + str(xsec_num) + " for wing: " + wing_id) + thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(xsec_num)) if vsp.GetXSecShape(xsec_id) == vsp.XS_FOUR_SERIES: # XSec shape: NACA 4-series - thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(xsec_num)) camber = vsp.GetParmVal(wing_id, 'Camber', 'XSecCurve_' + str(xsec_num)) if camber == 0.: camber_loc = 0. else: camber_loc = vsp.GetParmVal(wing_id, 'CamberLoc', 'XSecCurve_' + str(xsec_num)) - 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)) From 5816a8d56b2c5115d9495d5ce0f9ad4ec6e3d672 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 08:27:16 +0300 Subject: [PATCH 18/58] fix naca6 naming --- aerosandbox/tools/openvsp/vsp_read_wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 55b134c5e..36ea34590 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -121,7 +121,7 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): series_vsp = int(vsp.GetParmVal(wing_id, 'Series', 'XSecCurve_' + str(xsec_num))) 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] - tag = 'naca' + series + str(ideal_CL) + str(thick_cord_round) + ' a=' + str(np.around(a_value,1)) + tag = 'naca' + series + str(ideal_CL) + str(thick_cord_round) print(" Airfoil is XS_SIX_SERIES: " + tag) return Airfoil(name=tag) elif vsp.GetXSecShape(xsec_id) == vsp.XS_FILE_AIRFOIL: # XSec shape: 12 is type AF_FILE From c2bd975acc69ffea2ece211b65b60eb815ac6293 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 09:08:03 +0300 Subject: [PATCH 19/58] add debug --- aerosandbox/tools/openvsp/vsp_read_wing.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 36ea34590..49988a704 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -92,8 +92,14 @@ def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, in point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) xyz_le = np.array(list(p)) + print(" xyz_le: " + str(xyz_le) chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) + print(" Root_Chord_Wing: " + str(root_chord) + print(" Root_Chord_Xsec: " + str(chord) + chord_tip = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) + print(" Tip_Chord_Xsec: " + str(chord_tip) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) + print(" Twist: " + str(twist) airfoil = getXsecAirfoil(wing_id, xsec, increment) return WingXSec(xyz_le, chord, twist, airfoil=airfoil) From 67e0bb3e774cfa32eee11d01617e142edf4081b6 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 09:16:24 +0300 Subject: [PATCH 20/58] fix typo --- aerosandbox/tools/openvsp/vsp_read_wing.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 49988a704..a2a252e40 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -92,14 +92,14 @@ def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, in point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) xyz_le = np.array(list(p)) - print(" xyz_le: " + str(xyz_le) + print(" xyz_le: " + str(xyz_le)) chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) - print(" Root_Chord_Wing: " + str(root_chord) - print(" Root_Chord_Xsec: " + str(chord) + print(" Root_Chord_Wing: " + str(root_chord)) + print(" Root_Chord_Xsec: " + str(chord)) chord_tip = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) - print(" Tip_Chord_Xsec: " + str(chord_tip) + print(" Tip_Chord_Xsec: " + str(chord_tip)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) - print(" Twist: " + str(twist) + print(" Twist: " + str(twist)) airfoil = getXsecAirfoil(wing_id, xsec, increment) return WingXSec(xyz_le, chord, twist, airfoil=airfoil) From 5229c3e7cf9e8adb98507ee7f79bb70514548f03 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 09:36:40 +0300 Subject: [PATCH 21/58] try using tip chord --- aerosandbox/tools/openvsp/vsp_read_wing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index a2a252e40..e8f67d2c2 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -93,10 +93,10 @@ def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, in p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) xyz_le = np.array(list(p)) print(" xyz_le: " + str(xyz_le)) - chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) + chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) print(" Root_Chord_Wing: " + str(root_chord)) print(" Root_Chord_Xsec: " + str(chord)) - chord_tip = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) + chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) print(" Tip_Chord_Xsec: " + str(chord_tip)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) print(" Twist: " + str(twist)) From 84872b0ac9cc9c9b944726db7bcdd6bccd332a5b Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 09:39:49 +0300 Subject: [PATCH 22/58] try using tip chord --- aerosandbox/tools/openvsp/vsp_read_wing.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index e8f67d2c2..e55a275a4 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -77,15 +77,14 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): # Wing segments # ------------- start = 0 - root_chord = total_chord xsecs = [] # Convert VSP XSecs to aerosandbox segments. for increment in range(start, segment_num): - xsec_next = getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, increment) + xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment) xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) -def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, increment): +def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment): print(" Processing xsec: " + str(increment) + " for wing: " + wing_id) xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xsec = vsp.GetXSec(xsec_root_id, increment) @@ -94,10 +93,9 @@ def getWingXsec(wing_id, root_chord, total_proj_span, symmetric, segment_num, in xyz_le = np.array(list(p)) print(" xyz_le: " + str(xyz_le)) chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) - print(" Root_Chord_Wing: " + str(root_chord)) - print(" Root_Chord_Xsec: " + str(chord)) + print(" Root_Chord_Xsec: " + str(chord_root)) chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) - print(" Tip_Chord_Xsec: " + str(chord_tip)) + print(" Tip_Chord_Xsec: " + str(chord)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) print(" Twist: " + str(twist)) airfoil = getXsecAirfoil(wing_id, xsec, increment) From 67ff3545c1dcaae3bffc7f9250ad31a8fc5a7bbd Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 10:35:53 +0300 Subject: [PATCH 23/58] test hack --- aerosandbox/tools/openvsp/vsp_read_wing.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index e55a275a4..2b85fe0f2 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -72,6 +72,10 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): x_sec = vsp.GetXSec(xsec_root_id, 0) chord_parm = vsp.GetXSecParm(x_sec,'Root_Chord') total_chord = vsp.GetParmVal(chord_parm) + x_rot = vsp.GetParmVal( wing_id,'X_Rotation','XForm') + vertical = False + if x_rot > 70: + vertical = True # ------------- # Wing segments @@ -80,17 +84,22 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): xsecs = [] # Convert VSP XSecs to aerosandbox segments. for increment in range(start, segment_num): - xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment) + xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical) xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) -def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment): +def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical): print(" Processing xsec: " + str(increment) + " for wing: " + wing_id) xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xsec = vsp.GetXSec(xsec_root_id, increment) point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) - xyz_le = np.array(list(p)) + if vertical: + xyz_le[0] = p[0] + xyz_le[1] = p[2] + xyz_le[2] = p[1] + else: + xyz_le = np.array(list(p)) print(" xyz_le: " + str(xyz_le)) chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) print(" Root_Chord_Xsec: " + str(chord_root)) From fca9fb9c7d2b90dcd93097f821f0fe045b9e5653 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 10:39:14 +0300 Subject: [PATCH 24/58] test hack --- aerosandbox/tools/openvsp/vsp_read_wing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 2b85fe0f2..788ae7909 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -95,6 +95,7 @@ def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, ver point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) if vertical: + xyz_le = np.array([0, 0, 0]) xyz_le[0] = p[0] xyz_le[1] = p[2] xyz_le[2] = p[1] From 38be2b81879d30fe3c655090347d12ad8cbe375d Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 10:59:27 +0300 Subject: [PATCH 25/58] test hack --- aerosandbox/tools/openvsp/vsp_read_wing.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 788ae7909..c4359e8ef 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -69,12 +69,10 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). - x_sec = vsp.GetXSec(xsec_root_id, 0) - chord_parm = vsp.GetXSecParm(x_sec,'Root_Chord') - total_chord = vsp.GetParmVal(chord_parm) x_rot = vsp.GetParmVal( wing_id,'X_Rotation','XForm') vertical = False - if x_rot > 70: + print(" x_rot: " + str(x_rot)) + if x_rot > 70 or x_rot > -70: vertical = True # ------------- From c3261065ce4ada139c7c85a168d8597117042224 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 11:02:19 +0300 Subject: [PATCH 26/58] test hack --- aerosandbox/tools/openvsp/vsp_read_wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index c4359e8ef..9512e4eb9 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -72,7 +72,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): x_rot = vsp.GetParmVal( wing_id,'X_Rotation','XForm') vertical = False print(" x_rot: " + str(x_rot)) - if x_rot > 70 or x_rot > -70: + if x_rot > 70 or x_rot < -70: vertical = True # ------------- From 598a76cc149ff673e90f22c0b9d0812960af10fd Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 12:04:42 +0300 Subject: [PATCH 27/58] more hacking --- aerosandbox/tools/openvsp/vsp_read_wing.py | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 9512e4eb9..36cd2a7e7 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -80,17 +80,32 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): # ------------- start = 0 xsecs = [] - # Convert VSP XSecs to aerosandbox segments. + # Convert VSP XSecs to aerosandbox segments. + # if there are x xsec segments in openvsp, there will be x+1 in aerosandbox + # for the last xsec, get both the root and tip for increment in range(start, segment_num): - xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical) + xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "root") xsecs.append(xsec_next) + if increment == segment_num-1: + print("Adding tip xsec") + xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") + xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) -def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical): - print(" Processing xsec: " + str(increment) + " for wing: " + wing_id) +def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, chord_type): + print(" Processing xsec: " + str(increment) + " for wing: " + wing_id + "chord type: " + str(chord_type) + chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) + print(" Root_Chord_Xsec: " + str(chord_root)) + chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) + print(" Tip_Chord_Xsec: " + str(chord)) xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xsec = vsp.GetXSec(xsec_root_id, increment) - point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge + if chord_type = "root": + point = vsp.ComputeXSecPnt(xsec, 1.0) # get xsec point at leading edge of root chord + chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) + else #chord type is tip + point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord + chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) if vertical: xyz_le = np.array([0, 0, 0]) @@ -100,10 +115,6 @@ def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, ver else: xyz_le = np.array(list(p)) print(" xyz_le: " + str(xyz_le)) - chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) - print(" Root_Chord_Xsec: " + str(chord_root)) - chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) - print(" Tip_Chord_Xsec: " + str(chord)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) print(" Twist: " + str(twist)) airfoil = getXsecAirfoil(wing_id, xsec, increment) From 1b8632733e898445c6c215180ce62ae4ff7b54ab Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 12:30:08 +0300 Subject: [PATCH 28/58] add ) --- aerosandbox/tools/openvsp/vsp_read_wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 36cd2a7e7..47d5fe069 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -93,7 +93,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): return Wing(tag, xyz_le, xsecs, symmetric) def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, chord_type): - print(" Processing xsec: " + str(increment) + " for wing: " + wing_id + "chord type: " + str(chord_type) + print(" Processing xsec: " + str(increment) + " for wing: " + wing_id + "chord type: " + str(chord_type)) chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) print(" Root_Chord_Xsec: " + str(chord_root)) chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) From ede8459ab422ee741f3de44e2ba076450ab4c094 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 12:33:05 +0300 Subject: [PATCH 29/58] add ) --- aerosandbox/tools/openvsp/vsp_read_wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 47d5fe069..2c5009f99 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -100,7 +100,7 @@ def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, ver print(" Tip_Chord_Xsec: " + str(chord)) xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xsec = vsp.GetXSec(xsec_root_id, increment) - if chord_type = "root": + if chord_type == "root": point = vsp.ComputeXSecPnt(xsec, 1.0) # get xsec point at leading edge of root chord chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) else #chord type is tip From 25e4224048ae4dbbfcb85213d665f418e3960670 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 12:37:42 +0300 Subject: [PATCH 30/58] add ) --- aerosandbox/tools/openvsp/vsp_read_wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 2c5009f99..e62d7b5af 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -103,7 +103,7 @@ def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, ver if chord_type == "root": point = vsp.ComputeXSecPnt(xsec, 1.0) # get xsec point at leading edge of root chord chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) - else #chord type is tip + else: #chord type is tip point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) From ff11b21f251892b1277a81f3aa4c349357c80d6e Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 12:52:53 +0300 Subject: [PATCH 31/58] root/tip work --- aerosandbox/tools/openvsp/vsp_read_wing.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index e62d7b5af..b300042ec 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -84,16 +84,16 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): # if there are x xsec segments in openvsp, there will be x+1 in aerosandbox # for the last xsec, get both the root and tip for increment in range(start, segment_num): - xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "root") - xsecs.append(xsec_next) - if increment == segment_num-1: - print("Adding tip xsec") + if increment == 0: + print(" Adding tip xsec") xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") xsecs.append(xsec_next) + xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "root") + xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, chord_type): - print(" Processing xsec: " + str(increment) + " for wing: " + wing_id + "chord type: " + str(chord_type)) + print(" Processing xsec: " + str(increment) + " for wing: " + wing_id + " chord type: " + str(chord_type)) chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) print(" Root_Chord_Xsec: " + str(chord_root)) chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) From 06e3010cc0a8f9796f9d66b0d2bd1653463fe697 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 13:16:45 +0300 Subject: [PATCH 32/58] root/tip work --- aerosandbox/tools/openvsp/vsp_read_wing.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index b300042ec..1542e41dc 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -84,11 +84,11 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): # if there are x xsec segments in openvsp, there will be x+1 in aerosandbox # for the last xsec, get both the root and tip for increment in range(start, segment_num): - if increment == 0: - print(" Adding tip xsec") - xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") - xsecs.append(xsec_next) - xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "root") + #if increment == 0: + # print(" Adding tip xsec") + # xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") + # xsecs.append(xsec_next) + xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) @@ -101,7 +101,7 @@ def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, ver xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xsec = vsp.GetXSec(xsec_root_id, increment) if chord_type == "root": - point = vsp.ComputeXSecPnt(xsec, 1.0) # get xsec point at leading edge of root chord + point = vsp.ComputeXSecPnt(xsec, 9.0) # get xsec point at leading edge of root chord chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) else: #chord type is tip point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord From 53db5a0c5b2e0b543c5e81d8e8d7662f240e2cc0 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 13:51:54 +0300 Subject: [PATCH 33/58] root/tip work --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 24101e9c5..6a5d3d40a 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -65,14 +65,19 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): Y_Loc_P = vsp.GetXSecParm(xsec, 'YLocPercent') Z_Loc_P = vsp.GetXSecParm(xsec, 'ZLocPercent') + height = vsp.GetXSecHeight(xsec) + width = vsp.GetXSecWidth(xsec) percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. xyz_c[0] = percent_x_location*total_length percent_y_location = vsp.GetParmVal(Y_Loc_P) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. - height = vsp.GetXSecHeight(xsec) - width = vsp.GetXSecWidth(xsec) effective_diameter = (height+width)/2. radius = effective_diameter/2. + + point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord + p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + test = np.array(list(p)) + print(" fuse test: " + str(test)) #xsec shape not supported for aerosandbox FuselageXSec #shape = vsp.GetXSecShape(segment.vsp_data.xsec_id) From df27a3ffe9505beace8f36f7d196eae6d405c000 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 13:55:10 +0300 Subject: [PATCH 34/58] root/tip work --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 6a5d3d40a..d20d402f4 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -3,6 +3,7 @@ from aerosandbox.geometry import FuselageXSec import openvsp as vsp import aerosandbox.numpy as np +from ctypes import * # ---------------------------------------------------------------------- # vsp read fuselage From 807fbe45196ace0661a9ada6dbd44e1373e463f8 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 14:01:49 +0300 Subject: [PATCH 35/58] root/tip work --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index d20d402f4..429c57fcd 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -60,7 +60,13 @@ def vsp_read_fuselage(fuselage_id): def getVspXSec(xsec_root_id, xsec_num, total_length, increment): print(" Processing xsec: " + str(increment)) # Create the segment - xyz_c = np.array([0, 0, 0]) + # + # this is a point on the fuse and not the center point so entire geometry is shifted for now + point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord + p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + xyz_c = np.array(list(p)) + print(" fuse test: " + str(xyz_c)) + xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. X_Loc_P = vsp.GetXSecParm(xsec, 'XLocPercent') Y_Loc_P = vsp.GetXSecParm(xsec, 'YLocPercent') @@ -69,17 +75,12 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): height = vsp.GetXSecHeight(xsec) width = vsp.GetXSecWidth(xsec) percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. - xyz_c[0] = percent_x_location*total_length + #xyz_c[0] = percent_x_location*total_length percent_y_location = vsp.GetParmVal(Y_Loc_P) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. effective_diameter = (height+width)/2. radius = effective_diameter/2. - point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord - p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) - test = np.array(list(p)) - print(" fuse test: " + str(test)) - #xsec shape not supported for aerosandbox FuselageXSec #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'} From 8d92c88d39c90e029f5edf7a76a66d597e40d6e0 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 14:07:46 +0300 Subject: [PATCH 36/58] root/tip work --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 429c57fcd..364b011b9 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -61,13 +61,14 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): print(" Processing xsec: " + str(increment)) # Create the segment # + xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. + # this is a point on the fuse and not the center point so entire geometry is shifted for now point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) xyz_c = np.array(list(p)) print(" fuse test: " + str(xyz_c)) - xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. X_Loc_P = vsp.GetXSecParm(xsec, 'XLocPercent') Y_Loc_P = vsp.GetXSecParm(xsec, 'YLocPercent') Z_Loc_P = vsp.GetXSecParm(xsec, 'ZLocPercent') From 03e441a15f74b6b875e4307fe3a791d95395f034 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 14:27:17 +0300 Subject: [PATCH 37/58] fuse radius improvement --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 364b011b9..c6b293fbd 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -67,7 +67,7 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) xyz_c = np.array(list(p)) - print(" fuse test: " + str(xyz_c)) + print(" fuse coordinate: " + str(xyz_c)) X_Loc_P = vsp.GetXSecParm(xsec, 'XLocPercent') Y_Loc_P = vsp.GetXSecParm(xsec, 'YLocPercent') @@ -76,9 +76,11 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): height = vsp.GetXSecHeight(xsec) width = vsp.GetXSecWidth(xsec) percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. - #xyz_c[0] = percent_x_location*total_length + print(" percent x location", percent_x_location)) percent_y_location = vsp.GetParmVal(Y_Loc_P) + print(" percent y location", percent_y_location)) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. + print(" percent z location", percent_z_location)) effective_diameter = (height+width)/2. radius = effective_diameter/2. From ecbd96d12f04ea2568aab9cc649effadb755a2c3 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 14:29:33 +0300 Subject: [PATCH 38/58] fuse radius improvement --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index c6b293fbd..bd8c5c437 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -76,11 +76,11 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): height = vsp.GetXSecHeight(xsec) width = vsp.GetXSecWidth(xsec) percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. - print(" percent x location", percent_x_location)) + print(" percent x location", str(percent_x_location)) percent_y_location = vsp.GetParmVal(Y_Loc_P) - print(" percent y location", percent_y_location)) + print(" percent y location", str(percent_y_location)) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. - print(" percent z location", percent_z_location)) + print(" percent z location", str(percent_z_location)) effective_diameter = (height+width)/2. radius = effective_diameter/2. From f15617e9e6935391efc770f46dc161d5ae6faefa Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 14:46:25 +0300 Subject: [PATCH 39/58] fuse radius improvement --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index bd8c5c437..f8c48455a 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -68,6 +68,8 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) xyz_c = np.array(list(p)) print(" fuse coordinate: " + str(xyz_c)) + test = getXsecCenter(xsec) + print(" test center: " + str(test)) X_Loc_P = vsp.GetXSecParm(xsec, 'XLocPercent') Y_Loc_P = vsp.GetXSecParm(xsec, 'YLocPercent') @@ -90,6 +92,18 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): #vsp_data.shape = shape_dict[shape] return FuselageXSec(xyz_c, radius) +def getXsecCenter(xsec): + x = [] + y = [] + z = [] + for increment in np.linspace(0,1,100): + point = vsp.ComputeXSecPnt(xsec, increment) # get xsec point at leading edge of tip chord + p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + x.append(p[0]) + y.append(p[1]) + z.append(p[2]) + return np.array([sum(x) / len(x), sum(y) / len(y), sum(z) / len(z)) + def get_fuselage_height(fuselage, location): """This linearly estimates fuselage height at any percentage point (0,100) along fuselage length. From 8d212643199449e7534244acc13cc17606b04b11 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 14:49:50 +0300 Subject: [PATCH 40/58] fuse radius improvement --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index f8c48455a..bda7c494a 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -102,7 +102,7 @@ def getXsecCenter(xsec): x.append(p[0]) y.append(p[1]) z.append(p[2]) - return np.array([sum(x) / len(x), sum(y) / len(y), sum(z) / len(z)) + return np.array([sum(x) / len(x), sum(y) / len(y), sum(z) / len(z)]) def get_fuselage_height(fuselage, location): From 39eeb4d0ddc213905415e4c38567945ea025439b Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 14:59:43 +0300 Subject: [PATCH 41/58] root/tip work --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index bda7c494a..bb6acb52d 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -64,12 +64,12 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. # this is a point on the fuse and not the center point so entire geometry is shifted for now - point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord - p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) - xyz_c = np.array(list(p)) - print(" fuse coordinate: " + str(xyz_c)) - test = getXsecCenter(xsec) - print(" test center: " + str(test)) + #point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord + #p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + #xyz_c = np.array(list(p)) + #print(" fuse coordinate: " + str(xyz_c)) + xyz_c = getXsecCenter(xsec) + print(" center: " + str(xyz_c)) X_Loc_P = vsp.GetXSecParm(xsec, 'XLocPercent') Y_Loc_P = vsp.GetXSecParm(xsec, 'YLocPercent') From 3c0d590ba38939de4f0d54ffb03498a20fdca18b Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 18:26:57 +0300 Subject: [PATCH 42/58] check rotation --- aerosandbox/tools/openvsp/vsp_read_wing.py | 27 ++++++++++------------ 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 1542e41dc..6a625eb34 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -33,14 +33,9 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): 1. VSP 10-digit geom ID for wing. Outputs: - Writes aerosandbox wing object - - Properties Used: - N/A + returns aerosandbox wing object """ print("Converting wing: " + wing_id) - x_rot = vsp.GetParmVal(wing_id,'X_Rotation','XForm') - # Apply a tag to the wing if vsp.GetGeomName(wing_id): tag = vsp.GetGeomName(wing_id) @@ -48,12 +43,20 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): tag = tag else: tag = 'winggeom' + + # Wing rotation + xyz_rot = np.array([0, 0, 0]) + xyz_rot[0] = vsp.GetParmVal(wing_id,'X_Rotation','XForm') + xyz_rot[1] = vsp.GetParmVal(wing_id,'Y_Rotation','XForm') + xyz_rot[2] = vsp.GetParmVal(wing_id,'Z_Rotation','XForm') + print(" wing xyz_rot: " + str(xyz_rot)) # Wing origin xyz_le = np.array([0, 0, 0]) xyz_le[0] = vsp.GetParmVal(wing_id, 'X_Location', 'XForm') xyz_le[1] = vsp.GetParmVal(wing_id, 'Y_Location', 'XForm') xyz_le[2] = vsp.GetParmVal(wing_id, 'Z_Location', 'XForm') + print(" wing xyz_le: " + str(xyz_le)) # Wing Symmetry sym_planar = vsp.GetParmVal(wing_id, 'Sym_Planar_Flag', 'Sym') @@ -69,21 +72,15 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). - x_rot = vsp.GetParmVal( wing_id,'X_Rotation','XForm') vertical = False print(" x_rot: " + str(x_rot)) - if x_rot > 70 or x_rot < -70: + if xyz_rot[0] > 70 or xyz_rot[0] < -70: vertical = True - # ------------- - # Wing segments - # ------------- - start = 0 + # wing segments xsecs = [] # Convert VSP XSecs to aerosandbox segments. - # if there are x xsec segments in openvsp, there will be x+1 in aerosandbox - # for the last xsec, get both the root and tip - for increment in range(start, segment_num): + for increment in range(0, segment_num): #if increment == 0: # print(" Adding tip xsec") # xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") From 51b9d422b8273fcb9ca450752c99cea8ccc2574d Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 18:32:19 +0300 Subject: [PATCH 43/58] check rotation --- aerosandbox/tools/openvsp/vsp_read_wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 6a625eb34..72df339c2 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -73,7 +73,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). vertical = False - print(" x_rot: " + str(x_rot)) + print(" x_rot: " + str(xyz_rot[0])) if xyz_rot[0] > 70 or xyz_rot[0] < -70: vertical = True From 16f62cf0fbffcecf05dd37ec29b20970ea4b6c63 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 19:53:29 +0300 Subject: [PATCH 44/58] try rotation matrix --- aerosandbox/tools/openvsp/vsp_read_wing.py | 44 +++++++++++++++++----- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 72df339c2..310c93f42 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -85,11 +85,11 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): # print(" Adding tip xsec") # xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") # xsecs.append(xsec_next) - xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") + xsec_next = getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, vertical, "tip") xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) -def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, chord_type): +def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, vertical, chord_type): print(" Processing xsec: " + str(increment) + " for wing: " + wing_id + " chord type: " + str(chord_type)) chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) print(" Root_Chord_Xsec: " + str(chord_root)) @@ -104,13 +104,24 @@ def getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, ver point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) - if vertical: - xyz_le = np.array([0, 0, 0]) - xyz_le[0] = p[0] - xyz_le[1] = p[2] - xyz_le[2] = p[1] - else: - xyz_le = np.array(list(p)) + + # transform point using the wing rotation matrix + xyz_le = np.array(list(p)) + xyz_le = x_rotation(xyz_le, math.radians(xyz_rot[0] + print(" xyz_le after x rotation: " + str(xyz_le)) + xyz_le = y_rotation(xyz_le, math.radians(xyz_rot[1] + print(" xyz_le after y rotation: " + str(xyz_le)) + xyz_le = z_rotation(xyz_le, math.radians(xyz_rot[2] + print(" xyz_le after z rotation: " + str(xyz_le)) + + #if vertical: + # xyz_le = np.array([0, 0, 0]) + # xyz_le[0] = p[0] + # xyz_le[1] = p[2] + # xyz_le[2] = p[1] + #else: + # xyz_le = np.array(list(p)) + print(" xyz_le: " + str(xyz_le)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) print(" Twist: " + str(twist)) @@ -152,6 +163,21 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): else: print(" Error: Could not determine airfoil") +def x_rotation(vector,theta): + """Rotates 3-D vector around x-axis""" + R = np.array([[1,0,0],[0,np.cos(theta),-np.sin(theta)],[0, np.sin(theta), np.cos(theta)]]) + return np.dot(R,vector) + +def y_rotation(vector,theta): + """Rotates 3-D vector around y-axis""" + R = np.array([[np.cos(theta),0,np.sin(theta)],[0,1,0],[-np.sin(theta), 0, np.cos(theta)]]) + return np.dot(R,vector) + +def z_rotation(vector,theta): + """Rotates 3-D vector around z-axis""" + R = np.array([[np.cos(theta), -np.sin(theta),0],[np.sin(theta), np.cos(theta),0],[0,0,1]]) + return np.dot(R,vector) + def getXSecSpans(wing_id): xsec_spans = [] xsec_root_id = vsp.GetXSecSurf(wing_id, 0) From cb86bd1637ed71f24f59b7b55c9e9074e98f280a Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 19:56:07 +0300 Subject: [PATCH 45/58] try rotation matrix --- aerosandbox/tools/openvsp/vsp_read_wing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 310c93f42..8aeca7cc5 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -107,11 +107,11 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, vertical, c # transform point using the wing rotation matrix xyz_le = np.array(list(p)) - xyz_le = x_rotation(xyz_le, math.radians(xyz_rot[0] + xyz_le = x_rotation(xyz_le, math.radians(xyz_rot[0])) print(" xyz_le after x rotation: " + str(xyz_le)) - xyz_le = y_rotation(xyz_le, math.radians(xyz_rot[1] + xyz_le = y_rotation(xyz_le, math.radians(xyz_rot[1])) print(" xyz_le after y rotation: " + str(xyz_le)) - xyz_le = z_rotation(xyz_le, math.radians(xyz_rot[2] + xyz_le = z_rotation(xyz_le, math.radians(xyz_rot[2])) print(" xyz_le after z rotation: " + str(xyz_le)) #if vertical: From 45f98c9a0b98ab045e50859f94e6c31b9202ba39 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Thu, 5 Aug 2021 19:58:11 +0300 Subject: [PATCH 46/58] try rotation matrix --- aerosandbox/tools/openvsp/vsp_read_wing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 8aeca7cc5..2c8423b84 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -1,3 +1,4 @@ +import math import aerosandbox from aerosandbox.geometry.airfoil import Airfoil from aerosandbox.geometry import Wing From a7cac6a8ad874b391aa614b2504980eaeb85a2d7 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 08:44:09 +0300 Subject: [PATCH 47/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 29 ++++++++-------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 2c8423b84..91e408295 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -73,10 +73,6 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). - vertical = False - print(" x_rot: " + str(xyz_rot[0])) - if xyz_rot[0] > 70 or xyz_rot[0] < -70: - vertical = True # wing segments xsecs = [] @@ -84,7 +80,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): for increment in range(0, segment_num): #if increment == 0: # print(" Adding tip xsec") - # xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, vertical, "tip") + # xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, "tip") # xsecs.append(xsec_next) xsec_next = getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, vertical, "tip") xsecs.append(xsec_next) @@ -99,31 +95,28 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, vertical, c xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xsec = vsp.GetXSec(xsec_root_id, increment) if chord_type == "root": - point = vsp.ComputeXSecPnt(xsec, 9.0) # get xsec point at leading edge of root chord + point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of root chord chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) else: #chord type is tip point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + xsecsurface = vsp.GetXSecSurf(wing_id, increment) + surfacepoint = vsp.CompPnt01(wing_id, xsecsurface, 0.0, 0.0) + surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacetest = np.array(list(surfacep)) + print(" xsec surface point: " + str(surfacetest)) + # transform point using the wing rotation matrix xyz_le = np.array(list(p)) xyz_le = x_rotation(xyz_le, math.radians(xyz_rot[0])) - print(" xyz_le after x rotation: " + str(xyz_le)) + print(" xyz_le after x rotation: " + str(xyz_le)) xyz_le = y_rotation(xyz_le, math.radians(xyz_rot[1])) - print(" xyz_le after y rotation: " + str(xyz_le)) + print(" xyz_le after y rotation: " + str(xyz_le)) xyz_le = z_rotation(xyz_le, math.radians(xyz_rot[2])) - print(" xyz_le after z rotation: " + str(xyz_le)) - - #if vertical: - # xyz_le = np.array([0, 0, 0]) - # xyz_le[0] = p[0] - # xyz_le[1] = p[2] - # xyz_le[2] = p[1] - #else: - # xyz_le = np.array(list(p)) + print(" xyz_le after z rotation: " + str(xyz_le)) - print(" xyz_le: " + str(xyz_le)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) print(" Twist: " + str(twist)) airfoil = getXsecAirfoil(wing_id, xsec, increment) From b13e7e5bc53b8f9385de26199a977dd4a84e3f49 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 08:47:37 +0300 Subject: [PATCH 48/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 91e408295..0b5ba9124 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -82,11 +82,11 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): # print(" Adding tip xsec") # xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, "tip") # xsecs.append(xsec_next) - xsec_next = getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, vertical, "tip") + xsec_next = getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, "tip") xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) -def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, vertical, chord_type): +def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type): print(" Processing xsec: " + str(increment) + " for wing: " + wing_id + " chord type: " + str(chord_type)) chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) print(" Root_Chord_Xsec: " + str(chord_root)) From d1b9dc8acd72f1484fa2d4886fcdb694e813720b Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 09:05:17 +0300 Subject: [PATCH 49/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 0b5ba9124..6ad3e071e 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -102,8 +102,7 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) - xsecsurface = vsp.GetXSecSurf(wing_id, increment) - surfacepoint = vsp.CompPnt01(wing_id, xsecsurface, 0.0, 0.0) + surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, 0.0) surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) surfacetest = np.array(list(surfacep)) print(" xsec surface point: " + str(surfacetest)) From a935837ce2854dfe1b93e03619fe752777cd0a51 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 09:13:22 +0300 Subject: [PATCH 50/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 6ad3e071e..e75b90fff 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -51,6 +51,8 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): xyz_rot[1] = vsp.GetParmVal(wing_id,'Y_Rotation','XForm') xyz_rot[2] = vsp.GetParmVal(wing_id,'Z_Rotation','XForm') print(" wing xyz_rot: " + str(xyz_rot)) + xyz_rot = xyz_rot * (-1) + print(" wing xyz_rot reversed: " + str(xyz_rot)) # Wing origin xyz_le = np.array([0, 0, 0]) From fdf211a6142f1b18043f684756910f338552fa33 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 09:46:14 +0300 Subject: [PATCH 51/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index e75b90fff..53a936cd6 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -51,8 +51,6 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): xyz_rot[1] = vsp.GetParmVal(wing_id,'Y_Rotation','XForm') xyz_rot[2] = vsp.GetParmVal(wing_id,'Z_Rotation','XForm') print(" wing xyz_rot: " + str(xyz_rot)) - xyz_rot = xyz_rot * (-1) - print(" wing xyz_rot reversed: " + str(xyz_rot)) # Wing origin xyz_le = np.array([0, 0, 0]) @@ -111,6 +109,7 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) # transform point using the wing rotation matrix xyz_le = np.array(list(p)) + print(" xyz_le before rotation: " + str(xyz_le)) xyz_le = x_rotation(xyz_le, math.radians(xyz_rot[0])) print(" xyz_le after x rotation: " + str(xyz_le)) xyz_le = y_rotation(xyz_le, math.radians(xyz_rot[1])) From 16d31a6b17887e01908e48295788f074e4435c53 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 10:26:45 +0300 Subject: [PATCH 52/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 53a936cd6..00e6dfc30 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -102,10 +102,25 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacepoint =vsp.ComputeXSecPnt(xsec, 1.0) + surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacetest = np.array(list(surfacep)) + print(" xsec test surface point: " + str(surfacetest)) + surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, 0.0) surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) surfacetest = np.array(list(surfacep)) - print(" xsec surface point: " + str(surfacetest)) + print(" xsec test surface point: " + str(surfacetest)) + + surfacepoint = vsp.CompPnt01(wing_id, 0, 1.0, 0.0) + surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacetest = np.array(list(surfacep)) + print(" xsec test surface point: " + str(surfacetest)) + + surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, 1.0) + surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacetest = np.array(list(surfacep)) + print(" xsec test surface point: " + str(surfacetest)) # transform point using the wing rotation matrix xyz_le = np.array(list(p)) From 8c1f051978f9c1c83cb4c2f43663121981778802 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 10:33:29 +0300 Subject: [PATCH 53/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 00e6dfc30..1c9ebab5b 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -102,7 +102,7 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) - surfacepoint =vsp.ComputeXSecPnt(xsec, 1.0) + surfacepoint =vsp.ComputeXSecPnt(xsec, .5) surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) surfacetest = np.array(list(surfacep)) print(" xsec test surface point: " + str(surfacetest)) @@ -112,12 +112,12 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) surfacetest = np.array(list(surfacep)) print(" xsec test surface point: " + str(surfacetest)) - surfacepoint = vsp.CompPnt01(wing_id, 0, 1.0, 0.0) + surfacepoint = vsp.CompPnt01(wing_id, 0, .5, 0.0) surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) surfacetest = np.array(list(surfacep)) print(" xsec test surface point: " + str(surfacetest)) - surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, 1.0) + surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, .5) surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) surfacetest = np.array(list(surfacep)) print(" xsec test surface point: " + str(surfacetest)) From 982315ef25451cd500d6fce1602c9d623eacb7c2 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 10:41:57 +0300 Subject: [PATCH 54/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 1c9ebab5b..ad73b88e2 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -103,22 +103,22 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) surfacepoint =vsp.ComputeXSecPnt(xsec, .5) - surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(surfacepoint.data()))) surfacetest = np.array(list(surfacep)) print(" xsec test surface point: " + str(surfacetest)) surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, 0.0) - surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(surfacepoint.data()))) surfacetest = np.array(list(surfacep)) print(" xsec test surface point: " + str(surfacetest)) surfacepoint = vsp.CompPnt01(wing_id, 0, .5, 0.0) - surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(surfacepoint.data()))) surfacetest = np.array(list(surfacep)) print(" xsec test surface point: " + str(surfacetest)) surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, .5) - surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) + surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(surfacepoint.data()))) surfacetest = np.array(list(surfacep)) print(" xsec test surface point: " + str(surfacetest)) From f84e2d900b248306913bc3441958dee049e53647 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 10:53:35 +0300 Subject: [PATCH 55/58] try using geometry surface --- aerosandbox/tools/openvsp/vsp_read_wing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index ad73b88e2..493b0dc6e 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -95,10 +95,10 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xsec = vsp.GetXSec(xsec_root_id, increment) if chord_type == "root": - point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of root chord + point = vsp.ComputeXSecPnt(xsec, 0.5) # get xsec point at leading edge of root chord chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) else: #chord type is tip - point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord + point = vsp.ComputeXSecPnt(xsec, 0.5) # get xsec point at leading edge of tip chord chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) From 4eda7db92ea50ff283c4bfafd4eb1cffc1bd724c Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 11:30:52 +0300 Subject: [PATCH 56/58] code cleanup --- .../tools/openvsp/vsp_read_fuselage.py | 6 ---- aerosandbox/tools/openvsp/vsp_read_wing.py | 30 +------------------ 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index bb6acb52d..dbdd555bf 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -62,12 +62,6 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): # Create the segment # xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID. - - # this is a point on the fuse and not the center point so entire geometry is shifted for now - #point = vsp.ComputeXSecPnt(xsec, 0.0) # get xsec point at leading edge of tip chord - #p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) - #xyz_c = np.array(list(p)) - #print(" fuse coordinate: " + str(xyz_c)) xyz_c = getXsecCenter(xsec) print(" center: " + str(xyz_c)) diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index 493b0dc6e..f3ea18aca 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -70,7 +70,6 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): symmetric = False #More top level parameters - total_proj_span = vsp.GetParmVal(wing_id, 'TotalProjectedSpan', 'WingGeom') xsec_root_id = vsp.GetXSecSurf(wing_id, 0) # This is how VSP stores surfaces. segment_num = vsp.GetNumXSec(xsec_root_id) # Get number of wing segments (is one more than the VSP GUI shows). @@ -78,10 +77,6 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): xsecs = [] # Convert VSP XSecs to aerosandbox segments. for increment in range(0, segment_num): - #if increment == 0: - # print(" Adding tip xsec") - # xsec_next = getWingXsec(wing_id, total_proj_span, symmetric, segment_num, increment, "tip") - # xsecs.append(xsec_next) xsec_next = getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, "tip") xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) @@ -102,35 +97,12 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) chord = vsp.GetParmVal(wing_id, 'Tip_Chord', 'XSec_' + str(increment)) p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data()))) - surfacepoint =vsp.ComputeXSecPnt(xsec, .5) - surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(surfacepoint.data()))) - surfacetest = np.array(list(surfacep)) - print(" xsec test surface point: " + str(surfacetest)) - - surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, 0.0) - surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(surfacepoint.data()))) - surfacetest = np.array(list(surfacep)) - print(" xsec test surface point: " + str(surfacetest)) - - surfacepoint = vsp.CompPnt01(wing_id, 0, .5, 0.0) - surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(surfacepoint.data()))) - surfacetest = np.array(list(surfacep)) - print(" xsec test surface point: " + str(surfacetest)) - - surfacepoint = vsp.CompPnt01(wing_id, 0, 0.0, .5) - surfacep = (c_double * 3).from_address(int(np.ctypeslib.as_array(surfacepoint.data()))) - surfacetest = np.array(list(surfacep)) - print(" xsec test surface point: " + str(surfacetest)) - # transform point using the wing rotation matrix xyz_le = np.array(list(p)) - print(" xyz_le before rotation: " + str(xyz_le)) xyz_le = x_rotation(xyz_le, math.radians(xyz_rot[0])) - print(" xyz_le after x rotation: " + str(xyz_le)) xyz_le = y_rotation(xyz_le, math.radians(xyz_rot[1])) - print(" xyz_le after y rotation: " + str(xyz_le)) xyz_le = z_rotation(xyz_le, math.radians(xyz_rot[2])) - print(" xyz_le after z rotation: " + str(xyz_le)) + print(" xyz_le after rotation: " + str(xyz_le)) twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(increment)) print(" Twist: " + str(twist)) From 79ef0360ce54000d13f8bcd857bb9ae9d851181b Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 12:18:23 +0300 Subject: [PATCH 57/58] cleanup and add comments --- aerosandbox/tools/openvsp/vsp_read.py | 15 +++------------ aerosandbox/tools/openvsp/vsp_read_fuselage.py | 2 +- aerosandbox/tools/openvsp/vsp_read_wing.py | 10 ++++++---- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read.py b/aerosandbox/tools/openvsp/vsp_read.py index 51863a922..c71d3a6ee 100644 --- a/aerosandbox/tools/openvsp/vsp_read.py +++ b/aerosandbox/tools/openvsp/vsp_read.py @@ -1,15 +1,9 @@ -## @ingroup Input_Output-OpenVSP -# vsp_read.py - # Created: Jun 2018, T. St Francis # Modified: Aug 2021 Michael Shamberger # Aug 2018, T. St Francis # Jan 2020, T. MacDonald # Jul 2020, E. Botero - -# ---------------------------------------------------------------------- -# Imports -# ---------------------------------------------------------------------- +# Original code taken from Suave project and modified for AeroSandbox import aerosandbox from aerosandbox.geometry import Airplane @@ -23,9 +17,6 @@ # ---------------------------------------------------------------------- # vsp read # ---------------------------------------------------------------------- - - -## @ingroup Input_Output-OpenVSP def vsp_read(tag): """This reads an OpenVSP vehicle geometry and writes it into a Aerosandbox vehicle format. Includes wings, fuselages, and propellers. @@ -39,7 +30,7 @@ def vsp_read(tag): 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.21.1 + 3. Written for OpenVSP 3.24 Source: N/A @@ -83,7 +74,7 @@ def vsp_read(tag): vsp_fuselages.append(geom) if geom_name == 'Wing': vsp_wings.append(geom) - # No propeller geometry class available + # No aerosandbox propeller geometry class available #if geom_name == 'Propeller': # vsp_props.append(geom) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index dbdd555bf..2ff23fd23 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -20,7 +20,7 @@ def vsp_read_fuselage(fuselage_id): 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.21.1 + 5. Written for OpenVSP 3.24 Source: N/A diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index f3ea18aca..fa39bee8a 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -24,10 +24,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): Assumptions: 1. OpenVSP wing is divided into segments ("XSecs" in VSP). - 2. Written for OpenVSP 3.21.1 - - Source: - N/A + 2. Written for OpenVSP 3.24 Inputs: 0. Pre-loaded VSP vehicle in memory, via vsp_read. @@ -81,6 +78,7 @@ def vsp_read_wing(wing_id, write_airfoil_file=True): xsecs.append(xsec_next) return Wing(tag, xyz_le, xsecs, symmetric) +# create a aerosandbox xsec by looking at the openvsp xsec def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type): print(" Processing xsec: " + str(increment) + " for wing: " + wing_id + " chord type: " + str(chord_type)) chord_root = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) @@ -109,6 +107,7 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) airfoil = getXsecAirfoil(wing_id, xsec, increment) return WingXSec(xyz_le, chord, twist, airfoil=airfoil) +# determine the airfoil type def getXsecAirfoil(wing_id, xsec_id, xsec_num): xsec_root_id = vsp.GetXSecSurf(wing_id, 0) total_xsec = vsp.GetNumXSec(xsec_root_id) @@ -144,16 +143,19 @@ def getXsecAirfoil(wing_id, xsec_id, xsec_num): else: print(" Error: Could not determine airfoil") +# x rotation of a point def x_rotation(vector,theta): """Rotates 3-D vector around x-axis""" R = np.array([[1,0,0],[0,np.cos(theta),-np.sin(theta)],[0, np.sin(theta), np.cos(theta)]]) return np.dot(R,vector) +# y rotation of a point def y_rotation(vector,theta): """Rotates 3-D vector around y-axis""" R = np.array([[np.cos(theta),0,np.sin(theta)],[0,1,0],[-np.sin(theta), 0, np.cos(theta)]]) return np.dot(R,vector) +# z rotation of a point def z_rotation(vector,theta): """Rotates 3-D vector around z-axis""" R = np.array([[np.cos(theta), -np.sin(theta),0],[np.sin(theta), np.cos(theta),0],[0,0,1]]) From 3d70c07b7f95b1dd3d39c83d8c01a7ca2cec25c7 Mon Sep 17 00:00:00 2001 From: Michael Shamberger Date: Fri, 6 Aug 2021 12:28:13 +0300 Subject: [PATCH 58/58] cleanup and add comments --- aerosandbox/tools/openvsp/vsp_read_fuselage.py | 12 ------------ aerosandbox/tools/openvsp/vsp_read_wing.py | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/aerosandbox/tools/openvsp/vsp_read_fuselage.py b/aerosandbox/tools/openvsp/vsp_read_fuselage.py index 2ff23fd23..34bae1d91 100644 --- a/aerosandbox/tools/openvsp/vsp_read_fuselage.py +++ b/aerosandbox/tools/openvsp/vsp_read_fuselage.py @@ -22,9 +22,6 @@ def vsp_read_fuselage(fuselage_id): of the vehicle or in front (to make all X-coordinates of vehicle positive). 5. Written for OpenVSP 3.24 - Source: - N/A - Inputs: 0. Pre-loaded VSP vehicle in memory, via vsp_read. 1. VSP 10-digit geom ID for fuselage. @@ -72,11 +69,8 @@ def getVspXSec(xsec_root_id, xsec_num, total_length, increment): height = vsp.GetXSecHeight(xsec) width = vsp.GetXSecWidth(xsec) percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length. - print(" percent x location", str(percent_x_location)) percent_y_location = vsp.GetParmVal(Y_Loc_P) - print(" percent y location", str(percent_y_location)) percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center. - print(" percent z location", str(percent_z_location)) effective_diameter = (height+width)/2. radius = effective_diameter/2. @@ -102,12 +96,6 @@ def getXsecCenter(xsec): def get_fuselage_height(fuselage, location): """This linearly estimates fuselage height at any percentage point (0,100) along fuselage length. - Assumptions: - Written for OpenVSP 3.16.1 - - Source: - N/A - Inputs: 0. Pre-loaded VSP vehicle in memory, via vsp_read. 1. Suave fuselage [object], containing fuselage.vsp_data.xsec_num in its data structure. diff --git a/aerosandbox/tools/openvsp/vsp_read_wing.py b/aerosandbox/tools/openvsp/vsp_read_wing.py index fa39bee8a..5488bf47a 100644 --- a/aerosandbox/tools/openvsp/vsp_read_wing.py +++ b/aerosandbox/tools/openvsp/vsp_read_wing.py @@ -88,7 +88,7 @@ def getWingXsec(wing_id, xyz_rot, symmetric, segment_num, increment, chord_type) xsec_root_id = vsp.GetXSecSurf(wing_id, 0) xsec = vsp.GetXSec(xsec_root_id, increment) if chord_type == "root": - point = vsp.ComputeXSecPnt(xsec, 0.5) # get xsec point at leading edge of root chord + point = vsp.ComputeXSecPnt(xsec, 0.5) # get xsec point at leading edge of root chord. (0/1 are trailing edge) chord = vsp.GetParmVal(wing_id, 'Root_Chord', 'XSec_' + str(increment)) else: #chord type is tip point = vsp.ComputeXSecPnt(xsec, 0.5) # get xsec point at leading edge of tip chord