Skip to content

Commit

Permalink
BICAS: Add bicas.tools.batch package (on devel)
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikPGJ committed Feb 26, 2024
1 parent 833863c commit eca22ab
Show file tree
Hide file tree
Showing 30 changed files with 3,519 additions and 0 deletions.
26 changes: 26 additions & 0 deletions irf/+irf/+fs/create_empty_file.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
%
% Create empty file. This is useful for debugging purposes sometimes, e.g.
% if batch code selects the correct files to be created.
%
%
% ARGUMENTS
% =========
% path
% Path to file.
% NOTE: Parent directory has to pre-exist.
%
%
% Author: Erik P G Johansson, IRF, Uppsala, Sweden
%
function create_empty_file(path)
% PROPOSAL: Error if fails to create file.
% PROPOSAL: Policy arguments
% (1) Whether to permit path not available:
% Permit overwrite
% Assert no overwrite
% (2) What happens when createing, writing file:
% Assert write success (does not assert no overwrite)
% Permit write failure (does not assert no overwrite), return ~error code/boolean

fclose(fopen(path, 'w'));
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
%
% Convert a BPCI into a sequence of arguments that can be used for calling
% BICAS.
%
%
% Initially created 2020-03-02 by Erik P G Johansson, IRF, Uppsala, Sweden.
%
function argsCa = BPCI_to_BICAS_call_args(Bpci)
% PROPOSAL: Refactor into BPCI method.
% PROPOSAL: No hardcoded CLI_OPTION_PREFIX
% PROPOSAL: CLI_OPTION_PREFIX as argument.
% PROPOSAL: CLI_OPTION_PREFIX using BICAS constant.

CLI_OPTION_PREFIX = '--';

assert(isa(Bpci, 'bicas.tools.batch.BicasProcessingCallInfo'))

argsCa = {Bpci.swmCliOption};

for i = 1:numel(Bpci.inputsArray)
In = Bpci.inputsArray(i);
argsCa{end+1} = [CLI_OPTION_PREFIX, In.cohb];
argsCa{end+1} = In.path;
end

for i = 1:numel(Bpci.outputsArray)
Out = Bpci.outputsArray(i);
argsCa{end+1} = [CLI_OPTION_PREFIX, Out.cohb];
argsCa{end+1} = Out.path;
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
%
% Abstract class for handling the communication with BICAS for the purpose of
% processing data.
%
%
% Author: Erik P G Johansson, IRF, Uppsala, Sweden
%
classdef(Abstract) BicasProcessingAccessAbstract < handle



%#########################
%#########################
% PUBLIC INSTANCE METHODS
%#########################
%#########################
methods(Abstract)



% Call bicas.main() with the exact same arguments and return value(s).
[varargout] = bicas_main(obj, varargin);



end % methods(Access=public)



end
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
%
% Implementation of abstract class for nominal use.
%
%
% Author: Erik P G Johansson, IRF, Uppsala, Sweden
%
classdef BicasProcessingAccessImpl < bicas.tools.batch.BicasProcessingAccessAbstract



%#########################
%#########################
% PUBLIC INSTANCE METHODS
%#########################
%#########################
methods(Access=public)



% OVERRIDE
function [varargout] = bicas_main(obj, varargin)
for i = 1:numel(varargin)
assert(ischar(varargin{i}))
end

[varargout{1:nargout}] = bicas.main(varargin{:});
end



end % methods(Access=public)



end
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
%
% Implementation for automatic tests.
%
%
% Author: Erik P G Johansson, IRF, Uppsala, Sweden
%
classdef BicasProcessingAccessTest < bicas.tools.batch.BicasProcessingAccessAbstract
% PROPOSAL: Support returning non-zero error code.
% PROPOSAL: Support raising exception.



%#####################
%#####################
% INSTANCE PROPERTIES
%#####################
%#####################
properties(SetAccess=immutable, GetAccess=private)
SwmArray
callNonZeroErrorArray
end % properties(SetAccess=immutable)
properties(Access=private)
% The number of times method "bicas_main" has been called.
nCalls
end



%#########################
%#########################
% PUBLIC INSTANCE METHODS
%#########################
%#########################
methods(Access=public)



% callNonZeroErrorArray
% Array of numbers. Call numbers for when method bicas_main()
% should return non-zero error code and simulate failure.
% 1=First call.
%
function obj = BicasProcessingAccessTest(SwmArray, callNonZeroErrorArray)
assert(isa(SwmArray, 'bicas.swm.SoftwareMode') & iscolumn(SwmArray))
assert(isnumeric(callNonZeroErrorArray))
assert(iscolumn(callNonZeroErrorArray) || isempty (callNonZeroErrorArray))

obj.SwmArray = SwmArray;
obj.callNonZeroErrorArray = callNonZeroErrorArray;
obj.nCalls = 0;
end



