Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions API/controlsClass.m
Original file line number Diff line number Diff line change
Expand Up @@ -440,11 +440,8 @@
fwrite(fileID, true, 'uchar');
fclose(fileID);
end
end

%------------------------- Display Methods --------------------------
methods (Access = protected)
function groups = getPropertyGroups(obj)

function dispPropList = getAvailableFields(obj)
masterPropList = struct('parallel', {obj.parallel},...
'procedure', {obj.procedure},...
'display', {obj.display},...
Expand Down Expand Up @@ -499,20 +496,29 @@
'boundHandling',...
'adaptPCR'};


dispPropList = masterPropList;
if strcmpi(obj.procedure, 'calculate')
dispPropList = rmfield(masterPropList, [deCell, simplexCell, nsCell, dreamCell, {'updatePlotFreq','updateFreq'}]);
elseif strcmpi(obj.procedure, 'simplex')
dispPropList = rmfield(masterPropList, [deCell, nsCell, dreamCell]);
elseif strcmpi(obj.procedure, 'de')
dispPropList = rmfield(masterPropList, [simplexCell, nsCell, dreamCell]);
% Add the update back...
elseif strcmpi(obj.procedure, 'ns')
dispPropList = rmfield(masterPropList, [simplexCell, deCell, dreamCell, {'updatePlotFreq','updateFreq'}]);
elseif strcmpi(obj.procedure, 'dream')
dispPropList = rmfield(masterPropList, [simplexCell, deCell, nsCell, {'updatePlotFreq','updateFreq'}]);
end
end
end

%------------------------- Display Methods --------------------------
methods (Access = protected)
function groups = getPropertyGroups(obj)

if isscalar(obj)
dispPropList = masterPropList;
if strcmpi(obj.procedure, 'calculate')
dispPropList = rmfield(masterPropList, [deCell, simplexCell, nsCell, dreamCell, {'updatePlotFreq','updateFreq'}]);
elseif strcmpi(obj.procedure, 'simplex')
dispPropList = rmfield(masterPropList, [deCell, nsCell, dreamCell]);
elseif strcmpi(obj.procedure, 'de')
dispPropList = rmfield(masterPropList, [simplexCell, nsCell, dreamCell]);
% Add the update back...
elseif strcmpi(obj.procedure, 'ns')
dispPropList = rmfield(masterPropList, [simplexCell, deCell, dreamCell, {'updatePlotFreq','updateFreq'}]);
elseif strcmpi(obj.procedure, 'dream')
dispPropList = rmfield(masterPropList, [simplexCell, deCell, nsCell, {'updatePlotFreq','updateFreq'}]);
end
dispPropList = obj.getAvailableFields();
groups = matlab.mixin.util.PropertyGroup(dispPropList);
else
groups = getPropertyGroups@matlab.mixin.CustomDisplay(obj);
Expand Down
67 changes: 60 additions & 7 deletions tests/testJsonToProject/testJsonToProject.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@

resultFile = {'result', ...
'result_bayes'}

controlsParams = {{'calculate', 'numSimulationPoints', 100},...
{'simplex' 'xTolerance', 19},...
{'de' 'populationSize', 200},...
{'ns' 'nLive', 19},...
{'dream' 'nSamples', 200}}
r2Tests = {{'normalReflectivity', 'standardLayers', 'standardLayersDSPCScript'},...
{'domains', 'customLayers', 'domainsCustomLayersScript'},...
{'domains', 'customXY', 'domainsCustomXYScript'}}
end

methods(TestClassSetup)
function addDataPath(testCase)
import matlab.unittest.fixtures.PathFixture
path = fullfile(getappdata(0, 'root'), 'tests', 'testJsonToProject');
testCase.applyFixture(PathFixture(path))
testCase.applyFixture(PathFixture(path));
end
function setWorkingFolder(testCase)
import matlab.unittest.fixtures.WorkingFolderFixture;
Expand Down Expand Up @@ -54,13 +63,9 @@ function testJsonResultConversion(testCase, resultFile)
end
end

function testJsonControlsConversion(testCase)
function testJsonControlsConversion(testCase, controlsParams)
controls = controlsClass();
controls.numSimulationPoints = 100;
controls.xTolerance = 19;
controls.populationSize = 200;
controls.nLive = 140;
controls.nSamples = 200;
controls.setProcedure(controlsParams{1}, controlsParams{2:end});

