def set_autopanels(aircraft, settings): """ Automatically set chord- and spanwise discretisation settings Args: :aircraft: (object) data structure for aircraft geometry :autopanels_c: (int) number of chordwise panels on the main wing :autopanels_s: (int) number of spanwise panels on the main wing """ autopanels_c = settings.settings.get('vlm_autopanels_c', MIN_AUTOPANELS) autopanels_s = settings.settings.get('vlm_autopanels_s', MIN_AUTOPANELS) for this_segment, _ in ot.all_segments(aircraft): segment = this_segment[2] if segment.panels['num_c'] is None: segment.panels['num_c'] = autopanels_c if segment.panels['num_s'] is None: wing_span = segment.parent_wing.span segment_span = segment.geometry['span'] segment.panels['num_s'] = ceil((segment_span/wing_span)*autopanels_s) for this_control, this_wing in ot.all_controls(aircraft): control = this_control[2] if control.panels['num_c'] is None: control.panels['num_c'] = autopanels_c
def add_controls(axes_2d, axes_3d, aircraft): """ Add control surfaces to axes objects Args: :axes_2d: 2D axes object (matplotlib) :axes_3d: 3D axes object (matplotlib) :aircraft: (object) data structure for aircraft model """ axes_yz, axes_xz, axes_xy = axes_2d for (_, _, control), (_, _, wing) in ot.all_controls(aircraft): # ----- Add outer control geometry ----- color = C.CONTROL_FLAP if control.device_type == 'flap' else C.CONTROL_SLAT vertex_order = 'dabc' if control.device_type == 'flap' else 'bcda' points = np.array([ control.abs_vertices[vertex_name] for vertex_name in vertex_order ]) _plot_XYZ_points(axes_2d, axes_3d, points, wing.symmetry, linewidth=PS.LINEWIDTH_c, color=color) # ----- Add hinges ----- points = np.array([ control.abs_hinge_vertices['p_inner'], control.abs_hinge_vertices['p_outer'], ]) _plot_XYZ_points(axes_2d, axes_3d, points, wing.symmetry, linewidth=PS.LINEWIDTH_c, color=C.CONTROL_HINGE)
def pre_panelling(aircraft): """ Create subdivisions and subareas for all aircraft wings Note: * This routine divides the wing into subdivisions and subareas in order to generate a suitable mesh for wing with control surfaces. * In a first step "mandatory" subdivisions are made: The wing is divided into a minimum amount of subareas according to the leading and trailing edge control surfaces. * In a second step further spanwise subdivisions are added. Args: :aircraft: (obj) aircraft object """ # TODO: # - Potential problem: # * The algorithm is based on "correct ordering" of segments: # Segments must be ordered from root to tip (check if this always given!?) # ===== PART ONE (MANDATORY SUBDIVISIONS) ===== # For each control we must add suitable subdivisions for this_control, this_wing in ot.all_controls(aircraft): control = this_control[2] wing = this_wing[2] # Segment names on which control surface edges are located segment_inner_name = control.segment_uid['inner'] segment_outer_name = control.segment_uid['outer'] # Control surface geometry eta_inner = control.rel_vertices['eta_inner'] eta_outer = control.rel_vertices['eta_outer'] xsi_inner = control.rel_vertices['xsi_inner'] xsi_outer = control.rel_vertices['xsi_outer'] # Hinge axis xsi_h1 = control.rel_hinge_vertices['xsi_inner'] xsi_h2 = control.rel_hinge_vertices['xsi_outer'] # ----- CASE (A) ----- # The left and right edge of the control are located on SAME segment if segment_inner_name == segment_outer_name: wing.segments[segment_inner_name].add_subdivision_for_control( eta_inner, eta_outer, control, xsi_inner, xsi_outer, xsi_h1, xsi_h2) # ----- CASE (B) ----- # - The control surface spans over one or more segment borders # - Now we will make a list of segments over which the control spans # - We will interpolate the position of the control and the hinge # axis at segment borders else: # Create a list of segments which contain the control # list_of_segments[0]: segment_uid # list_of_segments[1]: eta_inner # list_of_segments[2]: eta_outer # list_of_segments[3]: xsi_inner # list_of_segments[4]: xsi_outer # list_of_segments[5]: xsi_h1 # list_of_segments[6]: xsi_h2 list_of_segments = [] # Flags to indicate that the inner or outer control positions have been set inner_set = False outer_set = False # To start with we use averaged values for xsi (geometry and hinge axis) xsi_avg = (xsi_inner + xsi_outer)/2 xsi_h_avg = (xsi_h1 + xsi_h2)/2 for segment_uid in wing.segments.keys(): if segment_uid == segment_inner_name: inner_set = True # Note: eta_outer = 1 list_of_segments.append([segment_uid, eta_inner, 1, xsi_inner, xsi_avg, xsi_h1, xsi_h_avg]) continue elif inner_set and not outer_set: # Note: eta_inner = 0 # Note: eta_outer = 1 list_of_segments.append([segment_uid, 0, 1, xsi_avg, xsi_avg, xsi_h_avg, xsi_h_avg]) # If we are on the last segment we must update some incorrectly set values if segment_uid == segment_outer_name: outer_set = True list_of_segments[-1][2] = eta_outer list_of_segments[-1][4] = xsi_outer list_of_segments[-1][6] = xsi_h2 break # Potentially, we must readjust the control surface geometry/hinge axis at borders if (xsi_inner != xsi_outer) or (xsi_h1 != xsi_h2): # Let's first compute the "length" of the control surface control_len = [0, ] for row in list_of_segments: segment_uid, eta_i, eta_o, xsi_i, xsi_o, xsi_hi, xsi_ho = row segment = wing.segments[segment_uid] segment_vertices = segment.vertices a = get_abs_segment_point_coords(segment_vertices, eta_i, xsi_i) b = get_abs_segment_point_coords(segment_vertices, eta_o, xsi_o) ab = b - a # l: total length of control l = control_len[-1] control_len.append(l + np.sqrt(np.dot(ab, ab))) l = control_len[-1] # Now, we update the xsi values using linear interpolation for i, row in enumerate(list_of_segments): segment_uid, eta_i, eta_o, xsi_i, xsi_o, xsi_hi, xsi_ho = row # Update the xsi values l_i = control_len[i] l_o = control_len[i+1] xsi_i = lin_interpol((xsi_inner, xsi_outer), (0, l), l_i) xsi_o = lin_interpol((xsi_inner, xsi_outer), (0, l), l_o) xsi_hi = lin_interpol((xsi_h1, xsi_h2), (0, l), l_i) xsi_ho = lin_interpol((xsi_h1, xsi_h2), (0, l), l_o) list_of_segments[i] = [segment_uid, eta_i, eta_o, xsi_i, xsi_o, xsi_hi, xsi_ho] # Finally, we create the subdivisions using our list for row in list_of_segments: segment_uid, eta_i, eta_o, xsi_i, xsi_o, xsi_h1, xsi_h2 = row wing.segments[segment_uid].add_subdivision_for_control( eta_i, eta_o, control, xsi_i, xsi_o, xsi_h1, xsi_h2) # ===== PART TWO (ADDITIONAL SPANWISE SUBDIVISIONS) ===== # - Adding additional spanwise subdivisions is done here in Python rather # than in the C code as it is more convenient to keep track of which # parts (subareas) of the discretised surface have which functions for this_segment, _ in ot.all_segments(aircraft): segment = this_segment[2] for eta in np.linspace(0, 1, segment.panels['num_s']+1): if (eta == 0) or (eta == 1): continue segment.add_subdivision(eta, eta, ignore_inval_eta=True)
def get_aircraft_controls(aircraft, wing_uid, idx_wing, tixi, tigl): """ Extract the controls surfaces Args: :aircraft: Aircraft model :wing_uid: Name of the wing :idx_wing: Index of the wing :tixi: Tixi handle :tigl: Tigl handle .. warning:: * CPACS3 changed the control surface defintions! * In Tigl 3.0.0 some fuctions for controlSurfaces are missing (currently we use a workaround, see PATCH_* functions) * In CPACS3 relative coordinates can be defined based on a 'section' or 'componentSegment', currently we assume the old definition (based on 'componentSegment') """ # Abbreviate long function name tigl.get_eta_xsi = tigl.wingComponentSegmentPointGetSegmentEtaXsi # ---------- Iterate through component sections (contain control surfaces) ---------- num_comp_sections = tigl.wingGetComponentSegmentCount(idx_wing) for idx_comp_section in range(1, num_comp_sections + 1): name_comp_section = tigl.wingGetComponentSegmentUID( idx_wing, idx_comp_section) # ---------- Iterate through controls ---------- # PATCHED # for idx_control in range(1, tigl.getControlSurfaceCount(name_comp_section) + 1): num_controls = PATCH_getControlSurfaceCount(tixi, name_comp_section) for idx_control in range(1, num_controls + 1): for device_pos in ('leading', 'trailing'): # PATCHED # control_uid = tigl.getControlSurfaceUID(name_comp_section, idx_control) control_uid = PATCH_getControlSurfaceUID( tixi, name_comp_section, idx_control) logger.debug( f"Wing {idx_wing:d} has control '{control_uid:s}'") node_control = XPATHS.CONTROL(idx_wing, idx_comp_section, idx_control, device_pos) # Try to read the relative coordinates for each control (eta, xsi) # ====================================================== # TODO: does tixi.getDoubleElement() raise an error??? # ====================================================== try: # Control vertices etaLE_ib = tixi.getDoubleElement( node_control + "/outerShape/innerBorder/etaLE/eta") etaTE_ib = tixi.getDoubleElement( node_control + "/outerShape/innerBorder/etaTE/eta") xsiLE_ib = tixi.getDoubleElement( node_control + "/outerShape/innerBorder/xsiLE/xsi") etaLE_ob = tixi.getDoubleElement( node_control + "/outerShape/outerBorder/etaLE/eta") etaTE_ob = tixi.getDoubleElement( node_control + "/outerShape/outerBorder/etaTE/eta") xsiLE_ob = tixi.getDoubleElement( node_control + "/outerShape/outerBorder/xsiLE/xsi") # Hinge parameters hingeXsi_ib = tixi.getDoubleElement( node_control + "/path/innerHingePoint/hingeXsi") hingeXsi_ob = tixi.getDoubleElement( node_control + "/path/outerHingePoint/hingeXsi") except tixiwrapper.TixiException: logger.debug( f"No control data found for NODE {node_control:s}") continue if device_pos == 'leading': # Enforcing parallelism between control edges and x-axis xsiLE_ib = 0.0 xsiLE_ob = 0.0 # Relative coordinates of control w.r.t. component segment _, segment_uid_inner, eta_inner, xsi_inner = tigl.get_eta_xsi( name_comp_section, etaTE_ib, xsiTE_ib) _, segment_uid_outer, eta_outer, xsi_outer = tigl.get_eta_xsi( name_comp_section, etaTE_ob, xsiTE_ob) # Relative coordinates of control hinge line w.r.t. component segment _, _, _, xsi_h1 = tigl.get_eta_xsi(name_comp_section, etaTE_ib, hingeXsi_ib) _, _, _, xsi_h2 = tigl.get_eta_xsi(name_comp_section, etaTE_ob, hingeXsi_ob) elif device_pos == 'trailing': xsiTE_ib = 1.0 xsiTE_ob = 1.0 # Relative coordinates of control w.r.t. component segment _, segment_uid_inner, eta_inner, xsi_inner = tigl.get_eta_xsi( name_comp_section, etaLE_ib, xsiLE_ib) _, segment_uid_outer, eta_outer, xsi_outer = tigl.get_eta_xsi( name_comp_section, etaLE_ob, xsiLE_ob) # Relative coordinates of control hinge line w.r.t. component segment _, _, _, xsi_h1 = tigl.get_eta_xsi(name_comp_section, etaLE_ib, hingeXsi_ib) _, _, _, xsi_h2 = tigl.get_eta_xsi(name_comp_section, etaLE_ob, hingeXsi_ob) # ADD WING CONTROL AND SET ATTRIBUTES control = aircraft.wings[wing_uid].add_control(control_uid) control.device_type = 'flap' if device_pos == 'trailing' else 'slat' # Set DEFAULT deflection to 0 control.deflection = 0 control.rel_vertices['eta_inner'] = eta_inner control.rel_vertices['xsi_inner'] = xsi_inner control.rel_vertices['eta_outer'] = eta_outer control.rel_vertices['xsi_outer'] = xsi_outer control.rel_hinge_vertices['xsi_inner'] = xsi_h1 control.rel_hinge_vertices['xsi_outer'] = xsi_h2 control.segment_uid['inner'] = segment_uid_inner control.segment_uid['outer'] = segment_uid_outer # ----- CONTROL SURFACE DEFLECTION ----- try: n_control_dev = tixi.getNamedChildrenCount(XPATHS.TOOLSPEC_CONTROL, 'controlDevice') except: n_control_dev = 0 for idx_control in range(1, n_control_dev + 1): node_control_device = XPATHS.TOOLSPEC_CONTROL + '/controlDevice[{}]'.format( idx_control) control_uid = tixi.getTextAttribute(node_control_device, 'uID') deflection = 0 deflection_mirror = None try: deflection = tixi.getDoubleElement(node_control_device + '/deflection') except tixiwrapper.TixiException: logger.error( "Unable to read 'deflection' for control '{:s}'".format( control_uid)) try: deflection_mirror = tixi.getDoubleElement(node_control_device + '/deflectionMirror') except: logger.warning( "Unable to read 'deflection_mirror' for control '{:s}'".format( control_uid)) deflection_is_set = False for this_wing in all_wings(aircraft): wing = this_wing[2] if control_uid in wing.controls.keys(): wing.controls[control_uid].deflection = deflection wing.controls[ control_uid].deflection_mirror = deflection_mirror deflection_is_set = True break if not deflection_is_set: logger.error("Could not set deflection for control '{:s}'".format( control_uid)) raise ComponentDefinitionError( "Control '{:s}' not found".format(control_uid)) # ----- CONTROL CHECKS ----- for this_control, _ in all_controls(aircraft): this_control[2].check()