Setup and Import

f_user_input

Code

  1function [settings, results, sb] = ...
  2    f_user_input(model_folders, analysis_options, user_choices)
  3% This function processes user input for model, analysis options, and
  4% settings files, and returns settings, results, and sbTab data structures.
  5% It utilizes helper functions to validate user input, apply settings, and
  6% manage persistent variables.
  7%
  8% Inputs:
  9% - model_folders: Model folders structure
 10% - analysis_options: Array of available analysis options
 11% - user_choices: Cell array of user input choices for model folder, 
 12% analysis, and settings
 13%
 14% Outputs:
 15% - settings: Struct containing all settings for the chosen analysis
 16% - results: Struct containing the results of the analysis
 17% - sbTab: Struct containing SBtab data
 18%
 19% Used Functions:
 20% - getValidInput: Validates user input for model folder, analysis option, 
 21% and settings file
 22% - apply_settings: Updates settings based on chosen settings file and
 23% checks for changes
 24% - choose_options: Helps user choose valid options from available choices
 25% - parse_choices: Presents list of choices to user and validates input
 26% - compare_and_update: Checks if current and previous values are different
 27% and clears functions if necessary
 28%
 29% Variables:
 30% Loaded:
 31% - None
 32%
 33% Initialized:
 34% - results: Empty struct for storing analysis results
 35% - settings: Empty struct for storing analysis settings
 36% - sbTab: Empty struct for storing SBtab data
 37%
 38% Persistent:
 39% - last_settings_file_text: Stores the last settings file text
 40% - last_settings_file_date: Stores the last settings file date
 41% - last_model_folder: Stores the last chosen model folder
 42% - last_analysis_text: Stores the last chosen analysis option
 43% - last_settings_file_text: Stores the last chosen settings file text
 44% - last_SBtab_date: Stores the last SBtab date
 45% - functions_cleared: Flag indicating if functions have been cleared or
 46% not
 47
 48
 49
 50% Define persistent variables to store the last settings file text and
 51% date.
 52persistent last_settings_file_text
 53persistent last_settings_file_date
 54
 55% Initialize the results, settings and sbTab variables.
 56results = [];
 57settings = [];
 58sb = [];
 59functions_cleared = 0;
 60
 61% Set model folder paths
 62general_model_folder = model_folders.main + "Model/";
 63
 64% Get the valid model folder based on user input.
 65model_folder =...
 66    getValidInput(general_model_folder, user_choices{1}, "model folder");
 67specific_model_folder = general_model_folder + model_folder;
 68
 69% Get the valid analysis option based on user input.
 70analysis_text =...
 71    getValidInput(analysis_options, user_choices{2}, "analysis option");
 72
 73% Store the name of the chosen analysis in the settings struct
 74settings.analysis = analysis_text;
 75
 76% Process user input for analysis options 1-5 and 8
 77if any(contains(analysis_options([1:5, 8]), analysis_text))
 78
 79    % Set settings folder path based on user input
 80    settings_folder = specific_model_folder + "/Matlab/Settings/";
 81    settings_file_text =...
 82        getValidInput(settings_folder, user_choices{3}, "settings file");
 83
 84    % Apply settings and return the settings struct
 85    [settings, last_settings_file_text, last_settings_file_date] = ...
 86        apply_settings(settings, settings_folder, settings_file_text, ...
 87        last_settings_file_date, last_settings_file_text, analysis_options, ...
 88        analysis_text, specific_model_folder, functions_cleared, ...
 89        model_folders);
 90
 91    % Process user input for analysis options 6-7
 92elseif any(contains(analysis_options(6:7), analysis_text))
 93
 94    % Set results folder path
 95    results_folder = specific_model_folder + "/Matlab/Results";
 96
 97    % Get the analysis to be reproduced based on user input.
 98    last_choice = [];
 99    prompt = "\nWhat analysis should be reproduced?\n";
100
101    [r_analysis_text, ~] =...
102        choose_options(results_folder, prompt, last_choice);
103
104    specific_results_folder = results_folder + "/" + ...
105        r_analysis_text;
106
107    % Get the date of the original analysis based on user input.
108    last_choice = [];
109    prompt = "\nWhen was this analysis run originaly?\n";
110
111    [r_analysis_date_text, ~] =...
112        choose_options(specific_results_folder, prompt, last_choice);
113
114    specific_results_folder_date = specific_results_folder + "/" + ...
115        r_analysis_date_text;
116
117    % Load the settings file and the SBtab struct
118    load(specific_results_folder_date + "/Analysis.mat", "settings", "sb")
119
120    % Set inport to false since we don't want to overwrite anything
121    settings.import = false;
122
123    % If the reproduction of an analysis is chosen, clear the functions
124    % because the settings most likely changed.
125        f_functions_to_clear()
126
127    % If the reproduction of the plots of an analysis is chosen, set the
128    % code to produce plots and load the results that were previously
129    % obtained.
130    if contains(analysis_options(7), analysis_text)
131        % Store the name of the chosen analysis in the settings struct
132        settings.analysis = analysis_text;
133
134        settings.plot = true;
135        load(specific_results_folder_date + "/Analysis.mat", "results")
136    end
137end
138
139% % Store the name of the chosen analysis in the settings struct
140% settings.analysis = analysis_text;
141
142% Set the chosen model folder in the settings struct
143settings.folder_model = model_folder;
144end
145
146function [settings, last_settings_file_text, last_settings_file_date] = ...
147    apply_settings(settings, settings_folder, settings_file_text, ...
148    last_settings_file_date, last_settings_file_text, analysis_options, ...
149    analysis_text, specific_model_folder, functions_cleared, model_folders)
150% Function apply_settings updates the settings based on the chosen settings
151% file and checks if any changes have been made to the settings file or the
152% SBtab since the last analysis
153
154persistent last_SBtab_date
155
156settings_file = strrep(settings_file_text, ".m", "");
157% Add the default settings to the struct
158stg_add_default = eval("default_settings()");
159
160% Iterate through the fields of the default settings struct and add them to
161% the settings struct
162f = fieldnames(stg_add_default);
163for i = 1:length(f)
164    settings.(f{i}) = stg_add_default.(f{i});
165end
166
167% Add chosen settings to the struct overwriting defaults when appropriate
168[stg_add] = eval(settings_file + "()");
169
170% Iterate through the fields of the chosen settings struct and add them to
171% the settings struct, overwriting the default values if necessary
172f = fieldnames(stg_add);
173for i = 1:length(f)
174    settings.(f{i}) = stg_add.(f{i});
175end
176
177% Check if the date of the settings file changed, if so clear functions
178listing = dir(settings_folder);
179for n = 1:size(listing, 1)
180    if matches(settings_file_text, listing(n).name, "IgnoreCase", true)
181        settings_file_date = listing(n).date;
182    end
183end
184
185if isempty(last_settings_file_date)
186    settings.import = true;
187else
188    settings.import = false;
189end
190
191% Check if the date of the settings file changed, if so clear functions
192[last_settings_file_date, functions_cleared] = ...
193    compare_and_update(settings_file_date, last_settings_file_date, ...
194    functions_cleared);
195
196% Check if the name of the settings file changed, if so clear functions
197[last_settings_file_text, functions_cleared] = ...
198    compare_and_update(settings_file_text, last_settings_file_text, ...
199    functions_cleared);
200
201% Check if the date of the SBtab changed, if so clear functions
202listing = dir(specific_model_folder);
203for n = 1:size(listing, 1)
204    if matches(settings.sbtab_excel_name, listing(n).name, ...
205            "IgnoreCase", true)
206        sbtab_date = listing(n).date;
207    end
208end
209
210[last_SBtab_date, functions_cleared] = ...
211    compare_and_update(sbtab_date, last_SBtab_date, functions_cleared);
212
213if functions_cleared == 1
214    settings.import = true;
215end
216
217if contains(analysis_options(8), analysis_text)
218    settings.import = true;
219    settings.save_results = false;
220    settings.plot = false;
221end
222end
223
224function valid_input = getValidInput(options, user_choice, input_type)
225% Function getValidInput validates the user input for the model folder, 
226% settings file, and analysis option
227
228persistent last_model_folder
229persistent last_analysis_text
230persistent last_settings_file_text
231
232valid_input = user_choice;
233
234% Check the validity of the input based on the input_type
235switch input_type
236    case "model folder"
237
238        % If the input is a valid model folder, return it
239        if isstring(user_choice) && isfolder(options + valid_input)
240            disp("The " + input_type + " chosen was: " + valid_input)
241            return;
242            % Otherwise, prompt the user to choose a valid one
243        else
244            disp("The chosen " + input_type + ...
245                " is not valid, please choose a valid " + input_type)
246            prompt = "What " + input_type + " should be used?\n";
247            [valid_input, last_model_folder] = ...
248            choose_options(options, prompt, last_model_folder);
249        end
250
251    case "settings file"
252        % If the input is a valid settings file, return it
253        if isstring(user_choice) && isfile(options + valid_input)
254            disp("The " + input_type + " chosen was: " + valid_input)
255            return;
256            % Otherwise, prompt the user to choose a valid one
257        else
258            disp("The chosen " + input_type + ...
259                " is not valid, please choose a valid " + input_type)
260            prompt = "What " + input_type + " should be used?\n";
261            [valid_input, last_settings_file_text] = ...
262                choose_options(options, prompt, last_settings_file_text);
263        end
264    case "analysis option"
265        % If the input is not a valid analysis, prompt the user to choose a
266        % valid analysis
267        if isstring(user_choice) || ~(user_choice >= 1) || ...
268            ~(user_choice <= 8)
269            disp("The chosen " + input_type + ...
270                " is not valid, please choose a valid " + input_type)
271            prompt = "What " + input_type + " should be used?\n";
272            [valid_input, last_analysis_text] = ...
273                parse_choices(prompt, options, last_analysis_text);
274            % Otherwise, if the analysis is valid, return it
275        else
276            valid_input = options(user_choice);
277            disp("The " + input_type + " chosen was: " + valid_input)
278        end
279end
280end
281
282function [choice, last_choice] = ...
283    choose_options(folder, prompt, last_choice)
284% Function choose_options helps user to choose valid options from available
285% choices
286
287listing = dir(folder);
288
289% Remove unnecessary entries from the listing
290for n = size(listing, 1): -1: 1
291    if any(matches(listing(n).name, [".", "..", "Place models here.txt"]))
292        listing(n) = [];
293    end
294end
295
296% Create an options array containing the names of the valid choices
297for n = 1:size(listing, 1)
298    folder(n) = string(listing(n).name);
299end
300
301% Call parse_choices to handle user input
302[choice, last_choice] = parse_choices(prompt, folder, last_choice);
303end
304
305function [choice, last_choice] = ...
306    parse_choices(prompt, options, last_choice)
307% Function parse_choices presents a list of choices to the user and
308% validates their input, then returns the chosen option
309
310% Build the prompt string with the available options
311for n = 1:size(options, 2)
312    prompt = prompt + "\n" + n + ": " + options(n);
313end
314
315% If there's a last_choice, include it in the prompt as the default
316if ~isempty(last_choice)
317    if any(contains(options, last_choice))
318        prompt = prompt + "\n\nPress enter to use " + last_choice;
319    else
320        last_choice = [];
321    end
322end
323
324prompt = prompt + "\n";
325
326% Get userinput and handle it accordingly
327i = input(prompt);
328
329% If the user input is empty, set the choice to an empty array
330if isempty(i)
331    choice = [];
332    % If the user input is a valid index, set the choice to the
333    % corresponding option
334elseif i > 0 && i < size(options, 2) + 1
335    choice = options(i);
336    disp("The option chosen was: " + choice)
337    % If the user input is invalid, call parse_choices recursively with an
338    % updated prompt
339else
340    prompt = "Please choose from the provided options";
341    [choice, last_choice] = parse_choices(prompt, options, last_choice);
342end
343
344% If the choice is empty and there's a last_choice, set the choice to
345% last_choice
346if isempty(choice)
347    if ~isempty(last_choice)
348        choice = last_choice;
349        disp("The option chosen was: " + last_choice)
350    else
351        prompt = "Please choose from the provided options";
352        [choice, last_choice] = parse_choices(prompt, options, last_choice);
353    end
354else
355    last_choice = choice;
356end
357end
358
359function [previous, is_cleared] = ...
360    compare_and_update(current, previous, is_cleared)
361% Function compare_and_update checks if the current and previous values are
362% different and clears the functions if necessary
363
364% If there's a previous value, compare it with the current value
365if ~isempty(previous)
366    % If the current and previous values are different, clear functions if
367    % not already cleared
368    if ~contains(current, previous)
369        if is_cleared == false
370            disp("Settings file changed, clearing functions")
371            f_functions_to_clear()
372            is_cleared = true;
373        end
374    end
375end
376% Update the previous value to the current value
377previous = current;
378end

