From 756f17e425a0f8efe9bdbecac86818e4c483692e Mon Sep 17 00:00:00 2001
From: galperti <cristian.galperti@epfl.ch>
Date: Thu, 16 Jun 2022 13:40:16 +0200
Subject: [PATCH] addtunparamstruct method with permissivity switch

---
 algos/template/algoobj_template.m |  2 +-
 classes/SCDclass_algo.m           | 51 +++++++++++++++++++++++++++----
 classes/SCDclass_mdspar.m         | 10 +++++-
 classes/SCDclass_mdsparnumeric.m  | 27 +++++++++++++---
 4 files changed, 78 insertions(+), 12 deletions(-)

diff --git a/algos/template/algoobj_template.m b/algos/template/algoobj_template.m
index 90a1ea8..558f4c4 100644
--- a/algos/template/algoobj_template.m
+++ b/algos/template/algoobj_template.m
@@ -10,7 +10,7 @@ obj=obj.settiming(-1,1e-3,1.0);
 obj=obj.addfpinitfcn('algo_template_loadfp','algo_template_fp');
 
 %% Tunable parameters structure name
-obj=obj.addtunparamstruct('algo_template_tp', @()algo_template_loadtp());
+obj=obj.addtunparamstruct('algo_template_tp', @()algo_template_loadtp(), false);
 
 %% Tunable parameters
 obj=obj.addparameter(SCDclass_mdsparnumeric('ks1','gain'            ,'srcsrv','spcpc171.epfl.ch','srctree','martetest')); 
diff --git a/classes/SCDclass_algo.m b/classes/SCDclass_algo.m
index a0cced4..30173d4 100644
--- a/classes/SCDclass_algo.m
+++ b/classes/SCDclass_algo.m
@@ -21,7 +21,9 @@ classdef SCDclass_algo
        fpinits             % inits scripts for fixed parameters
        timing              % Timing info structure
        exportedtpsdefaults % default tunable parameters defining functions
+       exportedtpspermiss  % tunable parameters loading error permissivity rule
        buslist             % list of buses and their sources
+       defaulttunparampermissivity % default tunparams loading permissivity
     end
     
     properties 
@@ -42,6 +44,7 @@ classdef SCDclass_algo
             obj.taskcontainer = SCDclass_taskcontainer;
             obj.exportedtps = {};
             obj.exportedtpsdefaults = {};
+            obj.exportedtpspermiss = {};
             obj.stdinits  = {};
             obj.fpinits   = {};
             obj.datadictionary = '';           
@@ -50,6 +53,7 @@ classdef SCDclass_algo
             obj.timing.t_stop  = 1   ;
             obj.timing.dt      = 1e-3;
             obj.buslist = [];
+            obj.defaulttunparampermissivity = true;
             
             % Buses
             obj.modelslx =  [obj.modelname,'.slx'];
@@ -366,29 +370,39 @@ classdef SCDclass_algo
             out = obj.exportedtps;
         end
         
-        function obj = addtunparamstruct(obj, structname, default_function)
+        function obj = addtunparamstruct(obj, structname, default_function, load_permissive)
             % obj = addtunparamstruct(structname, varargin)
             %
             % adds a tunable parameter to the algo object
             % inputs:
             %  structname:  name of the tunable param (string)
-            %  varargin{1}: a function handle to get 
+            %  default_function: a function handle to get 
             %   its default value, this function takes no arguments
             %   and must return either a struct or a Simulink.Parameter
-            %
+            %  load_permissive: a boolean value, if true any failing
+            %   loading attemp to this structure (via a loading function)
+            %   will return a warning, otherwise an error. Default: true.
+            % 
             % example: obj=obj.addtunparamstruct('SCDalgo_doublet_tp',
             % @()SCDalgo_doublet_loadtp());
+            % 
             if(~ismember(structname, obj.exportedtps))
                 obj.exportedtps{end+1}=structname;
             else
                 error('SCDclass_algo:addtunparamsstruct','Tunable parameter struct already present, cannot add!');
             end
-            if nargin==3
+            if nargin>=3
                 assert(isa(default_function, 'function_handle'),'SCDclass_algo:addtunparamstruct', 'third argument, if present, must be a function handle');
                 obj.exportedtpsdefaults{end+1} = default_function; % add defaults to list
             else
                 obj.exportedtpsdefaults{end+1} = []; % empty, no default assigned for this tp
             end
+            if nargin==4
+                assert(isa(load_permissive,'logical'),'SCDclass_algo:addtunparamstruct','fourth argument, if present, must be boolean');
+                obj.exportedtpspermiss{end+1} = load_permissive;
+            else
+                obj.exportedtpspermiss{end+1} = true;
+            end
         end
                
         function obj = updatetemplatetp(obj)
@@ -505,13 +519,38 @@ classdef SCDclass_algo
         %% MDS container methods forwarders
         
         function obj = addparameter(obj, params)
