From 30b9d4bb83f50cadde8ac2edbc945dab682bfe83 Mon Sep 17 00:00:00 2001
From: Michael Innerberger <michael.innerberger@asc.tuwien.ac.at>
Date: Mon, 7 Aug 2023 16:38:15 -0400
Subject: [PATCH] Make meta data a dictionary -> require 2022b!

---
 README.md                                     |  2 +-
 lib/storage/@LevelData/LevelData.m            | 48 ++++++----------
 lib/storage/@LevelData/plotToFile.m           |  2 +-
 lib/storage/@LevelData/saveToFile.m           |  5 +-
 lib/storage/@LevelData/saveToTable.m          |  2 +-
 .../LevelDataCollection.m                     | 55 +++++++------------
 lib/storage/@LevelDataCollection/saveToFile.m |  2 +-
 .../@LevelDataCollection/saveToTable.m        |  4 +-
 lib/storage/TimeIt.m                          |  6 +-
 9 files changed, 50 insertions(+), 76 deletions(-)

diff --git a/README.md b/README.md
index f7c00b0..0e8f478 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ Advantages:
 
 To get started, run `setup.m` in the root folder. This adds everything to the
 path and compiles .mex files if necessary.
-Note that, at least, Matlab version R2022a is required.
+Note that, at least, Matlab version R2022b is required.
 
 ## First steps
 
diff --git a/lib/storage/@LevelData/LevelData.m b/lib/storage/@LevelData/LevelData.m
index 8275605..7018f7f 100644
--- a/lib/storage/@LevelData/LevelData.m
+++ b/lib/storage/@LevelData/LevelData.m
@@ -18,14 +18,7 @@ classdef LevelData < handle
 %
 
     properties
-        % Name of problem
-        problem = 'problem'
-        % Name of domain
-        domain = 'domain'
-        % Name of method
-        method = 'method'
-        % Identifier for computation
-        identifier = 'main'
+        metaData
         % Root folder for file storage
         root = 'results'
         % Structure array storing string representations of variables
@@ -94,35 +87,30 @@ classdef LevelData < handle
             if nargin >= 1
                 obj.root = rootpath;
             end
-            ensureFolderExists(obj.root);
-            % Set hostname
-            obj.hostname = getHostname();
+
+            % TODO: set output of hostname to string and remove cast
+            obj.metaData = dictionary(...
+                "problem", "problem", ...
+                "domain", "domain", ...
+                "method", "method", ...
+                "identifier", "main", ...
+                "hostname", string(getHostname()));
+
             % Save time of creation
             if isOctave()
-                obj.timestamp = datestr(now, 'yyyy-MM-dd_HH:mm:ss'); %#ok<TNOW1,DATST>
+                obj.metaData("timestamp") = datestr(now, 'yyyy-MM-dd_HH:mm:ss'); %#ok<TNOW1,DATST>
             else
-                obj.timestamp = char(datetime('now', 'Format', 'yyyy-MM-dd_HH:mm:ss'));
+                obj.metaData("timestamp") = char(datetime('now', 'Format', 'yyyy-MM-dd_HH:mm:ss'));
             end
+
+            ensureFolderExists(obj.root);
+            % Set hostname
+            obj.hostname = getHostname();
             % Initialise dictionary with some default values
             obj.dictionary = getDefaultDictionary();
         end
 
         %% SET GLOBAL VARIABLES
-        function set.problem(obj, name)
-            assert(ischar(name), 'Insert character array as problem name.');
-            obj.problem = name;
-        end
-
-        function set.domain(obj, name)
-            assert(ischar(name), 'Insert character array as domain name.');
-            obj.domain = name;
-        end
-
-        function set.method(obj, name)
-            assert(ischar(name), 'Insert character array as method name.');
-            obj.method = name;
-        end
-
         function set.root(obj, path)
             assert(ischar(path), 'Insert character array as path name.');
             obj.root = path;
@@ -152,12 +140,12 @@ classdef LevelData < handle
             if numel(rootpath) > 0 && ~strcmp(rootpath(end), '/')
                 rootpath = [rootpath, '/'];
             end
-            path = [rootpath, obj.problem, '_', obj.domain, '_', obj.method];
+            path = rootpath + strjoin([obj.metaData("problem"), obj.metaData("domain"), obj.metaData("method")], '_');
         end
 
         function file = get.filename(obj)
             % Name of file for file storage