% OVERRIDE
function [varargout] = bicas_main(obj, varargin)

obj.nCalls = obj.nCalls + 1;
iCall = obj.nCalls;
if ismember(iCall, obj.callNonZeroErrorArray)
%=============================
% CASE: Return non-zero error
%=============================

% Do no processing (generate no output files)
% -------------------------------------------
% NOTE: One could imagine simulating an error after or between
% output datasets are generated but that should be overkill.

[varargout{1}] = 1;
else
%=======================================
% CASE: Error code zero. Do processing.
%=======================================

for i = 1:numel(varargin)
assert(ischar(varargin{i}))
end

swmCliOption = varargin{1};

iSwm = find(strcmp(swmCliOption, {obj.SwmArray(:).cliOption}));
assert(isscalar(iSwm), 'Did not find exactly one SWM which matches CLI arg. "%s".', swmCliOption)
Swm = obj.SwmArray(iSwm);



%=========================================
% Input datasets: Assert that files exist
%=========================================
for iInput = 1:numel(Swm.inputsList)
cohb = Swm.inputsList(iInput).cliOptionHeaderBody;
iCoh = find(strcmp(['--', cohb], varargin));
assert(isscalar(iCoh), ...
'Can not identify exactly one BICAS argument with cohb="%s"', cohb)
inputPath = varargin{iCoh+1};

% ASSERTION: Input dataset exists.
irf.assert.file_exists(inputPath)
end

%===============================================
% Output datasets: Create empty output datasets
%===============================================
for iOutput = 1:numel(Swm.outputsList)
cohb = Swm.outputsList(iOutput).cliOptionHeaderBody;
iCoh = find(strcmp(['--', cohb], varargin));
outputFilename = varargin{iCoh+1};

% NOTE: Can not assert that output datasets do not pre-exist,
% since bicas.batch.main permits overwriting files.

% CREATE EMPTY OUTPUT DATASET.
irf.fs.create_empty_file(outputFilename);
end

[varargout{1}] = 0;
end



end



end % methods(Access=public)



end
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
%
% Info required for processing datasets using one single BICAS call, but not the
% argument list as such.
%
%
% Author: Erik P G Johansson, Uppsala, Sweden
% First created 2020-05-27.
%
classdef BicasProcessingCallInfo
% PROPOSAL: Better name. "info" is too generic.
% NOTE: Compare bicas.tools.batch.BicasProcessingCallSummary.
% NOTE: Only includes information on SWM + input + output, but excludes
% custom settings. Excludes --version, --swdescriptor, --config etc.
% PROPOSAL: Only imply specifying datasets (paths) in & out, not
% specifying the entire call.
% --
% BICAS
% Datasets
% Paths
% Input/output (datasets)
% I/O
% Processing (as opposed to non-processing)
% Data, Info, Record
% --
% BicasCallPathsIO, BicasCallDatasetsIO
%
% PROPOSAL: Be able to generate BPCI from SWM for testing purposes.
% See bicas.tools.batch.autocreate_one_SWM_BPCI().
% CON: Still needs to be able to associate COBHs with paths and filenames.



%#####################
%#####################
% INSTANCE PROPERTIES
%#####################
%#####################
properties(SetAccess=immutable)
swmCliOption
inputsArray
outputsArray
end



%#########################
%#########################
% PUBLIC INSTANCE METHODS
%#########################
%#########################
methods(Access=public)



function obj = BicasProcessingCallInfo(swmCliOption, inputsArray, outputsArray)
assert(ischar(swmCliOption))
assert(iscolumn(inputsArray) & isa(inputsArray, 'bicas.tools.batch.BpciInput'))
assert(iscolumn(outputsArray) & isa(outputsArray, 'bicas.tools.batch.BpciOutput'))

obj.swmCliOption = swmCliOption;
obj.inputsArray = inputsArray;
obj.outputsArray = outputsArray;
end



function filenameCa = get_output_filenames(obj)
filenameCa = cellfun(...
@irf.fs.get_name, {obj.outputsArray.path}', ...
'UniformOutput', false);
filenameCa = filenameCa(:);
end



% Create modified copy of object. Prepend all output paths with a
% specified path.
function obj = prepend_output_directory(obj, outputDir)
outputsArray = bicas.tools.batch.BpciOutput.empty(0, 1);
for i = 1:numel(obj.outputsArray)
o = obj.outputsArray(i);
outputsArray(i, 1) = bicas.tools.batch.BpciOutput(...
o.cohb, o.dsi, fullfile(outputDir, o.path));
end

obj = bicas.tools.batch.BicasProcessingCallInfo(...
obj.swmCliOption, obj.inputsArray, outputsArray);
end



end % methods(Access=public)



end
Loading

0 comments on commit eca22ab

Please sign in to comment.