-          % assume this parameter is bound to last exported tp on the list
+          % obj = addparameter(obj, params)
+          % 
+          % this method offers the way to add tunable
+          % parameters description to the object.
+          % params must resolve to a SCDDS loader class
+          % object
+          %
+          % assume this parameter is bound to last exported tp on the
+          %
+          % example:
+          % 
+          % obj=obj.addtunparamstruct('algo_template_tp', @()algo_template_loadtp());
+          % obj=obj.addparameter(SCDclass_mdsparnumeric('ks1','gain'               );
+          %
+          % the couples of lines before first add a tunable parameter
+          % structure and the a numeric type loader class.
+          % The final result is that this logical link between
+          % the source param and dest Simulink.Parameter object
+          % will be put in place:
+          %
+          % algo_template_tp.gain <-> ks1
+          
           if ~isempty(obj.exportedtps), tpname = obj.exportedtps{end};
           else, tpname = '';
           end
           
+          if ~isempty(obj.exportedtpspermiss), permiss = obj.exportedtpspermiss{end};
+          else, permiss = obj.defaulttunparampermissivity;
+          end
+          
           % bind parameter(s) to algoobj's name, dictionary and exportedtp
-          params = params.bind(obj.modelname, obj.datadictionary, tpname);
+          params = params.bind(obj.modelname, obj.datadictionary, tpname, permiss);
           
           % add params to mdscontainer
           obj.mdscontainer=obj.mdscontainer.addparameter(params);
diff --git a/classes/SCDclass_mdspar.m b/classes/SCDclass_mdspar.m
index a15f8ea..6f32b58 100644
--- a/classes/SCDclass_mdspar.m
+++ b/classes/SCDclass_mdspar.m
@@ -40,6 +40,8 @@ classdef SCDclass_mdspar < matlab.mixin.Heterogeneous
         
         mdshelpstr          % MDS help string used in tree autopopulation
         mdsvalidationstr    % MDS validation string used in autopopulation
+    
+        loadpermissivity    % true if load error shoudn't cause an error (warning only)
     end
     
     properties 
@@ -254,6 +256,11 @@ classdef SCDclass_mdspar < matlab.mixin.Heterogeneous
           assert(nargout==1,'must set out argument for set method')
           obj.datadictionary = ddname;
         end
+        
+        function obj = setloadpermissivity(obj, permissivity)
+            assert(nargout==1,'must set out argument for set method')
+            obj.loadpermissivity = permissivity;
+        end
     end
     
     methods(Sealed) % works for heterogeneous class arrays
@@ -270,11 +277,12 @@ classdef SCDclass_mdspar < matlab.mixin.Heterogeneous
           out = strrep(obj.modelparam, obj.matlabseparator, obj.marteseparator);         
         end
              
-        function obj = bind(obj,modelname,datadictionary,exportedtp)
+        function obj = bind(obj,modelname,datadictionary,exportedtp,load_permissivity)
           for ii=1:numel(obj)
             obj(ii) = obj(ii).setmodelname(modelname);
             obj(ii) = obj(ii).setdatadictionary(datadictionary);
             obj(ii) = obj(ii).setparamstructure(exportedtp);
+            obj(ii) = obj(ii).setloadpermissivity(load_permissivity);
           end
         end
     end
diff --git a/classes/SCDclass_mdsparnumeric.m b/classes/SCDclass_mdsparnumeric.m
index 7983cf3..e62f145 100644
--- a/classes/SCDclass_mdsparnumeric.m
+++ b/classes/SCDclass_mdsparnumeric.m
@@ -18,7 +18,14 @@ classdef SCDclass_mdsparnumeric < SCDclass_mdspar
 
         function actualizedata(obj, shot) 
               obj=obj.preactualize(shot);
-              if ~obj.actualizable, return; end
+              if ~obj.actualizable
+                  if obj.loadpermissivity
+                      warning('SCDDScore:mdsparnumeric','%s: parameters not actualizable (preactualize fails), actualization skipped!',obj.modelparam);
+                  else
+                      error('SCDDScore:mdsparnumeric','%s: parameters not actualizable (preactualize fails), actualization skipped!',obj.modelparam);
+                  end
+                  return;
+              end
      
               %%% Actualization checks %%%
               % dimensions
@@ -27,7 +34,11 @@ classdef SCDclass_mdsparnumeric < SCDclass_mdspar
 
               actchk=true;
               if numel(sourcedim)~=numel(targetdim)
-                  warning('SCDDScore:mdsparnumeric','%s: number of dimensions not matching, actualization skipped!',obj.modelparam); 
+                  if obj.loadpermissivity
+                    warning('SCDDScore:mdsparnumeric','%s: number of dimensions not matching, actualization skipped!',obj.modelparam); 
+                  else
+                    error('SCDDScore:mdsparnumeric','%s: number of dimensions not matching, actualization skipped!',obj.modelparam); 
+                  end
                   sourcedim
                   targetdim
                   actchk=false;
@@ -44,7 +55,11 @@ classdef SCDclass_mdsparnumeric < SCDclass_mdspar
                  end
               end
               if actchk && ~any(sourcedim == targetdim)
-                  warning('SCDDScore:mdsparnumeric','%s: dimensions not matching, actualization skipped!',obj.modelparam); 
+                  if obj.loadpermissivity
+                    warning('SCDDScore:mdsparnumeric','%s: dimensions not matching, actualization skipped!',obj.modelparam); 
+                  else
+                    error('SCDDScore:mdsparnumeric','%s: dimensions not matching, actualization skipped!',obj.modelparam); 
+                  end
                   sourcedim
                   targetdim
                   actchk=false;
@@ -54,7 +69,11 @@ classdef SCDclass_mdsparnumeric < SCDclass_mdspar
               sourceclass=class(obj.value);
               targetclass=Simulink.data.evalinGlobal(obj.modelname,sprintf('class(%s)',obj.assignvar));
               if actchk && ~strcmp(sourceclass,targetclass)
-                  warning('SCDDScore:mdsparnumeric','%s: Data types not matching, actualization skipped!',obj.modelparam); 
+                  if obj.loadpermissivity
+                    warning('SCDDScore:mdsparnumeric','%s: Data types not matching, actualization skipped!',obj.modelparam); 
+                  else
+                    error('SCDDScore:mdsparnumeric','%s: Data types not matching, actualization skipped!',obj.modelparam); 
+                  end
                   sourceclass
                   targetclass
                   actchk=false;
-- 
GitLab