-            file = [obj.identifier];
+            file = [obj.metaData("identifier")];
         end
 
         function bool = get.isScalar(obj)
diff --git a/lib/storage/@LevelData/plotToFile.m b/lib/storage/@LevelData/plotToFile.m
index 2efe1f1..23ffcee 100644
--- a/lib/storage/@LevelData/plotToFile.m
+++ b/lib/storage/@LevelData/plotToFile.m
@@ -37,7 +37,7 @@ function plotToFile(obj, xVariable, varargin)
     end
 
     % Export plot
-    print(h, '-dpng', '-r600', [obj.foldername, '/', obj.filename, '.png']);
+    print(h, '-dpng', '-r600', obj.foldername + '/' + obj.filename + '.png');
 
     % Close figure
     close(h);
diff --git a/lib/storage/@LevelData/saveToFile.m b/lib/storage/@LevelData/saveToFile.m
index b6af1ce..b46a2b8 100644
--- a/lib/storage/@LevelData/saveToFile.m
+++ b/lib/storage/@LevelData/saveToFile.m
@@ -32,9 +32,10 @@ function saveToFile(obj, folder, file)
     % Create problem- and method-specific folder
     ensureFolderExists(folder);
     % Save this object to file
+    pathToMat = folder + '/' + file + '.mat';
     if isOctave()
-        save([folder, '/', file, '.mat'], 'obj', '-v7');
+        save(pathToMat, 'obj', '-v7');
     else
-        save([folder, '/', file, '.mat'], 'obj', '-v7.3');
+        save(pathToMat, 'obj', '-v7.3');
     end
 end
diff --git a/lib/storage/@LevelData/saveToTable.m b/lib/storage/@LevelData/saveToTable.m
index 9ee04bf..8ac9fc8 100644
--- a/lib/storage/@LevelData/saveToTable.m
+++ b/lib/storage/@LevelData/saveToTable.m
@@ -33,7 +33,7 @@ function saveToTable(obj, separator)
     ensureFolderExists(obj.foldername);
 
     % Open file
-    fid = fopen([obj.foldername, '/', obj.filename, '.csv'], 'w');
+    fid = fopen(obj.foldername + '/' + obj.filename + '.csv', 'w');
 
     % Save header to file
     fprintf(fid, obj.headerSpecifier, obj.scalarVariable{:});
diff --git a/lib/storage/@LevelDataCollection/LevelDataCollection.m b/lib/storage/@LevelDataCollection/LevelDataCollection.m
index 69c5efe..90fd021 100644
--- a/lib/storage/@LevelDataCollection/LevelDataCollection.m
+++ b/lib/storage/@LevelDataCollection/LevelDataCollection.m
@@ -19,8 +19,7 @@ classdef LevelDataCollection < handle
 
 
     properties
-        % Identifier for computation
-        identifier = ''
+        metaData
         % Root folder for file storage
         root = 'results'
         % Cell array of LevelData objects
@@ -28,12 +27,6 @@ classdef LevelDataCollection < handle
     end
 
     properties (Dependent)
-        % Name of problem
-        problem (1,:) char
-        % Name of domain
-        domain (1,:) char
-        % Name of method
-        method (1,:) char
         % Path to folder for file storage
         foldername (1,:) char
         % Name of file for storage
@@ -73,9 +66,25 @@ classdef LevelDataCollection < handle
             end
             ensureFolderExists(obj.root);
 
+            % TODO: set output of hostname to string and remove cast
+            % TODO: does it make sense to store this here? -> see e.g. get.problem before
+            obj.metaData = dictionary(...
+                "problem", "problem", ...
+                "domain", "domain", ...
+                "method", "method", ...
+                "identifier", "main", ...
+                "hostname", string(getHostname()));
+
+            % Save time of creation
+            if isOctave()
+                obj.metaData("timestamp") = datestr(now, 'yyyy-MM-dd_HH:mm:ss'); %#ok<TNOW1,DATST>
+            else
+                obj.metaData("timestamp") = char(datetime('now', 'Format', 'yyyy-MM-dd_HH:mm:ss'));
+            end
+
             % Set identifier
             if nargin >= 2
-                obj.identifier = identifier;
+                obj.metaData("identifier") = identifier;
             end
         end
 