controlsToJson(controls, "test.json");
controls2 = jsonToControls("test.json");
Expand All @@ -69,6 +74,54 @@ function testJsonControlsConversion(testCase)
for i = 1:length(props)
testCase.verifyEqual(controls.(props{i}), controls2.(props{i}));
end
end

function testR2Conversion(testCase, r2Tests)
scriptName = r2Tests{3};
outFolder = ['save_' scriptName];

copyfile(fullfile(getappdata(0, 'root'), 'examples', r2Tests{1}, r2Tests{2}), ...
fullfile(pwd))
evalc(scriptName);

controls = controlsClass();
[~, project, result] = evalc('RAT(problem, controls);');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion:
I can vageuly understand and accept why one would use evalc in 85, though IMHO function handle would be much better. But in 88! Why?
Why to use:

[~, project, result] =  evalc('RAT(problem, controls);');

instead of just:

 [project, result] =  RAT(problem, controls);

It works faster and much more clear code.


saveR2(outFolder, project, result, controls)
testCase.verifyEqual(exist(fullfile(pwd, outFolder, 'results.json'), 'file'), 2)
testCase.verifyEqual(exist(fullfile(pwd, outFolder, 'project.json'), 'file'), 2)
testCase.verifyEqual(exist(fullfile(pwd, outFolder, 'controls.json'), 'file'), 2)
for i=1:project.customFile.rowCount
customFile = project.customFile.varTable{i, 2};
testCase.verifyEqual(exist(fullfile(pwd, outFolder, customFile), 'file'), 2)
end

[project2, result2] = loadR2(outFolder);
props = properties(project);
for i = 1:length(props)
% verifies the problem name, model type and geometry
Comment on lines +101 to +102
Copy link
Collaborator

@abuts abuts Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request if I understand it correctly:
I am puzzled. Why this loop? Nothing inside it depends on i or props -- you just run the same check 16 times. Should loop be removed?

All prop check is correctly perfromed at rows 120-124.

Test between for and end partially repeats 120-124 but ok, this way of testing may be more beneficial or clear, but why to run it in a loop?

testCase.verifyEqual(project.experimentName, project2.experimentName);
testCase.verifyEqual(project.modelType, project2.modelType);
testCase.verifyEqual(project.geometry, project2.geometry);

% verifies the count of problem properties
testCase.verifyEqual(project.contrasts.numberOfContrasts, project2.contrasts.numberOfContrasts);
testCase.verifyEqual(project.parameters.rowCount, project2.parameters.rowCount);
testCase.verifyEqual(project.bulkOut.rowCount, project2.bulkOut.rowCount);
testCase.verifyEqual(project.background.backgrounds.rowCount, project2.background.backgrounds.rowCount);
testCase.verifyEqual(project.data.rowCount, project2.data.rowCount);
testCase.verifyEqual(project.scalefactors.rowCount, project2.scalefactors.rowCount);
if isa(project.layers, 'layersClass')
testCase.verifyEqual(project.layers.rowCount, project2.layers.rowCount);
end
testCase.verifyEqual(project.bulkIn.rowCount, project2.bulkIn.rowCount);
end

props = properties(result);
for i = 1:length(props)
testCase.verifyEqual(result.(props{i}), result2.(props{i}));
end
close all
end
end

Expand Down
2 changes: 1 addition & 1 deletion utilities/misc/controlsToJson.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
function controlsToJson(controls,filename)

% Saves the current controls block as a json..
encoded = jsonencode(controls,ConvertInfAndNaN=false);
encoded = jsonencode(controls.getAvailableFields(),ConvertInfAndNaN=false);

[path,filename,~] = fileparts(filename);
fid = fullfile(path, append(filename, '.json'));
Expand Down
65 changes: 38 additions & 27 deletions utilities/misc/jsonToResults.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,37 +53,48 @@

% Check we don't already have cells..
if iscell(inArray)
nArrays = numel(inArray);
if nArrays == nContrasts % (not domains)
outCell = inArray;
else % ..domains - [n x 2] cell array
outCell = reshape(inArray,nContrasts,2);
row = size(inArray, 1);
col = size(inArray(1),1);
outCell = cell(row, col);
for i=1:row
for j=1:col
outCell{i, j} = squeeze(inArray{i}{j});
end
end
else

% Get number of profiles...
nProfiles = size(inArray,1);

% Make them into cells....
for i = 1:nProfiles
thisSLD = inArray(i,:,:,:);
thisSLD = squeeze(thisSLD); % Collapse singleton dims....
outCell{i,1} = thisSLD;
end

