Skip to content

Commit

Permalink
Updated for Alpha release 3
Browse files Browse the repository at this point in the history
  • Loading branch information
JonKing93 committed Oct 15, 2020
1 parent 12fc8b1 commit 2d9a3f8
Show file tree
Hide file tree
Showing 81 changed files with 2,619 additions and 308 deletions.
22 changes: 22 additions & 0 deletions @dash/assertScalarType.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function[] = assertScalarType(input, name, type, typeName)
%% Checks that an input is a scalar of a particular class. Throws a custom
% error message if not.
%
% dash.assertScalarType(input, name, type, typeName)
%
% ----- Inputs -----
%
% input: The input being checked
%
% name: The name of the input. A string. Used for error message.
%
% type: The required class type of the input. A string
%
% typeName: The name used to reference the type. Used for error messages. A
% string.

if ~isscalar(input) || ~isa(input, type)
error('%s must be a scalar %s.', name, typeName);
end

end
7 changes: 7 additions & 0 deletions @dash/bothNaN.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function[tf] = bothNaN(A, B)
%% Tests if two inputs are both NaN.
tf = false;
if isnumeric(A) && isnumeric(B) && isscalar(A) && isscalar(B) && isnan(A) && isnan(B)
tf = true;
end
end
2 changes: 1 addition & 1 deletion @dash/checkIndices.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

% Other types are not allowed
else
error('%s must either be logical or numeric.');
error('%s must either be logical or numeric.', name);
end
end

Expand Down
18 changes: 13 additions & 5 deletions @dash/dash.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,27 @@
methods (Static)

% Misc
names = dimensionNames;
varargout = parseInputs(inArgs, flags, defaults, nPrev);
[names, lon, lat, coord, lev, time, run, var] = dimensionNames;
convertToV7_3(filename);
X = permuteToOrder(X, order, nDims);
[X, order] = permuteDimensions(X, index, iscomplete, nDims);
tf = bothNaN(A, B);
s = loadMatfileFields(file, fields, extName);

% Input parsing
varargout = parseInputs(inArgs, flags, defaults, nPrev);
[input, wasCell] = parseInputCell(input, nDims, name);
input = parseLogicalString(input, nDims, logicalName, stringName, allowedStrings, lastTrue, name);
index = parseListIndices(input, strName, indexName, list, listName, lengthName, inputNumber, eltNames);

% Structures
[s, inputs] = preallocateStructs(fields, siz);
values = collectField(s, field);

% File paths
% Files
path = checkFileExists(file);
path = unixStylePath(path);
path = relativePath(toFile, fromFolder);
filename = setupNewFile(filename, ext, overwrite);

% Strings and string lists
tf = isstrflag( input );
Expand All @@ -28,7 +36,7 @@
str = messageList(list);

% Input assertions
assertScalarLogical(input, name);
assertScalarType(input, name, type, typeName);
assertRealDefined(input, name, allowNaN, allowInf, allowComplex);
assertVectorTypeN(input, type, N, name);
assertPositiveIntegers(input, allowNaN, allowInf, name);
Expand Down
42 changes: 42 additions & 0 deletions @dash/loadMatfileFields.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
function[s] = loadMatfileFields(file, matFields, extName)
%% Checks that a file is a .mat formatted file with required fields.
% Returns a structure (not a matfile) with the fields.
%
% s = dash.loadMatfileFields(file, matFields, extName)
%
% ----- Inputs -----
%
% file: The name of a .mat formatted file. A string.
%
% matFields: The names of the required fields in the matfile. A string vector.
%
% extName: The extension type used by the .mat formatted file. A string
%
% ----- Outputs -----
%
% s: A structure with the loaded fields

% Check the file exists
if ~isfile(file)
error('The file "%s" no longer exists. It may have been deleted or moved to a new location.', file);
end

% Load the data in the matfile. (Use load instead of indexing to avoid
% calls to "whos", which are expensive)
matFields = cellstr(matFields);
try
s = load(file, '-mat', matFields{:});
catch
error(['Could not load data from "%s". It may not be a %s file. If it ',...
'a %s file, it may have become corrupted.'], objName, file, extName, extName);
end

% Check each field is in the file
loadedFields = fields(s);
infile = ismember(matFields, loadedFields);
if any(~infile)
bad = find(~infile,1);
error('File "%s" does not contain the "%s" field.', file, matFields{bad});
end

end
30 changes: 30 additions & 0 deletions @dash/parseInputCell.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
function[input, wasCell] = parseInputCell(input, nDims, name)
%% Parses inputs that may either be an input, or a cell vector of inputs.
% Returns the input as a cell. Throws a custom error message if cell
% vectors are incorrect.
%
% input = dash.parseInputCells(input, nDims, name)
%
% ----- Inputs -----
%
% input: The input being parsed
%
% nDims: The number of input dimensions.
%
% name: The name of the input cell. A string.
%
% ----- Outputs -----
%
% input: The input as a cell
%
% wasCell: Scalar logical. Whether the input was a cell or not

if nDims>1 || iscell(input)
dash.assertVectorTypeN(input, 'cell', nDims, name);
wasCell = true;
else
input = {input};
wasCell = false;
end