In this code, the main function f_user_input is responsible for processing user inputs related to model folder, analysis options, and settings file. Based on these inputs, the function returns the necessary settings, results, and SBtab data.

Inputs:

  • mmf: a struct containing the main folder path.

  • analysis_options: an array containing the available analysis options.

  • user_choices: a cell array containing user inputs for the model folder, analysis option, and settings file.

Outputs:

  • settings: a struct containing the necessary settings for the chosen analysis.

  • results: a struct containing the results (if any) of the chosen analysis.

  • sbTab: a struct containing the SBtab data (if any) associated with the chosen analysis.

The main function relies on several helper functions to process the user input, update settings, and handle user choices.

  1. apply_settings: This function updates the settings based on the chosen settings file, and checks if any changes have been made to the settings file or SBtab since the last analysis.

    Inputs: settings, settings_folder, settings_file_text, last_settings_file_date, last_settings_file_text, analysis_options, analysis_text, specific_model_folder, functions_cleared

    Outputs: settings, last_settings_file_text, last_settings_file_date

  2. getValidInput: This function validates the user input for the model folder, settings file, and analysis option, and returns the valid input.

    Inputs: options, user_choice, input_type

    Outputs: valid_input

  3. choose_options: This function helps the user to choose valid options from available choices in a folder.

    Inputs: folder, prompt, last_choice

    Outputs: choice, last_choice

  4. parse_choices: This function presents a list of choices to the user, validates their input, and returns the chosen option.

    Inputs: prompt, options, last_choice

    Outputs: choice, last_choice

  5. compare_and_update: This function compares the current and previous values, and clears functions if necessary.

    Inputs: current, previous, is_cleared

    Outputs: previous, is_cleared

The main function starts by initializing the results, settings, and sbTab variables, and setting the model folder paths. It then calls the getValidInput function to obtain valid user input for the model folder and analysis option. Depending on the user’s chosen analysis option, the code proceeds differently. For analysis options 1-5 and 8, the apply_settings function is called to update the settings. For analysis options 6-7, the function loads the settings file and SBtab struct from a previous analysis, and processes the user input accordingly. Finally, the chosen model folder is set in the settings struct, and the function returns the updated settings, results, and sbTab data.

f_import

Code

 1function [settings, sb] = f_import(settings, model_folder)
 2% Function f_import: Import a model from an SBtab file, generate model
 3% files, and setup necessary inputs for experiments
 4%
 5% Inputs:
 6% - settings: A struct containing settings for the model import process
 7% - model_folder: A string specifying the folder where the model and
 8% related files should be saved
 9%
10% Outputs:
11% - settings: Updated struct with additional information about the number
12% of experiments and outputs
13% - sb: A struct containing data from the imported SBtab file
14%
15% Used Functions:
16% - f_excel_sbtab_importer: Converts an SBtab file into a .mat file and tsv
17% files
18% - f_generate_sbtab_struct: Generates a struct based on the SBtab and
19% updates settings with the number of experiments and outputs
20% - f_sbtab_to_model: Saves the model in .mat, .sbproj, and .xml formats, 
21% and creates a data file with required settings for running the model in
22% various experimental settings
23% - f_setup_input: Generates code to load inputs for each experiment into a
24% .mat file and creates code to read these inputs during simulation
25% - f_build_model_exp: Creates .mat files for each experiment containing
26% rules, species, and parameters based on the SBtab for equilibrium, 
27% default, and detailed simulation runs
28%
29% Variables:
30% Loaded:
31% - None
32%
33% Initialized:
34% - None
35%
36% Persistent:
37% - None
38
39disp("Generating model files and folder from SBtab")
40
41% Convert the SBtab file into a .mat file and tsv files
42f_excel_sbtab_importer(model_folder);
43
44% Creates a struct based on the SBtab that is used elswhere in the code and
45% also adds the number of experiments and outputs to the settings struct
46[settings, sb] = f_generate_sbtab_struct(settings, model_folder);
47
48% Save the model in .mat, .sbproj, and .xml formats, and create a data file
49% with the required settings for running the model in various  experimental
50% settings defined in the SBtab
51f_sbtab_to_model(settings, sb, model_folder)
52
53% Generate code to load inputs for each experiment into a .mat file, and
54% create code to read these inputs during simulation, stored in the Input
55% functions folder
56f_setup_input(settings, model_folder)
57
58% Create three .mat files for each experiment containing the necessary
59% rules, species, and parameters based on the SBtab, for equilibrium, 
60% default, and detailed simulation runs
61f_build_model_exp(settings, sb, model_folder)
62
63disp("Model files and folders generated successfully")
64end

