Skip to content
Snippets Groups Projects
Verified Commit 7ce55752 authored by Thomas Lambert's avatar Thomas Lambert :helicopter:
Browse files

feat: add UIUCCleaner

parent cf0b0430
No related branches found
No related tags found
No related merge requests found
function Dat = uiuccleaner(varargin)
% UIUCCLEANER Cleans airfoil data from UIUC Airfoil Database.
% The UIUC airfoil database from the University of Illinois gathers the
% coordinates for more than 1600 airfoils. However, there is a few
% discrepencies between the format and ordering of these coordinates. This
% scipts alleviates that by re-formatting any input file from the original
% database.
%
% Format:
% The output format of this script follows the "labeled coordinates" file,
% used originally by Selig on the UIUC Airfoil Database.
% The first line contains the name of the airfoil, and each line after that is
% a set of coordinates. The coordinates are ordered from the trailing edge,
% along the upper surface to the leading edge and back around the lower
% surface to trailing edge.
%
% Note:
% This function can be used on many files at once in order to speed-up the
% process.
%
% <a href="https://gitlab.uliege.be/thlamb/airfoil_toolbox">Documentation (README)</a>
% <a href="https://gitlab.uliege.be/thlamb/airfoil_toolbox/-/issues">Report an issue</a>
% -----
%
% Usage:
% DAT = UIUCCLEANER prompts the user for all inputs, then converts the
% coordinates to the correct standard.
%
% DAT = UIUCCLEANER(INPUTDIR) converts all dat files found in INPUTDIR.
%
% DAT = UIUCCLEANER(INPUTDIR, INPUTFILES) converts only the polars
% specified by INPUTFILES found in INPUTDIR.
%
% DAT = UIUCCLEANER(..., 'autosave', true) saves the resulting coordinates
% in a new dat-file.
%
% DAT = UIUCCLEANER(..., 'overwrite', true) saves the resulting coordinates
% by overwriting the original dat-file. If autosave is not specified but
% overwrite is true, the file will be overwritten anyway. If autosave is set
% to false and overwrite is true, the file will not be saved at all.
%
% Inputs:
% inputDir : Path of the directory with the UIUC oridinal dat-files
% inputFiles : Files to select (ex: '*' (default), '*0012*', {'file1','file2'}, etc)
%
% Output:
% Dat : A structure for the results for each input file.
% - Dat.file : original filename
% - Dat.airfoil : airfoil name, parsed from the input file
% - Dat.x : airfoil X coordinates, with 0 <= X <= 1
% - Dat.y : airfoil Y coordinates.
%
% Example:
% UIUCCLEANER
% UIUCCLEANER('test_data')
% UIUCCLEANER('test_data', '*0012*')
% UIUCCLEANER('test_data', {'0012_re1e5', '0012_re1e6'})
% UIUCCLEANER('test_data', 'autosave', true)
% UIUCCLEANER('test_data', 'overwrite', true)
%
% See also: NACAAIRFOIL.
% -----
% XFOIL: http://web.mit.edu/drela/Public/web/xfoil/
% XFLR5: https://www.xflr5.tech/xflr5.htm
% -----
% Copyright 2022 Thomas Lambert <t.lambert@uliege.be>
% ULiege - Aeroelasticity and Experimental Aerodynamics
% Apache 2.0 License
% https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox
% ------------------------------------------------------------------------------
narginchk(0,6);
% Import other functions from this package
import af_tools.utils.*
% Parse inputs
[allFileNames, fullpath, autosave, overwrite] = parseinputs(varargin{:});
% Convert filenames to string array
allFileNames = string(allFileNames);
% -------------------------------------
% Convert all files
% Number of files found
nbFiles=length(allFileNames);
% Initialize structures
Dat = struct('file', [], 'airfoil', [], 'x', [], 'y', []);
for i=1:nbFiles
% Load file and start parsing
% No matter the file type, line 1 should always be the airfoil name
fileID = fopen(fullfile(fullpath,allFileNames{i}));
tmpAirfoil = textscan(fileID,'%s', 1, 'Delimiter','\n:','HeaderLines',0);
resultArray = cell2mat(textscan(fileID,'%f %f %*[^\n]', 'HeaderLines',0)); % ! HeaderLines is a cursor. This will start reading at line 13
fclose(fileID); clear fileID;
% Re-order file if it is needed
if resultArray(1,1) ~= 0 && resultArray(1,1) ~= 1 && resultArray(2,1) == 0
% Remove first line
resultArray = resultArray(2:end,:);
% Find index at the end of the upper side (normally diff would be -1,
% but we use -0.5 in case the LE and TE are not precisely at 0 and 1. It
% should be the only negative diff anyway).
idx = find(diff(resultArray) < -0.5 ,1);
upper = flipud(resultArray(1:idx,:));
lower = resultArray(idx+1:end,:);
resultArray = [upper;lower(2:end,:)];
end
% Output structure
Dat(i).path = fullpath;
Dat(i).file = allFileNames{i};
Dat(i).airfoil = char(cellstr(tmpAirfoil{:}));
Dat(i).x = resultArray(:,1);
Dat(i).y = resultArray(:,2);
end
% -------------------------------------
% Save results automatically
if autosave
for i = 1:length(Dat)
filename = split(Dat(i).file,'.dat');
if ~overwrite
filename = [filename{1} ,'-CLEAN'];
end
filename = appendextension(filename,'.dat');
filename = fullfile(Dat(i).path,filename);
header = Dat(i).airfoil;
savecoordtodat(filename, header, Dat(i).x, Dat(i).y)
end
end
end
% ------------------------------------------------------------------------------
function [allFileNames, fullpath, autosave, overwrite] = parseinputs(varargin)
% PARSEINPUTS Parse inputs and return the list of files and options
import af_tools.utils.*
% Constants and defaults
DEFAULT_INPUTFILES = '*'; % If not specified, all files of the dir are included by default
DEFAULT_AUTOSAVE = false; % Do not autosave by default
DEFAULT_OVERWRITE = false; % Do not overwrite files by default
OPTION_LIST = {'autosave','overwrite'};
% Parse main inputs
hasNoInput = isempty(varargin) || isoption(OPTION_LIST, varargin{1});
if hasNoInput
% Prompt user for the files to read
[allFileNames, fullpath] = uigetfile('*.dat', 'Select all dat-files to aggregate', 'MultiSelect', 'on','textFiles');
idxOpts = 1;
else
inputDir = varargin{1};
idxOpts = 2;
if nargin >= 2 && ~isoption(OPTION_LIST, varargin{2})
idxOpts = 3;
inputFiles = varargin{2};
else
inputFiles = DEFAULT_INPUTFILES;
end
% Validate inputDir
validateattributes(inputDir, {'char','string'},{'nonempty','vector'}, mfilename(), 'inputDir')
if ~exist(inputDir, 'dir')
error('MATLAB:uiuccleaner:dirNotFound', ['The directory specified as inputDir (%s) can not be found!\n'], inputDir);
end
% Validate inputFiles
validateattributes(inputFiles, {'char','cell'},{'nonempty','vector'}, mfilename(), 'inputFiles', 4)
if iscell(inputFiles) && ~iscellstr(inputFiles)
error('MATLAB:uiuccleaner:wrongInputFiles', ['If inpuFiles is given as a cell array, it must '...
'contain only character vectors!\n']);
end
% ------------------------------------------------------
% Look for files
% Get absolute path
if contains(inputDir, pwd)
fullpath = inputDir;
else
fullpath = fullfile(pwd, inputDir);
end
% Convert inputFiles to string for simpler handling
inputFiles = string(inputFiles);
% Get all files
AllFiles = [];
for i = 1:length(inputFiles)
inputFiles(i) = appendextension(inputFiles(i),'.txt'); % Add extension
dummy = dir(fullfile(fullpath,inputFiles(i)));
if isempty(dummy)
warning('MATLAB:uiuccleaner:FileNotFound', 'Could not find file %s.', fullfile(fullpath,inputFiles(i)));
end
AllFiles = [AllFiles; dummy];
end
if isempty(AllFiles)
error('MATLAB:uiuccleaner:noFilesFound', 'Impossible to find ANY file matching the input arguments.');
end
allFileNames = cell(1,length(AllFiles));
for i = 1:length(AllFiles)
allFileNames{i} = AllFiles(i).name;
end
end
% Option validator
validLogical = @(x) validateattributes(x, {'logical'},{'scalar'}, mfilename());
% Parse options
p = inputParser;
addParameter(p,'autosave', DEFAULT_AUTOSAVE, validLogical);
addParameter(p,'overwrite', DEFAULT_OVERWRITE, validLogical);
parse(p,varargin{idxOpts:end});
autosave = p.Results.autosave;
overwrite = p.Results.overwrite;
end
% ------------------------------------------------------------------------------
function bool = isoption(optList, var)
% ISOPTION Returns true if var is contained in option list
bool = any(strcmpi(var,optList));
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment