Analysis

f_analysis

Code

 1function [rst,stg] = f_analysis(stg,analysis,mmf,analysis_options,rst)
 2% This function performs a specific analysis based on the given analysis
 3% options. The function calls the appropriate analysis functions
 4% (f_diagnostics, f_opt, f_sim_score, f_lsa, f_gsa, f_PL_m) depending on
 5% the selected analysis type. The analysis results are stored in an updated
 6% 'rst' structure, and the settings are updated as needed.
 7%
 8% Inputs:
 9% - stg: Settings to use in the analysis
10% - analysis: Type of analysis to be performed
11% - mmf: Main model files
12% - analysis_options: List of possible analysis options
13% - rst: Structure for storing analysis results
14%
15% Outputs:
16% - rst: Updated structure containing the results of the analysis
17% - stg: Updated settings after the analysis
18%
19% Used Functions:
20% - f_diagnostics: Performs diagnostic analysis
21% - f_opt: Performs optimization analysis
22% - f_sim_score: Runs simulation for a given option
23% - f_lsa: Performs Local sensititivity Analysis (LSA)
24% - f_gsa: Performs Global ensititivity Analysis (GSA)
25% - f_PL_m: Performs Profile Likelihood Analysisa (PLA)
26%
27% Variables:
28% Initialized:
29% - matching_option_idx: Index of the selected analysis option
30% - sim_results: Cell array for storing simulation results
31% - valid_options: Array of valid optimization options
32%
33% Persistent: None
34% analysis
35% analysis_options
36% matching_option_idx
37matching_option_idx = find(contains(analysis_options, analysis), 1);
38
39% display start message
40disp("Starting " + {analysis_options(matching_option_idx)})
41
42% Perform the analysis based on the current analysis option index
43switch matching_option_idx
44    case 1
45        % run diagnostic analysis
46        rst.diag = f_diagnostics(stg,mmf);
47    case 2
48        % run optimization analysis
49        [rst.opt,pa] = f_opt(stg,mmf);
50        % find valid optimization options
51        valid_options = find(pa(:,1) ~= 0);
52        % update settings with valid options
53        stg.pat = transpose(valid_options);
54        % create cell array for simulation results
55        sim_results = cell(length(valid_options),1);
56        % parallelize simulation runs
57        for j = stg.pat
58            % run simulation for current valid option
59            [~,sim_results{j},~] = f_sim_score(pa(j,:),stg,mmf);
60        end
61        % store simulation results in results structure
62        rst.diag(stg.pat) = [sim_results{:}];
63    case 3
64        % run LSA analysis
65        rst.lsa = f_lsa(stg,mmf);
66    case 4
67        % run GSA analysis
68        rst.gsa = f_gsa(stg,mmf);
69    case 5
70        % run PLA analysis
71        rst.PLA = f_PL_m(stg,mmf);
72end
73
74% display completion message
75disp(analysis_options(matching_option_idx) + " completed successfully")
76end

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
36if stg.optmc
37    disp("Running the model and obtaining Scores (Multicore)")
38
39    pa = stg.pa;
40    % Iterate over the parameter arrays to be tested
41    parfor par_array_idx = stg.pat
42        [~,rst(par_array_idx),~] =...
43            f_sim_score(pa(par_array_idx,:),stg,mmf);
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 = stg.pat
52        [~,rst(par_array_idx),~] =...
53            f_sim_score(stg.pa(par_array_idx,:),stg,mmf);
54    end
55end
56end
Used to understand the effects of different parameters sets on model behaviour or in comparing different parameters sets.
It loads the user defined configurations, performs all the needed simulations, and calculates scores of the error functions either per experimental output, per experiment, or in total (check 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
 44% Set the random seed for reproducibility
 45rng(settings.rseed);
 46
 47% Initialize the cell array containing optimization algorithm names and
 48% corresponding settings flags
 49optimization_algorithms = {
 50    'Genetic algorithm', 'ga';
 51    'fmincon', 'fmincon';
 52    'Simulated annealing', 'sa';
 53    'Pattern search', 'psearch';
 54   'Particle swarm', 'pswarm';
 55    'Surrogate optimization', 'sopt'
 56    };
 57
 58p = gcp(); % If no pool, do not create new one.
 59poolsize = p.NumWorkers;
 60settings.pat = 1:poolsize;
 61for n = 1:poolsize
 62settings.pa(n,:) = settings.pa(1,:);
 63end
 64parfor n = 1:poolsize
 65[~] = f_diagnostics(settings,model_folders);
 66end
 67
 68% Iterate through the optimization_algorithms cell array and call the
 69% corresponding algorithms if their flag is set in the settings
 70for i = 1:size(optimization_algorithms, 1)
 71    % algorithm_func = optimization_algorithms{i, 1};
 72    algorithm_flag = optimization_algorithms{i, 2};
 73
 74    if settings.(algorithm_flag)
 75        [result(i), parameter_array(i, :)] = ...
 76            run_algorithm(@optimize_algorithm,...
 77            optimization_algorithms{i, 1}, settings, model_folders);
 78    end
 79end
 80end
 81
 82function [algorithm_result, algorithm_parameter_array] =...
 83    run_algorithm(algorithm_func, optimization_algorithms_names,...
 84    settings, model_folders)
 85
 86% Define the objective function
 87objective_function = @(x)f_sim_score(x, settings, model_folders);
 88
 89% Call the optimization algorithm
 90algorithm_result = algorithm_func(optimization_algorithms_names,...
 91    settings, objective_function);
 92
 93% Find the minimum value and its corresponding parameters
 94[~, min_index] = min(algorithm_result.fval);
 95algorithm_parameter_array = algorithm_result.x(min_index, :);
 96end
 97
 98function result_opt = optimize_algorithm(algorithm_name,...
 99    settings, objective_function)
100p = gcp(); % If no pool, do not create new one.
101poolsize = p.NumWorkers;
102mst = settings.mst;
103if contains(algorithm_name,{'fmincon','Simulated annealing','Pattern search','Surrogate optimization'})
104settings.mst = true;
105settings.msts = poolsize;
106else
107settings.mst = mst;
108settings.msts = poolsize;
109end
110% Determine the starting point for the optimization
111[startpoint, ~, spop] = f_opt_start(settings);
112
113% Prepare optimization options based on settings and algorithm_name
114options = prepare_optimization_options(settings, algorithm_name);
115
116% Execute the optimization algorithm
117[x, fval, exitflag, output] = run_optimization(settings, algorithm_name,...
118    objective_function, startpoint, spop, settings.lb,...
119    settings.ub, options);
120
121% Save optimization results
122result_opt.name = algorithm_name;
123result_opt.x = x;
124result_opt.fval = fval;
125result_opt.exitflag = exitflag;
126result_opt.output = output;
127end
128
129function [x, fval, exitflag, output] = run_optimization(settings,...
130    algorithm_name, objective_function, startpoint, spop, lb, ub,...
131    options)
132
133% Run the optimization algorithm using either multiple starting points (mst)
134% or a single starting point (the average of the lower and upper bounds)
135if settings.mst
136    parfor n = 1:settings.msts
137        disp(string(n))
138        [x(n,:), fval(n), exitflag(n), output(n)] = ...
139            run_optimizer(algorithm_name, objective_function,...
140            startpoint(n,:), spop{n}, lb, ub, options);
141    end
142else
143    [x(1,:), fval(1), exitflag(1), output(1)] = ...
144        run_optimizer(algorithm_name, objective_function,...
145        (lb + ub) / 2, spop, lb, ub, options);
146end
147end
148
149function [x, fval, exitflag, output] = ...
150    run_optimizer(algorithm_name, objective_function, startpoint, spop,...
151    lb, ub, options)
152
153% Execute the appropriate optimization algorithm based on algorithm_name
154switch algorithm_name
155    case 'fmincon'
156        [x, fval, exitflag, output] = ...
157            fmincon(objective_function, startpoint, [], [], [], [], lb, ub, [], options);
158    case 'Simulated annealing'
159        [x, fval, exitflag, output] = ...
160        simulannealbnd(objective_function, startpoint, lb, ub, options);
161    case 'Pattern search'
162        [x, fval, exitflag, output] = ...
163            patternsearch(objective_function, startpoint, ...
164            [], [], [], [], lb, ub, [], options);
165    case 'Genetic algorithm'
166        parnum = length(lb);
167        [x, fval] = ga(objective_function, parnum, ...
168            [], [], [], [], lb, ub, [], options);
169        exitflag = [" "];
170        output = [" "];
171    case 'Particle swarm'
172        parnum = length(lb);
173        [x, fval, exitflag, output] = ...
174            particleswarm(objective_function, parnum, lb, ub, options);
175    case 'Surrogate optimization'
176        options.InitialPoints = spop;
177        [x, fval, exitflag, output] = ...
178        surrogateopt(objective_function, lb, ub, options);
179    otherwise
180        error('Unsupported optimization algorithm.');
181end
182end
183
184function options = prepare_optimization_options(settings, algorithm_name)
185
186% Set options for each algorithm
187switch algorithm_name
188    case 'fmincon'
189        options = settings.fm_options;
190        options.UseParallel = settings.optmc;
191    case 'Simulated annealing'
192        options =  settings.sa_options;
193        options.MaxTime = settings.optt;
194        options.InitialTemperature = ones(1,settings.parnum)*2;
195    case 'Pattern search'
196        options = settings.psearch_options;
197        options.MaxTime = settings.optt;
198        options.UseParallel = settings.optmc;
199    case 'Genetic algorithm'
200        options = settings.ga_options;
201        options.MaxTime = settings.optt;
202        options.PopulationSize = settings.popsize;
203        options.UseParallel = settings.optmc;
204        [~,startpop,~] = f_opt_start(settings);
205        options.InitialPopulationMatrix = startpop;
206    case 'Particle swarm'
207        options = settings.pswarm_options;
208        options.MaxTime = settings.optt;
209        options.SwarmSize = settings.popsize;
210        options.UseParallel = settings.optmc;
211        [~,startpop,~] = f_opt_start(settings);
212        options.InitialSwarmMatrix = startpop;
213    case 'Surrogate optimization'
214        options = settings.sopt_options;
215        options.MaxTime = settings.optt;
216        options.UseParallel = settings.optmc;
217    otherwise
218        error('Unsupported optimization algorithm.');
219end
220
221% Enable plots if chosen in settings
222if settings.optplots
223    % Set the appropriate PlotFcn based on the optimization algorithm
224    options.PlotFcn = get_plot_functions(algorithm_name);
225end
226
227% Enable console messages if chosen in settings
228if settings.optcsl
229    options.Display = 'iter';
230end
231end
232
233function plot_functions = get_plot_functions(algorithm_name)
234
235% Set the appropriate PlotFcn based on the optimization algorithm
236switch algorithm_name
237    case 'fmincon'
238        plot_functions = ...
239            {@optimplotx, @optimplotfunccount, @optimplotfval, ...
240            @optimplotstepsize, @optimplotfirstorderopt};
241    case 'Simulated annealing'
242        plot_functions = ...
243            {@saplotbestf, @saplottemperature, @saplotf, ...
244            @saplotstopping, @saplotx};
245    case 'Pattern search'
246        plot_functions = ...
247            {@psplotbestf, @psplotfuncount, @psplotmeshsize, @psplotbestx};
248    case 'Genetic algorithm'
249        plot_functions = ...
250            {@gaplotbestf, @gaplotexpectation, @gaplotrange, ...
251            @gaplotscorediversity, @gaplotstopping, ...
252            @gaplotscores, @gaplotdistance, @gaplotselection};
253    case 'Particle swarm'
254        plot_functions = {@pswplotbestf};
255    case 'Surrogate optimization'
256        plot_functions = {@surrogateoptplot};
257    otherwise
258        error('Unsupported optimization algorithm.');
259end
260end
261
262function [spoint,spop_mc,spop_sc] = f_opt_start(stg)
263% Set the randomm seed for reproducibility
264rng(stg.rseed);
265
266% Optimization Start method 1
267if stg.osm == 1
268    
269    % Get a random starting point or group of starting points, if using
270    % multistart, inside the bounds
271    spoint = lhsdesign(stg.msts,stg.parnum).*(stg.ub-stg.lb)+stg.lb;
272
273    % Get a group of ramdom starting points inside the bounds
274    spop_mc = lhsdesign(stg.popsize,stg.parnum).*(stg.ub-stg.lb)+stg.lb;
275
276    % Get a group of ramdom starting points inside the bounds
277    for n = 1:stg.msts
278    spop_sc{n} = lhsdesign(ceil(stg.popsize/36),stg.parnum).*(stg.ub-stg.lb)+stg.lb;
279    end
280    % Optimization Start method 2
281elseif stg.osm == 2
282    
283    % Get a random starting point or group of starting points, if using
284    % multistart, near the best point
285    spoint = stg.bestpa - stg.dbs +...
286        (stg.dbs*2*lhsdesign(stg.msts,stg.parnum));
287    
288    % Get a group of ramdom starting points near the best point
289    spop_mc = stg.bestpa - stg.dbs +...
290        (stg.dbs*2*lhsdesign(stg.popsize,stg.parnum));
291
292    for n = 1:stg.msts
293    spop_sc{n} = stg.bestpa - stg.dbs +...
294        (stg.dbs*2*lhsdesign(ceil(stg.popsize/36),stg.parnum));
295    end
296end
297end

Calls the correct optmizer or optimizers that have been chosen in the settings file.

f_opt_start

Code

Creates the starting parameter set or sets of the optimizations, if single or multistart selected in settings file.
It supports two different random distributions for the starting points.

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:

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.

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 = compute_f(results.M1, nSamples, settings, model_folders, nPars, time_begin,"GSA M1","fM");
 46results.fM2 = compute_f(results.M2, nSamples, settings, model_folders, nPars, time_begin,"GSA M2","fM");
 47results.fN = compute_f(results.N, nSamples, settings, model_folders, nPars, time_begin,"GSA N","fN");
 48end
 49
 50function [f_out] =...
 51    compute_f(parameter_array, nSamples, settings, model_folders, nPars, time_begin, task_name, matrix_type)
 52
 53% Create a DataQueue for parallel processing
 54D = parallel.pool.DataQueue;
 55
 56% Set up the progress tracker for the DataQueue
 57afterEach(D, @progress_track);
 58
 59clear R RN
 60
 61% Choose the matrix type and perform the calculations accordingly
 62switch matrix_type
 63    case 'fM'
 64        R = cell(nSamples,1);
 65      
 66        % Parallel loop for computing the output
 67        parfor i = 1:nSamples
 68            [~,~,R{i}] = f_sim_score(parameter_array(i,:), settings, model_folders);
 69            send(D, {task_name, 1, time_begin, nSamples, nPars});
 70        end
 71        % Extract the computed values
 72
 73        sd = zeros(nSamples,size(R{1}.sd,1)*size(R{1}.sd,2));
 74        se = zeros(nSamples,size(R{1}.se,1));
 75        st = zeros(nSamples,size(R{1}.st,1));
 76        xfinal = zeros(nSamples,size(R{1}.sd,1)*(max(settings.exprun)-min(settings.exprun)+1));
 77
 78        for i = 1:nSamples
 79            sd(i,:) = reshape(R{i}.sd(:,:), 1, []);
 80            se(i,:) = R{i}.se(:);
 81            st(i,:) = R{i}.st;
 82            xfinal(i,:) = [R{i}.xfinal{:}];
 83        end
 84
 85    case 'fN'
 86        % Nested parallel loop for computing the output
 87        RN = cell(nSamples,nPars);
 88        
 89        parfor i = 1:nSamples
 90            for j = 1:nPars
 91                [~,~,RN{i,j}] = f_sim_score(parameter_array(i,:,j), settings, model_folders);
 92                
 93            end
 94            send(D, {task_name, 1, time_begin, nSamples, nPars});
 95          
 96        end
 97
 98        sd = zeros(nSamples,size(RN{1,1}.sd,1)*size(RN{1,1}.sd,2),nPars);
 99        se = zeros(nSamples,size(RN{1,1}.se,1),nPars);
100        st = zeros(nSamples,size(RN{1,1}.st,1),nPars);
101        xfinal = zeros(nSamples,size(RN{1,1}.sd,1)*(max(settings.exprun)-min(settings.exprun)+1),nPars);
102
103        for i = 1:nSamples
104            for j = 1:nPars
105                sd(i,:,j) = reshape(RN{i,j}.sd, 1, []);
106                se(i,:,j) = RN{i,j}.se;
107                st(i,:,j) = RN{i,j}.st;
108                xfinal(i,:,j) = [RN{i,j}.xfinal{:}];
109            end
110        end
111end
112
113f_out.sd = sd;
114f_out.se = se;
115f_out.st = st;
116f_out.xfinal = xfinal;
117
118% Display the runtime information for the task
119disp(task_name + " Runtime: " + string(datetime - time_begin) +...
120    "  All " + nSamples + " samples executed")
121end
122
123% Function to track progress of the LSA
124function progress_track(arg)
125persistent current_sample
126persistent last_time
127
128% Initialize or update the current sample counter
129if isempty(current_sample) || current_sample == arg{4}
130    current_sample = arg{2};
131end
132
133% Retrieve other required arguments
134task_name = arg{1};
135start_time = arg{3};
136num_samples = arg{4};
137par_n = arg{5};
138current_sample = current_sample + 1;
139
140% Print progress information at each step
141if mod(current_sample,ceil(num_samples/10)) == 0 &&...
142        current_sample ~= num_samples
143    
144    if ((num_samples-current_sample)/num_samples)*10 <...
145            ((num_samples-(num_samples/10))/num_samples)*10
146        % Calculate the remaining time
147        dt = (datetime-last_time);
148       
149        remaining_time = seconds(dt);
150        remaining_time =...
151            remaining_time*(num_samples-current_sample)/num_samples*10;
152        remaining_time = seconds(remaining_time);
153        remaining_time.Format = 'hh:mm:ss';
154     
155        % Print the progress and remaining time
156        fprintf('%s Runtime: %s  Time to finish: %s  Samples: %d/%d\n', ...
157            task_name, string(datetime - start_time), string(remaining_time), ...
158            current_sample, num_samples);
159    else
160
161        % Print the progress without remaining time
162        fprintf('%s Runtime: %s  Samples: %d/%d\n', ...
163            task_name, string(datetime - start_time), ...
164            current_sample, num_samples);
165    end
166
167    last_time = datetime;
168end
169end

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.

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 type
 31% - fM2: a structure containing the total-order score data for each score type
 32% - fN: a structure containing the score data for each score type and parameter
 33% - settings: a structure containing settings for the calculation
 34%
 35% Persistent variables:
 36% - None
 37
 38% Remove simulation errors from the input data
 39results = remove_sim_error(results,settings);
 40
 41% Calculate Si and SiT using the bootstrap method and store them in the results
 42% structure
 43[results.SiQ,results.SiTQ,results.Si,results.SiT] = bootstrap(results,settings);
 44end
 45
 46function [SiQ,SiTQ,Si,SiT]=bootstrap(results,settings)
 47% calculates confidence intervals for the sensitivity indices using the
 48% bootstrap method.
 49
 50% Initialize variables
 51fM1 = results.fM1;
 52fM2 = results.fM2;
 53fN = results.fN;
 54
 55% Set the number of resamples for bootstrapping if not provided
 56if (isempty(settings.gsabootstrapsize))
 57    settings.gsabootstrapsize=ceil(sqrt(size(fM1.sd,2)));
 58end%if
 59
 60% Define the list of scores to be used in the calculation
 61scores_list = ["sd","se","st","xfinal"];
 62
 63% Generate random indices for bootstrapping
 64for j=1:settings.gsabootstrapsize
 65    rng(j*settings.rseed)
 66    I(j,:)=ceil(rand(size(fM1.sd,1),1)*size(fM1.sd,1));
 67end
 68
 69% Calculate Si and SiT for each score type and perform bootstrapping
 70for n = 1:size(scores_list,2)
 71    fM1h = fM1.(scores_list(n));
 72    fM2h = fM2.(scores_list(n));
 73    fNh = fN.(scores_list(n));
 74
 75    % Calculate Si and SiT without bootstrapping
 76    [Sih,SiTh] = calcSobolSaltelli(fM1h,fM2h,fNh,settings);
 77    Si.(scores_list(n)) = Sih;
 78    SiT.(scores_list(n)) = SiTh;
 79
 80    % Initialize variables for bootstrapped Si and SiT
 81    SiQh = cell(1, settings.gsabootstrapsize);
 82    SiTQh = cell(1, settings.gsabootstrapsize);
 83
 84    % Perform bootstrapping for the current score type
 85    parfor j=1:settings.gsabootstrapsize
 86        [SiQh{j},SiTQh{j}] = bootstrap_q(fM1h,fM2h,fNh,settings,j,I);
 87    end%parfor
 88
 89    % Store bootstrapped Si and SiT values in the output structures
 90    for j=1:settings.gsabootstrapsize
 91        SiQ.(scores_list(n))(j,:,:) = SiQh{j};
 92        SiTQ.(scores_list(n))(j,:,:) = SiTQh{j};
 93    end
 94end
 95end%function
 96
 97function [Si,SiT] = bootstrap_q(fM1,fM2,fN,settings,j,I)
 98    % Create bootstrapped samples using the generated indices
 99    fM1q = fM1(I(j,:),:);
100    fM2q = fM2(I(j,:),:);
101    fNq = fN(I(j,:),:,:);
102
103    % Calculate Si and SiT for the bootstrapped samples
104    [Si,SiT] = calcSobolSaltelli(fM1q,fM2q,fNq,settings);
105end
106
107function [Si,SiT] = calcSobolSaltelli(fM1,fM2,fN,settings)
108% Calculates Si and SiT using the Sobol-Saltelli method.
109% Code inspired by Geir Halnes et al. 2009 paper. (Halnes, Geir, et al. J.
110% comp. neuroscience 27.3 (2009): 471.)
111
112% Get the dimensions of the input data
113[Nsamples,Nvars,Npars]=size(fN);
114
115% Optionally subtract the mean to stabilize the model
116if(settings.sasubmean)
117    fM1 = fM1 - mean(fM1,1);
118    fM2 = fM2 - mean(fM2,1);
119    for i=1:Npars
120        fN(:,:,i) =  fN(:,:,i) - mean(fN(:,:,i),1);
121    end
122end
123
124% Calculate EY2 and variances
125EY2 = mean(fM1.*fM2); % Valid definition (see Halnes et. al. Appendix)
126VY = sum(fM1.^2)/(Nsamples-1) - EY2;
127VYT = sum(fM2.^2)/(Nsamples-1) - EY2;
128
129% Initialize Si and SiT arrays
130Si = zeros(Nvars,Npars);
131SiT= zeros(Nvars,Npars);
132
133% Calculate Si and SiT for each parameter
134for i=1:Npars
135    Si(:,i) = (sum(fM1.*fN(:,:,i))/(Nsamples-1) - EY2)./VY;
136    SiT(:,i) = 1 - (sum(fM2.*fN(:,:,i))/(Nsamples-1) - EY2)./VYT;
137end
138end
139
140function results = remove_sim_error(results,settings)
141% Removes any simulation errors present in the input data.
142
143error_indices = any(results.fM1.sd == settings.errorscore, 2) | ...
144                any(results.fM2.sd == settings.errorscore, 2) | ...
145                any(any(results.fN.sd == settings.errorscore, 3), 2);
146
147% Remove error rows from all fields of the input data
148fields = fieldnames(results.fM1);
149for i = 1:numel(fields)
150    results.fM1.(fields{i})(error_indices, :) = [];
151    results.fM2.(fields{i})(error_indices, :) = [];
152    results.fN.(fields{i})(error_indices, :, :) = [];
153end
154end

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.

References

Halnes, G., Ulfhielm, E., Ljunggren, E.E., Kotaleski, J.H. and Rospars, J.P., 2009. Modelling and sensitivity analysis of the reactions involving receptor, G-protein and effector in vertebrate olfactory receptor neurons. Journal of Computational Neuroscience, 27(3), p.471.