% If domains, reorganise the cells...
if nProfiles > nContrasts
outCell = transpose(reshape(outCell,nContrasts,2));
end
end

% We have an annoying automatic reshape of single layers into columns.
% Fix this...
for i = 1:numel(outCell)
if iscolumn(outCell{i})
outCell{i} = transpose(outCell{i});
row = size(inArray, 1);
col = size(inArray(1),1);
outCell = cell(row, col);
for i=1:row
for j=1:col
outCell{i, j} = squeeze(inArray(i, j, :, :));
end
end
end
%
% % Get number of profiles...
% nProfiles = size(inArray,1);
%
% % Make them into cells....
% for i = 1:nProfiles
% thisSLD = inArray(i,:,:,:);
% thisSLD = squeeze(thisSLD); % Collapse singleton dims....
% outCell{i,1} = thisSLD;
% end
%
% % If domains, reorganise the cells...
% if nProfiles > nContrasts
% outCell = transpose(reshape(outCell,nContrasts,2));
% end
% end
%
% % We have an annoying automatic reshape of single layers into columns.
% % Fix this...
% for i = 1:numel(outCell)
% if iscolumn(outCell{i})
% outCell{i} = transpose(outCell{i});
% end
% end

end

Expand Down
40 changes: 40 additions & 0 deletions utilities/misc/loadR2.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

function [problem,varargout] = loadR2(dirName)
% Loads in a RasCAL2 project.
%
% Examples
% --------
% >>> project = loadR2("r2_example"); % Load project from a given directory
% >>> [project, results] = loadR2("r2_example"); % Load project and result
%
% Parameters
% ----------
% dirName : string or char array
% The path of the R2 project folder.
%
% Returns
% -------
% project : projectClass
% An instance of the ``projectClass`` which should be equivalent to the given R2 problem.
% results : struct
% An optional output. A struct which contains the R2 results if present.

arguments
dirName {mustBeTextScalar, mustBeNonempty}
end
% Load the project.
projectFile = fullfile(dirName,'project.json');
problem = jsonToProject(projectFile);

% If there is a second output, also load results.
if nargout > 1
resultsFile = fullfile(dirName, 'results.json');
if exist(resultsFile, 'file') == 2
varargout{1} = jsonToResults(resultsFile);
else
varargout{1} = struct();
warning("result.json was not found in the project.");
end
end

end
53 changes: 52 additions & 1 deletion utilities/misc/resultsToJson.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,64 @@
function resultsToJson(results,filename)

% Encodes the results into a json file...
tmpResults = struct();
for fn = fieldnames(results)'
tmpResults.(fn{1}) = results.(fn{1});
end

tmpResults.reflectivity = correctCellArray(tmpResults.reflectivity);
tmpResults.simulation = correctCellArray(tmpResults.simulation);
tmpResults.shiftedData = correctCellArray(tmpResults.shiftedData);
tmpResults.backgrounds = correctCellArray(tmpResults.backgrounds);
tmpResults.resolutions = correctCellArray(tmpResults.resolutions );
tmpResults.sldProfiles = makeCellJson(tmpResults.sldProfiles);
tmpResults.layers = makeCellJson(tmpResults.layers);
tmpResults.resampledLayers = makeCellJson(tmpResults.resampledLayers);

encoded = jsonencode(tmpResults,ConvertInfAndNaN=false);
encoded = strrep(encoded, '"[', '[');
encoded = strrep(encoded, ']"', ']');

encoded = jsonencode(results,ConvertInfAndNaN=false);

[path,filename,~] = fileparts(filename);
fid = fullfile(path, append(filename, '.json'));
fid = fopen(fid,'w');
fprintf(fid,'%s',encoded);
fclose(fid);

end

function outputArray = makeCellJson(cellArray)
% The jsonencode function flattens 2d cell arrays this is a workaround to
% avoid flattening by converting to a string array with is not flattened.
[row, col] = size(cellArray, [1, 2]);
outputArray = strings([row, col]);
for i=1:row
for j=1:col
entry = cellArray{i, j};
if size(entry, 1) == 1
entry = {entry};
end
if col == 1
entry = {entry};
end
outputArray(i, j) = jsonencode(entry);
end
end
if row == 1
outputArray = {outputArray};
end

end

function cellArray = correctCellArray(cellArray)
% Corrects array with single row so its written as 2D array in json
[row, col] = size(cellArray, [1, 2]);
for i=1:row
for j=1:col
if size(cellArray{i, j}, 1) == 1
cellArray{i, j} = {cellArray{i, j}};
end
end
end
end
Loading