@@ -100,40 +109,16 @@ classdef LevelDataCollection < handle
             bool = (obj.nItem <= 1);
         end
 
-        function name = get.problem(obj)
-            if isempty(obj.item)
-                name = '';
-            else
-                name = [obj.item{1}.problem];
-            end
-        end
-
-        function name = get.domain(obj)
-            if isempty(obj.item)
-                name = '';
-            else
-                name = [obj.item{1}.domain];
-            end
-        end
-
-        function name = get.method(obj)
-            if isempty(obj.item)
-                name = '';
-            else
-                name = [obj.item{1}.method];
-            end
-        end
-
         function path = get.foldername(obj)
             rootpath = obj.root;
             if numel(rootpath) > 0 && ~strcmp(rootpath(end), '/')
                 rootpath = [rootpath, '/'];
             end
-            path = [rootpath, obj.problem, '_', obj.domain, '_', obj.method];
+            path = rootpath + strjoin([obj.metaData("problem"), obj.metaData("domain"), obj.metaData("method")], '_');
         end
 
         function file = get.filename(obj)
-            file = [obj.identifier, '_collection'];
+            file = obj.metaData("identifier") + '_collection';
         end
 
         function spec = get.headerSpecifier(obj)
diff --git a/lib/storage/@LevelDataCollection/saveToFile.m b/lib/storage/@LevelDataCollection/saveToFile.m
index 81d502c..b43d1e7 100644
--- a/lib/storage/@LevelDataCollection/saveToFile.m
+++ b/lib/storage/@LevelDataCollection/saveToFile.m
@@ -38,6 +38,6 @@ function saveToFile(obj, folder, file)
         warning(['LevelData not stored. Octave cannot save classdef objects. ', ...
                  'See GNU Octave Bug: #45833']);
     else
-        save([folder, '/', file, '.mat'], 'obj', '-v7.3');
+        save(folder + '/' + file + '.mat', 'obj', '-v7.3');
     end
 end
diff --git a/lib/storage/@LevelDataCollection/saveToTable.m b/lib/storage/@LevelDataCollection/saveToTable.m
index 1fe0f07..6f748df 100644
--- a/lib/storage/@LevelDataCollection/saveToTable.m
+++ b/lib/storage/@LevelDataCollection/saveToTable.m
@@ -35,8 +35,8 @@ function saveToTable(obj, separator)
     % Save data for each variable to a separate file
     data = obj.get(':', obj.timeVariable{:});
     for j = 1:obj.nTimeVariable
-        fid = fopen([obj.foldername, '/', obj.filename, '_', ...
-                     obj.timeVariable{j},'.csv'], 'w');
+        fid = fopen(obj.foldername + '/' + obj.filename + '_' + ...
+                     obj.timeVariable{j} + '.csv', 'w');
         obj.printTable(fid, obj.timeVariable{j}, data{j});
         fclose(fid);
     end
diff --git a/lib/storage/TimeIt.m b/lib/storage/TimeIt.m
index d84698b..c8b5334 100644
--- a/lib/storage/TimeIt.m
+++ b/lib/storage/TimeIt.m
@@ -25,13 +25,13 @@ function leveldatacollection = TimeIt(identifier, nRun, functionName, varargin)
     end
 
     % Welcome statement
-    fprintf('\n#\n# OCTAFEM - TIME MEASUREMENT\n');
+    fprintf('\n#\n# MooAFEM - TIME MEASUREMENT\n');
     fprintf('# Current Time: %s\n#\n\n', datestr(now));
     fprintf('This is TimeIt wrapper for function "%s"\n\n', functionName);
 
     % Initialisation of collection for LevelData objects
     leveldatacollection = LevelDataCollection();
-    leveldatacollection.identifier = identifier;
+    leveldatacollection.metaData("identifier") = identifier;
 
     % Run experiments
     for j = 1:nRun
@@ -39,7 +39,7 @@ function leveldatacollection = TimeIt(identifier, nRun, functionName, varargin)
         temporaryIdentifier = sprintf('timingRun%04d', j);
         outputList = fevalc(functionName, varargin{:});
         leveldata = outputList{1};
-        leveldata.identifier = temporaryIdentifier;
+        leveldata.metaData("identifier") = temporaryIdentifier;
         % Remove unused information
         leveldata.removeNonscalar();
         % Store information
-- 
GitLab