Creates the necessary folders inside the model folder. Calls subfunctions that convert the SBtab from an Excel into MATLAB® files useful for the workflow, TSVs and a SBML.

f_excel_sbtab_importer

Code

  1function f_excel_sbtab_importer(model_folders)
  2% This function, f_excel_sbtab_importer, takes a model_folders structure as
  3% input, which contains paths to the source Excel SBtab file and the
  4% destination folders for the parsed data (MATLAB .mat file) and TSV files.
  5% The function processes the Excel file with multiple sheets in the SBtab
  6% format, imports the data from each sheet, replaces missing values with
  7% empty spaces, and exports the processed data as .mat and TSV files.
  8%
  9% Inputs:
 10% - model_folders: A structure containing the following fields:
 11% - model.sbtab: Path to the source Excel SBtab file.
 12% - model.data.sbtab: Path to the destination folder for the parsed .mat
 13% file.
 14% - model.tsv.model_name: Path to the destination folder for the TSV files.
 15%
 16% Outputs: - No direct output. The parsed data is saved as .mat and TSV
 17% files in the specified folders.
 18%
 19% Functions called:
 20% - impexp: This function is called for each sheet in the Excel SBtab file.
 21% It imports the sheet's data, replaces missing values with empty spaces, 
 22% and exports the processed data as a TSV file.
 23% - cell_write_tsv: This function writes the data in a cell array to a TSV
 24% file, taking care of transposing the array and converting numeric values
 25% to strings.
 26% 
 27% Variables:
 28% Loaded:
 29% - Source_sbtab: Path to the source Excel SBtab file.
 30% - Matlab_sbtab: Path to the destination folder for the parsed .mat file.
 31% - sheets: Cell array containing the names of sheets in the Excel SBtab
 32% file.
 33% - sbtab_excel: A cell array containing the processed data for each sheet.
 34%
 35% Initialized:
 36% - None
 37%
 38% Persistent:
 39% - None
 40
 41
 42% Get the folders for the model SBtab file and the destination for the
 43% parsed data
 44Source_sbtab = model_folders.model.sbtab;
 45Matlab_sbtab = model_folders.model.data.sbtab;
 46
 47% Get the total number of sheets in the SBTAB
 48sheets = sheetnames(Source_sbtab);
 49
 50% Attempt to run the import of sheets in parallel, depending on the version
 51% of Excel being used, this may not work
 52try
 53    parfor i = 1:size(sheets, 1)
 54        sbtab_excel{i} = impexp (i, model_folders);
 55    end
 56catch
 57    for i = 1:size(sheets, 1)
 58        sbtab_excel{i} = impexp (i, model_folders);
 59    end
 60end
 61
 62% Save the parsed SBTAB tables in .mat format
 63save(Matlab_sbtab, 'sbtab_excel');
 64disp("SBtab with " + size(sheets, 1) + " sheets parsed successfully")
 65end
 66
 67function sbtab_excel = impexp (i, model_folders)
 68
 69% Load the source SBTAB file and the folder to save the TSV files
 70Source_sbtab = model_folders.model.sbtab;
 71tsv_name_folder = model_folders.model.tsv.model_name;
 72
 73% Import the SBTAB sheet as a cell array
 74sbtab_excel = readcell(Source_sbtab, 'sheet', i);
 75
 76% Replace missing values with empty spaces
 77mask = cellfun(@ismissing, sbtab_excel, 'UniformOutput', false);
 78mask = cellfun(@min, mask);
 79mask = logical(mask);
 80sbtab_excel(mask) = {[]};
 81
 82% Get the name for the TSV file to be exported
 83field = regexp(sbtab_excel{1, 2}, "TableName='[^']*'", 'match');
 84field = string(replace(field, ["TableName='", "'", " "], ["", "", "_"]));
 85
 86% Export the TSV file
 87cell_write_tsv(tsv_name_folder + field + ".tsv", sbtab_excel)
 88end
 89
 90function cell_write_tsv(filename, origCell)
 91
 92% Create a new version of the cell for reference
 93modCell = origCell;
 94
 95% Find the indices of numeric cells
 96iNum = cellfun(@isnumeric, origCell);
 97
 98% % Replace numeric cells with cell strings
 99for n = 1:size(iNum, 1)
100    for m = 1:size(iNum, 2)
101        modCell(n, m) = cellstr(num2str(origCell{n, m}));
102    end
103end
104
105% Transpose the cell array to have the correct orientation
106modCell = transpose(modCell);
107
108% Create a format string for saving the TSV file
109[rNum, cNum] = size(origCell);
110frmt = repmat([repmat('%s\t', 1, cNum-1), '%s\n'], 1, rNum);
111fid = fopen(filename, 'wt');
112
113% Save the TSV file using the format string
114fprintf(fid, frmt, modCell{:});
115fclose(fid);
116end

Loads the information in the SBtab and creates a . mat file that contains the sbtab and TSVs corresponding to all the SBtab tabs.

f_generate_sbtab_struct

Code

 1function [stg, sb] = f_generate_sbtab_struct(stg, mmf)
 2% This function is used to load an SBtab data file, convert the SBtab data
 3% into a structure, and extract the number of experiments and outputs. The
 4% function takes two input arguments, stg and mmf, and returns two output
 5% arguments, the modified stg and the generated sb structure. The function
 6% calls the helper function convert_sbtab_to_struct to convert the SBtab
 7% data into a structure. The SBtab data file is loaded into the variable
 8% sbtab_excel.
 9%
10% Inputs:
11% - stg: An existing structure that will be updated with the number of
12% experiments and outputs.
13% - mmf: A structure containing the model information, including the SBtab
14% data file name.
15%
16% Outputs:
17% - stg: The updated structure containing the number of experiments
18% and outputs.
19% - sb: A structure generated from the SBtab data.
20%
21% Called functions:
22% - convert_sbtab_to_struct: A helper function that converts SBtab data
23% into a structure.
24%
25% Variables:
26% Loaded:
27% sbtab_excel: A variable that holds the loaded SBtab data from the
28% specified file.
29%
30% Initialized:
31% - None
32%
33% Persistent:
34% - None
35
36
37% Extract the sbtab file name from the mmf structure
38Matlab_sbtab = mmf.model.data.sbtab;
39
40% Check if the sbtab file exists
41if isfile(Matlab_sbtab)
42
43    % Load the sbtab data into a variable called 'sbtab_excel'
44    load(Matlab_sbtab, 'sbtab_excel');
45
46    % Convert the sbtab data into a structure
47    sb = convert_sbtab_to_struct(sbtab_excel);
48
49    % Extract the number of experiments and outputs
50    stg.expn = size(sb.Experiments.ID, 1);
51    stg.outn = size(sb.Output.ID, 1);
52end
53end
54
55% Helper function that converts sbtab data into a structure
56function sb = convert_sbtab_to_struct(sbtab_excel)
57
58% Initialize an empty structure
59sb = struct();
60
61% Loop through all columns in the sbtab data
62for col = 1:size(sbtab_excel, 2)
63
64    % Check if the first row of the column contains a table name
65    if ~isempty(sbtab_excel{1, col}{1, 2})
66
67        % Extract the table name from the first row of the column
68        field =...
69            regexp(sbtab_excel{1, col}{1, 2}, ...
70            "TableName='([^']*)'", 'tokens');
71        field = string(replace(field{1}, " ", "_"));
72
73        % Loop through all rows in the column
74        for row = 1:size(sbtab_excel{1, col}, 2)
75
76            % Check if the current row contains a subfield name
77            if ~isempty(sbtab_excel{1, col}{2, row})
78                % Extract the subfield name from the current row
79                subfield = sbtab_excel{1, col}{2, row};
80                subfield = regexprep(subfield, '[!>]', '');
81                subfield = regexprep(subfield, '[:\s]', '_');
82
83                % Extract the subfield values from the column
84                sb.(field).(subfield)(:, 1) = ...
85                    sbtab_excel{1, col}(3:end, row)';
86
87                % Remove empty values from the subfield
88                sb.(field).(subfield) = sb.(field).(subfield)...
89                    (~cellfun('isempty', sb.(field).(subfield)));
90            end
91        end
92    end
93end
94end