end
34 changes: 34 additions & 0 deletions @dash/parseListIndices.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
function[index] = parseListIndices(input, strName, indexName, list, listName, lengthName, inputNumber, eltNames)
%% Parses inputs that can either be strings in a list or set of indices. Returns
% the input as a set of linear indices.
%
% input: The input being parsed
%
% strName: The name of the input when a string list. A string.
%
% indexName: The name of the input when a set of indices. A string.
%
% list: The allowed values for strings. String vector.
%
% listName: The name of the list. A string
%
% lengthName: The name for the length. A string.
%
% inputNumber: Which input this is. A scalar integer.
%
% eltNames: The name of the elements in the list. A string.
%
% ----- Outputs -----
%
% index: Linear indices. If string inputs were provided, the indices of the
% inputs in the list.

if dash.isstrlist(input)
index = dash.checkStrsInList(input, list, strName, listName);
elseif isnumeric(input) || islogical(input)
index = dash.checkIndices(input, indexName, numel(list), lengthName);
else
error('Input %.f must either be a list of %s, or a set of indices.', inputNumber, eltNames);
end

end
55 changes: 55 additions & 0 deletions @dash/parseLogicalString.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
function[input] = parseLogicalString(input, nDims, logicalName, stringName, allowedStrings, lastTrue, name)
%% Parses inputs that can either be a logical or string. Returns the input
% as a logical. Throws custom error messages.
%
% input = dash.parseLogicalString( ...
% input, nDims, logicalName, stringName, allowedStrings, lastTrue)
%
% ----- Inputs -----
%
% input: The input being parsed
%
% nDims: The number of input dimensions.
%
% logicalName: The name of a logical input
%
% stringName: The name of a string input
%
% allowedStrings: Options for the string input. Should be organized such
% that all strings equivalent to a logical true are first.
%
% lastTrue: The index of the last string in allowedStrings equivalent to a
% logical true.
%
% name: An name for the combined string/logical variables.
%
% ----- Outputs -----
%
% input: The input as a logical

% Default for empty calls
if nDims==0 && isempty(input)
input = false(0,1);
end

% Logical
if islogical(input)
if ~isscalar(input)
dash.assertVectorTypeN(input, [], nDims, sprintf('Since %s is not a scalar, it', logicalName));
end

% Strings
elseif ischar(input) || isstring(input) || iscellstr(input)
input = string(input);
if ~isscalar(input)
dash.assertVectorTypeN(input, [], nDims, sprintf('Since %s is not a string scalar, it', stringName));
end
k = dash.checkStrsInList(input, allowedStrings, stringName, 'recognized flag');
input = k<=lastTrue;

% Anything else
else
error('%s must either be logicals or strings.', name);
end

end
51 changes: 51 additions & 0 deletions @dash/permuteDimensions.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
function[X, order] = permuteDimensions(X, index, iscomplete, nDims)
%% Permutes dimensions of an array to match a requested order. There are
% two common use cases.
%
% Case 1: The array has the complete set of dimensions and should be
% permuted to match a custom order. The custom order might only include
% a subset of all possible dimensions.
%
% Case 2: The array is in a custom order and might only hold a subset of all
% possible dimensions. We want to permute the array to fill the complete
% set of dimensions.
%
% [X, order] = dash.permuteDimensions(X, index, iscomplete, nDims)
%
% ----- Inputs -----
%
% X: The array
%
% index: The locations of the custom ordered dimensions in the complete set
% of dimensions. Usually generated via something like:
% >> [~, index] = ismember( customDims, allDims )
%
% iscomplete: A scalar logical indicating whether the input array has the
% complete set of dimensions in order. Use true for case 1 and false for
% case 2.
%
% nDims: The number of dimensions in the complete set of dimensions
%
% ----- Output -----
%
% X: The permuted array
%
% order: The permutation order used to permute X.

% Get the order of the subset dimensions in the complete array
d = 1:nDims;
order = [index, d(~ismember(d, index))];

% Case 1, the current dimension order is the complete array.
% In this case we are done. The order will map the complete array to the
% subset.

% Case 2, the current dimension order is a subset of the complete array.
if ~iscomplete
[~, order] = sort(order);
end

% Permute the array
X = permute(X, order);

end
41 changes: 41 additions & 0 deletions @dash/setupNewFile.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
function[filename] = setupNewFile( filename, ext, overwrite )
%% Does setup tasks for a new file. Adds the required extension if missing.
% Gets the full file path. If not overwriting, checks the file does not
% already exist.
%
% filename = dash.setupNewFile( filename, ext, overwrite )
%
% ----- Inputs -----
%
% filename: The input name of the file. A string.
%
% ext: The required file extension. A string.
%
% overwrite: A scalar logical indicating whether to overwrite an existing
% file.
%
% ----- Outputs -----
%
% filename: The full file path. A string

% Ensure the file has the correct extension
filename = char(filename);
[path, ~, currentExt] = fileparts(filename);
if ~strcmpi(ext, currentExt)
filename = strcat(filename, ext);
end

% Get the full path if unspecified
if isempty(path)
filename = fullfile(pwd, filename);
end

% If not allowing overlap, check the file does not already exist
if ~overwrite && isfile(filename)
error('The file "%s" already exists.', filename);
end

% Return filename as a string
filename = string(filename);

end
Loading

0 comments on commit 2d9a3f8

Please sign in to comment.