diff --git a/+af_tools/+utils/parsefileinputs.m b/+af_tools/+utils/parsefileinputs.m index f68462f591b501e1da6e21b4bba3e1935894e4d1..6b51f2a78e46598d5eaab06725699d69f76768a0 100644 --- a/+af_tools/+utils/parsefileinputs.m +++ b/+af_tools/+utils/parsefileinputs.m @@ -106,6 +106,10 @@ end function bool = isoption(optList, var) % ISOPTION Returns true if var is contained in option list -bool = any(strcmpi(var,optList)); +if iscell(var) + bool = false; +else + bool = any(strcmpi(var,optList)); +end end diff --git a/+af_tools/+utils/spacedvector.m b/+af_tools/+utils/spacedvector.m new file mode 100644 index 0000000000000000000000000000000000000000..3601a13af9850aa0f7404792e7acfdc69e8346e5 --- /dev/null +++ b/+af_tools/+utils/spacedvector.m @@ -0,0 +1,15 @@ +function vect = spacedvector(spacing, nPoints) +% SPACEDVECTOR Returns a vector based on chosen spacing and number of points + +switch spacing + case 'linear' + vect = linspace(0, 1, (nPoints)); + case 'halfcosine' + beta = linspace(0, pi, (nPoints)); + vect = (1-cos(beta))/2; + case 'cosine' + beta = linspace(0, pi/2, (nPoints)); + vect = 1-cos(beta); +end + +end diff --git a/+af_tools/uiuccleaner.m b/+af_tools/uiuccleaner.m index 3503ba1eb75738e29f9b0f342cf38922daa4f874..2226312d17f740d7b57e2c0619f4509e5e9d875f 100644 --- a/+af_tools/uiuccleaner.m +++ b/+af_tools/uiuccleaner.m @@ -39,6 +39,10 @@ function Dat = uiuccleaner(varargin) % 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. % +% DAT = UIUCCLEANER(..., 'refine', true) refines the input data by using a +% spline interpolation with 100 coordinates in total, spaced following the +% half-cosine rule. False by default. +% % Inputs: % inputDir : Path of the directory with the UIUC oridinal dat-files % inputFiles : Files to select (ex: '*' (default), '*0012*', {'file1','file2'}, etc) @@ -57,6 +61,7 @@ function Dat = uiuccleaner(varargin) % UIUCCLEANER('test_data', {'0012_re1e5', '0012_re1e6'}) % UIUCCLEANER('test_data', 'autosave', true) % UIUCCLEANER('test_data', 'overwrite', true) +% UIUCCLEANER('test_data', 'refine', true) % % See also: NACAAIRFOIL. @@ -69,18 +74,20 @@ function Dat = uiuccleaner(varargin) % https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox % ------------------------------------------------------------------------------ -narginchk(0,6); +narginchk(0,8); % Import other functions from this package import af_tools.utils.* % Constants and defaults -OPTION_LIST = {'autosave', 'overwrite'}; +OPTION_LIST = {'autosave', 'overwrite', 'refine'}; FILETYPE = '.dat'; +REFINED_SPACING = 'halfcosine'; +REFINED_NPOINTS = ceil((100+1)/2); % Parse inputs [allFileNames, fullpath, idxOpts] = parsefileinputs(OPTION_LIST, FILETYPE, varargin{:}); -[autosave, overwrite] = parseoptioninputs(varargin{idxOpts:end}); +[autosave, overwrite, refine] = parseoptioninputs(varargin{idxOpts:end}); % Convert filenames to string array allFileNames = string(allFileNames); @@ -115,14 +122,31 @@ for i=1:nbFiles upper = flipud(resultArray(1:idx,:)); lower = resultArray(idx+1:end,:); resultArray = [upper;lower(2:end,:)]; + end + + % Refine coordinates to add more points + if refine && size(resultArray,1) < 2*REFINED_NPOINTS + xc = fliplr(spacedvector(REFINED_SPACING, REFINED_NPOINTS))'; + + idx = find(diff(resultArray(:,1)) < 0, 1, 'last'); + upper = resultArray(1:idx+1,:); + lower = resultArray(idx+1:end,:); + + refinedUpperY = interp1(upper(:,1),upper(:,2),xc,'spline'); + refinedLowerY = interp1(lower(:,1),lower(:,2),flipud(xc),'spline'); + x = [xc; flipud(xc(1:end-1))]; + y = [refinedUpperY; refinedLowerY(2:end)]; + resultArray = [x,y]; 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 @@ -150,7 +174,7 @@ end % ------------------------------------------------------------------------------ -function [autosave, overwrite] = parseoptioninputs(varargin) +function [autosave, overwrite, refine] = parseoptioninputs(varargin) % PARSEOPTIONINPUTS Parses the options and checks their validity import af_tools.utils.* @@ -158,6 +182,7 @@ import af_tools.utils.* % Constants and defaults DEFAULT_AUTOSAVE = false; DEFAULT_OVEWRITE = false; +DEFAULT_REFINE = false; % Option validator validLogical = @(x) validateattributes(x, {'logical'},{'scalar'}, mfilename()); @@ -166,8 +191,10 @@ validLogical = @(x) validateattributes(x, {'logical'},{'scalar'}, mfilename()); p = inputParser; addParameter(p,'autosave',DEFAULT_AUTOSAVE, validLogical); addParameter(p,'overwrite',DEFAULT_OVEWRITE, validLogical); +addParameter(p,'refine',DEFAULT_REFINE, validLogical); parse(p,varargin{:}); autosave = p.Results.autosave; overwrite = p.Results.overwrite; +refine = p.Results.refine; end diff --git a/README.md b/README.md index b213e247934e1a9012b3fd3df44f840eea55ffca..0915c8cc4f9ef5c2b523846f6ef69319131b3489 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ Polar = uiuccleaner(inputDir, inputFiles, 'overwrite', true) | | | | | 'autosave' | `false`, `true` | `false` | | 'overwrite' | `false`, `true` | `false` | +| 'refine' | `false`, `true` | `false` | ### Airfoil generation diff --git a/tests/test_uiuccleaner.m b/tests/test_uiuccleaner.m index 451192e24f180d88faee72aaed53a524d5838453..dea3c76fc6d71b08b843d5b5f7ea7bd23e311feb 100644 --- a/tests/test_uiuccleaner.m +++ b/tests/test_uiuccleaner.m @@ -59,7 +59,7 @@ function test_nargin(testCase) dummy = (1:10)'; -verifyError(testCase, @() af_tools.uiuccleaner(dummy, dummy, dummy, 'autosave',true,'overwrite',false), 'MATLAB:narginchk:tooManyInputs') +verifyError(testCase, @() af_tools.uiuccleaner(dummy, dummy, dummy, 'autosave',true,'overwrite',false, 'refine', true), 'MATLAB:narginchk:tooManyInputs') end @@ -124,6 +124,12 @@ verifyError(testCase, @() af_tools.uiuccleaner(testdir, 'overwrite', char), 'MAT verifyError(testCase, @() af_tools.uiuccleaner(testdir, 'overwrite', Struct), 'MATLAB:uiuccleaner:invalidType') verifyError(testCase, @() af_tools.uiuccleaner(testdir, 'overwrite', vect), 'MATLAB:uiuccleaner:invalidType') +verifyError(testCase, @() af_tools.uiuccleaner(testdir, 'refine', empty), 'MATLAB:uiuccleaner:invalidType') +verifyError(testCase, @() af_tools.uiuccleaner(testdir, 'refine', scal), 'MATLAB:uiuccleaner:invalidType') +verifyError(testCase, @() af_tools.uiuccleaner(testdir, 'refine', char), 'MATLAB:uiuccleaner:invalidType') +verifyError(testCase, @() af_tools.uiuccleaner(testdir, 'refine', Struct), 'MATLAB:uiuccleaner:invalidType') +verifyError(testCase, @() af_tools.uiuccleaner(testdir, 'refine', vect), 'MATLAB:uiuccleaner:invalidType') + end @@ -164,4 +170,26 @@ verifyEqual(testCase, Dat(1).x(end), 1) verifyEqual(testCase, Dat(2).x(end), 1) verifyEqual(testCase, Dat(2).x(end), 1) +end + +function test_correctRefinePoints(testCase) +% Verify if the output of refined solution has 101 points + +testdir = [pwd,'/test_utils']; +nPoints = 101; + +DatNoRefine = af_tools.uiuccleaner(testdir, '*'); +Dat = af_tools.uiuccleaner(testdir, '*', 'refine', true); + +for i = 1:length(Dat) + if length(DatNoRefine(i).x) > nPoints + verifyEqual(testCase, Dat(i).x, DatNoRefine(i).x) + verifyEqual(testCase, Dat(i).y, DatNoRefine(i).y) + else + verifyEqual(testCase, length(Dat(i).x), nPoints) + verifyEqual(testCase, length(Dat(i).y), nPoints) + end +end + + end