Loads the SBtab saved in the .mat file and creates a MATLAB® struct that can be more easily parsed.

f_sbtab_to_model

Code

  1function f_sbtab_to_model(stg, sb, mmf)
  2% This function, f_sbtab_to_model, converts an SBtab data structure into a
  3% model format that can be used for simulations and analysis. It then saves
  4% the model in .mat, .sbproj, and .xml formats for future use. The function
  5% also processes experimental settings defined in the SBtab data structure, 
  6% adding compartments, species, parameters, reactions, expressions, inputs, 
  7% constants, and boundary conditions to the model.
  8% 
  9% Inputs:
 10% - stg: Settings structure containing configuration information
 11% - sb: SBtab data structure containing information about species, 
 12% reactions, compartments, and parameters
 13% - mmf: Model management files structure containing the paths to save the
 14% model
 15%
 16% Outputs:
 17% - No direct outputs, but the function saves the model in .mat, .sbproj, 
 18% and .xml formats
 19%
 20% Used Functions:
 21% - add_reactions_to_model: Adds reactions from the SBtab data structure to
 22% the model object
 23% - set_boundary_Condition: Sets boundary conditions for the model
 24% - add_expressions_to_model: Adds expressions from the SBtab data
 25% structure to the model object
 26% - add_inputs_to_model: Adds inputs from the SBtab data structure to the
 27% model object
 28% - add_constants_to_model: Adds constants from the SBtab data structure to
 29% the model object
 30% - process_experiments: Processes experimental data from the SBtab data
 31% structure
 32%
 33% Variables
 34% Loaded:
 35% - sbtab.species: Species related data from the SBtab data structure
 36% - sbtab.defpar: Default parameter related data from the SBtab data
 37% structure
 38% - sbtab.sim_time: Simulation time extracted from the SBtab data structure
 39%
 40% Initialized:
 41% - modelobj: Initialized model object
 42% - compobj: Initialized compartment object
 43%
 44% Persistent:
 45% - None
 46
 47% Initialize the model object and compartment object
 48modelobj = sbiomodel(stg.name);
 49compobj = [];
 50
 51% Combine species related data into sbtab.species
 52sbtab.species = ...
 53    [sb.Compound.Name, sb.Compound.InitialValue, sb.Compound.IsConstant, ...
 54    sb.Compound.Unit, sb.Compound.Location];
 55% Combine default parameter related data into sbtab.defpar
 56sbtab.defpar = ...
 57    [sb.Parameter.Comment, sb.Parameter.Value_linspace, sb.Parameter.Unit];
 58
 59% Add compartments to the model Iterate through each compartment in the
 60% SBtab data structure and add it to the model
 61for n = 1:size(sb.Compartment.ID, 2)
 62    compobj{n} = addcompartment(modelobj, sb.Compartment.Name{n});
 63    set(compobj{n}, 'CapacityUnits', sb.Compartment.Unit{n});
 64    set(compobj{n}, 'Value', sb.Compartment.Size{n});
 65end
 66
 67% Add species to the compartments Iterate through each species in the SBtab
 68% data structure and add it to the appropriate compartment
 69for n = 1:size(sbtab.species, 1)
 70    compartment_number_match = ...
 71        find_compartment_number(compobj, sb.Compound.Location{n});
 72    addspecies (compobj{compartment_number_match}, sb.Compound.Name{n}, ...
 73        sb.Compound.InitialValue{n}, ...
 74        'InitialAmountUnits', sb.Compound.Unit{n});
 75end
 76
 77% Add species to the compartments Iterate through each species in the SBtab
 78% data structure and add it to the appropriate compartment
 79for n = 1:size(sbtab.defpar, 1)
 80    addparameter(modelobj, sb.Parameter.Name{n}, ...
 81        sb.Parameter.Value_linspace{n}, 'ValueUnits', ...
 82        sb.Parameter.Unit{n}, 'Notes', sb.Parameter.Comment{n});
 83end
 84
 85% Add reactions, expressions, inputs, constants, and boundary conditions to
 86% the model
 87modelobj = add_reactions_to_model(sb, modelobj);
 88modelobj = set_boundary_Condition(sb, modelobj);
 89modelobj = add_expressions_to_model(sb, modelobj);
 90modelobj = add_inputs_to_model(sb, modelobj);
 91modelobj = add_constants_to_model(sb, modelobj);
 92
 93% Extract simulation time from the SBtab data structure
 94sbtab.sim_time = [sb.Experiments.Sim_Time{:}];
 95% Process experimental data from the SBtab data structure
 96[sbtab, Data] = process_experiments(sb, sbtab);
 97
 98% Save the model in .mat, .sbproj, and .xml formats
 99sbproj_model = mmf.model.data.sbproj_model;
