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

# ----------------------------------------------------------------------
#  Imports
# ----------------------------------------------------------------------

# package imports 
import numpy as np

from RCAIDE.Framework.Core                                       import  Data
from RCAIDE.Library.Components.Wings                             import All_Moving_Surface
from RCAIDE.Library.Components.Fuselages                         import Fuselage 
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
 

# ----------------------------------------------------------------------
#  Generate Vortex Distribution
# ----------------------------------------------------------------------
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
# ----------------------------------------------------------------------
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
# ----------------------------------------------------------------------
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, 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
