Analysis
f_analysis
Code
1function [results, settings] = ... 2 f_analysis(settings, analysis, model_folders, analysis_options, results) 3% This function performs a specific analysis based on the given analysis 4% options. The function calls the appropriate analysis functions 5% (f_diagnostics, f_opt, f_sim_score, f_lsa, f_gsa, f_PL_m) depending on 6% the selected analysis type. The analysis results are stored in an updated 7% 'rst' structure, and the settings are updated as needed. 8% 9% Inputs: 10% - stg: Settings to use in the analysis 11% - analysis: Type of analysis to be performed 12% - mmf: Main model files 13% - analysis_options: List of possible analysis options 14% - rst: Structure for storing analysis results 15% 16% Outputs: 17% - rst: Updated structure containing the results of the analysis 18% - stg: Updated settings after the analysis 19% 20% Used Functions: 21% - f_diagnostics: Performs diagnostic analysis 22% - f_opt: Performs optimization analysis 23% - f_sim_score: Runs simulation for a given option 24% - f_lsa: Performs Local sensititivity Analysis (LSA) 25% - f_gsa: Performs Global ensititivity Analysis (GSA) 26% - f_PL_m: Performs Profile Likelihood Analysisa (PLA) 27% 28% Variables: 29% Initialized: 30% - matching_option_idx: Index of the selected analysis option 31% - sim_results: Cell array for storing simulation results 32% - valid_options: Array of valid optimization options 33% 34% Persistent: None 35% analysis 36% analysis_options 37% matching_option_idx 38matching_option_idx = find(contains(analysis_options, analysis), 1); 39 40% display start message 41disp("Starting " + {analysis_options(matching_option_idx)}) 42 43% Perform the analysis based on the current analysis option index 44switch matching_option_idx 45 case 1 46 % run diagnostic analysis 47 results.diag = f_diagnostics(settings, model_folders); 48 case 2 49 % run optimization analysis 50 [results.opt, pa] = f_opt(settings, model_folders); 51 % find valid optimization options 52 valid_options = find(pa(:, 1) ~= 0); 53 % update settings with valid options 54 settings.pat = transpose(valid_options); 55 % create cell array for simulation results 56 sim_results = cell(length(valid_options), 1); 57 % parallelize simulation runs 58 for j = settings.pat 59 % run simulation for current valid option 60 [~, sim_results{j}, ~] = ... 61 f_sim_score(pa(j, :), settings, model_folders, 0, 0); 62 end 63 % store simulation results in results structure 64 results.diag(settings.pat) = [sim_results{:}]; 65 case 3 66 % run LSA analysis 67 results.lsa = f_lsa(settings, model_folders); 68 case 4 69 % run GSA analysis 70 results.gsa = f_gsa(settings, model_folders); 71 case 5 72 % run PLA analysis 73 results.PLA = f_PL_m(settings, model_folders); 74end 75 76% display completion message 77disp(analysis_options(matching_option_idx) + " completed successfully") 78end
The f_analysis function performs a specific analysis based on the given analysis options. It takes settings, analysis type, main model files, a list of possible analysis options, and a structure for storing analysis results as input arguments. The function outputs the results of the analysis and updates the settings as needed. The function calls the appropriate analysis functions (f_diagnostics, f_opt, f_sim_score, f_lsa, f_gsa, f_PL_m) depending on the selected analysis type.
Inputs
stg: Settings to use in the analysis.
analysis: Type of analysis to be performed.
mmf: Main model files.
analysis_options: List of possible analysis options.
rst: Structure for storing analysis results.
Outputs
rst: Updated structure containing the results of the analysis.
stg: Updated settings after the analysis.
Usage
[rst, stg] = f_analysis(stg, analysis, mmf, analysis_options, rst)
Example
settings = :ref:`stg<stg>`;
analysis_type = 'diagnostics';
model_files = 'path/to/model/files';
options = ["Diagnostics","Parameter Estimation",...
"Local Sensitivity Analysis","Global Sensitivity Analysis",...
"Profile Likelihood Analysis","Reproduce a previous analysis",...
"Reproduce the plots of a previous analysis","Import model files"];
results = :ref:`stg<stg>`;
[results, settings] = f_analysis(settings, analysis_type, model_files, options, results);
Diagnostics
f_diagnostics
Code
1function rst = f_diagnostics(stg, mmf) 2% Description: This function runs a model for given parameters and 3% settings, and computes the scores for fitness, both in multi-core and 4% single-core mode. The function uses f_sim_score() to obtain the score for 5% each parameter array. The mode (multi-core or single-core) is determined 6% by the 'optmc' field in the 'stg' input. 7% 8% Inputs: 9% - stg: A structure containing settings for the model, such as: 10% * pa: An array of parameter arrays to be tested. 11% * pat: Indices of the parameter arrays to be tested. 12% * optmc: A Boolean flag, if true the function runs in multi-core 13% mode, otherwise it runs in single-core mode. 14% - mmf: A custom memory-mapped file object, used for reading or writing 15% data. 16% 17% Outputs: 18% - rst: A vector containing the computed scores for each parameter array. 19% 20% Used Functions: 21% - f_sim_score: A function that takes a parameter array, model settings 22% (stg), and a custom memory-mapped file object (mmf) as inputs and returns 23% the computed score for that parameter array. 24% 25% Variables: 26% Loaded: 27% (None) 28% 29% Initialized: 30% - par_array_idx: The current index of the parameter array being tested. 31% 32% Persistent: 33% (None) 34 35% Run the model and obtain scores for fitness Multi Core 36pa = stg.pa(stg.pat, :); 37if stg.optmc 38 disp("Running the model and obtaining Scores (Multicore)") 39 40 % Iterate over the parameter arrays to be tested 41 parfor par_array_idx = 1:length(stg.pat) 42 [~, rst(par_array_idx), ~] = ... 43 f_sim_score(pa(par_array_idx, :), stg, mmf, 0, 0); 44 end 45 46 % Run the model and obtain scores for fitness single Core 47else 48 disp("Running the model and obtaining Scores (Singlecore)") 49 50 % Iterate over the parameter arrays to be tested 51 for par_array_idx = 1:length(stg.pat) 52 [~, rst(par_array_idx), ~] = ... 53 f_sim_score(pa(par_array_idx, :), stg, mmf, 0, 0); 54 end 55end 56rst(stg.pat(1:length(stg.pat))) = rst(1:length(stg.pat)); 57end
Inputs
Outputs - rst (diagnostics results)
Optimization
f_opt
Code
1function [result,parameter_array] = f_opt(settings,model_folders) 2% This function performs optimization on a given objective function using 3% different optimization algorithms. The available algorithms include 4% fmincon, Simulated annealing, Pattern search, Genetic algorithm, Particle 5% swarm, and Surrogate optimization. It iterates through the 6% optimization_algorithms cell array and calls the appropriate optimization 7% algorithm if its flag is set in the 'settings'. 8% 9% Inputs: 10% - settings: A struct containing settings for the optimization algorithms. 11% - model_folders: An array containing information about the models to be 12% optimized. 13% 14% Outputs: 15% - result: A vector containing the results of each optimization algorithm. 16% - parameter_array: A matrix containing the parameters for each 17% optimization algorithm result. 18% 19% Used Functions: 20% - run_algorithm: Handles the execution of a specific optimization 21% algorithm. 22% - optimize_algorithm: Sets up the optimization algorithm and executes it. 23% - run_optimization: Runs the selected optimization algorithm with 24% appropriate settings. 25% - run_optimizer: Executes the chosen optimization algorithm. 26% - prepare_optimization_options: Prepares the optimization options based 27% on the algorithm. 28% - get_plot_functions: Returns the appropriate plotting function for the 29% optimization algorithm. 30% - f_opt_start: Returns the starting point and the starting population for 31% optimization algorithms. 32% 33% Loaded Variables: 34% - optimization_algorithms: A cell array containing optimization algorithm 35% names and flags. 36% - algorithm_flag: The flag corresponding to the optimization algorithm. 37% - objective_function: A function handle to the objective function for 38% optimization. 39% - options: A struct containing options for the optimization algorithm. 40% - plot_functions: A cell array containing plot functions specific to each 41% optimization algorithm. 42 43% settings.optt = 60*60; 44% settings.popsize = 720; 45% Set the random seed for reproducibility 46rng(settings.rseed); 47 48% Initialize the cell array containing optimization algorithm names and 49% corresponding settings flags 50optimization_algorithms = { 51 'Genetic algorithm', 'ga'; 52 'fmincon', 'fmincon'; 53 'Simulated annealing', 'sa'; 54 'Pattern search', 'psearch'; 55 'Particle swarm', 'pswarm'; 56 'Surrogate optimization', 'sopt'}; 57 58p = gcp(); % If no pool, do not create new one. 59poolsize = p.NumWorkers; 60 61settings.pat_original = settings.pat; 62settings.pa_original = settings.pa; 63 64 65settings.pat = 1:poolsize; 66for n = 1:poolsize 67settings.pa(n, :) = settings.pa(1, :); 68end 69parfor n = 1:poolsize 70[~] = f_diagnostics(settings, model_folders); 71end 72 73% Iterate through the optimization_algorithms cell array and call the 74% corresponding algorithms if their flag is set in the settings 75for i = 1:size(optimization_algorithms, 1) 76 % algorithm_func = optimization_algorithms{i, 1}; 77 algorithm_flag = optimization_algorithms{i, 2}; 78opt_time = tic; 79 if settings.(algorithm_flag) 80 [result(i), parameter_array(i, :)] = ... 81 run_algorithm(@optimize_algorithm,... 82 optimization_algorithms{i, 1}, settings, model_folders); 83 end 84disp(convertCharsToStrings(optimization_algorithms{i, 2}) + ": " + ... 85 toc(opt_time)) 86end 87end 88 89function [algorithm_result, algorithm_parameter_array] =... 90 run_algorithm(algorithm_func, optimization_algorithms_names,... 91 settings, model_folders) 92 93% Define the objective function 94objective_function = @(x)f_sim_score(x, settings, model_folders, 0, 0); 95 96% Call the optimization algorithm 97algorithm_result = algorithm_func(optimization_algorithms_names,... 98 settings, objective_function); 99 100% Find the minimum value and its corresponding parameters 101[~, min_index] = min(algorithm_result.fval); 102algorithm_parameter_array = algorithm_result.x(min_index, :); 103end 104 105function result_opt = optimize_algorithm(algorithm_name,... 106 settings, objective_function) 107p = gcp(); % If no pool, do not create new one. 108 109% poolsize = p.NumWorkers; 110% mst = settings.mst; 111% optt = settings.optt = 60*10; 112% if contains(algorithm_name, {'Pattern search', 'Surrogate optimization'}) 113% settings.mst = true; 114% settings.msts = poolsize; 115% elseif contains(algorithm_name, {'fmincon', 'Simulated annealing'}) 116% settings.mst = true; 117% settings.msts = poolsize*5; 118% settings.optt = optt/5; 119% else 120% settings.mst = mst; 121% settings.msts = poolsize; 122% settings.optt = optt; 123% end 124 125% Determine the starting point for the optimization 126[startpoint, ~, spop] = f_opt_start(settings); 127 128% Prepare optimization options based on settings and algorithm_name 129options = prepare_optimization_options(settings, algorithm_name); 130 131% Execute the optimization algorithm 132[x, fval, exitflag, output] = run_optimization(settings, algorithm_name,... 133 objective_function, startpoint, spop, settings.lb, settings.ub,... 134 options); 135 136% Save optimization results 137result_opt.name = algorithm_name; 138result_opt.x = x; 139result_opt.fval = fval; 140result_opt.exitflag = exitflag; 141result_opt.output = output; 142end 143 144function [x, fval, exitflag, output] = run_optimization(settings,... 145 algorithm_name, objective_function, startpoint, spop, lb, ub,... 146 options) 147 148% Run the optimization algorithm using either multiple starting points (mst) 149% or a single starting point (the average of the lower and upper bounds) 150if settings.mst 151 parfor n = 1:settings.msts 152 [x(n,:), fval(n), exitflag(n), output(n)] = ... 153 run_optimizer(algorithm_name, objective_function,... 154 startpoint(n,:), spop{n}, lb, ub, options); 155 end 156else 157 158 [x(1,:), fval(1), exitflag(1), output(1)] = ... 159 run_optimizer(algorithm_name, objective_function,... 160 (lb + ub) / 2, spop, lb, ub, options); 161 162 % [x(1,:), fval(1), exitflag(1), output(1)] = ... 163 % run_optimizer(algorithm_name, objective_function,... 164 % settings.bestpa, spop, lb, ub, options); 165end 166end 167 168function [x, fval, exitflag, output] = ... 169 run_optimizer(algorithm_name, objective_function, startpoint, spop,... 170 lb, ub, options) 171% Execute the appropriate optimization algorithm based on algorithm_name 172switch algorithm_name 173 case 'fmincon' 174 [x, fval, exitflag, output] = ... 175 fmincon(objective_function, startpoint, ... 176 [], [], [], [], lb, ub, [], options); 177 case 'Simulated annealing' 178 [x, fval, exitflag, output] = ... 179 simulannealbnd(objective_function, startpoint, lb, ub, options); 180 case 'Pattern search' 181 182 [x, fval, exitflag, output] = ... 183 patternsearch(objective_function, startpoint, ... 184 [], [], [], [], lb, ub, [], options); 185 case 'Genetic algorithm' 186 parnum = length(lb); 187 [x, fval,exitflag,output] = ga(objective_function, parnum, ... 188 [], [], [], [], lb, ub, [], options); 189 case 'Particle swarm' 190 parnum = length(lb); 191 [x, fval, exitflag, output] = ... 192 particleswarm(objective_function, parnum, lb, ub, options); 193 case 'Surrogate optimization' 194 options.InitialPoints = spop; 195 [x, fval, exitflag, output] = ... 196 surrogateopt(objective_function, lb, ub, options); 197 otherwise 198 error('Unsupported optimization algorithm.'); 199end 200end 201 202function options = prepare_optimization_options(settings, algorithm_name) 203 204% Set options for each algorithm 205switch algorithm_name 206 case 'fmincon' 207 options = settings.fm_options; 208 options.UseParallel = settings.optmc; 209 case 'Simulated annealing' 210 options = settings.sa_options; 211 options.MaxTime = settings.optt; 212 case 'Pattern search' 213 options = settings.psearch_options; 214 options.MaxTime = settings.optt; 215 options.UseParallel = settings.optmc; 216 case 'Genetic algorithm' 217 218 % test = settings.pa_original(settings.pat_original, :); 219 220 options = settings.ga_options; 221 options.MaxTime = settings.optt; 222 % options.PopulationSize = settings.popsize+length(test); 223 options.PopulationSize = settings.popsize; 224 options.UseParallel = settings.optmc; 225 [~, startpop, ~] = f_opt_start(settings); 226 options.InitialPopulationMatrix = startpop; 227 case 'Particle swarm' 228 options = settings.pswarm_options; 229 options.MaxTime = settings.optt; 230 options.SwarmSize = settings.popsize; 231 options.UseParallel = settings.optmc; 232 [~, startpop, ~] = f_opt_start(settings); 233 options.InitialSwarmMatrix = startpop; 234 case 'Surrogate optimization' 235 options = settings.sopt_options; 236 options.MaxTime = settings.optt; 237 options.UseParallel = settings.optmc; 238 otherwise 239 error('Unsupported optimization algorithm.'); 240end 241 242% Enable plots if chosen in settings 243if settings.optplots 244 % Set the appropriate PlotFcn based on the optimization algorithm 245 options.PlotFcn = get_plot_functions(algorithm_name); 246end 247 248% Enable console messages if chosen in settings 249if settings.optcsl 250 options.Display = 'iter'; 251end 252end 253 254function plot_functions = get_plot_functions(algorithm_name) 255 256% Set the appropriate PlotFcn based on the optimization algorithm 257switch algorithm_name 258 case 'fmincon' 259 plot_functions = ... 260 {@optimplotx, @optimplotfunccount, @optimplotfval, ... 261 @optimplotstepsize, @optimplotfirstorderopt}; 262 case 'Simulated annealing' 263 plot_functions = ... 264 {@saplotbestf, @saplottemperature, @saplotf, ... 265 @saplotstopping, @saplotx}; 266 case 'Pattern search' 267 plot_functions = ... 268 {@psplotbestf, @psplotfuncount, @psplotmeshsize, @psplotbestx}; 269 case 'Genetic algorithm' 270 plot_functions = ... 271 {@gaplotbestf, @gaplotexpectation, @gaplotrange, ... 272 @gaplotscorediversity, @gaplotstopping, ... 273 @gaplotscores, @gaplotdistance, @gaplotselection, @gaplotbestindiv}; 274 case 'Particle swarm' 275 plot_functions = {@pswplotbestf}; 276 case 'Surrogate optimization' 277 plot_functions = {@surrogateoptplot}; 278 otherwise 279 error('Unsupported optimization algorithm.'); 280end 281end 282 283function [spoint,spop_mc,spop_sc] = f_opt_start(settings) 284% Set the randomm seed for reproducibility 285rng(settings.rseed); 286 287test = settings.pa_original(settings.pat_original, :); 288 289% Optimization Start method 1 290if settings.osm == 1 291% stg.pat_original 292% stg.pa_original 293% for n = stg.pat_original 294% n 295% stg.pa_original(n,:) 296 297% end 298% test 299% lhsdesign(stg.popsize,stg.parnum).*(stg.ub-stg.lb)+stg.lb 300 301% test = stg.pa_original(stg.pat_original,:); 302 % Get a random starting point or group of starting points, if using 303 % multistart, inside the bounds 304 spoint = lhsdesign(settings.msts, settings.parnum) .* ... 305 (settings.ub - settings.lb) + settings.lb; 306 307 % Get a group of ramdom starting points inside the bounds 308 spop_mc = lhsdesign(settings.popsize, settings.parnum) .* ... 309 (settings.ub - settings.lb) + settings.lb; 310 % spop_mc = [lhsdesign(settings.popsize,settings.parnum).*(settings.ub-stg.lb)+settings.lb;test]; 311 312 % Get a group of ramdom starting points inside the bounds 313 for n = 1:settings.msts 314 spop_sc{n} = lhsdesign(ceil(settings.popsize / 36), ... 315 settings.parnum) .* (settings.ub- settings.lb) + settings.lb; 316 end 317 % Optimization Start method 2 318elseif settings.osm == 2 319 320 % Get a random starting point or group of starting points, if using 321 % multistart, near the best point 322 spoint = settings.bestpa - settings.dbpa + ... 323 (settings.dbpa * 2 * lhsdesign(settings.msts, settings.parnum)); 324 325 spoint = max(min(5,spoint), -7); 326 327 % Get a group of random starting points near the best point 328 spop_mc = settings.bestpa - settings.dbpa + ... 329 (settings.dbpa * 2 * lhsdesign(settings.popsize, settings.parnum)); 330 331 spop_mc = max(min(settings.ub,spop_mc),settings.lb); 332 spop_mc = [spop_mc;test]; 333 for n = 1:settings.msts 334 spop_sc{n} = settings.bestpa - settings.dbpa + ... 335 (settings.dbpa * 2 * lhsdesign(ceil(settings.popsize / 36), ... 336 settings.parnum)); 337 338 spop_sc{n} = max(min(settings.ub,spop_sc{n}), settings.lb); 339 end 340end 341end
Calls the correct optmizer or optimizers that have been chosen in the settings file.
Inputs
Outputs - rst (optimization results)
f_opt_start
Code
Inputs
Outputs
spoint - (double) starting parameter set for the optimization
spop - (double) Starting parameter sets for multiple start optimizations
f_opt_fmincon/sa/psearch/ga/pswarm/sopt
Code
f_opt_fmincon
f_opt_sa
f_opt_psearch
f_opt_ga
f_opt_pswarm
f_opt_sopt
These functions call built in MATLAB® functions that perform parameter optimization . For furher information relating to how these optimizers work please follow the links to the MATLAB® documentation. Optimizers used:
f_opt_fmincon - fmincon
f_opt_sa - Simmulated annealing
f_opt_psearch - Pattern search
f_opt_ga - Genetic algorihtm
f_opt_pswarm - Particle swarm
f_opt_sopt - Surrogate optmization
Inputs - stg
Outputs - Optimization results
Global Sensitivity Analysis
f_gsa
Code
1function results = f_gsa(settings, model_folders) 2% f_gsa - Performs global sensitivity analysis (GSA) using the 3% Sobol-Saltelli method on a given model 4% 5% This function conducts a GSA based on the Sobol-Saltelli method for a 6% given model, as inspired by Geir Halnes et al.'s 2009 paper (J. comp. 7% neuroscience 27.3 (2009): 471). The function takes two inputs: 8% 'settings', a structure containing various settings for the analysis, and 9% 'model_folders', the model folders structure. The function returns 10% 'results', a structure containing the GSA results, including sensitivity 11% indices (Si) and total sensitivity indices (SiT) for each score type. 12% 13% Inputs: 14% - settings: A structure containing settings for the GSA, such as 15% parameter bounds, sampling mode, and random seed. 16% - model_folders: A structure containing the necessary model folder paths. 17% 18% Outputs: 19% - results: A structure containing the GSA results, including sensitivity 20% indices (Si) and total sensitivity indices (SiT) for each score type. 21% 22% Functions called: 23% - f_make_par_samples(settings): Generates sample matrices of model 24% parameters. 25% - f_make_output_sample(results, settings, model_folders): Calculates the 26% outputs for three different matrices (GSA M1, GSA M2, and GSA N) based on 27% the input parameters, settings, and mathematical model. 28% - f_calc_sensitivities(results, settings): Removes simulation errors 29% from the data and calculates Si and SiT using the bootstrap method. 30 31results = f_make_par_samples(settings); 32 33results = f_make_output_sample(results,settings,model_folders); 34 35results = f_calc_sensitivities(results,settings); 36end
Calls the global sensitivity analysis functions in the correct order.
f_make_par_samples
Code
1function results = f_make_par_samples(settings) 2% This function creates sample matrices of model parameters according to 3% specified distributions and settings, based on Geir Halnes et al.'s 2009 4% paper (J. comp. neuroscience 27.3 (2009): 471). It generates two sample 5% matrices M1 and M2, and a 3D matrix N, where N(:,:,i) is M2 with its i:th 6% column replaced by M1(:,i). 7% 8% Inputs: 9% - settings: A structure containing fields for generating samples, 10% including sansamples, parnum, rseed, sasamplemode, lb, ub, bestpa, and 11% sasamplesigma. 12% 13% Outputs: 14% - results: A structure containing the following fields: 15% - M1: Sample matrix 1. 16% - M2: Sample matrix 2. 17% - N: A 3D matrix where N(:,:,i) is M2 with its i:th column replaced by 18% M1(:,i). 19% 20% Functions called: 21% - makedist: Create a probability distribution object. 22% - truncate: Truncate a probability distribution. 23% - random: Generate random numbers from a probability distribution. 24% 25% Variables: 26% Initialized: 27% - M1: Sample matrix 1. 28% - M2: Sample matrix 2. 29% - N: A 3D matrix where N(:,:,i) is M2 with its i:th column replaced by 30% M1(:,i). 31% - pd: An array of probability distribution objects for each parameter. 32% 33% Loaded (from settings structure): 34% - sansamples: Number of samples to generate for each parameter. 35% - parnum: Number of model parameters. 36% - rseed: Seed for the random number generator. 37% - sasamplemode: Sampling mode. 38% - lb: Vector containing lower bounds for each parameter. 39% - ub: Vector containing upper bounds for each parameter. 40% - bestpa: Vector containing the best parameter values. 41% - sasamplesigma: Standard deviation for normal distribution-based 42% sampling modes. 43 44% Pre-allocate memory for sample matrices 45M1 = zeros(settings.sansamples, settings.parnum); 46M2 = zeros(settings.sansamples, settings.parnum); 47N = zeros(settings.sansamples, settings.parnum, settings.parnum); 48rng(settings.rseed) 49 50% Loop through each parameter and create a distribution based on the 51% specified settings(Note that the sampling is being performed in log space 52% as the parameters and its bounds are in log space) 53for i = 1:settings.parnum 54 % Initialize distribution parameters depending on the sample mode 55 switch settings.sasamplemode 56 case 0 57 % Uniform distribution with bounds defined by parameter limits 58 lb = settings.lb(i); 59 ub = settings.ub(i); 60 case {1, 2} 61 % Normal distribution centered at the best parameter value with 62 % specified standard deviation 63 mu = settings.bestpa(i); 64 sigma = settings.sasamplesigma; 65 case {3, 4} 66 % Normal distribution centered at the mean of parameter bounds 67 % with specified standard deviation 68 mu = settings.lb(i) + (settings.ub(i) - settings.lb(i)) / 2; 69 sigma = settings.sasamplesigma; 70 end 71 % Generate samples based on the distribution parameters 72 if settings.sasamplemode == 0 73 % Uniform distribution 74 M1(:, i) = lb + (ub - lb) .* rand(1, settings.sansamples); 75 M2(:, i) = lb + (ub - lb) .* rand(1, settings.sansamples); 76 else 77 % Normal distribution 78 pd(i) = makedist('Normal', 'mu', mu, 'sigma', sigma); 79 80 % Truncate the distribution if specified 81 if ismember(settings.sasamplemode, [1, 3]) 82 pd(i) = truncate(pd(i), settings.lb(i), settings.ub(i)); 83 end 84 M1(:, i) = random(pd(i), settings.sansamples, 1); 85 M2(:, i) = random(pd(i), settings.sansamples, 1); 86 end 87end 88% Replace the i:th column in M2 by the i:th column from M1 to create N 89% matrices 90for i=1:settings.parnum 91 N(:, :, i) = M2; 92 N(:, i, i) = M1(:, i); 93end 94 95% Store resulting matrices in the output structure 96results.M1 = M1; 97results.M2 = M2; 98results.N = N; 99end
Creates parameter sets samples with specific parameter distributions that are used to perform the global sensitivity analysis.
Inputs
stg - stg.sansamples, stg.parnum, stg.sasamplemode, stg.ub, stg.lb
Code inspired by Geir Halnes et al. 2009 paper.
f_make_output_sample
Code
1function results = f_make_output_sample(results,settings,model_folders) 2% This function calculates the outputs for three different matrices (GSA 3% M1, GSA M2, and GSA N) based on the input parameters, settings, and a 4% mathematical model. This code is inspired by Geir Halnes et al. 2009 5% paper. 6% 7% Inputs: 8% - results: A structure containing M1, M2, and N matrices 9% - settings: A structure with settings, including sansamples and parnum 10% - model_folders: A variable containing folders for the models 11% 12% Outputs: 13% - results: A structure containing fM1, fM2, and fN fields, each 14% containing computed outputs for corresponding GSA methods 15% 16% Used Functions : 17% - compute_f: Compute the results for GSA M1, GSA M2, and GSA N methods 18% - f_sim_score: Simulation score calculation function 19% - progress_track: Track progress of the calculations 20% 21% Variables 22% Loaded: 23% - nSamples: Number of samples (loaded from settings.sansamples) 24% - nPars: Number of parameters (loaded from settings.parnum) 25% 26% Initialized: 27% - time_begin: The start time of the function 28% - f_out: Structure holding the computed values for fM1, fM2, and fN 29% 30% Persistent: 31% - current_sample: Keeps track of the current sample number for progress 32% tracking 33% - last_time: Keeps track of the last time progress was printed 34 35% Number of samples 36nSamples = settings.sansamples; 37 38% Number of parameters 39nPars = settings.parnum; 40 41% Start time of the function 42time_begin = datetime; 43 44% Compute the results for GSA M1, GSA M2, and GSA N methods 45results.fM1 = ... 46 compute_f(results.M1, nSamples, settings, model_folders, nPars, ... 47 time_begin, "GSA M1", "fM"); 48results.fM2 = ... 49 compute_f(results.M2, nSamples, settings, model_folders, nPars, ... 50 time_begin, "GSA M2", "fM"); 51results.fN = ... 52 compute_f(results.N, nSamples, settings, model_folders, nPars, ... 53 time_begin, "GSA N", "fN"); 54end 55 56function [f_out] =... 57 compute_f(parameter_array, nSamples, settings, model_folders, nPars, ... 58 time_begin, task_name, matrix_type) 59 60% Create a DataQueue for parallel processing 61D = parallel.pool.DataQueue; 62 63% Set up the progress tracker for the DataQueue 64afterEach(D, @progress_track_GSA); 65 66clear R RN 67 68% Choose the matrix type and perform the calculations accordingly 69switch matrix_type 70 case 'fM' 71 R = cell(nSamples, 1); 72 73 % Parallel loop for computing the output 74 parfor i = 1:nSamples 75 [~, ~, R{i}] = ... 76 f_sim_score(parameter_array(i,:), settings, ... 77 model_folders, i, 1); 78 send(D, {task_name, 0, time_begin, nSamples, nPars}); 79 end 80 % Extract the computed values 81 82 sd = zeros(nSamples, size(R{1}.sd, 1) * size(R{1}.sd, 2)); 83 se = zeros(nSamples, size(R{1}.se, 1)); 84 st = zeros(nSamples, size(R{1}.st, 1)); 85 xfinal = zeros(nSamples, size([R{1}.xfinal{:}], 2)); 86 87 for i = 1:nSamples 88 sd(i, :) = reshape(R{i}.sd(:, :), 1, []); 89 se(i, :) = R{i}.se(:); 90 st(i, :) = R{i}.st; 91 xfinal(i, :) = [R{i}.xfinal{:}]; 92 end 93 case 'fN' 94 % Nested parallel loop for computing the output 95 RN = cell(nSamples, nPars); 96 97 parfor i = 1:nSamples 98 for j = 1:nPars 99 % disp("i: " + i + " j: " + j) 100 % settings.i = i; 101 % setting.j = j; 102 [~,~,RN{i,j}] = ... 103 f_sim_score(parameter_array(i, :, j), settings, ... 104 model_folders, i, j); 105 end 106 send(D, {task_name, 0, time_begin, nSamples, nPars}); 107 end 108 109 sd = ... 110 zeros(nSamples, size(RN{1, 1}.sd, 1) * ... 111 size(RN{1, 1}.sd, 2), nPars); 112 se = zeros(nSamples, size(RN{1, 1}.se, 1), nPars); 113 st = zeros(nSamples, size(RN{1, 1}.st, 1), nPars); 114 xfinal = zeros(nSamples, size([RN{1, 1}.xfinal{:}], 2), nPars); 115 116 for i = 1:nSamples 117 for j = 1:nPars 118 sd(i, :, j) = reshape(RN{i, j}.sd, 1, []); 119 se(i, :, j) = RN{i, j}.se; 120 st(i, :, j) = RN{i, j}.st; 121 xfinal(i, :, j) = [RN{i, j}.xfinal{:}]; 122 end 123 end 124end 125 126f_out.sd = sd; 127f_out.se = se; 128f_out.st = st; 129f_out.xfinal = xfinal; 130 131% Display the runtime information for the task 132disp(task_name + " Runtime: " + string(datetime - time_begin) +... 133 " All " + nSamples + " samples executed") 134end 135 136% Function to track progress of the GSA 137function progress_track_GSA(arg) 138persistent current_sample 139persistent last_time 140 141% Initialize or update the current sample counter 142if isempty(current_sample) || current_sample == arg{4} 143 current_sample = arg{2}; 144end 145 146% Retrieve other required arguments 147task_name = arg{1}; 148start_time = arg{3}; 149num_samples = arg{4}; 150par_n = arg{5}; 151current_sample = current_sample + 1; 152 153% Print progress information at each step 154if mod(current_sample, ceil(num_samples / 10)) == 0 &&... 155 current_sample ~= num_samples 156 % 0 157 % num_samples 158 % current_sample 159 % ((num_samples-current_sample)/num_samples)*10 160 % ((num_samples-(ceil(num_samples/10)))/num_samples)*10 161 if ((num_samples - current_sample) / num_samples) * 10 <... 162 ((num_samples - (ceil(num_samples / 10))) / num_samples) * 10 163 % Calculate the remaining time 164 % datetime 165 % last_time 166 dt = (datetime-last_time); 167 % 1 168 remaining_time = seconds(dt); 169% 2 170 remaining_time = ... 171 remaining_time * ceil((num_samples - current_sample) / ... 172 num_samples * 10); 173% 3 174 remaining_time = seconds(remaining_time); 175% 4 176 remaining_time.Format = 'hh:mm:ss'; 177 % 5 178 % Print the progress and remaining time 179 fprintf('%s Runtime: %s Time to finish: %s Samples: %d/%d\n', ... 180 task_name, string(datetime - start_time), string(remaining_time), ... 181 current_sample, num_samples); 182 % 6 183 else 184% 7 185 % Print the progress without remaining time 186 fprintf('%s Runtime: %s Samples: %d/%d\n', ... 187 task_name, string(datetime - start_time), ... 188 current_sample, num_samples); 189 % 8 190 end 191% 9 192 last_time = datetime; 193end 194end
For each parameter set given in the matrices M1, M2, and N it runs the function f_sim_score generating new matrices fM1, fM2, and fN respectively.
Inputs - M1, M2, N, stg.sansamples, stg.parnum,
Code inspired by Geir Halnes et al. 2009 paper.
f_calc_sensitivities
Code
1function results = f_calc_sensitivities(results,settings) 2% Computes the first-order (Si) and total-order (SiT) sensitivity indices 3% for each score type present in the input data using the bootstrap method. 4% This function takes in the raw data and various settings for the 5% calculation process, and returns the results structure with calculated Si 6% and SiT for each score type. 7% 8% Inputs: 9% - results: a structure containing raw data (fM1, fM2, and fN) for 10% different score types 11% - settings: a structure containing settings for the calculation, such as 12% bootstrap size, random seed, and error score 13% 14% Outputs: 15% - results: a modified version of the input results structure containing 16% the computed Si and SiT for each score type 17% 18% Functions called: 19% - remove_sim_error: removes simulation errors from the input data 20% - bootstrap: calculates Si and SiT using the bootstrap method 21% - bootstrap_q: creates bootstrapped samples and calculates Si and SiT for 22% the bootstrapped samples 23% - calcSobolSaltelli: calculates Si and SiT using the Sobol-Saltelli 24% method 25% 26% Loaded variables: 27% - None 28% 29% Initialized variables: 30% - fM1: a structure containing the first-order score data for each score 31% type 32% - fM2: a structure containing the total-order score data for each score 33% type 34% - fN: a structure containing the score data for each score type and 35% parameter 36% - settings: a structure containing settings for the calculation 37% 38% Persistent variables: 39% - None 40 41% Remove simulation errors from the input data 42results = remove_sim_error(results, settings); 43 44% Calculate Si and SiT using the bootstrap method and store them in the 45% results structure 46[results.SiQ,results.SiTQ, results.Si, results.SiT] = ... 47 bootstrap(results, settings); 48end 49 50function [SiQ,SiTQ,Si,SiT]=bootstrap(results,settings) 51% calculates confidence intervals for the sensitivity indices using the 52% bootstrap method. 53 54% Initialize variables 55fM1 = results.fM1; 56fM2 = results.fM2; 57fN = results.fN; 58 59% Set the number of resamples for bootstrapping if not provided 60if (isempty(settings.gsabootstrapsize)) 61 settings.gsabootstrapsize = ceil(sqrt(size(fM1.sd, 2))); 62end%if 63 64% Define the list of scores to be used in the calculation 65scores_list = ["sd","se","st","xfinal"]; 66 67% Generate random indices for bootstrapping 68for j = 1: settings.gsabootstrapsize 69 rng(j * settings.rseed) 70 I(j, :) = ceil(rand(size(fM1.sd, 1), 1) * size(fM1.sd, 1)); 71end 72 73% Calculate Si and SiT for each score type and perform bootstrapping 74for n = 1:size(scores_list,2) 75 fM1h = fM1.(scores_list(n)); 76 fM2h = fM2.(scores_list(n)); 77 fNh = fN.(scores_list(n)); 78 79 % Calculate Si and SiT without bootstrapping 80 [Sih,SiTh] = calcSobolSaltelli(fM1h, fM2h, fNh, settings); 81 Si.(scores_list(n)) = Sih; 82 SiT.(scores_list(n)) = SiTh; 83 84 % Initialize variables for bootstrapped Si and SiT 85 SiQh = cell(1, settings.gsabootstrapsize); 86 SiTQh = cell(1, settings.gsabootstrapsize); 87 88 % Perform bootstrapping for the current score type 89 parfor j = 1:settings.gsabootstrapsize 90 [SiQh{j},SiTQh{j}] = bootstrap_q(fM1h, fM2h, fNh, settings, j, I); 91 end%parfor 92 93 % Store bootstrapped Si and SiT values in the output structures 94 for j=1:settings.gsabootstrapsize 95 SiQ.(scores_list(n))(j, :, :) = SiQh{j}; 96 SiTQ.(scores_list(n))(j, :, :) = SiTQh{j}; 97 end 98end 99end%function 100 101function [Si,SiT] = bootstrap_q(fM1, fM2, fN, settings, j, I) 102 % Create bootstrapped samples using the generated indices 103 fM1q = fM1(I(j, :), :); 104 fM2q = fM2(I(j, :), :); 105 fNq = fN(I(j, :), :, :); 106 107 % Calculate Si and SiT for the bootstrapped samples 108 [Si, SiT] = calcSobolSaltelli(fM1q, fM2q, fNq, settings); 109end 110 111function [Si, SiT] = calcSobolSaltelli(fM1, fM2, fN, settings) 112% Calculates Si and SiT using the Sobol-Saltelli method. 113% Code inspired by Geir Halnes et al. 2009 paper. (Halnes, Geir, et al. J. 114% comp. neuroscience 27.3 (2009): 471.) 115 116% Get the dimensions of the input data 117[Nsamples, Nvars, Npars] = size(fN); 118 119% Optionally subtract the mean to stabilize the model 120if(settings.sasubmean) 121 fM1 = fM1 - mean(fM1, 1); 122 fM2 = fM2 - mean(fM2, 1); 123 for i = 1: Npars 124 fN(:, :, i) = fN(:,:,i) - mean(fN(:, :, i), 1); 125 end 126end 127 128% Calculate EY2 and variances 129EY2 = mean(fM1 .* fM2); % Valid definition (see Halnes et. al. Appendix) 130VY = sum(fM1 .^ 2)/(Nsamples - 1) - EY2; 131VYT = sum(fM2 .^ 2)/(Nsamples - 1) - EY2; 132 133% Initialize Si and SiT arrays 134Si = zeros(Nvars, Npars); 135SiT= zeros(Nvars, Npars); 136 137% Calculate Si and SiT for each parameter 138for i = 1: Npars 139 Si(:, i) = (sum(fM1 .* fN(:, :, i))/(Nsamples - 1) - EY2) ./ VY; 140 SiT(:, i) = 1 - (sum(fM2 .* fN(:, :, i))/(Nsamples - 1) - EY2) ./ VYT; 141end 142end 143 144function results = remove_sim_error(results, settings) 145% Removes any simulation errors present in the input data. 146error_indices = any(results.fM1.sd >= settings.errorscore, 2) | ... 147 any(results.fM2.sd >= settings.errorscore, 2) | ... 148 any(any(results.fN.sd >= settings.errorscore, 3), 2); 149 150% Remove error rows from all fields of the input data 151fields = fieldnames(results.fM1); 152for i = 1:numel(fields) 153 results.fM1.(fields{i})(error_indices, :) = []; 154 results.fM2.(fields{i})(error_indices, :) = []; 155 results.fN.(fields{i})(error_indices, :, :) = []; 156end 157end
Takes the matrices fM1, fM2, and fN and calculates sensitivity indexes. It calculates indexes based on the following oputputs of the f_sim_score function:
Code modified from the Geir Halnes et al. 2009 paper.