100matlab_model = mmf.model.data.mat_model;
101data_model = mmf.model.data.data_model;
102xml_model = mmf.model.data.xml_model;
103
104sbiosaveproject(sbproj_model, 'modelobj')
105save(matlab_model, 'modelobj')
106save(data_model, 'Data', 'sbtab', 'sb')
107sbmlexport(modelobj, xml_model)
108end
109
110function modelobj = add_constants_to_model(sb, modelobj)
111% This function adds constants from sb to the given model object. This
112% function checks if the sb structure has a "Constant" field, and if so, 
113% iterates through the constants and adds them as parameters to the model
114% object.
115
116% Check if the sb object has a "Constant" field
117if isfield(sb, "Constant")
118    % Iterate through the constants and add them to the model object
119    for m = 1:size(sb.Constant.ID, 1)
120        addparameter(modelobj, char(sb.Constant.Name(m)), ...
121            str2double(string(sb.Constant.Value{m})), ...
122            'ValueUnits', sb.Constant.Unit{m});
123    end
124end
125end
126
127function modelobj = add_inputs_to_model(sb, modelobj)
128% This function adds inputs from sb to the given model object. This
129% function checks if the sb structure has an "Input" field, and if so, 
130% iterates through the inputs and adds them as parameters, species, and
131% rules to the model object according to the input properties.
132
133% Check if the sb structure contains the 'Input' field
134if isfield(sb, "Input")
135    % Iterate through all inputs
136    for m = 1:size(sb.Input.ID, 1)
137        % Check if the input contains the 'Formula' field
138        if isfield(sb.Input, 'Formula')
139            % If the input formula is a double, add it as a species
140            if isa(sb.Input.Formula{m}, 'double')
141                addspecies (modelobj, char(sb.Input.Name(m)), ...
142                    str2double(string(sb.Input.DefaultValue{m})), ...
143                    'InitialAmountUnits', sb.Input.Unit{m});
144                % Otherwise, try adding it as a species with initial amount
145                % 0
146            else
147                try
148                    addspecies (modelobj, char(sb.Input.Name(m)), 0, ...
149                        'InitialAmountUnits', sb.Input.Unit{m});
150                catch
151                end
152                % Add a rule for the species using the input formula
153                addrule(modelobj, char({convertStringsToChars(...
154                    string(sb.Input.Location{m}) + "." + ...
155                    string(sb.Input.Name{m}) + " = " + ...
156                    string(sb.Input.DefaultValue{m}))}), ...
157                    'repeatedAssignment');
158            end
159        else
160            % If no 'Formula' field, add the input as a parameter
161            addparameter(modelobj, char(sb.Input.Name(m)), ...
162                str2double(string(sb.Input.DefaultValue{m})), ...
163                'ValueUnits', sb.Input.Unit{m});
164        end
165    end
166end
167end
168
169function compartment_number = find_compartment_number(compobj, location)
170% This function finds the compartment number in compobj corresponding to
171% the given location. This function iterates through all compartments in
172% compobj and returns the index of the compartment whose name matches the
173% given location.
174
175% Iterate through all compartments
176for m = 1:size(compobj, 2)
177    % Check if the current compartment's name matches the given location
178    if strcmp(compobj{m}.Name, location)
179        % If it matches, return the index and break the loop
180        compartment_number = m;
181        break;
182    end
183end
184end
185
186function [sbtab, Data] = process_experiments(sb, sbtab)
187% This function processes experiments from sb and stores data in sbtab and
188% Data. This function extracts relevant data from sb, a structured
189% representation of an SBML model, and stores it in sbtab, a structured
190% representation of an SBtab file, and Data structures, used for further
191% analysis and processing.
192
193% Initialize species_inp_indices to store the indices of species present in
194% sb.Experiments
195species_inp_indices = {};
196% Iterate through sb.Compound.ID to find species present in sb.Experiments
197for n = 1:size(sb.Compound.ID, 1)
198    field_name = "S" + (n - 1);
199    % Check if sb.Experiments has the field specified in field_name
200    if isfield(sb.Experiments, field_name)
201        species_inp_indices{end + 1, 1} = n;
202    end
203end
204
205% Iterate through sb.Experiments.ID to process each experiment
206for n = 1:size(sb.Experiments.ID, 1)
207    start_amount = cell(1, size(species_inp_indices, 1));
208    n_start_amount = 0;
209    n_input_time = 0;
210    n_input = 0;
211    n_output = 0;
212
213
214    % Check if sb.Experiments has a Normalize field, and store it in
215    % sbtab.datasets(n).Normalize
216    if isfield(sb.Experiments, "Normalize")
217        if sb.Experiments.Normalize{n} ~= 0
218            sbtab.datasets(n).Normalize = sb.Experiments.Normalize{n};
219        else
220            sbtab.datasets(n).Normalize = [];
221        end
222    else
223        sbtab.datasets(n).Normalize = [];
224    end
225
226    % Retrieve the Time data for the current experiment and store it in
227    % Data(n).Experiment.t
228    experiment_field_name = "E" + (n - 1);
229    if isfield(sb.(experiment_field_name), "Time")
230        Data(n).Experiment.t = ...
231            transpose([sb.(experiment_field_name).Time{:}]);
232    end
233
234    % Process input species data for the current experiment
235    experiment_input_field_name = "E" + (n - 1) + "I";
236    start_amount_name = cell(1, size(species_inp_indices, 1));
237    for m = 1:size(sb.Compound.ID, 1)
238        field_name = "S" + (m - 1);
239        if isfield(sb.Experiments, field_name)
240            n_start_amount = n_start_amount + 1;
241            start_amount{n_start_amount} = sb.Experiments.(field_name)(n);
242            start_amount_name{n_start_amount} = sb.Compound.Name(m);
243        end
244        % Retrieve input time data for the current experiment and species
245        if isfield(sb.(experiment_input_field_name), ...
246                "Input_Time_S" + (m - 1))
247            n_input_time = n_input_time + 1;
248            sbtab.datasets(n).input_time{1, n_input_time} = ...
249                [sb.(experiment_input_field_name).("Input_Time_S" + ...
250                (m - 1)){:}];
251        end
252        % Retrieve input value data for the current experiment and species
253        if isfield(sb.(experiment_input_field_name), "S" + (m - 1))
254            n_input = n_input + 1;
255            sbtab.datasets(n).input_value{1, n_input} = ...
256                [sb.(experiment_input_field_name).("S" + (m - 1)){:}];
257            sbtab.datasets(n).input{n_input} = char("S" + (m - 1));
258        end
259    end
260
261    % Process output data for the current experiment
262    for m = 1:size(sb.Output.ID, 1)
263        if isfield(sb.(experiment_field_name), "Y" + (m - 1))
264            n_output = n_output + 1;
265            % Retrieve output values for the current experiment and output
266            Data(n).Experiment.x(:, n_output) = ...
267                [sb.(experiment_field_name).("Y" + (m - 1)){:}];
268            % Retrieve standard deviation of output values for the current
269            % experiment and output
270            Data(n).Experiment.x_SD(:, n_output) = ....
271                [sb.(experiment_field_name).("SD_Y" + (m - 1)){:}];
272            % Store output related information in sbtab.datasets(n)
273            sbtab.datasets(n).output{n_output} = sb.Output.Name(m);
274            sbtab.datasets(n).output_value{n_output} = ...
275                {convertStringsToChars(...
276                strrep(string(sb.Output.Location{m}) + "." + ...
277                string(sb.Output.Name{m}) + " = " + ...
278                string(sb.Output.Formula{m}), 'eps', '0.0001'))};
279            sbtab.datasets(n).output_unit{n_output} = sb.Output.Unit{m};
280            sbtab.datasets(n).output_name{n_output} = sb.Output.Name(m);
281            sbtab.datasets(n).output_ID{n_output} = sb.Output.ID(m);
282            sbtab.datasets(n).output_location{n_output} = ...
283            sb.Output.Location(m);
284        end
285    end
286    % Store output count and start amount information in sbtab.datasets(n)
287    sbtab.datasets(n).stg.outnumber = n_output;
288    sbtab.datasets(n).start_amount = cat(2, start_amount_name(:), ...
289        transpose([start_amount{:}]), species_inp_indices);
290end
291end
292
293
294function model_obj = add_expressions_to_model(sb, model_obj)
295% This function adds expressions to the given model object by iterating
296% through sb.Expression fields and populating the model object with
297% parameters, species, and rules according to the expression properties
298
299% Check if the sb structure contains the 'Expression' field
300if isfield(sb, "Expression")
301    % Iterate through all expressions
302    for m = 1:size(sb.Expression.ID, 1)
303        % Check if the expression contains the 'Formula' field
304        if isfield(sb.Expression, 'Formula')
305            % If the expression formula is a double, add it as a species
306            if isa(sb.Expression.Formula{m}, 'double')
307                addspecies (model_obj, char(sb.Expression.Name(m)), ...
308                    str2double(string(sb.Expression.Formula{m})), ...
309                    'InitialAmountUnits', sb.Expression.Unit{m});
310                % Otherwise, try adding it as a species with initial amount
311                % 0
312            else
313                try
314                    addspecies (model_obj, char(sb.Expression.Name(m)), 0, ...
315                        'InitialAmountUnits', sb.Expression.Unit{m});
316                catch
317                end
318                % Add a rule for the species using the expression formula
319                addrule(model_obj, char({convertStringsToChars(...
320                    string(sb.Expression.Location{m}) + "." + ...
321                    string(sb.Expression.Name{m}) + " = " + ...
322                    string(sb.Expression.Formula{m}))}), ...
323                    'repeatedAssignment');
324            end
325        else
326            % If no 'Formula' field, add the expression as a parameter
327            addparameter(model_obj, char(sb.Expression.Name(m)), ...
328                str2double(string(sb.Expression.DefaultValue{m})), ...
329                'ValueUnits', sb.Expression.Unit{m});
330        end
331    end
332end
333end
334
335function model_obj = add_reactions_to_model(sb, model_obj)
336
337num_reactions = size(sb.Reaction.ID, 1);
338num_compounds = size(sb.Compound.Name, 1);
339
340% Add reactions to the model
341for reaction_idx = 1:num_reactions
342
343    is_reversible = sb.Reaction.IsReversible{reaction_idx};
344    reaction_formula = sb.Reaction.ReactionFormula{reaction_idx};
345    location = sb.Reaction.Location{reaction_idx};
346
347    % Determine reaction reversibility and modify reaction_name accordingly
348    if ischar(is_reversible)
349        if contains(is_reversible, "true", 'IgnoreCase', true)
350            arrow = ' <-> ';
351        else
352            arrow = ' -> ';
353        end
354    else
355        if is_reversible
356            arrow = ' <-> ';
357        else
358            arrow = ' -> ';
359        end
360    end
361    reaction = strrep(reaction_formula, '<=>', arrow);
362    % Add compartment location to the reaction name
363    for compound_idx = 1:num_compounds
364        compound_name = string(sb.Compound.Name{compound_idx});
365        reaction = insertBefore(string(reaction), " " + compound_name, ...
366            " " + location);
367    end
368
369    % Remove extra locations that were added when patterns get recognized
370    % twice because we are not matching properly
371    while contains(reaction, location + " " + location)
372        reaction = strrep(reaction, location + " " + location, " " + ...
373            location);
374    end
375
376    % Remove unnecessary spaces and characters
377    while contains(reaction, "  ")
378        reaction = strrep(reaction, "  ", " ");
379    end
380
381    % Replace the space between the location and the species with a dot
382    reaction = strrep(reaction, ...
383        location + " ", location + ".");
384
385    % Add the location to the first species of the reaction
386    reaction = location + "." + reaction;
387
388    % Add the reaction to the model
389    reaction_object = addreaction(model_obj, reaction);
390    set(reaction_object, 'ReactionRate', ...
391        sb.Reaction.KineticLaw{reaction_idx});
392end
393end
394
395function model_obj = set_boundary_Condition(sb, model_obj)
396% This function sets the boundary conditions for the species in a model
397% object based on information in the sb structure.
398
399% Loop over each compound in the sb structure
400for n = 1:size(sb.Compound.ID, 1)
401
402    % Extract information about the boundary condition for the current
403    % compound
404    assignment = sb.Compound.Assignment{n};
405    interpolation = sb.Compound.Interpolation{n};
406    is_constant = sb.Compound.IsConstant{n};
407
408    % Determine whether the current compound has a boundary condition set
409    if ischar(assignment) && contains(lower(assignment), "true")
410        % If the assignment field is the string "true", set the boundary
411        % condition to 1
412        Boundary_Condition = 1;
413    elseif isnumeric(assignment) && assignment == 1
414        % If the assignment field is the number 1, set the boundary
415        % condition to 1
416        Boundary_Condition = 1;
417    elseif assignment
418        Boundary_Condition = 1;
419    elseif ischar(interpolation) && contains(lower(interpolation), "true")
420        % If the interpolation field is the string "true", set the boundary
421        % condition to 1
422        Boundary_Condition = 1;
423    elseif isnumeric(interpolation) && interpolation == 1
424        % If the interpolation field is the number 1, set the boundary
425        % condition to 1
426        Boundary_Condition = 1;
427    elseif interpolation
428        Boundary_Condition = 1;
429    elseif ischar(is_constant) && contains(lower(is_constant), "true")
430        % If the is_constant field is the string "true", set the boundary
431        % condition to 1
432        Boundary_Condition = 1;
433    elseif isnumeric(is_constant) && is_constant == 1
434        % If the is_constant field is the number 1, set the boundary
435        % condition to 1
436        Boundary_Condition = 1;
437    elseif is_constant
438        Boundary_Condition = 1;
439    else
440        % If none of the fields indicate a boundary condition, set the
441        % boundary condition to 0
442        Boundary_Condition = 0;
443    end
444
445    model_obj.species(n).BoundaryCondition = Boundary_Condition;
446end
447end

