classdef rzp_test < meq_test
  % Test class for rzp
  % Test the workflow of rzip with different input parameters.
  %
  % [+MEQ MatlabEQuilibrium Toolbox+] Swiss Plasma Center EPFL Lausanne 2022. All rights reserved.
  
  properties
    verbosity = 0; % 1 to make verbose output, 2 to make plot

    selu      = 'v';
    selx      = 'X';
    
    tok,shot,t,LXliu,LXfbt;
  end
  
  properties (ClassSetupParameter)
    tok_            = {'ana','tcv'};
    tnum            = {1,10};
    shot_time_index = {1,2,3};
  end
  
  properties (TestParameter)
    cde     = struct('standard', '',    'parametrised', '',    'no_li', '',    'cde_OhmTor', 'OhmTor', 'cde_OhmTorRigid', 'OhmTor_rigid', 'no_lin', '',    'insrc_fbt', ''   );
    agcon_3 = struct('standard', '',    'parametrised', 'li',  'no_li', 'qA',  'cde_OhmTor', 'li',     'cde_OhmTorRigid', 'li',           'no_lin', 'li',  'insrc_fbt', ''   );
    lin     = struct('standard', '',    'parametrised', true,  'no_li', true,  'cde_OhmTor', true,     'cde_OhmTorRigid', true,           'no_lin', false, 'insrc_fbt', ''   );
    insrc   = struct('standard', '',    'parametrised', 'liu', 'no_li', 'liu', 'cde_OhmTor', 'liu',    'cde_OhmTorRigid', 'liu',          'no_lin', 'liu', 'insrc_fbt', 'fbt');
  end
  
  methods
    function LY = rzp_single_output(testCase,varargin)
      L = rzp(testCase.tok,testCase.shot,[],varargin{:});
      switch L.P.insrc
        case 'liu', LXfgs = testCase.LXliu;
        case 'fbt', LXfgs = testCase.LXfbt;
      end
      % Get inputs data for simulation
      LX = rzpx(testCase.tok,testCase.t,L,LXfgs);
      % compute linearization and initial condition
      L = rzpl(L,meqxk(LX,1));

      LY = fget(L,LX);
    end
  end
  
  methods (TestClassSetup)
    function setup_parameters(testCase,tok_,tnum,shot_time_index)
      testCase.tok  = tok_;
      if strcmp(tok_,'ana')  
        shot_list     = [1,2,4]; 
        time_list     = {linspace(0.005,0.015,tnum),linspace(0.005,0.015,tnum),linspace(0.005,0.015,tnum)};
        testCase.shot = shot_list(shot_time_index);
        testCase.t    = time_list{shot_time_index};
      else 
        shot_list     = [61400,69393,63783]; 
        time_list     = {linspace(0.99,1,tnum),linspace(0.99,1,tnum),linspace(0.99,1,tnum)};
        testCase.shot = shot_list(shot_time_index);
        testCase.t    = time_list{shot_time_index};
      end

      [~,testCase.LXliu] = fgs(testCase.tok,testCase.shot,testCase.t,'selu',testCase.selu,'selx',testCase.selx,'insrc','liu');
      [~,testCase.LXfbt] = fgs(testCase.tok,testCase.shot,testCase.t,'selu',testCase.selu,'selx',testCase.selx,'insrc','fbt');
    end
  end
  
  methods (Test, TestTags = {'rzp'}, ParameterCombination='sequential')   
    function code_test_parameter(testCase,cde,agcon_3,lin,insrc)    
      %% Test that rzp is operating
      % Check for cde={'','OhmTor_rigid','OhmTor'}, agcon_3={'li','qA'},
      % lin={true,false}. Check that operates without errors in the case
      % the parameters are coherent, that throws an error otherwise. 
      case_string = sprintf('rzp with %s_%u_%.5g',testCase.tok,testCase.shot,testCase.t(1));
      P_args = {'selu',testCase.selu,'selx',testCase.selx,'debug',testCase.verbosity,'cde',cde};
      P_error = sprintf('%s: %s, ',P_args{1:2}); 
      if ~strcmp(num2str(insrc),''),   P_args=[P_args,{'insrc',insrc}];               P_error=[P_error sprintf('%s: %s, '  ,P_args{end-1:end})];                      end
      if ~strcmp(num2str(lin),''),     P_args=[P_args,{'lin',lin}];                   P_error=[P_error sprintf('%s: %u, '  ,P_args{end-1:end})];                      end
      if ~strcmp(agcon_3,''),          P_args=[P_args,{'agcon',{'Ip','bp',agcon_3}}]; P_error=[P_error sprintf('%s: {%s}, ',P_args{end-1},strjoin(P_args{end},','))]; end
      P_error = [P_error sprintf('%s: %s',P_args{7:8})];
      
      if ~strcmp(cde,'OhmTor_rigid') && ~strcmp(cde,'')
        % RZP implements only the OhmTor_rigid CDE
        testCase.verifyError( @() testCase.rzp_single_output(P_args{:}),''); 
      elseif ~strcmp(agcon_3,'li') && ~strcmp(agcon_3,'')     
        % RZP implements only constraining 'li'
        testCase.verifyError( @() testCase.rzp_single_output(P_args{:}),'');    
      elseif strcmp(num2str(lin),'0') && (numel(testCase.t) > 1)
        % RZP with multiple time slices requires linearization
        testCase.verifyError( @() testCase.rzp_single_output(P_args{:}),'');
      else
        try
          testCase.rzp_single_output(P_args{:});
        catch ME
          fprintf('\n %s error caused in %s in fget by parameters %s \n',...
          ME.message,case_string,P_error);
          rethrow(ME);
        end
      end 
    end
  end
end