Source code for RCAIDE.Library.Methods.Aerodynamics.Vortex_Lattice_Method.generate_vortex_distribution

# generate_vortex_distribution.py
# 
# Created:  May 2018, M. Clarke
# Modified: Apr 2020, M. Clarke
#           Jun 2021, A. Blaufox

# ----------------------------------------------------------------------
#  Imports
# ----------------------------------------------------------------------
import RCAIDE
from RCAIDE.Framework.Core                                                              import  Data
from RCAIDE.Library.Components.Wings                                                    import All_Moving_Surface 
from RCAIDE.Library.Methods.Aerodynamics.Vortex_Lattice_Method.generate_VD_helpers      import postprocess_VD
from RCAIDE.Library.Methods.Aerodynamics.Vortex_Lattice_Method.make_VLM_wings           import make_VLM_wings 
from RCAIDE.Library.Methods.Aerodynamics.Vortex_Lattice_Method.deflect_control_surface  import deflect_control_surface
from RCAIDE.Library.Methods.Geometry.Airfoil                                            import import_airfoil_geometry
  
# package imports 
import numpy as np

# ----------------------------------------------------------------------
#  Generate Vortex Distribution
# ----------------------------------------------------------------------
[docs] def generate_vortex_distribution(geometry,settings): ''' Compute the coordinates of panels, vortices , control points and geometry used to build the influence coefficient matrix. A different discretization (n_sw and n_cw) may be defined for each type of major section (wings and fuselages). Control surfaces are modelled as wings, but adapt their panel density to that of the area in which they reside on their own wing. Assumptions: Below is a schematic of the coordinates of an arbitrary panel XA1 ____________________________ XB1 | | | bound vortex | XAH| ________________________ |XBH | | XCH | | | | | | | | | | | | | | | | | | | | 0 <--control | | | | XC point | | | | | | XA2 |_|________________________|_|XB2 | | | trailing | | <-- vortex --> | | legs | In addition, all control surfaces should be appended directly to the wing, not the wing segments For control surfaces, "positve" deflection corresponds to the RH rule where the axis of rotation is the OUTBOARD-pointing hinge vector symmetry: the LH rule is applied to the reflected surface for non-ailerons. Ailerons follow a RH rule for both sides Source: None Inputs: geometry.wings [Unitless] settings.floating_point_precision [np.dtype] Of the following settings, the user should define either the number_ atrributes or the wing_ and fuse_ attributes. settings.number_of_spanwise_vortices - a base number of vortices to be applied to both wings and fuselages settings.number_of_chordwise_vortices - a base number of vortices to be applied to both wings and fuselages settings.wing_spanwise_vortices - the number of vortices to be applied to only the wings settings.wing_chordwise_vortices - the number of vortices to be applied to only the wings settings.fuselage_spanwise_vortices - the number of vortices to be applied to only the fuslages settings.fuselage_chordwise_vortices - the number of vortices to be applied to only the fuselages Outputs: VD - vehicle vortex distribution [Unitless] Properties Used: N/A ''' # --------------------------------------------------------------------------------------- # STEP 0: Unpack settings # --------------------------------------------------------------------------------------- #unpack other settings---------------------------------------------------- spc = settings.spanwise_cosine_spacing model_fuselage = settings.model_fuselage precision = settings.floating_point_precision show_prints = settings.verbose if ('verbose' in settings.keys()) else False # unpack discretization settings------------------------------------------ n_sw_global = settings.number_of_spanwise_vortices n_cw_global = settings.number_of_chordwise_vortices n_sw_wing = settings.wing_spanwise_vortices n_cw_wing = settings.wing_chordwise_vortices n_sw_fuse = settings.fuselage_spanwise_vortices n_cw_fuse = settings.fuselage_chordwise_vortices #make sure n_cw and n_sw are both defined or not defined invalid_global_n = bool(n_sw_global) != bool(n_cw_global) invalid_wing_n = bool(n_sw_wing) != bool(n_cw_wing) invalid_fuse_n = bool(n_sw_fuse) != bool(n_cw_fuse) invalid_separate_n = bool(n_sw_wing) != bool(n_sw_fuse) if invalid_global_n: raise AssertionError('If using global surface discretization, both n_sw and n_cw must be defined') elif invalid_wing_n or invalid_fuse_n: raise AssertionError('If using separate surface discretization, all n_sw and n_cw values must be defined') elif invalid_separate_n: raise AssertionError('If using separate surface discretization, both wing and fuselage discretization must be defined') #make sure that global and separate settings aren't both defined global_n_defined = bool(n_sw_global) separate_n_defined = bool(n_sw_wing) if global_n_defined == separate_n_defined: raise AssertionError('Specify either global or separate discretization') elif global_n_defined: n_sw_wing = n_sw_global n_cw_wing = n_cw_global n_sw_fuse = n_sw_global n_cw_fuse = n_cw_global else: #separate_n_defined #everything is already set up to use separate discretization pass # --------------------------------------------------------------------------------------- # STEP 1: Define empty vectors for coordinates of panes, control points and bound vortices # --------------------------------------------------------------------------------------- VD = Data() VD.XAH = np.empty(shape=[0,1], dtype=precision) VD.YAH = np.empty(shape=[0,1], dtype=precision) VD.ZAH = np.empty(shape=[0,1], dtype=precision) VD.XBH = np.empty(shape=[0,1], dtype=precision) VD.YBH = np.empty(shape=[0,1], dtype=precision) VD.ZBH = np.empty(shape=[0,1], dtype=precision) VD.XCH = np.empty(shape=[0,1], dtype=precision) VD.YCH = np.empty(shape=[0,1], dtype=precision) VD.ZCH = np.empty(shape=[0,1], dtype=precision) VD.XA1 = np.empty(shape=[0,1], dtype=precision) VD.YA1 = np.empty(shape=[0,1], dtype=precision) VD.ZA1 = np.empty(shape=[0,1], dtype=precision) VD.XA2 = np.empty(shape=[0,1], dtype=precision) VD.YA2 = np.empty(shape=[0,1], dtype=precision) VD.ZA2 = np.empty(shape=[0,1], dtype=precision) VD.XB1 = np.empty(shape=[0,1], dtype=precision) VD.YB1 = np.empty(shape=[0,1], dtype=precision) VD.ZB1 = np.empty(shape=[0,1], dtype=precision) VD.XB2 = np.empty(shape=[0,1], dtype=precision) VD.YB2 = np.empty(shape=[0,1], dtype=precision) VD.ZB2 = np.empty(shape=[0,1], dtype=precision) VD.XAC = np.empty(shape=[0,1], dtype=precision) VD.YAC = np.empty(shape=[0,1], dtype=precision) VD.ZAC = np.empty(shape=[0,1], dtype=precision) VD.XBC = np.empty(shape=[0,1], dtype=precision) VD.YBC = np.empty(shape=[0,1], dtype=precision) VD.ZBC = np.empty(shape=[0,1], dtype=precision) VD.XC_TE = np.empty(shape=[0,1], dtype=precision) VD.YC_TE = np.empty(shape=[0,1], dtype=precision) VD.ZC_TE = np.empty(shape=[0,1], dtype=precision) VD.XA_TE = np.empty(shape=[0,1], dtype=precision) VD.YA_TE = np.empty(shape=[0,1], dtype=precision) VD.ZA_TE = np.empty(shape=[0,1], dtype=precision) VD.XB_TE = np.empty(shape=[0,1], dtype=precision) VD.YB_TE = np.empty(shape=[0,1], dtype=precision) VD.ZB_TE = np.empty(shape=[0,1], dtype=precision) VD.XC = np.empty(shape=[0,1], dtype=precision) VD.YC = np.empty(shape=[0,1], dtype=precision) VD.ZC = np.empty(shape=[0,1], dtype=precision) VD.FUS_XC = np.empty(shape=[0,1], dtype=precision) VD.FUS_YC = np.empty(shape=[0,1], dtype=precision) VD.FUS_ZC = np.empty(shape=[0,1], dtype=precision) VD.CS = np.empty(shape=[0,1], dtype=precision) VD.X = np.empty(shape=[0,1], dtype=precision) VD.Y = np.empty(shape=[0,1], dtype=precision) VD.Z = np.empty(shape=[0,1], dtype=precision) VD.Y_SW = np.empty(shape=[0,1], dtype=precision) VD.DY = np.empty(shape=[0,1], dtype=precision) # empty vectors necessary for arbitrary discretization dimensions VD.n_w = 0 # number of wings counter (refers to wings, fuselages or other structures) VD.n_cp = 0 # number of bound vortices (panels) counter VD.n_sw = np.array([], dtype=np.int16) # array of the number of spanwise strips in each wing VD.n_cw = np.array([], dtype=np.int16) # array of the number of chordwise panels per strip in each wing VD.chordwise_breaks = np.array([], dtype=np.int32) # indices of the first panel in every strip (given a list of all panels) VD.spanwise_breaks = np.array([], dtype=np.int32) # indices of the first strip of panels in a wing (given chordwise_breaks) VD.symmetric_wings = np.array([], dtype=np.int32) VD.surface_ID = np.empty(shape=[0,1], dtype=np.int16) VD.surface_ID_full = np.empty(shape=[0,1], dtype=np.int16) VD.leading_edge_indices = np.array([], dtype=bool) # bool array of leading edge indices (all false except for panels at leading edge) VD.trailing_edge_indices = np.array([], dtype=bool) # bool array of trailing edge indices (all false except for panels at trailing edge) VD.panels_per_strip = np.array([], dtype=np.int16) # array of the number of panels per strip (RNMAX); this is assigned for all panels VD.chordwise_panel_number = np.array([], dtype=np.int16) # array of panels' numbers in their strips. VD.chord_lengths = np.array([], dtype=precision) # Chord length, this is assigned for all panels. VD.tangent_incidence_angle = np.array([], dtype=precision) # Tangent Incidence Angles of the chordwise strip. LE to TE, ZETA VD.exposed_leading_edge_flag = np.array([], dtype=np.int16) # 0 or 1 per strip. 0 turns off leading edge suction for non-slat control surfaces # --------------------------------------------------------------------------------------- # Unpack aircraft wing geometry # --------------------------------------------------------------------------------------- VD.wing_areas = [] # instantiate wing areas VD.vortex_lift = [] VD.counter = 0 #reformat/preprocess wings and control surfaces for VLM panelization VLM_wings = make_VLM_wings(geometry, settings) VD.VLM_wings = VLM_wings #generate panelization for each wing. Wings first, then control surface wings for wing in VD.VLM_wings: if not wing.is_a_control_surface: if show_prints: print('discretizing ' + wing.tag) VD, wing = generate_wing_vortex_distribution(VD,wing,n_cw_wing,n_sw_wing,spc,precision) for wing in VD.VLM_wings: if wing.is_a_control_surface: if show_prints:print('discretizing ' + wing.tag) VD, wing = generate_wing_vortex_distribution(VD,wing,n_cw_wing,n_sw_wing,spc,precision) # --------------------------------------------------------------------------------------- # Unpack aircraft fuselage geometry # --------------------------------------------------------------------------------------- VD.wing_areas = np.array(VD.wing_areas, dtype=precision) VD.n_fus = 0 for fus in geometry.fuselages: if show_prints: print('discretizing ' + fus.tag) VD = generate_fuselage_and_nacelle_vortex_distribution(VD,fus,n_cw_fuse,n_sw_fuse,precision,model_fuselage) # --------------------------------------------------------------------------------------- # Deflect Control Surfaces # --------------------------------------------------------------------------------------- for wing in VD.VLM_wings: wing_is_all_moving = (not wing.is_a_control_surface) and issubclass(wing.wing_type, All_Moving_Surface) if wing.is_a_control_surface or wing_is_all_moving: # Deflect the control surface VD, wing = deflect_control_surface(VD, wing) # --------------------------------------------------------------------------------------- # Postprocess VD information # --------------------------------------------------------------------------------------- VD = postprocess_VD(VD, settings) # pack VD into geometry geometry.vortex_distribution = VD if show_prints: print('finish discretization') return VD
# ---------------------------------------------------------------------- # Discretize Wings # ----------------------------------------------------------------------
[docs] def generate_wing_vortex_distribution(VD,wing,n_cw,n_sw,spc,precision): """ This generates vortex distribution points for the given wing Assumptions: The wing is segmented and was made or modified by make_VLM_wings() For control surfaces, "positve" deflection corresponds to the RH rule where the axis of rotation is the OUTBOARD-pointing hinge vector symmetry: the LH rule is applied to the reflected surface for non-ailerons. Ailerons follow a RH rule for both sides The hinge_vector will only ever be calcualted on the first strip of any control/all-moving surface. It is assumed that all control surfaces are trapezoids, thus needing only one hinge, and that all all-moving surfaces have exactly one point of rotation. Source: None Inputs: VD - vortex distribution wing - a Data object made or modified by make_VLM_wings() to mimick a Wing object Properties Used: N/A """ wings = VD.VLM_wings # get geometry of wing span = wing.spans.projected root_chord = wing.chords.root tip_chord = wing.chords.tip sweep_qc = wing.sweeps.quarter_chord sweep_le = wing.sweeps.leading_edge twist_rc = wing.twists.root twist_tc = wing.twists.tip dihedral = wing.dihedral sym_para = wing.symmetric vertical_wing = wing.vertical wing_origin = wing.origin[0] VD.vortex_lift.append(wing.vortex_lift) # determine if vehicle has symmetry if sym_para is True : span = span/2 VD.vortex_lift.append(wing.vortex_lift) VD.counter +=1 wing.surface_ID = VD.counter*1 # --------------------------------------------------------------------------------------- # STEP 3: Get discretization control variables # --------------------------------------------------------------------------------------- # get number of spanwise and chordwise panels for this wing n_sw = n_sw if (not wing.is_a_control_surface) else max(len(wing.y_coords_required)-1,1) n_cw = n_cw if (not wing.is_a_control_surface) else max(int(np.ceil(wing.chord_fraction*n_cw)),2) # get y_coordinates (y-locations of the edges of each strip in wing-local coords) if spc == True: # discretize wing using cosine spacing n = np.linspace(n_sw+1,0,n_sw+1) # vectorize thetan = n*(np.pi/2)/(n_sw+1) # angular stations y_coordinates = span*np.cos(thetan) # y locations based on the angular spacing else: # discretize wing using linear spacing y_coordinates = np.linspace(0,span,n_sw+1) # get span_breaks object span_breaks = wing.span_breaks n_breaks = len(span_breaks) # --------------------------------------------------------------------------------------- # STEP 4: Setup span_break and section arrays. A 'section' is the trapezoid between two # span_breaks. A 'span_break' is described in the file make_VLM_wings.py # --------------------------------------------------------------------------------------- break_chord = np.zeros(n_breaks) break_twist = np.zeros(n_breaks) break_sweep = np.zeros(n_breaks) break_dihedral = np.zeros(n_breaks) break_camber_xs = [] break_camber_zs = [] break_x_offset = np.zeros(n_breaks) break_z_offset = np.zeros(n_breaks) break_spans = np.zeros(n_breaks) section_span = np.zeros(n_breaks) section_area = np.zeros(n_breaks) section_LE_cut = np.zeros(n_breaks) section_TE_cut = np.ones(n_breaks) # --------------------------------------------------------------------------------------- # STEP 5: Obtain sweep, chord, dihedral and twist at the beginning/end of each break. # If applicable, append airfoil section VD and flap/aileron deflection angles. # --------------------------------------------------------------------------------------- for i_break in range(n_breaks): break_spans[i_break] = span_breaks[i_break].span_fraction*span break_chord[i_break] = span_breaks[i_break].local_chord break_twist[i_break] = span_breaks[i_break].twist break_dihedral[i_break] = span_breaks[i_break].dihedral_outboard # get leading edge sweep. make_VLM wings should have precomputed this for all span_breaks is_not_last_break = (i_break != n_breaks-1) break_sweep[i_break] = span_breaks[i_break].sweep_outboard_LE if is_not_last_break else 0 # find span and area. All span_break offsets should be calculated in make_VLM_wings if i_break == 0: section_span[i_break] = 0.0 break_x_offset[i_break] = 0.0 break_z_offset[i_break] = 0.0 else: section_span[i_break] = break_spans[i_break] - break_spans[i_break-1] section_area[i_break] = 0.5*(break_chord[i_break-1] + break_chord[i_break])*section_span[i_break] break_x_offset[i_break] = span_breaks[i_break].x_offset break_z_offset[i_break] = span_breaks[i_break].dih_offset # Get airfoil section VD if span_breaks[i_break].airfoil: airfoil_geo_data = import_airfoil_geometry(span_breaks[i_break].airfoil.coordinate_file) break_camber_zs.append(airfoil_geo_data.camber_coordinates) break_camber_xs.append(airfoil_geo_data.x_lower_surface) else: break_camber_zs.append(np.zeros(30)) break_camber_xs.append(np.linspace(0,1,30)) # Get control surface leading and trailing edge cute cuts: section__cuts[-1] should never be used in the following code section_LE_cut[i_break] = span_breaks[i_break].cuts[0,1] section_TE_cut[i_break] = span_breaks[i_break].cuts[1,1] VD.wing_areas.append(np.sum(section_area[:], dtype=precision)) if sym_para is True : VD.wing_areas.append(np.sum(section_area[:], dtype=precision)) #Shift spanwise vortices onto section breaks if len(y_coordinates) < n_breaks: raise ValueError('Not enough spanwise VLM stations for segment breaks') y_coords_required = break_spans if (not wing.is_a_control_surface) else np.array(sorted(wing.y_coords_required)) #control surfaces have additional required y_coords shifted_idxs = np.zeros(len(y_coordinates)) for y_req in y_coords_required: idx = (np.abs(y_coordinates - y_req) + shifted_idxs).argmin() #index of y-coord nearest to the span break shifted_idxs[idx] = np.inf y_coordinates[idx] = y_req y_coordinates = np.array(sorted(y_coordinates)) for y_req in y_coords_required: if y_req not in y_coordinates: raise ValueError('VLM did not capture all section breaks') # --------------------------------------------------------------------------------------- # STEP 6: Define coordinates of panels horseshoe vortices and control points # --------------------------------------------------------------------------------------- y_a = y_coordinates[:-1] y_b = y_coordinates[1:] del_y = y_coordinates[1:] - y_coordinates[:-1] # Let relevant control surfaces know which y-coords they are required to have---------------------------------- if not wing.is_a_control_surface: i_break = 0 for idx_y in range(n_sw): span_break = span_breaks[i_break] cs_IDs = span_break.cs_IDs[:,1] #only the outboard control surfaces y_coord = y_coordinates[idx_y] for cs_ID in cs_IDs[cs_IDs >= 0]: cs_tag = wing.tag + '__cs_id_{}'.format(cs_ID) cs_wing = wings[cs_tag] rel_offset = cs_wing.origin[0,1] - wing.origin[0][1] if not vertical_wing else cs_wing.origin[0,2] - wing.origin[0][2] cs_wing.y_coords_required.append(y_coord - rel_offset) if y_coordinates[idx_y+1] == break_spans[i_break+1]: i_break += 1 # ------------------------------------------------------------------------------------------------------------- # Run the strip contruction loop again if wing is symmetric. # Reflection plane = x-y plane for vertical wings. Otherwise, reflection plane = x-z plane signs = np.array([1, -1]) # acts as a multiplier for symmetry. -1 is only ever used for symmetric wings symmetry_mask = [True,sym_para] for sym_sign in signs[symmetry_mask]: # create empty vectors for coordinates xah = np.zeros(n_cw*n_sw) yah = np.zeros(n_cw*n_sw) zah = np.zeros(n_cw*n_sw) xbh = np.zeros(n_cw*n_sw) ybh = np.zeros(n_cw*n_sw) zbh = np.zeros(n_cw*n_sw) xch = np.zeros(n_cw*n_sw) ych = np.zeros(n_cw*n_sw) zch = np.zeros(n_cw*n_sw) xa1 = np.zeros(n_cw*n_sw) ya1 = np.zeros(n_cw*n_sw) za1 = np.zeros(n_cw*n_sw) xa2 = np.zeros(n_cw*n_sw) ya2 = np.zeros(n_cw*n_sw) za2 = np.zeros(n_cw*n_sw) xb1 = np.zeros(n_cw*n_sw) yb1 = np.zeros(n_cw*n_sw) zb1 = np.zeros(n_cw*n_sw) xb2 = np.zeros(n_cw*n_sw) yb2 = np.zeros(n_cw*n_sw) zb2 = np.zeros(n_cw*n_sw) xac = np.zeros(n_cw*n_sw) yac = np.zeros(n_cw*n_sw) zac = np.zeros(n_cw*n_sw) xbc = np.zeros(n_cw*n_sw) ybc = np.zeros(n_cw*n_sw) zbc = np.zeros(n_cw*n_sw) xc = np.zeros(n_cw*n_sw) yc = np.zeros(n_cw*n_sw) zc = np.zeros(n_cw*n_sw) x = np.zeros((n_cw+1)*(n_sw+1)) # may have to change to make space for split if control surfaces are allowed to have more than two Segments y = np.zeros((n_cw+1)*(n_sw+1)) z = np.zeros((n_cw+1)*(n_sw+1)) cs_w = np.zeros(n_sw) # adjust origin for symmetry with special case for vertical symmetry wing_origin_x = wing_origin[0] wing_origin_y = wing_origin[1] * ((1-vertical_wing)*sym_sign+vertical_wing) wing_origin_z = wing_origin[2] * ((1-vertical_wing)+sym_sign*vertical_wing) # --------------------------------------------------------------------------------------------------------- # Loop over each strip of panels in the wing i_break = 0 for idx_y in range(n_sw): # define basic geometric values------------------------------------------------------------------------ # inboard, outboard, and central panel values eta_a = (y_a[idx_y] - break_spans[i_break]) eta_b = (y_b[idx_y] - break_spans[i_break]) eta = (y_b[idx_y] - del_y[idx_y]/2 - break_spans[i_break]) # Inverted wing wing.inverted_wing = -np.sign(break_dihedral[i_break] - np.pi/2) segment_chord_ratio = (break_chord[i_break+1] - break_chord[i_break])/section_span[i_break+1] segment_twist_ratio = (break_twist[i_break+1] - break_twist[i_break])/section_span[i_break+1] wing_chord_section_a = break_chord[i_break] + (eta_a*segment_chord_ratio) wing_chord_section_b = break_chord[i_break] + (eta_b*segment_chord_ratio) wing_chord_section = break_chord[i_break] + (eta*segment_chord_ratio) # x-positions based on whether the wing needs 'cuts' for its control sufaces nondim_x_stations = np.interp(np.linspace(0.,1.,num=n_cw+1), [0.,1.], [section_LE_cut[i_break], section_TE_cut[i_break]]) x_stations_a = nondim_x_stations * wing_chord_section_a #x positions accounting for control surface cuts, relative to leading x_stations_b = nondim_x_stations * wing_chord_section_b x_stations = nondim_x_stations * wing_chord_section delta_x_a = (x_stations_a[-1] - x_stations_a[0])/n_cw delta_x_b = (x_stations_b[-1] - x_stations_b[0])/n_cw delta_x = (x_stations[-1] - x_stations[0] )/n_cw # define coordinates of horseshoe vortices and control points------------------------------------------ xi_a1 = break_x_offset[i_break] + eta_a*np.tan(break_sweep[i_break]) + x_stations_a[:-1] # x coordinate of top left corner of panel xi_ah = break_x_offset[i_break] + eta_a*np.tan(break_sweep[i_break]) + x_stations_a[:-1] + delta_x_a*0.25 # x coordinate of left corner of panel xi_ac = break_x_offset[i_break] + eta_a*np.tan(break_sweep[i_break]) + x_stations_a[:-1] + delta_x_a*0.75 # x coordinate of bottom left corner of control point vortex xi_a2 = break_x_offset[i_break] + eta_a*np.tan(break_sweep[i_break]) + x_stations_a[1:] # x coordinate of bottom left corner of bound vortex xi_b1 = break_x_offset[i_break] + eta_b*np.tan(break_sweep[i_break]) + x_stations_b[:-1] # x coordinate of top right corner of panel xi_bh = break_x_offset[i_break] + eta_b*np.tan(break_sweep[i_break]) + x_stations_b[:-1] + delta_x_b*0.25 # x coordinate of right corner of bound vortex xi_bc = break_x_offset[i_break] + eta_b*np.tan(break_sweep[i_break]) + x_stations_b[:-1] + delta_x_b*0.75 # x coordinate of bottom right corner of control point vortex xi_b2 = break_x_offset[i_break] + eta_b*np.tan(break_sweep[i_break]) + x_stations_b[1:] # x coordinate of bottom right corner of panel xi_ch = break_x_offset[i_break] + eta *np.tan(break_sweep[i_break]) + x_stations[:-1] + delta_x *0.25 # x coordinate center of bound vortex of each panel xi_c = break_x_offset[i_break] + eta *np.tan(break_sweep[i_break]) + x_stations[:-1] + delta_x *0.75 # x coordinate three-quarter chord control point for each panel #adjust for camber------------------------------------------------------------------------------------- #format camber vars for wings vs control surface wings nondim_camber_x_coords = break_camber_xs[i_break] *1 nondim_camber = break_camber_zs[i_break] *1 if wing.is_a_control_surface: #rescale so that airfoils get cut properly if not wing.is_slat: nondim_camber_x_coords -= 1 - wing.chord_fraction nondim_camber_x_coords /= wing.chord_fraction nondim_camber /= wing.chord_fraction # adjustment of coordinates for camber section_camber_a = nondim_camber*wing_chord_section_a section_camber_b = nondim_camber*wing_chord_section_b section_camber_c = nondim_camber*wing_chord_section section_x_coord_a = nondim_camber_x_coords*wing_chord_section_a section_x_coord_b = nondim_camber_x_coords*wing_chord_section_b section_x_coord = nondim_camber_x_coords*wing_chord_section z_c_a1 = np.interp((x_stations_a[:-1] ) ,section_x_coord_a, section_camber_a) z_c_ah = np.interp((x_stations_a[:-1] + delta_x_a*0.25) ,section_x_coord_a, section_camber_a) z_c_ac = np.interp((x_stations_a[:-1] + delta_x_a*0.75) ,section_x_coord_a, section_camber_a) z_c_a2 = np.interp((x_stations_a[1:] ) ,section_x_coord_a, section_camber_a) z_c_b1 = np.interp((x_stations_b[:-1] ) ,section_x_coord_b, section_camber_b) z_c_bh = np.interp((x_stations_b[:-1] + delta_x_b*0.25) ,section_x_coord_b, section_camber_b) z_c_bc = np.interp((x_stations_b[:-1] + delta_x_b*0.75) ,section_x_coord_b, section_camber_b) z_c_b2 = np.interp((x_stations_b[1:] ) ,section_x_coord_b, section_camber_b) z_c_ch = np.interp((x_stations[:-1] + delta_x *0.25) ,section_x_coord , section_camber_c) z_c = np.interp((x_stations[:-1] + delta_x *0.75) ,section_x_coord , section_camber_c) # adjust for dihedral and add to camber---------------------------------------------------------------- zeta_a1 = break_z_offset[i_break] + eta_a*np.tan(break_dihedral[i_break]) + z_c_a1 # z coordinate of top left corner of panel zeta_ah = break_z_offset[i_break] + eta_a*np.tan(break_dihedral[i_break]) + z_c_ah # z coordinate of left corner of bound vortex zeta_a2 = break_z_offset[i_break] + eta_a*np.tan(break_dihedral[i_break]) + z_c_a2 # z coordinate of bottom left corner of panel zeta_ac = break_z_offset[i_break] + eta_a*np.tan(break_dihedral[i_break]) + z_c_ac # z coordinate of bottom left corner of panel of control point zeta_bc = break_z_offset[i_break] + eta_b*np.tan(break_dihedral[i_break]) + z_c_bc # z coordinate of top right corner of panel of control point zeta_b1 = break_z_offset[i_break] + eta_b*np.tan(break_dihedral[i_break]) + z_c_b1 # z coordinate of top right corner of panel zeta_bh = break_z_offset[i_break] + eta_b*np.tan(break_dihedral[i_break]) + z_c_bh # z coordinate of right corner of bound vortex zeta_b2 = break_z_offset[i_break] + eta_b*np.tan(break_dihedral[i_break]) + z_c_b2 # z coordinate of bottom right corner of panel zeta_ch = break_z_offset[i_break] + eta *np.tan(break_dihedral[i_break]) + z_c_ch # z coordinate center of bound vortex on each panel zeta = break_z_offset[i_break] + eta *np.tan(break_dihedral[i_break]) + z_c # z coordinate three-quarter chord control point for each panel # adjust for twist------------------------------------------------------------------------------------- # pivot point is the leading edge before camber pivot_x_a = break_x_offset[i_break] + eta_a*np.tan(break_sweep[i_break]) # x location of leading edge left corner of wing pivot_x_b = break_x_offset[i_break] + eta_b*np.tan(break_sweep[i_break]) # x location of leading edge right of wing pivot_x = break_x_offset[i_break] + eta *np.tan(break_sweep[i_break]) # x location of leading edge center of wing pivot_z_a = break_z_offset[i_break] + eta_a*np.tan(break_dihedral[i_break]) # z location of leading edge left corner of wing pivot_z_b = break_z_offset[i_break] + eta_b*np.tan(break_dihedral[i_break]) # z location of leading edge right of wing pivot_z = break_z_offset[i_break] + eta *np.tan(break_dihedral[i_break]) # z location of leading edge center of wing # adjust twist pivot line for control surface wings: offset leading edge to match that of the owning wing if wing.is_a_control_surface and not wing.is_slat: #correction only leading for non-leading edge control surfaces since the LE is the pivot by default nondim_cs_LE = (1 - wing.chord_fraction) pivot_x_a -= nondim_cs_LE *(wing_chord_section_a /wing.chord_fraction) pivot_x_b -= nondim_cs_LE *(wing_chord_section_b /wing.chord_fraction) pivot_x -= nondim_cs_LE *(wing_chord_section /wing.chord_fraction) # adjust coordinates for twist section_twist_a = break_twist[i_break] + (eta_a * segment_twist_ratio) # twist at left side of panel section_twist_b = break_twist[i_break] + (eta_b * segment_twist_ratio) # twist at right side of panel section_twist = break_twist[i_break] + (eta * segment_twist_ratio) # twist at center local chord xi_prime_a1 = pivot_x_a + np.cos(section_twist_a)*(xi_a1-pivot_x_a) + np.sin(section_twist_a)*(zeta_a1-pivot_z_a) # x coordinate transformation of top left corner xi_prime_ah = pivot_x_a + np.cos(section_twist_a)*(xi_ah-pivot_x_a) + np.sin(section_twist_a)*(zeta_ah-pivot_z_a) # x coordinate transformation of bottom left corner xi_prime_ac = pivot_x_a + np.cos(section_twist_a)*(xi_ac-pivot_x_a) + np.sin(section_twist_a)*(zeta_a2-pivot_z_a) # x coordinate transformation of bottom left corner of control point xi_prime_a2 = pivot_x_a + np.cos(section_twist_a)*(xi_a2-pivot_x_a) + np.sin(section_twist_a)*(zeta_a2-pivot_z_a) # x coordinate transformation of bottom left corner xi_prime_b1 = pivot_x_b + np.cos(section_twist_b)*(xi_b1-pivot_x_b) + np.sin(section_twist_b)*(zeta_b1-pivot_z_b) # x coordinate transformation of top right corner xi_prime_bh = pivot_x_b + np.cos(section_twist_b)*(xi_bh-pivot_x_b) + np.sin(section_twist_b)*(zeta_bh-pivot_z_b) # x coordinate transformation of top right corner xi_prime_bc = pivot_x_b + np.cos(section_twist_b)*(xi_bc-pivot_x_b) + np.sin(section_twist_b)*(zeta_b1-pivot_z_b) # x coordinate transformation of top right corner of control point xi_prime_b2 = pivot_x_b + np.cos(section_twist_b)*(xi_b2-pivot_x_b) + np.sin(section_twist_b)*(zeta_b2-pivot_z_b) # x coordinate transformation of botton right corner xi_prime_ch = pivot_x + np.cos(section_twist) *(xi_ch-pivot_x) + np.sin(section_twist) *(zeta_ch-pivot_z) # x coordinate transformation of center of horeshoe vortex xi_prime = pivot_x + np.cos(section_twist) *(xi_c -pivot_x) + np.sin(section_twist) *(zeta -pivot_z) # x coordinate transformation of control point zeta_prime_a1 = pivot_z_a - np.sin(section_twist_a)*(xi_a1-pivot_x_a) + np.cos(section_twist_a)*(zeta_a1-pivot_z_a) # z coordinate transformation of top left corner zeta_prime_ah = pivot_z_a - np.sin(section_twist_a)*(xi_ah-pivot_x_a) + np.cos(section_twist_a)*(zeta_ah-pivot_z_a) # z coordinate transformation of bottom left corner zeta_prime_ac = pivot_z_a - np.sin(section_twist_a)*(xi_ac-pivot_x_a) + np.cos(section_twist_a)*(zeta_ac-pivot_z_a) # z coordinate transformation of bottom left corner zeta_prime_a2 = pivot_z_a - np.sin(section_twist_a)*(xi_a2-pivot_x_a) + np.cos(section_twist_a)*(zeta_a2-pivot_z_a) # z coordinate transformation of bottom left corner zeta_prime_b1 = pivot_z_b - np.sin(section_twist_b)*(xi_b1-pivot_x_b) + np.cos(section_twist_b)*(zeta_b1-pivot_z_b) # z coordinate transformation of top right corner zeta_prime_bh = pivot_z_b - np.sin(section_twist_b)*(xi_bh-pivot_x_b) + np.cos(section_twist_b)*(zeta_bh-pivot_z_b) # z coordinate transformation of top right corner zeta_prime_bc = pivot_z_b - np.sin(section_twist_b)*(xi_bc-pivot_x_b) + np.cos(section_twist_b)*(zeta_bc-pivot_z_b) # z coordinate transformation of top right corner zeta_prime_b2 = pivot_z_b - np.sin(section_twist_b)*(xi_b2-pivot_x_b) + np.cos(section_twist_b)*(zeta_b2-pivot_z_b) # z coordinate transformation of botton right corner zeta_prime_ch = pivot_z - np.sin(section_twist) *(xi_ch-pivot_x) + np.cos(-section_twist) *(zeta_ch-pivot_z) # z coordinate transformation of center of horseshoe zeta_prime = pivot_z - np.sin(section_twist) *(xi_c -pivot_x) + np.cos(-section_twist) *(zeta -pivot_z) # z coordinate transformation of control point # Define y-coordinate and other arrays----------------------------------------------------------------- # take normal value for first wing, then reflect over xz plane for a symmetric wing y_prime_as = (np.ones(n_cw+1)*y_a[idx_y] ) *sym_sign y_prime_a1 = (y_prime_as[:-1] ) *1 y_prime_ah = (y_prime_as[:-1] ) *1 y_prime_ac = (y_prime_as[:-1] ) *1 y_prime_a2 = (y_prime_as[:-1] ) *1 y_prime_bs = (np.ones(n_cw+1)*y_b[idx_y] ) *sym_sign y_prime_b1 = (y_prime_bs[:-1] ) *1 y_prime_bh = (y_prime_bs[:-1] ) *1 y_prime_bc = (y_prime_bs[:-1] ) *1 y_prime_b2 = (y_prime_bs[:-1] ) *1 y_prime_ch = (np.ones(n_cw)*(y_b[idx_y] - del_y[idx_y]/2)) *sym_sign y_prime = (y_prime_ch ) *1 # populate all corners of all panels. Right side only populated for last strip wing the wing xi_prime_as = np.concatenate([xi_prime_a1, np.array([xi_prime_a2 [-1]])])*1 xi_prime_bs = np.concatenate([xi_prime_b1, np.array([xi_prime_b2 [-1]])])*1 zeta_prime_as = np.concatenate([zeta_prime_a1,np.array([zeta_prime_a2[-1]])])*1 zeta_prime_bs = np.concatenate([zeta_prime_b1,np.array([zeta_prime_b2[-1]])])*1 # reflect over the plane y = z for a vertical wing----------------------------------------------------- if vertical_wing: y_prime_a1, zeta_prime_a1 = zeta_prime_a1, wing.inverted_wing*y_prime_a1 y_prime_ah, zeta_prime_ah = zeta_prime_ah, wing.inverted_wing*y_prime_ah y_prime_ac, zeta_prime_ac = zeta_prime_ac, wing.inverted_wing*y_prime_ac y_prime_a2, zeta_prime_a2 = zeta_prime_a2, wing.inverted_wing*y_prime_a2 y_prime_b1, zeta_prime_b1 = zeta_prime_b1, wing.inverted_wing*y_prime_b1 y_prime_bh, zeta_prime_bh = zeta_prime_bh, wing.inverted_wing*y_prime_bh y_prime_bc, zeta_prime_bc = zeta_prime_bc, wing.inverted_wing*y_prime_bc y_prime_b2, zeta_prime_b2 = zeta_prime_b2, wing.inverted_wing*y_prime_b2 y_prime_ch, zeta_prime_ch = zeta_prime_ch, wing.inverted_wing*y_prime_ch y_prime , zeta_prime = zeta_prime , wing.inverted_wing*y_prime y_prime_as, zeta_prime_as = zeta_prime_as, wing.inverted_wing*y_prime_as y_prime_bs = wing.inverted_wing*y_prime_bs y_prime_bs, zeta_prime_bs = zeta_prime_bs, y_prime_bs # store coordinates of panels, horseshoeces vortices and control points relative to wing root---------- xa1[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_a1 # top left corner of panel ya1[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_a1 za1[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_a1 xah[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_ah # left coord of horseshoe yah[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_ah zah[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_ah xac[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_ac # left coord of control point yac[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_ac zac[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_ac xa2[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_a2 # bottom left corner of panel ya2[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_a2 za2[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_a2 xb1[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_b1 # top right corner of panel yb1[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_b1 zb1[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_b1 xbh[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_bh # right coord of horseshoe ybh[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_bh zbh[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_bh xbc[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_bc # right coord of control point ybc[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_bc zbc[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_bc xb2[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_b2 # bottom right corner of panel yb2[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_b2 zb2[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_b2 xch[idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime_ch # center coord of horseshoe ych[idx_y*n_cw:(idx_y+1)*n_cw] = y_prime_ch zch[idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime_ch xc [idx_y*n_cw:(idx_y+1)*n_cw] = xi_prime # center (true) coord of control point yc [idx_y*n_cw:(idx_y+1)*n_cw] = y_prime zc [idx_y*n_cw:(idx_y+1)*n_cw] = zeta_prime x[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = xi_prime_as # x, y, z represent all all points of the corners of the panels, LE and TE inclusive y[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = y_prime_as # the final right corners get appended at last strip in wing, later z[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = zeta_prime_as cs_w[idx_y] = wing_chord_section # store this strip's discretization information-------------------------------------------------------- LE_inds = np.full(n_cw, False) TE_inds = np.full(n_cw, False) LE_inds[0] = True TE_inds[-1] = True RNMAX = np.ones(n_cw, np.int16)*n_cw panel_numbers = np.linspace(1,n_cw,n_cw, dtype=np.int16) is_a_slat = wing.is_a_control_surface and wing.is_slat strip_has_no_slat = (not wing.is_a_control_surface) and (span_breaks[i_break].cs_IDs[0,1] == -1) # wing's le, outboard control surface ID exposed_leading_edge_flag = np.int16(1) if is_a_slat or strip_has_no_slat else np.int16(0) VD.leading_edge_indices = np.append(VD.leading_edge_indices , LE_inds ) VD.trailing_edge_indices = np.append(VD.trailing_edge_indices , TE_inds ) VD.panels_per_strip = np.append(VD.panels_per_strip , RNMAX ) VD.chordwise_panel_number = np.append(VD.chordwise_panel_number , panel_numbers ) VD.exposed_leading_edge_flag = np.append(VD.exposed_leading_edge_flag, exposed_leading_edge_flag) #increment i_break if needed; check for end of wing---------------------------------------------------- if y_b[idx_y] == break_spans[i_break+1]: i_break += 1 #End 'for each strip' loop # store outboardmost edge x[-(n_cw+1):] = xi_prime_bs y[-(n_cw+1):] = y_prime_bs z[-(n_cw+1):] = zeta_prime_bs # adjusting coordinate axis so reference point is at the nose of the aircraft------------------------------ xah = xah + wing_origin_x # x coordinate of left corner of bound vortex yah = yah + wing_origin_y # y coordinate of left corner of bound vortex zah = zah + wing_origin_z # z coordinate of left corner of bound vortex xbh = xbh + wing_origin_x # x coordinate of right corner of bound vortex ybh = ybh + wing_origin_y # y coordinate of right corner of bound vortex zbh = zbh + wing_origin_z # z coordinate of right corner of bound vortex xch = xch + wing_origin_x # x coordinate of center of bound vortex on panel ych = ych + wing_origin_y # y coordinate of center of bound vortex on panel zch = zch + wing_origin_z # z coordinate of center of bound vortex on panel xa1 = xa1 + wing_origin_x # x coordinate of top left corner of panel ya1 = ya1 + wing_origin_y # y coordinate of bottom left corner of panel za1 = za1 + wing_origin_z # z coordinate of top left corner of panel xa2 = xa2 + wing_origin_x # x coordinate of bottom left corner of panel ya2 = ya2 + wing_origin_y # x coordinate of bottom left corner of panel za2 = za2 + wing_origin_z # z coordinate of bottom left corner of panel xb1 = xb1 + wing_origin_x # x coordinate of top right corner of panel yb1 = yb1 + wing_origin_y # y coordinate of top right corner of panel zb1 = zb1 + wing_origin_z # z coordinate of top right corner of panel xb2 = xb2 + wing_origin_x # x coordinate of bottom rightcorner of panel yb2 = yb2 + wing_origin_y # y coordinate of bottom rightcorner of panel zb2 = zb2 + wing_origin_z # z coordinate of bottom right corner of panel xac = xac + wing_origin_x # x coordinate of control points on panel yac = yac + wing_origin_y # y coordinate of control points on panel zac = zac + wing_origin_z # z coordinate of control points on panel xbc = xbc + wing_origin_x # x coordinate of control points on panel ybc = ybc + wing_origin_y # y coordinate of control points on panel zbc = zbc + wing_origin_z # z coordinate of control points on panel xc = xc + wing_origin_x # x coordinate of control points on panel yc = yc + wing_origin_y # y coordinate of control points on panel zc = zc + wing_origin_z # y coordinate of control points on panel x = x + wing_origin_x # x coordinate of control points on panel y = y + wing_origin_y # y coordinate of control points on panel z = z + wing_origin_z # y coordinate of control points on panel # VD discretization information---------------------------------------------------------------------------- # increment number of wings and panels n_panels = len(xch) VD.n_w += 1 VD.n_cp += n_panels # store this wing's discretization information first_panel_ind = VD.XAH.size first_strip_ind = VD.chordwise_breaks.size chordwise_breaks = first_panel_ind + np.arange(n_panels)[0::n_cw] ID = VD.counter*1 VD.chordwise_breaks = np.append(VD.chordwise_breaks, np.int32(chordwise_breaks)) VD.spanwise_breaks = np.append(VD.spanwise_breaks , np.int32(first_strip_ind )) VD.n_sw = np.append(VD.n_sw , np.int16(n_sw) ) VD.n_cw = np.append(VD.n_cw , np.int16(n_cw) ) VD.surface_ID = np.append(VD.surface_ID , np.ones(n_cw*n_sw)*ID*sym_sign) # Update me when the loop is gone VD.surface_ID_full = np.append(VD.surface_ID_full , np.ones((n_cw+1)*(n_sw+1))*ID*sym_sign) # Update me when the loop is gone # --------------------------------------------------------------------------------------- # STEP 7: Store wing in vehicle vector # --------------------------------------------------------------------------------------- VD.XAH = np.append(VD.XAH , np.array(xah , dtype=precision)) VD.YAH = np.append(VD.YAH , np.array(yah , dtype=precision)) VD.ZAH = np.append(VD.ZAH , np.array(zah , dtype=precision)) VD.XBH = np.append(VD.XBH , np.array(xbh , dtype=precision)) VD.YBH = np.append(VD.YBH , np.array(ybh , dtype=precision)) VD.ZBH = np.append(VD.ZBH , np.array(zbh , dtype=precision)) VD.XCH = np.append(VD.XCH , np.array(xch , dtype=precision)) VD.YCH = np.append(VD.YCH , np.array(ych , dtype=precision)) VD.ZCH = np.append(VD.ZCH , np.array(zch , dtype=precision)) VD.XA1 = np.append(VD.XA1 , np.array(xa1 , dtype=precision)) VD.YA1 = np.append(VD.YA1 , np.array(ya1 , dtype=precision)) VD.ZA1 = np.append(VD.ZA1 , np.array(za1 , dtype=precision)) VD.XA2 = np.append(VD.XA2 , np.array(xa2 , dtype=precision)) VD.YA2 = np.append(VD.YA2 , np.array(ya2 , dtype=precision)) VD.ZA2 = np.append(VD.ZA2 , np.array(za2 , dtype=precision)) VD.XB1 = np.append(VD.XB1 , np.array(xb1 , dtype=precision)) VD.YB1 = np.append(VD.YB1 , np.array(yb1 , dtype=precision)) VD.ZB1 = np.append(VD.ZB1 , np.array(zb1 , dtype=precision)) VD.XB2 = np.append(VD.XB2 , np.array(xb2 , dtype=precision)) VD.YB2 = np.append(VD.YB2 , np.array(yb2 , dtype=precision)) VD.ZB2 = np.append(VD.ZB2 , np.array(zb2 , dtype=precision)) VD.XAC = np.append(VD.XAC , np.array(xac , dtype=precision)) VD.YAC = np.append(VD.YAC , np.array(yac , dtype=precision)) VD.ZAC = np.append(VD.ZAC , np.array(zac , dtype=precision)) VD.XBC = np.append(VD.XBC , np.array(xbc , dtype=precision)) VD.YBC = np.append(VD.YBC , np.array(ybc , dtype=precision)) VD.ZBC = np.append(VD.ZBC , np.array(zbc , dtype=precision)) VD.XC = np.append(VD.XC , np.array(xc , dtype=precision)) VD.YC = np.append(VD.YC , np.array(yc , dtype=precision)) VD.ZC = np.append(VD.ZC , np.array(zc , dtype=precision)) VD.X = np.append(VD.X , np.array(x , dtype=precision)) VD.Y = np.append(VD.Y , np.array(y , dtype=precision)) VD.Z = np.append(VD.Z , np.array(z , dtype=precision)) VD.CS = np.append(VD.CS , np.array(cs_w , dtype=precision)) VD.DY = np.append(VD.DY , np.array(del_y, dtype=precision)) #End symmetry loop VD.symmetric_wings = np.append(VD.symmetric_wings, int(sym_para)) # Pack wing data wing.n_sw = n_sw wing.n_cw = n_cw return VD, wing
# ---------------------------------------------------------------------- # Discretize Fuselage # ----------------------------------------------------------------------
[docs] def generate_fuselage_and_nacelle_vortex_distribution(VD,fus,n_cw,n_sw,precision,model_geometry=False): """ This generates the vortex distribution points on a fuselage or nacelle component Assumptions: If nacelle has segments defined, the mean width and height of the nacelle is used Source: None Inputs: VD - vortex distribution Properties Used: N/A """ fhs_xa1 = np.zeros(n_cw*n_sw) fhs_ya1 = np.zeros(n_cw*n_sw) fhs_za1 = np.zeros(n_cw*n_sw) fhs_xa2 = np.zeros(n_cw*n_sw) fhs_ya2 = np.zeros(n_cw*n_sw) fhs_za2 = np.zeros(n_cw*n_sw) fhs_xb1 = np.zeros(n_cw*n_sw) fhs_yb1 = np.zeros(n_cw*n_sw) fhs_zb1 = np.zeros(n_cw*n_sw) fhs_yb2 = np.zeros(n_cw*n_sw) fhs_xb2 = np.zeros(n_cw*n_sw) fhs_zb2 = np.zeros(n_cw*n_sw) fhs_xah = np.zeros(n_cw*n_sw) fhs_yah = np.zeros(n_cw*n_sw) fhs_zah = np.zeros(n_cw*n_sw) fhs_xbh = np.zeros(n_cw*n_sw) fhs_ybh = np.zeros(n_cw*n_sw) fhs_zbh = np.zeros(n_cw*n_sw) fhs_xch = np.zeros(n_cw*n_sw) fhs_ych = np.zeros(n_cw*n_sw) fhs_zch = np.zeros(n_cw*n_sw) fhs_xc = np.zeros(n_cw*n_sw) fhs_yc = np.zeros(n_cw*n_sw) fhs_zc = np.zeros(n_cw*n_sw) fhs_xac = np.zeros(n_cw*n_sw) fhs_yac = np.zeros(n_cw*n_sw) fhs_zac = np.zeros(n_cw*n_sw) fhs_xbc = np.zeros(n_cw*n_sw) fhs_ybc = np.zeros(n_cw*n_sw) fhs_zbc = np.zeros(n_cw*n_sw) fhs_x = np.zeros((n_cw+1)*(n_sw+1)) fhs_y = np.zeros((n_cw+1)*(n_sw+1)) fhs_z = np.zeros((n_cw+1)*(n_sw+1)) fvs_xc = np.zeros(n_cw*n_sw) fvs_zc = np.zeros(n_cw*n_sw) fvs_yc = np.zeros(n_cw*n_sw) fvs_x = np.zeros((n_cw+1)*(n_sw+1)) fvs_y = np.zeros((n_cw+1)*(n_sw+1)) fvs_z = np.zeros((n_cw+1)*(n_sw+1)) fus_v_cs = np.zeros(n_sw) # arrays to hold strip discretization values leading_edge_indices = np.array([],dtype=bool) trailing_edge_indices = np.array([],dtype=bool) panels_per_strip = np.array([],dtype=np.int16) chordwise_panel_number = np.array([],dtype=np.int16) # geometry values origin = fus.origin[0] # --TO DO-- model fuselage segments if defined, else use the following code # Horizontal Sections of fuselage fhs = Data() fhs.origin = np.zeros((n_sw+1,3)) fhs.chord = np.zeros((n_sw+1)) fhs.sweep = np.zeros((n_sw+1)) fvs = Data() fvs.origin = np.zeros((n_sw+1,3)) fvs.chord = np.zeros((n_sw+1)) fvs.sweep = np.zeros((n_sw+1)) if isinstance(fus, RCAIDE.Library.Components.Fuselages.Fuselage): # Compute the curvature of the nose/tail given fineness ratio. Curvature is derived from general quadratic equation # This method relates the fineness ratio to the quadratic curve formula via a spline fit interpolation vec1 = [2 , 1.5, 1.2 , 1] vec2 = [1 ,1.57 , 3.2, 8] x = np.linspace(0,1,4) fus_nose_curvature = np.interp(np.interp(fus.fineness.nose,vec2,x), x , vec1) fus_tail_curvature = np.interp(np.interp(fus.fineness.tail,vec2,x), x , vec1) semispan_h = fus.width * 0.5 semispan_v = fus.heights.maximum * 0.5 si = np.arange(1,((n_sw*2)+2)) spacing = np.cos((2*si - 1)/(2*len(si))*np.pi) h_array = semispan_h*spacing[0:int((len(si)+1)/2)][::-1] v_array = semispan_v*spacing[0:int((len(si)+1)/2)][::-1] for i in range(n_sw+1): fhs_cabin_length = fus.lengths.total - (fus.lengths.nose + fus.lengths.tail) fhs.nose_length = ((1 - ((abs(h_array[i]/semispan_h))**fus_nose_curvature ))**(1/fus_nose_curvature))*fus.lengths.nose fhs.tail_length = ((1 - ((abs(h_array[i]/semispan_h))**fus_tail_curvature ))**(1/fus_tail_curvature))*fus.lengths.tail fhs.nose_origin = fus.lengths.nose - fhs.nose_length fhs.origin[i][:] = np.array([fhs.nose_origin , h_array[i], 0.]) # Local origin fhs.chord[i] = fhs_cabin_length + fhs.nose_length + fhs.tail_length fvs_cabin_length = fus.lengths.total - (fus.lengths.nose + fus.lengths.tail) fvs.nose_length = ((1 - ((abs(v_array[i]/semispan_v))**fus_nose_curvature ))**(1/fus_nose_curvature))*fus.lengths.nose fvs.tail_length = ((1 - ((abs(v_array[i]/semispan_v))**fus_tail_curvature ))**(1/fus_tail_curvature))*fus.lengths.tail fvs.nose_origin = fus.lengths.nose - fvs.nose_length fvs.origin[i][:] = np.array([origin[0] + fvs.nose_origin , origin[1] , origin[2]+ v_array[i]]) fvs.chord[i] = fvs_cabin_length + fvs.nose_length + fvs.tail_length fhs.sweep[:] = np.concatenate([np.arctan((fhs.origin[:,0][1:] - fhs.origin[:,0][:-1])/(fhs.origin[:,1][1:] - fhs.origin[:,1][:-1])) ,np.zeros(1)]) fvs.sweep[:] = np.concatenate([np.arctan((fvs.origin[:,0][1:] - fvs.origin[:,0][:-1])/(fvs.origin[:,2][1:] - fvs.origin[:,2][:-1])) ,np.zeros(1)]) # --------------------------------------------------------------------------------------- # STEP 9: Define coordinates of panels horseshoe vortices and control points # --------------------------------------------------------------------------------------- fhs_eta_a = h_array[:-1] fhs_eta_b = h_array[1:] fhs_del_y = h_array[1:] - h_array[:-1] fhs_eta = h_array[1:] - fhs_del_y/2 fvs_eta_a = v_array[:-1] fvs_eta_b = v_array[1:] fvs_del_y = v_array[1:] - v_array[:-1] fvs_eta = v_array[1:] - fvs_del_y/2 fhs_cs = np.concatenate([fhs.chord,fhs.chord]) fvs_cs = np.concatenate([fvs.chord,fvs.chord]) fus_h_area = 0 fus_v_area = 0 # define coordinates of horseshoe vortices and control points for idx_y in range(n_sw): idx_x = np.arange(n_cw) # fuselage horizontal section delta_x_a = fhs.chord[idx_y]/n_cw delta_x_b = fhs.chord[idx_y + 1]/n_cw delta_x = (fhs.chord[idx_y]+fhs.chord[idx_y + 1])/(2*n_cw) fhs_xi_a1 = fhs.origin[idx_y][0] + delta_x_a*idx_x # x coordinate of top left corner of panel fhs_xi_ah = fhs.origin[idx_y][0] + delta_x_a*idx_x + delta_x_a*0.25 # x coordinate of left corner of panel fhs_xi_a2 = fhs.origin[idx_y][0] + delta_x_a*idx_x + delta_x_a # x coordinate of bottom left corner of bound vortex fhs_xi_ac = fhs.origin[idx_y][0] + delta_x_a*idx_x + delta_x_a*0.75 # x coordinate of bottom left corner of control point vortex fhs_xi_b1 = fhs.origin[idx_y+1][0] + delta_x_b*idx_x # x coordinate of top right corner of panel fhs_xi_bh = fhs.origin[idx_y+1][0] + delta_x_b*idx_x + delta_x_b*0.25 # x coordinate of right corner of bound vortex fhs_xi_b2 = fhs.origin[idx_y+1][0] + delta_x_b*idx_x + delta_x_b # x coordinate of bottom right corner of panel fhs_xi_bc = fhs.origin[idx_y+1][0] + delta_x_b*idx_x + delta_x_b*0.75 # x coordinate of bottom right corner of control point vortex fhs_xi_c = (fhs.origin[idx_y][0] + fhs.origin[idx_y+1][0])/2 + delta_x*idx_x + delta_x*0.75 # x coordinate three-quarter chord control point for each panel fhs_xi_ch = (fhs.origin[idx_y][0] + fhs.origin[idx_y+1][0])/2 + delta_x*idx_x + delta_x*0.25 # x coordinate center of bound vortex of each panel fhs_xa1[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_a1 + fus.origin[0][0] fhs_ya1[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta_a[idx_y] + fus.origin[0][1] fhs_za1[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xa2[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_a2 + fus.origin[0][0] fhs_ya2[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta_a[idx_y] + fus.origin[0][1] fhs_za2[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xb1[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_b1 + fus.origin[0][0] fhs_yb1[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta_b[idx_y] + fus.origin[0][1] fhs_zb1[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xb2[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_b2 + fus.origin[0][0] fhs_yb2[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta_b[idx_y] + fus.origin[0][1] fhs_zb2[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xah[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_ah + fus.origin[0][0] fhs_yah[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta_a[idx_y] + fus.origin[0][1] fhs_zah[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xbh[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_bh + fus.origin[0][0] fhs_ybh[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta_b[idx_y] + fus.origin[0][1] fhs_zbh[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xch[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_ch + fus.origin[0][0] fhs_ych[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta[idx_y] + fus.origin[0][1] fhs_zch[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xc [idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_c + fus.origin[0][0] fhs_yc [idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta[idx_y] + fus.origin[0][1] fhs_zc [idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xac[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_ac + fus.origin[0][0] fhs_yac[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta_a[idx_y] + fus.origin[0][1] fhs_zac[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_xbc[idx_y*n_cw:(idx_y+1)*n_cw] = fhs_xi_bc + fus.origin[0][0] fhs_ybc[idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fhs_eta_b[idx_y] + fus.origin[0][1] fhs_zbc[idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][2] fhs_x[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = np.concatenate([fhs_xi_a1,np.array([fhs_xi_a2[-1]])]) + fus.origin[0][0] fhs_y[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = np.ones(n_cw+1)*fhs_eta_a[idx_y] + fus.origin[0][1] fhs_z[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = np.zeros(n_cw+1) + fus.origin[0][2] # fuselage vertical section delta_x_a = fvs.chord[idx_y]/n_cw delta_x_b = fvs.chord[idx_y + 1]/n_cw delta_x = (fvs.chord[idx_y]+fvs.chord[idx_y + 1])/(2*n_cw) fvs_xi_a1 = fvs.origin[idx_y][0] + delta_x_a*idx_x # z coordinate of top left corner of panel fvs_xi_ah = fvs.origin[idx_y][0] + delta_x_a*idx_x + delta_x_a*0.25 # z coordinate of left corner of panel fvs_xi_a2 = fvs.origin[idx_y][0] + delta_x_a*idx_x + delta_x_a # z coordinate of bottom left corner of bound vortex fvs_xi_ac = fvs.origin[idx_y][0] + delta_x_a*idx_x + delta_x_a*0.75 # z coordinate of bottom left corner of control point vortex fvs_xi_b1 = fvs.origin[idx_y+1][0] + delta_x_b*idx_x # z coordinate of top right corner of panel fvs_xi_bh = fvs.origin[idx_y+1][0] + delta_x_b*idx_x + delta_x_b*0.25 # z coordinate of right corner of bound vortex fvs_xi_b2 = fvs.origin[idx_y+1][0] + delta_x_b*idx_x + delta_x_b # z coordinate of bottom right corner of panel fvs_xi_bc = fvs.origin[idx_y+1][0] + delta_x_b*idx_x + delta_x_b*0.75 # z coordinate of bottom right corner of control point vortex fvs_xi_c = (fvs.origin[idx_y][0] + fvs.origin[idx_y+1][0])/2 + delta_x *idx_x + delta_x*0.75 # z coordinate three-quarter chord control point for each panel fvs_xi_ch = (fvs.origin[idx_y][0] + fvs.origin[idx_y+1][0])/2 + delta_x *idx_x + delta_x*0.25 # z coordinate center of bound vortex of each panel fvs_xc [idx_y*n_cw:(idx_y+1)*n_cw] = fvs_xi_c + fus.origin[0][0] fvs_zc [idx_y*n_cw:(idx_y+1)*n_cw] = np.ones(n_cw)*fvs_eta[idx_y] + fus.origin[0][2] fvs_yc [idx_y*n_cw:(idx_y+1)*n_cw] = np.zeros(n_cw) + fus.origin[0][1] fvs_x[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = np.concatenate([fvs_xi_a1,np.array([fvs_xi_a2[-1]])]) + fus.origin[0][0] fvs_z[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = np.ones(n_cw+1)*fvs_eta_a[idx_y] + fus.origin[0][2] fvs_y[idx_y*(n_cw+1):(idx_y+1)*(n_cw+1)] = np.zeros(n_cw+1) + fus.origin[0][1] fus_h_area += ((fhs.chord[idx_y]+fhs.chord[idx_y + 1])/2)*(fhs_eta_b[idx_y] - fhs_eta_a[idx_y]) fus_v_area += ((fvs.chord[idx_y]+fvs.chord[idx_y + 1])/2)*(fvs_eta_b[idx_y] - fvs_eta_a[idx_y]) # store this strip's discretization information LE_inds = np.full(n_cw, False) TE_inds = np.full(n_cw, False) LE_inds[0] = True TE_inds[-1] = True RNMAX = np.ones(n_cw, np.int16)*n_cw panel_numbers = np.linspace(1,n_cw,n_cw, dtype=np.int16) leading_edge_indices = np.append(leading_edge_indices , LE_inds ) trailing_edge_indices = np.append(trailing_edge_indices , TE_inds ) panels_per_strip = np.append(panels_per_strip , RNMAX ) chordwise_panel_number = np.append(chordwise_panel_number , panel_numbers ) # xyz positions for the right side of this fuselage's outermost panels fhs_x[-(n_cw+1):] = np.concatenate([fhs_xi_b1,np.array([fhs_xi_b2[-1]])])+ fus.origin[0][0] fhs_y[-(n_cw+1):] = np.ones(n_cw+1)*fhs_eta_b[idx_y] + fus.origin[0][1] fhs_z[-(n_cw+1):] = np.zeros(n_cw+1) + fus.origin[0][2] fvs_x[-(n_cw+1):] = np.concatenate([fvs_xi_a1,np.array([fvs_xi_a2[-1]])]) + fus.origin[0][0] fvs_z[-(n_cw+1):] = np.ones(n_cw+1)*fvs_eta_a[idx_y] + fus.origin[0][2] fvs_y[-(n_cw+1):] = np.zeros(n_cw+1) + fus.origin[0][1] fhs_cs = (fhs.chord[:-1]+fhs.chord[1:])/2 fvs_cs = (fvs.chord[:-1]+fvs.chord[1:])/2 # Horizontal Fuselage Sections wing_areas = [] wing_areas.append(np.array(fus_h_area, dtype=precision)) wing_areas.append(np.array(fus_h_area, dtype=precision)) # store points of horizontal section of fuselage fhs_cs = np.concatenate([fhs_cs, fhs_cs]) fhs_xah = np.concatenate([fhs_xah, fhs_xah]) fhs_yah = np.concatenate([fhs_yah,-fhs_yah]) fhs_zah = np.concatenate([fhs_zah, fhs_zah]) fhs_xbh = np.concatenate([fhs_xbh, fhs_xbh]) fhs_ybh = np.concatenate([fhs_ybh,-fhs_ybh]) fhs_zbh = np.concatenate([fhs_zbh, fhs_zbh]) fhs_xch = np.concatenate([fhs_xch, fhs_xch]) fhs_ych = np.concatenate([fhs_ych,-fhs_ych]) fhs_zch = np.concatenate([fhs_zch, fhs_zch]) fhs_xa1 = np.concatenate([fhs_xa1, fhs_xa1]) fhs_ya1 = np.concatenate([fhs_ya1,-fhs_ya1]) fhs_za1 = np.concatenate([fhs_za1, fhs_za1]) fhs_xa2 = np.concatenate([fhs_xa2, fhs_xa2]) fhs_ya2 = np.concatenate([fhs_ya2,-fhs_ya2]) fhs_za2 = np.concatenate([fhs_za2, fhs_za2]) fhs_xb1 = np.concatenate([fhs_xb1, fhs_xb1]) fhs_yb1 = np.concatenate([fhs_yb1,-fhs_yb1]) fhs_zb1 = np.concatenate([fhs_zb1, fhs_zb1]) fhs_xb2 = np.concatenate([fhs_xb2, fhs_xb2]) fhs_yb2 = np.concatenate([fhs_yb2,-fhs_yb2]) fhs_zb2 = np.concatenate([fhs_zb2, fhs_zb2]) fhs_xac = np.concatenate([fhs_xac, fhs_xac]) fhs_yac = np.concatenate([fhs_yac,-fhs_yac]) fhs_zac = np.concatenate([fhs_zac, fhs_zac]) fhs_xbc = np.concatenate([fhs_xbc, fhs_xbc]) fhs_ybc = np.concatenate([fhs_ybc,-fhs_ybc]) fhs_zbc = np.concatenate([fhs_zbc, fhs_zbc]) fhs_xc = np.concatenate([fhs_xc , fhs_xc ]) fhs_yc = np.concatenate([fhs_yc ,-fhs_yc]) fhs_zc = np.concatenate([fhs_zc , fhs_zc ]) fhs_x = np.concatenate([fhs_x , fhs_x ]) fhs_y = np.concatenate([fhs_y ,-fhs_y ]) fhs_z = np.concatenate([fhs_z , fhs_z ]) if model_geometry == True: # increment fuslage lifting surface sections VD.n_fus += 2 VD.n_cp += len(fhs_xch) VD.n_w += 2 VD.counter += 1 # store this fuselage's discretization information n_panels = n_sw*n_cw first_panel_ind = VD.XAH.size first_strip_ind = [VD.chordwise_breaks.size, VD.chordwise_breaks.size+n_sw] chordwise_breaks = first_panel_ind + np.arange(0,2*n_panels)[0::n_cw] VD.chordwise_breaks = np.append(VD.chordwise_breaks, np.int32(chordwise_breaks)) VD.spanwise_breaks = np.append(VD.spanwise_breaks , np.int32(first_strip_ind )) VD.n_sw = np.append(VD.n_sw , np.int16([n_sw, n_sw]) ) VD.n_cw = np.append(VD.n_cw , np.int16([n_cw, n_cw]) ) VD.surface_ID = np.append(VD.surface_ID , np.ones(len(fhs_xch)) * VD.counter) VD.surface_ID_full = np.append(VD.surface_ID_full , np.ones(((n_sw+1)*(n_cw+1))*2) * VD.counter) VD.leading_edge_indices = np.append(VD.leading_edge_indices , np.tile(leading_edge_indices , 2) ) VD.trailing_edge_indices = np.append(VD.trailing_edge_indices , np.tile(trailing_edge_indices , 2) ) VD.panels_per_strip = np.append(VD.panels_per_strip , np.tile(panels_per_strip , 2) ) VD.chordwise_panel_number = np.append(VD.chordwise_panel_number , np.tile(chordwise_panel_number , 2) ) VD.exposed_leading_edge_flag = np.append(VD.exposed_leading_edge_flag, np.tile(np.ones(n_sw,dtype=np.int16), 2) ) # Store fus in vehicle vector VD.XAH = np.append(VD.XAH , np.array(fhs_xah , dtype=precision)) VD.YAH = np.append(VD.YAH , np.array(fhs_yah , dtype=precision)) VD.ZAH = np.append(VD.ZAH , np.array(fhs_zah , dtype=precision)) VD.XBH = np.append(VD.XBH , np.array(fhs_xbh , dtype=precision)) VD.YBH = np.append(VD.YBH , np.array(fhs_ybh , dtype=precision)) VD.ZBH = np.append(VD.ZBH , np.array(fhs_zbh , dtype=precision)) VD.XCH = np.append(VD.XCH , np.array(fhs_xch , dtype=precision)) VD.YCH = np.append(VD.YCH , np.array(fhs_ych , dtype=precision)) VD.ZCH = np.append(VD.ZCH , np.array(fhs_zch , dtype=precision)) VD.XA1 = np.append(VD.XA1 , np.array(fhs_xa1 , dtype=precision)) VD.YA1 = np.append(VD.YA1 , np.array(fhs_ya1 , dtype=precision)) VD.ZA1 = np.append(VD.ZA1 , np.array(fhs_za1 , dtype=precision)) VD.XA2 = np.append(VD.XA2 , np.array(fhs_xa2 , dtype=precision)) VD.YA2 = np.append(VD.YA2 , np.array(fhs_ya2 , dtype=precision)) VD.ZA2 = np.append(VD.ZA2 , np.array(fhs_za2 , dtype=precision)) VD.XB1 = np.append(VD.XB1 , np.array(fhs_xb1 , dtype=precision)) VD.YB1 = np.append(VD.YB1 , np.array(fhs_yb1 , dtype=precision)) VD.ZB1 = np.append(VD.ZB1 , np.array(fhs_zb1 , dtype=precision)) VD.XB2 = np.append(VD.XB2 , np.array(fhs_xb2 , dtype=precision)) VD.YB2 = np.append(VD.YB2 , np.array(fhs_yb2 , dtype=precision)) VD.ZB2 = np.append(VD.ZB2 , np.array(fhs_zb2 , dtype=precision)) VD.XAC = np.append(VD.XAC , np.array(fhs_xac , dtype=precision)) VD.YAC = np.append(VD.YAC , np.array(fhs_yac , dtype=precision)) VD.ZAC = np.append(VD.ZAC , np.array(fhs_zac , dtype=precision)) VD.XBC = np.append(VD.XBC , np.array(fhs_xbc , dtype=precision)) VD.YBC = np.append(VD.YBC , np.array(fhs_ybc , dtype=precision)) VD.ZBC = np.append(VD.ZBC , np.array(fhs_zbc , dtype=precision)) VD.XC = np.append(VD.XC , np.array(fhs_xc , dtype=precision)) VD.YC = np.append(VD.YC , np.array(fhs_yc , dtype=precision)) VD.ZC = np.append(VD.ZC , np.array(fhs_zc , dtype=precision)) VD.CS = np.append(VD.CS , np.array(fhs_cs , dtype=precision)) VD.X = np.append(VD.X , np.array(fhs_x , dtype=precision)) VD.Y = np.append(VD.Y , np.array(fhs_y , dtype=precision)) VD.Z = np.append(VD.Z , np.array(fhs_z , dtype=precision)) VD.wing_areas = np.append(VD.wing_areas, wing_areas) VL = VD.vortex_lift VL.append(False) VL.append(False) return VD