This function, f_sbtab_to_model, converts an SBtab data structure into a model format that can be used for simulations and analysis. It then saves the model in .mat, .sbproj, and .xml formats for future use. The function also processes experimental settings defined in the SBtab data structure, adding compartments, species, parameters, reactions, expressions, inputs, constants, and boundary conditions to the model.

Inputs

  • stg: A structure containing the settings for the model conversion.

  • sb: An SBtab data structure containing the model data.

  • mmf: A structure containing the file names for saving the model in different formats.

Outputs

The function saves the generated model in .mat, .sbproj, and SBML(.xml) formats.

Functions called:

  • addcompartment: Adds a compartment to the SimBiology model object.

  • addspecies: Adds a species to a specific compartment within the model.

  • addparameter: Adds a parameter to the model, including its value, unit, and associated notes.

  • find_compartment_number: Locates the index of the compartment based on its name within the compobj cell array.

  • add_reactions_to_model: Adds reactions to the model by processing the reaction-related data in the SBtab data structure.

  • set_boundary_Condition: Sets the boundary conditions for the model using the information provided in the SBtab data structure.

  • add_expressions_to_model: Adds algebraic expressions to the model using the information provided in the SBtab data structure.

  • add_inputs_to_model: Adds input variables to the model using the information provided in the SBtab data structure.

  • add_constants_to_model: Adds constant variables to the model using the information provided in the SBtab data structure.

  • process_experiments: Processes experimental data from the SBtab data structure and returns the updated SBtab and a Data structure containing the processed experimental data.

  • sbiosaveproject: Saves the SimBiology model object as an .sbproj file.

  • save: Saves the SimBiology model object as a .mat file, and the experimental data as a separate .mat file.

  • sbmlexport: Exports the SimBiology model object as an .xml file in the Systems Biology Markup Language (SBML) format.

Loaded variables:

  • modelobj: A SimBiology model object.

  • compobj: A cell array containing compartment objects.

  • sbtab.species: A table containing species-related data.

  • sbtab.defpar: A table containing default parameter-related data.

  • sbtab.sim_time: A table containing simulation time data.

  • Data: A structure containing processed experimental data.

  • sbproj_model, matlab_model, data_model, xml_model: Variables for saving the model in .sbproj, .mat, SBML(.xml) formats, and the experimental data(file), respectively.

f_setup_input

Code

  1function f_setup_input(stg, mmf)
  2% The f_setup_input function is designed to generate code for loading
  3% experiment inputs into a .mat file and create code to read these inputs
  4% during the simulation of the experiments. The generated code is stored in
  5% the "Input_functions" folder.
  6% 
  7% Inputs:
  8% - stg: A structure containing information about the simulation settings.
  9% - mmf: A structure containing information about the model, including the
 10% model data, main folder, and input functions.
 11%
 12% Outputs:
 13% - This function creates input function files and an input creator
 14% function file in the "Input_functions" folder. The input functions are
 15% used to calculate input values based on the simulation time, while the
 16% input creator function is used to create input data from the
 17% sbtab.datasets.
 18%
 19% Used Functions :
 20% - template1: Generates code for input functions.
 21% - template2: Generates code for the first input of the first experiment
 22% in the input creator function.
 23% - template3: Generates code for the rest of the inputs in the input
 24% creator function.
 25%
 26% Loaded Variables:
 27% - matlab_model: Loaded from mmf.model.data.mat_model.
 28% - data_model: Loaded from mmf.model.data.data_model.
 29% - inp_model_data: Loaded from mmf.model.data.input_model_data.
 30% - Model_folder: Loaded from mmf.model.main.
 31% - model_input: Loaded from mmf.model.input_functions.input.
 32% - sbtab: Loaded from the data_model file.
 33% - modelobj: Loaded from the matlab_model file.
 34
 35
 36% Load required data from mmf.model.data:
 37matlab_model = mmf.model.data.mat_model;
 38data_model = mmf.model.data.data_model;
 39inp_model_data = mmf.model.data.input_model_data;
 40Model_folder = mmf.model.main;
 41model_input = mmf.model.input_functions.input;
 42
 43% Load the sbtab and modelobj variables from the respective files:
 44load(data_model, 'sbtab')
 45load(matlab_model, 'modelobj');
 46
 47% Iterate over the experiments and their inputs to generate input functions
 48% and an input creator function:
 49for Exp_n = 1:size(sbtab.datasets, 2)
 50    for index = 1:size(sbtab.datasets(Exp_n).input, 2)
 51        % If input size is larger than 100, generate input function file
 52        % for each input
 53        if size(sbtab.datasets(Exp_n).input_value{index}, 2) > 100
 54            
 55            % Generate input names by replacing "." with an empty string, 
 56            % and concatenating the "X", "T", "h1", and "h2" suffixes:
 57            input_name = strrep(modelobj.species(1 + str2double(strrep(...
 58                sbtab.datasets(Exp_n).input(index), 'S', ''))).name, ".", "");
 59            input_X = input_name + "X";
 60            input_T = input_name + "T";
 61            input_h1 = input_name + "h1";
 62            input_h2 = input_name + "h2";
 63            input_h3 = input_name + "h3";
 64
 65            % Create a new .m file for each input and write the generated
 66            % code to that file, based on the template1() function:
 67            fullFileName = sprintf('%s.m', ...
 68                model_input + Exp_n + "_" + input_name  );
 69
 70            fileID = fopen(fullFileName, 'wt');
 71
 72            inp_str = template1();
 73            inp_str = replace(inp_str, ...
 74                ["SBtab_name", "Exp_n", "input_name", ...
 75                "input_X", "input_T", "input_h1", "input_h2", "input_h3", "inp_model_data", ...
 76                "sbtab.sim_time(Exp_n)"], [stg.name, Exp_n, ...
 77                input_name, input_X, input_T, input_h1, ...
 78                input_h2, input_h3, inp_model_data, ...
 79                sbtab.sim_time(Exp_n)]);
 80
 81            fprintf(fileID, inp_str);
 82            fclose(fileID);
 83        end
 84    end
 85end
 86
 87% Create the input creator function file:
 88fullFileName = sprintf('%s.m', model_input + "_creator"  );
 89fileID = fopen(fullFileName, 'wt');
 90
 91% Write the content of the input creator function:
 92fprintf(fileID, "function " + stg.name + "_input_creator(~)\n");
 93helper = 0;
 94for Exp_n = 1:size(sbtab.datasets, 2)
 95    for index =1:size(sbtab.datasets(Exp_n).input, 2)
 96        if size(sbtab.datasets(Exp_n).input_value{index}, 2) > 100
 97            input_name = strrep(modelobj.species(1 + str2double(strrep(...
 98                sbtab.datasets(Exp_n).input(index), 'S', ''))).name, ".", "");
 99            if helper == 0
