arSIAInit.m
%==========================================================================
% Matlab toolbox for structural identifiability and observability
% analysis of nonlinear models
%--------------------------------------------------------------------------
% based on:
% StrIkE-GOLDD (v3.0, last modified: 19/10/2020)
% https://github.com/afvillaverde/strike-goldd
%--------------------------------------------------------------------------
% options can be specified in 'ar.ia.opts'
% m model number in ar struct. default value is m=1
function arSIAInit(m)
global ar
if isfield(ar,'ia')
if isfield(ar.ia,'opts')
opts_old = ar.ia.opts;
opts_old.use_existing_results = 0;
end
ar = rmfield(ar,'ia');
end
%userManual = [ar.ia.paths.strike_goldd '/doc/STRIKE-GOLDD_manual.pdf'];
disp(' ')
disp('====================================================================')
disp(' this toolbox uses <a href="https://github.com/afvillaverde/strike-goldd">STRIKE-GOLDD (v3.0)</a> package for analysing')
disp('the structural identifiability and observability of nonlinear models')
%disp(' (<a href="matlab: open(userManual)">user manual</a>)')
disp('--------------------------------------------------------------------')
disp(' For more information about the theory of finding and breaking');
disp(' Lie Symmetries click <a href="https://doi.org/10.3390/sym12030469">here</a>')
disp('====================================================================')
if ~exist('ar','var') && ~isfield(ar,'model')
error('Please initialize and load the model');
end
if ~exist('m','var') || isempty(m)
m = 1;
end
if isempty(ar.model(m).y)
error('The toolbox is not compatible with models with no observables!');
end
if exist('ar','var') && isfield(ar,'ia') && isfield(ar.ia,'paths')
cd(ar.ia.paths.d2dmodel)
end
% create the model
arStrikeGolddModel(m);
% set options
if exist('opts_old','var')
ar.ia.opts = opts_old;
else
InitiateOptions;
end
ar.ia.about = 'this field contains information used in the strike-goldd toolbox';
currentFolder = pwd;
ar.ia.paths.d2dmodel = currentFolder;
ar_path = fileparts(which('arInit.m'));
strike_goldd_path = strcat(ar_path,filesep,'ThirdParty',filesep,'strike-goldd',filesep,'STRIKE-GOLDD');
ar.ia.paths.strike_goldd = strike_goldd_path;
ID = 1; % check if the model is already exist
if ~exist('Results', 'dir')
ID = 0;
status = mkdir('Results');
if status == 0
error('Making folder "Results" was not successful');
end
end
model_path = strcat(currentFolder,filesep,'Results');
cd(model_path)
if ~exist('Identifiability_Analysis', 'dir')
ID = 0;
status = mkdir('Identifiability_Analysis');
if status == 0
error('Making folder "Identifiability_Analysis" was not successful');
end
end
model_path = strcat(model_path,filesep,'Identifiability_Analysis');
cd(model_path)
if ~exist(ar.ia.modelname_checkstr, 'dir')
ID = 0;
status = mkdir(ar.ia.modelname_checkstr);
if status == 0
error('Making folder "%s" was not successful',ar.ia.modelname_checkstr);
end
end
model_path = strcat(model_path,filesep,ar.ia.modelname_checkstr);
mkdir(model_path)
cd(model_path)
% defenitely not a perfect solution. But checking and only making when neede
% did not work. No idea why. mkdir does not overwrite if already exists, so
% should not be a problem.
mkdir('result');
if ~exist(strcat(ar.ia.modelname,'.m'),'file') || ~exist(strcat(ar.ia.modelname,'.mat'),'file')
ID = 0;
% write the model to file
arStrikeGolddWriteModel
% run the model
run([ar.ia.modelname,'.m'])
end
% check if the result is already exist
if ID==1
folderInfo={};
tmp = dir('result');
for i=1:length(tmp)
folderInfo{end+1} = tmp(i).name;
end
status = 0;
for i=1:length(folderInfo)
status = contains(folderInfo,strcat('id_results_',ar.ia.modelname));
end
if sum(status)==1
ar.ia.opts.use_existing_results = 1;
ar.ia.opts.results_file = folderInfo{status};
fprintf(' * The model has already been analysed!\n\n');
end
end
% redirect to the strike_goldd path
cd(strike_goldd_path)
% create needed paths
ar.ia.paths.meigo = strcat(pwd,filesep,'MEIGO64/MEIGO');
ar.ia.paths.models = strcat(model_path);
ar.ia.paths.results = strcat(model_path,filesep,'result');
ar.ia.paths.functions = strcat(pwd,filesep,'functions');
% initiate strike-goldd and adds paths to the matlab search path
install
% add paths to the matlab search path
addpath(model_path)
addpath(fullfile(model_path,'result'))
ar.ia.addedpaths{end+1} = model_path;
ar.ia.addedpaths{end+1} = fullfile(model_path,'result');
ar.ia = orderfields(ar.ia);
% set the options
options;
% remove paths from the matlab search path.
rmpath(ar.ia.addedpaths{:})
% redirect to the original folder
cd(ar.ia.paths.d2dmodel)
fprintf(' Initialization ... [done]\n');
end
function InitiateOptions
% defult values to uses STRIKE-GOLDD (v3.0)
% these values can be changes by the user after initialization.
% this function initializes all the information needed in option.m
global ar
% AUTOMATIC REPARAMETERIZATION
ar.ia.opts.autoRepar = 0;
% IDENTIFIABILITY OPTIONS:
ar.ia.opts.numeric = 0; % calculate rank numerically ( = 1) or symbolically ( = 0)
ar.ia.opts.replaceICs = 0; % replace states with specific initial conditions ( = 1) or use generic values ( = 0) when calculating rank
ar.ia.opts.checkObser = 1; % check state observability, i.e. identifiability of initial conditions (1 = yes; 0 = no).
ar.ia.opts.checkObsIn = 1; % check input observability (1 = yes; 0 = no).
ar.ia.opts.unidentif = 0; % use method to try to establish unidentifiability instead of identifiability, when using decomposition.
ar.ia.opts.forcedecomp = 0; % always decompose model (1 = yes; 0 = no).
ar.ia.opts.decomp = 0; % decompose model if the whole model is too large (1 = yes; 0 = no: instead, calculate rank with few Lie derivatives).
ar.ia.opts.decomp_user = 0; % when decomposing model, use submodels specified by the user ( = 1) or found by optimization ( = 0).
ar.ia.opts.maxLietime = 100; % max. time allowed for calculating 1 Lie derivative.
ar.ia.opts.maxOpttime = 30; % max. time allowed for every optimization (if optimization-based decomposition is used).
ar.ia.opts.maxstates = 6; % max. number of states in the submodels (if optimization-based decomposition is used).
ar.ia.opts.nnzDerU = 0; % numbers of nonzero derivatives of the measured inputs (u); may be 'inf'
ar.ia.opts.nnzDerW = 0; % numbers of nonzero derivatives of the unmeasured inputs (w); may be 'inf'
ar.ia.opts.nnzDerIn = ar.ia.opts.nnzDerU; % deprecated option
% AFFINE OPTIONS (to use the ORC-DF algorithm):
ar.ia.opts.affine = 0; % use the ORC-DF algorithm for affine control systems ( =1) or not( =0).
ar.ia.opts.affine_tStage = 1000; % max. computation time for the last iteration.
ar.ia.opts.affine_kmax = 4; % max. number of iterations.
ar.ia.opts.affine_parallel = 0; % use parallel toolbox ( =1) or not ( =0) to calculate partial ranks.
ar.ia.opts.affine_workers = 4; % number of workers for parallel pool.
ar.ia.opts.affine_graphics = 1; % display graphics ( =1) or not ( =0)
ar.ia.opts.affine_delete_model = 1; % delete affine model when finished ( =1) or not ( =0).
% DECOMPOSITION OPTIONS -- User-defined submodels for decomposition (may be left = []):
ar.ia.opts.submodels = [];
%- Submodels are specified as a vector of states, as e.g.:
% submodels{1} = [1 2];
% submodels{2} = [1 3];
% MULTI-EXPERIMENT OPTIONS:
ar.ia.opts.multiexp = 0; % Execute multi-experiment analysis ( =1) or not ( =0).
ar.ia.opts.multiexp_numexp = 2; % Number of experiments.
ar.ia.opts.multiexp_user_nnzDerU = 0; % Set manually the number of non-zero known input derivatives in each experiment ( =1) or not ( =0).
ar.ia.opts.multiexp_nnzDerU = [0 1]; % Number of non-zero known input derivatives in each experiment (Rows =inputs;Columns =experiments).
ar.ia.opts.multiexp_user_nnzDerW = 0; % Set manually the number of non-zero unknown input derivatives in each experiment ( =1) or not ( =0).
ar.ia.opts.multiexp_nnzDerW = [1 0]; % Number of non-zero unknown input derivatives in each experiment (Rows =inputs;Columns =experiments).
ar.ia.opts.multiexp_user_ics = 0; % Set manually the initial conditions for each experiment ( =1) or not ( =0).
%- Multi-experiment initial conditions (Rows =variables;Columns:experiments):
ar.ia.opts.multiexp_ics = [ [1,0,0,1,0,1,0,0,0].', [1,0,0,1,0,1,0,0,0].' ];
%- Which initial conditions are replaced (Rows =variables;Columns =experiments):
ar.ia.opts.multiexp_known_ics = [ [0,1,1,0,1,0,1,1,1].', [0,1,1,0,1,0,1,1,1].' ];
% LIE SYMMETRIES & REPARAMETERIZATION OPTIONS:
ar.ia.opts.ansatz = 2; % Type of Ansatz: % uni -> Univariate (1)
% par -> Partially variate (2)
% multi -> Multivariate (3)
ar.ia.opts.degree = 2; % Degree of Ansatz Polynomial
ar.ia.opts.tmax = 4; % Maximum degree of Lie series
ar.ia.opts.ode_n = 1; % (Only in Matlab R2020a and later:) use ode solver ( =1) or not ( =0)
ar.ia.opts.use_existing_results = 0; % if the model has already been analysed with STRIKE-GOLDD ( =1) or not ( =0)
%ar.ia.opts.results_file = 'id_results_1D_BIG_p_16-Oct-2020.mat'; % .mat file to use if use_existing_results = 1
ar.ia.opts.results_file = ''; % .mat file to use if use_existing_results = 1
% KNOWN/IDENTIFIABLE PARAMETERS (parameters assumed known, or already classified as identifiable):
ar.ia.opts.prev_ident_pars = [];
%- example:
% syms p2 p5
% prev_ident_pars = [p2 p5];
end