def get_aircraft_name(aircraft, tixi): """ Extract the aircraft name from CPACS and add it to the aircraft model Args: :aircraft: Aircraft model :tixi: Tixi handle """ if tixi.checkElement(XPATHS.MODEL): aircraft_uid = parse_str(tixi.getTextAttribute(XPATHS.MODEL, 'uID')) logger.debug(f"Aircraft name: '{aircraft.uid}'") else: logger.warning(f"Could not find path '{XPATHS.MODEL}'") aircraft_uid = 'NAME_NOT_FOUND' aircraft.uid = aircraft_uid
def get_aircraft_wings(aircraft, settings, tixi, tigl): """ Extract aircraft wings including airfoils and controls Args: :aircraft: Aircraft model :tixi: Tixi handle :tigl: Tigl handle """ logger.info("Loading aircraft wings...") if not tixi.checkElement(XPATHS.WINGS): err_msg = f""" Could not find path '{XPATHS.WINGS}'. The aircraft must have at least one wing. """ logger.error(err_msg) raise ValueError(err_msg) # ---------- Iterate through wings ---------- num_wings = tixi.getNamedChildrenCount(XPATHS.WINGS, 'wing') for idx_wing in range(1, num_wings + 1): xpath_wing = XPATHS.WINGS + f"/wing[{idx_wing}]" try: wing_uid = parse_str(tixi.getTextAttribute(xpath_wing, 'uID')) except tixiwrapper.TixiException: wing_uid = f'WING{idx_wing:02}' logger.debug(f"Wing name: '{wing_uid}'") aircraft.add_wing(wing_uid) aircraft.wings[wing_uid].symmetry = tigl.wingGetSymmetry(idx_wing) # For each wing we set segment and control data get_aircraft_wing_segments(aircraft, settings, xpath_wing, wing_uid, idx_wing, tixi, tigl) get_aircraft_controls(aircraft, wing_uid, idx_wing, tixi, tigl)
def get_aircraft_airfoils(aircraft, settings, tigl, wing_uid, segment_uid, idx_wing, idx_segment): """ Extract the aircraft airfoils Args: :aircraft: Aircraft model :settings: Settings object :tigl: Tigl handle :segment_uid: Name of the segment :idx_wing: Index of the wing :idx_segment: Index of the segment """ for position in ['inner', 'outer']: if position == 'inner': tigl_func = tigl.wingGetInnerSectionAndElementIndex else: tigl_func = tigl.wingGetOuterSectionAndElementIndex idx_section, idx_elem = tigl_func(idx_wing, idx_segment) name_airfoil = parse_str( tigl.wingGetProfileName(idx_wing, idx_section, idx_elem)) if not name_airfoil: err_msg = f""" CPACS error: Could not extract {position} airfoil name * Wing: {idx_wing} * Segment: {idx_section} * Element: {idx_elem} """ raise ValueError(err_msg) file_airfoil = join_paths(settings.paths('root'), PATHS.FILES.AIRFOIL(name_airfoil)) aircraft.wings[wing_uid].segments[segment_uid].airfoils[ position] = str(file_airfoil)
def write_airfoil_files(settings, tixi): """ Extract airfoil data from CPACS and write airfoil files Args: :settings: Settings object :tixi: Tixi handle """ logger.debug("Extracting airfoil data...") num_airfoils = tixi.getNumberOfChilds(XPATHS.AIRFOILS) for i in range(1, num_airfoils + 1): node_airfoil = XPATHS.AIRFOILS + f"/wingAirfoil[{i}]" node_data = node_airfoil + "/pointList" try: name_airfoil = parse_str( tixi.getTextElement(node_airfoil + '/name')) except tixiwrapper.TixiException: name_airfoil = f'AIRFOIL{i:02d}' file_airfoil = join_paths(settings.paths('root'), PATHS.FILES.AIRFOIL(name_airfoil)) # Convert string to numpy array coords_x = np.fromstring(tixi.getTextElement(node_data + '/x'), sep=';') coords_z = np.fromstring(tixi.getTextElement(node_data + '/z'), sep=';') coords = np.transpose([coords_x, coords_z]) logger.info(f"Copying airfoil {name_airfoil} to file...") np.savetxt(file_airfoil, coords, header=f"{name_airfoil}", fmt=COORD_FORMAT)
def get_aircraft_wing_segments(aircraft, settings, xpath_wing, wing_uid, idx_wing, tixi, tigl): """ Extract a wing segment for a given wing Args: :aircraft: Aircraft model :settings: Settings object :xpath_wing: CPACS wing path :idx_wing: Wing index :tixi: Tixi handle :tigl: Tigl handle """ xpath_segments = xpath_wing + '/segments' if not tixi.checkElement(xpath_segments): err_msg = f"Could not find path '{xpath_segments}'" logger.error(err_msg) raise ValueError(err_msg) logger.debug(f"Loading segments of wing '{wing_uid}'...") # ---------- Iterate through segments of given wing ---------- num_segments = tixi.getNamedChildrenCount(xpath_segments, 'segment') for idx_segment in range(1, num_segments + 1): node_segment = xpath_segments + f"/segment[{idx_segment}]" try: segment_uid = parse_str(tixi.getTextAttribute(node_segment, 'uID')) except tixiwrapper.TixiException: segment_uid = f"{wing_uid}_SEGMENT{idx_segment:02}" logger.debug(f"Loading segment '{segment_uid}'...") aircraft.wings[wing_uid].add_segment(segment_uid) # Get the absolute segment vertices a = get_segment_mid_point(tigl, idx_wing, idx_segment, eta=0, xsi=0) b = get_segment_mid_point(tigl, idx_wing, idx_segment, eta=1, xsi=0) c = get_segment_mid_point(tigl, idx_wing, idx_segment, eta=1, xsi=1) d = get_segment_mid_point(tigl, idx_wing, idx_segment, eta=0, xsi=1) ######################################################################### # TODO: Put this in "objects.aircraft!?" ######################################################################### # Re-order vertices # * A, D should be at root and B, C at tip # * This is done so that the segments (thus panel normals point in the correct direction) if b[1] - a[1] < 0.0 or (b[1] == a[1] and b[2] - a[2] < 0.0): a, b, c, d = b, a, c, d if c[1] - d[1] < 0.0 or (c[1] == d[1] and c[2] - d[2] < 0.0): a, b, c, d = a, b, d, c if d[0] - a[0] < 0.0: a, b, c, d = d, b, c, a if c[0] - b[0] < 0.0: a, b, c, d = a, c, b, d ######################################################################### ######################################################################### ######################################################################### aircraft.wings[wing_uid].segments[segment_uid].vertices['a'] = a aircraft.wings[wing_uid].segments[segment_uid].vertices['b'] = b aircraft.wings[wing_uid].segments[segment_uid].vertices['c'] = c aircraft.wings[wing_uid].segments[segment_uid].vertices['d'] = d # ----- Set airfoils ----- get_aircraft_airfoils(aircraft, settings, tigl, wing_uid, segment_uid, idx_wing, idx_segment)