100                helper = 1;
101                helper2 = Exp_n;
102            end
103            % Write code to the input creator function file, using either
104            % template2() or template3() functions:
105            if index == 1 && Exp_n == helper2
106                fprintf(fileID, "load('" + data_model + "', 'sbtab');\n");
107                inp_creator_str = template2();
108                inp_creator_str = replace(inp_creator_str, ...
109                    ["Exp_n", "input_name", "index", "inp_model_data"], ...
110                    [Exp_n, input_name, index, inp_model_data]);
111            else
112                inp_creator_str = template3();
113                inp_creator_str = replace(inp_creator_str, ...
114                    ["Exp_n", "input_name", "index", "inp_model_data"], ...
115                    [Exp_n, input_name, index, inp_model_data]);
116            end
117            fprintf(fileID, inp_creator_str);
118        end
119    end
120end
121fprintf(fileID, "end\n");
122fclose(fileID);
123
124eval(stg.name + "_input_creator()");
125end
126
127% The template1() function generates the code for the input functions, 
128% which calculate the input based on the simulation time.
129function inp_str = template1()
130inp_str =...
131    "function thisAmp = SBtab_name_inputExp_n_input_name(times)\n" + ...
132    "persistent input_X\n" + ...
133    "persistent input_T\n" + ...
134    "persistent input_h1\n" + ...
135    "persistent input_h2\n" + ...
136    "if isempty(input_X)\n" + ...
137    "Data = coder.load('inp_model_data', 'expExp_n_input_name');\n" + ...
138    "input_X = Data.expExp_n_input_name(:, 2);\n" + ...
139    "input_T = Data.expExp_n_input_name(:, 1);\n" + ...
140    "input_h2 = input_T(2)-input_T(1);\n" + ...
141    "input_h1 = 1;\n" + ...
142    "thisAmp = input_X(1);\n" + ...
143    "elseif times <= 0\n" + ...
144    "thisAmp = input_X(1);\n" + ...
145    "elseif times >= 20\n" + ...
146    "thisAmp = input_X(end);\n" + ...
147    "else\n" + ...
148    "while times > input_T(input_h1)\n" + ...
149    "input_h1 = input_h1 + 1;\n" + ...
150    "end\n" + ...
151    "while times < input_T(input_h1-1)\n" + ...
152    "input_h1  = input_h1-1;\n" + ...
153    "end\n" + ...
154    "input_h3 = (input_T(input_h1)-times)/input_h2;\n" + ...
155    "thisAmp = input_X(input_h1-1)*input_h3 + input_X(input_h1)*(1-input_h3);\n" + ...
156    "end\n" + ...
157    "end";
158end
159   
160% The template2() function generates the code for the first input of the
161% first experiment in the "_input_creator()" function.
162function inp_creator_str = template2()
163inp_creator_str = ...
164    "expExp_n_input_name(:, 1) = sbtab.datasets(Exp_n).input_time{index};\n" + ...
165    "expExp_n_input_name(:, 2) = sbtab.datasets(Exp_n).input_value{index};\n" + ...
166    "save('inp_model_data', 'expExp_n_input_name');\n";
167end
168
169% The template3() function generates the code for the rest of the inputs in
170% the "_input_creator()" function.
171function inp_creator_str = template3()
172inp_creator_str = ...
173    "expExp_n_input_name(:, 1) = sbtab.datasets(Exp_n).input_time{index};\n" + ...
174    "expExp_n_input_name(:, 2) = sbtab.datasets(Exp_n).input_value{index};\n" + ...
175    "save('inp_model_data', 'expExp_n_input_name', '-append');\n";
176end

The f_setup_input function is designed to generate code for loading experiment inputs into a .mat file and create code to read these inputs during the simulation of the experiments. The generated code is stored in the “Input_functions” folder.

param stg:

A structure containing information about the simulation settings.

type stg:

structure

param mmf:

A structure containing information about the model, including the model data, main folder, and input functions.

type mmf:

structure

return:

This function creates input function files and an input creator function file in the “Input_functions” folder. The input functions are used to calculate input values based on the simulation time, while the input creator function is used to create input data from the sbtab.datasets.

rtype:

None

The function calls the following helper functions:

  • template1: Generates code for input functions.

  • template2: Generates code for the first input of the first experiment in the input creator function.

  • template3: Generates code for the rest of the inputs in the input creator function.

The function loads the following variables:

  • matlab_model: Loaded from mmf.model.data.mat_model.

  • data_model: Loaded from mmf.model.data.data_model.

  • inp_model_data: Loaded from mmf.model.data.input_model_data.

  • Model_folder: Loaded from mmf.model.main.

  • model_input: Loaded from mmf.model.input_functions.input.

  • sbtab: Loaded from the data_model file.

  • modelobj: Loaded from the matlab_model file.

f_build_model_exp

Code

  1function f_build_model_exp(stg, sb, mmf)
  2% This function generates .mat files for equilibrium and proper simulation
  3% runs for a set of experiments. It reads experiment settings from an sbtab
  4% structure, configures the simulation settings, processes input and output
  5% species, and saves the resulting .mat files.
  6%
  7% Inputs:
  8% - stg: A structure containing settings for the simulations, including
  9% maximum wall clock time, stop times, dimensional analysis, unit
 10% conversion, tolerances, step sizes, and time units.
 11% - sb: An sbtab structure containing information about experiments, such
 12% as output values, output species, output units, input times, input
 13% values, and input species.
 14% - mmf: A model management framework structure containing the data and mat
 15% models, which include data_model, mat_model, model_exp_eq, 
 16% model_exp_default, and model_exp_detail.
 17%
 18% Outputs:
 19% - Equilibrium and proper simulation run .mat files for each experiment, 
 20% saved with filenames based on model_exp_eq, model_exp_default, and
 21% model_exp_detail.
 22%
 23% Called Functions:
 24% - getconfigset: Retrieves the configuration set object from a SimBiology
 25% model.
 26% - copyobj: Creates a copy of a SimBiology model object.
 27% - set: Sets properties of a SimBiology object.
 28% - load: Loads variables from .mat files.
 29% - save: Saves variables to .mat files.
 30% - addspecies: Adds species to a SimBiology model compartment.
 31% - addrule: Adds rules to a SimBiology model.
 32% - addparameter: Adds parameters to a SimBiology model.
 33% - addevent: Adds events to a SimBiology model.
 34% 
 35% Variables:
 36% Loaded:
 37% - data_model: File path of the data_model .mat file containing Data and
 38% sbtab.
 39% - mat_model: File path of the mat_model .mat file containing the
 40% SimBiology model object.
 41% - model_exp_eq: File path prefix for saving equilibrium simulation run
 42% .mat files.
 43% - model_exp_default: File path prefix for saving proper simulation run
 44% .mat files.
 45% - model_exp_detail: File path prefix for saving detailed simulation run
 46% .mat files.
 47% - Data: Data structure containing experiment time points.
 48% - sbtab: sbtab structure containing experiment settings and information.
 49% - modelobj: SimBiology model object loaded from the mat_model file.
 50%
 51% Initialized:
 52% - None
 53%
 54% Persistent:
 55% - None
 56%
 57% Notes:
 58% - The function iterates through all experiments, configuring simulation
 59% settings and processing species for each experiment, then saves the
 60% corresponding .mat files.
 61
 62% Load data_model and mat_model files
 63data_model = mmf.model.data.data_model;
 64mat_model = mmf.model.data.mat_model;
 65model_exp_eq = mmf.model.data.model_exp.equilibration;
 66model_exp_default = mmf.model.data.model_exp.default;
 67model_exp_detail = mmf.model.data.model_exp.detail;
 68
 69% Load Data and modelobj from data_model and mat_model files
 70load(data_model, 'Data', 'sbtab')
 71load(mat_model, 'modelobj');
 72
 73% Initialize model_run and configsetObj arrays
 74model_run = cell(size(sb.Experiments.ID, 1), 1);
 75configsetObj = cell(size(sb.Experiments.ID, 1), 1);
 76
 77% Loop through all experiments
 78for number_exp = 1:size(sb.Experiments.ID, 1)
 79    
 80    % Load sbtab dataset information
 81    output_value = sbtab.datasets(number_exp).output_value;
 82    output = sbtab.datasets(number_exp).output;
 83    output_unit = sbtab.datasets(number_exp).output_unit;
 84    input_time = sbtab.datasets(number_exp).input_time;
 85    input_value = sbtab.datasets(number_exp).input_value;
 86    input_species = sbtab.datasets(number_exp).input;
 87    
 88    % Initialize model and configuration set objects for the current
 89    % experiment
 90    model_run{number_exp} = copyobj(modelobj);
 91    configsetObj{number_exp} = getconfigset(model_run{number_exp});
 92    
 93    % Configure simulation settings for the equilibrium simulation run
 94    set(configsetObj{number_exp}, 'MaximumWallClock', 0.2);
 95    set(configsetObj{number_exp}, 'StopTime', stg.eqt);
 96    set(configsetObj{number_exp}.CompileOptions, ...
 97        'DimensionalAnalysis', stg.dimenanal);
 98    set(configsetObj{number_exp}.CompileOptions, ...
 99        'UnitConversion', stg.UnitConversion);
