Skip to content

Commit

Permalink
feat(IMOS): schema evaluation for PP/QC
Browse files Browse the repository at this point in the history
This implements a simple function based schema validation
for PP/QC routines. The idea is to externalise some long
verification calls and inspections of individual routines
and turn the actual code that perform the PP/QC cleaner.

The schemas must be named exactly as functions within the
`+schema` folder.

`IMOS.validate_dataset` perform a schema validation of a function.

For practical examples, see
imosEchoIntensitySetQC & imosSurfaceDetectionByDepthSetQC.
  • Loading branch information
ocehugo committed Apr 1, 2021
1 parent fc362f0 commit 97d1146
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 0 deletions.
50 changes: 50 additions & 0 deletions Util/+IMOS/+schemas/imosEchoIntensitySetQC.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
function [bool, reason] = imosEchoIntensitySetQC(sample_data)
% function [bool,reason] = imosEchoIntensitySetQC(sample_data)
%
% Check if sample_data is a valid input for SurfaceDetectionByEchoIntensityQC.
%
% Inputs:
%
% sample_data [struct] - A toolbox dataset.
%
% Outputs:
%
% bool - True if dataset is valid. False otherwise.
% reason - The reasons why the dataset is invalid.
%
% Example:
%
% %see test_imosEchoIntensitySetQC.
%
% author: hugo.oliveira@utas.edu.au
%
narginchk(1,1)
reason = {};

if ~IMOS.adcp.contains_adcp_dimensions(sample_data)
reason{1} = 'Not an adcp file.';
end

avail_variables = IMOS.get(sample_data.variables,'name');
absic_counter = sum(contains(avail_variables,'ABSIC'));
if absic_counter == 0
reason{end+1} = 'Missing ABSIC variables.';
end

vel_vars = IMOS.meta.velocity_variables(sample_data);
if numel(vel_vars) == 0
reason{end+1} = 'Missing at leat one velocity variable to flag.';
end


if absic_counter > 4
reason{end+1} = 'Number of ABSIC variables is invalid';
end

if isempty(reason)
bool = true;
else
bool = false;
end

end
89 changes: 89 additions & 0 deletions Util/+IMOS/+schemas/imosSurfaceDetectionByDepthSetQC.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
function [bool, reason] = imosSurfaceDetectionByDepthSetQC(sample_data)
% function [bool,reason] = imosSurfaceDetectionByDepthSetQC(sample_data)
%
% Check if sample_data is a valid input for SurfaceDetectionByDepthSetQC.
%
% Inputs:
%
% sample_data [struct] - A toolbox dataset.
%
% Outputs:
%
% bool - True if dataset is valid. False otherwise.
% reason - The reasons why the dataset is invalid.
%
% Example:
%
% %see test_imosSurfaceDetectionByDepthSetQC.m
%
%
% author: hugo.oliveira@utas.edu.au
%
narginchk(1,1)
reason = {};

if ~IMOS.adcp.contains_adcp_dimensions(sample_data)
reason{1} = 'Not an adcp file.';
end

try
avail_dimensions = IMOS.get(sample_data.dimensions, 'name');
along_height = inCell(avail_dimensions, 'HEIGHT_ABOVE_SENSOR');
along_beams = inCell(avail_dimensions, 'DIST_ALONG_BEAMS');

if ~along_height && ~along_beams
reason{end + 1} = 'Missing adcp bin dimensions';
end

time = IMOS.get_data(sample_data.dimensions, 'TIME');

if isempty(time)
reason{end + 1} = 'No TIME dimension.';
end

if along_height
bin_dist = IMOS.get_data(sample_data.dimensions, 'HEIGHT_ABOVE_SENSOR');
elseif along_beams
bin_dist = IMOS.get_data(sample_data.dimensions, 'DIST_ALONG_BEAMS');
else
bin_dist = [];
end

if isempty(bin_dist)
reason{end + 1} = 'No bin distance dimensions.';
end

catch
reason{end + 1} = 'No dimensions in dataset.';
end

try
idepth = IMOS.get_data(sample_data.variables, 'DEPTH');

if isempty(idepth)
reason{end + 1} = 'no DEPTH variable.';
end

catch
reason{end + 1} = 'No variables in dataset.';
end

bathy = IMOS.meta.site_bathymetry(sample_data);

if isempty(bathy)
reason{end + 1} = 'no bathymetry metadata.';
end

beam_face_config = IMOS.meta.beam_face_config(sample_data);

if ~strcmpi(beam_face_config, 'up') && ~strcmpi(beam_face_config, 'down')
reason{end + 1} = 'unknown ADCP beam face config or inconsistent sensor height values.';
end

if isempty(reason)
bool = true;
else
bool = false;
end

end
49 changes: 49 additions & 0 deletions Util/+IMOS/validate_dataset.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
function [bool, reason] = validate_dataset(sample_data, fname)
% function [bool,reason] = validate_dataset(sample_data,fname)
%
% Validate a toolbox dataset against a function name.
%
% The idea of this function is to execute the associated
% `fname` schema function, which verifies the feasability
% of the sample_data content for use within `fname` function.
%
% Think all the checks you do at a function but wrapped in
% one call.
%
% Inputs:
%
% sample_data [struct] - a toolbox sample data.
% fname [string] = the function name.
%
% Outputs:
%
% bool[logical] - True if dataset is accepted by fname.
% reason [cell{str}] - The reasons why the dataset is invalid for fname.
%
% Example:
%
% %basic usage
%
%
% author: hugo.oliveira@utas.edu.au
%
func = ['IMOS.schemas.' fname];
try
feval(func)
missing_schema = true;
catch me
missing_schema = ~strcmpi(me.message,'Not enough input arguments.');
end

if missing_schema
errormsg('Schema %s not available',fname);
end

try
[bool, reason] = feval(func, sample_data);
catch
bool = false;
reason{1} = sprintf('%s failed.', func);
end

end

0 comments on commit 97d1146

Please sign in to comment.