100    set(configsetObj{number_exp}.SolverOptions, ...
101        'AbsoluteToleranceScaling', stg.abstolscale);
102    set(configsetObj{number_exp}.SolverOptions, ...
103        'RelativeTolerance', stg.reltol);
104    set(configsetObj{number_exp}.SolverOptions, ...
105        'AbsoluteTolerance', stg.abstol);
106    set(configsetObj{number_exp}.SolverOptions, ...
107        'AbsoluteToleranceStepSize', stg.abstolstepsize_eq);
108    helper = [0,10 .^ (-20: 0.01: log10(stg.eqt))];
109    if helper(end) ~= stg.eqt
110        helper = [helper,stg.eqt];
111    end
112
113    set(configsetObj{number_exp}.SolverOptions, 'OutputTimes', ...
114        helper);
115    set(configsetObj{number_exp}, 'TimeUnits', stg.simtime);
116    set(configsetObj{number_exp}.SolverOptions, 'MaxStep', stg.maxstepeq);
117
118    % Save equilibrium simulation run .mat file
119    model_exp = model_run{number_exp};
120    config_exp = configsetObj{number_exp};
121    save(model_exp_eq + number_exp + ".mat", 'model_exp', 'config_exp')
122    sbiosaveproject(model_exp_eq + number_exp, 'modelobj')
123
124    % Update simulation settings for the proper simulation run
125    set(configsetObj{number_exp}, 'MaximumWallClock', stg.maxt);
126    set(configsetObj{number_exp}, 'StopTime', sbtab.sim_time(number_exp));
127    set(configsetObj{number_exp}.SolverOptions, 'OutputTimes', ...
128        Data(number_exp).Experiment.t);
129    set(configsetObj{number_exp}.SolverOptions, 'MaxStep', stg.maxstep);
130    
131    % Process output species. Adds output species and rules
132    for n = 1:size(output, 2)
133        % Check if output species exist in the model
134        m = 0;
135        for k = 1:size(model_run{number_exp}.species, 1)
136            if model_run{number_exp}.species(k).name == ...
137                    string(output{1, n})
138                model_run{number_exp}.species(k).BoundaryCondition = 1;
139                m = 1;
140            end
141        end
142        % If output species does not exist, add it to the model
143        if m == 0
144            if strcmp( output_unit{1, n}, 'dimensionless' )
145                warning('off', 'SimBiology:InvalidSpeciesInitAmtUnits')
146            else
147                warning('on', 'SimBiology:InvalidSpeciesInitAmtUnits')
148            end
149            addspecies (model_run{number_exp}.Compartments(1), ...
150                char(output{1, n}), 0, ...
151                'InitialAmountUnits', output_unit{1, n});
152        end
153        % Add repeated assignment rule for output species
154        addrule(model_run{number_exp}, char(output_value{1, n}), ...
155            'repeatedAssignment');
156    end
157    
158    % Process input species. Adds input species and rules, either as events
159    % or repeated assignments
160    for j = 1:size(input_species, 2)
161        
162        input_indexcode = str2double(strrep(input_species(j), 'S', ''));
163        input_name = string(model_run{number_exp}.species(1 + ...
164                input_indexcode).name);
165        
166        % If the input time is less than 100, add events
167        if size(input_time{j}, 2) < 100
168            
169            model_run{number_exp}.species(...
170                1 + input_indexcode).BoundaryCondition = 1;
171            for n = 1:size(input_time{j}, 2)
172                if ~isnan(input_time{j}(n))
173
174                    % Add parameters for time and input values
175                    addparameter(model_run{number_exp}, ...
176                        char("time_event_t_" + j + "_" +  n), ...
177                        str2double(string(input_time{j}(n))), ...
178                        'ValueUnits', char(stg.simtime));
179                    
180                    addparameter(model_run{number_exp}, ...
181                        char("time_event_r_" + j + "_" +  n), ...
182                        str2double(string(input_value{j}(n))), ...
183                        'ValueUnits', ...
184                        char(model_run{number_exp}.species(1 + ...
185                        input_indexcode).InitialAmountUnits));
186
187                    % Add event for input species
188                    addevent(model_run{number_exp}, ...
189                        char("time>=time_event_t_" + j + "_" +  n), ...
190                        cellstr( ...
191                        sbtab.datasets(number_exp).output_location{1} + ...
192                        "." + input_name + ...
193                        " = time_event_r_" + j + "_" +  n));
194                end
195            end
196        else
197            % If the input time is greater than or equal to 100, add
198            % repeated assignment rule
199            addrule(model_run{number_exp}, char(sbtab.datasets(...
200                number_exp).output_location{1} + "." + input_name + ...
201                "=" + string(model_run{number_exp}.name) + "_input" + ...
202                number_exp + "_" + input_name + "(time)"), ...
203                'repeatedAssignment');
204        end
205    end
206
207    % Save proper simulation run .mat file (default)
208    model_exp = model_run{number_exp};
209    config_exp = configsetObj{number_exp};
210    save(model_exp_default + number_exp + ".mat", ...
211        'model_exp', 'config_exp')
212    sbiosaveproject(model_exp_default + number_exp, 'model_exp')
213
214
215    % Update simulation settings for detailed simulation run
216    set(configsetObj{number_exp}.SolverOptions, 'OutputTimes', []);
217    set(configsetObj{number_exp}.SolverOptions, ...
218        'MaxStep', stg.maxstepdetail);
219
220    % Save detailed simulation run .mat file
221    model_exp = model_run{number_exp};
222    config_exp = configsetObj{number_exp};
223    save(model_exp_detail + number_exp + ".mat", 'model_exp', 'config_exp')
224    
225end
226end

Creates two .mat files for each experiment, one for the equilibrium simulation run and one for the proper simulation. These files have all the added rules, species and parameters needed depending on the inputs and outputs specified on the SBtab.

Function: f_build_model_exp Description: This function creates two .mat files for each experiment: one for the equilibrium simulation run and one for the proper run. The .mat files contain necessary rules, species, and parameters based on the inputs and outputs specified in the sbtab. The function also configures simulation settings for the equilibrium and proper simulation runs, processes output and input species, and saves the .mat files for each experiment.

Inputs: - stg: A structure containing settings for the simulations - sb: An sbtab structure containing information about experiments - mmf: A model management framework structure containing the data and mat models

Outputs: - .mat files for equilibrium and proper runs for each experiment

Called Functions: - getconfigset - copyobj - set - load - save - addspecies - addrule - addparameter - addevent

Loaded Variables: - data_model - mat_model - model_exp_eq - model_exp_default - model_exp_detail - Data - sbtab - modelobj

Notes: - The function has a loop that iterates through all experiments and saves the corresponding .mat files.

Usage example:

% Initialize stg, sb, and mmf structures
stg = ...
sb = ...
mmf = ...

% Call the f_build_model_exp function
f_build_model_exp(stg, sb, mmf);

This will create .mat files for equilibrium and proper runs for each experiment based on the information provided in the stg, sb, and mmf structures. The function f_build_model_exp processes the input structures stg, sb, and mmf to create .mat files for each experiment. The stg structure contains simulation settings such as time units, maximum wall clock, and tolerances. The sb structure contains information about the experiments, while the mmf structure contains data and mat models.

The function loads data from the data_model and mat_model files and initializes arrays for model_run and configsetObj. It then iterates through all experiments, configuring the simulation settings for both the equilibrium and proper simulation runs.

For each experiment, the function processes the output species, adding them to the model if they don’t already exist and setting up the appropriate rules. It then processes the input species, adding them either as events or repeated assignments based on the input time.

Finally, the function saves the .mat files for each experiment, creating separate files for the equilibrium, proper (default), and detailed simulation runs.